From d4b23b80d2de2ebe068d46cdc77f3fee40c8b3dd Mon Sep 17 00:00:00 2001 From: Mesi Rendon Date: Fri, 17 Sep 2021 10:23:13 -0500 Subject: [PATCH] Cleaning repo for security audit repo I've removed the whitelist feature since it isn't a feature we want to have on the production hardlaunch. Also checking final dependencies. --- .gitignore | 3 + abis/CErc20Immutable.json | 1 - abis/CRBTC.json | 1 - abis/CToken.json | 1 - abis/ComptrollerG6.json | 1 - abis/HurricaneInterestRateModel.json | 1 - abis/JumpRateModelV2.json | 1 - abis/PriceOracleAdapterMoc.json | 1 - abis/PriceOracleProxy.json | 1 - abis/PriceProviderMoC.json | 1 - abis/StandardToken.json | 1 - abis/TropykusLens.json | 1 - abis/Unitroller.json | 1 - abis/WhitePaperInterestRateModel.json | 1 - abis/Whitelist.json | 1 - contracts/CToken.sol | 16 - contracts/Whitelist.sol | 54 - contracts/WhitelistInterface.sol | 12 - datagen.js | 2 - deploy/mainDeploy.js | 11 +- deployments/localhost/.chainId | 1 - deployments/localhost/Doc.json | 379 - deployments/localhost/DocOracle.json | 183 - deployments/localhost/MultiSigWallet.json | 847 --- deployments/localhost/PriceOracleProxy.json | 392 - deployments/localhost/RIF.json | 379 - deployments/localhost/RbtcOracle.json | 183 - deployments/localhost/RifOracle.json | 183 - .../localhost/RifPriceOracleAdapterMoc.json | 245 - deployments/localhost/USDT.json | 379 - deployments/localhost/USDTOracle.json | 183 - deployments/localhost/Unitroller.json | 379 - .../localhost/UsdtPriceOracleAdapterMoc.json | 245 - .../3f2295c0e5923ce11cb0f26c6e52bee2.json | 176 - .../eec293f42f2aab5bd7ef36a794d2c589.json | 35 - flatten/BaseJumpRateModelV2.sol | 998 --- flatten/CCompLikeDelegate.sol | 4246 ----------- flatten/CErc20.sol | 4162 ----------- flatten/CErc20Delegate.sol | 4211 ----------- flatten/CErc20Delegator.sol | 2128 ------ flatten/CErc20Immutable.sol | 4215 ----------- flatten/CRBTC.sol | 4118 ---------- flatten/CToken.sol | 3923 ---------- flatten/CTokenInterfaces.sol | 1451 ---- flatten/CarefulMath.sol | 88 - flatten/Comptroller.sol | 6443 ---------------- flatten/ComptrollerG1.sol | 5608 -------------- flatten/ComptrollerG2.sol | 5713 -------------- flatten/ComptrollerG3.sol | 6608 ----------------- flatten/ComptrollerG4.sol | 6579 ---------------- flatten/ComptrollerG5.sol | 6607 ---------------- flatten/ComptrollerG6.sol | 6605 ---------------- flatten/ComptrollerInterface.sol | 128 - flatten/ComptrollerStorage.sol | 4099 ---------- flatten/EIP20Interface.sol | 82 - flatten/EIP20NonStandardInterface.sol | 85 - flatten/ERC20.sol | 438 -- flatten/ErrorReporter.sol | 220 - flatten/Exponential.sol | 474 -- flatten/ExponentialNoError.sol | 198 - flatten/GovernorAlpha.sol | 548 -- flatten/HurricaneInterestRateModel.sol | 860 --- flatten/InterestRateModel.sol | 779 -- flatten/JumpRateModel.sol | 919 --- flatten/JumpRateModelV2.sol | 1030 --- flatten/LegacyInterestRateModel.sol | 28 - flatten/LegacyJumpRateModelV2.sol | 1060 --- flatten/Maximillion.sol | 4180 ----------- flatten/MockPriceProviderMoC.sol | 4226 ----------- flatten/MultiSigWallet.sol | 417 -- flatten/PriceOracle.sol | 3947 ---------- flatten/PriceOracleAdapter.sol | 20 - flatten/PriceOracleAdapterCompound.sol | 4303 ----------- flatten/PriceOracleAdapterMoc.sol | 111 - flatten/PriceOracleProxy.sol | 4115 ---------- flatten/Reservoir.sol | 205 - flatten/SafeMath.sol | 189 - flatten/SignedSafeMath.sol | 68 - flatten/SimplePriceOracle.sol | 4254 ----------- flatten/TROP.sol | 448 -- flatten/Timelock.sol | 400 - flatten/TropykusLens.sol | 5518 -------------- flatten/Unitroller.sol | 4298 ----------- flatten/WhitePaperInterestRateModel.sol | 863 --- flatten/Whitelist.sol | 70 - flatten/WhitelistInterface.sol | 14 - instructions | 1 - tests/repayBorrow/repay.js | 9 - 88 files changed, 4 insertions(+), 126604 deletions(-) delete mode 100644 abis/CErc20Immutable.json delete mode 100644 abis/CRBTC.json delete mode 100644 abis/CToken.json delete mode 100644 abis/ComptrollerG6.json delete mode 100644 abis/HurricaneInterestRateModel.json delete mode 100644 abis/JumpRateModelV2.json delete mode 100644 abis/PriceOracleAdapterMoc.json delete mode 100644 abis/PriceOracleProxy.json delete mode 100644 abis/PriceProviderMoC.json delete mode 100644 abis/StandardToken.json delete mode 100644 abis/TropykusLens.json delete mode 100644 abis/Unitroller.json delete mode 100644 abis/WhitePaperInterestRateModel.json delete mode 100644 abis/Whitelist.json delete mode 100644 contracts/Whitelist.sol delete mode 100644 contracts/WhitelistInterface.sol delete mode 100644 deployments/localhost/.chainId delete mode 100644 deployments/localhost/Doc.json delete mode 100644 deployments/localhost/DocOracle.json delete mode 100644 deployments/localhost/MultiSigWallet.json delete mode 100644 deployments/localhost/PriceOracleProxy.json delete mode 100644 deployments/localhost/RIF.json delete mode 100644 deployments/localhost/RbtcOracle.json delete mode 100644 deployments/localhost/RifOracle.json delete mode 100644 deployments/localhost/RifPriceOracleAdapterMoc.json delete mode 100644 deployments/localhost/USDT.json delete mode 100644 deployments/localhost/USDTOracle.json delete mode 100644 deployments/localhost/Unitroller.json delete mode 100644 deployments/localhost/UsdtPriceOracleAdapterMoc.json delete mode 100644 deployments/localhost/solcInputs/3f2295c0e5923ce11cb0f26c6e52bee2.json delete mode 100644 deployments/localhost/solcInputs/eec293f42f2aab5bd7ef36a794d2c589.json delete mode 100644 flatten/BaseJumpRateModelV2.sol delete mode 100644 flatten/CCompLikeDelegate.sol delete mode 100644 flatten/CErc20.sol delete mode 100644 flatten/CErc20Delegate.sol delete mode 100644 flatten/CErc20Delegator.sol delete mode 100644 flatten/CErc20Immutable.sol delete mode 100644 flatten/CRBTC.sol delete mode 100644 flatten/CToken.sol delete mode 100644 flatten/CTokenInterfaces.sol delete mode 100644 flatten/CarefulMath.sol delete mode 100644 flatten/Comptroller.sol delete mode 100644 flatten/ComptrollerG1.sol delete mode 100644 flatten/ComptrollerG2.sol delete mode 100644 flatten/ComptrollerG3.sol delete mode 100644 flatten/ComptrollerG4.sol delete mode 100644 flatten/ComptrollerG5.sol delete mode 100644 flatten/ComptrollerG6.sol delete mode 100644 flatten/ComptrollerInterface.sol delete mode 100644 flatten/ComptrollerStorage.sol delete mode 100644 flatten/EIP20Interface.sol delete mode 100644 flatten/EIP20NonStandardInterface.sol delete mode 100644 flatten/ERC20.sol delete mode 100644 flatten/ErrorReporter.sol delete mode 100644 flatten/Exponential.sol delete mode 100644 flatten/ExponentialNoError.sol delete mode 100644 flatten/GovernorAlpha.sol delete mode 100644 flatten/HurricaneInterestRateModel.sol delete mode 100644 flatten/InterestRateModel.sol delete mode 100644 flatten/JumpRateModel.sol delete mode 100644 flatten/JumpRateModelV2.sol delete mode 100644 flatten/LegacyInterestRateModel.sol delete mode 100644 flatten/LegacyJumpRateModelV2.sol delete mode 100644 flatten/Maximillion.sol delete mode 100644 flatten/MockPriceProviderMoC.sol delete mode 100644 flatten/MultiSigWallet.sol delete mode 100644 flatten/PriceOracle.sol delete mode 100644 flatten/PriceOracleAdapter.sol delete mode 100644 flatten/PriceOracleAdapterCompound.sol delete mode 100644 flatten/PriceOracleAdapterMoc.sol delete mode 100644 flatten/PriceOracleProxy.sol delete mode 100644 flatten/Reservoir.sol delete mode 100644 flatten/SafeMath.sol delete mode 100644 flatten/SignedSafeMath.sol delete mode 100644 flatten/SimplePriceOracle.sol delete mode 100644 flatten/TROP.sol delete mode 100644 flatten/Timelock.sol delete mode 100644 flatten/TropykusLens.sol delete mode 100644 flatten/Unitroller.sol delete mode 100644 flatten/WhitePaperInterestRateModel.sol delete mode 100644 flatten/Whitelist.sol delete mode 100644 flatten/WhitelistInterface.sol diff --git a/.gitignore b/.gitignore index 9d185a6..4758a46 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,7 @@ allFiredEvents +abis/ +flatten/ +deployments/ .build-temp build build_ diff --git a/abis/CErc20Immutable.json b/abis/CErc20Immutable.json deleted file mode 100644 index 258bae1..0000000 --- a/abis/CErc20Immutable.json +++ /dev/null @@ -1 +0,0 @@ -[{"inputs":[{"internalType":"address","name":"underlying_","type":"address"},{"internalType":"contract ComptrollerInterface","name":"comptroller_","type":"address"},{"internalType":"contract InterestRateModel","name":"interestRateModel_","type":"address"},{"internalType":"uint256","name":"initialExchangeRateMantissa_","type":"uint256"},{"internalType":"string","name":"name_","type":"string"},{"internalType":"string","name":"symbol_","type":"string"},{"internalType":"uint8","name":"decimals_","type":"uint8"},{"internalType":"address payable","name":"admin_","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"cashPrior","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"interestAccumulated","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"borrowIndex","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalBorrows","type":"uint256"}],"name":"AccrueInterest","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"borrower","type":"address"},{"indexed":false,"internalType":"uint256","name":"borrowAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"accountBorrows","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalBorrows","type":"uint256"}],"name":"Borrow","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"error","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"info","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"detail","type":"uint256"}],"name":"CTokenStorageFailure","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"liquidator","type":"address"},{"indexed":true,"internalType":"address","name":"borrower","type":"address"},{"indexed":false,"internalType":"uint256","name":"repayAmount","type":"uint256"},{"indexed":true,"internalType":"address","name":"cTokenCollateral","type":"address"},{"indexed":false,"internalType":"uint256","name":"seizeTokens","type":"uint256"}],"name":"LiquidateBorrow","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"minter","type":"address"},{"indexed":false,"internalType":"uint256","name":"mintAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"mintTokens","type":"uint256"}],"name":"Mint","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldAdmin","type":"address"},{"indexed":false,"internalType":"address","name":"newAdmin","type":"address"}],"name":"NewAdmin","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract ComptrollerInterface","name":"oldComptroller","type":"address"},{"indexed":false,"internalType":"contract ComptrollerInterface","name":"newComptroller","type":"address"}],"name":"NewComptroller","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract InterestRateModel","name":"oldInterestRateModel","type":"address"},{"indexed":false,"internalType":"contract InterestRateModel","name":"newInterestRateModel","type":"address"}],"name":"NewMarketInterestRateModel","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldPendingAdmin","type":"address"},{"indexed":false,"internalType":"address","name":"newPendingAdmin","type":"address"}],"name":"NewPendingAdmin","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldReserveFactorMantissa","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newReserveFactorMantissa","type":"uint256"}],"name":"NewReserveFactor","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"redeemer","type":"address"},{"indexed":false,"internalType":"uint256","name":"redeemAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"redeemTokens","type":"uint256"}],"name":"Redeem","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"payer","type":"address"},{"indexed":true,"internalType":"address","name":"borrower","type":"address"},{"indexed":false,"internalType":"uint256","name":"repayAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"accountBorrows","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalBorrows","type":"uint256"}],"name":"RepayBorrow","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"benefactor","type":"address"},{"indexed":false,"internalType":"uint256","name":"addAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newTotalReserves","type":"uint256"}],"name":"ReservesAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"admin","type":"address"},{"indexed":false,"internalType":"uint256","name":"reduceAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newTotalReserves","type":"uint256"}],"name":"ReservesReduced","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"benefactor","type":"address"},{"indexed":false,"internalType":"uint256","name":"addAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newSubsidyFund","type":"uint256"}],"name":"SubsidyAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"error","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"info","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"detail","type":"uint256"}],"name":"TokenFailure","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[],"name":"_acceptAdmin","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"addAmount","type":"uint256"}],"name":"_addReserves","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"reduceAmount","type":"uint256"}],"name":"_reduceReserves","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ComptrollerInterface","name":"newComptroller","type":"address"}],"name":"_setComptroller","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract InterestRateModel","name":"newInterestRateModel","type":"address"}],"name":"_setInterestRateModel","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address payable","name":"newPendingAdmin","type":"address"}],"name":"_setPendingAdmin","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newReserveFactorMantissa","type":"uint256"}],"name":"_setReserveFactor","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"accrualBlockNumber","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"accrueInterest","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_whitelist","type":"address"}],"name":"addWhitelist","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"admin","outputs":[{"internalType":"address payable","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOfUnderlying","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"borrowAmount","type":"uint256"}],"name":"borrow","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"borrowBalanceCurrent","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"borrowBalanceStored","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"borrowIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"borrowRatePerBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"comptroller","outputs":[{"internalType":"contract ComptrollerInterface","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"exchangeRateCurrent","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"exchangeRateStored","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"getAccountSnapshot","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"getBorrowerPrincipalStored","outputs":[{"internalType":"uint256","name":"borrowed","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getCash","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"getSupplierSnapshotStored","outputs":[{"internalType":"uint256","name":"tokens","type":"uint256"},{"internalType":"uint256","name":"underlyingAmount","type":"uint256"},{"internalType":"uint256","name":"suppliedAt","type":"uint256"},{"internalType":"uint256","name":"promisedSupplyRate","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"initialExchangeRateMantissa","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"underlying_","type":"address"},{"internalType":"contract ComptrollerInterface","name":"comptroller_","type":"address"},{"internalType":"contract InterestRateModel","name":"interestRateModel_","type":"address"},{"internalType":"uint256","name":"initialExchangeRateMantissa_","type":"uint256"},{"internalType":"string","name":"name_","type":"string"},{"internalType":"string","name":"symbol_","type":"string"},{"internalType":"uint8","name":"decimals_","type":"uint8"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ComptrollerInterface","name":"comptroller_","type":"address"},{"internalType":"contract InterestRateModel","name":"interestRateModel_","type":"address"},{"internalType":"uint256","name":"initialExchangeRateMantissa_","type":"uint256"},{"internalType":"string","name":"name_","type":"string"},{"internalType":"string","name":"symbol_","type":"string"},{"internalType":"uint8","name":"decimals_","type":"uint8"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"interestRateModel","outputs":[{"internalType":"contract InterestRateModel","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isCToken","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"borrower","type":"address"},{"internalType":"uint256","name":"repayAmount","type":"uint256"},{"internalType":"contract CTokenInterface","name":"cTokenCollateral","type":"address"}],"name":"liquidateBorrow","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"mintAmount","type":"uint256"}],"name":"mint","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingAdmin","outputs":[{"internalType":"address payable","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"redeemAmount","type":"uint256"}],"name":"redeem","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"repayAmount","type":"uint256"}],"name":"repayBorrow","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"reserveFactorMantissa","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"liquidator","type":"address"},{"internalType":"address","name":"borrower","type":"address"},{"internalType":"uint256","name":"seizeTokens","type":"uint256"}],"name":"seize","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"subsidyFund","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"supplyRatePerBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract EIP20NonStandardInterface","name":"token","type":"address"}],"name":"sweepToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalBorrows","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalBorrowsCurrent","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"totalReserves","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"dst","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"src","type":"address"},{"internalType":"address","name":"dst","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"underlying","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"}] \ No newline at end of file diff --git a/abis/CRBTC.json b/abis/CRBTC.json deleted file mode 100644 index 3e4c6f7..0000000 --- a/abis/CRBTC.json +++ /dev/null @@ -1 +0,0 @@ -[{"inputs":[{"internalType":"contract ComptrollerInterface","name":"comptroller_","type":"address"},{"internalType":"contract InterestRateModel","name":"interestRateModel_","type":"address"},{"internalType":"uint256","name":"initialExchangeRateMantissa_","type":"uint256"},{"internalType":"string","name":"name_","type":"string"},{"internalType":"string","name":"symbol_","type":"string"},{"internalType":"uint8","name":"decimals_","type":"uint8"},{"internalType":"address payable","name":"admin_","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"cashPrior","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"interestAccumulated","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"borrowIndex","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalBorrows","type":"uint256"}],"name":"AccrueInterest","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"borrower","type":"address"},{"indexed":false,"internalType":"uint256","name":"borrowAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"accountBorrows","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalBorrows","type":"uint256"}],"name":"Borrow","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"error","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"info","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"detail","type":"uint256"}],"name":"CTokenStorageFailure","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"liquidator","type":"address"},{"indexed":true,"internalType":"address","name":"borrower","type":"address"},{"indexed":false,"internalType":"uint256","name":"repayAmount","type":"uint256"},{"indexed":true,"internalType":"address","name":"cTokenCollateral","type":"address"},{"indexed":false,"internalType":"uint256","name":"seizeTokens","type":"uint256"}],"name":"LiquidateBorrow","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"minter","type":"address"},{"indexed":false,"internalType":"uint256","name":"mintAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"mintTokens","type":"uint256"}],"name":"Mint","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldAdmin","type":"address"},{"indexed":false,"internalType":"address","name":"newAdmin","type":"address"}],"name":"NewAdmin","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract ComptrollerInterface","name":"oldComptroller","type":"address"},{"indexed":false,"internalType":"contract ComptrollerInterface","name":"newComptroller","type":"address"}],"name":"NewComptroller","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract InterestRateModel","name":"oldInterestRateModel","type":"address"},{"indexed":false,"internalType":"contract InterestRateModel","name":"newInterestRateModel","type":"address"}],"name":"NewMarketInterestRateModel","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldPendingAdmin","type":"address"},{"indexed":false,"internalType":"address","name":"newPendingAdmin","type":"address"}],"name":"NewPendingAdmin","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldReserveFactorMantissa","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newReserveFactorMantissa","type":"uint256"}],"name":"NewReserveFactor","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"redeemer","type":"address"},{"indexed":false,"internalType":"uint256","name":"redeemAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"redeemTokens","type":"uint256"}],"name":"Redeem","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"payer","type":"address"},{"indexed":true,"internalType":"address","name":"borrower","type":"address"},{"indexed":false,"internalType":"uint256","name":"repayAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"accountBorrows","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalBorrows","type":"uint256"}],"name":"RepayBorrow","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"benefactor","type":"address"},{"indexed":false,"internalType":"uint256","name":"addAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newTotalReserves","type":"uint256"}],"name":"ReservesAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"admin","type":"address"},{"indexed":false,"internalType":"uint256","name":"reduceAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newTotalReserves","type":"uint256"}],"name":"ReservesReduced","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"benefactor","type":"address"},{"indexed":false,"internalType":"uint256","name":"addAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newSubsidyFund","type":"uint256"}],"name":"SubsidyAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"error","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"info","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"detail","type":"uint256"}],"name":"TokenFailure","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Transfer","type":"event"},{"stateMutability":"payable","type":"fallback"},{"inputs":[],"name":"_acceptAdmin","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"reduceAmount","type":"uint256"}],"name":"_reduceReserves","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ComptrollerInterface","name":"newComptroller","type":"address"}],"name":"_setComptroller","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract InterestRateModel","name":"newInterestRateModel","type":"address"}],"name":"_setInterestRateModel","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address payable","name":"newPendingAdmin","type":"address"}],"name":"_setPendingAdmin","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newReserveFactorMantissa","type":"uint256"}],"name":"_setReserveFactor","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"accrualBlockNumber","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"accrueInterest","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"addSubsidy","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_whitelist","type":"address"}],"name":"addWhitelist","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"admin","outputs":[{"internalType":"address payable","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOfUnderlying","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"borrowAmount","type":"uint256"}],"name":"borrow","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"borrowBalanceCurrent","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"borrowBalanceStored","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"borrowIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"borrowRatePerBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"comptroller","outputs":[{"internalType":"contract ComptrollerInterface","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"exchangeRateCurrent","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"exchangeRateStored","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"getAccountSnapshot","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"getBorrowerPrincipalStored","outputs":[{"internalType":"uint256","name":"borrowed","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getCash","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"getSupplierSnapshotStored","outputs":[{"internalType":"uint256","name":"tokens","type":"uint256"},{"internalType":"uint256","name":"underlyingAmount","type":"uint256"},{"internalType":"uint256","name":"suppliedAt","type":"uint256"},{"internalType":"uint256","name":"promisedSupplyRate","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"initialExchangeRateMantissa","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract ComptrollerInterface","name":"comptroller_","type":"address"},{"internalType":"contract InterestRateModel","name":"interestRateModel_","type":"address"},{"internalType":"uint256","name":"initialExchangeRateMantissa_","type":"uint256"},{"internalType":"string","name":"name_","type":"string"},{"internalType":"string","name":"symbol_","type":"string"},{"internalType":"uint8","name":"decimals_","type":"uint8"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"interestRateModel","outputs":[{"internalType":"contract InterestRateModel","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"internalFallback","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"isCToken","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"borrower","type":"address"},{"internalType":"contract CToken","name":"cTokenCollateral","type":"address"}],"name":"liquidateBorrow","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"mint","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingAdmin","outputs":[{"internalType":"address payable","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"redeemAmount","type":"uint256"}],"name":"redeem","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"repayBorrow","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"reserveFactorMantissa","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"liquidator","type":"address"},{"internalType":"address","name":"borrower","type":"address"},{"internalType":"uint256","name":"seizeTokens","type":"uint256"}],"name":"seize","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"subsidyFund","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"supplyRatePerBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalBorrows","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalBorrowsCurrent","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"totalReserves","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"dst","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"src","type":"address"},{"internalType":"address","name":"dst","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}] \ No newline at end of file diff --git a/abis/CToken.json b/abis/CToken.json deleted file mode 100644 index 258bae1..0000000 --- a/abis/CToken.json +++ /dev/null @@ -1 +0,0 @@ -[{"inputs":[{"internalType":"address","name":"underlying_","type":"address"},{"internalType":"contract ComptrollerInterface","name":"comptroller_","type":"address"},{"internalType":"contract InterestRateModel","name":"interestRateModel_","type":"address"},{"internalType":"uint256","name":"initialExchangeRateMantissa_","type":"uint256"},{"internalType":"string","name":"name_","type":"string"},{"internalType":"string","name":"symbol_","type":"string"},{"internalType":"uint8","name":"decimals_","type":"uint8"},{"internalType":"address payable","name":"admin_","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"cashPrior","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"interestAccumulated","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"borrowIndex","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalBorrows","type":"uint256"}],"name":"AccrueInterest","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"borrower","type":"address"},{"indexed":false,"internalType":"uint256","name":"borrowAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"accountBorrows","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalBorrows","type":"uint256"}],"name":"Borrow","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"error","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"info","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"detail","type":"uint256"}],"name":"CTokenStorageFailure","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"liquidator","type":"address"},{"indexed":true,"internalType":"address","name":"borrower","type":"address"},{"indexed":false,"internalType":"uint256","name":"repayAmount","type":"uint256"},{"indexed":true,"internalType":"address","name":"cTokenCollateral","type":"address"},{"indexed":false,"internalType":"uint256","name":"seizeTokens","type":"uint256"}],"name":"LiquidateBorrow","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"minter","type":"address"},{"indexed":false,"internalType":"uint256","name":"mintAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"mintTokens","type":"uint256"}],"name":"Mint","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldAdmin","type":"address"},{"indexed":false,"internalType":"address","name":"newAdmin","type":"address"}],"name":"NewAdmin","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract ComptrollerInterface","name":"oldComptroller","type":"address"},{"indexed":false,"internalType":"contract ComptrollerInterface","name":"newComptroller","type":"address"}],"name":"NewComptroller","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract InterestRateModel","name":"oldInterestRateModel","type":"address"},{"indexed":false,"internalType":"contract InterestRateModel","name":"newInterestRateModel","type":"address"}],"name":"NewMarketInterestRateModel","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldPendingAdmin","type":"address"},{"indexed":false,"internalType":"address","name":"newPendingAdmin","type":"address"}],"name":"NewPendingAdmin","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldReserveFactorMantissa","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newReserveFactorMantissa","type":"uint256"}],"name":"NewReserveFactor","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"redeemer","type":"address"},{"indexed":false,"internalType":"uint256","name":"redeemAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"redeemTokens","type":"uint256"}],"name":"Redeem","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"payer","type":"address"},{"indexed":true,"internalType":"address","name":"borrower","type":"address"},{"indexed":false,"internalType":"uint256","name":"repayAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"accountBorrows","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalBorrows","type":"uint256"}],"name":"RepayBorrow","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"benefactor","type":"address"},{"indexed":false,"internalType":"uint256","name":"addAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newTotalReserves","type":"uint256"}],"name":"ReservesAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"admin","type":"address"},{"indexed":false,"internalType":"uint256","name":"reduceAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newTotalReserves","type":"uint256"}],"name":"ReservesReduced","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"benefactor","type":"address"},{"indexed":false,"internalType":"uint256","name":"addAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newSubsidyFund","type":"uint256"}],"name":"SubsidyAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"error","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"info","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"detail","type":"uint256"}],"name":"TokenFailure","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[],"name":"_acceptAdmin","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"addAmount","type":"uint256"}],"name":"_addReserves","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"reduceAmount","type":"uint256"}],"name":"_reduceReserves","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ComptrollerInterface","name":"newComptroller","type":"address"}],"name":"_setComptroller","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract InterestRateModel","name":"newInterestRateModel","type":"address"}],"name":"_setInterestRateModel","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address payable","name":"newPendingAdmin","type":"address"}],"name":"_setPendingAdmin","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newReserveFactorMantissa","type":"uint256"}],"name":"_setReserveFactor","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"accrualBlockNumber","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"accrueInterest","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_whitelist","type":"address"}],"name":"addWhitelist","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"admin","outputs":[{"internalType":"address payable","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOfUnderlying","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"borrowAmount","type":"uint256"}],"name":"borrow","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"borrowBalanceCurrent","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"borrowBalanceStored","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"borrowIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"borrowRatePerBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"comptroller","outputs":[{"internalType":"contract ComptrollerInterface","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"exchangeRateCurrent","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"exchangeRateStored","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"getAccountSnapshot","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"getBorrowerPrincipalStored","outputs":[{"internalType":"uint256","name":"borrowed","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getCash","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"getSupplierSnapshotStored","outputs":[{"internalType":"uint256","name":"tokens","type":"uint256"},{"internalType":"uint256","name":"underlyingAmount","type":"uint256"},{"internalType":"uint256","name":"suppliedAt","type":"uint256"},{"internalType":"uint256","name":"promisedSupplyRate","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"initialExchangeRateMantissa","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"underlying_","type":"address"},{"internalType":"contract ComptrollerInterface","name":"comptroller_","type":"address"},{"internalType":"contract InterestRateModel","name":"interestRateModel_","type":"address"},{"internalType":"uint256","name":"initialExchangeRateMantissa_","type":"uint256"},{"internalType":"string","name":"name_","type":"string"},{"internalType":"string","name":"symbol_","type":"string"},{"internalType":"uint8","name":"decimals_","type":"uint8"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ComptrollerInterface","name":"comptroller_","type":"address"},{"internalType":"contract InterestRateModel","name":"interestRateModel_","type":"address"},{"internalType":"uint256","name":"initialExchangeRateMantissa_","type":"uint256"},{"internalType":"string","name":"name_","type":"string"},{"internalType":"string","name":"symbol_","type":"string"},{"internalType":"uint8","name":"decimals_","type":"uint8"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"interestRateModel","outputs":[{"internalType":"contract InterestRateModel","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isCToken","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"borrower","type":"address"},{"internalType":"uint256","name":"repayAmount","type":"uint256"},{"internalType":"contract CTokenInterface","name":"cTokenCollateral","type":"address"}],"name":"liquidateBorrow","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"mintAmount","type":"uint256"}],"name":"mint","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingAdmin","outputs":[{"internalType":"address payable","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"redeemAmount","type":"uint256"}],"name":"redeem","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"repayAmount","type":"uint256"}],"name":"repayBorrow","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"reserveFactorMantissa","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"liquidator","type":"address"},{"internalType":"address","name":"borrower","type":"address"},{"internalType":"uint256","name":"seizeTokens","type":"uint256"}],"name":"seize","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"subsidyFund","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"supplyRatePerBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract EIP20NonStandardInterface","name":"token","type":"address"}],"name":"sweepToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalBorrows","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalBorrowsCurrent","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"totalReserves","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"dst","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"src","type":"address"},{"internalType":"address","name":"dst","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"underlying","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"}] \ No newline at end of file diff --git a/abis/ComptrollerG6.json b/abis/ComptrollerG6.json deleted file mode 100644 index a115262..0000000 --- a/abis/ComptrollerG6.json +++ /dev/null @@ -1 +0,0 @@ -[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"action","type":"string"},{"indexed":false,"internalType":"bool","name":"pauseState","type":"bool"}],"name":"ActionPaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract CToken","name":"cToken","type":"address"},{"indexed":false,"internalType":"string","name":"action","type":"string"},{"indexed":false,"internalType":"bool","name":"pauseState","type":"bool"}],"name":"ActionPaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"CompGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"contract CToken","name":"cToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"newSpeed","type":"uint256"}],"name":"CompSpeedUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"contributor","type":"address"},{"indexed":false,"internalType":"uint256","name":"newSpeed","type":"uint256"}],"name":"ContributorCompSpeedUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"contract CToken","name":"cToken","type":"address"},{"indexed":true,"internalType":"address","name":"borrower","type":"address"},{"indexed":false,"internalType":"uint256","name":"compDelta","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"compBorrowIndex","type":"uint256"}],"name":"DistributedBorrowerComp","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"contract CToken","name":"cToken","type":"address"},{"indexed":true,"internalType":"address","name":"supplier","type":"address"},{"indexed":false,"internalType":"uint256","name":"compDelta","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"compSupplyIndex","type":"uint256"}],"name":"DistributedSupplierComp","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"error","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"info","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"detail","type":"uint256"}],"name":"Failure","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract CToken","name":"cToken","type":"address"},{"indexed":false,"internalType":"bool","name":"isComped","type":"bool"}],"name":"MarketComped","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract CToken","name":"cToken","type":"address"},{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"MarketEntered","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract CToken","name":"cToken","type":"address"},{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"MarketExited","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract CToken","name":"cToken","type":"address"}],"name":"MarketListed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"contract CToken","name":"cToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"newBorrowCap","type":"uint256"}],"name":"NewBorrowCap","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldBorrowCapGuardian","type":"address"},{"indexed":false,"internalType":"address","name":"newBorrowCapGuardian","type":"address"}],"name":"NewBorrowCapGuardian","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldCloseFactorMantissa","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newCloseFactorMantissa","type":"uint256"}],"name":"NewCloseFactor","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract CToken","name":"cToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"oldCollateralFactorMantissa","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newCollateralFactorMantissa","type":"uint256"}],"name":"NewCollateralFactor","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldCompRate","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newCompRate","type":"uint256"}],"name":"NewCompRate","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldLiquidationIncentiveMantissa","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newLiquidationIncentiveMantissa","type":"uint256"}],"name":"NewLiquidationIncentive","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldPauseGuardian","type":"address"},{"indexed":false,"internalType":"address","name":"newPauseGuardian","type":"address"}],"name":"NewPauseGuardian","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract PriceOracle","name":"oldPriceOracle","type":"address"},{"indexed":false,"internalType":"contract PriceOracle","name":"newPriceOracle","type":"address"}],"name":"NewPriceOracle","type":"event"},{"inputs":[{"internalType":"address[]","name":"cTokens","type":"address[]"}],"name":"_addCompMarkets","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract Unitroller","name":"unitroller","type":"address"}],"name":"_become","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"_borrowGuardianPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"cToken","type":"address"}],"name":"_dropCompMarket","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"_grantComp","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"_mintGuardianPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newBorrowCapGuardian","type":"address"}],"name":"_setBorrowCapGuardian","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract CToken","name":"cToken","type":"address"},{"internalType":"bool","name":"state","type":"bool"}],"name":"_setBorrowPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newCloseFactorMantissa","type":"uint256"}],"name":"_setCloseFactor","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract CToken","name":"cToken","type":"address"},{"internalType":"uint256","name":"newCollateralFactorMantissa","type":"uint256"}],"name":"_setCollateralFactor","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"compRate_","type":"uint256"}],"name":"_setCompRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"contributor","type":"address"},{"internalType":"uint256","name":"compSpeed","type":"uint256"}],"name":"_setContributorCompSpeed","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newLiquidationIncentiveMantissa","type":"uint256"}],"name":"_setLiquidationIncentive","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract CToken[]","name":"cTokens","type":"address[]"},{"internalType":"uint256[]","name":"newBorrowCaps","type":"uint256[]"}],"name":"_setMarketBorrowCaps","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract CToken","name":"cToken","type":"address"},{"internalType":"bool","name":"state","type":"bool"}],"name":"_setMintPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newPauseGuardian","type":"address"}],"name":"_setPauseGuardian","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract PriceOracle","name":"newOracle","type":"address"}],"name":"_setPriceOracle","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"state","type":"bool"}],"name":"_setSeizePaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"state","type":"bool"}],"name":"_setTransferPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract CToken","name":"cToken","type":"address"}],"name":"_supportMarket","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"accountAssets","outputs":[{"internalType":"contract CToken","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"admin","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"allMarkets","outputs":[{"internalType":"contract CToken","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"cToken","type":"address"},{"internalType":"address","name":"borrower","type":"address"},{"internalType":"uint256","name":"borrowAmount","type":"uint256"}],"name":"borrowAllowed","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"borrowCapGuardian","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"borrowCaps","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"borrowGuardianPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"cToken","type":"address"},{"internalType":"address","name":"borrower","type":"address"},{"internalType":"uint256","name":"borrowAmount","type":"uint256"}],"name":"borrowVerify","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"contract CToken","name":"cToken","type":"address"}],"name":"checkMembership","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"holder","type":"address"},{"internalType":"contract CToken[]","name":"cTokens","type":"address[]"}],"name":"claimComp","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"holders","type":"address[]"},{"internalType":"contract CToken[]","name":"cTokens","type":"address[]"},{"internalType":"bool","name":"borrowers","type":"bool"},{"internalType":"bool","name":"suppliers","type":"bool"}],"name":"claimComp","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"holder","type":"address"}],"name":"claimComp","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"closeFactorMantissa","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"compAccrued","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"compBorrowState","outputs":[{"internalType":"uint224","name":"index","type":"uint224"},{"internalType":"uint32","name":"block","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"compBorrowerIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"compClaimThreshold","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"compContributorSpeeds","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"compInitialIndex","outputs":[{"internalType":"uint224","name":"","type":"uint224"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"compRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"compSpeeds","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"compSupplierIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"compSupplyState","outputs":[{"internalType":"uint224","name":"index","type":"uint224"},{"internalType":"uint32","name":"block","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"comptrollerImplementation","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"cTokens","type":"address[]"}],"name":"enterMarkets","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"cTokenAddress","type":"address"}],"name":"exitMarket","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"getAccountLiquidity","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getAllMarkets","outputs":[{"internalType":"contract CToken[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"getAssetsIn","outputs":[{"internalType":"contract CToken[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getBlockNumber","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getCompAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"address","name":"cTokenModify","type":"address"},{"internalType":"uint256","name":"redeemTokens","type":"uint256"},{"internalType":"uint256","name":"borrowAmount","type":"uint256"}],"name":"getHypotheticalAccountLiquidity","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isComptroller","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"lastContributorBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"cTokenBorrowed","type":"address"},{"internalType":"address","name":"cTokenCollateral","type":"address"},{"internalType":"address","name":"liquidator","type":"address"},{"internalType":"address","name":"borrower","type":"address"},{"internalType":"uint256","name":"repayAmount","type":"uint256"}],"name":"liquidateBorrowAllowed","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"cTokenBorrowed","type":"address"},{"internalType":"address","name":"cTokenCollateral","type":"address"},{"internalType":"address","name":"liquidator","type":"address"},{"internalType":"address","name":"borrower","type":"address"},{"internalType":"uint256","name":"actualRepayAmount","type":"uint256"},{"internalType":"uint256","name":"seizeTokens","type":"uint256"}],"name":"liquidateBorrowVerify","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"cTokenBorrowed","type":"address"},{"internalType":"address","name":"cTokenCollateral","type":"address"},{"internalType":"uint256","name":"actualRepayAmount","type":"uint256"}],"name":"liquidateCalculateSeizeTokens","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"liquidationIncentiveMantissa","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"markets","outputs":[{"internalType":"bool","name":"isListed","type":"bool"},{"internalType":"uint256","name":"collateralFactorMantissa","type":"uint256"},{"internalType":"bool","name":"isComped","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxAssets","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"cToken","type":"address"},{"internalType":"address","name":"minter","type":"address"},{"internalType":"uint256","name":"mintAmount","type":"uint256"}],"name":"mintAllowed","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"mintGuardianPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"cToken","type":"address"},{"internalType":"address","name":"minter","type":"address"},{"internalType":"uint256","name":"actualMintAmount","type":"uint256"},{"internalType":"uint256","name":"mintTokens","type":"uint256"}],"name":"mintVerify","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"oracle","outputs":[{"internalType":"contract PriceOracle","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pauseGuardian","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingAdmin","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingComptrollerImplementation","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"cToken","type":"address"},{"internalType":"address","name":"redeemer","type":"address"},{"internalType":"uint256","name":"redeemTokens","type":"uint256"}],"name":"redeemAllowed","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"cToken","type":"address"},{"internalType":"address","name":"redeemer","type":"address"},{"internalType":"uint256","name":"redeemAmount","type":"uint256"},{"internalType":"uint256","name":"redeemTokens","type":"uint256"}],"name":"redeemVerify","outputs":[],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"refreshCompSpeeds","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"cToken","type":"address"},{"internalType":"address","name":"payer","type":"address"},{"internalType":"address","name":"borrower","type":"address"},{"internalType":"uint256","name":"repayAmount","type":"uint256"}],"name":"repayBorrowAllowed","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"cToken","type":"address"},{"internalType":"address","name":"payer","type":"address"},{"internalType":"address","name":"borrower","type":"address"},{"internalType":"uint256","name":"actualRepayAmount","type":"uint256"},{"internalType":"uint256","name":"borrowerIndex","type":"uint256"}],"name":"repayBorrowVerify","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"cTokenCollateral","type":"address"},{"internalType":"address","name":"cTokenBorrowed","type":"address"},{"internalType":"address","name":"liquidator","type":"address"},{"internalType":"address","name":"borrower","type":"address"},{"internalType":"uint256","name":"seizeTokens","type":"uint256"}],"name":"seizeAllowed","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"seizeGuardianPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"cTokenCollateral","type":"address"},{"internalType":"address","name":"cTokenBorrowed","type":"address"},{"internalType":"address","name":"liquidator","type":"address"},{"internalType":"address","name":"borrower","type":"address"},{"internalType":"uint256","name":"seizeTokens","type":"uint256"}],"name":"seizeVerify","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"cToken","type":"address"},{"internalType":"address","name":"src","type":"address"},{"internalType":"address","name":"dst","type":"address"},{"internalType":"uint256","name":"transferTokens","type":"uint256"}],"name":"transferAllowed","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"transferGuardianPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"cToken","type":"address"},{"internalType":"address","name":"src","type":"address"},{"internalType":"address","name":"dst","type":"address"},{"internalType":"uint256","name":"transferTokens","type":"uint256"}],"name":"transferVerify","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"tropAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"contributor","type":"address"}],"name":"updateContributorRewards","outputs":[],"stateMutability":"nonpayable","type":"function"}] \ No newline at end of file diff --git a/abis/HurricaneInterestRateModel.json b/abis/HurricaneInterestRateModel.json deleted file mode 100644 index 9df3a4c..0000000 --- a/abis/HurricaneInterestRateModel.json +++ /dev/null @@ -1 +0,0 @@ -[{"inputs":[{"internalType":"uint256","name":"_baseBorrowRate","type":"uint256"},{"internalType":"uint256","name":"_promisedBaseReturnRate","type":"uint256"},{"internalType":"uint256","name":"_optimalUtilizationRate","type":"uint256"},{"internalType":"uint256","name":"_borrowRateSlope","type":"uint256"},{"internalType":"uint256","name":"_supplyRateSlope","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"baseBorrowRatePerBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"blocksPerYear","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"borrowRateSlopePerBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"cash","type":"uint256"},{"internalType":"uint256","name":"borrows","type":"uint256"},{"internalType":"uint256","name":"reserves","type":"uint256"}],"name":"getBorrowRate","outputs":[{"internalType":"uint256","name":"borrowRate","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_totalCash","type":"uint256"},{"internalType":"uint256","name":"_totalBorrows","type":"uint256"},{"internalType":"uint256","name":"_totalReserves","type":"uint256"},{"internalType":"uint256","name":"_totalSupply","type":"uint256"}],"name":"getExchangeRate","outputs":[{"internalType":"enum CarefulMath.MathError","name":"","type":"uint8"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"cash","type":"uint256"},{"internalType":"uint256","name":"borrows","type":"uint256"},{"internalType":"uint256","name":"reserves","type":"uint256"},{"internalType":"uint256","name":"reserveFactorMantissa","type":"uint256"}],"name":"getSupplyRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"cash","type":"uint256"},{"internalType":"uint256","name":"borrows","type":"uint256"},{"internalType":"uint256","name":"reserves","type":"uint256"}],"name":"isAboveOptimal","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isInterestRateModel","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isTropykusInterestRateModel","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"optimalUtilizationRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"promisedBaseReturnRatePerBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"supplyRateSlopePerBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"cash","type":"uint256"},{"internalType":"uint256","name":"borrows","type":"uint256"},{"internalType":"uint256","name":"reserves","type":"uint256"}],"name":"utilizationRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"}] \ No newline at end of file diff --git a/abis/JumpRateModelV2.json b/abis/JumpRateModelV2.json deleted file mode 100644 index b96d398..0000000 --- a/abis/JumpRateModelV2.json +++ /dev/null @@ -1 +0,0 @@ -[{"inputs":[{"internalType":"uint256","name":"baseRatePerYear","type":"uint256"},{"internalType":"uint256","name":"multiplierPerYear","type":"uint256"},{"internalType":"uint256","name":"jumpMultiplierPerYear","type":"uint256"},{"internalType":"uint256","name":"kink_","type":"uint256"},{"internalType":"address","name":"owner_","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"newAdmin","type":"address"}],"name":"NewAdmin","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"baseRatePerBlock","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"multiplierPerBlock","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"jumpMultiplierPerBlock","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"kink","type":"uint256"}],"name":"NewInterestParams","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"newPendingAdmin","type":"address"}],"name":"NewPendingAdmin","type":"event"},{"inputs":[],"name":"acceptAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"baseRatePerBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"blocksPerYear","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"cash","type":"uint256"},{"internalType":"uint256","name":"borrows","type":"uint256"},{"internalType":"uint256","name":"reserves","type":"uint256"}],"name":"getBorrowRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_totalCash","type":"uint256"},{"internalType":"uint256","name":"_totalBorrows","type":"uint256"},{"internalType":"uint256","name":"_totalReserves","type":"uint256"},{"internalType":"uint256","name":"_totalSupply","type":"uint256"}],"name":"getExchangeRate","outputs":[{"internalType":"enum CarefulMath.MathError","name":"","type":"uint8"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"cash","type":"uint256"},{"internalType":"uint256","name":"borrows","type":"uint256"},{"internalType":"uint256","name":"reserves","type":"uint256"},{"internalType":"uint256","name":"reserveFactorMantissa","type":"uint256"}],"name":"getSupplyRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"cash","type":"uint256"},{"internalType":"uint256","name":"borrows","type":"uint256"},{"internalType":"uint256","name":"reserves","type":"uint256"}],"name":"isAboveOptimal","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isInterestRateModel","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isTropykusInterestRateModel","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"jumpMultiplierPerBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"kink","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"multiplierPerBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingAdmin","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"pendingAdmin_","type":"address"}],"name":"setPendingAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"baseRatePerYear","type":"uint256"},{"internalType":"uint256","name":"multiplierPerYear","type":"uint256"},{"internalType":"uint256","name":"jumpMultiplierPerYear","type":"uint256"},{"internalType":"uint256","name":"kink_","type":"uint256"}],"name":"updateJumpRateModel","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"cash","type":"uint256"},{"internalType":"uint256","name":"borrows","type":"uint256"},{"internalType":"uint256","name":"reserves","type":"uint256"}],"name":"utilizationRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"}] \ No newline at end of file diff --git a/abis/PriceOracleAdapterMoc.json b/abis/PriceOracleAdapterMoc.json deleted file mode 100644 index 224b818..0000000 --- a/abis/PriceOracleAdapterMoc.json +++ /dev/null @@ -1 +0,0 @@ -[{"inputs":[{"internalType":"address","name":"guardian_","type":"address"},{"internalType":"address","name":"priceProvider","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldGuardian","type":"address"},{"indexed":false,"internalType":"address","name":"newGuardian","type":"address"}],"name":"NewGuardian","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldAddress","type":"address"},{"indexed":false,"internalType":"address","name":"newAddress","type":"address"}],"name":"PriceOracleAdapterUpdated","type":"event"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"assetPrices","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"guardian","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"priceProviderMoC","outputs":[{"internalType":"contract PriceProviderMoC","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newGuardian","type":"address"}],"name":"setGuardian","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"priceProviderAddress","type":"address"}],"name":"setPriceProvider","outputs":[],"stateMutability":"nonpayable","type":"function"}] \ No newline at end of file diff --git a/abis/PriceOracleProxy.json b/abis/PriceOracleProxy.json deleted file mode 100644 index 0619816..0000000 --- a/abis/PriceOracleProxy.json +++ /dev/null @@ -1 +0,0 @@ -[{"inputs":[{"internalType":"address","name":"guardian_","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldGuardian","type":"address"},{"indexed":false,"internalType":"address","name":"newGuardian","type":"address"}],"name":"NewGuardian","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldPendingGuardian","type":"address"},{"indexed":false,"internalType":"address","name":"newPendingGuardian","type":"address"}],"name":"NewPendingGuardian","type":"event"},{"inputs":[],"name":"_acceptAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newPendingGuardian","type":"address"}],"name":"_setPendingAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"cTokenArrayCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"cTokensArray","outputs":[{"internalType":"address","name":"cToken","type":"address"},{"internalType":"string","name":"cTokenName","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract CToken","name":"cToken","type":"address"}],"name":"getUnderlyingPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"guardian","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isPriceOracle","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingGuardian","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"addressToken","type":"address"},{"internalType":"address","name":"addressAdapter","type":"address"}],"name":"setAdapterToToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"tokenAdapter","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"}] \ No newline at end of file diff --git a/abis/PriceProviderMoC.json b/abis/PriceProviderMoC.json deleted file mode 100644 index 0c38344..0000000 --- a/abis/PriceProviderMoC.json +++ /dev/null @@ -1 +0,0 @@ -[{"inputs":[],"name":"peek","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"},{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}] \ No newline at end of file diff --git a/abis/StandardToken.json b/abis/StandardToken.json deleted file mode 100644 index 0c25b39..0000000 --- a/abis/StandardToken.json +++ /dev/null @@ -1 +0,0 @@ -[{"inputs":[{"internalType":"uint256","name":"_initialAmount","type":"uint256"},{"internalType":"string","name":"_tokenName","type":"string"},{"internalType":"uint8","name":"_decimalUnits","type":"uint8"},{"internalType":"string","name":"_tokenSymbol","type":"string"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"dst","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"src","type":"address"},{"internalType":"address","name":"dst","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"}] \ No newline at end of file diff --git a/abis/TropykusLens.json b/abis/TropykusLens.json deleted file mode 100644 index 9c05c48..0000000 --- a/abis/TropykusLens.json +++ /dev/null @@ -1 +0,0 @@ -[{"inputs":[{"internalType":"contract CToken","name":"cToken","type":"address"},{"internalType":"address payable","name":"account","type":"address"}],"name":"cTokenBalances","outputs":[{"components":[{"internalType":"address","name":"cToken","type":"address"},{"internalType":"uint256","name":"balanceOf","type":"uint256"},{"internalType":"uint256","name":"borrowBalanceCurrent","type":"uint256"},{"internalType":"uint256","name":"balanceOfUnderlying","type":"uint256"},{"internalType":"uint256","name":"tokenBalance","type":"uint256"},{"internalType":"uint256","name":"tokenAllowance","type":"uint256"}],"internalType":"struct TropykusLens.CTokenBalances","name":"","type":"tuple"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract CToken[]","name":"cTokens","type":"address[]"},{"internalType":"address payable","name":"account","type":"address"}],"name":"cTokenBalancesAll","outputs":[{"components":[{"internalType":"address","name":"cToken","type":"address"},{"internalType":"uint256","name":"balanceOf","type":"uint256"},{"internalType":"uint256","name":"borrowBalanceCurrent","type":"uint256"},{"internalType":"uint256","name":"balanceOfUnderlying","type":"uint256"},{"internalType":"uint256","name":"tokenBalance","type":"uint256"},{"internalType":"uint256","name":"tokenAllowance","type":"uint256"}],"internalType":"struct TropykusLens.CTokenBalances[]","name":"","type":"tuple[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract CToken","name":"cToken","type":"address"}],"name":"cTokenMetadata","outputs":[{"components":[{"internalType":"address","name":"cToken","type":"address"},{"internalType":"uint256","name":"exchangeRateCurrent","type":"uint256"},{"internalType":"uint256","name":"supplyRatePerBlock","type":"uint256"},{"internalType":"uint256","name":"borrowRatePerBlock","type":"uint256"},{"internalType":"uint256","name":"reserveFactorMantissa","type":"uint256"},{"internalType":"uint256","name":"totalBorrows","type":"uint256"},{"internalType":"uint256","name":"totalReserves","type":"uint256"},{"internalType":"uint256","name":"totalSupply","type":"uint256"},{"internalType":"uint256","name":"totalCash","type":"uint256"},{"internalType":"bool","name":"isListed","type":"bool"},{"internalType":"uint256","name":"collateralFactorMantissa","type":"uint256"},{"internalType":"address","name":"underlyingAssetAddress","type":"address"},{"internalType":"uint256","name":"cTokenDecimals","type":"uint256"},{"internalType":"uint256","name":"underlyingDecimals","type":"uint256"}],"internalType":"struct TropykusLens.CTokenMetadata","name":"","type":"tuple"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract CToken[]","name":"cTokens","type":"address[]"}],"name":"cTokenMetadataAll","outputs":[{"components":[{"internalType":"address","name":"cToken","type":"address"},{"internalType":"uint256","name":"exchangeRateCurrent","type":"uint256"},{"internalType":"uint256","name":"supplyRatePerBlock","type":"uint256"},{"internalType":"uint256","name":"borrowRatePerBlock","type":"uint256"},{"internalType":"uint256","name":"reserveFactorMantissa","type":"uint256"},{"internalType":"uint256","name":"totalBorrows","type":"uint256"},{"internalType":"uint256","name":"totalReserves","type":"uint256"},{"internalType":"uint256","name":"totalSupply","type":"uint256"},{"internalType":"uint256","name":"totalCash","type":"uint256"},{"internalType":"bool","name":"isListed","type":"bool"},{"internalType":"uint256","name":"collateralFactorMantissa","type":"uint256"},{"internalType":"address","name":"underlyingAssetAddress","type":"address"},{"internalType":"uint256","name":"cTokenDecimals","type":"uint256"},{"internalType":"uint256","name":"underlyingDecimals","type":"uint256"}],"internalType":"struct TropykusLens.CTokenMetadata[]","name":"","type":"tuple[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract CToken","name":"cToken","type":"address"}],"name":"cTokenUnderlyingPrice","outputs":[{"components":[{"internalType":"address","name":"cToken","type":"address"},{"internalType":"uint256","name":"underlyingPrice","type":"uint256"}],"internalType":"struct TropykusLens.CTokenUnderlyingPrice","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract CToken[]","name":"cTokens","type":"address[]"}],"name":"cTokenUnderlyingPriceAll","outputs":[{"components":[{"internalType":"address","name":"cToken","type":"address"},{"internalType":"uint256","name":"underlyingPrice","type":"uint256"}],"internalType":"struct TropykusLens.CTokenUnderlyingPrice[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract ComptrollerLensInterface","name":"comptroller","type":"address"},{"internalType":"address","name":"account","type":"address"}],"name":"getAccountLimits","outputs":[{"components":[{"internalType":"contract CToken[]","name":"markets","type":"address[]"},{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"shortfall","type":"uint256"}],"internalType":"struct TropykusLens.AccountLimits","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract TROP","name":"comp","type":"address"},{"internalType":"address","name":"account","type":"address"}],"name":"getCompBalanceMetadata","outputs":[{"components":[{"internalType":"uint256","name":"balance","type":"uint256"},{"internalType":"uint256","name":"votes","type":"uint256"},{"internalType":"address","name":"delegate","type":"address"}],"internalType":"struct TropykusLens.CompBalanceMetadata","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract TROP","name":"comp","type":"address"},{"internalType":"contract ComptrollerLensInterface","name":"comptroller","type":"address"},{"internalType":"address","name":"account","type":"address"}],"name":"getCompBalanceMetadataExt","outputs":[{"components":[{"internalType":"uint256","name":"balance","type":"uint256"},{"internalType":"uint256","name":"votes","type":"uint256"},{"internalType":"address","name":"delegate","type":"address"},{"internalType":"uint256","name":"allocated","type":"uint256"}],"internalType":"struct TropykusLens.CompBalanceMetadataExt","name":"","type":"tuple"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract TROP","name":"comp","type":"address"},{"internalType":"address","name":"account","type":"address"},{"internalType":"uint32[]","name":"blockNumbers","type":"uint32[]"}],"name":"getCompVotes","outputs":[{"components":[{"internalType":"uint256","name":"blockNumber","type":"uint256"},{"internalType":"uint256","name":"votes","type":"uint256"}],"internalType":"struct TropykusLens.CompVotes[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract GovernorAlpha","name":"governor","type":"address"},{"internalType":"uint256[]","name":"proposalIds","type":"uint256[]"}],"name":"getGovProposals","outputs":[{"components":[{"internalType":"uint256","name":"proposalId","type":"uint256"},{"internalType":"address","name":"proposer","type":"address"},{"internalType":"uint256","name":"eta","type":"uint256"},{"internalType":"address[]","name":"targets","type":"address[]"},{"internalType":"uint256[]","name":"values","type":"uint256[]"},{"internalType":"string[]","name":"signatures","type":"string[]"},{"internalType":"bytes[]","name":"calldatas","type":"bytes[]"},{"internalType":"uint256","name":"startBlock","type":"uint256"},{"internalType":"uint256","name":"endBlock","type":"uint256"},{"internalType":"uint256","name":"forVotes","type":"uint256"},{"internalType":"uint256","name":"againstVotes","type":"uint256"},{"internalType":"bool","name":"canceled","type":"bool"},{"internalType":"bool","name":"executed","type":"bool"}],"internalType":"struct TropykusLens.GovProposal[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract GovernorAlpha","name":"governor","type":"address"},{"internalType":"address","name":"voter","type":"address"},{"internalType":"uint256[]","name":"proposalIds","type":"uint256[]"}],"name":"getGovReceipts","outputs":[{"components":[{"internalType":"uint256","name":"proposalId","type":"uint256"},{"internalType":"bool","name":"hasVoted","type":"bool"},{"internalType":"bool","name":"support","type":"bool"},{"internalType":"uint96","name":"votes","type":"uint96"}],"internalType":"struct TropykusLens.GovReceipt[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"}] \ No newline at end of file diff --git a/abis/Unitroller.json b/abis/Unitroller.json deleted file mode 100644 index a364d11..0000000 --- a/abis/Unitroller.json +++ /dev/null @@ -1 +0,0 @@ -[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"error","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"info","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"detail","type":"uint256"}],"name":"Failure","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldAdmin","type":"address"},{"indexed":false,"internalType":"address","name":"newAdmin","type":"address"}],"name":"NewAdmin","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldImplementation","type":"address"},{"indexed":false,"internalType":"address","name":"newImplementation","type":"address"}],"name":"NewImplementation","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldPendingAdmin","type":"address"},{"indexed":false,"internalType":"address","name":"newPendingAdmin","type":"address"}],"name":"NewPendingAdmin","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldPendingImplementation","type":"address"},{"indexed":false,"internalType":"address","name":"newPendingImplementation","type":"address"}],"name":"NewPendingImplementation","type":"event"},{"stateMutability":"payable","type":"fallback"},{"inputs":[],"name":"_acceptAdmin","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"_acceptImplementation","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newPendingAdmin","type":"address"}],"name":"_setPendingAdmin","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newPendingImplementation","type":"address"}],"name":"_setPendingImplementation","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"admin","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"comptrollerImplementation","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"internalFallback","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"pendingAdmin","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingComptrollerImplementation","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}] \ No newline at end of file diff --git a/abis/WhitePaperInterestRateModel.json b/abis/WhitePaperInterestRateModel.json deleted file mode 100644 index 5cfb503..0000000 --- a/abis/WhitePaperInterestRateModel.json +++ /dev/null @@ -1 +0,0 @@ -[{"inputs":[{"internalType":"uint256","name":"baseRatePerYear","type":"uint256"},{"internalType":"uint256","name":"multiplierPerYear","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"baseRatePerBlock","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"multiplierPerBlock","type":"uint256"}],"name":"NewInterestParams","type":"event"},{"inputs":[],"name":"baseRatePerBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"blocksPerYear","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"cash","type":"uint256"},{"internalType":"uint256","name":"borrows","type":"uint256"},{"internalType":"uint256","name":"reserves","type":"uint256"}],"name":"getBorrowRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_totalCash","type":"uint256"},{"internalType":"uint256","name":"_totalBorrows","type":"uint256"},{"internalType":"uint256","name":"_totalReserves","type":"uint256"},{"internalType":"uint256","name":"_totalSupply","type":"uint256"}],"name":"getExchangeRate","outputs":[{"internalType":"enum CarefulMath.MathError","name":"","type":"uint8"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"cash","type":"uint256"},{"internalType":"uint256","name":"borrows","type":"uint256"},{"internalType":"uint256","name":"reserves","type":"uint256"},{"internalType":"uint256","name":"reserveFactorMantissa","type":"uint256"}],"name":"getSupplyRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"cash","type":"uint256"},{"internalType":"uint256","name":"borrows","type":"uint256"},{"internalType":"uint256","name":"reserves","type":"uint256"}],"name":"isAboveOptimal","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isInterestRateModel","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isTropykusInterestRateModel","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"multiplierPerBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"cash","type":"uint256"},{"internalType":"uint256","name":"borrows","type":"uint256"},{"internalType":"uint256","name":"reserves","type":"uint256"}],"name":"utilizationRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"}] \ No newline at end of file diff --git a/abis/Whitelist.json b/abis/Whitelist.json deleted file mode 100644 index 0c77297..0000000 --- a/abis/Whitelist.json +++ /dev/null @@ -1 +0,0 @@ -[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address[]","name":"_users","type":"address[]"}],"name":"addUsers","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"enabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"exist","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getUsers","outputs":[{"internalType":"address[]","name":"currentUsers","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"}],"name":"removeUser","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_newStatus","type":"bool"}],"name":"setStatus","outputs":[],"stateMutability":"nonpayable","type":"function"}] \ No newline at end of file diff --git a/contracts/CToken.sol b/contracts/CToken.sol index 6de76d3..a66f23f 100644 --- a/contracts/CToken.sol +++ b/contracts/CToken.sol @@ -7,7 +7,6 @@ import "./ErrorReporter.sol"; import "./Exponential.sol"; import "./EIP20Interface.sol"; import "./InterestRateModel.sol"; -import "./WhitelistInterface.sol"; /** * @title tropykus CToken Contract @@ -15,8 +14,6 @@ import "./WhitelistInterface.sol"; * @author tropykus */ abstract contract CToken is CTokenInterface, Exponential, TokenErrorReporter { - address whitelist; - /** * @notice Initialize the money market * @param comptroller_ The address of the Comptroller @@ -56,16 +53,6 @@ abstract contract CToken is CTokenInterface, Exponential, TokenErrorReporter { _notEntered = true; } - function addWhitelist(address _whitelist) external { - if (msg.sender != admin) { - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_INTEREST_RATE_MODEL_OWNER_CHECK - ); - } - whitelist = _whitelist; - } - /** * @notice Transfer `tokens` tokens from `src` to `dst` by `spender` * @dev Called by both `transfer` and `transferFrom` internally @@ -760,9 +747,6 @@ abstract contract CToken is CTokenInterface, Exponential, TokenErrorReporter { nonReentrant returns (uint256, uint256) { - if (WhitelistInterface(whitelist).enabled()) { - require(WhitelistInterface(whitelist).exist(msg.sender), "CT26"); - } uint256 error = accrueInterest(); if (error != uint256(Error.NO_ERROR)) { return ( diff --git a/contracts/Whitelist.sol b/contracts/Whitelist.sol deleted file mode 100644 index 82303a5..0000000 --- a/contracts/Whitelist.sol +++ /dev/null @@ -1,54 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity 0.8.6; - -import "./WhitelistInterface.sol"; - -contract Whitelist is WhitelistInterface { - bool public override enabled; - address owner; - mapping(address => bool) public override exist; - address[] users; - - modifier onlyOwner() { - require(msg.sender == owner); - _; - } - - constructor() { - owner = msg.sender; - enabled = true; - } - - function setStatus(bool _newStatus) external override onlyOwner { - enabled = _newStatus; - } - - function addUsers(address[] memory _users) external override onlyOwner { - for (uint256 i = 0; i < _users.length; i++) { - if (exist[_users[i]]) continue; - users.push(_users[i]); - exist[_users[i]] = true; - } - } - - function getUsers() - external - view - override - returns (address[] memory currentUsers) - { - currentUsers = users; - } - - function removeUser(address _user) external override onlyOwner { - if (exist[_user]) { - exist[_user] = false; - address[] memory oldUsers = users; - users = new address[](0); - for (uint256 i = 0; i < oldUsers.length; i++) { - if (oldUsers[i] == _user) continue; - users.push(oldUsers[i]); - } - } - } -} diff --git a/contracts/WhitelistInterface.sol b/contracts/WhitelistInterface.sol deleted file mode 100644 index 3081060..0000000 --- a/contracts/WhitelistInterface.sol +++ /dev/null @@ -1,12 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity 0.8.6; - -interface WhitelistInterface { - function setStatus(bool _newStatus) external; - function enabled() external view returns(bool); - - function addUsers(address[] memory _users) external; - function exist(address _user) external view returns(bool); - function getUsers() external view returns(address[] memory currentUsers); - function removeUser(address _user) external; -} \ No newline at end of file diff --git a/datagen.js b/datagen.js index 3bbfb2a..e03d06b 100644 --- a/datagen.js +++ b/datagen.js @@ -34,5 +34,3 @@ fs.writeFileSync('./abis/StandardToken.json', JSON.stringify(contracts.contracts console.log('StandardToken.json created'); fs.writeFileSync('./abis/CErc20Immutable.json', JSON.stringify(contracts.contracts['contracts/CErc20Immutable.sol:CErc20Immutable'].abi)); console.log('CErc20Immutable.json created'); -fs.writeFileSync('./abis/Whitelist.json', JSON.stringify(contracts.contracts['contracts/Whitelist.sol:Whitelist'].abi)); -console.log('CErc20Immutable.json created'); diff --git a/deploy/mainDeploy.js b/deploy/mainDeploy.js index a00dda7..4bd21c7 100644 --- a/deploy/mainDeploy.js +++ b/deploy/mainDeploy.js @@ -85,10 +85,6 @@ async function main() { const comptrollerDeployed = await comptrollerContract.deploy(); // console.log(`Comptroller = ${comptrollerDeployed.address}`); - const Whitelist = await ethers.getContractFactory('Whitelist'); - const whitelistDeployed = await Whitelist.deploy(); - console.log(`Whitelist = '${whitelistDeployed.address}';`); - // console.log('\n~~~~~~~~~~~~~~~~~~~~~~~~ TOKENS ~~~~~~~~~~~~~~~~~~~~~~~~'); const standardTokenContract = await ethers.getContractFactory('StandardToken'); let rifToken = { @@ -174,12 +170,7 @@ async function main() { console.log(`cUSDT = '${cUSDTdeployed.address}';`); console.log(`cRBTC = '${cRBTCdeployed.address}';`); console.log(`cSAT = '${cSATdeployed.address}';`); - - await cRIFdeployed.addWhitelist(whitelistDeployed.address); - await cDOCdeployed.addWhitelist(whitelistDeployed.address); - await cUSDTdeployed.addWhitelist(whitelistDeployed.address); - await cRBTCdeployed.addWhitelist(whitelistDeployed.address); - await cSATdeployed.addWhitelist(whitelistDeployed.address); + // console.log('~~~~~~~~~~~~~~~~~~~~ /MARKETS cTOKENS ~~~~~~~~~~~~~~~~~~~~\n'); const tropykusLensContract = await ethers.getContractFactory('TropykusLens'); diff --git a/deployments/localhost/.chainId b/deployments/localhost/.chainId deleted file mode 100644 index fa1bddf..0000000 --- a/deployments/localhost/.chainId +++ /dev/null @@ -1 +0,0 @@ -1337 \ No newline at end of file diff --git a/deployments/localhost/Doc.json b/deployments/localhost/Doc.json deleted file mode 100644 index 1a8ea22..0000000 --- a/deployments/localhost/Doc.json +++ /dev/null @@ -1,379 +0,0 @@ -{ - "address": "0x322813Fd9A801c5507c9de605d63CEA4f2CE6c44", - "abi": [ - { - "inputs": [ - { - "internalType": "uint256", - "name": "_initialAmount", - "type": "uint256" - }, - { - "internalType": "string", - "name": "_tokenName", - "type": "string" - }, - { - "internalType": "uint8", - "name": "_decimalUnits", - "type": "uint8" - }, - { - "internalType": "string", - "name": "_tokenSymbol", - "type": "string" - } - ], - "stateMutability": "nonpayable", - "type": "constructor" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "spender", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "Approval", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "Transfer", - "type": "event" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - }, - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "name": "allowance", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_spender", - "type": "address" - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "approve", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "name": "balanceOf", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "decimals", - "outputs": [ - { - "internalType": "uint8", - "name": "", - "type": "uint8" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "name", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "symbol", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalSupply", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "dst", - "type": "address" - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "transfer", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "src", - "type": "address" - }, - { - "internalType": "address", - "name": "dst", - "type": "address" - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "transferFrom", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "nonpayable", - "type": "function" - } - ], - "transactionHash": "0x81827bf12ec6b8f53faf14d914702829a2fa64d2b19f971db14061f040b5e741", - "receipt": { - "to": null, - "from": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", - "contractAddress": "0x322813Fd9A801c5507c9de605d63CEA4f2CE6c44", - "transactionIndex": 0, - "gasUsed": "576618", - "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "blockHash": "0x4746e4af254f4a30aff3664af9f4059be6f5241a7f89de58fc7d4409578c7954", - "transactionHash": "0x81827bf12ec6b8f53faf14d914702829a2fa64d2b19f971db14061f040b5e741", - "logs": [], - "blockNumber": 24, - "cumulativeGasUsed": "576618", - "status": 1, - "byzantium": true - }, - "args": [ - "2000000000000000000000000", - "DOC token", - 18, - "DOC" - ], - "solcInputHash": "3f2295c0e5923ce11cb0f26c6e52bee2", - "metadata": "{\"compiler\":{\"version\":\"0.8.6+commit.11564f7e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_initialAmount\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"_tokenName\",\"type\":\"string\"},{\"internalType\":\"uint8\",\"name\":\"_decimalUnits\",\"type\":\"uint8\"},{\"internalType\":\"string\",\"name\":\"_tokenSymbol\",\"type\":\"string\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"Approval\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"Transfer\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"allowance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"approve\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"balanceOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"decimals\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"name\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"symbol\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"totalSupply\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"dst\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"transfer\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"src\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"dst\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"transferFrom\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Implementation of the basic standard token. See https://github.com/ethereum/EIPs/issues/20\",\"kind\":\"dev\",\"methods\":{},\"title\":\"Standard ERC20 token\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/ERC20.sol\":\"StandardToken\"},\"evmVersion\":\"berlin\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"contracts/ERC20.sol\":{\"content\":\"// SPDX-License-Identifier: UNLICENSED\\npragma solidity 0.8.6;\\n\\nimport \\\"./SafeMath.sol\\\";\\n\\ninterface ERC20Base {\\n event Approval(\\n address indexed owner,\\n address indexed spender,\\n uint256 value\\n );\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n function totalSupply() external view returns (uint256);\\n\\n function allowance(address owner, address spender)\\n external\\n view\\n returns (uint256);\\n\\n function approve(address spender, uint256 value)\\n external\\n returns (bool);\\n\\n function balanceOf(address who) external view returns (uint256);\\n}\\n\\nabstract contract ERC20 is ERC20Base {\\n function transfer(address to, uint256 value)\\n external\\n virtual\\n returns (bool);\\n\\n function transferFrom(\\n address from,\\n address to,\\n uint256 value\\n ) external virtual returns (bool);\\n}\\n\\nabstract contract ERC20NS is ERC20Base {\\n function transfer(address to, uint256 value) external virtual;\\n\\n function transferFrom(\\n address from,\\n address to,\\n uint256 value\\n ) external virtual;\\n}\\n\\n/**\\n * @title Standard ERC20 token\\n * @dev Implementation of the basic standard token.\\n * See https://github.com/ethereum/EIPs/issues/20\\n */\\ncontract StandardToken is ERC20 {\\n using SafeMath for uint256;\\n\\n string public name;\\n string public symbol;\\n uint8 public decimals;\\n uint256 public override totalSupply;\\n mapping(address => mapping(address => uint256)) public override allowance;\\n mapping(address => uint256) public override balanceOf;\\n\\n constructor(\\n uint256 _initialAmount,\\n string memory _tokenName,\\n uint8 _decimalUnits,\\n string memory _tokenSymbol\\n ) {\\n totalSupply = _initialAmount;\\n balanceOf[msg.sender] = _initialAmount;\\n name = _tokenName;\\n symbol = _tokenSymbol;\\n decimals = _decimalUnits;\\n }\\n\\n function transfer(address dst, uint256 amount)\\n external\\n virtual\\n override\\n returns (bool)\\n {\\n balanceOf[msg.sender] = balanceOf[msg.sender].sub(\\n amount,\\n \\\"Insufficient balance\\\"\\n );\\n balanceOf[dst] = balanceOf[dst].add(amount, \\\"Balance overflow\\\");\\n emit Transfer(msg.sender, dst, amount);\\n return true;\\n }\\n\\n function transferFrom(\\n address src,\\n address dst,\\n uint256 amount\\n ) external virtual override returns (bool) {\\n allowance[src][msg.sender] = allowance[src][msg.sender].sub(\\n amount,\\n \\\"Insufficient allowance\\\"\\n );\\n balanceOf[src] = balanceOf[src].sub(amount, \\\"Insufficient balance\\\");\\n balanceOf[dst] = balanceOf[dst].add(amount, \\\"Balance overflow\\\");\\n emit Transfer(src, dst, amount);\\n return true;\\n }\\n\\n function approve(address _spender, uint256 amount)\\n external\\n override\\n returns (bool)\\n {\\n allowance[msg.sender][_spender] = amount;\\n emit Approval(msg.sender, _spender, amount);\\n return true;\\n }\\n}\\n\\n/**\\n * @title Non-Standard ERC20 token\\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 */\\ncontract NonStandardToken is ERC20NS {\\n using SafeMath for uint256;\\n\\n string public name;\\n uint8 public decimals;\\n string public symbol;\\n uint256 public override totalSupply;\\n mapping(address => mapping(address => uint256)) public override allowance;\\n mapping(address => uint256) public override balanceOf;\\n\\n constructor(\\n uint256 _initialAmount,\\n string memory _tokenName,\\n uint8 _decimalUnits,\\n string memory _tokenSymbol\\n ) {\\n totalSupply = _initialAmount;\\n balanceOf[msg.sender] = _initialAmount;\\n name = _tokenName;\\n symbol = _tokenSymbol;\\n decimals = _decimalUnits;\\n }\\n\\n function transfer(address dst, uint256 amount) external override {\\n balanceOf[msg.sender] = balanceOf[msg.sender].sub(\\n amount,\\n \\\"Insufficient balance\\\"\\n );\\n balanceOf[dst] = balanceOf[dst].add(amount, \\\"Balance overflow\\\");\\n emit Transfer(msg.sender, dst, amount);\\n }\\n\\n function transferFrom(\\n address src,\\n address dst,\\n uint256 amount\\n ) external override {\\n allowance[src][msg.sender] = allowance[src][msg.sender].sub(\\n amount,\\n \\\"Insufficient allowance\\\"\\n );\\n balanceOf[src] = balanceOf[src].sub(amount, \\\"Insufficient balance\\\");\\n balanceOf[dst] = balanceOf[dst].add(amount, \\\"Balance overflow\\\");\\n emit Transfer(src, dst, amount);\\n }\\n\\n function approve(address _spender, uint256 amount)\\n external\\n override\\n returns (bool)\\n {\\n allowance[msg.sender][_spender] = amount;\\n emit Approval(msg.sender, _spender, amount);\\n return true;\\n }\\n}\\n\\ncontract ERC20Harness is StandardToken {\\n using SafeMath for uint256;\\n\\n // To support testing, we can specify addresses for which transferFrom should fail and return false\\n mapping(address => bool) public failTransferFromAddresses;\\n\\n // To support testing, we allow the contract to always fail `transfer`.\\n mapping(address => bool) public failTransferToAddresses;\\n\\n constructor(\\n uint256 _initialAmount,\\n string memory _tokenName,\\n uint8 _decimalUnits,\\n string memory _tokenSymbol\\n ) StandardToken(_initialAmount, _tokenName, _decimalUnits, _tokenSymbol) {}\\n\\n function harnessSetFailTransferFromAddress(address src, bool _fail) public {\\n failTransferFromAddresses[src] = _fail;\\n }\\n\\n function harnessSetFailTransferToAddress(address dst, bool _fail) public {\\n failTransferToAddresses[dst] = _fail;\\n }\\n\\n function harnessSetBalance(address _account, uint256 _amount) public {\\n balanceOf[_account] = _amount;\\n }\\n\\n function transfer(address dst, uint256 amount)\\n external\\n override\\n returns (bool success)\\n {\\n // Added for testing purposes\\n if (failTransferToAddresses[dst]) {\\n return false;\\n }\\n balanceOf[msg.sender] = balanceOf[msg.sender].sub(\\n amount,\\n \\\"Insufficient balance\\\"\\n );\\n balanceOf[dst] = balanceOf[dst].add(amount, \\\"Balance overflow\\\");\\n emit Transfer(msg.sender, dst, amount);\\n return true;\\n }\\n\\n function transferFrom(\\n address src,\\n address dst,\\n uint256 amount\\n ) external override returns (bool success) {\\n // Added for testing purposes\\n if (failTransferFromAddresses[src]) {\\n return false;\\n }\\n allowance[src][msg.sender] = allowance[src][msg.sender].sub(\\n amount,\\n \\\"Insufficient allowance\\\"\\n );\\n balanceOf[src] = balanceOf[src].sub(amount, \\\"Insufficient balance\\\");\\n balanceOf[dst] = balanceOf[dst].add(amount, \\\"Balance overflow\\\");\\n emit Transfer(src, dst, amount);\\n return true;\\n }\\n}\\n\",\"keccak256\":\"0x5450f997ac4f79dc1109aed20142bc67e17b97b78d7d399f7250f6ee04b38582\",\"license\":\"UNLICENSED\"},\"contracts/SafeMath.sol\":{\"content\":\"// SPDX-License-Identifier: UNLICENSED\\npragma solidity 0.8.6;\\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\":\"0xe578b9602160e7ddbb5e7b6d355bb4508fa134684afe46e4043602c652e0e041\",\"license\":\"UNLICENSED\"}},\"version\":1}", - "bytecode": "0x60806040523480156200001157600080fd5b5060405162000a3f38038062000a3f8339810160408190526200003491620001f0565b6003849055336000908152600560209081526040822086905584516200005e929186019062000093565b5080516200007490600190602084019062000093565b50506002805460ff191660ff9290921691909117905550620002d29050565b828054620000a1906200027f565b90600052602060002090601f016020900481019282620000c5576000855562000110565b82601f10620000e057805160ff191683800117855562000110565b8280016001018555821562000110579182015b8281111562000110578251825591602001919060010190620000f3565b506200011e92915062000122565b5090565b5b808211156200011e576000815560010162000123565b600082601f8301126200014b57600080fd5b81516001600160401b0380821115620001685762000168620002bc565b604051601f8301601f19908116603f01168101908282118183101715620001935762000193620002bc565b81604052838152602092508683858801011115620001b057600080fd5b600091505b83821015620001d45785820183015181830184015290820190620001b5565b83821115620001e65760008385830101525b9695505050505050565b600080600080608085870312156200020757600080fd5b845160208601519094506001600160401b03808211156200022757600080fd5b620002358883890162000139565b94506040870151915060ff821682146200024e57600080fd5b6060870151919350808211156200026457600080fd5b50620002738782880162000139565b91505092959194509250565b600181811c908216806200029457607f821691505b60208210811415620002b657634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052604160045260246000fd5b61075d80620002e26000396000f3fe608060405234801561001057600080fd5b50600436106100935760003560e01c8063313ce56711610066578063313ce5671461010357806370a082311461012257806395d89b4114610142578063a9059cbb1461014a578063dd62ed3e1461015d57600080fd5b806306fdde0314610098578063095ea7b3146100b657806318160ddd146100d957806323b872dd146100f0575b600080fd5b6100a0610188565b6040516100ad9190610652565b60405180910390f35b6100c96100c4366004610628565b610216565b60405190151581526020016100ad565b6100e260035481565b6040519081526020016100ad565b6100c96100fe3660046105ec565b610282565b6002546101109060ff1681565b60405160ff90911681526020016100ad565b6100e2610130366004610597565b60056020526000908152604090205481565b6100a0610401565b6100c9610158366004610628565b61040e565b6100e261016b3660046105b9565b600460209081526000928352604080842090915290825290205481565b60008054610195906106d6565b80601f01602080910402602001604051908101604052809291908181526020018280546101c1906106d6565b801561020e5780601f106101e35761010080835404028352916020019161020e565b820191906000526020600020905b8154815290600101906020018083116101f157829003601f168201915b505050505081565b3360008181526004602090815260408083206001600160a01b038716808552925280832085905551919290917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925906102719086815260200190565b60405180910390a350600192915050565b6040805180820182526016815275496e73756666696369656e7420616c6c6f77616e636560501b6020808301919091526001600160a01b038616600090815260048252838120338252909152918220546102dd9184906104fe565b6001600160a01b0385166000818152600460209081526040808320338452825280832094909455835180850185526014815273496e73756666696369656e742062616c616e636560601b818301529282526005905291909120546103429184906104fe565b6001600160a01b0380861660009081526005602081815260408084209590955584518086018652601081526f42616c616e6365206f766572666c6f7760801b81830152938816835252919091205461039b918490610541565b6001600160a01b0380851660008181526005602052604090819020939093559151908616907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef906103ef9086815260200190565b60405180910390a35060019392505050565b60018054610195906106d6565b6040805180820182526014815273496e73756666696369656e742062616c616e636560601b6020808301919091523360009081526005909152918220546104569184906104fe565b3360009081526005602081815260408084209490945583518085018552601081526f42616c616e6365206f766572666c6f7760801b818301526001600160a01b0388168452919052919020546104ad918490610541565b6001600160a01b0384166000818152600560205260409081902092909255905133907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef906102719086815260200190565b6000818484111561052b5760405162461bcd60e51b81526004016105229190610652565b60405180910390fd5b50600061053884866106bf565b95945050505050565b60008061054e84866106a7565b905082858210156105725760405162461bcd60e51b81526004016105229190610652565b50949350505050565b80356001600160a01b038116811461059257600080fd5b919050565b6000602082840312156105a957600080fd5b6105b28261057b565b9392505050565b600080604083850312156105cc57600080fd5b6105d58361057b565b91506105e36020840161057b565b90509250929050565b60008060006060848603121561060157600080fd5b61060a8461057b565b92506106186020850161057b565b9150604084013590509250925092565b6000806040838503121561063b57600080fd5b6106448361057b565b946020939093013593505050565b600060208083528351808285015260005b8181101561067f57858101830151858201604001528201610663565b81811115610691576000604083870101525b50601f01601f1916929092016040019392505050565b600082198211156106ba576106ba610711565b500190565b6000828210156106d1576106d1610711565b500390565b600181811c908216806106ea57607f821691505b6020821081141561070b57634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052601160045260246000fdfea2646970667358221220d01609e330d83e9dc4a8b2b591f78f2787d98d49067556154372370d143909ef64736f6c63430008060033", - "deployedBytecode": "0x608060405234801561001057600080fd5b50600436106100935760003560e01c8063313ce56711610066578063313ce5671461010357806370a082311461012257806395d89b4114610142578063a9059cbb1461014a578063dd62ed3e1461015d57600080fd5b806306fdde0314610098578063095ea7b3146100b657806318160ddd146100d957806323b872dd146100f0575b600080fd5b6100a0610188565b6040516100ad9190610652565b60405180910390f35b6100c96100c4366004610628565b610216565b60405190151581526020016100ad565b6100e260035481565b6040519081526020016100ad565b6100c96100fe3660046105ec565b610282565b6002546101109060ff1681565b60405160ff90911681526020016100ad565b6100e2610130366004610597565b60056020526000908152604090205481565b6100a0610401565b6100c9610158366004610628565b61040e565b6100e261016b3660046105b9565b600460209081526000928352604080842090915290825290205481565b60008054610195906106d6565b80601f01602080910402602001604051908101604052809291908181526020018280546101c1906106d6565b801561020e5780601f106101e35761010080835404028352916020019161020e565b820191906000526020600020905b8154815290600101906020018083116101f157829003601f168201915b505050505081565b3360008181526004602090815260408083206001600160a01b038716808552925280832085905551919290917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925906102719086815260200190565b60405180910390a350600192915050565b6040805180820182526016815275496e73756666696369656e7420616c6c6f77616e636560501b6020808301919091526001600160a01b038616600090815260048252838120338252909152918220546102dd9184906104fe565b6001600160a01b0385166000818152600460209081526040808320338452825280832094909455835180850185526014815273496e73756666696369656e742062616c616e636560601b818301529282526005905291909120546103429184906104fe565b6001600160a01b0380861660009081526005602081815260408084209590955584518086018652601081526f42616c616e6365206f766572666c6f7760801b81830152938816835252919091205461039b918490610541565b6001600160a01b0380851660008181526005602052604090819020939093559151908616907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef906103ef9086815260200190565b60405180910390a35060019392505050565b60018054610195906106d6565b6040805180820182526014815273496e73756666696369656e742062616c616e636560601b6020808301919091523360009081526005909152918220546104569184906104fe565b3360009081526005602081815260408084209490945583518085018552601081526f42616c616e6365206f766572666c6f7760801b818301526001600160a01b0388168452919052919020546104ad918490610541565b6001600160a01b0384166000818152600560205260409081902092909255905133907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef906102719086815260200190565b6000818484111561052b5760405162461bcd60e51b81526004016105229190610652565b60405180910390fd5b50600061053884866106bf565b95945050505050565b60008061054e84866106a7565b905082858210156105725760405162461bcd60e51b81526004016105229190610652565b50949350505050565b80356001600160a01b038116811461059257600080fd5b919050565b6000602082840312156105a957600080fd5b6105b28261057b565b9392505050565b600080604083850312156105cc57600080fd5b6105d58361057b565b91506105e36020840161057b565b90509250929050565b60008060006060848603121561060157600080fd5b61060a8461057b565b92506106186020850161057b565b9150604084013590509250925092565b6000806040838503121561063b57600080fd5b6106448361057b565b946020939093013593505050565b600060208083528351808285015260005b8181101561067f57858101830151858201604001528201610663565b81811115610691576000604083870101525b50601f01601f1916929092016040019392505050565b600082198211156106ba576106ba610711565b500190565b6000828210156106d1576106d1610711565b500390565b600181811c908216806106ea57607f821691505b6020821081141561070b57634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052601160045260246000fdfea2646970667358221220d01609e330d83e9dc4a8b2b591f78f2787d98d49067556154372370d143909ef64736f6c63430008060033", - "devdoc": { - "details": "Implementation of the basic standard token. See https://github.com/ethereum/EIPs/issues/20", - "kind": "dev", - "methods": {}, - "title": "Standard ERC20 token", - "version": 1 - }, - "userdoc": { - "kind": "user", - "methods": {}, - "version": 1 - }, - "storageLayout": { - "storage": [ - { - "astId": 33360, - "contract": "contracts/ERC20.sol:StandardToken", - "label": "name", - "offset": 0, - "slot": "0", - "type": "t_string_storage" - }, - { - "astId": 33362, - "contract": "contracts/ERC20.sol:StandardToken", - "label": "symbol", - "offset": 0, - "slot": "1", - "type": "t_string_storage" - }, - { - "astId": 33364, - "contract": "contracts/ERC20.sol:StandardToken", - "label": "decimals", - "offset": 0, - "slot": "2", - "type": "t_uint8" - }, - { - "astId": 33367, - "contract": "contracts/ERC20.sol:StandardToken", - "label": "totalSupply", - "offset": 0, - "slot": "3", - "type": "t_uint256" - }, - { - "astId": 33374, - "contract": "contracts/ERC20.sol:StandardToken", - "label": "allowance", - "offset": 0, - "slot": "4", - "type": "t_mapping(t_address,t_mapping(t_address,t_uint256))" - }, - { - "astId": 33379, - "contract": "contracts/ERC20.sol:StandardToken", - "label": "balanceOf", - "offset": 0, - "slot": "5", - "type": "t_mapping(t_address,t_uint256)" - } - ], - "types": { - "t_address": { - "encoding": "inplace", - "label": "address", - "numberOfBytes": "20" - }, - "t_mapping(t_address,t_mapping(t_address,t_uint256))": { - "encoding": "mapping", - "key": "t_address", - "label": "mapping(address => mapping(address => uint256))", - "numberOfBytes": "32", - "value": "t_mapping(t_address,t_uint256)" - }, - "t_mapping(t_address,t_uint256)": { - "encoding": "mapping", - "key": "t_address", - "label": "mapping(address => uint256)", - "numberOfBytes": "32", - "value": "t_uint256" - }, - "t_string_storage": { - "encoding": "bytes", - "label": "string", - "numberOfBytes": "32" - }, - "t_uint256": { - "encoding": "inplace", - "label": "uint256", - "numberOfBytes": "32" - }, - "t_uint8": { - "encoding": "inplace", - "label": "uint8", - "numberOfBytes": "1" - } - } - } -} \ No newline at end of file diff --git a/deployments/localhost/DocOracle.json b/deployments/localhost/DocOracle.json deleted file mode 100644 index 51dbd9d..0000000 --- a/deployments/localhost/DocOracle.json +++ /dev/null @@ -1,183 +0,0 @@ -{ - "address": "0x5FC8d32690cc91D4c39d9d3abcBD16989F875707", - "abi": [ - { - "inputs": [ - { - "internalType": "address", - "name": "guardian_", - "type": "address" - }, - { - "internalType": "uint256", - "name": "price", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "constructor" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "oldPrice", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "newPrice", - "type": "uint256" - } - ], - "name": "MockPriceProviderMoCUpdated", - "type": "event" - }, - { - "inputs": [], - "name": "guardian", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "peek", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - }, - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "price", - "type": "uint256" - } - ], - "name": "setPrice", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - } - ], - "transactionHash": "0x1093c5e577d08eb5d84257962629e62160d9e85b75c354155c85ef1e32ad7abe", - "receipt": { - "to": null, - "from": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", - "contractAddress": "0x5FC8d32690cc91D4c39d9d3abcBD16989F875707", - "transactionIndex": 0, - "gasUsed": "220564", - "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "blockHash": "0x330bc56ed994fa8dd085b63d85671d6f9c70f1d63fb126539aca46dd12097019", - "transactionHash": "0x1093c5e577d08eb5d84257962629e62160d9e85b75c354155c85ef1e32ad7abe", - "logs": [], - "blockNumber": 6, - "cumulativeGasUsed": "220564", - "status": 1, - "byzantium": true - }, - "args": [ - "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", - "1100000000000000000" - ], - "solcInputHash": "3f2295c0e5923ce11cb0f26c6e52bee2", - "metadata": "{\"compiler\":{\"version\":\"0.8.6+commit.11564f7e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"guardian_\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"price\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldPrice\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newPrice\",\"type\":\"uint256\"}],\"name\":\"MockPriceProviderMoCUpdated\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"guardian\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"peek\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"price\",\"type\":\"uint256\"}],\"name\":\"setPrice\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"setPrice(uint256)\":{\"params\":{\"price\":\"uint of price provider\"}}},\"title\":\"A mock price provider of Money on Chain (MoC)\",\"version\":1},\"userdoc\":{\"events\":{\"MockPriceProviderMoCUpdated(uint256,uint256)\":{\"notice\":\"Event rbtcPrice updated\"}},\"kind\":\"user\",\"methods\":{\"guardian()\":{\"notice\":\"Address of the guardian\"},\"setPrice(uint256)\":{\"notice\":\"Set the rbtcPrice price provider\"}},\"notice\":\"You can use this contract for only simulation\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/mocks/MockPriceProviderMoC.sol\":\"MockPriceProviderMoC\"},\"evmVersion\":\"berlin\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"contracts/CErc20.sol\":{\"content\":\"// SPDX-License-Identifier: UNLICENSED\\npragma solidity 0.8.6;\\n\\nimport \\\"./CToken.sol\\\";\\nimport \\\"./CTokenInterfaces.sol\\\";\\n\\n/**\\n * @title tropykus CErc20 Contract\\n * @notice CTokens which wrap an EIP-20 underlying\\n * @author tropykus\\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(\\n address underlying_,\\n ComptrollerInterface comptroller_,\\n InterestRateModel interestRateModel_,\\n uint256 initialExchangeRateMantissa_,\\n string memory name_,\\n string memory symbol_,\\n uint8 decimals_\\n ) public {\\n // CToken initialize does the bulk of the work\\n super.initialize(\\n comptroller_,\\n interestRateModel_,\\n initialExchangeRateMantissa_,\\n name_,\\n symbol_,\\n decimals_\\n );\\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(uint256 mintAmount) external override returns (uint256) {\\n (uint256 err, ) = mintInternal(mintAmount);\\n return err;\\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 redeem(uint256 redeemAmount)\\n external\\n override\\n returns (uint256)\\n {\\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(uint256 borrowAmount) external override returns (uint256) {\\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(uint256 repayAmount)\\n external\\n override\\n returns (uint256)\\n {\\n (uint256 err, ) = repayBorrowInternal(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(\\n address borrower,\\n uint256 repayAmount,\\n CTokenInterface cTokenCollateral\\n ) external override returns (uint256) {\\n (uint256 err, ) = liquidateBorrowInternal(\\n borrower,\\n repayAmount,\\n cTokenCollateral\\n );\\n return err;\\n }\\n\\n /**\\n * @notice A public function to sweep accidental ERC-20 transfers to this contract. Tokens are sent to admin (timelock)\\n * @param token The address of the ERC-20 token to sweep\\n */\\n function sweepToken(EIP20NonStandardInterface token) external override {\\n require(address(token) != underlying, \\\"EC01\\\");\\n uint256 balance = token.balanceOf(address(this));\\n token.transfer(admin, balance);\\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(uint256 addAmount)\\n external\\n override\\n returns (uint256)\\n {\\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 override returns (uint256) {\\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, uint256 amount)\\n internal\\n override\\n returns (uint256)\\n {\\n EIP20NonStandardInterface token = EIP20NonStandardInterface(underlying);\\n uint256 balanceBefore = EIP20Interface(underlying).balanceOf(\\n address(this)\\n );\\n token.transferFrom(from, address(this), amount);\\n\\n bool success;\\n assembly {\\n switch returndatasize()\\n case 0 {\\n // This is a non-standard ERC-20\\n success := not(0) // set success to true\\n }\\n case 32 {\\n // This is a compliant ERC-20\\n returndatacopy(0, 0, 32)\\n success := mload(0) // Set `success = returndata` of external call\\n }\\n default {\\n // This is an excessively non-compliant ERC-20, revert.\\n revert(0, 0)\\n }\\n }\\n require(success, \\\"EC02\\\");\\n\\n // Calculate the amount that was *actually* transferred\\n uint256 balanceAfter = EIP20Interface(underlying).balanceOf(\\n address(this)\\n );\\n require(balanceAfter >= balanceBefore, \\\"EC03\\\");\\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, uint256 amount)\\n internal\\n virtual\\n override\\n {\\n EIP20NonStandardInterface token = EIP20NonStandardInterface(underlying);\\n token.transfer(to, amount);\\n\\n bool success;\\n assembly {\\n switch returndatasize()\\n case 0 {\\n // This is a non-standard ERC-20\\n success := not(0) // set success to true\\n }\\n case 32 {\\n // This is a complaint ERC-20\\n returndatacopy(0, 0, 32)\\n success := mload(0) // Set `success = returndata` of external call\\n }\\n default {\\n // This is an excessively non-compliant ERC-20, revert.\\n revert(0, 0)\\n }\\n }\\n require(success, \\\"CE01\\\");\\n }\\n}\\n\",\"keccak256\":\"0x539c67e8b5bf011926bd82655501f2016db29e890139a1b466461a3298950365\",\"license\":\"UNLICENSED\"},\"contracts/CToken.sol\":{\"content\":\"// SPDX-License-Identifier: UNLICENSED\\npragma solidity 0.8.6;\\n\\nimport \\\"./ComptrollerInterface.sol\\\";\\nimport \\\"./CTokenInterfaces.sol\\\";\\nimport \\\"./ErrorReporter.sol\\\";\\nimport \\\"./Exponential.sol\\\";\\nimport \\\"./EIP20Interface.sol\\\";\\nimport \\\"./InterestRateModel.sol\\\";\\nimport \\\"./WhitelistInterface.sol\\\";\\n\\n/**\\n * @title tropykus CToken Contract\\n * @notice Abstract base for CTokens\\n * @author tropykus\\n */\\nabstract contract CToken is CTokenInterface, Exponential, TokenErrorReporter {\\n address whitelist;\\n\\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(\\n ComptrollerInterface comptroller_,\\n InterestRateModel interestRateModel_,\\n uint256 initialExchangeRateMantissa_,\\n string memory name_,\\n string memory symbol_,\\n uint8 decimals_\\n ) public {\\n require(msg.sender == admin, \\\"CT01\\\");\\n require(accrualBlockNumber == 0 && borrowIndex == 0, \\\"CT02\\\");\\n\\n initialExchangeRateMantissa = initialExchangeRateMantissa_;\\n require(initialExchangeRateMantissa > 0, \\\"CT03\\\");\\n\\n uint256 err = _setComptroller(comptroller_);\\n require(err == uint256(Error.NO_ERROR), \\\"CT04\\\");\\n\\n accrualBlockNumber = getBlockNumber();\\n borrowIndex = mantissaOne;\\n\\n err = _setInterestRateModelFresh(interestRateModel_);\\n require(err == uint256(Error.NO_ERROR), \\\"CT05\\\");\\n\\n name = name_;\\n symbol = symbol_;\\n decimals = decimals_;\\n\\n _notEntered = true;\\n }\\n\\n function addWhitelist(address _whitelist) external returns (uint256) {\\n if (msg.sender != admin) {\\n return\\n fail(\\n Error.UNAUTHORIZED,\\n FailureInfo.SET_INTEREST_RATE_MODEL_OWNER_CHECK\\n );\\n }\\n whitelist = _whitelist;\\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(\\n address spender,\\n address src,\\n address dst,\\n uint256 tokens\\n ) internal returns (uint256) {\\n uint256 allowed = comptroller.transferAllowed(\\n address(this),\\n src,\\n dst,\\n tokens\\n );\\n if (allowed != 0) {\\n return\\n failOpaque(\\n Error.COMPTROLLER_REJECTION,\\n FailureInfo.TRANSFER_COMPTROLLER_REJECTION,\\n allowed\\n );\\n }\\n\\n if (src == dst) {\\n return fail(Error.BAD_INPUT, FailureInfo.TRANSFER_NOT_ALLOWED);\\n }\\n\\n uint256 startingAllowance = 0;\\n if (spender == src) {\\n startingAllowance = type(uint256).max;\\n } else {\\n startingAllowance = transferAllowances[src][spender];\\n }\\n\\n MathError mathErr;\\n uint256 allowanceNew;\\n uint256 srcTokensNew;\\n uint256 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, 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, tokens);\\n if (mathErr != MathError.NO_ERROR) {\\n return fail(Error.MATH_ERROR, FailureInfo.TRANSFER_TOO_MUCH);\\n }\\n\\n accountTokens[src].tokens = srcTokensNew;\\n accountTokens[dst].tokens = dstTokensNew;\\n\\n if (startingAllowance != type(uint256).max) {\\n transferAllowances[src][spender] = allowanceNew;\\n }\\n\\n emit Transfer(src, dst, tokens);\\n\\n return uint256(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)\\n external\\n override\\n nonReentrant\\n returns (bool)\\n {\\n return\\n transferTokens(msg.sender, msg.sender, dst, amount) ==\\n uint256(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(\\n address src,\\n address dst,\\n uint256 amount\\n ) external override nonReentrant returns (bool) {\\n return\\n transferTokens(msg.sender, src, dst, amount) ==\\n uint256(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)\\n external\\n override\\n returns (bool)\\n {\\n transferAllowances[msg.sender][spender] = amount;\\n emit Approval(msg.sender, 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)\\n external\\n view\\n override\\n returns (uint256)\\n {\\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 override returns (uint256) {\\n return accountTokens[owner].tokens;\\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)\\n external\\n override\\n returns (uint256)\\n {\\n (MathError mErr, uint256 balance) = mulScalarTruncate(\\n Exp({mantissa: exchangeRateCurrent()}),\\n accountTokens[owner].tokens\\n );\\n require(mErr == MathError.NO_ERROR, \\\"CT06\\\");\\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)\\n external\\n view\\n override\\n returns (\\n uint256,\\n uint256,\\n uint256,\\n uint256\\n )\\n {\\n uint256 cTokenBalance = accountTokens[account].tokens;\\n uint256 borrowBalance;\\n uint256 exchangeRateMantissa;\\n\\n MathError mErr;\\n\\n (mErr, borrowBalance) = borrowBalanceStoredInternal(account);\\n if (mErr != MathError.NO_ERROR) {\\n return (uint256(Error.MATH_ERROR), 0, 0, 0);\\n }\\n\\n (mErr, exchangeRateMantissa) = exchangeRateStoredInternal();\\n if (mErr != MathError.NO_ERROR) {\\n return (uint256(Error.MATH_ERROR), 0, 0, 0);\\n }\\n\\n return (\\n uint256(Error.NO_ERROR),\\n cTokenBalance,\\n borrowBalance,\\n exchangeRateMantissa\\n );\\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 virtual returns (uint256) {\\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 override returns (uint256) {\\n return\\n interestRateModel.getBorrowRate(\\n getCashPrior(),\\n totalBorrows,\\n totalReserves\\n );\\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 override returns (uint256) {\\n return\\n interestRateModel.getSupplyRate(\\n getCashPrior(),\\n totalBorrows,\\n totalReserves,\\n reserveFactorMantissa\\n );\\n }\\n\\n /**\\n * @notice Returns the current total borrows plus accrued interest\\n * @return The total borrows with interest\\n */\\n function totalBorrowsCurrent()\\n external\\n override\\n nonReentrant\\n returns (uint256)\\n {\\n require(accrueInterest() == uint256(Error.NO_ERROR), \\\"CT07\\\");\\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)\\n external\\n override\\n nonReentrant\\n returns (uint256)\\n {\\n require(accrueInterest() == uint256(Error.NO_ERROR), \\\"CT07\\\");\\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)\\n public\\n view\\n override\\n returns (uint256)\\n {\\n (MathError err, uint256 result) = borrowBalanceStoredInternal(account);\\n require(err == MathError.NO_ERROR, \\\"CT08\\\");\\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)\\n internal\\n view\\n returns (MathError, uint256)\\n {\\n MathError mathErr;\\n uint256 principalTimesIndex;\\n uint256 result;\\n\\n BorrowSnapshot storage borrowSnapshot = accountBorrows[account];\\n\\n if (borrowSnapshot.principal == 0) {\\n return (MathError.NO_ERROR, 0);\\n }\\n\\n (mathErr, principalTimesIndex) = mulUInt(\\n borrowSnapshot.principal,\\n borrowIndex\\n );\\n if (mathErr != MathError.NO_ERROR) {\\n return (mathErr, 0);\\n }\\n\\n (mathErr, result) = divUInt(\\n principalTimesIndex,\\n borrowSnapshot.interestIndex\\n );\\n if (mathErr != MathError.NO_ERROR) {\\n return (mathErr, 0);\\n }\\n\\n return (MathError.NO_ERROR, result);\\n }\\n\\n function getBorrowerPrincipalStored(address account)\\n public\\n view\\n returns (uint256 borrowed)\\n {\\n borrowed = accountBorrows[account].principal;\\n }\\n\\n function getSupplierSnapshotStored(address account)\\n public\\n view\\n returns (\\n uint256 tokens,\\n uint256 underlyingAmount,\\n uint256 suppliedAt,\\n uint256 promisedSupplyRate\\n )\\n {\\n tokens = accountTokens[account].tokens;\\n underlyingAmount = accountTokens[account].underlyingAmount;\\n suppliedAt = accountTokens[account].suppliedAt;\\n promisedSupplyRate = accountTokens[account].promisedSupplyRate;\\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()\\n public\\n override\\n nonReentrant\\n returns (uint256)\\n {\\n require(accrueInterest() == uint256(Error.NO_ERROR), \\\"CT07\\\");\\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 override returns (uint256) {\\n (MathError err, uint256 result) = exchangeRateStoredInternal();\\n require(err == MathError.NO_ERROR, \\\"CT09\\\");\\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()\\n internal\\n view\\n virtual\\n returns (MathError, uint256)\\n {\\n uint256 _totalSupply = totalSupply;\\n if (_totalSupply == 0) {\\n return (MathError.NO_ERROR, initialExchangeRateMantissa);\\n } else {\\n MathError error;\\n uint256 exchangeRate;\\n uint256 totalCash = getCashPrior();\\n if (interestRateModel.isTropykusInterestRateModel()) {\\n (error, exchangeRate) = tropykusExchangeRateStoredInternal(\\n msg.sender\\n );\\n if (error == MathError.NO_ERROR) {\\n return (MathError.NO_ERROR, exchangeRate);\\n } else {\\n return (MathError.NO_ERROR, initialExchangeRateMantissa);\\n }\\n }\\n return\\n interestRateModel.getExchangeRate(\\n totalCash,\\n totalBorrows,\\n totalReserves,\\n totalSupply\\n );\\n }\\n }\\n\\n function tropykusExchangeRateStoredInternal(address redeemer)\\n internal\\n view\\n returns (MathError, uint256)\\n {\\n if (totalSupply == 0) {\\n return (MathError.NO_ERROR, initialExchangeRateMantissa);\\n } else {\\n SupplySnapshot storage supplySnapshot = accountTokens[redeemer];\\n if (supplySnapshot.suppliedAt == 0) {\\n return (MathError.DIVISION_BY_ZERO, 0);\\n }\\n (, uint256 interestFactorMantissa, ) = tropykusInterestAccrued(\\n redeemer\\n );\\n Exp memory interestFactor = Exp({mantissa: interestFactorMantissa});\\n uint256 currentUnderlying = supplySnapshot.underlyingAmount;\\n Exp memory redeemerUnderlying = Exp({mantissa: currentUnderlying});\\n (, Exp memory realAmount) = mulExp(\\n interestFactor,\\n redeemerUnderlying\\n );\\n (, Exp memory exchangeRate) = getExp(\\n realAmount.mantissa,\\n supplySnapshot.tokens\\n );\\n return (MathError.NO_ERROR, exchangeRate.mantissa);\\n }\\n }\\n\\n function tropykusInterestAccrued(address account)\\n internal\\n view\\n returns (\\n MathError,\\n uint256,\\n uint256\\n )\\n {\\n SupplySnapshot storage supplySnapshot = accountTokens[account];\\n uint256 promisedSupplyRate = supplySnapshot.promisedSupplyRate;\\n Exp memory expectedSupplyRatePerBlock = Exp({\\n mantissa: promisedSupplyRate\\n });\\n (, uint256 delta) = subUInt(\\n accrualBlockNumber,\\n supplySnapshot.suppliedAt\\n );\\n (, Exp memory expectedSupplyRatePerBlockWithDelta) = mulScalar(\\n expectedSupplyRatePerBlock,\\n delta\\n );\\n (, Exp memory interestFactor) = addExp(\\n Exp({mantissa: 1e18}),\\n expectedSupplyRatePerBlockWithDelta\\n );\\n uint256 currentUnderlying = supplySnapshot.underlyingAmount;\\n Exp memory redeemerUnderlying = Exp({mantissa: currentUnderlying});\\n (, Exp memory realAmount) = mulExp(interestFactor, redeemerUnderlying);\\n (, uint256 interestEarned) = subUInt(\\n realAmount.mantissa,\\n currentUnderlying\\n );\\n return (MathError.NO_ERROR, interestFactor.mantissa, interestEarned);\\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 override returns (uint256) {\\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 override returns (uint256) {\\n uint256 currentBlockNumber = getBlockNumber();\\n uint256 accrualBlockNumberPrior = accrualBlockNumber;\\n\\n if (accrualBlockNumberPrior == currentBlockNumber) {\\n return uint256(Error.NO_ERROR);\\n }\\n\\n uint256 cashPrior = getCashPrior();\\n uint256 borrowsPrior = totalBorrows;\\n uint256 reservesPrior = totalReserves;\\n uint256 borrowIndexPrior = borrowIndex;\\n\\n uint256 borrowRateMantissa = interestRateModel.getBorrowRate(\\n cashPrior,\\n borrowsPrior,\\n reservesPrior\\n );\\n require(borrowRateMantissa <= borrowRateMaxMantissa, \\\"CT10\\\");\\n\\n (MathError mathErr, uint256 blockDelta) = subUInt(\\n currentBlockNumber,\\n accrualBlockNumberPrior\\n );\\n require(mathErr == MathError.NO_ERROR, \\\"CT11\\\");\\n\\n Exp memory simpleInterestFactor;\\n uint256 interestAccumulated;\\n uint256 totalBorrowsNew;\\n uint256 totalReservesNew;\\n uint256 borrowIndexNew;\\n\\n (mathErr, simpleInterestFactor) = mulScalar(\\n Exp({mantissa: borrowRateMantissa}),\\n blockDelta\\n );\\n if (mathErr != MathError.NO_ERROR) {\\n return\\n failOpaque(\\n Error.MATH_ERROR,\\n FailureInfo\\n .ACCRUE_INTEREST_SIMPLE_INTEREST_FACTOR_CALCULATION_FAILED,\\n uint256(mathErr)\\n );\\n }\\n\\n (mathErr, interestAccumulated) = mulScalarTruncate(\\n simpleInterestFactor,\\n borrowsPrior\\n );\\n if (mathErr != MathError.NO_ERROR) {\\n return\\n failOpaque(\\n Error.MATH_ERROR,\\n FailureInfo\\n .ACCRUE_INTEREST_ACCUMULATED_INTEREST_CALCULATION_FAILED,\\n uint256(mathErr)\\n );\\n }\\n\\n (mathErr, totalBorrowsNew) = addUInt(interestAccumulated, borrowsPrior);\\n if (mathErr != MathError.NO_ERROR) {\\n return\\n failOpaque(\\n Error.MATH_ERROR,\\n FailureInfo\\n .ACCRUE_INTEREST_NEW_TOTAL_BORROWS_CALCULATION_FAILED,\\n uint256(mathErr)\\n );\\n }\\n\\n (mathErr, totalReservesNew) = mulScalarTruncateAddUInt(\\n Exp({mantissa: reserveFactorMantissa}),\\n interestAccumulated,\\n reservesPrior\\n );\\n if (mathErr != MathError.NO_ERROR) {\\n return\\n failOpaque(\\n Error.MATH_ERROR,\\n FailureInfo\\n .ACCRUE_INTEREST_NEW_TOTAL_RESERVES_CALCULATION_FAILED,\\n uint256(mathErr)\\n );\\n }\\n\\n if (interestRateModel.isTropykusInterestRateModel()) {\\n (mathErr, totalReservesNew) = newReserves(\\n borrowRateMantissa,\\n cashPrior,\\n borrowsPrior,\\n reservesPrior,\\n interestAccumulated\\n );\\n if (mathErr != MathError.NO_ERROR) {\\n return\\n failOpaque(\\n Error.MATH_ERROR,\\n FailureInfo\\n .ACCRUE_INTEREST_NEW_TOTAL_RESERVES_CALCULATION_FAILED,\\n uint256(mathErr)\\n );\\n }\\n }\\n\\n (mathErr, borrowIndexNew) = mulScalarTruncateAddUInt(\\n simpleInterestFactor,\\n borrowIndexPrior,\\n borrowIndexPrior\\n );\\n if (mathErr != MathError.NO_ERROR) {\\n return\\n failOpaque(\\n Error.MATH_ERROR,\\n FailureInfo\\n .ACCRUE_INTEREST_NEW_BORROW_INDEX_CALCULATION_FAILED,\\n uint256(mathErr)\\n );\\n }\\n\\n accrualBlockNumber = currentBlockNumber;\\n borrowIndex = borrowIndexNew;\\n totalBorrows = totalBorrowsNew;\\n totalReserves = totalReservesNew;\\n\\n emit AccrueInterest(\\n cashPrior,\\n interestAccumulated,\\n borrowIndexNew,\\n totalBorrowsNew\\n );\\n\\n return uint256(Error.NO_ERROR);\\n }\\n\\n function newReserves(\\n uint256 borrowRateMantissa,\\n uint256 cashPrior,\\n uint256 borrowsPrior,\\n uint256 reservesPrior,\\n uint256 interestAccumulated\\n ) internal view returns (MathError mathErr, uint256 totalReservesNew) {\\n uint256 newReserveFactorMantissa;\\n uint256 utilizationRate = interestRateModel.utilizationRate(\\n cashPrior,\\n borrowsPrior,\\n reservesPrior\\n );\\n uint256 expectedSupplyRate = interestRateModel.getSupplyRate(\\n cashPrior,\\n borrowsPrior,\\n reservesPrior,\\n reserveFactorMantissa\\n );\\n if (\\n interestRateModel.isAboveOptimal(\\n cashPrior,\\n borrowsPrior,\\n reservesPrior\\n )\\n ) {\\n (mathErr, newReserveFactorMantissa) = mulScalarTruncate(\\n Exp({mantissa: utilizationRate}),\\n borrowRateMantissa\\n );\\n if (mathErr != MathError.NO_ERROR) {\\n return (mathErr, 0);\\n }\\n (mathErr, newReserveFactorMantissa) = subUInt(\\n newReserveFactorMantissa,\\n expectedSupplyRate\\n );\\n if (mathErr != MathError.NO_ERROR) {\\n return (mathErr, 0);\\n }\\n (mathErr, totalReservesNew) = mulScalarTruncateAddUInt(\\n Exp({mantissa: newReserveFactorMantissa}),\\n interestAccumulated,\\n reservesPrior\\n );\\n if (mathErr != MathError.NO_ERROR) {\\n return (mathErr, 0);\\n }\\n } else {\\n mathErr = MathError.NO_ERROR;\\n totalReservesNew = reservesPrior;\\n }\\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(uint256 mintAmount)\\n internal\\n nonReentrant\\n returns (uint256, uint256)\\n {\\n if (WhitelistInterface(whitelist).enabled()) {\\n require(WhitelistInterface(whitelist).exist(msg.sender), \\\"CT26\\\");\\n }\\n uint256 error = accrueInterest();\\n if (error != uint256(Error.NO_ERROR)) {\\n return (\\n fail(Error(error), FailureInfo.MINT_ACCRUE_INTEREST_FAILED),\\n 0\\n );\\n }\\n return mintFresh(msg.sender, mintAmount);\\n }\\n\\n struct MintLocalVars {\\n Error err;\\n MathError mathErr;\\n uint256 exchangeRateMantissa;\\n uint256 mintTokens;\\n uint256 totalSupplyNew;\\n uint256 accountTokensNew;\\n uint256 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, uint256 mintAmount)\\n internal\\n returns (uint256, uint256)\\n {\\n uint256 allowed = comptroller.mintAllowed(\\n address(this),\\n minter,\\n mintAmount\\n );\\n if (allowed != 0) {\\n return (\\n failOpaque(\\n Error.COMPTROLLER_REJECTION,\\n FailureInfo.MINT_COMPTROLLER_REJECTION,\\n allowed\\n ),\\n 0\\n );\\n }\\n\\n if (accrualBlockNumber != getBlockNumber()) {\\n return (\\n fail(Error.MARKET_NOT_FRESH, FailureInfo.MINT_FRESHNESS_CHECK),\\n 0\\n );\\n }\\n\\n MintLocalVars memory vars;\\n\\n (\\n vars.mathErr,\\n vars.exchangeRateMantissa\\n ) = exchangeRateStoredInternal();\\n if (vars.mathErr != MathError.NO_ERROR) {\\n return (\\n failOpaque(\\n Error.MATH_ERROR,\\n FailureInfo.MINT_EXCHANGE_RATE_READ_FAILED,\\n uint256(vars.mathErr)\\n ),\\n 0\\n );\\n }\\n if (interestRateModel.isTropykusInterestRateModel()) {\\n SupplySnapshot storage supplySnapshot = accountTokens[minter];\\n (, uint256 newTotalSupply) = addUInt(\\n supplySnapshot.underlyingAmount,\\n mintAmount\\n );\\n require(newTotalSupply <= 0.1e18, \\\"CT24\\\");\\n }\\n vars.actualMintAmount = doTransferIn(minter, mintAmount);\\n\\n (vars.mathErr, vars.mintTokens) = divScalarByExpTruncate(\\n vars.actualMintAmount,\\n Exp({mantissa: vars.exchangeRateMantissa})\\n );\\n require(vars.mathErr == MathError.NO_ERROR, \\\"CT12\\\");\\n\\n (vars.mathErr, vars.totalSupplyNew) = addUInt(\\n totalSupply,\\n vars.mintTokens\\n );\\n require(vars.mathErr == MathError.NO_ERROR, \\\"CT13\\\");\\n\\n (vars.mathErr, vars.accountTokensNew) = addUInt(\\n accountTokens[minter].tokens,\\n vars.mintTokens\\n );\\n require(vars.mathErr == MathError.NO_ERROR, \\\"CT14\\\");\\n\\n uint256 currentSupplyRate = interestRateModel.getSupplyRate(\\n getCashPrior(),\\n totalBorrows,\\n totalReserves,\\n reserveFactorMantissa\\n );\\n\\n bool isTropykusInterestRateModel = interestRateModel\\n .isTropykusInterestRateModel();\\n\\n if (accountTokens[minter].tokens > 0) {\\n Exp memory updatedUnderlying;\\n if (isTropykusInterestRateModel) {\\n (, uint256 interestFactorMantissa, ) = tropykusInterestAccrued(\\n minter\\n );\\n Exp memory interestFactor = Exp({\\n mantissa: interestFactorMantissa\\n });\\n uint256 currentUnderlyingAmount = accountTokens[minter]\\n .underlyingAmount;\\n MathError mErrorNewAmount;\\n (mErrorNewAmount, updatedUnderlying) = mulExp(\\n Exp({mantissa: currentUnderlyingAmount}),\\n interestFactor\\n );\\n if (mErrorNewAmount != MathError.NO_ERROR) {\\n return (\\n failOpaque(\\n Error.MATH_ERROR,\\n FailureInfo.MINT_EXCHANGE_CALCULATION_FAILED,\\n uint256(mErrorNewAmount)\\n ),\\n 0\\n );\\n }\\n } else {\\n uint256 currentTokens = accountTokens[minter].tokens;\\n MathError mErrorUpdatedUnderlying;\\n (mErrorUpdatedUnderlying, updatedUnderlying) = mulExp(\\n Exp({mantissa: currentTokens}),\\n Exp({mantissa: vars.exchangeRateMantissa})\\n );\\n if (mErrorUpdatedUnderlying != MathError.NO_ERROR) {\\n return (\\n failOpaque(\\n Error.MATH_ERROR,\\n FailureInfo.MINT_EXCHANGE_CALCULATION_FAILED,\\n uint256(mErrorUpdatedUnderlying)\\n ),\\n 0\\n );\\n }\\n }\\n (, mintAmount) = addUInt(updatedUnderlying.mantissa, mintAmount);\\n }\\n\\n totalSupply = vars.totalSupplyNew;\\n accountTokens[minter] = SupplySnapshot({\\n tokens: vars.accountTokensNew,\\n underlyingAmount: mintAmount,\\n suppliedAt: accrualBlockNumber,\\n promisedSupplyRate: currentSupplyRate\\n });\\n\\n emit Mint(minter, vars.actualMintAmount, vars.mintTokens);\\n emit Transfer(address(this), minter, vars.mintTokens);\\n\\n return (uint256(Error.NO_ERROR), vars.actualMintAmount);\\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(uint256 redeemAmount)\\n internal\\n nonReentrant\\n returns (uint256)\\n {\\n uint256 error = accrueInterest();\\n if (error != uint256(Error.NO_ERROR)) {\\n return\\n fail(Error(error), FailureInfo.REDEEM_ACCRUE_INTEREST_FAILED);\\n }\\n return redeemFresh(payable(msg.sender), redeemAmount);\\n }\\n\\n struct RedeemLocalVars {\\n Error err;\\n MathError mathErr;\\n uint256 exchangeRateMantissa;\\n uint256 redeemTokens;\\n uint256 redeemAmount;\\n uint256 totalSupplyNew;\\n uint256 accountTokensNew;\\n uint256 newSubsidyFund;\\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 redeemAmountIn The number of underlying tokens to receive from redeeming cTokens\\n * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)\\n */\\n function redeemFresh(address payable redeemer, uint256 redeemAmountIn)\\n internal\\n returns (uint256)\\n {\\n require(redeemAmountIn > 0, \\\"CT15\\\");\\n\\n RedeemLocalVars memory vars;\\n\\n SupplySnapshot storage supplySnapshot = accountTokens[redeemer];\\n\\n (\\n vars.mathErr,\\n vars.exchangeRateMantissa\\n ) = exchangeRateStoredInternal();\\n if (vars.mathErr != MathError.NO_ERROR) {\\n return\\n failOpaque(\\n Error.MATH_ERROR,\\n FailureInfo.REDEEM_EXCHANGE_RATE_READ_FAILED,\\n uint256(vars.mathErr)\\n );\\n }\\n\\n uint256 interestEarned;\\n uint256 subsidyFundPortion;\\n uint256 currentUnderlying;\\n\\n bool isTropykusInterestRateModel = interestRateModel\\n .isTropykusInterestRateModel();\\n if (isTropykusInterestRateModel) {\\n currentUnderlying = supplySnapshot.underlyingAmount;\\n (, , interestEarned) = tropykusInterestAccrued(redeemer);\\n }\\n supplySnapshot.promisedSupplyRate = interestRateModel.getSupplyRate(\\n getCashPrior(),\\n totalBorrows,\\n totalReserves,\\n reserveFactorMantissa\\n );\\n\\n if (\\n isTropykusInterestRateModel &&\\n !interestRateModel.isAboveOptimal(\\n getCashPrior(),\\n totalBorrows,\\n totalReserves\\n )\\n ) {\\n uint256 borrowRate = interestRateModel.getBorrowRate(\\n getCashPrior(),\\n totalBorrows,\\n totalReserves\\n );\\n\\n uint256 utilizationRate = interestRateModel.utilizationRate(\\n getCashPrior(),\\n totalBorrows,\\n totalReserves\\n );\\n\\n (, uint256 estimatedEarning) = mulScalarTruncate(\\n Exp({mantissa: borrowRate}),\\n utilizationRate\\n );\\n\\n (, subsidyFundPortion) = subUInt(\\n supplySnapshot.promisedSupplyRate,\\n estimatedEarning\\n );\\n (, Exp memory subsidyFactor) = getExp(\\n subsidyFundPortion,\\n supplySnapshot.promisedSupplyRate\\n );\\n (, subsidyFundPortion) = mulScalarTruncate(\\n subsidyFactor,\\n interestEarned\\n );\\n }\\n\\n vars.redeemAmount = redeemAmountIn;\\n\\n if (isTropykusInterestRateModel) {\\n (, Exp memory num) = mulExp(\\n vars.redeemAmount,\\n supplySnapshot.tokens\\n );\\n (, Exp memory realTokensWithdrawAmount) = getExp(\\n num.mantissa,\\n currentUnderlying\\n );\\n vars.redeemTokens = realTokensWithdrawAmount.mantissa;\\n } else {\\n (vars.mathErr, vars.redeemTokens) = divScalarByExpTruncate(\\n redeemAmountIn,\\n Exp({mantissa: vars.exchangeRateMantissa})\\n );\\n if (vars.mathErr != MathError.NO_ERROR) {\\n return\\n failOpaque(\\n Error.MATH_ERROR,\\n FailureInfo.REDEEM_EXCHANGE_AMOUNT_CALCULATION_FAILED,\\n uint256(vars.mathErr)\\n );\\n }\\n }\\n // }\\n\\n uint256 allowed = comptroller.redeemAllowed(\\n address(this),\\n redeemer,\\n vars.redeemTokens\\n );\\n if (allowed != 0) {\\n return\\n failOpaque(\\n Error.COMPTROLLER_REJECTION,\\n FailureInfo.REDEEM_COMPTROLLER_REJECTION,\\n allowed\\n );\\n }\\n\\n if (accrualBlockNumber != getBlockNumber()) {\\n return\\n fail(\\n Error.MARKET_NOT_FRESH,\\n FailureInfo.REDEEM_FRESHNESS_CHECK\\n );\\n }\\n\\n (vars.mathErr, vars.totalSupplyNew) = subUInt(\\n totalSupply,\\n vars.redeemTokens\\n );\\n if (vars.mathErr != MathError.NO_ERROR) {\\n return\\n failOpaque(\\n Error.MATH_ERROR,\\n FailureInfo.REDEEM_NEW_TOTAL_SUPPLY_CALCULATION_FAILED,\\n uint256(vars.mathErr)\\n );\\n }\\n\\n (, vars.newSubsidyFund) = subUInt(subsidyFund, subsidyFundPortion);\\n\\n (vars.mathErr, vars.accountTokensNew) = subUInt(\\n supplySnapshot.tokens,\\n vars.redeemTokens\\n );\\n if (vars.mathErr != MathError.NO_ERROR) {\\n return\\n failOpaque(\\n Error.MATH_ERROR,\\n FailureInfo.REDEEM_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED,\\n uint256(vars.mathErr)\\n );\\n }\\n\\n uint256 cash = getCashPrior();\\n if (isTropykusInterestRateModel) {\\n cash = address(this).balance;\\n }\\n\\n if (cash < vars.redeemAmount) {\\n return\\n fail(\\n Error.TOKEN_INSUFFICIENT_CASH,\\n FailureInfo.REDEEM_TRANSFER_OUT_NOT_POSSIBLE\\n );\\n }\\n\\n doTransferOut(redeemer, vars.redeemAmount);\\n\\n totalSupply = vars.totalSupplyNew;\\n subsidyFund = vars.newSubsidyFund;\\n supplySnapshot.tokens = vars.accountTokensNew;\\n supplySnapshot.suppliedAt = accrualBlockNumber;\\n (, supplySnapshot.underlyingAmount) = subUInt(\\n supplySnapshot.underlyingAmount,\\n vars.redeemAmount\\n );\\n\\n emit Transfer(redeemer, address(this), vars.redeemTokens);\\n emit Redeem(redeemer, vars.redeemAmount, vars.redeemTokens);\\n\\n comptroller.redeemVerify(\\n address(this),\\n redeemer,\\n vars.redeemAmount,\\n vars.redeemTokens\\n );\\n\\n return uint256(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(uint256 borrowAmount)\\n internal\\n nonReentrant\\n returns (uint256)\\n {\\n uint256 error = accrueInterest();\\n if (error != uint256(Error.NO_ERROR)) {\\n return\\n fail(Error(error), FailureInfo.BORROW_ACCRUE_INTEREST_FAILED);\\n }\\n return borrowFresh(payable(msg.sender), borrowAmount);\\n }\\n\\n struct BorrowLocalVars {\\n MathError mathErr;\\n uint256 accountBorrows;\\n uint256 accountBorrowsNew;\\n uint256 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, uint256 borrowAmount)\\n internal\\n returns (uint256)\\n {\\n uint256 allowed = comptroller.borrowAllowed(\\n address(this),\\n borrower,\\n borrowAmount\\n );\\n if (allowed != 0) {\\n return\\n failOpaque(\\n Error.COMPTROLLER_REJECTION,\\n FailureInfo.BORROW_COMPTROLLER_REJECTION,\\n allowed\\n );\\n }\\n\\n if (accrualBlockNumber != getBlockNumber()) {\\n return\\n fail(\\n Error.MARKET_NOT_FRESH,\\n FailureInfo.BORROW_FRESHNESS_CHECK\\n );\\n }\\n\\n if (getCashPrior() < borrowAmount) {\\n return\\n fail(\\n Error.TOKEN_INSUFFICIENT_CASH,\\n FailureInfo.BORROW_CASH_NOT_AVAILABLE\\n );\\n }\\n\\n BorrowLocalVars memory vars;\\n\\n (vars.mathErr, vars.accountBorrows) = borrowBalanceStoredInternal(\\n borrower\\n );\\n if (vars.mathErr != MathError.NO_ERROR) {\\n return\\n failOpaque(\\n Error.MATH_ERROR,\\n FailureInfo.BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED,\\n uint256(vars.mathErr)\\n );\\n }\\n\\n (vars.mathErr, vars.accountBorrowsNew) = addUInt(\\n vars.accountBorrows,\\n borrowAmount\\n );\\n if (vars.mathErr != MathError.NO_ERROR) {\\n return\\n failOpaque(\\n Error.MATH_ERROR,\\n FailureInfo\\n .BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED,\\n uint256(vars.mathErr)\\n );\\n }\\n\\n (vars.mathErr, vars.totalBorrowsNew) = addUInt(\\n totalBorrows,\\n borrowAmount\\n );\\n if (interestRateModel.isTropykusInterestRateModel()) {\\n require(vars.totalBorrowsNew <= 0.1e18, \\\"CT25\\\");\\n }\\n if (vars.mathErr != MathError.NO_ERROR) {\\n return\\n failOpaque(\\n Error.MATH_ERROR,\\n FailureInfo.BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED,\\n uint256(vars.mathErr)\\n );\\n }\\n\\n doTransferOut(borrower, borrowAmount);\\n\\n accountBorrows[borrower].principal = vars.accountBorrowsNew;\\n accountBorrows[borrower].interestIndex = borrowIndex;\\n totalBorrows = vars.totalBorrowsNew;\\n\\n emit Borrow(\\n borrower,\\n borrowAmount,\\n vars.accountBorrowsNew,\\n vars.totalBorrowsNew\\n );\\n\\n return uint256(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(uint256 repayAmount)\\n internal\\n nonReentrant\\n returns (uint256, uint256)\\n {\\n uint256 error = accrueInterest();\\n if (error != uint256(Error.NO_ERROR)) {\\n return (\\n fail(\\n Error(error),\\n FailureInfo.REPAY_BORROW_ACCRUE_INTEREST_FAILED\\n ),\\n 0\\n );\\n }\\n return repayBorrowFresh(msg.sender, msg.sender, repayAmount);\\n }\\n\\n struct RepayBorrowLocalVars {\\n Error err;\\n MathError mathErr;\\n uint256 repayAmount;\\n uint256 borrowerIndex;\\n uint256 accountBorrows;\\n uint256 accountBorrowsNew;\\n uint256 totalBorrowsNew;\\n uint256 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(\\n address payer,\\n address borrower,\\n uint256 repayAmount\\n ) internal returns (uint256, uint256) {\\n uint256 allowed = comptroller.repayBorrowAllowed(\\n address(this),\\n payer,\\n borrower,\\n repayAmount\\n );\\n if (allowed != 0) {\\n return (\\n failOpaque(\\n Error.COMPTROLLER_REJECTION,\\n FailureInfo.REPAY_BORROW_COMPTROLLER_REJECTION,\\n allowed\\n ),\\n 0\\n );\\n }\\n\\n if (accrualBlockNumber != getBlockNumber()) {\\n return (\\n fail(\\n Error.MARKET_NOT_FRESH,\\n FailureInfo.REPAY_BORROW_FRESHNESS_CHECK\\n ),\\n 0\\n );\\n }\\n\\n RepayBorrowLocalVars memory vars;\\n\\n vars.borrowerIndex = accountBorrows[borrower].interestIndex;\\n\\n (vars.mathErr, vars.accountBorrows) = borrowBalanceStoredInternal(\\n borrower\\n );\\n if (vars.mathErr != MathError.NO_ERROR) {\\n return (\\n failOpaque(\\n Error.MATH_ERROR,\\n FailureInfo\\n .REPAY_BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED,\\n uint256(vars.mathErr)\\n ),\\n 0\\n );\\n }\\n\\n if (repayAmount == type(uint256).max) {\\n vars.repayAmount = vars.accountBorrows;\\n } else {\\n vars.repayAmount = repayAmount;\\n }\\n\\n vars.actualRepayAmount = doTransferIn(payer, vars.repayAmount);\\n\\n (vars.mathErr, vars.accountBorrowsNew) = subUInt(\\n vars.accountBorrows,\\n vars.actualRepayAmount\\n );\\n require(vars.mathErr == MathError.NO_ERROR, \\\"CT16\\\");\\n\\n (vars.mathErr, vars.totalBorrowsNew) = subUInt(\\n totalBorrows,\\n vars.actualRepayAmount\\n );\\n require(vars.mathErr == MathError.NO_ERROR, \\\"CT17\\\");\\n\\n accountBorrows[borrower].principal = vars.accountBorrowsNew;\\n accountBorrows[borrower].interestIndex = borrowIndex;\\n totalBorrows = vars.totalBorrowsNew;\\n\\n emit RepayBorrow(\\n payer,\\n borrower,\\n vars.actualRepayAmount,\\n vars.accountBorrowsNew,\\n vars.totalBorrowsNew\\n );\\n\\n return (uint256(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(\\n address borrower,\\n uint256 repayAmount,\\n CTokenInterface cTokenCollateral\\n ) internal nonReentrant returns (uint256, uint256) {\\n uint256 error = accrueInterest();\\n if (error != uint256(Error.NO_ERROR)) {\\n return (\\n fail(\\n Error(error),\\n FailureInfo.LIQUIDATE_ACCRUE_BORROW_INTEREST_FAILED\\n ),\\n 0\\n );\\n }\\n\\n error = cTokenCollateral.accrueInterest();\\n if (error != uint256(Error.NO_ERROR)) {\\n return (\\n fail(\\n Error(error),\\n FailureInfo.LIQUIDATE_ACCRUE_COLLATERAL_INTEREST_FAILED\\n ),\\n 0\\n );\\n }\\n\\n // liquidateBorrowFresh emits borrow-specific logs on errors, so we don't need to\\n return\\n liquidateBorrowFresh(\\n msg.sender,\\n borrower,\\n repayAmount,\\n cTokenCollateral\\n );\\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(\\n address liquidator,\\n address borrower,\\n uint256 repayAmount,\\n CTokenInterface cTokenCollateral\\n ) internal returns (uint256, uint256) {\\n uint256 allowed = comptroller.liquidateBorrowAllowed(\\n address(this),\\n address(cTokenCollateral),\\n liquidator,\\n borrower,\\n repayAmount\\n );\\n if (allowed != 0) {\\n return (\\n failOpaque(\\n Error.COMPTROLLER_REJECTION,\\n FailureInfo.LIQUIDATE_COMPTROLLER_REJECTION,\\n allowed\\n ),\\n 0\\n );\\n }\\n\\n if (accrualBlockNumber != getBlockNumber()) {\\n return (\\n fail(\\n Error.MARKET_NOT_FRESH,\\n FailureInfo.LIQUIDATE_FRESHNESS_CHECK\\n ),\\n 0\\n );\\n }\\n\\n if (cTokenCollateral.accrualBlockNumber() != getBlockNumber()) {\\n return (\\n fail(\\n Error.MARKET_NOT_FRESH,\\n FailureInfo.LIQUIDATE_COLLATERAL_FRESHNESS_CHECK\\n ),\\n 0\\n );\\n }\\n\\n if (borrower == liquidator) {\\n return (\\n fail(\\n Error.INVALID_ACCOUNT_PAIR,\\n FailureInfo.LIQUIDATE_LIQUIDATOR_IS_BORROWER\\n ),\\n 0\\n );\\n }\\n\\n if (repayAmount == 0) {\\n return (\\n fail(\\n Error.INVALID_CLOSE_AMOUNT_REQUESTED,\\n FailureInfo.LIQUIDATE_CLOSE_AMOUNT_IS_ZERO\\n ),\\n 0\\n );\\n }\\n\\n if (repayAmount == type(uint256).max) {\\n return (\\n fail(\\n Error.INVALID_CLOSE_AMOUNT_REQUESTED,\\n FailureInfo.LIQUIDATE_CLOSE_AMOUNT_IS_UINT_MAX\\n ),\\n 0\\n );\\n }\\n\\n (\\n uint256 repayBorrowError,\\n uint256 actualRepayAmount\\n ) = repayBorrowFresh(liquidator, borrower, repayAmount);\\n if (repayBorrowError != uint256(Error.NO_ERROR)) {\\n return (\\n fail(\\n Error(repayBorrowError),\\n FailureInfo.LIQUIDATE_REPAY_BORROW_FRESH_FAILED\\n ),\\n 0\\n );\\n }\\n\\n (uint256 amountSeizeError, uint256 seizeTokens) = comptroller\\n .liquidateCalculateSeizeTokens(\\n address(this),\\n address(cTokenCollateral),\\n actualRepayAmount\\n );\\n require(amountSeizeError == uint256(Error.NO_ERROR), \\\"CT18\\\");\\n\\n require(cTokenCollateral.balanceOf(borrower) >= seizeTokens, \\\"CT19\\\");\\n\\n uint256 seizeError;\\n if (address(cTokenCollateral) == address(this)) {\\n seizeError = seizeInternal(\\n address(this),\\n liquidator,\\n borrower,\\n seizeTokens\\n );\\n } else {\\n seizeError = cTokenCollateral.seize(\\n liquidator,\\n borrower,\\n seizeTokens\\n );\\n }\\n\\n require(seizeError == uint256(Error.NO_ERROR), \\\"CT20\\\");\\n\\n emit LiquidateBorrow(\\n liquidator,\\n borrower,\\n actualRepayAmount,\\n address(cTokenCollateral),\\n seizeTokens\\n );\\n\\n return (uint256(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(\\n address liquidator,\\n address borrower,\\n uint256 seizeTokens\\n ) external override nonReentrant returns (uint256) {\\n return seizeInternal(msg.sender, liquidator, borrower, seizeTokens);\\n }\\n\\n struct SeizeVars {\\n uint256 seizeAmount;\\n uint256 exchangeRate;\\n uint256 borrowerTokensNew;\\n uint256 borrowerAmountNew;\\n uint256 liquidatorTokensNew;\\n uint256 liquidatorAmountNew;\\n uint256 totalCash;\\n uint256 supplyRate;\\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(\\n address seizerToken,\\n address liquidator,\\n address borrower,\\n uint256 seizeTokens\\n ) internal returns (uint256) {\\n uint256 allowed = comptroller.seizeAllowed(\\n address(this),\\n seizerToken,\\n liquidator,\\n borrower,\\n seizeTokens\\n );\\n if (allowed != 0) {\\n return\\n failOpaque(\\n Error.COMPTROLLER_REJECTION,\\n FailureInfo.LIQUIDATE_SEIZE_COMPTROLLER_REJECTION,\\n allowed\\n );\\n }\\n\\n if (borrower == liquidator) {\\n return\\n fail(\\n Error.INVALID_ACCOUNT_PAIR,\\n FailureInfo.LIQUIDATE_SEIZE_LIQUIDATOR_IS_BORROWER\\n );\\n }\\n\\n SeizeVars memory seizeVars;\\n\\n MathError mathErr;\\n\\n (mathErr, seizeVars.borrowerTokensNew) = subUInt(\\n accountTokens[borrower].tokens,\\n seizeTokens\\n );\\n if (mathErr != MathError.NO_ERROR) {\\n return\\n failOpaque(\\n Error.MATH_ERROR,\\n FailureInfo.LIQUIDATE_SEIZE_BALANCE_DECREMENT_FAILED,\\n uint256(mathErr)\\n );\\n }\\n\\n seizeVars.totalCash = getCashPrior();\\n seizeVars.supplyRate = interestRateModel.getSupplyRate(\\n seizeVars.totalCash,\\n totalBorrows,\\n totalReserves,\\n reserveFactorMantissa\\n );\\n\\n (, seizeVars.exchangeRate) = interestRateModel.getExchangeRate(\\n seizeVars.totalCash,\\n totalBorrows,\\n totalReserves,\\n totalSupply\\n );\\n\\n if (interestRateModel.isTropykusInterestRateModel()) {\\n (, seizeVars.exchangeRate) = tropykusExchangeRateStoredInternal(\\n borrower\\n );\\n }\\n\\n (, seizeVars.seizeAmount) = mulUInt(\\n seizeTokens,\\n seizeVars.exchangeRate\\n );\\n (, seizeVars.seizeAmount) = divUInt(seizeVars.seizeAmount, 1e18);\\n\\n (, seizeVars.borrowerAmountNew) = subUInt(\\n accountTokens[borrower].underlyingAmount,\\n seizeVars.seizeAmount\\n );\\n\\n (mathErr, seizeVars.liquidatorTokensNew) = addUInt(\\n accountTokens[liquidator].tokens,\\n seizeTokens\\n );\\n if (mathErr != MathError.NO_ERROR) {\\n return\\n failOpaque(\\n Error.MATH_ERROR,\\n FailureInfo.LIQUIDATE_SEIZE_BALANCE_INCREMENT_FAILED,\\n uint256(mathErr)\\n );\\n }\\n\\n (, seizeVars.liquidatorAmountNew) = addUInt(\\n accountTokens[liquidator].underlyingAmount,\\n seizeVars.seizeAmount\\n );\\n\\n accountTokens[borrower].tokens = seizeVars.borrowerTokensNew;\\n accountTokens[borrower].underlyingAmount = seizeVars.borrowerAmountNew;\\n accountTokens[borrower].suppliedAt = getBlockNumber();\\n accountTokens[borrower].promisedSupplyRate = seizeVars.supplyRate;\\n\\n accountTokens[liquidator].tokens = seizeVars.liquidatorTokensNew;\\n accountTokens[liquidator].underlyingAmount = seizeVars\\n .liquidatorAmountNew;\\n accountTokens[liquidator].suppliedAt = getBlockNumber();\\n accountTokens[liquidator].promisedSupplyRate = seizeVars.supplyRate;\\n\\n emit Transfer(borrower, liquidator, seizeTokens);\\n\\n return uint256(Error.NO_ERROR);\\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 payable newPendingAdmin)\\n external\\n override\\n returns (uint256)\\n {\\n if (msg.sender != admin) {\\n return\\n fail(\\n Error.UNAUTHORIZED,\\n FailureInfo.SET_PENDING_ADMIN_OWNER_CHECK\\n );\\n }\\n\\n address oldPendingAdmin = pendingAdmin;\\n\\n pendingAdmin = newPendingAdmin;\\n\\n emit NewPendingAdmin(oldPendingAdmin, newPendingAdmin);\\n\\n return uint256(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 override returns (uint256) {\\n if (msg.sender != pendingAdmin || msg.sender == address(0)) {\\n return\\n fail(\\n Error.UNAUTHORIZED,\\n FailureInfo.ACCEPT_ADMIN_PENDING_ADMIN_CHECK\\n );\\n }\\n\\n address oldAdmin = admin;\\n address oldPendingAdmin = pendingAdmin;\\n\\n admin = pendingAdmin;\\n\\n pendingAdmin = payable(address(0));\\n\\n emit NewAdmin(oldAdmin, admin);\\n emit NewPendingAdmin(oldPendingAdmin, pendingAdmin);\\n\\n return uint256(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)\\n public\\n override\\n returns (uint256)\\n {\\n if (msg.sender != admin) {\\n return\\n fail(\\n Error.UNAUTHORIZED,\\n FailureInfo.SET_COMPTROLLER_OWNER_CHECK\\n );\\n }\\n\\n ComptrollerInterface oldComptroller = comptroller;\\n require(newComptroller.isComptroller(), \\\"CT21\\\");\\n\\n comptroller = newComptroller;\\n\\n emit NewComptroller(oldComptroller, newComptroller);\\n\\n return uint256(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(uint256 newReserveFactorMantissa)\\n external\\n override\\n nonReentrant\\n returns (uint256)\\n {\\n uint256 error = accrueInterest();\\n if (error != uint256(Error.NO_ERROR)) {\\n return\\n fail(\\n Error(error),\\n FailureInfo.SET_RESERVE_FACTOR_ACCRUE_INTEREST_FAILED\\n );\\n }\\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(uint256 newReserveFactorMantissa)\\n internal\\n returns (uint256)\\n {\\n if (msg.sender != admin) {\\n return\\n fail(\\n Error.UNAUTHORIZED,\\n FailureInfo.SET_RESERVE_FACTOR_ADMIN_CHECK\\n );\\n }\\n\\n if (accrualBlockNumber != getBlockNumber()) {\\n return\\n fail(\\n Error.MARKET_NOT_FRESH,\\n FailureInfo.SET_RESERVE_FACTOR_FRESH_CHECK\\n );\\n }\\n\\n if (newReserveFactorMantissa > reserveFactorMaxMantissa) {\\n return\\n fail(\\n Error.BAD_INPUT,\\n FailureInfo.SET_RESERVE_FACTOR_BOUNDS_CHECK\\n );\\n }\\n\\n uint256 oldReserveFactorMantissa = reserveFactorMantissa;\\n reserveFactorMantissa = newReserveFactorMantissa;\\n\\n emit NewReserveFactor(\\n oldReserveFactorMantissa,\\n newReserveFactorMantissa\\n );\\n\\n return uint256(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(uint256 addAmount)\\n internal\\n nonReentrant\\n returns (uint256)\\n {\\n uint256 error = accrueInterest();\\n if (error != uint256(Error.NO_ERROR)) {\\n return\\n fail(\\n Error(error),\\n FailureInfo.ADD_RESERVES_ACCRUE_INTEREST_FAILED\\n );\\n }\\n\\n uint256 totalReservesNew;\\n uint256 actualAddAmount;\\n\\n if (accrualBlockNumber != getBlockNumber()) {\\n return (\\n fail(\\n Error.MARKET_NOT_FRESH,\\n FailureInfo.ADD_RESERVES_FRESH_CHECK\\n )\\n );\\n }\\n\\n actualAddAmount = doTransferIn(msg.sender, addAmount);\\n\\n totalReservesNew = totalReserves + actualAddAmount;\\n\\n require(totalReservesNew >= totalReserves, \\\"CT22\\\");\\n\\n totalReserves = totalReservesNew;\\n\\n emit ReservesAdded(msg.sender, actualAddAmount, totalReservesNew);\\n\\n return (uint256(Error.NO_ERROR));\\n }\\n\\n function _addSubsidyInternal(uint256 addAmount)\\n internal\\n nonReentrant\\n returns (uint256)\\n {\\n uint256 error = accrueInterest();\\n if (error != uint256(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_SUBSIDY_FUND_FAILED);\\n }\\n\\n uint256 subsidyFundNew;\\n uint256 actualAddAmount;\\n\\n if (accrualBlockNumber != getBlockNumber()) {\\n return (\\n fail(\\n Error.MARKET_NOT_FRESH,\\n FailureInfo.ADD_SUBSIDY_FUND_FRESH_CHECK\\n )\\n );\\n }\\n\\n actualAddAmount = doTransferIn(msg.sender, addAmount);\\n\\n subsidyFundNew = subsidyFund + actualAddAmount;\\n\\n require(subsidyFundNew >= subsidyFund, \\\"CT22\\\");\\n\\n subsidyFund = subsidyFundNew;\\n\\n emit SubsidyAdded(msg.sender, actualAddAmount, subsidyFundNew);\\n\\n /* Return (NO_ERROR, actualAddAmount) */\\n return (uint256(Error.NO_ERROR));\\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(uint256 reduceAmount)\\n external\\n override\\n nonReentrant\\n returns (uint256)\\n {\\n uint256 error = accrueInterest();\\n if (error != uint256(Error.NO_ERROR)) {\\n return\\n fail(\\n Error(error),\\n FailureInfo.REDUCE_RESERVES_ACCRUE_INTEREST_FAILED\\n );\\n }\\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(uint256 reduceAmount)\\n internal\\n returns (uint256)\\n {\\n uint256 totalReservesNew;\\n\\n if (msg.sender != admin) {\\n return\\n fail(\\n Error.UNAUTHORIZED,\\n FailureInfo.REDUCE_RESERVES_ADMIN_CHECK\\n );\\n }\\n\\n if (accrualBlockNumber != getBlockNumber()) {\\n return\\n fail(\\n Error.MARKET_NOT_FRESH,\\n FailureInfo.REDUCE_RESERVES_FRESH_CHECK\\n );\\n }\\n\\n if (getCashPrior() < reduceAmount) {\\n return\\n fail(\\n Error.TOKEN_INSUFFICIENT_CASH,\\n FailureInfo.REDUCE_RESERVES_CASH_NOT_AVAILABLE\\n );\\n }\\n\\n if (reduceAmount > totalReserves) {\\n return\\n fail(Error.BAD_INPUT, FailureInfo.REDUCE_RESERVES_VALIDATION);\\n }\\n\\n totalReservesNew = totalReserves - reduceAmount;\\n require(totalReservesNew <= totalReserves, \\\"CT23\\\");\\n\\n totalReserves = totalReservesNew;\\n\\n doTransferOut(admin, reduceAmount);\\n\\n emit ReservesReduced(admin, reduceAmount, totalReservesNew);\\n\\n return uint256(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)\\n public\\n override\\n returns (uint256)\\n {\\n uint256 error = accrueInterest();\\n if (error != uint256(Error.NO_ERROR)) {\\n return\\n fail(\\n Error(error),\\n FailureInfo.SET_INTEREST_RATE_MODEL_ACCRUE_INTEREST_FAILED\\n );\\n }\\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)\\n internal\\n returns (uint256)\\n {\\n InterestRateModel oldInterestRateModel;\\n\\n if (msg.sender != admin) {\\n return\\n fail(\\n Error.UNAUTHORIZED,\\n FailureInfo.SET_INTEREST_RATE_MODEL_OWNER_CHECK\\n );\\n }\\n\\n if (accrualBlockNumber != getBlockNumber()) {\\n return\\n fail(\\n Error.MARKET_NOT_FRESH,\\n FailureInfo.SET_INTEREST_RATE_MODEL_FRESH_CHECK\\n );\\n }\\n\\n oldInterestRateModel = interestRateModel;\\n\\n require(newInterestRateModel.isInterestRateModel(), \\\"CT21\\\");\\n\\n interestRateModel = newInterestRateModel;\\n\\n emit NewMarketInterestRateModel(\\n oldInterestRateModel,\\n newInterestRateModel\\n );\\n\\n return uint256(Error.NO_ERROR);\\n }\\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 virtual returns (uint256);\\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, uint256 amount)\\n internal\\n virtual\\n returns (uint256);\\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, uint256 amount) internal virtual;\\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;\\n }\\n}\\n\",\"keccak256\":\"0x66c781aa1ccc507ce80a431b9ee06801bb81b954bd0697a1f656de400b5cb381\",\"license\":\"UNLICENSED\"},\"contracts/CTokenInterfaces.sol\":{\"content\":\"// SPDX-License-Identifier: UNLICENSED\\npragma solidity 0.8.6;\\n\\nimport \\\"./ComptrollerInterface.sol\\\";\\nimport \\\"./InterestRateModel.sol\\\";\\nimport \\\"./EIP20NonStandardInterface.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 uint256 internal constant borrowRateMaxMantissa = 0.0005e16;\\n\\n /**\\n * @notice Maximum fraction of interest that can be set aside for reserves\\n */\\n uint256 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 uint256 public initialExchangeRateMantissa;\\n\\n /**\\n * @notice Fraction of interest currently set aside for reserves\\n */\\n uint256 public reserveFactorMantissa;\\n\\n /**\\n * @notice Block number that interest was last accrued at\\n */\\n uint256 public accrualBlockNumber;\\n\\n /**\\n * @notice Accumulator of the total earned interest rate since the opening of the market\\n */\\n uint256 public borrowIndex;\\n\\n /**\\n * @notice Total amount of outstanding borrows of the underlying in this market\\n */\\n uint256 public totalBorrows;\\n\\n /**\\n * @notice Total amount of reserves of the underlying held in this market\\n */\\n uint256 public totalReserves;\\n\\n /**\\n * @notice Total number of tokens in circulation\\n */\\n uint256 public totalSupply;\\n\\n uint256 public subsidyFund;\\n\\n struct SupplySnapshot {\\n uint256 tokens;\\n uint256 underlyingAmount;\\n uint256 suppliedAt;\\n uint256 promisedSupplyRate;\\n }\\n\\n /**\\n * @notice Official record of token balances for each account\\n */\\n mapping(address => SupplySnapshot) internal accountTokens;\\n\\n /**\\n * @notice Approved token transfer amounts on behalf of others\\n */\\n mapping(address => mapping(address => uint256)) 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 uint256 principal;\\n uint256 interestIndex;\\n }\\n\\n /**\\n * @notice Mapping of account addresses to outstanding borrow balances\\n */\\n mapping(address => BorrowSnapshot) internal accountBorrows;\\n}\\n\\nabstract contract CTokenInterface is CTokenStorage {\\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 interest is accrued\\n */\\n event AccrueInterest(\\n uint256 cashPrior,\\n uint256 interestAccumulated,\\n uint256 borrowIndex,\\n uint256 totalBorrows\\n );\\n\\n /**\\n * @notice Event emitted when tokens are minted\\n */\\n event Mint(address indexed minter, uint256 mintAmount, uint256 mintTokens);\\n\\n /**\\n * @notice Event emitted when tokens are redeemed\\n */\\n event Redeem(\\n address indexed redeemer,\\n uint256 redeemAmount,\\n uint256 redeemTokens\\n );\\n\\n /**\\n * @notice Event emitted when underlying is borrowed\\n */\\n event Borrow(\\n address indexed borrower,\\n uint256 borrowAmount,\\n uint256 accountBorrows,\\n uint256 totalBorrows\\n );\\n\\n /**\\n * @notice Event emitted when a borrow is repaid\\n */\\n event RepayBorrow(\\n address indexed payer,\\n address indexed borrower,\\n uint256 repayAmount,\\n uint256 accountBorrows,\\n uint256 totalBorrows\\n );\\n\\n /**\\n * @notice Event emitted when a borrow is liquidated\\n */\\n event LiquidateBorrow(\\n address indexed liquidator,\\n address indexed borrower,\\n uint256 repayAmount,\\n address indexed cTokenCollateral,\\n uint256 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(\\n ComptrollerInterface oldComptroller,\\n ComptrollerInterface newComptroller\\n );\\n\\n /**\\n * @notice Event emitted when interestRateModel is changed\\n */\\n event NewMarketInterestRateModel(\\n InterestRateModel oldInterestRateModel,\\n InterestRateModel newInterestRateModel\\n );\\n\\n /**\\n * @notice Event emitted when the reserve factor is changed\\n */\\n event NewReserveFactor(\\n uint256 oldReserveFactorMantissa,\\n uint256 newReserveFactorMantissa\\n );\\n\\n /**\\n * @notice Event emitted when the reserves are added\\n */\\n event ReservesAdded(\\n address benefactor,\\n uint256 addAmount,\\n uint256 newTotalReserves\\n );\\n\\n event SubsidyAdded(\\n address benefactor,\\n uint256 addAmount,\\n uint256 newSubsidyFund\\n );\\n\\n /**\\n * @notice Event emitted when the reserves are reduced\\n */\\n event ReservesReduced(\\n address admin,\\n uint256 reduceAmount,\\n uint256 newTotalReserves\\n );\\n\\n /**\\n * @notice EIP20 Transfer event\\n */\\n event Transfer(address indexed from, address indexed to, uint256 amount);\\n\\n /**\\n * @notice EIP20 Approval event\\n */\\n event Approval(\\n address indexed owner,\\n address indexed spender,\\n uint256 amount\\n );\\n\\n /**\\n * @notice Failure event\\n */\\n event CTokenStorageFailure(uint256 error, uint256 info, uint256 detail);\\n\\n /*** User Interface ***/\\n\\n function transfer(address dst, uint256 amount)\\n external\\n virtual\\n returns (bool);\\n\\n function transferFrom(\\n address src,\\n address dst,\\n uint256 amount\\n ) external virtual returns (bool);\\n\\n function approve(address spender, uint256 amount)\\n external\\n virtual\\n returns (bool);\\n\\n function allowance(address owner, address spender)\\n external\\n view\\n virtual\\n returns (uint256);\\n\\n function balanceOf(address owner) external view virtual returns (uint256);\\n\\n function balanceOfUnderlying(address owner)\\n external\\n virtual\\n returns (uint256);\\n\\n function getAccountSnapshot(address account)\\n external\\n view\\n virtual\\n returns (\\n uint256,\\n uint256,\\n uint256,\\n uint256\\n );\\n\\n function borrowRatePerBlock() external view virtual returns (uint256);\\n\\n function supplyRatePerBlock() external view virtual returns (uint256);\\n\\n function totalBorrowsCurrent() external virtual returns (uint256);\\n\\n function borrowBalanceCurrent(address account)\\n external\\n virtual\\n returns (uint256);\\n\\n function borrowBalanceStored(address account)\\n public\\n view\\n virtual\\n returns (uint256);\\n\\n function exchangeRateCurrent() public virtual returns (uint256);\\n\\n function exchangeRateStored() public view virtual returns (uint256);\\n\\n function getCash() external view virtual returns (uint256);\\n\\n function accrueInterest() public virtual returns (uint256);\\n\\n function seize(\\n address liquidator,\\n address borrower,\\n uint256 seizeTokens\\n ) external virtual returns (uint256);\\n\\n /*** Admin Functions ***/\\n\\n function _setPendingAdmin(address payable newPendingAdmin)\\n external\\n virtual\\n returns (uint256);\\n\\n function _acceptAdmin() external virtual returns (uint256);\\n\\n function _setComptroller(ComptrollerInterface newComptroller)\\n public\\n virtual\\n returns (uint256);\\n\\n function _setReserveFactor(uint256 newReserveFactorMantissa)\\n external\\n virtual\\n returns (uint256);\\n\\n function _reduceReserves(uint256 reduceAmount)\\n external\\n virtual\\n returns (uint256);\\n\\n function _setInterestRateModel(InterestRateModel newInterestRateModel)\\n public\\n virtual\\n returns (uint256);\\n}\\n\\ncontract CErc20Storage {\\n /**\\n * @notice Underlying asset for this CToken\\n */\\n address public underlying;\\n}\\n\\nabstract contract CErc20Interface is CErc20Storage {\\n /*** User Interface ***/\\n\\n function mint(uint256 mintAmount) external virtual returns (uint256);\\n\\n function redeem(uint256 redeemAmount)\\n external\\n virtual\\n returns (uint256);\\n\\n function borrow(uint256 borrowAmount) external virtual returns (uint256);\\n\\n function repayBorrow(uint256 repayAmount)\\n external\\n virtual\\n returns (uint256);\\n\\n function liquidateBorrow(\\n address borrower,\\n uint256 repayAmount,\\n CTokenInterface cTokenCollateral\\n ) external virtual returns (uint256);\\n\\n function sweepToken(EIP20NonStandardInterface token) external virtual;\\n\\n /*** Admin Functions ***/\\n\\n function _addReserves(uint256 addAmount) external virtual returns (uint256);\\n}\\n\\ncontract CDelegationStorage {\\n /**\\n * @notice Implementation address for this contract\\n */\\n address public implementation;\\n}\\n\\nabstract contract CDelegatorInterface is CDelegationStorage {\\n /**\\n * @notice Emitted when implementation is changed\\n */\\n event NewImplementation(\\n address oldImplementation,\\n address newImplementation\\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(\\n address implementation_,\\n bool allowResign,\\n bytes memory becomeImplementationData\\n ) public virtual;\\n}\\n\\nabstract contract 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 virtual;\\n\\n /**\\n * @notice Called by the delegator on a delegate to forfeit its responsibility\\n */\\n function _resignImplementation() public virtual;\\n}\\n\",\"keccak256\":\"0xd0c347830afeac6c54eb7fbac35b60215d9acdd1fb2a3abb16df18923384fa42\",\"license\":\"UNLICENSED\"},\"contracts/CarefulMath.sol\":{\"content\":\"// SPDX-License-Identifier: UNLICENSED\\npragma solidity 0.8.6;\\n\\n/**\\n * @title Careful Math\\n * @author tropykus\\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}\\n\",\"keccak256\":\"0x2aa4360607bccc28c9bde237718c5fabc5e68a34befec92724d30bfbc0b9499f\",\"license\":\"UNLICENSED\"},\"contracts/ComptrollerInterface.sol\":{\"content\":\"// SPDX-License-Identifier: UNLICENSED\\npragma solidity 0.8.6;\\n\\nabstract contract 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)\\n external\\n virtual\\n returns (uint256[] memory);\\n\\n function exitMarket(address cToken) external virtual returns (uint256);\\n\\n /*** Policy Hooks ***/\\n\\n function mintAllowed(\\n address cToken,\\n address minter,\\n uint256 mintAmount\\n ) external virtual returns (uint256);\\n\\n function mintVerify(\\n address cToken,\\n address minter,\\n uint256 mintAmount,\\n uint256 mintTokens\\n ) external virtual;\\n\\n function redeemAllowed(\\n address cToken,\\n address redeemer,\\n uint256 redeemTokens\\n ) external virtual returns (uint256);\\n\\n function redeemVerify(\\n address cToken,\\n address redeemer,\\n uint256 redeemAmount,\\n uint256 redeemTokens\\n ) external virtual;\\n\\n function borrowAllowed(\\n address cToken,\\n address borrower,\\n uint256 borrowAmount\\n ) external virtual returns (uint256);\\n\\n function borrowVerify(\\n address cToken,\\n address borrower,\\n uint256 borrowAmount\\n ) external virtual;\\n\\n function repayBorrowAllowed(\\n address cToken,\\n address payer,\\n address borrower,\\n uint256 repayAmount\\n ) external virtual returns (uint256);\\n\\n function repayBorrowVerify(\\n address cToken,\\n address payer,\\n address borrower,\\n uint256 repayAmount,\\n uint256 borrowerIndex\\n ) external virtual;\\n\\n function liquidateBorrowAllowed(\\n address cTokenBorrowed,\\n address cTokenCollateral,\\n address liquidator,\\n address borrower,\\n uint256 repayAmount\\n ) external virtual returns (uint256);\\n\\n function liquidateBorrowVerify(\\n address cTokenBorrowed,\\n address cTokenCollateral,\\n address liquidator,\\n address borrower,\\n uint256 repayAmount,\\n uint256 seizeTokens\\n ) external virtual;\\n\\n function seizeAllowed(\\n address cTokenCollateral,\\n address cTokenBorrowed,\\n address liquidator,\\n address borrower,\\n uint256 seizeTokens\\n ) external virtual returns (uint256);\\n\\n function seizeVerify(\\n address cTokenCollateral,\\n address cTokenBorrowed,\\n address liquidator,\\n address borrower,\\n uint256 seizeTokens\\n ) external virtual;\\n\\n function transferAllowed(\\n address cToken,\\n address src,\\n address dst,\\n uint256 transferTokens\\n ) external virtual returns (uint256);\\n\\n function transferVerify(\\n address cToken,\\n address src,\\n address dst,\\n uint256 transferTokens\\n ) external virtual;\\n\\n /*** Liquidity/Liquidation Calculations ***/\\n\\n function liquidateCalculateSeizeTokens(\\n address cTokenBorrowed,\\n address cTokenCollateral,\\n uint256 repayAmount\\n ) external view virtual returns (uint256, uint256);\\n}\\n\",\"keccak256\":\"0x4f6874b6790450374231de9b8c33652d620ec9457835e78d36ceaa561875a1b9\",\"license\":\"UNLICENSED\"},\"contracts/EIP20Interface.sol\":{\"content\":\"// SPDX-License-Identifier: UNLICENSED\\npragma solidity 0.8.6;\\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\\n function symbol() external view returns (string memory);\\n\\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 balance 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 success Whether or not the transfer succeeded\\n */\\n function transfer(address dst, uint256 amount)\\n external\\n 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 success Whether or not the transfer succeeded\\n */\\n function transferFrom(\\n address src,\\n address dst,\\n uint256 amount\\n ) 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 success Whether or not the approval succeeded\\n */\\n function approve(address spender, uint256 amount)\\n external\\n 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 remaining The number of tokens allowed to be spent (-1 means infinite)\\n */\\n function allowance(address owner, address spender)\\n external\\n view\\n returns (uint256 remaining);\\n\\n event Transfer(address indexed from, address indexed to, uint256 amount);\\n event Approval(\\n address indexed owner,\\n address indexed spender,\\n uint256 amount\\n );\\n}\\n\",\"keccak256\":\"0xe445bee8cc89c468e8822aa0d39c8f4ee6b6ac059191365ecef889cd83b53a75\",\"license\":\"UNLICENSED\"},\"contracts/EIP20NonStandardInterface.sol\":{\"content\":\"// SPDX-License-Identifier: UNLICENSED\\npragma solidity 0.8.6;\\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 * @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 balance 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(\\n address src,\\n address dst,\\n uint256 amount\\n ) 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 success Whether or not the approval succeeded\\n */\\n function approve(address spender, uint256 amount)\\n external\\n 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 remaining The number of tokens allowed to be spent\\n */\\n function allowance(address owner, address spender)\\n external\\n view\\n returns (uint256 remaining);\\n\\n event Transfer(address indexed from, address indexed to, uint256 amount);\\n event Approval(\\n address indexed owner,\\n address indexed spender,\\n uint256 amount\\n );\\n}\\n\",\"keccak256\":\"0xab8b46aaf5f985d5e3e1f1aa3dbc2e30d69ae0760b3a6b0478f50b9fca3bbc39\",\"license\":\"UNLICENSED\"},\"contracts/ErrorReporter.sol\":{\"content\":\"// SPDX-License-Identifier: UNLICENSED\\npragma solidity 0.8.6;\\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(uint256 error, uint256 info, uint256 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 (uint256) {\\n emit Failure(uint256(err), uint256(info), 0);\\n\\n return uint256(err);\\n }\\n\\n /**\\n * @dev use this when reporting an opaque error from an upgradeable collaborator contract\\n */\\n function failOpaque(\\n Error err,\\n FailureInfo info,\\n uint256 opaqueError\\n ) internal returns (uint256) {\\n emit Failure(uint256(err), uint256(info), opaqueError);\\n\\n return uint256(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 ADD_SUBSIDY_FUND_FAILED,\\n ADD_SUBSIDY_FUND_FRESH_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 TokenFailure(uint256 error, uint256 info, uint256 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 (uint256) {\\n emit TokenFailure(uint256(err), uint256(info), 0);\\n\\n return uint256(err);\\n }\\n\\n /**\\n * @dev use this when reporting an opaque error from an upgradeable collaborator contract\\n */\\n function failOpaque(\\n Error err,\\n FailureInfo info,\\n uint256 opaqueError\\n ) internal returns (uint256) {\\n emit TokenFailure(uint256(err), uint256(info), opaqueError);\\n\\n return uint256(err);\\n }\\n}\\n\",\"keccak256\":\"0x097b23a9ddec2e563458dadd7e03fb1756514acb8a05eb924da76b470582ceb9\",\"license\":\"UNLICENSED\"},\"contracts/Exponential.sol\":{\"content\":\"// SPDX-License-Identifier: UNLICENSED\\npragma solidity 0.8.6;\\n\\nimport \\\"./CarefulMath.sol\\\";\\nimport \\\"./ExponentialNoError.sol\\\";\\n\\n/**\\n * @title Exponential module for storing fixed-precision decimals\\n * @author tropykus\\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) internal pure 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) internal pure 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) internal pure 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) internal pure 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) internal pure 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) internal pure 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) internal pure 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) internal pure 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) internal pure 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) internal pure 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) internal pure 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) internal pure 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) internal pure returns (MathError, Exp memory) {\\n return getExp(a.mantissa, b.mantissa);\\n }\\n}\\n\",\"keccak256\":\"0x4d59359e644bc1df4c60f967b00027aed07612c3471c7c1206d61e10ab705475\",\"license\":\"UNLICENSED\"},\"contracts/ExponentialNoError.sol\":{\"content\":\"// SPDX-License-Identifier: UNLICENSED\\npragma solidity 0.8.6;\\n\\n/**\\n * @title Exponential module for storing fixed-precision decimals\\n * @author tropykus\\n * @notice Exp is a struct which stores decimals with a fixed precision of 18 decimal places.\\n * Thus, if we wanted to store the 5.1, mantissa would store 5.1e18. That is:\\n * `Exp({mantissa: 5100000000000000000})`.\\n */\\ncontract ExponentialNoError {\\n uint constant expScale = 1e18;\\n uint constant doubleScale = 1e36;\\n uint constant halfExpScale = expScale/2;\\n uint constant mantissaOne = expScale;\\n\\n struct Exp {\\n uint mantissa;\\n }\\n\\n struct Double {\\n uint mantissa;\\n }\\n\\n /**\\n * @dev Truncates the given exp to a whole number value.\\n * For example, truncate(Exp{mantissa: 15 * expScale}) = 15\\n */\\n function truncate(Exp memory exp) pure internal returns (uint) {\\n // Note: We are not using careful math here as we're performing a division that cannot fail\\n return exp.mantissa / expScale;\\n }\\n\\n /**\\n * @dev Multiply an Exp by a scalar, then truncate to return an unsigned integer.\\n */\\n function mul_ScalarTruncate(Exp memory a, uint scalar) pure internal returns (uint) {\\n Exp memory product = mul_(a, scalar);\\n return truncate(product);\\n }\\n\\n /**\\n * @dev Multiply an Exp by a scalar, truncate, then add an to an unsigned integer, returning an unsigned integer.\\n */\\n function mul_ScalarTruncateAddUInt(Exp memory a, uint scalar, uint addend) pure internal returns (uint) {\\n Exp memory product = mul_(a, scalar);\\n return add_(truncate(product), addend);\\n }\\n\\n /**\\n * @dev Checks if first Exp is less than second Exp.\\n */\\n function lessThanExp(Exp memory left, Exp memory right) pure internal returns (bool) {\\n return left.mantissa < right.mantissa;\\n }\\n\\n /**\\n * @dev Checks if left Exp <= right Exp.\\n */\\n function lessThanOrEqualExp(Exp memory left, Exp memory right) pure internal returns (bool) {\\n return left.mantissa <= right.mantissa;\\n }\\n\\n /**\\n * @dev Checks if left Exp > right Exp.\\n */\\n function greaterThanExp(Exp memory left, Exp memory right) pure internal returns (bool) {\\n return left.mantissa > right.mantissa;\\n }\\n\\n /**\\n * @dev returns true if Exp is exactly zero\\n */\\n function isZeroExp(Exp memory value) pure internal returns (bool) {\\n return value.mantissa == 0;\\n }\\n\\n function safe224(uint n, string memory errorMessage) pure internal returns (uint224) {\\n require(n < 2**224, errorMessage);\\n return uint224(n);\\n }\\n\\n function safe32(uint n, string memory errorMessage) pure internal returns (uint32) {\\n require(n < 2**32, errorMessage);\\n return uint32(n);\\n }\\n\\n function add_(Exp memory a, Exp memory b) pure internal returns (Exp memory) {\\n return Exp({mantissa: add_(a.mantissa, b.mantissa)});\\n }\\n\\n function add_(Double memory a, Double memory b) pure internal returns (Double memory) {\\n return Double({mantissa: add_(a.mantissa, b.mantissa)});\\n }\\n\\n function add_(uint a, uint b) pure internal returns (uint) {\\n return add_(a, b, \\\"addition overflow\\\");\\n }\\n\\n function add_(uint a, uint b, string memory errorMessage) pure internal returns (uint) {\\n uint c = a + b;\\n require(c >= a, errorMessage);\\n return c;\\n }\\n\\n function sub_(Exp memory a, Exp memory b) pure internal returns (Exp memory) {\\n return Exp({mantissa: sub_(a.mantissa, b.mantissa)});\\n }\\n\\n function sub_(Double memory a, Double memory b) pure internal returns (Double memory) {\\n return Double({mantissa: sub_(a.mantissa, b.mantissa)});\\n }\\n\\n function sub_(uint a, uint b) pure internal returns (uint) {\\n return sub_(a, b, \\\"subtraction underflow\\\");\\n }\\n\\n function sub_(uint a, uint b, string memory errorMessage) pure internal returns (uint) {\\n require(b <= a, errorMessage);\\n return a - b;\\n }\\n\\n function mul_(Exp memory a, Exp memory b) pure internal returns (Exp memory) {\\n return Exp({mantissa: mul_(a.mantissa, b.mantissa) / expScale});\\n }\\n\\n function mul_(Exp memory a, uint b) pure internal returns (Exp memory) {\\n return Exp({mantissa: mul_(a.mantissa, b)});\\n }\\n\\n function mul_(uint a, Exp memory b) pure internal returns (uint) {\\n return mul_(a, b.mantissa) / expScale;\\n }\\n\\n function mul_(Double memory a, Double memory b) pure internal returns (Double memory) {\\n return Double({mantissa: mul_(a.mantissa, b.mantissa) / doubleScale});\\n }\\n\\n function mul_(Double memory a, uint b) pure internal returns (Double memory) {\\n return Double({mantissa: mul_(a.mantissa, b)});\\n }\\n\\n function mul_(uint a, Double memory b) pure internal returns (uint) {\\n return mul_(a, b.mantissa) / doubleScale;\\n }\\n\\n function mul_(uint a, uint b) pure internal returns (uint) {\\n return mul_(a, b, \\\"multiplication overflow\\\");\\n }\\n\\n function mul_(uint a, uint b, string memory errorMessage) pure internal returns (uint) {\\n if (a == 0 || b == 0) {\\n return 0;\\n }\\n uint c = a * b;\\n require(c / a == b, errorMessage);\\n return c;\\n }\\n\\n function div_(Exp memory a, Exp memory b) pure internal returns (Exp memory) {\\n return Exp({mantissa: div_(mul_(a.mantissa, expScale), b.mantissa)});\\n }\\n\\n function div_(Exp memory a, uint b) pure internal returns (Exp memory) {\\n return Exp({mantissa: div_(a.mantissa, b)});\\n }\\n\\n function div_(uint a, Exp memory b) pure internal returns (uint) {\\n return div_(mul_(a, expScale), b.mantissa);\\n }\\n\\n function div_(Double memory a, Double memory b) pure internal returns (Double memory) {\\n return Double({mantissa: div_(mul_(a.mantissa, doubleScale), b.mantissa)});\\n }\\n\\n function div_(Double memory a, uint b) pure internal returns (Double memory) {\\n return Double({mantissa: div_(a.mantissa, b)});\\n }\\n\\n function div_(uint a, Double memory b) pure internal returns (uint) {\\n return div_(mul_(a, doubleScale), b.mantissa);\\n }\\n\\n function div_(uint a, uint b) pure internal returns (uint) {\\n return div_(a, b, \\\"divide by zero\\\");\\n }\\n\\n function div_(uint a, uint b, string memory errorMessage) pure internal returns (uint) {\\n require(b > 0, errorMessage);\\n return a / b;\\n }\\n\\n function fraction(uint a, uint b) pure internal returns (Double memory) {\\n return Double({mantissa: div_(mul_(a, doubleScale), b)});\\n }\\n}\\n\",\"keccak256\":\"0x50ebd15fc98c12e065477f11230f5d7cd583b5fe25a3c532cb90e75950667795\",\"license\":\"UNLICENSED\"},\"contracts/InterestRateModel.sol\":{\"content\":\"// SPDX-License-Identifier: UNLICENSED\\npragma solidity 0.8.6;\\n\\nimport \\\"./Exponential.sol\\\";\\nimport \\\"./SafeMath.sol\\\";\\n\\n/**\\n * @title tropykus InterestRateModel Interface\\n * @author tropykus\\n */\\nabstract contract InterestRateModel is Exponential {\\n using SafeMath for uint256;\\n\\n /// @notice Indicator that this is an InterestRateModel contract (for inspection)\\n bool public constant isInterestRateModel = true;\\n bool public isTropykusInterestRateModel;\\n\\n /**\\n * @notice The approximate number of blocks per year that is assumed by the interest rate model\\n */\\n uint256 public constant blocksPerYear = 1051200;\\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(\\n uint256 cash,\\n uint256 borrows,\\n uint256 reserves\\n ) public pure virtual returns (uint256) {\\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 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 amnount of reserves the market has\\n * @return The borrow rate per block (as a percentage, and scaled by 1e18)\\n */\\n function getBorrowRate(\\n uint256 cash,\\n uint256 borrows,\\n uint256 reserves\\n ) external view virtual returns (uint256);\\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 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(\\n uint256 cash,\\n uint256 borrows,\\n uint256 reserves,\\n uint256 reserveFactorMantissa\\n ) external view virtual returns (uint256);\\n\\n function getExchangeRate(\\n uint256 _totalCash,\\n uint256 _totalBorrows,\\n uint256 _totalReserves,\\n uint256 _totalSupply\\n ) public pure returns (MathError, uint256) {\\n /*\\n * exchangeRate = (totalCash + totalBorrows - totalReserves) / totalSupply\\n */\\n Exp memory exchangeRate;\\n MathError mathErr;\\n uint256 cashPlusBorrowsMinusReserves;\\n (mathErr, cashPlusBorrowsMinusReserves) = addThenSubUInt(\\n _totalCash,\\n _totalBorrows,\\n _totalReserves\\n );\\n if (mathErr != MathError.NO_ERROR) {\\n return (mathErr, 0);\\n }\\n (mathErr, exchangeRate) = getExp(\\n cashPlusBorrowsMinusReserves,\\n _totalSupply\\n );\\n if (mathErr != MathError.NO_ERROR) {\\n return (mathErr, 0);\\n }\\n\\n return (MathError.NO_ERROR, exchangeRate.mantissa);\\n }\\n\\n function isAboveOptimal(\\n uint256 cash,\\n uint256 borrows,\\n uint256 reserves\\n ) public view virtual returns (bool) {\\n cash;\\n borrows;\\n reserves;\\n return false;\\n }\\n}\\n\",\"keccak256\":\"0x2cdc1a63482287513664d98d778c718c336461272885f61585c6ba404feb2edc\",\"license\":\"UNLICENSED\"},\"contracts/SafeMath.sol\":{\"content\":\"// SPDX-License-Identifier: UNLICENSED\\npragma solidity 0.8.6;\\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\":\"0xe578b9602160e7ddbb5e7b6d355bb4508fa134684afe46e4043602c652e0e041\",\"license\":\"UNLICENSED\"},\"contracts/WhitelistInterface.sol\":{\"content\":\"// SPDX-License-Identifier: UNLICENSED\\npragma solidity 0.8.6;\\n\\ninterface WhitelistInterface {\\n function setStatus(bool _newStatus) external;\\n function enabled() external view returns(bool);\\n\\n function addUsers(address[] memory _users) external;\\n function exist(address _user) external view returns(bool);\\n function getUsers() external view returns(address[] memory currentUsers);\\n function removeUser(address _user) external;\\n}\",\"keccak256\":\"0xb00f782772179693611aefb08d51640de313bc901d6d9d78d1e1b86922e99130\",\"license\":\"UNLICENSED\"},\"contracts/mocks/MockPriceProviderMoC.sol\":{\"content\":\"// SPDX-License-Identifier: UNLICENSED\\npragma solidity 0.8.6;\\n\\nimport \\\"../CErc20.sol\\\";\\n\\n/**\\n * @title A mock price provider of Money on Chain (MoC)\\n * @notice You can use this contract for only simulation\\n */\\ncontract MockPriceProviderMoC {\\n /// @notice rbtcPrice of the interface provicer MoC\\n bytes32 rbtcPrice;\\n /// @notice has of the interface provicer MoC\\n bool has;\\n /// @notice Address of the guardian\\n address public guardian;\\n /// @notice Event rbtcPrice updated\\n event MockPriceProviderMoCUpdated(uint256 oldPrice, uint256 newPrice);\\n\\n constructor(address guardian_, uint256 price) {\\n require(\\n guardian_ != address(0),\\n \\\"MockPriceProviderMoC: address could not be 0\\\"\\n );\\n require(\\n price != uint256(0),\\n \\\"MockPriceProviderMoC: price could not be 0\\\"\\n );\\n guardian = guardian_;\\n rbtcPrice = bytes32(price);\\n has = true;\\n }\\n\\n function peek() public view returns (bytes32, bool) {\\n return (rbtcPrice, has);\\n }\\n\\n /**\\n * @notice Set the rbtcPrice price provider\\n * @param price uint of price provider\\n */\\n function setPrice(uint256 price) public {\\n require(\\n msg.sender == guardian,\\n \\\"MockPriceProviderMoC: only guardian may set the address\\\"\\n );\\n require(\\n price != uint256(0),\\n \\\"MockPriceProviderMoC: price could not be 0\\\"\\n );\\n //set old price\\n bytes32 oldRbtcPrice = rbtcPrice;\\n //update rbtcPrice\\n rbtcPrice = bytes32(price);\\n //emit event\\n emit MockPriceProviderMoCUpdated(\\n uint256(oldRbtcPrice),\\n uint256(rbtcPrice)\\n );\\n }\\n}\\n\",\"keccak256\":\"0xc92138e00d6d4a6a90185de32002ee03c70254fa27d4be28539d72c22785cce9\",\"license\":\"UNLICENSED\"}},\"version\":1}", - "bytecode": "0x608060405234801561001057600080fd5b506040516103aa3803806103aa83398101604081905261002f91610135565b6001600160a01b03821661009f5760405162461bcd60e51b815260206004820152602c60248201527f4d6f636b507269636550726f76696465724d6f433a206164647265737320636f60448201526b0756c64206e6f7420626520360a41b60648201526084015b60405180910390fd5b806100ff5760405162461bcd60e51b815260206004820152602a60248201527f4d6f636b507269636550726f76696465724d6f433a20707269636520636f756c604482015269064206e6f7420626520360b41b6064820152608401610096565b6001805460009290925560ff196001600160a01b0390931661010002929092166001600160a81b0319909116178117905561016f565b6000806040838503121561014857600080fd5b82516001600160a01b038116811461015f57600080fd5b6020939093015192949293505050565b61022c8061017e6000396000f3fe608060405234801561001057600080fd5b50600436106100415760003560e01c8063452a93201461004657806359e02dd71461007b57806391b7f5ed14610099575b600080fd5b60015461005e9061010090046001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b60005460015460ff1660408051928352901515602083015201610072565b6100ac6100a73660046101dd565b6100ae565b005b60015461010090046001600160a01b031633146101385760405162461bcd60e51b815260206004820152603760248201527f4d6f636b507269636550726f76696465724d6f433a206f6e6c7920677561726460448201527f69616e206d61792073657420746865206164647265737300000000000000000060648201526084015b60405180910390fd5b806101985760405162461bcd60e51b815260206004820152602a60248201527f4d6f636b507269636550726f76696465724d6f433a20707269636520636f756c604482015269064206e6f7420626520360b41b606482015260840161012f565b600080549082905560408051828152602081018490527f0f044c0280bacc38accfa21abc3ff4078e3acc7d7a14569f5db61f36870df047910160405180910390a15050565b6000602082840312156101ef57600080fd5b503591905056fea2646970667358221220f7515fbb2e55846cd982cf3d3ec4650f7c5c8cad8c3466ce1148d1d7ab30910064736f6c63430008060033", - "deployedBytecode": "0x608060405234801561001057600080fd5b50600436106100415760003560e01c8063452a93201461004657806359e02dd71461007b57806391b7f5ed14610099575b600080fd5b60015461005e9061010090046001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b60005460015460ff1660408051928352901515602083015201610072565b6100ac6100a73660046101dd565b6100ae565b005b60015461010090046001600160a01b031633146101385760405162461bcd60e51b815260206004820152603760248201527f4d6f636b507269636550726f76696465724d6f433a206f6e6c7920677561726460448201527f69616e206d61792073657420746865206164647265737300000000000000000060648201526084015b60405180910390fd5b806101985760405162461bcd60e51b815260206004820152602a60248201527f4d6f636b507269636550726f76696465724d6f433a20707269636520636f756c604482015269064206e6f7420626520360b41b606482015260840161012f565b600080549082905560408051828152602081018490527f0f044c0280bacc38accfa21abc3ff4078e3acc7d7a14569f5db61f36870df047910160405180910390a15050565b6000602082840312156101ef57600080fd5b503591905056fea2646970667358221220f7515fbb2e55846cd982cf3d3ec4650f7c5c8cad8c3466ce1148d1d7ab30910064736f6c63430008060033", - "devdoc": { - "kind": "dev", - "methods": { - "setPrice(uint256)": { - "params": { - "price": "uint of price provider" - } - } - }, - "title": "A mock price provider of Money on Chain (MoC)", - "version": 1 - }, - "userdoc": { - "events": { - "MockPriceProviderMoCUpdated(uint256,uint256)": { - "notice": "Event rbtcPrice updated" - } - }, - "kind": "user", - "methods": { - "guardian()": { - "notice": "Address of the guardian" - }, - "setPrice(uint256)": { - "notice": "Set the rbtcPrice price provider" - } - }, - "notice": "You can use this contract for only simulation", - "version": 1 - }, - "storageLayout": { - "storage": [ - { - "astId": 41911, - "contract": "contracts/mocks/MockPriceProviderMoC.sol:MockPriceProviderMoC", - "label": "rbtcPrice", - "offset": 0, - "slot": "0", - "type": "t_bytes32" - }, - { - "astId": 41914, - "contract": "contracts/mocks/MockPriceProviderMoC.sol:MockPriceProviderMoC", - "label": "has", - "offset": 0, - "slot": "1", - "type": "t_bool" - }, - { - "astId": 41917, - "contract": "contracts/mocks/MockPriceProviderMoC.sol:MockPriceProviderMoC", - "label": "guardian", - "offset": 1, - "slot": "1", - "type": "t_address" - } - ], - "types": { - "t_address": { - "encoding": "inplace", - "label": "address", - "numberOfBytes": "20" - }, - "t_bool": { - "encoding": "inplace", - "label": "bool", - "numberOfBytes": "1" - }, - "t_bytes32": { - "encoding": "inplace", - "label": "bytes32", - "numberOfBytes": "32" - } - } - } -} \ No newline at end of file diff --git a/deployments/localhost/MultiSigWallet.json b/deployments/localhost/MultiSigWallet.json deleted file mode 100644 index fcf4b9a..0000000 --- a/deployments/localhost/MultiSigWallet.json +++ /dev/null @@ -1,847 +0,0 @@ -{ - "address": "0x09635F643e140090A9A8Dcd712eD6285858ceBef", - "abi": [ - { - "inputs": [ - { - "internalType": "address[]", - "name": "_owners", - "type": "address[]" - }, - { - "internalType": "uint256", - "name": "_required", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "constructor" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "sender", - "type": "address" - }, - { - "indexed": true, - "internalType": "uint256", - "name": "transactionId", - "type": "uint256" - } - ], - "name": "Confirmation", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "sender", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "Deposit", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "uint256", - "name": "transactionId", - "type": "uint256" - } - ], - "name": "Execution", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "uint256", - "name": "transactionId", - "type": "uint256" - } - ], - "name": "ExecutionFailure", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - } - ], - "name": "OwnerAddition", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - } - ], - "name": "OwnerRemoval", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "required", - "type": "uint256" - } - ], - "name": "RequirementChange", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "sender", - "type": "address" - }, - { - "indexed": true, - "internalType": "uint256", - "name": "transactionId", - "type": "uint256" - } - ], - "name": "Revocation", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "uint256", - "name": "transactionId", - "type": "uint256" - } - ], - "name": "Submission", - "type": "event" - }, - { - "stateMutability": "payable", - "type": "fallback" - }, - { - "inputs": [], - "name": "MAX_OWNER_COUNT", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "owner", - "type": "address" - } - ], - "name": "addOwner", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_required", - "type": "uint256" - } - ], - "name": "changeRequirement", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "transactionId", - "type": "uint256" - } - ], - "name": "confirmTransaction", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - }, - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "name": "confirmations", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "transactionId", - "type": "uint256" - } - ], - "name": "executeTransaction", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "transactionId", - "type": "uint256" - } - ], - "name": "getConfirmationCount", - "outputs": [ - { - "internalType": "uint256", - "name": "count", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "transactionId", - "type": "uint256" - } - ], - "name": "getConfirmations", - "outputs": [ - { - "internalType": "address[]", - "name": "_confirmations", - "type": "address[]" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "getOwners", - "outputs": [ - { - "internalType": "address[]", - "name": "", - "type": "address[]" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bool", - "name": "pending", - "type": "bool" - }, - { - "internalType": "bool", - "name": "executed", - "type": "bool" - } - ], - "name": "getTransactionCount", - "outputs": [ - { - "internalType": "uint256", - "name": "count", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "from", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "to", - "type": "uint256" - }, - { - "internalType": "bool", - "name": "pending", - "type": "bool" - }, - { - "internalType": "bool", - "name": "executed", - "type": "bool" - } - ], - "name": "getTransactionIds", - "outputs": [ - { - "internalType": "uint256[]", - "name": "_transactionIds", - "type": "uint256[]" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "transactionId", - "type": "uint256" - } - ], - "name": "isConfirmed", - "outputs": [ - { - "internalType": "bool", - "name": "result", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "name": "isOwner", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "name": "owners", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "owner", - "type": "address" - } - ], - "name": "removeOwner", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "newOwner", - "type": "address" - } - ], - "name": "replaceOwner", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "required", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "transactionId", - "type": "uint256" - } - ], - "name": "revokeConfirmation", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "destination", - "type": "address" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "data", - "type": "bytes" - } - ], - "name": "submitTransaction", - "outputs": [ - { - "internalType": "uint256", - "name": "transactionId", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "transactionCount", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "name": "transactions", - "outputs": [ - { - "internalType": "address", - "name": "destination", - "type": "address" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "data", - "type": "bytes" - }, - { - "internalType": "bool", - "name": "executed", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "stateMutability": "payable", - "type": "receive" - } - ], - "transactionHash": "0x4d7f5b610cc4bb073bb5d2d8bc57f4f401c60f77c8d909573f2d0ba3e56b3075", - "receipt": { - "to": null, - "from": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", - "contractAddress": "0x09635F643e140090A9A8Dcd712eD6285858ceBef", - "transactionIndex": 0, - "gasUsed": "1785146", - "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "blockHash": "0xfe44ea502149c31528f74a8ec5317bcd8a779adf51d04b0c1cc10db14bd9f3e8", - "transactionHash": "0x4d7f5b610cc4bb073bb5d2d8bc57f4f401c60f77c8d909573f2d0ba3e56b3075", - "logs": [], - "blockNumber": 28, - "cumulativeGasUsed": "1785146", - "status": 1, - "byzantium": true - }, - "args": [ - [ - "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" - ], - 1 - ], - "solcInputHash": "eec293f42f2aab5bd7ef36a794d2c589", - "metadata": "{\"compiler\":{\"version\":\"0.8.6+commit.11564f7e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"_owners\",\"type\":\"address[]\"},{\"internalType\":\"uint256\",\"name\":\"_required\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"transactionId\",\"type\":\"uint256\"}],\"name\":\"Confirmation\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"Deposit\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"transactionId\",\"type\":\"uint256\"}],\"name\":\"Execution\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"transactionId\",\"type\":\"uint256\"}],\"name\":\"ExecutionFailure\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"OwnerAddition\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"OwnerRemoval\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"required\",\"type\":\"uint256\"}],\"name\":\"RequirementChange\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"transactionId\",\"type\":\"uint256\"}],\"name\":\"Revocation\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"transactionId\",\"type\":\"uint256\"}],\"name\":\"Submission\",\"type\":\"event\"},{\"stateMutability\":\"payable\",\"type\":\"fallback\"},{\"inputs\":[],\"name\":\"MAX_OWNER_COUNT\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"addOwner\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_required\",\"type\":\"uint256\"}],\"name\":\"changeRequirement\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"transactionId\",\"type\":\"uint256\"}],\"name\":\"confirmTransaction\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"confirmations\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"transactionId\",\"type\":\"uint256\"}],\"name\":\"executeTransaction\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"transactionId\",\"type\":\"uint256\"}],\"name\":\"getConfirmationCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"count\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"transactionId\",\"type\":\"uint256\"}],\"name\":\"getConfirmations\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"_confirmations\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getOwners\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"pending\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"executed\",\"type\":\"bool\"}],\"name\":\"getTransactionCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"count\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"from\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"to\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"pending\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"executed\",\"type\":\"bool\"}],\"name\":\"getTransactionIds\",\"outputs\":[{\"internalType\":\"uint256[]\",\"name\":\"_transactionIds\",\"type\":\"uint256[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"transactionId\",\"type\":\"uint256\"}],\"name\":\"isConfirmed\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"result\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"isOwner\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"owners\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"removeOwner\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"replaceOwner\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"required\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"transactionId\",\"type\":\"uint256\"}],\"name\":\"revokeConfirmation\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"destination\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"submitTransaction\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"transactionId\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"transactionCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"transactions\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"destination\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"internalType\":\"bool\",\"name\":\"executed\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}],\"devdoc\":{\"author\":\"Stefan George - \",\"kind\":\"dev\",\"methods\":{\"addOwner(address)\":{\"details\":\"Allows to add a new owner. Transaction has to be sent by wallet.\",\"params\":{\"owner\":\"Address of new owner.\"}},\"changeRequirement(uint256)\":{\"details\":\"Allows to change the number of required confirmations. Transaction has to be sent by wallet.\",\"params\":{\"_required\":\"Number of required confirmations.\"}},\"confirmTransaction(uint256)\":{\"details\":\"Allows an owner to confirm a transaction.\",\"params\":{\"transactionId\":\"Transaction ID.\"}},\"constructor\":{\"details\":\"Contract constructor sets initial owners and required number of confirmations.\",\"params\":{\"_owners\":\"List of initial owners.\",\"_required\":\"Number of required confirmations.\"}},\"executeTransaction(uint256)\":{\"details\":\"Allows anyone to execute a confirmed transaction.\",\"params\":{\"transactionId\":\"Transaction ID.\"}},\"getConfirmationCount(uint256)\":{\"details\":\"Returns number of confirmations of a transaction.\",\"params\":{\"transactionId\":\"Transaction ID.\"},\"returns\":{\"count\":\"Number of confirmations.\"}},\"getConfirmations(uint256)\":{\"details\":\"Returns array with owner addresses, which confirmed transaction.\",\"params\":{\"transactionId\":\"Transaction ID.\"},\"returns\":{\"_confirmations\":\"Returns array of owner addresses.\"}},\"getOwners()\":{\"details\":\"Returns list of owners.\",\"returns\":{\"_0\":\"List of owner addresses.\"}},\"getTransactionCount(bool,bool)\":{\"details\":\"Returns total number of transactions after filers are applied.\",\"params\":{\"executed\":\"Include executed transactions.\",\"pending\":\"Include pending transactions.\"},\"returns\":{\"count\":\"Total number of transactions after filters are applied.\"}},\"getTransactionIds(uint256,uint256,bool,bool)\":{\"details\":\"Returns list of transaction IDs in defined range.\",\"params\":{\"executed\":\"Include executed transactions.\",\"from\":\"Index start position of transaction array.\",\"pending\":\"Include pending transactions.\",\"to\":\"Index end position of transaction array.\"},\"returns\":{\"_transactionIds\":\"Returns array of transaction IDs.\"}},\"isConfirmed(uint256)\":{\"details\":\"Returns the confirmation status of a transaction.\",\"params\":{\"transactionId\":\"Transaction ID.\"},\"returns\":{\"result\":\"Confirmation status.\"}},\"removeOwner(address)\":{\"details\":\"Allows to remove an owner. Transaction has to be sent by wallet.\",\"params\":{\"owner\":\"Address of owner.\"}},\"replaceOwner(address,address)\":{\"details\":\"Allows to replace an owner with a new owner. Transaction has to be sent by wallet.\",\"params\":{\"newOwner\":\"Address of new owner.\",\"owner\":\"Address of owner to be replaced.\"}},\"revokeConfirmation(uint256)\":{\"details\":\"Allows an owner to revoke a confirmation for a transaction.\",\"params\":{\"transactionId\":\"Transaction ID.\"}},\"submitTransaction(address,uint256,bytes)\":{\"details\":\"Allows an owner to submit and confirm a transaction.\",\"params\":{\"data\":\"Transaction data payload.\",\"destination\":\"Transaction target address.\",\"value\":\"Transaction ether value.\"},\"returns\":{\"transactionId\":\"Returns transaction ID.\"}}},\"title\":\"Multisignature wallet - Allows multiple parties to agree on transactions before execution.\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/MultiSigWallet.sol\":\"MultiSigWallet\"},\"evmVersion\":\"berlin\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"contracts/MultiSigWallet.sol\":{\"content\":\"// SPDX-License-Identifier: UNLICENSED\\npragma solidity 0.8.6;\\n\\n/// @title Multisignature wallet - Allows multiple parties to agree on transactions before execution.\\n/// @author Stefan George - \\ncontract MultiSigWallet {\\n /*\\n * Events\\n */\\n event Confirmation(address indexed sender, uint256 indexed transactionId);\\n event Revocation(address indexed sender, uint256 indexed transactionId);\\n event Submission(uint256 indexed transactionId);\\n event Execution(uint256 indexed transactionId);\\n event ExecutionFailure(uint256 indexed transactionId);\\n event Deposit(address indexed sender, uint256 value);\\n event OwnerAddition(address indexed owner);\\n event OwnerRemoval(address indexed owner);\\n event RequirementChange(uint256 required);\\n\\n /*\\n * views\\n */\\n uint256 public constant MAX_OWNER_COUNT = 50;\\n\\n /*\\n * Storage\\n */\\n mapping(uint256 => Transaction) public transactions;\\n mapping(uint256 => mapping(address => bool)) public confirmations;\\n mapping(address => bool) public isOwner;\\n address[] public owners;\\n uint256 public required;\\n uint256 public transactionCount;\\n\\n struct Transaction {\\n address destination;\\n uint256 value;\\n bytes data;\\n bool executed;\\n }\\n\\n /*\\n * Modifiers\\n */\\n modifier onlyWallet() {\\n require(msg.sender == address(this), \\\"Only wallet allowed\\\");\\n _;\\n }\\n\\n modifier ownerDoesNotExist(address owner) {\\n require(!isOwner[owner], \\\"The owner already exists\\\");\\n _;\\n }\\n\\n modifier ownerExists(address owner) {\\n require(isOwner[owner], \\\"The owner does not exist\\\");\\n _;\\n }\\n\\n modifier transactionExists(uint256 transactionId) {\\n require(\\n transactions[transactionId].destination != address(0),\\n \\\"Transaction does not exist\\\"\\n );\\n _;\\n }\\n\\n modifier confirmed(uint256 transactionId, address owner) {\\n require(\\n confirmations[transactionId][owner],\\n \\\"Transaction is not confirmed by owner\\\"\\n );\\n _;\\n }\\n\\n modifier notConfirmed(uint256 transactionId, address owner) {\\n require(\\n !confirmations[transactionId][owner],\\n \\\"Transaction is already confirmed by owner\\\"\\n );\\n _;\\n }\\n\\n modifier notExecuted(uint256 transactionId) {\\n require(\\n !transactions[transactionId].executed,\\n \\\"Transaction was already executed\\\"\\n );\\n _;\\n }\\n\\n modifier notNull(address _address) {\\n require(_address != address(0), \\\"Address cannot be empty\\\");\\n _;\\n }\\n\\n modifier validRequirement(uint256 ownerCount, uint256 _required) {\\n // solium-disable-next-line max-len\\n require(\\n ownerCount <= MAX_OWNER_COUNT &&\\n _required <= ownerCount &&\\n _required != 0 &&\\n ownerCount != 0,\\n \\\"Required value is invalid for the current owners count\\\"\\n );\\n _;\\n }\\n\\n /// @dev Fallback function allows to deposit ether.\\n fallback() external payable {\\n if (msg.value > 0) emit Deposit(msg.sender, msg.value);\\n }\\n\\n receive() external payable {\\n if (msg.value > 0) emit Deposit(msg.sender, msg.value);\\n }\\n\\n /*\\n * Public functions\\n */\\n /// @dev Contract constructor sets initial owners and required number of confirmations.\\n /// @param _owners List of initial owners.\\n /// @param _required Number of required confirmations.\\n constructor(address[] memory _owners, uint256 _required)\\n validRequirement(_owners.length, _required)\\n {\\n for (uint256 i = 0; i < _owners.length; i++) {\\n require(\\n !isOwner[_owners[i]] && _owners[i] != address(0),\\n \\\"Owners addresses are invalid\\\"\\n );\\n isOwner[_owners[i]] = true;\\n }\\n owners = _owners;\\n required = _required;\\n }\\n\\n /// @dev Allows to add a new owner. Transaction has to be sent by wallet.\\n /// @param owner Address of new owner.\\n function addOwner(address owner)\\n public\\n onlyWallet\\n ownerDoesNotExist(owner)\\n notNull(owner)\\n validRequirement(owners.length + 1, required)\\n {\\n isOwner[owner] = true;\\n owners.push(owner);\\n emit OwnerAddition(owner);\\n }\\n\\n /// @dev Allows to remove an owner. Transaction has to be sent by wallet.\\n /// @param owner Address of owner.\\n function removeOwner(address owner) public onlyWallet ownerExists(owner) {\\n isOwner[owner] = false;\\n address[] memory oldOwners = owners;\\n owners = new address[](0);\\n for (uint256 i = 0; i < oldOwners.length; i++) {\\n if (oldOwners[i] == owner) continue;\\n owners.push(owners[i]);\\n }\\n if (required > owners.length) changeRequirement(owners.length);\\n emit OwnerRemoval(owner);\\n }\\n\\n /// @dev Allows to replace an owner with a new owner. Transaction has to be sent by wallet.\\n /// @param owner Address of owner to be replaced.\\n /// @param newOwner Address of new owner.\\n function replaceOwner(address owner, address newOwner)\\n public\\n onlyWallet\\n ownerExists(owner)\\n ownerDoesNotExist(newOwner)\\n {\\n for (uint256 i = 0; i < owners.length; i++)\\n if (owners[i] == owner) {\\n owners[i] = newOwner;\\n break;\\n }\\n isOwner[owner] = false;\\n isOwner[newOwner] = true;\\n emit OwnerRemoval(owner);\\n emit OwnerAddition(newOwner);\\n }\\n\\n /// @dev Allows to change the number of required confirmations. Transaction has to be sent by wallet.\\n /// @param _required Number of required confirmations.\\n function changeRequirement(uint256 _required)\\n public\\n onlyWallet\\n validRequirement(owners.length, _required)\\n {\\n required = _required;\\n emit RequirementChange(_required);\\n }\\n\\n /// @dev Allows an owner to submit and confirm a transaction.\\n /// @param destination Transaction target address.\\n /// @param value Transaction ether value.\\n /// @param data Transaction data payload.\\n /// @return transactionId Returns transaction ID.\\n function submitTransaction(\\n address destination,\\n uint256 value,\\n bytes memory data\\n ) public returns (uint256 transactionId) {\\n transactionId = addTransaction(destination, value, data);\\n confirmTransaction(transactionId);\\n }\\n\\n /// @dev Allows an owner to confirm a transaction.\\n /// @param transactionId Transaction ID.\\n function confirmTransaction(uint256 transactionId)\\n public\\n ownerExists(msg.sender)\\n transactionExists(transactionId)\\n notConfirmed(transactionId, msg.sender)\\n {\\n confirmations[transactionId][msg.sender] = true;\\n emit Confirmation(msg.sender, transactionId);\\n executeTransaction(transactionId);\\n }\\n\\n /// @dev Allows an owner to revoke a confirmation for a transaction.\\n /// @param transactionId Transaction ID.\\n function revokeConfirmation(uint256 transactionId)\\n public\\n ownerExists(msg.sender)\\n confirmed(transactionId, msg.sender)\\n notExecuted(transactionId)\\n {\\n confirmations[transactionId][msg.sender] = false;\\n emit Revocation(msg.sender, transactionId);\\n }\\n\\n /// @dev Allows anyone to execute a confirmed transaction.\\n /// @param transactionId Transaction ID.\\n function executeTransaction(uint256 transactionId)\\n public\\n ownerExists(msg.sender)\\n confirmed(transactionId, msg.sender)\\n notExecuted(transactionId)\\n {\\n if (isConfirmed(transactionId)) {\\n Transaction storage txn = transactions[transactionId];\\n txn.executed = true;\\n if (\\n external_call(\\n txn.destination,\\n txn.value,\\n txn.data.length,\\n txn.data\\n )\\n ) emit Execution(transactionId);\\n else {\\n emit ExecutionFailure(transactionId);\\n txn.executed = false;\\n }\\n }\\n }\\n\\n // call has been separated into its own function in order to take advantage\\n // of the Solidity's code generator to produce a loop that copies tx.data into memory.\\n function external_call(\\n address destination,\\n uint256 value,\\n uint256 dataLength,\\n bytes memory data\\n ) internal returns (bool) {\\n bool result;\\n // solium-disable-next-line security/no-inline-assembly\\n assembly {\\n let x := mload(0x40) // \\\"Allocate\\\" memory for output (0x40 is where \\\"free memory\\\" pointer is stored by convention)\\n let d := add(data, 32) // First 32 bytes are the padded length of data, so exclude that\\n result := call(\\n sub(gas(), 34710), // 34710 is the value that solidity is currently emitting\\n // It includes callGas (700) + callVeryLow (3, to pay for SUB) + callValueTransferGas (9000) +\\n // callNewAccountGas (25000, in case the destination address does not exist and needs creating)\\n destination,\\n value,\\n d,\\n dataLength, // Size of the input (in bytes) - this is what fixes the padding problem\\n x,\\n 0 // Output is ignored, therefore the output size is zero\\n )\\n }\\n return result;\\n }\\n\\n /// @dev Returns the confirmation status of a transaction.\\n /// @param transactionId Transaction ID.\\n /// @return result Confirmation status.\\n function isConfirmed(uint256 transactionId) public view returns (bool result) {\\n uint256 count = 0;\\n for (uint256 i = 0; i < owners.length; i++) {\\n if (confirmations[transactionId][owners[i]]) count += 1;\\n if (count == required) return true;\\n }\\n }\\n\\n /*\\n * Internal functions\\n */\\n /// @dev Adds a new transaction to the transaction mapping, if transaction does not exist yet.\\n /// @param destination Transaction target address.\\n /// @param value Transaction ether value.\\n /// @param data Transaction data payload.\\n /// @return transactionId Returns transaction ID.\\n function addTransaction(\\n address destination,\\n uint256 value,\\n bytes memory data\\n ) internal notNull(destination) returns (uint256 transactionId) {\\n transactionId = transactionCount;\\n transactions[transactionId] = Transaction({\\n destination: destination,\\n value: value,\\n data: data,\\n executed: false\\n });\\n transactionCount += 1;\\n emit Submission(transactionId);\\n }\\n\\n /*\\n * Web3 call functions\\n */\\n /// @dev Returns number of confirmations of a transaction.\\n /// @param transactionId Transaction ID.\\n /// @return count Number of confirmations.\\n function getConfirmationCount(uint256 transactionId)\\n public\\n view\\n returns (uint256 count)\\n {\\n for (uint256 i = 0; i < owners.length; i++) {\\n if (confirmations[transactionId][owners[i]]) {\\n count += 1;\\n }\\n }\\n }\\n\\n /// @dev Returns total number of transactions after filers are applied.\\n /// @param pending Include pending transactions.\\n /// @param executed Include executed transactions.\\n /// @return count Total number of transactions after filters are applied.\\n function getTransactionCount(bool pending, bool executed)\\n public\\n view\\n returns (uint256 count)\\n {\\n for (uint256 i = 0; i < transactionCount; i++) {\\n if (\\n (pending && !transactions[i].executed) ||\\n (executed && transactions[i].executed)\\n ) {\\n count += 1;\\n }\\n }\\n }\\n\\n /// @dev Returns list of owners.\\n /// @return List of owner addresses.\\n function getOwners() public view returns (address[] memory) {\\n return owners;\\n }\\n\\n /// @dev Returns array with owner addresses, which confirmed transaction.\\n /// @param transactionId Transaction ID.\\n /// @return _confirmations Returns array of owner addresses.\\n function getConfirmations(uint256 transactionId)\\n public\\n view\\n returns (address[] memory _confirmations)\\n {\\n address[] memory confirmationsTemp = new address[](owners.length);\\n uint256 count = 0;\\n uint256 i;\\n for (i = 0; i < owners.length; i++)\\n if (confirmations[transactionId][owners[i]]) {\\n confirmationsTemp[count] = owners[i];\\n count += 1;\\n }\\n _confirmations = new address[](count);\\n for (i = 0; i < count; i++) _confirmations[i] = confirmationsTemp[i];\\n }\\n\\n /// @dev Returns list of transaction IDs in defined range.\\n /// @param from Index start position of transaction array.\\n /// @param to Index end position of transaction array.\\n /// @param pending Include pending transactions.\\n /// @param executed Include executed transactions.\\n /// @return _transactionIds Returns array of transaction IDs.\\n function getTransactionIds(\\n uint256 from,\\n uint256 to,\\n bool pending,\\n bool executed\\n ) public view returns (uint256[] memory _transactionIds) {\\n uint256[] memory transactionIdsTemp = new uint256[](transactionCount);\\n uint256 count = 0;\\n uint256 i;\\n for (i = 0; i < transactionCount; i++)\\n if (\\n (pending && !transactions[i].executed) ||\\n (executed && transactions[i].executed)\\n ) {\\n transactionIdsTemp[count] = i;\\n count += 1;\\n }\\n _transactionIds = new uint256[](to - from);\\n for (i = from; i < to; i++)\\n _transactionIds[i - from] = transactionIdsTemp[i];\\n }\\n}\\n\",\"keccak256\":\"0x0a7eb6c2c5e72c65685ccd1c5157b67fb26aaa21cf6b427f77334759c8d06402\",\"license\":\"UNLICENSED\"}},\"version\":1}", - "bytecode": "0x60806040523480156200001157600080fd5b506040516200219b3803806200219b8339810160408190526200003491620002d4565b81518160328211158015620000495750818111155b80156200005557508015155b80156200006157508115155b620000d95760405162461bcd60e51b815260206004820152603660248201527f52657175697265642076616c756520697320696e76616c696420666f7220746860448201527f652063757272656e74206f776e65727320636f756e740000000000000000000060648201526084015b60405180910390fd5b60005b8451811015620002135760026000868381518110620000ff57620000ff620003df565b6020908102919091018101516001600160a01b031682528101919091526040016000205460ff1615801562000163575060006001600160a01b03168582815181106200014f576200014f620003df565b60200260200101516001600160a01b031614155b620001b15760405162461bcd60e51b815260206004820152601c60248201527f4f776e657273206164647265737365732061726520696e76616c6964000000006044820152606401620000d0565b600160026000878481518110620001cc57620001cc620003df565b6020908102919091018101516001600160a01b03168252810191909152604001600020805460ff1916911515919091179055806200020a81620003b5565b915050620000dc565b5083516200022990600390602087019062000236565b505050600455506200040b565b8280548282559060005260206000209081019282156200028e579160200282015b828111156200028e57825182546001600160a01b0319166001600160a01b0390911617825560209092019160019091019062000257565b506200029c929150620002a0565b5090565b5b808211156200029c5760008155600101620002a1565b80516001600160a01b0381168114620002cf57600080fd5b919050565b60008060408385031215620002e857600080fd5b82516001600160401b03808211156200030057600080fd5b818501915085601f8301126200031557600080fd5b81516020828211156200032c576200032c620003f5565b8160051b604051601f19603f83011681018181108682111715620003545762000354620003f5565b604052838152828101945085830182870184018b10156200037457600080fd5b600096505b84871015620003a2576200038d81620002b7565b86526001969096019594830194830162000379565b5097909101519698969750505050505050565b6000600019821415620003d857634e487b7160e01b600052601160045260246000fd5b5060010190565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052604160045260246000fd5b611d80806200041b6000396000f3fe60806040526004361061012e5760003560e01c8063a0e67e2b116100ab578063c01a8c841161006f578063c01a8c8414610405578063c642747414610425578063d74f8edd14610445578063dc8452cd1461045a578063e20056e614610470578063ee22610b1461049057610172565b8063a0e67e2b14610360578063a8abe69a14610382578063b5dc40c3146103af578063b77bf600146103cf578063ba51a6df146103e557610172565b806354741525116100f257806354741525146102a25780637065cb48146102d0578063784547a7146102f05780638b51d13f146103105780639ace38c21461033057610172565b8063025e7c27146101aa578063173825d9146101e757806320ea8d86146102075780632f54bf6e146102275780633411c81c1461026757610172565b366101725734156101705760405134815233907fe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c906020015b60405180910390a25b005b34156101705760405134815233907fe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c90602001610167565b3480156101b657600080fd5b506101ca6101c5366004611a07565b6104b0565b6040516001600160a01b0390911681526020015b60405180910390f35b3480156101f357600080fd5b506101706102023660046118c4565b6104da565b34801561021357600080fd5b50610170610222366004611a07565b6106f8565b34801561023357600080fd5b506102576102423660046118c4565b60026020526000908152604090205460ff1681565b60405190151581526020016101de565b34801561027357600080fd5b50610257610282366004611a20565b600160209081526000928352604080842090915290825290205460ff1681565b3480156102ae57600080fd5b506102c26102bd3660046119dd565b610817565b6040519081526020016101de565b3480156102dc57600080fd5b506101706102eb3660046118c4565b610894565b3480156102fc57600080fd5b5061025761030b366004611a07565b610a4e565b34801561031c57600080fd5b506102c261032b366004611a07565b610aea565b34801561033c57600080fd5b5061035061034b366004611a07565b610b70565b6040516101de9493929190611a89565b34801561036c57600080fd5b50610375610c2e565b6040516101de9190611b05565b34801561038e57600080fd5b506103a261039d366004611a43565b610c90565b6040516101de9190611b52565b3480156103bb57600080fd5b506103756103ca366004611a07565b610e28565b3480156103db57600080fd5b506102c260055481565b3480156103f157600080fd5b50610170610400366004611a07565b611000565b34801561041157600080fd5b50610170610420366004611a07565b6110a3565b34801561043157600080fd5b506102c2610440366004611912565b611215565b34801561045157600080fd5b506102c2603281565b34801561046657600080fd5b506102c260045481565b34801561047c57600080fd5b5061017061048b3660046118df565b611234565b34801561049c57600080fd5b506101706104ab366004611a07565b61142b565b600381815481106104c057600080fd5b6000918252602090912001546001600160a01b0316905081565b3330146105025760405162461bcd60e51b81526004016104f990611c25565b60405180910390fd5b6001600160a01b038116600090815260026020526040902054819060ff1661053c5760405162461bcd60e51b81526004016104f990611c52565b6001600160a01b0382166000908152600260209081526040808320805460ff191690556003805482518185028101850190935280835291929091908301828280156105b057602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311610592575b50939450600093506105c192505050565b6040519080825280602002602001820160405280156105ea578160200160208202803683370190505b5080516105ff916003916020909101906117aa565b5060005b81518110156106a657836001600160a01b031682828151811061062857610628611d1e565b60200260200101516001600160a01b0316141561064457610694565b600380828154811061065857610658611d1e565b60009182526020808320909101548354600181018555938352912090910180546001600160a01b0319166001600160a01b039092169190911790555b8061069e81611ced565b915050610603565b5060035460045411156106bf576003546106bf90611000565b6040516001600160a01b038416907f8001553a916ef2f495d26a907cc54d96ed840d7bda71e73194bf5a9df7a76b9090600090a2505050565b3360008181526002602052604090205460ff166107275760405162461bcd60e51b81526004016104f990611c52565b60008281526001602090815260408083203380855292529091205483919060ff166107645760405162461bcd60e51b81526004016104f990611be0565b600084815260208190526040902060030154849060ff16156107c85760405162461bcd60e51b815260206004820181905260248201527f5472616e73616374696f6e2077617320616c726561647920657865637574656460448201526064016104f9565b6000858152600160209081526040808320338085529252808320805460ff191690555187927ff6a317157440607f36269043eb55f1287a5a19ba2216afeab88cd46cbcfb88e991a35050505050565b6000805b60055481101561088d57838015610844575060008181526020819052604090206003015460ff16155b806108685750828015610868575060008181526020819052604090206003015460ff165b1561087b57610878600183611c89565b91505b8061088581611ced565b91505061081b565b5092915050565b3330146108b35760405162461bcd60e51b81526004016104f990611c25565b6001600160a01b038116600090815260026020526040902054819060ff16156109195760405162461bcd60e51b8152602060048201526018602482015277546865206f776e657220616c72656164792065786973747360401b60448201526064016104f9565b816001600160a01b03811661096a5760405162461bcd60e51b8152602060048201526017602482015276416464726573732063616e6e6f7420626520656d70747960481b60448201526064016104f9565b600354610978906001611c89565b6004546032821115801561098c5750818111155b801561099757508015155b80156109a257508115155b6109be5760405162461bcd60e51b81526004016104f990611b8a565b6001600160a01b038516600081815260026020526040808220805460ff1916600190811790915560038054918201815583527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b0180546001600160a01b03191684179055517ff39e6e1eb0edcf53c221607b54b00cd28f3196fed0a24994dc308b8f611b682d9190a25050505050565b600080805b600354811015610ae35760008481526001602052604081206003805491929184908110610a8257610a82611d1e565b60009182526020808320909101546001600160a01b0316835282019290925260400190205460ff1615610abd57610aba600183611c89565b91505b600454821415610ad1575060019392505050565b80610adb81611ced565b915050610a53565b5050919050565b6000805b600354811015610b6a5760008381526001602052604081206003805491929184908110610b1d57610b1d611d1e565b60009182526020808320909101546001600160a01b0316835282019290925260400190205460ff1615610b5857610b55600183611c89565b91505b80610b6281611ced565b915050610aee565b50919050565b6000602081905290815260409020805460018201546002830180546001600160a01b03909316939192610ba290611cb8565b80601f0160208091040260200160405190810160405280929190818152602001828054610bce90611cb8565b8015610c1b5780601f10610bf057610100808354040283529160200191610c1b565b820191906000526020600020905b815481529060010190602001808311610bfe57829003601f168201915b5050506003909301549192505060ff1684565b60606003805480602002602001604051908101604052809291908181526020018280548015610c8657602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311610c68575b5050505050905090565b6060600060055467ffffffffffffffff811115610caf57610caf611d34565b604051908082528060200260200182016040528015610cd8578160200160208202803683370190505b5090506000805b600554811015610d6f57858015610d08575060008181526020819052604090206003015460ff16155b80610d2c5750848015610d2c575060008181526020819052604090206003015460ff165b15610d5d5780838381518110610d4457610d44611d1e565b6020908102919091010152610d5a600183611c89565b91505b80610d6781611ced565b915050610cdf565b610d798888611ca1565b67ffffffffffffffff811115610d9157610d91611d34565b604051908082528060200260200182016040528015610dba578160200160208202803683370190505b5093508790505b86811015610e1d57828181518110610ddb57610ddb611d1e565b6020026020010151848983610df09190611ca1565b81518110610e0057610e00611d1e565b602090810291909101015280610e1581611ced565b915050610dc1565b505050949350505050565b60035460609060009067ffffffffffffffff811115610e4957610e49611d34565b604051908082528060200260200182016040528015610e72578160200160208202803683370190505b5090506000805b600354811015610f505760008581526001602052604081206003805491929184908110610ea857610ea8611d1e565b60009182526020808320909101546001600160a01b0316835282019290925260400190205460ff1615610f3e5760038181548110610ee857610ee8611d1e565b9060005260206000200160009054906101000a90046001600160a01b0316838381518110610f1857610f18611d1e565b6001600160a01b0390921660209283029190910190910152610f3b600183611c89565b91505b80610f4881611ced565b915050610e79565b8167ffffffffffffffff811115610f6957610f69611d34565b604051908082528060200260200182016040528015610f92578160200160208202803683370190505b509350600090505b81811015610ff857828181518110610fb457610fb4611d1e565b6020026020010151848281518110610fce57610fce611d1e565b6001600160a01b039092166020928302919091019091015280610ff081611ced565b915050610f9a565b505050919050565b33301461101f5760405162461bcd60e51b81526004016104f990611c25565b60035481603282118015906110345750818111155b801561103f57508015155b801561104a57508115155b6110665760405162461bcd60e51b81526004016104f990611b8a565b60048390556040518381527fa3f1ee9126a074d9326c682f561767f710e927faa811f7a99829d49dc421797a9060200160405180910390a1505050565b3360008181526002602052604090205460ff166110d25760405162461bcd60e51b81526004016104f990611c52565b60008281526020819052604090205482906001600160a01b03166111385760405162461bcd60e51b815260206004820152601a60248201527f5472616e73616374696f6e20646f6573206e6f7420657869737400000000000060448201526064016104f9565b60008381526001602090815260408083203380855292529091205484919060ff16156111b85760405162461bcd60e51b815260206004820152602960248201527f5472616e73616374696f6e20697320616c726561647920636f6e6669726d656460448201526810313c9037bbb732b960b91b60648201526084016104f9565b6000858152600160208181526040808420338086529252808420805460ff1916909317909255905187927f4a504a94899432a9846e1aa406dceb1bcfd538bb839071d49d1e5e23f5be30ef91a361120e8561142b565b5050505050565b6000611222848484611657565b905061122d816110a3565b9392505050565b3330146112535760405162461bcd60e51b81526004016104f990611c25565b6001600160a01b038216600090815260026020526040902054829060ff1661128d5760405162461bcd60e51b81526004016104f990611c52565b6001600160a01b038216600090815260026020526040902054829060ff16156112f35760405162461bcd60e51b8152602060048201526018602482015277546865206f776e657220616c72656164792065786973747360401b60448201526064016104f9565b60005b60035481101561139157846001600160a01b03166003828154811061131d5761131d611d1e565b6000918252602090912001546001600160a01b0316141561137f57836003828154811061134c5761134c611d1e565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b03160217905550611391565b8061138981611ced565b9150506112f6565b506001600160a01b03808516600081815260026020526040808220805460ff1990811690915593871682528082208054909416600117909355915190917f8001553a916ef2f495d26a907cc54d96ed840d7bda71e73194bf5a9df7a76b9091a26040516001600160a01b038416907ff39e6e1eb0edcf53c221607b54b00cd28f3196fed0a24994dc308b8f611b682d90600090a250505050565b3360008181526002602052604090205460ff1661145a5760405162461bcd60e51b81526004016104f990611c52565b60008281526001602090815260408083203380855292529091205483919060ff166114975760405162461bcd60e51b81526004016104f990611be0565b600084815260208190526040902060030154849060ff16156114fb5760405162461bcd60e51b815260206004820181905260248201527f5472616e73616374696f6e2077617320616c726561647920657865637574656460448201526064016104f9565b61150485610a4e565b1561120e57600085815260208190526040902060038101805460ff191660019081179091558154908201546002830180546115e2936001600160a01b031692919061154e90611cb8565b905084600201805461155f90611cb8565b80601f016020809104026020016040519081016040528092919081815260200182805461158b90611cb8565b80156115d85780601f106115ad576101008083540402835291602001916115d8565b820191906000526020600020905b8154815290600101906020018083116115bb57829003601f168201915b5050505050611787565b156116175760405186907f33e13ecb54c3076d8e8bb8c2881800a4d972b792045ffae98fdf46df365fed7590600090a261164f565b60405186907f526441bb6c1aba3c9a4a6ca1d6545da9c2333c8c48343ef398eb858d72b7923690600090a260038101805460ff191690555b505050505050565b6000836001600160a01b0381166116aa5760405162461bcd60e51b8152602060048201526017602482015276416464726573732063616e6e6f7420626520656d70747960481b60448201526064016104f9565b600554604080516080810182526001600160a01b038881168252602080830189815283850189815260006060860181905287815280845295909520845181546001600160a01b0319169416939093178355516001830155925180519496509193909261171d92600285019291019061180f565b50606091909101516003909101805460ff1916911515919091179055600580546001919060009061174f908490611c89565b909155505060405182907fc0ba8fe4b176c1714197d43b9cc6bcf797a4a7461c5fe8d0ef6e184ae7601e5190600090a2509392505050565b6000806040516020840160008287838a8c6187965a03f198975050505050505050565b8280548282559060005260206000209081019282156117ff579160200282015b828111156117ff57825182546001600160a01b0319166001600160a01b039091161782556020909201916001909101906117ca565b5061180b929150611883565b5090565b82805461181b90611cb8565b90600052602060002090601f01602090048101928261183d57600085556117ff565b82601f1061185657805160ff19168380011785556117ff565b828001600101855582156117ff579182015b828111156117ff578251825591602001919060010190611868565b5b8082111561180b5760008155600101611884565b80356001600160a01b03811681146118af57600080fd5b919050565b803580151581146118af57600080fd5b6000602082840312156118d657600080fd5b61122d82611898565b600080604083850312156118f257600080fd5b6118fb83611898565b915061190960208401611898565b90509250929050565b60008060006060848603121561192757600080fd5b61193084611898565b925060208401359150604084013567ffffffffffffffff8082111561195457600080fd5b818601915086601f83011261196857600080fd5b81358181111561197a5761197a611d34565b604051601f8201601f19908116603f011681019083821181831017156119a2576119a2611d34565b816040528281528960208487010111156119bb57600080fd5b8260208601602083013760006020848301015280955050505050509250925092565b600080604083850312156119f057600080fd5b6119f9836118b4565b9150611909602084016118b4565b600060208284031215611a1957600080fd5b5035919050565b60008060408385031215611a3357600080fd5b8235915061190960208401611898565b60008060008060808587031215611a5957600080fd5b8435935060208501359250611a70604086016118b4565b9150611a7e606086016118b4565b905092959194509250565b60018060a01b038516815260006020858184015260806040840152845180608085015260005b81811015611acb5786810183015185820160a001528201611aaf565b81811115611add57600060a083870101525b50601f01601f1916830160a0019150611afc9050606083018415159052565b95945050505050565b6020808252825182820181905260009190848201906040850190845b81811015611b465783516001600160a01b031683529284019291840191600101611b21565b50909695505050505050565b6020808252825182820181905260009190848201906040850190845b81811015611b4657835183529284019291840191600101611b6e565b60208082526036908201527f52657175697265642076616c756520697320696e76616c696420666f72207468604082015275194818dd5c9c995b9d081bdddb995c9cc818dbdd5b9d60521b606082015260800190565b60208082526025908201527f5472616e73616374696f6e206973206e6f7420636f6e6669726d65642062792060408201526437bbb732b960d91b606082015260800190565b60208082526013908201527213db9b1e481dd85b1b195d08185b1b1bddd959606a1b604082015260600190565b60208082526018908201527f546865206f776e657220646f6573206e6f742065786973740000000000000000604082015260600190565b60008219821115611c9c57611c9c611d08565b500190565b600082821015611cb357611cb3611d08565b500390565b600181811c90821680611ccc57607f821691505b60208210811415610b6a57634e487b7160e01b600052602260045260246000fd5b6000600019821415611d0157611d01611d08565b5060010190565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052604160045260246000fdfea26469706673582212206218bf781dcbc620e8829bdebcbc6ce03bf4703a647141467643a6c8d5d3bc2364736f6c63430008060033", - "deployedBytecode": "0x60806040526004361061012e5760003560e01c8063a0e67e2b116100ab578063c01a8c841161006f578063c01a8c8414610405578063c642747414610425578063d74f8edd14610445578063dc8452cd1461045a578063e20056e614610470578063ee22610b1461049057610172565b8063a0e67e2b14610360578063a8abe69a14610382578063b5dc40c3146103af578063b77bf600146103cf578063ba51a6df146103e557610172565b806354741525116100f257806354741525146102a25780637065cb48146102d0578063784547a7146102f05780638b51d13f146103105780639ace38c21461033057610172565b8063025e7c27146101aa578063173825d9146101e757806320ea8d86146102075780632f54bf6e146102275780633411c81c1461026757610172565b366101725734156101705760405134815233907fe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c906020015b60405180910390a25b005b34156101705760405134815233907fe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c90602001610167565b3480156101b657600080fd5b506101ca6101c5366004611a07565b6104b0565b6040516001600160a01b0390911681526020015b60405180910390f35b3480156101f357600080fd5b506101706102023660046118c4565b6104da565b34801561021357600080fd5b50610170610222366004611a07565b6106f8565b34801561023357600080fd5b506102576102423660046118c4565b60026020526000908152604090205460ff1681565b60405190151581526020016101de565b34801561027357600080fd5b50610257610282366004611a20565b600160209081526000928352604080842090915290825290205460ff1681565b3480156102ae57600080fd5b506102c26102bd3660046119dd565b610817565b6040519081526020016101de565b3480156102dc57600080fd5b506101706102eb3660046118c4565b610894565b3480156102fc57600080fd5b5061025761030b366004611a07565b610a4e565b34801561031c57600080fd5b506102c261032b366004611a07565b610aea565b34801561033c57600080fd5b5061035061034b366004611a07565b610b70565b6040516101de9493929190611a89565b34801561036c57600080fd5b50610375610c2e565b6040516101de9190611b05565b34801561038e57600080fd5b506103a261039d366004611a43565b610c90565b6040516101de9190611b52565b3480156103bb57600080fd5b506103756103ca366004611a07565b610e28565b3480156103db57600080fd5b506102c260055481565b3480156103f157600080fd5b50610170610400366004611a07565b611000565b34801561041157600080fd5b50610170610420366004611a07565b6110a3565b34801561043157600080fd5b506102c2610440366004611912565b611215565b34801561045157600080fd5b506102c2603281565b34801561046657600080fd5b506102c260045481565b34801561047c57600080fd5b5061017061048b3660046118df565b611234565b34801561049c57600080fd5b506101706104ab366004611a07565b61142b565b600381815481106104c057600080fd5b6000918252602090912001546001600160a01b0316905081565b3330146105025760405162461bcd60e51b81526004016104f990611c25565b60405180910390fd5b6001600160a01b038116600090815260026020526040902054819060ff1661053c5760405162461bcd60e51b81526004016104f990611c52565b6001600160a01b0382166000908152600260209081526040808320805460ff191690556003805482518185028101850190935280835291929091908301828280156105b057602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311610592575b50939450600093506105c192505050565b6040519080825280602002602001820160405280156105ea578160200160208202803683370190505b5080516105ff916003916020909101906117aa565b5060005b81518110156106a657836001600160a01b031682828151811061062857610628611d1e565b60200260200101516001600160a01b0316141561064457610694565b600380828154811061065857610658611d1e565b60009182526020808320909101548354600181018555938352912090910180546001600160a01b0319166001600160a01b039092169190911790555b8061069e81611ced565b915050610603565b5060035460045411156106bf576003546106bf90611000565b6040516001600160a01b038416907f8001553a916ef2f495d26a907cc54d96ed840d7bda71e73194bf5a9df7a76b9090600090a2505050565b3360008181526002602052604090205460ff166107275760405162461bcd60e51b81526004016104f990611c52565b60008281526001602090815260408083203380855292529091205483919060ff166107645760405162461bcd60e51b81526004016104f990611be0565b600084815260208190526040902060030154849060ff16156107c85760405162461bcd60e51b815260206004820181905260248201527f5472616e73616374696f6e2077617320616c726561647920657865637574656460448201526064016104f9565b6000858152600160209081526040808320338085529252808320805460ff191690555187927ff6a317157440607f36269043eb55f1287a5a19ba2216afeab88cd46cbcfb88e991a35050505050565b6000805b60055481101561088d57838015610844575060008181526020819052604090206003015460ff16155b806108685750828015610868575060008181526020819052604090206003015460ff165b1561087b57610878600183611c89565b91505b8061088581611ced565b91505061081b565b5092915050565b3330146108b35760405162461bcd60e51b81526004016104f990611c25565b6001600160a01b038116600090815260026020526040902054819060ff16156109195760405162461bcd60e51b8152602060048201526018602482015277546865206f776e657220616c72656164792065786973747360401b60448201526064016104f9565b816001600160a01b03811661096a5760405162461bcd60e51b8152602060048201526017602482015276416464726573732063616e6e6f7420626520656d70747960481b60448201526064016104f9565b600354610978906001611c89565b6004546032821115801561098c5750818111155b801561099757508015155b80156109a257508115155b6109be5760405162461bcd60e51b81526004016104f990611b8a565b6001600160a01b038516600081815260026020526040808220805460ff1916600190811790915560038054918201815583527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b0180546001600160a01b03191684179055517ff39e6e1eb0edcf53c221607b54b00cd28f3196fed0a24994dc308b8f611b682d9190a25050505050565b600080805b600354811015610ae35760008481526001602052604081206003805491929184908110610a8257610a82611d1e565b60009182526020808320909101546001600160a01b0316835282019290925260400190205460ff1615610abd57610aba600183611c89565b91505b600454821415610ad1575060019392505050565b80610adb81611ced565b915050610a53565b5050919050565b6000805b600354811015610b6a5760008381526001602052604081206003805491929184908110610b1d57610b1d611d1e565b60009182526020808320909101546001600160a01b0316835282019290925260400190205460ff1615610b5857610b55600183611c89565b91505b80610b6281611ced565b915050610aee565b50919050565b6000602081905290815260409020805460018201546002830180546001600160a01b03909316939192610ba290611cb8565b80601f0160208091040260200160405190810160405280929190818152602001828054610bce90611cb8565b8015610c1b5780601f10610bf057610100808354040283529160200191610c1b565b820191906000526020600020905b815481529060010190602001808311610bfe57829003601f168201915b5050506003909301549192505060ff1684565b60606003805480602002602001604051908101604052809291908181526020018280548015610c8657602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311610c68575b5050505050905090565b6060600060055467ffffffffffffffff811115610caf57610caf611d34565b604051908082528060200260200182016040528015610cd8578160200160208202803683370190505b5090506000805b600554811015610d6f57858015610d08575060008181526020819052604090206003015460ff16155b80610d2c5750848015610d2c575060008181526020819052604090206003015460ff165b15610d5d5780838381518110610d4457610d44611d1e565b6020908102919091010152610d5a600183611c89565b91505b80610d6781611ced565b915050610cdf565b610d798888611ca1565b67ffffffffffffffff811115610d9157610d91611d34565b604051908082528060200260200182016040528015610dba578160200160208202803683370190505b5093508790505b86811015610e1d57828181518110610ddb57610ddb611d1e565b6020026020010151848983610df09190611ca1565b81518110610e0057610e00611d1e565b602090810291909101015280610e1581611ced565b915050610dc1565b505050949350505050565b60035460609060009067ffffffffffffffff811115610e4957610e49611d34565b604051908082528060200260200182016040528015610e72578160200160208202803683370190505b5090506000805b600354811015610f505760008581526001602052604081206003805491929184908110610ea857610ea8611d1e565b60009182526020808320909101546001600160a01b0316835282019290925260400190205460ff1615610f3e5760038181548110610ee857610ee8611d1e565b9060005260206000200160009054906101000a90046001600160a01b0316838381518110610f1857610f18611d1e565b6001600160a01b0390921660209283029190910190910152610f3b600183611c89565b91505b80610f4881611ced565b915050610e79565b8167ffffffffffffffff811115610f6957610f69611d34565b604051908082528060200260200182016040528015610f92578160200160208202803683370190505b509350600090505b81811015610ff857828181518110610fb457610fb4611d1e565b6020026020010151848281518110610fce57610fce611d1e565b6001600160a01b039092166020928302919091019091015280610ff081611ced565b915050610f9a565b505050919050565b33301461101f5760405162461bcd60e51b81526004016104f990611c25565b60035481603282118015906110345750818111155b801561103f57508015155b801561104a57508115155b6110665760405162461bcd60e51b81526004016104f990611b8a565b60048390556040518381527fa3f1ee9126a074d9326c682f561767f710e927faa811f7a99829d49dc421797a9060200160405180910390a1505050565b3360008181526002602052604090205460ff166110d25760405162461bcd60e51b81526004016104f990611c52565b60008281526020819052604090205482906001600160a01b03166111385760405162461bcd60e51b815260206004820152601a60248201527f5472616e73616374696f6e20646f6573206e6f7420657869737400000000000060448201526064016104f9565b60008381526001602090815260408083203380855292529091205484919060ff16156111b85760405162461bcd60e51b815260206004820152602960248201527f5472616e73616374696f6e20697320616c726561647920636f6e6669726d656460448201526810313c9037bbb732b960b91b60648201526084016104f9565b6000858152600160208181526040808420338086529252808420805460ff1916909317909255905187927f4a504a94899432a9846e1aa406dceb1bcfd538bb839071d49d1e5e23f5be30ef91a361120e8561142b565b5050505050565b6000611222848484611657565b905061122d816110a3565b9392505050565b3330146112535760405162461bcd60e51b81526004016104f990611c25565b6001600160a01b038216600090815260026020526040902054829060ff1661128d5760405162461bcd60e51b81526004016104f990611c52565b6001600160a01b038216600090815260026020526040902054829060ff16156112f35760405162461bcd60e51b8152602060048201526018602482015277546865206f776e657220616c72656164792065786973747360401b60448201526064016104f9565b60005b60035481101561139157846001600160a01b03166003828154811061131d5761131d611d1e565b6000918252602090912001546001600160a01b0316141561137f57836003828154811061134c5761134c611d1e565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b03160217905550611391565b8061138981611ced565b9150506112f6565b506001600160a01b03808516600081815260026020526040808220805460ff1990811690915593871682528082208054909416600117909355915190917f8001553a916ef2f495d26a907cc54d96ed840d7bda71e73194bf5a9df7a76b9091a26040516001600160a01b038416907ff39e6e1eb0edcf53c221607b54b00cd28f3196fed0a24994dc308b8f611b682d90600090a250505050565b3360008181526002602052604090205460ff1661145a5760405162461bcd60e51b81526004016104f990611c52565b60008281526001602090815260408083203380855292529091205483919060ff166114975760405162461bcd60e51b81526004016104f990611be0565b600084815260208190526040902060030154849060ff16156114fb5760405162461bcd60e51b815260206004820181905260248201527f5472616e73616374696f6e2077617320616c726561647920657865637574656460448201526064016104f9565b61150485610a4e565b1561120e57600085815260208190526040902060038101805460ff191660019081179091558154908201546002830180546115e2936001600160a01b031692919061154e90611cb8565b905084600201805461155f90611cb8565b80601f016020809104026020016040519081016040528092919081815260200182805461158b90611cb8565b80156115d85780601f106115ad576101008083540402835291602001916115d8565b820191906000526020600020905b8154815290600101906020018083116115bb57829003601f168201915b5050505050611787565b156116175760405186907f33e13ecb54c3076d8e8bb8c2881800a4d972b792045ffae98fdf46df365fed7590600090a261164f565b60405186907f526441bb6c1aba3c9a4a6ca1d6545da9c2333c8c48343ef398eb858d72b7923690600090a260038101805460ff191690555b505050505050565b6000836001600160a01b0381166116aa5760405162461bcd60e51b8152602060048201526017602482015276416464726573732063616e6e6f7420626520656d70747960481b60448201526064016104f9565b600554604080516080810182526001600160a01b038881168252602080830189815283850189815260006060860181905287815280845295909520845181546001600160a01b0319169416939093178355516001830155925180519496509193909261171d92600285019291019061180f565b50606091909101516003909101805460ff1916911515919091179055600580546001919060009061174f908490611c89565b909155505060405182907fc0ba8fe4b176c1714197d43b9cc6bcf797a4a7461c5fe8d0ef6e184ae7601e5190600090a2509392505050565b6000806040516020840160008287838a8c6187965a03f198975050505050505050565b8280548282559060005260206000209081019282156117ff579160200282015b828111156117ff57825182546001600160a01b0319166001600160a01b039091161782556020909201916001909101906117ca565b5061180b929150611883565b5090565b82805461181b90611cb8565b90600052602060002090601f01602090048101928261183d57600085556117ff565b82601f1061185657805160ff19168380011785556117ff565b828001600101855582156117ff579182015b828111156117ff578251825591602001919060010190611868565b5b8082111561180b5760008155600101611884565b80356001600160a01b03811681146118af57600080fd5b919050565b803580151581146118af57600080fd5b6000602082840312156118d657600080fd5b61122d82611898565b600080604083850312156118f257600080fd5b6118fb83611898565b915061190960208401611898565b90509250929050565b60008060006060848603121561192757600080fd5b61193084611898565b925060208401359150604084013567ffffffffffffffff8082111561195457600080fd5b818601915086601f83011261196857600080fd5b81358181111561197a5761197a611d34565b604051601f8201601f19908116603f011681019083821181831017156119a2576119a2611d34565b816040528281528960208487010111156119bb57600080fd5b8260208601602083013760006020848301015280955050505050509250925092565b600080604083850312156119f057600080fd5b6119f9836118b4565b9150611909602084016118b4565b600060208284031215611a1957600080fd5b5035919050565b60008060408385031215611a3357600080fd5b8235915061190960208401611898565b60008060008060808587031215611a5957600080fd5b8435935060208501359250611a70604086016118b4565b9150611a7e606086016118b4565b905092959194509250565b60018060a01b038516815260006020858184015260806040840152845180608085015260005b81811015611acb5786810183015185820160a001528201611aaf565b81811115611add57600060a083870101525b50601f01601f1916830160a0019150611afc9050606083018415159052565b95945050505050565b6020808252825182820181905260009190848201906040850190845b81811015611b465783516001600160a01b031683529284019291840191600101611b21565b50909695505050505050565b6020808252825182820181905260009190848201906040850190845b81811015611b4657835183529284019291840191600101611b6e565b60208082526036908201527f52657175697265642076616c756520697320696e76616c696420666f72207468604082015275194818dd5c9c995b9d081bdddb995c9cc818dbdd5b9d60521b606082015260800190565b60208082526025908201527f5472616e73616374696f6e206973206e6f7420636f6e6669726d65642062792060408201526437bbb732b960d91b606082015260800190565b60208082526013908201527213db9b1e481dd85b1b195d08185b1b1bddd959606a1b604082015260600190565b60208082526018908201527f546865206f776e657220646f6573206e6f742065786973740000000000000000604082015260600190565b60008219821115611c9c57611c9c611d08565b500190565b600082821015611cb357611cb3611d08565b500390565b600181811c90821680611ccc57607f821691505b60208210811415610b6a57634e487b7160e01b600052602260045260246000fd5b6000600019821415611d0157611d01611d08565b5060010190565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052604160045260246000fdfea26469706673582212206218bf781dcbc620e8829bdebcbc6ce03bf4703a647141467643a6c8d5d3bc2364736f6c63430008060033", - "devdoc": { - "author": "Stefan George - ", - "kind": "dev", - "methods": { - "addOwner(address)": { - "details": "Allows to add a new owner. Transaction has to be sent by wallet.", - "params": { - "owner": "Address of new owner." - } - }, - "changeRequirement(uint256)": { - "details": "Allows to change the number of required confirmations. Transaction has to be sent by wallet.", - "params": { - "_required": "Number of required confirmations." - } - }, - "confirmTransaction(uint256)": { - "details": "Allows an owner to confirm a transaction.", - "params": { - "transactionId": "Transaction ID." - } - }, - "constructor": { - "details": "Contract constructor sets initial owners and required number of confirmations.", - "params": { - "_owners": "List of initial owners.", - "_required": "Number of required confirmations." - } - }, - "executeTransaction(uint256)": { - "details": "Allows anyone to execute a confirmed transaction.", - "params": { - "transactionId": "Transaction ID." - } - }, - "getConfirmationCount(uint256)": { - "details": "Returns number of confirmations of a transaction.", - "params": { - "transactionId": "Transaction ID." - }, - "returns": { - "count": "Number of confirmations." - } - }, - "getConfirmations(uint256)": { - "details": "Returns array with owner addresses, which confirmed transaction.", - "params": { - "transactionId": "Transaction ID." - }, - "returns": { - "_confirmations": "Returns array of owner addresses." - } - }, - "getOwners()": { - "details": "Returns list of owners.", - "returns": { - "_0": "List of owner addresses." - } - }, - "getTransactionCount(bool,bool)": { - "details": "Returns total number of transactions after filers are applied.", - "params": { - "executed": "Include executed transactions.", - "pending": "Include pending transactions." - }, - "returns": { - "count": "Total number of transactions after filters are applied." - } - }, - "getTransactionIds(uint256,uint256,bool,bool)": { - "details": "Returns list of transaction IDs in defined range.", - "params": { - "executed": "Include executed transactions.", - "from": "Index start position of transaction array.", - "pending": "Include pending transactions.", - "to": "Index end position of transaction array." - }, - "returns": { - "_transactionIds": "Returns array of transaction IDs." - } - }, - "isConfirmed(uint256)": { - "details": "Returns the confirmation status of a transaction.", - "params": { - "transactionId": "Transaction ID." - }, - "returns": { - "result": "Confirmation status." - } - }, - "removeOwner(address)": { - "details": "Allows to remove an owner. Transaction has to be sent by wallet.", - "params": { - "owner": "Address of owner." - } - }, - "replaceOwner(address,address)": { - "details": "Allows to replace an owner with a new owner. Transaction has to be sent by wallet.", - "params": { - "newOwner": "Address of new owner.", - "owner": "Address of owner to be replaced." - } - }, - "revokeConfirmation(uint256)": { - "details": "Allows an owner to revoke a confirmation for a transaction.", - "params": { - "transactionId": "Transaction ID." - } - }, - "submitTransaction(address,uint256,bytes)": { - "details": "Allows an owner to submit and confirm a transaction.", - "params": { - "data": "Transaction data payload.", - "destination": "Transaction target address.", - "value": "Transaction ether value." - }, - "returns": { - "transactionId": "Returns transaction ID." - } - } - }, - "title": "Multisignature wallet - Allows multiple parties to agree on transactions before execution.", - "version": 1 - }, - "userdoc": { - "kind": "user", - "methods": {}, - "version": 1 - }, - "storageLayout": { - "storage": [ - { - "astId": 52, - "contract": "contracts/MultiSigWallet.sol:MultiSigWallet", - "label": "transactions", - "offset": 0, - "slot": "0", - "type": "t_mapping(t_uint256,t_struct(Transaction)78_storage)" - }, - { - "astId": 58, - "contract": "contracts/MultiSigWallet.sol:MultiSigWallet", - "label": "confirmations", - "offset": 0, - "slot": "1", - "type": "t_mapping(t_uint256,t_mapping(t_address,t_bool))" - }, - { - "astId": 62, - "contract": "contracts/MultiSigWallet.sol:MultiSigWallet", - "label": "isOwner", - "offset": 0, - "slot": "2", - "type": "t_mapping(t_address,t_bool)" - }, - { - "astId": 65, - "contract": "contracts/MultiSigWallet.sol:MultiSigWallet", - "label": "owners", - "offset": 0, - "slot": "3", - "type": "t_array(t_address)dyn_storage" - }, - { - "astId": 67, - "contract": "contracts/MultiSigWallet.sol:MultiSigWallet", - "label": "required", - "offset": 0, - "slot": "4", - "type": "t_uint256" - }, - { - "astId": 69, - "contract": "contracts/MultiSigWallet.sol:MultiSigWallet", - "label": "transactionCount", - "offset": 0, - "slot": "5", - "type": "t_uint256" - } - ], - "types": { - "t_address": { - "encoding": "inplace", - "label": "address", - "numberOfBytes": "20" - }, - "t_array(t_address)dyn_storage": { - "base": "t_address", - "encoding": "dynamic_array", - "label": "address[]", - "numberOfBytes": "32" - }, - "t_bool": { - "encoding": "inplace", - "label": "bool", - "numberOfBytes": "1" - }, - "t_bytes_storage": { - "encoding": "bytes", - "label": "bytes", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_bool)": { - "encoding": "mapping", - "key": "t_address", - "label": "mapping(address => bool)", - "numberOfBytes": "32", - "value": "t_bool" - }, - "t_mapping(t_uint256,t_mapping(t_address,t_bool))": { - "encoding": "mapping", - "key": "t_uint256", - "label": "mapping(uint256 => mapping(address => bool))", - "numberOfBytes": "32", - "value": "t_mapping(t_address,t_bool)" - }, - "t_mapping(t_uint256,t_struct(Transaction)78_storage)": { - "encoding": "mapping", - "key": "t_uint256", - "label": "mapping(uint256 => struct MultiSigWallet.Transaction)", - "numberOfBytes": "32", - "value": "t_struct(Transaction)78_storage" - }, - "t_struct(Transaction)78_storage": { - "encoding": "inplace", - "label": "struct MultiSigWallet.Transaction", - "members": [ - { - "astId": 71, - "contract": "contracts/MultiSigWallet.sol:MultiSigWallet", - "label": "destination", - "offset": 0, - "slot": "0", - "type": "t_address" - }, - { - "astId": 73, - "contract": "contracts/MultiSigWallet.sol:MultiSigWallet", - "label": "value", - "offset": 0, - "slot": "1", - "type": "t_uint256" - }, - { - "astId": 75, - "contract": "contracts/MultiSigWallet.sol:MultiSigWallet", - "label": "data", - "offset": 0, - "slot": "2", - "type": "t_bytes_storage" - }, - { - "astId": 77, - "contract": "contracts/MultiSigWallet.sol:MultiSigWallet", - "label": "executed", - "offset": 0, - "slot": "3", - "type": "t_bool" - } - ], - "numberOfBytes": "128" - }, - "t_uint256": { - "encoding": "inplace", - "label": "uint256", - "numberOfBytes": "32" - } - } - } -} \ No newline at end of file diff --git a/deployments/localhost/PriceOracleProxy.json b/deployments/localhost/PriceOracleProxy.json deleted file mode 100644 index 09d8909..0000000 --- a/deployments/localhost/PriceOracleProxy.json +++ /dev/null @@ -1,392 +0,0 @@ -{ - "address": "0x851356ae760d987E095750cCeb3bC6014560891C", - "abi": [ - { - "inputs": [ - { - "internalType": "address", - "name": "guardian_", - "type": "address" - } - ], - "stateMutability": "nonpayable", - "type": "constructor" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "oldGuardian", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "newGuardian", - "type": "address" - } - ], - "name": "NewGuardian", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "oldPendingGuardian", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "newPendingGuardian", - "type": "address" - } - ], - "name": "NewPendingGuardian", - "type": "event" - }, - { - "inputs": [], - "name": "_acceptAdmin", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newPendingGuardian", - "type": "address" - } - ], - "name": "_setPendingAdmin", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "cTokenArrayCount", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "name": "cTokensArray", - "outputs": [ - { - "internalType": "address", - "name": "cToken", - "type": "address" - }, - { - "internalType": "string", - "name": "cTokenName", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "contract CToken", - "name": "cToken", - "type": "address" - } - ], - "name": "getUnderlyingPrice", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "guardian", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "isPriceOracle", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "pendingGuardian", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "addressToken", - "type": "address" - }, - { - "internalType": "address", - "name": "addressAdapter", - "type": "address" - } - ], - "name": "setAdapterToToken", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "name": "tokenAdapter", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - } - ], - "transactionHash": "0x8641df4f10c70fd672e6a025ae1db1053e5bf9342ad7d5bd52d5c5be8a7903fd", - "receipt": { - "to": null, - "from": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", - "contractAddress": "0x851356ae760d987E095750cCeb3bC6014560891C", - "transactionIndex": 0, - "gasUsed": "681323", - "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "blockHash": "0x9280a6f3e153148fa0e6db52b3a592a9d7f14b88fdae8dcc97f76bc35f9e9354", - "transactionHash": "0x8641df4f10c70fd672e6a025ae1db1053e5bf9342ad7d5bd52d5c5be8a7903fd", - "logs": [], - "blockNumber": 37, - "cumulativeGasUsed": "681323", - "status": 1, - "byzantium": true - }, - "args": [ - "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" - ], - "solcInputHash": "3f2295c0e5923ce11cb0f26c6e52bee2", - "metadata": "{\"compiler\":{\"version\":\"0.8.6+commit.11564f7e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"guardian_\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"oldGuardian\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"newGuardian\",\"type\":\"address\"}],\"name\":\"NewGuardian\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"oldPendingGuardian\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"newPendingGuardian\",\"type\":\"address\"}],\"name\":\"NewPendingGuardian\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"_acceptAdmin\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newPendingGuardian\",\"type\":\"address\"}],\"name\":\"_setPendingAdmin\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"cTokenArrayCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"cTokensArray\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"cToken\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"cTokenName\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contract CToken\",\"name\":\"cToken\",\"type\":\"address\"}],\"name\":\"getUnderlyingPrice\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"guardian\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"isPriceOracle\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"pendingGuardian\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"addressToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"addressAdapter\",\"type\":\"address\"}],\"name\":\"setAdapterToToken\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"tokenAdapter\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"_setPendingAdmin(address)\":{\"params\":{\"newPendingGuardian\":\"New pending gaurdian.\"}},\"cTokenArrayCount()\":{\"returns\":{\"_0\":\"The length of cTokensArray\"}},\"constructor\":{\"params\":{\"guardian_\":\"The address of the guardian, which may set the\"}},\"getUnderlyingPrice(address)\":{\"params\":{\"cToken\":\"The cToken to get the underlying price of\"},\"returns\":{\"_0\":\"The underlying asset price mantissa (scaled by 1e18)\"}},\"setAdapterToToken(address,address)\":{\"params\":{\"addressAdapter\":\"Address of the OracleAdapter\",\"addressToken\":\"Address of the cToken\"}}},\"version\":1},\"userdoc\":{\"events\":{\"NewGuardian(address,address)\":{\"notice\":\"Emitted when pendingGuardian is accepted, which means gaurdian is updated\"},\"NewPendingGuardian(address,address)\":{\"notice\":\"Emitted when pendingGuardian is changed\"}},\"kind\":\"user\",\"methods\":{\"_acceptAdmin()\":{\"notice\":\"Accepts transfer of gaurdian rights. msg.sender must be pendingGaurdian\"},\"_setPendingAdmin(address)\":{\"notice\":\"Begins transfer of gaurdian rights. The newPendingGaurdian must call `_acceptAdmin` to finalize the transfer.\"},\"cTokenArrayCount()\":{\"notice\":\"Get the length of cTokensArray\"},\"cTokensArray(uint256)\":{\"notice\":\"Array of cTokensDetail\"},\"getUnderlyingPrice(address)\":{\"notice\":\"Get the underlying price of a listed cToken asset\"},\"guardian()\":{\"notice\":\"Address of the guardian\"},\"isPriceOracle()\":{\"notice\":\"Indicator that this is a PriceOracle contract (for inspection)\"},\"pendingGuardian()\":{\"notice\":\"Address of the pending guardian\"},\"setAdapterToToken(address,address)\":{\"notice\":\"Set the underlying price of a listed cToken asset\"},\"tokenAdapter(address)\":{\"notice\":\"Mapping of the cTokenAddress => adapterAddress\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/PriceOracleProxy.sol\":\"PriceOracleProxy\"},\"evmVersion\":\"berlin\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"contracts/CToken.sol\":{\"content\":\"// SPDX-License-Identifier: UNLICENSED\\npragma solidity 0.8.6;\\n\\nimport \\\"./ComptrollerInterface.sol\\\";\\nimport \\\"./CTokenInterfaces.sol\\\";\\nimport \\\"./ErrorReporter.sol\\\";\\nimport \\\"./Exponential.sol\\\";\\nimport \\\"./EIP20Interface.sol\\\";\\nimport \\\"./InterestRateModel.sol\\\";\\nimport \\\"./WhitelistInterface.sol\\\";\\n\\n/**\\n * @title tropykus CToken Contract\\n * @notice Abstract base for CTokens\\n * @author tropykus\\n */\\nabstract contract CToken is CTokenInterface, Exponential, TokenErrorReporter {\\n address whitelist;\\n\\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(\\n ComptrollerInterface comptroller_,\\n InterestRateModel interestRateModel_,\\n uint256 initialExchangeRateMantissa_,\\n string memory name_,\\n string memory symbol_,\\n uint8 decimals_\\n ) public {\\n require(msg.sender == admin, \\\"CT01\\\");\\n require(accrualBlockNumber == 0 && borrowIndex == 0, \\\"CT02\\\");\\n\\n initialExchangeRateMantissa = initialExchangeRateMantissa_;\\n require(initialExchangeRateMantissa > 0, \\\"CT03\\\");\\n\\n uint256 err = _setComptroller(comptroller_);\\n require(err == uint256(Error.NO_ERROR), \\\"CT04\\\");\\n\\n accrualBlockNumber = getBlockNumber();\\n borrowIndex = mantissaOne;\\n\\n err = _setInterestRateModelFresh(interestRateModel_);\\n require(err == uint256(Error.NO_ERROR), \\\"CT05\\\");\\n\\n name = name_;\\n symbol = symbol_;\\n decimals = decimals_;\\n\\n _notEntered = true;\\n }\\n\\n function addWhitelist(address _whitelist) external returns (uint256) {\\n if (msg.sender != admin) {\\n return\\n fail(\\n Error.UNAUTHORIZED,\\n FailureInfo.SET_INTEREST_RATE_MODEL_OWNER_CHECK\\n );\\n }\\n whitelist = _whitelist;\\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(\\n address spender,\\n address src,\\n address dst,\\n uint256 tokens\\n ) internal returns (uint256) {\\n uint256 allowed = comptroller.transferAllowed(\\n address(this),\\n src,\\n dst,\\n tokens\\n );\\n if (allowed != 0) {\\n return\\n failOpaque(\\n Error.COMPTROLLER_REJECTION,\\n FailureInfo.TRANSFER_COMPTROLLER_REJECTION,\\n allowed\\n );\\n }\\n\\n if (src == dst) {\\n return fail(Error.BAD_INPUT, FailureInfo.TRANSFER_NOT_ALLOWED);\\n }\\n\\n uint256 startingAllowance = 0;\\n if (spender == src) {\\n startingAllowance = type(uint256).max;\\n } else {\\n startingAllowance = transferAllowances[src][spender];\\n }\\n\\n MathError mathErr;\\n uint256 allowanceNew;\\n uint256 srcTokensNew;\\n uint256 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, 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, tokens);\\n if (mathErr != MathError.NO_ERROR) {\\n return fail(Error.MATH_ERROR, FailureInfo.TRANSFER_TOO_MUCH);\\n }\\n\\n accountTokens[src].tokens = srcTokensNew;\\n accountTokens[dst].tokens = dstTokensNew;\\n\\n if (startingAllowance != type(uint256).max) {\\n transferAllowances[src][spender] = allowanceNew;\\n }\\n\\n emit Transfer(src, dst, tokens);\\n\\n return uint256(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)\\n external\\n override\\n nonReentrant\\n returns (bool)\\n {\\n return\\n transferTokens(msg.sender, msg.sender, dst, amount) ==\\n uint256(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(\\n address src,\\n address dst,\\n uint256 amount\\n ) external override nonReentrant returns (bool) {\\n return\\n transferTokens(msg.sender, src, dst, amount) ==\\n uint256(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)\\n external\\n override\\n returns (bool)\\n {\\n transferAllowances[msg.sender][spender] = amount;\\n emit Approval(msg.sender, 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)\\n external\\n view\\n override\\n returns (uint256)\\n {\\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 override returns (uint256) {\\n return accountTokens[owner].tokens;\\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)\\n external\\n override\\n returns (uint256)\\n {\\n (MathError mErr, uint256 balance) = mulScalarTruncate(\\n Exp({mantissa: exchangeRateCurrent()}),\\n accountTokens[owner].tokens\\n );\\n require(mErr == MathError.NO_ERROR, \\\"CT06\\\");\\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)\\n external\\n view\\n override\\n returns (\\n uint256,\\n uint256,\\n uint256,\\n uint256\\n )\\n {\\n uint256 cTokenBalance = accountTokens[account].tokens;\\n uint256 borrowBalance;\\n uint256 exchangeRateMantissa;\\n\\n MathError mErr;\\n\\n (mErr, borrowBalance) = borrowBalanceStoredInternal(account);\\n if (mErr != MathError.NO_ERROR) {\\n return (uint256(Error.MATH_ERROR), 0, 0, 0);\\n }\\n\\n (mErr, exchangeRateMantissa) = exchangeRateStoredInternal();\\n if (mErr != MathError.NO_ERROR) {\\n return (uint256(Error.MATH_ERROR), 0, 0, 0);\\n }\\n\\n return (\\n uint256(Error.NO_ERROR),\\n cTokenBalance,\\n borrowBalance,\\n exchangeRateMantissa\\n );\\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 virtual returns (uint256) {\\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 override returns (uint256) {\\n return\\n interestRateModel.getBorrowRate(\\n getCashPrior(),\\n totalBorrows,\\n totalReserves\\n );\\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 override returns (uint256) {\\n return\\n interestRateModel.getSupplyRate(\\n getCashPrior(),\\n totalBorrows,\\n totalReserves,\\n reserveFactorMantissa\\n );\\n }\\n\\n /**\\n * @notice Returns the current total borrows plus accrued interest\\n * @return The total borrows with interest\\n */\\n function totalBorrowsCurrent()\\n external\\n override\\n nonReentrant\\n returns (uint256)\\n {\\n require(accrueInterest() == uint256(Error.NO_ERROR), \\\"CT07\\\");\\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)\\n external\\n override\\n nonReentrant\\n returns (uint256)\\n {\\n require(accrueInterest() == uint256(Error.NO_ERROR), \\\"CT07\\\");\\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)\\n public\\n view\\n override\\n returns (uint256)\\n {\\n (MathError err, uint256 result) = borrowBalanceStoredInternal(account);\\n require(err == MathError.NO_ERROR, \\\"CT08\\\");\\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)\\n internal\\n view\\n returns (MathError, uint256)\\n {\\n MathError mathErr;\\n uint256 principalTimesIndex;\\n uint256 result;\\n\\n BorrowSnapshot storage borrowSnapshot = accountBorrows[account];\\n\\n if (borrowSnapshot.principal == 0) {\\n return (MathError.NO_ERROR, 0);\\n }\\n\\n (mathErr, principalTimesIndex) = mulUInt(\\n borrowSnapshot.principal,\\n borrowIndex\\n );\\n if (mathErr != MathError.NO_ERROR) {\\n return (mathErr, 0);\\n }\\n\\n (mathErr, result) = divUInt(\\n principalTimesIndex,\\n borrowSnapshot.interestIndex\\n );\\n if (mathErr != MathError.NO_ERROR) {\\n return (mathErr, 0);\\n }\\n\\n return (MathError.NO_ERROR, result);\\n }\\n\\n function getBorrowerPrincipalStored(address account)\\n public\\n view\\n returns (uint256 borrowed)\\n {\\n borrowed = accountBorrows[account].principal;\\n }\\n\\n function getSupplierSnapshotStored(address account)\\n public\\n view\\n returns (\\n uint256 tokens,\\n uint256 underlyingAmount,\\n uint256 suppliedAt,\\n uint256 promisedSupplyRate\\n )\\n {\\n tokens = accountTokens[account].tokens;\\n underlyingAmount = accountTokens[account].underlyingAmount;\\n suppliedAt = accountTokens[account].suppliedAt;\\n promisedSupplyRate = accountTokens[account].promisedSupplyRate;\\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()\\n public\\n override\\n nonReentrant\\n returns (uint256)\\n {\\n require(accrueInterest() == uint256(Error.NO_ERROR), \\\"CT07\\\");\\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 override returns (uint256) {\\n (MathError err, uint256 result) = exchangeRateStoredInternal();\\n require(err == MathError.NO_ERROR, \\\"CT09\\\");\\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()\\n internal\\n view\\n virtual\\n returns (MathError, uint256)\\n {\\n uint256 _totalSupply = totalSupply;\\n if (_totalSupply == 0) {\\n return (MathError.NO_ERROR, initialExchangeRateMantissa);\\n } else {\\n MathError error;\\n uint256 exchangeRate;\\n uint256 totalCash = getCashPrior();\\n if (interestRateModel.isTropykusInterestRateModel()) {\\n (error, exchangeRate) = tropykusExchangeRateStoredInternal(\\n msg.sender\\n );\\n if (error == MathError.NO_ERROR) {\\n return (MathError.NO_ERROR, exchangeRate);\\n } else {\\n return (MathError.NO_ERROR, initialExchangeRateMantissa);\\n }\\n }\\n return\\n interestRateModel.getExchangeRate(\\n totalCash,\\n totalBorrows,\\n totalReserves,\\n totalSupply\\n );\\n }\\n }\\n\\n function tropykusExchangeRateStoredInternal(address redeemer)\\n internal\\n view\\n returns (MathError, uint256)\\n {\\n if (totalSupply == 0) {\\n return (MathError.NO_ERROR, initialExchangeRateMantissa);\\n } else {\\n SupplySnapshot storage supplySnapshot = accountTokens[redeemer];\\n if (supplySnapshot.suppliedAt == 0) {\\n return (MathError.DIVISION_BY_ZERO, 0);\\n }\\n (, uint256 interestFactorMantissa, ) = tropykusInterestAccrued(\\n redeemer\\n );\\n Exp memory interestFactor = Exp({mantissa: interestFactorMantissa});\\n uint256 currentUnderlying = supplySnapshot.underlyingAmount;\\n Exp memory redeemerUnderlying = Exp({mantissa: currentUnderlying});\\n (, Exp memory realAmount) = mulExp(\\n interestFactor,\\n redeemerUnderlying\\n );\\n (, Exp memory exchangeRate) = getExp(\\n realAmount.mantissa,\\n supplySnapshot.tokens\\n );\\n return (MathError.NO_ERROR, exchangeRate.mantissa);\\n }\\n }\\n\\n function tropykusInterestAccrued(address account)\\n internal\\n view\\n returns (\\n MathError,\\n uint256,\\n uint256\\n )\\n {\\n SupplySnapshot storage supplySnapshot = accountTokens[account];\\n uint256 promisedSupplyRate = supplySnapshot.promisedSupplyRate;\\n Exp memory expectedSupplyRatePerBlock = Exp({\\n mantissa: promisedSupplyRate\\n });\\n (, uint256 delta) = subUInt(\\n accrualBlockNumber,\\n supplySnapshot.suppliedAt\\n );\\n (, Exp memory expectedSupplyRatePerBlockWithDelta) = mulScalar(\\n expectedSupplyRatePerBlock,\\n delta\\n );\\n (, Exp memory interestFactor) = addExp(\\n Exp({mantissa: 1e18}),\\n expectedSupplyRatePerBlockWithDelta\\n );\\n uint256 currentUnderlying = supplySnapshot.underlyingAmount;\\n Exp memory redeemerUnderlying = Exp({mantissa: currentUnderlying});\\n (, Exp memory realAmount) = mulExp(interestFactor, redeemerUnderlying);\\n (, uint256 interestEarned) = subUInt(\\n realAmount.mantissa,\\n currentUnderlying\\n );\\n return (MathError.NO_ERROR, interestFactor.mantissa, interestEarned);\\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 override returns (uint256) {\\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 override returns (uint256) {\\n uint256 currentBlockNumber = getBlockNumber();\\n uint256 accrualBlockNumberPrior = accrualBlockNumber;\\n\\n if (accrualBlockNumberPrior == currentBlockNumber) {\\n return uint256(Error.NO_ERROR);\\n }\\n\\n uint256 cashPrior = getCashPrior();\\n uint256 borrowsPrior = totalBorrows;\\n uint256 reservesPrior = totalReserves;\\n uint256 borrowIndexPrior = borrowIndex;\\n\\n uint256 borrowRateMantissa = interestRateModel.getBorrowRate(\\n cashPrior,\\n borrowsPrior,\\n reservesPrior\\n );\\n require(borrowRateMantissa <= borrowRateMaxMantissa, \\\"CT10\\\");\\n\\n (MathError mathErr, uint256 blockDelta) = subUInt(\\n currentBlockNumber,\\n accrualBlockNumberPrior\\n );\\n require(mathErr == MathError.NO_ERROR, \\\"CT11\\\");\\n\\n Exp memory simpleInterestFactor;\\n uint256 interestAccumulated;\\n uint256 totalBorrowsNew;\\n uint256 totalReservesNew;\\n uint256 borrowIndexNew;\\n\\n (mathErr, simpleInterestFactor) = mulScalar(\\n Exp({mantissa: borrowRateMantissa}),\\n blockDelta\\n );\\n if (mathErr != MathError.NO_ERROR) {\\n return\\n failOpaque(\\n Error.MATH_ERROR,\\n FailureInfo\\n .ACCRUE_INTEREST_SIMPLE_INTEREST_FACTOR_CALCULATION_FAILED,\\n uint256(mathErr)\\n );\\n }\\n\\n (mathErr, interestAccumulated) = mulScalarTruncate(\\n simpleInterestFactor,\\n borrowsPrior\\n );\\n if (mathErr != MathError.NO_ERROR) {\\n return\\n failOpaque(\\n Error.MATH_ERROR,\\n FailureInfo\\n .ACCRUE_INTEREST_ACCUMULATED_INTEREST_CALCULATION_FAILED,\\n uint256(mathErr)\\n );\\n }\\n\\n (mathErr, totalBorrowsNew) = addUInt(interestAccumulated, borrowsPrior);\\n if (mathErr != MathError.NO_ERROR) {\\n return\\n failOpaque(\\n Error.MATH_ERROR,\\n FailureInfo\\n .ACCRUE_INTEREST_NEW_TOTAL_BORROWS_CALCULATION_FAILED,\\n uint256(mathErr)\\n );\\n }\\n\\n (mathErr, totalReservesNew) = mulScalarTruncateAddUInt(\\n Exp({mantissa: reserveFactorMantissa}),\\n interestAccumulated,\\n reservesPrior\\n );\\n if (mathErr != MathError.NO_ERROR) {\\n return\\n failOpaque(\\n Error.MATH_ERROR,\\n FailureInfo\\n .ACCRUE_INTEREST_NEW_TOTAL_RESERVES_CALCULATION_FAILED,\\n uint256(mathErr)\\n );\\n }\\n\\n if (interestRateModel.isTropykusInterestRateModel()) {\\n (mathErr, totalReservesNew) = newReserves(\\n borrowRateMantissa,\\n cashPrior,\\n borrowsPrior,\\n reservesPrior,\\n interestAccumulated\\n );\\n if (mathErr != MathError.NO_ERROR) {\\n return\\n failOpaque(\\n Error.MATH_ERROR,\\n FailureInfo\\n .ACCRUE_INTEREST_NEW_TOTAL_RESERVES_CALCULATION_FAILED,\\n uint256(mathErr)\\n );\\n }\\n }\\n\\n (mathErr, borrowIndexNew) = mulScalarTruncateAddUInt(\\n simpleInterestFactor,\\n borrowIndexPrior,\\n borrowIndexPrior\\n );\\n if (mathErr != MathError.NO_ERROR) {\\n return\\n failOpaque(\\n Error.MATH_ERROR,\\n FailureInfo\\n .ACCRUE_INTEREST_NEW_BORROW_INDEX_CALCULATION_FAILED,\\n uint256(mathErr)\\n );\\n }\\n\\n accrualBlockNumber = currentBlockNumber;\\n borrowIndex = borrowIndexNew;\\n totalBorrows = totalBorrowsNew;\\n totalReserves = totalReservesNew;\\n\\n emit AccrueInterest(\\n cashPrior,\\n interestAccumulated,\\n borrowIndexNew,\\n totalBorrowsNew\\n );\\n\\n return uint256(Error.NO_ERROR);\\n }\\n\\n function newReserves(\\n uint256 borrowRateMantissa,\\n uint256 cashPrior,\\n uint256 borrowsPrior,\\n uint256 reservesPrior,\\n uint256 interestAccumulated\\n ) internal view returns (MathError mathErr, uint256 totalReservesNew) {\\n uint256 newReserveFactorMantissa;\\n uint256 utilizationRate = interestRateModel.utilizationRate(\\n cashPrior,\\n borrowsPrior,\\n reservesPrior\\n );\\n uint256 expectedSupplyRate = interestRateModel.getSupplyRate(\\n cashPrior,\\n borrowsPrior,\\n reservesPrior,\\n reserveFactorMantissa\\n );\\n if (\\n interestRateModel.isAboveOptimal(\\n cashPrior,\\n borrowsPrior,\\n reservesPrior\\n )\\n ) {\\n (mathErr, newReserveFactorMantissa) = mulScalarTruncate(\\n Exp({mantissa: utilizationRate}),\\n borrowRateMantissa\\n );\\n if (mathErr != MathError.NO_ERROR) {\\n return (mathErr, 0);\\n }\\n (mathErr, newReserveFactorMantissa) = subUInt(\\n newReserveFactorMantissa,\\n expectedSupplyRate\\n );\\n if (mathErr != MathError.NO_ERROR) {\\n return (mathErr, 0);\\n }\\n (mathErr, totalReservesNew) = mulScalarTruncateAddUInt(\\n Exp({mantissa: newReserveFactorMantissa}),\\n interestAccumulated,\\n reservesPrior\\n );\\n if (mathErr != MathError.NO_ERROR) {\\n return (mathErr, 0);\\n }\\n } else {\\n mathErr = MathError.NO_ERROR;\\n totalReservesNew = reservesPrior;\\n }\\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(uint256 mintAmount)\\n internal\\n nonReentrant\\n returns (uint256, uint256)\\n {\\n if (WhitelistInterface(whitelist).enabled()) {\\n require(WhitelistInterface(whitelist).exist(msg.sender), \\\"CT26\\\");\\n }\\n uint256 error = accrueInterest();\\n if (error != uint256(Error.NO_ERROR)) {\\n return (\\n fail(Error(error), FailureInfo.MINT_ACCRUE_INTEREST_FAILED),\\n 0\\n );\\n }\\n return mintFresh(msg.sender, mintAmount);\\n }\\n\\n struct MintLocalVars {\\n Error err;\\n MathError mathErr;\\n uint256 exchangeRateMantissa;\\n uint256 mintTokens;\\n uint256 totalSupplyNew;\\n uint256 accountTokensNew;\\n uint256 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, uint256 mintAmount)\\n internal\\n returns (uint256, uint256)\\n {\\n uint256 allowed = comptroller.mintAllowed(\\n address(this),\\n minter,\\n mintAmount\\n );\\n if (allowed != 0) {\\n return (\\n failOpaque(\\n Error.COMPTROLLER_REJECTION,\\n FailureInfo.MINT_COMPTROLLER_REJECTION,\\n allowed\\n ),\\n 0\\n );\\n }\\n\\n if (accrualBlockNumber != getBlockNumber()) {\\n return (\\n fail(Error.MARKET_NOT_FRESH, FailureInfo.MINT_FRESHNESS_CHECK),\\n 0\\n );\\n }\\n\\n MintLocalVars memory vars;\\n\\n (\\n vars.mathErr,\\n vars.exchangeRateMantissa\\n ) = exchangeRateStoredInternal();\\n if (vars.mathErr != MathError.NO_ERROR) {\\n return (\\n failOpaque(\\n Error.MATH_ERROR,\\n FailureInfo.MINT_EXCHANGE_RATE_READ_FAILED,\\n uint256(vars.mathErr)\\n ),\\n 0\\n );\\n }\\n if (interestRateModel.isTropykusInterestRateModel()) {\\n SupplySnapshot storage supplySnapshot = accountTokens[minter];\\n (, uint256 newTotalSupply) = addUInt(\\n supplySnapshot.underlyingAmount,\\n mintAmount\\n );\\n require(newTotalSupply <= 0.1e18, \\\"CT24\\\");\\n }\\n vars.actualMintAmount = doTransferIn(minter, mintAmount);\\n\\n (vars.mathErr, vars.mintTokens) = divScalarByExpTruncate(\\n vars.actualMintAmount,\\n Exp({mantissa: vars.exchangeRateMantissa})\\n );\\n require(vars.mathErr == MathError.NO_ERROR, \\\"CT12\\\");\\n\\n (vars.mathErr, vars.totalSupplyNew) = addUInt(\\n totalSupply,\\n vars.mintTokens\\n );\\n require(vars.mathErr == MathError.NO_ERROR, \\\"CT13\\\");\\n\\n (vars.mathErr, vars.accountTokensNew) = addUInt(\\n accountTokens[minter].tokens,\\n vars.mintTokens\\n );\\n require(vars.mathErr == MathError.NO_ERROR, \\\"CT14\\\");\\n\\n uint256 currentSupplyRate = interestRateModel.getSupplyRate(\\n getCashPrior(),\\n totalBorrows,\\n totalReserves,\\n reserveFactorMantissa\\n );\\n\\n bool isTropykusInterestRateModel = interestRateModel\\n .isTropykusInterestRateModel();\\n\\n if (accountTokens[minter].tokens > 0) {\\n Exp memory updatedUnderlying;\\n if (isTropykusInterestRateModel) {\\n (, uint256 interestFactorMantissa, ) = tropykusInterestAccrued(\\n minter\\n );\\n Exp memory interestFactor = Exp({\\n mantissa: interestFactorMantissa\\n });\\n uint256 currentUnderlyingAmount = accountTokens[minter]\\n .underlyingAmount;\\n MathError mErrorNewAmount;\\n (mErrorNewAmount, updatedUnderlying) = mulExp(\\n Exp({mantissa: currentUnderlyingAmount}),\\n interestFactor\\n );\\n if (mErrorNewAmount != MathError.NO_ERROR) {\\n return (\\n failOpaque(\\n Error.MATH_ERROR,\\n FailureInfo.MINT_EXCHANGE_CALCULATION_FAILED,\\n uint256(mErrorNewAmount)\\n ),\\n 0\\n );\\n }\\n } else {\\n uint256 currentTokens = accountTokens[minter].tokens;\\n MathError mErrorUpdatedUnderlying;\\n (mErrorUpdatedUnderlying, updatedUnderlying) = mulExp(\\n Exp({mantissa: currentTokens}),\\n Exp({mantissa: vars.exchangeRateMantissa})\\n );\\n if (mErrorUpdatedUnderlying != MathError.NO_ERROR) {\\n return (\\n failOpaque(\\n Error.MATH_ERROR,\\n FailureInfo.MINT_EXCHANGE_CALCULATION_FAILED,\\n uint256(mErrorUpdatedUnderlying)\\n ),\\n 0\\n );\\n }\\n }\\n (, mintAmount) = addUInt(updatedUnderlying.mantissa, mintAmount);\\n }\\n\\n totalSupply = vars.totalSupplyNew;\\n accountTokens[minter] = SupplySnapshot({\\n tokens: vars.accountTokensNew,\\n underlyingAmount: mintAmount,\\n suppliedAt: accrualBlockNumber,\\n promisedSupplyRate: currentSupplyRate\\n });\\n\\n emit Mint(minter, vars.actualMintAmount, vars.mintTokens);\\n emit Transfer(address(this), minter, vars.mintTokens);\\n\\n return (uint256(Error.NO_ERROR), vars.actualMintAmount);\\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(uint256 redeemAmount)\\n internal\\n nonReentrant\\n returns (uint256)\\n {\\n uint256 error = accrueInterest();\\n if (error != uint256(Error.NO_ERROR)) {\\n return\\n fail(Error(error), FailureInfo.REDEEM_ACCRUE_INTEREST_FAILED);\\n }\\n return redeemFresh(payable(msg.sender), redeemAmount);\\n }\\n\\n struct RedeemLocalVars {\\n Error err;\\n MathError mathErr;\\n uint256 exchangeRateMantissa;\\n uint256 redeemTokens;\\n uint256 redeemAmount;\\n uint256 totalSupplyNew;\\n uint256 accountTokensNew;\\n uint256 newSubsidyFund;\\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 redeemAmountIn The number of underlying tokens to receive from redeeming cTokens\\n * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)\\n */\\n function redeemFresh(address payable redeemer, uint256 redeemAmountIn)\\n internal\\n returns (uint256)\\n {\\n require(redeemAmountIn > 0, \\\"CT15\\\");\\n\\n RedeemLocalVars memory vars;\\n\\n SupplySnapshot storage supplySnapshot = accountTokens[redeemer];\\n\\n (\\n vars.mathErr,\\n vars.exchangeRateMantissa\\n ) = exchangeRateStoredInternal();\\n if (vars.mathErr != MathError.NO_ERROR) {\\n return\\n failOpaque(\\n Error.MATH_ERROR,\\n FailureInfo.REDEEM_EXCHANGE_RATE_READ_FAILED,\\n uint256(vars.mathErr)\\n );\\n }\\n\\n uint256 interestEarned;\\n uint256 subsidyFundPortion;\\n uint256 currentUnderlying;\\n\\n bool isTropykusInterestRateModel = interestRateModel\\n .isTropykusInterestRateModel();\\n if (isTropykusInterestRateModel) {\\n currentUnderlying = supplySnapshot.underlyingAmount;\\n (, , interestEarned) = tropykusInterestAccrued(redeemer);\\n }\\n supplySnapshot.promisedSupplyRate = interestRateModel.getSupplyRate(\\n getCashPrior(),\\n totalBorrows,\\n totalReserves,\\n reserveFactorMantissa\\n );\\n\\n if (\\n isTropykusInterestRateModel &&\\n !interestRateModel.isAboveOptimal(\\n getCashPrior(),\\n totalBorrows,\\n totalReserves\\n )\\n ) {\\n uint256 borrowRate = interestRateModel.getBorrowRate(\\n getCashPrior(),\\n totalBorrows,\\n totalReserves\\n );\\n\\n uint256 utilizationRate = interestRateModel.utilizationRate(\\n getCashPrior(),\\n totalBorrows,\\n totalReserves\\n );\\n\\n (, uint256 estimatedEarning) = mulScalarTruncate(\\n Exp({mantissa: borrowRate}),\\n utilizationRate\\n );\\n\\n (, subsidyFundPortion) = subUInt(\\n supplySnapshot.promisedSupplyRate,\\n estimatedEarning\\n );\\n (, Exp memory subsidyFactor) = getExp(\\n subsidyFundPortion,\\n supplySnapshot.promisedSupplyRate\\n );\\n (, subsidyFundPortion) = mulScalarTruncate(\\n subsidyFactor,\\n interestEarned\\n );\\n }\\n\\n vars.redeemAmount = redeemAmountIn;\\n\\n if (isTropykusInterestRateModel) {\\n (, Exp memory num) = mulExp(\\n vars.redeemAmount,\\n supplySnapshot.tokens\\n );\\n (, Exp memory realTokensWithdrawAmount) = getExp(\\n num.mantissa,\\n currentUnderlying\\n );\\n vars.redeemTokens = realTokensWithdrawAmount.mantissa;\\n } else {\\n (vars.mathErr, vars.redeemTokens) = divScalarByExpTruncate(\\n redeemAmountIn,\\n Exp({mantissa: vars.exchangeRateMantissa})\\n );\\n if (vars.mathErr != MathError.NO_ERROR) {\\n return\\n failOpaque(\\n Error.MATH_ERROR,\\n FailureInfo.REDEEM_EXCHANGE_AMOUNT_CALCULATION_FAILED,\\n uint256(vars.mathErr)\\n );\\n }\\n }\\n // }\\n\\n uint256 allowed = comptroller.redeemAllowed(\\n address(this),\\n redeemer,\\n vars.redeemTokens\\n );\\n if (allowed != 0) {\\n return\\n failOpaque(\\n Error.COMPTROLLER_REJECTION,\\n FailureInfo.REDEEM_COMPTROLLER_REJECTION,\\n allowed\\n );\\n }\\n\\n if (accrualBlockNumber != getBlockNumber()) {\\n return\\n fail(\\n Error.MARKET_NOT_FRESH,\\n FailureInfo.REDEEM_FRESHNESS_CHECK\\n );\\n }\\n\\n (vars.mathErr, vars.totalSupplyNew) = subUInt(\\n totalSupply,\\n vars.redeemTokens\\n );\\n if (vars.mathErr != MathError.NO_ERROR) {\\n return\\n failOpaque(\\n Error.MATH_ERROR,\\n FailureInfo.REDEEM_NEW_TOTAL_SUPPLY_CALCULATION_FAILED,\\n uint256(vars.mathErr)\\n );\\n }\\n\\n (, vars.newSubsidyFund) = subUInt(subsidyFund, subsidyFundPortion);\\n\\n (vars.mathErr, vars.accountTokensNew) = subUInt(\\n supplySnapshot.tokens,\\n vars.redeemTokens\\n );\\n if (vars.mathErr != MathError.NO_ERROR) {\\n return\\n failOpaque(\\n Error.MATH_ERROR,\\n FailureInfo.REDEEM_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED,\\n uint256(vars.mathErr)\\n );\\n }\\n\\n uint256 cash = getCashPrior();\\n if (isTropykusInterestRateModel) {\\n cash = address(this).balance;\\n }\\n\\n if (cash < vars.redeemAmount) {\\n return\\n fail(\\n Error.TOKEN_INSUFFICIENT_CASH,\\n FailureInfo.REDEEM_TRANSFER_OUT_NOT_POSSIBLE\\n );\\n }\\n\\n doTransferOut(redeemer, vars.redeemAmount);\\n\\n totalSupply = vars.totalSupplyNew;\\n subsidyFund = vars.newSubsidyFund;\\n supplySnapshot.tokens = vars.accountTokensNew;\\n supplySnapshot.suppliedAt = accrualBlockNumber;\\n (, supplySnapshot.underlyingAmount) = subUInt(\\n supplySnapshot.underlyingAmount,\\n vars.redeemAmount\\n );\\n\\n emit Transfer(redeemer, address(this), vars.redeemTokens);\\n emit Redeem(redeemer, vars.redeemAmount, vars.redeemTokens);\\n\\n comptroller.redeemVerify(\\n address(this),\\n redeemer,\\n vars.redeemAmount,\\n vars.redeemTokens\\n );\\n\\n return uint256(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(uint256 borrowAmount)\\n internal\\n nonReentrant\\n returns (uint256)\\n {\\n uint256 error = accrueInterest();\\n if (error != uint256(Error.NO_ERROR)) {\\n return\\n fail(Error(error), FailureInfo.BORROW_ACCRUE_INTEREST_FAILED);\\n }\\n return borrowFresh(payable(msg.sender), borrowAmount);\\n }\\n\\n struct BorrowLocalVars {\\n MathError mathErr;\\n uint256 accountBorrows;\\n uint256 accountBorrowsNew;\\n uint256 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, uint256 borrowAmount)\\n internal\\n returns (uint256)\\n {\\n uint256 allowed = comptroller.borrowAllowed(\\n address(this),\\n borrower,\\n borrowAmount\\n );\\n if (allowed != 0) {\\n return\\n failOpaque(\\n Error.COMPTROLLER_REJECTION,\\n FailureInfo.BORROW_COMPTROLLER_REJECTION,\\n allowed\\n );\\n }\\n\\n if (accrualBlockNumber != getBlockNumber()) {\\n return\\n fail(\\n Error.MARKET_NOT_FRESH,\\n FailureInfo.BORROW_FRESHNESS_CHECK\\n );\\n }\\n\\n if (getCashPrior() < borrowAmount) {\\n return\\n fail(\\n Error.TOKEN_INSUFFICIENT_CASH,\\n FailureInfo.BORROW_CASH_NOT_AVAILABLE\\n );\\n }\\n\\n BorrowLocalVars memory vars;\\n\\n (vars.mathErr, vars.accountBorrows) = borrowBalanceStoredInternal(\\n borrower\\n );\\n if (vars.mathErr != MathError.NO_ERROR) {\\n return\\n failOpaque(\\n Error.MATH_ERROR,\\n FailureInfo.BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED,\\n uint256(vars.mathErr)\\n );\\n }\\n\\n (vars.mathErr, vars.accountBorrowsNew) = addUInt(\\n vars.accountBorrows,\\n borrowAmount\\n );\\n if (vars.mathErr != MathError.NO_ERROR) {\\n return\\n failOpaque(\\n Error.MATH_ERROR,\\n FailureInfo\\n .BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED,\\n uint256(vars.mathErr)\\n );\\n }\\n\\n (vars.mathErr, vars.totalBorrowsNew) = addUInt(\\n totalBorrows,\\n borrowAmount\\n );\\n if (interestRateModel.isTropykusInterestRateModel()) {\\n require(vars.totalBorrowsNew <= 0.1e18, \\\"CT25\\\");\\n }\\n if (vars.mathErr != MathError.NO_ERROR) {\\n return\\n failOpaque(\\n Error.MATH_ERROR,\\n FailureInfo.BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED,\\n uint256(vars.mathErr)\\n );\\n }\\n\\n doTransferOut(borrower, borrowAmount);\\n\\n accountBorrows[borrower].principal = vars.accountBorrowsNew;\\n accountBorrows[borrower].interestIndex = borrowIndex;\\n totalBorrows = vars.totalBorrowsNew;\\n\\n emit Borrow(\\n borrower,\\n borrowAmount,\\n vars.accountBorrowsNew,\\n vars.totalBorrowsNew\\n );\\n\\n return uint256(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(uint256 repayAmount)\\n internal\\n nonReentrant\\n returns (uint256, uint256)\\n {\\n uint256 error = accrueInterest();\\n if (error != uint256(Error.NO_ERROR)) {\\n return (\\n fail(\\n Error(error),\\n FailureInfo.REPAY_BORROW_ACCRUE_INTEREST_FAILED\\n ),\\n 0\\n );\\n }\\n return repayBorrowFresh(msg.sender, msg.sender, repayAmount);\\n }\\n\\n struct RepayBorrowLocalVars {\\n Error err;\\n MathError mathErr;\\n uint256 repayAmount;\\n uint256 borrowerIndex;\\n uint256 accountBorrows;\\n uint256 accountBorrowsNew;\\n uint256 totalBorrowsNew;\\n uint256 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(\\n address payer,\\n address borrower,\\n uint256 repayAmount\\n ) internal returns (uint256, uint256) {\\n uint256 allowed = comptroller.repayBorrowAllowed(\\n address(this),\\n payer,\\n borrower,\\n repayAmount\\n );\\n if (allowed != 0) {\\n return (\\n failOpaque(\\n Error.COMPTROLLER_REJECTION,\\n FailureInfo.REPAY_BORROW_COMPTROLLER_REJECTION,\\n allowed\\n ),\\n 0\\n );\\n }\\n\\n if (accrualBlockNumber != getBlockNumber()) {\\n return (\\n fail(\\n Error.MARKET_NOT_FRESH,\\n FailureInfo.REPAY_BORROW_FRESHNESS_CHECK\\n ),\\n 0\\n );\\n }\\n\\n RepayBorrowLocalVars memory vars;\\n\\n vars.borrowerIndex = accountBorrows[borrower].interestIndex;\\n\\n (vars.mathErr, vars.accountBorrows) = borrowBalanceStoredInternal(\\n borrower\\n );\\n if (vars.mathErr != MathError.NO_ERROR) {\\n return (\\n failOpaque(\\n Error.MATH_ERROR,\\n FailureInfo\\n .REPAY_BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED,\\n uint256(vars.mathErr)\\n ),\\n 0\\n );\\n }\\n\\n if (repayAmount == type(uint256).max) {\\n vars.repayAmount = vars.accountBorrows;\\n } else {\\n vars.repayAmount = repayAmount;\\n }\\n\\n vars.actualRepayAmount = doTransferIn(payer, vars.repayAmount);\\n\\n (vars.mathErr, vars.accountBorrowsNew) = subUInt(\\n vars.accountBorrows,\\n vars.actualRepayAmount\\n );\\n require(vars.mathErr == MathError.NO_ERROR, \\\"CT16\\\");\\n\\n (vars.mathErr, vars.totalBorrowsNew) = subUInt(\\n totalBorrows,\\n vars.actualRepayAmount\\n );\\n require(vars.mathErr == MathError.NO_ERROR, \\\"CT17\\\");\\n\\n accountBorrows[borrower].principal = vars.accountBorrowsNew;\\n accountBorrows[borrower].interestIndex = borrowIndex;\\n totalBorrows = vars.totalBorrowsNew;\\n\\n emit RepayBorrow(\\n payer,\\n borrower,\\n vars.actualRepayAmount,\\n vars.accountBorrowsNew,\\n vars.totalBorrowsNew\\n );\\n\\n return (uint256(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(\\n address borrower,\\n uint256 repayAmount,\\n CTokenInterface cTokenCollateral\\n ) internal nonReentrant returns (uint256, uint256) {\\n uint256 error = accrueInterest();\\n if (error != uint256(Error.NO_ERROR)) {\\n return (\\n fail(\\n Error(error),\\n FailureInfo.LIQUIDATE_ACCRUE_BORROW_INTEREST_FAILED\\n ),\\n 0\\n );\\n }\\n\\n error = cTokenCollateral.accrueInterest();\\n if (error != uint256(Error.NO_ERROR)) {\\n return (\\n fail(\\n Error(error),\\n FailureInfo.LIQUIDATE_ACCRUE_COLLATERAL_INTEREST_FAILED\\n ),\\n 0\\n );\\n }\\n\\n // liquidateBorrowFresh emits borrow-specific logs on errors, so we don't need to\\n return\\n liquidateBorrowFresh(\\n msg.sender,\\n borrower,\\n repayAmount,\\n cTokenCollateral\\n );\\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(\\n address liquidator,\\n address borrower,\\n uint256 repayAmount,\\n CTokenInterface cTokenCollateral\\n ) internal returns (uint256, uint256) {\\n uint256 allowed = comptroller.liquidateBorrowAllowed(\\n address(this),\\n address(cTokenCollateral),\\n liquidator,\\n borrower,\\n repayAmount\\n );\\n if (allowed != 0) {\\n return (\\n failOpaque(\\n Error.COMPTROLLER_REJECTION,\\n FailureInfo.LIQUIDATE_COMPTROLLER_REJECTION,\\n allowed\\n ),\\n 0\\n );\\n }\\n\\n if (accrualBlockNumber != getBlockNumber()) {\\n return (\\n fail(\\n Error.MARKET_NOT_FRESH,\\n FailureInfo.LIQUIDATE_FRESHNESS_CHECK\\n ),\\n 0\\n );\\n }\\n\\n if (cTokenCollateral.accrualBlockNumber() != getBlockNumber()) {\\n return (\\n fail(\\n Error.MARKET_NOT_FRESH,\\n FailureInfo.LIQUIDATE_COLLATERAL_FRESHNESS_CHECK\\n ),\\n 0\\n );\\n }\\n\\n if (borrower == liquidator) {\\n return (\\n fail(\\n Error.INVALID_ACCOUNT_PAIR,\\n FailureInfo.LIQUIDATE_LIQUIDATOR_IS_BORROWER\\n ),\\n 0\\n );\\n }\\n\\n if (repayAmount == 0) {\\n return (\\n fail(\\n Error.INVALID_CLOSE_AMOUNT_REQUESTED,\\n FailureInfo.LIQUIDATE_CLOSE_AMOUNT_IS_ZERO\\n ),\\n 0\\n );\\n }\\n\\n if (repayAmount == type(uint256).max) {\\n return (\\n fail(\\n Error.INVALID_CLOSE_AMOUNT_REQUESTED,\\n FailureInfo.LIQUIDATE_CLOSE_AMOUNT_IS_UINT_MAX\\n ),\\n 0\\n );\\n }\\n\\n (\\n uint256 repayBorrowError,\\n uint256 actualRepayAmount\\n ) = repayBorrowFresh(liquidator, borrower, repayAmount);\\n if (repayBorrowError != uint256(Error.NO_ERROR)) {\\n return (\\n fail(\\n Error(repayBorrowError),\\n FailureInfo.LIQUIDATE_REPAY_BORROW_FRESH_FAILED\\n ),\\n 0\\n );\\n }\\n\\n (uint256 amountSeizeError, uint256 seizeTokens) = comptroller\\n .liquidateCalculateSeizeTokens(\\n address(this),\\n address(cTokenCollateral),\\n actualRepayAmount\\n );\\n require(amountSeizeError == uint256(Error.NO_ERROR), \\\"CT18\\\");\\n\\n require(cTokenCollateral.balanceOf(borrower) >= seizeTokens, \\\"CT19\\\");\\n\\n uint256 seizeError;\\n if (address(cTokenCollateral) == address(this)) {\\n seizeError = seizeInternal(\\n address(this),\\n liquidator,\\n borrower,\\n seizeTokens\\n );\\n } else {\\n seizeError = cTokenCollateral.seize(\\n liquidator,\\n borrower,\\n seizeTokens\\n );\\n }\\n\\n require(seizeError == uint256(Error.NO_ERROR), \\\"CT20\\\");\\n\\n emit LiquidateBorrow(\\n liquidator,\\n borrower,\\n actualRepayAmount,\\n address(cTokenCollateral),\\n seizeTokens\\n );\\n\\n return (uint256(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(\\n address liquidator,\\n address borrower,\\n uint256 seizeTokens\\n ) external override nonReentrant returns (uint256) {\\n return seizeInternal(msg.sender, liquidator, borrower, seizeTokens);\\n }\\n\\n struct SeizeVars {\\n uint256 seizeAmount;\\n uint256 exchangeRate;\\n uint256 borrowerTokensNew;\\n uint256 borrowerAmountNew;\\n uint256 liquidatorTokensNew;\\n uint256 liquidatorAmountNew;\\n uint256 totalCash;\\n uint256 supplyRate;\\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(\\n address seizerToken,\\n address liquidator,\\n address borrower,\\n uint256 seizeTokens\\n ) internal returns (uint256) {\\n uint256 allowed = comptroller.seizeAllowed(\\n address(this),\\n seizerToken,\\n liquidator,\\n borrower,\\n seizeTokens\\n );\\n if (allowed != 0) {\\n return\\n failOpaque(\\n Error.COMPTROLLER_REJECTION,\\n FailureInfo.LIQUIDATE_SEIZE_COMPTROLLER_REJECTION,\\n allowed\\n );\\n }\\n\\n if (borrower == liquidator) {\\n return\\n fail(\\n Error.INVALID_ACCOUNT_PAIR,\\n FailureInfo.LIQUIDATE_SEIZE_LIQUIDATOR_IS_BORROWER\\n );\\n }\\n\\n SeizeVars memory seizeVars;\\n\\n MathError mathErr;\\n\\n (mathErr, seizeVars.borrowerTokensNew) = subUInt(\\n accountTokens[borrower].tokens,\\n seizeTokens\\n );\\n if (mathErr != MathError.NO_ERROR) {\\n return\\n failOpaque(\\n Error.MATH_ERROR,\\n FailureInfo.LIQUIDATE_SEIZE_BALANCE_DECREMENT_FAILED,\\n uint256(mathErr)\\n );\\n }\\n\\n seizeVars.totalCash = getCashPrior();\\n seizeVars.supplyRate = interestRateModel.getSupplyRate(\\n seizeVars.totalCash,\\n totalBorrows,\\n totalReserves,\\n reserveFactorMantissa\\n );\\n\\n (, seizeVars.exchangeRate) = interestRateModel.getExchangeRate(\\n seizeVars.totalCash,\\n totalBorrows,\\n totalReserves,\\n totalSupply\\n );\\n\\n if (interestRateModel.isTropykusInterestRateModel()) {\\n (, seizeVars.exchangeRate) = tropykusExchangeRateStoredInternal(\\n borrower\\n );\\n }\\n\\n (, seizeVars.seizeAmount) = mulUInt(\\n seizeTokens,\\n seizeVars.exchangeRate\\n );\\n (, seizeVars.seizeAmount) = divUInt(seizeVars.seizeAmount, 1e18);\\n\\n (, seizeVars.borrowerAmountNew) = subUInt(\\n accountTokens[borrower].underlyingAmount,\\n seizeVars.seizeAmount\\n );\\n\\n (mathErr, seizeVars.liquidatorTokensNew) = addUInt(\\n accountTokens[liquidator].tokens,\\n seizeTokens\\n );\\n if (mathErr != MathError.NO_ERROR) {\\n return\\n failOpaque(\\n Error.MATH_ERROR,\\n FailureInfo.LIQUIDATE_SEIZE_BALANCE_INCREMENT_FAILED,\\n uint256(mathErr)\\n );\\n }\\n\\n (, seizeVars.liquidatorAmountNew) = addUInt(\\n accountTokens[liquidator].underlyingAmount,\\n seizeVars.seizeAmount\\n );\\n\\n accountTokens[borrower].tokens = seizeVars.borrowerTokensNew;\\n accountTokens[borrower].underlyingAmount = seizeVars.borrowerAmountNew;\\n accountTokens[borrower].suppliedAt = getBlockNumber();\\n accountTokens[borrower].promisedSupplyRate = seizeVars.supplyRate;\\n\\n accountTokens[liquidator].tokens = seizeVars.liquidatorTokensNew;\\n accountTokens[liquidator].underlyingAmount = seizeVars\\n .liquidatorAmountNew;\\n accountTokens[liquidator].suppliedAt = getBlockNumber();\\n accountTokens[liquidator].promisedSupplyRate = seizeVars.supplyRate;\\n\\n emit Transfer(borrower, liquidator, seizeTokens);\\n\\n return uint256(Error.NO_ERROR);\\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 payable newPendingAdmin)\\n external\\n override\\n returns (uint256)\\n {\\n if (msg.sender != admin) {\\n return\\n fail(\\n Error.UNAUTHORIZED,\\n FailureInfo.SET_PENDING_ADMIN_OWNER_CHECK\\n );\\n }\\n\\n address oldPendingAdmin = pendingAdmin;\\n\\n pendingAdmin = newPendingAdmin;\\n\\n emit NewPendingAdmin(oldPendingAdmin, newPendingAdmin);\\n\\n return uint256(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 override returns (uint256) {\\n if (msg.sender != pendingAdmin || msg.sender == address(0)) {\\n return\\n fail(\\n Error.UNAUTHORIZED,\\n FailureInfo.ACCEPT_ADMIN_PENDING_ADMIN_CHECK\\n );\\n }\\n\\n address oldAdmin = admin;\\n address oldPendingAdmin = pendingAdmin;\\n\\n admin = pendingAdmin;\\n\\n pendingAdmin = payable(address(0));\\n\\n emit NewAdmin(oldAdmin, admin);\\n emit NewPendingAdmin(oldPendingAdmin, pendingAdmin);\\n\\n return uint256(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)\\n public\\n override\\n returns (uint256)\\n {\\n if (msg.sender != admin) {\\n return\\n fail(\\n Error.UNAUTHORIZED,\\n FailureInfo.SET_COMPTROLLER_OWNER_CHECK\\n );\\n }\\n\\n ComptrollerInterface oldComptroller = comptroller;\\n require(newComptroller.isComptroller(), \\\"CT21\\\");\\n\\n comptroller = newComptroller;\\n\\n emit NewComptroller(oldComptroller, newComptroller);\\n\\n return uint256(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(uint256 newReserveFactorMantissa)\\n external\\n override\\n nonReentrant\\n returns (uint256)\\n {\\n uint256 error = accrueInterest();\\n if (error != uint256(Error.NO_ERROR)) {\\n return\\n fail(\\n Error(error),\\n FailureInfo.SET_RESERVE_FACTOR_ACCRUE_INTEREST_FAILED\\n );\\n }\\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(uint256 newReserveFactorMantissa)\\n internal\\n returns (uint256)\\n {\\n if (msg.sender != admin) {\\n return\\n fail(\\n Error.UNAUTHORIZED,\\n FailureInfo.SET_RESERVE_FACTOR_ADMIN_CHECK\\n );\\n }\\n\\n if (accrualBlockNumber != getBlockNumber()) {\\n return\\n fail(\\n Error.MARKET_NOT_FRESH,\\n FailureInfo.SET_RESERVE_FACTOR_FRESH_CHECK\\n );\\n }\\n\\n if (newReserveFactorMantissa > reserveFactorMaxMantissa) {\\n return\\n fail(\\n Error.BAD_INPUT,\\n FailureInfo.SET_RESERVE_FACTOR_BOUNDS_CHECK\\n );\\n }\\n\\n uint256 oldReserveFactorMantissa = reserveFactorMantissa;\\n reserveFactorMantissa = newReserveFactorMantissa;\\n\\n emit NewReserveFactor(\\n oldReserveFactorMantissa,\\n newReserveFactorMantissa\\n );\\n\\n return uint256(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(uint256 addAmount)\\n internal\\n nonReentrant\\n returns (uint256)\\n {\\n uint256 error = accrueInterest();\\n if (error != uint256(Error.NO_ERROR)) {\\n return\\n fail(\\n Error(error),\\n FailureInfo.ADD_RESERVES_ACCRUE_INTEREST_FAILED\\n );\\n }\\n\\n uint256 totalReservesNew;\\n uint256 actualAddAmount;\\n\\n if (accrualBlockNumber != getBlockNumber()) {\\n return (\\n fail(\\n Error.MARKET_NOT_FRESH,\\n FailureInfo.ADD_RESERVES_FRESH_CHECK\\n )\\n );\\n }\\n\\n actualAddAmount = doTransferIn(msg.sender, addAmount);\\n\\n totalReservesNew = totalReserves + actualAddAmount;\\n\\n require(totalReservesNew >= totalReserves, \\\"CT22\\\");\\n\\n totalReserves = totalReservesNew;\\n\\n emit ReservesAdded(msg.sender, actualAddAmount, totalReservesNew);\\n\\n return (uint256(Error.NO_ERROR));\\n }\\n\\n function _addSubsidyInternal(uint256 addAmount)\\n internal\\n nonReentrant\\n returns (uint256)\\n {\\n uint256 error = accrueInterest();\\n if (error != uint256(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_SUBSIDY_FUND_FAILED);\\n }\\n\\n uint256 subsidyFundNew;\\n uint256 actualAddAmount;\\n\\n if (accrualBlockNumber != getBlockNumber()) {\\n return (\\n fail(\\n Error.MARKET_NOT_FRESH,\\n FailureInfo.ADD_SUBSIDY_FUND_FRESH_CHECK\\n )\\n );\\n }\\n\\n actualAddAmount = doTransferIn(msg.sender, addAmount);\\n\\n subsidyFundNew = subsidyFund + actualAddAmount;\\n\\n require(subsidyFundNew >= subsidyFund, \\\"CT22\\\");\\n\\n subsidyFund = subsidyFundNew;\\n\\n emit SubsidyAdded(msg.sender, actualAddAmount, subsidyFundNew);\\n\\n /* Return (NO_ERROR, actualAddAmount) */\\n return (uint256(Error.NO_ERROR));\\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(uint256 reduceAmount)\\n external\\n override\\n nonReentrant\\n returns (uint256)\\n {\\n uint256 error = accrueInterest();\\n if (error != uint256(Error.NO_ERROR)) {\\n return\\n fail(\\n Error(error),\\n FailureInfo.REDUCE_RESERVES_ACCRUE_INTEREST_FAILED\\n );\\n }\\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(uint256 reduceAmount)\\n internal\\n returns (uint256)\\n {\\n uint256 totalReservesNew;\\n\\n if (msg.sender != admin) {\\n return\\n fail(\\n Error.UNAUTHORIZED,\\n FailureInfo.REDUCE_RESERVES_ADMIN_CHECK\\n );\\n }\\n\\n if (accrualBlockNumber != getBlockNumber()) {\\n return\\n fail(\\n Error.MARKET_NOT_FRESH,\\n FailureInfo.REDUCE_RESERVES_FRESH_CHECK\\n );\\n }\\n\\n if (getCashPrior() < reduceAmount) {\\n return\\n fail(\\n Error.TOKEN_INSUFFICIENT_CASH,\\n FailureInfo.REDUCE_RESERVES_CASH_NOT_AVAILABLE\\n );\\n }\\n\\n if (reduceAmount > totalReserves) {\\n return\\n fail(Error.BAD_INPUT, FailureInfo.REDUCE_RESERVES_VALIDATION);\\n }\\n\\n totalReservesNew = totalReserves - reduceAmount;\\n require(totalReservesNew <= totalReserves, \\\"CT23\\\");\\n\\n totalReserves = totalReservesNew;\\n\\n doTransferOut(admin, reduceAmount);\\n\\n emit ReservesReduced(admin, reduceAmount, totalReservesNew);\\n\\n return uint256(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)\\n public\\n override\\n returns (uint256)\\n {\\n uint256 error = accrueInterest();\\n if (error != uint256(Error.NO_ERROR)) {\\n return\\n fail(\\n Error(error),\\n FailureInfo.SET_INTEREST_RATE_MODEL_ACCRUE_INTEREST_FAILED\\n );\\n }\\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)\\n internal\\n returns (uint256)\\n {\\n InterestRateModel oldInterestRateModel;\\n\\n if (msg.sender != admin) {\\n return\\n fail(\\n Error.UNAUTHORIZED,\\n FailureInfo.SET_INTEREST_RATE_MODEL_OWNER_CHECK\\n );\\n }\\n\\n if (accrualBlockNumber != getBlockNumber()) {\\n return\\n fail(\\n Error.MARKET_NOT_FRESH,\\n FailureInfo.SET_INTEREST_RATE_MODEL_FRESH_CHECK\\n );\\n }\\n\\n oldInterestRateModel = interestRateModel;\\n\\n require(newInterestRateModel.isInterestRateModel(), \\\"CT21\\\");\\n\\n interestRateModel = newInterestRateModel;\\n\\n emit NewMarketInterestRateModel(\\n oldInterestRateModel,\\n newInterestRateModel\\n );\\n\\n return uint256(Error.NO_ERROR);\\n }\\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 virtual returns (uint256);\\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, uint256 amount)\\n internal\\n virtual\\n returns (uint256);\\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, uint256 amount) internal virtual;\\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;\\n }\\n}\\n\",\"keccak256\":\"0x66c781aa1ccc507ce80a431b9ee06801bb81b954bd0697a1f656de400b5cb381\",\"license\":\"UNLICENSED\"},\"contracts/CTokenInterfaces.sol\":{\"content\":\"// SPDX-License-Identifier: UNLICENSED\\npragma solidity 0.8.6;\\n\\nimport \\\"./ComptrollerInterface.sol\\\";\\nimport \\\"./InterestRateModel.sol\\\";\\nimport \\\"./EIP20NonStandardInterface.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 uint256 internal constant borrowRateMaxMantissa = 0.0005e16;\\n\\n /**\\n * @notice Maximum fraction of interest that can be set aside for reserves\\n */\\n uint256 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 uint256 public initialExchangeRateMantissa;\\n\\n /**\\n * @notice Fraction of interest currently set aside for reserves\\n */\\n uint256 public reserveFactorMantissa;\\n\\n /**\\n * @notice Block number that interest was last accrued at\\n */\\n uint256 public accrualBlockNumber;\\n\\n /**\\n * @notice Accumulator of the total earned interest rate since the opening of the market\\n */\\n uint256 public borrowIndex;\\n\\n /**\\n * @notice Total amount of outstanding borrows of the underlying in this market\\n */\\n uint256 public totalBorrows;\\n\\n /**\\n * @notice Total amount of reserves of the underlying held in this market\\n */\\n uint256 public totalReserves;\\n\\n /**\\n * @notice Total number of tokens in circulation\\n */\\n uint256 public totalSupply;\\n\\n uint256 public subsidyFund;\\n\\n struct SupplySnapshot {\\n uint256 tokens;\\n uint256 underlyingAmount;\\n uint256 suppliedAt;\\n uint256 promisedSupplyRate;\\n }\\n\\n /**\\n * @notice Official record of token balances for each account\\n */\\n mapping(address => SupplySnapshot) internal accountTokens;\\n\\n /**\\n * @notice Approved token transfer amounts on behalf of others\\n */\\n mapping(address => mapping(address => uint256)) 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 uint256 principal;\\n uint256 interestIndex;\\n }\\n\\n /**\\n * @notice Mapping of account addresses to outstanding borrow balances\\n */\\n mapping(address => BorrowSnapshot) internal accountBorrows;\\n}\\n\\nabstract contract CTokenInterface is CTokenStorage {\\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 interest is accrued\\n */\\n event AccrueInterest(\\n uint256 cashPrior,\\n uint256 interestAccumulated,\\n uint256 borrowIndex,\\n uint256 totalBorrows\\n );\\n\\n /**\\n * @notice Event emitted when tokens are minted\\n */\\n event Mint(address indexed minter, uint256 mintAmount, uint256 mintTokens);\\n\\n /**\\n * @notice Event emitted when tokens are redeemed\\n */\\n event Redeem(\\n address indexed redeemer,\\n uint256 redeemAmount,\\n uint256 redeemTokens\\n );\\n\\n /**\\n * @notice Event emitted when underlying is borrowed\\n */\\n event Borrow(\\n address indexed borrower,\\n uint256 borrowAmount,\\n uint256 accountBorrows,\\n uint256 totalBorrows\\n );\\n\\n /**\\n * @notice Event emitted when a borrow is repaid\\n */\\n event RepayBorrow(\\n address indexed payer,\\n address indexed borrower,\\n uint256 repayAmount,\\n uint256 accountBorrows,\\n uint256 totalBorrows\\n );\\n\\n /**\\n * @notice Event emitted when a borrow is liquidated\\n */\\n event LiquidateBorrow(\\n address indexed liquidator,\\n address indexed borrower,\\n uint256 repayAmount,\\n address indexed cTokenCollateral,\\n uint256 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(\\n ComptrollerInterface oldComptroller,\\n ComptrollerInterface newComptroller\\n );\\n\\n /**\\n * @notice Event emitted when interestRateModel is changed\\n */\\n event NewMarketInterestRateModel(\\n InterestRateModel oldInterestRateModel,\\n InterestRateModel newInterestRateModel\\n );\\n\\n /**\\n * @notice Event emitted when the reserve factor is changed\\n */\\n event NewReserveFactor(\\n uint256 oldReserveFactorMantissa,\\n uint256 newReserveFactorMantissa\\n );\\n\\n /**\\n * @notice Event emitted when the reserves are added\\n */\\n event ReservesAdded(\\n address benefactor,\\n uint256 addAmount,\\n uint256 newTotalReserves\\n );\\n\\n event SubsidyAdded(\\n address benefactor,\\n uint256 addAmount,\\n uint256 newSubsidyFund\\n );\\n\\n /**\\n * @notice Event emitted when the reserves are reduced\\n */\\n event ReservesReduced(\\n address admin,\\n uint256 reduceAmount,\\n uint256 newTotalReserves\\n );\\n\\n /**\\n * @notice EIP20 Transfer event\\n */\\n event Transfer(address indexed from, address indexed to, uint256 amount);\\n\\n /**\\n * @notice EIP20 Approval event\\n */\\n event Approval(\\n address indexed owner,\\n address indexed spender,\\n uint256 amount\\n );\\n\\n /**\\n * @notice Failure event\\n */\\n event CTokenStorageFailure(uint256 error, uint256 info, uint256 detail);\\n\\n /*** User Interface ***/\\n\\n function transfer(address dst, uint256 amount)\\n external\\n virtual\\n returns (bool);\\n\\n function transferFrom(\\n address src,\\n address dst,\\n uint256 amount\\n ) external virtual returns (bool);\\n\\n function approve(address spender, uint256 amount)\\n external\\n virtual\\n returns (bool);\\n\\n function allowance(address owner, address spender)\\n external\\n view\\n virtual\\n returns (uint256);\\n\\n function balanceOf(address owner) external view virtual returns (uint256);\\n\\n function balanceOfUnderlying(address owner)\\n external\\n virtual\\n returns (uint256);\\n\\n function getAccountSnapshot(address account)\\n external\\n view\\n virtual\\n returns (\\n uint256,\\n uint256,\\n uint256,\\n uint256\\n );\\n\\n function borrowRatePerBlock() external view virtual returns (uint256);\\n\\n function supplyRatePerBlock() external view virtual returns (uint256);\\n\\n function totalBorrowsCurrent() external virtual returns (uint256);\\n\\n function borrowBalanceCurrent(address account)\\n external\\n virtual\\n returns (uint256);\\n\\n function borrowBalanceStored(address account)\\n public\\n view\\n virtual\\n returns (uint256);\\n\\n function exchangeRateCurrent() public virtual returns (uint256);\\n\\n function exchangeRateStored() public view virtual returns (uint256);\\n\\n function getCash() external view virtual returns (uint256);\\n\\n function accrueInterest() public virtual returns (uint256);\\n\\n function seize(\\n address liquidator,\\n address borrower,\\n uint256 seizeTokens\\n ) external virtual returns (uint256);\\n\\n /*** Admin Functions ***/\\n\\n function _setPendingAdmin(address payable newPendingAdmin)\\n external\\n virtual\\n returns (uint256);\\n\\n function _acceptAdmin() external virtual returns (uint256);\\n\\n function _setComptroller(ComptrollerInterface newComptroller)\\n public\\n virtual\\n returns (uint256);\\n\\n function _setReserveFactor(uint256 newReserveFactorMantissa)\\n external\\n virtual\\n returns (uint256);\\n\\n function _reduceReserves(uint256 reduceAmount)\\n external\\n virtual\\n returns (uint256);\\n\\n function _setInterestRateModel(InterestRateModel newInterestRateModel)\\n public\\n virtual\\n returns (uint256);\\n}\\n\\ncontract CErc20Storage {\\n /**\\n * @notice Underlying asset for this CToken\\n */\\n address public underlying;\\n}\\n\\nabstract contract CErc20Interface is CErc20Storage {\\n /*** User Interface ***/\\n\\n function mint(uint256 mintAmount) external virtual returns (uint256);\\n\\n function redeem(uint256 redeemAmount)\\n external\\n virtual\\n returns (uint256);\\n\\n function borrow(uint256 borrowAmount) external virtual returns (uint256);\\n\\n function repayBorrow(uint256 repayAmount)\\n external\\n virtual\\n returns (uint256);\\n\\n function liquidateBorrow(\\n address borrower,\\n uint256 repayAmount,\\n CTokenInterface cTokenCollateral\\n ) external virtual returns (uint256);\\n\\n function sweepToken(EIP20NonStandardInterface token) external virtual;\\n\\n /*** Admin Functions ***/\\n\\n function _addReserves(uint256 addAmount) external virtual returns (uint256);\\n}\\n\\ncontract CDelegationStorage {\\n /**\\n * @notice Implementation address for this contract\\n */\\n address public implementation;\\n}\\n\\nabstract contract CDelegatorInterface is CDelegationStorage {\\n /**\\n * @notice Emitted when implementation is changed\\n */\\n event NewImplementation(\\n address oldImplementation,\\n address newImplementation\\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(\\n address implementation_,\\n bool allowResign,\\n bytes memory becomeImplementationData\\n ) public virtual;\\n}\\n\\nabstract contract 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 virtual;\\n\\n /**\\n * @notice Called by the delegator on a delegate to forfeit its responsibility\\n */\\n function _resignImplementation() public virtual;\\n}\\n\",\"keccak256\":\"0xd0c347830afeac6c54eb7fbac35b60215d9acdd1fb2a3abb16df18923384fa42\",\"license\":\"UNLICENSED\"},\"contracts/CarefulMath.sol\":{\"content\":\"// SPDX-License-Identifier: UNLICENSED\\npragma solidity 0.8.6;\\n\\n/**\\n * @title Careful Math\\n * @author tropykus\\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}\\n\",\"keccak256\":\"0x2aa4360607bccc28c9bde237718c5fabc5e68a34befec92724d30bfbc0b9499f\",\"license\":\"UNLICENSED\"},\"contracts/ComptrollerInterface.sol\":{\"content\":\"// SPDX-License-Identifier: UNLICENSED\\npragma solidity 0.8.6;\\n\\nabstract contract 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)\\n external\\n virtual\\n returns (uint256[] memory);\\n\\n function exitMarket(address cToken) external virtual returns (uint256);\\n\\n /*** Policy Hooks ***/\\n\\n function mintAllowed(\\n address cToken,\\n address minter,\\n uint256 mintAmount\\n ) external virtual returns (uint256);\\n\\n function mintVerify(\\n address cToken,\\n address minter,\\n uint256 mintAmount,\\n uint256 mintTokens\\n ) external virtual;\\n\\n function redeemAllowed(\\n address cToken,\\n address redeemer,\\n uint256 redeemTokens\\n ) external virtual returns (uint256);\\n\\n function redeemVerify(\\n address cToken,\\n address redeemer,\\n uint256 redeemAmount,\\n uint256 redeemTokens\\n ) external virtual;\\n\\n function borrowAllowed(\\n address cToken,\\n address borrower,\\n uint256 borrowAmount\\n ) external virtual returns (uint256);\\n\\n function borrowVerify(\\n address cToken,\\n address borrower,\\n uint256 borrowAmount\\n ) external virtual;\\n\\n function repayBorrowAllowed(\\n address cToken,\\n address payer,\\n address borrower,\\n uint256 repayAmount\\n ) external virtual returns (uint256);\\n\\n function repayBorrowVerify(\\n address cToken,\\n address payer,\\n address borrower,\\n uint256 repayAmount,\\n uint256 borrowerIndex\\n ) external virtual;\\n\\n function liquidateBorrowAllowed(\\n address cTokenBorrowed,\\n address cTokenCollateral,\\n address liquidator,\\n address borrower,\\n uint256 repayAmount\\n ) external virtual returns (uint256);\\n\\n function liquidateBorrowVerify(\\n address cTokenBorrowed,\\n address cTokenCollateral,\\n address liquidator,\\n address borrower,\\n uint256 repayAmount,\\n uint256 seizeTokens\\n ) external virtual;\\n\\n function seizeAllowed(\\n address cTokenCollateral,\\n address cTokenBorrowed,\\n address liquidator,\\n address borrower,\\n uint256 seizeTokens\\n ) external virtual returns (uint256);\\n\\n function seizeVerify(\\n address cTokenCollateral,\\n address cTokenBorrowed,\\n address liquidator,\\n address borrower,\\n uint256 seizeTokens\\n ) external virtual;\\n\\n function transferAllowed(\\n address cToken,\\n address src,\\n address dst,\\n uint256 transferTokens\\n ) external virtual returns (uint256);\\n\\n function transferVerify(\\n address cToken,\\n address src,\\n address dst,\\n uint256 transferTokens\\n ) external virtual;\\n\\n /*** Liquidity/Liquidation Calculations ***/\\n\\n function liquidateCalculateSeizeTokens(\\n address cTokenBorrowed,\\n address cTokenCollateral,\\n uint256 repayAmount\\n ) external view virtual returns (uint256, uint256);\\n}\\n\",\"keccak256\":\"0x4f6874b6790450374231de9b8c33652d620ec9457835e78d36ceaa561875a1b9\",\"license\":\"UNLICENSED\"},\"contracts/EIP20Interface.sol\":{\"content\":\"// SPDX-License-Identifier: UNLICENSED\\npragma solidity 0.8.6;\\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\\n function symbol() external view returns (string memory);\\n\\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 balance 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 success Whether or not the transfer succeeded\\n */\\n function transfer(address dst, uint256 amount)\\n external\\n 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 success Whether or not the transfer succeeded\\n */\\n function transferFrom(\\n address src,\\n address dst,\\n uint256 amount\\n ) 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 success Whether or not the approval succeeded\\n */\\n function approve(address spender, uint256 amount)\\n external\\n 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 remaining The number of tokens allowed to be spent (-1 means infinite)\\n */\\n function allowance(address owner, address spender)\\n external\\n view\\n returns (uint256 remaining);\\n\\n event Transfer(address indexed from, address indexed to, uint256 amount);\\n event Approval(\\n address indexed owner,\\n address indexed spender,\\n uint256 amount\\n );\\n}\\n\",\"keccak256\":\"0xe445bee8cc89c468e8822aa0d39c8f4ee6b6ac059191365ecef889cd83b53a75\",\"license\":\"UNLICENSED\"},\"contracts/EIP20NonStandardInterface.sol\":{\"content\":\"// SPDX-License-Identifier: UNLICENSED\\npragma solidity 0.8.6;\\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 * @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 balance 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(\\n address src,\\n address dst,\\n uint256 amount\\n ) 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 success Whether or not the approval succeeded\\n */\\n function approve(address spender, uint256 amount)\\n external\\n 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 remaining The number of tokens allowed to be spent\\n */\\n function allowance(address owner, address spender)\\n external\\n view\\n returns (uint256 remaining);\\n\\n event Transfer(address indexed from, address indexed to, uint256 amount);\\n event Approval(\\n address indexed owner,\\n address indexed spender,\\n uint256 amount\\n );\\n}\\n\",\"keccak256\":\"0xab8b46aaf5f985d5e3e1f1aa3dbc2e30d69ae0760b3a6b0478f50b9fca3bbc39\",\"license\":\"UNLICENSED\"},\"contracts/ErrorReporter.sol\":{\"content\":\"// SPDX-License-Identifier: UNLICENSED\\npragma solidity 0.8.6;\\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(uint256 error, uint256 info, uint256 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 (uint256) {\\n emit Failure(uint256(err), uint256(info), 0);\\n\\n return uint256(err);\\n }\\n\\n /**\\n * @dev use this when reporting an opaque error from an upgradeable collaborator contract\\n */\\n function failOpaque(\\n Error err,\\n FailureInfo info,\\n uint256 opaqueError\\n ) internal returns (uint256) {\\n emit Failure(uint256(err), uint256(info), opaqueError);\\n\\n return uint256(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 ADD_SUBSIDY_FUND_FAILED,\\n ADD_SUBSIDY_FUND_FRESH_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 TokenFailure(uint256 error, uint256 info, uint256 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 (uint256) {\\n emit TokenFailure(uint256(err), uint256(info), 0);\\n\\n return uint256(err);\\n }\\n\\n /**\\n * @dev use this when reporting an opaque error from an upgradeable collaborator contract\\n */\\n function failOpaque(\\n Error err,\\n FailureInfo info,\\n uint256 opaqueError\\n ) internal returns (uint256) {\\n emit TokenFailure(uint256(err), uint256(info), opaqueError);\\n\\n return uint256(err);\\n }\\n}\\n\",\"keccak256\":\"0x097b23a9ddec2e563458dadd7e03fb1756514acb8a05eb924da76b470582ceb9\",\"license\":\"UNLICENSED\"},\"contracts/Exponential.sol\":{\"content\":\"// SPDX-License-Identifier: UNLICENSED\\npragma solidity 0.8.6;\\n\\nimport \\\"./CarefulMath.sol\\\";\\nimport \\\"./ExponentialNoError.sol\\\";\\n\\n/**\\n * @title Exponential module for storing fixed-precision decimals\\n * @author tropykus\\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) internal pure 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) internal pure 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) internal pure 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) internal pure 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) internal pure 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) internal pure 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) internal pure 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) internal pure 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) internal pure 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) internal pure 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) internal pure 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) internal pure 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) internal pure returns (MathError, Exp memory) {\\n return getExp(a.mantissa, b.mantissa);\\n }\\n}\\n\",\"keccak256\":\"0x4d59359e644bc1df4c60f967b00027aed07612c3471c7c1206d61e10ab705475\",\"license\":\"UNLICENSED\"},\"contracts/ExponentialNoError.sol\":{\"content\":\"// SPDX-License-Identifier: UNLICENSED\\npragma solidity 0.8.6;\\n\\n/**\\n * @title Exponential module for storing fixed-precision decimals\\n * @author tropykus\\n * @notice Exp is a struct which stores decimals with a fixed precision of 18 decimal places.\\n * Thus, if we wanted to store the 5.1, mantissa would store 5.1e18. That is:\\n * `Exp({mantissa: 5100000000000000000})`.\\n */\\ncontract ExponentialNoError {\\n uint constant expScale = 1e18;\\n uint constant doubleScale = 1e36;\\n uint constant halfExpScale = expScale/2;\\n uint constant mantissaOne = expScale;\\n\\n struct Exp {\\n uint mantissa;\\n }\\n\\n struct Double {\\n uint mantissa;\\n }\\n\\n /**\\n * @dev Truncates the given exp to a whole number value.\\n * For example, truncate(Exp{mantissa: 15 * expScale}) = 15\\n */\\n function truncate(Exp memory exp) pure internal returns (uint) {\\n // Note: We are not using careful math here as we're performing a division that cannot fail\\n return exp.mantissa / expScale;\\n }\\n\\n /**\\n * @dev Multiply an Exp by a scalar, then truncate to return an unsigned integer.\\n */\\n function mul_ScalarTruncate(Exp memory a, uint scalar) pure internal returns (uint) {\\n Exp memory product = mul_(a, scalar);\\n return truncate(product);\\n }\\n\\n /**\\n * @dev Multiply an Exp by a scalar, truncate, then add an to an unsigned integer, returning an unsigned integer.\\n */\\n function mul_ScalarTruncateAddUInt(Exp memory a, uint scalar, uint addend) pure internal returns (uint) {\\n Exp memory product = mul_(a, scalar);\\n return add_(truncate(product), addend);\\n }\\n\\n /**\\n * @dev Checks if first Exp is less than second Exp.\\n */\\n function lessThanExp(Exp memory left, Exp memory right) pure internal returns (bool) {\\n return left.mantissa < right.mantissa;\\n }\\n\\n /**\\n * @dev Checks if left Exp <= right Exp.\\n */\\n function lessThanOrEqualExp(Exp memory left, Exp memory right) pure internal returns (bool) {\\n return left.mantissa <= right.mantissa;\\n }\\n\\n /**\\n * @dev Checks if left Exp > right Exp.\\n */\\n function greaterThanExp(Exp memory left, Exp memory right) pure internal returns (bool) {\\n return left.mantissa > right.mantissa;\\n }\\n\\n /**\\n * @dev returns true if Exp is exactly zero\\n */\\n function isZeroExp(Exp memory value) pure internal returns (bool) {\\n return value.mantissa == 0;\\n }\\n\\n function safe224(uint n, string memory errorMessage) pure internal returns (uint224) {\\n require(n < 2**224, errorMessage);\\n return uint224(n);\\n }\\n\\n function safe32(uint n, string memory errorMessage) pure internal returns (uint32) {\\n require(n < 2**32, errorMessage);\\n return uint32(n);\\n }\\n\\n function add_(Exp memory a, Exp memory b) pure internal returns (Exp memory) {\\n return Exp({mantissa: add_(a.mantissa, b.mantissa)});\\n }\\n\\n function add_(Double memory a, Double memory b) pure internal returns (Double memory) {\\n return Double({mantissa: add_(a.mantissa, b.mantissa)});\\n }\\n\\n function add_(uint a, uint b) pure internal returns (uint) {\\n return add_(a, b, \\\"addition overflow\\\");\\n }\\n\\n function add_(uint a, uint b, string memory errorMessage) pure internal returns (uint) {\\n uint c = a + b;\\n require(c >= a, errorMessage);\\n return c;\\n }\\n\\n function sub_(Exp memory a, Exp memory b) pure internal returns (Exp memory) {\\n return Exp({mantissa: sub_(a.mantissa, b.mantissa)});\\n }\\n\\n function sub_(Double memory a, Double memory b) pure internal returns (Double memory) {\\n return Double({mantissa: sub_(a.mantissa, b.mantissa)});\\n }\\n\\n function sub_(uint a, uint b) pure internal returns (uint) {\\n return sub_(a, b, \\\"subtraction underflow\\\");\\n }\\n\\n function sub_(uint a, uint b, string memory errorMessage) pure internal returns (uint) {\\n require(b <= a, errorMessage);\\n return a - b;\\n }\\n\\n function mul_(Exp memory a, Exp memory b) pure internal returns (Exp memory) {\\n return Exp({mantissa: mul_(a.mantissa, b.mantissa) / expScale});\\n }\\n\\n function mul_(Exp memory a, uint b) pure internal returns (Exp memory) {\\n return Exp({mantissa: mul_(a.mantissa, b)});\\n }\\n\\n function mul_(uint a, Exp memory b) pure internal returns (uint) {\\n return mul_(a, b.mantissa) / expScale;\\n }\\n\\n function mul_(Double memory a, Double memory b) pure internal returns (Double memory) {\\n return Double({mantissa: mul_(a.mantissa, b.mantissa) / doubleScale});\\n }\\n\\n function mul_(Double memory a, uint b) pure internal returns (Double memory) {\\n return Double({mantissa: mul_(a.mantissa, b)});\\n }\\n\\n function mul_(uint a, Double memory b) pure internal returns (uint) {\\n return mul_(a, b.mantissa) / doubleScale;\\n }\\n\\n function mul_(uint a, uint b) pure internal returns (uint) {\\n return mul_(a, b, \\\"multiplication overflow\\\");\\n }\\n\\n function mul_(uint a, uint b, string memory errorMessage) pure internal returns (uint) {\\n if (a == 0 || b == 0) {\\n return 0;\\n }\\n uint c = a * b;\\n require(c / a == b, errorMessage);\\n return c;\\n }\\n\\n function div_(Exp memory a, Exp memory b) pure internal returns (Exp memory) {\\n return Exp({mantissa: div_(mul_(a.mantissa, expScale), b.mantissa)});\\n }\\n\\n function div_(Exp memory a, uint b) pure internal returns (Exp memory) {\\n return Exp({mantissa: div_(a.mantissa, b)});\\n }\\n\\n function div_(uint a, Exp memory b) pure internal returns (uint) {\\n return div_(mul_(a, expScale), b.mantissa);\\n }\\n\\n function div_(Double memory a, Double memory b) pure internal returns (Double memory) {\\n return Double({mantissa: div_(mul_(a.mantissa, doubleScale), b.mantissa)});\\n }\\n\\n function div_(Double memory a, uint b) pure internal returns (Double memory) {\\n return Double({mantissa: div_(a.mantissa, b)});\\n }\\n\\n function div_(uint a, Double memory b) pure internal returns (uint) {\\n return div_(mul_(a, doubleScale), b.mantissa);\\n }\\n\\n function div_(uint a, uint b) pure internal returns (uint) {\\n return div_(a, b, \\\"divide by zero\\\");\\n }\\n\\n function div_(uint a, uint b, string memory errorMessage) pure internal returns (uint) {\\n require(b > 0, errorMessage);\\n return a / b;\\n }\\n\\n function fraction(uint a, uint b) pure internal returns (Double memory) {\\n return Double({mantissa: div_(mul_(a, doubleScale), b)});\\n }\\n}\\n\",\"keccak256\":\"0x50ebd15fc98c12e065477f11230f5d7cd583b5fe25a3c532cb90e75950667795\",\"license\":\"UNLICENSED\"},\"contracts/InterestRateModel.sol\":{\"content\":\"// SPDX-License-Identifier: UNLICENSED\\npragma solidity 0.8.6;\\n\\nimport \\\"./Exponential.sol\\\";\\nimport \\\"./SafeMath.sol\\\";\\n\\n/**\\n * @title tropykus InterestRateModel Interface\\n * @author tropykus\\n */\\nabstract contract InterestRateModel is Exponential {\\n using SafeMath for uint256;\\n\\n /// @notice Indicator that this is an InterestRateModel contract (for inspection)\\n bool public constant isInterestRateModel = true;\\n bool public isTropykusInterestRateModel;\\n\\n /**\\n * @notice The approximate number of blocks per year that is assumed by the interest rate model\\n */\\n uint256 public constant blocksPerYear = 1051200;\\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(\\n uint256 cash,\\n uint256 borrows,\\n uint256 reserves\\n ) public pure virtual returns (uint256) {\\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 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 amnount of reserves the market has\\n * @return The borrow rate per block (as a percentage, and scaled by 1e18)\\n */\\n function getBorrowRate(\\n uint256 cash,\\n uint256 borrows,\\n uint256 reserves\\n ) external view virtual returns (uint256);\\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 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(\\n uint256 cash,\\n uint256 borrows,\\n uint256 reserves,\\n uint256 reserveFactorMantissa\\n ) external view virtual returns (uint256);\\n\\n function getExchangeRate(\\n uint256 _totalCash,\\n uint256 _totalBorrows,\\n uint256 _totalReserves,\\n uint256 _totalSupply\\n ) public pure returns (MathError, uint256) {\\n /*\\n * exchangeRate = (totalCash + totalBorrows - totalReserves) / totalSupply\\n */\\n Exp memory exchangeRate;\\n MathError mathErr;\\n uint256 cashPlusBorrowsMinusReserves;\\n (mathErr, cashPlusBorrowsMinusReserves) = addThenSubUInt(\\n _totalCash,\\n _totalBorrows,\\n _totalReserves\\n );\\n if (mathErr != MathError.NO_ERROR) {\\n return (mathErr, 0);\\n }\\n (mathErr, exchangeRate) = getExp(\\n cashPlusBorrowsMinusReserves,\\n _totalSupply\\n );\\n if (mathErr != MathError.NO_ERROR) {\\n return (mathErr, 0);\\n }\\n\\n return (MathError.NO_ERROR, exchangeRate.mantissa);\\n }\\n\\n function isAboveOptimal(\\n uint256 cash,\\n uint256 borrows,\\n uint256 reserves\\n ) public view virtual returns (bool) {\\n cash;\\n borrows;\\n reserves;\\n return false;\\n }\\n}\\n\",\"keccak256\":\"0x2cdc1a63482287513664d98d778c718c336461272885f61585c6ba404feb2edc\",\"license\":\"UNLICENSED\"},\"contracts/PriceOracle.sol\":{\"content\":\"// SPDX-License-Identifier: UNLICENSED\\npragma solidity 0.8.6;\\n\\nimport \\\"./CToken.sol\\\";\\n\\nabstract contract 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)\\n external\\n view\\n virtual\\n returns (uint256);\\n}\\n\",\"keccak256\":\"0x74e7a498f96d6fdab6dec52d7501bba644df3f498c6233247dd2db9687e839d8\",\"license\":\"UNLICENSED\"},\"contracts/PriceOracleAdapter.sol\":{\"content\":\"// SPDX-License-Identifier: UNLICENSED\\npragma solidity 0.8.6;\\n\\nabstract contract PriceOracleAdapter {\\n /// @notice Event adapter interface updated\\n event PriceOracleAdapterUpdated(address oldAddress, address newAddress);\\n\\n /**\\n * @notice Get the price\\n * @return The underlying asset price mantissa (scaled by 1e18).\\n * Zero means the price is unavailable.\\n */\\n function assetPrices(address cTokenAddress)\\n external\\n view\\n virtual\\n returns (uint256);\\n}\\n\",\"keccak256\":\"0xce2a8f27186d355a24a4402469afe76e4522e97ad9a1a8388defd85fa4c054ec\",\"license\":\"UNLICENSED\"},\"contracts/PriceOracleProxy.sol\":{\"content\":\"// SPDX-License-Identifier: UNLICENSED\\npragma solidity 0.8.6;\\n\\nimport \\\"./PriceOracle.sol\\\";\\nimport \\\"./PriceOracleAdapter.sol\\\";\\n\\ncontract PriceOracleProxy is PriceOracle {\\n /// @notice Address of the guardian\\n address public guardian;\\n /// @notice Address of the pending guardian\\n address public pendingGuardian;\\n /// @notice Mapping of the cTokenAddress => adapterAddress\\n mapping(address => address) public tokenAdapter;\\n ///@notice Emitted when pendingGuardian is changed\\n event NewPendingGuardian(\\n address oldPendingGuardian,\\n address newPendingGuardian\\n );\\n ///@notice Emitted when pendingGuardian is accepted, which means gaurdian is updated\\n event NewGuardian(address oldGuardian, address newGuardian);\\n /// @notice Struct of the cTokensDetail\\n struct CtokenDetail {\\n address cToken;\\n string cTokenName;\\n }\\n\\n /// @notice Array of cTokensDetail\\n CtokenDetail[] public cTokensArray;\\n\\n /**\\n * @notice Get the length of cTokensArray\\n * @return The length of cTokensArray\\n */\\n function cTokenArrayCount() public view returns (uint256) {\\n return cTokensArray.length;\\n }\\n\\n /// @param guardian_ The address of the guardian, which may set the\\n constructor(address guardian_) {\\n guardian = guardian_;\\n }\\n\\n /**\\n * @notice Get the underlying price of a listed cToken asset\\n * @param cToken The cToken to get the underlying price of\\n * @return The underlying asset price mantissa (scaled by 1e18)\\n */\\n function getUnderlyingPrice(CToken cToken)\\n public\\n view\\n virtual\\n override\\n returns (uint256)\\n {\\n address oracleAdapter = tokenAdapter[address(cToken)];\\n //validate mapping\\n if (oracleAdapter == address(0)) {\\n return 0;\\n }\\n return PriceOracleAdapter(oracleAdapter).assetPrices(address(cToken));\\n }\\n\\n /**\\n * @notice Set the underlying price of a listed cToken asset\\n * @param addressToken Address of the cToken\\n * @param addressAdapter Address of the OracleAdapter\\n */\\n function setAdapterToToken(address addressToken, address addressAdapter)\\n public\\n {\\n //validate only guardian can set\\n require(\\n msg.sender == guardian,\\n \\\"PriceOracleProxy: only guardian may set the address\\\"\\n );\\n require(\\n addressToken != address(0),\\n \\\"PriceOracleProxy: address token can not be 0\\\"\\n );\\n require(\\n addressAdapter != address(0),\\n \\\"PriceOracleProxy: address adapter can not be 0\\\"\\n );\\n //validate and set new cToken in CtokenDetail\\n if (tokenAdapter[addressToken] == address(0)) {\\n CtokenDetail memory _cTokenD = CtokenDetail({\\n cToken: addressToken,\\n cTokenName: CToken(addressToken).symbol()\\n });\\n\\n cTokensArray.push(_cTokenD);\\n }\\n //set token => adapter\\n tokenAdapter[addressToken] = addressAdapter;\\n }\\n\\n /**\\n * @notice Begins transfer of gaurdian rights. The newPendingGaurdian must call `_acceptAdmin` to finalize the transfer.\\n * @param newPendingGuardian New pending gaurdian.\\n */\\n function _setPendingAdmin(address newPendingGuardian) public {\\n // Check caller = gaurdian\\n require(\\n msg.sender == guardian,\\n \\\"PriceOracleProxy: only guardian may set the address\\\"\\n );\\n require(\\n newPendingGuardian != address(0),\\n \\\"PriceOracleProxy: address admin can not be 0\\\"\\n );\\n // Save current value, if any, for inclusion in log\\n address oldPendingGuardian = guardian;\\n // Store pendingGaurdian with value newPendingGaurdian\\n pendingGuardian = newPendingGuardian;\\n // Emit NewPendingGaurdian(oldPendingGaurdian, newPendingGaurdian)\\n emit NewPendingGuardian(oldPendingGuardian, newPendingGuardian);\\n }\\n\\n /// @notice Accepts transfer of gaurdian rights. msg.sender must be pendingGaurdian\\n function _acceptAdmin() public {\\n // Check caller is pendingGaurdian and pendingGaurdian \\u2260 address(0)\\n require(\\n msg.sender == pendingGuardian,\\n \\\"PriceOracleProxy: only guardian may set the address\\\"\\n );\\n require(\\n msg.sender != address(0),\\n \\\"PriceOracleProxy: sender can not be 0\\\"\\n );\\n\\n // Save current values for inclusion in log\\n address oldGuardian = guardian;\\n address oldPendingGaurdian = pendingGuardian;\\n\\n // Store gaurdian with value pendingGaurdian\\n guardian = pendingGuardian;\\n\\n // Clear the pending value\\n pendingGuardian = address(0);\\n\\n emit NewGuardian(oldGuardian, guardian);\\n emit NewPendingGuardian(oldPendingGaurdian, pendingGuardian);\\n }\\n}\\n\",\"keccak256\":\"0x4fb04e6a373554880293e6dac16e2cf558489511cb45df6a6878cc24a8c0a6a5\",\"license\":\"UNLICENSED\"},\"contracts/SafeMath.sol\":{\"content\":\"// SPDX-License-Identifier: UNLICENSED\\npragma solidity 0.8.6;\\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\":\"0xe578b9602160e7ddbb5e7b6d355bb4508fa134684afe46e4043602c652e0e041\",\"license\":\"UNLICENSED\"},\"contracts/WhitelistInterface.sol\":{\"content\":\"// SPDX-License-Identifier: UNLICENSED\\npragma solidity 0.8.6;\\n\\ninterface WhitelistInterface {\\n function setStatus(bool _newStatus) external;\\n function enabled() external view returns(bool);\\n\\n function addUsers(address[] memory _users) external;\\n function exist(address _user) external view returns(bool);\\n function getUsers() external view returns(address[] memory currentUsers);\\n function removeUser(address _user) external;\\n}\",\"keccak256\":\"0xb00f782772179693611aefb08d51640de313bc901d6d9d78d1e1b86922e99130\",\"license\":\"UNLICENSED\"}},\"version\":1}", - "bytecode": "0x608060405234801561001057600080fd5b50604051610b84380380610b8483398101604081905261002f91610054565b600080546001600160a01b0319166001600160a01b0392909216919091179055610084565b60006020828403121561006657600080fd5b81516001600160a01b038116811461007d57600080fd5b9392505050565b610af1806100936000396000f3fe608060405234801561001057600080fd5b506004361061009e5760003560e01c8063762c31ba11610066578063762c31ba146101335780637bdef09d14610146578063b71d1a0c1461016f578063e9c714f214610182578063fc57d4df1461018a57600080fd5b8063452a9320146100a3578063540399da146100d3578063639a0df7146100e557806366331bba1461010657806372a74ed51461011e575b600080fd5b6000546100b6906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b6003545b6040519081526020016100ca565b6100f86100f336600461095b565b61019d565b6040516100ca92919061098d565b61010e600181565b60405190151581526020016100ca565b61013161012c366004610875565b61025f565b005b6001546100b6906001600160a01b031681565b6100b6610154366004610858565b6002602052600090815260409020546001600160a01b031681565b61013161017d366004610858565b6104e6565b6101316105e1565b6100d7610198366004610858565b610714565b600381815481106101ad57600080fd5b6000918252602090912060029091020180546001820180546001600160a01b039092169350906101dc90610a52565b80601f016020809104026020016040519081016040528092919081815260200182805461020890610a52565b80156102555780601f1061022a57610100808354040283529160200191610255565b820191906000526020600020905b81548152906001019060200180831161023857829003601f168201915b5050505050905082565b6000546001600160a01b031633146102925760405162461bcd60e51b8152600401610289906109cf565b60405180910390fd5b6001600160a01b0382166102fd5760405162461bcd60e51b815260206004820152602c60248201527f50726963654f7261636c6550726f78793a206164647265737320746f6b656e2060448201526b063616e206e6f7420626520360a41b6064820152608401610289565b6001600160a01b03811661036a5760405162461bcd60e51b815260206004820152602e60248201527f50726963654f7261636c6550726f78793a20616464726573732061646170746560448201526d0722063616e206e6f7420626520360941b6064820152608401610289565b6001600160a01b03828116600090815260026020526040902054166104b85760006040518060400160405280846001600160a01b03168152602001846001600160a01b03166395d89b416040518163ffffffff1660e01b815260040160006040518083038186803b1580156103de57600080fd5b505afa1580156103f2573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261041a91908101906108ae565b905260038054600181018255600091909152815160029091027fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b810180546001600160a01b039093166001600160a01b0319909316929092178255602080840151805194955085946104b3937fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85c019291909101906107bf565b505050505b6001600160a01b03918216600090815260026020526040902080546001600160a01b03191691909216179055565b6000546001600160a01b031633146105105760405162461bcd60e51b8152600401610289906109cf565b6001600160a01b03811661057b5760405162461bcd60e51b815260206004820152602c60248201527f50726963654f7261636c6550726f78793a20616464726573732061646d696e2060448201526b063616e206e6f7420626520360a41b6064820152608401610289565b600054600180546001600160a01b0319166001600160a01b0384811691821790925560408051929093168083526020830191909152917f82b7d5b540b091a495b35b109d1fff4d3128e7c81e8b8277c9167628f10a0e0b91015b60405180910390a15050565b6001546001600160a01b0316331461060b5760405162461bcd60e51b8152600401610289906109cf565b336106665760405162461bcd60e51b815260206004820152602560248201527f50726963654f7261636c6550726f78793a2073656e6465722063616e206e6f74604482015264020626520360dc1b6064820152608401610289565b60008054600180546001600160a01b038082166001600160a01b031980861682179096559490911690915560408051919092168082526020820184905292917f08fdaf06427a2010e5958f4329b566993472d14ce81d3f16ce7f2a2660da98e3910160405180910390a1600154604080516001600160a01b03808516825290921660208301527f82b7d5b540b091a495b35b109d1fff4d3128e7c81e8b8277c9167628f10a0e0b91016105d5565b6001600160a01b038082166000908152600260205260408120549091168061073f5750600092915050565b6040516317a6948f60e21b81526001600160a01b038481166004830152821690635e9a523c9060240160206040518083038186803b15801561078057600080fd5b505afa158015610794573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107b89190610974565b9392505050565b8280546107cb90610a52565b90600052602060002090601f0160209004810192826107ed5760008555610833565b82601f1061080657805160ff1916838001178555610833565b82800160010185558215610833579182015b82811115610833578251825591602001919060010190610818565b5061083f929150610843565b5090565b5b8082111561083f5760008155600101610844565b60006020828403121561086a57600080fd5b81356107b881610aa3565b6000806040838503121561088857600080fd5b823561089381610aa3565b915060208301356108a381610aa3565b809150509250929050565b6000602082840312156108c057600080fd5b815167ffffffffffffffff808211156108d857600080fd5b818401915084601f8301126108ec57600080fd5b8151818111156108fe576108fe610a8d565b604051601f8201601f19908116603f0116810190838211818310171561092657610926610a8d565b8160405282815287602084870101111561093f57600080fd5b610950836020830160208801610a22565b979650505050505050565b60006020828403121561096d57600080fd5b5035919050565b60006020828403121561098657600080fd5b5051919050565b60018060a01b038316815260406020820152600082518060408401526109ba816060850160208701610a22565b601f01601f1916919091016060019392505050565b60208082526033908201527f50726963654f7261636c6550726f78793a206f6e6c7920677561726469616e206040820152726d61792073657420746865206164647265737360681b606082015260800190565b60005b83811015610a3d578181015183820152602001610a25565b83811115610a4c576000848401525b50505050565b600181811c90821680610a6657607f821691505b60208210811415610a8757634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052604160045260246000fd5b6001600160a01b0381168114610ab857600080fd5b5056fea264697066735822122041982bfa8263db6f67b4cb31b2123dc88c94c4bddf1142a19a52222187f77b6364736f6c63430008060033", - "deployedBytecode": "0x608060405234801561001057600080fd5b506004361061009e5760003560e01c8063762c31ba11610066578063762c31ba146101335780637bdef09d14610146578063b71d1a0c1461016f578063e9c714f214610182578063fc57d4df1461018a57600080fd5b8063452a9320146100a3578063540399da146100d3578063639a0df7146100e557806366331bba1461010657806372a74ed51461011e575b600080fd5b6000546100b6906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b6003545b6040519081526020016100ca565b6100f86100f336600461095b565b61019d565b6040516100ca92919061098d565b61010e600181565b60405190151581526020016100ca565b61013161012c366004610875565b61025f565b005b6001546100b6906001600160a01b031681565b6100b6610154366004610858565b6002602052600090815260409020546001600160a01b031681565b61013161017d366004610858565b6104e6565b6101316105e1565b6100d7610198366004610858565b610714565b600381815481106101ad57600080fd5b6000918252602090912060029091020180546001820180546001600160a01b039092169350906101dc90610a52565b80601f016020809104026020016040519081016040528092919081815260200182805461020890610a52565b80156102555780601f1061022a57610100808354040283529160200191610255565b820191906000526020600020905b81548152906001019060200180831161023857829003601f168201915b5050505050905082565b6000546001600160a01b031633146102925760405162461bcd60e51b8152600401610289906109cf565b60405180910390fd5b6001600160a01b0382166102fd5760405162461bcd60e51b815260206004820152602c60248201527f50726963654f7261636c6550726f78793a206164647265737320746f6b656e2060448201526b063616e206e6f7420626520360a41b6064820152608401610289565b6001600160a01b03811661036a5760405162461bcd60e51b815260206004820152602e60248201527f50726963654f7261636c6550726f78793a20616464726573732061646170746560448201526d0722063616e206e6f7420626520360941b6064820152608401610289565b6001600160a01b03828116600090815260026020526040902054166104b85760006040518060400160405280846001600160a01b03168152602001846001600160a01b03166395d89b416040518163ffffffff1660e01b815260040160006040518083038186803b1580156103de57600080fd5b505afa1580156103f2573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261041a91908101906108ae565b905260038054600181018255600091909152815160029091027fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b810180546001600160a01b039093166001600160a01b0319909316929092178255602080840151805194955085946104b3937fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85c019291909101906107bf565b505050505b6001600160a01b03918216600090815260026020526040902080546001600160a01b03191691909216179055565b6000546001600160a01b031633146105105760405162461bcd60e51b8152600401610289906109cf565b6001600160a01b03811661057b5760405162461bcd60e51b815260206004820152602c60248201527f50726963654f7261636c6550726f78793a20616464726573732061646d696e2060448201526b063616e206e6f7420626520360a41b6064820152608401610289565b600054600180546001600160a01b0319166001600160a01b0384811691821790925560408051929093168083526020830191909152917f82b7d5b540b091a495b35b109d1fff4d3128e7c81e8b8277c9167628f10a0e0b91015b60405180910390a15050565b6001546001600160a01b0316331461060b5760405162461bcd60e51b8152600401610289906109cf565b336106665760405162461bcd60e51b815260206004820152602560248201527f50726963654f7261636c6550726f78793a2073656e6465722063616e206e6f74604482015264020626520360dc1b6064820152608401610289565b60008054600180546001600160a01b038082166001600160a01b031980861682179096559490911690915560408051919092168082526020820184905292917f08fdaf06427a2010e5958f4329b566993472d14ce81d3f16ce7f2a2660da98e3910160405180910390a1600154604080516001600160a01b03808516825290921660208301527f82b7d5b540b091a495b35b109d1fff4d3128e7c81e8b8277c9167628f10a0e0b91016105d5565b6001600160a01b038082166000908152600260205260408120549091168061073f5750600092915050565b6040516317a6948f60e21b81526001600160a01b038481166004830152821690635e9a523c9060240160206040518083038186803b15801561078057600080fd5b505afa158015610794573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107b89190610974565b9392505050565b8280546107cb90610a52565b90600052602060002090601f0160209004810192826107ed5760008555610833565b82601f1061080657805160ff1916838001178555610833565b82800160010185558215610833579182015b82811115610833578251825591602001919060010190610818565b5061083f929150610843565b5090565b5b8082111561083f5760008155600101610844565b60006020828403121561086a57600080fd5b81356107b881610aa3565b6000806040838503121561088857600080fd5b823561089381610aa3565b915060208301356108a381610aa3565b809150509250929050565b6000602082840312156108c057600080fd5b815167ffffffffffffffff808211156108d857600080fd5b818401915084601f8301126108ec57600080fd5b8151818111156108fe576108fe610a8d565b604051601f8201601f19908116603f0116810190838211818310171561092657610926610a8d565b8160405282815287602084870101111561093f57600080fd5b610950836020830160208801610a22565b979650505050505050565b60006020828403121561096d57600080fd5b5035919050565b60006020828403121561098657600080fd5b5051919050565b60018060a01b038316815260406020820152600082518060408401526109ba816060850160208701610a22565b601f01601f1916919091016060019392505050565b60208082526033908201527f50726963654f7261636c6550726f78793a206f6e6c7920677561726469616e206040820152726d61792073657420746865206164647265737360681b606082015260800190565b60005b83811015610a3d578181015183820152602001610a25565b83811115610a4c576000848401525b50505050565b600181811c90821680610a6657607f821691505b60208210811415610a8757634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052604160045260246000fd5b6001600160a01b0381168114610ab857600080fd5b5056fea264697066735822122041982bfa8263db6f67b4cb31b2123dc88c94c4bddf1142a19a52222187f77b6364736f6c63430008060033", - "devdoc": { - "kind": "dev", - "methods": { - "_setPendingAdmin(address)": { - "params": { - "newPendingGuardian": "New pending gaurdian." - } - }, - "cTokenArrayCount()": { - "returns": { - "_0": "The length of cTokensArray" - } - }, - "constructor": { - "params": { - "guardian_": "The address of the guardian, which may set the" - } - }, - "getUnderlyingPrice(address)": { - "params": { - "cToken": "The cToken to get the underlying price of" - }, - "returns": { - "_0": "The underlying asset price mantissa (scaled by 1e18)" - } - }, - "setAdapterToToken(address,address)": { - "params": { - "addressAdapter": "Address of the OracleAdapter", - "addressToken": "Address of the cToken" - } - } - }, - "version": 1 - }, - "userdoc": { - "events": { - "NewGuardian(address,address)": { - "notice": "Emitted when pendingGuardian is accepted, which means gaurdian is updated" - }, - "NewPendingGuardian(address,address)": { - "notice": "Emitted when pendingGuardian is changed" - } - }, - "kind": "user", - "methods": { - "_acceptAdmin()": { - "notice": "Accepts transfer of gaurdian rights. msg.sender must be pendingGaurdian" - }, - "_setPendingAdmin(address)": { - "notice": "Begins transfer of gaurdian rights. The newPendingGaurdian must call `_acceptAdmin` to finalize the transfer." - }, - "cTokenArrayCount()": { - "notice": "Get the length of cTokensArray" - }, - "cTokensArray(uint256)": { - "notice": "Array of cTokensDetail" - }, - "getUnderlyingPrice(address)": { - "notice": "Get the underlying price of a listed cToken asset" - }, - "guardian()": { - "notice": "Address of the guardian" - }, - "isPriceOracle()": { - "notice": "Indicator that this is a PriceOracle contract (for inspection)" - }, - "pendingGuardian()": { - "notice": "Address of the pending guardian" - }, - "setAdapterToToken(address,address)": { - "notice": "Set the underlying price of a listed cToken asset" - }, - "tokenAdapter(address)": { - "notice": "Mapping of the cTokenAddress => adapterAddress" - } - }, - "version": 1 - }, - "storageLayout": { - "storage": [ - { - "astId": 40032, - "contract": "contracts/PriceOracleProxy.sol:PriceOracleProxy", - "label": "guardian", - "offset": 0, - "slot": "0", - "type": "t_address" - }, - { - "astId": 40035, - "contract": "contracts/PriceOracleProxy.sol:PriceOracleProxy", - "label": "pendingGuardian", - "offset": 0, - "slot": "1", - "type": "t_address" - }, - { - "astId": 40040, - "contract": "contracts/PriceOracleProxy.sol:PriceOracleProxy", - "label": "tokenAdapter", - "offset": 0, - "slot": "2", - "type": "t_mapping(t_address,t_address)" - }, - { - "astId": 40064, - "contract": "contracts/PriceOracleProxy.sol:PriceOracleProxy", - "label": "cTokensArray", - "offset": 0, - "slot": "3", - "type": "t_array(t_struct(CtokenDetail)40059_storage)dyn_storage" - } - ], - "types": { - "t_address": { - "encoding": "inplace", - "label": "address", - "numberOfBytes": "20" - }, - "t_array(t_struct(CtokenDetail)40059_storage)dyn_storage": { - "base": "t_struct(CtokenDetail)40059_storage", - "encoding": "dynamic_array", - "label": "struct PriceOracleProxy.CtokenDetail[]", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_address)": { - "encoding": "mapping", - "key": "t_address", - "label": "mapping(address => address)", - "numberOfBytes": "32", - "value": "t_address" - }, - "t_string_storage": { - "encoding": "bytes", - "label": "string", - "numberOfBytes": "32" - }, - "t_struct(CtokenDetail)40059_storage": { - "encoding": "inplace", - "label": "struct PriceOracleProxy.CtokenDetail", - "members": [ - { - "astId": 40056, - "contract": "contracts/PriceOracleProxy.sol:PriceOracleProxy", - "label": "cToken", - "offset": 0, - "slot": "0", - "type": "t_address" - }, - { - "astId": 40058, - "contract": "contracts/PriceOracleProxy.sol:PriceOracleProxy", - "label": "cTokenName", - "offset": 0, - "slot": "1", - "type": "t_string_storage" - } - ], - "numberOfBytes": "64" - } - } - } -} \ No newline at end of file diff --git a/deployments/localhost/RIF.json b/deployments/localhost/RIF.json deleted file mode 100644 index b382f43..0000000 --- a/deployments/localhost/RIF.json +++ /dev/null @@ -1,379 +0,0 @@ -{ - "address": "0x3Aa5ebB10DC797CAC828524e59A333d0A371443c", - "abi": [ - { - "inputs": [ - { - "internalType": "uint256", - "name": "_initialAmount", - "type": "uint256" - }, - { - "internalType": "string", - "name": "_tokenName", - "type": "string" - }, - { - "internalType": "uint8", - "name": "_decimalUnits", - "type": "uint8" - }, - { - "internalType": "string", - "name": "_tokenSymbol", - "type": "string" - } - ], - "stateMutability": "nonpayable", - "type": "constructor" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "spender", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "Approval", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "Transfer", - "type": "event" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - }, - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "name": "allowance", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_spender", - "type": "address" - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "approve", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "name": "balanceOf", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "decimals", - "outputs": [ - { - "internalType": "uint8", - "name": "", - "type": "uint8" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "name", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "symbol", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalSupply", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "dst", - "type": "address" - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "transfer", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "src", - "type": "address" - }, - { - "internalType": "address", - "name": "dst", - "type": "address" - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "transferFrom", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "nonpayable", - "type": "function" - } - ], - "transactionHash": "0x6301bb2c8a11993ce66281e2bd293e6da74502830ab6736a15e1fa3045ac8466", - "receipt": { - "to": null, - "from": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", - "contractAddress": "0x3Aa5ebB10DC797CAC828524e59A333d0A371443c", - "transactionIndex": 0, - "gasUsed": "576618", - "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "blockHash": "0xace590d8197a9d96994a8c8054ba7a2a6d112cef6b38eef45d908fd9e816064f", - "transactionHash": "0x6301bb2c8a11993ce66281e2bd293e6da74502830ab6736a15e1fa3045ac8466", - "logs": [], - "blockNumber": 20, - "cumulativeGasUsed": "576618", - "status": 1, - "byzantium": true - }, - "args": [ - "2000000000000000000000000", - "RIF token", - 18, - "RIF" - ], - "solcInputHash": "3f2295c0e5923ce11cb0f26c6e52bee2", - "metadata": "{\"compiler\":{\"version\":\"0.8.6+commit.11564f7e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_initialAmount\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"_tokenName\",\"type\":\"string\"},{\"internalType\":\"uint8\",\"name\":\"_decimalUnits\",\"type\":\"uint8\"},{\"internalType\":\"string\",\"name\":\"_tokenSymbol\",\"type\":\"string\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"Approval\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"Transfer\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"allowance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"approve\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"balanceOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"decimals\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"name\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"symbol\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"totalSupply\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"dst\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"transfer\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"src\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"dst\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"transferFrom\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Implementation of the basic standard token. See https://github.com/ethereum/EIPs/issues/20\",\"kind\":\"dev\",\"methods\":{},\"title\":\"Standard ERC20 token\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/ERC20.sol\":\"StandardToken\"},\"evmVersion\":\"berlin\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"contracts/ERC20.sol\":{\"content\":\"// SPDX-License-Identifier: UNLICENSED\\npragma solidity 0.8.6;\\n\\nimport \\\"./SafeMath.sol\\\";\\n\\ninterface ERC20Base {\\n event Approval(\\n address indexed owner,\\n address indexed spender,\\n uint256 value\\n );\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n function totalSupply() external view returns (uint256);\\n\\n function allowance(address owner, address spender)\\n external\\n view\\n returns (uint256);\\n\\n function approve(address spender, uint256 value)\\n external\\n returns (bool);\\n\\n function balanceOf(address who) external view returns (uint256);\\n}\\n\\nabstract contract ERC20 is ERC20Base {\\n function transfer(address to, uint256 value)\\n external\\n virtual\\n returns (bool);\\n\\n function transferFrom(\\n address from,\\n address to,\\n uint256 value\\n ) external virtual returns (bool);\\n}\\n\\nabstract contract ERC20NS is ERC20Base {\\n function transfer(address to, uint256 value) external virtual;\\n\\n function transferFrom(\\n address from,\\n address to,\\n uint256 value\\n ) external virtual;\\n}\\n\\n/**\\n * @title Standard ERC20 token\\n * @dev Implementation of the basic standard token.\\n * See https://github.com/ethereum/EIPs/issues/20\\n */\\ncontract StandardToken is ERC20 {\\n using SafeMath for uint256;\\n\\n string public name;\\n string public symbol;\\n uint8 public decimals;\\n uint256 public override totalSupply;\\n mapping(address => mapping(address => uint256)) public override allowance;\\n mapping(address => uint256) public override balanceOf;\\n\\n constructor(\\n uint256 _initialAmount,\\n string memory _tokenName,\\n uint8 _decimalUnits,\\n string memory _tokenSymbol\\n ) {\\n totalSupply = _initialAmount;\\n balanceOf[msg.sender] = _initialAmount;\\n name = _tokenName;\\n symbol = _tokenSymbol;\\n decimals = _decimalUnits;\\n }\\n\\n function transfer(address dst, uint256 amount)\\n external\\n virtual\\n override\\n returns (bool)\\n {\\n balanceOf[msg.sender] = balanceOf[msg.sender].sub(\\n amount,\\n \\\"Insufficient balance\\\"\\n );\\n balanceOf[dst] = balanceOf[dst].add(amount, \\\"Balance overflow\\\");\\n emit Transfer(msg.sender, dst, amount);\\n return true;\\n }\\n\\n function transferFrom(\\n address src,\\n address dst,\\n uint256 amount\\n ) external virtual override returns (bool) {\\n allowance[src][msg.sender] = allowance[src][msg.sender].sub(\\n amount,\\n \\\"Insufficient allowance\\\"\\n );\\n balanceOf[src] = balanceOf[src].sub(amount, \\\"Insufficient balance\\\");\\n balanceOf[dst] = balanceOf[dst].add(amount, \\\"Balance overflow\\\");\\n emit Transfer(src, dst, amount);\\n return true;\\n }\\n\\n function approve(address _spender, uint256 amount)\\n external\\n override\\n returns (bool)\\n {\\n allowance[msg.sender][_spender] = amount;\\n emit Approval(msg.sender, _spender, amount);\\n return true;\\n }\\n}\\n\\n/**\\n * @title Non-Standard ERC20 token\\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 */\\ncontract NonStandardToken is ERC20NS {\\n using SafeMath for uint256;\\n\\n string public name;\\n uint8 public decimals;\\n string public symbol;\\n uint256 public override totalSupply;\\n mapping(address => mapping(address => uint256)) public override allowance;\\n mapping(address => uint256) public override balanceOf;\\n\\n constructor(\\n uint256 _initialAmount,\\n string memory _tokenName,\\n uint8 _decimalUnits,\\n string memory _tokenSymbol\\n ) {\\n totalSupply = _initialAmount;\\n balanceOf[msg.sender] = _initialAmount;\\n name = _tokenName;\\n symbol = _tokenSymbol;\\n decimals = _decimalUnits;\\n }\\n\\n function transfer(address dst, uint256 amount) external override {\\n balanceOf[msg.sender] = balanceOf[msg.sender].sub(\\n amount,\\n \\\"Insufficient balance\\\"\\n );\\n balanceOf[dst] = balanceOf[dst].add(amount, \\\"Balance overflow\\\");\\n emit Transfer(msg.sender, dst, amount);\\n }\\n\\n function transferFrom(\\n address src,\\n address dst,\\n uint256 amount\\n ) external override {\\n allowance[src][msg.sender] = allowance[src][msg.sender].sub(\\n amount,\\n \\\"Insufficient allowance\\\"\\n );\\n balanceOf[src] = balanceOf[src].sub(amount, \\\"Insufficient balance\\\");\\n balanceOf[dst] = balanceOf[dst].add(amount, \\\"Balance overflow\\\");\\n emit Transfer(src, dst, amount);\\n }\\n\\n function approve(address _spender, uint256 amount)\\n external\\n override\\n returns (bool)\\n {\\n allowance[msg.sender][_spender] = amount;\\n emit Approval(msg.sender, _spender, amount);\\n return true;\\n }\\n}\\n\\ncontract ERC20Harness is StandardToken {\\n using SafeMath for uint256;\\n\\n // To support testing, we can specify addresses for which transferFrom should fail and return false\\n mapping(address => bool) public failTransferFromAddresses;\\n\\n // To support testing, we allow the contract to always fail `transfer`.\\n mapping(address => bool) public failTransferToAddresses;\\n\\n constructor(\\n uint256 _initialAmount,\\n string memory _tokenName,\\n uint8 _decimalUnits,\\n string memory _tokenSymbol\\n ) StandardToken(_initialAmount, _tokenName, _decimalUnits, _tokenSymbol) {}\\n\\n function harnessSetFailTransferFromAddress(address src, bool _fail) public {\\n failTransferFromAddresses[src] = _fail;\\n }\\n\\n function harnessSetFailTransferToAddress(address dst, bool _fail) public {\\n failTransferToAddresses[dst] = _fail;\\n }\\n\\n function harnessSetBalance(address _account, uint256 _amount) public {\\n balanceOf[_account] = _amount;\\n }\\n\\n function transfer(address dst, uint256 amount)\\n external\\n override\\n returns (bool success)\\n {\\n // Added for testing purposes\\n if (failTransferToAddresses[dst]) {\\n return false;\\n }\\n balanceOf[msg.sender] = balanceOf[msg.sender].sub(\\n amount,\\n \\\"Insufficient balance\\\"\\n );\\n balanceOf[dst] = balanceOf[dst].add(amount, \\\"Balance overflow\\\");\\n emit Transfer(msg.sender, dst, amount);\\n return true;\\n }\\n\\n function transferFrom(\\n address src,\\n address dst,\\n uint256 amount\\n ) external override returns (bool success) {\\n // Added for testing purposes\\n if (failTransferFromAddresses[src]) {\\n return false;\\n }\\n allowance[src][msg.sender] = allowance[src][msg.sender].sub(\\n amount,\\n \\\"Insufficient allowance\\\"\\n );\\n balanceOf[src] = balanceOf[src].sub(amount, \\\"Insufficient balance\\\");\\n balanceOf[dst] = balanceOf[dst].add(amount, \\\"Balance overflow\\\");\\n emit Transfer(src, dst, amount);\\n return true;\\n }\\n}\\n\",\"keccak256\":\"0x5450f997ac4f79dc1109aed20142bc67e17b97b78d7d399f7250f6ee04b38582\",\"license\":\"UNLICENSED\"},\"contracts/SafeMath.sol\":{\"content\":\"// SPDX-License-Identifier: UNLICENSED\\npragma solidity 0.8.6;\\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\":\"0xe578b9602160e7ddbb5e7b6d355bb4508fa134684afe46e4043602c652e0e041\",\"license\":\"UNLICENSED\"}},\"version\":1}", - "bytecode": "0x60806040523480156200001157600080fd5b5060405162000a3f38038062000a3f8339810160408190526200003491620001f0565b6003849055336000908152600560209081526040822086905584516200005e929186019062000093565b5080516200007490600190602084019062000093565b50506002805460ff191660ff9290921691909117905550620002d29050565b828054620000a1906200027f565b90600052602060002090601f016020900481019282620000c5576000855562000110565b82601f10620000e057805160ff191683800117855562000110565b8280016001018555821562000110579182015b8281111562000110578251825591602001919060010190620000f3565b506200011e92915062000122565b5090565b5b808211156200011e576000815560010162000123565b600082601f8301126200014b57600080fd5b81516001600160401b0380821115620001685762000168620002bc565b604051601f8301601f19908116603f01168101908282118183101715620001935762000193620002bc565b81604052838152602092508683858801011115620001b057600080fd5b600091505b83821015620001d45785820183015181830184015290820190620001b5565b83821115620001e65760008385830101525b9695505050505050565b600080600080608085870312156200020757600080fd5b845160208601519094506001600160401b03808211156200022757600080fd5b620002358883890162000139565b94506040870151915060ff821682146200024e57600080fd5b6060870151919350808211156200026457600080fd5b50620002738782880162000139565b91505092959194509250565b600181811c908216806200029457607f821691505b60208210811415620002b657634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052604160045260246000fd5b61075d80620002e26000396000f3fe608060405234801561001057600080fd5b50600436106100935760003560e01c8063313ce56711610066578063313ce5671461010357806370a082311461012257806395d89b4114610142578063a9059cbb1461014a578063dd62ed3e1461015d57600080fd5b806306fdde0314610098578063095ea7b3146100b657806318160ddd146100d957806323b872dd146100f0575b600080fd5b6100a0610188565b6040516100ad9190610652565b60405180910390f35b6100c96100c4366004610628565b610216565b60405190151581526020016100ad565b6100e260035481565b6040519081526020016100ad565b6100c96100fe3660046105ec565b610282565b6002546101109060ff1681565b60405160ff90911681526020016100ad565b6100e2610130366004610597565b60056020526000908152604090205481565b6100a0610401565b6100c9610158366004610628565b61040e565b6100e261016b3660046105b9565b600460209081526000928352604080842090915290825290205481565b60008054610195906106d6565b80601f01602080910402602001604051908101604052809291908181526020018280546101c1906106d6565b801561020e5780601f106101e35761010080835404028352916020019161020e565b820191906000526020600020905b8154815290600101906020018083116101f157829003601f168201915b505050505081565b3360008181526004602090815260408083206001600160a01b038716808552925280832085905551919290917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925906102719086815260200190565b60405180910390a350600192915050565b6040805180820182526016815275496e73756666696369656e7420616c6c6f77616e636560501b6020808301919091526001600160a01b038616600090815260048252838120338252909152918220546102dd9184906104fe565b6001600160a01b0385166000818152600460209081526040808320338452825280832094909455835180850185526014815273496e73756666696369656e742062616c616e636560601b818301529282526005905291909120546103429184906104fe565b6001600160a01b0380861660009081526005602081815260408084209590955584518086018652601081526f42616c616e6365206f766572666c6f7760801b81830152938816835252919091205461039b918490610541565b6001600160a01b0380851660008181526005602052604090819020939093559151908616907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef906103ef9086815260200190565b60405180910390a35060019392505050565b60018054610195906106d6565b6040805180820182526014815273496e73756666696369656e742062616c616e636560601b6020808301919091523360009081526005909152918220546104569184906104fe565b3360009081526005602081815260408084209490945583518085018552601081526f42616c616e6365206f766572666c6f7760801b818301526001600160a01b0388168452919052919020546104ad918490610541565b6001600160a01b0384166000818152600560205260409081902092909255905133907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef906102719086815260200190565b6000818484111561052b5760405162461bcd60e51b81526004016105229190610652565b60405180910390fd5b50600061053884866106bf565b95945050505050565b60008061054e84866106a7565b905082858210156105725760405162461bcd60e51b81526004016105229190610652565b50949350505050565b80356001600160a01b038116811461059257600080fd5b919050565b6000602082840312156105a957600080fd5b6105b28261057b565b9392505050565b600080604083850312156105cc57600080fd5b6105d58361057b565b91506105e36020840161057b565b90509250929050565b60008060006060848603121561060157600080fd5b61060a8461057b565b92506106186020850161057b565b9150604084013590509250925092565b6000806040838503121561063b57600080fd5b6106448361057b565b946020939093013593505050565b600060208083528351808285015260005b8181101561067f57858101830151858201604001528201610663565b81811115610691576000604083870101525b50601f01601f1916929092016040019392505050565b600082198211156106ba576106ba610711565b500190565b6000828210156106d1576106d1610711565b500390565b600181811c908216806106ea57607f821691505b6020821081141561070b57634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052601160045260246000fdfea2646970667358221220d01609e330d83e9dc4a8b2b591f78f2787d98d49067556154372370d143909ef64736f6c63430008060033", - "deployedBytecode": "0x608060405234801561001057600080fd5b50600436106100935760003560e01c8063313ce56711610066578063313ce5671461010357806370a082311461012257806395d89b4114610142578063a9059cbb1461014a578063dd62ed3e1461015d57600080fd5b806306fdde0314610098578063095ea7b3146100b657806318160ddd146100d957806323b872dd146100f0575b600080fd5b6100a0610188565b6040516100ad9190610652565b60405180910390f35b6100c96100c4366004610628565b610216565b60405190151581526020016100ad565b6100e260035481565b6040519081526020016100ad565b6100c96100fe3660046105ec565b610282565b6002546101109060ff1681565b60405160ff90911681526020016100ad565b6100e2610130366004610597565b60056020526000908152604090205481565b6100a0610401565b6100c9610158366004610628565b61040e565b6100e261016b3660046105b9565b600460209081526000928352604080842090915290825290205481565b60008054610195906106d6565b80601f01602080910402602001604051908101604052809291908181526020018280546101c1906106d6565b801561020e5780601f106101e35761010080835404028352916020019161020e565b820191906000526020600020905b8154815290600101906020018083116101f157829003601f168201915b505050505081565b3360008181526004602090815260408083206001600160a01b038716808552925280832085905551919290917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925906102719086815260200190565b60405180910390a350600192915050565b6040805180820182526016815275496e73756666696369656e7420616c6c6f77616e636560501b6020808301919091526001600160a01b038616600090815260048252838120338252909152918220546102dd9184906104fe565b6001600160a01b0385166000818152600460209081526040808320338452825280832094909455835180850185526014815273496e73756666696369656e742062616c616e636560601b818301529282526005905291909120546103429184906104fe565b6001600160a01b0380861660009081526005602081815260408084209590955584518086018652601081526f42616c616e6365206f766572666c6f7760801b81830152938816835252919091205461039b918490610541565b6001600160a01b0380851660008181526005602052604090819020939093559151908616907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef906103ef9086815260200190565b60405180910390a35060019392505050565b60018054610195906106d6565b6040805180820182526014815273496e73756666696369656e742062616c616e636560601b6020808301919091523360009081526005909152918220546104569184906104fe565b3360009081526005602081815260408084209490945583518085018552601081526f42616c616e6365206f766572666c6f7760801b818301526001600160a01b0388168452919052919020546104ad918490610541565b6001600160a01b0384166000818152600560205260409081902092909255905133907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef906102719086815260200190565b6000818484111561052b5760405162461bcd60e51b81526004016105229190610652565b60405180910390fd5b50600061053884866106bf565b95945050505050565b60008061054e84866106a7565b905082858210156105725760405162461bcd60e51b81526004016105229190610652565b50949350505050565b80356001600160a01b038116811461059257600080fd5b919050565b6000602082840312156105a957600080fd5b6105b28261057b565b9392505050565b600080604083850312156105cc57600080fd5b6105d58361057b565b91506105e36020840161057b565b90509250929050565b60008060006060848603121561060157600080fd5b61060a8461057b565b92506106186020850161057b565b9150604084013590509250925092565b6000806040838503121561063b57600080fd5b6106448361057b565b946020939093013593505050565b600060208083528351808285015260005b8181101561067f57858101830151858201604001528201610663565b81811115610691576000604083870101525b50601f01601f1916929092016040019392505050565b600082198211156106ba576106ba610711565b500190565b6000828210156106d1576106d1610711565b500390565b600181811c908216806106ea57607f821691505b6020821081141561070b57634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052601160045260246000fdfea2646970667358221220d01609e330d83e9dc4a8b2b591f78f2787d98d49067556154372370d143909ef64736f6c63430008060033", - "devdoc": { - "details": "Implementation of the basic standard token. See https://github.com/ethereum/EIPs/issues/20", - "kind": "dev", - "methods": {}, - "title": "Standard ERC20 token", - "version": 1 - }, - "userdoc": { - "kind": "user", - "methods": {}, - "version": 1 - }, - "storageLayout": { - "storage": [ - { - "astId": 33360, - "contract": "contracts/ERC20.sol:StandardToken", - "label": "name", - "offset": 0, - "slot": "0", - "type": "t_string_storage" - }, - { - "astId": 33362, - "contract": "contracts/ERC20.sol:StandardToken", - "label": "symbol", - "offset": 0, - "slot": "1", - "type": "t_string_storage" - }, - { - "astId": 33364, - "contract": "contracts/ERC20.sol:StandardToken", - "label": "decimals", - "offset": 0, - "slot": "2", - "type": "t_uint8" - }, - { - "astId": 33367, - "contract": "contracts/ERC20.sol:StandardToken", - "label": "totalSupply", - "offset": 0, - "slot": "3", - "type": "t_uint256" - }, - { - "astId": 33374, - "contract": "contracts/ERC20.sol:StandardToken", - "label": "allowance", - "offset": 0, - "slot": "4", - "type": "t_mapping(t_address,t_mapping(t_address,t_uint256))" - }, - { - "astId": 33379, - "contract": "contracts/ERC20.sol:StandardToken", - "label": "balanceOf", - "offset": 0, - "slot": "5", - "type": "t_mapping(t_address,t_uint256)" - } - ], - "types": { - "t_address": { - "encoding": "inplace", - "label": "address", - "numberOfBytes": "20" - }, - "t_mapping(t_address,t_mapping(t_address,t_uint256))": { - "encoding": "mapping", - "key": "t_address", - "label": "mapping(address => mapping(address => uint256))", - "numberOfBytes": "32", - "value": "t_mapping(t_address,t_uint256)" - }, - "t_mapping(t_address,t_uint256)": { - "encoding": "mapping", - "key": "t_address", - "label": "mapping(address => uint256)", - "numberOfBytes": "32", - "value": "t_uint256" - }, - "t_string_storage": { - "encoding": "bytes", - "label": "string", - "numberOfBytes": "32" - }, - "t_uint256": { - "encoding": "inplace", - "label": "uint256", - "numberOfBytes": "32" - }, - "t_uint8": { - "encoding": "inplace", - "label": "uint8", - "numberOfBytes": "1" - } - } - } -} \ No newline at end of file diff --git a/deployments/localhost/RbtcOracle.json b/deployments/localhost/RbtcOracle.json deleted file mode 100644 index 3aa4690..0000000 --- a/deployments/localhost/RbtcOracle.json +++ /dev/null @@ -1,183 +0,0 @@ -{ - "address": "0x8A791620dd6260079BF849Dc5567aDC3F2FdC318", - "abi": [ - { - "inputs": [ - { - "internalType": "address", - "name": "guardian_", - "type": "address" - }, - { - "internalType": "uint256", - "name": "price", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "constructor" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "oldPrice", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "newPrice", - "type": "uint256" - } - ], - "name": "MockPriceProviderMoCUpdated", - "type": "event" - }, - { - "inputs": [], - "name": "guardian", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "peek", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - }, - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "price", - "type": "uint256" - } - ], - "name": "setPrice", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - } - ], - "transactionHash": "0x33f404fbe1fe6e916c1d8ca60732861e87e54f3c0305df2fa999fca993d1b314", - "receipt": { - "to": null, - "from": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", - "contractAddress": "0x8A791620dd6260079BF849Dc5567aDC3F2FdC318", - "transactionIndex": 0, - "gasUsed": "220588", - "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "blockHash": "0x857bb751ae7ab5bd6027be14548da3eed66d9c2820284b6d51e1045119dc67b6", - "transactionHash": "0x33f404fbe1fe6e916c1d8ca60732861e87e54f3c0305df2fa999fca993d1b314", - "logs": [], - "blockNumber": 10, - "cumulativeGasUsed": "220588", - "status": 1, - "byzantium": true - }, - "args": [ - "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", - "33000000000000000000000" - ], - "solcInputHash": "3f2295c0e5923ce11cb0f26c6e52bee2", - "metadata": "{\"compiler\":{\"version\":\"0.8.6+commit.11564f7e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"guardian_\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"price\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldPrice\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newPrice\",\"type\":\"uint256\"}],\"name\":\"MockPriceProviderMoCUpdated\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"guardian\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"peek\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"price\",\"type\":\"uint256\"}],\"name\":\"setPrice\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"setPrice(uint256)\":{\"params\":{\"price\":\"uint of price provider\"}}},\"title\":\"A mock price provider of Money on Chain (MoC)\",\"version\":1},\"userdoc\":{\"events\":{\"MockPriceProviderMoCUpdated(uint256,uint256)\":{\"notice\":\"Event rbtcPrice updated\"}},\"kind\":\"user\",\"methods\":{\"guardian()\":{\"notice\":\"Address of the guardian\"},\"setPrice(uint256)\":{\"notice\":\"Set the rbtcPrice price provider\"}},\"notice\":\"You can use this contract for only simulation\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/mocks/MockPriceProviderMoC.sol\":\"MockPriceProviderMoC\"},\"evmVersion\":\"berlin\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"contracts/CErc20.sol\":{\"content\":\"// SPDX-License-Identifier: UNLICENSED\\npragma solidity 0.8.6;\\n\\nimport \\\"./CToken.sol\\\";\\nimport \\\"./CTokenInterfaces.sol\\\";\\n\\n/**\\n * @title tropykus CErc20 Contract\\n * @notice CTokens which wrap an EIP-20 underlying\\n * @author tropykus\\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(\\n address underlying_,\\n ComptrollerInterface comptroller_,\\n InterestRateModel interestRateModel_,\\n uint256 initialExchangeRateMantissa_,\\n string memory name_,\\n string memory symbol_,\\n uint8 decimals_\\n ) public {\\n // CToken initialize does the bulk of the work\\n super.initialize(\\n comptroller_,\\n interestRateModel_,\\n initialExchangeRateMantissa_,\\n name_,\\n symbol_,\\n decimals_\\n );\\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(uint256 mintAmount) external override returns (uint256) {\\n (uint256 err, ) = mintInternal(mintAmount);\\n return err;\\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 redeem(uint256 redeemAmount)\\n external\\n override\\n returns (uint256)\\n {\\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(uint256 borrowAmount) external override returns (uint256) {\\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(uint256 repayAmount)\\n external\\n override\\n returns (uint256)\\n {\\n (uint256 err, ) = repayBorrowInternal(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(\\n address borrower,\\n uint256 repayAmount,\\n CTokenInterface cTokenCollateral\\n ) external override returns (uint256) {\\n (uint256 err, ) = liquidateBorrowInternal(\\n borrower,\\n repayAmount,\\n cTokenCollateral\\n );\\n return err;\\n }\\n\\n /**\\n * @notice A public function to sweep accidental ERC-20 transfers to this contract. Tokens are sent to admin (timelock)\\n * @param token The address of the ERC-20 token to sweep\\n */\\n function sweepToken(EIP20NonStandardInterface token) external override {\\n require(address(token) != underlying, \\\"EC01\\\");\\n uint256 balance = token.balanceOf(address(this));\\n token.transfer(admin, balance);\\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(uint256 addAmount)\\n external\\n override\\n returns (uint256)\\n {\\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 override returns (uint256) {\\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, uint256 amount)\\n internal\\n override\\n returns (uint256)\\n {\\n EIP20NonStandardInterface token = EIP20NonStandardInterface(underlying);\\n uint256 balanceBefore = EIP20Interface(underlying).balanceOf(\\n address(this)\\n );\\n token.transferFrom(from, address(this), amount);\\n\\n bool success;\\n assembly {\\n switch returndatasize()\\n case 0 {\\n // This is a non-standard ERC-20\\n success := not(0) // set success to true\\n }\\n case 32 {\\n // This is a compliant ERC-20\\n returndatacopy(0, 0, 32)\\n success := mload(0) // Set `success = returndata` of external call\\n }\\n default {\\n // This is an excessively non-compliant ERC-20, revert.\\n revert(0, 0)\\n }\\n }\\n require(success, \\\"EC02\\\");\\n\\n // Calculate the amount that was *actually* transferred\\n uint256 balanceAfter = EIP20Interface(underlying).balanceOf(\\n address(this)\\n );\\n require(balanceAfter >= balanceBefore, \\\"EC03\\\");\\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, uint256 amount)\\n internal\\n virtual\\n override\\n {\\n EIP20NonStandardInterface token = EIP20NonStandardInterface(underlying);\\n token.transfer(to, amount);\\n\\n bool success;\\n assembly {\\n switch returndatasize()\\n case 0 {\\n // This is a non-standard ERC-20\\n success := not(0) // set success to true\\n }\\n case 32 {\\n // This is a complaint ERC-20\\n returndatacopy(0, 0, 32)\\n success := mload(0) // Set `success = returndata` of external call\\n }\\n default {\\n // This is an excessively non-compliant ERC-20, revert.\\n revert(0, 0)\\n }\\n }\\n require(success, \\\"CE01\\\");\\n }\\n}\\n\",\"keccak256\":\"0x539c67e8b5bf011926bd82655501f2016db29e890139a1b466461a3298950365\",\"license\":\"UNLICENSED\"},\"contracts/CToken.sol\":{\"content\":\"// SPDX-License-Identifier: UNLICENSED\\npragma solidity 0.8.6;\\n\\nimport \\\"./ComptrollerInterface.sol\\\";\\nimport \\\"./CTokenInterfaces.sol\\\";\\nimport \\\"./ErrorReporter.sol\\\";\\nimport \\\"./Exponential.sol\\\";\\nimport \\\"./EIP20Interface.sol\\\";\\nimport \\\"./InterestRateModel.sol\\\";\\nimport \\\"./WhitelistInterface.sol\\\";\\n\\n/**\\n * @title tropykus CToken Contract\\n * @notice Abstract base for CTokens\\n * @author tropykus\\n */\\nabstract contract CToken is CTokenInterface, Exponential, TokenErrorReporter {\\n address whitelist;\\n\\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(\\n ComptrollerInterface comptroller_,\\n InterestRateModel interestRateModel_,\\n uint256 initialExchangeRateMantissa_,\\n string memory name_,\\n string memory symbol_,\\n uint8 decimals_\\n ) public {\\n require(msg.sender == admin, \\\"CT01\\\");\\n require(accrualBlockNumber == 0 && borrowIndex == 0, \\\"CT02\\\");\\n\\n initialExchangeRateMantissa = initialExchangeRateMantissa_;\\n require(initialExchangeRateMantissa > 0, \\\"CT03\\\");\\n\\n uint256 err = _setComptroller(comptroller_);\\n require(err == uint256(Error.NO_ERROR), \\\"CT04\\\");\\n\\n accrualBlockNumber = getBlockNumber();\\n borrowIndex = mantissaOne;\\n\\n err = _setInterestRateModelFresh(interestRateModel_);\\n require(err == uint256(Error.NO_ERROR), \\\"CT05\\\");\\n\\n name = name_;\\n symbol = symbol_;\\n decimals = decimals_;\\n\\n _notEntered = true;\\n }\\n\\n function addWhitelist(address _whitelist) external returns (uint256) {\\n if (msg.sender != admin) {\\n return\\n fail(\\n Error.UNAUTHORIZED,\\n FailureInfo.SET_INTEREST_RATE_MODEL_OWNER_CHECK\\n );\\n }\\n whitelist = _whitelist;\\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(\\n address spender,\\n address src,\\n address dst,\\n uint256 tokens\\n ) internal returns (uint256) {\\n uint256 allowed = comptroller.transferAllowed(\\n address(this),\\n src,\\n dst,\\n tokens\\n );\\n if (allowed != 0) {\\n return\\n failOpaque(\\n Error.COMPTROLLER_REJECTION,\\n FailureInfo.TRANSFER_COMPTROLLER_REJECTION,\\n allowed\\n );\\n }\\n\\n if (src == dst) {\\n return fail(Error.BAD_INPUT, FailureInfo.TRANSFER_NOT_ALLOWED);\\n }\\n\\n uint256 startingAllowance = 0;\\n if (spender == src) {\\n startingAllowance = type(uint256).max;\\n } else {\\n startingAllowance = transferAllowances[src][spender];\\n }\\n\\n MathError mathErr;\\n uint256 allowanceNew;\\n uint256 srcTokensNew;\\n uint256 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, 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, tokens);\\n if (mathErr != MathError.NO_ERROR) {\\n return fail(Error.MATH_ERROR, FailureInfo.TRANSFER_TOO_MUCH);\\n }\\n\\n accountTokens[src].tokens = srcTokensNew;\\n accountTokens[dst].tokens = dstTokensNew;\\n\\n if (startingAllowance != type(uint256).max) {\\n transferAllowances[src][spender] = allowanceNew;\\n }\\n\\n emit Transfer(src, dst, tokens);\\n\\n return uint256(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)\\n external\\n override\\n nonReentrant\\n returns (bool)\\n {\\n return\\n transferTokens(msg.sender, msg.sender, dst, amount) ==\\n uint256(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(\\n address src,\\n address dst,\\n uint256 amount\\n ) external override nonReentrant returns (bool) {\\n return\\n transferTokens(msg.sender, src, dst, amount) ==\\n uint256(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)\\n external\\n override\\n returns (bool)\\n {\\n transferAllowances[msg.sender][spender] = amount;\\n emit Approval(msg.sender, 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)\\n external\\n view\\n override\\n returns (uint256)\\n {\\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 override returns (uint256) {\\n return accountTokens[owner].tokens;\\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)\\n external\\n override\\n returns (uint256)\\n {\\n (MathError mErr, uint256 balance) = mulScalarTruncate(\\n Exp({mantissa: exchangeRateCurrent()}),\\n accountTokens[owner].tokens\\n );\\n require(mErr == MathError.NO_ERROR, \\\"CT06\\\");\\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)\\n external\\n view\\n override\\n returns (\\n uint256,\\n uint256,\\n uint256,\\n uint256\\n )\\n {\\n uint256 cTokenBalance = accountTokens[account].tokens;\\n uint256 borrowBalance;\\n uint256 exchangeRateMantissa;\\n\\n MathError mErr;\\n\\n (mErr, borrowBalance) = borrowBalanceStoredInternal(account);\\n if (mErr != MathError.NO_ERROR) {\\n return (uint256(Error.MATH_ERROR), 0, 0, 0);\\n }\\n\\n (mErr, exchangeRateMantissa) = exchangeRateStoredInternal();\\n if (mErr != MathError.NO_ERROR) {\\n return (uint256(Error.MATH_ERROR), 0, 0, 0);\\n }\\n\\n return (\\n uint256(Error.NO_ERROR),\\n cTokenBalance,\\n borrowBalance,\\n exchangeRateMantissa\\n );\\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 virtual returns (uint256) {\\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 override returns (uint256) {\\n return\\n interestRateModel.getBorrowRate(\\n getCashPrior(),\\n totalBorrows,\\n totalReserves\\n );\\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 override returns (uint256) {\\n return\\n interestRateModel.getSupplyRate(\\n getCashPrior(),\\n totalBorrows,\\n totalReserves,\\n reserveFactorMantissa\\n );\\n }\\n\\n /**\\n * @notice Returns the current total borrows plus accrued interest\\n * @return The total borrows with interest\\n */\\n function totalBorrowsCurrent()\\n external\\n override\\n nonReentrant\\n returns (uint256)\\n {\\n require(accrueInterest() == uint256(Error.NO_ERROR), \\\"CT07\\\");\\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)\\n external\\n override\\n nonReentrant\\n returns (uint256)\\n {\\n require(accrueInterest() == uint256(Error.NO_ERROR), \\\"CT07\\\");\\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)\\n public\\n view\\n override\\n returns (uint256)\\n {\\n (MathError err, uint256 result) = borrowBalanceStoredInternal(account);\\n require(err == MathError.NO_ERROR, \\\"CT08\\\");\\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)\\n internal\\n view\\n returns (MathError, uint256)\\n {\\n MathError mathErr;\\n uint256 principalTimesIndex;\\n uint256 result;\\n\\n BorrowSnapshot storage borrowSnapshot = accountBorrows[account];\\n\\n if (borrowSnapshot.principal == 0) {\\n return (MathError.NO_ERROR, 0);\\n }\\n\\n (mathErr, principalTimesIndex) = mulUInt(\\n borrowSnapshot.principal,\\n borrowIndex\\n );\\n if (mathErr != MathError.NO_ERROR) {\\n return (mathErr, 0);\\n }\\n\\n (mathErr, result) = divUInt(\\n principalTimesIndex,\\n borrowSnapshot.interestIndex\\n );\\n if (mathErr != MathError.NO_ERROR) {\\n return (mathErr, 0);\\n }\\n\\n return (MathError.NO_ERROR, result);\\n }\\n\\n function getBorrowerPrincipalStored(address account)\\n public\\n view\\n returns (uint256 borrowed)\\n {\\n borrowed = accountBorrows[account].principal;\\n }\\n\\n function getSupplierSnapshotStored(address account)\\n public\\n view\\n returns (\\n uint256 tokens,\\n uint256 underlyingAmount,\\n uint256 suppliedAt,\\n uint256 promisedSupplyRate\\n )\\n {\\n tokens = accountTokens[account].tokens;\\n underlyingAmount = accountTokens[account].underlyingAmount;\\n suppliedAt = accountTokens[account].suppliedAt;\\n promisedSupplyRate = accountTokens[account].promisedSupplyRate;\\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()\\n public\\n override\\n nonReentrant\\n returns (uint256)\\n {\\n require(accrueInterest() == uint256(Error.NO_ERROR), \\\"CT07\\\");\\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 override returns (uint256) {\\n (MathError err, uint256 result) = exchangeRateStoredInternal();\\n require(err == MathError.NO_ERROR, \\\"CT09\\\");\\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()\\n internal\\n view\\n virtual\\n returns (MathError, uint256)\\n {\\n uint256 _totalSupply = totalSupply;\\n if (_totalSupply == 0) {\\n return (MathError.NO_ERROR, initialExchangeRateMantissa);\\n } else {\\n MathError error;\\n uint256 exchangeRate;\\n uint256 totalCash = getCashPrior();\\n if (interestRateModel.isTropykusInterestRateModel()) {\\n (error, exchangeRate) = tropykusExchangeRateStoredInternal(\\n msg.sender\\n );\\n if (error == MathError.NO_ERROR) {\\n return (MathError.NO_ERROR, exchangeRate);\\n } else {\\n return (MathError.NO_ERROR, initialExchangeRateMantissa);\\n }\\n }\\n return\\n interestRateModel.getExchangeRate(\\n totalCash,\\n totalBorrows,\\n totalReserves,\\n totalSupply\\n );\\n }\\n }\\n\\n function tropykusExchangeRateStoredInternal(address redeemer)\\n internal\\n view\\n returns (MathError, uint256)\\n {\\n if (totalSupply == 0) {\\n return (MathError.NO_ERROR, initialExchangeRateMantissa);\\n } else {\\n SupplySnapshot storage supplySnapshot = accountTokens[redeemer];\\n if (supplySnapshot.suppliedAt == 0) {\\n return (MathError.DIVISION_BY_ZERO, 0);\\n }\\n (, uint256 interestFactorMantissa, ) = tropykusInterestAccrued(\\n redeemer\\n );\\n Exp memory interestFactor = Exp({mantissa: interestFactorMantissa});\\n uint256 currentUnderlying = supplySnapshot.underlyingAmount;\\n Exp memory redeemerUnderlying = Exp({mantissa: currentUnderlying});\\n (, Exp memory realAmount) = mulExp(\\n interestFactor,\\n redeemerUnderlying\\n );\\n (, Exp memory exchangeRate) = getExp(\\n realAmount.mantissa,\\n supplySnapshot.tokens\\n );\\n return (MathError.NO_ERROR, exchangeRate.mantissa);\\n }\\n }\\n\\n function tropykusInterestAccrued(address account)\\n internal\\n view\\n returns (\\n MathError,\\n uint256,\\n uint256\\n )\\n {\\n SupplySnapshot storage supplySnapshot = accountTokens[account];\\n uint256 promisedSupplyRate = supplySnapshot.promisedSupplyRate;\\n Exp memory expectedSupplyRatePerBlock = Exp({\\n mantissa: promisedSupplyRate\\n });\\n (, uint256 delta) = subUInt(\\n accrualBlockNumber,\\n supplySnapshot.suppliedAt\\n );\\n (, Exp memory expectedSupplyRatePerBlockWithDelta) = mulScalar(\\n expectedSupplyRatePerBlock,\\n delta\\n );\\n (, Exp memory interestFactor) = addExp(\\n Exp({mantissa: 1e18}),\\n expectedSupplyRatePerBlockWithDelta\\n );\\n uint256 currentUnderlying = supplySnapshot.underlyingAmount;\\n Exp memory redeemerUnderlying = Exp({mantissa: currentUnderlying});\\n (, Exp memory realAmount) = mulExp(interestFactor, redeemerUnderlying);\\n (, uint256 interestEarned) = subUInt(\\n realAmount.mantissa,\\n currentUnderlying\\n );\\n return (MathError.NO_ERROR, interestFactor.mantissa, interestEarned);\\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 override returns (uint256) {\\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 override returns (uint256) {\\n uint256 currentBlockNumber = getBlockNumber();\\n uint256 accrualBlockNumberPrior = accrualBlockNumber;\\n\\n if (accrualBlockNumberPrior == currentBlockNumber) {\\n return uint256(Error.NO_ERROR);\\n }\\n\\n uint256 cashPrior = getCashPrior();\\n uint256 borrowsPrior = totalBorrows;\\n uint256 reservesPrior = totalReserves;\\n uint256 borrowIndexPrior = borrowIndex;\\n\\n uint256 borrowRateMantissa = interestRateModel.getBorrowRate(\\n cashPrior,\\n borrowsPrior,\\n reservesPrior\\n );\\n require(borrowRateMantissa <= borrowRateMaxMantissa, \\\"CT10\\\");\\n\\n (MathError mathErr, uint256 blockDelta) = subUInt(\\n currentBlockNumber,\\n accrualBlockNumberPrior\\n );\\n require(mathErr == MathError.NO_ERROR, \\\"CT11\\\");\\n\\n Exp memory simpleInterestFactor;\\n uint256 interestAccumulated;\\n uint256 totalBorrowsNew;\\n uint256 totalReservesNew;\\n uint256 borrowIndexNew;\\n\\n (mathErr, simpleInterestFactor) = mulScalar(\\n Exp({mantissa: borrowRateMantissa}),\\n blockDelta\\n );\\n if (mathErr != MathError.NO_ERROR) {\\n return\\n failOpaque(\\n Error.MATH_ERROR,\\n FailureInfo\\n .ACCRUE_INTEREST_SIMPLE_INTEREST_FACTOR_CALCULATION_FAILED,\\n uint256(mathErr)\\n );\\n }\\n\\n (mathErr, interestAccumulated) = mulScalarTruncate(\\n simpleInterestFactor,\\n borrowsPrior\\n );\\n if (mathErr != MathError.NO_ERROR) {\\n return\\n failOpaque(\\n Error.MATH_ERROR,\\n FailureInfo\\n .ACCRUE_INTEREST_ACCUMULATED_INTEREST_CALCULATION_FAILED,\\n uint256(mathErr)\\n );\\n }\\n\\n (mathErr, totalBorrowsNew) = addUInt(interestAccumulated, borrowsPrior);\\n if (mathErr != MathError.NO_ERROR) {\\n return\\n failOpaque(\\n Error.MATH_ERROR,\\n FailureInfo\\n .ACCRUE_INTEREST_NEW_TOTAL_BORROWS_CALCULATION_FAILED,\\n uint256(mathErr)\\n );\\n }\\n\\n (mathErr, totalReservesNew) = mulScalarTruncateAddUInt(\\n Exp({mantissa: reserveFactorMantissa}),\\n interestAccumulated,\\n reservesPrior\\n );\\n if (mathErr != MathError.NO_ERROR) {\\n return\\n failOpaque(\\n Error.MATH_ERROR,\\n FailureInfo\\n .ACCRUE_INTEREST_NEW_TOTAL_RESERVES_CALCULATION_FAILED,\\n uint256(mathErr)\\n );\\n }\\n\\n if (interestRateModel.isTropykusInterestRateModel()) {\\n (mathErr, totalReservesNew) = newReserves(\\n borrowRateMantissa,\\n cashPrior,\\n borrowsPrior,\\n reservesPrior,\\n interestAccumulated\\n );\\n if (mathErr != MathError.NO_ERROR) {\\n return\\n failOpaque(\\n Error.MATH_ERROR,\\n FailureInfo\\n .ACCRUE_INTEREST_NEW_TOTAL_RESERVES_CALCULATION_FAILED,\\n uint256(mathErr)\\n );\\n }\\n }\\n\\n (mathErr, borrowIndexNew) = mulScalarTruncateAddUInt(\\n simpleInterestFactor,\\n borrowIndexPrior,\\n borrowIndexPrior\\n );\\n if (mathErr != MathError.NO_ERROR) {\\n return\\n failOpaque(\\n Error.MATH_ERROR,\\n FailureInfo\\n .ACCRUE_INTEREST_NEW_BORROW_INDEX_CALCULATION_FAILED,\\n uint256(mathErr)\\n );\\n }\\n\\n accrualBlockNumber = currentBlockNumber;\\n borrowIndex = borrowIndexNew;\\n totalBorrows = totalBorrowsNew;\\n totalReserves = totalReservesNew;\\n\\n emit AccrueInterest(\\n cashPrior,\\n interestAccumulated,\\n borrowIndexNew,\\n totalBorrowsNew\\n );\\n\\n return uint256(Error.NO_ERROR);\\n }\\n\\n function newReserves(\\n uint256 borrowRateMantissa,\\n uint256 cashPrior,\\n uint256 borrowsPrior,\\n uint256 reservesPrior,\\n uint256 interestAccumulated\\n ) internal view returns (MathError mathErr, uint256 totalReservesNew) {\\n uint256 newReserveFactorMantissa;\\n uint256 utilizationRate = interestRateModel.utilizationRate(\\n cashPrior,\\n borrowsPrior,\\n reservesPrior\\n );\\n uint256 expectedSupplyRate = interestRateModel.getSupplyRate(\\n cashPrior,\\n borrowsPrior,\\n reservesPrior,\\n reserveFactorMantissa\\n );\\n if (\\n interestRateModel.isAboveOptimal(\\n cashPrior,\\n borrowsPrior,\\n reservesPrior\\n )\\n ) {\\n (mathErr, newReserveFactorMantissa) = mulScalarTruncate(\\n Exp({mantissa: utilizationRate}),\\n borrowRateMantissa\\n );\\n if (mathErr != MathError.NO_ERROR) {\\n return (mathErr, 0);\\n }\\n (mathErr, newReserveFactorMantissa) = subUInt(\\n newReserveFactorMantissa,\\n expectedSupplyRate\\n );\\n if (mathErr != MathError.NO_ERROR) {\\n return (mathErr, 0);\\n }\\n (mathErr, totalReservesNew) = mulScalarTruncateAddUInt(\\n Exp({mantissa: newReserveFactorMantissa}),\\n interestAccumulated,\\n reservesPrior\\n );\\n if (mathErr != MathError.NO_ERROR) {\\n return (mathErr, 0);\\n }\\n } else {\\n mathErr = MathError.NO_ERROR;\\n totalReservesNew = reservesPrior;\\n }\\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(uint256 mintAmount)\\n internal\\n nonReentrant\\n returns (uint256, uint256)\\n {\\n if (WhitelistInterface(whitelist).enabled()) {\\n require(WhitelistInterface(whitelist).exist(msg.sender), \\\"CT26\\\");\\n }\\n uint256 error = accrueInterest();\\n if (error != uint256(Error.NO_ERROR)) {\\n return (\\n fail(Error(error), FailureInfo.MINT_ACCRUE_INTEREST_FAILED),\\n 0\\n );\\n }\\n return mintFresh(msg.sender, mintAmount);\\n }\\n\\n struct MintLocalVars {\\n Error err;\\n MathError mathErr;\\n uint256 exchangeRateMantissa;\\n uint256 mintTokens;\\n uint256 totalSupplyNew;\\n uint256 accountTokensNew;\\n uint256 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, uint256 mintAmount)\\n internal\\n returns (uint256, uint256)\\n {\\n uint256 allowed = comptroller.mintAllowed(\\n address(this),\\n minter,\\n mintAmount\\n );\\n if (allowed != 0) {\\n return (\\n failOpaque(\\n Error.COMPTROLLER_REJECTION,\\n FailureInfo.MINT_COMPTROLLER_REJECTION,\\n allowed\\n ),\\n 0\\n );\\n }\\n\\n if (accrualBlockNumber != getBlockNumber()) {\\n return (\\n fail(Error.MARKET_NOT_FRESH, FailureInfo.MINT_FRESHNESS_CHECK),\\n 0\\n );\\n }\\n\\n MintLocalVars memory vars;\\n\\n (\\n vars.mathErr,\\n vars.exchangeRateMantissa\\n ) = exchangeRateStoredInternal();\\n if (vars.mathErr != MathError.NO_ERROR) {\\n return (\\n failOpaque(\\n Error.MATH_ERROR,\\n FailureInfo.MINT_EXCHANGE_RATE_READ_FAILED,\\n uint256(vars.mathErr)\\n ),\\n 0\\n );\\n }\\n if (interestRateModel.isTropykusInterestRateModel()) {\\n SupplySnapshot storage supplySnapshot = accountTokens[minter];\\n (, uint256 newTotalSupply) = addUInt(\\n supplySnapshot.underlyingAmount,\\n mintAmount\\n );\\n require(newTotalSupply <= 0.1e18, \\\"CT24\\\");\\n }\\n vars.actualMintAmount = doTransferIn(minter, mintAmount);\\n\\n (vars.mathErr, vars.mintTokens) = divScalarByExpTruncate(\\n vars.actualMintAmount,\\n Exp({mantissa: vars.exchangeRateMantissa})\\n );\\n require(vars.mathErr == MathError.NO_ERROR, \\\"CT12\\\");\\n\\n (vars.mathErr, vars.totalSupplyNew) = addUInt(\\n totalSupply,\\n vars.mintTokens\\n );\\n require(vars.mathErr == MathError.NO_ERROR, \\\"CT13\\\");\\n\\n (vars.mathErr, vars.accountTokensNew) = addUInt(\\n accountTokens[minter].tokens,\\n vars.mintTokens\\n );\\n require(vars.mathErr == MathError.NO_ERROR, \\\"CT14\\\");\\n\\n uint256 currentSupplyRate = interestRateModel.getSupplyRate(\\n getCashPrior(),\\n totalBorrows,\\n totalReserves,\\n reserveFactorMantissa\\n );\\n\\n bool isTropykusInterestRateModel = interestRateModel\\n .isTropykusInterestRateModel();\\n\\n if (accountTokens[minter].tokens > 0) {\\n Exp memory updatedUnderlying;\\n if (isTropykusInterestRateModel) {\\n (, uint256 interestFactorMantissa, ) = tropykusInterestAccrued(\\n minter\\n );\\n Exp memory interestFactor = Exp({\\n mantissa: interestFactorMantissa\\n });\\n uint256 currentUnderlyingAmount = accountTokens[minter]\\n .underlyingAmount;\\n MathError mErrorNewAmount;\\n (mErrorNewAmount, updatedUnderlying) = mulExp(\\n Exp({mantissa: currentUnderlyingAmount}),\\n interestFactor\\n );\\n if (mErrorNewAmount != MathError.NO_ERROR) {\\n return (\\n failOpaque(\\n Error.MATH_ERROR,\\n FailureInfo.MINT_EXCHANGE_CALCULATION_FAILED,\\n uint256(mErrorNewAmount)\\n ),\\n 0\\n );\\n }\\n } else {\\n uint256 currentTokens = accountTokens[minter].tokens;\\n MathError mErrorUpdatedUnderlying;\\n (mErrorUpdatedUnderlying, updatedUnderlying) = mulExp(\\n Exp({mantissa: currentTokens}),\\n Exp({mantissa: vars.exchangeRateMantissa})\\n );\\n if (mErrorUpdatedUnderlying != MathError.NO_ERROR) {\\n return (\\n failOpaque(\\n Error.MATH_ERROR,\\n FailureInfo.MINT_EXCHANGE_CALCULATION_FAILED,\\n uint256(mErrorUpdatedUnderlying)\\n ),\\n 0\\n );\\n }\\n }\\n (, mintAmount) = addUInt(updatedUnderlying.mantissa, mintAmount);\\n }\\n\\n totalSupply = vars.totalSupplyNew;\\n accountTokens[minter] = SupplySnapshot({\\n tokens: vars.accountTokensNew,\\n underlyingAmount: mintAmount,\\n suppliedAt: accrualBlockNumber,\\n promisedSupplyRate: currentSupplyRate\\n });\\n\\n emit Mint(minter, vars.actualMintAmount, vars.mintTokens);\\n emit Transfer(address(this), minter, vars.mintTokens);\\n\\n return (uint256(Error.NO_ERROR), vars.actualMintAmount);\\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(uint256 redeemAmount)\\n internal\\n nonReentrant\\n returns (uint256)\\n {\\n uint256 error = accrueInterest();\\n if (error != uint256(Error.NO_ERROR)) {\\n return\\n fail(Error(error), FailureInfo.REDEEM_ACCRUE_INTEREST_FAILED);\\n }\\n return redeemFresh(payable(msg.sender), redeemAmount);\\n }\\n\\n struct RedeemLocalVars {\\n Error err;\\n MathError mathErr;\\n uint256 exchangeRateMantissa;\\n uint256 redeemTokens;\\n uint256 redeemAmount;\\n uint256 totalSupplyNew;\\n uint256 accountTokensNew;\\n uint256 newSubsidyFund;\\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 redeemAmountIn The number of underlying tokens to receive from redeeming cTokens\\n * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)\\n */\\n function redeemFresh(address payable redeemer, uint256 redeemAmountIn)\\n internal\\n returns (uint256)\\n {\\n require(redeemAmountIn > 0, \\\"CT15\\\");\\n\\n RedeemLocalVars memory vars;\\n\\n SupplySnapshot storage supplySnapshot = accountTokens[redeemer];\\n\\n (\\n vars.mathErr,\\n vars.exchangeRateMantissa\\n ) = exchangeRateStoredInternal();\\n if (vars.mathErr != MathError.NO_ERROR) {\\n return\\n failOpaque(\\n Error.MATH_ERROR,\\n FailureInfo.REDEEM_EXCHANGE_RATE_READ_FAILED,\\n uint256(vars.mathErr)\\n );\\n }\\n\\n uint256 interestEarned;\\n uint256 subsidyFundPortion;\\n uint256 currentUnderlying;\\n\\n bool isTropykusInterestRateModel = interestRateModel\\n .isTropykusInterestRateModel();\\n if (isTropykusInterestRateModel) {\\n currentUnderlying = supplySnapshot.underlyingAmount;\\n (, , interestEarned) = tropykusInterestAccrued(redeemer);\\n }\\n supplySnapshot.promisedSupplyRate = interestRateModel.getSupplyRate(\\n getCashPrior(),\\n totalBorrows,\\n totalReserves,\\n reserveFactorMantissa\\n );\\n\\n if (\\n isTropykusInterestRateModel &&\\n !interestRateModel.isAboveOptimal(\\n getCashPrior(),\\n totalBorrows,\\n totalReserves\\n )\\n ) {\\n uint256 borrowRate = interestRateModel.getBorrowRate(\\n getCashPrior(),\\n totalBorrows,\\n totalReserves\\n );\\n\\n uint256 utilizationRate = interestRateModel.utilizationRate(\\n getCashPrior(),\\n totalBorrows,\\n totalReserves\\n );\\n\\n (, uint256 estimatedEarning) = mulScalarTruncate(\\n Exp({mantissa: borrowRate}),\\n utilizationRate\\n );\\n\\n (, subsidyFundPortion) = subUInt(\\n supplySnapshot.promisedSupplyRate,\\n estimatedEarning\\n );\\n (, Exp memory subsidyFactor) = getExp(\\n subsidyFundPortion,\\n supplySnapshot.promisedSupplyRate\\n );\\n (, subsidyFundPortion) = mulScalarTruncate(\\n subsidyFactor,\\n interestEarned\\n );\\n }\\n\\n vars.redeemAmount = redeemAmountIn;\\n\\n if (isTropykusInterestRateModel) {\\n (, Exp memory num) = mulExp(\\n vars.redeemAmount,\\n supplySnapshot.tokens\\n );\\n (, Exp memory realTokensWithdrawAmount) = getExp(\\n num.mantissa,\\n currentUnderlying\\n );\\n vars.redeemTokens = realTokensWithdrawAmount.mantissa;\\n } else {\\n (vars.mathErr, vars.redeemTokens) = divScalarByExpTruncate(\\n redeemAmountIn,\\n Exp({mantissa: vars.exchangeRateMantissa})\\n );\\n if (vars.mathErr != MathError.NO_ERROR) {\\n return\\n failOpaque(\\n Error.MATH_ERROR,\\n FailureInfo.REDEEM_EXCHANGE_AMOUNT_CALCULATION_FAILED,\\n uint256(vars.mathErr)\\n );\\n }\\n }\\n // }\\n\\n uint256 allowed = comptroller.redeemAllowed(\\n address(this),\\n redeemer,\\n vars.redeemTokens\\n );\\n if (allowed != 0) {\\n return\\n failOpaque(\\n Error.COMPTROLLER_REJECTION,\\n FailureInfo.REDEEM_COMPTROLLER_REJECTION,\\n allowed\\n );\\n }\\n\\n if (accrualBlockNumber != getBlockNumber()) {\\n return\\n fail(\\n Error.MARKET_NOT_FRESH,\\n FailureInfo.REDEEM_FRESHNESS_CHECK\\n );\\n }\\n\\n (vars.mathErr, vars.totalSupplyNew) = subUInt(\\n totalSupply,\\n vars.redeemTokens\\n );\\n if (vars.mathErr != MathError.NO_ERROR) {\\n return\\n failOpaque(\\n Error.MATH_ERROR,\\n FailureInfo.REDEEM_NEW_TOTAL_SUPPLY_CALCULATION_FAILED,\\n uint256(vars.mathErr)\\n );\\n }\\n\\n (, vars.newSubsidyFund) = subUInt(subsidyFund, subsidyFundPortion);\\n\\n (vars.mathErr, vars.accountTokensNew) = subUInt(\\n supplySnapshot.tokens,\\n vars.redeemTokens\\n );\\n if (vars.mathErr != MathError.NO_ERROR) {\\n return\\n failOpaque(\\n Error.MATH_ERROR,\\n FailureInfo.REDEEM_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED,\\n uint256(vars.mathErr)\\n );\\n }\\n\\n uint256 cash = getCashPrior();\\n if (isTropykusInterestRateModel) {\\n cash = address(this).balance;\\n }\\n\\n if (cash < vars.redeemAmount) {\\n return\\n fail(\\n Error.TOKEN_INSUFFICIENT_CASH,\\n FailureInfo.REDEEM_TRANSFER_OUT_NOT_POSSIBLE\\n );\\n }\\n\\n doTransferOut(redeemer, vars.redeemAmount);\\n\\n totalSupply = vars.totalSupplyNew;\\n subsidyFund = vars.newSubsidyFund;\\n supplySnapshot.tokens = vars.accountTokensNew;\\n supplySnapshot.suppliedAt = accrualBlockNumber;\\n (, supplySnapshot.underlyingAmount) = subUInt(\\n supplySnapshot.underlyingAmount,\\n vars.redeemAmount\\n );\\n\\n emit Transfer(redeemer, address(this), vars.redeemTokens);\\n emit Redeem(redeemer, vars.redeemAmount, vars.redeemTokens);\\n\\n comptroller.redeemVerify(\\n address(this),\\n redeemer,\\n vars.redeemAmount,\\n vars.redeemTokens\\n );\\n\\n return uint256(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(uint256 borrowAmount)\\n internal\\n nonReentrant\\n returns (uint256)\\n {\\n uint256 error = accrueInterest();\\n if (error != uint256(Error.NO_ERROR)) {\\n return\\n fail(Error(error), FailureInfo.BORROW_ACCRUE_INTEREST_FAILED);\\n }\\n return borrowFresh(payable(msg.sender), borrowAmount);\\n }\\n\\n struct BorrowLocalVars {\\n MathError mathErr;\\n uint256 accountBorrows;\\n uint256 accountBorrowsNew;\\n uint256 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, uint256 borrowAmount)\\n internal\\n returns (uint256)\\n {\\n uint256 allowed = comptroller.borrowAllowed(\\n address(this),\\n borrower,\\n borrowAmount\\n );\\n if (allowed != 0) {\\n return\\n failOpaque(\\n Error.COMPTROLLER_REJECTION,\\n FailureInfo.BORROW_COMPTROLLER_REJECTION,\\n allowed\\n );\\n }\\n\\n if (accrualBlockNumber != getBlockNumber()) {\\n return\\n fail(\\n Error.MARKET_NOT_FRESH,\\n FailureInfo.BORROW_FRESHNESS_CHECK\\n );\\n }\\n\\n if (getCashPrior() < borrowAmount) {\\n return\\n fail(\\n Error.TOKEN_INSUFFICIENT_CASH,\\n FailureInfo.BORROW_CASH_NOT_AVAILABLE\\n );\\n }\\n\\n BorrowLocalVars memory vars;\\n\\n (vars.mathErr, vars.accountBorrows) = borrowBalanceStoredInternal(\\n borrower\\n );\\n if (vars.mathErr != MathError.NO_ERROR) {\\n return\\n failOpaque(\\n Error.MATH_ERROR,\\n FailureInfo.BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED,\\n uint256(vars.mathErr)\\n );\\n }\\n\\n (vars.mathErr, vars.accountBorrowsNew) = addUInt(\\n vars.accountBorrows,\\n borrowAmount\\n );\\n if (vars.mathErr != MathError.NO_ERROR) {\\n return\\n failOpaque(\\n Error.MATH_ERROR,\\n FailureInfo\\n .BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED,\\n uint256(vars.mathErr)\\n );\\n }\\n\\n (vars.mathErr, vars.totalBorrowsNew) = addUInt(\\n totalBorrows,\\n borrowAmount\\n );\\n if (interestRateModel.isTropykusInterestRateModel()) {\\n require(vars.totalBorrowsNew <= 0.1e18, \\\"CT25\\\");\\n }\\n if (vars.mathErr != MathError.NO_ERROR) {\\n return\\n failOpaque(\\n Error.MATH_ERROR,\\n FailureInfo.BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED,\\n uint256(vars.mathErr)\\n );\\n }\\n\\n doTransferOut(borrower, borrowAmount);\\n\\n accountBorrows[borrower].principal = vars.accountBorrowsNew;\\n accountBorrows[borrower].interestIndex = borrowIndex;\\n totalBorrows = vars.totalBorrowsNew;\\n\\n emit Borrow(\\n borrower,\\n borrowAmount,\\n vars.accountBorrowsNew,\\n vars.totalBorrowsNew\\n );\\n\\n return uint256(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(uint256 repayAmount)\\n internal\\n nonReentrant\\n returns (uint256, uint256)\\n {\\n uint256 error = accrueInterest();\\n if (error != uint256(Error.NO_ERROR)) {\\n return (\\n fail(\\n Error(error),\\n FailureInfo.REPAY_BORROW_ACCRUE_INTEREST_FAILED\\n ),\\n 0\\n );\\n }\\n return repayBorrowFresh(msg.sender, msg.sender, repayAmount);\\n }\\n\\n struct RepayBorrowLocalVars {\\n Error err;\\n MathError mathErr;\\n uint256 repayAmount;\\n uint256 borrowerIndex;\\n uint256 accountBorrows;\\n uint256 accountBorrowsNew;\\n uint256 totalBorrowsNew;\\n uint256 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(\\n address payer,\\n address borrower,\\n uint256 repayAmount\\n ) internal returns (uint256, uint256) {\\n uint256 allowed = comptroller.repayBorrowAllowed(\\n address(this),\\n payer,\\n borrower,\\n repayAmount\\n );\\n if (allowed != 0) {\\n return (\\n failOpaque(\\n Error.COMPTROLLER_REJECTION,\\n FailureInfo.REPAY_BORROW_COMPTROLLER_REJECTION,\\n allowed\\n ),\\n 0\\n );\\n }\\n\\n if (accrualBlockNumber != getBlockNumber()) {\\n return (\\n fail(\\n Error.MARKET_NOT_FRESH,\\n FailureInfo.REPAY_BORROW_FRESHNESS_CHECK\\n ),\\n 0\\n );\\n }\\n\\n RepayBorrowLocalVars memory vars;\\n\\n vars.borrowerIndex = accountBorrows[borrower].interestIndex;\\n\\n (vars.mathErr, vars.accountBorrows) = borrowBalanceStoredInternal(\\n borrower\\n );\\n if (vars.mathErr != MathError.NO_ERROR) {\\n return (\\n failOpaque(\\n Error.MATH_ERROR,\\n FailureInfo\\n .REPAY_BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED,\\n uint256(vars.mathErr)\\n ),\\n 0\\n );\\n }\\n\\n if (repayAmount == type(uint256).max) {\\n vars.repayAmount = vars.accountBorrows;\\n } else {\\n vars.repayAmount = repayAmount;\\n }\\n\\n vars.actualRepayAmount = doTransferIn(payer, vars.repayAmount);\\n\\n (vars.mathErr, vars.accountBorrowsNew) = subUInt(\\n vars.accountBorrows,\\n vars.actualRepayAmount\\n );\\n require(vars.mathErr == MathError.NO_ERROR, \\\"CT16\\\");\\n\\n (vars.mathErr, vars.totalBorrowsNew) = subUInt(\\n totalBorrows,\\n vars.actualRepayAmount\\n );\\n require(vars.mathErr == MathError.NO_ERROR, \\\"CT17\\\");\\n\\n accountBorrows[borrower].principal = vars.accountBorrowsNew;\\n accountBorrows[borrower].interestIndex = borrowIndex;\\n totalBorrows = vars.totalBorrowsNew;\\n\\n emit RepayBorrow(\\n payer,\\n borrower,\\n vars.actualRepayAmount,\\n vars.accountBorrowsNew,\\n vars.totalBorrowsNew\\n );\\n\\n return (uint256(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(\\n address borrower,\\n uint256 repayAmount,\\n CTokenInterface cTokenCollateral\\n ) internal nonReentrant returns (uint256, uint256) {\\n uint256 error = accrueInterest();\\n if (error != uint256(Error.NO_ERROR)) {\\n return (\\n fail(\\n Error(error),\\n FailureInfo.LIQUIDATE_ACCRUE_BORROW_INTEREST_FAILED\\n ),\\n 0\\n );\\n }\\n\\n error = cTokenCollateral.accrueInterest();\\n if (error != uint256(Error.NO_ERROR)) {\\n return (\\n fail(\\n Error(error),\\n FailureInfo.LIQUIDATE_ACCRUE_COLLATERAL_INTEREST_FAILED\\n ),\\n 0\\n );\\n }\\n\\n // liquidateBorrowFresh emits borrow-specific logs on errors, so we don't need to\\n return\\n liquidateBorrowFresh(\\n msg.sender,\\n borrower,\\n repayAmount,\\n cTokenCollateral\\n );\\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(\\n address liquidator,\\n address borrower,\\n uint256 repayAmount,\\n CTokenInterface cTokenCollateral\\n ) internal returns (uint256, uint256) {\\n uint256 allowed = comptroller.liquidateBorrowAllowed(\\n address(this),\\n address(cTokenCollateral),\\n liquidator,\\n borrower,\\n repayAmount\\n );\\n if (allowed != 0) {\\n return (\\n failOpaque(\\n Error.COMPTROLLER_REJECTION,\\n FailureInfo.LIQUIDATE_COMPTROLLER_REJECTION,\\n allowed\\n ),\\n 0\\n );\\n }\\n\\n if (accrualBlockNumber != getBlockNumber()) {\\n return (\\n fail(\\n Error.MARKET_NOT_FRESH,\\n FailureInfo.LIQUIDATE_FRESHNESS_CHECK\\n ),\\n 0\\n );\\n }\\n\\n if (cTokenCollateral.accrualBlockNumber() != getBlockNumber()) {\\n return (\\n fail(\\n Error.MARKET_NOT_FRESH,\\n FailureInfo.LIQUIDATE_COLLATERAL_FRESHNESS_CHECK\\n ),\\n 0\\n );\\n }\\n\\n if (borrower == liquidator) {\\n return (\\n fail(\\n Error.INVALID_ACCOUNT_PAIR,\\n FailureInfo.LIQUIDATE_LIQUIDATOR_IS_BORROWER\\n ),\\n 0\\n );\\n }\\n\\n if (repayAmount == 0) {\\n return (\\n fail(\\n Error.INVALID_CLOSE_AMOUNT_REQUESTED,\\n FailureInfo.LIQUIDATE_CLOSE_AMOUNT_IS_ZERO\\n ),\\n 0\\n );\\n }\\n\\n if (repayAmount == type(uint256).max) {\\n return (\\n fail(\\n Error.INVALID_CLOSE_AMOUNT_REQUESTED,\\n FailureInfo.LIQUIDATE_CLOSE_AMOUNT_IS_UINT_MAX\\n ),\\n 0\\n );\\n }\\n\\n (\\n uint256 repayBorrowError,\\n uint256 actualRepayAmount\\n ) = repayBorrowFresh(liquidator, borrower, repayAmount);\\n if (repayBorrowError != uint256(Error.NO_ERROR)) {\\n return (\\n fail(\\n Error(repayBorrowError),\\n FailureInfo.LIQUIDATE_REPAY_BORROW_FRESH_FAILED\\n ),\\n 0\\n );\\n }\\n\\n (uint256 amountSeizeError, uint256 seizeTokens) = comptroller\\n .liquidateCalculateSeizeTokens(\\n address(this),\\n address(cTokenCollateral),\\n actualRepayAmount\\n );\\n require(amountSeizeError == uint256(Error.NO_ERROR), \\\"CT18\\\");\\n\\n require(cTokenCollateral.balanceOf(borrower) >= seizeTokens, \\\"CT19\\\");\\n\\n uint256 seizeError;\\n if (address(cTokenCollateral) == address(this)) {\\n seizeError = seizeInternal(\\n address(this),\\n liquidator,\\n borrower,\\n seizeTokens\\n );\\n } else {\\n seizeError = cTokenCollateral.seize(\\n liquidator,\\n borrower,\\n seizeTokens\\n );\\n }\\n\\n require(seizeError == uint256(Error.NO_ERROR), \\\"CT20\\\");\\n\\n emit LiquidateBorrow(\\n liquidator,\\n borrower,\\n actualRepayAmount,\\n address(cTokenCollateral),\\n seizeTokens\\n );\\n\\n return (uint256(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(\\n address liquidator,\\n address borrower,\\n uint256 seizeTokens\\n ) external override nonReentrant returns (uint256) {\\n return seizeInternal(msg.sender, liquidator, borrower, seizeTokens);\\n }\\n\\n struct SeizeVars {\\n uint256 seizeAmount;\\n uint256 exchangeRate;\\n uint256 borrowerTokensNew;\\n uint256 borrowerAmountNew;\\n uint256 liquidatorTokensNew;\\n uint256 liquidatorAmountNew;\\n uint256 totalCash;\\n uint256 supplyRate;\\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(\\n address seizerToken,\\n address liquidator,\\n address borrower,\\n uint256 seizeTokens\\n ) internal returns (uint256) {\\n uint256 allowed = comptroller.seizeAllowed(\\n address(this),\\n seizerToken,\\n liquidator,\\n borrower,\\n seizeTokens\\n );\\n if (allowed != 0) {\\n return\\n failOpaque(\\n Error.COMPTROLLER_REJECTION,\\n FailureInfo.LIQUIDATE_SEIZE_COMPTROLLER_REJECTION,\\n allowed\\n );\\n }\\n\\n if (borrower == liquidator) {\\n return\\n fail(\\n Error.INVALID_ACCOUNT_PAIR,\\n FailureInfo.LIQUIDATE_SEIZE_LIQUIDATOR_IS_BORROWER\\n );\\n }\\n\\n SeizeVars memory seizeVars;\\n\\n MathError mathErr;\\n\\n (mathErr, seizeVars.borrowerTokensNew) = subUInt(\\n accountTokens[borrower].tokens,\\n seizeTokens\\n );\\n if (mathErr != MathError.NO_ERROR) {\\n return\\n failOpaque(\\n Error.MATH_ERROR,\\n FailureInfo.LIQUIDATE_SEIZE_BALANCE_DECREMENT_FAILED,\\n uint256(mathErr)\\n );\\n }\\n\\n seizeVars.totalCash = getCashPrior();\\n seizeVars.supplyRate = interestRateModel.getSupplyRate(\\n seizeVars.totalCash,\\n totalBorrows,\\n totalReserves,\\n reserveFactorMantissa\\n );\\n\\n (, seizeVars.exchangeRate) = interestRateModel.getExchangeRate(\\n seizeVars.totalCash,\\n totalBorrows,\\n totalReserves,\\n totalSupply\\n );\\n\\n if (interestRateModel.isTropykusInterestRateModel()) {\\n (, seizeVars.exchangeRate) = tropykusExchangeRateStoredInternal(\\n borrower\\n );\\n }\\n\\n (, seizeVars.seizeAmount) = mulUInt(\\n seizeTokens,\\n seizeVars.exchangeRate\\n );\\n (, seizeVars.seizeAmount) = divUInt(seizeVars.seizeAmount, 1e18);\\n\\n (, seizeVars.borrowerAmountNew) = subUInt(\\n accountTokens[borrower].underlyingAmount,\\n seizeVars.seizeAmount\\n );\\n\\n (mathErr, seizeVars.liquidatorTokensNew) = addUInt(\\n accountTokens[liquidator].tokens,\\n seizeTokens\\n );\\n if (mathErr != MathError.NO_ERROR) {\\n return\\n failOpaque(\\n Error.MATH_ERROR,\\n FailureInfo.LIQUIDATE_SEIZE_BALANCE_INCREMENT_FAILED,\\n uint256(mathErr)\\n );\\n }\\n\\n (, seizeVars.liquidatorAmountNew) = addUInt(\\n accountTokens[liquidator].underlyingAmount,\\n seizeVars.seizeAmount\\n );\\n\\n accountTokens[borrower].tokens = seizeVars.borrowerTokensNew;\\n accountTokens[borrower].underlyingAmount = seizeVars.borrowerAmountNew;\\n accountTokens[borrower].suppliedAt = getBlockNumber();\\n accountTokens[borrower].promisedSupplyRate = seizeVars.supplyRate;\\n\\n accountTokens[liquidator].tokens = seizeVars.liquidatorTokensNew;\\n accountTokens[liquidator].underlyingAmount = seizeVars\\n .liquidatorAmountNew;\\n accountTokens[liquidator].suppliedAt = getBlockNumber();\\n accountTokens[liquidator].promisedSupplyRate = seizeVars.supplyRate;\\n\\n emit Transfer(borrower, liquidator, seizeTokens);\\n\\n return uint256(Error.NO_ERROR);\\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 payable newPendingAdmin)\\n external\\n override\\n returns (uint256)\\n {\\n if (msg.sender != admin) {\\n return\\n fail(\\n Error.UNAUTHORIZED,\\n FailureInfo.SET_PENDING_ADMIN_OWNER_CHECK\\n );\\n }\\n\\n address oldPendingAdmin = pendingAdmin;\\n\\n pendingAdmin = newPendingAdmin;\\n\\n emit NewPendingAdmin(oldPendingAdmin, newPendingAdmin);\\n\\n return uint256(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 override returns (uint256) {\\n if (msg.sender != pendingAdmin || msg.sender == address(0)) {\\n return\\n fail(\\n Error.UNAUTHORIZED,\\n FailureInfo.ACCEPT_ADMIN_PENDING_ADMIN_CHECK\\n );\\n }\\n\\n address oldAdmin = admin;\\n address oldPendingAdmin = pendingAdmin;\\n\\n admin = pendingAdmin;\\n\\n pendingAdmin = payable(address(0));\\n\\n emit NewAdmin(oldAdmin, admin);\\n emit NewPendingAdmin(oldPendingAdmin, pendingAdmin);\\n\\n return uint256(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)\\n public\\n override\\n returns (uint256)\\n {\\n if (msg.sender != admin) {\\n return\\n fail(\\n Error.UNAUTHORIZED,\\n FailureInfo.SET_COMPTROLLER_OWNER_CHECK\\n );\\n }\\n\\n ComptrollerInterface oldComptroller = comptroller;\\n require(newComptroller.isComptroller(), \\\"CT21\\\");\\n\\n comptroller = newComptroller;\\n\\n emit NewComptroller(oldComptroller, newComptroller);\\n\\n return uint256(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(uint256 newReserveFactorMantissa)\\n external\\n override\\n nonReentrant\\n returns (uint256)\\n {\\n uint256 error = accrueInterest();\\n if (error != uint256(Error.NO_ERROR)) {\\n return\\n fail(\\n Error(error),\\n FailureInfo.SET_RESERVE_FACTOR_ACCRUE_INTEREST_FAILED\\n );\\n }\\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(uint256 newReserveFactorMantissa)\\n internal\\n returns (uint256)\\n {\\n if (msg.sender != admin) {\\n return\\n fail(\\n Error.UNAUTHORIZED,\\n FailureInfo.SET_RESERVE_FACTOR_ADMIN_CHECK\\n );\\n }\\n\\n if (accrualBlockNumber != getBlockNumber()) {\\n return\\n fail(\\n Error.MARKET_NOT_FRESH,\\n FailureInfo.SET_RESERVE_FACTOR_FRESH_CHECK\\n );\\n }\\n\\n if (newReserveFactorMantissa > reserveFactorMaxMantissa) {\\n return\\n fail(\\n Error.BAD_INPUT,\\n FailureInfo.SET_RESERVE_FACTOR_BOUNDS_CHECK\\n );\\n }\\n\\n uint256 oldReserveFactorMantissa = reserveFactorMantissa;\\n reserveFactorMantissa = newReserveFactorMantissa;\\n\\n emit NewReserveFactor(\\n oldReserveFactorMantissa,\\n newReserveFactorMantissa\\n );\\n\\n return uint256(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(uint256 addAmount)\\n internal\\n nonReentrant\\n returns (uint256)\\n {\\n uint256 error = accrueInterest();\\n if (error != uint256(Error.NO_ERROR)) {\\n return\\n fail(\\n Error(error),\\n FailureInfo.ADD_RESERVES_ACCRUE_INTEREST_FAILED\\n );\\n }\\n\\n uint256 totalReservesNew;\\n uint256 actualAddAmount;\\n\\n if (accrualBlockNumber != getBlockNumber()) {\\n return (\\n fail(\\n Error.MARKET_NOT_FRESH,\\n FailureInfo.ADD_RESERVES_FRESH_CHECK\\n )\\n );\\n }\\n\\n actualAddAmount = doTransferIn(msg.sender, addAmount);\\n\\n totalReservesNew = totalReserves + actualAddAmount;\\n\\n require(totalReservesNew >= totalReserves, \\\"CT22\\\");\\n\\n totalReserves = totalReservesNew;\\n\\n emit ReservesAdded(msg.sender, actualAddAmount, totalReservesNew);\\n\\n return (uint256(Error.NO_ERROR));\\n }\\n\\n function _addSubsidyInternal(uint256 addAmount)\\n internal\\n nonReentrant\\n returns (uint256)\\n {\\n uint256 error = accrueInterest();\\n if (error != uint256(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_SUBSIDY_FUND_FAILED);\\n }\\n\\n uint256 subsidyFundNew;\\n uint256 actualAddAmount;\\n\\n if (accrualBlockNumber != getBlockNumber()) {\\n return (\\n fail(\\n Error.MARKET_NOT_FRESH,\\n FailureInfo.ADD_SUBSIDY_FUND_FRESH_CHECK\\n )\\n );\\n }\\n\\n actualAddAmount = doTransferIn(msg.sender, addAmount);\\n\\n subsidyFundNew = subsidyFund + actualAddAmount;\\n\\n require(subsidyFundNew >= subsidyFund, \\\"CT22\\\");\\n\\n subsidyFund = subsidyFundNew;\\n\\n emit SubsidyAdded(msg.sender, actualAddAmount, subsidyFundNew);\\n\\n /* Return (NO_ERROR, actualAddAmount) */\\n return (uint256(Error.NO_ERROR));\\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(uint256 reduceAmount)\\n external\\n override\\n nonReentrant\\n returns (uint256)\\n {\\n uint256 error = accrueInterest();\\n if (error != uint256(Error.NO_ERROR)) {\\n return\\n fail(\\n Error(error),\\n FailureInfo.REDUCE_RESERVES_ACCRUE_INTEREST_FAILED\\n );\\n }\\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(uint256 reduceAmount)\\n internal\\n returns (uint256)\\n {\\n uint256 totalReservesNew;\\n\\n if (msg.sender != admin) {\\n return\\n fail(\\n Error.UNAUTHORIZED,\\n FailureInfo.REDUCE_RESERVES_ADMIN_CHECK\\n );\\n }\\n\\n if (accrualBlockNumber != getBlockNumber()) {\\n return\\n fail(\\n Error.MARKET_NOT_FRESH,\\n FailureInfo.REDUCE_RESERVES_FRESH_CHECK\\n );\\n }\\n\\n if (getCashPrior() < reduceAmount) {\\n return\\n fail(\\n Error.TOKEN_INSUFFICIENT_CASH,\\n FailureInfo.REDUCE_RESERVES_CASH_NOT_AVAILABLE\\n );\\n }\\n\\n if (reduceAmount > totalReserves) {\\n return\\n fail(Error.BAD_INPUT, FailureInfo.REDUCE_RESERVES_VALIDATION);\\n }\\n\\n totalReservesNew = totalReserves - reduceAmount;\\n require(totalReservesNew <= totalReserves, \\\"CT23\\\");\\n\\n totalReserves = totalReservesNew;\\n\\n doTransferOut(admin, reduceAmount);\\n\\n emit ReservesReduced(admin, reduceAmount, totalReservesNew);\\n\\n return uint256(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)\\n public\\n override\\n returns (uint256)\\n {\\n uint256 error = accrueInterest();\\n if (error != uint256(Error.NO_ERROR)) {\\n return\\n fail(\\n Error(error),\\n FailureInfo.SET_INTEREST_RATE_MODEL_ACCRUE_INTEREST_FAILED\\n );\\n }\\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)\\n internal\\n returns (uint256)\\n {\\n InterestRateModel oldInterestRateModel;\\n\\n if (msg.sender != admin) {\\n return\\n fail(\\n Error.UNAUTHORIZED,\\n FailureInfo.SET_INTEREST_RATE_MODEL_OWNER_CHECK\\n );\\n }\\n\\n if (accrualBlockNumber != getBlockNumber()) {\\n return\\n fail(\\n Error.MARKET_NOT_FRESH,\\n FailureInfo.SET_INTEREST_RATE_MODEL_FRESH_CHECK\\n );\\n }\\n\\n oldInterestRateModel = interestRateModel;\\n\\n require(newInterestRateModel.isInterestRateModel(), \\\"CT21\\\");\\n\\n interestRateModel = newInterestRateModel;\\n\\n emit NewMarketInterestRateModel(\\n oldInterestRateModel,\\n newInterestRateModel\\n );\\n\\n return uint256(Error.NO_ERROR);\\n }\\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 virtual returns (uint256);\\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, uint256 amount)\\n internal\\n virtual\\n returns (uint256);\\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, uint256 amount) internal virtual;\\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;\\n }\\n}\\n\",\"keccak256\":\"0x66c781aa1ccc507ce80a431b9ee06801bb81b954bd0697a1f656de400b5cb381\",\"license\":\"UNLICENSED\"},\"contracts/CTokenInterfaces.sol\":{\"content\":\"// SPDX-License-Identifier: UNLICENSED\\npragma solidity 0.8.6;\\n\\nimport \\\"./ComptrollerInterface.sol\\\";\\nimport \\\"./InterestRateModel.sol\\\";\\nimport \\\"./EIP20NonStandardInterface.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 uint256 internal constant borrowRateMaxMantissa = 0.0005e16;\\n\\n /**\\n * @notice Maximum fraction of interest that can be set aside for reserves\\n */\\n uint256 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 uint256 public initialExchangeRateMantissa;\\n\\n /**\\n * @notice Fraction of interest currently set aside for reserves\\n */\\n uint256 public reserveFactorMantissa;\\n\\n /**\\n * @notice Block number that interest was last accrued at\\n */\\n uint256 public accrualBlockNumber;\\n\\n /**\\n * @notice Accumulator of the total earned interest rate since the opening of the market\\n */\\n uint256 public borrowIndex;\\n\\n /**\\n * @notice Total amount of outstanding borrows of the underlying in this market\\n */\\n uint256 public totalBorrows;\\n\\n /**\\n * @notice Total amount of reserves of the underlying held in this market\\n */\\n uint256 public totalReserves;\\n\\n /**\\n * @notice Total number of tokens in circulation\\n */\\n uint256 public totalSupply;\\n\\n uint256 public subsidyFund;\\n\\n struct SupplySnapshot {\\n uint256 tokens;\\n uint256 underlyingAmount;\\n uint256 suppliedAt;\\n uint256 promisedSupplyRate;\\n }\\n\\n /**\\n * @notice Official record of token balances for each account\\n */\\n mapping(address => SupplySnapshot) internal accountTokens;\\n\\n /**\\n * @notice Approved token transfer amounts on behalf of others\\n */\\n mapping(address => mapping(address => uint256)) 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 uint256 principal;\\n uint256 interestIndex;\\n }\\n\\n /**\\n * @notice Mapping of account addresses to outstanding borrow balances\\n */\\n mapping(address => BorrowSnapshot) internal accountBorrows;\\n}\\n\\nabstract contract CTokenInterface is CTokenStorage {\\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 interest is accrued\\n */\\n event AccrueInterest(\\n uint256 cashPrior,\\n uint256 interestAccumulated,\\n uint256 borrowIndex,\\n uint256 totalBorrows\\n );\\n\\n /**\\n * @notice Event emitted when tokens are minted\\n */\\n event Mint(address indexed minter, uint256 mintAmount, uint256 mintTokens);\\n\\n /**\\n * @notice Event emitted when tokens are redeemed\\n */\\n event Redeem(\\n address indexed redeemer,\\n uint256 redeemAmount,\\n uint256 redeemTokens\\n );\\n\\n /**\\n * @notice Event emitted when underlying is borrowed\\n */\\n event Borrow(\\n address indexed borrower,\\n uint256 borrowAmount,\\n uint256 accountBorrows,\\n uint256 totalBorrows\\n );\\n\\n /**\\n * @notice Event emitted when a borrow is repaid\\n */\\n event RepayBorrow(\\n address indexed payer,\\n address indexed borrower,\\n uint256 repayAmount,\\n uint256 accountBorrows,\\n uint256 totalBorrows\\n );\\n\\n /**\\n * @notice Event emitted when a borrow is liquidated\\n */\\n event LiquidateBorrow(\\n address indexed liquidator,\\n address indexed borrower,\\n uint256 repayAmount,\\n address indexed cTokenCollateral,\\n uint256 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(\\n ComptrollerInterface oldComptroller,\\n ComptrollerInterface newComptroller\\n );\\n\\n /**\\n * @notice Event emitted when interestRateModel is changed\\n */\\n event NewMarketInterestRateModel(\\n InterestRateModel oldInterestRateModel,\\n InterestRateModel newInterestRateModel\\n );\\n\\n /**\\n * @notice Event emitted when the reserve factor is changed\\n */\\n event NewReserveFactor(\\n uint256 oldReserveFactorMantissa,\\n uint256 newReserveFactorMantissa\\n );\\n\\n /**\\n * @notice Event emitted when the reserves are added\\n */\\n event ReservesAdded(\\n address benefactor,\\n uint256 addAmount,\\n uint256 newTotalReserves\\n );\\n\\n event SubsidyAdded(\\n address benefactor,\\n uint256 addAmount,\\n uint256 newSubsidyFund\\n );\\n\\n /**\\n * @notice Event emitted when the reserves are reduced\\n */\\n event ReservesReduced(\\n address admin,\\n uint256 reduceAmount,\\n uint256 newTotalReserves\\n );\\n\\n /**\\n * @notice EIP20 Transfer event\\n */\\n event Transfer(address indexed from, address indexed to, uint256 amount);\\n\\n /**\\n * @notice EIP20 Approval event\\n */\\n event Approval(\\n address indexed owner,\\n address indexed spender,\\n uint256 amount\\n );\\n\\n /**\\n * @notice Failure event\\n */\\n event CTokenStorageFailure(uint256 error, uint256 info, uint256 detail);\\n\\n /*** User Interface ***/\\n\\n function transfer(address dst, uint256 amount)\\n external\\n virtual\\n returns (bool);\\n\\n function transferFrom(\\n address src,\\n address dst,\\n uint256 amount\\n ) external virtual returns (bool);\\n\\n function approve(address spender, uint256 amount)\\n external\\n virtual\\n returns (bool);\\n\\n function allowance(address owner, address spender)\\n external\\n view\\n virtual\\n returns (uint256);\\n\\n function balanceOf(address owner) external view virtual returns (uint256);\\n\\n function balanceOfUnderlying(address owner)\\n external\\n virtual\\n returns (uint256);\\n\\n function getAccountSnapshot(address account)\\n external\\n view\\n virtual\\n returns (\\n uint256,\\n uint256,\\n uint256,\\n uint256\\n );\\n\\n function borrowRatePerBlock() external view virtual returns (uint256);\\n\\n function supplyRatePerBlock() external view virtual returns (uint256);\\n\\n function totalBorrowsCurrent() external virtual returns (uint256);\\n\\n function borrowBalanceCurrent(address account)\\n external\\n virtual\\n returns (uint256);\\n\\n function borrowBalanceStored(address account)\\n public\\n view\\n virtual\\n returns (uint256);\\n\\n function exchangeRateCurrent() public virtual returns (uint256);\\n\\n function exchangeRateStored() public view virtual returns (uint256);\\n\\n function getCash() external view virtual returns (uint256);\\n\\n function accrueInterest() public virtual returns (uint256);\\n\\n function seize(\\n address liquidator,\\n address borrower,\\n uint256 seizeTokens\\n ) external virtual returns (uint256);\\n\\n /*** Admin Functions ***/\\n\\n function _setPendingAdmin(address payable newPendingAdmin)\\n external\\n virtual\\n returns (uint256);\\n\\n function _acceptAdmin() external virtual returns (uint256);\\n\\n function _setComptroller(ComptrollerInterface newComptroller)\\n public\\n virtual\\n returns (uint256);\\n\\n function _setReserveFactor(uint256 newReserveFactorMantissa)\\n external\\n virtual\\n returns (uint256);\\n\\n function _reduceReserves(uint256 reduceAmount)\\n external\\n virtual\\n returns (uint256);\\n\\n function _setInterestRateModel(InterestRateModel newInterestRateModel)\\n public\\n virtual\\n returns (uint256);\\n}\\n\\ncontract CErc20Storage {\\n /**\\n * @notice Underlying asset for this CToken\\n */\\n address public underlying;\\n}\\n\\nabstract contract CErc20Interface is CErc20Storage {\\n /*** User Interface ***/\\n\\n function mint(uint256 mintAmount) external virtual returns (uint256);\\n\\n function redeem(uint256 redeemAmount)\\n external\\n virtual\\n returns (uint256);\\n\\n function borrow(uint256 borrowAmount) external virtual returns (uint256);\\n\\n function repayBorrow(uint256 repayAmount)\\n external\\n virtual\\n returns (uint256);\\n\\n function liquidateBorrow(\\n address borrower,\\n uint256 repayAmount,\\n CTokenInterface cTokenCollateral\\n ) external virtual returns (uint256);\\n\\n function sweepToken(EIP20NonStandardInterface token) external virtual;\\n\\n /*** Admin Functions ***/\\n\\n function _addReserves(uint256 addAmount) external virtual returns (uint256);\\n}\\n\\ncontract CDelegationStorage {\\n /**\\n * @notice Implementation address for this contract\\n */\\n address public implementation;\\n}\\n\\nabstract contract CDelegatorInterface is CDelegationStorage {\\n /**\\n * @notice Emitted when implementation is changed\\n */\\n event NewImplementation(\\n address oldImplementation,\\n address newImplementation\\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(\\n address implementation_,\\n bool allowResign,\\n bytes memory becomeImplementationData\\n ) public virtual;\\n}\\n\\nabstract contract 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 virtual;\\n\\n /**\\n * @notice Called by the delegator on a delegate to forfeit its responsibility\\n */\\n function _resignImplementation() public virtual;\\n}\\n\",\"keccak256\":\"0xd0c347830afeac6c54eb7fbac35b60215d9acdd1fb2a3abb16df18923384fa42\",\"license\":\"UNLICENSED\"},\"contracts/CarefulMath.sol\":{\"content\":\"// SPDX-License-Identifier: UNLICENSED\\npragma solidity 0.8.6;\\n\\n/**\\n * @title Careful Math\\n * @author tropykus\\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}\\n\",\"keccak256\":\"0x2aa4360607bccc28c9bde237718c5fabc5e68a34befec92724d30bfbc0b9499f\",\"license\":\"UNLICENSED\"},\"contracts/ComptrollerInterface.sol\":{\"content\":\"// SPDX-License-Identifier: UNLICENSED\\npragma solidity 0.8.6;\\n\\nabstract contract 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)\\n external\\n virtual\\n returns (uint256[] memory);\\n\\n function exitMarket(address cToken) external virtual returns (uint256);\\n\\n /*** Policy Hooks ***/\\n\\n function mintAllowed(\\n address cToken,\\n address minter,\\n uint256 mintAmount\\n ) external virtual returns (uint256);\\n\\n function mintVerify(\\n address cToken,\\n address minter,\\n uint256 mintAmount,\\n uint256 mintTokens\\n ) external virtual;\\n\\n function redeemAllowed(\\n address cToken,\\n address redeemer,\\n uint256 redeemTokens\\n ) external virtual returns (uint256);\\n\\n function redeemVerify(\\n address cToken,\\n address redeemer,\\n uint256 redeemAmount,\\n uint256 redeemTokens\\n ) external virtual;\\n\\n function borrowAllowed(\\n address cToken,\\n address borrower,\\n uint256 borrowAmount\\n ) external virtual returns (uint256);\\n\\n function borrowVerify(\\n address cToken,\\n address borrower,\\n uint256 borrowAmount\\n ) external virtual;\\n\\n function repayBorrowAllowed(\\n address cToken,\\n address payer,\\n address borrower,\\n uint256 repayAmount\\n ) external virtual returns (uint256);\\n\\n function repayBorrowVerify(\\n address cToken,\\n address payer,\\n address borrower,\\n uint256 repayAmount,\\n uint256 borrowerIndex\\n ) external virtual;\\n\\n function liquidateBorrowAllowed(\\n address cTokenBorrowed,\\n address cTokenCollateral,\\n address liquidator,\\n address borrower,\\n uint256 repayAmount\\n ) external virtual returns (uint256);\\n\\n function liquidateBorrowVerify(\\n address cTokenBorrowed,\\n address cTokenCollateral,\\n address liquidator,\\n address borrower,\\n uint256 repayAmount,\\n uint256 seizeTokens\\n ) external virtual;\\n\\n function seizeAllowed(\\n address cTokenCollateral,\\n address cTokenBorrowed,\\n address liquidator,\\n address borrower,\\n uint256 seizeTokens\\n ) external virtual returns (uint256);\\n\\n function seizeVerify(\\n address cTokenCollateral,\\n address cTokenBorrowed,\\n address liquidator,\\n address borrower,\\n uint256 seizeTokens\\n ) external virtual;\\n\\n function transferAllowed(\\n address cToken,\\n address src,\\n address dst,\\n uint256 transferTokens\\n ) external virtual returns (uint256);\\n\\n function transferVerify(\\n address cToken,\\n address src,\\n address dst,\\n uint256 transferTokens\\n ) external virtual;\\n\\n /*** Liquidity/Liquidation Calculations ***/\\n\\n function liquidateCalculateSeizeTokens(\\n address cTokenBorrowed,\\n address cTokenCollateral,\\n uint256 repayAmount\\n ) external view virtual returns (uint256, uint256);\\n}\\n\",\"keccak256\":\"0x4f6874b6790450374231de9b8c33652d620ec9457835e78d36ceaa561875a1b9\",\"license\":\"UNLICENSED\"},\"contracts/EIP20Interface.sol\":{\"content\":\"// SPDX-License-Identifier: UNLICENSED\\npragma solidity 0.8.6;\\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\\n function symbol() external view returns (string memory);\\n\\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 balance 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 success Whether or not the transfer succeeded\\n */\\n function transfer(address dst, uint256 amount)\\n external\\n 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 success Whether or not the transfer succeeded\\n */\\n function transferFrom(\\n address src,\\n address dst,\\n uint256 amount\\n ) 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 success Whether or not the approval succeeded\\n */\\n function approve(address spender, uint256 amount)\\n external\\n 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 remaining The number of tokens allowed to be spent (-1 means infinite)\\n */\\n function allowance(address owner, address spender)\\n external\\n view\\n returns (uint256 remaining);\\n\\n event Transfer(address indexed from, address indexed to, uint256 amount);\\n event Approval(\\n address indexed owner,\\n address indexed spender,\\n uint256 amount\\n );\\n}\\n\",\"keccak256\":\"0xe445bee8cc89c468e8822aa0d39c8f4ee6b6ac059191365ecef889cd83b53a75\",\"license\":\"UNLICENSED\"},\"contracts/EIP20NonStandardInterface.sol\":{\"content\":\"// SPDX-License-Identifier: UNLICENSED\\npragma solidity 0.8.6;\\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 * @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 balance 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(\\n address src,\\n address dst,\\n uint256 amount\\n ) 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 success Whether or not the approval succeeded\\n */\\n function approve(address spender, uint256 amount)\\n external\\n 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 remaining The number of tokens allowed to be spent\\n */\\n function allowance(address owner, address spender)\\n external\\n view\\n returns (uint256 remaining);\\n\\n event Transfer(address indexed from, address indexed to, uint256 amount);\\n event Approval(\\n address indexed owner,\\n address indexed spender,\\n uint256 amount\\n );\\n}\\n\",\"keccak256\":\"0xab8b46aaf5f985d5e3e1f1aa3dbc2e30d69ae0760b3a6b0478f50b9fca3bbc39\",\"license\":\"UNLICENSED\"},\"contracts/ErrorReporter.sol\":{\"content\":\"// SPDX-License-Identifier: UNLICENSED\\npragma solidity 0.8.6;\\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(uint256 error, uint256 info, uint256 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 (uint256) {\\n emit Failure(uint256(err), uint256(info), 0);\\n\\n return uint256(err);\\n }\\n\\n /**\\n * @dev use this when reporting an opaque error from an upgradeable collaborator contract\\n */\\n function failOpaque(\\n Error err,\\n FailureInfo info,\\n uint256 opaqueError\\n ) internal returns (uint256) {\\n emit Failure(uint256(err), uint256(info), opaqueError);\\n\\n return uint256(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 ADD_SUBSIDY_FUND_FAILED,\\n ADD_SUBSIDY_FUND_FRESH_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 TokenFailure(uint256 error, uint256 info, uint256 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 (uint256) {\\n emit TokenFailure(uint256(err), uint256(info), 0);\\n\\n return uint256(err);\\n }\\n\\n /**\\n * @dev use this when reporting an opaque error from an upgradeable collaborator contract\\n */\\n function failOpaque(\\n Error err,\\n FailureInfo info,\\n uint256 opaqueError\\n ) internal returns (uint256) {\\n emit TokenFailure(uint256(err), uint256(info), opaqueError);\\n\\n return uint256(err);\\n }\\n}\\n\",\"keccak256\":\"0x097b23a9ddec2e563458dadd7e03fb1756514acb8a05eb924da76b470582ceb9\",\"license\":\"UNLICENSED\"},\"contracts/Exponential.sol\":{\"content\":\"// SPDX-License-Identifier: UNLICENSED\\npragma solidity 0.8.6;\\n\\nimport \\\"./CarefulMath.sol\\\";\\nimport \\\"./ExponentialNoError.sol\\\";\\n\\n/**\\n * @title Exponential module for storing fixed-precision decimals\\n * @author tropykus\\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) internal pure 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) internal pure 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) internal pure 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) internal pure 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) internal pure 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) internal pure 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) internal pure 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) internal pure 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) internal pure 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) internal pure 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) internal pure 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) internal pure 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) internal pure returns (MathError, Exp memory) {\\n return getExp(a.mantissa, b.mantissa);\\n }\\n}\\n\",\"keccak256\":\"0x4d59359e644bc1df4c60f967b00027aed07612c3471c7c1206d61e10ab705475\",\"license\":\"UNLICENSED\"},\"contracts/ExponentialNoError.sol\":{\"content\":\"// SPDX-License-Identifier: UNLICENSED\\npragma solidity 0.8.6;\\n\\n/**\\n * @title Exponential module for storing fixed-precision decimals\\n * @author tropykus\\n * @notice Exp is a struct which stores decimals with a fixed precision of 18 decimal places.\\n * Thus, if we wanted to store the 5.1, mantissa would store 5.1e18. That is:\\n * `Exp({mantissa: 5100000000000000000})`.\\n */\\ncontract ExponentialNoError {\\n uint constant expScale = 1e18;\\n uint constant doubleScale = 1e36;\\n uint constant halfExpScale = expScale/2;\\n uint constant mantissaOne = expScale;\\n\\n struct Exp {\\n uint mantissa;\\n }\\n\\n struct Double {\\n uint mantissa;\\n }\\n\\n /**\\n * @dev Truncates the given exp to a whole number value.\\n * For example, truncate(Exp{mantissa: 15 * expScale}) = 15\\n */\\n function truncate(Exp memory exp) pure internal returns (uint) {\\n // Note: We are not using careful math here as we're performing a division that cannot fail\\n return exp.mantissa / expScale;\\n }\\n\\n /**\\n * @dev Multiply an Exp by a scalar, then truncate to return an unsigned integer.\\n */\\n function mul_ScalarTruncate(Exp memory a, uint scalar) pure internal returns (uint) {\\n Exp memory product = mul_(a, scalar);\\n return truncate(product);\\n }\\n\\n /**\\n * @dev Multiply an Exp by a scalar, truncate, then add an to an unsigned integer, returning an unsigned integer.\\n */\\n function mul_ScalarTruncateAddUInt(Exp memory a, uint scalar, uint addend) pure internal returns (uint) {\\n Exp memory product = mul_(a, scalar);\\n return add_(truncate(product), addend);\\n }\\n\\n /**\\n * @dev Checks if first Exp is less than second Exp.\\n */\\n function lessThanExp(Exp memory left, Exp memory right) pure internal returns (bool) {\\n return left.mantissa < right.mantissa;\\n }\\n\\n /**\\n * @dev Checks if left Exp <= right Exp.\\n */\\n function lessThanOrEqualExp(Exp memory left, Exp memory right) pure internal returns (bool) {\\n return left.mantissa <= right.mantissa;\\n }\\n\\n /**\\n * @dev Checks if left Exp > right Exp.\\n */\\n function greaterThanExp(Exp memory left, Exp memory right) pure internal returns (bool) {\\n return left.mantissa > right.mantissa;\\n }\\n\\n /**\\n * @dev returns true if Exp is exactly zero\\n */\\n function isZeroExp(Exp memory value) pure internal returns (bool) {\\n return value.mantissa == 0;\\n }\\n\\n function safe224(uint n, string memory errorMessage) pure internal returns (uint224) {\\n require(n < 2**224, errorMessage);\\n return uint224(n);\\n }\\n\\n function safe32(uint n, string memory errorMessage) pure internal returns (uint32) {\\n require(n < 2**32, errorMessage);\\n return uint32(n);\\n }\\n\\n function add_(Exp memory a, Exp memory b) pure internal returns (Exp memory) {\\n return Exp({mantissa: add_(a.mantissa, b.mantissa)});\\n }\\n\\n function add_(Double memory a, Double memory b) pure internal returns (Double memory) {\\n return Double({mantissa: add_(a.mantissa, b.mantissa)});\\n }\\n\\n function add_(uint a, uint b) pure internal returns (uint) {\\n return add_(a, b, \\\"addition overflow\\\");\\n }\\n\\n function add_(uint a, uint b, string memory errorMessage) pure internal returns (uint) {\\n uint c = a + b;\\n require(c >= a, errorMessage);\\n return c;\\n }\\n\\n function sub_(Exp memory a, Exp memory b) pure internal returns (Exp memory) {\\n return Exp({mantissa: sub_(a.mantissa, b.mantissa)});\\n }\\n\\n function sub_(Double memory a, Double memory b) pure internal returns (Double memory) {\\n return Double({mantissa: sub_(a.mantissa, b.mantissa)});\\n }\\n\\n function sub_(uint a, uint b) pure internal returns (uint) {\\n return sub_(a, b, \\\"subtraction underflow\\\");\\n }\\n\\n function sub_(uint a, uint b, string memory errorMessage) pure internal returns (uint) {\\n require(b <= a, errorMessage);\\n return a - b;\\n }\\n\\n function mul_(Exp memory a, Exp memory b) pure internal returns (Exp memory) {\\n return Exp({mantissa: mul_(a.mantissa, b.mantissa) / expScale});\\n }\\n\\n function mul_(Exp memory a, uint b) pure internal returns (Exp memory) {\\n return Exp({mantissa: mul_(a.mantissa, b)});\\n }\\n\\n function mul_(uint a, Exp memory b) pure internal returns (uint) {\\n return mul_(a, b.mantissa) / expScale;\\n }\\n\\n function mul_(Double memory a, Double memory b) pure internal returns (Double memory) {\\n return Double({mantissa: mul_(a.mantissa, b.mantissa) / doubleScale});\\n }\\n\\n function mul_(Double memory a, uint b) pure internal returns (Double memory) {\\n return Double({mantissa: mul_(a.mantissa, b)});\\n }\\n\\n function mul_(uint a, Double memory b) pure internal returns (uint) {\\n return mul_(a, b.mantissa) / doubleScale;\\n }\\n\\n function mul_(uint a, uint b) pure internal returns (uint) {\\n return mul_(a, b, \\\"multiplication overflow\\\");\\n }\\n\\n function mul_(uint a, uint b, string memory errorMessage) pure internal returns (uint) {\\n if (a == 0 || b == 0) {\\n return 0;\\n }\\n uint c = a * b;\\n require(c / a == b, errorMessage);\\n return c;\\n }\\n\\n function div_(Exp memory a, Exp memory b) pure internal returns (Exp memory) {\\n return Exp({mantissa: div_(mul_(a.mantissa, expScale), b.mantissa)});\\n }\\n\\n function div_(Exp memory a, uint b) pure internal returns (Exp memory) {\\n return Exp({mantissa: div_(a.mantissa, b)});\\n }\\n\\n function div_(uint a, Exp memory b) pure internal returns (uint) {\\n return div_(mul_(a, expScale), b.mantissa);\\n }\\n\\n function div_(Double memory a, Double memory b) pure internal returns (Double memory) {\\n return Double({mantissa: div_(mul_(a.mantissa, doubleScale), b.mantissa)});\\n }\\n\\n function div_(Double memory a, uint b) pure internal returns (Double memory) {\\n return Double({mantissa: div_(a.mantissa, b)});\\n }\\n\\n function div_(uint a, Double memory b) pure internal returns (uint) {\\n return div_(mul_(a, doubleScale), b.mantissa);\\n }\\n\\n function div_(uint a, uint b) pure internal returns (uint) {\\n return div_(a, b, \\\"divide by zero\\\");\\n }\\n\\n function div_(uint a, uint b, string memory errorMessage) pure internal returns (uint) {\\n require(b > 0, errorMessage);\\n return a / b;\\n }\\n\\n function fraction(uint a, uint b) pure internal returns (Double memory) {\\n return Double({mantissa: div_(mul_(a, doubleScale), b)});\\n }\\n}\\n\",\"keccak256\":\"0x50ebd15fc98c12e065477f11230f5d7cd583b5fe25a3c532cb90e75950667795\",\"license\":\"UNLICENSED\"},\"contracts/InterestRateModel.sol\":{\"content\":\"// SPDX-License-Identifier: UNLICENSED\\npragma solidity 0.8.6;\\n\\nimport \\\"./Exponential.sol\\\";\\nimport \\\"./SafeMath.sol\\\";\\n\\n/**\\n * @title tropykus InterestRateModel Interface\\n * @author tropykus\\n */\\nabstract contract InterestRateModel is Exponential {\\n using SafeMath for uint256;\\n\\n /// @notice Indicator that this is an InterestRateModel contract (for inspection)\\n bool public constant isInterestRateModel = true;\\n bool public isTropykusInterestRateModel;\\n\\n /**\\n * @notice The approximate number of blocks per year that is assumed by the interest rate model\\n */\\n uint256 public constant blocksPerYear = 1051200;\\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(\\n uint256 cash,\\n uint256 borrows,\\n uint256 reserves\\n ) public pure virtual returns (uint256) {\\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 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 amnount of reserves the market has\\n * @return The borrow rate per block (as a percentage, and scaled by 1e18)\\n */\\n function getBorrowRate(\\n uint256 cash,\\n uint256 borrows,\\n uint256 reserves\\n ) external view virtual returns (uint256);\\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 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(\\n uint256 cash,\\n uint256 borrows,\\n uint256 reserves,\\n uint256 reserveFactorMantissa\\n ) external view virtual returns (uint256);\\n\\n function getExchangeRate(\\n uint256 _totalCash,\\n uint256 _totalBorrows,\\n uint256 _totalReserves,\\n uint256 _totalSupply\\n ) public pure returns (MathError, uint256) {\\n /*\\n * exchangeRate = (totalCash + totalBorrows - totalReserves) / totalSupply\\n */\\n Exp memory exchangeRate;\\n MathError mathErr;\\n uint256 cashPlusBorrowsMinusReserves;\\n (mathErr, cashPlusBorrowsMinusReserves) = addThenSubUInt(\\n _totalCash,\\n _totalBorrows,\\n _totalReserves\\n );\\n if (mathErr != MathError.NO_ERROR) {\\n return (mathErr, 0);\\n }\\n (mathErr, exchangeRate) = getExp(\\n cashPlusBorrowsMinusReserves,\\n _totalSupply\\n );\\n if (mathErr != MathError.NO_ERROR) {\\n return (mathErr, 0);\\n }\\n\\n return (MathError.NO_ERROR, exchangeRate.mantissa);\\n }\\n\\n function isAboveOptimal(\\n uint256 cash,\\n uint256 borrows,\\n uint256 reserves\\n ) public view virtual returns (bool) {\\n cash;\\n borrows;\\n reserves;\\n return false;\\n }\\n}\\n\",\"keccak256\":\"0x2cdc1a63482287513664d98d778c718c336461272885f61585c6ba404feb2edc\",\"license\":\"UNLICENSED\"},\"contracts/SafeMath.sol\":{\"content\":\"// SPDX-License-Identifier: UNLICENSED\\npragma solidity 0.8.6;\\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\":\"0xe578b9602160e7ddbb5e7b6d355bb4508fa134684afe46e4043602c652e0e041\",\"license\":\"UNLICENSED\"},\"contracts/WhitelistInterface.sol\":{\"content\":\"// SPDX-License-Identifier: UNLICENSED\\npragma solidity 0.8.6;\\n\\ninterface WhitelistInterface {\\n function setStatus(bool _newStatus) external;\\n function enabled() external view returns(bool);\\n\\n function addUsers(address[] memory _users) external;\\n function exist(address _user) external view returns(bool);\\n function getUsers() external view returns(address[] memory currentUsers);\\n function removeUser(address _user) external;\\n}\",\"keccak256\":\"0xb00f782772179693611aefb08d51640de313bc901d6d9d78d1e1b86922e99130\",\"license\":\"UNLICENSED\"},\"contracts/mocks/MockPriceProviderMoC.sol\":{\"content\":\"// SPDX-License-Identifier: UNLICENSED\\npragma solidity 0.8.6;\\n\\nimport \\\"../CErc20.sol\\\";\\n\\n/**\\n * @title A mock price provider of Money on Chain (MoC)\\n * @notice You can use this contract for only simulation\\n */\\ncontract MockPriceProviderMoC {\\n /// @notice rbtcPrice of the interface provicer MoC\\n bytes32 rbtcPrice;\\n /// @notice has of the interface provicer MoC\\n bool has;\\n /// @notice Address of the guardian\\n address public guardian;\\n /// @notice Event rbtcPrice updated\\n event MockPriceProviderMoCUpdated(uint256 oldPrice, uint256 newPrice);\\n\\n constructor(address guardian_, uint256 price) {\\n require(\\n guardian_ != address(0),\\n \\\"MockPriceProviderMoC: address could not be 0\\\"\\n );\\n require(\\n price != uint256(0),\\n \\\"MockPriceProviderMoC: price could not be 0\\\"\\n );\\n guardian = guardian_;\\n rbtcPrice = bytes32(price);\\n has = true;\\n }\\n\\n function peek() public view returns (bytes32, bool) {\\n return (rbtcPrice, has);\\n }\\n\\n /**\\n * @notice Set the rbtcPrice price provider\\n * @param price uint of price provider\\n */\\n function setPrice(uint256 price) public {\\n require(\\n msg.sender == guardian,\\n \\\"MockPriceProviderMoC: only guardian may set the address\\\"\\n );\\n require(\\n price != uint256(0),\\n \\\"MockPriceProviderMoC: price could not be 0\\\"\\n );\\n //set old price\\n bytes32 oldRbtcPrice = rbtcPrice;\\n //update rbtcPrice\\n rbtcPrice = bytes32(price);\\n //emit event\\n emit MockPriceProviderMoCUpdated(\\n uint256(oldRbtcPrice),\\n uint256(rbtcPrice)\\n );\\n }\\n}\\n\",\"keccak256\":\"0xc92138e00d6d4a6a90185de32002ee03c70254fa27d4be28539d72c22785cce9\",\"license\":\"UNLICENSED\"}},\"version\":1}", - "bytecode": "0x608060405234801561001057600080fd5b506040516103aa3803806103aa83398101604081905261002f91610135565b6001600160a01b03821661009f5760405162461bcd60e51b815260206004820152602c60248201527f4d6f636b507269636550726f76696465724d6f433a206164647265737320636f60448201526b0756c64206e6f7420626520360a41b60648201526084015b60405180910390fd5b806100ff5760405162461bcd60e51b815260206004820152602a60248201527f4d6f636b507269636550726f76696465724d6f433a20707269636520636f756c604482015269064206e6f7420626520360b41b6064820152608401610096565b6001805460009290925560ff196001600160a01b0390931661010002929092166001600160a81b0319909116178117905561016f565b6000806040838503121561014857600080fd5b82516001600160a01b038116811461015f57600080fd5b6020939093015192949293505050565b61022c8061017e6000396000f3fe608060405234801561001057600080fd5b50600436106100415760003560e01c8063452a93201461004657806359e02dd71461007b57806391b7f5ed14610099575b600080fd5b60015461005e9061010090046001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b60005460015460ff1660408051928352901515602083015201610072565b6100ac6100a73660046101dd565b6100ae565b005b60015461010090046001600160a01b031633146101385760405162461bcd60e51b815260206004820152603760248201527f4d6f636b507269636550726f76696465724d6f433a206f6e6c7920677561726460448201527f69616e206d61792073657420746865206164647265737300000000000000000060648201526084015b60405180910390fd5b806101985760405162461bcd60e51b815260206004820152602a60248201527f4d6f636b507269636550726f76696465724d6f433a20707269636520636f756c604482015269064206e6f7420626520360b41b606482015260840161012f565b600080549082905560408051828152602081018490527f0f044c0280bacc38accfa21abc3ff4078e3acc7d7a14569f5db61f36870df047910160405180910390a15050565b6000602082840312156101ef57600080fd5b503591905056fea2646970667358221220f7515fbb2e55846cd982cf3d3ec4650f7c5c8cad8c3466ce1148d1d7ab30910064736f6c63430008060033", - "deployedBytecode": "0x608060405234801561001057600080fd5b50600436106100415760003560e01c8063452a93201461004657806359e02dd71461007b57806391b7f5ed14610099575b600080fd5b60015461005e9061010090046001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b60005460015460ff1660408051928352901515602083015201610072565b6100ac6100a73660046101dd565b6100ae565b005b60015461010090046001600160a01b031633146101385760405162461bcd60e51b815260206004820152603760248201527f4d6f636b507269636550726f76696465724d6f433a206f6e6c7920677561726460448201527f69616e206d61792073657420746865206164647265737300000000000000000060648201526084015b60405180910390fd5b806101985760405162461bcd60e51b815260206004820152602a60248201527f4d6f636b507269636550726f76696465724d6f433a20707269636520636f756c604482015269064206e6f7420626520360b41b606482015260840161012f565b600080549082905560408051828152602081018490527f0f044c0280bacc38accfa21abc3ff4078e3acc7d7a14569f5db61f36870df047910160405180910390a15050565b6000602082840312156101ef57600080fd5b503591905056fea2646970667358221220f7515fbb2e55846cd982cf3d3ec4650f7c5c8cad8c3466ce1148d1d7ab30910064736f6c63430008060033", - "devdoc": { - "kind": "dev", - "methods": { - "setPrice(uint256)": { - "params": { - "price": "uint of price provider" - } - } - }, - "title": "A mock price provider of Money on Chain (MoC)", - "version": 1 - }, - "userdoc": { - "events": { - "MockPriceProviderMoCUpdated(uint256,uint256)": { - "notice": "Event rbtcPrice updated" - } - }, - "kind": "user", - "methods": { - "guardian()": { - "notice": "Address of the guardian" - }, - "setPrice(uint256)": { - "notice": "Set the rbtcPrice price provider" - } - }, - "notice": "You can use this contract for only simulation", - "version": 1 - }, - "storageLayout": { - "storage": [ - { - "astId": 41911, - "contract": "contracts/mocks/MockPriceProviderMoC.sol:MockPriceProviderMoC", - "label": "rbtcPrice", - "offset": 0, - "slot": "0", - "type": "t_bytes32" - }, - { - "astId": 41914, - "contract": "contracts/mocks/MockPriceProviderMoC.sol:MockPriceProviderMoC", - "label": "has", - "offset": 0, - "slot": "1", - "type": "t_bool" - }, - { - "astId": 41917, - "contract": "contracts/mocks/MockPriceProviderMoC.sol:MockPriceProviderMoC", - "label": "guardian", - "offset": 1, - "slot": "1", - "type": "t_address" - } - ], - "types": { - "t_address": { - "encoding": "inplace", - "label": "address", - "numberOfBytes": "20" - }, - "t_bool": { - "encoding": "inplace", - "label": "bool", - "numberOfBytes": "1" - }, - "t_bytes32": { - "encoding": "inplace", - "label": "bytes32", - "numberOfBytes": "32" - } - } - } -} \ No newline at end of file diff --git a/deployments/localhost/RifOracle.json b/deployments/localhost/RifOracle.json deleted file mode 100644 index ca87d41..0000000 --- a/deployments/localhost/RifOracle.json +++ /dev/null @@ -1,183 +0,0 @@ -{ - "address": "0x5FbDB2315678afecb367f032d93F642f64180aa3", - "abi": [ - { - "inputs": [ - { - "internalType": "address", - "name": "guardian_", - "type": "address" - }, - { - "internalType": "uint256", - "name": "price", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "constructor" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "oldPrice", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "newPrice", - "type": "uint256" - } - ], - "name": "MockPriceProviderMoCUpdated", - "type": "event" - }, - { - "inputs": [], - "name": "guardian", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "peek", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - }, - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "price", - "type": "uint256" - } - ], - "name": "setPrice", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - } - ], - "transactionHash": "0xe832b378d18f4ac7b7e9f1aa1f96bca969edcd0bc0423ff1ec29da96a4453265", - "receipt": { - "to": null, - "from": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", - "contractAddress": "0x5FbDB2315678afecb367f032d93F642f64180aa3", - "transactionIndex": 0, - "gasUsed": "220564", - "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "blockHash": "0x1fba456973c2186aaf12c04c536982eb487061598ff134ee105a35e31d0968c4", - "transactionHash": "0xe832b378d18f4ac7b7e9f1aa1f96bca969edcd0bc0423ff1ec29da96a4453265", - "logs": [], - "blockNumber": 1, - "cumulativeGasUsed": "220564", - "status": 1, - "byzantium": true - }, - "args": [ - "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", - "330000000000000000" - ], - "solcInputHash": "3f2295c0e5923ce11cb0f26c6e52bee2", - "metadata": "{\"compiler\":{\"version\":\"0.8.6+commit.11564f7e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"guardian_\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"price\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldPrice\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newPrice\",\"type\":\"uint256\"}],\"name\":\"MockPriceProviderMoCUpdated\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"guardian\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"peek\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"price\",\"type\":\"uint256\"}],\"name\":\"setPrice\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"setPrice(uint256)\":{\"params\":{\"price\":\"uint of price provider\"}}},\"title\":\"A mock price provider of Money on Chain (MoC)\",\"version\":1},\"userdoc\":{\"events\":{\"MockPriceProviderMoCUpdated(uint256,uint256)\":{\"notice\":\"Event rbtcPrice updated\"}},\"kind\":\"user\",\"methods\":{\"guardian()\":{\"notice\":\"Address of the guardian\"},\"setPrice(uint256)\":{\"notice\":\"Set the rbtcPrice price provider\"}},\"notice\":\"You can use this contract for only simulation\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/mocks/MockPriceProviderMoC.sol\":\"MockPriceProviderMoC\"},\"evmVersion\":\"berlin\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"contracts/CErc20.sol\":{\"content\":\"// SPDX-License-Identifier: UNLICENSED\\npragma solidity 0.8.6;\\n\\nimport \\\"./CToken.sol\\\";\\nimport \\\"./CTokenInterfaces.sol\\\";\\n\\n/**\\n * @title tropykus CErc20 Contract\\n * @notice CTokens which wrap an EIP-20 underlying\\n * @author tropykus\\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(\\n address underlying_,\\n ComptrollerInterface comptroller_,\\n InterestRateModel interestRateModel_,\\n uint256 initialExchangeRateMantissa_,\\n string memory name_,\\n string memory symbol_,\\n uint8 decimals_\\n ) public {\\n // CToken initialize does the bulk of the work\\n super.initialize(\\n comptroller_,\\n interestRateModel_,\\n initialExchangeRateMantissa_,\\n name_,\\n symbol_,\\n decimals_\\n );\\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(uint256 mintAmount) external override returns (uint256) {\\n (uint256 err, ) = mintInternal(mintAmount);\\n return err;\\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 redeem(uint256 redeemAmount)\\n external\\n override\\n returns (uint256)\\n {\\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(uint256 borrowAmount) external override returns (uint256) {\\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(uint256 repayAmount)\\n external\\n override\\n returns (uint256)\\n {\\n (uint256 err, ) = repayBorrowInternal(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(\\n address borrower,\\n uint256 repayAmount,\\n CTokenInterface cTokenCollateral\\n ) external override returns (uint256) {\\n (uint256 err, ) = liquidateBorrowInternal(\\n borrower,\\n repayAmount,\\n cTokenCollateral\\n );\\n return err;\\n }\\n\\n /**\\n * @notice A public function to sweep accidental ERC-20 transfers to this contract. Tokens are sent to admin (timelock)\\n * @param token The address of the ERC-20 token to sweep\\n */\\n function sweepToken(EIP20NonStandardInterface token) external override {\\n require(address(token) != underlying, \\\"EC01\\\");\\n uint256 balance = token.balanceOf(address(this));\\n token.transfer(admin, balance);\\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(uint256 addAmount)\\n external\\n override\\n returns (uint256)\\n {\\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 override returns (uint256) {\\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, uint256 amount)\\n internal\\n override\\n returns (uint256)\\n {\\n EIP20NonStandardInterface token = EIP20NonStandardInterface(underlying);\\n uint256 balanceBefore = EIP20Interface(underlying).balanceOf(\\n address(this)\\n );\\n token.transferFrom(from, address(this), amount);\\n\\n bool success;\\n assembly {\\n switch returndatasize()\\n case 0 {\\n // This is a non-standard ERC-20\\n success := not(0) // set success to true\\n }\\n case 32 {\\n // This is a compliant ERC-20\\n returndatacopy(0, 0, 32)\\n success := mload(0) // Set `success = returndata` of external call\\n }\\n default {\\n // This is an excessively non-compliant ERC-20, revert.\\n revert(0, 0)\\n }\\n }\\n require(success, \\\"EC02\\\");\\n\\n // Calculate the amount that was *actually* transferred\\n uint256 balanceAfter = EIP20Interface(underlying).balanceOf(\\n address(this)\\n );\\n require(balanceAfter >= balanceBefore, \\\"EC03\\\");\\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, uint256 amount)\\n internal\\n virtual\\n override\\n {\\n EIP20NonStandardInterface token = EIP20NonStandardInterface(underlying);\\n token.transfer(to, amount);\\n\\n bool success;\\n assembly {\\n switch returndatasize()\\n case 0 {\\n // This is a non-standard ERC-20\\n success := not(0) // set success to true\\n }\\n case 32 {\\n // This is a complaint ERC-20\\n returndatacopy(0, 0, 32)\\n success := mload(0) // Set `success = returndata` of external call\\n }\\n default {\\n // This is an excessively non-compliant ERC-20, revert.\\n revert(0, 0)\\n }\\n }\\n require(success, \\\"CE01\\\");\\n }\\n}\\n\",\"keccak256\":\"0x539c67e8b5bf011926bd82655501f2016db29e890139a1b466461a3298950365\",\"license\":\"UNLICENSED\"},\"contracts/CToken.sol\":{\"content\":\"// SPDX-License-Identifier: UNLICENSED\\npragma solidity 0.8.6;\\n\\nimport \\\"./ComptrollerInterface.sol\\\";\\nimport \\\"./CTokenInterfaces.sol\\\";\\nimport \\\"./ErrorReporter.sol\\\";\\nimport \\\"./Exponential.sol\\\";\\nimport \\\"./EIP20Interface.sol\\\";\\nimport \\\"./InterestRateModel.sol\\\";\\nimport \\\"./WhitelistInterface.sol\\\";\\n\\n/**\\n * @title tropykus CToken Contract\\n * @notice Abstract base for CTokens\\n * @author tropykus\\n */\\nabstract contract CToken is CTokenInterface, Exponential, TokenErrorReporter {\\n address whitelist;\\n\\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(\\n ComptrollerInterface comptroller_,\\n InterestRateModel interestRateModel_,\\n uint256 initialExchangeRateMantissa_,\\n string memory name_,\\n string memory symbol_,\\n uint8 decimals_\\n ) public {\\n require(msg.sender == admin, \\\"CT01\\\");\\n require(accrualBlockNumber == 0 && borrowIndex == 0, \\\"CT02\\\");\\n\\n initialExchangeRateMantissa = initialExchangeRateMantissa_;\\n require(initialExchangeRateMantissa > 0, \\\"CT03\\\");\\n\\n uint256 err = _setComptroller(comptroller_);\\n require(err == uint256(Error.NO_ERROR), \\\"CT04\\\");\\n\\n accrualBlockNumber = getBlockNumber();\\n borrowIndex = mantissaOne;\\n\\n err = _setInterestRateModelFresh(interestRateModel_);\\n require(err == uint256(Error.NO_ERROR), \\\"CT05\\\");\\n\\n name = name_;\\n symbol = symbol_;\\n decimals = decimals_;\\n\\n _notEntered = true;\\n }\\n\\n function addWhitelist(address _whitelist) external returns (uint256) {\\n if (msg.sender != admin) {\\n return\\n fail(\\n Error.UNAUTHORIZED,\\n FailureInfo.SET_INTEREST_RATE_MODEL_OWNER_CHECK\\n );\\n }\\n whitelist = _whitelist;\\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(\\n address spender,\\n address src,\\n address dst,\\n uint256 tokens\\n ) internal returns (uint256) {\\n uint256 allowed = comptroller.transferAllowed(\\n address(this),\\n src,\\n dst,\\n tokens\\n );\\n if (allowed != 0) {\\n return\\n failOpaque(\\n Error.COMPTROLLER_REJECTION,\\n FailureInfo.TRANSFER_COMPTROLLER_REJECTION,\\n allowed\\n );\\n }\\n\\n if (src == dst) {\\n return fail(Error.BAD_INPUT, FailureInfo.TRANSFER_NOT_ALLOWED);\\n }\\n\\n uint256 startingAllowance = 0;\\n if (spender == src) {\\n startingAllowance = type(uint256).max;\\n } else {\\n startingAllowance = transferAllowances[src][spender];\\n }\\n\\n MathError mathErr;\\n uint256 allowanceNew;\\n uint256 srcTokensNew;\\n uint256 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, 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, tokens);\\n if (mathErr != MathError.NO_ERROR) {\\n return fail(Error.MATH_ERROR, FailureInfo.TRANSFER_TOO_MUCH);\\n }\\n\\n accountTokens[src].tokens = srcTokensNew;\\n accountTokens[dst].tokens = dstTokensNew;\\n\\n if (startingAllowance != type(uint256).max) {\\n transferAllowances[src][spender] = allowanceNew;\\n }\\n\\n emit Transfer(src, dst, tokens);\\n\\n return uint256(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)\\n external\\n override\\n nonReentrant\\n returns (bool)\\n {\\n return\\n transferTokens(msg.sender, msg.sender, dst, amount) ==\\n uint256(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(\\n address src,\\n address dst,\\n uint256 amount\\n ) external override nonReentrant returns (bool) {\\n return\\n transferTokens(msg.sender, src, dst, amount) ==\\n uint256(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)\\n external\\n override\\n returns (bool)\\n {\\n transferAllowances[msg.sender][spender] = amount;\\n emit Approval(msg.sender, 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)\\n external\\n view\\n override\\n returns (uint256)\\n {\\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 override returns (uint256) {\\n return accountTokens[owner].tokens;\\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)\\n external\\n override\\n returns (uint256)\\n {\\n (MathError mErr, uint256 balance) = mulScalarTruncate(\\n Exp({mantissa: exchangeRateCurrent()}),\\n accountTokens[owner].tokens\\n );\\n require(mErr == MathError.NO_ERROR, \\\"CT06\\\");\\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)\\n external\\n view\\n override\\n returns (\\n uint256,\\n uint256,\\n uint256,\\n uint256\\n )\\n {\\n uint256 cTokenBalance = accountTokens[account].tokens;\\n uint256 borrowBalance;\\n uint256 exchangeRateMantissa;\\n\\n MathError mErr;\\n\\n (mErr, borrowBalance) = borrowBalanceStoredInternal(account);\\n if (mErr != MathError.NO_ERROR) {\\n return (uint256(Error.MATH_ERROR), 0, 0, 0);\\n }\\n\\n (mErr, exchangeRateMantissa) = exchangeRateStoredInternal();\\n if (mErr != MathError.NO_ERROR) {\\n return (uint256(Error.MATH_ERROR), 0, 0, 0);\\n }\\n\\n return (\\n uint256(Error.NO_ERROR),\\n cTokenBalance,\\n borrowBalance,\\n exchangeRateMantissa\\n );\\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 virtual returns (uint256) {\\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 override returns (uint256) {\\n return\\n interestRateModel.getBorrowRate(\\n getCashPrior(),\\n totalBorrows,\\n totalReserves\\n );\\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 override returns (uint256) {\\n return\\n interestRateModel.getSupplyRate(\\n getCashPrior(),\\n totalBorrows,\\n totalReserves,\\n reserveFactorMantissa\\n );\\n }\\n\\n /**\\n * @notice Returns the current total borrows plus accrued interest\\n * @return The total borrows with interest\\n */\\n function totalBorrowsCurrent()\\n external\\n override\\n nonReentrant\\n returns (uint256)\\n {\\n require(accrueInterest() == uint256(Error.NO_ERROR), \\\"CT07\\\");\\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)\\n external\\n override\\n nonReentrant\\n returns (uint256)\\n {\\n require(accrueInterest() == uint256(Error.NO_ERROR), \\\"CT07\\\");\\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)\\n public\\n view\\n override\\n returns (uint256)\\n {\\n (MathError err, uint256 result) = borrowBalanceStoredInternal(account);\\n require(err == MathError.NO_ERROR, \\\"CT08\\\");\\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)\\n internal\\n view\\n returns (MathError, uint256)\\n {\\n MathError mathErr;\\n uint256 principalTimesIndex;\\n uint256 result;\\n\\n BorrowSnapshot storage borrowSnapshot = accountBorrows[account];\\n\\n if (borrowSnapshot.principal == 0) {\\n return (MathError.NO_ERROR, 0);\\n }\\n\\n (mathErr, principalTimesIndex) = mulUInt(\\n borrowSnapshot.principal,\\n borrowIndex\\n );\\n if (mathErr != MathError.NO_ERROR) {\\n return (mathErr, 0);\\n }\\n\\n (mathErr, result) = divUInt(\\n principalTimesIndex,\\n borrowSnapshot.interestIndex\\n );\\n if (mathErr != MathError.NO_ERROR) {\\n return (mathErr, 0);\\n }\\n\\n return (MathError.NO_ERROR, result);\\n }\\n\\n function getBorrowerPrincipalStored(address account)\\n public\\n view\\n returns (uint256 borrowed)\\n {\\n borrowed = accountBorrows[account].principal;\\n }\\n\\n function getSupplierSnapshotStored(address account)\\n public\\n view\\n returns (\\n uint256 tokens,\\n uint256 underlyingAmount,\\n uint256 suppliedAt,\\n uint256 promisedSupplyRate\\n )\\n {\\n tokens = accountTokens[account].tokens;\\n underlyingAmount = accountTokens[account].underlyingAmount;\\n suppliedAt = accountTokens[account].suppliedAt;\\n promisedSupplyRate = accountTokens[account].promisedSupplyRate;\\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()\\n public\\n override\\n nonReentrant\\n returns (uint256)\\n {\\n require(accrueInterest() == uint256(Error.NO_ERROR), \\\"CT07\\\");\\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 override returns (uint256) {\\n (MathError err, uint256 result) = exchangeRateStoredInternal();\\n require(err == MathError.NO_ERROR, \\\"CT09\\\");\\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()\\n internal\\n view\\n virtual\\n returns (MathError, uint256)\\n {\\n uint256 _totalSupply = totalSupply;\\n if (_totalSupply == 0) {\\n return (MathError.NO_ERROR, initialExchangeRateMantissa);\\n } else {\\n MathError error;\\n uint256 exchangeRate;\\n uint256 totalCash = getCashPrior();\\n if (interestRateModel.isTropykusInterestRateModel()) {\\n (error, exchangeRate) = tropykusExchangeRateStoredInternal(\\n msg.sender\\n );\\n if (error == MathError.NO_ERROR) {\\n return (MathError.NO_ERROR, exchangeRate);\\n } else {\\n return (MathError.NO_ERROR, initialExchangeRateMantissa);\\n }\\n }\\n return\\n interestRateModel.getExchangeRate(\\n totalCash,\\n totalBorrows,\\n totalReserves,\\n totalSupply\\n );\\n }\\n }\\n\\n function tropykusExchangeRateStoredInternal(address redeemer)\\n internal\\n view\\n returns (MathError, uint256)\\n {\\n if (totalSupply == 0) {\\n return (MathError.NO_ERROR, initialExchangeRateMantissa);\\n } else {\\n SupplySnapshot storage supplySnapshot = accountTokens[redeemer];\\n if (supplySnapshot.suppliedAt == 0) {\\n return (MathError.DIVISION_BY_ZERO, 0);\\n }\\n (, uint256 interestFactorMantissa, ) = tropykusInterestAccrued(\\n redeemer\\n );\\n Exp memory interestFactor = Exp({mantissa: interestFactorMantissa});\\n uint256 currentUnderlying = supplySnapshot.underlyingAmount;\\n Exp memory redeemerUnderlying = Exp({mantissa: currentUnderlying});\\n (, Exp memory realAmount) = mulExp(\\n interestFactor,\\n redeemerUnderlying\\n );\\n (, Exp memory exchangeRate) = getExp(\\n realAmount.mantissa,\\n supplySnapshot.tokens\\n );\\n return (MathError.NO_ERROR, exchangeRate.mantissa);\\n }\\n }\\n\\n function tropykusInterestAccrued(address account)\\n internal\\n view\\n returns (\\n MathError,\\n uint256,\\n uint256\\n )\\n {\\n SupplySnapshot storage supplySnapshot = accountTokens[account];\\n uint256 promisedSupplyRate = supplySnapshot.promisedSupplyRate;\\n Exp memory expectedSupplyRatePerBlock = Exp({\\n mantissa: promisedSupplyRate\\n });\\n (, uint256 delta) = subUInt(\\n accrualBlockNumber,\\n supplySnapshot.suppliedAt\\n );\\n (, Exp memory expectedSupplyRatePerBlockWithDelta) = mulScalar(\\n expectedSupplyRatePerBlock,\\n delta\\n );\\n (, Exp memory interestFactor) = addExp(\\n Exp({mantissa: 1e18}),\\n expectedSupplyRatePerBlockWithDelta\\n );\\n uint256 currentUnderlying = supplySnapshot.underlyingAmount;\\n Exp memory redeemerUnderlying = Exp({mantissa: currentUnderlying});\\n (, Exp memory realAmount) = mulExp(interestFactor, redeemerUnderlying);\\n (, uint256 interestEarned) = subUInt(\\n realAmount.mantissa,\\n currentUnderlying\\n );\\n return (MathError.NO_ERROR, interestFactor.mantissa, interestEarned);\\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 override returns (uint256) {\\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 override returns (uint256) {\\n uint256 currentBlockNumber = getBlockNumber();\\n uint256 accrualBlockNumberPrior = accrualBlockNumber;\\n\\n if (accrualBlockNumberPrior == currentBlockNumber) {\\n return uint256(Error.NO_ERROR);\\n }\\n\\n uint256 cashPrior = getCashPrior();\\n uint256 borrowsPrior = totalBorrows;\\n uint256 reservesPrior = totalReserves;\\n uint256 borrowIndexPrior = borrowIndex;\\n\\n uint256 borrowRateMantissa = interestRateModel.getBorrowRate(\\n cashPrior,\\n borrowsPrior,\\n reservesPrior\\n );\\n require(borrowRateMantissa <= borrowRateMaxMantissa, \\\"CT10\\\");\\n\\n (MathError mathErr, uint256 blockDelta) = subUInt(\\n currentBlockNumber,\\n accrualBlockNumberPrior\\n );\\n require(mathErr == MathError.NO_ERROR, \\\"CT11\\\");\\n\\n Exp memory simpleInterestFactor;\\n uint256 interestAccumulated;\\n uint256 totalBorrowsNew;\\n uint256 totalReservesNew;\\n uint256 borrowIndexNew;\\n\\n (mathErr, simpleInterestFactor) = mulScalar(\\n Exp({mantissa: borrowRateMantissa}),\\n blockDelta\\n );\\n if (mathErr != MathError.NO_ERROR) {\\n return\\n failOpaque(\\n Error.MATH_ERROR,\\n FailureInfo\\n .ACCRUE_INTEREST_SIMPLE_INTEREST_FACTOR_CALCULATION_FAILED,\\n uint256(mathErr)\\n );\\n }\\n\\n (mathErr, interestAccumulated) = mulScalarTruncate(\\n simpleInterestFactor,\\n borrowsPrior\\n );\\n if (mathErr != MathError.NO_ERROR) {\\n return\\n failOpaque(\\n Error.MATH_ERROR,\\n FailureInfo\\n .ACCRUE_INTEREST_ACCUMULATED_INTEREST_CALCULATION_FAILED,\\n uint256(mathErr)\\n );\\n }\\n\\n (mathErr, totalBorrowsNew) = addUInt(interestAccumulated, borrowsPrior);\\n if (mathErr != MathError.NO_ERROR) {\\n return\\n failOpaque(\\n Error.MATH_ERROR,\\n FailureInfo\\n .ACCRUE_INTEREST_NEW_TOTAL_BORROWS_CALCULATION_FAILED,\\n uint256(mathErr)\\n );\\n }\\n\\n (mathErr, totalReservesNew) = mulScalarTruncateAddUInt(\\n Exp({mantissa: reserveFactorMantissa}),\\n interestAccumulated,\\n reservesPrior\\n );\\n if (mathErr != MathError.NO_ERROR) {\\n return\\n failOpaque(\\n Error.MATH_ERROR,\\n FailureInfo\\n .ACCRUE_INTEREST_NEW_TOTAL_RESERVES_CALCULATION_FAILED,\\n uint256(mathErr)\\n );\\n }\\n\\n if (interestRateModel.isTropykusInterestRateModel()) {\\n (mathErr, totalReservesNew) = newReserves(\\n borrowRateMantissa,\\n cashPrior,\\n borrowsPrior,\\n reservesPrior,\\n interestAccumulated\\n );\\n if (mathErr != MathError.NO_ERROR) {\\n return\\n failOpaque(\\n Error.MATH_ERROR,\\n FailureInfo\\n .ACCRUE_INTEREST_NEW_TOTAL_RESERVES_CALCULATION_FAILED,\\n uint256(mathErr)\\n );\\n }\\n }\\n\\n (mathErr, borrowIndexNew) = mulScalarTruncateAddUInt(\\n simpleInterestFactor,\\n borrowIndexPrior,\\n borrowIndexPrior\\n );\\n if (mathErr != MathError.NO_ERROR) {\\n return\\n failOpaque(\\n Error.MATH_ERROR,\\n FailureInfo\\n .ACCRUE_INTEREST_NEW_BORROW_INDEX_CALCULATION_FAILED,\\n uint256(mathErr)\\n );\\n }\\n\\n accrualBlockNumber = currentBlockNumber;\\n borrowIndex = borrowIndexNew;\\n totalBorrows = totalBorrowsNew;\\n totalReserves = totalReservesNew;\\n\\n emit AccrueInterest(\\n cashPrior,\\n interestAccumulated,\\n borrowIndexNew,\\n totalBorrowsNew\\n );\\n\\n return uint256(Error.NO_ERROR);\\n }\\n\\n function newReserves(\\n uint256 borrowRateMantissa,\\n uint256 cashPrior,\\n uint256 borrowsPrior,\\n uint256 reservesPrior,\\n uint256 interestAccumulated\\n ) internal view returns (MathError mathErr, uint256 totalReservesNew) {\\n uint256 newReserveFactorMantissa;\\n uint256 utilizationRate = interestRateModel.utilizationRate(\\n cashPrior,\\n borrowsPrior,\\n reservesPrior\\n );\\n uint256 expectedSupplyRate = interestRateModel.getSupplyRate(\\n cashPrior,\\n borrowsPrior,\\n reservesPrior,\\n reserveFactorMantissa\\n );\\n if (\\n interestRateModel.isAboveOptimal(\\n cashPrior,\\n borrowsPrior,\\n reservesPrior\\n )\\n ) {\\n (mathErr, newReserveFactorMantissa) = mulScalarTruncate(\\n Exp({mantissa: utilizationRate}),\\n borrowRateMantissa\\n );\\n if (mathErr != MathError.NO_ERROR) {\\n return (mathErr, 0);\\n }\\n (mathErr, newReserveFactorMantissa) = subUInt(\\n newReserveFactorMantissa,\\n expectedSupplyRate\\n );\\n if (mathErr != MathError.NO_ERROR) {\\n return (mathErr, 0);\\n }\\n (mathErr, totalReservesNew) = mulScalarTruncateAddUInt(\\n Exp({mantissa: newReserveFactorMantissa}),\\n interestAccumulated,\\n reservesPrior\\n );\\n if (mathErr != MathError.NO_ERROR) {\\n return (mathErr, 0);\\n }\\n } else {\\n mathErr = MathError.NO_ERROR;\\n totalReservesNew = reservesPrior;\\n }\\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(uint256 mintAmount)\\n internal\\n nonReentrant\\n returns (uint256, uint256)\\n {\\n if (WhitelistInterface(whitelist).enabled()) {\\n require(WhitelistInterface(whitelist).exist(msg.sender), \\\"CT26\\\");\\n }\\n uint256 error = accrueInterest();\\n if (error != uint256(Error.NO_ERROR)) {\\n return (\\n fail(Error(error), FailureInfo.MINT_ACCRUE_INTEREST_FAILED),\\n 0\\n );\\n }\\n return mintFresh(msg.sender, mintAmount);\\n }\\n\\n struct MintLocalVars {\\n Error err;\\n MathError mathErr;\\n uint256 exchangeRateMantissa;\\n uint256 mintTokens;\\n uint256 totalSupplyNew;\\n uint256 accountTokensNew;\\n uint256 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, uint256 mintAmount)\\n internal\\n returns (uint256, uint256)\\n {\\n uint256 allowed = comptroller.mintAllowed(\\n address(this),\\n minter,\\n mintAmount\\n );\\n if (allowed != 0) {\\n return (\\n failOpaque(\\n Error.COMPTROLLER_REJECTION,\\n FailureInfo.MINT_COMPTROLLER_REJECTION,\\n allowed\\n ),\\n 0\\n );\\n }\\n\\n if (accrualBlockNumber != getBlockNumber()) {\\n return (\\n fail(Error.MARKET_NOT_FRESH, FailureInfo.MINT_FRESHNESS_CHECK),\\n 0\\n );\\n }\\n\\n MintLocalVars memory vars;\\n\\n (\\n vars.mathErr,\\n vars.exchangeRateMantissa\\n ) = exchangeRateStoredInternal();\\n if (vars.mathErr != MathError.NO_ERROR) {\\n return (\\n failOpaque(\\n Error.MATH_ERROR,\\n FailureInfo.MINT_EXCHANGE_RATE_READ_FAILED,\\n uint256(vars.mathErr)\\n ),\\n 0\\n );\\n }\\n if (interestRateModel.isTropykusInterestRateModel()) {\\n SupplySnapshot storage supplySnapshot = accountTokens[minter];\\n (, uint256 newTotalSupply) = addUInt(\\n supplySnapshot.underlyingAmount,\\n mintAmount\\n );\\n require(newTotalSupply <= 0.1e18, \\\"CT24\\\");\\n }\\n vars.actualMintAmount = doTransferIn(minter, mintAmount);\\n\\n (vars.mathErr, vars.mintTokens) = divScalarByExpTruncate(\\n vars.actualMintAmount,\\n Exp({mantissa: vars.exchangeRateMantissa})\\n );\\n require(vars.mathErr == MathError.NO_ERROR, \\\"CT12\\\");\\n\\n (vars.mathErr, vars.totalSupplyNew) = addUInt(\\n totalSupply,\\n vars.mintTokens\\n );\\n require(vars.mathErr == MathError.NO_ERROR, \\\"CT13\\\");\\n\\n (vars.mathErr, vars.accountTokensNew) = addUInt(\\n accountTokens[minter].tokens,\\n vars.mintTokens\\n );\\n require(vars.mathErr == MathError.NO_ERROR, \\\"CT14\\\");\\n\\n uint256 currentSupplyRate = interestRateModel.getSupplyRate(\\n getCashPrior(),\\n totalBorrows,\\n totalReserves,\\n reserveFactorMantissa\\n );\\n\\n bool isTropykusInterestRateModel = interestRateModel\\n .isTropykusInterestRateModel();\\n\\n if (accountTokens[minter].tokens > 0) {\\n Exp memory updatedUnderlying;\\n if (isTropykusInterestRateModel) {\\n (, uint256 interestFactorMantissa, ) = tropykusInterestAccrued(\\n minter\\n );\\n Exp memory interestFactor = Exp({\\n mantissa: interestFactorMantissa\\n });\\n uint256 currentUnderlyingAmount = accountTokens[minter]\\n .underlyingAmount;\\n MathError mErrorNewAmount;\\n (mErrorNewAmount, updatedUnderlying) = mulExp(\\n Exp({mantissa: currentUnderlyingAmount}),\\n interestFactor\\n );\\n if (mErrorNewAmount != MathError.NO_ERROR) {\\n return (\\n failOpaque(\\n Error.MATH_ERROR,\\n FailureInfo.MINT_EXCHANGE_CALCULATION_FAILED,\\n uint256(mErrorNewAmount)\\n ),\\n 0\\n );\\n }\\n } else {\\n uint256 currentTokens = accountTokens[minter].tokens;\\n MathError mErrorUpdatedUnderlying;\\n (mErrorUpdatedUnderlying, updatedUnderlying) = mulExp(\\n Exp({mantissa: currentTokens}),\\n Exp({mantissa: vars.exchangeRateMantissa})\\n );\\n if (mErrorUpdatedUnderlying != MathError.NO_ERROR) {\\n return (\\n failOpaque(\\n Error.MATH_ERROR,\\n FailureInfo.MINT_EXCHANGE_CALCULATION_FAILED,\\n uint256(mErrorUpdatedUnderlying)\\n ),\\n 0\\n );\\n }\\n }\\n (, mintAmount) = addUInt(updatedUnderlying.mantissa, mintAmount);\\n }\\n\\n totalSupply = vars.totalSupplyNew;\\n accountTokens[minter] = SupplySnapshot({\\n tokens: vars.accountTokensNew,\\n underlyingAmount: mintAmount,\\n suppliedAt: accrualBlockNumber,\\n promisedSupplyRate: currentSupplyRate\\n });\\n\\n emit Mint(minter, vars.actualMintAmount, vars.mintTokens);\\n emit Transfer(address(this), minter, vars.mintTokens);\\n\\n return (uint256(Error.NO_ERROR), vars.actualMintAmount);\\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(uint256 redeemAmount)\\n internal\\n nonReentrant\\n returns (uint256)\\n {\\n uint256 error = accrueInterest();\\n if (error != uint256(Error.NO_ERROR)) {\\n return\\n fail(Error(error), FailureInfo.REDEEM_ACCRUE_INTEREST_FAILED);\\n }\\n return redeemFresh(payable(msg.sender), redeemAmount);\\n }\\n\\n struct RedeemLocalVars {\\n Error err;\\n MathError mathErr;\\n uint256 exchangeRateMantissa;\\n uint256 redeemTokens;\\n uint256 redeemAmount;\\n uint256 totalSupplyNew;\\n uint256 accountTokensNew;\\n uint256 newSubsidyFund;\\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 redeemAmountIn The number of underlying tokens to receive from redeeming cTokens\\n * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)\\n */\\n function redeemFresh(address payable redeemer, uint256 redeemAmountIn)\\n internal\\n returns (uint256)\\n {\\n require(redeemAmountIn > 0, \\\"CT15\\\");\\n\\n RedeemLocalVars memory vars;\\n\\n SupplySnapshot storage supplySnapshot = accountTokens[redeemer];\\n\\n (\\n vars.mathErr,\\n vars.exchangeRateMantissa\\n ) = exchangeRateStoredInternal();\\n if (vars.mathErr != MathError.NO_ERROR) {\\n return\\n failOpaque(\\n Error.MATH_ERROR,\\n FailureInfo.REDEEM_EXCHANGE_RATE_READ_FAILED,\\n uint256(vars.mathErr)\\n );\\n }\\n\\n uint256 interestEarned;\\n uint256 subsidyFundPortion;\\n uint256 currentUnderlying;\\n\\n bool isTropykusInterestRateModel = interestRateModel\\n .isTropykusInterestRateModel();\\n if (isTropykusInterestRateModel) {\\n currentUnderlying = supplySnapshot.underlyingAmount;\\n (, , interestEarned) = tropykusInterestAccrued(redeemer);\\n }\\n supplySnapshot.promisedSupplyRate = interestRateModel.getSupplyRate(\\n getCashPrior(),\\n totalBorrows,\\n totalReserves,\\n reserveFactorMantissa\\n );\\n\\n if (\\n isTropykusInterestRateModel &&\\n !interestRateModel.isAboveOptimal(\\n getCashPrior(),\\n totalBorrows,\\n totalReserves\\n )\\n ) {\\n uint256 borrowRate = interestRateModel.getBorrowRate(\\n getCashPrior(),\\n totalBorrows,\\n totalReserves\\n );\\n\\n uint256 utilizationRate = interestRateModel.utilizationRate(\\n getCashPrior(),\\n totalBorrows,\\n totalReserves\\n );\\n\\n (, uint256 estimatedEarning) = mulScalarTruncate(\\n Exp({mantissa: borrowRate}),\\n utilizationRate\\n );\\n\\n (, subsidyFundPortion) = subUInt(\\n supplySnapshot.promisedSupplyRate,\\n estimatedEarning\\n );\\n (, Exp memory subsidyFactor) = getExp(\\n subsidyFundPortion,\\n supplySnapshot.promisedSupplyRate\\n );\\n (, subsidyFundPortion) = mulScalarTruncate(\\n subsidyFactor,\\n interestEarned\\n );\\n }\\n\\n vars.redeemAmount = redeemAmountIn;\\n\\n if (isTropykusInterestRateModel) {\\n (, Exp memory num) = mulExp(\\n vars.redeemAmount,\\n supplySnapshot.tokens\\n );\\n (, Exp memory realTokensWithdrawAmount) = getExp(\\n num.mantissa,\\n currentUnderlying\\n );\\n vars.redeemTokens = realTokensWithdrawAmount.mantissa;\\n } else {\\n (vars.mathErr, vars.redeemTokens) = divScalarByExpTruncate(\\n redeemAmountIn,\\n Exp({mantissa: vars.exchangeRateMantissa})\\n );\\n if (vars.mathErr != MathError.NO_ERROR) {\\n return\\n failOpaque(\\n Error.MATH_ERROR,\\n FailureInfo.REDEEM_EXCHANGE_AMOUNT_CALCULATION_FAILED,\\n uint256(vars.mathErr)\\n );\\n }\\n }\\n // }\\n\\n uint256 allowed = comptroller.redeemAllowed(\\n address(this),\\n redeemer,\\n vars.redeemTokens\\n );\\n if (allowed != 0) {\\n return\\n failOpaque(\\n Error.COMPTROLLER_REJECTION,\\n FailureInfo.REDEEM_COMPTROLLER_REJECTION,\\n allowed\\n );\\n }\\n\\n if (accrualBlockNumber != getBlockNumber()) {\\n return\\n fail(\\n Error.MARKET_NOT_FRESH,\\n FailureInfo.REDEEM_FRESHNESS_CHECK\\n );\\n }\\n\\n (vars.mathErr, vars.totalSupplyNew) = subUInt(\\n totalSupply,\\n vars.redeemTokens\\n );\\n if (vars.mathErr != MathError.NO_ERROR) {\\n return\\n failOpaque(\\n Error.MATH_ERROR,\\n FailureInfo.REDEEM_NEW_TOTAL_SUPPLY_CALCULATION_FAILED,\\n uint256(vars.mathErr)\\n );\\n }\\n\\n (, vars.newSubsidyFund) = subUInt(subsidyFund, subsidyFundPortion);\\n\\n (vars.mathErr, vars.accountTokensNew) = subUInt(\\n supplySnapshot.tokens,\\n vars.redeemTokens\\n );\\n if (vars.mathErr != MathError.NO_ERROR) {\\n return\\n failOpaque(\\n Error.MATH_ERROR,\\n FailureInfo.REDEEM_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED,\\n uint256(vars.mathErr)\\n );\\n }\\n\\n uint256 cash = getCashPrior();\\n if (isTropykusInterestRateModel) {\\n cash = address(this).balance;\\n }\\n\\n if (cash < vars.redeemAmount) {\\n return\\n fail(\\n Error.TOKEN_INSUFFICIENT_CASH,\\n FailureInfo.REDEEM_TRANSFER_OUT_NOT_POSSIBLE\\n );\\n }\\n\\n doTransferOut(redeemer, vars.redeemAmount);\\n\\n totalSupply = vars.totalSupplyNew;\\n subsidyFund = vars.newSubsidyFund;\\n supplySnapshot.tokens = vars.accountTokensNew;\\n supplySnapshot.suppliedAt = accrualBlockNumber;\\n (, supplySnapshot.underlyingAmount) = subUInt(\\n supplySnapshot.underlyingAmount,\\n vars.redeemAmount\\n );\\n\\n emit Transfer(redeemer, address(this), vars.redeemTokens);\\n emit Redeem(redeemer, vars.redeemAmount, vars.redeemTokens);\\n\\n comptroller.redeemVerify(\\n address(this),\\n redeemer,\\n vars.redeemAmount,\\n vars.redeemTokens\\n );\\n\\n return uint256(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(uint256 borrowAmount)\\n internal\\n nonReentrant\\n returns (uint256)\\n {\\n uint256 error = accrueInterest();\\n if (error != uint256(Error.NO_ERROR)) {\\n return\\n fail(Error(error), FailureInfo.BORROW_ACCRUE_INTEREST_FAILED);\\n }\\n return borrowFresh(payable(msg.sender), borrowAmount);\\n }\\n\\n struct BorrowLocalVars {\\n MathError mathErr;\\n uint256 accountBorrows;\\n uint256 accountBorrowsNew;\\n uint256 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, uint256 borrowAmount)\\n internal\\n returns (uint256)\\n {\\n uint256 allowed = comptroller.borrowAllowed(\\n address(this),\\n borrower,\\n borrowAmount\\n );\\n if (allowed != 0) {\\n return\\n failOpaque(\\n Error.COMPTROLLER_REJECTION,\\n FailureInfo.BORROW_COMPTROLLER_REJECTION,\\n allowed\\n );\\n }\\n\\n if (accrualBlockNumber != getBlockNumber()) {\\n return\\n fail(\\n Error.MARKET_NOT_FRESH,\\n FailureInfo.BORROW_FRESHNESS_CHECK\\n );\\n }\\n\\n if (getCashPrior() < borrowAmount) {\\n return\\n fail(\\n Error.TOKEN_INSUFFICIENT_CASH,\\n FailureInfo.BORROW_CASH_NOT_AVAILABLE\\n );\\n }\\n\\n BorrowLocalVars memory vars;\\n\\n (vars.mathErr, vars.accountBorrows) = borrowBalanceStoredInternal(\\n borrower\\n );\\n if (vars.mathErr != MathError.NO_ERROR) {\\n return\\n failOpaque(\\n Error.MATH_ERROR,\\n FailureInfo.BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED,\\n uint256(vars.mathErr)\\n );\\n }\\n\\n (vars.mathErr, vars.accountBorrowsNew) = addUInt(\\n vars.accountBorrows,\\n borrowAmount\\n );\\n if (vars.mathErr != MathError.NO_ERROR) {\\n return\\n failOpaque(\\n Error.MATH_ERROR,\\n FailureInfo\\n .BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED,\\n uint256(vars.mathErr)\\n );\\n }\\n\\n (vars.mathErr, vars.totalBorrowsNew) = addUInt(\\n totalBorrows,\\n borrowAmount\\n );\\n if (interestRateModel.isTropykusInterestRateModel()) {\\n require(vars.totalBorrowsNew <= 0.1e18, \\\"CT25\\\");\\n }\\n if (vars.mathErr != MathError.NO_ERROR) {\\n return\\n failOpaque(\\n Error.MATH_ERROR,\\n FailureInfo.BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED,\\n uint256(vars.mathErr)\\n );\\n }\\n\\n doTransferOut(borrower, borrowAmount);\\n\\n accountBorrows[borrower].principal = vars.accountBorrowsNew;\\n accountBorrows[borrower].interestIndex = borrowIndex;\\n totalBorrows = vars.totalBorrowsNew;\\n\\n emit Borrow(\\n borrower,\\n borrowAmount,\\n vars.accountBorrowsNew,\\n vars.totalBorrowsNew\\n );\\n\\n return uint256(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(uint256 repayAmount)\\n internal\\n nonReentrant\\n returns (uint256, uint256)\\n {\\n uint256 error = accrueInterest();\\n if (error != uint256(Error.NO_ERROR)) {\\n return (\\n fail(\\n Error(error),\\n FailureInfo.REPAY_BORROW_ACCRUE_INTEREST_FAILED\\n ),\\n 0\\n );\\n }\\n return repayBorrowFresh(msg.sender, msg.sender, repayAmount);\\n }\\n\\n struct RepayBorrowLocalVars {\\n Error err;\\n MathError mathErr;\\n uint256 repayAmount;\\n uint256 borrowerIndex;\\n uint256 accountBorrows;\\n uint256 accountBorrowsNew;\\n uint256 totalBorrowsNew;\\n uint256 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(\\n address payer,\\n address borrower,\\n uint256 repayAmount\\n ) internal returns (uint256, uint256) {\\n uint256 allowed = comptroller.repayBorrowAllowed(\\n address(this),\\n payer,\\n borrower,\\n repayAmount\\n );\\n if (allowed != 0) {\\n return (\\n failOpaque(\\n Error.COMPTROLLER_REJECTION,\\n FailureInfo.REPAY_BORROW_COMPTROLLER_REJECTION,\\n allowed\\n ),\\n 0\\n );\\n }\\n\\n if (accrualBlockNumber != getBlockNumber()) {\\n return (\\n fail(\\n Error.MARKET_NOT_FRESH,\\n FailureInfo.REPAY_BORROW_FRESHNESS_CHECK\\n ),\\n 0\\n );\\n }\\n\\n RepayBorrowLocalVars memory vars;\\n\\n vars.borrowerIndex = accountBorrows[borrower].interestIndex;\\n\\n (vars.mathErr, vars.accountBorrows) = borrowBalanceStoredInternal(\\n borrower\\n );\\n if (vars.mathErr != MathError.NO_ERROR) {\\n return (\\n failOpaque(\\n Error.MATH_ERROR,\\n FailureInfo\\n .REPAY_BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED,\\n uint256(vars.mathErr)\\n ),\\n 0\\n );\\n }\\n\\n if (repayAmount == type(uint256).max) {\\n vars.repayAmount = vars.accountBorrows;\\n } else {\\n vars.repayAmount = repayAmount;\\n }\\n\\n vars.actualRepayAmount = doTransferIn(payer, vars.repayAmount);\\n\\n (vars.mathErr, vars.accountBorrowsNew) = subUInt(\\n vars.accountBorrows,\\n vars.actualRepayAmount\\n );\\n require(vars.mathErr == MathError.NO_ERROR, \\\"CT16\\\");\\n\\n (vars.mathErr, vars.totalBorrowsNew) = subUInt(\\n totalBorrows,\\n vars.actualRepayAmount\\n );\\n require(vars.mathErr == MathError.NO_ERROR, \\\"CT17\\\");\\n\\n accountBorrows[borrower].principal = vars.accountBorrowsNew;\\n accountBorrows[borrower].interestIndex = borrowIndex;\\n totalBorrows = vars.totalBorrowsNew;\\n\\n emit RepayBorrow(\\n payer,\\n borrower,\\n vars.actualRepayAmount,\\n vars.accountBorrowsNew,\\n vars.totalBorrowsNew\\n );\\n\\n return (uint256(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(\\n address borrower,\\n uint256 repayAmount,\\n CTokenInterface cTokenCollateral\\n ) internal nonReentrant returns (uint256, uint256) {\\n uint256 error = accrueInterest();\\n if (error != uint256(Error.NO_ERROR)) {\\n return (\\n fail(\\n Error(error),\\n FailureInfo.LIQUIDATE_ACCRUE_BORROW_INTEREST_FAILED\\n ),\\n 0\\n );\\n }\\n\\n error = cTokenCollateral.accrueInterest();\\n if (error != uint256(Error.NO_ERROR)) {\\n return (\\n fail(\\n Error(error),\\n FailureInfo.LIQUIDATE_ACCRUE_COLLATERAL_INTEREST_FAILED\\n ),\\n 0\\n );\\n }\\n\\n // liquidateBorrowFresh emits borrow-specific logs on errors, so we don't need to\\n return\\n liquidateBorrowFresh(\\n msg.sender,\\n borrower,\\n repayAmount,\\n cTokenCollateral\\n );\\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(\\n address liquidator,\\n address borrower,\\n uint256 repayAmount,\\n CTokenInterface cTokenCollateral\\n ) internal returns (uint256, uint256) {\\n uint256 allowed = comptroller.liquidateBorrowAllowed(\\n address(this),\\n address(cTokenCollateral),\\n liquidator,\\n borrower,\\n repayAmount\\n );\\n if (allowed != 0) {\\n return (\\n failOpaque(\\n Error.COMPTROLLER_REJECTION,\\n FailureInfo.LIQUIDATE_COMPTROLLER_REJECTION,\\n allowed\\n ),\\n 0\\n );\\n }\\n\\n if (accrualBlockNumber != getBlockNumber()) {\\n return (\\n fail(\\n Error.MARKET_NOT_FRESH,\\n FailureInfo.LIQUIDATE_FRESHNESS_CHECK\\n ),\\n 0\\n );\\n }\\n\\n if (cTokenCollateral.accrualBlockNumber() != getBlockNumber()) {\\n return (\\n fail(\\n Error.MARKET_NOT_FRESH,\\n FailureInfo.LIQUIDATE_COLLATERAL_FRESHNESS_CHECK\\n ),\\n 0\\n );\\n }\\n\\n if (borrower == liquidator) {\\n return (\\n fail(\\n Error.INVALID_ACCOUNT_PAIR,\\n FailureInfo.LIQUIDATE_LIQUIDATOR_IS_BORROWER\\n ),\\n 0\\n );\\n }\\n\\n if (repayAmount == 0) {\\n return (\\n fail(\\n Error.INVALID_CLOSE_AMOUNT_REQUESTED,\\n FailureInfo.LIQUIDATE_CLOSE_AMOUNT_IS_ZERO\\n ),\\n 0\\n );\\n }\\n\\n if (repayAmount == type(uint256).max) {\\n return (\\n fail(\\n Error.INVALID_CLOSE_AMOUNT_REQUESTED,\\n FailureInfo.LIQUIDATE_CLOSE_AMOUNT_IS_UINT_MAX\\n ),\\n 0\\n );\\n }\\n\\n (\\n uint256 repayBorrowError,\\n uint256 actualRepayAmount\\n ) = repayBorrowFresh(liquidator, borrower, repayAmount);\\n if (repayBorrowError != uint256(Error.NO_ERROR)) {\\n return (\\n fail(\\n Error(repayBorrowError),\\n FailureInfo.LIQUIDATE_REPAY_BORROW_FRESH_FAILED\\n ),\\n 0\\n );\\n }\\n\\n (uint256 amountSeizeError, uint256 seizeTokens) = comptroller\\n .liquidateCalculateSeizeTokens(\\n address(this),\\n address(cTokenCollateral),\\n actualRepayAmount\\n );\\n require(amountSeizeError == uint256(Error.NO_ERROR), \\\"CT18\\\");\\n\\n require(cTokenCollateral.balanceOf(borrower) >= seizeTokens, \\\"CT19\\\");\\n\\n uint256 seizeError;\\n if (address(cTokenCollateral) == address(this)) {\\n seizeError = seizeInternal(\\n address(this),\\n liquidator,\\n borrower,\\n seizeTokens\\n );\\n } else {\\n seizeError = cTokenCollateral.seize(\\n liquidator,\\n borrower,\\n seizeTokens\\n );\\n }\\n\\n require(seizeError == uint256(Error.NO_ERROR), \\\"CT20\\\");\\n\\n emit LiquidateBorrow(\\n liquidator,\\n borrower,\\n actualRepayAmount,\\n address(cTokenCollateral),\\n seizeTokens\\n );\\n\\n return (uint256(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(\\n address liquidator,\\n address borrower,\\n uint256 seizeTokens\\n ) external override nonReentrant returns (uint256) {\\n return seizeInternal(msg.sender, liquidator, borrower, seizeTokens);\\n }\\n\\n struct SeizeVars {\\n uint256 seizeAmount;\\n uint256 exchangeRate;\\n uint256 borrowerTokensNew;\\n uint256 borrowerAmountNew;\\n uint256 liquidatorTokensNew;\\n uint256 liquidatorAmountNew;\\n uint256 totalCash;\\n uint256 supplyRate;\\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(\\n address seizerToken,\\n address liquidator,\\n address borrower,\\n uint256 seizeTokens\\n ) internal returns (uint256) {\\n uint256 allowed = comptroller.seizeAllowed(\\n address(this),\\n seizerToken,\\n liquidator,\\n borrower,\\n seizeTokens\\n );\\n if (allowed != 0) {\\n return\\n failOpaque(\\n Error.COMPTROLLER_REJECTION,\\n FailureInfo.LIQUIDATE_SEIZE_COMPTROLLER_REJECTION,\\n allowed\\n );\\n }\\n\\n if (borrower == liquidator) {\\n return\\n fail(\\n Error.INVALID_ACCOUNT_PAIR,\\n FailureInfo.LIQUIDATE_SEIZE_LIQUIDATOR_IS_BORROWER\\n );\\n }\\n\\n SeizeVars memory seizeVars;\\n\\n MathError mathErr;\\n\\n (mathErr, seizeVars.borrowerTokensNew) = subUInt(\\n accountTokens[borrower].tokens,\\n seizeTokens\\n );\\n if (mathErr != MathError.NO_ERROR) {\\n return\\n failOpaque(\\n Error.MATH_ERROR,\\n FailureInfo.LIQUIDATE_SEIZE_BALANCE_DECREMENT_FAILED,\\n uint256(mathErr)\\n );\\n }\\n\\n seizeVars.totalCash = getCashPrior();\\n seizeVars.supplyRate = interestRateModel.getSupplyRate(\\n seizeVars.totalCash,\\n totalBorrows,\\n totalReserves,\\n reserveFactorMantissa\\n );\\n\\n (, seizeVars.exchangeRate) = interestRateModel.getExchangeRate(\\n seizeVars.totalCash,\\n totalBorrows,\\n totalReserves,\\n totalSupply\\n );\\n\\n if (interestRateModel.isTropykusInterestRateModel()) {\\n (, seizeVars.exchangeRate) = tropykusExchangeRateStoredInternal(\\n borrower\\n );\\n }\\n\\n (, seizeVars.seizeAmount) = mulUInt(\\n seizeTokens,\\n seizeVars.exchangeRate\\n );\\n (, seizeVars.seizeAmount) = divUInt(seizeVars.seizeAmount, 1e18);\\n\\n (, seizeVars.borrowerAmountNew) = subUInt(\\n accountTokens[borrower].underlyingAmount,\\n seizeVars.seizeAmount\\n );\\n\\n (mathErr, seizeVars.liquidatorTokensNew) = addUInt(\\n accountTokens[liquidator].tokens,\\n seizeTokens\\n );\\n if (mathErr != MathError.NO_ERROR) {\\n return\\n failOpaque(\\n Error.MATH_ERROR,\\n FailureInfo.LIQUIDATE_SEIZE_BALANCE_INCREMENT_FAILED,\\n uint256(mathErr)\\n );\\n }\\n\\n (, seizeVars.liquidatorAmountNew) = addUInt(\\n accountTokens[liquidator].underlyingAmount,\\n seizeVars.seizeAmount\\n );\\n\\n accountTokens[borrower].tokens = seizeVars.borrowerTokensNew;\\n accountTokens[borrower].underlyingAmount = seizeVars.borrowerAmountNew;\\n accountTokens[borrower].suppliedAt = getBlockNumber();\\n accountTokens[borrower].promisedSupplyRate = seizeVars.supplyRate;\\n\\n accountTokens[liquidator].tokens = seizeVars.liquidatorTokensNew;\\n accountTokens[liquidator].underlyingAmount = seizeVars\\n .liquidatorAmountNew;\\n accountTokens[liquidator].suppliedAt = getBlockNumber();\\n accountTokens[liquidator].promisedSupplyRate = seizeVars.supplyRate;\\n\\n emit Transfer(borrower, liquidator, seizeTokens);\\n\\n return uint256(Error.NO_ERROR);\\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 payable newPendingAdmin)\\n external\\n override\\n returns (uint256)\\n {\\n if (msg.sender != admin) {\\n return\\n fail(\\n Error.UNAUTHORIZED,\\n FailureInfo.SET_PENDING_ADMIN_OWNER_CHECK\\n );\\n }\\n\\n address oldPendingAdmin = pendingAdmin;\\n\\n pendingAdmin = newPendingAdmin;\\n\\n emit NewPendingAdmin(oldPendingAdmin, newPendingAdmin);\\n\\n return uint256(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 override returns (uint256) {\\n if (msg.sender != pendingAdmin || msg.sender == address(0)) {\\n return\\n fail(\\n Error.UNAUTHORIZED,\\n FailureInfo.ACCEPT_ADMIN_PENDING_ADMIN_CHECK\\n );\\n }\\n\\n address oldAdmin = admin;\\n address oldPendingAdmin = pendingAdmin;\\n\\n admin = pendingAdmin;\\n\\n pendingAdmin = payable(address(0));\\n\\n emit NewAdmin(oldAdmin, admin);\\n emit NewPendingAdmin(oldPendingAdmin, pendingAdmin);\\n\\n return uint256(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)\\n public\\n override\\n returns (uint256)\\n {\\n if (msg.sender != admin) {\\n return\\n fail(\\n Error.UNAUTHORIZED,\\n FailureInfo.SET_COMPTROLLER_OWNER_CHECK\\n );\\n }\\n\\n ComptrollerInterface oldComptroller = comptroller;\\n require(newComptroller.isComptroller(), \\\"CT21\\\");\\n\\n comptroller = newComptroller;\\n\\n emit NewComptroller(oldComptroller, newComptroller);\\n\\n return uint256(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(uint256 newReserveFactorMantissa)\\n external\\n override\\n nonReentrant\\n returns (uint256)\\n {\\n uint256 error = accrueInterest();\\n if (error != uint256(Error.NO_ERROR)) {\\n return\\n fail(\\n Error(error),\\n FailureInfo.SET_RESERVE_FACTOR_ACCRUE_INTEREST_FAILED\\n );\\n }\\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(uint256 newReserveFactorMantissa)\\n internal\\n returns (uint256)\\n {\\n if (msg.sender != admin) {\\n return\\n fail(\\n Error.UNAUTHORIZED,\\n FailureInfo.SET_RESERVE_FACTOR_ADMIN_CHECK\\n );\\n }\\n\\n if (accrualBlockNumber != getBlockNumber()) {\\n return\\n fail(\\n Error.MARKET_NOT_FRESH,\\n FailureInfo.SET_RESERVE_FACTOR_FRESH_CHECK\\n );\\n }\\n\\n if (newReserveFactorMantissa > reserveFactorMaxMantissa) {\\n return\\n fail(\\n Error.BAD_INPUT,\\n FailureInfo.SET_RESERVE_FACTOR_BOUNDS_CHECK\\n );\\n }\\n\\n uint256 oldReserveFactorMantissa = reserveFactorMantissa;\\n reserveFactorMantissa = newReserveFactorMantissa;\\n\\n emit NewReserveFactor(\\n oldReserveFactorMantissa,\\n newReserveFactorMantissa\\n );\\n\\n return uint256(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(uint256 addAmount)\\n internal\\n nonReentrant\\n returns (uint256)\\n {\\n uint256 error = accrueInterest();\\n if (error != uint256(Error.NO_ERROR)) {\\n return\\n fail(\\n Error(error),\\n FailureInfo.ADD_RESERVES_ACCRUE_INTEREST_FAILED\\n );\\n }\\n\\n uint256 totalReservesNew;\\n uint256 actualAddAmount;\\n\\n if (accrualBlockNumber != getBlockNumber()) {\\n return (\\n fail(\\n Error.MARKET_NOT_FRESH,\\n FailureInfo.ADD_RESERVES_FRESH_CHECK\\n )\\n );\\n }\\n\\n actualAddAmount = doTransferIn(msg.sender, addAmount);\\n\\n totalReservesNew = totalReserves + actualAddAmount;\\n\\n require(totalReservesNew >= totalReserves, \\\"CT22\\\");\\n\\n totalReserves = totalReservesNew;\\n\\n emit ReservesAdded(msg.sender, actualAddAmount, totalReservesNew);\\n\\n return (uint256(Error.NO_ERROR));\\n }\\n\\n function _addSubsidyInternal(uint256 addAmount)\\n internal\\n nonReentrant\\n returns (uint256)\\n {\\n uint256 error = accrueInterest();\\n if (error != uint256(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_SUBSIDY_FUND_FAILED);\\n }\\n\\n uint256 subsidyFundNew;\\n uint256 actualAddAmount;\\n\\n if (accrualBlockNumber != getBlockNumber()) {\\n return (\\n fail(\\n Error.MARKET_NOT_FRESH,\\n FailureInfo.ADD_SUBSIDY_FUND_FRESH_CHECK\\n )\\n );\\n }\\n\\n actualAddAmount = doTransferIn(msg.sender, addAmount);\\n\\n subsidyFundNew = subsidyFund + actualAddAmount;\\n\\n require(subsidyFundNew >= subsidyFund, \\\"CT22\\\");\\n\\n subsidyFund = subsidyFundNew;\\n\\n emit SubsidyAdded(msg.sender, actualAddAmount, subsidyFundNew);\\n\\n /* Return (NO_ERROR, actualAddAmount) */\\n return (uint256(Error.NO_ERROR));\\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(uint256 reduceAmount)\\n external\\n override\\n nonReentrant\\n returns (uint256)\\n {\\n uint256 error = accrueInterest();\\n if (error != uint256(Error.NO_ERROR)) {\\n return\\n fail(\\n Error(error),\\n FailureInfo.REDUCE_RESERVES_ACCRUE_INTEREST_FAILED\\n );\\n }\\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(uint256 reduceAmount)\\n internal\\n returns (uint256)\\n {\\n uint256 totalReservesNew;\\n\\n if (msg.sender != admin) {\\n return\\n fail(\\n Error.UNAUTHORIZED,\\n FailureInfo.REDUCE_RESERVES_ADMIN_CHECK\\n );\\n }\\n\\n if (accrualBlockNumber != getBlockNumber()) {\\n return\\n fail(\\n Error.MARKET_NOT_FRESH,\\n FailureInfo.REDUCE_RESERVES_FRESH_CHECK\\n );\\n }\\n\\n if (getCashPrior() < reduceAmount) {\\n return\\n fail(\\n Error.TOKEN_INSUFFICIENT_CASH,\\n FailureInfo.REDUCE_RESERVES_CASH_NOT_AVAILABLE\\n );\\n }\\n\\n if (reduceAmount > totalReserves) {\\n return\\n fail(Error.BAD_INPUT, FailureInfo.REDUCE_RESERVES_VALIDATION);\\n }\\n\\n totalReservesNew = totalReserves - reduceAmount;\\n require(totalReservesNew <= totalReserves, \\\"CT23\\\");\\n\\n totalReserves = totalReservesNew;\\n\\n doTransferOut(admin, reduceAmount);\\n\\n emit ReservesReduced(admin, reduceAmount, totalReservesNew);\\n\\n return uint256(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)\\n public\\n override\\n returns (uint256)\\n {\\n uint256 error = accrueInterest();\\n if (error != uint256(Error.NO_ERROR)) {\\n return\\n fail(\\n Error(error),\\n FailureInfo.SET_INTEREST_RATE_MODEL_ACCRUE_INTEREST_FAILED\\n );\\n }\\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)\\n internal\\n returns (uint256)\\n {\\n InterestRateModel oldInterestRateModel;\\n\\n if (msg.sender != admin) {\\n return\\n fail(\\n Error.UNAUTHORIZED,\\n FailureInfo.SET_INTEREST_RATE_MODEL_OWNER_CHECK\\n );\\n }\\n\\n if (accrualBlockNumber != getBlockNumber()) {\\n return\\n fail(\\n Error.MARKET_NOT_FRESH,\\n FailureInfo.SET_INTEREST_RATE_MODEL_FRESH_CHECK\\n );\\n }\\n\\n oldInterestRateModel = interestRateModel;\\n\\n require(newInterestRateModel.isInterestRateModel(), \\\"CT21\\\");\\n\\n interestRateModel = newInterestRateModel;\\n\\n emit NewMarketInterestRateModel(\\n oldInterestRateModel,\\n newInterestRateModel\\n );\\n\\n return uint256(Error.NO_ERROR);\\n }\\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 virtual returns (uint256);\\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, uint256 amount)\\n internal\\n virtual\\n returns (uint256);\\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, uint256 amount) internal virtual;\\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;\\n }\\n}\\n\",\"keccak256\":\"0x66c781aa1ccc507ce80a431b9ee06801bb81b954bd0697a1f656de400b5cb381\",\"license\":\"UNLICENSED\"},\"contracts/CTokenInterfaces.sol\":{\"content\":\"// SPDX-License-Identifier: UNLICENSED\\npragma solidity 0.8.6;\\n\\nimport \\\"./ComptrollerInterface.sol\\\";\\nimport \\\"./InterestRateModel.sol\\\";\\nimport \\\"./EIP20NonStandardInterface.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 uint256 internal constant borrowRateMaxMantissa = 0.0005e16;\\n\\n /**\\n * @notice Maximum fraction of interest that can be set aside for reserves\\n */\\n uint256 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 uint256 public initialExchangeRateMantissa;\\n\\n /**\\n * @notice Fraction of interest currently set aside for reserves\\n */\\n uint256 public reserveFactorMantissa;\\n\\n /**\\n * @notice Block number that interest was last accrued at\\n */\\n uint256 public accrualBlockNumber;\\n\\n /**\\n * @notice Accumulator of the total earned interest rate since the opening of the market\\n */\\n uint256 public borrowIndex;\\n\\n /**\\n * @notice Total amount of outstanding borrows of the underlying in this market\\n */\\n uint256 public totalBorrows;\\n\\n /**\\n * @notice Total amount of reserves of the underlying held in this market\\n */\\n uint256 public totalReserves;\\n\\n /**\\n * @notice Total number of tokens in circulation\\n */\\n uint256 public totalSupply;\\n\\n uint256 public subsidyFund;\\n\\n struct SupplySnapshot {\\n uint256 tokens;\\n uint256 underlyingAmount;\\n uint256 suppliedAt;\\n uint256 promisedSupplyRate;\\n }\\n\\n /**\\n * @notice Official record of token balances for each account\\n */\\n mapping(address => SupplySnapshot) internal accountTokens;\\n\\n /**\\n * @notice Approved token transfer amounts on behalf of others\\n */\\n mapping(address => mapping(address => uint256)) 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 uint256 principal;\\n uint256 interestIndex;\\n }\\n\\n /**\\n * @notice Mapping of account addresses to outstanding borrow balances\\n */\\n mapping(address => BorrowSnapshot) internal accountBorrows;\\n}\\n\\nabstract contract CTokenInterface is CTokenStorage {\\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 interest is accrued\\n */\\n event AccrueInterest(\\n uint256 cashPrior,\\n uint256 interestAccumulated,\\n uint256 borrowIndex,\\n uint256 totalBorrows\\n );\\n\\n /**\\n * @notice Event emitted when tokens are minted\\n */\\n event Mint(address indexed minter, uint256 mintAmount, uint256 mintTokens);\\n\\n /**\\n * @notice Event emitted when tokens are redeemed\\n */\\n event Redeem(\\n address indexed redeemer,\\n uint256 redeemAmount,\\n uint256 redeemTokens\\n );\\n\\n /**\\n * @notice Event emitted when underlying is borrowed\\n */\\n event Borrow(\\n address indexed borrower,\\n uint256 borrowAmount,\\n uint256 accountBorrows,\\n uint256 totalBorrows\\n );\\n\\n /**\\n * @notice Event emitted when a borrow is repaid\\n */\\n event RepayBorrow(\\n address indexed payer,\\n address indexed borrower,\\n uint256 repayAmount,\\n uint256 accountBorrows,\\n uint256 totalBorrows\\n );\\n\\n /**\\n * @notice Event emitted when a borrow is liquidated\\n */\\n event LiquidateBorrow(\\n address indexed liquidator,\\n address indexed borrower,\\n uint256 repayAmount,\\n address indexed cTokenCollateral,\\n uint256 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(\\n ComptrollerInterface oldComptroller,\\n ComptrollerInterface newComptroller\\n );\\n\\n /**\\n * @notice Event emitted when interestRateModel is changed\\n */\\n event NewMarketInterestRateModel(\\n InterestRateModel oldInterestRateModel,\\n InterestRateModel newInterestRateModel\\n );\\n\\n /**\\n * @notice Event emitted when the reserve factor is changed\\n */\\n event NewReserveFactor(\\n uint256 oldReserveFactorMantissa,\\n uint256 newReserveFactorMantissa\\n );\\n\\n /**\\n * @notice Event emitted when the reserves are added\\n */\\n event ReservesAdded(\\n address benefactor,\\n uint256 addAmount,\\n uint256 newTotalReserves\\n );\\n\\n event SubsidyAdded(\\n address benefactor,\\n uint256 addAmount,\\n uint256 newSubsidyFund\\n );\\n\\n /**\\n * @notice Event emitted when the reserves are reduced\\n */\\n event ReservesReduced(\\n address admin,\\n uint256 reduceAmount,\\n uint256 newTotalReserves\\n );\\n\\n /**\\n * @notice EIP20 Transfer event\\n */\\n event Transfer(address indexed from, address indexed to, uint256 amount);\\n\\n /**\\n * @notice EIP20 Approval event\\n */\\n event Approval(\\n address indexed owner,\\n address indexed spender,\\n uint256 amount\\n );\\n\\n /**\\n * @notice Failure event\\n */\\n event CTokenStorageFailure(uint256 error, uint256 info, uint256 detail);\\n\\n /*** User Interface ***/\\n\\n function transfer(address dst, uint256 amount)\\n external\\n virtual\\n returns (bool);\\n\\n function transferFrom(\\n address src,\\n address dst,\\n uint256 amount\\n ) external virtual returns (bool);\\n\\n function approve(address spender, uint256 amount)\\n external\\n virtual\\n returns (bool);\\n\\n function allowance(address owner, address spender)\\n external\\n view\\n virtual\\n returns (uint256);\\n\\n function balanceOf(address owner) external view virtual returns (uint256);\\n\\n function balanceOfUnderlying(address owner)\\n external\\n virtual\\n returns (uint256);\\n\\n function getAccountSnapshot(address account)\\n external\\n view\\n virtual\\n returns (\\n uint256,\\n uint256,\\n uint256,\\n uint256\\n );\\n\\n function borrowRatePerBlock() external view virtual returns (uint256);\\n\\n function supplyRatePerBlock() external view virtual returns (uint256);\\n\\n function totalBorrowsCurrent() external virtual returns (uint256);\\n\\n function borrowBalanceCurrent(address account)\\n external\\n virtual\\n returns (uint256);\\n\\n function borrowBalanceStored(address account)\\n public\\n view\\n virtual\\n returns (uint256);\\n\\n function exchangeRateCurrent() public virtual returns (uint256);\\n\\n function exchangeRateStored() public view virtual returns (uint256);\\n\\n function getCash() external view virtual returns (uint256);\\n\\n function accrueInterest() public virtual returns (uint256);\\n\\n function seize(\\n address liquidator,\\n address borrower,\\n uint256 seizeTokens\\n ) external virtual returns (uint256);\\n\\n /*** Admin Functions ***/\\n\\n function _setPendingAdmin(address payable newPendingAdmin)\\n external\\n virtual\\n returns (uint256);\\n\\n function _acceptAdmin() external virtual returns (uint256);\\n\\n function _setComptroller(ComptrollerInterface newComptroller)\\n public\\n virtual\\n returns (uint256);\\n\\n function _setReserveFactor(uint256 newReserveFactorMantissa)\\n external\\n virtual\\n returns (uint256);\\n\\n function _reduceReserves(uint256 reduceAmount)\\n external\\n virtual\\n returns (uint256);\\n\\n function _setInterestRateModel(InterestRateModel newInterestRateModel)\\n public\\n virtual\\n returns (uint256);\\n}\\n\\ncontract CErc20Storage {\\n /**\\n * @notice Underlying asset for this CToken\\n */\\n address public underlying;\\n}\\n\\nabstract contract CErc20Interface is CErc20Storage {\\n /*** User Interface ***/\\n\\n function mint(uint256 mintAmount) external virtual returns (uint256);\\n\\n function redeem(uint256 redeemAmount)\\n external\\n virtual\\n returns (uint256);\\n\\n function borrow(uint256 borrowAmount) external virtual returns (uint256);\\n\\n function repayBorrow(uint256 repayAmount)\\n external\\n virtual\\n returns (uint256);\\n\\n function liquidateBorrow(\\n address borrower,\\n uint256 repayAmount,\\n CTokenInterface cTokenCollateral\\n ) external virtual returns (uint256);\\n\\n function sweepToken(EIP20NonStandardInterface token) external virtual;\\n\\n /*** Admin Functions ***/\\n\\n function _addReserves(uint256 addAmount) external virtual returns (uint256);\\n}\\n\\ncontract CDelegationStorage {\\n /**\\n * @notice Implementation address for this contract\\n */\\n address public implementation;\\n}\\n\\nabstract contract CDelegatorInterface is CDelegationStorage {\\n /**\\n * @notice Emitted when implementation is changed\\n */\\n event NewImplementation(\\n address oldImplementation,\\n address newImplementation\\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(\\n address implementation_,\\n bool allowResign,\\n bytes memory becomeImplementationData\\n ) public virtual;\\n}\\n\\nabstract contract 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 virtual;\\n\\n /**\\n * @notice Called by the delegator on a delegate to forfeit its responsibility\\n */\\n function _resignImplementation() public virtual;\\n}\\n\",\"keccak256\":\"0xd0c347830afeac6c54eb7fbac35b60215d9acdd1fb2a3abb16df18923384fa42\",\"license\":\"UNLICENSED\"},\"contracts/CarefulMath.sol\":{\"content\":\"// SPDX-License-Identifier: UNLICENSED\\npragma solidity 0.8.6;\\n\\n/**\\n * @title Careful Math\\n * @author tropykus\\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}\\n\",\"keccak256\":\"0x2aa4360607bccc28c9bde237718c5fabc5e68a34befec92724d30bfbc0b9499f\",\"license\":\"UNLICENSED\"},\"contracts/ComptrollerInterface.sol\":{\"content\":\"// SPDX-License-Identifier: UNLICENSED\\npragma solidity 0.8.6;\\n\\nabstract contract 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)\\n external\\n virtual\\n returns (uint256[] memory);\\n\\n function exitMarket(address cToken) external virtual returns (uint256);\\n\\n /*** Policy Hooks ***/\\n\\n function mintAllowed(\\n address cToken,\\n address minter,\\n uint256 mintAmount\\n ) external virtual returns (uint256);\\n\\n function mintVerify(\\n address cToken,\\n address minter,\\n uint256 mintAmount,\\n uint256 mintTokens\\n ) external virtual;\\n\\n function redeemAllowed(\\n address cToken,\\n address redeemer,\\n uint256 redeemTokens\\n ) external virtual returns (uint256);\\n\\n function redeemVerify(\\n address cToken,\\n address redeemer,\\n uint256 redeemAmount,\\n uint256 redeemTokens\\n ) external virtual;\\n\\n function borrowAllowed(\\n address cToken,\\n address borrower,\\n uint256 borrowAmount\\n ) external virtual returns (uint256);\\n\\n function borrowVerify(\\n address cToken,\\n address borrower,\\n uint256 borrowAmount\\n ) external virtual;\\n\\n function repayBorrowAllowed(\\n address cToken,\\n address payer,\\n address borrower,\\n uint256 repayAmount\\n ) external virtual returns (uint256);\\n\\n function repayBorrowVerify(\\n address cToken,\\n address payer,\\n address borrower,\\n uint256 repayAmount,\\n uint256 borrowerIndex\\n ) external virtual;\\n\\n function liquidateBorrowAllowed(\\n address cTokenBorrowed,\\n address cTokenCollateral,\\n address liquidator,\\n address borrower,\\n uint256 repayAmount\\n ) external virtual returns (uint256);\\n\\n function liquidateBorrowVerify(\\n address cTokenBorrowed,\\n address cTokenCollateral,\\n address liquidator,\\n address borrower,\\n uint256 repayAmount,\\n uint256 seizeTokens\\n ) external virtual;\\n\\n function seizeAllowed(\\n address cTokenCollateral,\\n address cTokenBorrowed,\\n address liquidator,\\n address borrower,\\n uint256 seizeTokens\\n ) external virtual returns (uint256);\\n\\n function seizeVerify(\\n address cTokenCollateral,\\n address cTokenBorrowed,\\n address liquidator,\\n address borrower,\\n uint256 seizeTokens\\n ) external virtual;\\n\\n function transferAllowed(\\n address cToken,\\n address src,\\n address dst,\\n uint256 transferTokens\\n ) external virtual returns (uint256);\\n\\n function transferVerify(\\n address cToken,\\n address src,\\n address dst,\\n uint256 transferTokens\\n ) external virtual;\\n\\n /*** Liquidity/Liquidation Calculations ***/\\n\\n function liquidateCalculateSeizeTokens(\\n address cTokenBorrowed,\\n address cTokenCollateral,\\n uint256 repayAmount\\n ) external view virtual returns (uint256, uint256);\\n}\\n\",\"keccak256\":\"0x4f6874b6790450374231de9b8c33652d620ec9457835e78d36ceaa561875a1b9\",\"license\":\"UNLICENSED\"},\"contracts/EIP20Interface.sol\":{\"content\":\"// SPDX-License-Identifier: UNLICENSED\\npragma solidity 0.8.6;\\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\\n function symbol() external view returns (string memory);\\n\\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 balance 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 success Whether or not the transfer succeeded\\n */\\n function transfer(address dst, uint256 amount)\\n external\\n 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 success Whether or not the transfer succeeded\\n */\\n function transferFrom(\\n address src,\\n address dst,\\n uint256 amount\\n ) 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 success Whether or not the approval succeeded\\n */\\n function approve(address spender, uint256 amount)\\n external\\n 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 remaining The number of tokens allowed to be spent (-1 means infinite)\\n */\\n function allowance(address owner, address spender)\\n external\\n view\\n returns (uint256 remaining);\\n\\n event Transfer(address indexed from, address indexed to, uint256 amount);\\n event Approval(\\n address indexed owner,\\n address indexed spender,\\n uint256 amount\\n );\\n}\\n\",\"keccak256\":\"0xe445bee8cc89c468e8822aa0d39c8f4ee6b6ac059191365ecef889cd83b53a75\",\"license\":\"UNLICENSED\"},\"contracts/EIP20NonStandardInterface.sol\":{\"content\":\"// SPDX-License-Identifier: UNLICENSED\\npragma solidity 0.8.6;\\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 * @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 balance 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(\\n address src,\\n address dst,\\n uint256 amount\\n ) 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 success Whether or not the approval succeeded\\n */\\n function approve(address spender, uint256 amount)\\n external\\n 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 remaining The number of tokens allowed to be spent\\n */\\n function allowance(address owner, address spender)\\n external\\n view\\n returns (uint256 remaining);\\n\\n event Transfer(address indexed from, address indexed to, uint256 amount);\\n event Approval(\\n address indexed owner,\\n address indexed spender,\\n uint256 amount\\n );\\n}\\n\",\"keccak256\":\"0xab8b46aaf5f985d5e3e1f1aa3dbc2e30d69ae0760b3a6b0478f50b9fca3bbc39\",\"license\":\"UNLICENSED\"},\"contracts/ErrorReporter.sol\":{\"content\":\"// SPDX-License-Identifier: UNLICENSED\\npragma solidity 0.8.6;\\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(uint256 error, uint256 info, uint256 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 (uint256) {\\n emit Failure(uint256(err), uint256(info), 0);\\n\\n return uint256(err);\\n }\\n\\n /**\\n * @dev use this when reporting an opaque error from an upgradeable collaborator contract\\n */\\n function failOpaque(\\n Error err,\\n FailureInfo info,\\n uint256 opaqueError\\n ) internal returns (uint256) {\\n emit Failure(uint256(err), uint256(info), opaqueError);\\n\\n return uint256(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 ADD_SUBSIDY_FUND_FAILED,\\n ADD_SUBSIDY_FUND_FRESH_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 TokenFailure(uint256 error, uint256 info, uint256 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 (uint256) {\\n emit TokenFailure(uint256(err), uint256(info), 0);\\n\\n return uint256(err);\\n }\\n\\n /**\\n * @dev use this when reporting an opaque error from an upgradeable collaborator contract\\n */\\n function failOpaque(\\n Error err,\\n FailureInfo info,\\n uint256 opaqueError\\n ) internal returns (uint256) {\\n emit TokenFailure(uint256(err), uint256(info), opaqueError);\\n\\n return uint256(err);\\n }\\n}\\n\",\"keccak256\":\"0x097b23a9ddec2e563458dadd7e03fb1756514acb8a05eb924da76b470582ceb9\",\"license\":\"UNLICENSED\"},\"contracts/Exponential.sol\":{\"content\":\"// SPDX-License-Identifier: UNLICENSED\\npragma solidity 0.8.6;\\n\\nimport \\\"./CarefulMath.sol\\\";\\nimport \\\"./ExponentialNoError.sol\\\";\\n\\n/**\\n * @title Exponential module for storing fixed-precision decimals\\n * @author tropykus\\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) internal pure 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) internal pure 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) internal pure 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) internal pure 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) internal pure 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) internal pure 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) internal pure 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) internal pure 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) internal pure 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) internal pure 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) internal pure 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) internal pure 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) internal pure returns (MathError, Exp memory) {\\n return getExp(a.mantissa, b.mantissa);\\n }\\n}\\n\",\"keccak256\":\"0x4d59359e644bc1df4c60f967b00027aed07612c3471c7c1206d61e10ab705475\",\"license\":\"UNLICENSED\"},\"contracts/ExponentialNoError.sol\":{\"content\":\"// SPDX-License-Identifier: UNLICENSED\\npragma solidity 0.8.6;\\n\\n/**\\n * @title Exponential module for storing fixed-precision decimals\\n * @author tropykus\\n * @notice Exp is a struct which stores decimals with a fixed precision of 18 decimal places.\\n * Thus, if we wanted to store the 5.1, mantissa would store 5.1e18. That is:\\n * `Exp({mantissa: 5100000000000000000})`.\\n */\\ncontract ExponentialNoError {\\n uint constant expScale = 1e18;\\n uint constant doubleScale = 1e36;\\n uint constant halfExpScale = expScale/2;\\n uint constant mantissaOne = expScale;\\n\\n struct Exp {\\n uint mantissa;\\n }\\n\\n struct Double {\\n uint mantissa;\\n }\\n\\n /**\\n * @dev Truncates the given exp to a whole number value.\\n * For example, truncate(Exp{mantissa: 15 * expScale}) = 15\\n */\\n function truncate(Exp memory exp) pure internal returns (uint) {\\n // Note: We are not using careful math here as we're performing a division that cannot fail\\n return exp.mantissa / expScale;\\n }\\n\\n /**\\n * @dev Multiply an Exp by a scalar, then truncate to return an unsigned integer.\\n */\\n function mul_ScalarTruncate(Exp memory a, uint scalar) pure internal returns (uint) {\\n Exp memory product = mul_(a, scalar);\\n return truncate(product);\\n }\\n\\n /**\\n * @dev Multiply an Exp by a scalar, truncate, then add an to an unsigned integer, returning an unsigned integer.\\n */\\n function mul_ScalarTruncateAddUInt(Exp memory a, uint scalar, uint addend) pure internal returns (uint) {\\n Exp memory product = mul_(a, scalar);\\n return add_(truncate(product), addend);\\n }\\n\\n /**\\n * @dev Checks if first Exp is less than second Exp.\\n */\\n function lessThanExp(Exp memory left, Exp memory right) pure internal returns (bool) {\\n return left.mantissa < right.mantissa;\\n }\\n\\n /**\\n * @dev Checks if left Exp <= right Exp.\\n */\\n function lessThanOrEqualExp(Exp memory left, Exp memory right) pure internal returns (bool) {\\n return left.mantissa <= right.mantissa;\\n }\\n\\n /**\\n * @dev Checks if left Exp > right Exp.\\n */\\n function greaterThanExp(Exp memory left, Exp memory right) pure internal returns (bool) {\\n return left.mantissa > right.mantissa;\\n }\\n\\n /**\\n * @dev returns true if Exp is exactly zero\\n */\\n function isZeroExp(Exp memory value) pure internal returns (bool) {\\n return value.mantissa == 0;\\n }\\n\\n function safe224(uint n, string memory errorMessage) pure internal returns (uint224) {\\n require(n < 2**224, errorMessage);\\n return uint224(n);\\n }\\n\\n function safe32(uint n, string memory errorMessage) pure internal returns (uint32) {\\n require(n < 2**32, errorMessage);\\n return uint32(n);\\n }\\n\\n function add_(Exp memory a, Exp memory b) pure internal returns (Exp memory) {\\n return Exp({mantissa: add_(a.mantissa, b.mantissa)});\\n }\\n\\n function add_(Double memory a, Double memory b) pure internal returns (Double memory) {\\n return Double({mantissa: add_(a.mantissa, b.mantissa)});\\n }\\n\\n function add_(uint a, uint b) pure internal returns (uint) {\\n return add_(a, b, \\\"addition overflow\\\");\\n }\\n\\n function add_(uint a, uint b, string memory errorMessage) pure internal returns (uint) {\\n uint c = a + b;\\n require(c >= a, errorMessage);\\n return c;\\n }\\n\\n function sub_(Exp memory a, Exp memory b) pure internal returns (Exp memory) {\\n return Exp({mantissa: sub_(a.mantissa, b.mantissa)});\\n }\\n\\n function sub_(Double memory a, Double memory b) pure internal returns (Double memory) {\\n return Double({mantissa: sub_(a.mantissa, b.mantissa)});\\n }\\n\\n function sub_(uint a, uint b) pure internal returns (uint) {\\n return sub_(a, b, \\\"subtraction underflow\\\");\\n }\\n\\n function sub_(uint a, uint b, string memory errorMessage) pure internal returns (uint) {\\n require(b <= a, errorMessage);\\n return a - b;\\n }\\n\\n function mul_(Exp memory a, Exp memory b) pure internal returns (Exp memory) {\\n return Exp({mantissa: mul_(a.mantissa, b.mantissa) / expScale});\\n }\\n\\n function mul_(Exp memory a, uint b) pure internal returns (Exp memory) {\\n return Exp({mantissa: mul_(a.mantissa, b)});\\n }\\n\\n function mul_(uint a, Exp memory b) pure internal returns (uint) {\\n return mul_(a, b.mantissa) / expScale;\\n }\\n\\n function mul_(Double memory a, Double memory b) pure internal returns (Double memory) {\\n return Double({mantissa: mul_(a.mantissa, b.mantissa) / doubleScale});\\n }\\n\\n function mul_(Double memory a, uint b) pure internal returns (Double memory) {\\n return Double({mantissa: mul_(a.mantissa, b)});\\n }\\n\\n function mul_(uint a, Double memory b) pure internal returns (uint) {\\n return mul_(a, b.mantissa) / doubleScale;\\n }\\n\\n function mul_(uint a, uint b) pure internal returns (uint) {\\n return mul_(a, b, \\\"multiplication overflow\\\");\\n }\\n\\n function mul_(uint a, uint b, string memory errorMessage) pure internal returns (uint) {\\n if (a == 0 || b == 0) {\\n return 0;\\n }\\n uint c = a * b;\\n require(c / a == b, errorMessage);\\n return c;\\n }\\n\\n function div_(Exp memory a, Exp memory b) pure internal returns (Exp memory) {\\n return Exp({mantissa: div_(mul_(a.mantissa, expScale), b.mantissa)});\\n }\\n\\n function div_(Exp memory a, uint b) pure internal returns (Exp memory) {\\n return Exp({mantissa: div_(a.mantissa, b)});\\n }\\n\\n function div_(uint a, Exp memory b) pure internal returns (uint) {\\n return div_(mul_(a, expScale), b.mantissa);\\n }\\n\\n function div_(Double memory a, Double memory b) pure internal returns (Double memory) {\\n return Double({mantissa: div_(mul_(a.mantissa, doubleScale), b.mantissa)});\\n }\\n\\n function div_(Double memory a, uint b) pure internal returns (Double memory) {\\n return Double({mantissa: div_(a.mantissa, b)});\\n }\\n\\n function div_(uint a, Double memory b) pure internal returns (uint) {\\n return div_(mul_(a, doubleScale), b.mantissa);\\n }\\n\\n function div_(uint a, uint b) pure internal returns (uint) {\\n return div_(a, b, \\\"divide by zero\\\");\\n }\\n\\n function div_(uint a, uint b, string memory errorMessage) pure internal returns (uint) {\\n require(b > 0, errorMessage);\\n return a / b;\\n }\\n\\n function fraction(uint a, uint b) pure internal returns (Double memory) {\\n return Double({mantissa: div_(mul_(a, doubleScale), b)});\\n }\\n}\\n\",\"keccak256\":\"0x50ebd15fc98c12e065477f11230f5d7cd583b5fe25a3c532cb90e75950667795\",\"license\":\"UNLICENSED\"},\"contracts/InterestRateModel.sol\":{\"content\":\"// SPDX-License-Identifier: UNLICENSED\\npragma solidity 0.8.6;\\n\\nimport \\\"./Exponential.sol\\\";\\nimport \\\"./SafeMath.sol\\\";\\n\\n/**\\n * @title tropykus InterestRateModel Interface\\n * @author tropykus\\n */\\nabstract contract InterestRateModel is Exponential {\\n using SafeMath for uint256;\\n\\n /// @notice Indicator that this is an InterestRateModel contract (for inspection)\\n bool public constant isInterestRateModel = true;\\n bool public isTropykusInterestRateModel;\\n\\n /**\\n * @notice The approximate number of blocks per year that is assumed by the interest rate model\\n */\\n uint256 public constant blocksPerYear = 1051200;\\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(\\n uint256 cash,\\n uint256 borrows,\\n uint256 reserves\\n ) public pure virtual returns (uint256) {\\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 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 amnount of reserves the market has\\n * @return The borrow rate per block (as a percentage, and scaled by 1e18)\\n */\\n function getBorrowRate(\\n uint256 cash,\\n uint256 borrows,\\n uint256 reserves\\n ) external view virtual returns (uint256);\\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 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(\\n uint256 cash,\\n uint256 borrows,\\n uint256 reserves,\\n uint256 reserveFactorMantissa\\n ) external view virtual returns (uint256);\\n\\n function getExchangeRate(\\n uint256 _totalCash,\\n uint256 _totalBorrows,\\n uint256 _totalReserves,\\n uint256 _totalSupply\\n ) public pure returns (MathError, uint256) {\\n /*\\n * exchangeRate = (totalCash + totalBorrows - totalReserves) / totalSupply\\n */\\n Exp memory exchangeRate;\\n MathError mathErr;\\n uint256 cashPlusBorrowsMinusReserves;\\n (mathErr, cashPlusBorrowsMinusReserves) = addThenSubUInt(\\n _totalCash,\\n _totalBorrows,\\n _totalReserves\\n );\\n if (mathErr != MathError.NO_ERROR) {\\n return (mathErr, 0);\\n }\\n (mathErr, exchangeRate) = getExp(\\n cashPlusBorrowsMinusReserves,\\n _totalSupply\\n );\\n if (mathErr != MathError.NO_ERROR) {\\n return (mathErr, 0);\\n }\\n\\n return (MathError.NO_ERROR, exchangeRate.mantissa);\\n }\\n\\n function isAboveOptimal(\\n uint256 cash,\\n uint256 borrows,\\n uint256 reserves\\n ) public view virtual returns (bool) {\\n cash;\\n borrows;\\n reserves;\\n return false;\\n }\\n}\\n\",\"keccak256\":\"0x2cdc1a63482287513664d98d778c718c336461272885f61585c6ba404feb2edc\",\"license\":\"UNLICENSED\"},\"contracts/SafeMath.sol\":{\"content\":\"// SPDX-License-Identifier: UNLICENSED\\npragma solidity 0.8.6;\\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\":\"0xe578b9602160e7ddbb5e7b6d355bb4508fa134684afe46e4043602c652e0e041\",\"license\":\"UNLICENSED\"},\"contracts/WhitelistInterface.sol\":{\"content\":\"// SPDX-License-Identifier: UNLICENSED\\npragma solidity 0.8.6;\\n\\ninterface WhitelistInterface {\\n function setStatus(bool _newStatus) external;\\n function enabled() external view returns(bool);\\n\\n function addUsers(address[] memory _users) external;\\n function exist(address _user) external view returns(bool);\\n function getUsers() external view returns(address[] memory currentUsers);\\n function removeUser(address _user) external;\\n}\",\"keccak256\":\"0xb00f782772179693611aefb08d51640de313bc901d6d9d78d1e1b86922e99130\",\"license\":\"UNLICENSED\"},\"contracts/mocks/MockPriceProviderMoC.sol\":{\"content\":\"// SPDX-License-Identifier: UNLICENSED\\npragma solidity 0.8.6;\\n\\nimport \\\"../CErc20.sol\\\";\\n\\n/**\\n * @title A mock price provider of Money on Chain (MoC)\\n * @notice You can use this contract for only simulation\\n */\\ncontract MockPriceProviderMoC {\\n /// @notice rbtcPrice of the interface provicer MoC\\n bytes32 rbtcPrice;\\n /// @notice has of the interface provicer MoC\\n bool has;\\n /// @notice Address of the guardian\\n address public guardian;\\n /// @notice Event rbtcPrice updated\\n event MockPriceProviderMoCUpdated(uint256 oldPrice, uint256 newPrice);\\n\\n constructor(address guardian_, uint256 price) {\\n require(\\n guardian_ != address(0),\\n \\\"MockPriceProviderMoC: address could not be 0\\\"\\n );\\n require(\\n price != uint256(0),\\n \\\"MockPriceProviderMoC: price could not be 0\\\"\\n );\\n guardian = guardian_;\\n rbtcPrice = bytes32(price);\\n has = true;\\n }\\n\\n function peek() public view returns (bytes32, bool) {\\n return (rbtcPrice, has);\\n }\\n\\n /**\\n * @notice Set the rbtcPrice price provider\\n * @param price uint of price provider\\n */\\n function setPrice(uint256 price) public {\\n require(\\n msg.sender == guardian,\\n \\\"MockPriceProviderMoC: only guardian may set the address\\\"\\n );\\n require(\\n price != uint256(0),\\n \\\"MockPriceProviderMoC: price could not be 0\\\"\\n );\\n //set old price\\n bytes32 oldRbtcPrice = rbtcPrice;\\n //update rbtcPrice\\n rbtcPrice = bytes32(price);\\n //emit event\\n emit MockPriceProviderMoCUpdated(\\n uint256(oldRbtcPrice),\\n uint256(rbtcPrice)\\n );\\n }\\n}\\n\",\"keccak256\":\"0xc92138e00d6d4a6a90185de32002ee03c70254fa27d4be28539d72c22785cce9\",\"license\":\"UNLICENSED\"}},\"version\":1}", - "bytecode": "0x608060405234801561001057600080fd5b506040516103aa3803806103aa83398101604081905261002f91610135565b6001600160a01b03821661009f5760405162461bcd60e51b815260206004820152602c60248201527f4d6f636b507269636550726f76696465724d6f433a206164647265737320636f60448201526b0756c64206e6f7420626520360a41b60648201526084015b60405180910390fd5b806100ff5760405162461bcd60e51b815260206004820152602a60248201527f4d6f636b507269636550726f76696465724d6f433a20707269636520636f756c604482015269064206e6f7420626520360b41b6064820152608401610096565b6001805460009290925560ff196001600160a01b0390931661010002929092166001600160a81b0319909116178117905561016f565b6000806040838503121561014857600080fd5b82516001600160a01b038116811461015f57600080fd5b6020939093015192949293505050565b61022c8061017e6000396000f3fe608060405234801561001057600080fd5b50600436106100415760003560e01c8063452a93201461004657806359e02dd71461007b57806391b7f5ed14610099575b600080fd5b60015461005e9061010090046001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b60005460015460ff1660408051928352901515602083015201610072565b6100ac6100a73660046101dd565b6100ae565b005b60015461010090046001600160a01b031633146101385760405162461bcd60e51b815260206004820152603760248201527f4d6f636b507269636550726f76696465724d6f433a206f6e6c7920677561726460448201527f69616e206d61792073657420746865206164647265737300000000000000000060648201526084015b60405180910390fd5b806101985760405162461bcd60e51b815260206004820152602a60248201527f4d6f636b507269636550726f76696465724d6f433a20707269636520636f756c604482015269064206e6f7420626520360b41b606482015260840161012f565b600080549082905560408051828152602081018490527f0f044c0280bacc38accfa21abc3ff4078e3acc7d7a14569f5db61f36870df047910160405180910390a15050565b6000602082840312156101ef57600080fd5b503591905056fea2646970667358221220f7515fbb2e55846cd982cf3d3ec4650f7c5c8cad8c3466ce1148d1d7ab30910064736f6c63430008060033", - "deployedBytecode": "0x608060405234801561001057600080fd5b50600436106100415760003560e01c8063452a93201461004657806359e02dd71461007b57806391b7f5ed14610099575b600080fd5b60015461005e9061010090046001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b60005460015460ff1660408051928352901515602083015201610072565b6100ac6100a73660046101dd565b6100ae565b005b60015461010090046001600160a01b031633146101385760405162461bcd60e51b815260206004820152603760248201527f4d6f636b507269636550726f76696465724d6f433a206f6e6c7920677561726460448201527f69616e206d61792073657420746865206164647265737300000000000000000060648201526084015b60405180910390fd5b806101985760405162461bcd60e51b815260206004820152602a60248201527f4d6f636b507269636550726f76696465724d6f433a20707269636520636f756c604482015269064206e6f7420626520360b41b606482015260840161012f565b600080549082905560408051828152602081018490527f0f044c0280bacc38accfa21abc3ff4078e3acc7d7a14569f5db61f36870df047910160405180910390a15050565b6000602082840312156101ef57600080fd5b503591905056fea2646970667358221220f7515fbb2e55846cd982cf3d3ec4650f7c5c8cad8c3466ce1148d1d7ab30910064736f6c63430008060033", - "devdoc": { - "kind": "dev", - "methods": { - "setPrice(uint256)": { - "params": { - "price": "uint of price provider" - } - } - }, - "title": "A mock price provider of Money on Chain (MoC)", - "version": 1 - }, - "userdoc": { - "events": { - "MockPriceProviderMoCUpdated(uint256,uint256)": { - "notice": "Event rbtcPrice updated" - } - }, - "kind": "user", - "methods": { - "guardian()": { - "notice": "Address of the guardian" - }, - "setPrice(uint256)": { - "notice": "Set the rbtcPrice price provider" - } - }, - "notice": "You can use this contract for only simulation", - "version": 1 - }, - "storageLayout": { - "storage": [ - { - "astId": 41911, - "contract": "contracts/mocks/MockPriceProviderMoC.sol:MockPriceProviderMoC", - "label": "rbtcPrice", - "offset": 0, - "slot": "0", - "type": "t_bytes32" - }, - { - "astId": 41914, - "contract": "contracts/mocks/MockPriceProviderMoC.sol:MockPriceProviderMoC", - "label": "has", - "offset": 0, - "slot": "1", - "type": "t_bool" - }, - { - "astId": 41917, - "contract": "contracts/mocks/MockPriceProviderMoC.sol:MockPriceProviderMoC", - "label": "guardian", - "offset": 1, - "slot": "1", - "type": "t_address" - } - ], - "types": { - "t_address": { - "encoding": "inplace", - "label": "address", - "numberOfBytes": "20" - }, - "t_bool": { - "encoding": "inplace", - "label": "bool", - "numberOfBytes": "1" - }, - "t_bytes32": { - "encoding": "inplace", - "label": "bytes32", - "numberOfBytes": "32" - } - } - } -} \ No newline at end of file diff --git a/deployments/localhost/RifPriceOracleAdapterMoc.json b/deployments/localhost/RifPriceOracleAdapterMoc.json deleted file mode 100644 index 3f05aeb..0000000 --- a/deployments/localhost/RifPriceOracleAdapterMoc.json +++ /dev/null @@ -1,245 +0,0 @@ -{ - "address": "0x9d4454B023096f34B160D6B654540c56A1F81688", - "abi": [ - { - "inputs": [ - { - "internalType": "address", - "name": "guardian_", - "type": "address" - }, - { - "internalType": "address", - "name": "priceProvider", - "type": "address" - } - ], - "stateMutability": "nonpayable", - "type": "constructor" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "oldGuardian", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "newGuardian", - "type": "address" - } - ], - "name": "NewGuardian", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "oldAddress", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "newAddress", - "type": "address" - } - ], - "name": "PriceOracleAdapterUpdated", - "type": "event" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "name": "assetPrices", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "guardian", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "priceProviderMoC", - "outputs": [ - { - "internalType": "contract PriceProviderMoC", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newGuardian", - "type": "address" - } - ], - "name": "setGuardian", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "priceProviderAddress", - "type": "address" - } - ], - "name": "setPriceProvider", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - } - ], - "transactionHash": "0x6227f88f6f7bdf17d1c56af2b5191303b766b30ef23020fa49d8676f3cd0b338", - "receipt": { - "to": null, - "from": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", - "contractAddress": "0x9d4454B023096f34B160D6B654540c56A1F81688", - "transactionIndex": 0, - "gasUsed": "378544", - "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "blockHash": "0x86606812b0bcdbac1d796b3a3b5ea05c73779d405c0cc7a88b8788ae9d1502d3", - "transactionHash": "0x6227f88f6f7bdf17d1c56af2b5191303b766b30ef23020fa49d8676f3cd0b338", - "logs": [], - "blockNumber": 46, - "cumulativeGasUsed": "378544", - "status": 1, - "byzantium": true - }, - "args": [ - "0x09635F643e140090A9A8Dcd712eD6285858ceBef", - "0x5FbDB2315678afecb367f032d93F642f64180aa3" - ], - "solcInputHash": "3f2295c0e5923ce11cb0f26c6e52bee2", - "metadata": "{\"compiler\":{\"version\":\"0.8.6+commit.11564f7e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"guardian_\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"priceProvider\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"oldGuardian\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"newGuardian\",\"type\":\"address\"}],\"name\":\"NewGuardian\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"oldAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"newAddress\",\"type\":\"address\"}],\"name\":\"PriceOracleAdapterUpdated\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"assetPrices\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"guardian\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"priceProviderMoC\",\"outputs\":[{\"internalType\":\"contract PriceProviderMoC\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newGuardian\",\"type\":\"address\"}],\"name\":\"setGuardian\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"priceProviderAddress\",\"type\":\"address\"}],\"name\":\"setPriceProvider\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"assetPrices(address)\":{\"returns\":{\"_0\":\"The price\"}},\"constructor\":{\"params\":{\"guardian_\":\"address of guardian that is allowed to manage this contract\",\"priceProvider\":\"address of asset's MoC price provider\"}},\"setGuardian(address)\":{\"params\":{\"newGuardian\":\"address of the guardian\"}},\"setPriceProvider(address)\":{\"params\":{\"priceProviderAddress\":\"address of price provider\"}}},\"version\":1},\"userdoc\":{\"events\":{\"NewGuardian(address,address)\":{\"notice\":\"Guardian updated\"},\"PriceOracleAdapterUpdated(address,address)\":{\"notice\":\"Event adapter interface updated\"}},\"kind\":\"user\",\"methods\":{\"assetPrices(address)\":{\"notice\":\"Get the price from MoC and divide it by the rBTC price\"},\"constructor\":{\"notice\":\"Construct a PriceOracleAdapter for a MoC oracle\"},\"guardian()\":{\"notice\":\"Address of the guardian\"},\"priceProviderMoC()\":{\"notice\":\"The MoC price oracle, which will continue to serve prices\"},\"setGuardian(address)\":{\"notice\":\"Set the address of the guardian\"},\"setPriceProvider(address)\":{\"notice\":\"Set the address of price provider\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/PriceOracleAdapterMoc.sol\":\"PriceOracleAdapterMoc\"},\"evmVersion\":\"berlin\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"contracts/PriceOracleAdapter.sol\":{\"content\":\"// SPDX-License-Identifier: UNLICENSED\\npragma solidity 0.8.6;\\n\\nabstract contract PriceOracleAdapter {\\n /// @notice Event adapter interface updated\\n event PriceOracleAdapterUpdated(address oldAddress, address newAddress);\\n\\n /**\\n * @notice Get the price\\n * @return The underlying asset price mantissa (scaled by 1e18).\\n * Zero means the price is unavailable.\\n */\\n function assetPrices(address cTokenAddress)\\n external\\n view\\n virtual\\n returns (uint256);\\n}\\n\",\"keccak256\":\"0xce2a8f27186d355a24a4402469afe76e4522e97ad9a1a8388defd85fa4c054ec\",\"license\":\"UNLICENSED\"},\"contracts/PriceOracleAdapterMoc.sol\":{\"content\":\"// SPDX-License-Identifier: UNLICENSED\\npragma solidity 0.8.6;\\n\\nimport \\\"./PriceOracleAdapter.sol\\\";\\n\\ninterface PriceProviderMoC {\\n function peek() external view returns (bytes32, bool);\\n}\\n\\ncontract PriceOracleAdapterMoc is PriceOracleAdapter {\\n /// @notice Address of the guardian\\n address public guardian;\\n /// @notice The MoC price oracle, which will continue to serve prices\\n PriceProviderMoC public priceProviderMoC;\\n\\n /// @notice Guardian updated\\n event NewGuardian(address oldGuardian, address newGuardian);\\n\\n /**\\n * @notice Construct a PriceOracleAdapter for a MoC oracle\\n * @param guardian_ address of guardian that is allowed to manage this contract\\n * @param priceProvider address of asset's MoC price provider\\n */\\n constructor(address guardian_, address priceProvider) {\\n require(\\n guardian_ != address(0),\\n \\\"PriceOracleAdapterMoc: guardian could not be 0\\\"\\n );\\n require(\\n priceProvider != address(0),\\n \\\"PriceOracleAdapterMoc: priceProvider could not be 0\\\"\\n );\\n guardian = guardian_;\\n priceProviderMoC = PriceProviderMoC(priceProvider);\\n }\\n\\n /**\\n * @notice Get the price from MoC and divide it by the rBTC price\\n * @return The price\\n */\\n function assetPrices(address) public view override returns (uint256) {\\n (bytes32 price, bool has) = priceProviderMoC.peek();\\n require(has, \\\"PriceOracleAdapterMoc: Oracle have no Price\\\");\\n return uint256(price);\\n }\\n\\n /**\\n * @notice Set the address of price provider\\n * @param priceProviderAddress address of price provider\\n */\\n function setPriceProvider(address priceProviderAddress) public {\\n require(\\n msg.sender == guardian,\\n \\\"PriceOracleAdapterMoc: only guardian may set the address\\\"\\n );\\n require(\\n priceProviderAddress != address(0),\\n \\\"PriceOracleAdapterMoc: address could not be 0\\\"\\n );\\n //set old address\\n address oldPriceProviderAddress = address(priceProviderMoC);\\n //update interface address\\n priceProviderMoC = PriceProviderMoC(priceProviderAddress);\\n //emit event\\n emit PriceOracleAdapterUpdated(\\n oldPriceProviderAddress,\\n priceProviderAddress\\n );\\n }\\n\\n /**\\n * @notice Set the address of the guardian\\n * @param newGuardian address of the guardian\\n */\\n function setGuardian(address newGuardian) public {\\n require(msg.sender == guardian, \\\"PriceOracleAdapterMoc: only guardian\\\");\\n require(\\n guardian != address(0),\\n \\\"PriceOracleAdapterMoc: guardin address can not be 0\\\"\\n );\\n //set old address\\n address oldGuardian = guardian;\\n //update\\n guardian = newGuardian;\\n //emit event\\n emit NewGuardian(oldGuardian, newGuardian);\\n }\\n}\\n\",\"keccak256\":\"0x6dc53b5de8b6f9e0b65eab05bfa3833f6bbf20444f2cc652da1b5a2dd592c462\",\"license\":\"UNLICENSED\"}},\"version\":1}", - "bytecode": "0x608060405234801561001057600080fd5b506040516106ac3803806106ac83398101604081905261002f9161016a565b6001600160a01b0382166100a15760405162461bcd60e51b815260206004820152602e60248201527f50726963654f7261636c65416461707465724d6f633a20677561726469616e2060448201526d0636f756c64206e6f7420626520360941b60648201526084015b60405180910390fd5b6001600160a01b03811661011d5760405162461bcd60e51b815260206004820152603360248201527f50726963654f7261636c65416461707465724d6f633a20707269636550726f7660448201527f6964657220636f756c64206e6f742062652030000000000000000000000000006064820152608401610098565b600080546001600160a01b039384166001600160a01b0319918216179091556001805492909316911617905561019d565b80516001600160a01b038116811461016557600080fd5b919050565b6000806040838503121561017d57600080fd5b6101868361014e565b91506101946020840161014e565b90509250929050565b610500806101ac6000396000f3fe608060405234801561001057600080fd5b50600436106100575760003560e01c806303fa251b1461005c578063372aa2241461008c578063452a9320146100a15780635e9a523c146100b45780638a0dac4a146100d5575b600080fd5b60015461006f906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b61009f61009a366004610465565b6100e8565b005b60005461006f906001600160a01b031681565b6100c76100c2366004610465565b61023b565b604051908152602001610083565b61009f6100e3366004610465565b610331565b6000546001600160a01b0316331461016d5760405162461bcd60e51b815260206004820152603860248201527f50726963654f7261636c65416461707465724d6f633a206f6e6c79206775617260448201527f6469616e206d617920736574207468652061646472657373000000000000000060648201526084015b60405180910390fd5b6001600160a01b0381166101d95760405162461bcd60e51b815260206004820152602d60248201527f50726963654f7261636c65416461707465724d6f633a2061646472657373206360448201526c06f756c64206e6f74206265203609c1b6064820152608401610164565b600180546001600160a01b038381166001600160a01b031983168117909355604080519190921680825260208201939093527f58d7caa9bcc8339b310213ec53c711c9157920c93aef03ac3c4a16ce01bc602e91015b60405180910390a15050565b6000806000600160009054906101000a90046001600160a01b03166001600160a01b03166359e02dd76040518163ffffffff1660e01b8152600401604080518083038186803b15801561028d57600080fd5b505afa1580156102a1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102c59190610495565b915091508061032a5760405162461bcd60e51b815260206004820152602b60248201527f50726963654f7261636c65416461707465724d6f633a204f7261636c6520686160448201526a7665206e6f20507269636560a81b6064820152608401610164565b5092915050565b6000546001600160a01b031633146103975760405162461bcd60e51b8152602060048201526024808201527f50726963654f7261636c65416461707465724d6f633a206f6e6c7920677561726044820152633234b0b760e11b6064820152608401610164565b6000546001600160a01b031661040b5760405162461bcd60e51b815260206004820152603360248201527f50726963654f7261636c65416461707465724d6f633a206775617264696e206160448201527206464726573732063616e206e6f74206265203606c1b6064820152608401610164565b600080546001600160a01b038381166001600160a01b031983168117909355604080519190921680825260208201939093527f08fdaf06427a2010e5958f4329b566993472d14ce81d3f16ce7f2a2660da98e3910161022f565b60006020828403121561047757600080fd5b81356001600160a01b038116811461048e57600080fd5b9392505050565b600080604083850312156104a857600080fd5b82519150602083015180151581146104bf57600080fd5b80915050925092905056fea2646970667358221220b3bf3342ac9831f468619e5dd1c72b3b86a808aa0bd558fde453ce03f4f9a2e764736f6c63430008060033", - "deployedBytecode": "0x608060405234801561001057600080fd5b50600436106100575760003560e01c806303fa251b1461005c578063372aa2241461008c578063452a9320146100a15780635e9a523c146100b45780638a0dac4a146100d5575b600080fd5b60015461006f906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b61009f61009a366004610465565b6100e8565b005b60005461006f906001600160a01b031681565b6100c76100c2366004610465565b61023b565b604051908152602001610083565b61009f6100e3366004610465565b610331565b6000546001600160a01b0316331461016d5760405162461bcd60e51b815260206004820152603860248201527f50726963654f7261636c65416461707465724d6f633a206f6e6c79206775617260448201527f6469616e206d617920736574207468652061646472657373000000000000000060648201526084015b60405180910390fd5b6001600160a01b0381166101d95760405162461bcd60e51b815260206004820152602d60248201527f50726963654f7261636c65416461707465724d6f633a2061646472657373206360448201526c06f756c64206e6f74206265203609c1b6064820152608401610164565b600180546001600160a01b038381166001600160a01b031983168117909355604080519190921680825260208201939093527f58d7caa9bcc8339b310213ec53c711c9157920c93aef03ac3c4a16ce01bc602e91015b60405180910390a15050565b6000806000600160009054906101000a90046001600160a01b03166001600160a01b03166359e02dd76040518163ffffffff1660e01b8152600401604080518083038186803b15801561028d57600080fd5b505afa1580156102a1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102c59190610495565b915091508061032a5760405162461bcd60e51b815260206004820152602b60248201527f50726963654f7261636c65416461707465724d6f633a204f7261636c6520686160448201526a7665206e6f20507269636560a81b6064820152608401610164565b5092915050565b6000546001600160a01b031633146103975760405162461bcd60e51b8152602060048201526024808201527f50726963654f7261636c65416461707465724d6f633a206f6e6c7920677561726044820152633234b0b760e11b6064820152608401610164565b6000546001600160a01b031661040b5760405162461bcd60e51b815260206004820152603360248201527f50726963654f7261636c65416461707465724d6f633a206775617264696e206160448201527206464726573732063616e206e6f74206265203606c1b6064820152608401610164565b600080546001600160a01b038381166001600160a01b031983168117909355604080519190921680825260208201939093527f08fdaf06427a2010e5958f4329b566993472d14ce81d3f16ce7f2a2660da98e3910161022f565b60006020828403121561047757600080fd5b81356001600160a01b038116811461048e57600080fd5b9392505050565b600080604083850312156104a857600080fd5b82519150602083015180151581146104bf57600080fd5b80915050925092905056fea2646970667358221220b3bf3342ac9831f468619e5dd1c72b3b86a808aa0bd558fde453ce03f4f9a2e764736f6c63430008060033", - "devdoc": { - "kind": "dev", - "methods": { - "assetPrices(address)": { - "returns": { - "_0": "The price" - } - }, - "constructor": { - "params": { - "guardian_": "address of guardian that is allowed to manage this contract", - "priceProvider": "address of asset's MoC price provider" - } - }, - "setGuardian(address)": { - "params": { - "newGuardian": "address of the guardian" - } - }, - "setPriceProvider(address)": { - "params": { - "priceProviderAddress": "address of price provider" - } - } - }, - "version": 1 - }, - "userdoc": { - "events": { - "NewGuardian(address,address)": { - "notice": "Guardian updated" - }, - "PriceOracleAdapterUpdated(address,address)": { - "notice": "Event adapter interface updated" - } - }, - "kind": "user", - "methods": { - "assetPrices(address)": { - "notice": "Get the price from MoC and divide it by the rBTC price" - }, - "constructor": { - "notice": "Construct a PriceOracleAdapter for a MoC oracle" - }, - "guardian()": { - "notice": "Address of the guardian" - }, - "priceProviderMoC()": { - "notice": "The MoC price oracle, which will continue to serve prices" - }, - "setGuardian(address)": { - "notice": "Set the address of the guardian" - }, - "setPriceProvider(address)": { - "notice": "Set the address of price provider" - } - }, - "version": 1 - }, - "storageLayout": { - "storage": [ - { - "astId": 39863, - "contract": "contracts/PriceOracleAdapterMoc.sol:PriceOracleAdapterMoc", - "label": "guardian", - "offset": 0, - "slot": "0", - "type": "t_address" - }, - { - "astId": 39867, - "contract": "contracts/PriceOracleAdapterMoc.sol:PriceOracleAdapterMoc", - "label": "priceProviderMoC", - "offset": 0, - "slot": "1", - "type": "t_contract(PriceProviderMoC)39858" - } - ], - "types": { - "t_address": { - "encoding": "inplace", - "label": "address", - "numberOfBytes": "20" - }, - "t_contract(PriceProviderMoC)39858": { - "encoding": "inplace", - "label": "contract PriceProviderMoC", - "numberOfBytes": "20" - } - } - } -} \ No newline at end of file diff --git a/deployments/localhost/USDT.json b/deployments/localhost/USDT.json deleted file mode 100644 index 65aac17..0000000 --- a/deployments/localhost/USDT.json +++ /dev/null @@ -1,379 +0,0 @@ -{ - "address": "0x9A676e781A523b5d0C0e43731313A708CB607508", - "abi": [ - { - "inputs": [ - { - "internalType": "uint256", - "name": "_initialAmount", - "type": "uint256" - }, - { - "internalType": "string", - "name": "_tokenName", - "type": "string" - }, - { - "internalType": "uint8", - "name": "_decimalUnits", - "type": "uint8" - }, - { - "internalType": "string", - "name": "_tokenSymbol", - "type": "string" - } - ], - "stateMutability": "nonpayable", - "type": "constructor" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "spender", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "Approval", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "Transfer", - "type": "event" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - }, - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "name": "allowance", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_spender", - "type": "address" - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "approve", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "name": "balanceOf", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "decimals", - "outputs": [ - { - "internalType": "uint8", - "name": "", - "type": "uint8" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "name", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "symbol", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalSupply", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "dst", - "type": "address" - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "transfer", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "src", - "type": "address" - }, - { - "internalType": "address", - "name": "dst", - "type": "address" - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "transferFrom", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "nonpayable", - "type": "function" - } - ], - "transactionHash": "0xc0610946ccaca8ac622e6ef661eb5cf0ae30d1bea8389f903d59f589d7f91fdb", - "receipt": { - "to": null, - "from": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", - "contractAddress": "0x9A676e781A523b5d0C0e43731313A708CB607508", - "transactionIndex": 0, - "gasUsed": "576654", - "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "blockHash": "0x5a3471bd812fcc27ff45fd57f24421f4c436b66a62dcea6cad66af25839b67cf", - "transactionHash": "0xc0610946ccaca8ac622e6ef661eb5cf0ae30d1bea8389f903d59f589d7f91fdb", - "logs": [], - "blockNumber": 15, - "cumulativeGasUsed": "576654", - "status": 1, - "byzantium": true - }, - "args": [ - "2000000000000000000000000", - "USDT token", - 18, - "rUSDT" - ], - "solcInputHash": "3f2295c0e5923ce11cb0f26c6e52bee2", - "metadata": "{\"compiler\":{\"version\":\"0.8.6+commit.11564f7e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_initialAmount\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"_tokenName\",\"type\":\"string\"},{\"internalType\":\"uint8\",\"name\":\"_decimalUnits\",\"type\":\"uint8\"},{\"internalType\":\"string\",\"name\":\"_tokenSymbol\",\"type\":\"string\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"Approval\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"Transfer\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"allowance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"approve\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"balanceOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"decimals\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"name\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"symbol\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"totalSupply\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"dst\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"transfer\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"src\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"dst\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"transferFrom\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Implementation of the basic standard token. See https://github.com/ethereum/EIPs/issues/20\",\"kind\":\"dev\",\"methods\":{},\"title\":\"Standard ERC20 token\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/ERC20.sol\":\"StandardToken\"},\"evmVersion\":\"berlin\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"contracts/ERC20.sol\":{\"content\":\"// SPDX-License-Identifier: UNLICENSED\\npragma solidity 0.8.6;\\n\\nimport \\\"./SafeMath.sol\\\";\\n\\ninterface ERC20Base {\\n event Approval(\\n address indexed owner,\\n address indexed spender,\\n uint256 value\\n );\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n function totalSupply() external view returns (uint256);\\n\\n function allowance(address owner, address spender)\\n external\\n view\\n returns (uint256);\\n\\n function approve(address spender, uint256 value)\\n external\\n returns (bool);\\n\\n function balanceOf(address who) external view returns (uint256);\\n}\\n\\nabstract contract ERC20 is ERC20Base {\\n function transfer(address to, uint256 value)\\n external\\n virtual\\n returns (bool);\\n\\n function transferFrom(\\n address from,\\n address to,\\n uint256 value\\n ) external virtual returns (bool);\\n}\\n\\nabstract contract ERC20NS is ERC20Base {\\n function transfer(address to, uint256 value) external virtual;\\n\\n function transferFrom(\\n address from,\\n address to,\\n uint256 value\\n ) external virtual;\\n}\\n\\n/**\\n * @title Standard ERC20 token\\n * @dev Implementation of the basic standard token.\\n * See https://github.com/ethereum/EIPs/issues/20\\n */\\ncontract StandardToken is ERC20 {\\n using SafeMath for uint256;\\n\\n string public name;\\n string public symbol;\\n uint8 public decimals;\\n uint256 public override totalSupply;\\n mapping(address => mapping(address => uint256)) public override allowance;\\n mapping(address => uint256) public override balanceOf;\\n\\n constructor(\\n uint256 _initialAmount,\\n string memory _tokenName,\\n uint8 _decimalUnits,\\n string memory _tokenSymbol\\n ) {\\n totalSupply = _initialAmount;\\n balanceOf[msg.sender] = _initialAmount;\\n name = _tokenName;\\n symbol = _tokenSymbol;\\n decimals = _decimalUnits;\\n }\\n\\n function transfer(address dst, uint256 amount)\\n external\\n virtual\\n override\\n returns (bool)\\n {\\n balanceOf[msg.sender] = balanceOf[msg.sender].sub(\\n amount,\\n \\\"Insufficient balance\\\"\\n );\\n balanceOf[dst] = balanceOf[dst].add(amount, \\\"Balance overflow\\\");\\n emit Transfer(msg.sender, dst, amount);\\n return true;\\n }\\n\\n function transferFrom(\\n address src,\\n address dst,\\n uint256 amount\\n ) external virtual override returns (bool) {\\n allowance[src][msg.sender] = allowance[src][msg.sender].sub(\\n amount,\\n \\\"Insufficient allowance\\\"\\n );\\n balanceOf[src] = balanceOf[src].sub(amount, \\\"Insufficient balance\\\");\\n balanceOf[dst] = balanceOf[dst].add(amount, \\\"Balance overflow\\\");\\n emit Transfer(src, dst, amount);\\n return true;\\n }\\n\\n function approve(address _spender, uint256 amount)\\n external\\n override\\n returns (bool)\\n {\\n allowance[msg.sender][_spender] = amount;\\n emit Approval(msg.sender, _spender, amount);\\n return true;\\n }\\n}\\n\\n/**\\n * @title Non-Standard ERC20 token\\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 */\\ncontract NonStandardToken is ERC20NS {\\n using SafeMath for uint256;\\n\\n string public name;\\n uint8 public decimals;\\n string public symbol;\\n uint256 public override totalSupply;\\n mapping(address => mapping(address => uint256)) public override allowance;\\n mapping(address => uint256) public override balanceOf;\\n\\n constructor(\\n uint256 _initialAmount,\\n string memory _tokenName,\\n uint8 _decimalUnits,\\n string memory _tokenSymbol\\n ) {\\n totalSupply = _initialAmount;\\n balanceOf[msg.sender] = _initialAmount;\\n name = _tokenName;\\n symbol = _tokenSymbol;\\n decimals = _decimalUnits;\\n }\\n\\n function transfer(address dst, uint256 amount) external override {\\n balanceOf[msg.sender] = balanceOf[msg.sender].sub(\\n amount,\\n \\\"Insufficient balance\\\"\\n );\\n balanceOf[dst] = balanceOf[dst].add(amount, \\\"Balance overflow\\\");\\n emit Transfer(msg.sender, dst, amount);\\n }\\n\\n function transferFrom(\\n address src,\\n address dst,\\n uint256 amount\\n ) external override {\\n allowance[src][msg.sender] = allowance[src][msg.sender].sub(\\n amount,\\n \\\"Insufficient allowance\\\"\\n );\\n balanceOf[src] = balanceOf[src].sub(amount, \\\"Insufficient balance\\\");\\n balanceOf[dst] = balanceOf[dst].add(amount, \\\"Balance overflow\\\");\\n emit Transfer(src, dst, amount);\\n }\\n\\n function approve(address _spender, uint256 amount)\\n external\\n override\\n returns (bool)\\n {\\n allowance[msg.sender][_spender] = amount;\\n emit Approval(msg.sender, _spender, amount);\\n return true;\\n }\\n}\\n\\ncontract ERC20Harness is StandardToken {\\n using SafeMath for uint256;\\n\\n // To support testing, we can specify addresses for which transferFrom should fail and return false\\n mapping(address => bool) public failTransferFromAddresses;\\n\\n // To support testing, we allow the contract to always fail `transfer`.\\n mapping(address => bool) public failTransferToAddresses;\\n\\n constructor(\\n uint256 _initialAmount,\\n string memory _tokenName,\\n uint8 _decimalUnits,\\n string memory _tokenSymbol\\n ) StandardToken(_initialAmount, _tokenName, _decimalUnits, _tokenSymbol) {}\\n\\n function harnessSetFailTransferFromAddress(address src, bool _fail) public {\\n failTransferFromAddresses[src] = _fail;\\n }\\n\\n function harnessSetFailTransferToAddress(address dst, bool _fail) public {\\n failTransferToAddresses[dst] = _fail;\\n }\\n\\n function harnessSetBalance(address _account, uint256 _amount) public {\\n balanceOf[_account] = _amount;\\n }\\n\\n function transfer(address dst, uint256 amount)\\n external\\n override\\n returns (bool success)\\n {\\n // Added for testing purposes\\n if (failTransferToAddresses[dst]) {\\n return false;\\n }\\n balanceOf[msg.sender] = balanceOf[msg.sender].sub(\\n amount,\\n \\\"Insufficient balance\\\"\\n );\\n balanceOf[dst] = balanceOf[dst].add(amount, \\\"Balance overflow\\\");\\n emit Transfer(msg.sender, dst, amount);\\n return true;\\n }\\n\\n function transferFrom(\\n address src,\\n address dst,\\n uint256 amount\\n ) external override returns (bool success) {\\n // Added for testing purposes\\n if (failTransferFromAddresses[src]) {\\n return false;\\n }\\n allowance[src][msg.sender] = allowance[src][msg.sender].sub(\\n amount,\\n \\\"Insufficient allowance\\\"\\n );\\n balanceOf[src] = balanceOf[src].sub(amount, \\\"Insufficient balance\\\");\\n balanceOf[dst] = balanceOf[dst].add(amount, \\\"Balance overflow\\\");\\n emit Transfer(src, dst, amount);\\n return true;\\n }\\n}\\n\",\"keccak256\":\"0x5450f997ac4f79dc1109aed20142bc67e17b97b78d7d399f7250f6ee04b38582\",\"license\":\"UNLICENSED\"},\"contracts/SafeMath.sol\":{\"content\":\"// SPDX-License-Identifier: UNLICENSED\\npragma solidity 0.8.6;\\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\":\"0xe578b9602160e7ddbb5e7b6d355bb4508fa134684afe46e4043602c652e0e041\",\"license\":\"UNLICENSED\"}},\"version\":1}", - "bytecode": "0x60806040523480156200001157600080fd5b5060405162000a3f38038062000a3f8339810160408190526200003491620001f0565b6003849055336000908152600560209081526040822086905584516200005e929186019062000093565b5080516200007490600190602084019062000093565b50506002805460ff191660ff9290921691909117905550620002d29050565b828054620000a1906200027f565b90600052602060002090601f016020900481019282620000c5576000855562000110565b82601f10620000e057805160ff191683800117855562000110565b8280016001018555821562000110579182015b8281111562000110578251825591602001919060010190620000f3565b506200011e92915062000122565b5090565b5b808211156200011e576000815560010162000123565b600082601f8301126200014b57600080fd5b81516001600160401b0380821115620001685762000168620002bc565b604051601f8301601f19908116603f01168101908282118183101715620001935762000193620002bc565b81604052838152602092508683858801011115620001b057600080fd5b600091505b83821015620001d45785820183015181830184015290820190620001b5565b83821115620001e65760008385830101525b9695505050505050565b600080600080608085870312156200020757600080fd5b845160208601519094506001600160401b03808211156200022757600080fd5b620002358883890162000139565b94506040870151915060ff821682146200024e57600080fd5b6060870151919350808211156200026457600080fd5b50620002738782880162000139565b91505092959194509250565b600181811c908216806200029457607f821691505b60208210811415620002b657634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052604160045260246000fd5b61075d80620002e26000396000f3fe608060405234801561001057600080fd5b50600436106100935760003560e01c8063313ce56711610066578063313ce5671461010357806370a082311461012257806395d89b4114610142578063a9059cbb1461014a578063dd62ed3e1461015d57600080fd5b806306fdde0314610098578063095ea7b3146100b657806318160ddd146100d957806323b872dd146100f0575b600080fd5b6100a0610188565b6040516100ad9190610652565b60405180910390f35b6100c96100c4366004610628565b610216565b60405190151581526020016100ad565b6100e260035481565b6040519081526020016100ad565b6100c96100fe3660046105ec565b610282565b6002546101109060ff1681565b60405160ff90911681526020016100ad565b6100e2610130366004610597565b60056020526000908152604090205481565b6100a0610401565b6100c9610158366004610628565b61040e565b6100e261016b3660046105b9565b600460209081526000928352604080842090915290825290205481565b60008054610195906106d6565b80601f01602080910402602001604051908101604052809291908181526020018280546101c1906106d6565b801561020e5780601f106101e35761010080835404028352916020019161020e565b820191906000526020600020905b8154815290600101906020018083116101f157829003601f168201915b505050505081565b3360008181526004602090815260408083206001600160a01b038716808552925280832085905551919290917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925906102719086815260200190565b60405180910390a350600192915050565b6040805180820182526016815275496e73756666696369656e7420616c6c6f77616e636560501b6020808301919091526001600160a01b038616600090815260048252838120338252909152918220546102dd9184906104fe565b6001600160a01b0385166000818152600460209081526040808320338452825280832094909455835180850185526014815273496e73756666696369656e742062616c616e636560601b818301529282526005905291909120546103429184906104fe565b6001600160a01b0380861660009081526005602081815260408084209590955584518086018652601081526f42616c616e6365206f766572666c6f7760801b81830152938816835252919091205461039b918490610541565b6001600160a01b0380851660008181526005602052604090819020939093559151908616907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef906103ef9086815260200190565b60405180910390a35060019392505050565b60018054610195906106d6565b6040805180820182526014815273496e73756666696369656e742062616c616e636560601b6020808301919091523360009081526005909152918220546104569184906104fe565b3360009081526005602081815260408084209490945583518085018552601081526f42616c616e6365206f766572666c6f7760801b818301526001600160a01b0388168452919052919020546104ad918490610541565b6001600160a01b0384166000818152600560205260409081902092909255905133907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef906102719086815260200190565b6000818484111561052b5760405162461bcd60e51b81526004016105229190610652565b60405180910390fd5b50600061053884866106bf565b95945050505050565b60008061054e84866106a7565b905082858210156105725760405162461bcd60e51b81526004016105229190610652565b50949350505050565b80356001600160a01b038116811461059257600080fd5b919050565b6000602082840312156105a957600080fd5b6105b28261057b565b9392505050565b600080604083850312156105cc57600080fd5b6105d58361057b565b91506105e36020840161057b565b90509250929050565b60008060006060848603121561060157600080fd5b61060a8461057b565b92506106186020850161057b565b9150604084013590509250925092565b6000806040838503121561063b57600080fd5b6106448361057b565b946020939093013593505050565b600060208083528351808285015260005b8181101561067f57858101830151858201604001528201610663565b81811115610691576000604083870101525b50601f01601f1916929092016040019392505050565b600082198211156106ba576106ba610711565b500190565b6000828210156106d1576106d1610711565b500390565b600181811c908216806106ea57607f821691505b6020821081141561070b57634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052601160045260246000fdfea2646970667358221220d01609e330d83e9dc4a8b2b591f78f2787d98d49067556154372370d143909ef64736f6c63430008060033", - "deployedBytecode": "0x608060405234801561001057600080fd5b50600436106100935760003560e01c8063313ce56711610066578063313ce5671461010357806370a082311461012257806395d89b4114610142578063a9059cbb1461014a578063dd62ed3e1461015d57600080fd5b806306fdde0314610098578063095ea7b3146100b657806318160ddd146100d957806323b872dd146100f0575b600080fd5b6100a0610188565b6040516100ad9190610652565b60405180910390f35b6100c96100c4366004610628565b610216565b60405190151581526020016100ad565b6100e260035481565b6040519081526020016100ad565b6100c96100fe3660046105ec565b610282565b6002546101109060ff1681565b60405160ff90911681526020016100ad565b6100e2610130366004610597565b60056020526000908152604090205481565b6100a0610401565b6100c9610158366004610628565b61040e565b6100e261016b3660046105b9565b600460209081526000928352604080842090915290825290205481565b60008054610195906106d6565b80601f01602080910402602001604051908101604052809291908181526020018280546101c1906106d6565b801561020e5780601f106101e35761010080835404028352916020019161020e565b820191906000526020600020905b8154815290600101906020018083116101f157829003601f168201915b505050505081565b3360008181526004602090815260408083206001600160a01b038716808552925280832085905551919290917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925906102719086815260200190565b60405180910390a350600192915050565b6040805180820182526016815275496e73756666696369656e7420616c6c6f77616e636560501b6020808301919091526001600160a01b038616600090815260048252838120338252909152918220546102dd9184906104fe565b6001600160a01b0385166000818152600460209081526040808320338452825280832094909455835180850185526014815273496e73756666696369656e742062616c616e636560601b818301529282526005905291909120546103429184906104fe565b6001600160a01b0380861660009081526005602081815260408084209590955584518086018652601081526f42616c616e6365206f766572666c6f7760801b81830152938816835252919091205461039b918490610541565b6001600160a01b0380851660008181526005602052604090819020939093559151908616907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef906103ef9086815260200190565b60405180910390a35060019392505050565b60018054610195906106d6565b6040805180820182526014815273496e73756666696369656e742062616c616e636560601b6020808301919091523360009081526005909152918220546104569184906104fe565b3360009081526005602081815260408084209490945583518085018552601081526f42616c616e6365206f766572666c6f7760801b818301526001600160a01b0388168452919052919020546104ad918490610541565b6001600160a01b0384166000818152600560205260409081902092909255905133907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef906102719086815260200190565b6000818484111561052b5760405162461bcd60e51b81526004016105229190610652565b60405180910390fd5b50600061053884866106bf565b95945050505050565b60008061054e84866106a7565b905082858210156105725760405162461bcd60e51b81526004016105229190610652565b50949350505050565b80356001600160a01b038116811461059257600080fd5b919050565b6000602082840312156105a957600080fd5b6105b28261057b565b9392505050565b600080604083850312156105cc57600080fd5b6105d58361057b565b91506105e36020840161057b565b90509250929050565b60008060006060848603121561060157600080fd5b61060a8461057b565b92506106186020850161057b565b9150604084013590509250925092565b6000806040838503121561063b57600080fd5b6106448361057b565b946020939093013593505050565b600060208083528351808285015260005b8181101561067f57858101830151858201604001528201610663565b81811115610691576000604083870101525b50601f01601f1916929092016040019392505050565b600082198211156106ba576106ba610711565b500190565b6000828210156106d1576106d1610711565b500390565b600181811c908216806106ea57607f821691505b6020821081141561070b57634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052601160045260246000fdfea2646970667358221220d01609e330d83e9dc4a8b2b591f78f2787d98d49067556154372370d143909ef64736f6c63430008060033", - "devdoc": { - "details": "Implementation of the basic standard token. See https://github.com/ethereum/EIPs/issues/20", - "kind": "dev", - "methods": {}, - "title": "Standard ERC20 token", - "version": 1 - }, - "userdoc": { - "kind": "user", - "methods": {}, - "version": 1 - }, - "storageLayout": { - "storage": [ - { - "astId": 33360, - "contract": "contracts/ERC20.sol:StandardToken", - "label": "name", - "offset": 0, - "slot": "0", - "type": "t_string_storage" - }, - { - "astId": 33362, - "contract": "contracts/ERC20.sol:StandardToken", - "label": "symbol", - "offset": 0, - "slot": "1", - "type": "t_string_storage" - }, - { - "astId": 33364, - "contract": "contracts/ERC20.sol:StandardToken", - "label": "decimals", - "offset": 0, - "slot": "2", - "type": "t_uint8" - }, - { - "astId": 33367, - "contract": "contracts/ERC20.sol:StandardToken", - "label": "totalSupply", - "offset": 0, - "slot": "3", - "type": "t_uint256" - }, - { - "astId": 33374, - "contract": "contracts/ERC20.sol:StandardToken", - "label": "allowance", - "offset": 0, - "slot": "4", - "type": "t_mapping(t_address,t_mapping(t_address,t_uint256))" - }, - { - "astId": 33379, - "contract": "contracts/ERC20.sol:StandardToken", - "label": "balanceOf", - "offset": 0, - "slot": "5", - "type": "t_mapping(t_address,t_uint256)" - } - ], - "types": { - "t_address": { - "encoding": "inplace", - "label": "address", - "numberOfBytes": "20" - }, - "t_mapping(t_address,t_mapping(t_address,t_uint256))": { - "encoding": "mapping", - "key": "t_address", - "label": "mapping(address => mapping(address => uint256))", - "numberOfBytes": "32", - "value": "t_mapping(t_address,t_uint256)" - }, - "t_mapping(t_address,t_uint256)": { - "encoding": "mapping", - "key": "t_address", - "label": "mapping(address => uint256)", - "numberOfBytes": "32", - "value": "t_uint256" - }, - "t_string_storage": { - "encoding": "bytes", - "label": "string", - "numberOfBytes": "32" - }, - "t_uint256": { - "encoding": "inplace", - "label": "uint256", - "numberOfBytes": "32" - }, - "t_uint8": { - "encoding": "inplace", - "label": "uint8", - "numberOfBytes": "1" - } - } - } -} \ No newline at end of file diff --git a/deployments/localhost/USDTOracle.json b/deployments/localhost/USDTOracle.json deleted file mode 100644 index a289b22..0000000 --- a/deployments/localhost/USDTOracle.json +++ /dev/null @@ -1,183 +0,0 @@ -{ - "address": "0x67d269191c92Caf3cD7723F116c85e6E9bf55933", - "abi": [ - { - "inputs": [ - { - "internalType": "address", - "name": "guardian_", - "type": "address" - }, - { - "internalType": "uint256", - "name": "price", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "constructor" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "oldPrice", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "newPrice", - "type": "uint256" - } - ], - "name": "MockPriceProviderMoCUpdated", - "type": "event" - }, - { - "inputs": [], - "name": "guardian", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "peek", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - }, - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "price", - "type": "uint256" - } - ], - "name": "setPrice", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - } - ], - "transactionHash": "0x2bfcd2a97331cec964e37eeb6170241fe18fee436349f3c2d47d1cc3404ce783", - "receipt": { - "to": null, - "from": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", - "contractAddress": "0x67d269191c92Caf3cD7723F116c85e6E9bf55933", - "transactionIndex": 0, - "gasUsed": "220552", - "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "blockHash": "0x7101bcacbf126a6f34d18321ba226b922b8cfb0094002579e31beea848ceccb0", - "transactionHash": "0x2bfcd2a97331cec964e37eeb6170241fe18fee436349f3c2d47d1cc3404ce783", - "logs": [], - "blockNumber": 30, - "cumulativeGasUsed": "220552", - "status": 1, - "byzantium": true - }, - "args": [ - "0x09635F643e140090A9A8Dcd712eD6285858ceBef", - "1050000000000000000" - ], - "solcInputHash": "3f2295c0e5923ce11cb0f26c6e52bee2", - "metadata": "{\"compiler\":{\"version\":\"0.8.6+commit.11564f7e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"guardian_\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"price\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldPrice\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newPrice\",\"type\":\"uint256\"}],\"name\":\"MockPriceProviderMoCUpdated\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"guardian\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"peek\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"price\",\"type\":\"uint256\"}],\"name\":\"setPrice\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"setPrice(uint256)\":{\"params\":{\"price\":\"uint of price provider\"}}},\"title\":\"A mock price provider of Money on Chain (MoC)\",\"version\":1},\"userdoc\":{\"events\":{\"MockPriceProviderMoCUpdated(uint256,uint256)\":{\"notice\":\"Event rbtcPrice updated\"}},\"kind\":\"user\",\"methods\":{\"guardian()\":{\"notice\":\"Address of the guardian\"},\"setPrice(uint256)\":{\"notice\":\"Set the rbtcPrice price provider\"}},\"notice\":\"You can use this contract for only simulation\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/mocks/MockPriceProviderMoC.sol\":\"MockPriceProviderMoC\"},\"evmVersion\":\"berlin\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"contracts/CErc20.sol\":{\"content\":\"// SPDX-License-Identifier: UNLICENSED\\npragma solidity 0.8.6;\\n\\nimport \\\"./CToken.sol\\\";\\nimport \\\"./CTokenInterfaces.sol\\\";\\n\\n/**\\n * @title tropykus CErc20 Contract\\n * @notice CTokens which wrap an EIP-20 underlying\\n * @author tropykus\\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(\\n address underlying_,\\n ComptrollerInterface comptroller_,\\n InterestRateModel interestRateModel_,\\n uint256 initialExchangeRateMantissa_,\\n string memory name_,\\n string memory symbol_,\\n uint8 decimals_\\n ) public {\\n // CToken initialize does the bulk of the work\\n super.initialize(\\n comptroller_,\\n interestRateModel_,\\n initialExchangeRateMantissa_,\\n name_,\\n symbol_,\\n decimals_\\n );\\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(uint256 mintAmount) external override returns (uint256) {\\n (uint256 err, ) = mintInternal(mintAmount);\\n return err;\\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 redeem(uint256 redeemAmount)\\n external\\n override\\n returns (uint256)\\n {\\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(uint256 borrowAmount) external override returns (uint256) {\\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(uint256 repayAmount)\\n external\\n override\\n returns (uint256)\\n {\\n (uint256 err, ) = repayBorrowInternal(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(\\n address borrower,\\n uint256 repayAmount,\\n CTokenInterface cTokenCollateral\\n ) external override returns (uint256) {\\n (uint256 err, ) = liquidateBorrowInternal(\\n borrower,\\n repayAmount,\\n cTokenCollateral\\n );\\n return err;\\n }\\n\\n /**\\n * @notice A public function to sweep accidental ERC-20 transfers to this contract. Tokens are sent to admin (timelock)\\n * @param token The address of the ERC-20 token to sweep\\n */\\n function sweepToken(EIP20NonStandardInterface token) external override {\\n require(address(token) != underlying, \\\"EC01\\\");\\n uint256 balance = token.balanceOf(address(this));\\n token.transfer(admin, balance);\\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(uint256 addAmount)\\n external\\n override\\n returns (uint256)\\n {\\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 override returns (uint256) {\\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, uint256 amount)\\n internal\\n override\\n returns (uint256)\\n {\\n EIP20NonStandardInterface token = EIP20NonStandardInterface(underlying);\\n uint256 balanceBefore = EIP20Interface(underlying).balanceOf(\\n address(this)\\n );\\n token.transferFrom(from, address(this), amount);\\n\\n bool success;\\n assembly {\\n switch returndatasize()\\n case 0 {\\n // This is a non-standard ERC-20\\n success := not(0) // set success to true\\n }\\n case 32 {\\n // This is a compliant ERC-20\\n returndatacopy(0, 0, 32)\\n success := mload(0) // Set `success = returndata` of external call\\n }\\n default {\\n // This is an excessively non-compliant ERC-20, revert.\\n revert(0, 0)\\n }\\n }\\n require(success, \\\"EC02\\\");\\n\\n // Calculate the amount that was *actually* transferred\\n uint256 balanceAfter = EIP20Interface(underlying).balanceOf(\\n address(this)\\n );\\n require(balanceAfter >= balanceBefore, \\\"EC03\\\");\\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, uint256 amount)\\n internal\\n virtual\\n override\\n {\\n EIP20NonStandardInterface token = EIP20NonStandardInterface(underlying);\\n token.transfer(to, amount);\\n\\n bool success;\\n assembly {\\n switch returndatasize()\\n case 0 {\\n // This is a non-standard ERC-20\\n success := not(0) // set success to true\\n }\\n case 32 {\\n // This is a complaint ERC-20\\n returndatacopy(0, 0, 32)\\n success := mload(0) // Set `success = returndata` of external call\\n }\\n default {\\n // This is an excessively non-compliant ERC-20, revert.\\n revert(0, 0)\\n }\\n }\\n require(success, \\\"CE01\\\");\\n }\\n}\\n\",\"keccak256\":\"0x539c67e8b5bf011926bd82655501f2016db29e890139a1b466461a3298950365\",\"license\":\"UNLICENSED\"},\"contracts/CToken.sol\":{\"content\":\"// SPDX-License-Identifier: UNLICENSED\\npragma solidity 0.8.6;\\n\\nimport \\\"./ComptrollerInterface.sol\\\";\\nimport \\\"./CTokenInterfaces.sol\\\";\\nimport \\\"./ErrorReporter.sol\\\";\\nimport \\\"./Exponential.sol\\\";\\nimport \\\"./EIP20Interface.sol\\\";\\nimport \\\"./InterestRateModel.sol\\\";\\nimport \\\"./WhitelistInterface.sol\\\";\\n\\n/**\\n * @title tropykus CToken Contract\\n * @notice Abstract base for CTokens\\n * @author tropykus\\n */\\nabstract contract CToken is CTokenInterface, Exponential, TokenErrorReporter {\\n address whitelist;\\n\\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(\\n ComptrollerInterface comptroller_,\\n InterestRateModel interestRateModel_,\\n uint256 initialExchangeRateMantissa_,\\n string memory name_,\\n string memory symbol_,\\n uint8 decimals_\\n ) public {\\n require(msg.sender == admin, \\\"CT01\\\");\\n require(accrualBlockNumber == 0 && borrowIndex == 0, \\\"CT02\\\");\\n\\n initialExchangeRateMantissa = initialExchangeRateMantissa_;\\n require(initialExchangeRateMantissa > 0, \\\"CT03\\\");\\n\\n uint256 err = _setComptroller(comptroller_);\\n require(err == uint256(Error.NO_ERROR), \\\"CT04\\\");\\n\\n accrualBlockNumber = getBlockNumber();\\n borrowIndex = mantissaOne;\\n\\n err = _setInterestRateModelFresh(interestRateModel_);\\n require(err == uint256(Error.NO_ERROR), \\\"CT05\\\");\\n\\n name = name_;\\n symbol = symbol_;\\n decimals = decimals_;\\n\\n _notEntered = true;\\n }\\n\\n function addWhitelist(address _whitelist) external returns (uint256) {\\n if (msg.sender != admin) {\\n return\\n fail(\\n Error.UNAUTHORIZED,\\n FailureInfo.SET_INTEREST_RATE_MODEL_OWNER_CHECK\\n );\\n }\\n whitelist = _whitelist;\\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(\\n address spender,\\n address src,\\n address dst,\\n uint256 tokens\\n ) internal returns (uint256) {\\n uint256 allowed = comptroller.transferAllowed(\\n address(this),\\n src,\\n dst,\\n tokens\\n );\\n if (allowed != 0) {\\n return\\n failOpaque(\\n Error.COMPTROLLER_REJECTION,\\n FailureInfo.TRANSFER_COMPTROLLER_REJECTION,\\n allowed\\n );\\n }\\n\\n if (src == dst) {\\n return fail(Error.BAD_INPUT, FailureInfo.TRANSFER_NOT_ALLOWED);\\n }\\n\\n uint256 startingAllowance = 0;\\n if (spender == src) {\\n startingAllowance = type(uint256).max;\\n } else {\\n startingAllowance = transferAllowances[src][spender];\\n }\\n\\n MathError mathErr;\\n uint256 allowanceNew;\\n uint256 srcTokensNew;\\n uint256 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, 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, tokens);\\n if (mathErr != MathError.NO_ERROR) {\\n return fail(Error.MATH_ERROR, FailureInfo.TRANSFER_TOO_MUCH);\\n }\\n\\n accountTokens[src].tokens = srcTokensNew;\\n accountTokens[dst].tokens = dstTokensNew;\\n\\n if (startingAllowance != type(uint256).max) {\\n transferAllowances[src][spender] = allowanceNew;\\n }\\n\\n emit Transfer(src, dst, tokens);\\n\\n return uint256(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)\\n external\\n override\\n nonReentrant\\n returns (bool)\\n {\\n return\\n transferTokens(msg.sender, msg.sender, dst, amount) ==\\n uint256(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(\\n address src,\\n address dst,\\n uint256 amount\\n ) external override nonReentrant returns (bool) {\\n return\\n transferTokens(msg.sender, src, dst, amount) ==\\n uint256(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)\\n external\\n override\\n returns (bool)\\n {\\n transferAllowances[msg.sender][spender] = amount;\\n emit Approval(msg.sender, 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)\\n external\\n view\\n override\\n returns (uint256)\\n {\\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 override returns (uint256) {\\n return accountTokens[owner].tokens;\\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)\\n external\\n override\\n returns (uint256)\\n {\\n (MathError mErr, uint256 balance) = mulScalarTruncate(\\n Exp({mantissa: exchangeRateCurrent()}),\\n accountTokens[owner].tokens\\n );\\n require(mErr == MathError.NO_ERROR, \\\"CT06\\\");\\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)\\n external\\n view\\n override\\n returns (\\n uint256,\\n uint256,\\n uint256,\\n uint256\\n )\\n {\\n uint256 cTokenBalance = accountTokens[account].tokens;\\n uint256 borrowBalance;\\n uint256 exchangeRateMantissa;\\n\\n MathError mErr;\\n\\n (mErr, borrowBalance) = borrowBalanceStoredInternal(account);\\n if (mErr != MathError.NO_ERROR) {\\n return (uint256(Error.MATH_ERROR), 0, 0, 0);\\n }\\n\\n (mErr, exchangeRateMantissa) = exchangeRateStoredInternal();\\n if (mErr != MathError.NO_ERROR) {\\n return (uint256(Error.MATH_ERROR), 0, 0, 0);\\n }\\n\\n return (\\n uint256(Error.NO_ERROR),\\n cTokenBalance,\\n borrowBalance,\\n exchangeRateMantissa\\n );\\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 virtual returns (uint256) {\\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 override returns (uint256) {\\n return\\n interestRateModel.getBorrowRate(\\n getCashPrior(),\\n totalBorrows,\\n totalReserves\\n );\\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 override returns (uint256) {\\n return\\n interestRateModel.getSupplyRate(\\n getCashPrior(),\\n totalBorrows,\\n totalReserves,\\n reserveFactorMantissa\\n );\\n }\\n\\n /**\\n * @notice Returns the current total borrows plus accrued interest\\n * @return The total borrows with interest\\n */\\n function totalBorrowsCurrent()\\n external\\n override\\n nonReentrant\\n returns (uint256)\\n {\\n require(accrueInterest() == uint256(Error.NO_ERROR), \\\"CT07\\\");\\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)\\n external\\n override\\n nonReentrant\\n returns (uint256)\\n {\\n require(accrueInterest() == uint256(Error.NO_ERROR), \\\"CT07\\\");\\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)\\n public\\n view\\n override\\n returns (uint256)\\n {\\n (MathError err, uint256 result) = borrowBalanceStoredInternal(account);\\n require(err == MathError.NO_ERROR, \\\"CT08\\\");\\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)\\n internal\\n view\\n returns (MathError, uint256)\\n {\\n MathError mathErr;\\n uint256 principalTimesIndex;\\n uint256 result;\\n\\n BorrowSnapshot storage borrowSnapshot = accountBorrows[account];\\n\\n if (borrowSnapshot.principal == 0) {\\n return (MathError.NO_ERROR, 0);\\n }\\n\\n (mathErr, principalTimesIndex) = mulUInt(\\n borrowSnapshot.principal,\\n borrowIndex\\n );\\n if (mathErr != MathError.NO_ERROR) {\\n return (mathErr, 0);\\n }\\n\\n (mathErr, result) = divUInt(\\n principalTimesIndex,\\n borrowSnapshot.interestIndex\\n );\\n if (mathErr != MathError.NO_ERROR) {\\n return (mathErr, 0);\\n }\\n\\n return (MathError.NO_ERROR, result);\\n }\\n\\n function getBorrowerPrincipalStored(address account)\\n public\\n view\\n returns (uint256 borrowed)\\n {\\n borrowed = accountBorrows[account].principal;\\n }\\n\\n function getSupplierSnapshotStored(address account)\\n public\\n view\\n returns (\\n uint256 tokens,\\n uint256 underlyingAmount,\\n uint256 suppliedAt,\\n uint256 promisedSupplyRate\\n )\\n {\\n tokens = accountTokens[account].tokens;\\n underlyingAmount = accountTokens[account].underlyingAmount;\\n suppliedAt = accountTokens[account].suppliedAt;\\n promisedSupplyRate = accountTokens[account].promisedSupplyRate;\\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()\\n public\\n override\\n nonReentrant\\n returns (uint256)\\n {\\n require(accrueInterest() == uint256(Error.NO_ERROR), \\\"CT07\\\");\\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 override returns (uint256) {\\n (MathError err, uint256 result) = exchangeRateStoredInternal();\\n require(err == MathError.NO_ERROR, \\\"CT09\\\");\\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()\\n internal\\n view\\n virtual\\n returns (MathError, uint256)\\n {\\n uint256 _totalSupply = totalSupply;\\n if (_totalSupply == 0) {\\n return (MathError.NO_ERROR, initialExchangeRateMantissa);\\n } else {\\n MathError error;\\n uint256 exchangeRate;\\n uint256 totalCash = getCashPrior();\\n if (interestRateModel.isTropykusInterestRateModel()) {\\n (error, exchangeRate) = tropykusExchangeRateStoredInternal(\\n msg.sender\\n );\\n if (error == MathError.NO_ERROR) {\\n return (MathError.NO_ERROR, exchangeRate);\\n } else {\\n return (MathError.NO_ERROR, initialExchangeRateMantissa);\\n }\\n }\\n return\\n interestRateModel.getExchangeRate(\\n totalCash,\\n totalBorrows,\\n totalReserves,\\n totalSupply\\n );\\n }\\n }\\n\\n function tropykusExchangeRateStoredInternal(address redeemer)\\n internal\\n view\\n returns (MathError, uint256)\\n {\\n if (totalSupply == 0) {\\n return (MathError.NO_ERROR, initialExchangeRateMantissa);\\n } else {\\n SupplySnapshot storage supplySnapshot = accountTokens[redeemer];\\n if (supplySnapshot.suppliedAt == 0) {\\n return (MathError.DIVISION_BY_ZERO, 0);\\n }\\n (, uint256 interestFactorMantissa, ) = tropykusInterestAccrued(\\n redeemer\\n );\\n Exp memory interestFactor = Exp({mantissa: interestFactorMantissa});\\n uint256 currentUnderlying = supplySnapshot.underlyingAmount;\\n Exp memory redeemerUnderlying = Exp({mantissa: currentUnderlying});\\n (, Exp memory realAmount) = mulExp(\\n interestFactor,\\n redeemerUnderlying\\n );\\n (, Exp memory exchangeRate) = getExp(\\n realAmount.mantissa,\\n supplySnapshot.tokens\\n );\\n return (MathError.NO_ERROR, exchangeRate.mantissa);\\n }\\n }\\n\\n function tropykusInterestAccrued(address account)\\n internal\\n view\\n returns (\\n MathError,\\n uint256,\\n uint256\\n )\\n {\\n SupplySnapshot storage supplySnapshot = accountTokens[account];\\n uint256 promisedSupplyRate = supplySnapshot.promisedSupplyRate;\\n Exp memory expectedSupplyRatePerBlock = Exp({\\n mantissa: promisedSupplyRate\\n });\\n (, uint256 delta) = subUInt(\\n accrualBlockNumber,\\n supplySnapshot.suppliedAt\\n );\\n (, Exp memory expectedSupplyRatePerBlockWithDelta) = mulScalar(\\n expectedSupplyRatePerBlock,\\n delta\\n );\\n (, Exp memory interestFactor) = addExp(\\n Exp({mantissa: 1e18}),\\n expectedSupplyRatePerBlockWithDelta\\n );\\n uint256 currentUnderlying = supplySnapshot.underlyingAmount;\\n Exp memory redeemerUnderlying = Exp({mantissa: currentUnderlying});\\n (, Exp memory realAmount) = mulExp(interestFactor, redeemerUnderlying);\\n (, uint256 interestEarned) = subUInt(\\n realAmount.mantissa,\\n currentUnderlying\\n );\\n return (MathError.NO_ERROR, interestFactor.mantissa, interestEarned);\\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 override returns (uint256) {\\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 override returns (uint256) {\\n uint256 currentBlockNumber = getBlockNumber();\\n uint256 accrualBlockNumberPrior = accrualBlockNumber;\\n\\n if (accrualBlockNumberPrior == currentBlockNumber) {\\n return uint256(Error.NO_ERROR);\\n }\\n\\n uint256 cashPrior = getCashPrior();\\n uint256 borrowsPrior = totalBorrows;\\n uint256 reservesPrior = totalReserves;\\n uint256 borrowIndexPrior = borrowIndex;\\n\\n uint256 borrowRateMantissa = interestRateModel.getBorrowRate(\\n cashPrior,\\n borrowsPrior,\\n reservesPrior\\n );\\n require(borrowRateMantissa <= borrowRateMaxMantissa, \\\"CT10\\\");\\n\\n (MathError mathErr, uint256 blockDelta) = subUInt(\\n currentBlockNumber,\\n accrualBlockNumberPrior\\n );\\n require(mathErr == MathError.NO_ERROR, \\\"CT11\\\");\\n\\n Exp memory simpleInterestFactor;\\n uint256 interestAccumulated;\\n uint256 totalBorrowsNew;\\n uint256 totalReservesNew;\\n uint256 borrowIndexNew;\\n\\n (mathErr, simpleInterestFactor) = mulScalar(\\n Exp({mantissa: borrowRateMantissa}),\\n blockDelta\\n );\\n if (mathErr != MathError.NO_ERROR) {\\n return\\n failOpaque(\\n Error.MATH_ERROR,\\n FailureInfo\\n .ACCRUE_INTEREST_SIMPLE_INTEREST_FACTOR_CALCULATION_FAILED,\\n uint256(mathErr)\\n );\\n }\\n\\n (mathErr, interestAccumulated) = mulScalarTruncate(\\n simpleInterestFactor,\\n borrowsPrior\\n );\\n if (mathErr != MathError.NO_ERROR) {\\n return\\n failOpaque(\\n Error.MATH_ERROR,\\n FailureInfo\\n .ACCRUE_INTEREST_ACCUMULATED_INTEREST_CALCULATION_FAILED,\\n uint256(mathErr)\\n );\\n }\\n\\n (mathErr, totalBorrowsNew) = addUInt(interestAccumulated, borrowsPrior);\\n if (mathErr != MathError.NO_ERROR) {\\n return\\n failOpaque(\\n Error.MATH_ERROR,\\n FailureInfo\\n .ACCRUE_INTEREST_NEW_TOTAL_BORROWS_CALCULATION_FAILED,\\n uint256(mathErr)\\n );\\n }\\n\\n (mathErr, totalReservesNew) = mulScalarTruncateAddUInt(\\n Exp({mantissa: reserveFactorMantissa}),\\n interestAccumulated,\\n reservesPrior\\n );\\n if (mathErr != MathError.NO_ERROR) {\\n return\\n failOpaque(\\n Error.MATH_ERROR,\\n FailureInfo\\n .ACCRUE_INTEREST_NEW_TOTAL_RESERVES_CALCULATION_FAILED,\\n uint256(mathErr)\\n );\\n }\\n\\n if (interestRateModel.isTropykusInterestRateModel()) {\\n (mathErr, totalReservesNew) = newReserves(\\n borrowRateMantissa,\\n cashPrior,\\n borrowsPrior,\\n reservesPrior,\\n interestAccumulated\\n );\\n if (mathErr != MathError.NO_ERROR) {\\n return\\n failOpaque(\\n Error.MATH_ERROR,\\n FailureInfo\\n .ACCRUE_INTEREST_NEW_TOTAL_RESERVES_CALCULATION_FAILED,\\n uint256(mathErr)\\n );\\n }\\n }\\n\\n (mathErr, borrowIndexNew) = mulScalarTruncateAddUInt(\\n simpleInterestFactor,\\n borrowIndexPrior,\\n borrowIndexPrior\\n );\\n if (mathErr != MathError.NO_ERROR) {\\n return\\n failOpaque(\\n Error.MATH_ERROR,\\n FailureInfo\\n .ACCRUE_INTEREST_NEW_BORROW_INDEX_CALCULATION_FAILED,\\n uint256(mathErr)\\n );\\n }\\n\\n accrualBlockNumber = currentBlockNumber;\\n borrowIndex = borrowIndexNew;\\n totalBorrows = totalBorrowsNew;\\n totalReserves = totalReservesNew;\\n\\n emit AccrueInterest(\\n cashPrior,\\n interestAccumulated,\\n borrowIndexNew,\\n totalBorrowsNew\\n );\\n\\n return uint256(Error.NO_ERROR);\\n }\\n\\n function newReserves(\\n uint256 borrowRateMantissa,\\n uint256 cashPrior,\\n uint256 borrowsPrior,\\n uint256 reservesPrior,\\n uint256 interestAccumulated\\n ) internal view returns (MathError mathErr, uint256 totalReservesNew) {\\n uint256 newReserveFactorMantissa;\\n uint256 utilizationRate = interestRateModel.utilizationRate(\\n cashPrior,\\n borrowsPrior,\\n reservesPrior\\n );\\n uint256 expectedSupplyRate = interestRateModel.getSupplyRate(\\n cashPrior,\\n borrowsPrior,\\n reservesPrior,\\n reserveFactorMantissa\\n );\\n if (\\n interestRateModel.isAboveOptimal(\\n cashPrior,\\n borrowsPrior,\\n reservesPrior\\n )\\n ) {\\n (mathErr, newReserveFactorMantissa) = mulScalarTruncate(\\n Exp({mantissa: utilizationRate}),\\n borrowRateMantissa\\n );\\n if (mathErr != MathError.NO_ERROR) {\\n return (mathErr, 0);\\n }\\n (mathErr, newReserveFactorMantissa) = subUInt(\\n newReserveFactorMantissa,\\n expectedSupplyRate\\n );\\n if (mathErr != MathError.NO_ERROR) {\\n return (mathErr, 0);\\n }\\n (mathErr, totalReservesNew) = mulScalarTruncateAddUInt(\\n Exp({mantissa: newReserveFactorMantissa}),\\n interestAccumulated,\\n reservesPrior\\n );\\n if (mathErr != MathError.NO_ERROR) {\\n return (mathErr, 0);\\n }\\n } else {\\n mathErr = MathError.NO_ERROR;\\n totalReservesNew = reservesPrior;\\n }\\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(uint256 mintAmount)\\n internal\\n nonReentrant\\n returns (uint256, uint256)\\n {\\n if (WhitelistInterface(whitelist).enabled()) {\\n require(WhitelistInterface(whitelist).exist(msg.sender), \\\"CT26\\\");\\n }\\n uint256 error = accrueInterest();\\n if (error != uint256(Error.NO_ERROR)) {\\n return (\\n fail(Error(error), FailureInfo.MINT_ACCRUE_INTEREST_FAILED),\\n 0\\n );\\n }\\n return mintFresh(msg.sender, mintAmount);\\n }\\n\\n struct MintLocalVars {\\n Error err;\\n MathError mathErr;\\n uint256 exchangeRateMantissa;\\n uint256 mintTokens;\\n uint256 totalSupplyNew;\\n uint256 accountTokensNew;\\n uint256 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, uint256 mintAmount)\\n internal\\n returns (uint256, uint256)\\n {\\n uint256 allowed = comptroller.mintAllowed(\\n address(this),\\n minter,\\n mintAmount\\n );\\n if (allowed != 0) {\\n return (\\n failOpaque(\\n Error.COMPTROLLER_REJECTION,\\n FailureInfo.MINT_COMPTROLLER_REJECTION,\\n allowed\\n ),\\n 0\\n );\\n }\\n\\n if (accrualBlockNumber != getBlockNumber()) {\\n return (\\n fail(Error.MARKET_NOT_FRESH, FailureInfo.MINT_FRESHNESS_CHECK),\\n 0\\n );\\n }\\n\\n MintLocalVars memory vars;\\n\\n (\\n vars.mathErr,\\n vars.exchangeRateMantissa\\n ) = exchangeRateStoredInternal();\\n if (vars.mathErr != MathError.NO_ERROR) {\\n return (\\n failOpaque(\\n Error.MATH_ERROR,\\n FailureInfo.MINT_EXCHANGE_RATE_READ_FAILED,\\n uint256(vars.mathErr)\\n ),\\n 0\\n );\\n }\\n if (interestRateModel.isTropykusInterestRateModel()) {\\n SupplySnapshot storage supplySnapshot = accountTokens[minter];\\n (, uint256 newTotalSupply) = addUInt(\\n supplySnapshot.underlyingAmount,\\n mintAmount\\n );\\n require(newTotalSupply <= 0.1e18, \\\"CT24\\\");\\n }\\n vars.actualMintAmount = doTransferIn(minter, mintAmount);\\n\\n (vars.mathErr, vars.mintTokens) = divScalarByExpTruncate(\\n vars.actualMintAmount,\\n Exp({mantissa: vars.exchangeRateMantissa})\\n );\\n require(vars.mathErr == MathError.NO_ERROR, \\\"CT12\\\");\\n\\n (vars.mathErr, vars.totalSupplyNew) = addUInt(\\n totalSupply,\\n vars.mintTokens\\n );\\n require(vars.mathErr == MathError.NO_ERROR, \\\"CT13\\\");\\n\\n (vars.mathErr, vars.accountTokensNew) = addUInt(\\n accountTokens[minter].tokens,\\n vars.mintTokens\\n );\\n require(vars.mathErr == MathError.NO_ERROR, \\\"CT14\\\");\\n\\n uint256 currentSupplyRate = interestRateModel.getSupplyRate(\\n getCashPrior(),\\n totalBorrows,\\n totalReserves,\\n reserveFactorMantissa\\n );\\n\\n bool isTropykusInterestRateModel = interestRateModel\\n .isTropykusInterestRateModel();\\n\\n if (accountTokens[minter].tokens > 0) {\\n Exp memory updatedUnderlying;\\n if (isTropykusInterestRateModel) {\\n (, uint256 interestFactorMantissa, ) = tropykusInterestAccrued(\\n minter\\n );\\n Exp memory interestFactor = Exp({\\n mantissa: interestFactorMantissa\\n });\\n uint256 currentUnderlyingAmount = accountTokens[minter]\\n .underlyingAmount;\\n MathError mErrorNewAmount;\\n (mErrorNewAmount, updatedUnderlying) = mulExp(\\n Exp({mantissa: currentUnderlyingAmount}),\\n interestFactor\\n );\\n if (mErrorNewAmount != MathError.NO_ERROR) {\\n return (\\n failOpaque(\\n Error.MATH_ERROR,\\n FailureInfo.MINT_EXCHANGE_CALCULATION_FAILED,\\n uint256(mErrorNewAmount)\\n ),\\n 0\\n );\\n }\\n } else {\\n uint256 currentTokens = accountTokens[minter].tokens;\\n MathError mErrorUpdatedUnderlying;\\n (mErrorUpdatedUnderlying, updatedUnderlying) = mulExp(\\n Exp({mantissa: currentTokens}),\\n Exp({mantissa: vars.exchangeRateMantissa})\\n );\\n if (mErrorUpdatedUnderlying != MathError.NO_ERROR) {\\n return (\\n failOpaque(\\n Error.MATH_ERROR,\\n FailureInfo.MINT_EXCHANGE_CALCULATION_FAILED,\\n uint256(mErrorUpdatedUnderlying)\\n ),\\n 0\\n );\\n }\\n }\\n (, mintAmount) = addUInt(updatedUnderlying.mantissa, mintAmount);\\n }\\n\\n totalSupply = vars.totalSupplyNew;\\n accountTokens[minter] = SupplySnapshot({\\n tokens: vars.accountTokensNew,\\n underlyingAmount: mintAmount,\\n suppliedAt: accrualBlockNumber,\\n promisedSupplyRate: currentSupplyRate\\n });\\n\\n emit Mint(minter, vars.actualMintAmount, vars.mintTokens);\\n emit Transfer(address(this), minter, vars.mintTokens);\\n\\n return (uint256(Error.NO_ERROR), vars.actualMintAmount);\\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(uint256 redeemAmount)\\n internal\\n nonReentrant\\n returns (uint256)\\n {\\n uint256 error = accrueInterest();\\n if (error != uint256(Error.NO_ERROR)) {\\n return\\n fail(Error(error), FailureInfo.REDEEM_ACCRUE_INTEREST_FAILED);\\n }\\n return redeemFresh(payable(msg.sender), redeemAmount);\\n }\\n\\n struct RedeemLocalVars {\\n Error err;\\n MathError mathErr;\\n uint256 exchangeRateMantissa;\\n uint256 redeemTokens;\\n uint256 redeemAmount;\\n uint256 totalSupplyNew;\\n uint256 accountTokensNew;\\n uint256 newSubsidyFund;\\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 redeemAmountIn The number of underlying tokens to receive from redeeming cTokens\\n * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)\\n */\\n function redeemFresh(address payable redeemer, uint256 redeemAmountIn)\\n internal\\n returns (uint256)\\n {\\n require(redeemAmountIn > 0, \\\"CT15\\\");\\n\\n RedeemLocalVars memory vars;\\n\\n SupplySnapshot storage supplySnapshot = accountTokens[redeemer];\\n\\n (\\n vars.mathErr,\\n vars.exchangeRateMantissa\\n ) = exchangeRateStoredInternal();\\n if (vars.mathErr != MathError.NO_ERROR) {\\n return\\n failOpaque(\\n Error.MATH_ERROR,\\n FailureInfo.REDEEM_EXCHANGE_RATE_READ_FAILED,\\n uint256(vars.mathErr)\\n );\\n }\\n\\n uint256 interestEarned;\\n uint256 subsidyFundPortion;\\n uint256 currentUnderlying;\\n\\n bool isTropykusInterestRateModel = interestRateModel\\n .isTropykusInterestRateModel();\\n if (isTropykusInterestRateModel) {\\n currentUnderlying = supplySnapshot.underlyingAmount;\\n (, , interestEarned) = tropykusInterestAccrued(redeemer);\\n }\\n supplySnapshot.promisedSupplyRate = interestRateModel.getSupplyRate(\\n getCashPrior(),\\n totalBorrows,\\n totalReserves,\\n reserveFactorMantissa\\n );\\n\\n if (\\n isTropykusInterestRateModel &&\\n !interestRateModel.isAboveOptimal(\\n getCashPrior(),\\n totalBorrows,\\n totalReserves\\n )\\n ) {\\n uint256 borrowRate = interestRateModel.getBorrowRate(\\n getCashPrior(),\\n totalBorrows,\\n totalReserves\\n );\\n\\n uint256 utilizationRate = interestRateModel.utilizationRate(\\n getCashPrior(),\\n totalBorrows,\\n totalReserves\\n );\\n\\n (, uint256 estimatedEarning) = mulScalarTruncate(\\n Exp({mantissa: borrowRate}),\\n utilizationRate\\n );\\n\\n (, subsidyFundPortion) = subUInt(\\n supplySnapshot.promisedSupplyRate,\\n estimatedEarning\\n );\\n (, Exp memory subsidyFactor) = getExp(\\n subsidyFundPortion,\\n supplySnapshot.promisedSupplyRate\\n );\\n (, subsidyFundPortion) = mulScalarTruncate(\\n subsidyFactor,\\n interestEarned\\n );\\n }\\n\\n vars.redeemAmount = redeemAmountIn;\\n\\n if (isTropykusInterestRateModel) {\\n (, Exp memory num) = mulExp(\\n vars.redeemAmount,\\n supplySnapshot.tokens\\n );\\n (, Exp memory realTokensWithdrawAmount) = getExp(\\n num.mantissa,\\n currentUnderlying\\n );\\n vars.redeemTokens = realTokensWithdrawAmount.mantissa;\\n } else {\\n (vars.mathErr, vars.redeemTokens) = divScalarByExpTruncate(\\n redeemAmountIn,\\n Exp({mantissa: vars.exchangeRateMantissa})\\n );\\n if (vars.mathErr != MathError.NO_ERROR) {\\n return\\n failOpaque(\\n Error.MATH_ERROR,\\n FailureInfo.REDEEM_EXCHANGE_AMOUNT_CALCULATION_FAILED,\\n uint256(vars.mathErr)\\n );\\n }\\n }\\n // }\\n\\n uint256 allowed = comptroller.redeemAllowed(\\n address(this),\\n redeemer,\\n vars.redeemTokens\\n );\\n if (allowed != 0) {\\n return\\n failOpaque(\\n Error.COMPTROLLER_REJECTION,\\n FailureInfo.REDEEM_COMPTROLLER_REJECTION,\\n allowed\\n );\\n }\\n\\n if (accrualBlockNumber != getBlockNumber()) {\\n return\\n fail(\\n Error.MARKET_NOT_FRESH,\\n FailureInfo.REDEEM_FRESHNESS_CHECK\\n );\\n }\\n\\n (vars.mathErr, vars.totalSupplyNew) = subUInt(\\n totalSupply,\\n vars.redeemTokens\\n );\\n if (vars.mathErr != MathError.NO_ERROR) {\\n return\\n failOpaque(\\n Error.MATH_ERROR,\\n FailureInfo.REDEEM_NEW_TOTAL_SUPPLY_CALCULATION_FAILED,\\n uint256(vars.mathErr)\\n );\\n }\\n\\n (, vars.newSubsidyFund) = subUInt(subsidyFund, subsidyFundPortion);\\n\\n (vars.mathErr, vars.accountTokensNew) = subUInt(\\n supplySnapshot.tokens,\\n vars.redeemTokens\\n );\\n if (vars.mathErr != MathError.NO_ERROR) {\\n return\\n failOpaque(\\n Error.MATH_ERROR,\\n FailureInfo.REDEEM_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED,\\n uint256(vars.mathErr)\\n );\\n }\\n\\n uint256 cash = getCashPrior();\\n if (isTropykusInterestRateModel) {\\n cash = address(this).balance;\\n }\\n\\n if (cash < vars.redeemAmount) {\\n return\\n fail(\\n Error.TOKEN_INSUFFICIENT_CASH,\\n FailureInfo.REDEEM_TRANSFER_OUT_NOT_POSSIBLE\\n );\\n }\\n\\n doTransferOut(redeemer, vars.redeemAmount);\\n\\n totalSupply = vars.totalSupplyNew;\\n subsidyFund = vars.newSubsidyFund;\\n supplySnapshot.tokens = vars.accountTokensNew;\\n supplySnapshot.suppliedAt = accrualBlockNumber;\\n (, supplySnapshot.underlyingAmount) = subUInt(\\n supplySnapshot.underlyingAmount,\\n vars.redeemAmount\\n );\\n\\n emit Transfer(redeemer, address(this), vars.redeemTokens);\\n emit Redeem(redeemer, vars.redeemAmount, vars.redeemTokens);\\n\\n comptroller.redeemVerify(\\n address(this),\\n redeemer,\\n vars.redeemAmount,\\n vars.redeemTokens\\n );\\n\\n return uint256(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(uint256 borrowAmount)\\n internal\\n nonReentrant\\n returns (uint256)\\n {\\n uint256 error = accrueInterest();\\n if (error != uint256(Error.NO_ERROR)) {\\n return\\n fail(Error(error), FailureInfo.BORROW_ACCRUE_INTEREST_FAILED);\\n }\\n return borrowFresh(payable(msg.sender), borrowAmount);\\n }\\n\\n struct BorrowLocalVars {\\n MathError mathErr;\\n uint256 accountBorrows;\\n uint256 accountBorrowsNew;\\n uint256 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, uint256 borrowAmount)\\n internal\\n returns (uint256)\\n {\\n uint256 allowed = comptroller.borrowAllowed(\\n address(this),\\n borrower,\\n borrowAmount\\n );\\n if (allowed != 0) {\\n return\\n failOpaque(\\n Error.COMPTROLLER_REJECTION,\\n FailureInfo.BORROW_COMPTROLLER_REJECTION,\\n allowed\\n );\\n }\\n\\n if (accrualBlockNumber != getBlockNumber()) {\\n return\\n fail(\\n Error.MARKET_NOT_FRESH,\\n FailureInfo.BORROW_FRESHNESS_CHECK\\n );\\n }\\n\\n if (getCashPrior() < borrowAmount) {\\n return\\n fail(\\n Error.TOKEN_INSUFFICIENT_CASH,\\n FailureInfo.BORROW_CASH_NOT_AVAILABLE\\n );\\n }\\n\\n BorrowLocalVars memory vars;\\n\\n (vars.mathErr, vars.accountBorrows) = borrowBalanceStoredInternal(\\n borrower\\n );\\n if (vars.mathErr != MathError.NO_ERROR) {\\n return\\n failOpaque(\\n Error.MATH_ERROR,\\n FailureInfo.BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED,\\n uint256(vars.mathErr)\\n );\\n }\\n\\n (vars.mathErr, vars.accountBorrowsNew) = addUInt(\\n vars.accountBorrows,\\n borrowAmount\\n );\\n if (vars.mathErr != MathError.NO_ERROR) {\\n return\\n failOpaque(\\n Error.MATH_ERROR,\\n FailureInfo\\n .BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED,\\n uint256(vars.mathErr)\\n );\\n }\\n\\n (vars.mathErr, vars.totalBorrowsNew) = addUInt(\\n totalBorrows,\\n borrowAmount\\n );\\n if (interestRateModel.isTropykusInterestRateModel()) {\\n require(vars.totalBorrowsNew <= 0.1e18, \\\"CT25\\\");\\n }\\n if (vars.mathErr != MathError.NO_ERROR) {\\n return\\n failOpaque(\\n Error.MATH_ERROR,\\n FailureInfo.BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED,\\n uint256(vars.mathErr)\\n );\\n }\\n\\n doTransferOut(borrower, borrowAmount);\\n\\n accountBorrows[borrower].principal = vars.accountBorrowsNew;\\n accountBorrows[borrower].interestIndex = borrowIndex;\\n totalBorrows = vars.totalBorrowsNew;\\n\\n emit Borrow(\\n borrower,\\n borrowAmount,\\n vars.accountBorrowsNew,\\n vars.totalBorrowsNew\\n );\\n\\n return uint256(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(uint256 repayAmount)\\n internal\\n nonReentrant\\n returns (uint256, uint256)\\n {\\n uint256 error = accrueInterest();\\n if (error != uint256(Error.NO_ERROR)) {\\n return (\\n fail(\\n Error(error),\\n FailureInfo.REPAY_BORROW_ACCRUE_INTEREST_FAILED\\n ),\\n 0\\n );\\n }\\n return repayBorrowFresh(msg.sender, msg.sender, repayAmount);\\n }\\n\\n struct RepayBorrowLocalVars {\\n Error err;\\n MathError mathErr;\\n uint256 repayAmount;\\n uint256 borrowerIndex;\\n uint256 accountBorrows;\\n uint256 accountBorrowsNew;\\n uint256 totalBorrowsNew;\\n uint256 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(\\n address payer,\\n address borrower,\\n uint256 repayAmount\\n ) internal returns (uint256, uint256) {\\n uint256 allowed = comptroller.repayBorrowAllowed(\\n address(this),\\n payer,\\n borrower,\\n repayAmount\\n );\\n if (allowed != 0) {\\n return (\\n failOpaque(\\n Error.COMPTROLLER_REJECTION,\\n FailureInfo.REPAY_BORROW_COMPTROLLER_REJECTION,\\n allowed\\n ),\\n 0\\n );\\n }\\n\\n if (accrualBlockNumber != getBlockNumber()) {\\n return (\\n fail(\\n Error.MARKET_NOT_FRESH,\\n FailureInfo.REPAY_BORROW_FRESHNESS_CHECK\\n ),\\n 0\\n );\\n }\\n\\n RepayBorrowLocalVars memory vars;\\n\\n vars.borrowerIndex = accountBorrows[borrower].interestIndex;\\n\\n (vars.mathErr, vars.accountBorrows) = borrowBalanceStoredInternal(\\n borrower\\n );\\n if (vars.mathErr != MathError.NO_ERROR) {\\n return (\\n failOpaque(\\n Error.MATH_ERROR,\\n FailureInfo\\n .REPAY_BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED,\\n uint256(vars.mathErr)\\n ),\\n 0\\n );\\n }\\n\\n if (repayAmount == type(uint256).max) {\\n vars.repayAmount = vars.accountBorrows;\\n } else {\\n vars.repayAmount = repayAmount;\\n }\\n\\n vars.actualRepayAmount = doTransferIn(payer, vars.repayAmount);\\n\\n (vars.mathErr, vars.accountBorrowsNew) = subUInt(\\n vars.accountBorrows,\\n vars.actualRepayAmount\\n );\\n require(vars.mathErr == MathError.NO_ERROR, \\\"CT16\\\");\\n\\n (vars.mathErr, vars.totalBorrowsNew) = subUInt(\\n totalBorrows,\\n vars.actualRepayAmount\\n );\\n require(vars.mathErr == MathError.NO_ERROR, \\\"CT17\\\");\\n\\n accountBorrows[borrower].principal = vars.accountBorrowsNew;\\n accountBorrows[borrower].interestIndex = borrowIndex;\\n totalBorrows = vars.totalBorrowsNew;\\n\\n emit RepayBorrow(\\n payer,\\n borrower,\\n vars.actualRepayAmount,\\n vars.accountBorrowsNew,\\n vars.totalBorrowsNew\\n );\\n\\n return (uint256(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(\\n address borrower,\\n uint256 repayAmount,\\n CTokenInterface cTokenCollateral\\n ) internal nonReentrant returns (uint256, uint256) {\\n uint256 error = accrueInterest();\\n if (error != uint256(Error.NO_ERROR)) {\\n return (\\n fail(\\n Error(error),\\n FailureInfo.LIQUIDATE_ACCRUE_BORROW_INTEREST_FAILED\\n ),\\n 0\\n );\\n }\\n\\n error = cTokenCollateral.accrueInterest();\\n if (error != uint256(Error.NO_ERROR)) {\\n return (\\n fail(\\n Error(error),\\n FailureInfo.LIQUIDATE_ACCRUE_COLLATERAL_INTEREST_FAILED\\n ),\\n 0\\n );\\n }\\n\\n // liquidateBorrowFresh emits borrow-specific logs on errors, so we don't need to\\n return\\n liquidateBorrowFresh(\\n msg.sender,\\n borrower,\\n repayAmount,\\n cTokenCollateral\\n );\\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(\\n address liquidator,\\n address borrower,\\n uint256 repayAmount,\\n CTokenInterface cTokenCollateral\\n ) internal returns (uint256, uint256) {\\n uint256 allowed = comptroller.liquidateBorrowAllowed(\\n address(this),\\n address(cTokenCollateral),\\n liquidator,\\n borrower,\\n repayAmount\\n );\\n if (allowed != 0) {\\n return (\\n failOpaque(\\n Error.COMPTROLLER_REJECTION,\\n FailureInfo.LIQUIDATE_COMPTROLLER_REJECTION,\\n allowed\\n ),\\n 0\\n );\\n }\\n\\n if (accrualBlockNumber != getBlockNumber()) {\\n return (\\n fail(\\n Error.MARKET_NOT_FRESH,\\n FailureInfo.LIQUIDATE_FRESHNESS_CHECK\\n ),\\n 0\\n );\\n }\\n\\n if (cTokenCollateral.accrualBlockNumber() != getBlockNumber()) {\\n return (\\n fail(\\n Error.MARKET_NOT_FRESH,\\n FailureInfo.LIQUIDATE_COLLATERAL_FRESHNESS_CHECK\\n ),\\n 0\\n );\\n }\\n\\n if (borrower == liquidator) {\\n return (\\n fail(\\n Error.INVALID_ACCOUNT_PAIR,\\n FailureInfo.LIQUIDATE_LIQUIDATOR_IS_BORROWER\\n ),\\n 0\\n );\\n }\\n\\n if (repayAmount == 0) {\\n return (\\n fail(\\n Error.INVALID_CLOSE_AMOUNT_REQUESTED,\\n FailureInfo.LIQUIDATE_CLOSE_AMOUNT_IS_ZERO\\n ),\\n 0\\n );\\n }\\n\\n if (repayAmount == type(uint256).max) {\\n return (\\n fail(\\n Error.INVALID_CLOSE_AMOUNT_REQUESTED,\\n FailureInfo.LIQUIDATE_CLOSE_AMOUNT_IS_UINT_MAX\\n ),\\n 0\\n );\\n }\\n\\n (\\n uint256 repayBorrowError,\\n uint256 actualRepayAmount\\n ) = repayBorrowFresh(liquidator, borrower, repayAmount);\\n if (repayBorrowError != uint256(Error.NO_ERROR)) {\\n return (\\n fail(\\n Error(repayBorrowError),\\n FailureInfo.LIQUIDATE_REPAY_BORROW_FRESH_FAILED\\n ),\\n 0\\n );\\n }\\n\\n (uint256 amountSeizeError, uint256 seizeTokens) = comptroller\\n .liquidateCalculateSeizeTokens(\\n address(this),\\n address(cTokenCollateral),\\n actualRepayAmount\\n );\\n require(amountSeizeError == uint256(Error.NO_ERROR), \\\"CT18\\\");\\n\\n require(cTokenCollateral.balanceOf(borrower) >= seizeTokens, \\\"CT19\\\");\\n\\n uint256 seizeError;\\n if (address(cTokenCollateral) == address(this)) {\\n seizeError = seizeInternal(\\n address(this),\\n liquidator,\\n borrower,\\n seizeTokens\\n );\\n } else {\\n seizeError = cTokenCollateral.seize(\\n liquidator,\\n borrower,\\n seizeTokens\\n );\\n }\\n\\n require(seizeError == uint256(Error.NO_ERROR), \\\"CT20\\\");\\n\\n emit LiquidateBorrow(\\n liquidator,\\n borrower,\\n actualRepayAmount,\\n address(cTokenCollateral),\\n seizeTokens\\n );\\n\\n return (uint256(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(\\n address liquidator,\\n address borrower,\\n uint256 seizeTokens\\n ) external override nonReentrant returns (uint256) {\\n return seizeInternal(msg.sender, liquidator, borrower, seizeTokens);\\n }\\n\\n struct SeizeVars {\\n uint256 seizeAmount;\\n uint256 exchangeRate;\\n uint256 borrowerTokensNew;\\n uint256 borrowerAmountNew;\\n uint256 liquidatorTokensNew;\\n uint256 liquidatorAmountNew;\\n uint256 totalCash;\\n uint256 supplyRate;\\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(\\n address seizerToken,\\n address liquidator,\\n address borrower,\\n uint256 seizeTokens\\n ) internal returns (uint256) {\\n uint256 allowed = comptroller.seizeAllowed(\\n address(this),\\n seizerToken,\\n liquidator,\\n borrower,\\n seizeTokens\\n );\\n if (allowed != 0) {\\n return\\n failOpaque(\\n Error.COMPTROLLER_REJECTION,\\n FailureInfo.LIQUIDATE_SEIZE_COMPTROLLER_REJECTION,\\n allowed\\n );\\n }\\n\\n if (borrower == liquidator) {\\n return\\n fail(\\n Error.INVALID_ACCOUNT_PAIR,\\n FailureInfo.LIQUIDATE_SEIZE_LIQUIDATOR_IS_BORROWER\\n );\\n }\\n\\n SeizeVars memory seizeVars;\\n\\n MathError mathErr;\\n\\n (mathErr, seizeVars.borrowerTokensNew) = subUInt(\\n accountTokens[borrower].tokens,\\n seizeTokens\\n );\\n if (mathErr != MathError.NO_ERROR) {\\n return\\n failOpaque(\\n Error.MATH_ERROR,\\n FailureInfo.LIQUIDATE_SEIZE_BALANCE_DECREMENT_FAILED,\\n uint256(mathErr)\\n );\\n }\\n\\n seizeVars.totalCash = getCashPrior();\\n seizeVars.supplyRate = interestRateModel.getSupplyRate(\\n seizeVars.totalCash,\\n totalBorrows,\\n totalReserves,\\n reserveFactorMantissa\\n );\\n\\n (, seizeVars.exchangeRate) = interestRateModel.getExchangeRate(\\n seizeVars.totalCash,\\n totalBorrows,\\n totalReserves,\\n totalSupply\\n );\\n\\n if (interestRateModel.isTropykusInterestRateModel()) {\\n (, seizeVars.exchangeRate) = tropykusExchangeRateStoredInternal(\\n borrower\\n );\\n }\\n\\n (, seizeVars.seizeAmount) = mulUInt(\\n seizeTokens,\\n seizeVars.exchangeRate\\n );\\n (, seizeVars.seizeAmount) = divUInt(seizeVars.seizeAmount, 1e18);\\n\\n (, seizeVars.borrowerAmountNew) = subUInt(\\n accountTokens[borrower].underlyingAmount,\\n seizeVars.seizeAmount\\n );\\n\\n (mathErr, seizeVars.liquidatorTokensNew) = addUInt(\\n accountTokens[liquidator].tokens,\\n seizeTokens\\n );\\n if (mathErr != MathError.NO_ERROR) {\\n return\\n failOpaque(\\n Error.MATH_ERROR,\\n FailureInfo.LIQUIDATE_SEIZE_BALANCE_INCREMENT_FAILED,\\n uint256(mathErr)\\n );\\n }\\n\\n (, seizeVars.liquidatorAmountNew) = addUInt(\\n accountTokens[liquidator].underlyingAmount,\\n seizeVars.seizeAmount\\n );\\n\\n accountTokens[borrower].tokens = seizeVars.borrowerTokensNew;\\n accountTokens[borrower].underlyingAmount = seizeVars.borrowerAmountNew;\\n accountTokens[borrower].suppliedAt = getBlockNumber();\\n accountTokens[borrower].promisedSupplyRate = seizeVars.supplyRate;\\n\\n accountTokens[liquidator].tokens = seizeVars.liquidatorTokensNew;\\n accountTokens[liquidator].underlyingAmount = seizeVars\\n .liquidatorAmountNew;\\n accountTokens[liquidator].suppliedAt = getBlockNumber();\\n accountTokens[liquidator].promisedSupplyRate = seizeVars.supplyRate;\\n\\n emit Transfer(borrower, liquidator, seizeTokens);\\n\\n return uint256(Error.NO_ERROR);\\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 payable newPendingAdmin)\\n external\\n override\\n returns (uint256)\\n {\\n if (msg.sender != admin) {\\n return\\n fail(\\n Error.UNAUTHORIZED,\\n FailureInfo.SET_PENDING_ADMIN_OWNER_CHECK\\n );\\n }\\n\\n address oldPendingAdmin = pendingAdmin;\\n\\n pendingAdmin = newPendingAdmin;\\n\\n emit NewPendingAdmin(oldPendingAdmin, newPendingAdmin);\\n\\n return uint256(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 override returns (uint256) {\\n if (msg.sender != pendingAdmin || msg.sender == address(0)) {\\n return\\n fail(\\n Error.UNAUTHORIZED,\\n FailureInfo.ACCEPT_ADMIN_PENDING_ADMIN_CHECK\\n );\\n }\\n\\n address oldAdmin = admin;\\n address oldPendingAdmin = pendingAdmin;\\n\\n admin = pendingAdmin;\\n\\n pendingAdmin = payable(address(0));\\n\\n emit NewAdmin(oldAdmin, admin);\\n emit NewPendingAdmin(oldPendingAdmin, pendingAdmin);\\n\\n return uint256(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)\\n public\\n override\\n returns (uint256)\\n {\\n if (msg.sender != admin) {\\n return\\n fail(\\n Error.UNAUTHORIZED,\\n FailureInfo.SET_COMPTROLLER_OWNER_CHECK\\n );\\n }\\n\\n ComptrollerInterface oldComptroller = comptroller;\\n require(newComptroller.isComptroller(), \\\"CT21\\\");\\n\\n comptroller = newComptroller;\\n\\n emit NewComptroller(oldComptroller, newComptroller);\\n\\n return uint256(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(uint256 newReserveFactorMantissa)\\n external\\n override\\n nonReentrant\\n returns (uint256)\\n {\\n uint256 error = accrueInterest();\\n if (error != uint256(Error.NO_ERROR)) {\\n return\\n fail(\\n Error(error),\\n FailureInfo.SET_RESERVE_FACTOR_ACCRUE_INTEREST_FAILED\\n );\\n }\\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(uint256 newReserveFactorMantissa)\\n internal\\n returns (uint256)\\n {\\n if (msg.sender != admin) {\\n return\\n fail(\\n Error.UNAUTHORIZED,\\n FailureInfo.SET_RESERVE_FACTOR_ADMIN_CHECK\\n );\\n }\\n\\n if (accrualBlockNumber != getBlockNumber()) {\\n return\\n fail(\\n Error.MARKET_NOT_FRESH,\\n FailureInfo.SET_RESERVE_FACTOR_FRESH_CHECK\\n );\\n }\\n\\n if (newReserveFactorMantissa > reserveFactorMaxMantissa) {\\n return\\n fail(\\n Error.BAD_INPUT,\\n FailureInfo.SET_RESERVE_FACTOR_BOUNDS_CHECK\\n );\\n }\\n\\n uint256 oldReserveFactorMantissa = reserveFactorMantissa;\\n reserveFactorMantissa = newReserveFactorMantissa;\\n\\n emit NewReserveFactor(\\n oldReserveFactorMantissa,\\n newReserveFactorMantissa\\n );\\n\\n return uint256(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(uint256 addAmount)\\n internal\\n nonReentrant\\n returns (uint256)\\n {\\n uint256 error = accrueInterest();\\n if (error != uint256(Error.NO_ERROR)) {\\n return\\n fail(\\n Error(error),\\n FailureInfo.ADD_RESERVES_ACCRUE_INTEREST_FAILED\\n );\\n }\\n\\n uint256 totalReservesNew;\\n uint256 actualAddAmount;\\n\\n if (accrualBlockNumber != getBlockNumber()) {\\n return (\\n fail(\\n Error.MARKET_NOT_FRESH,\\n FailureInfo.ADD_RESERVES_FRESH_CHECK\\n )\\n );\\n }\\n\\n actualAddAmount = doTransferIn(msg.sender, addAmount);\\n\\n totalReservesNew = totalReserves + actualAddAmount;\\n\\n require(totalReservesNew >= totalReserves, \\\"CT22\\\");\\n\\n totalReserves = totalReservesNew;\\n\\n emit ReservesAdded(msg.sender, actualAddAmount, totalReservesNew);\\n\\n return (uint256(Error.NO_ERROR));\\n }\\n\\n function _addSubsidyInternal(uint256 addAmount)\\n internal\\n nonReentrant\\n returns (uint256)\\n {\\n uint256 error = accrueInterest();\\n if (error != uint256(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_SUBSIDY_FUND_FAILED);\\n }\\n\\n uint256 subsidyFundNew;\\n uint256 actualAddAmount;\\n\\n if (accrualBlockNumber != getBlockNumber()) {\\n return (\\n fail(\\n Error.MARKET_NOT_FRESH,\\n FailureInfo.ADD_SUBSIDY_FUND_FRESH_CHECK\\n )\\n );\\n }\\n\\n actualAddAmount = doTransferIn(msg.sender, addAmount);\\n\\n subsidyFundNew = subsidyFund + actualAddAmount;\\n\\n require(subsidyFundNew >= subsidyFund, \\\"CT22\\\");\\n\\n subsidyFund = subsidyFundNew;\\n\\n emit SubsidyAdded(msg.sender, actualAddAmount, subsidyFundNew);\\n\\n /* Return (NO_ERROR, actualAddAmount) */\\n return (uint256(Error.NO_ERROR));\\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(uint256 reduceAmount)\\n external\\n override\\n nonReentrant\\n returns (uint256)\\n {\\n uint256 error = accrueInterest();\\n if (error != uint256(Error.NO_ERROR)) {\\n return\\n fail(\\n Error(error),\\n FailureInfo.REDUCE_RESERVES_ACCRUE_INTEREST_FAILED\\n );\\n }\\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(uint256 reduceAmount)\\n internal\\n returns (uint256)\\n {\\n uint256 totalReservesNew;\\n\\n if (msg.sender != admin) {\\n return\\n fail(\\n Error.UNAUTHORIZED,\\n FailureInfo.REDUCE_RESERVES_ADMIN_CHECK\\n );\\n }\\n\\n if (accrualBlockNumber != getBlockNumber()) {\\n return\\n fail(\\n Error.MARKET_NOT_FRESH,\\n FailureInfo.REDUCE_RESERVES_FRESH_CHECK\\n );\\n }\\n\\n if (getCashPrior() < reduceAmount) {\\n return\\n fail(\\n Error.TOKEN_INSUFFICIENT_CASH,\\n FailureInfo.REDUCE_RESERVES_CASH_NOT_AVAILABLE\\n );\\n }\\n\\n if (reduceAmount > totalReserves) {\\n return\\n fail(Error.BAD_INPUT, FailureInfo.REDUCE_RESERVES_VALIDATION);\\n }\\n\\n totalReservesNew = totalReserves - reduceAmount;\\n require(totalReservesNew <= totalReserves, \\\"CT23\\\");\\n\\n totalReserves = totalReservesNew;\\n\\n doTransferOut(admin, reduceAmount);\\n\\n emit ReservesReduced(admin, reduceAmount, totalReservesNew);\\n\\n return uint256(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)\\n public\\n override\\n returns (uint256)\\n {\\n uint256 error = accrueInterest();\\n if (error != uint256(Error.NO_ERROR)) {\\n return\\n fail(\\n Error(error),\\n FailureInfo.SET_INTEREST_RATE_MODEL_ACCRUE_INTEREST_FAILED\\n );\\n }\\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)\\n internal\\n returns (uint256)\\n {\\n InterestRateModel oldInterestRateModel;\\n\\n if (msg.sender != admin) {\\n return\\n fail(\\n Error.UNAUTHORIZED,\\n FailureInfo.SET_INTEREST_RATE_MODEL_OWNER_CHECK\\n );\\n }\\n\\n if (accrualBlockNumber != getBlockNumber()) {\\n return\\n fail(\\n Error.MARKET_NOT_FRESH,\\n FailureInfo.SET_INTEREST_RATE_MODEL_FRESH_CHECK\\n );\\n }\\n\\n oldInterestRateModel = interestRateModel;\\n\\n require(newInterestRateModel.isInterestRateModel(), \\\"CT21\\\");\\n\\n interestRateModel = newInterestRateModel;\\n\\n emit NewMarketInterestRateModel(\\n oldInterestRateModel,\\n newInterestRateModel\\n );\\n\\n return uint256(Error.NO_ERROR);\\n }\\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 virtual returns (uint256);\\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, uint256 amount)\\n internal\\n virtual\\n returns (uint256);\\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, uint256 amount) internal virtual;\\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;\\n }\\n}\\n\",\"keccak256\":\"0x66c781aa1ccc507ce80a431b9ee06801bb81b954bd0697a1f656de400b5cb381\",\"license\":\"UNLICENSED\"},\"contracts/CTokenInterfaces.sol\":{\"content\":\"// SPDX-License-Identifier: UNLICENSED\\npragma solidity 0.8.6;\\n\\nimport \\\"./ComptrollerInterface.sol\\\";\\nimport \\\"./InterestRateModel.sol\\\";\\nimport \\\"./EIP20NonStandardInterface.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 uint256 internal constant borrowRateMaxMantissa = 0.0005e16;\\n\\n /**\\n * @notice Maximum fraction of interest that can be set aside for reserves\\n */\\n uint256 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 uint256 public initialExchangeRateMantissa;\\n\\n /**\\n * @notice Fraction of interest currently set aside for reserves\\n */\\n uint256 public reserveFactorMantissa;\\n\\n /**\\n * @notice Block number that interest was last accrued at\\n */\\n uint256 public accrualBlockNumber;\\n\\n /**\\n * @notice Accumulator of the total earned interest rate since the opening of the market\\n */\\n uint256 public borrowIndex;\\n\\n /**\\n * @notice Total amount of outstanding borrows of the underlying in this market\\n */\\n uint256 public totalBorrows;\\n\\n /**\\n * @notice Total amount of reserves of the underlying held in this market\\n */\\n uint256 public totalReserves;\\n\\n /**\\n * @notice Total number of tokens in circulation\\n */\\n uint256 public totalSupply;\\n\\n uint256 public subsidyFund;\\n\\n struct SupplySnapshot {\\n uint256 tokens;\\n uint256 underlyingAmount;\\n uint256 suppliedAt;\\n uint256 promisedSupplyRate;\\n }\\n\\n /**\\n * @notice Official record of token balances for each account\\n */\\n mapping(address => SupplySnapshot) internal accountTokens;\\n\\n /**\\n * @notice Approved token transfer amounts on behalf of others\\n */\\n mapping(address => mapping(address => uint256)) 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 uint256 principal;\\n uint256 interestIndex;\\n }\\n\\n /**\\n * @notice Mapping of account addresses to outstanding borrow balances\\n */\\n mapping(address => BorrowSnapshot) internal accountBorrows;\\n}\\n\\nabstract contract CTokenInterface is CTokenStorage {\\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 interest is accrued\\n */\\n event AccrueInterest(\\n uint256 cashPrior,\\n uint256 interestAccumulated,\\n uint256 borrowIndex,\\n uint256 totalBorrows\\n );\\n\\n /**\\n * @notice Event emitted when tokens are minted\\n */\\n event Mint(address indexed minter, uint256 mintAmount, uint256 mintTokens);\\n\\n /**\\n * @notice Event emitted when tokens are redeemed\\n */\\n event Redeem(\\n address indexed redeemer,\\n uint256 redeemAmount,\\n uint256 redeemTokens\\n );\\n\\n /**\\n * @notice Event emitted when underlying is borrowed\\n */\\n event Borrow(\\n address indexed borrower,\\n uint256 borrowAmount,\\n uint256 accountBorrows,\\n uint256 totalBorrows\\n );\\n\\n /**\\n * @notice Event emitted when a borrow is repaid\\n */\\n event RepayBorrow(\\n address indexed payer,\\n address indexed borrower,\\n uint256 repayAmount,\\n uint256 accountBorrows,\\n uint256 totalBorrows\\n );\\n\\n /**\\n * @notice Event emitted when a borrow is liquidated\\n */\\n event LiquidateBorrow(\\n address indexed liquidator,\\n address indexed borrower,\\n uint256 repayAmount,\\n address indexed cTokenCollateral,\\n uint256 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(\\n ComptrollerInterface oldComptroller,\\n ComptrollerInterface newComptroller\\n );\\n\\n /**\\n * @notice Event emitted when interestRateModel is changed\\n */\\n event NewMarketInterestRateModel(\\n InterestRateModel oldInterestRateModel,\\n InterestRateModel newInterestRateModel\\n );\\n\\n /**\\n * @notice Event emitted when the reserve factor is changed\\n */\\n event NewReserveFactor(\\n uint256 oldReserveFactorMantissa,\\n uint256 newReserveFactorMantissa\\n );\\n\\n /**\\n * @notice Event emitted when the reserves are added\\n */\\n event ReservesAdded(\\n address benefactor,\\n uint256 addAmount,\\n uint256 newTotalReserves\\n );\\n\\n event SubsidyAdded(\\n address benefactor,\\n uint256 addAmount,\\n uint256 newSubsidyFund\\n );\\n\\n /**\\n * @notice Event emitted when the reserves are reduced\\n */\\n event ReservesReduced(\\n address admin,\\n uint256 reduceAmount,\\n uint256 newTotalReserves\\n );\\n\\n /**\\n * @notice EIP20 Transfer event\\n */\\n event Transfer(address indexed from, address indexed to, uint256 amount);\\n\\n /**\\n * @notice EIP20 Approval event\\n */\\n event Approval(\\n address indexed owner,\\n address indexed spender,\\n uint256 amount\\n );\\n\\n /**\\n * @notice Failure event\\n */\\n event CTokenStorageFailure(uint256 error, uint256 info, uint256 detail);\\n\\n /*** User Interface ***/\\n\\n function transfer(address dst, uint256 amount)\\n external\\n virtual\\n returns (bool);\\n\\n function transferFrom(\\n address src,\\n address dst,\\n uint256 amount\\n ) external virtual returns (bool);\\n\\n function approve(address spender, uint256 amount)\\n external\\n virtual\\n returns (bool);\\n\\n function allowance(address owner, address spender)\\n external\\n view\\n virtual\\n returns (uint256);\\n\\n function balanceOf(address owner) external view virtual returns (uint256);\\n\\n function balanceOfUnderlying(address owner)\\n external\\n virtual\\n returns (uint256);\\n\\n function getAccountSnapshot(address account)\\n external\\n view\\n virtual\\n returns (\\n uint256,\\n uint256,\\n uint256,\\n uint256\\n );\\n\\n function borrowRatePerBlock() external view virtual returns (uint256);\\n\\n function supplyRatePerBlock() external view virtual returns (uint256);\\n\\n function totalBorrowsCurrent() external virtual returns (uint256);\\n\\n function borrowBalanceCurrent(address account)\\n external\\n virtual\\n returns (uint256);\\n\\n function borrowBalanceStored(address account)\\n public\\n view\\n virtual\\n returns (uint256);\\n\\n function exchangeRateCurrent() public virtual returns (uint256);\\n\\n function exchangeRateStored() public view virtual returns (uint256);\\n\\n function getCash() external view virtual returns (uint256);\\n\\n function accrueInterest() public virtual returns (uint256);\\n\\n function seize(\\n address liquidator,\\n address borrower,\\n uint256 seizeTokens\\n ) external virtual returns (uint256);\\n\\n /*** Admin Functions ***/\\n\\n function _setPendingAdmin(address payable newPendingAdmin)\\n external\\n virtual\\n returns (uint256);\\n\\n function _acceptAdmin() external virtual returns (uint256);\\n\\n function _setComptroller(ComptrollerInterface newComptroller)\\n public\\n virtual\\n returns (uint256);\\n\\n function _setReserveFactor(uint256 newReserveFactorMantissa)\\n external\\n virtual\\n returns (uint256);\\n\\n function _reduceReserves(uint256 reduceAmount)\\n external\\n virtual\\n returns (uint256);\\n\\n function _setInterestRateModel(InterestRateModel newInterestRateModel)\\n public\\n virtual\\n returns (uint256);\\n}\\n\\ncontract CErc20Storage {\\n /**\\n * @notice Underlying asset for this CToken\\n */\\n address public underlying;\\n}\\n\\nabstract contract CErc20Interface is CErc20Storage {\\n /*** User Interface ***/\\n\\n function mint(uint256 mintAmount) external virtual returns (uint256);\\n\\n function redeem(uint256 redeemAmount)\\n external\\n virtual\\n returns (uint256);\\n\\n function borrow(uint256 borrowAmount) external virtual returns (uint256);\\n\\n function repayBorrow(uint256 repayAmount)\\n external\\n virtual\\n returns (uint256);\\n\\n function liquidateBorrow(\\n address borrower,\\n uint256 repayAmount,\\n CTokenInterface cTokenCollateral\\n ) external virtual returns (uint256);\\n\\n function sweepToken(EIP20NonStandardInterface token) external virtual;\\n\\n /*** Admin Functions ***/\\n\\n function _addReserves(uint256 addAmount) external virtual returns (uint256);\\n}\\n\\ncontract CDelegationStorage {\\n /**\\n * @notice Implementation address for this contract\\n */\\n address public implementation;\\n}\\n\\nabstract contract CDelegatorInterface is CDelegationStorage {\\n /**\\n * @notice Emitted when implementation is changed\\n */\\n event NewImplementation(\\n address oldImplementation,\\n address newImplementation\\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(\\n address implementation_,\\n bool allowResign,\\n bytes memory becomeImplementationData\\n ) public virtual;\\n}\\n\\nabstract contract 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 virtual;\\n\\n /**\\n * @notice Called by the delegator on a delegate to forfeit its responsibility\\n */\\n function _resignImplementation() public virtual;\\n}\\n\",\"keccak256\":\"0xd0c347830afeac6c54eb7fbac35b60215d9acdd1fb2a3abb16df18923384fa42\",\"license\":\"UNLICENSED\"},\"contracts/CarefulMath.sol\":{\"content\":\"// SPDX-License-Identifier: UNLICENSED\\npragma solidity 0.8.6;\\n\\n/**\\n * @title Careful Math\\n * @author tropykus\\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}\\n\",\"keccak256\":\"0x2aa4360607bccc28c9bde237718c5fabc5e68a34befec92724d30bfbc0b9499f\",\"license\":\"UNLICENSED\"},\"contracts/ComptrollerInterface.sol\":{\"content\":\"// SPDX-License-Identifier: UNLICENSED\\npragma solidity 0.8.6;\\n\\nabstract contract 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)\\n external\\n virtual\\n returns (uint256[] memory);\\n\\n function exitMarket(address cToken) external virtual returns (uint256);\\n\\n /*** Policy Hooks ***/\\n\\n function mintAllowed(\\n address cToken,\\n address minter,\\n uint256 mintAmount\\n ) external virtual returns (uint256);\\n\\n function mintVerify(\\n address cToken,\\n address minter,\\n uint256 mintAmount,\\n uint256 mintTokens\\n ) external virtual;\\n\\n function redeemAllowed(\\n address cToken,\\n address redeemer,\\n uint256 redeemTokens\\n ) external virtual returns (uint256);\\n\\n function redeemVerify(\\n address cToken,\\n address redeemer,\\n uint256 redeemAmount,\\n uint256 redeemTokens\\n ) external virtual;\\n\\n function borrowAllowed(\\n address cToken,\\n address borrower,\\n uint256 borrowAmount\\n ) external virtual returns (uint256);\\n\\n function borrowVerify(\\n address cToken,\\n address borrower,\\n uint256 borrowAmount\\n ) external virtual;\\n\\n function repayBorrowAllowed(\\n address cToken,\\n address payer,\\n address borrower,\\n uint256 repayAmount\\n ) external virtual returns (uint256);\\n\\n function repayBorrowVerify(\\n address cToken,\\n address payer,\\n address borrower,\\n uint256 repayAmount,\\n uint256 borrowerIndex\\n ) external virtual;\\n\\n function liquidateBorrowAllowed(\\n address cTokenBorrowed,\\n address cTokenCollateral,\\n address liquidator,\\n address borrower,\\n uint256 repayAmount\\n ) external virtual returns (uint256);\\n\\n function liquidateBorrowVerify(\\n address cTokenBorrowed,\\n address cTokenCollateral,\\n address liquidator,\\n address borrower,\\n uint256 repayAmount,\\n uint256 seizeTokens\\n ) external virtual;\\n\\n function seizeAllowed(\\n address cTokenCollateral,\\n address cTokenBorrowed,\\n address liquidator,\\n address borrower,\\n uint256 seizeTokens\\n ) external virtual returns (uint256);\\n\\n function seizeVerify(\\n address cTokenCollateral,\\n address cTokenBorrowed,\\n address liquidator,\\n address borrower,\\n uint256 seizeTokens\\n ) external virtual;\\n\\n function transferAllowed(\\n address cToken,\\n address src,\\n address dst,\\n uint256 transferTokens\\n ) external virtual returns (uint256);\\n\\n function transferVerify(\\n address cToken,\\n address src,\\n address dst,\\n uint256 transferTokens\\n ) external virtual;\\n\\n /*** Liquidity/Liquidation Calculations ***/\\n\\n function liquidateCalculateSeizeTokens(\\n address cTokenBorrowed,\\n address cTokenCollateral,\\n uint256 repayAmount\\n ) external view virtual returns (uint256, uint256);\\n}\\n\",\"keccak256\":\"0x4f6874b6790450374231de9b8c33652d620ec9457835e78d36ceaa561875a1b9\",\"license\":\"UNLICENSED\"},\"contracts/EIP20Interface.sol\":{\"content\":\"// SPDX-License-Identifier: UNLICENSED\\npragma solidity 0.8.6;\\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\\n function symbol() external view returns (string memory);\\n\\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 balance 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 success Whether or not the transfer succeeded\\n */\\n function transfer(address dst, uint256 amount)\\n external\\n 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 success Whether or not the transfer succeeded\\n */\\n function transferFrom(\\n address src,\\n address dst,\\n uint256 amount\\n ) 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 success Whether or not the approval succeeded\\n */\\n function approve(address spender, uint256 amount)\\n external\\n 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 remaining The number of tokens allowed to be spent (-1 means infinite)\\n */\\n function allowance(address owner, address spender)\\n external\\n view\\n returns (uint256 remaining);\\n\\n event Transfer(address indexed from, address indexed to, uint256 amount);\\n event Approval(\\n address indexed owner,\\n address indexed spender,\\n uint256 amount\\n );\\n}\\n\",\"keccak256\":\"0xe445bee8cc89c468e8822aa0d39c8f4ee6b6ac059191365ecef889cd83b53a75\",\"license\":\"UNLICENSED\"},\"contracts/EIP20NonStandardInterface.sol\":{\"content\":\"// SPDX-License-Identifier: UNLICENSED\\npragma solidity 0.8.6;\\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 * @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 balance 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(\\n address src,\\n address dst,\\n uint256 amount\\n ) 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 success Whether or not the approval succeeded\\n */\\n function approve(address spender, uint256 amount)\\n external\\n 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 remaining The number of tokens allowed to be spent\\n */\\n function allowance(address owner, address spender)\\n external\\n view\\n returns (uint256 remaining);\\n\\n event Transfer(address indexed from, address indexed to, uint256 amount);\\n event Approval(\\n address indexed owner,\\n address indexed spender,\\n uint256 amount\\n );\\n}\\n\",\"keccak256\":\"0xab8b46aaf5f985d5e3e1f1aa3dbc2e30d69ae0760b3a6b0478f50b9fca3bbc39\",\"license\":\"UNLICENSED\"},\"contracts/ErrorReporter.sol\":{\"content\":\"// SPDX-License-Identifier: UNLICENSED\\npragma solidity 0.8.6;\\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(uint256 error, uint256 info, uint256 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 (uint256) {\\n emit Failure(uint256(err), uint256(info), 0);\\n\\n return uint256(err);\\n }\\n\\n /**\\n * @dev use this when reporting an opaque error from an upgradeable collaborator contract\\n */\\n function failOpaque(\\n Error err,\\n FailureInfo info,\\n uint256 opaqueError\\n ) internal returns (uint256) {\\n emit Failure(uint256(err), uint256(info), opaqueError);\\n\\n return uint256(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 ADD_SUBSIDY_FUND_FAILED,\\n ADD_SUBSIDY_FUND_FRESH_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 TokenFailure(uint256 error, uint256 info, uint256 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 (uint256) {\\n emit TokenFailure(uint256(err), uint256(info), 0);\\n\\n return uint256(err);\\n }\\n\\n /**\\n * @dev use this when reporting an opaque error from an upgradeable collaborator contract\\n */\\n function failOpaque(\\n Error err,\\n FailureInfo info,\\n uint256 opaqueError\\n ) internal returns (uint256) {\\n emit TokenFailure(uint256(err), uint256(info), opaqueError);\\n\\n return uint256(err);\\n }\\n}\\n\",\"keccak256\":\"0x097b23a9ddec2e563458dadd7e03fb1756514acb8a05eb924da76b470582ceb9\",\"license\":\"UNLICENSED\"},\"contracts/Exponential.sol\":{\"content\":\"// SPDX-License-Identifier: UNLICENSED\\npragma solidity 0.8.6;\\n\\nimport \\\"./CarefulMath.sol\\\";\\nimport \\\"./ExponentialNoError.sol\\\";\\n\\n/**\\n * @title Exponential module for storing fixed-precision decimals\\n * @author tropykus\\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) internal pure 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) internal pure 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) internal pure 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) internal pure 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) internal pure 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) internal pure 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) internal pure 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) internal pure 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) internal pure 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) internal pure 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) internal pure 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) internal pure 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) internal pure returns (MathError, Exp memory) {\\n return getExp(a.mantissa, b.mantissa);\\n }\\n}\\n\",\"keccak256\":\"0x4d59359e644bc1df4c60f967b00027aed07612c3471c7c1206d61e10ab705475\",\"license\":\"UNLICENSED\"},\"contracts/ExponentialNoError.sol\":{\"content\":\"// SPDX-License-Identifier: UNLICENSED\\npragma solidity 0.8.6;\\n\\n/**\\n * @title Exponential module for storing fixed-precision decimals\\n * @author tropykus\\n * @notice Exp is a struct which stores decimals with a fixed precision of 18 decimal places.\\n * Thus, if we wanted to store the 5.1, mantissa would store 5.1e18. That is:\\n * `Exp({mantissa: 5100000000000000000})`.\\n */\\ncontract ExponentialNoError {\\n uint constant expScale = 1e18;\\n uint constant doubleScale = 1e36;\\n uint constant halfExpScale = expScale/2;\\n uint constant mantissaOne = expScale;\\n\\n struct Exp {\\n uint mantissa;\\n }\\n\\n struct Double {\\n uint mantissa;\\n }\\n\\n /**\\n * @dev Truncates the given exp to a whole number value.\\n * For example, truncate(Exp{mantissa: 15 * expScale}) = 15\\n */\\n function truncate(Exp memory exp) pure internal returns (uint) {\\n // Note: We are not using careful math here as we're performing a division that cannot fail\\n return exp.mantissa / expScale;\\n }\\n\\n /**\\n * @dev Multiply an Exp by a scalar, then truncate to return an unsigned integer.\\n */\\n function mul_ScalarTruncate(Exp memory a, uint scalar) pure internal returns (uint) {\\n Exp memory product = mul_(a, scalar);\\n return truncate(product);\\n }\\n\\n /**\\n * @dev Multiply an Exp by a scalar, truncate, then add an to an unsigned integer, returning an unsigned integer.\\n */\\n function mul_ScalarTruncateAddUInt(Exp memory a, uint scalar, uint addend) pure internal returns (uint) {\\n Exp memory product = mul_(a, scalar);\\n return add_(truncate(product), addend);\\n }\\n\\n /**\\n * @dev Checks if first Exp is less than second Exp.\\n */\\n function lessThanExp(Exp memory left, Exp memory right) pure internal returns (bool) {\\n return left.mantissa < right.mantissa;\\n }\\n\\n /**\\n * @dev Checks if left Exp <= right Exp.\\n */\\n function lessThanOrEqualExp(Exp memory left, Exp memory right) pure internal returns (bool) {\\n return left.mantissa <= right.mantissa;\\n }\\n\\n /**\\n * @dev Checks if left Exp > right Exp.\\n */\\n function greaterThanExp(Exp memory left, Exp memory right) pure internal returns (bool) {\\n return left.mantissa > right.mantissa;\\n }\\n\\n /**\\n * @dev returns true if Exp is exactly zero\\n */\\n function isZeroExp(Exp memory value) pure internal returns (bool) {\\n return value.mantissa == 0;\\n }\\n\\n function safe224(uint n, string memory errorMessage) pure internal returns (uint224) {\\n require(n < 2**224, errorMessage);\\n return uint224(n);\\n }\\n\\n function safe32(uint n, string memory errorMessage) pure internal returns (uint32) {\\n require(n < 2**32, errorMessage);\\n return uint32(n);\\n }\\n\\n function add_(Exp memory a, Exp memory b) pure internal returns (Exp memory) {\\n return Exp({mantissa: add_(a.mantissa, b.mantissa)});\\n }\\n\\n function add_(Double memory a, Double memory b) pure internal returns (Double memory) {\\n return Double({mantissa: add_(a.mantissa, b.mantissa)});\\n }\\n\\n function add_(uint a, uint b) pure internal returns (uint) {\\n return add_(a, b, \\\"addition overflow\\\");\\n }\\n\\n function add_(uint a, uint b, string memory errorMessage) pure internal returns (uint) {\\n uint c = a + b;\\n require(c >= a, errorMessage);\\n return c;\\n }\\n\\n function sub_(Exp memory a, Exp memory b) pure internal returns (Exp memory) {\\n return Exp({mantissa: sub_(a.mantissa, b.mantissa)});\\n }\\n\\n function sub_(Double memory a, Double memory b) pure internal returns (Double memory) {\\n return Double({mantissa: sub_(a.mantissa, b.mantissa)});\\n }\\n\\n function sub_(uint a, uint b) pure internal returns (uint) {\\n return sub_(a, b, \\\"subtraction underflow\\\");\\n }\\n\\n function sub_(uint a, uint b, string memory errorMessage) pure internal returns (uint) {\\n require(b <= a, errorMessage);\\n return a - b;\\n }\\n\\n function mul_(Exp memory a, Exp memory b) pure internal returns (Exp memory) {\\n return Exp({mantissa: mul_(a.mantissa, b.mantissa) / expScale});\\n }\\n\\n function mul_(Exp memory a, uint b) pure internal returns (Exp memory) {\\n return Exp({mantissa: mul_(a.mantissa, b)});\\n }\\n\\n function mul_(uint a, Exp memory b) pure internal returns (uint) {\\n return mul_(a, b.mantissa) / expScale;\\n }\\n\\n function mul_(Double memory a, Double memory b) pure internal returns (Double memory) {\\n return Double({mantissa: mul_(a.mantissa, b.mantissa) / doubleScale});\\n }\\n\\n function mul_(Double memory a, uint b) pure internal returns (Double memory) {\\n return Double({mantissa: mul_(a.mantissa, b)});\\n }\\n\\n function mul_(uint a, Double memory b) pure internal returns (uint) {\\n return mul_(a, b.mantissa) / doubleScale;\\n }\\n\\n function mul_(uint a, uint b) pure internal returns (uint) {\\n return mul_(a, b, \\\"multiplication overflow\\\");\\n }\\n\\n function mul_(uint a, uint b, string memory errorMessage) pure internal returns (uint) {\\n if (a == 0 || b == 0) {\\n return 0;\\n }\\n uint c = a * b;\\n require(c / a == b, errorMessage);\\n return c;\\n }\\n\\n function div_(Exp memory a, Exp memory b) pure internal returns (Exp memory) {\\n return Exp({mantissa: div_(mul_(a.mantissa, expScale), b.mantissa)});\\n }\\n\\n function div_(Exp memory a, uint b) pure internal returns (Exp memory) {\\n return Exp({mantissa: div_(a.mantissa, b)});\\n }\\n\\n function div_(uint a, Exp memory b) pure internal returns (uint) {\\n return div_(mul_(a, expScale), b.mantissa);\\n }\\n\\n function div_(Double memory a, Double memory b) pure internal returns (Double memory) {\\n return Double({mantissa: div_(mul_(a.mantissa, doubleScale), b.mantissa)});\\n }\\n\\n function div_(Double memory a, uint b) pure internal returns (Double memory) {\\n return Double({mantissa: div_(a.mantissa, b)});\\n }\\n\\n function div_(uint a, Double memory b) pure internal returns (uint) {\\n return div_(mul_(a, doubleScale), b.mantissa);\\n }\\n\\n function div_(uint a, uint b) pure internal returns (uint) {\\n return div_(a, b, \\\"divide by zero\\\");\\n }\\n\\n function div_(uint a, uint b, string memory errorMessage) pure internal returns (uint) {\\n require(b > 0, errorMessage);\\n return a / b;\\n }\\n\\n function fraction(uint a, uint b) pure internal returns (Double memory) {\\n return Double({mantissa: div_(mul_(a, doubleScale), b)});\\n }\\n}\\n\",\"keccak256\":\"0x50ebd15fc98c12e065477f11230f5d7cd583b5fe25a3c532cb90e75950667795\",\"license\":\"UNLICENSED\"},\"contracts/InterestRateModel.sol\":{\"content\":\"// SPDX-License-Identifier: UNLICENSED\\npragma solidity 0.8.6;\\n\\nimport \\\"./Exponential.sol\\\";\\nimport \\\"./SafeMath.sol\\\";\\n\\n/**\\n * @title tropykus InterestRateModel Interface\\n * @author tropykus\\n */\\nabstract contract InterestRateModel is Exponential {\\n using SafeMath for uint256;\\n\\n /// @notice Indicator that this is an InterestRateModel contract (for inspection)\\n bool public constant isInterestRateModel = true;\\n bool public isTropykusInterestRateModel;\\n\\n /**\\n * @notice The approximate number of blocks per year that is assumed by the interest rate model\\n */\\n uint256 public constant blocksPerYear = 1051200;\\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(\\n uint256 cash,\\n uint256 borrows,\\n uint256 reserves\\n ) public pure virtual returns (uint256) {\\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 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 amnount of reserves the market has\\n * @return The borrow rate per block (as a percentage, and scaled by 1e18)\\n */\\n function getBorrowRate(\\n uint256 cash,\\n uint256 borrows,\\n uint256 reserves\\n ) external view virtual returns (uint256);\\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 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(\\n uint256 cash,\\n uint256 borrows,\\n uint256 reserves,\\n uint256 reserveFactorMantissa\\n ) external view virtual returns (uint256);\\n\\n function getExchangeRate(\\n uint256 _totalCash,\\n uint256 _totalBorrows,\\n uint256 _totalReserves,\\n uint256 _totalSupply\\n ) public pure returns (MathError, uint256) {\\n /*\\n * exchangeRate = (totalCash + totalBorrows - totalReserves) / totalSupply\\n */\\n Exp memory exchangeRate;\\n MathError mathErr;\\n uint256 cashPlusBorrowsMinusReserves;\\n (mathErr, cashPlusBorrowsMinusReserves) = addThenSubUInt(\\n _totalCash,\\n _totalBorrows,\\n _totalReserves\\n );\\n if (mathErr != MathError.NO_ERROR) {\\n return (mathErr, 0);\\n }\\n (mathErr, exchangeRate) = getExp(\\n cashPlusBorrowsMinusReserves,\\n _totalSupply\\n );\\n if (mathErr != MathError.NO_ERROR) {\\n return (mathErr, 0);\\n }\\n\\n return (MathError.NO_ERROR, exchangeRate.mantissa);\\n }\\n\\n function isAboveOptimal(\\n uint256 cash,\\n uint256 borrows,\\n uint256 reserves\\n ) public view virtual returns (bool) {\\n cash;\\n borrows;\\n reserves;\\n return false;\\n }\\n}\\n\",\"keccak256\":\"0x2cdc1a63482287513664d98d778c718c336461272885f61585c6ba404feb2edc\",\"license\":\"UNLICENSED\"},\"contracts/SafeMath.sol\":{\"content\":\"// SPDX-License-Identifier: UNLICENSED\\npragma solidity 0.8.6;\\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\":\"0xe578b9602160e7ddbb5e7b6d355bb4508fa134684afe46e4043602c652e0e041\",\"license\":\"UNLICENSED\"},\"contracts/WhitelistInterface.sol\":{\"content\":\"// SPDX-License-Identifier: UNLICENSED\\npragma solidity 0.8.6;\\n\\ninterface WhitelistInterface {\\n function setStatus(bool _newStatus) external;\\n function enabled() external view returns(bool);\\n\\n function addUsers(address[] memory _users) external;\\n function exist(address _user) external view returns(bool);\\n function getUsers() external view returns(address[] memory currentUsers);\\n function removeUser(address _user) external;\\n}\",\"keccak256\":\"0xb00f782772179693611aefb08d51640de313bc901d6d9d78d1e1b86922e99130\",\"license\":\"UNLICENSED\"},\"contracts/mocks/MockPriceProviderMoC.sol\":{\"content\":\"// SPDX-License-Identifier: UNLICENSED\\npragma solidity 0.8.6;\\n\\nimport \\\"../CErc20.sol\\\";\\n\\n/**\\n * @title A mock price provider of Money on Chain (MoC)\\n * @notice You can use this contract for only simulation\\n */\\ncontract MockPriceProviderMoC {\\n /// @notice rbtcPrice of the interface provicer MoC\\n bytes32 rbtcPrice;\\n /// @notice has of the interface provicer MoC\\n bool has;\\n /// @notice Address of the guardian\\n address public guardian;\\n /// @notice Event rbtcPrice updated\\n event MockPriceProviderMoCUpdated(uint256 oldPrice, uint256 newPrice);\\n\\n constructor(address guardian_, uint256 price) {\\n require(\\n guardian_ != address(0),\\n \\\"MockPriceProviderMoC: address could not be 0\\\"\\n );\\n require(\\n price != uint256(0),\\n \\\"MockPriceProviderMoC: price could not be 0\\\"\\n );\\n guardian = guardian_;\\n rbtcPrice = bytes32(price);\\n has = true;\\n }\\n\\n function peek() public view returns (bytes32, bool) {\\n return (rbtcPrice, has);\\n }\\n\\n /**\\n * @notice Set the rbtcPrice price provider\\n * @param price uint of price provider\\n */\\n function setPrice(uint256 price) public {\\n require(\\n msg.sender == guardian,\\n \\\"MockPriceProviderMoC: only guardian may set the address\\\"\\n );\\n require(\\n price != uint256(0),\\n \\\"MockPriceProviderMoC: price could not be 0\\\"\\n );\\n //set old price\\n bytes32 oldRbtcPrice = rbtcPrice;\\n //update rbtcPrice\\n rbtcPrice = bytes32(price);\\n //emit event\\n emit MockPriceProviderMoCUpdated(\\n uint256(oldRbtcPrice),\\n uint256(rbtcPrice)\\n );\\n }\\n}\\n\",\"keccak256\":\"0xc92138e00d6d4a6a90185de32002ee03c70254fa27d4be28539d72c22785cce9\",\"license\":\"UNLICENSED\"}},\"version\":1}", - "bytecode": "0x608060405234801561001057600080fd5b506040516103aa3803806103aa83398101604081905261002f91610135565b6001600160a01b03821661009f5760405162461bcd60e51b815260206004820152602c60248201527f4d6f636b507269636550726f76696465724d6f433a206164647265737320636f60448201526b0756c64206e6f7420626520360a41b60648201526084015b60405180910390fd5b806100ff5760405162461bcd60e51b815260206004820152602a60248201527f4d6f636b507269636550726f76696465724d6f433a20707269636520636f756c604482015269064206e6f7420626520360b41b6064820152608401610096565b6001805460009290925560ff196001600160a01b0390931661010002929092166001600160a81b0319909116178117905561016f565b6000806040838503121561014857600080fd5b82516001600160a01b038116811461015f57600080fd5b6020939093015192949293505050565b61022c8061017e6000396000f3fe608060405234801561001057600080fd5b50600436106100415760003560e01c8063452a93201461004657806359e02dd71461007b57806391b7f5ed14610099575b600080fd5b60015461005e9061010090046001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b60005460015460ff1660408051928352901515602083015201610072565b6100ac6100a73660046101dd565b6100ae565b005b60015461010090046001600160a01b031633146101385760405162461bcd60e51b815260206004820152603760248201527f4d6f636b507269636550726f76696465724d6f433a206f6e6c7920677561726460448201527f69616e206d61792073657420746865206164647265737300000000000000000060648201526084015b60405180910390fd5b806101985760405162461bcd60e51b815260206004820152602a60248201527f4d6f636b507269636550726f76696465724d6f433a20707269636520636f756c604482015269064206e6f7420626520360b41b606482015260840161012f565b600080549082905560408051828152602081018490527f0f044c0280bacc38accfa21abc3ff4078e3acc7d7a14569f5db61f36870df047910160405180910390a15050565b6000602082840312156101ef57600080fd5b503591905056fea2646970667358221220f7515fbb2e55846cd982cf3d3ec4650f7c5c8cad8c3466ce1148d1d7ab30910064736f6c63430008060033", - "deployedBytecode": "0x608060405234801561001057600080fd5b50600436106100415760003560e01c8063452a93201461004657806359e02dd71461007b57806391b7f5ed14610099575b600080fd5b60015461005e9061010090046001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b60005460015460ff1660408051928352901515602083015201610072565b6100ac6100a73660046101dd565b6100ae565b005b60015461010090046001600160a01b031633146101385760405162461bcd60e51b815260206004820152603760248201527f4d6f636b507269636550726f76696465724d6f433a206f6e6c7920677561726460448201527f69616e206d61792073657420746865206164647265737300000000000000000060648201526084015b60405180910390fd5b806101985760405162461bcd60e51b815260206004820152602a60248201527f4d6f636b507269636550726f76696465724d6f433a20707269636520636f756c604482015269064206e6f7420626520360b41b606482015260840161012f565b600080549082905560408051828152602081018490527f0f044c0280bacc38accfa21abc3ff4078e3acc7d7a14569f5db61f36870df047910160405180910390a15050565b6000602082840312156101ef57600080fd5b503591905056fea2646970667358221220f7515fbb2e55846cd982cf3d3ec4650f7c5c8cad8c3466ce1148d1d7ab30910064736f6c63430008060033", - "devdoc": { - "kind": "dev", - "methods": { - "setPrice(uint256)": { - "params": { - "price": "uint of price provider" - } - } - }, - "title": "A mock price provider of Money on Chain (MoC)", - "version": 1 - }, - "userdoc": { - "events": { - "MockPriceProviderMoCUpdated(uint256,uint256)": { - "notice": "Event rbtcPrice updated" - } - }, - "kind": "user", - "methods": { - "guardian()": { - "notice": "Address of the guardian" - }, - "setPrice(uint256)": { - "notice": "Set the rbtcPrice price provider" - } - }, - "notice": "You can use this contract for only simulation", - "version": 1 - }, - "storageLayout": { - "storage": [ - { - "astId": 41911, - "contract": "contracts/mocks/MockPriceProviderMoC.sol:MockPriceProviderMoC", - "label": "rbtcPrice", - "offset": 0, - "slot": "0", - "type": "t_bytes32" - }, - { - "astId": 41914, - "contract": "contracts/mocks/MockPriceProviderMoC.sol:MockPriceProviderMoC", - "label": "has", - "offset": 0, - "slot": "1", - "type": "t_bool" - }, - { - "astId": 41917, - "contract": "contracts/mocks/MockPriceProviderMoC.sol:MockPriceProviderMoC", - "label": "guardian", - "offset": 1, - "slot": "1", - "type": "t_address" - } - ], - "types": { - "t_address": { - "encoding": "inplace", - "label": "address", - "numberOfBytes": "20" - }, - "t_bool": { - "encoding": "inplace", - "label": "bool", - "numberOfBytes": "1" - }, - "t_bytes32": { - "encoding": "inplace", - "label": "bytes32", - "numberOfBytes": "32" - } - } - } -} \ No newline at end of file diff --git a/deployments/localhost/Unitroller.json b/deployments/localhost/Unitroller.json deleted file mode 100644 index d4b05dd..0000000 --- a/deployments/localhost/Unitroller.json +++ /dev/null @@ -1,379 +0,0 @@ -{ - "address": "0x84eA74d481Ee0A5332c457a4d796187F6Ba67fEB", - "abi": [ - { - "inputs": [], - "stateMutability": "nonpayable", - "type": "constructor" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "error", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "info", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "detail", - "type": "uint256" - } - ], - "name": "Failure", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "oldAdmin", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "newAdmin", - "type": "address" - } - ], - "name": "NewAdmin", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "oldImplementation", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "newImplementation", - "type": "address" - } - ], - "name": "NewImplementation", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "oldPendingAdmin", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "newPendingAdmin", - "type": "address" - } - ], - "name": "NewPendingAdmin", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "oldPendingImplementation", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "newPendingImplementation", - "type": "address" - } - ], - "name": "NewPendingImplementation", - "type": "event" - }, - { - "stateMutability": "payable", - "type": "fallback" - }, - { - "inputs": [], - "name": "_acceptAdmin", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "_acceptImplementation", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newPendingAdmin", - "type": "address" - } - ], - "name": "_setPendingAdmin", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newPendingImplementation", - "type": "address" - } - ], - "name": "_setPendingImplementation", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "admin", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "comptrollerImplementation", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "internalFallback", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [], - "name": "pendingAdmin", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "pendingComptrollerImplementation", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "stateMutability": "payable", - "type": "receive" - } - ], - "transactionHash": "0x89e1ebcb484f23abed252a4e247e6975e5715a3ae964d05930bbd3b2487995bd", - "receipt": { - "to": null, - "from": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", - "contractAddress": "0x84eA74d481Ee0A5332c457a4d796187F6Ba67fEB", - "transactionIndex": 0, - "gasUsed": "407096", - "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "blockHash": "0x2cbe712700c4112ac345526cfa72dc11917816e29ba988d1877e26653c93ebca", - "transactionHash": "0x89e1ebcb484f23abed252a4e247e6975e5715a3ae964d05930bbd3b2487995bd", - "logs": [], - "blockNumber": 33, - "cumulativeGasUsed": "407096", - "status": 1, - "byzantium": true - }, - "args": [], - "solcInputHash": "3f2295c0e5923ce11cb0f26c6e52bee2", - "metadata": "{\"compiler\":{\"version\":\"0.8.6+commit.11564f7e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"error\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"info\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"detail\",\"type\":\"uint256\"}],\"name\":\"Failure\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"oldAdmin\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"newAdmin\",\"type\":\"address\"}],\"name\":\"NewAdmin\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"oldImplementation\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"newImplementation\",\"type\":\"address\"}],\"name\":\"NewImplementation\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"oldPendingAdmin\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"newPendingAdmin\",\"type\":\"address\"}],\"name\":\"NewPendingAdmin\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"oldPendingImplementation\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"newPendingImplementation\",\"type\":\"address\"}],\"name\":\"NewPendingImplementation\",\"type\":\"event\"},{\"stateMutability\":\"payable\",\"type\":\"fallback\"},{\"inputs\":[],\"name\":\"_acceptAdmin\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"_acceptImplementation\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newPendingAdmin\",\"type\":\"address\"}],\"name\":\"_setPendingAdmin\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newPendingImplementation\",\"type\":\"address\"}],\"name\":\"_setPendingImplementation\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"admin\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"comptrollerImplementation\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"internalFallback\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"pendingAdmin\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"pendingComptrollerImplementation\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}],\"devdoc\":{\"details\":\"Storage for the comptroller is at this address, while execution is delegated to the `comptrollerImplementation`. CTokens should reference this contract as their comptroller.\",\"kind\":\"dev\",\"methods\":{\"_acceptAdmin()\":{\"details\":\"Admin function for pending admin to accept role and update admin\",\"returns\":{\"_0\":\"uint 0=success, otherwise a failure (see ErrorReporter.sol for details)\"}},\"_acceptImplementation()\":{\"details\":\"Admin function for new implementation to accept it's role as implementation\",\"returns\":{\"_0\":\"uint 0=success, otherwise a failure (see ErrorReporter.sol for details)\"}},\"_setPendingAdmin(address)\":{\"details\":\"Admin function to begin change of admin. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer.\",\"params\":{\"newPendingAdmin\":\"New pending admin.\"},\"returns\":{\"_0\":\"uint 0=success, otherwise a failure (see ErrorReporter.sol for details)\"}},\"internalFallback()\":{\"details\":\"Delegates execution to an implementation contract. It returns to the external caller whatever the implementation returns or forwards reverts.\"}},\"title\":\"ComptrollerCore\",\"version\":1},\"userdoc\":{\"events\":{\"NewAdmin(address,address)\":{\"notice\":\"Emitted when pendingAdmin is accepted, which means admin is updated\"},\"NewImplementation(address,address)\":{\"notice\":\"Emitted when pendingComptrollerImplementation is accepted, which means comptroller implementation is updated\"},\"NewPendingAdmin(address,address)\":{\"notice\":\"Emitted when pendingAdmin is changed\"},\"NewPendingImplementation(address,address)\":{\"notice\":\"Emitted when pendingComptrollerImplementation is changed\"}},\"kind\":\"user\",\"methods\":{\"_acceptAdmin()\":{\"notice\":\"Accepts transfer of admin rights. msg.sender must be pendingAdmin\"},\"_acceptImplementation()\":{\"notice\":\"Accepts new implementation of comptroller. msg.sender must be pendingImplementation\"},\"_setPendingAdmin(address)\":{\"notice\":\"Begins transfer of admin rights. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer.\"},\"admin()\":{\"notice\":\"Administrator for this contract\"},\"comptrollerImplementation()\":{\"notice\":\"Active brains of Unitroller\"},\"pendingAdmin()\":{\"notice\":\"Pending administrator for this contract\"},\"pendingComptrollerImplementation()\":{\"notice\":\"Pending brains of Unitroller\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/Unitroller.sol\":\"Unitroller\"},\"evmVersion\":\"berlin\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"contracts/CToken.sol\":{\"content\":\"// SPDX-License-Identifier: UNLICENSED\\npragma solidity 0.8.6;\\n\\nimport \\\"./ComptrollerInterface.sol\\\";\\nimport \\\"./CTokenInterfaces.sol\\\";\\nimport \\\"./ErrorReporter.sol\\\";\\nimport \\\"./Exponential.sol\\\";\\nimport \\\"./EIP20Interface.sol\\\";\\nimport \\\"./InterestRateModel.sol\\\";\\nimport \\\"./WhitelistInterface.sol\\\";\\n\\n/**\\n * @title tropykus CToken Contract\\n * @notice Abstract base for CTokens\\n * @author tropykus\\n */\\nabstract contract CToken is CTokenInterface, Exponential, TokenErrorReporter {\\n address whitelist;\\n\\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(\\n ComptrollerInterface comptroller_,\\n InterestRateModel interestRateModel_,\\n uint256 initialExchangeRateMantissa_,\\n string memory name_,\\n string memory symbol_,\\n uint8 decimals_\\n ) public {\\n require(msg.sender == admin, \\\"CT01\\\");\\n require(accrualBlockNumber == 0 && borrowIndex == 0, \\\"CT02\\\");\\n\\n initialExchangeRateMantissa = initialExchangeRateMantissa_;\\n require(initialExchangeRateMantissa > 0, \\\"CT03\\\");\\n\\n uint256 err = _setComptroller(comptroller_);\\n require(err == uint256(Error.NO_ERROR), \\\"CT04\\\");\\n\\n accrualBlockNumber = getBlockNumber();\\n borrowIndex = mantissaOne;\\n\\n err = _setInterestRateModelFresh(interestRateModel_);\\n require(err == uint256(Error.NO_ERROR), \\\"CT05\\\");\\n\\n name = name_;\\n symbol = symbol_;\\n decimals = decimals_;\\n\\n _notEntered = true;\\n }\\n\\n function addWhitelist(address _whitelist) external returns (uint256) {\\n if (msg.sender != admin) {\\n return\\n fail(\\n Error.UNAUTHORIZED,\\n FailureInfo.SET_INTEREST_RATE_MODEL_OWNER_CHECK\\n );\\n }\\n whitelist = _whitelist;\\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(\\n address spender,\\n address src,\\n address dst,\\n uint256 tokens\\n ) internal returns (uint256) {\\n uint256 allowed = comptroller.transferAllowed(\\n address(this),\\n src,\\n dst,\\n tokens\\n );\\n if (allowed != 0) {\\n return\\n failOpaque(\\n Error.COMPTROLLER_REJECTION,\\n FailureInfo.TRANSFER_COMPTROLLER_REJECTION,\\n allowed\\n );\\n }\\n\\n if (src == dst) {\\n return fail(Error.BAD_INPUT, FailureInfo.TRANSFER_NOT_ALLOWED);\\n }\\n\\n uint256 startingAllowance = 0;\\n if (spender == src) {\\n startingAllowance = type(uint256).max;\\n } else {\\n startingAllowance = transferAllowances[src][spender];\\n }\\n\\n MathError mathErr;\\n uint256 allowanceNew;\\n uint256 srcTokensNew;\\n uint256 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, 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, tokens);\\n if (mathErr != MathError.NO_ERROR) {\\n return fail(Error.MATH_ERROR, FailureInfo.TRANSFER_TOO_MUCH);\\n }\\n\\n accountTokens[src].tokens = srcTokensNew;\\n accountTokens[dst].tokens = dstTokensNew;\\n\\n if (startingAllowance != type(uint256).max) {\\n transferAllowances[src][spender] = allowanceNew;\\n }\\n\\n emit Transfer(src, dst, tokens);\\n\\n return uint256(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)\\n external\\n override\\n nonReentrant\\n returns (bool)\\n {\\n return\\n transferTokens(msg.sender, msg.sender, dst, amount) ==\\n uint256(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(\\n address src,\\n address dst,\\n uint256 amount\\n ) external override nonReentrant returns (bool) {\\n return\\n transferTokens(msg.sender, src, dst, amount) ==\\n uint256(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)\\n external\\n override\\n returns (bool)\\n {\\n transferAllowances[msg.sender][spender] = amount;\\n emit Approval(msg.sender, 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)\\n external\\n view\\n override\\n returns (uint256)\\n {\\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 override returns (uint256) {\\n return accountTokens[owner].tokens;\\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)\\n external\\n override\\n returns (uint256)\\n {\\n (MathError mErr, uint256 balance) = mulScalarTruncate(\\n Exp({mantissa: exchangeRateCurrent()}),\\n accountTokens[owner].tokens\\n );\\n require(mErr == MathError.NO_ERROR, \\\"CT06\\\");\\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)\\n external\\n view\\n override\\n returns (\\n uint256,\\n uint256,\\n uint256,\\n uint256\\n )\\n {\\n uint256 cTokenBalance = accountTokens[account].tokens;\\n uint256 borrowBalance;\\n uint256 exchangeRateMantissa;\\n\\n MathError mErr;\\n\\n (mErr, borrowBalance) = borrowBalanceStoredInternal(account);\\n if (mErr != MathError.NO_ERROR) {\\n return (uint256(Error.MATH_ERROR), 0, 0, 0);\\n }\\n\\n (mErr, exchangeRateMantissa) = exchangeRateStoredInternal();\\n if (mErr != MathError.NO_ERROR) {\\n return (uint256(Error.MATH_ERROR), 0, 0, 0);\\n }\\n\\n return (\\n uint256(Error.NO_ERROR),\\n cTokenBalance,\\n borrowBalance,\\n exchangeRateMantissa\\n );\\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 virtual returns (uint256) {\\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 override returns (uint256) {\\n return\\n interestRateModel.getBorrowRate(\\n getCashPrior(),\\n totalBorrows,\\n totalReserves\\n );\\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 override returns (uint256) {\\n return\\n interestRateModel.getSupplyRate(\\n getCashPrior(),\\n totalBorrows,\\n totalReserves,\\n reserveFactorMantissa\\n );\\n }\\n\\n /**\\n * @notice Returns the current total borrows plus accrued interest\\n * @return The total borrows with interest\\n */\\n function totalBorrowsCurrent()\\n external\\n override\\n nonReentrant\\n returns (uint256)\\n {\\n require(accrueInterest() == uint256(Error.NO_ERROR), \\\"CT07\\\");\\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)\\n external\\n override\\n nonReentrant\\n returns (uint256)\\n {\\n require(accrueInterest() == uint256(Error.NO_ERROR), \\\"CT07\\\");\\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)\\n public\\n view\\n override\\n returns (uint256)\\n {\\n (MathError err, uint256 result) = borrowBalanceStoredInternal(account);\\n require(err == MathError.NO_ERROR, \\\"CT08\\\");\\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)\\n internal\\n view\\n returns (MathError, uint256)\\n {\\n MathError mathErr;\\n uint256 principalTimesIndex;\\n uint256 result;\\n\\n BorrowSnapshot storage borrowSnapshot = accountBorrows[account];\\n\\n if (borrowSnapshot.principal == 0) {\\n return (MathError.NO_ERROR, 0);\\n }\\n\\n (mathErr, principalTimesIndex) = mulUInt(\\n borrowSnapshot.principal,\\n borrowIndex\\n );\\n if (mathErr != MathError.NO_ERROR) {\\n return (mathErr, 0);\\n }\\n\\n (mathErr, result) = divUInt(\\n principalTimesIndex,\\n borrowSnapshot.interestIndex\\n );\\n if (mathErr != MathError.NO_ERROR) {\\n return (mathErr, 0);\\n }\\n\\n return (MathError.NO_ERROR, result);\\n }\\n\\n function getBorrowerPrincipalStored(address account)\\n public\\n view\\n returns (uint256 borrowed)\\n {\\n borrowed = accountBorrows[account].principal;\\n }\\n\\n function getSupplierSnapshotStored(address account)\\n public\\n view\\n returns (\\n uint256 tokens,\\n uint256 underlyingAmount,\\n uint256 suppliedAt,\\n uint256 promisedSupplyRate\\n )\\n {\\n tokens = accountTokens[account].tokens;\\n underlyingAmount = accountTokens[account].underlyingAmount;\\n suppliedAt = accountTokens[account].suppliedAt;\\n promisedSupplyRate = accountTokens[account].promisedSupplyRate;\\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()\\n public\\n override\\n nonReentrant\\n returns (uint256)\\n {\\n require(accrueInterest() == uint256(Error.NO_ERROR), \\\"CT07\\\");\\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 override returns (uint256) {\\n (MathError err, uint256 result) = exchangeRateStoredInternal();\\n require(err == MathError.NO_ERROR, \\\"CT09\\\");\\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()\\n internal\\n view\\n virtual\\n returns (MathError, uint256)\\n {\\n uint256 _totalSupply = totalSupply;\\n if (_totalSupply == 0) {\\n return (MathError.NO_ERROR, initialExchangeRateMantissa);\\n } else {\\n MathError error;\\n uint256 exchangeRate;\\n uint256 totalCash = getCashPrior();\\n if (interestRateModel.isTropykusInterestRateModel()) {\\n (error, exchangeRate) = tropykusExchangeRateStoredInternal(\\n msg.sender\\n );\\n if (error == MathError.NO_ERROR) {\\n return (MathError.NO_ERROR, exchangeRate);\\n } else {\\n return (MathError.NO_ERROR, initialExchangeRateMantissa);\\n }\\n }\\n return\\n interestRateModel.getExchangeRate(\\n totalCash,\\n totalBorrows,\\n totalReserves,\\n totalSupply\\n );\\n }\\n }\\n\\n function tropykusExchangeRateStoredInternal(address redeemer)\\n internal\\n view\\n returns (MathError, uint256)\\n {\\n if (totalSupply == 0) {\\n return (MathError.NO_ERROR, initialExchangeRateMantissa);\\n } else {\\n SupplySnapshot storage supplySnapshot = accountTokens[redeemer];\\n if (supplySnapshot.suppliedAt == 0) {\\n return (MathError.DIVISION_BY_ZERO, 0);\\n }\\n (, uint256 interestFactorMantissa, ) = tropykusInterestAccrued(\\n redeemer\\n );\\n Exp memory interestFactor = Exp({mantissa: interestFactorMantissa});\\n uint256 currentUnderlying = supplySnapshot.underlyingAmount;\\n Exp memory redeemerUnderlying = Exp({mantissa: currentUnderlying});\\n (, Exp memory realAmount) = mulExp(\\n interestFactor,\\n redeemerUnderlying\\n );\\n (, Exp memory exchangeRate) = getExp(\\n realAmount.mantissa,\\n supplySnapshot.tokens\\n );\\n return (MathError.NO_ERROR, exchangeRate.mantissa);\\n }\\n }\\n\\n function tropykusInterestAccrued(address account)\\n internal\\n view\\n returns (\\n MathError,\\n uint256,\\n uint256\\n )\\n {\\n SupplySnapshot storage supplySnapshot = accountTokens[account];\\n uint256 promisedSupplyRate = supplySnapshot.promisedSupplyRate;\\n Exp memory expectedSupplyRatePerBlock = Exp({\\n mantissa: promisedSupplyRate\\n });\\n (, uint256 delta) = subUInt(\\n accrualBlockNumber,\\n supplySnapshot.suppliedAt\\n );\\n (, Exp memory expectedSupplyRatePerBlockWithDelta) = mulScalar(\\n expectedSupplyRatePerBlock,\\n delta\\n );\\n (, Exp memory interestFactor) = addExp(\\n Exp({mantissa: 1e18}),\\n expectedSupplyRatePerBlockWithDelta\\n );\\n uint256 currentUnderlying = supplySnapshot.underlyingAmount;\\n Exp memory redeemerUnderlying = Exp({mantissa: currentUnderlying});\\n (, Exp memory realAmount) = mulExp(interestFactor, redeemerUnderlying);\\n (, uint256 interestEarned) = subUInt(\\n realAmount.mantissa,\\n currentUnderlying\\n );\\n return (MathError.NO_ERROR, interestFactor.mantissa, interestEarned);\\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 override returns (uint256) {\\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 override returns (uint256) {\\n uint256 currentBlockNumber = getBlockNumber();\\n uint256 accrualBlockNumberPrior = accrualBlockNumber;\\n\\n if (accrualBlockNumberPrior == currentBlockNumber) {\\n return uint256(Error.NO_ERROR);\\n }\\n\\n uint256 cashPrior = getCashPrior();\\n uint256 borrowsPrior = totalBorrows;\\n uint256 reservesPrior = totalReserves;\\n uint256 borrowIndexPrior = borrowIndex;\\n\\n uint256 borrowRateMantissa = interestRateModel.getBorrowRate(\\n cashPrior,\\n borrowsPrior,\\n reservesPrior\\n );\\n require(borrowRateMantissa <= borrowRateMaxMantissa, \\\"CT10\\\");\\n\\n (MathError mathErr, uint256 blockDelta) = subUInt(\\n currentBlockNumber,\\n accrualBlockNumberPrior\\n );\\n require(mathErr == MathError.NO_ERROR, \\\"CT11\\\");\\n\\n Exp memory simpleInterestFactor;\\n uint256 interestAccumulated;\\n uint256 totalBorrowsNew;\\n uint256 totalReservesNew;\\n uint256 borrowIndexNew;\\n\\n (mathErr, simpleInterestFactor) = mulScalar(\\n Exp({mantissa: borrowRateMantissa}),\\n blockDelta\\n );\\n if (mathErr != MathError.NO_ERROR) {\\n return\\n failOpaque(\\n Error.MATH_ERROR,\\n FailureInfo\\n .ACCRUE_INTEREST_SIMPLE_INTEREST_FACTOR_CALCULATION_FAILED,\\n uint256(mathErr)\\n );\\n }\\n\\n (mathErr, interestAccumulated) = mulScalarTruncate(\\n simpleInterestFactor,\\n borrowsPrior\\n );\\n if (mathErr != MathError.NO_ERROR) {\\n return\\n failOpaque(\\n Error.MATH_ERROR,\\n FailureInfo\\n .ACCRUE_INTEREST_ACCUMULATED_INTEREST_CALCULATION_FAILED,\\n uint256(mathErr)\\n );\\n }\\n\\n (mathErr, totalBorrowsNew) = addUInt(interestAccumulated, borrowsPrior);\\n if (mathErr != MathError.NO_ERROR) {\\n return\\n failOpaque(\\n Error.MATH_ERROR,\\n FailureInfo\\n .ACCRUE_INTEREST_NEW_TOTAL_BORROWS_CALCULATION_FAILED,\\n uint256(mathErr)\\n );\\n }\\n\\n (mathErr, totalReservesNew) = mulScalarTruncateAddUInt(\\n Exp({mantissa: reserveFactorMantissa}),\\n interestAccumulated,\\n reservesPrior\\n );\\n if (mathErr != MathError.NO_ERROR) {\\n return\\n failOpaque(\\n Error.MATH_ERROR,\\n FailureInfo\\n .ACCRUE_INTEREST_NEW_TOTAL_RESERVES_CALCULATION_FAILED,\\n uint256(mathErr)\\n );\\n }\\n\\n if (interestRateModel.isTropykusInterestRateModel()) {\\n (mathErr, totalReservesNew) = newReserves(\\n borrowRateMantissa,\\n cashPrior,\\n borrowsPrior,\\n reservesPrior,\\n interestAccumulated\\n );\\n if (mathErr != MathError.NO_ERROR) {\\n return\\n failOpaque(\\n Error.MATH_ERROR,\\n FailureInfo\\n .ACCRUE_INTEREST_NEW_TOTAL_RESERVES_CALCULATION_FAILED,\\n uint256(mathErr)\\n );\\n }\\n }\\n\\n (mathErr, borrowIndexNew) = mulScalarTruncateAddUInt(\\n simpleInterestFactor,\\n borrowIndexPrior,\\n borrowIndexPrior\\n );\\n if (mathErr != MathError.NO_ERROR) {\\n return\\n failOpaque(\\n Error.MATH_ERROR,\\n FailureInfo\\n .ACCRUE_INTEREST_NEW_BORROW_INDEX_CALCULATION_FAILED,\\n uint256(mathErr)\\n );\\n }\\n\\n accrualBlockNumber = currentBlockNumber;\\n borrowIndex = borrowIndexNew;\\n totalBorrows = totalBorrowsNew;\\n totalReserves = totalReservesNew;\\n\\n emit AccrueInterest(\\n cashPrior,\\n interestAccumulated,\\n borrowIndexNew,\\n totalBorrowsNew\\n );\\n\\n return uint256(Error.NO_ERROR);\\n }\\n\\n function newReserves(\\n uint256 borrowRateMantissa,\\n uint256 cashPrior,\\n uint256 borrowsPrior,\\n uint256 reservesPrior,\\n uint256 interestAccumulated\\n ) internal view returns (MathError mathErr, uint256 totalReservesNew) {\\n uint256 newReserveFactorMantissa;\\n uint256 utilizationRate = interestRateModel.utilizationRate(\\n cashPrior,\\n borrowsPrior,\\n reservesPrior\\n );\\n uint256 expectedSupplyRate = interestRateModel.getSupplyRate(\\n cashPrior,\\n borrowsPrior,\\n reservesPrior,\\n reserveFactorMantissa\\n );\\n if (\\n interestRateModel.isAboveOptimal(\\n cashPrior,\\n borrowsPrior,\\n reservesPrior\\n )\\n ) {\\n (mathErr, newReserveFactorMantissa) = mulScalarTruncate(\\n Exp({mantissa: utilizationRate}),\\n borrowRateMantissa\\n );\\n if (mathErr != MathError.NO_ERROR) {\\n return (mathErr, 0);\\n }\\n (mathErr, newReserveFactorMantissa) = subUInt(\\n newReserveFactorMantissa,\\n expectedSupplyRate\\n );\\n if (mathErr != MathError.NO_ERROR) {\\n return (mathErr, 0);\\n }\\n (mathErr, totalReservesNew) = mulScalarTruncateAddUInt(\\n Exp({mantissa: newReserveFactorMantissa}),\\n interestAccumulated,\\n reservesPrior\\n );\\n if (mathErr != MathError.NO_ERROR) {\\n return (mathErr, 0);\\n }\\n } else {\\n mathErr = MathError.NO_ERROR;\\n totalReservesNew = reservesPrior;\\n }\\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(uint256 mintAmount)\\n internal\\n nonReentrant\\n returns (uint256, uint256)\\n {\\n if (WhitelistInterface(whitelist).enabled()) {\\n require(WhitelistInterface(whitelist).exist(msg.sender), \\\"CT26\\\");\\n }\\n uint256 error = accrueInterest();\\n if (error != uint256(Error.NO_ERROR)) {\\n return (\\n fail(Error(error), FailureInfo.MINT_ACCRUE_INTEREST_FAILED),\\n 0\\n );\\n }\\n return mintFresh(msg.sender, mintAmount);\\n }\\n\\n struct MintLocalVars {\\n Error err;\\n MathError mathErr;\\n uint256 exchangeRateMantissa;\\n uint256 mintTokens;\\n uint256 totalSupplyNew;\\n uint256 accountTokensNew;\\n uint256 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, uint256 mintAmount)\\n internal\\n returns (uint256, uint256)\\n {\\n uint256 allowed = comptroller.mintAllowed(\\n address(this),\\n minter,\\n mintAmount\\n );\\n if (allowed != 0) {\\n return (\\n failOpaque(\\n Error.COMPTROLLER_REJECTION,\\n FailureInfo.MINT_COMPTROLLER_REJECTION,\\n allowed\\n ),\\n 0\\n );\\n }\\n\\n if (accrualBlockNumber != getBlockNumber()) {\\n return (\\n fail(Error.MARKET_NOT_FRESH, FailureInfo.MINT_FRESHNESS_CHECK),\\n 0\\n );\\n }\\n\\n MintLocalVars memory vars;\\n\\n (\\n vars.mathErr,\\n vars.exchangeRateMantissa\\n ) = exchangeRateStoredInternal();\\n if (vars.mathErr != MathError.NO_ERROR) {\\n return (\\n failOpaque(\\n Error.MATH_ERROR,\\n FailureInfo.MINT_EXCHANGE_RATE_READ_FAILED,\\n uint256(vars.mathErr)\\n ),\\n 0\\n );\\n }\\n if (interestRateModel.isTropykusInterestRateModel()) {\\n SupplySnapshot storage supplySnapshot = accountTokens[minter];\\n (, uint256 newTotalSupply) = addUInt(\\n supplySnapshot.underlyingAmount,\\n mintAmount\\n );\\n require(newTotalSupply <= 0.1e18, \\\"CT24\\\");\\n }\\n vars.actualMintAmount = doTransferIn(minter, mintAmount);\\n\\n (vars.mathErr, vars.mintTokens) = divScalarByExpTruncate(\\n vars.actualMintAmount,\\n Exp({mantissa: vars.exchangeRateMantissa})\\n );\\n require(vars.mathErr == MathError.NO_ERROR, \\\"CT12\\\");\\n\\n (vars.mathErr, vars.totalSupplyNew) = addUInt(\\n totalSupply,\\n vars.mintTokens\\n );\\n require(vars.mathErr == MathError.NO_ERROR, \\\"CT13\\\");\\n\\n (vars.mathErr, vars.accountTokensNew) = addUInt(\\n accountTokens[minter].tokens,\\n vars.mintTokens\\n );\\n require(vars.mathErr == MathError.NO_ERROR, \\\"CT14\\\");\\n\\n uint256 currentSupplyRate = interestRateModel.getSupplyRate(\\n getCashPrior(),\\n totalBorrows,\\n totalReserves,\\n reserveFactorMantissa\\n );\\n\\n bool isTropykusInterestRateModel = interestRateModel\\n .isTropykusInterestRateModel();\\n\\n if (accountTokens[minter].tokens > 0) {\\n Exp memory updatedUnderlying;\\n if (isTropykusInterestRateModel) {\\n (, uint256 interestFactorMantissa, ) = tropykusInterestAccrued(\\n minter\\n );\\n Exp memory interestFactor = Exp({\\n mantissa: interestFactorMantissa\\n });\\n uint256 currentUnderlyingAmount = accountTokens[minter]\\n .underlyingAmount;\\n MathError mErrorNewAmount;\\n (mErrorNewAmount, updatedUnderlying) = mulExp(\\n Exp({mantissa: currentUnderlyingAmount}),\\n interestFactor\\n );\\n if (mErrorNewAmount != MathError.NO_ERROR) {\\n return (\\n failOpaque(\\n Error.MATH_ERROR,\\n FailureInfo.MINT_EXCHANGE_CALCULATION_FAILED,\\n uint256(mErrorNewAmount)\\n ),\\n 0\\n );\\n }\\n } else {\\n uint256 currentTokens = accountTokens[minter].tokens;\\n MathError mErrorUpdatedUnderlying;\\n (mErrorUpdatedUnderlying, updatedUnderlying) = mulExp(\\n Exp({mantissa: currentTokens}),\\n Exp({mantissa: vars.exchangeRateMantissa})\\n );\\n if (mErrorUpdatedUnderlying != MathError.NO_ERROR) {\\n return (\\n failOpaque(\\n Error.MATH_ERROR,\\n FailureInfo.MINT_EXCHANGE_CALCULATION_FAILED,\\n uint256(mErrorUpdatedUnderlying)\\n ),\\n 0\\n );\\n }\\n }\\n (, mintAmount) = addUInt(updatedUnderlying.mantissa, mintAmount);\\n }\\n\\n totalSupply = vars.totalSupplyNew;\\n accountTokens[minter] = SupplySnapshot({\\n tokens: vars.accountTokensNew,\\n underlyingAmount: mintAmount,\\n suppliedAt: accrualBlockNumber,\\n promisedSupplyRate: currentSupplyRate\\n });\\n\\n emit Mint(minter, vars.actualMintAmount, vars.mintTokens);\\n emit Transfer(address(this), minter, vars.mintTokens);\\n\\n return (uint256(Error.NO_ERROR), vars.actualMintAmount);\\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(uint256 redeemAmount)\\n internal\\n nonReentrant\\n returns (uint256)\\n {\\n uint256 error = accrueInterest();\\n if (error != uint256(Error.NO_ERROR)) {\\n return\\n fail(Error(error), FailureInfo.REDEEM_ACCRUE_INTEREST_FAILED);\\n }\\n return redeemFresh(payable(msg.sender), redeemAmount);\\n }\\n\\n struct RedeemLocalVars {\\n Error err;\\n MathError mathErr;\\n uint256 exchangeRateMantissa;\\n uint256 redeemTokens;\\n uint256 redeemAmount;\\n uint256 totalSupplyNew;\\n uint256 accountTokensNew;\\n uint256 newSubsidyFund;\\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 redeemAmountIn The number of underlying tokens to receive from redeeming cTokens\\n * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)\\n */\\n function redeemFresh(address payable redeemer, uint256 redeemAmountIn)\\n internal\\n returns (uint256)\\n {\\n require(redeemAmountIn > 0, \\\"CT15\\\");\\n\\n RedeemLocalVars memory vars;\\n\\n SupplySnapshot storage supplySnapshot = accountTokens[redeemer];\\n\\n (\\n vars.mathErr,\\n vars.exchangeRateMantissa\\n ) = exchangeRateStoredInternal();\\n if (vars.mathErr != MathError.NO_ERROR) {\\n return\\n failOpaque(\\n Error.MATH_ERROR,\\n FailureInfo.REDEEM_EXCHANGE_RATE_READ_FAILED,\\n uint256(vars.mathErr)\\n );\\n }\\n\\n uint256 interestEarned;\\n uint256 subsidyFundPortion;\\n uint256 currentUnderlying;\\n\\n bool isTropykusInterestRateModel = interestRateModel\\n .isTropykusInterestRateModel();\\n if (isTropykusInterestRateModel) {\\n currentUnderlying = supplySnapshot.underlyingAmount;\\n (, , interestEarned) = tropykusInterestAccrued(redeemer);\\n }\\n supplySnapshot.promisedSupplyRate = interestRateModel.getSupplyRate(\\n getCashPrior(),\\n totalBorrows,\\n totalReserves,\\n reserveFactorMantissa\\n );\\n\\n if (\\n isTropykusInterestRateModel &&\\n !interestRateModel.isAboveOptimal(\\n getCashPrior(),\\n totalBorrows,\\n totalReserves\\n )\\n ) {\\n uint256 borrowRate = interestRateModel.getBorrowRate(\\n getCashPrior(),\\n totalBorrows,\\n totalReserves\\n );\\n\\n uint256 utilizationRate = interestRateModel.utilizationRate(\\n getCashPrior(),\\n totalBorrows,\\n totalReserves\\n );\\n\\n (, uint256 estimatedEarning) = mulScalarTruncate(\\n Exp({mantissa: borrowRate}),\\n utilizationRate\\n );\\n\\n (, subsidyFundPortion) = subUInt(\\n supplySnapshot.promisedSupplyRate,\\n estimatedEarning\\n );\\n (, Exp memory subsidyFactor) = getExp(\\n subsidyFundPortion,\\n supplySnapshot.promisedSupplyRate\\n );\\n (, subsidyFundPortion) = mulScalarTruncate(\\n subsidyFactor,\\n interestEarned\\n );\\n }\\n\\n vars.redeemAmount = redeemAmountIn;\\n\\n if (isTropykusInterestRateModel) {\\n (, Exp memory num) = mulExp(\\n vars.redeemAmount,\\n supplySnapshot.tokens\\n );\\n (, Exp memory realTokensWithdrawAmount) = getExp(\\n num.mantissa,\\n currentUnderlying\\n );\\n vars.redeemTokens = realTokensWithdrawAmount.mantissa;\\n } else {\\n (vars.mathErr, vars.redeemTokens) = divScalarByExpTruncate(\\n redeemAmountIn,\\n Exp({mantissa: vars.exchangeRateMantissa})\\n );\\n if (vars.mathErr != MathError.NO_ERROR) {\\n return\\n failOpaque(\\n Error.MATH_ERROR,\\n FailureInfo.REDEEM_EXCHANGE_AMOUNT_CALCULATION_FAILED,\\n uint256(vars.mathErr)\\n );\\n }\\n }\\n // }\\n\\n uint256 allowed = comptroller.redeemAllowed(\\n address(this),\\n redeemer,\\n vars.redeemTokens\\n );\\n if (allowed != 0) {\\n return\\n failOpaque(\\n Error.COMPTROLLER_REJECTION,\\n FailureInfo.REDEEM_COMPTROLLER_REJECTION,\\n allowed\\n );\\n }\\n\\n if (accrualBlockNumber != getBlockNumber()) {\\n return\\n fail(\\n Error.MARKET_NOT_FRESH,\\n FailureInfo.REDEEM_FRESHNESS_CHECK\\n );\\n }\\n\\n (vars.mathErr, vars.totalSupplyNew) = subUInt(\\n totalSupply,\\n vars.redeemTokens\\n );\\n if (vars.mathErr != MathError.NO_ERROR) {\\n return\\n failOpaque(\\n Error.MATH_ERROR,\\n FailureInfo.REDEEM_NEW_TOTAL_SUPPLY_CALCULATION_FAILED,\\n uint256(vars.mathErr)\\n );\\n }\\n\\n (, vars.newSubsidyFund) = subUInt(subsidyFund, subsidyFundPortion);\\n\\n (vars.mathErr, vars.accountTokensNew) = subUInt(\\n supplySnapshot.tokens,\\n vars.redeemTokens\\n );\\n if (vars.mathErr != MathError.NO_ERROR) {\\n return\\n failOpaque(\\n Error.MATH_ERROR,\\n FailureInfo.REDEEM_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED,\\n uint256(vars.mathErr)\\n );\\n }\\n\\n uint256 cash = getCashPrior();\\n if (isTropykusInterestRateModel) {\\n cash = address(this).balance;\\n }\\n\\n if (cash < vars.redeemAmount) {\\n return\\n fail(\\n Error.TOKEN_INSUFFICIENT_CASH,\\n FailureInfo.REDEEM_TRANSFER_OUT_NOT_POSSIBLE\\n );\\n }\\n\\n doTransferOut(redeemer, vars.redeemAmount);\\n\\n totalSupply = vars.totalSupplyNew;\\n subsidyFund = vars.newSubsidyFund;\\n supplySnapshot.tokens = vars.accountTokensNew;\\n supplySnapshot.suppliedAt = accrualBlockNumber;\\n (, supplySnapshot.underlyingAmount) = subUInt(\\n supplySnapshot.underlyingAmount,\\n vars.redeemAmount\\n );\\n\\n emit Transfer(redeemer, address(this), vars.redeemTokens);\\n emit Redeem(redeemer, vars.redeemAmount, vars.redeemTokens);\\n\\n comptroller.redeemVerify(\\n address(this),\\n redeemer,\\n vars.redeemAmount,\\n vars.redeemTokens\\n );\\n\\n return uint256(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(uint256 borrowAmount)\\n internal\\n nonReentrant\\n returns (uint256)\\n {\\n uint256 error = accrueInterest();\\n if (error != uint256(Error.NO_ERROR)) {\\n return\\n fail(Error(error), FailureInfo.BORROW_ACCRUE_INTEREST_FAILED);\\n }\\n return borrowFresh(payable(msg.sender), borrowAmount);\\n }\\n\\n struct BorrowLocalVars {\\n MathError mathErr;\\n uint256 accountBorrows;\\n uint256 accountBorrowsNew;\\n uint256 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, uint256 borrowAmount)\\n internal\\n returns (uint256)\\n {\\n uint256 allowed = comptroller.borrowAllowed(\\n address(this),\\n borrower,\\n borrowAmount\\n );\\n if (allowed != 0) {\\n return\\n failOpaque(\\n Error.COMPTROLLER_REJECTION,\\n FailureInfo.BORROW_COMPTROLLER_REJECTION,\\n allowed\\n );\\n }\\n\\n if (accrualBlockNumber != getBlockNumber()) {\\n return\\n fail(\\n Error.MARKET_NOT_FRESH,\\n FailureInfo.BORROW_FRESHNESS_CHECK\\n );\\n }\\n\\n if (getCashPrior() < borrowAmount) {\\n return\\n fail(\\n Error.TOKEN_INSUFFICIENT_CASH,\\n FailureInfo.BORROW_CASH_NOT_AVAILABLE\\n );\\n }\\n\\n BorrowLocalVars memory vars;\\n\\n (vars.mathErr, vars.accountBorrows) = borrowBalanceStoredInternal(\\n borrower\\n );\\n if (vars.mathErr != MathError.NO_ERROR) {\\n return\\n failOpaque(\\n Error.MATH_ERROR,\\n FailureInfo.BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED,\\n uint256(vars.mathErr)\\n );\\n }\\n\\n (vars.mathErr, vars.accountBorrowsNew) = addUInt(\\n vars.accountBorrows,\\n borrowAmount\\n );\\n if (vars.mathErr != MathError.NO_ERROR) {\\n return\\n failOpaque(\\n Error.MATH_ERROR,\\n FailureInfo\\n .BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED,\\n uint256(vars.mathErr)\\n );\\n }\\n\\n (vars.mathErr, vars.totalBorrowsNew) = addUInt(\\n totalBorrows,\\n borrowAmount\\n );\\n if (interestRateModel.isTropykusInterestRateModel()) {\\n require(vars.totalBorrowsNew <= 0.1e18, \\\"CT25\\\");\\n }\\n if (vars.mathErr != MathError.NO_ERROR) {\\n return\\n failOpaque(\\n Error.MATH_ERROR,\\n FailureInfo.BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED,\\n uint256(vars.mathErr)\\n );\\n }\\n\\n doTransferOut(borrower, borrowAmount);\\n\\n accountBorrows[borrower].principal = vars.accountBorrowsNew;\\n accountBorrows[borrower].interestIndex = borrowIndex;\\n totalBorrows = vars.totalBorrowsNew;\\n\\n emit Borrow(\\n borrower,\\n borrowAmount,\\n vars.accountBorrowsNew,\\n vars.totalBorrowsNew\\n );\\n\\n return uint256(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(uint256 repayAmount)\\n internal\\n nonReentrant\\n returns (uint256, uint256)\\n {\\n uint256 error = accrueInterest();\\n if (error != uint256(Error.NO_ERROR)) {\\n return (\\n fail(\\n Error(error),\\n FailureInfo.REPAY_BORROW_ACCRUE_INTEREST_FAILED\\n ),\\n 0\\n );\\n }\\n return repayBorrowFresh(msg.sender, msg.sender, repayAmount);\\n }\\n\\n struct RepayBorrowLocalVars {\\n Error err;\\n MathError mathErr;\\n uint256 repayAmount;\\n uint256 borrowerIndex;\\n uint256 accountBorrows;\\n uint256 accountBorrowsNew;\\n uint256 totalBorrowsNew;\\n uint256 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(\\n address payer,\\n address borrower,\\n uint256 repayAmount\\n ) internal returns (uint256, uint256) {\\n uint256 allowed = comptroller.repayBorrowAllowed(\\n address(this),\\n payer,\\n borrower,\\n repayAmount\\n );\\n if (allowed != 0) {\\n return (\\n failOpaque(\\n Error.COMPTROLLER_REJECTION,\\n FailureInfo.REPAY_BORROW_COMPTROLLER_REJECTION,\\n allowed\\n ),\\n 0\\n );\\n }\\n\\n if (accrualBlockNumber != getBlockNumber()) {\\n return (\\n fail(\\n Error.MARKET_NOT_FRESH,\\n FailureInfo.REPAY_BORROW_FRESHNESS_CHECK\\n ),\\n 0\\n );\\n }\\n\\n RepayBorrowLocalVars memory vars;\\n\\n vars.borrowerIndex = accountBorrows[borrower].interestIndex;\\n\\n (vars.mathErr, vars.accountBorrows) = borrowBalanceStoredInternal(\\n borrower\\n );\\n if (vars.mathErr != MathError.NO_ERROR) {\\n return (\\n failOpaque(\\n Error.MATH_ERROR,\\n FailureInfo\\n .REPAY_BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED,\\n uint256(vars.mathErr)\\n ),\\n 0\\n );\\n }\\n\\n if (repayAmount == type(uint256).max) {\\n vars.repayAmount = vars.accountBorrows;\\n } else {\\n vars.repayAmount = repayAmount;\\n }\\n\\n vars.actualRepayAmount = doTransferIn(payer, vars.repayAmount);\\n\\n (vars.mathErr, vars.accountBorrowsNew) = subUInt(\\n vars.accountBorrows,\\n vars.actualRepayAmount\\n );\\n require(vars.mathErr == MathError.NO_ERROR, \\\"CT16\\\");\\n\\n (vars.mathErr, vars.totalBorrowsNew) = subUInt(\\n totalBorrows,\\n vars.actualRepayAmount\\n );\\n require(vars.mathErr == MathError.NO_ERROR, \\\"CT17\\\");\\n\\n accountBorrows[borrower].principal = vars.accountBorrowsNew;\\n accountBorrows[borrower].interestIndex = borrowIndex;\\n totalBorrows = vars.totalBorrowsNew;\\n\\n emit RepayBorrow(\\n payer,\\n borrower,\\n vars.actualRepayAmount,\\n vars.accountBorrowsNew,\\n vars.totalBorrowsNew\\n );\\n\\n return (uint256(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(\\n address borrower,\\n uint256 repayAmount,\\n CTokenInterface cTokenCollateral\\n ) internal nonReentrant returns (uint256, uint256) {\\n uint256 error = accrueInterest();\\n if (error != uint256(Error.NO_ERROR)) {\\n return (\\n fail(\\n Error(error),\\n FailureInfo.LIQUIDATE_ACCRUE_BORROW_INTEREST_FAILED\\n ),\\n 0\\n );\\n }\\n\\n error = cTokenCollateral.accrueInterest();\\n if (error != uint256(Error.NO_ERROR)) {\\n return (\\n fail(\\n Error(error),\\n FailureInfo.LIQUIDATE_ACCRUE_COLLATERAL_INTEREST_FAILED\\n ),\\n 0\\n );\\n }\\n\\n // liquidateBorrowFresh emits borrow-specific logs on errors, so we don't need to\\n return\\n liquidateBorrowFresh(\\n msg.sender,\\n borrower,\\n repayAmount,\\n cTokenCollateral\\n );\\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(\\n address liquidator,\\n address borrower,\\n uint256 repayAmount,\\n CTokenInterface cTokenCollateral\\n ) internal returns (uint256, uint256) {\\n uint256 allowed = comptroller.liquidateBorrowAllowed(\\n address(this),\\n address(cTokenCollateral),\\n liquidator,\\n borrower,\\n repayAmount\\n );\\n if (allowed != 0) {\\n return (\\n failOpaque(\\n Error.COMPTROLLER_REJECTION,\\n FailureInfo.LIQUIDATE_COMPTROLLER_REJECTION,\\n allowed\\n ),\\n 0\\n );\\n }\\n\\n if (accrualBlockNumber != getBlockNumber()) {\\n return (\\n fail(\\n Error.MARKET_NOT_FRESH,\\n FailureInfo.LIQUIDATE_FRESHNESS_CHECK\\n ),\\n 0\\n );\\n }\\n\\n if (cTokenCollateral.accrualBlockNumber() != getBlockNumber()) {\\n return (\\n fail(\\n Error.MARKET_NOT_FRESH,\\n FailureInfo.LIQUIDATE_COLLATERAL_FRESHNESS_CHECK\\n ),\\n 0\\n );\\n }\\n\\n if (borrower == liquidator) {\\n return (\\n fail(\\n Error.INVALID_ACCOUNT_PAIR,\\n FailureInfo.LIQUIDATE_LIQUIDATOR_IS_BORROWER\\n ),\\n 0\\n );\\n }\\n\\n if (repayAmount == 0) {\\n return (\\n fail(\\n Error.INVALID_CLOSE_AMOUNT_REQUESTED,\\n FailureInfo.LIQUIDATE_CLOSE_AMOUNT_IS_ZERO\\n ),\\n 0\\n );\\n }\\n\\n if (repayAmount == type(uint256).max) {\\n return (\\n fail(\\n Error.INVALID_CLOSE_AMOUNT_REQUESTED,\\n FailureInfo.LIQUIDATE_CLOSE_AMOUNT_IS_UINT_MAX\\n ),\\n 0\\n );\\n }\\n\\n (\\n uint256 repayBorrowError,\\n uint256 actualRepayAmount\\n ) = repayBorrowFresh(liquidator, borrower, repayAmount);\\n if (repayBorrowError != uint256(Error.NO_ERROR)) {\\n return (\\n fail(\\n Error(repayBorrowError),\\n FailureInfo.LIQUIDATE_REPAY_BORROW_FRESH_FAILED\\n ),\\n 0\\n );\\n }\\n\\n (uint256 amountSeizeError, uint256 seizeTokens) = comptroller\\n .liquidateCalculateSeizeTokens(\\n address(this),\\n address(cTokenCollateral),\\n actualRepayAmount\\n );\\n require(amountSeizeError == uint256(Error.NO_ERROR), \\\"CT18\\\");\\n\\n require(cTokenCollateral.balanceOf(borrower) >= seizeTokens, \\\"CT19\\\");\\n\\n uint256 seizeError;\\n if (address(cTokenCollateral) == address(this)) {\\n seizeError = seizeInternal(\\n address(this),\\n liquidator,\\n borrower,\\n seizeTokens\\n );\\n } else {\\n seizeError = cTokenCollateral.seize(\\n liquidator,\\n borrower,\\n seizeTokens\\n );\\n }\\n\\n require(seizeError == uint256(Error.NO_ERROR), \\\"CT20\\\");\\n\\n emit LiquidateBorrow(\\n liquidator,\\n borrower,\\n actualRepayAmount,\\n address(cTokenCollateral),\\n seizeTokens\\n );\\n\\n return (uint256(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(\\n address liquidator,\\n address borrower,\\n uint256 seizeTokens\\n ) external override nonReentrant returns (uint256) {\\n return seizeInternal(msg.sender, liquidator, borrower, seizeTokens);\\n }\\n\\n struct SeizeVars {\\n uint256 seizeAmount;\\n uint256 exchangeRate;\\n uint256 borrowerTokensNew;\\n uint256 borrowerAmountNew;\\n uint256 liquidatorTokensNew;\\n uint256 liquidatorAmountNew;\\n uint256 totalCash;\\n uint256 supplyRate;\\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(\\n address seizerToken,\\n address liquidator,\\n address borrower,\\n uint256 seizeTokens\\n ) internal returns (uint256) {\\n uint256 allowed = comptroller.seizeAllowed(\\n address(this),\\n seizerToken,\\n liquidator,\\n borrower,\\n seizeTokens\\n );\\n if (allowed != 0) {\\n return\\n failOpaque(\\n Error.COMPTROLLER_REJECTION,\\n FailureInfo.LIQUIDATE_SEIZE_COMPTROLLER_REJECTION,\\n allowed\\n );\\n }\\n\\n if (borrower == liquidator) {\\n return\\n fail(\\n Error.INVALID_ACCOUNT_PAIR,\\n FailureInfo.LIQUIDATE_SEIZE_LIQUIDATOR_IS_BORROWER\\n );\\n }\\n\\n SeizeVars memory seizeVars;\\n\\n MathError mathErr;\\n\\n (mathErr, seizeVars.borrowerTokensNew) = subUInt(\\n accountTokens[borrower].tokens,\\n seizeTokens\\n );\\n if (mathErr != MathError.NO_ERROR) {\\n return\\n failOpaque(\\n Error.MATH_ERROR,\\n FailureInfo.LIQUIDATE_SEIZE_BALANCE_DECREMENT_FAILED,\\n uint256(mathErr)\\n );\\n }\\n\\n seizeVars.totalCash = getCashPrior();\\n seizeVars.supplyRate = interestRateModel.getSupplyRate(\\n seizeVars.totalCash,\\n totalBorrows,\\n totalReserves,\\n reserveFactorMantissa\\n );\\n\\n (, seizeVars.exchangeRate) = interestRateModel.getExchangeRate(\\n seizeVars.totalCash,\\n totalBorrows,\\n totalReserves,\\n totalSupply\\n );\\n\\n if (interestRateModel.isTropykusInterestRateModel()) {\\n (, seizeVars.exchangeRate) = tropykusExchangeRateStoredInternal(\\n borrower\\n );\\n }\\n\\n (, seizeVars.seizeAmount) = mulUInt(\\n seizeTokens,\\n seizeVars.exchangeRate\\n );\\n (, seizeVars.seizeAmount) = divUInt(seizeVars.seizeAmount, 1e18);\\n\\n (, seizeVars.borrowerAmountNew) = subUInt(\\n accountTokens[borrower].underlyingAmount,\\n seizeVars.seizeAmount\\n );\\n\\n (mathErr, seizeVars.liquidatorTokensNew) = addUInt(\\n accountTokens[liquidator].tokens,\\n seizeTokens\\n );\\n if (mathErr != MathError.NO_ERROR) {\\n return\\n failOpaque(\\n Error.MATH_ERROR,\\n FailureInfo.LIQUIDATE_SEIZE_BALANCE_INCREMENT_FAILED,\\n uint256(mathErr)\\n );\\n }\\n\\n (, seizeVars.liquidatorAmountNew) = addUInt(\\n accountTokens[liquidator].underlyingAmount,\\n seizeVars.seizeAmount\\n );\\n\\n accountTokens[borrower].tokens = seizeVars.borrowerTokensNew;\\n accountTokens[borrower].underlyingAmount = seizeVars.borrowerAmountNew;\\n accountTokens[borrower].suppliedAt = getBlockNumber();\\n accountTokens[borrower].promisedSupplyRate = seizeVars.supplyRate;\\n\\n accountTokens[liquidator].tokens = seizeVars.liquidatorTokensNew;\\n accountTokens[liquidator].underlyingAmount = seizeVars\\n .liquidatorAmountNew;\\n accountTokens[liquidator].suppliedAt = getBlockNumber();\\n accountTokens[liquidator].promisedSupplyRate = seizeVars.supplyRate;\\n\\n emit Transfer(borrower, liquidator, seizeTokens);\\n\\n return uint256(Error.NO_ERROR);\\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 payable newPendingAdmin)\\n external\\n override\\n returns (uint256)\\n {\\n if (msg.sender != admin) {\\n return\\n fail(\\n Error.UNAUTHORIZED,\\n FailureInfo.SET_PENDING_ADMIN_OWNER_CHECK\\n );\\n }\\n\\n address oldPendingAdmin = pendingAdmin;\\n\\n pendingAdmin = newPendingAdmin;\\n\\n emit NewPendingAdmin(oldPendingAdmin, newPendingAdmin);\\n\\n return uint256(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 override returns (uint256) {\\n if (msg.sender != pendingAdmin || msg.sender == address(0)) {\\n return\\n fail(\\n Error.UNAUTHORIZED,\\n FailureInfo.ACCEPT_ADMIN_PENDING_ADMIN_CHECK\\n );\\n }\\n\\n address oldAdmin = admin;\\n address oldPendingAdmin = pendingAdmin;\\n\\n admin = pendingAdmin;\\n\\n pendingAdmin = payable(address(0));\\n\\n emit NewAdmin(oldAdmin, admin);\\n emit NewPendingAdmin(oldPendingAdmin, pendingAdmin);\\n\\n return uint256(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)\\n public\\n override\\n returns (uint256)\\n {\\n if (msg.sender != admin) {\\n return\\n fail(\\n Error.UNAUTHORIZED,\\n FailureInfo.SET_COMPTROLLER_OWNER_CHECK\\n );\\n }\\n\\n ComptrollerInterface oldComptroller = comptroller;\\n require(newComptroller.isComptroller(), \\\"CT21\\\");\\n\\n comptroller = newComptroller;\\n\\n emit NewComptroller(oldComptroller, newComptroller);\\n\\n return uint256(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(uint256 newReserveFactorMantissa)\\n external\\n override\\n nonReentrant\\n returns (uint256)\\n {\\n uint256 error = accrueInterest();\\n if (error != uint256(Error.NO_ERROR)) {\\n return\\n fail(\\n Error(error),\\n FailureInfo.SET_RESERVE_FACTOR_ACCRUE_INTEREST_FAILED\\n );\\n }\\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(uint256 newReserveFactorMantissa)\\n internal\\n returns (uint256)\\n {\\n if (msg.sender != admin) {\\n return\\n fail(\\n Error.UNAUTHORIZED,\\n FailureInfo.SET_RESERVE_FACTOR_ADMIN_CHECK\\n );\\n }\\n\\n if (accrualBlockNumber != getBlockNumber()) {\\n return\\n fail(\\n Error.MARKET_NOT_FRESH,\\n FailureInfo.SET_RESERVE_FACTOR_FRESH_CHECK\\n );\\n }\\n\\n if (newReserveFactorMantissa > reserveFactorMaxMantissa) {\\n return\\n fail(\\n Error.BAD_INPUT,\\n FailureInfo.SET_RESERVE_FACTOR_BOUNDS_CHECK\\n );\\n }\\n\\n uint256 oldReserveFactorMantissa = reserveFactorMantissa;\\n reserveFactorMantissa = newReserveFactorMantissa;\\n\\n emit NewReserveFactor(\\n oldReserveFactorMantissa,\\n newReserveFactorMantissa\\n );\\n\\n return uint256(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(uint256 addAmount)\\n internal\\n nonReentrant\\n returns (uint256)\\n {\\n uint256 error = accrueInterest();\\n if (error != uint256(Error.NO_ERROR)) {\\n return\\n fail(\\n Error(error),\\n FailureInfo.ADD_RESERVES_ACCRUE_INTEREST_FAILED\\n );\\n }\\n\\n uint256 totalReservesNew;\\n uint256 actualAddAmount;\\n\\n if (accrualBlockNumber != getBlockNumber()) {\\n return (\\n fail(\\n Error.MARKET_NOT_FRESH,\\n FailureInfo.ADD_RESERVES_FRESH_CHECK\\n )\\n );\\n }\\n\\n actualAddAmount = doTransferIn(msg.sender, addAmount);\\n\\n totalReservesNew = totalReserves + actualAddAmount;\\n\\n require(totalReservesNew >= totalReserves, \\\"CT22\\\");\\n\\n totalReserves = totalReservesNew;\\n\\n emit ReservesAdded(msg.sender, actualAddAmount, totalReservesNew);\\n\\n return (uint256(Error.NO_ERROR));\\n }\\n\\n function _addSubsidyInternal(uint256 addAmount)\\n internal\\n nonReentrant\\n returns (uint256)\\n {\\n uint256 error = accrueInterest();\\n if (error != uint256(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_SUBSIDY_FUND_FAILED);\\n }\\n\\n uint256 subsidyFundNew;\\n uint256 actualAddAmount;\\n\\n if (accrualBlockNumber != getBlockNumber()) {\\n return (\\n fail(\\n Error.MARKET_NOT_FRESH,\\n FailureInfo.ADD_SUBSIDY_FUND_FRESH_CHECK\\n )\\n );\\n }\\n\\n actualAddAmount = doTransferIn(msg.sender, addAmount);\\n\\n subsidyFundNew = subsidyFund + actualAddAmount;\\n\\n require(subsidyFundNew >= subsidyFund, \\\"CT22\\\");\\n\\n subsidyFund = subsidyFundNew;\\n\\n emit SubsidyAdded(msg.sender, actualAddAmount, subsidyFundNew);\\n\\n /* Return (NO_ERROR, actualAddAmount) */\\n return (uint256(Error.NO_ERROR));\\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(uint256 reduceAmount)\\n external\\n override\\n nonReentrant\\n returns (uint256)\\n {\\n uint256 error = accrueInterest();\\n if (error != uint256(Error.NO_ERROR)) {\\n return\\n fail(\\n Error(error),\\n FailureInfo.REDUCE_RESERVES_ACCRUE_INTEREST_FAILED\\n );\\n }\\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(uint256 reduceAmount)\\n internal\\n returns (uint256)\\n {\\n uint256 totalReservesNew;\\n\\n if (msg.sender != admin) {\\n return\\n fail(\\n Error.UNAUTHORIZED,\\n FailureInfo.REDUCE_RESERVES_ADMIN_CHECK\\n );\\n }\\n\\n if (accrualBlockNumber != getBlockNumber()) {\\n return\\n fail(\\n Error.MARKET_NOT_FRESH,\\n FailureInfo.REDUCE_RESERVES_FRESH_CHECK\\n );\\n }\\n\\n if (getCashPrior() < reduceAmount) {\\n return\\n fail(\\n Error.TOKEN_INSUFFICIENT_CASH,\\n FailureInfo.REDUCE_RESERVES_CASH_NOT_AVAILABLE\\n );\\n }\\n\\n if (reduceAmount > totalReserves) {\\n return\\n fail(Error.BAD_INPUT, FailureInfo.REDUCE_RESERVES_VALIDATION);\\n }\\n\\n totalReservesNew = totalReserves - reduceAmount;\\n require(totalReservesNew <= totalReserves, \\\"CT23\\\");\\n\\n totalReserves = totalReservesNew;\\n\\n doTransferOut(admin, reduceAmount);\\n\\n emit ReservesReduced(admin, reduceAmount, totalReservesNew);\\n\\n return uint256(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)\\n public\\n override\\n returns (uint256)\\n {\\n uint256 error = accrueInterest();\\n if (error != uint256(Error.NO_ERROR)) {\\n return\\n fail(\\n Error(error),\\n FailureInfo.SET_INTEREST_RATE_MODEL_ACCRUE_INTEREST_FAILED\\n );\\n }\\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)\\n internal\\n returns (uint256)\\n {\\n InterestRateModel oldInterestRateModel;\\n\\n if (msg.sender != admin) {\\n return\\n fail(\\n Error.UNAUTHORIZED,\\n FailureInfo.SET_INTEREST_RATE_MODEL_OWNER_CHECK\\n );\\n }\\n\\n if (accrualBlockNumber != getBlockNumber()) {\\n return\\n fail(\\n Error.MARKET_NOT_FRESH,\\n FailureInfo.SET_INTEREST_RATE_MODEL_FRESH_CHECK\\n );\\n }\\n\\n oldInterestRateModel = interestRateModel;\\n\\n require(newInterestRateModel.isInterestRateModel(), \\\"CT21\\\");\\n\\n interestRateModel = newInterestRateModel;\\n\\n emit NewMarketInterestRateModel(\\n oldInterestRateModel,\\n newInterestRateModel\\n );\\n\\n return uint256(Error.NO_ERROR);\\n }\\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 virtual returns (uint256);\\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, uint256 amount)\\n internal\\n virtual\\n returns (uint256);\\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, uint256 amount) internal virtual;\\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;\\n }\\n}\\n\",\"keccak256\":\"0x66c781aa1ccc507ce80a431b9ee06801bb81b954bd0697a1f656de400b5cb381\",\"license\":\"UNLICENSED\"},\"contracts/CTokenInterfaces.sol\":{\"content\":\"// SPDX-License-Identifier: UNLICENSED\\npragma solidity 0.8.6;\\n\\nimport \\\"./ComptrollerInterface.sol\\\";\\nimport \\\"./InterestRateModel.sol\\\";\\nimport \\\"./EIP20NonStandardInterface.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 uint256 internal constant borrowRateMaxMantissa = 0.0005e16;\\n\\n /**\\n * @notice Maximum fraction of interest that can be set aside for reserves\\n */\\n uint256 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 uint256 public initialExchangeRateMantissa;\\n\\n /**\\n * @notice Fraction of interest currently set aside for reserves\\n */\\n uint256 public reserveFactorMantissa;\\n\\n /**\\n * @notice Block number that interest was last accrued at\\n */\\n uint256 public accrualBlockNumber;\\n\\n /**\\n * @notice Accumulator of the total earned interest rate since the opening of the market\\n */\\n uint256 public borrowIndex;\\n\\n /**\\n * @notice Total amount of outstanding borrows of the underlying in this market\\n */\\n uint256 public totalBorrows;\\n\\n /**\\n * @notice Total amount of reserves of the underlying held in this market\\n */\\n uint256 public totalReserves;\\n\\n /**\\n * @notice Total number of tokens in circulation\\n */\\n uint256 public totalSupply;\\n\\n uint256 public subsidyFund;\\n\\n struct SupplySnapshot {\\n uint256 tokens;\\n uint256 underlyingAmount;\\n uint256 suppliedAt;\\n uint256 promisedSupplyRate;\\n }\\n\\n /**\\n * @notice Official record of token balances for each account\\n */\\n mapping(address => SupplySnapshot) internal accountTokens;\\n\\n /**\\n * @notice Approved token transfer amounts on behalf of others\\n */\\n mapping(address => mapping(address => uint256)) 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 uint256 principal;\\n uint256 interestIndex;\\n }\\n\\n /**\\n * @notice Mapping of account addresses to outstanding borrow balances\\n */\\n mapping(address => BorrowSnapshot) internal accountBorrows;\\n}\\n\\nabstract contract CTokenInterface is CTokenStorage {\\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 interest is accrued\\n */\\n event AccrueInterest(\\n uint256 cashPrior,\\n uint256 interestAccumulated,\\n uint256 borrowIndex,\\n uint256 totalBorrows\\n );\\n\\n /**\\n * @notice Event emitted when tokens are minted\\n */\\n event Mint(address indexed minter, uint256 mintAmount, uint256 mintTokens);\\n\\n /**\\n * @notice Event emitted when tokens are redeemed\\n */\\n event Redeem(\\n address indexed redeemer,\\n uint256 redeemAmount,\\n uint256 redeemTokens\\n );\\n\\n /**\\n * @notice Event emitted when underlying is borrowed\\n */\\n event Borrow(\\n address indexed borrower,\\n uint256 borrowAmount,\\n uint256 accountBorrows,\\n uint256 totalBorrows\\n );\\n\\n /**\\n * @notice Event emitted when a borrow is repaid\\n */\\n event RepayBorrow(\\n address indexed payer,\\n address indexed borrower,\\n uint256 repayAmount,\\n uint256 accountBorrows,\\n uint256 totalBorrows\\n );\\n\\n /**\\n * @notice Event emitted when a borrow is liquidated\\n */\\n event LiquidateBorrow(\\n address indexed liquidator,\\n address indexed borrower,\\n uint256 repayAmount,\\n address indexed cTokenCollateral,\\n uint256 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(\\n ComptrollerInterface oldComptroller,\\n ComptrollerInterface newComptroller\\n );\\n\\n /**\\n * @notice Event emitted when interestRateModel is changed\\n */\\n event NewMarketInterestRateModel(\\n InterestRateModel oldInterestRateModel,\\n InterestRateModel newInterestRateModel\\n );\\n\\n /**\\n * @notice Event emitted when the reserve factor is changed\\n */\\n event NewReserveFactor(\\n uint256 oldReserveFactorMantissa,\\n uint256 newReserveFactorMantissa\\n );\\n\\n /**\\n * @notice Event emitted when the reserves are added\\n */\\n event ReservesAdded(\\n address benefactor,\\n uint256 addAmount,\\n uint256 newTotalReserves\\n );\\n\\n event SubsidyAdded(\\n address benefactor,\\n uint256 addAmount,\\n uint256 newSubsidyFund\\n );\\n\\n /**\\n * @notice Event emitted when the reserves are reduced\\n */\\n event ReservesReduced(\\n address admin,\\n uint256 reduceAmount,\\n uint256 newTotalReserves\\n );\\n\\n /**\\n * @notice EIP20 Transfer event\\n */\\n event Transfer(address indexed from, address indexed to, uint256 amount);\\n\\n /**\\n * @notice EIP20 Approval event\\n */\\n event Approval(\\n address indexed owner,\\n address indexed spender,\\n uint256 amount\\n );\\n\\n /**\\n * @notice Failure event\\n */\\n event CTokenStorageFailure(uint256 error, uint256 info, uint256 detail);\\n\\n /*** User Interface ***/\\n\\n function transfer(address dst, uint256 amount)\\n external\\n virtual\\n returns (bool);\\n\\n function transferFrom(\\n address src,\\n address dst,\\n uint256 amount\\n ) external virtual returns (bool);\\n\\n function approve(address spender, uint256 amount)\\n external\\n virtual\\n returns (bool);\\n\\n function allowance(address owner, address spender)\\n external\\n view\\n virtual\\n returns (uint256);\\n\\n function balanceOf(address owner) external view virtual returns (uint256);\\n\\n function balanceOfUnderlying(address owner)\\n external\\n virtual\\n returns (uint256);\\n\\n function getAccountSnapshot(address account)\\n external\\n view\\n virtual\\n returns (\\n uint256,\\n uint256,\\n uint256,\\n uint256\\n );\\n\\n function borrowRatePerBlock() external view virtual returns (uint256);\\n\\n function supplyRatePerBlock() external view virtual returns (uint256);\\n\\n function totalBorrowsCurrent() external virtual returns (uint256);\\n\\n function borrowBalanceCurrent(address account)\\n external\\n virtual\\n returns (uint256);\\n\\n function borrowBalanceStored(address account)\\n public\\n view\\n virtual\\n returns (uint256);\\n\\n function exchangeRateCurrent() public virtual returns (uint256);\\n\\n function exchangeRateStored() public view virtual returns (uint256);\\n\\n function getCash() external view virtual returns (uint256);\\n\\n function accrueInterest() public virtual returns (uint256);\\n\\n function seize(\\n address liquidator,\\n address borrower,\\n uint256 seizeTokens\\n ) external virtual returns (uint256);\\n\\n /*** Admin Functions ***/\\n\\n function _setPendingAdmin(address payable newPendingAdmin)\\n external\\n virtual\\n returns (uint256);\\n\\n function _acceptAdmin() external virtual returns (uint256);\\n\\n function _setComptroller(ComptrollerInterface newComptroller)\\n public\\n virtual\\n returns (uint256);\\n\\n function _setReserveFactor(uint256 newReserveFactorMantissa)\\n external\\n virtual\\n returns (uint256);\\n\\n function _reduceReserves(uint256 reduceAmount)\\n external\\n virtual\\n returns (uint256);\\n\\n function _setInterestRateModel(InterestRateModel newInterestRateModel)\\n public\\n virtual\\n returns (uint256);\\n}\\n\\ncontract CErc20Storage {\\n /**\\n * @notice Underlying asset for this CToken\\n */\\n address public underlying;\\n}\\n\\nabstract contract CErc20Interface is CErc20Storage {\\n /*** User Interface ***/\\n\\n function mint(uint256 mintAmount) external virtual returns (uint256);\\n\\n function redeem(uint256 redeemAmount)\\n external\\n virtual\\n returns (uint256);\\n\\n function borrow(uint256 borrowAmount) external virtual returns (uint256);\\n\\n function repayBorrow(uint256 repayAmount)\\n external\\n virtual\\n returns (uint256);\\n\\n function liquidateBorrow(\\n address borrower,\\n uint256 repayAmount,\\n CTokenInterface cTokenCollateral\\n ) external virtual returns (uint256);\\n\\n function sweepToken(EIP20NonStandardInterface token) external virtual;\\n\\n /*** Admin Functions ***/\\n\\n function _addReserves(uint256 addAmount) external virtual returns (uint256);\\n}\\n\\ncontract CDelegationStorage {\\n /**\\n * @notice Implementation address for this contract\\n */\\n address public implementation;\\n}\\n\\nabstract contract CDelegatorInterface is CDelegationStorage {\\n /**\\n * @notice Emitted when implementation is changed\\n */\\n event NewImplementation(\\n address oldImplementation,\\n address newImplementation\\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(\\n address implementation_,\\n bool allowResign,\\n bytes memory becomeImplementationData\\n ) public virtual;\\n}\\n\\nabstract contract 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 virtual;\\n\\n /**\\n * @notice Called by the delegator on a delegate to forfeit its responsibility\\n */\\n function _resignImplementation() public virtual;\\n}\\n\",\"keccak256\":\"0xd0c347830afeac6c54eb7fbac35b60215d9acdd1fb2a3abb16df18923384fa42\",\"license\":\"UNLICENSED\"},\"contracts/CarefulMath.sol\":{\"content\":\"// SPDX-License-Identifier: UNLICENSED\\npragma solidity 0.8.6;\\n\\n/**\\n * @title Careful Math\\n * @author tropykus\\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}\\n\",\"keccak256\":\"0x2aa4360607bccc28c9bde237718c5fabc5e68a34befec92724d30bfbc0b9499f\",\"license\":\"UNLICENSED\"},\"contracts/ComptrollerInterface.sol\":{\"content\":\"// SPDX-License-Identifier: UNLICENSED\\npragma solidity 0.8.6;\\n\\nabstract contract 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)\\n external\\n virtual\\n returns (uint256[] memory);\\n\\n function exitMarket(address cToken) external virtual returns (uint256);\\n\\n /*** Policy Hooks ***/\\n\\n function mintAllowed(\\n address cToken,\\n address minter,\\n uint256 mintAmount\\n ) external virtual returns (uint256);\\n\\n function mintVerify(\\n address cToken,\\n address minter,\\n uint256 mintAmount,\\n uint256 mintTokens\\n ) external virtual;\\n\\n function redeemAllowed(\\n address cToken,\\n address redeemer,\\n uint256 redeemTokens\\n ) external virtual returns (uint256);\\n\\n function redeemVerify(\\n address cToken,\\n address redeemer,\\n uint256 redeemAmount,\\n uint256 redeemTokens\\n ) external virtual;\\n\\n function borrowAllowed(\\n address cToken,\\n address borrower,\\n uint256 borrowAmount\\n ) external virtual returns (uint256);\\n\\n function borrowVerify(\\n address cToken,\\n address borrower,\\n uint256 borrowAmount\\n ) external virtual;\\n\\n function repayBorrowAllowed(\\n address cToken,\\n address payer,\\n address borrower,\\n uint256 repayAmount\\n ) external virtual returns (uint256);\\n\\n function repayBorrowVerify(\\n address cToken,\\n address payer,\\n address borrower,\\n uint256 repayAmount,\\n uint256 borrowerIndex\\n ) external virtual;\\n\\n function liquidateBorrowAllowed(\\n address cTokenBorrowed,\\n address cTokenCollateral,\\n address liquidator,\\n address borrower,\\n uint256 repayAmount\\n ) external virtual returns (uint256);\\n\\n function liquidateBorrowVerify(\\n address cTokenBorrowed,\\n address cTokenCollateral,\\n address liquidator,\\n address borrower,\\n uint256 repayAmount,\\n uint256 seizeTokens\\n ) external virtual;\\n\\n function seizeAllowed(\\n address cTokenCollateral,\\n address cTokenBorrowed,\\n address liquidator,\\n address borrower,\\n uint256 seizeTokens\\n ) external virtual returns (uint256);\\n\\n function seizeVerify(\\n address cTokenCollateral,\\n address cTokenBorrowed,\\n address liquidator,\\n address borrower,\\n uint256 seizeTokens\\n ) external virtual;\\n\\n function transferAllowed(\\n address cToken,\\n address src,\\n address dst,\\n uint256 transferTokens\\n ) external virtual returns (uint256);\\n\\n function transferVerify(\\n address cToken,\\n address src,\\n address dst,\\n uint256 transferTokens\\n ) external virtual;\\n\\n /*** Liquidity/Liquidation Calculations ***/\\n\\n function liquidateCalculateSeizeTokens(\\n address cTokenBorrowed,\\n address cTokenCollateral,\\n uint256 repayAmount\\n ) external view virtual returns (uint256, uint256);\\n}\\n\",\"keccak256\":\"0x4f6874b6790450374231de9b8c33652d620ec9457835e78d36ceaa561875a1b9\",\"license\":\"UNLICENSED\"},\"contracts/ComptrollerStorage.sol\":{\"content\":\"// SPDX-License-Identifier: UNLICENSED\\npragma solidity 0.8.6;\\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 // @notice address of the TROP token\\n address public tropAddress;\\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\",\"keccak256\":\"0x579e076dd14c70e039340215821c701b068b6af25c0d6ee422946eb25b8630d1\",\"license\":\"UNLICENSED\"},\"contracts/EIP20Interface.sol\":{\"content\":\"// SPDX-License-Identifier: UNLICENSED\\npragma solidity 0.8.6;\\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\\n function symbol() external view returns (string memory);\\n\\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 balance 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 success Whether or not the transfer succeeded\\n */\\n function transfer(address dst, uint256 amount)\\n external\\n 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 success Whether or not the transfer succeeded\\n */\\n function transferFrom(\\n address src,\\n address dst,\\n uint256 amount\\n ) 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 success Whether or not the approval succeeded\\n */\\n function approve(address spender, uint256 amount)\\n external\\n 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 remaining The number of tokens allowed to be spent (-1 means infinite)\\n */\\n function allowance(address owner, address spender)\\n external\\n view\\n returns (uint256 remaining);\\n\\n event Transfer(address indexed from, address indexed to, uint256 amount);\\n event Approval(\\n address indexed owner,\\n address indexed spender,\\n uint256 amount\\n );\\n}\\n\",\"keccak256\":\"0xe445bee8cc89c468e8822aa0d39c8f4ee6b6ac059191365ecef889cd83b53a75\",\"license\":\"UNLICENSED\"},\"contracts/EIP20NonStandardInterface.sol\":{\"content\":\"// SPDX-License-Identifier: UNLICENSED\\npragma solidity 0.8.6;\\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 * @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 balance 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(\\n address src,\\n address dst,\\n uint256 amount\\n ) 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 success Whether or not the approval succeeded\\n */\\n function approve(address spender, uint256 amount)\\n external\\n 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 remaining The number of tokens allowed to be spent\\n */\\n function allowance(address owner, address spender)\\n external\\n view\\n returns (uint256 remaining);\\n\\n event Transfer(address indexed from, address indexed to, uint256 amount);\\n event Approval(\\n address indexed owner,\\n address indexed spender,\\n uint256 amount\\n );\\n}\\n\",\"keccak256\":\"0xab8b46aaf5f985d5e3e1f1aa3dbc2e30d69ae0760b3a6b0478f50b9fca3bbc39\",\"license\":\"UNLICENSED\"},\"contracts/ErrorReporter.sol\":{\"content\":\"// SPDX-License-Identifier: UNLICENSED\\npragma solidity 0.8.6;\\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(uint256 error, uint256 info, uint256 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 (uint256) {\\n emit Failure(uint256(err), uint256(info), 0);\\n\\n return uint256(err);\\n }\\n\\n /**\\n * @dev use this when reporting an opaque error from an upgradeable collaborator contract\\n */\\n function failOpaque(\\n Error err,\\n FailureInfo info,\\n uint256 opaqueError\\n ) internal returns (uint256) {\\n emit Failure(uint256(err), uint256(info), opaqueError);\\n\\n return uint256(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 ADD_SUBSIDY_FUND_FAILED,\\n ADD_SUBSIDY_FUND_FRESH_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 TokenFailure(uint256 error, uint256 info, uint256 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 (uint256) {\\n emit TokenFailure(uint256(err), uint256(info), 0);\\n\\n return uint256(err);\\n }\\n\\n /**\\n * @dev use this when reporting an opaque error from an upgradeable collaborator contract\\n */\\n function failOpaque(\\n Error err,\\n FailureInfo info,\\n uint256 opaqueError\\n ) internal returns (uint256) {\\n emit TokenFailure(uint256(err), uint256(info), opaqueError);\\n\\n return uint256(err);\\n }\\n}\\n\",\"keccak256\":\"0x097b23a9ddec2e563458dadd7e03fb1756514acb8a05eb924da76b470582ceb9\",\"license\":\"UNLICENSED\"},\"contracts/Exponential.sol\":{\"content\":\"// SPDX-License-Identifier: UNLICENSED\\npragma solidity 0.8.6;\\n\\nimport \\\"./CarefulMath.sol\\\";\\nimport \\\"./ExponentialNoError.sol\\\";\\n\\n/**\\n * @title Exponential module for storing fixed-precision decimals\\n * @author tropykus\\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) internal pure 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) internal pure 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) internal pure 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) internal pure 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) internal pure 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) internal pure 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) internal pure 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) internal pure 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) internal pure 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) internal pure 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) internal pure 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) internal pure 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) internal pure returns (MathError, Exp memory) {\\n return getExp(a.mantissa, b.mantissa);\\n }\\n}\\n\",\"keccak256\":\"0x4d59359e644bc1df4c60f967b00027aed07612c3471c7c1206d61e10ab705475\",\"license\":\"UNLICENSED\"},\"contracts/ExponentialNoError.sol\":{\"content\":\"// SPDX-License-Identifier: UNLICENSED\\npragma solidity 0.8.6;\\n\\n/**\\n * @title Exponential module for storing fixed-precision decimals\\n * @author tropykus\\n * @notice Exp is a struct which stores decimals with a fixed precision of 18 decimal places.\\n * Thus, if we wanted to store the 5.1, mantissa would store 5.1e18. That is:\\n * `Exp({mantissa: 5100000000000000000})`.\\n */\\ncontract ExponentialNoError {\\n uint constant expScale = 1e18;\\n uint constant doubleScale = 1e36;\\n uint constant halfExpScale = expScale/2;\\n uint constant mantissaOne = expScale;\\n\\n struct Exp {\\n uint mantissa;\\n }\\n\\n struct Double {\\n uint mantissa;\\n }\\n\\n /**\\n * @dev Truncates the given exp to a whole number value.\\n * For example, truncate(Exp{mantissa: 15 * expScale}) = 15\\n */\\n function truncate(Exp memory exp) pure internal returns (uint) {\\n // Note: We are not using careful math here as we're performing a division that cannot fail\\n return exp.mantissa / expScale;\\n }\\n\\n /**\\n * @dev Multiply an Exp by a scalar, then truncate to return an unsigned integer.\\n */\\n function mul_ScalarTruncate(Exp memory a, uint scalar) pure internal returns (uint) {\\n Exp memory product = mul_(a, scalar);\\n return truncate(product);\\n }\\n\\n /**\\n * @dev Multiply an Exp by a scalar, truncate, then add an to an unsigned integer, returning an unsigned integer.\\n */\\n function mul_ScalarTruncateAddUInt(Exp memory a, uint scalar, uint addend) pure internal returns (uint) {\\n Exp memory product = mul_(a, scalar);\\n return add_(truncate(product), addend);\\n }\\n\\n /**\\n * @dev Checks if first Exp is less than second Exp.\\n */\\n function lessThanExp(Exp memory left, Exp memory right) pure internal returns (bool) {\\n return left.mantissa < right.mantissa;\\n }\\n\\n /**\\n * @dev Checks if left Exp <= right Exp.\\n */\\n function lessThanOrEqualExp(Exp memory left, Exp memory right) pure internal returns (bool) {\\n return left.mantissa <= right.mantissa;\\n }\\n\\n /**\\n * @dev Checks if left Exp > right Exp.\\n */\\n function greaterThanExp(Exp memory left, Exp memory right) pure internal returns (bool) {\\n return left.mantissa > right.mantissa;\\n }\\n\\n /**\\n * @dev returns true if Exp is exactly zero\\n */\\n function isZeroExp(Exp memory value) pure internal returns (bool) {\\n return value.mantissa == 0;\\n }\\n\\n function safe224(uint n, string memory errorMessage) pure internal returns (uint224) {\\n require(n < 2**224, errorMessage);\\n return uint224(n);\\n }\\n\\n function safe32(uint n, string memory errorMessage) pure internal returns (uint32) {\\n require(n < 2**32, errorMessage);\\n return uint32(n);\\n }\\n\\n function add_(Exp memory a, Exp memory b) pure internal returns (Exp memory) {\\n return Exp({mantissa: add_(a.mantissa, b.mantissa)});\\n }\\n\\n function add_(Double memory a, Double memory b) pure internal returns (Double memory) {\\n return Double({mantissa: add_(a.mantissa, b.mantissa)});\\n }\\n\\n function add_(uint a, uint b) pure internal returns (uint) {\\n return add_(a, b, \\\"addition overflow\\\");\\n }\\n\\n function add_(uint a, uint b, string memory errorMessage) pure internal returns (uint) {\\n uint c = a + b;\\n require(c >= a, errorMessage);\\n return c;\\n }\\n\\n function sub_(Exp memory a, Exp memory b) pure internal returns (Exp memory) {\\n return Exp({mantissa: sub_(a.mantissa, b.mantissa)});\\n }\\n\\n function sub_(Double memory a, Double memory b) pure internal returns (Double memory) {\\n return Double({mantissa: sub_(a.mantissa, b.mantissa)});\\n }\\n\\n function sub_(uint a, uint b) pure internal returns (uint) {\\n return sub_(a, b, \\\"subtraction underflow\\\");\\n }\\n\\n function sub_(uint a, uint b, string memory errorMessage) pure internal returns (uint) {\\n require(b <= a, errorMessage);\\n return a - b;\\n }\\n\\n function mul_(Exp memory a, Exp memory b) pure internal returns (Exp memory) {\\n return Exp({mantissa: mul_(a.mantissa, b.mantissa) / expScale});\\n }\\n\\n function mul_(Exp memory a, uint b) pure internal returns (Exp memory) {\\n return Exp({mantissa: mul_(a.mantissa, b)});\\n }\\n\\n function mul_(uint a, Exp memory b) pure internal returns (uint) {\\n return mul_(a, b.mantissa) / expScale;\\n }\\n\\n function mul_(Double memory a, Double memory b) pure internal returns (Double memory) {\\n return Double({mantissa: mul_(a.mantissa, b.mantissa) / doubleScale});\\n }\\n\\n function mul_(Double memory a, uint b) pure internal returns (Double memory) {\\n return Double({mantissa: mul_(a.mantissa, b)});\\n }\\n\\n function mul_(uint a, Double memory b) pure internal returns (uint) {\\n return mul_(a, b.mantissa) / doubleScale;\\n }\\n\\n function mul_(uint a, uint b) pure internal returns (uint) {\\n return mul_(a, b, \\\"multiplication overflow\\\");\\n }\\n\\n function mul_(uint a, uint b, string memory errorMessage) pure internal returns (uint) {\\n if (a == 0 || b == 0) {\\n return 0;\\n }\\n uint c = a * b;\\n require(c / a == b, errorMessage);\\n return c;\\n }\\n\\n function div_(Exp memory a, Exp memory b) pure internal returns (Exp memory) {\\n return Exp({mantissa: div_(mul_(a.mantissa, expScale), b.mantissa)});\\n }\\n\\n function div_(Exp memory a, uint b) pure internal returns (Exp memory) {\\n return Exp({mantissa: div_(a.mantissa, b)});\\n }\\n\\n function div_(uint a, Exp memory b) pure internal returns (uint) {\\n return div_(mul_(a, expScale), b.mantissa);\\n }\\n\\n function div_(Double memory a, Double memory b) pure internal returns (Double memory) {\\n return Double({mantissa: div_(mul_(a.mantissa, doubleScale), b.mantissa)});\\n }\\n\\n function div_(Double memory a, uint b) pure internal returns (Double memory) {\\n return Double({mantissa: div_(a.mantissa, b)});\\n }\\n\\n function div_(uint a, Double memory b) pure internal returns (uint) {\\n return div_(mul_(a, doubleScale), b.mantissa);\\n }\\n\\n function div_(uint a, uint b) pure internal returns (uint) {\\n return div_(a, b, \\\"divide by zero\\\");\\n }\\n\\n function div_(uint a, uint b, string memory errorMessage) pure internal returns (uint) {\\n require(b > 0, errorMessage);\\n return a / b;\\n }\\n\\n function fraction(uint a, uint b) pure internal returns (Double memory) {\\n return Double({mantissa: div_(mul_(a, doubleScale), b)});\\n }\\n}\\n\",\"keccak256\":\"0x50ebd15fc98c12e065477f11230f5d7cd583b5fe25a3c532cb90e75950667795\",\"license\":\"UNLICENSED\"},\"contracts/InterestRateModel.sol\":{\"content\":\"// SPDX-License-Identifier: UNLICENSED\\npragma solidity 0.8.6;\\n\\nimport \\\"./Exponential.sol\\\";\\nimport \\\"./SafeMath.sol\\\";\\n\\n/**\\n * @title tropykus InterestRateModel Interface\\n * @author tropykus\\n */\\nabstract contract InterestRateModel is Exponential {\\n using SafeMath for uint256;\\n\\n /// @notice Indicator that this is an InterestRateModel contract (for inspection)\\n bool public constant isInterestRateModel = true;\\n bool public isTropykusInterestRateModel;\\n\\n /**\\n * @notice The approximate number of blocks per year that is assumed by the interest rate model\\n */\\n uint256 public constant blocksPerYear = 1051200;\\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(\\n uint256 cash,\\n uint256 borrows,\\n uint256 reserves\\n ) public pure virtual returns (uint256) {\\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 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 amnount of reserves the market has\\n * @return The borrow rate per block (as a percentage, and scaled by 1e18)\\n */\\n function getBorrowRate(\\n uint256 cash,\\n uint256 borrows,\\n uint256 reserves\\n ) external view virtual returns (uint256);\\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 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(\\n uint256 cash,\\n uint256 borrows,\\n uint256 reserves,\\n uint256 reserveFactorMantissa\\n ) external view virtual returns (uint256);\\n\\n function getExchangeRate(\\n uint256 _totalCash,\\n uint256 _totalBorrows,\\n uint256 _totalReserves,\\n uint256 _totalSupply\\n ) public pure returns (MathError, uint256) {\\n /*\\n * exchangeRate = (totalCash + totalBorrows - totalReserves) / totalSupply\\n */\\n Exp memory exchangeRate;\\n MathError mathErr;\\n uint256 cashPlusBorrowsMinusReserves;\\n (mathErr, cashPlusBorrowsMinusReserves) = addThenSubUInt(\\n _totalCash,\\n _totalBorrows,\\n _totalReserves\\n );\\n if (mathErr != MathError.NO_ERROR) {\\n return (mathErr, 0);\\n }\\n (mathErr, exchangeRate) = getExp(\\n cashPlusBorrowsMinusReserves,\\n _totalSupply\\n );\\n if (mathErr != MathError.NO_ERROR) {\\n return (mathErr, 0);\\n }\\n\\n return (MathError.NO_ERROR, exchangeRate.mantissa);\\n }\\n\\n function isAboveOptimal(\\n uint256 cash,\\n uint256 borrows,\\n uint256 reserves\\n ) public view virtual returns (bool) {\\n cash;\\n borrows;\\n reserves;\\n return false;\\n }\\n}\\n\",\"keccak256\":\"0x2cdc1a63482287513664d98d778c718c336461272885f61585c6ba404feb2edc\",\"license\":\"UNLICENSED\"},\"contracts/PriceOracle.sol\":{\"content\":\"// SPDX-License-Identifier: UNLICENSED\\npragma solidity 0.8.6;\\n\\nimport \\\"./CToken.sol\\\";\\n\\nabstract contract 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)\\n external\\n view\\n virtual\\n returns (uint256);\\n}\\n\",\"keccak256\":\"0x74e7a498f96d6fdab6dec52d7501bba644df3f498c6233247dd2db9687e839d8\",\"license\":\"UNLICENSED\"},\"contracts/SafeMath.sol\":{\"content\":\"// SPDX-License-Identifier: UNLICENSED\\npragma solidity 0.8.6;\\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\":\"0xe578b9602160e7ddbb5e7b6d355bb4508fa134684afe46e4043602c652e0e041\",\"license\":\"UNLICENSED\"},\"contracts/Unitroller.sol\":{\"content\":\"// SPDX-License-Identifier: UNLICENSED\\npragma solidity 0.8.6;\\n\\nimport \\\"./ErrorReporter.sol\\\";\\nimport \\\"./ComptrollerStorage.sol\\\";\\n\\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 * @notice Emitted when pendingComptrollerImplementation is changed\\n */\\n event NewPendingImplementation(\\n address oldPendingImplementation,\\n address newPendingImplementation\\n );\\n\\n /**\\n * @notice Emitted when pendingComptrollerImplementation is accepted, which means comptroller implementation is updated\\n */\\n event NewImplementation(\\n address oldImplementation,\\n address newImplementation\\n );\\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() {\\n // Set admin to caller\\n admin = msg.sender;\\n }\\n\\n /*** Admin Functions ***/\\n function _setPendingImplementation(address newPendingImplementation)\\n public\\n returns (uint256)\\n {\\n if (msg.sender != admin) {\\n return\\n fail(\\n Error.UNAUTHORIZED,\\n FailureInfo.SET_PENDING_IMPLEMENTATION_OWNER_CHECK\\n );\\n }\\n\\n address oldPendingImplementation = pendingComptrollerImplementation;\\n\\n pendingComptrollerImplementation = newPendingImplementation;\\n\\n emit NewPendingImplementation(\\n oldPendingImplementation,\\n pendingComptrollerImplementation\\n );\\n\\n return uint256(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 (uint256) {\\n // Check caller is pendingImplementation and pendingImplementation \\u2260 address(0)\\n if (\\n msg.sender != pendingComptrollerImplementation ||\\n pendingComptrollerImplementation == address(0)\\n ) {\\n return\\n fail(\\n Error.UNAUTHORIZED,\\n FailureInfo.ACCEPT_PENDING_IMPLEMENTATION_ADDRESS_CHECK\\n );\\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(\\n oldPendingImplementation,\\n pendingComptrollerImplementation\\n );\\n\\n return uint256(Error.NO_ERROR);\\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)\\n public\\n returns (uint256)\\n {\\n // Check caller = admin\\n if (msg.sender != admin) {\\n return\\n fail(\\n Error.UNAUTHORIZED,\\n FailureInfo.SET_PENDING_ADMIN_OWNER_CHECK\\n );\\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 uint256(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 (uint256) {\\n // Check caller is pendingAdmin and pendingAdmin \\u2260 address(0)\\n if (msg.sender != pendingAdmin || msg.sender == address(0)) {\\n return\\n fail(\\n Error.UNAUTHORIZED,\\n FailureInfo.ACCEPT_ADMIN_PENDING_ADMIN_CHECK\\n );\\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 uint256(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 internalFallback() public payable {\\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 {\\n revert(free_mem_ptr, returndatasize())\\n }\\n default {\\n return(free_mem_ptr, returndatasize())\\n }\\n }\\n }\\n\\n fallback() external payable {\\n internalFallback();\\n }\\n\\n receive() external payable {\\n internalFallback();\\n }\\n}\\n\",\"keccak256\":\"0xb0335909825db0ff6752eb42eda15855c00b91ecc28a7c7a45af9658239cad43\",\"license\":\"UNLICENSED\"},\"contracts/WhitelistInterface.sol\":{\"content\":\"// SPDX-License-Identifier: UNLICENSED\\npragma solidity 0.8.6;\\n\\ninterface WhitelistInterface {\\n function setStatus(bool _newStatus) external;\\n function enabled() external view returns(bool);\\n\\n function addUsers(address[] memory _users) external;\\n function exist(address _user) external view returns(bool);\\n function getUsers() external view returns(address[] memory currentUsers);\\n function removeUser(address _user) external;\\n}\",\"keccak256\":\"0xb00f782772179693611aefb08d51640de313bc901d6d9d78d1e1b86922e99130\",\"license\":\"UNLICENSED\"}},\"version\":1}", - "bytecode": "0x608060405234801561001057600080fd5b50600080546001600160a01b03191633179055610605806100326000396000f3fe60806040526004361061008a5760003560e01c8063c1e8033411610059578063c1e803341461012c578063dcfbc0c714610141578063e992a04114610161578063e9c714f214610181578063f851a4401461019657610099565b806326782247146100a157806381c9772c14610099578063b71d1a0c146100de578063bb82aa5e1461010c57610099565b36610099576100976101b6565b005b6100976101b6565b3480156100ad57600080fd5b506001546100c1906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b3480156100ea57600080fd5b506100fe6100f9366004610580565b610231565b6040519081526020016100d5565b34801561011857600080fd5b506002546100c1906001600160a01b031681565b34801561013857600080fd5b506100fe6102be565b34801561014d57600080fd5b506003546100c1906001600160a01b031681565b34801561016d57600080fd5b506100fe61017c366004610580565b6103b4565b34801561018d57600080fd5b506100fe61042d565b3480156101a257600080fd5b506000546100c1906001600160a01b031681565b6002546040516000916001600160a01b0316906101d690839036906105a9565b600060405180830381855af49150503d8060008114610211576040519150601f19603f3d011682016040523d82523d6000602084013e610216565b606091505b505090506040513d6000823e81801561022d573d82f35b3d82fd5b600080546001600160a01b03163314610256576102506001600e610507565b92915050565b600180546001600160a01b038481166001600160a01b031983168117909355604080519190921680825260208201939093527fca4f2f25d0898edd99413412fb94012f9e54ec8142f9b093e7720646a95b16a991015b60405180910390a160005b9392505050565b6003546000906001600160a01b0316331415806102e457506003546001600160a01b0316155b156102f9576102f4600180610507565b905090565b60028054600380546001600160a01b038082166001600160a01b031980861682179096559490911690915560408051919092168082526020820184905292917fd604de94d45953f9138079ec1b82d533cb2160c906d1076d1f7ed54befbca97a910160405180910390a1600354604080516001600160a01b03808516825290921660208301527fe945ccee5d701fc83f9b8aa8ca94ea4219ec1fcbd4f4cab4f0ea57c5c3e1d81591015b60405180910390a160009250505090565b600080546001600160a01b031633146103d3576102506001600f610507565b600380546001600160a01b038481166001600160a01b031983168117909355604080519190921680825260208201939093527fe945ccee5d701fc83f9b8aa8ca94ea4219ec1fcbd4f4cab4f0ea57c5c3e1d81591016102ac565b6001546000906001600160a01b031633141580610448575033155b15610459576102f460016000610507565b60008054600180546001600160a01b038082166001600160a01b031980861682179096559490911690915560408051919092168082526020820184905292917ff9ffabca9c8276e99321725bcb43fb076a6c66a54b7f21c4e8146d8519b417dc910160405180910390a1600154604080516001600160a01b03808516825290921660208301527fca4f2f25d0898edd99413412fb94012f9e54ec8142f9b093e7720646a95b16a991016103a3565b60007f45b96fe442630264581b197e84bbada861235052c5a1aadfff9ea4e40a969aa083601181111561053c5761053c6105b9565b83601381111561054e5761054e6105b9565b60408051928352602083019190915260009082015260600160405180910390a18260118111156102b7576102b76105b9565b60006020828403121561059257600080fd5b81356001600160a01b03811681146102b757600080fd5b8183823760009101908152919050565b634e487b7160e01b600052602160045260246000fdfea264697066735822122022ff8cfcd40fe993cc6c33a99b7a272aed01a49340829c8412391999a0e5d58064736f6c63430008060033", - "deployedBytecode": "0x60806040526004361061008a5760003560e01c8063c1e8033411610059578063c1e803341461012c578063dcfbc0c714610141578063e992a04114610161578063e9c714f214610181578063f851a4401461019657610099565b806326782247146100a157806381c9772c14610099578063b71d1a0c146100de578063bb82aa5e1461010c57610099565b36610099576100976101b6565b005b6100976101b6565b3480156100ad57600080fd5b506001546100c1906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b3480156100ea57600080fd5b506100fe6100f9366004610580565b610231565b6040519081526020016100d5565b34801561011857600080fd5b506002546100c1906001600160a01b031681565b34801561013857600080fd5b506100fe6102be565b34801561014d57600080fd5b506003546100c1906001600160a01b031681565b34801561016d57600080fd5b506100fe61017c366004610580565b6103b4565b34801561018d57600080fd5b506100fe61042d565b3480156101a257600080fd5b506000546100c1906001600160a01b031681565b6002546040516000916001600160a01b0316906101d690839036906105a9565b600060405180830381855af49150503d8060008114610211576040519150601f19603f3d011682016040523d82523d6000602084013e610216565b606091505b505090506040513d6000823e81801561022d573d82f35b3d82fd5b600080546001600160a01b03163314610256576102506001600e610507565b92915050565b600180546001600160a01b038481166001600160a01b031983168117909355604080519190921680825260208201939093527fca4f2f25d0898edd99413412fb94012f9e54ec8142f9b093e7720646a95b16a991015b60405180910390a160005b9392505050565b6003546000906001600160a01b0316331415806102e457506003546001600160a01b0316155b156102f9576102f4600180610507565b905090565b60028054600380546001600160a01b038082166001600160a01b031980861682179096559490911690915560408051919092168082526020820184905292917fd604de94d45953f9138079ec1b82d533cb2160c906d1076d1f7ed54befbca97a910160405180910390a1600354604080516001600160a01b03808516825290921660208301527fe945ccee5d701fc83f9b8aa8ca94ea4219ec1fcbd4f4cab4f0ea57c5c3e1d81591015b60405180910390a160009250505090565b600080546001600160a01b031633146103d3576102506001600f610507565b600380546001600160a01b038481166001600160a01b031983168117909355604080519190921680825260208201939093527fe945ccee5d701fc83f9b8aa8ca94ea4219ec1fcbd4f4cab4f0ea57c5c3e1d81591016102ac565b6001546000906001600160a01b031633141580610448575033155b15610459576102f460016000610507565b60008054600180546001600160a01b038082166001600160a01b031980861682179096559490911690915560408051919092168082526020820184905292917ff9ffabca9c8276e99321725bcb43fb076a6c66a54b7f21c4e8146d8519b417dc910160405180910390a1600154604080516001600160a01b03808516825290921660208301527fca4f2f25d0898edd99413412fb94012f9e54ec8142f9b093e7720646a95b16a991016103a3565b60007f45b96fe442630264581b197e84bbada861235052c5a1aadfff9ea4e40a969aa083601181111561053c5761053c6105b9565b83601381111561054e5761054e6105b9565b60408051928352602083019190915260009082015260600160405180910390a18260118111156102b7576102b76105b9565b60006020828403121561059257600080fd5b81356001600160a01b03811681146102b757600080fd5b8183823760009101908152919050565b634e487b7160e01b600052602160045260246000fdfea264697066735822122022ff8cfcd40fe993cc6c33a99b7a272aed01a49340829c8412391999a0e5d58064736f6c63430008060033", - "devdoc": { - "details": "Storage for the comptroller is at this address, while execution is delegated to the `comptrollerImplementation`. CTokens should reference this contract as their comptroller.", - "kind": "dev", - "methods": { - "_acceptAdmin()": { - "details": "Admin function for pending admin to accept role and update admin", - "returns": { - "_0": "uint 0=success, otherwise a failure (see ErrorReporter.sol for details)" - } - }, - "_acceptImplementation()": { - "details": "Admin function for new implementation to accept it's role as implementation", - "returns": { - "_0": "uint 0=success, otherwise a failure (see ErrorReporter.sol for details)" - } - }, - "_setPendingAdmin(address)": { - "details": "Admin function to begin change of admin. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer.", - "params": { - "newPendingAdmin": "New pending admin." - }, - "returns": { - "_0": "uint 0=success, otherwise a failure (see ErrorReporter.sol for details)" - } - }, - "internalFallback()": { - "details": "Delegates execution to an implementation contract. It returns to the external caller whatever the implementation returns or forwards reverts." - } - }, - "title": "ComptrollerCore", - "version": 1 - }, - "userdoc": { - "events": { - "NewAdmin(address,address)": { - "notice": "Emitted when pendingAdmin is accepted, which means admin is updated" - }, - "NewImplementation(address,address)": { - "notice": "Emitted when pendingComptrollerImplementation is accepted, which means comptroller implementation is updated" - }, - "NewPendingAdmin(address,address)": { - "notice": "Emitted when pendingAdmin is changed" - }, - "NewPendingImplementation(address,address)": { - "notice": "Emitted when pendingComptrollerImplementation is changed" - } - }, - "kind": "user", - "methods": { - "_acceptAdmin()": { - "notice": "Accepts transfer of admin rights. msg.sender must be pendingAdmin" - }, - "_acceptImplementation()": { - "notice": "Accepts new implementation of comptroller. msg.sender must be pendingImplementation" - }, - "_setPendingAdmin(address)": { - "notice": "Begins transfer of admin rights. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer." - }, - "admin()": { - "notice": "Administrator for this contract" - }, - "comptrollerImplementation()": { - "notice": "Active brains of Unitroller" - }, - "pendingAdmin()": { - "notice": "Pending administrator for this contract" - }, - "pendingComptrollerImplementation()": { - "notice": "Pending brains of Unitroller" - } - }, - "version": 1 - }, - "storageLayout": { - "storage": [ - { - "astId": 32943, - "contract": "contracts/Unitroller.sol:Unitroller", - "label": "admin", - "offset": 0, - "slot": "0", - "type": "t_address" - }, - { - "astId": 32946, - "contract": "contracts/Unitroller.sol:Unitroller", - "label": "pendingAdmin", - "offset": 0, - "slot": "1", - "type": "t_address" - }, - { - "astId": 32949, - "contract": "contracts/Unitroller.sol:Unitroller", - "label": "comptrollerImplementation", - "offset": 0, - "slot": "2", - "type": "t_address" - }, - { - "astId": 32952, - "contract": "contracts/Unitroller.sol:Unitroller", - "label": "pendingComptrollerImplementation", - "offset": 0, - "slot": "3", - "type": "t_address" - } - ], - "types": { - "t_address": { - "encoding": "inplace", - "label": "address", - "numberOfBytes": "20" - } - } - } -} \ No newline at end of file diff --git a/deployments/localhost/UsdtPriceOracleAdapterMoc.json b/deployments/localhost/UsdtPriceOracleAdapterMoc.json deleted file mode 100644 index 20b29b7..0000000 --- a/deployments/localhost/UsdtPriceOracleAdapterMoc.json +++ /dev/null @@ -1,245 +0,0 @@ -{ - "address": "0x82e01223d51Eb87e16A03E24687EDF0F294da6f1", - "abi": [ - { - "inputs": [ - { - "internalType": "address", - "name": "guardian_", - "type": "address" - }, - { - "internalType": "address", - "name": "priceProvider", - "type": "address" - } - ], - "stateMutability": "nonpayable", - "type": "constructor" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "oldGuardian", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "newGuardian", - "type": "address" - } - ], - "name": "NewGuardian", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "oldAddress", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "newAddress", - "type": "address" - } - ], - "name": "PriceOracleAdapterUpdated", - "type": "event" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "name": "assetPrices", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "guardian", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "priceProviderMoC", - "outputs": [ - { - "internalType": "contract PriceProviderMoC", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newGuardian", - "type": "address" - } - ], - "name": "setGuardian", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "priceProviderAddress", - "type": "address" - } - ], - "name": "setPriceProvider", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - } - ], - "transactionHash": "0x5f0dccaf3a7301bdf58a997224f92e8dbb43d9a4420a1278dee98ea483798f15", - "receipt": { - "to": null, - "from": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", - "contractAddress": "0x82e01223d51Eb87e16A03E24687EDF0F294da6f1", - "transactionIndex": 0, - "gasUsed": "378544", - "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "blockHash": "0x294fc5c9303a7ffa693f0472d4f385ecd93b6530727e631797e906c6e588d534", - "transactionHash": "0x5f0dccaf3a7301bdf58a997224f92e8dbb43d9a4420a1278dee98ea483798f15", - "logs": [], - "blockNumber": 55, - "cumulativeGasUsed": "378544", - "status": 1, - "byzantium": true - }, - "args": [ - "0x09635F643e140090A9A8Dcd712eD6285858ceBef", - "0x67d269191c92Caf3cD7723F116c85e6E9bf55933" - ], - "solcInputHash": "3f2295c0e5923ce11cb0f26c6e52bee2", - "metadata": "{\"compiler\":{\"version\":\"0.8.6+commit.11564f7e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"guardian_\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"priceProvider\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"oldGuardian\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"newGuardian\",\"type\":\"address\"}],\"name\":\"NewGuardian\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"oldAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"newAddress\",\"type\":\"address\"}],\"name\":\"PriceOracleAdapterUpdated\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"assetPrices\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"guardian\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"priceProviderMoC\",\"outputs\":[{\"internalType\":\"contract PriceProviderMoC\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newGuardian\",\"type\":\"address\"}],\"name\":\"setGuardian\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"priceProviderAddress\",\"type\":\"address\"}],\"name\":\"setPriceProvider\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"assetPrices(address)\":{\"returns\":{\"_0\":\"The price\"}},\"constructor\":{\"params\":{\"guardian_\":\"address of guardian that is allowed to manage this contract\",\"priceProvider\":\"address of asset's MoC price provider\"}},\"setGuardian(address)\":{\"params\":{\"newGuardian\":\"address of the guardian\"}},\"setPriceProvider(address)\":{\"params\":{\"priceProviderAddress\":\"address of price provider\"}}},\"version\":1},\"userdoc\":{\"events\":{\"NewGuardian(address,address)\":{\"notice\":\"Guardian updated\"},\"PriceOracleAdapterUpdated(address,address)\":{\"notice\":\"Event adapter interface updated\"}},\"kind\":\"user\",\"methods\":{\"assetPrices(address)\":{\"notice\":\"Get the price from MoC and divide it by the rBTC price\"},\"constructor\":{\"notice\":\"Construct a PriceOracleAdapter for a MoC oracle\"},\"guardian()\":{\"notice\":\"Address of the guardian\"},\"priceProviderMoC()\":{\"notice\":\"The MoC price oracle, which will continue to serve prices\"},\"setGuardian(address)\":{\"notice\":\"Set the address of the guardian\"},\"setPriceProvider(address)\":{\"notice\":\"Set the address of price provider\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/PriceOracleAdapterMoc.sol\":\"PriceOracleAdapterMoc\"},\"evmVersion\":\"berlin\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"contracts/PriceOracleAdapter.sol\":{\"content\":\"// SPDX-License-Identifier: UNLICENSED\\npragma solidity 0.8.6;\\n\\nabstract contract PriceOracleAdapter {\\n /// @notice Event adapter interface updated\\n event PriceOracleAdapterUpdated(address oldAddress, address newAddress);\\n\\n /**\\n * @notice Get the price\\n * @return The underlying asset price mantissa (scaled by 1e18).\\n * Zero means the price is unavailable.\\n */\\n function assetPrices(address cTokenAddress)\\n external\\n view\\n virtual\\n returns (uint256);\\n}\\n\",\"keccak256\":\"0xce2a8f27186d355a24a4402469afe76e4522e97ad9a1a8388defd85fa4c054ec\",\"license\":\"UNLICENSED\"},\"contracts/PriceOracleAdapterMoc.sol\":{\"content\":\"// SPDX-License-Identifier: UNLICENSED\\npragma solidity 0.8.6;\\n\\nimport \\\"./PriceOracleAdapter.sol\\\";\\n\\ninterface PriceProviderMoC {\\n function peek() external view returns (bytes32, bool);\\n}\\n\\ncontract PriceOracleAdapterMoc is PriceOracleAdapter {\\n /// @notice Address of the guardian\\n address public guardian;\\n /// @notice The MoC price oracle, which will continue to serve prices\\n PriceProviderMoC public priceProviderMoC;\\n\\n /// @notice Guardian updated\\n event NewGuardian(address oldGuardian, address newGuardian);\\n\\n /**\\n * @notice Construct a PriceOracleAdapter for a MoC oracle\\n * @param guardian_ address of guardian that is allowed to manage this contract\\n * @param priceProvider address of asset's MoC price provider\\n */\\n constructor(address guardian_, address priceProvider) {\\n require(\\n guardian_ != address(0),\\n \\\"PriceOracleAdapterMoc: guardian could not be 0\\\"\\n );\\n require(\\n priceProvider != address(0),\\n \\\"PriceOracleAdapterMoc: priceProvider could not be 0\\\"\\n );\\n guardian = guardian_;\\n priceProviderMoC = PriceProviderMoC(priceProvider);\\n }\\n\\n /**\\n * @notice Get the price from MoC and divide it by the rBTC price\\n * @return The price\\n */\\n function assetPrices(address) public view override returns (uint256) {\\n (bytes32 price, bool has) = priceProviderMoC.peek();\\n require(has, \\\"PriceOracleAdapterMoc: Oracle have no Price\\\");\\n return uint256(price);\\n }\\n\\n /**\\n * @notice Set the address of price provider\\n * @param priceProviderAddress address of price provider\\n */\\n function setPriceProvider(address priceProviderAddress) public {\\n require(\\n msg.sender == guardian,\\n \\\"PriceOracleAdapterMoc: only guardian may set the address\\\"\\n );\\n require(\\n priceProviderAddress != address(0),\\n \\\"PriceOracleAdapterMoc: address could not be 0\\\"\\n );\\n //set old address\\n address oldPriceProviderAddress = address(priceProviderMoC);\\n //update interface address\\n priceProviderMoC = PriceProviderMoC(priceProviderAddress);\\n //emit event\\n emit PriceOracleAdapterUpdated(\\n oldPriceProviderAddress,\\n priceProviderAddress\\n );\\n }\\n\\n /**\\n * @notice Set the address of the guardian\\n * @param newGuardian address of the guardian\\n */\\n function setGuardian(address newGuardian) public {\\n require(msg.sender == guardian, \\\"PriceOracleAdapterMoc: only guardian\\\");\\n require(\\n guardian != address(0),\\n \\\"PriceOracleAdapterMoc: guardin address can not be 0\\\"\\n );\\n //set old address\\n address oldGuardian = guardian;\\n //update\\n guardian = newGuardian;\\n //emit event\\n emit NewGuardian(oldGuardian, newGuardian);\\n }\\n}\\n\",\"keccak256\":\"0x6dc53b5de8b6f9e0b65eab05bfa3833f6bbf20444f2cc652da1b5a2dd592c462\",\"license\":\"UNLICENSED\"}},\"version\":1}", - "bytecode": "0x608060405234801561001057600080fd5b506040516106ac3803806106ac83398101604081905261002f9161016a565b6001600160a01b0382166100a15760405162461bcd60e51b815260206004820152602e60248201527f50726963654f7261636c65416461707465724d6f633a20677561726469616e2060448201526d0636f756c64206e6f7420626520360941b60648201526084015b60405180910390fd5b6001600160a01b03811661011d5760405162461bcd60e51b815260206004820152603360248201527f50726963654f7261636c65416461707465724d6f633a20707269636550726f7660448201527f6964657220636f756c64206e6f742062652030000000000000000000000000006064820152608401610098565b600080546001600160a01b039384166001600160a01b0319918216179091556001805492909316911617905561019d565b80516001600160a01b038116811461016557600080fd5b919050565b6000806040838503121561017d57600080fd5b6101868361014e565b91506101946020840161014e565b90509250929050565b610500806101ac6000396000f3fe608060405234801561001057600080fd5b50600436106100575760003560e01c806303fa251b1461005c578063372aa2241461008c578063452a9320146100a15780635e9a523c146100b45780638a0dac4a146100d5575b600080fd5b60015461006f906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b61009f61009a366004610465565b6100e8565b005b60005461006f906001600160a01b031681565b6100c76100c2366004610465565b61023b565b604051908152602001610083565b61009f6100e3366004610465565b610331565b6000546001600160a01b0316331461016d5760405162461bcd60e51b815260206004820152603860248201527f50726963654f7261636c65416461707465724d6f633a206f6e6c79206775617260448201527f6469616e206d617920736574207468652061646472657373000000000000000060648201526084015b60405180910390fd5b6001600160a01b0381166101d95760405162461bcd60e51b815260206004820152602d60248201527f50726963654f7261636c65416461707465724d6f633a2061646472657373206360448201526c06f756c64206e6f74206265203609c1b6064820152608401610164565b600180546001600160a01b038381166001600160a01b031983168117909355604080519190921680825260208201939093527f58d7caa9bcc8339b310213ec53c711c9157920c93aef03ac3c4a16ce01bc602e91015b60405180910390a15050565b6000806000600160009054906101000a90046001600160a01b03166001600160a01b03166359e02dd76040518163ffffffff1660e01b8152600401604080518083038186803b15801561028d57600080fd5b505afa1580156102a1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102c59190610495565b915091508061032a5760405162461bcd60e51b815260206004820152602b60248201527f50726963654f7261636c65416461707465724d6f633a204f7261636c6520686160448201526a7665206e6f20507269636560a81b6064820152608401610164565b5092915050565b6000546001600160a01b031633146103975760405162461bcd60e51b8152602060048201526024808201527f50726963654f7261636c65416461707465724d6f633a206f6e6c7920677561726044820152633234b0b760e11b6064820152608401610164565b6000546001600160a01b031661040b5760405162461bcd60e51b815260206004820152603360248201527f50726963654f7261636c65416461707465724d6f633a206775617264696e206160448201527206464726573732063616e206e6f74206265203606c1b6064820152608401610164565b600080546001600160a01b038381166001600160a01b031983168117909355604080519190921680825260208201939093527f08fdaf06427a2010e5958f4329b566993472d14ce81d3f16ce7f2a2660da98e3910161022f565b60006020828403121561047757600080fd5b81356001600160a01b038116811461048e57600080fd5b9392505050565b600080604083850312156104a857600080fd5b82519150602083015180151581146104bf57600080fd5b80915050925092905056fea2646970667358221220b3bf3342ac9831f468619e5dd1c72b3b86a808aa0bd558fde453ce03f4f9a2e764736f6c63430008060033", - "deployedBytecode": "0x608060405234801561001057600080fd5b50600436106100575760003560e01c806303fa251b1461005c578063372aa2241461008c578063452a9320146100a15780635e9a523c146100b45780638a0dac4a146100d5575b600080fd5b60015461006f906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b61009f61009a366004610465565b6100e8565b005b60005461006f906001600160a01b031681565b6100c76100c2366004610465565b61023b565b604051908152602001610083565b61009f6100e3366004610465565b610331565b6000546001600160a01b0316331461016d5760405162461bcd60e51b815260206004820152603860248201527f50726963654f7261636c65416461707465724d6f633a206f6e6c79206775617260448201527f6469616e206d617920736574207468652061646472657373000000000000000060648201526084015b60405180910390fd5b6001600160a01b0381166101d95760405162461bcd60e51b815260206004820152602d60248201527f50726963654f7261636c65416461707465724d6f633a2061646472657373206360448201526c06f756c64206e6f74206265203609c1b6064820152608401610164565b600180546001600160a01b038381166001600160a01b031983168117909355604080519190921680825260208201939093527f58d7caa9bcc8339b310213ec53c711c9157920c93aef03ac3c4a16ce01bc602e91015b60405180910390a15050565b6000806000600160009054906101000a90046001600160a01b03166001600160a01b03166359e02dd76040518163ffffffff1660e01b8152600401604080518083038186803b15801561028d57600080fd5b505afa1580156102a1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102c59190610495565b915091508061032a5760405162461bcd60e51b815260206004820152602b60248201527f50726963654f7261636c65416461707465724d6f633a204f7261636c6520686160448201526a7665206e6f20507269636560a81b6064820152608401610164565b5092915050565b6000546001600160a01b031633146103975760405162461bcd60e51b8152602060048201526024808201527f50726963654f7261636c65416461707465724d6f633a206f6e6c7920677561726044820152633234b0b760e11b6064820152608401610164565b6000546001600160a01b031661040b5760405162461bcd60e51b815260206004820152603360248201527f50726963654f7261636c65416461707465724d6f633a206775617264696e206160448201527206464726573732063616e206e6f74206265203606c1b6064820152608401610164565b600080546001600160a01b038381166001600160a01b031983168117909355604080519190921680825260208201939093527f08fdaf06427a2010e5958f4329b566993472d14ce81d3f16ce7f2a2660da98e3910161022f565b60006020828403121561047757600080fd5b81356001600160a01b038116811461048e57600080fd5b9392505050565b600080604083850312156104a857600080fd5b82519150602083015180151581146104bf57600080fd5b80915050925092905056fea2646970667358221220b3bf3342ac9831f468619e5dd1c72b3b86a808aa0bd558fde453ce03f4f9a2e764736f6c63430008060033", - "devdoc": { - "kind": "dev", - "methods": { - "assetPrices(address)": { - "returns": { - "_0": "The price" - } - }, - "constructor": { - "params": { - "guardian_": "address of guardian that is allowed to manage this contract", - "priceProvider": "address of asset's MoC price provider" - } - }, - "setGuardian(address)": { - "params": { - "newGuardian": "address of the guardian" - } - }, - "setPriceProvider(address)": { - "params": { - "priceProviderAddress": "address of price provider" - } - } - }, - "version": 1 - }, - "userdoc": { - "events": { - "NewGuardian(address,address)": { - "notice": "Guardian updated" - }, - "PriceOracleAdapterUpdated(address,address)": { - "notice": "Event adapter interface updated" - } - }, - "kind": "user", - "methods": { - "assetPrices(address)": { - "notice": "Get the price from MoC and divide it by the rBTC price" - }, - "constructor": { - "notice": "Construct a PriceOracleAdapter for a MoC oracle" - }, - "guardian()": { - "notice": "Address of the guardian" - }, - "priceProviderMoC()": { - "notice": "The MoC price oracle, which will continue to serve prices" - }, - "setGuardian(address)": { - "notice": "Set the address of the guardian" - }, - "setPriceProvider(address)": { - "notice": "Set the address of price provider" - } - }, - "version": 1 - }, - "storageLayout": { - "storage": [ - { - "astId": 39863, - "contract": "contracts/PriceOracleAdapterMoc.sol:PriceOracleAdapterMoc", - "label": "guardian", - "offset": 0, - "slot": "0", - "type": "t_address" - }, - { - "astId": 39867, - "contract": "contracts/PriceOracleAdapterMoc.sol:PriceOracleAdapterMoc", - "label": "priceProviderMoC", - "offset": 0, - "slot": "1", - "type": "t_contract(PriceProviderMoC)39858" - } - ], - "types": { - "t_address": { - "encoding": "inplace", - "label": "address", - "numberOfBytes": "20" - }, - "t_contract(PriceProviderMoC)39858": { - "encoding": "inplace", - "label": "contract PriceProviderMoC", - "numberOfBytes": "20" - } - } - } -} \ No newline at end of file diff --git a/deployments/localhost/solcInputs/3f2295c0e5923ce11cb0f26c6e52bee2.json b/deployments/localhost/solcInputs/3f2295c0e5923ce11cb0f26c6e52bee2.json deleted file mode 100644 index f065525..0000000 --- a/deployments/localhost/solcInputs/3f2295c0e5923ce11cb0f26c6e52bee2.json +++ /dev/null @@ -1,176 +0,0 @@ -{ - "language": "Solidity", - "sources": { - "contracts/BaseJumpRateModelV2.sol": { - "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity 0.8.6;\n\nimport \"./InterestRateModel.sol\";\nimport \"./SafeMath.sol\";\n\n/**\n * @title Logic for tropykus JumpRateModel Contract V2.\n * @author tropykus\n * @notice Version 2 modifies Version 1 by enabling updateable parameters.\n */\ncontract BaseJumpRateModelV2 is InterestRateModel {\n using SafeMath for uint256;\n\n event NewInterestParams(\n uint256 baseRatePerBlock,\n uint256 multiplierPerBlock,\n uint256 jumpMultiplierPerBlock,\n uint256 kink\n );\n event NewAdmin(address indexed newAdmin);\n event NewPendingAdmin(address indexed newPendingAdmin);\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 address of the owner, i.e. the Timelock contract, which can update parameters directly\n */\n address public pendingAdmin;\n\n /**\n * @notice The multiplier of utilization rate that gives the slope of the interest rate\n */\n uint256 public multiplierPerBlock;\n\n /**\n * @notice The base interest rate which is the y-intercept when utilization rate is 0\n */\n uint256 public baseRatePerBlock;\n\n /**\n * @notice The multiplierPerBlock after hitting a specified utilization point\n */\n uint256 public jumpMultiplierPerBlock;\n\n /**\n * @notice The utilization point at which the jump multiplier is applied\n */\n uint256 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(\n uint256 baseRatePerYear,\n uint256 multiplierPerYear,\n uint256 jumpMultiplierPerYear,\n uint256 kink_,\n address owner_\n ) {\n owner = owner_;\n emit NewAdmin(owner);\n updateJumpRateModelInternal(\n baseRatePerYear,\n multiplierPerYear,\n jumpMultiplierPerYear,\n kink_\n );\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(\n uint256 baseRatePerYear,\n uint256 multiplierPerYear,\n uint256 jumpMultiplierPerYear,\n uint256 kink_\n ) external {\n require(msg.sender == owner, \"only the owner may call this function.\");\n\n updateJumpRateModelInternal(\n baseRatePerYear,\n multiplierPerYear,\n jumpMultiplierPerYear,\n kink_\n );\n }\n\n /**\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(\n uint256 cash,\n uint256 borrows,\n uint256 reserves\n ) external view override returns (uint256) {\n return getBorrowRateInternal(cash, borrows, 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(\n uint256 cash,\n uint256 borrows,\n uint256 reserves\n ) internal view returns (uint256) {\n uint256 util = utilizationRate(cash, borrows, reserves);\n\n if (util <= kink) {\n return util.mul(multiplierPerBlock).div(1e18).add(baseRatePerBlock);\n } else {\n uint256 normalRate = kink.mul(multiplierPerBlock).div(1e18).add(\n baseRatePerBlock\n );\n uint256 excessUtil = util.sub(kink);\n return\n excessUtil.mul(jumpMultiplierPerBlock).div(1e18).add(\n normalRate\n );\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(\n uint256 cash,\n uint256 borrows,\n uint256 reserves,\n uint256 reserveFactorMantissa\n ) public view override returns (uint256) {\n uint256 oneMinusReserveFactor = uint256(1e18).sub(\n reserveFactorMantissa\n );\n uint256 borrowRate = getBorrowRateInternal(cash, borrows, reserves);\n uint256 rateToPool = borrowRate.mul(oneMinusReserveFactor).div(1e18);\n return\n 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(\n uint256 baseRatePerYear,\n uint256 multiplierPerYear,\n uint256 jumpMultiplierPerYear,\n uint256 kink_\n ) internal {\n baseRatePerBlock = baseRatePerYear.div(blocksPerYear);\n multiplierPerBlock = (multiplierPerYear.mul(1e18)).div(\n blocksPerYear.mul(kink_)\n );\n jumpMultiplierPerBlock = jumpMultiplierPerYear.div(blocksPerYear);\n kink = kink_;\n\n emit NewInterestParams(\n baseRatePerBlock,\n multiplierPerBlock,\n jumpMultiplierPerBlock,\n kink\n );\n }\n\n function acceptAdmin() public {\n require(\n msg.sender == pendingAdmin,\n \"BaseJumpRateModelV2::acceptAdmin: Call must come from pendingAdmin.\"\n );\n owner = msg.sender;\n pendingAdmin = address(0);\n\n emit NewAdmin(owner);\n }\n\n function setPendingAdmin(address pendingAdmin_) public {\n require(\n msg.sender == owner,\n \"BaseJumpRateModelV2::setPendingAdmin: Call must come from owner.\"\n );\n pendingAdmin = pendingAdmin_;\n\n emit NewPendingAdmin(pendingAdmin);\n }\n}\n" - }, - "contracts/InterestRateModel.sol": { - "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity 0.8.6;\n\nimport \"./Exponential.sol\";\nimport \"./SafeMath.sol\";\n\n/**\n * @title tropykus InterestRateModel Interface\n * @author tropykus\n */\nabstract contract InterestRateModel is Exponential {\n using SafeMath for uint256;\n\n /// @notice Indicator that this is an InterestRateModel contract (for inspection)\n bool public constant isInterestRateModel = true;\n bool public isTropykusInterestRateModel;\n\n /**\n * @notice The approximate number of blocks per year that is assumed by the interest rate model\n */\n uint256 public constant blocksPerYear = 1051200;\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(\n uint256 cash,\n uint256 borrows,\n uint256 reserves\n ) public pure virtual returns (uint256) {\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 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 amnount of reserves the market has\n * @return The borrow rate per block (as a percentage, and scaled by 1e18)\n */\n function getBorrowRate(\n uint256 cash,\n uint256 borrows,\n uint256 reserves\n ) external view virtual returns (uint256);\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 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(\n uint256 cash,\n uint256 borrows,\n uint256 reserves,\n uint256 reserveFactorMantissa\n ) external view virtual returns (uint256);\n\n function getExchangeRate(\n uint256 _totalCash,\n uint256 _totalBorrows,\n uint256 _totalReserves,\n uint256 _totalSupply\n ) public pure returns (MathError, uint256) {\n /*\n * exchangeRate = (totalCash + totalBorrows - totalReserves) / totalSupply\n */\n Exp memory exchangeRate;\n MathError mathErr;\n uint256 cashPlusBorrowsMinusReserves;\n (mathErr, cashPlusBorrowsMinusReserves) = addThenSubUInt(\n _totalCash,\n _totalBorrows,\n _totalReserves\n );\n if (mathErr != MathError.NO_ERROR) {\n return (mathErr, 0);\n }\n (mathErr, exchangeRate) = getExp(\n cashPlusBorrowsMinusReserves,\n _totalSupply\n );\n if (mathErr != MathError.NO_ERROR) {\n return (mathErr, 0);\n }\n\n return (MathError.NO_ERROR, exchangeRate.mantissa);\n }\n\n function isAboveOptimal(\n uint256 cash,\n uint256 borrows,\n uint256 reserves\n ) public view virtual returns (bool) {\n cash;\n borrows;\n reserves;\n return false;\n }\n}\n" - }, - "contracts/SafeMath.sol": { - "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity 0.8.6;\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/Exponential.sol": { - "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity 0.8.6;\n\nimport \"./CarefulMath.sol\";\nimport \"./ExponentialNoError.sol\";\n\n/**\n * @title Exponential module for storing fixed-precision decimals\n * @author tropykus\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) internal pure 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) internal pure 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) internal pure 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) internal pure 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) internal pure 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) internal pure 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) internal pure 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) internal pure 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) internal pure 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) internal pure 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) internal pure 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) internal pure 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) internal pure returns (MathError, Exp memory) {\n return getExp(a.mantissa, b.mantissa);\n }\n}\n" - }, - "contracts/CarefulMath.sol": { - "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity 0.8.6;\n\n/**\n * @title Careful Math\n * @author tropykus\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}\n" - }, - "contracts/ExponentialNoError.sol": { - "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity 0.8.6;\n\n/**\n * @title Exponential module for storing fixed-precision decimals\n * @author tropykus\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/LegacyJumpRateModelV2.sol": { - "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity 0.8.6;\n\nimport \"./BaseJumpRateModelV2.sol\";\nimport \"./LegacyInterestRateModel.sol\";\n\n/**\n * @title tropykus JumpRateModel Contract V2 for legacy cTokens\n * @author tropykus\n * @notice Supports only legacy cTokens\n */\ncontract LegacyJumpRateModelV2 is BaseJumpRateModelV2 {\n constructor(\n uint256 baseRatePerYear,\n uint256 multiplierPerYear,\n uint256 jumpMultiplierPerYear,\n uint256 kink_,\n address owner_\n )\n BaseJumpRateModelV2(\n baseRatePerYear,\n multiplierPerYear,\n jumpMultiplierPerYear,\n kink_,\n owner_\n )\n {\n isTropykusInterestRateModel = false;\n }\n}\n" - }, - "contracts/LegacyInterestRateModel.sol": { - "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity 0.8.6;\n\n/**\n * @title tropykus Legacy InterestRateModel Interface\n * @author tropykus (modified by Arr00)\n */\nabstract contract 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 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(\n uint256 cash,\n uint256 borrows,\n uint256 reserves,\n uint256 reserveFactorMantissa\n ) external view virtual returns (uint256);\n}\n" - }, - "contracts/JumpRateModelV2.sol": { - "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity 0.8.6;\n\nimport \"./BaseJumpRateModelV2.sol\";\n\n/**\n * @title tropykus JumpRateModel Contract V2 for V2 cTokens\n * @author tropykus\n * @notice Supports only for V2 cTokens\n */\ncontract JumpRateModelV2 is BaseJumpRateModelV2 {\n constructor(\n uint256 baseRatePerYear,\n uint256 multiplierPerYear,\n uint256 jumpMultiplierPerYear,\n uint256 kink_,\n address owner_\n )\n BaseJumpRateModelV2(\n baseRatePerYear,\n multiplierPerYear,\n jumpMultiplierPerYear,\n kink_,\n owner_\n )\n {\n isTropykusInterestRateModel = false;\n }\n}\n" - }, - "contracts/WhitePaperInterestRateModel.sol": { - "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity 0.8.6;\n\nimport \"./InterestRateModel.sol\";\nimport \"./SafeMath.sol\";\n\n/**\n * @title tropykus WhitePaperInterestRateModel Contract\n * @author tropykus\n * @notice The parameterized model described in section 2.4 of the original tropykus Protocol whitepaper\n */\ncontract WhitePaperInterestRateModel is InterestRateModel {\n using SafeMath for uint256;\n\n event NewInterestParams(\n uint256 baseRatePerBlock,\n uint256 multiplierPerBlock\n );\n\n /**\n * @notice The multiplier of utilization rate that gives the slope of the interest rate\n */\n uint256 public multiplierPerBlock;\n\n /**\n * @notice The base interest rate which is the y-intercept when utilization rate is 0\n */\n uint256 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(uint256 baseRatePerYear, uint256 multiplierPerYear) {\n baseRatePerBlock = baseRatePerYear.div(blocksPerYear);\n multiplierPerBlock = multiplierPerYear.div(blocksPerYear);\n isTropykusInterestRateModel = false;\n\n emit NewInterestParams(baseRatePerBlock, multiplierPerBlock);\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(\n uint256 cash,\n uint256 borrows,\n uint256 reserves\n ) public view override returns (uint256) {\n uint256 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(\n uint256 cash,\n uint256 borrows,\n uint256 reserves,\n uint256 reserveFactorMantissa\n ) public view override returns (uint256) {\n uint256 oneMinusReserveFactor = uint256(1e18).sub(\n reserveFactorMantissa\n );\n uint256 borrowRate = getBorrowRate(cash, borrows, reserves);\n uint256 rateToPool = borrowRate.mul(oneMinusReserveFactor).div(1e18);\n return\n utilizationRate(cash, borrows, reserves).mul(rateToPool).div(1e18);\n }\n}\n" - }, - "contracts/JumpRateModel.sol": { - "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity 0.8.6;\n\nimport \"./InterestRateModel.sol\";\nimport \"./SafeMath.sol\";\n\n/**\n * @title tropykus JumpRateModel Contract\n * @author tropykus\n */\ncontract JumpRateModel is InterestRateModel {\n using SafeMath for uint256;\n\n event NewInterestParams(\n uint256 baseRatePerBlock,\n uint256 multiplierPerBlock,\n uint256 jumpMultiplierPerBlock,\n uint256 kink\n );\n\n /**\n * @notice The multiplier of utilization rate that gives the slope of the interest rate\n */\n uint256 public multiplierPerBlock;\n\n /**\n * @notice The base interest rate which is the y-intercept when utilization rate is 0\n */\n uint256 public baseRatePerBlock;\n\n /**\n * @notice The multiplierPerBlock after hitting a specified utilization point\n */\n uint256 public jumpMultiplierPerBlock;\n\n /**\n * @notice The utilization point at which the jump multiplier is applied\n */\n uint256 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(\n uint256 baseRatePerYear,\n uint256 multiplierPerYear,\n uint256 jumpMultiplierPerYear,\n uint256 kink_\n ) {\n baseRatePerBlock = baseRatePerYear.div(blocksPerYear);\n multiplierPerBlock = multiplierPerYear.div(blocksPerYear);\n jumpMultiplierPerBlock = jumpMultiplierPerYear.div(blocksPerYear);\n kink = kink_;\n\n emit NewInterestParams(\n baseRatePerBlock,\n multiplierPerBlock,\n jumpMultiplierPerBlock,\n kink\n );\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(\n uint256 cash,\n uint256 borrows,\n uint256 reserves\n ) public pure override returns (uint256) {\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(\n uint256 cash,\n uint256 borrows,\n uint256 reserves\n ) public view override returns (uint256) {\n uint256 util = utilizationRate(cash, borrows, reserves);\n\n if (util <= kink) {\n return util.mul(multiplierPerBlock).div(1e18).add(baseRatePerBlock);\n } else {\n uint256 normalRate = kink.mul(multiplierPerBlock).div(1e18).add(\n baseRatePerBlock\n );\n uint256 excessUtil = util.sub(kink);\n return\n excessUtil.mul(jumpMultiplierPerBlock).div(1e18).add(\n normalRate\n );\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(\n uint256 cash,\n uint256 borrows,\n uint256 reserves,\n uint256 reserveFactorMantissa\n ) public view override returns (uint256) {\n uint256 oneMinusReserveFactor = uint256(1e18).sub(\n reserveFactorMantissa\n );\n uint256 borrowRate = getBorrowRate(cash, borrows, reserves);\n uint256 rateToPool = borrowRate.mul(oneMinusReserveFactor).div(1e18);\n return\n utilizationRate(cash, borrows, reserves).mul(rateToPool).div(1e18);\n }\n}\n" - }, - "contracts/HurricaneInterestRateModel.sol": { - "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity 0.8.6;\n\nimport \"./InterestRateModel.sol\";\n\ncontract HurricaneInterestRateModel is InterestRateModel {\n using SafeMath for uint256;\n\n address public owner;\n uint256 public baseBorrowRatePerBlock;\n uint256 public promisedBaseReturnRatePerBlock;\n uint256 public optimalUtilizationRate;\n uint256 public borrowRateSlopePerBlock;\n uint256 public supplyRateSlopePerBlock;\n\n uint256 constant FACTOR = 1e18;\n\n constructor(\n uint256 _baseBorrowRate,\n uint256 _promisedBaseReturnRate,\n uint256 _optimalUtilizationRate,\n uint256 _borrowRateSlope,\n uint256 _supplyRateSlope\n ) {\n baseBorrowRatePerBlock = _baseBorrowRate.div(blocksPerYear);\n promisedBaseReturnRatePerBlock = _promisedBaseReturnRate.div(\n blocksPerYear\n );\n optimalUtilizationRate = _optimalUtilizationRate;\n borrowRateSlopePerBlock = _borrowRateSlope.div(blocksPerYear);\n supplyRateSlopePerBlock = _supplyRateSlope.div(blocksPerYear);\n owner = msg.sender;\n isTropykusInterestRateModel = true;\n }\n\n modifier onlyOwner() {\n require(\n msg.sender == owner,\n \"You are not allowed to perform this action\"\n );\n _;\n }\n\n function getSupplyRate(\n uint256 cash,\n uint256 borrows,\n uint256 reserves,\n uint256 reserveFactorMantissa\n ) public view override returns (uint256) {\n reserveFactorMantissa;\n uint256 utilizationRate = utilizationRate(cash, borrows, reserves);\n return\n utilizationRate.mul(supplyRateSlopePerBlock).div(FACTOR).add(\n promisedBaseReturnRatePerBlock\n );\n }\n\n function getBorrowRate(\n uint256 cash,\n uint256 borrows,\n uint256 reserves\n ) public view override returns (uint256 borrowRate) {\n uint256 utilizationRate = utilizationRate(cash, borrows, reserves);\n borrowRate = utilizationRate\n .mul(borrowRateSlopePerBlock)\n .div(FACTOR)\n .add(baseBorrowRatePerBlock);\n }\n\n function isAboveOptimal(\n uint256 cash,\n uint256 borrows,\n uint256 reserves\n ) public view override returns (bool) {\n uint256 utilizationRate = utilizationRate(cash, borrows, reserves);\n return utilizationRate > optimalUtilizationRate;\n }\n}\n" - }, - "contracts/CTokenInterfaces.sol": { - "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity 0.8.6;\n\nimport \"./ComptrollerInterface.sol\";\nimport \"./InterestRateModel.sol\";\nimport \"./EIP20NonStandardInterface.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 uint256 internal constant borrowRateMaxMantissa = 0.0005e16;\n\n /**\n * @notice Maximum fraction of interest that can be set aside for reserves\n */\n uint256 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 uint256 public initialExchangeRateMantissa;\n\n /**\n * @notice Fraction of interest currently set aside for reserves\n */\n uint256 public reserveFactorMantissa;\n\n /**\n * @notice Block number that interest was last accrued at\n */\n uint256 public accrualBlockNumber;\n\n /**\n * @notice Accumulator of the total earned interest rate since the opening of the market\n */\n uint256 public borrowIndex;\n\n /**\n * @notice Total amount of outstanding borrows of the underlying in this market\n */\n uint256 public totalBorrows;\n\n /**\n * @notice Total amount of reserves of the underlying held in this market\n */\n uint256 public totalReserves;\n\n /**\n * @notice Total number of tokens in circulation\n */\n uint256 public totalSupply;\n\n uint256 public subsidyFund;\n\n struct SupplySnapshot {\n uint256 tokens;\n uint256 underlyingAmount;\n uint256 suppliedAt;\n uint256 promisedSupplyRate;\n }\n\n /**\n * @notice Official record of token balances for each account\n */\n mapping(address => SupplySnapshot) internal accountTokens;\n\n /**\n * @notice Approved token transfer amounts on behalf of others\n */\n mapping(address => mapping(address => uint256)) 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 uint256 principal;\n uint256 interestIndex;\n }\n\n /**\n * @notice Mapping of account addresses to outstanding borrow balances\n */\n mapping(address => BorrowSnapshot) internal accountBorrows;\n}\n\nabstract contract CTokenInterface is CTokenStorage {\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 interest is accrued\n */\n event AccrueInterest(\n uint256 cashPrior,\n uint256 interestAccumulated,\n uint256 borrowIndex,\n uint256 totalBorrows\n );\n\n /**\n * @notice Event emitted when tokens are minted\n */\n event Mint(address indexed minter, uint256 mintAmount, uint256 mintTokens);\n\n /**\n * @notice Event emitted when tokens are redeemed\n */\n event Redeem(\n address indexed redeemer,\n uint256 redeemAmount,\n uint256 redeemTokens\n );\n\n /**\n * @notice Event emitted when underlying is borrowed\n */\n event Borrow(\n address indexed borrower,\n uint256 borrowAmount,\n uint256 accountBorrows,\n uint256 totalBorrows\n );\n\n /**\n * @notice Event emitted when a borrow is repaid\n */\n event RepayBorrow(\n address indexed payer,\n address indexed borrower,\n uint256 repayAmount,\n uint256 accountBorrows,\n uint256 totalBorrows\n );\n\n /**\n * @notice Event emitted when a borrow is liquidated\n */\n event LiquidateBorrow(\n address indexed liquidator,\n address indexed borrower,\n uint256 repayAmount,\n address indexed cTokenCollateral,\n uint256 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(\n ComptrollerInterface oldComptroller,\n ComptrollerInterface newComptroller\n );\n\n /**\n * @notice Event emitted when interestRateModel is changed\n */\n event NewMarketInterestRateModel(\n InterestRateModel oldInterestRateModel,\n InterestRateModel newInterestRateModel\n );\n\n /**\n * @notice Event emitted when the reserve factor is changed\n */\n event NewReserveFactor(\n uint256 oldReserveFactorMantissa,\n uint256 newReserveFactorMantissa\n );\n\n /**\n * @notice Event emitted when the reserves are added\n */\n event ReservesAdded(\n address benefactor,\n uint256 addAmount,\n uint256 newTotalReserves\n );\n\n event SubsidyAdded(\n address benefactor,\n uint256 addAmount,\n uint256 newSubsidyFund\n );\n\n /**\n * @notice Event emitted when the reserves are reduced\n */\n event ReservesReduced(\n address admin,\n uint256 reduceAmount,\n uint256 newTotalReserves\n );\n\n /**\n * @notice EIP20 Transfer event\n */\n event Transfer(address indexed from, address indexed to, uint256 amount);\n\n /**\n * @notice EIP20 Approval event\n */\n event Approval(\n address indexed owner,\n address indexed spender,\n uint256 amount\n );\n\n /**\n * @notice Failure event\n */\n event CTokenStorageFailure(uint256 error, uint256 info, uint256 detail);\n\n /*** User Interface ***/\n\n function transfer(address dst, uint256 amount)\n external\n virtual\n returns (bool);\n\n function transferFrom(\n address src,\n address dst,\n uint256 amount\n ) external virtual returns (bool);\n\n function approve(address spender, uint256 amount)\n external\n virtual\n returns (bool);\n\n function allowance(address owner, address spender)\n external\n view\n virtual\n returns (uint256);\n\n function balanceOf(address owner) external view virtual returns (uint256);\n\n function balanceOfUnderlying(address owner)\n external\n virtual\n returns (uint256);\n\n function getAccountSnapshot(address account)\n external\n view\n virtual\n returns (\n uint256,\n uint256,\n uint256,\n uint256\n );\n\n function borrowRatePerBlock() external view virtual returns (uint256);\n\n function supplyRatePerBlock() external view virtual returns (uint256);\n\n function totalBorrowsCurrent() external virtual returns (uint256);\n\n function borrowBalanceCurrent(address account)\n external\n virtual\n returns (uint256);\n\n function borrowBalanceStored(address account)\n public\n view\n virtual\n returns (uint256);\n\n function exchangeRateCurrent() public virtual returns (uint256);\n\n function exchangeRateStored() public view virtual returns (uint256);\n\n function getCash() external view virtual returns (uint256);\n\n function accrueInterest() public virtual returns (uint256);\n\n function seize(\n address liquidator,\n address borrower,\n uint256 seizeTokens\n ) external virtual returns (uint256);\n\n /*** Admin Functions ***/\n\n function _setPendingAdmin(address payable newPendingAdmin)\n external\n virtual\n returns (uint256);\n\n function _acceptAdmin() external virtual returns (uint256);\n\n function _setComptroller(ComptrollerInterface newComptroller)\n public\n virtual\n returns (uint256);\n\n function _setReserveFactor(uint256 newReserveFactorMantissa)\n external\n virtual\n returns (uint256);\n\n function _reduceReserves(uint256 reduceAmount)\n external\n virtual\n returns (uint256);\n\n function _setInterestRateModel(InterestRateModel newInterestRateModel)\n public\n virtual\n returns (uint256);\n}\n\ncontract CErc20Storage {\n /**\n * @notice Underlying asset for this CToken\n */\n address public underlying;\n}\n\nabstract contract CErc20Interface is CErc20Storage {\n /*** User Interface ***/\n\n function mint(uint256 mintAmount) external virtual returns (uint256);\n\n function redeem(uint256 redeemAmount)\n external\n virtual\n returns (uint256);\n\n function borrow(uint256 borrowAmount) external virtual returns (uint256);\n\n function repayBorrow(uint256 repayAmount)\n external\n virtual\n returns (uint256);\n\n function liquidateBorrow(\n address borrower,\n uint256 repayAmount,\n CTokenInterface cTokenCollateral\n ) external virtual returns (uint256);\n\n function sweepToken(EIP20NonStandardInterface token) external virtual;\n\n /*** Admin Functions ***/\n\n function _addReserves(uint256 addAmount) external virtual returns (uint256);\n}\n\ncontract CDelegationStorage {\n /**\n * @notice Implementation address for this contract\n */\n address public implementation;\n}\n\nabstract contract CDelegatorInterface is CDelegationStorage {\n /**\n * @notice Emitted when implementation is changed\n */\n event NewImplementation(\n address oldImplementation,\n address newImplementation\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(\n address implementation_,\n bool allowResign,\n bytes memory becomeImplementationData\n ) public virtual;\n}\n\nabstract contract 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 virtual;\n\n /**\n * @notice Called by the delegator on a delegate to forfeit its responsibility\n */\n function _resignImplementation() public virtual;\n}\n" - }, - "contracts/ComptrollerInterface.sol": { - "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity 0.8.6;\n\nabstract contract 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)\n external\n virtual\n returns (uint256[] memory);\n\n function exitMarket(address cToken) external virtual returns (uint256);\n\n /*** Policy Hooks ***/\n\n function mintAllowed(\n address cToken,\n address minter,\n uint256 mintAmount\n ) external virtual returns (uint256);\n\n function mintVerify(\n address cToken,\n address minter,\n uint256 mintAmount,\n uint256 mintTokens\n ) external virtual;\n\n function redeemAllowed(\n address cToken,\n address redeemer,\n uint256 redeemTokens\n ) external virtual returns (uint256);\n\n function redeemVerify(\n address cToken,\n address redeemer,\n uint256 redeemAmount,\n uint256 redeemTokens\n ) external virtual;\n\n function borrowAllowed(\n address cToken,\n address borrower,\n uint256 borrowAmount\n ) external virtual returns (uint256);\n\n function borrowVerify(\n address cToken,\n address borrower,\n uint256 borrowAmount\n ) external virtual;\n\n function repayBorrowAllowed(\n address cToken,\n address payer,\n address borrower,\n uint256 repayAmount\n ) external virtual returns (uint256);\n\n function repayBorrowVerify(\n address cToken,\n address payer,\n address borrower,\n uint256 repayAmount,\n uint256 borrowerIndex\n ) external virtual;\n\n function liquidateBorrowAllowed(\n address cTokenBorrowed,\n address cTokenCollateral,\n address liquidator,\n address borrower,\n uint256 repayAmount\n ) external virtual returns (uint256);\n\n function liquidateBorrowVerify(\n address cTokenBorrowed,\n address cTokenCollateral,\n address liquidator,\n address borrower,\n uint256 repayAmount,\n uint256 seizeTokens\n ) external virtual;\n\n function seizeAllowed(\n address cTokenCollateral,\n address cTokenBorrowed,\n address liquidator,\n address borrower,\n uint256 seizeTokens\n ) external virtual returns (uint256);\n\n function seizeVerify(\n address cTokenCollateral,\n address cTokenBorrowed,\n address liquidator,\n address borrower,\n uint256 seizeTokens\n ) external virtual;\n\n function transferAllowed(\n address cToken,\n address src,\n address dst,\n uint256 transferTokens\n ) external virtual returns (uint256);\n\n function transferVerify(\n address cToken,\n address src,\n address dst,\n uint256 transferTokens\n ) external virtual;\n\n /*** Liquidity/Liquidation Calculations ***/\n\n function liquidateCalculateSeizeTokens(\n address cTokenBorrowed,\n address cTokenCollateral,\n uint256 repayAmount\n ) external view virtual returns (uint256, uint256);\n}\n" - }, - "contracts/EIP20NonStandardInterface.sol": { - "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity 0.8.6;\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 * @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 balance 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(\n address src,\n address dst,\n uint256 amount\n ) 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 success Whether or not the approval succeeded\n */\n function approve(address spender, uint256 amount)\n external\n 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 remaining The number of tokens allowed to be spent\n */\n function allowance(address owner, address spender)\n external\n view\n returns (uint256 remaining);\n\n event Transfer(address indexed from, address indexed to, uint256 amount);\n event Approval(\n address indexed owner,\n address indexed spender,\n uint256 amount\n );\n}\n" - }, - "contracts/CErc20Delegator.sol": { - "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity 0.8.6;\n\nimport \"./CTokenInterfaces.sol\";\n\n/**\n * @title tropykus CErc20Delegator Contract\n * @notice CTokens which wrap an EIP-20 underlying and delegate to an implementation\n * @author tropykus\n */\ncontract CErc20Delegator is\n CTokenInterface,\n CErc20Interface,\n CDelegatorInterface\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 * @param implementation_ The address of the implementation the contract delegates to\n * @param becomeImplementationData The encoded args for becomeImplementation\n */\n constructor(\n address underlying_,\n ComptrollerInterface comptroller_,\n InterestRateModel interestRateModel_,\n uint256 initialExchangeRateMantissa_,\n string memory name_,\n string memory symbol_,\n uint8 decimals_,\n address payable admin_,\n address implementation_,\n bytes memory becomeImplementationData\n ) {\n // Creator of the contract is admin during initialization\n admin = payable(msg.sender);\n\n // First delegate gets to initialize the delegator (i.e. storage contract)\n delegateTo(\n implementation_,\n abi.encodeWithSignature(\n \"initialize(address,address,address,uint256,string,string,uint8)\",\n underlying_,\n comptroller_,\n interestRateModel_,\n initialExchangeRateMantissa_,\n name_,\n symbol_,\n decimals_\n )\n );\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(\n address implementation_,\n bool allowResign,\n bytes memory becomeImplementationData\n ) public override {\n require(\n msg.sender == admin,\n \"CErc20Delegator::_setImplementation: Caller must be admin\"\n );\n\n if (allowResign) {\n delegateToImplementation(\n abi.encodeWithSignature(\"_resignImplementation()\")\n );\n }\n\n address oldImplementation = implementation;\n implementation = implementation_;\n\n delegateToImplementation(\n abi.encodeWithSignature(\n \"_becomeImplementation(bytes)\",\n becomeImplementationData\n )\n );\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(uint256 mintAmount) external override returns (uint256) {\n bytes memory data = delegateToImplementation(\n abi.encodeWithSignature(\"mint(uint256)\", mintAmount)\n );\n return abi.decode(data, (uint256));\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 redeem(uint256 redeemAmount)\n external\n override\n returns (uint256)\n {\n bytes memory data = delegateToImplementation(\n abi.encodeWithSignature(\"redeemUnderlying(uint256)\", redeemAmount)\n );\n return abi.decode(data, (uint256));\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(uint256 borrowAmount) external override returns (uint256) {\n bytes memory data = delegateToImplementation(\n abi.encodeWithSignature(\"borrow(uint256)\", borrowAmount)\n );\n return abi.decode(data, (uint256));\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(uint256 repayAmount)\n external\n override\n returns (uint256)\n {\n bytes memory data = delegateToImplementation(\n abi.encodeWithSignature(\"repayBorrow(uint256)\", repayAmount)\n );\n return abi.decode(data, (uint256));\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(\n address borrower,\n uint256 repayAmount,\n CTokenInterface cTokenCollateral\n ) external override returns (uint256) {\n bytes memory data = delegateToImplementation(\n abi.encodeWithSignature(\n \"liquidateBorrow(address,uint256,address)\",\n borrower,\n repayAmount,\n cTokenCollateral\n )\n );\n return abi.decode(data, (uint256));\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)\n external\n override\n returns (bool)\n {\n bytes memory data = delegateToImplementation(\n abi.encodeWithSignature(\"transfer(address,uint256)\", dst, amount)\n );\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(\n address src,\n address dst,\n uint256 amount\n ) external override returns (bool) {\n bytes memory data = delegateToImplementation(\n abi.encodeWithSignature(\n \"transferFrom(address,address,uint256)\",\n src,\n dst,\n amount\n )\n );\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)\n external\n override\n returns (bool)\n {\n bytes memory data = delegateToImplementation(\n abi.encodeWithSignature(\"approve(address,uint256)\", spender, amount)\n );\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)\n external\n view\n override\n returns (uint256)\n {\n bytes memory data = delegateToViewImplementation(\n abi.encodeWithSignature(\n \"allowance(address,address)\",\n owner,\n spender\n )\n );\n return abi.decode(data, (uint256));\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 override returns (uint256) {\n bytes memory data = delegateToViewImplementation(\n abi.encodeWithSignature(\"balanceOf(address)\", owner)\n );\n return abi.decode(data, (uint256));\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)\n external\n override\n returns (uint256)\n {\n bytes memory data = delegateToImplementation(\n abi.encodeWithSignature(\"balanceOfUnderlying(address)\", owner)\n );\n return abi.decode(data, (uint256));\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)\n external\n view\n override\n returns (\n uint256,\n uint256,\n uint256,\n uint256\n )\n {\n bytes memory data = delegateToViewImplementation(\n abi.encodeWithSignature(\"getAccountSnapshot(address)\", account)\n );\n return abi.decode(data, (uint256, uint256, uint256, uint256));\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 override returns (uint256) {\n bytes memory data = delegateToViewImplementation(\n abi.encodeWithSignature(\"borrowRatePerBlock()\")\n );\n return abi.decode(data, (uint256));\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 override returns (uint256) {\n bytes memory data = delegateToViewImplementation(\n abi.encodeWithSignature(\"supplyRatePerBlock()\")\n );\n return abi.decode(data, (uint256));\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 override returns (uint256) {\n bytes memory data = delegateToImplementation(\n abi.encodeWithSignature(\"totalBorrowsCurrent()\")\n );\n return abi.decode(data, (uint256));\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)\n external\n override\n returns (uint256)\n {\n bytes memory data = delegateToImplementation(\n abi.encodeWithSignature(\"borrowBalanceCurrent(address)\", account)\n );\n return abi.decode(data, (uint256));\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)\n public\n view\n override\n returns (uint256)\n {\n bytes memory data = delegateToViewImplementation(\n abi.encodeWithSignature(\"borrowBalanceStored(address)\", account)\n );\n return abi.decode(data, (uint256));\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 override returns (uint256) {\n bytes memory data = delegateToImplementation(\n abi.encodeWithSignature(\"exchangeRateCurrent()\")\n );\n return abi.decode(data, (uint256));\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 override returns (uint256) {\n bytes memory data = delegateToViewImplementation(\n abi.encodeWithSignature(\"exchangeRateStored()\")\n );\n return abi.decode(data, (uint256));\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 override returns (uint256) {\n bytes memory data = delegateToViewImplementation(\n abi.encodeWithSignature(\"getCash()\")\n );\n return abi.decode(data, (uint256));\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 override returns (uint256) {\n bytes memory data = delegateToImplementation(\n abi.encodeWithSignature(\"accrueInterest()\")\n );\n return abi.decode(data, (uint256));\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(\n address liquidator,\n address borrower,\n uint256 seizeTokens\n ) external override returns (uint256) {\n bytes memory data = delegateToImplementation(\n abi.encodeWithSignature(\n \"seize(address,address,uint256)\",\n liquidator,\n borrower,\n seizeTokens\n )\n );\n return abi.decode(data, (uint256));\n }\n\n /**\n * @notice A public function to sweep accidental ERC-20 transfers to this contract. Tokens are sent to admin (timelock)\n * @param token The address of the ERC-20 token to sweep\n */\n function sweepToken(EIP20NonStandardInterface token) external override {\n delegateToImplementation(\n abi.encodeWithSignature(\"sweepToken(address)\", token)\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)\n external\n override\n returns (uint256)\n {\n bytes memory data = delegateToImplementation(\n abi.encodeWithSignature(\n \"_setPendingAdmin(address)\",\n newPendingAdmin\n )\n );\n return abi.decode(data, (uint256));\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)\n public\n override\n returns (uint256)\n {\n bytes memory data = delegateToImplementation(\n abi.encodeWithSignature(\"_setComptroller(address)\", newComptroller)\n );\n return abi.decode(data, (uint256));\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(uint256 newReserveFactorMantissa)\n external\n override\n returns (uint256)\n {\n bytes memory data = delegateToImplementation(\n abi.encodeWithSignature(\n \"_setReserveFactor(uint256)\",\n newReserveFactorMantissa\n )\n );\n return abi.decode(data, (uint256));\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 override returns (uint256) {\n bytes memory data = delegateToImplementation(\n abi.encodeWithSignature(\"_acceptAdmin()\")\n );\n return abi.decode(data, (uint256));\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(uint256 addAmount)\n external\n override\n returns (uint256)\n {\n bytes memory data = delegateToImplementation(\n abi.encodeWithSignature(\"_addReserves(uint256)\", addAmount)\n );\n return abi.decode(data, (uint256));\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(uint256 reduceAmount)\n external\n override\n returns (uint256)\n {\n bytes memory data = delegateToImplementation(\n abi.encodeWithSignature(\"_reduceReserves(uint256)\", reduceAmount)\n );\n return abi.decode(data, (uint256));\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)\n public\n override\n returns (uint256)\n {\n bytes memory data = delegateToImplementation(\n abi.encodeWithSignature(\n \"_setInterestRateModel(address)\",\n newInterestRateModel\n )\n );\n return abi.decode(data, (uint256));\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)\n internal\n returns (bytes memory)\n {\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)\n public\n returns (bytes memory)\n {\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)\n public\n view\n returns (bytes memory)\n {\n (bool success, bytes memory returnData) = address(this).staticcall(\n abi.encodeWithSignature(\"delegateToImplementation(bytes)\", data)\n );\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 internalFallback() public payable {\n require(\n msg.value == 0,\n \"CErc20Delegator:fallback: cannot send value to fallback\"\n );\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 {\n revert(free_mem_ptr, returndatasize())\n }\n default {\n return(free_mem_ptr, returndatasize())\n }\n }\n }\n\n fallback() external payable {\n internalFallback();\n }\n\n receive() external payable {\n internalFallback();\n }\n}\n" - }, - "contracts/ComptrollerG6.sol": { - "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity 0.8.6;\n\nimport \"./CToken.sol\";\nimport \"./ErrorReporter.sol\";\nimport \"./PriceOracle.sol\";\nimport \"./ComptrollerInterface.sol\";\nimport \"./ComptrollerStorage.sol\";\nimport \"./Unitroller.sol\";\nimport \"./Governance/TROP.sol\";\n\n/**\n * @title tropykus Comptroller Contract\n * @author tropykus\n */\ncontract ComptrollerG6 is\n ComptrollerV5Storage,\n ComptrollerInterface,\n ComptrollerErrorReporter,\n ExponentialNoError\n{\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(\n uint256 oldCloseFactorMantissa,\n uint256 newCloseFactorMantissa\n );\n\n /// @notice Emitted when a collateral factor is changed by admin\n event NewCollateralFactor(\n CToken cToken,\n uint256 oldCollateralFactorMantissa,\n uint256 newCollateralFactorMantissa\n );\n\n /// @notice Emitted when liquidation incentive is changed by admin\n event NewLiquidationIncentive(\n uint256 oldLiquidationIncentiveMantissa,\n uint256 newLiquidationIncentiveMantissa\n );\n\n /// @notice Emitted when price oracle is changed\n event NewPriceOracle(\n PriceOracle oldPriceOracle,\n PriceOracle newPriceOracle\n );\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(uint256 oldCompRate, uint256 newCompRate);\n\n /// @notice Emitted when a new COMP speed is calculated for a market\n event CompSpeedUpdated(CToken indexed cToken, uint256 newSpeed);\n\n /// @notice Emitted when a new COMP speed is set for a contributor\n event ContributorCompSpeedUpdated(\n address indexed contributor,\n uint256 newSpeed\n );\n\n /// @notice Emitted when COMP is distributed to a supplier\n event DistributedSupplierComp(\n CToken indexed cToken,\n address indexed supplier,\n uint256 compDelta,\n uint256 compSupplyIndex\n );\n\n /// @notice Emitted when COMP is distributed to a borrower\n event DistributedBorrowerComp(\n CToken indexed cToken,\n address indexed borrower,\n uint256 compDelta,\n uint256 compBorrowIndex\n );\n\n /// @notice Emitted when borrow cap for a cToken is changed\n event NewBorrowCap(CToken indexed cToken, uint256 newBorrowCap);\n\n /// @notice Emitted when borrow cap guardian is changed\n event NewBorrowCapGuardian(\n address oldBorrowCapGuardian,\n address newBorrowCapGuardian\n );\n\n /// @notice Emitted when COMP is granted by admin\n event CompGranted(address recipient, uint256 amount);\n\n /// @notice The threshold above which the flywheel transfers COMP, in wei\n uint256 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 uint256 internal constant closeFactorMinMantissa = 0.05e18; // 0.05\n\n // closeFactorMantissa must not exceed this value\n uint256 internal constant closeFactorMaxMantissa = 0.9e18; // 0.9\n\n // No collateralFactorMantissa may exceed this value\n uint256 internal constant collateralFactorMaxMantissa = 0.9e18; // 0.9\n\n constructor() {\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)\n external\n view\n returns (CToken[] memory)\n {\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)\n external\n view\n returns (bool)\n {\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)\n public\n override\n returns (uint256[] memory)\n {\n uint256 len = cTokens.length;\n\n uint256[] memory results = new uint256[](len);\n for (uint256 i = 0; i < len; i++) {\n CToken cToken = CToken(cTokens[i]);\n\n results[i] = uint256(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)\n internal\n returns (Error)\n {\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)\n external\n override\n returns (uint256)\n {\n CToken cToken = CToken(cTokenAddress);\n /* Get sender tokensHeld and amountOwed underlying from the cToken */\n (uint256 oErr, uint256 tokensHeld, uint256 amountOwed, ) = cToken\n .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\n fail(\n Error.NONZERO_BORROW_BALANCE,\n FailureInfo.EXIT_MARKET_BALANCE_OWED\n );\n }\n\n /* Fail if the sender is not permitted to redeem all of their tokens */\n uint256 allowed = redeemAllowedInternal(\n cTokenAddress,\n msg.sender,\n tokensHeld\n );\n if (allowed != 0) {\n return\n failOpaque(\n Error.REJECTION,\n FailureInfo.EXIT_MARKET_REJECTION,\n allowed\n );\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 uint256(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 accountAssets[msg.sender] = new CToken[](0);\n CToken[] storage newMarketList = accountAssets[msg.sender];\n uint256 len = userAssetList.length;\n uint256 assetIndex = len;\n for (uint256 i = 0; i < len; i++) {\n if (userAssetList[i] == cToken) {\n assetIndex = i;\n continue;\n }\n newMarketList.push(userAssetList[i]);\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 emit MarketExited(cToken, msg.sender);\n\n return uint256(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(\n address cToken,\n address minter,\n uint256 mintAmount\n ) external override returns (uint256) {\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 uint256(Error.MARKET_NOT_LISTED);\n }\n\n // Keep the flywheel moving\n updateCompSupplyIndex(cToken);\n distributeSupplierComp(cToken, minter, false);\n\n return uint256(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(\n address cToken,\n address minter,\n uint256 actualMintAmount,\n uint256 mintTokens\n ) external override {\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(\n address cToken,\n address redeemer,\n uint256 redeemTokens\n ) external override returns (uint256) {\n uint256 allowed = redeemAllowedInternal(cToken, redeemer, redeemTokens);\n if (allowed != uint256(Error.NO_ERROR)) {\n return allowed;\n }\n\n // Keep the flywheel moving\n updateCompSupplyIndex(cToken);\n distributeSupplierComp(cToken, redeemer, false);\n\n return uint256(Error.NO_ERROR);\n }\n\n function redeemAllowedInternal(\n address cToken,\n address redeemer,\n uint256 redeemTokens\n ) internal view returns (uint256) {\n if (!markets[cToken].isListed) {\n return uint256(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 uint256(Error.NO_ERROR);\n }\n\n /* Otherwise, perform a hypothetical liquidity check to guard against shortfall */\n (\n Error err,\n ,\n uint256 shortfall\n ) = getHypotheticalAccountLiquidityInternal(\n redeemer,\n CToken(cToken),\n redeemTokens,\n 0\n );\n if (err != Error.NO_ERROR) {\n return uint256(err);\n }\n if (shortfall > 0) {\n return uint256(Error.INSUFFICIENT_LIQUIDITY);\n }\n\n return uint256(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(\n address cToken,\n address redeemer,\n uint256 redeemAmount,\n uint256 redeemTokens\n ) external pure override {\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(\n address cToken,\n address borrower,\n uint256 borrowAmount\n ) external override returns (uint256) {\n // Pausing is a very serious situation - we revert to sound the alarms\n Error err;\n uint256 shortfall;\n require(!borrowGuardianPaused[cToken], \"borrow is paused\");\n\n if (!markets[cToken].isListed) {\n return uint256(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 err = addToMarketInternal(CToken(msg.sender), borrower);\n if (err != Error.NO_ERROR) {\n return uint256(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 uint256(Error.PRICE_ERROR);\n }\n\n uint256 borrowCap = borrowCaps[cToken];\n // Borrow cap of 0 corresponds to unlimited borrowing\n if (borrowCap != 0) {\n uint256 totalBorrows = CToken(cToken).totalBorrows();\n uint256 nextTotalBorrows = add_(totalBorrows, borrowAmount);\n require(nextTotalBorrows < borrowCap, \"market borrow cap reached\");\n }\n\n (err, , shortfall) = getHypotheticalAccountLiquidityInternal(\n borrower,\n CToken(cToken),\n 0,\n borrowAmount\n );\n if (err != Error.NO_ERROR) {\n return uint256(err);\n }\n if (shortfall > 0) {\n return uint256(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 uint256(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(\n address cToken,\n address borrower,\n uint256 borrowAmount\n ) external override {\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 uint256 repayAmount\n ) external override returns (uint256) {\n // Shh - currently unused\n payer;\n borrower;\n repayAmount;\n\n if (!markets[cToken].isListed) {\n return uint256(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 uint256(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 uint256 actualRepayAmount,\n uint256 borrowerIndex\n ) external override {\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 uint256 repayAmount\n ) external view override returns (uint256) {\n // Shh - currently unused\n liquidator;\n\n if (\n !markets[cTokenBorrowed].isListed ||\n !markets[cTokenCollateral].isListed\n ) {\n return uint256(Error.MARKET_NOT_LISTED);\n }\n\n /* The borrower must have shortfall in order to be liquidatable */\n (Error err, , uint256 shortfall) = getAccountLiquidityInternal(\n borrower\n );\n if (err != Error.NO_ERROR) {\n return uint256(err);\n }\n if (shortfall == 0) {\n return uint256(Error.INSUFFICIENT_SHORTFALL);\n }\n\n /* The liquidator may not repay more than what is allowed by the closeFactor */\n uint256 borrowBalance = CToken(cTokenBorrowed).borrowBalanceStored(\n borrower\n );\n uint256 maxClose = mul_ScalarTruncate(\n Exp({mantissa: closeFactorMantissa}),\n borrowBalance\n );\n if (repayAmount > maxClose) {\n return uint256(Error.TOO_MUCH_REPAY);\n }\n\n return uint256(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 uint256 actualRepayAmount,\n uint256 seizeTokens\n ) external override {\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 uint256 seizeTokens\n ) external override returns (uint256) {\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 (\n !markets[cTokenCollateral].isListed ||\n !markets[cTokenBorrowed].isListed\n ) {\n return uint256(Error.MARKET_NOT_LISTED);\n }\n\n if (\n CToken(cTokenCollateral).comptroller() !=\n CToken(cTokenBorrowed).comptroller()\n ) {\n return uint256(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 uint256(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 uint256 seizeTokens\n ) external override {\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(\n address cToken,\n address src,\n address dst,\n uint256 transferTokens\n ) external override returns (uint256) {\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 uint256 allowed = redeemAllowedInternal(cToken, src, transferTokens);\n if (allowed != uint256(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 uint256(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(\n address cToken,\n address src,\n address dst,\n uint256 transferTokens\n ) external override {\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 uint256 sumCollateral;\n uint256 sumBorrowPlusEffects;\n uint256 cTokenBalance;\n uint256 borrowBalance;\n uint256 exchangeRateMantissa;\n uint256 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)\n public\n view\n returns (\n uint256,\n uint256,\n uint256\n )\n {\n (\n Error err,\n uint256 liquidity,\n uint256 shortfall\n ) = getHypotheticalAccountLiquidityInternal(\n account,\n CToken(address(0)),\n 0,\n 0\n );\n\n return (uint256(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)\n internal\n view\n returns (\n Error,\n uint256,\n uint256\n )\n {\n return\n getHypotheticalAccountLiquidityInternal(\n account,\n CToken(address(0)),\n 0,\n 0\n );\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 uint256 redeemTokens,\n uint256 borrowAmount\n )\n public\n view\n returns (\n uint256,\n uint256,\n uint256\n )\n {\n (\n Error err,\n uint256 liquidity,\n uint256 shortfall\n ) = getHypotheticalAccountLiquidityInternal(\n account,\n CToken(cTokenModify),\n redeemTokens,\n borrowAmount\n );\n return (uint256(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 uint256 redeemTokens,\n uint256 borrowAmount\n )\n internal\n view\n returns (\n Error,\n uint256,\n uint256\n )\n {\n AccountLiquidityLocalVars memory vars; // Holds all our calculation results\n uint256 oErr;\n\n // For each asset the account is in\n CToken[] memory assets = accountAssets[account];\n for (uint256 i = 0; i < assets.length; i++) {\n CToken asset = assets[i];\n\n // Read the balances and exchange rate from the cToken\n (\n oErr,\n vars.cTokenBalance,\n vars.borrowBalance,\n vars.exchangeRateMantissa\n ) = asset.getAccountSnapshot(account);\n if (oErr != 0) {\n // 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({\n mantissa: markets[address(asset)].collateralFactorMantissa\n });\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_(\n mul_(vars.collateralFactor, vars.exchangeRate),\n vars.oraclePrice\n );\n\n // sumCollateral += tokensToDenom * cTokenBalance\n vars.sumCollateral = mul_ScalarTruncateAddUInt(\n vars.tokensToDenom,\n vars.cTokenBalance,\n vars.sumCollateral\n );\n\n // sumBorrowPlusEffects += oraclePrice * borrowBalance\n vars.sumBorrowPlusEffects = mul_ScalarTruncateAddUInt(\n vars.oraclePrice,\n vars.borrowBalance,\n vars.sumBorrowPlusEffects\n );\n\n // Calculate effects of interacting with cTokenModify\n if (asset == cTokenModify) {\n // redeem effect\n // sumBorrowPlusEffects += tokensToDenom * redeemTokens\n vars.sumBorrowPlusEffects = mul_ScalarTruncateAddUInt(\n vars.tokensToDenom,\n redeemTokens,\n vars.sumBorrowPlusEffects\n );\n\n // borrow effect\n // sumBorrowPlusEffects += oraclePrice * borrowAmount\n vars.sumBorrowPlusEffects = mul_ScalarTruncateAddUInt(\n vars.oraclePrice,\n borrowAmount,\n vars.sumBorrowPlusEffects\n );\n }\n }\n\n // These are safe, as the underflow condition is checked first\n if (vars.sumCollateral > vars.sumBorrowPlusEffects) {\n return (\n Error.NO_ERROR,\n vars.sumCollateral - vars.sumBorrowPlusEffects,\n 0\n );\n } else {\n return (\n Error.NO_ERROR,\n 0,\n vars.sumBorrowPlusEffects - vars.sumCollateral\n );\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(\n address cTokenBorrowed,\n address cTokenCollateral,\n uint256 actualRepayAmount\n ) external view override returns (uint256, uint256) {\n /* Read oracle prices for borrowed and collateral markets */\n uint256 priceBorrowedMantissa = oracle.getUnderlyingPrice(\n CToken(cTokenBorrowed)\n );\n uint256 priceCollateralMantissa = oracle.getUnderlyingPrice(\n CToken(cTokenCollateral)\n );\n if (priceBorrowedMantissa == 0 || priceCollateralMantissa == 0) {\n return (uint256(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 uint256 exchangeRateMantissa = CToken(cTokenCollateral)\n .exchangeRateStored(); // Note: reverts on error\n uint256 seizeTokens;\n Exp memory numerator;\n Exp memory denominator;\n Exp memory ratio;\n\n numerator = mul_(\n Exp({mantissa: liquidationIncentiveMantissa}),\n Exp({mantissa: priceBorrowedMantissa})\n );\n denominator = mul_(\n Exp({mantissa: priceCollateralMantissa}),\n Exp({mantissa: exchangeRateMantissa})\n );\n ratio = div_(numerator, denominator);\n\n seizeTokens = mul_ScalarTruncate(ratio, actualRepayAmount);\n\n return (uint256(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 (uint256) {\n // Check caller is admin\n if (msg.sender != admin) {\n return\n fail(\n Error.UNAUTHORIZED,\n FailureInfo.SET_PRICE_ORACLE_OWNER_CHECK\n );\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 uint256(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(uint256 newCloseFactorMantissa)\n external\n returns (uint256)\n {\n // Check caller is admin\n require(msg.sender == admin, \"only admin can set close factor\");\n\n uint256 oldCloseFactorMantissa = closeFactorMantissa;\n closeFactorMantissa = newCloseFactorMantissa;\n emit NewCloseFactor(oldCloseFactorMantissa, closeFactorMantissa);\n\n return uint256(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(\n CToken cToken,\n uint256 newCollateralFactorMantissa\n ) external returns (uint256) {\n // Check caller is admin\n if (msg.sender != admin) {\n return\n fail(\n Error.UNAUTHORIZED,\n FailureInfo.SET_COLLATERAL_FACTOR_OWNER_CHECK\n );\n }\n\n // Verify market is listed\n Market storage market = markets[address(cToken)];\n if (!market.isListed) {\n return\n fail(\n Error.MARKET_NOT_LISTED,\n FailureInfo.SET_COLLATERAL_FACTOR_NO_EXISTS\n );\n }\n\n Exp memory newCollateralFactorExp = Exp({\n mantissa: newCollateralFactorMantissa\n });\n\n // Check collateral factor <= 0.9\n Exp memory highLimit = Exp({mantissa: collateralFactorMaxMantissa});\n if (lessThanExp(highLimit, newCollateralFactorExp)) {\n return\n fail(\n Error.INVALID_COLLATERAL_FACTOR,\n FailureInfo.SET_COLLATERAL_FACTOR_VALIDATION\n );\n }\n\n // If collateral factor != 0, fail if price == 0\n if (\n newCollateralFactorMantissa != 0 &&\n oracle.getUnderlyingPrice(cToken) == 0\n ) {\n return\n fail(\n Error.PRICE_ERROR,\n FailureInfo.SET_COLLATERAL_FACTOR_WITHOUT_PRICE\n );\n }\n\n // Set market's collateral factor to new collateral factor, remember old value\n uint256 oldCollateralFactorMantissa = market.collateralFactorMantissa;\n market.collateralFactorMantissa = newCollateralFactorMantissa;\n\n // Emit event with asset, old collateral factor, and new collateral factor\n emit NewCollateralFactor(\n cToken,\n oldCollateralFactorMantissa,\n newCollateralFactorMantissa\n );\n\n return uint256(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(uint256 newLiquidationIncentiveMantissa)\n external\n returns (uint256)\n {\n // Check caller is admin\n if (msg.sender != admin) {\n return\n fail(\n Error.UNAUTHORIZED,\n FailureInfo.SET_LIQUIDATION_INCENTIVE_OWNER_CHECK\n );\n }\n\n // Save current value for use in log\n uint256 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(\n oldLiquidationIncentiveMantissa,\n newLiquidationIncentiveMantissa\n );\n\n return uint256(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 (uint256) {\n if (msg.sender != admin) {\n return\n fail(\n Error.UNAUTHORIZED,\n FailureInfo.SUPPORT_MARKET_OWNER_CHECK\n );\n }\n\n if (markets[address(cToken)].isListed) {\n return\n fail(\n Error.MARKET_ALREADY_LISTED,\n FailureInfo.SUPPORT_MARKET_EXISTS\n );\n }\n\n cToken.isCToken(); // Sanity check to make sure its really a CToken\n\n Market storage market = markets[address(cToken)];\n market.isListed = true;\n market.isComped = false;\n market.collateralFactorMantissa = 0;\n\n _addMarketInternal(address(cToken));\n\n emit MarketListed(cToken);\n\n return uint256(Error.NO_ERROR);\n }\n\n function _addMarketInternal(address cToken) internal {\n for (uint256 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 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(\n CToken[] calldata cTokens,\n uint256[] calldata newBorrowCaps\n ) external {\n require(\n msg.sender == admin || msg.sender == borrowCapGuardian,\n \"only admin or borrow cap guardian can set borrow caps\"\n );\n\n uint256 numMarkets = cTokens.length;\n uint256 numBorrowCaps = newBorrowCaps.length;\n\n require(\n numMarkets != 0 && numMarkets == numBorrowCaps,\n \"invalid input\"\n );\n\n for (uint256 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)\n public\n returns (uint256)\n {\n if (msg.sender != admin) {\n return\n fail(\n Error.UNAUTHORIZED,\n FailureInfo.SET_PAUSE_GUARDIAN_OWNER_CHECK\n );\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 uint256(Error.NO_ERROR);\n }\n\n function _setMintPaused(CToken cToken, bool state) public returns (bool) {\n require(\n markets[address(cToken)].isListed,\n \"cannot pause a market that is not listed\"\n );\n require(\n msg.sender == pauseGuardian || msg.sender == admin,\n \"only pause guardian and admin can pause\"\n );\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(\n markets[address(cToken)].isListed,\n \"cannot pause a market that is not listed\"\n );\n require(\n msg.sender == pauseGuardian || msg.sender == admin,\n \"only pause guardian and admin can pause\"\n );\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(\n msg.sender == pauseGuardian || msg.sender == admin,\n \"only pause guardian and admin can pause\"\n );\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(\n msg.sender == pauseGuardian || msg.sender == admin,\n \"only pause guardian and admin can pause\"\n );\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(\n msg.sender == unitroller.admin(),\n \"only unitroller admin can change brains\"\n );\n require(\n unitroller._acceptImplementation() == 0,\n \"change not authorized\"\n );\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(\n msg.sender == tx.origin,\n \"only externally owned accounts may refresh speeds\"\n );\n refreshCompSpeedsInternal();\n }\n\n function refreshCompSpeedsInternal() internal {\n CToken[] memory allMarkets_ = allMarkets;\n\n for (uint256 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 (uint256 i = 0; i < allMarkets_.length; i++) {\n CToken cToken = allMarkets_[i];\n if (markets[address(cToken)].isComped) {\n Exp memory assetPrice = Exp({\n mantissa: oracle.getUnderlyingPrice(cToken)\n });\n Exp memory utility = mul_(assetPrice, cToken.totalBorrows());\n utilities[i] = utility;\n totalUtility = add_(totalUtility, utility);\n }\n }\n\n for (uint256 i = 0; i < allMarkets_.length; i++) {\n CToken cToken = allMarkets[i];\n uint256 newSpeed = totalUtility.mantissa > 0\n ? mul_(compRate, div_(utilities[i], totalUtility))\n : 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 uint256 supplySpeed = compSpeeds[cToken];\n uint256 blockNumber = getBlockNumber();\n uint256 deltaBlocks = sub_(blockNumber, uint256(supplyState.block));\n if (deltaBlocks > 0 && supplySpeed > 0) {\n uint256 supplyTokens = CToken(cToken).totalSupply();\n uint256 compAccrued = mul_(deltaBlocks, supplySpeed);\n Double memory ratio = supplyTokens > 0\n ? fraction(compAccrued, supplyTokens)\n : Double({mantissa: 0});\n Double memory index = add_(\n Double({mantissa: supplyState.index}),\n ratio\n );\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(\n blockNumber,\n \"block number exceeds 32 bits\"\n );\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)\n internal\n {\n CompMarketState storage borrowState = compBorrowState[cToken];\n uint256 borrowSpeed = compSpeeds[cToken];\n uint256 blockNumber = getBlockNumber();\n uint256 deltaBlocks = sub_(blockNumber, uint256(borrowState.block));\n if (deltaBlocks > 0 && borrowSpeed > 0) {\n uint256 borrowAmount = div_(\n CToken(cToken).totalBorrows(),\n marketBorrowIndex\n );\n uint256 compAccrued = mul_(deltaBlocks, borrowSpeed);\n Double memory ratio = borrowAmount > 0\n ? fraction(compAccrued, borrowAmount)\n : Double({mantissa: 0});\n Double memory index = add_(\n Double({mantissa: borrowState.index}),\n ratio\n );\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(\n blockNumber,\n \"block number exceeds 32 bits\"\n );\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(\n address cToken,\n address supplier,\n bool distributeAll\n ) internal {\n CompMarketState storage supplyState = compSupplyState[cToken];\n Double memory supplyIndex = Double({mantissa: supplyState.index});\n Double memory supplierIndex = Double({\n mantissa: compSupplierIndex[cToken][supplier]\n });\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 uint256 supplierTokens = CToken(cToken).balanceOf(supplier);\n uint256 supplierDelta = mul_(supplierTokens, deltaIndex);\n uint256 supplierAccrued = add_(compAccrued[supplier], supplierDelta);\n compAccrued[supplier] = transferComp(\n supplier,\n supplierAccrued,\n distributeAll ? 0 : compClaimThreshold\n );\n emit DistributedSupplierComp(\n CToken(cToken),\n supplier,\n supplierDelta,\n supplyIndex.mantissa\n );\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(\n address cToken,\n address borrower,\n Exp memory marketBorrowIndex,\n bool distributeAll\n ) internal {\n CompMarketState storage borrowState = compBorrowState[cToken];\n Double memory borrowIndex = Double({mantissa: borrowState.index});\n Double memory borrowerIndex = Double({\n mantissa: compBorrowerIndex[cToken][borrower]\n });\n compBorrowerIndex[cToken][borrower] = borrowIndex.mantissa;\n\n if (borrowerIndex.mantissa > 0) {\n Double memory deltaIndex = sub_(borrowIndex, borrowerIndex);\n uint256 borrowerAmount = div_(\n CToken(cToken).borrowBalanceStored(borrower),\n marketBorrowIndex\n );\n uint256 borrowerDelta = mul_(borrowerAmount, deltaIndex);\n uint256 borrowerAccrued = add_(\n compAccrued[borrower],\n borrowerDelta\n );\n compAccrued[borrower] = transferComp(\n borrower,\n borrowerAccrued,\n distributeAll ? 0 : compClaimThreshold\n );\n emit DistributedBorrowerComp(\n CToken(cToken),\n borrower,\n borrowerDelta,\n borrowIndex.mantissa\n );\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(\n address user,\n uint256 userAccrued,\n uint256 threshold\n ) internal returns (uint256) {\n if (userAccrued >= threshold && userAccrued > 0) {\n TROP comp = TROP(getCompAddress());\n uint256 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 uint256 compSpeed = compContributorSpeeds[contributor];\n uint256 blockNumber = getBlockNumber();\n uint256 deltaBlocks = sub_(\n blockNumber,\n lastContributorBlock[contributor]\n );\n if (deltaBlocks > 0 && compSpeed > 0) {\n uint256 newAccrued = mul_(deltaBlocks, compSpeed);\n uint256 contributorAccrued = add_(\n compAccrued[contributor],\n newAccrued\n );\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(\n address[] memory holders,\n CToken[] memory cTokens,\n bool borrowers,\n bool suppliers\n ) public {\n for (uint256 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 (uint256 j = 0; j < holders.length; j++) {\n distributeBorrowerComp(\n address(cToken),\n holders[j],\n borrowIndex,\n true\n );\n }\n }\n if (suppliers == true) {\n updateCompSupplyIndex(address(cToken));\n for (uint256 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, uint256 amount)\n internal\n returns (uint256)\n {\n TROP comp = TROP(getCompAddress());\n uint256 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, uint256 amount) public {\n require(adminOrInitializing(), \"only admin can grant comp\");\n uint256 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, uint256 compSpeed)\n public\n {\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(uint256 compRate_) public {\n require(adminOrInitializing(), \"only admin can change comp rate\");\n\n uint256 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 (uint256 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 (\n compSupplyState[cToken].index == 0 &&\n compSupplyState[cToken].block == 0\n ) {\n compSupplyState[cToken] = CompMarketState({\n index: compInitialIndex,\n block: safe32(getBlockNumber(), \"block number exceeds 32 bits\")\n });\n }\n\n if (\n compBorrowState[cToken].index == 0 &&\n compBorrowState[cToken].block == 0\n ) {\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 virtual returns (uint256) {\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 virtual returns (address) {\n return 0xc00e94Cb662C3520282E6f5717214004A7f26888;\n }\n}\n" - }, - "contracts/CToken.sol": { - "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity 0.8.6;\n\nimport \"./ComptrollerInterface.sol\";\nimport \"./CTokenInterfaces.sol\";\nimport \"./ErrorReporter.sol\";\nimport \"./Exponential.sol\";\nimport \"./EIP20Interface.sol\";\nimport \"./InterestRateModel.sol\";\nimport \"./WhitelistInterface.sol\";\n\n/**\n * @title tropykus CToken Contract\n * @notice Abstract base for CTokens\n * @author tropykus\n */\nabstract contract CToken is CTokenInterface, Exponential, TokenErrorReporter {\n address whitelist;\n\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(\n ComptrollerInterface comptroller_,\n InterestRateModel interestRateModel_,\n uint256 initialExchangeRateMantissa_,\n string memory name_,\n string memory symbol_,\n uint8 decimals_\n ) public {\n require(msg.sender == admin, \"CT01\");\n require(accrualBlockNumber == 0 && borrowIndex == 0, \"CT02\");\n\n initialExchangeRateMantissa = initialExchangeRateMantissa_;\n require(initialExchangeRateMantissa > 0, \"CT03\");\n\n uint256 err = _setComptroller(comptroller_);\n require(err == uint256(Error.NO_ERROR), \"CT04\");\n\n accrualBlockNumber = getBlockNumber();\n borrowIndex = mantissaOne;\n\n err = _setInterestRateModelFresh(interestRateModel_);\n require(err == uint256(Error.NO_ERROR), \"CT05\");\n\n name = name_;\n symbol = symbol_;\n decimals = decimals_;\n\n _notEntered = true;\n }\n\n function addWhitelist(address _whitelist) external returns (uint256) {\n if (msg.sender != admin) {\n return\n fail(\n Error.UNAUTHORIZED,\n FailureInfo.SET_INTEREST_RATE_MODEL_OWNER_CHECK\n );\n }\n whitelist = _whitelist;\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(\n address spender,\n address src,\n address dst,\n uint256 tokens\n ) internal returns (uint256) {\n uint256 allowed = comptroller.transferAllowed(\n address(this),\n src,\n dst,\n tokens\n );\n if (allowed != 0) {\n return\n failOpaque(\n Error.COMPTROLLER_REJECTION,\n FailureInfo.TRANSFER_COMPTROLLER_REJECTION,\n allowed\n );\n }\n\n if (src == dst) {\n return fail(Error.BAD_INPUT, FailureInfo.TRANSFER_NOT_ALLOWED);\n }\n\n uint256 startingAllowance = 0;\n if (spender == src) {\n startingAllowance = type(uint256).max;\n } else {\n startingAllowance = transferAllowances[src][spender];\n }\n\n MathError mathErr;\n uint256 allowanceNew;\n uint256 srcTokensNew;\n uint256 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, 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, tokens);\n if (mathErr != MathError.NO_ERROR) {\n return fail(Error.MATH_ERROR, FailureInfo.TRANSFER_TOO_MUCH);\n }\n\n accountTokens[src].tokens = srcTokensNew;\n accountTokens[dst].tokens = dstTokensNew;\n\n if (startingAllowance != type(uint256).max) {\n transferAllowances[src][spender] = allowanceNew;\n }\n\n emit Transfer(src, dst, tokens);\n\n return uint256(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)\n external\n override\n nonReentrant\n returns (bool)\n {\n return\n transferTokens(msg.sender, msg.sender, dst, amount) ==\n uint256(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(\n address src,\n address dst,\n uint256 amount\n ) external override nonReentrant returns (bool) {\n return\n transferTokens(msg.sender, src, dst, amount) ==\n uint256(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)\n external\n override\n returns (bool)\n {\n transferAllowances[msg.sender][spender] = amount;\n emit Approval(msg.sender, 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)\n external\n view\n override\n returns (uint256)\n {\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 override returns (uint256) {\n return accountTokens[owner].tokens;\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)\n external\n override\n returns (uint256)\n {\n (MathError mErr, uint256 balance) = mulScalarTruncate(\n Exp({mantissa: exchangeRateCurrent()}),\n accountTokens[owner].tokens\n );\n require(mErr == MathError.NO_ERROR, \"CT06\");\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)\n external\n view\n override\n returns (\n uint256,\n uint256,\n uint256,\n uint256\n )\n {\n uint256 cTokenBalance = accountTokens[account].tokens;\n uint256 borrowBalance;\n uint256 exchangeRateMantissa;\n\n MathError mErr;\n\n (mErr, borrowBalance) = borrowBalanceStoredInternal(account);\n if (mErr != MathError.NO_ERROR) {\n return (uint256(Error.MATH_ERROR), 0, 0, 0);\n }\n\n (mErr, exchangeRateMantissa) = exchangeRateStoredInternal();\n if (mErr != MathError.NO_ERROR) {\n return (uint256(Error.MATH_ERROR), 0, 0, 0);\n }\n\n return (\n uint256(Error.NO_ERROR),\n cTokenBalance,\n borrowBalance,\n exchangeRateMantissa\n );\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 virtual returns (uint256) {\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 override returns (uint256) {\n return\n interestRateModel.getBorrowRate(\n getCashPrior(),\n totalBorrows,\n totalReserves\n );\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 override returns (uint256) {\n return\n interestRateModel.getSupplyRate(\n getCashPrior(),\n totalBorrows,\n totalReserves,\n reserveFactorMantissa\n );\n }\n\n /**\n * @notice Returns the current total borrows plus accrued interest\n * @return The total borrows with interest\n */\n function totalBorrowsCurrent()\n external\n override\n nonReentrant\n returns (uint256)\n {\n require(accrueInterest() == uint256(Error.NO_ERROR), \"CT07\");\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)\n external\n override\n nonReentrant\n returns (uint256)\n {\n require(accrueInterest() == uint256(Error.NO_ERROR), \"CT07\");\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)\n public\n view\n override\n returns (uint256)\n {\n (MathError err, uint256 result) = borrowBalanceStoredInternal(account);\n require(err == MathError.NO_ERROR, \"CT08\");\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)\n internal\n view\n returns (MathError, uint256)\n {\n MathError mathErr;\n uint256 principalTimesIndex;\n uint256 result;\n\n BorrowSnapshot storage borrowSnapshot = accountBorrows[account];\n\n if (borrowSnapshot.principal == 0) {\n return (MathError.NO_ERROR, 0);\n }\n\n (mathErr, principalTimesIndex) = mulUInt(\n borrowSnapshot.principal,\n borrowIndex\n );\n if (mathErr != MathError.NO_ERROR) {\n return (mathErr, 0);\n }\n\n (mathErr, result) = divUInt(\n principalTimesIndex,\n borrowSnapshot.interestIndex\n );\n if (mathErr != MathError.NO_ERROR) {\n return (mathErr, 0);\n }\n\n return (MathError.NO_ERROR, result);\n }\n\n function getBorrowerPrincipalStored(address account)\n public\n view\n returns (uint256 borrowed)\n {\n borrowed = accountBorrows[account].principal;\n }\n\n function getSupplierSnapshotStored(address account)\n public\n view\n returns (\n uint256 tokens,\n uint256 underlyingAmount,\n uint256 suppliedAt,\n uint256 promisedSupplyRate\n )\n {\n tokens = accountTokens[account].tokens;\n underlyingAmount = accountTokens[account].underlyingAmount;\n suppliedAt = accountTokens[account].suppliedAt;\n promisedSupplyRate = accountTokens[account].promisedSupplyRate;\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()\n public\n override\n nonReentrant\n returns (uint256)\n {\n require(accrueInterest() == uint256(Error.NO_ERROR), \"CT07\");\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 override returns (uint256) {\n (MathError err, uint256 result) = exchangeRateStoredInternal();\n require(err == MathError.NO_ERROR, \"CT09\");\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()\n internal\n view\n virtual\n returns (MathError, uint256)\n {\n uint256 _totalSupply = totalSupply;\n if (_totalSupply == 0) {\n return (MathError.NO_ERROR, initialExchangeRateMantissa);\n } else {\n MathError error;\n uint256 exchangeRate;\n uint256 totalCash = getCashPrior();\n if (interestRateModel.isTropykusInterestRateModel()) {\n (error, exchangeRate) = tropykusExchangeRateStoredInternal(\n msg.sender\n );\n if (error == MathError.NO_ERROR) {\n return (MathError.NO_ERROR, exchangeRate);\n } else {\n return (MathError.NO_ERROR, initialExchangeRateMantissa);\n }\n }\n return\n interestRateModel.getExchangeRate(\n totalCash,\n totalBorrows,\n totalReserves,\n totalSupply\n );\n }\n }\n\n function tropykusExchangeRateStoredInternal(address redeemer)\n internal\n view\n returns (MathError, uint256)\n {\n if (totalSupply == 0) {\n return (MathError.NO_ERROR, initialExchangeRateMantissa);\n } else {\n SupplySnapshot storage supplySnapshot = accountTokens[redeemer];\n if (supplySnapshot.suppliedAt == 0) {\n return (MathError.DIVISION_BY_ZERO, 0);\n }\n (, uint256 interestFactorMantissa, ) = tropykusInterestAccrued(\n redeemer\n );\n Exp memory interestFactor = Exp({mantissa: interestFactorMantissa});\n uint256 currentUnderlying = supplySnapshot.underlyingAmount;\n Exp memory redeemerUnderlying = Exp({mantissa: currentUnderlying});\n (, Exp memory realAmount) = mulExp(\n interestFactor,\n redeemerUnderlying\n );\n (, Exp memory exchangeRate) = getExp(\n realAmount.mantissa,\n supplySnapshot.tokens\n );\n return (MathError.NO_ERROR, exchangeRate.mantissa);\n }\n }\n\n function tropykusInterestAccrued(address account)\n internal\n view\n returns (\n MathError,\n uint256,\n uint256\n )\n {\n SupplySnapshot storage supplySnapshot = accountTokens[account];\n uint256 promisedSupplyRate = supplySnapshot.promisedSupplyRate;\n Exp memory expectedSupplyRatePerBlock = Exp({\n mantissa: promisedSupplyRate\n });\n (, uint256 delta) = subUInt(\n accrualBlockNumber,\n supplySnapshot.suppliedAt\n );\n (, Exp memory expectedSupplyRatePerBlockWithDelta) = mulScalar(\n expectedSupplyRatePerBlock,\n delta\n );\n (, Exp memory interestFactor) = addExp(\n Exp({mantissa: 1e18}),\n expectedSupplyRatePerBlockWithDelta\n );\n uint256 currentUnderlying = supplySnapshot.underlyingAmount;\n Exp memory redeemerUnderlying = Exp({mantissa: currentUnderlying});\n (, Exp memory realAmount) = mulExp(interestFactor, redeemerUnderlying);\n (, uint256 interestEarned) = subUInt(\n realAmount.mantissa,\n currentUnderlying\n );\n return (MathError.NO_ERROR, interestFactor.mantissa, interestEarned);\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 override returns (uint256) {\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 override returns (uint256) {\n uint256 currentBlockNumber = getBlockNumber();\n uint256 accrualBlockNumberPrior = accrualBlockNumber;\n\n if (accrualBlockNumberPrior == currentBlockNumber) {\n return uint256(Error.NO_ERROR);\n }\n\n uint256 cashPrior = getCashPrior();\n uint256 borrowsPrior = totalBorrows;\n uint256 reservesPrior = totalReserves;\n uint256 borrowIndexPrior = borrowIndex;\n\n uint256 borrowRateMantissa = interestRateModel.getBorrowRate(\n cashPrior,\n borrowsPrior,\n reservesPrior\n );\n require(borrowRateMantissa <= borrowRateMaxMantissa, \"CT10\");\n\n (MathError mathErr, uint256 blockDelta) = subUInt(\n currentBlockNumber,\n accrualBlockNumberPrior\n );\n require(mathErr == MathError.NO_ERROR, \"CT11\");\n\n Exp memory simpleInterestFactor;\n uint256 interestAccumulated;\n uint256 totalBorrowsNew;\n uint256 totalReservesNew;\n uint256 borrowIndexNew;\n\n (mathErr, simpleInterestFactor) = mulScalar(\n Exp({mantissa: borrowRateMantissa}),\n blockDelta\n );\n if (mathErr != MathError.NO_ERROR) {\n return\n failOpaque(\n Error.MATH_ERROR,\n FailureInfo\n .ACCRUE_INTEREST_SIMPLE_INTEREST_FACTOR_CALCULATION_FAILED,\n uint256(mathErr)\n );\n }\n\n (mathErr, interestAccumulated) = mulScalarTruncate(\n simpleInterestFactor,\n borrowsPrior\n );\n if (mathErr != MathError.NO_ERROR) {\n return\n failOpaque(\n Error.MATH_ERROR,\n FailureInfo\n .ACCRUE_INTEREST_ACCUMULATED_INTEREST_CALCULATION_FAILED,\n uint256(mathErr)\n );\n }\n\n (mathErr, totalBorrowsNew) = addUInt(interestAccumulated, borrowsPrior);\n if (mathErr != MathError.NO_ERROR) {\n return\n failOpaque(\n Error.MATH_ERROR,\n FailureInfo\n .ACCRUE_INTEREST_NEW_TOTAL_BORROWS_CALCULATION_FAILED,\n uint256(mathErr)\n );\n }\n\n (mathErr, totalReservesNew) = mulScalarTruncateAddUInt(\n Exp({mantissa: reserveFactorMantissa}),\n interestAccumulated,\n reservesPrior\n );\n if (mathErr != MathError.NO_ERROR) {\n return\n failOpaque(\n Error.MATH_ERROR,\n FailureInfo\n .ACCRUE_INTEREST_NEW_TOTAL_RESERVES_CALCULATION_FAILED,\n uint256(mathErr)\n );\n }\n\n if (interestRateModel.isTropykusInterestRateModel()) {\n (mathErr, totalReservesNew) = newReserves(\n borrowRateMantissa,\n cashPrior,\n borrowsPrior,\n reservesPrior,\n interestAccumulated\n );\n if (mathErr != MathError.NO_ERROR) {\n return\n failOpaque(\n Error.MATH_ERROR,\n FailureInfo\n .ACCRUE_INTEREST_NEW_TOTAL_RESERVES_CALCULATION_FAILED,\n uint256(mathErr)\n );\n }\n }\n\n (mathErr, borrowIndexNew) = mulScalarTruncateAddUInt(\n simpleInterestFactor,\n borrowIndexPrior,\n borrowIndexPrior\n );\n if (mathErr != MathError.NO_ERROR) {\n return\n failOpaque(\n Error.MATH_ERROR,\n FailureInfo\n .ACCRUE_INTEREST_NEW_BORROW_INDEX_CALCULATION_FAILED,\n uint256(mathErr)\n );\n }\n\n accrualBlockNumber = currentBlockNumber;\n borrowIndex = borrowIndexNew;\n totalBorrows = totalBorrowsNew;\n totalReserves = totalReservesNew;\n\n emit AccrueInterest(\n cashPrior,\n interestAccumulated,\n borrowIndexNew,\n totalBorrowsNew\n );\n\n return uint256(Error.NO_ERROR);\n }\n\n function newReserves(\n uint256 borrowRateMantissa,\n uint256 cashPrior,\n uint256 borrowsPrior,\n uint256 reservesPrior,\n uint256 interestAccumulated\n ) internal view returns (MathError mathErr, uint256 totalReservesNew) {\n uint256 newReserveFactorMantissa;\n uint256 utilizationRate = interestRateModel.utilizationRate(\n cashPrior,\n borrowsPrior,\n reservesPrior\n );\n uint256 expectedSupplyRate = interestRateModel.getSupplyRate(\n cashPrior,\n borrowsPrior,\n reservesPrior,\n reserveFactorMantissa\n );\n if (\n interestRateModel.isAboveOptimal(\n cashPrior,\n borrowsPrior,\n reservesPrior\n )\n ) {\n (mathErr, newReserveFactorMantissa) = mulScalarTruncate(\n Exp({mantissa: utilizationRate}),\n borrowRateMantissa\n );\n if (mathErr != MathError.NO_ERROR) {\n return (mathErr, 0);\n }\n (mathErr, newReserveFactorMantissa) = subUInt(\n newReserveFactorMantissa,\n expectedSupplyRate\n );\n if (mathErr != MathError.NO_ERROR) {\n return (mathErr, 0);\n }\n (mathErr, totalReservesNew) = mulScalarTruncateAddUInt(\n Exp({mantissa: newReserveFactorMantissa}),\n interestAccumulated,\n reservesPrior\n );\n if (mathErr != MathError.NO_ERROR) {\n return (mathErr, 0);\n }\n } else {\n mathErr = MathError.NO_ERROR;\n totalReservesNew = reservesPrior;\n }\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(uint256 mintAmount)\n internal\n nonReentrant\n returns (uint256, uint256)\n {\n if (WhitelistInterface(whitelist).enabled()) {\n require(WhitelistInterface(whitelist).exist(msg.sender), \"CT26\");\n }\n uint256 error = accrueInterest();\n if (error != uint256(Error.NO_ERROR)) {\n return (\n fail(Error(error), FailureInfo.MINT_ACCRUE_INTEREST_FAILED),\n 0\n );\n }\n return mintFresh(msg.sender, mintAmount);\n }\n\n struct MintLocalVars {\n Error err;\n MathError mathErr;\n uint256 exchangeRateMantissa;\n uint256 mintTokens;\n uint256 totalSupplyNew;\n uint256 accountTokensNew;\n uint256 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, uint256 mintAmount)\n internal\n returns (uint256, uint256)\n {\n uint256 allowed = comptroller.mintAllowed(\n address(this),\n minter,\n mintAmount\n );\n if (allowed != 0) {\n return (\n failOpaque(\n Error.COMPTROLLER_REJECTION,\n FailureInfo.MINT_COMPTROLLER_REJECTION,\n allowed\n ),\n 0\n );\n }\n\n if (accrualBlockNumber != getBlockNumber()) {\n return (\n fail(Error.MARKET_NOT_FRESH, FailureInfo.MINT_FRESHNESS_CHECK),\n 0\n );\n }\n\n MintLocalVars memory vars;\n\n (\n vars.mathErr,\n vars.exchangeRateMantissa\n ) = exchangeRateStoredInternal();\n if (vars.mathErr != MathError.NO_ERROR) {\n return (\n failOpaque(\n Error.MATH_ERROR,\n FailureInfo.MINT_EXCHANGE_RATE_READ_FAILED,\n uint256(vars.mathErr)\n ),\n 0\n );\n }\n if (interestRateModel.isTropykusInterestRateModel()) {\n SupplySnapshot storage supplySnapshot = accountTokens[minter];\n (, uint256 newTotalSupply) = addUInt(\n supplySnapshot.underlyingAmount,\n mintAmount\n );\n require(newTotalSupply <= 0.1e18, \"CT24\");\n }\n vars.actualMintAmount = doTransferIn(minter, mintAmount);\n\n (vars.mathErr, vars.mintTokens) = divScalarByExpTruncate(\n vars.actualMintAmount,\n Exp({mantissa: vars.exchangeRateMantissa})\n );\n require(vars.mathErr == MathError.NO_ERROR, \"CT12\");\n\n (vars.mathErr, vars.totalSupplyNew) = addUInt(\n totalSupply,\n vars.mintTokens\n );\n require(vars.mathErr == MathError.NO_ERROR, \"CT13\");\n\n (vars.mathErr, vars.accountTokensNew) = addUInt(\n accountTokens[minter].tokens,\n vars.mintTokens\n );\n require(vars.mathErr == MathError.NO_ERROR, \"CT14\");\n\n uint256 currentSupplyRate = interestRateModel.getSupplyRate(\n getCashPrior(),\n totalBorrows,\n totalReserves,\n reserveFactorMantissa\n );\n\n bool isTropykusInterestRateModel = interestRateModel\n .isTropykusInterestRateModel();\n\n if (accountTokens[minter].tokens > 0) {\n Exp memory updatedUnderlying;\n if (isTropykusInterestRateModel) {\n (, uint256 interestFactorMantissa, ) = tropykusInterestAccrued(\n minter\n );\n Exp memory interestFactor = Exp({\n mantissa: interestFactorMantissa\n });\n uint256 currentUnderlyingAmount = accountTokens[minter]\n .underlyingAmount;\n MathError mErrorNewAmount;\n (mErrorNewAmount, updatedUnderlying) = mulExp(\n Exp({mantissa: currentUnderlyingAmount}),\n interestFactor\n );\n if (mErrorNewAmount != MathError.NO_ERROR) {\n return (\n failOpaque(\n Error.MATH_ERROR,\n FailureInfo.MINT_EXCHANGE_CALCULATION_FAILED,\n uint256(mErrorNewAmount)\n ),\n 0\n );\n }\n } else {\n uint256 currentTokens = accountTokens[minter].tokens;\n MathError mErrorUpdatedUnderlying;\n (mErrorUpdatedUnderlying, updatedUnderlying) = mulExp(\n Exp({mantissa: currentTokens}),\n Exp({mantissa: vars.exchangeRateMantissa})\n );\n if (mErrorUpdatedUnderlying != MathError.NO_ERROR) {\n return (\n failOpaque(\n Error.MATH_ERROR,\n FailureInfo.MINT_EXCHANGE_CALCULATION_FAILED,\n uint256(mErrorUpdatedUnderlying)\n ),\n 0\n );\n }\n }\n (, mintAmount) = addUInt(updatedUnderlying.mantissa, mintAmount);\n }\n\n totalSupply = vars.totalSupplyNew;\n accountTokens[minter] = SupplySnapshot({\n tokens: vars.accountTokensNew,\n underlyingAmount: mintAmount,\n suppliedAt: accrualBlockNumber,\n promisedSupplyRate: currentSupplyRate\n });\n\n emit Mint(minter, vars.actualMintAmount, vars.mintTokens);\n emit Transfer(address(this), minter, vars.mintTokens);\n\n return (uint256(Error.NO_ERROR), vars.actualMintAmount);\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(uint256 redeemAmount)\n internal\n nonReentrant\n returns (uint256)\n {\n uint256 error = accrueInterest();\n if (error != uint256(Error.NO_ERROR)) {\n return\n fail(Error(error), FailureInfo.REDEEM_ACCRUE_INTEREST_FAILED);\n }\n return redeemFresh(payable(msg.sender), redeemAmount);\n }\n\n struct RedeemLocalVars {\n Error err;\n MathError mathErr;\n uint256 exchangeRateMantissa;\n uint256 redeemTokens;\n uint256 redeemAmount;\n uint256 totalSupplyNew;\n uint256 accountTokensNew;\n uint256 newSubsidyFund;\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 redeemAmountIn The number of underlying tokens to receive from redeeming cTokens\n * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)\n */\n function redeemFresh(address payable redeemer, uint256 redeemAmountIn)\n internal\n returns (uint256)\n {\n require(redeemAmountIn > 0, \"CT15\");\n\n RedeemLocalVars memory vars;\n\n SupplySnapshot storage supplySnapshot = accountTokens[redeemer];\n\n (\n vars.mathErr,\n vars.exchangeRateMantissa\n ) = exchangeRateStoredInternal();\n if (vars.mathErr != MathError.NO_ERROR) {\n return\n failOpaque(\n Error.MATH_ERROR,\n FailureInfo.REDEEM_EXCHANGE_RATE_READ_FAILED,\n uint256(vars.mathErr)\n );\n }\n\n uint256 interestEarned;\n uint256 subsidyFundPortion;\n uint256 currentUnderlying;\n\n bool isTropykusInterestRateModel = interestRateModel\n .isTropykusInterestRateModel();\n if (isTropykusInterestRateModel) {\n currentUnderlying = supplySnapshot.underlyingAmount;\n (, , interestEarned) = tropykusInterestAccrued(redeemer);\n }\n supplySnapshot.promisedSupplyRate = interestRateModel.getSupplyRate(\n getCashPrior(),\n totalBorrows,\n totalReserves,\n reserveFactorMantissa\n );\n\n if (\n isTropykusInterestRateModel &&\n !interestRateModel.isAboveOptimal(\n getCashPrior(),\n totalBorrows,\n totalReserves\n )\n ) {\n uint256 borrowRate = interestRateModel.getBorrowRate(\n getCashPrior(),\n totalBorrows,\n totalReserves\n );\n\n uint256 utilizationRate = interestRateModel.utilizationRate(\n getCashPrior(),\n totalBorrows,\n totalReserves\n );\n\n (, uint256 estimatedEarning) = mulScalarTruncate(\n Exp({mantissa: borrowRate}),\n utilizationRate\n );\n\n (, subsidyFundPortion) = subUInt(\n supplySnapshot.promisedSupplyRate,\n estimatedEarning\n );\n (, Exp memory subsidyFactor) = getExp(\n subsidyFundPortion,\n supplySnapshot.promisedSupplyRate\n );\n (, subsidyFundPortion) = mulScalarTruncate(\n subsidyFactor,\n interestEarned\n );\n }\n\n vars.redeemAmount = redeemAmountIn;\n\n if (isTropykusInterestRateModel) {\n (, Exp memory num) = mulExp(\n vars.redeemAmount,\n supplySnapshot.tokens\n );\n (, Exp memory realTokensWithdrawAmount) = getExp(\n num.mantissa,\n currentUnderlying\n );\n vars.redeemTokens = realTokensWithdrawAmount.mantissa;\n } else {\n (vars.mathErr, vars.redeemTokens) = divScalarByExpTruncate(\n redeemAmountIn,\n Exp({mantissa: vars.exchangeRateMantissa})\n );\n if (vars.mathErr != MathError.NO_ERROR) {\n return\n failOpaque(\n Error.MATH_ERROR,\n FailureInfo.REDEEM_EXCHANGE_AMOUNT_CALCULATION_FAILED,\n uint256(vars.mathErr)\n );\n }\n }\n // }\n\n uint256 allowed = comptroller.redeemAllowed(\n address(this),\n redeemer,\n vars.redeemTokens\n );\n if (allowed != 0) {\n return\n failOpaque(\n Error.COMPTROLLER_REJECTION,\n FailureInfo.REDEEM_COMPTROLLER_REJECTION,\n allowed\n );\n }\n\n if (accrualBlockNumber != getBlockNumber()) {\n return\n fail(\n Error.MARKET_NOT_FRESH,\n FailureInfo.REDEEM_FRESHNESS_CHECK\n );\n }\n\n (vars.mathErr, vars.totalSupplyNew) = subUInt(\n totalSupply,\n vars.redeemTokens\n );\n if (vars.mathErr != MathError.NO_ERROR) {\n return\n failOpaque(\n Error.MATH_ERROR,\n FailureInfo.REDEEM_NEW_TOTAL_SUPPLY_CALCULATION_FAILED,\n uint256(vars.mathErr)\n );\n }\n\n (, vars.newSubsidyFund) = subUInt(subsidyFund, subsidyFundPortion);\n\n (vars.mathErr, vars.accountTokensNew) = subUInt(\n supplySnapshot.tokens,\n vars.redeemTokens\n );\n if (vars.mathErr != MathError.NO_ERROR) {\n return\n failOpaque(\n Error.MATH_ERROR,\n FailureInfo.REDEEM_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED,\n uint256(vars.mathErr)\n );\n }\n\n uint256 cash = getCashPrior();\n if (isTropykusInterestRateModel) {\n cash = address(this).balance;\n }\n\n if (cash < vars.redeemAmount) {\n return\n fail(\n Error.TOKEN_INSUFFICIENT_CASH,\n FailureInfo.REDEEM_TRANSFER_OUT_NOT_POSSIBLE\n );\n }\n\n doTransferOut(redeemer, vars.redeemAmount);\n\n totalSupply = vars.totalSupplyNew;\n subsidyFund = vars.newSubsidyFund;\n supplySnapshot.tokens = vars.accountTokensNew;\n supplySnapshot.suppliedAt = accrualBlockNumber;\n (, supplySnapshot.underlyingAmount) = subUInt(\n supplySnapshot.underlyingAmount,\n vars.redeemAmount\n );\n\n emit Transfer(redeemer, address(this), vars.redeemTokens);\n emit Redeem(redeemer, vars.redeemAmount, vars.redeemTokens);\n\n comptroller.redeemVerify(\n address(this),\n redeemer,\n vars.redeemAmount,\n vars.redeemTokens\n );\n\n return uint256(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(uint256 borrowAmount)\n internal\n nonReentrant\n returns (uint256)\n {\n uint256 error = accrueInterest();\n if (error != uint256(Error.NO_ERROR)) {\n return\n fail(Error(error), FailureInfo.BORROW_ACCRUE_INTEREST_FAILED);\n }\n return borrowFresh(payable(msg.sender), borrowAmount);\n }\n\n struct BorrowLocalVars {\n MathError mathErr;\n uint256 accountBorrows;\n uint256 accountBorrowsNew;\n uint256 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, uint256 borrowAmount)\n internal\n returns (uint256)\n {\n uint256 allowed = comptroller.borrowAllowed(\n address(this),\n borrower,\n borrowAmount\n );\n if (allowed != 0) {\n return\n failOpaque(\n Error.COMPTROLLER_REJECTION,\n FailureInfo.BORROW_COMPTROLLER_REJECTION,\n allowed\n );\n }\n\n if (accrualBlockNumber != getBlockNumber()) {\n return\n fail(\n Error.MARKET_NOT_FRESH,\n FailureInfo.BORROW_FRESHNESS_CHECK\n );\n }\n\n if (getCashPrior() < borrowAmount) {\n return\n fail(\n Error.TOKEN_INSUFFICIENT_CASH,\n FailureInfo.BORROW_CASH_NOT_AVAILABLE\n );\n }\n\n BorrowLocalVars memory vars;\n\n (vars.mathErr, vars.accountBorrows) = borrowBalanceStoredInternal(\n borrower\n );\n if (vars.mathErr != MathError.NO_ERROR) {\n return\n failOpaque(\n Error.MATH_ERROR,\n FailureInfo.BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED,\n uint256(vars.mathErr)\n );\n }\n\n (vars.mathErr, vars.accountBorrowsNew) = addUInt(\n vars.accountBorrows,\n borrowAmount\n );\n if (vars.mathErr != MathError.NO_ERROR) {\n return\n failOpaque(\n Error.MATH_ERROR,\n FailureInfo\n .BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED,\n uint256(vars.mathErr)\n );\n }\n\n (vars.mathErr, vars.totalBorrowsNew) = addUInt(\n totalBorrows,\n borrowAmount\n );\n if (interestRateModel.isTropykusInterestRateModel()) {\n require(vars.totalBorrowsNew <= 0.1e18, \"CT25\");\n }\n if (vars.mathErr != MathError.NO_ERROR) {\n return\n failOpaque(\n Error.MATH_ERROR,\n FailureInfo.BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED,\n uint256(vars.mathErr)\n );\n }\n\n doTransferOut(borrower, borrowAmount);\n\n accountBorrows[borrower].principal = vars.accountBorrowsNew;\n accountBorrows[borrower].interestIndex = borrowIndex;\n totalBorrows = vars.totalBorrowsNew;\n\n emit Borrow(\n borrower,\n borrowAmount,\n vars.accountBorrowsNew,\n vars.totalBorrowsNew\n );\n\n return uint256(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(uint256 repayAmount)\n internal\n nonReentrant\n returns (uint256, uint256)\n {\n uint256 error = accrueInterest();\n if (error != uint256(Error.NO_ERROR)) {\n return (\n fail(\n Error(error),\n FailureInfo.REPAY_BORROW_ACCRUE_INTEREST_FAILED\n ),\n 0\n );\n }\n return repayBorrowFresh(msg.sender, msg.sender, repayAmount);\n }\n\n struct RepayBorrowLocalVars {\n Error err;\n MathError mathErr;\n uint256 repayAmount;\n uint256 borrowerIndex;\n uint256 accountBorrows;\n uint256 accountBorrowsNew;\n uint256 totalBorrowsNew;\n uint256 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(\n address payer,\n address borrower,\n uint256 repayAmount\n ) internal returns (uint256, uint256) {\n uint256 allowed = comptroller.repayBorrowAllowed(\n address(this),\n payer,\n borrower,\n repayAmount\n );\n if (allowed != 0) {\n return (\n failOpaque(\n Error.COMPTROLLER_REJECTION,\n FailureInfo.REPAY_BORROW_COMPTROLLER_REJECTION,\n allowed\n ),\n 0\n );\n }\n\n if (accrualBlockNumber != getBlockNumber()) {\n return (\n fail(\n Error.MARKET_NOT_FRESH,\n FailureInfo.REPAY_BORROW_FRESHNESS_CHECK\n ),\n 0\n );\n }\n\n RepayBorrowLocalVars memory vars;\n\n vars.borrowerIndex = accountBorrows[borrower].interestIndex;\n\n (vars.mathErr, vars.accountBorrows) = borrowBalanceStoredInternal(\n borrower\n );\n if (vars.mathErr != MathError.NO_ERROR) {\n return (\n failOpaque(\n Error.MATH_ERROR,\n FailureInfo\n .REPAY_BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED,\n uint256(vars.mathErr)\n ),\n 0\n );\n }\n\n if (repayAmount == type(uint256).max) {\n vars.repayAmount = vars.accountBorrows;\n } else {\n vars.repayAmount = repayAmount;\n }\n\n vars.actualRepayAmount = doTransferIn(payer, vars.repayAmount);\n\n (vars.mathErr, vars.accountBorrowsNew) = subUInt(\n vars.accountBorrows,\n vars.actualRepayAmount\n );\n require(vars.mathErr == MathError.NO_ERROR, \"CT16\");\n\n (vars.mathErr, vars.totalBorrowsNew) = subUInt(\n totalBorrows,\n vars.actualRepayAmount\n );\n require(vars.mathErr == MathError.NO_ERROR, \"CT17\");\n\n accountBorrows[borrower].principal = vars.accountBorrowsNew;\n accountBorrows[borrower].interestIndex = borrowIndex;\n totalBorrows = vars.totalBorrowsNew;\n\n emit RepayBorrow(\n payer,\n borrower,\n vars.actualRepayAmount,\n vars.accountBorrowsNew,\n vars.totalBorrowsNew\n );\n\n return (uint256(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(\n address borrower,\n uint256 repayAmount,\n CTokenInterface cTokenCollateral\n ) internal nonReentrant returns (uint256, uint256) {\n uint256 error = accrueInterest();\n if (error != uint256(Error.NO_ERROR)) {\n return (\n fail(\n Error(error),\n FailureInfo.LIQUIDATE_ACCRUE_BORROW_INTEREST_FAILED\n ),\n 0\n );\n }\n\n error = cTokenCollateral.accrueInterest();\n if (error != uint256(Error.NO_ERROR)) {\n return (\n fail(\n Error(error),\n FailureInfo.LIQUIDATE_ACCRUE_COLLATERAL_INTEREST_FAILED\n ),\n 0\n );\n }\n\n // liquidateBorrowFresh emits borrow-specific logs on errors, so we don't need to\n return\n liquidateBorrowFresh(\n msg.sender,\n borrower,\n repayAmount,\n cTokenCollateral\n );\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(\n address liquidator,\n address borrower,\n uint256 repayAmount,\n CTokenInterface cTokenCollateral\n ) internal returns (uint256, uint256) {\n uint256 allowed = comptroller.liquidateBorrowAllowed(\n address(this),\n address(cTokenCollateral),\n liquidator,\n borrower,\n repayAmount\n );\n if (allowed != 0) {\n return (\n failOpaque(\n Error.COMPTROLLER_REJECTION,\n FailureInfo.LIQUIDATE_COMPTROLLER_REJECTION,\n allowed\n ),\n 0\n );\n }\n\n if (accrualBlockNumber != getBlockNumber()) {\n return (\n fail(\n Error.MARKET_NOT_FRESH,\n FailureInfo.LIQUIDATE_FRESHNESS_CHECK\n ),\n 0\n );\n }\n\n if (cTokenCollateral.accrualBlockNumber() != getBlockNumber()) {\n return (\n fail(\n Error.MARKET_NOT_FRESH,\n FailureInfo.LIQUIDATE_COLLATERAL_FRESHNESS_CHECK\n ),\n 0\n );\n }\n\n if (borrower == liquidator) {\n return (\n fail(\n Error.INVALID_ACCOUNT_PAIR,\n FailureInfo.LIQUIDATE_LIQUIDATOR_IS_BORROWER\n ),\n 0\n );\n }\n\n if (repayAmount == 0) {\n return (\n fail(\n Error.INVALID_CLOSE_AMOUNT_REQUESTED,\n FailureInfo.LIQUIDATE_CLOSE_AMOUNT_IS_ZERO\n ),\n 0\n );\n }\n\n if (repayAmount == type(uint256).max) {\n return (\n fail(\n Error.INVALID_CLOSE_AMOUNT_REQUESTED,\n FailureInfo.LIQUIDATE_CLOSE_AMOUNT_IS_UINT_MAX\n ),\n 0\n );\n }\n\n (\n uint256 repayBorrowError,\n uint256 actualRepayAmount\n ) = repayBorrowFresh(liquidator, borrower, repayAmount);\n if (repayBorrowError != uint256(Error.NO_ERROR)) {\n return (\n fail(\n Error(repayBorrowError),\n FailureInfo.LIQUIDATE_REPAY_BORROW_FRESH_FAILED\n ),\n 0\n );\n }\n\n (uint256 amountSeizeError, uint256 seizeTokens) = comptroller\n .liquidateCalculateSeizeTokens(\n address(this),\n address(cTokenCollateral),\n actualRepayAmount\n );\n require(amountSeizeError == uint256(Error.NO_ERROR), \"CT18\");\n\n require(cTokenCollateral.balanceOf(borrower) >= seizeTokens, \"CT19\");\n\n uint256 seizeError;\n if (address(cTokenCollateral) == address(this)) {\n seizeError = seizeInternal(\n address(this),\n liquidator,\n borrower,\n seizeTokens\n );\n } else {\n seizeError = cTokenCollateral.seize(\n liquidator,\n borrower,\n seizeTokens\n );\n }\n\n require(seizeError == uint256(Error.NO_ERROR), \"CT20\");\n\n emit LiquidateBorrow(\n liquidator,\n borrower,\n actualRepayAmount,\n address(cTokenCollateral),\n seizeTokens\n );\n\n return (uint256(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(\n address liquidator,\n address borrower,\n uint256 seizeTokens\n ) external override nonReentrant returns (uint256) {\n return seizeInternal(msg.sender, liquidator, borrower, seizeTokens);\n }\n\n struct SeizeVars {\n uint256 seizeAmount;\n uint256 exchangeRate;\n uint256 borrowerTokensNew;\n uint256 borrowerAmountNew;\n uint256 liquidatorTokensNew;\n uint256 liquidatorAmountNew;\n uint256 totalCash;\n uint256 supplyRate;\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(\n address seizerToken,\n address liquidator,\n address borrower,\n uint256 seizeTokens\n ) internal returns (uint256) {\n uint256 allowed = comptroller.seizeAllowed(\n address(this),\n seizerToken,\n liquidator,\n borrower,\n seizeTokens\n );\n if (allowed != 0) {\n return\n failOpaque(\n Error.COMPTROLLER_REJECTION,\n FailureInfo.LIQUIDATE_SEIZE_COMPTROLLER_REJECTION,\n allowed\n );\n }\n\n if (borrower == liquidator) {\n return\n fail(\n Error.INVALID_ACCOUNT_PAIR,\n FailureInfo.LIQUIDATE_SEIZE_LIQUIDATOR_IS_BORROWER\n );\n }\n\n SeizeVars memory seizeVars;\n\n MathError mathErr;\n\n (mathErr, seizeVars.borrowerTokensNew) = subUInt(\n accountTokens[borrower].tokens,\n seizeTokens\n );\n if (mathErr != MathError.NO_ERROR) {\n return\n failOpaque(\n Error.MATH_ERROR,\n FailureInfo.LIQUIDATE_SEIZE_BALANCE_DECREMENT_FAILED,\n uint256(mathErr)\n );\n }\n\n seizeVars.totalCash = getCashPrior();\n seizeVars.supplyRate = interestRateModel.getSupplyRate(\n seizeVars.totalCash,\n totalBorrows,\n totalReserves,\n reserveFactorMantissa\n );\n\n (, seizeVars.exchangeRate) = interestRateModel.getExchangeRate(\n seizeVars.totalCash,\n totalBorrows,\n totalReserves,\n totalSupply\n );\n\n if (interestRateModel.isTropykusInterestRateModel()) {\n (, seizeVars.exchangeRate) = tropykusExchangeRateStoredInternal(\n borrower\n );\n }\n\n (, seizeVars.seizeAmount) = mulUInt(\n seizeTokens,\n seizeVars.exchangeRate\n );\n (, seizeVars.seizeAmount) = divUInt(seizeVars.seizeAmount, 1e18);\n\n (, seizeVars.borrowerAmountNew) = subUInt(\n accountTokens[borrower].underlyingAmount,\n seizeVars.seizeAmount\n );\n\n (mathErr, seizeVars.liquidatorTokensNew) = addUInt(\n accountTokens[liquidator].tokens,\n seizeTokens\n );\n if (mathErr != MathError.NO_ERROR) {\n return\n failOpaque(\n Error.MATH_ERROR,\n FailureInfo.LIQUIDATE_SEIZE_BALANCE_INCREMENT_FAILED,\n uint256(mathErr)\n );\n }\n\n (, seizeVars.liquidatorAmountNew) = addUInt(\n accountTokens[liquidator].underlyingAmount,\n seizeVars.seizeAmount\n );\n\n accountTokens[borrower].tokens = seizeVars.borrowerTokensNew;\n accountTokens[borrower].underlyingAmount = seizeVars.borrowerAmountNew;\n accountTokens[borrower].suppliedAt = getBlockNumber();\n accountTokens[borrower].promisedSupplyRate = seizeVars.supplyRate;\n\n accountTokens[liquidator].tokens = seizeVars.liquidatorTokensNew;\n accountTokens[liquidator].underlyingAmount = seizeVars\n .liquidatorAmountNew;\n accountTokens[liquidator].suppliedAt = getBlockNumber();\n accountTokens[liquidator].promisedSupplyRate = seizeVars.supplyRate;\n\n emit Transfer(borrower, liquidator, seizeTokens);\n\n return uint256(Error.NO_ERROR);\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 payable newPendingAdmin)\n external\n override\n returns (uint256)\n {\n if (msg.sender != admin) {\n return\n fail(\n Error.UNAUTHORIZED,\n FailureInfo.SET_PENDING_ADMIN_OWNER_CHECK\n );\n }\n\n address oldPendingAdmin = pendingAdmin;\n\n pendingAdmin = newPendingAdmin;\n\n emit NewPendingAdmin(oldPendingAdmin, newPendingAdmin);\n\n return uint256(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 override returns (uint256) {\n if (msg.sender != pendingAdmin || msg.sender == address(0)) {\n return\n fail(\n Error.UNAUTHORIZED,\n FailureInfo.ACCEPT_ADMIN_PENDING_ADMIN_CHECK\n );\n }\n\n address oldAdmin = admin;\n address oldPendingAdmin = pendingAdmin;\n\n admin = pendingAdmin;\n\n pendingAdmin = payable(address(0));\n\n emit NewAdmin(oldAdmin, admin);\n emit NewPendingAdmin(oldPendingAdmin, pendingAdmin);\n\n return uint256(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)\n public\n override\n returns (uint256)\n {\n if (msg.sender != admin) {\n return\n fail(\n Error.UNAUTHORIZED,\n FailureInfo.SET_COMPTROLLER_OWNER_CHECK\n );\n }\n\n ComptrollerInterface oldComptroller = comptroller;\n require(newComptroller.isComptroller(), \"CT21\");\n\n comptroller = newComptroller;\n\n emit NewComptroller(oldComptroller, newComptroller);\n\n return uint256(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(uint256 newReserveFactorMantissa)\n external\n override\n nonReentrant\n returns (uint256)\n {\n uint256 error = accrueInterest();\n if (error != uint256(Error.NO_ERROR)) {\n return\n fail(\n Error(error),\n FailureInfo.SET_RESERVE_FACTOR_ACCRUE_INTEREST_FAILED\n );\n }\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(uint256 newReserveFactorMantissa)\n internal\n returns (uint256)\n {\n if (msg.sender != admin) {\n return\n fail(\n Error.UNAUTHORIZED,\n FailureInfo.SET_RESERVE_FACTOR_ADMIN_CHECK\n );\n }\n\n if (accrualBlockNumber != getBlockNumber()) {\n return\n fail(\n Error.MARKET_NOT_FRESH,\n FailureInfo.SET_RESERVE_FACTOR_FRESH_CHECK\n );\n }\n\n if (newReserveFactorMantissa > reserveFactorMaxMantissa) {\n return\n fail(\n Error.BAD_INPUT,\n FailureInfo.SET_RESERVE_FACTOR_BOUNDS_CHECK\n );\n }\n\n uint256 oldReserveFactorMantissa = reserveFactorMantissa;\n reserveFactorMantissa = newReserveFactorMantissa;\n\n emit NewReserveFactor(\n oldReserveFactorMantissa,\n newReserveFactorMantissa\n );\n\n return uint256(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(uint256 addAmount)\n internal\n nonReentrant\n returns (uint256)\n {\n uint256 error = accrueInterest();\n if (error != uint256(Error.NO_ERROR)) {\n return\n fail(\n Error(error),\n FailureInfo.ADD_RESERVES_ACCRUE_INTEREST_FAILED\n );\n }\n\n uint256 totalReservesNew;\n uint256 actualAddAmount;\n\n if (accrualBlockNumber != getBlockNumber()) {\n return (\n fail(\n Error.MARKET_NOT_FRESH,\n FailureInfo.ADD_RESERVES_FRESH_CHECK\n )\n );\n }\n\n actualAddAmount = doTransferIn(msg.sender, addAmount);\n\n totalReservesNew = totalReserves + actualAddAmount;\n\n require(totalReservesNew >= totalReserves, \"CT22\");\n\n totalReserves = totalReservesNew;\n\n emit ReservesAdded(msg.sender, actualAddAmount, totalReservesNew);\n\n return (uint256(Error.NO_ERROR));\n }\n\n function _addSubsidyInternal(uint256 addAmount)\n internal\n nonReentrant\n returns (uint256)\n {\n uint256 error = accrueInterest();\n if (error != uint256(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_SUBSIDY_FUND_FAILED);\n }\n\n uint256 subsidyFundNew;\n uint256 actualAddAmount;\n\n if (accrualBlockNumber != getBlockNumber()) {\n return (\n fail(\n Error.MARKET_NOT_FRESH,\n FailureInfo.ADD_SUBSIDY_FUND_FRESH_CHECK\n )\n );\n }\n\n actualAddAmount = doTransferIn(msg.sender, addAmount);\n\n subsidyFundNew = subsidyFund + actualAddAmount;\n\n require(subsidyFundNew >= subsidyFund, \"CT22\");\n\n subsidyFund = subsidyFundNew;\n\n emit SubsidyAdded(msg.sender, actualAddAmount, subsidyFundNew);\n\n /* Return (NO_ERROR, actualAddAmount) */\n return (uint256(Error.NO_ERROR));\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(uint256 reduceAmount)\n external\n override\n nonReentrant\n returns (uint256)\n {\n uint256 error = accrueInterest();\n if (error != uint256(Error.NO_ERROR)) {\n return\n fail(\n Error(error),\n FailureInfo.REDUCE_RESERVES_ACCRUE_INTEREST_FAILED\n );\n }\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(uint256 reduceAmount)\n internal\n returns (uint256)\n {\n uint256 totalReservesNew;\n\n if (msg.sender != admin) {\n return\n fail(\n Error.UNAUTHORIZED,\n FailureInfo.REDUCE_RESERVES_ADMIN_CHECK\n );\n }\n\n if (accrualBlockNumber != getBlockNumber()) {\n return\n fail(\n Error.MARKET_NOT_FRESH,\n FailureInfo.REDUCE_RESERVES_FRESH_CHECK\n );\n }\n\n if (getCashPrior() < reduceAmount) {\n return\n fail(\n Error.TOKEN_INSUFFICIENT_CASH,\n FailureInfo.REDUCE_RESERVES_CASH_NOT_AVAILABLE\n );\n }\n\n if (reduceAmount > totalReserves) {\n return\n fail(Error.BAD_INPUT, FailureInfo.REDUCE_RESERVES_VALIDATION);\n }\n\n totalReservesNew = totalReserves - reduceAmount;\n require(totalReservesNew <= totalReserves, \"CT23\");\n\n totalReserves = totalReservesNew;\n\n doTransferOut(admin, reduceAmount);\n\n emit ReservesReduced(admin, reduceAmount, totalReservesNew);\n\n return uint256(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)\n public\n override\n returns (uint256)\n {\n uint256 error = accrueInterest();\n if (error != uint256(Error.NO_ERROR)) {\n return\n fail(\n Error(error),\n FailureInfo.SET_INTEREST_RATE_MODEL_ACCRUE_INTEREST_FAILED\n );\n }\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)\n internal\n returns (uint256)\n {\n InterestRateModel oldInterestRateModel;\n\n if (msg.sender != admin) {\n return\n fail(\n Error.UNAUTHORIZED,\n FailureInfo.SET_INTEREST_RATE_MODEL_OWNER_CHECK\n );\n }\n\n if (accrualBlockNumber != getBlockNumber()) {\n return\n fail(\n Error.MARKET_NOT_FRESH,\n FailureInfo.SET_INTEREST_RATE_MODEL_FRESH_CHECK\n );\n }\n\n oldInterestRateModel = interestRateModel;\n\n require(newInterestRateModel.isInterestRateModel(), \"CT21\");\n\n interestRateModel = newInterestRateModel;\n\n emit NewMarketInterestRateModel(\n oldInterestRateModel,\n newInterestRateModel\n );\n\n return uint256(Error.NO_ERROR);\n }\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 virtual returns (uint256);\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, uint256 amount)\n internal\n virtual\n returns (uint256);\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, uint256 amount) internal virtual;\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;\n }\n}\n" - }, - "contracts/ErrorReporter.sol": { - "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity 0.8.6;\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(uint256 error, uint256 info, uint256 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 (uint256) {\n emit Failure(uint256(err), uint256(info), 0);\n\n return uint256(err);\n }\n\n /**\n * @dev use this when reporting an opaque error from an upgradeable collaborator contract\n */\n function failOpaque(\n Error err,\n FailureInfo info,\n uint256 opaqueError\n ) internal returns (uint256) {\n emit Failure(uint256(err), uint256(info), opaqueError);\n\n return uint256(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 ADD_SUBSIDY_FUND_FAILED,\n ADD_SUBSIDY_FUND_FRESH_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 TokenFailure(uint256 error, uint256 info, uint256 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 (uint256) {\n emit TokenFailure(uint256(err), uint256(info), 0);\n\n return uint256(err);\n }\n\n /**\n * @dev use this when reporting an opaque error from an upgradeable collaborator contract\n */\n function failOpaque(\n Error err,\n FailureInfo info,\n uint256 opaqueError\n ) internal returns (uint256) {\n emit TokenFailure(uint256(err), uint256(info), opaqueError);\n\n return uint256(err);\n }\n}\n" - }, - "contracts/PriceOracle.sol": { - "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity 0.8.6;\n\nimport \"./CToken.sol\";\n\nabstract contract 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)\n external\n view\n virtual\n returns (uint256);\n}\n" - }, - "contracts/ComptrollerStorage.sol": { - "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity 0.8.6;\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 // @notice address of the TROP token\n address public tropAddress;\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": "// SPDX-License-Identifier: UNLICENSED\npragma solidity 0.8.6;\n\nimport \"./ErrorReporter.sol\";\nimport \"./ComptrollerStorage.sol\";\n\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 * @notice Emitted when pendingComptrollerImplementation is changed\n */\n event NewPendingImplementation(\n address oldPendingImplementation,\n address newPendingImplementation\n );\n\n /**\n * @notice Emitted when pendingComptrollerImplementation is accepted, which means comptroller implementation is updated\n */\n event NewImplementation(\n address oldImplementation,\n address newImplementation\n );\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() {\n // Set admin to caller\n admin = msg.sender;\n }\n\n /*** Admin Functions ***/\n function _setPendingImplementation(address newPendingImplementation)\n public\n returns (uint256)\n {\n if (msg.sender != admin) {\n return\n fail(\n Error.UNAUTHORIZED,\n FailureInfo.SET_PENDING_IMPLEMENTATION_OWNER_CHECK\n );\n }\n\n address oldPendingImplementation = pendingComptrollerImplementation;\n\n pendingComptrollerImplementation = newPendingImplementation;\n\n emit NewPendingImplementation(\n oldPendingImplementation,\n pendingComptrollerImplementation\n );\n\n return uint256(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 (uint256) {\n // Check caller is pendingImplementation and pendingImplementation ≠ address(0)\n if (\n msg.sender != pendingComptrollerImplementation ||\n pendingComptrollerImplementation == address(0)\n ) {\n return\n fail(\n Error.UNAUTHORIZED,\n FailureInfo.ACCEPT_PENDING_IMPLEMENTATION_ADDRESS_CHECK\n );\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(\n oldPendingImplementation,\n pendingComptrollerImplementation\n );\n\n return uint256(Error.NO_ERROR);\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)\n public\n returns (uint256)\n {\n // Check caller = admin\n if (msg.sender != admin) {\n return\n fail(\n Error.UNAUTHORIZED,\n FailureInfo.SET_PENDING_ADMIN_OWNER_CHECK\n );\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 uint256(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 (uint256) {\n // Check caller is pendingAdmin and pendingAdmin ≠ address(0)\n if (msg.sender != pendingAdmin || msg.sender == address(0)) {\n return\n fail(\n Error.UNAUTHORIZED,\n FailureInfo.ACCEPT_ADMIN_PENDING_ADMIN_CHECK\n );\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 uint256(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 internalFallback() public payable {\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 {\n revert(free_mem_ptr, returndatasize())\n }\n default {\n return(free_mem_ptr, returndatasize())\n }\n }\n }\n\n fallback() external payable {\n internalFallback();\n }\n\n receive() external payable {\n internalFallback();\n }\n}\n" - }, - "contracts/Governance/TROP.sol": { - "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity 0.8.6;\npragma experimental ABIEncoderV2;\n\n/**\n * @title TROP ERC20 tokens.\n * @author tropykus\n * @notice Yield farming tokens that allow to propose and vote for protocol changes using the governance system.\n */\ncontract TROP {\n /// @notice EIP-20 token name for this token\n string public constant name = \"tropykus\";\n\n /// @notice EIP-20 token symbol for this token\n string public constant symbol = \"TROP\";\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 uint256 public constant totalSupply = 10000000e18; // 10 million TROP\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 =\n keccak256(\n \"EIP712Domain(string name,uint256 chainId,address verifyingContract)\"\n );\n\n /// @notice The EIP-712 typehash for the delegation struct used by the contract\n bytes32 public constant DELEGATION_TYPEHASH =\n keccak256(\"Delegation(address delegatee,uint256 nonce,uint256 expiry)\");\n\n /// @notice A record of states for signing / validating signatures\n mapping(address => uint256) public nonces;\n\n /// @notice An event thats emitted when an account changes its delegate\n event DelegateChanged(\n address indexed delegator,\n address indexed fromDelegate,\n address indexed toDelegate\n );\n\n /// @notice An event thats emitted when a delegate account's vote balance changes\n event DelegateVotesChanged(\n address indexed delegate,\n uint256 previousBalance,\n uint256 newBalance\n );\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(\n address indexed owner,\n address indexed spender,\n uint256 amount\n );\n\n /**\n * @notice Construct a new TROP token\n * @param account The initial account to grant all the tokens\n */\n constructor(address account) {\n balances[account] = uint96(totalSupply);\n emit Transfer(address(0), account, totalSupply);\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)\n external\n view\n returns (uint256)\n {\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, uint256 rawAmount)\n external\n returns (bool)\n {\n uint96 amount;\n if (rawAmount == type(uint256).max) {\n amount = type(uint96).max;\n } else {\n amount = safe96(rawAmount, \"TROP::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 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 (uint256) {\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, uint256 rawAmount) external returns (bool) {\n uint96 amount = safe96(\n rawAmount,\n \"TROP::transfer: amount exceeds 96 bits\"\n );\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(\n address src,\n address dst,\n uint256 rawAmount\n ) external returns (bool) {\n address spender = msg.sender;\n uint96 spenderAllowance = allowances[src][spender];\n uint96 amount = safe96(\n rawAmount,\n \"TROP::approve: amount exceeds 96 bits\"\n );\n\n if (spender != src && spenderAllowance != type(uint96).max) {\n uint96 newAllowance = sub96(\n spenderAllowance,\n amount,\n \"TROP::transferFrom: transfer amount exceeds spender allowance\"\n );\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(\n address delegatee,\n uint256 nonce,\n uint256 expiry,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) public {\n bytes32 domainSeparator = keccak256(\n abi.encode(\n DOMAIN_TYPEHASH,\n keccak256(bytes(name)),\n getChainId(),\n address(this)\n )\n );\n bytes32 structHash = keccak256(\n abi.encode(DELEGATION_TYPEHASH, delegatee, nonce, expiry)\n );\n bytes32 digest = keccak256(\n abi.encodePacked(\"\\x19\\x01\", domainSeparator, structHash)\n );\n address signatory = ecrecover(digest, v, r, s);\n require(\n signatory != 0xdcc703c0E500B653Ca82273B7BFAd8045D85a470 &&\n signatory != address(0),\n \"TROP::delegateBySig: invalid signature\"\n );\n require(\n nonce == nonces[signatory]++,\n \"TROP::delegateBySig: invalid nonce\"\n );\n require(\n block.timestamp <= expiry,\n \"TROP::delegateBySig: signature expired\"\n );\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\n 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, uint256 blockNumber)\n public\n view\n returns (uint96)\n {\n require(\n blockNumber < block.number,\n \"TROP::getPriorVotes: not yet determined\"\n );\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(\n address src,\n address dst,\n uint96 amount\n ) internal {\n require(\n src != address(0),\n \"TROP::_transferTokens: cannot transfer from the zero address\"\n );\n require(\n dst != address(0),\n \"TROP::_transferTokens: cannot transfer to the zero address\"\n );\n\n balances[src] = sub96(\n balances[src],\n amount,\n \"TROP::_transferTokens: transfer amount exceeds balance\"\n );\n balances[dst] = add96(\n balances[dst],\n amount,\n \"TROP::_transferTokens: transfer amount overflows\"\n );\n emit Transfer(src, dst, amount);\n\n _moveDelegates(delegates[src], delegates[dst], amount);\n }\n\n function _moveDelegates(\n address srcRep,\n address dstRep,\n uint96 amount\n ) internal {\n if (srcRep != dstRep && amount > 0) {\n if (srcRep != address(0)) {\n uint32 srcRepNum = numCheckpoints[srcRep];\n uint96 srcRepOld = srcRepNum > 0\n ? checkpoints[srcRep][srcRepNum - 1].votes\n : 0;\n uint96 srcRepNew = sub96(\n srcRepOld,\n amount,\n \"TROP::_moveVotes: vote amount underflows\"\n );\n _writeCheckpoint(srcRep, srcRepNum, srcRepOld, srcRepNew);\n }\n\n if (dstRep != address(0)) {\n uint32 dstRepNum = numCheckpoints[dstRep];\n uint96 dstRepOld = dstRepNum > 0\n ? checkpoints[dstRep][dstRepNum - 1].votes\n : 0;\n uint96 dstRepNew = add96(\n dstRepOld,\n amount,\n \"TROP::_moveVotes: vote amount overflows\"\n );\n _writeCheckpoint(dstRep, dstRepNum, dstRepOld, dstRepNew);\n }\n }\n }\n\n function _writeCheckpoint(\n address delegatee,\n uint32 nCheckpoints,\n uint96 oldVotes,\n uint96 newVotes\n ) internal {\n uint32 blockNumber = safe32(\n block.number,\n \"TROP::_writeCheckpoint: block number exceeds 32 bits\"\n );\n\n if (\n nCheckpoints > 0 &&\n checkpoints[delegatee][nCheckpoints - 1].fromBlock == blockNumber\n ) {\n checkpoints[delegatee][nCheckpoints - 1].votes = newVotes;\n } else {\n checkpoints[delegatee][nCheckpoints] = Checkpoint(\n blockNumber,\n newVotes\n );\n numCheckpoints[delegatee] = nCheckpoints + 1;\n }\n\n emit DelegateVotesChanged(delegatee, oldVotes, newVotes);\n }\n\n function safe32(uint256 n, string memory errorMessage)\n internal\n pure\n returns (uint32)\n {\n require(n < 2**32, errorMessage);\n return uint32(n);\n }\n\n function safe96(uint256 n, string memory errorMessage)\n internal\n pure\n returns (uint96)\n {\n require(n < 2**96, errorMessage);\n return uint96(n);\n }\n\n function add96(\n uint96 a,\n uint96 b,\n string memory errorMessage\n ) internal pure returns (uint96) {\n uint96 c = a + b;\n require(c >= a, errorMessage);\n return c;\n }\n\n function sub96(\n uint96 a,\n uint96 b,\n string memory errorMessage\n ) internal pure returns (uint96) {\n require(b <= a, errorMessage);\n return a - b;\n }\n\n function getChainId() internal view returns (uint256) {\n uint256 chainId;\n assembly {\n chainId := chainid()\n }\n return chainId;\n }\n}\n" - }, - "contracts/EIP20Interface.sol": { - "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity 0.8.6;\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\n function symbol() external view returns (string memory);\n\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 balance 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 success Whether or not the transfer succeeded\n */\n function transfer(address dst, uint256 amount)\n external\n 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 success Whether or not the transfer succeeded\n */\n function transferFrom(\n address src,\n address dst,\n uint256 amount\n ) 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 success Whether or not the approval succeeded\n */\n function approve(address spender, uint256 amount)\n external\n 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 remaining The number of tokens allowed to be spent (-1 means infinite)\n */\n function allowance(address owner, address spender)\n external\n view\n returns (uint256 remaining);\n\n event Transfer(address indexed from, address indexed to, uint256 amount);\n event Approval(\n address indexed owner,\n address indexed spender,\n uint256 amount\n );\n}\n" - }, - "contracts/WhitelistInterface.sol": { - "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity 0.8.6;\n\ninterface WhitelistInterface {\n function setStatus(bool _newStatus) external;\n function enabled() external view returns(bool);\n\n function addUsers(address[] memory _users) external;\n function exist(address _user) external view returns(bool);\n function getUsers() external view returns(address[] memory currentUsers);\n function removeUser(address _user) external;\n}" - }, - "contracts/Lens/TropykusLens.sol": { - "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity 0.8.6;\npragma experimental ABIEncoderV2;\n\nimport \"../CErc20.sol\";\nimport \"../CToken.sol\";\nimport \"../PriceOracle.sol\";\nimport \"../EIP20Interface.sol\";\nimport \"../Governance/GovernorAlpha.sol\";\nimport \"../Governance/TROP.sol\";\n\ninterface ComptrollerLensInterface {\n function markets(address) external view returns (bool, uint);\n function oracle() external view returns (PriceOracle);\n function getAccountLiquidity(address) external view returns (uint, uint, uint);\n function getAssetsIn(address) external view returns (CToken[] memory);\n function claimComp(address) external;\n function compAccrued(address) external view returns (uint);\n}\n\n/**\n * @title Helper contract to get information of the protocol .\n * @author tropykus\n * @notice TropykusLens allows to make obtain global information with a single call.\n */\ncontract TropykusLens {\n struct CTokenMetadata {\n address cToken;\n uint exchangeRateCurrent;\n uint supplyRatePerBlock;\n uint borrowRatePerBlock;\n uint reserveFactorMantissa;\n uint totalBorrows;\n uint totalReserves;\n uint totalSupply;\n uint totalCash;\n bool isListed;\n uint collateralFactorMantissa;\n address underlyingAssetAddress;\n uint cTokenDecimals;\n uint underlyingDecimals;\n }\n\n function cTokenMetadata(CToken cToken) public returns (CTokenMetadata memory) {\n uint exchangeRateCurrent = cToken.exchangeRateCurrent();\n ComptrollerLensInterface comptroller = ComptrollerLensInterface(address(cToken.comptroller()));\n (bool isListed, uint collateralFactorMantissa) = comptroller.markets(address(cToken));\n address underlyingAssetAddress;\n uint underlyingDecimals;\n\n if (compareStrings(cToken.symbol(), \"kRBTC\") || compareStrings(cToken.symbol(), \"kSAT\")) {\n underlyingAssetAddress = address(0);\n underlyingDecimals = 18;\n } else {\n CErc20 cErc20 = CErc20(address(cToken));\n underlyingAssetAddress = cErc20.underlying();\n underlyingDecimals = EIP20Interface(cErc20.underlying()).decimals();\n }\n\n return CTokenMetadata({\n cToken: address(cToken),\n exchangeRateCurrent: exchangeRateCurrent,\n supplyRatePerBlock: cToken.supplyRatePerBlock(),\n borrowRatePerBlock: cToken.borrowRatePerBlock(),\n reserveFactorMantissa: cToken.reserveFactorMantissa(),\n totalBorrows: cToken.totalBorrows(),\n totalReserves: cToken.totalReserves(),\n totalSupply: cToken.totalSupply(),\n totalCash: cToken.getCash(),\n isListed: isListed,\n collateralFactorMantissa: collateralFactorMantissa,\n underlyingAssetAddress: underlyingAssetAddress,\n cTokenDecimals: cToken.decimals(),\n underlyingDecimals: underlyingDecimals\n });\n }\n\n function cTokenMetadataAll(CToken[] calldata cTokens) external returns (CTokenMetadata[] memory) {\n uint cTokenCount = cTokens.length;\n CTokenMetadata[] memory res = new CTokenMetadata[](cTokenCount);\n for (uint i = 0; i < cTokenCount; i++) {\n res[i] = cTokenMetadata(cTokens[i]);\n }\n return res;\n }\n\n struct CTokenBalances {\n address cToken;\n uint balanceOf;\n uint borrowBalanceCurrent;\n uint balanceOfUnderlying;\n uint tokenBalance;\n uint tokenAllowance;\n }\n\n function cTokenBalances(CToken cToken, address payable account) public returns (CTokenBalances memory) {\n uint balanceOf = cToken.balanceOf(account);\n uint borrowBalanceCurrent = cToken.borrowBalanceCurrent(account);\n uint balanceOfUnderlying = cToken.balanceOfUnderlying(account);\n uint tokenBalance;\n uint tokenAllowance;\n\n if (compareStrings(cToken.symbol(), \"kRBTC\") || compareStrings(cToken.symbol(), \"kSAT\")) {\n tokenBalance = account.balance;\n tokenAllowance = account.balance;\n } else {\n CErc20 cErc20 = CErc20(address(cToken));\n EIP20Interface underlying = EIP20Interface(cErc20.underlying());\n tokenBalance = underlying.balanceOf(account);\n tokenAllowance = underlying.allowance(account, address(cToken));\n }\n\n return CTokenBalances({\n cToken: address(cToken),\n balanceOf: balanceOf,\n borrowBalanceCurrent: borrowBalanceCurrent,\n balanceOfUnderlying: balanceOfUnderlying,\n tokenBalance: tokenBalance,\n tokenAllowance: tokenAllowance\n });\n }\n\n function cTokenBalancesAll(CToken[] calldata cTokens, address payable account) external returns (CTokenBalances[] memory) {\n uint cTokenCount = cTokens.length;\n CTokenBalances[] memory res = new CTokenBalances[](cTokenCount);\n for (uint i = 0; i < cTokenCount; i++) {\n res[i] = cTokenBalances(cTokens[i], account);\n }\n return res;\n }\n\n struct CTokenUnderlyingPrice {\n address cToken;\n uint underlyingPrice;\n }\n\n function cTokenUnderlyingPrice(CToken cToken) public view returns (CTokenUnderlyingPrice memory) {\n ComptrollerLensInterface comptroller = ComptrollerLensInterface(address(cToken.comptroller()));\n PriceOracle priceOracle = comptroller.oracle();\n\n return CTokenUnderlyingPrice({\n cToken: address(cToken),\n underlyingPrice: priceOracle.getUnderlyingPrice(cToken)\n });\n }\n\n function cTokenUnderlyingPriceAll(CToken[] calldata cTokens) external view returns (CTokenUnderlyingPrice[] memory) {\n uint cTokenCount = cTokens.length;\n CTokenUnderlyingPrice[] memory res = new CTokenUnderlyingPrice[](cTokenCount);\n for (uint i = 0; i < cTokenCount; i++) {\n res[i] = cTokenUnderlyingPrice(cTokens[i]);\n }\n return res;\n }\n\n struct AccountLimits {\n CToken[] markets;\n uint liquidity;\n uint shortfall;\n }\n\n function getAccountLimits(ComptrollerLensInterface comptroller, address account) public view returns (AccountLimits memory) {\n (uint errorCode, uint liquidity, uint shortfall) = comptroller.getAccountLiquidity(account);\n require(errorCode == 0,\"liquidity error\");\n\n return AccountLimits({\n markets: comptroller.getAssetsIn(account),\n liquidity: liquidity,\n shortfall: shortfall\n });\n }\n\n struct GovReceipt {\n uint proposalId;\n bool hasVoted;\n bool support;\n uint96 votes;\n }\n\n function getGovReceipts(GovernorAlpha governor, address voter, uint[] memory proposalIds) public view returns (GovReceipt[] memory) {\n uint proposalCount = proposalIds.length;\n GovReceipt[] memory res = new GovReceipt[](proposalCount);\n for (uint i = 0; i < proposalCount; i++) {\n GovernorAlpha.Receipt memory receipt = governor.getReceipt(proposalIds[i], voter);\n res[i] = GovReceipt({\n proposalId: proposalIds[i],\n hasVoted: receipt.hasVoted,\n support: receipt.support,\n votes: receipt.votes\n });\n }\n return res;\n }\n\n struct GovProposal {\n uint proposalId;\n address proposer;\n uint eta;\n address[] targets;\n uint[] values;\n string[] signatures;\n bytes[] calldatas;\n uint startBlock;\n uint endBlock;\n uint forVotes;\n uint againstVotes;\n bool canceled;\n bool executed;\n }\n\n function setProposal(GovProposal memory res, GovernorAlpha governor, uint proposalId) internal view {\n (\n ,\n address proposer,\n uint eta,\n uint startBlock,\n uint endBlock,\n uint forVotes,\n uint againstVotes,\n bool canceled,\n bool executed\n ) = governor.proposals(proposalId);\n res.proposalId = proposalId;\n res.proposer = proposer;\n res.eta = eta;\n res.startBlock = startBlock;\n res.endBlock = endBlock;\n res.forVotes = forVotes;\n res.againstVotes = againstVotes;\n res.canceled = canceled;\n res.executed = executed;\n }\n\n function getGovProposals(GovernorAlpha governor, uint[] calldata proposalIds) external view returns (GovProposal[] memory) {\n GovProposal[] memory res = new GovProposal[](proposalIds.length);\n for (uint i = 0; i < proposalIds.length; i++) {\n (\n address[] memory targets,\n uint[] memory values,\n string[] memory signatures,\n bytes[] memory calldatas\n ) = governor.getActions(proposalIds[i]);\n res[i] = GovProposal({\n proposalId: 0,\n proposer: address(0),\n eta: 0,\n targets: targets,\n values: values,\n signatures: signatures,\n calldatas: calldatas,\n startBlock: 0,\n endBlock: 0,\n forVotes: 0,\n againstVotes: 0,\n canceled: false,\n executed: false\n });\n setProposal(res[i], governor, proposalIds[i]);\n }\n return res;\n }\n\n struct CompBalanceMetadata {\n uint balance;\n uint votes;\n address delegate;\n }\n\n function getCompBalanceMetadata(TROP comp, address account) external view returns (CompBalanceMetadata memory) {\n return CompBalanceMetadata({\n balance: comp.balanceOf(account),\n votes: uint256(comp.getCurrentVotes(account)),\n delegate: comp.delegates(account)\n });\n }\n\n struct CompBalanceMetadataExt {\n uint balance;\n uint votes;\n address delegate;\n uint allocated;\n }\n\n function getCompBalanceMetadataExt(TROP comp, ComptrollerLensInterface comptroller, address account) external returns (CompBalanceMetadataExt memory) {\n uint balance = comp.balanceOf(account);\n comptroller.claimComp(account);\n uint newBalance = comp.balanceOf(account);\n uint accrued = comptroller.compAccrued(account);\n uint total = add(accrued, newBalance, \"sum comp total\");\n uint allocated = sub(total, balance, \"sub allocated\");\n\n return CompBalanceMetadataExt({\n balance: balance,\n votes: uint256(comp.getCurrentVotes(account)),\n delegate: comp.delegates(account),\n allocated: allocated\n });\n }\n\n struct CompVotes {\n uint blockNumber;\n uint votes;\n }\n\n function getCompVotes(TROP comp, address account, uint32[] calldata blockNumbers) external view returns (CompVotes[] memory) {\n CompVotes[] memory res = new CompVotes[](blockNumbers.length);\n for (uint i = 0; i < blockNumbers.length; i++) {\n res[i] = CompVotes({\n blockNumber: uint256(blockNumbers[i]),\n votes: uint256(comp.getPriorVotes(account, blockNumbers[i]))\n });\n }\n return res;\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 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" - }, - "contracts/CErc20.sol": { - "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity 0.8.6;\n\nimport \"./CToken.sol\";\nimport \"./CTokenInterfaces.sol\";\n\n/**\n * @title tropykus CErc20 Contract\n * @notice CTokens which wrap an EIP-20 underlying\n * @author tropykus\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(\n address underlying_,\n ComptrollerInterface comptroller_,\n InterestRateModel interestRateModel_,\n uint256 initialExchangeRateMantissa_,\n string memory name_,\n string memory symbol_,\n uint8 decimals_\n ) public {\n // CToken initialize does the bulk of the work\n super.initialize(\n comptroller_,\n interestRateModel_,\n initialExchangeRateMantissa_,\n name_,\n symbol_,\n decimals_\n );\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(uint256 mintAmount) external override returns (uint256) {\n (uint256 err, ) = mintInternal(mintAmount);\n return err;\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 redeem(uint256 redeemAmount)\n external\n override\n returns (uint256)\n {\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(uint256 borrowAmount) external override returns (uint256) {\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(uint256 repayAmount)\n external\n override\n returns (uint256)\n {\n (uint256 err, ) = repayBorrowInternal(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(\n address borrower,\n uint256 repayAmount,\n CTokenInterface cTokenCollateral\n ) external override returns (uint256) {\n (uint256 err, ) = liquidateBorrowInternal(\n borrower,\n repayAmount,\n cTokenCollateral\n );\n return err;\n }\n\n /**\n * @notice A public function to sweep accidental ERC-20 transfers to this contract. Tokens are sent to admin (timelock)\n * @param token The address of the ERC-20 token to sweep\n */\n function sweepToken(EIP20NonStandardInterface token) external override {\n require(address(token) != underlying, \"EC01\");\n uint256 balance = token.balanceOf(address(this));\n token.transfer(admin, balance);\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(uint256 addAmount)\n external\n override\n returns (uint256)\n {\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 override returns (uint256) {\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, uint256 amount)\n internal\n override\n returns (uint256)\n {\n EIP20NonStandardInterface token = EIP20NonStandardInterface(underlying);\n uint256 balanceBefore = EIP20Interface(underlying).balanceOf(\n address(this)\n );\n token.transferFrom(from, address(this), amount);\n\n bool success;\n assembly {\n switch returndatasize()\n case 0 {\n // This is a non-standard ERC-20\n success := not(0) // set success to true\n }\n case 32 {\n // This is a compliant ERC-20\n returndatacopy(0, 0, 32)\n success := mload(0) // Set `success = returndata` of external call\n }\n default {\n // This is an excessively non-compliant ERC-20, revert.\n revert(0, 0)\n }\n }\n require(success, \"EC02\");\n\n // Calculate the amount that was *actually* transferred\n uint256 balanceAfter = EIP20Interface(underlying).balanceOf(\n address(this)\n );\n require(balanceAfter >= balanceBefore, \"EC03\");\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, uint256 amount)\n internal\n virtual\n override\n {\n EIP20NonStandardInterface token = EIP20NonStandardInterface(underlying);\n token.transfer(to, amount);\n\n bool success;\n assembly {\n switch returndatasize()\n case 0 {\n // This is a non-standard ERC-20\n success := not(0) // set success to true\n }\n case 32 {\n // This is a complaint ERC-20\n returndatacopy(0, 0, 32)\n success := mload(0) // Set `success = returndata` of external call\n }\n default {\n // This is an excessively non-compliant ERC-20, revert.\n revert(0, 0)\n }\n }\n require(success, \"CE01\");\n }\n}\n" - }, - "contracts/Governance/GovernorAlpha.sol": { - "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity 0.8.6;\npragma experimental ABIEncoderV2;\n\n/**\n * @title Governor contract to vote on tropykus platform using TROP tokens.\n * @author tropykus\n * @notice This contract allows to propose and vote for protocol changes using the TROP tokens.\n */\ncontract GovernorAlpha {\n /// @notice The name of this contract\n string public constant name = \"Compound Governor Alpha\";\n\n /// @notice The number of votes in support of a proposal required in order for a quorum to be reached and for a vote to succeed\n function quorumVotes() public pure returns (uint256) {\n return 400000e18;\n } // 400,000 = 4% of Comp\n\n /// @notice The number of votes required in order for a voter to become a proposer\n function proposalThreshold() public pure returns (uint256) {\n return 100000e18;\n } // 100,000 = 1% of Comp\n\n /// @notice The maximum number of actions that can be included in a proposal\n function proposalMaxOperations() public pure returns (uint256) {\n return 10;\n } // 10 actions\n\n /// @notice The delay before voting on a proposal may take place, once proposed\n function votingDelay() public pure returns (uint256) {\n return 1;\n } // 1 block\n\n /// @notice The duration of voting on a proposal, in blocks\n function votingPeriod() public pure virtual returns (uint256) {\n return 17280;\n } // ~3 days in blocks (assuming 15s blocks)\n\n /// @notice The address of the Compound Protocol Timelock\n TimelockInterface public timelock;\n\n /// @notice The address of the Compound governance token\n CompInterface public comp;\n\n /// @notice The address of the Governor Guardian\n address public guardian;\n\n /// @notice The total number of proposals\n uint256 public proposalCount;\n\n struct Proposal {\n /// @notice Unique id for looking up a proposal\n uint256 id;\n /// @notice Creator of the proposal\n address proposer;\n /// @notice The timestamp that the proposal will be available for execution, set once the vote succeeds\n uint256 eta;\n /// @notice the ordered list of target addresses for calls to be made\n address[] targets;\n /// @notice The ordered list of values (i.e. msg.value) to be passed to the calls to be made\n uint256[] values;\n /// @notice The ordered list of function signatures to be called\n string[] signatures;\n /// @notice The ordered list of calldata to be passed to each call\n bytes[] calldatas;\n /// @notice The block at which voting begins: holders must delegate their votes prior to this block\n uint256 startBlock;\n /// @notice The block at which voting ends: votes must be cast prior to this block\n uint256 endBlock;\n /// @notice Current number of votes in favor of this proposal\n uint256 forVotes;\n /// @notice Current number of votes in opposition to this proposal\n uint256 againstVotes;\n /// @notice Flag marking whether the proposal has been canceled\n bool canceled;\n /// @notice Flag marking whether the proposal has been executed\n bool executed;\n /// @notice Receipts of ballots for the entire set of voters\n mapping(address => Receipt) receipts;\n }\n\n /// @notice Ballot receipt record for a voter\n struct Receipt {\n /// @notice Whether or not a vote has been cast\n bool hasVoted;\n /// @notice Whether or not the voter supports the proposal\n bool support;\n /// @notice The number of votes the voter had, which were cast\n uint96 votes;\n }\n\n /// @notice Possible states that a proposal may be in\n enum ProposalState {\n Pending,\n Active,\n Canceled,\n Defeated,\n Succeeded,\n Queued,\n Expired,\n Executed\n }\n\n /// @notice The official record of all proposals ever proposed\n mapping(uint256 => Proposal) public proposals;\n\n /// @notice The latest proposal for each proposer\n mapping(address => uint256) public latestProposalIds;\n\n /// @notice The EIP-712 typehash for the contract's domain\n bytes32 public constant DOMAIN_TYPEHASH =\n keccak256(\n \"EIP712Domain(string name,uint256 chainId,address verifyingContract)\"\n );\n\n /// @notice The EIP-712 typehash for the ballot struct used by the contract\n bytes32 public constant BALLOT_TYPEHASH =\n keccak256(\"Ballot(uint256 proposalId,bool support)\");\n\n /// @notice An event emitted when a new proposal is created\n event ProposalCreated(\n uint256 id,\n address proposer,\n address[] targets,\n uint256[] values,\n string[] signatures,\n bytes[] calldatas,\n uint256 startBlock,\n uint256 endBlock,\n string description\n );\n\n /// @notice An event emitted when a vote has been cast on a proposal\n event VoteCast(\n address voter,\n uint256 proposalId,\n bool support,\n uint256 votes\n );\n\n /// @notice An event emitted when a proposal has been canceled\n event ProposalCanceled(uint256 id);\n\n /// @notice An event emitted when a proposal has been queued in the Timelock\n event ProposalQueued(uint256 id, uint256 eta);\n\n /// @notice An event emitted when a proposal has been executed in the Timelock\n event ProposalExecuted(uint256 id);\n\n constructor(\n address timelock_,\n address comp_,\n address guardian_\n ) {\n timelock = TimelockInterface(timelock_);\n comp = CompInterface(comp_);\n guardian = guardian_;\n }\n\n function propose(\n address[] memory targets,\n uint256[] memory values,\n string[] memory signatures,\n bytes[] memory calldatas,\n string memory description\n ) public returns (uint256) {\n require(\n comp.getPriorVotes(msg.sender, sub256(block.number, 1)) >\n proposalThreshold(),\n \"GovernorAlpha::propose: proposer votes below proposal threshold\"\n );\n require(\n targets.length == values.length &&\n targets.length == signatures.length &&\n targets.length == calldatas.length,\n \"GovernorAlpha::propose: proposal function information arity mismatch\"\n );\n require(\n targets.length != 0,\n \"GovernorAlpha::propose: must provide actions\"\n );\n require(\n targets.length <= proposalMaxOperations(),\n \"GovernorAlpha::propose: too many actions\"\n );\n\n uint256 latestProposalId = latestProposalIds[msg.sender];\n if (latestProposalId != 0) {\n ProposalState proposersLatestProposalState = state(\n latestProposalId\n );\n require(\n proposersLatestProposalState != ProposalState.Active,\n \"GovernorAlpha::propose: one live proposal per proposer\"\n );\n require(\n proposersLatestProposalState != ProposalState.Pending,\n \"GovernorAlpha::propose: one live proposal per proposer\"\n );\n }\n\n uint256 startBlock = add256(block.number, votingDelay());\n uint256 endBlock = add256(startBlock, votingPeriod());\n\n proposalCount++;\n Proposal storage newProposal = proposals[proposalCount];\n newProposal.id = proposalCount;\n newProposal.proposer = msg.sender;\n newProposal.eta = 0;\n newProposal.targets = targets;\n newProposal.values = values;\n newProposal.signatures = signatures;\n newProposal.calldatas = calldatas;\n newProposal.startBlock = startBlock;\n newProposal.endBlock = endBlock;\n newProposal.forVotes = 0;\n newProposal.againstVotes = 0;\n newProposal.canceled = false;\n newProposal.executed = false;\n\n latestProposalIds[newProposal.proposer] = newProposal.id;\n\n emit ProposalCreated(\n newProposal.id,\n msg.sender,\n targets,\n values,\n signatures,\n calldatas,\n startBlock,\n endBlock,\n description\n );\n return newProposal.id;\n }\n\n function queue(uint256 proposalId) public {\n require(\n state(proposalId) == ProposalState.Succeeded,\n \"GovernorAlpha::queue: proposal can only be queued if it is succeeded\"\n );\n Proposal storage proposal = proposals[proposalId];\n uint256 eta = add256(block.timestamp, timelock.delay());\n for (uint256 i = 0; i < proposal.targets.length; i++) {\n _queueOrRevert(\n proposal.targets[i],\n proposal.values[i],\n proposal.signatures[i],\n proposal.calldatas[i],\n eta\n );\n }\n proposal.eta = eta;\n emit ProposalQueued(proposalId, eta);\n }\n\n function _queueOrRevert(\n address target,\n uint256 value,\n string memory signature,\n bytes memory data,\n uint256 eta\n ) internal {\n require(\n !timelock.queuedTransactions(\n keccak256(abi.encode(target, value, signature, data, eta))\n ),\n \"GovernorAlpha::_queueOrRevert: proposal action already queued at eta\"\n );\n timelock.queueTransaction(target, value, signature, data, eta);\n }\n\n function execute(uint256 proposalId) public payable {\n require(\n state(proposalId) == ProposalState.Queued,\n \"GovernorAlpha::execute: proposal can only be executed if it is queued\"\n );\n Proposal storage proposal = proposals[proposalId];\n proposal.executed = true;\n for (uint256 i = 0; i < proposal.targets.length; i++) {\n timelock.executeTransaction{value: proposal.values[i]}(\n proposal.targets[i],\n proposal.values[i],\n proposal.signatures[i],\n proposal.calldatas[i],\n proposal.eta\n );\n }\n emit ProposalExecuted(proposalId);\n }\n\n function cancel(uint256 proposalId) public {\n ProposalState proposalState = state(proposalId);\n require(\n proposalState != ProposalState.Executed,\n \"GovernorAlpha::cancel: cannot cancel executed proposal\"\n );\n\n Proposal storage proposal = proposals[proposalId];\n require(\n msg.sender == guardian ||\n comp.getPriorVotes(proposal.proposer, sub256(block.number, 1)) <\n proposalThreshold(),\n \"GovernorAlpha::cancel: proposer above threshold\"\n );\n\n proposal.canceled = true;\n for (uint256 i = 0; i < proposal.targets.length; i++) {\n timelock.cancelTransaction(\n proposal.targets[i],\n proposal.values[i],\n proposal.signatures[i],\n proposal.calldatas[i],\n proposal.eta\n );\n }\n\n emit ProposalCanceled(proposalId);\n }\n\n function getActions(uint256 proposalId)\n public\n view\n returns (\n address[] memory targets,\n uint256[] memory values,\n string[] memory signatures,\n bytes[] memory calldatas\n )\n {\n Proposal storage p = proposals[proposalId];\n return (p.targets, p.values, p.signatures, p.calldatas);\n }\n\n function getReceipt(uint256 proposalId, address voter)\n public\n view\n returns (Receipt memory)\n {\n return proposals[proposalId].receipts[voter];\n }\n\n function state(uint256 proposalId) public view returns (ProposalState) {\n require(\n proposalCount >= proposalId && proposalId > 0,\n \"GovernorAlpha::state: invalid proposal id\"\n );\n Proposal storage proposal = proposals[proposalId];\n if (proposal.canceled) {\n return ProposalState.Canceled;\n } else if (block.number <= proposal.startBlock) {\n return ProposalState.Pending;\n } else if (block.number <= proposal.endBlock) {\n return ProposalState.Active;\n } else if (\n proposal.forVotes <= proposal.againstVotes ||\n proposal.forVotes < quorumVotes()\n ) {\n return ProposalState.Defeated;\n } else if (proposal.eta == 0) {\n return ProposalState.Succeeded;\n } else if (proposal.executed) {\n return ProposalState.Executed;\n } else if (\n block.timestamp >= add256(proposal.eta, timelock.GRACE_PERIOD())\n ) {\n return ProposalState.Expired;\n } else {\n return ProposalState.Queued;\n }\n }\n\n function castVote(uint256 proposalId, bool support) public {\n return _castVote(msg.sender, proposalId, support);\n }\n\n function castVoteBySig(\n uint256 proposalId,\n bool support,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) public {\n bytes32 domainSeparator = keccak256(\n abi.encode(\n DOMAIN_TYPEHASH,\n keccak256(bytes(name)),\n getChainId(),\n address(this)\n )\n );\n bytes32 structHash = keccak256(\n abi.encode(BALLOT_TYPEHASH, proposalId, support)\n );\n bytes32 digest = keccak256(\n abi.encodePacked(\"\\x19\\x01\", domainSeparator, structHash)\n );\n address signatory = ecrecover(digest, v, r, s);\n require(\n signatory != 0xdcc703c0E500B653Ca82273B7BFAd8045D85a470 &&\n signatory != address(0),\n \"GovernorAlpha::castVoteBySig: invalid signature\"\n );\n return _castVote(signatory, proposalId, support);\n }\n\n function _castVote(\n address voter,\n uint256 proposalId,\n bool support\n ) internal {\n require(\n state(proposalId) == ProposalState.Active,\n \"GovernorAlpha::_castVote: voting is closed\"\n );\n Proposal storage proposal = proposals[proposalId];\n Receipt storage receipt = proposal.receipts[voter];\n require(\n receipt.hasVoted == false,\n \"GovernorAlpha::_castVote: voter already voted\"\n );\n uint96 votes = comp.getPriorVotes(voter, proposal.startBlock);\n\n if (support) {\n proposal.forVotes = add256(proposal.forVotes, votes);\n } else {\n proposal.againstVotes = add256(proposal.againstVotes, votes);\n }\n\n receipt.hasVoted = true;\n receipt.support = support;\n receipt.votes = votes;\n\n emit VoteCast(voter, proposalId, support, votes);\n }\n\n function __acceptAdmin() public {\n require(\n msg.sender == guardian,\n \"GovernorAlpha::__acceptAdmin: sender must be gov guardian\"\n );\n timelock.acceptAdmin();\n }\n\n function __abdicate() public {\n require(\n msg.sender == guardian,\n \"GovernorAlpha::__abdicate: sender must be gov guardian\"\n );\n guardian = address(0);\n }\n\n function __queueSetTimelockPendingAdmin(\n address newPendingAdmin,\n uint256 eta\n ) public {\n require(\n msg.sender == guardian,\n \"GovernorAlpha::__queueSetTimelockPendingAdmin: sender must be gov guardian\"\n );\n timelock.queueTransaction(\n address(timelock),\n 0,\n \"setPendingAdmin(address)\",\n abi.encode(newPendingAdmin),\n eta\n );\n }\n\n function __executeSetTimelockPendingAdmin(\n address newPendingAdmin,\n uint256 eta\n ) public {\n require(\n msg.sender == guardian,\n \"GovernorAlpha::__executeSetTimelockPendingAdmin: sender must be gov guardian\"\n );\n timelock.executeTransaction(\n address(timelock),\n 0,\n \"setPendingAdmin(address)\",\n abi.encode(newPendingAdmin),\n eta\n );\n }\n\n function add256(uint256 a, uint256 b) internal pure returns (uint256) {\n uint256 c = a + b;\n require(c >= a, \"addition overflow\");\n return c;\n }\n\n function sub256(uint256 a, uint256 b) internal pure returns (uint256) {\n require(b <= a, \"subtraction underflow\");\n return a - b;\n }\n\n function getChainId() internal view returns (uint256) {\n uint256 chainId;\n assembly {\n chainId := chainid()\n }\n return chainId;\n }\n}\n\ninterface TimelockInterface {\n function delay() external view returns (uint256);\n\n function GRACE_PERIOD() external view returns (uint256);\n\n function acceptAdmin() external;\n\n function queuedTransactions(bytes32 hash) external view returns (bool);\n\n function queueTransaction(\n address target,\n uint256 value,\n string calldata signature,\n bytes calldata data,\n uint256 eta\n ) external returns (bytes32);\n\n function cancelTransaction(\n address target,\n uint256 value,\n string calldata signature,\n bytes calldata data,\n uint256 eta\n ) external;\n\n function executeTransaction(\n address target,\n uint256 value,\n string calldata signature,\n bytes calldata data,\n uint256 eta\n ) external payable returns (bytes memory);\n}\n\ninterface CompInterface {\n function getPriorVotes(address account, uint256 blockNumber)\n external\n view\n returns (uint96);\n}\n" - }, - "contracts/Reservoir.sol": { - "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity 0.8.6;\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 tropykus\n */\ncontract Reservoir {\n /// @notice The block number when the Reservoir started (immutable)\n uint256 public dripStart;\n\n /// @notice Tokens per block that to drip to target (immutable)\n uint256 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 uint256 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(\n uint256 dripRate_,\n EIP20Interface token_,\n address target_\n ) {\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 (uint256) {\n // First, read storage into memory\n EIP20Interface token_ = token;\n uint256 reservoirBalance_ = token_.balanceOf(address(this)); // TODO: Verify this is a static call\n uint256 dripRate_ = dripRate;\n uint256 dripStart_ = dripStart;\n uint256 dripped_ = dripped;\n address target_ = target;\n uint256 blockNumber_ = block.number;\n\n // Next, calculate intermediate values\n uint256 dripTotal_ = mul(\n dripRate_,\n blockNumber_ - dripStart_,\n \"dripTotal overflow\"\n );\n uint256 deltaDrip_ = sub(dripTotal_, dripped_, \"deltaDrip underflow\");\n uint256 toDrip_ = min(reservoirBalance_, deltaDrip_);\n uint256 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(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n uint256 c = a + b;\n require(c >= a, errorMessage);\n return c;\n }\n\n function sub(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n require(b <= a, errorMessage);\n uint256 c = a - b;\n return c;\n }\n\n function mul(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n if (a == 0) {\n return 0;\n }\n uint256 c = a * b;\n require(c / a == b, errorMessage);\n return c;\n }\n\n function min(uint256 a, uint256 b) internal pure returns (uint256) {\n if (a <= b) {\n return a;\n } else {\n return b;\n }\n }\n}\n\nimport \"./EIP20Interface.sol\";\n" - }, - "contracts/CRBTC.sol": { - "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity 0.8.6;\n\nimport \"./CToken.sol\";\n\n/**\n * @title tropykus CRBTC Contract\n * @notice CToken which wraps Ether\n * @author tropykus\n */\ncontract CRBTC is CToken {\n /**\n * @notice Construct a new CRBTC 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(\n ComptrollerInterface comptroller_,\n InterestRateModel interestRateModel_,\n uint256 initialExchangeRateMantissa_,\n string memory name_,\n string memory symbol_,\n uint8 decimals_,\n address payable admin_\n ) {\n // Creator of the contract is admin during initialization\n admin = payable(msg.sender);\n\n initialize(\n comptroller_,\n interestRateModel_,\n initialExchangeRateMantissa_,\n name_,\n symbol_,\n decimals_\n );\n\n // Set the proper admin now that initialization is done\n admin = admin_;\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 (uint256 err, ) = mintInternal(msg.value);\n requireNoError(err, \"RC01\");\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 redeem(uint256 redeemAmount) external returns (uint256) {\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(uint256 borrowAmount) external returns (uint256) {\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 (uint256 err, ) = repayBorrowInternal(msg.value);\n requireNoError(err, \"RC02\");\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)\n external\n payable\n {\n (uint256 err, ) = liquidateBorrowInternal(\n borrower,\n msg.value,\n cTokenCollateral\n );\n requireNoError(err, \"RC04\");\n }\n\n /**\n * @notice Send Ether to CRBTC to mint\n */\n fallback() external payable {\n internalFallback();\n }\n\n receive() external payable {\n internalFallback();\n }\n\n function internalFallback() public payable {\n (uint256 err, ) = mintInternal(msg.value);\n requireNoError(err, \"RC01\");\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 override returns (uint256) {\n (MathError err, uint256 startingBalance) = subUInt(\n address(this).balance,\n msg.value\n );\n if (interestRateModel.isTropykusInterestRateModel())\n (err, startingBalance) = subUInt(startingBalance, subsidyFund);\n require(err == MathError.NO_ERROR, \"RC05\");\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, uint256 amount)\n internal\n override\n returns (uint256)\n {\n // Sanity checks\n require(msg.sender == from, \"RC06\");\n require(msg.value == amount, \"RC07\");\n return amount;\n }\n\n function doTransferOut(address payable to, uint256 amount)\n internal\n virtual\n override\n {\n /* Send the Ether, with minimal gas and revert on failure */\n to.transfer(amount);\n }\n\n function requireNoError(uint256 errCode, string memory message)\n internal\n pure\n {\n if (errCode == uint256(Error.NO_ERROR)) {\n return;\n }\n\n bytes memory fullMessage = new bytes(bytes(message).length + 5);\n uint256 i;\n\n for (i = 0; i < bytes(message).length; i++) {\n fullMessage[i] = bytes(message)[i];\n }\n\n fullMessage[i + 0] = bytes1(uint8(32));\n fullMessage[i + 1] = bytes1(uint8(40));\n fullMessage[i + 2] = bytes1(uint8(48 + (errCode / 10)));\n fullMessage[i + 3] = bytes1(uint8(48 + (errCode % 10)));\n fullMessage[i + 4] = bytes1(uint8(41));\n\n require(errCode == uint256(Error.NO_ERROR), string(fullMessage));\n }\n\n function addSubsidy() external payable {\n _addSubsidyInternal(msg.value);\n }\n}\n" - }, - "contracts/ComptrollerG5.sol": { - "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity 0.8.6;\n\nimport \"./CToken.sol\";\nimport \"./ErrorReporter.sol\";\nimport \"./Exponential.sol\";\nimport \"./PriceOracle.sol\";\nimport \"./ComptrollerInterface.sol\";\nimport \"./ComptrollerStorage.sol\";\nimport \"./Unitroller.sol\";\nimport \"./Governance/TROP.sol\";\n\n/**\n * @title tropykus Comptroller Contract\n * @author tropykus\n */\ncontract ComptrollerG5 is\n ComptrollerV4Storage,\n ComptrollerInterface,\n ComptrollerErrorReporter,\n Exponential\n{\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(\n uint256 oldCloseFactorMantissa,\n uint256 newCloseFactorMantissa\n );\n\n /// @notice Emitted when a collateral factor is changed by admin\n event NewCollateralFactor(\n CToken cToken,\n uint256 oldCollateralFactorMantissa,\n uint256 newCollateralFactorMantissa\n );\n\n /// @notice Emitted when liquidation incentive is changed by admin\n event NewLiquidationIncentive(\n uint256 oldLiquidationIncentiveMantissa,\n uint256 newLiquidationIncentiveMantissa\n );\n\n /// @notice Emitted when maxAssets is changed by admin\n event NewMaxAssets(uint256 oldMaxAssets, uint256 newMaxAssets);\n\n /// @notice Emitted when price oracle is changed\n event NewPriceOracle(\n PriceOracle oldPriceOracle,\n PriceOracle newPriceOracle\n );\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(uint256 oldCompRate, uint256 newCompRate);\n\n /// @notice Emitted when a new COMP speed is calculated for a market\n event CompSpeedUpdated(CToken indexed cToken, uint256 newSpeed);\n\n /// @notice Emitted when COMP is distributed to a supplier\n event DistributedSupplierComp(\n CToken indexed cToken,\n address indexed supplier,\n uint256 compDelta,\n uint256 compSupplyIndex\n );\n\n /// @notice Emitted when COMP is distributed to a borrower\n event DistributedBorrowerComp(\n CToken indexed cToken,\n address indexed borrower,\n uint256 compDelta,\n uint256 compBorrowIndex\n );\n\n /// @notice Emitted when borrow cap for a cToken is changed\n event NewBorrowCap(CToken indexed cToken, uint256 newBorrowCap);\n\n /// @notice Emitted when borrow cap guardian is changed\n event NewBorrowCapGuardian(\n address oldBorrowCapGuardian,\n address newBorrowCapGuardian\n );\n\n /// @notice The threshold above which the flywheel transfers COMP, in wei\n uint256 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 uint256 internal constant closeFactorMinMantissa = 0.05e18; // 0.05\n\n // closeFactorMantissa must not exceed this value\n uint256 internal constant closeFactorMaxMantissa = 0.9e18; // 0.9\n\n // No collateralFactorMantissa may exceed this value\n uint256 internal constant collateralFactorMaxMantissa = 0.9e18; // 0.9\n\n // liquidationIncentiveMantissa must be no less than this value\n uint256 internal constant liquidationIncentiveMinMantissa = 1.0e18; // 1.0\n\n // liquidationIncentiveMantissa must be no greater than this value\n uint256 internal constant liquidationIncentiveMaxMantissa = 1.5e18; // 1.5\n\n constructor() {\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)\n external\n view\n returns (CToken[] memory)\n {\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)\n external\n view\n returns (bool)\n {\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)\n public\n override\n returns (uint256[] memory)\n {\n uint256 len = cTokens.length;\n\n uint256[] memory results = new uint256[](len);\n for (uint256 i = 0; i < len; i++) {\n CToken cToken = CToken(cTokens[i]);\n\n results[i] = uint256(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)\n internal\n returns (Error)\n {\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)\n external\n override\n returns (uint256)\n {\n CToken cToken = CToken(cTokenAddress);\n /* Get sender tokensHeld and amountOwed underlying from the cToken */\n (uint256 oErr, uint256 tokensHeld, uint256 amountOwed, ) = cToken\n .getAccountSnapshot(msg.sender);\n require(oErr == 0, \"C501\"); // semi-opaque error code\n\n /* Fail if the sender has a borrow balance */\n if (amountOwed != 0) {\n return\n fail(\n Error.NONZERO_BORROW_BALANCE,\n FailureInfo.EXIT_MARKET_BALANCE_OWED\n );\n }\n\n /* Fail if the sender is not permitted to redeem all of their tokens */\n uint256 allowed = redeemAllowedInternal(\n cTokenAddress,\n msg.sender,\n tokensHeld\n );\n if (allowed != 0) {\n return\n failOpaque(\n Error.REJECTION,\n FailureInfo.EXIT_MARKET_REJECTION,\n allowed\n );\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 uint256(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 accountAssets[msg.sender] = new CToken[](0);\n CToken[] storage newMarketList = accountAssets[msg.sender];\n uint256 len = userAssetList.length;\n uint256 assetIndex = len;\n for (uint256 i = 0; i < len; i++) {\n if (userAssetList[i] == cToken) {\n assetIndex = i;\n continue;\n }\n newMarketList.push(userAssetList[i]);\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 emit MarketExited(cToken, msg.sender);\n\n return uint256(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(\n address cToken,\n address minter,\n uint256 mintAmount\n ) external override returns (uint256) {\n // Pausing is a very serious situation - we revert to sound the alarms\n require(!mintGuardianPaused[cToken], \"C502\");\n\n // Shh - currently unused\n minter;\n mintAmount;\n\n if (!markets[cToken].isListed) {\n return uint256(Error.MARKET_NOT_LISTED);\n }\n\n // Keep the flywheel moving\n updateCompSupplyIndex(cToken);\n distributeSupplierComp(cToken, minter, false);\n\n return uint256(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(\n address cToken,\n address minter,\n uint256 actualMintAmount,\n uint256 mintTokens\n ) external override {\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(\n address cToken,\n address redeemer,\n uint256 redeemTokens\n ) external override returns (uint256) {\n uint256 allowed = redeemAllowedInternal(cToken, redeemer, redeemTokens);\n if (allowed != uint256(Error.NO_ERROR)) {\n return allowed;\n }\n\n // Keep the flywheel moving\n updateCompSupplyIndex(cToken);\n distributeSupplierComp(cToken, redeemer, false);\n\n return uint256(Error.NO_ERROR);\n }\n\n function redeemAllowedInternal(\n address cToken,\n address redeemer,\n uint256 redeemTokens\n ) internal view returns (uint256) {\n if (!markets[cToken].isListed) {\n return uint256(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 uint256(Error.NO_ERROR);\n }\n\n /* Otherwise, perform a hypothetical liquidity check to guard against shortfall */\n (\n Error err,\n ,\n uint256 shortfall\n ) = getHypotheticalAccountLiquidityInternal(\n redeemer,\n CToken(cToken),\n redeemTokens,\n 0\n );\n if (err != Error.NO_ERROR) {\n return uint256(err);\n }\n if (shortfall > 0) {\n return uint256(Error.INSUFFICIENT_LIQUIDITY);\n }\n\n return uint256(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(\n address cToken,\n address redeemer,\n uint256 redeemAmount,\n uint256 redeemTokens\n ) external pure override {\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(\"C503\");\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(\n address cToken,\n address borrower,\n uint256 borrowAmount\n ) external override returns (uint256) {\n // Pausing is a very serious situation - we revert to sound the alarms\n Error err;\n uint256 shortfall;\n require(!borrowGuardianPaused[cToken], \"C504\");\n\n if (!markets[cToken].isListed) {\n return uint256(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, \"C505\");\n\n // attempt to add borrower to the market\n err = addToMarketInternal(CToken(msg.sender), borrower);\n if (err != Error.NO_ERROR) {\n return uint256(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 uint256(Error.PRICE_ERROR);\n }\n\n uint256 borrowCap = borrowCaps[cToken];\n // Borrow cap of 0 corresponds to unlimited borrowing\n if (borrowCap != 0) {\n uint256 totalBorrows = CToken(cToken).totalBorrows();\n (MathError mathErr, uint256 nextTotalBorrows) = addUInt(\n totalBorrows,\n borrowAmount\n );\n require(mathErr == MathError.NO_ERROR, \"C506\");\n require(nextTotalBorrows < borrowCap, \"C507\");\n }\n\n (err, , shortfall) = getHypotheticalAccountLiquidityInternal(\n borrower,\n CToken(cToken),\n 0,\n borrowAmount\n );\n if (err != Error.NO_ERROR) {\n return uint256(err);\n }\n if (shortfall > 0) {\n return uint256(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 uint256(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(\n address cToken,\n address borrower,\n uint256 borrowAmount\n ) external override {\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 uint256 repayAmount\n ) external override returns (uint256) {\n // Shh - currently unused\n payer;\n borrower;\n repayAmount;\n\n if (!markets[cToken].isListed) {\n return uint256(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 uint256(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 uint256 actualRepayAmount,\n uint256 borrowerIndex\n ) external override {\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 uint256 repayAmount\n ) external view override returns (uint256) {\n // Shh - currently unused\n liquidator;\n\n if (\n !markets[cTokenBorrowed].isListed ||\n !markets[cTokenCollateral].isListed\n ) {\n return uint256(Error.MARKET_NOT_LISTED);\n }\n\n /* The borrower must have shortfall in order to be liquidatable */\n (Error err, , uint256 shortfall) = getAccountLiquidityInternal(\n borrower\n );\n if (err != Error.NO_ERROR) {\n return uint256(err);\n }\n if (shortfall == 0) {\n return uint256(Error.INSUFFICIENT_SHORTFALL);\n }\n\n /* The liquidator may not repay more than what is allowed by the closeFactor */\n uint256 borrowBalance = CToken(cTokenBorrowed).borrowBalanceStored(\n borrower\n );\n (MathError mathErr, uint256 maxClose) = mulScalarTruncate(\n Exp({mantissa: closeFactorMantissa}),\n borrowBalance\n );\n if (mathErr != MathError.NO_ERROR) {\n return uint256(Error.MATH_ERROR);\n }\n if (repayAmount > maxClose) {\n return uint256(Error.TOO_MUCH_REPAY);\n }\n\n return uint256(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 uint256 actualRepayAmount,\n uint256 seizeTokens\n ) external override {\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 uint256 seizeTokens\n ) external override returns (uint256) {\n // Pausing is a very serious situation - we revert to sound the alarms\n require(!seizeGuardianPaused, \"C508\");\n\n // Shh - currently unused\n seizeTokens;\n\n if (\n !markets[cTokenCollateral].isListed ||\n !markets[cTokenBorrowed].isListed\n ) {\n return uint256(Error.MARKET_NOT_LISTED);\n }\n\n if (\n CToken(cTokenCollateral).comptroller() !=\n CToken(cTokenBorrowed).comptroller()\n ) {\n return uint256(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 uint256(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 uint256 seizeTokens\n ) external override {\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(\n address cToken,\n address src,\n address dst,\n uint256 transferTokens\n ) external override returns (uint256) {\n // Pausing is a very serious situation - we revert to sound the alarms\n require(!transferGuardianPaused, \"C509\");\n\n // Currently the only consideration is whether or not\n // the src is allowed to redeem this many tokens\n uint256 allowed = redeemAllowedInternal(cToken, src, transferTokens);\n if (allowed != uint256(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 uint256(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(\n address cToken,\n address src,\n address dst,\n uint256 transferTokens\n ) external override {\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 uint256 sumCollateral;\n uint256 sumBorrowPlusEffects;\n uint256 cTokenBalance;\n uint256 borrowBalance;\n uint256 exchangeRateMantissa;\n uint256 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)\n public\n view\n returns (\n uint256,\n uint256,\n uint256\n )\n {\n (\n Error err,\n uint256 liquidity,\n uint256 shortfall\n ) = getHypotheticalAccountLiquidityInternal(\n account,\n CToken(address(0)),\n 0,\n 0\n );\n\n return (uint256(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)\n internal\n view\n returns (\n Error,\n uint256,\n uint256\n )\n {\n return\n getHypotheticalAccountLiquidityInternal(\n account,\n CToken(address(0)),\n 0,\n 0\n );\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 uint256 redeemTokens,\n uint256 borrowAmount\n )\n public\n view\n returns (\n uint256,\n uint256,\n uint256\n )\n {\n (\n Error err,\n uint256 liquidity,\n uint256 shortfall\n ) = getHypotheticalAccountLiquidityInternal(\n account,\n CToken(cTokenModify),\n redeemTokens,\n borrowAmount\n );\n return (uint256(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 uint256 redeemTokens,\n uint256 borrowAmount\n )\n internal\n view\n returns (\n Error,\n uint256,\n uint256\n )\n {\n AccountLiquidityLocalVars memory vars; // Holds all our calculation results\n uint256 oErr;\n MathError mErr;\n\n // For each asset the account is in\n CToken[] memory assets = accountAssets[account];\n for (uint256 i = 0; i < assets.length; i++) {\n CToken asset = assets[i];\n\n // Read the balances and exchange rate from the cToken\n (\n oErr,\n vars.cTokenBalance,\n vars.borrowBalance,\n vars.exchangeRateMantissa\n ) = asset.getAccountSnapshot(account);\n if (oErr != 0) {\n // 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({\n mantissa: markets[address(asset)].collateralFactorMantissa\n });\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(\n vars.collateralFactor,\n vars.exchangeRate,\n vars.oraclePrice\n );\n if (mErr != MathError.NO_ERROR) {\n return (Error.MATH_ERROR, 0, 0);\n }\n\n // sumCollateral += tokensToDenom * cTokenBalance\n (mErr, vars.sumCollateral) = mulScalarTruncateAddUInt(\n vars.tokensToDenom,\n vars.cTokenBalance,\n vars.sumCollateral\n );\n if (mErr != MathError.NO_ERROR) {\n return (Error.MATH_ERROR, 0, 0);\n }\n\n // sumBorrowPlusEffects += oraclePrice * borrowBalance\n (mErr, vars.sumBorrowPlusEffects) = mulScalarTruncateAddUInt(\n vars.oraclePrice,\n vars.borrowBalance,\n vars.sumBorrowPlusEffects\n );\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(\n vars.tokensToDenom,\n redeemTokens,\n vars.sumBorrowPlusEffects\n );\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(\n vars.oraclePrice,\n borrowAmount,\n vars.sumBorrowPlusEffects\n );\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 (\n Error.NO_ERROR,\n vars.sumCollateral - vars.sumBorrowPlusEffects,\n 0\n );\n } else {\n return (\n Error.NO_ERROR,\n 0,\n vars.sumBorrowPlusEffects - vars.sumCollateral\n );\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(\n address cTokenBorrowed,\n address cTokenCollateral,\n uint256 actualRepayAmount\n ) external view override returns (uint256, uint256) {\n /* Read oracle prices for borrowed and collateral markets */\n uint256 priceBorrowedMantissa = oracle.getUnderlyingPrice(\n CToken(cTokenBorrowed)\n );\n uint256 priceCollateralMantissa = oracle.getUnderlyingPrice(\n CToken(cTokenCollateral)\n );\n if (priceBorrowedMantissa == 0 || priceCollateralMantissa == 0) {\n return (uint256(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 uint256 exchangeRateMantissa = CToken(cTokenCollateral)\n .exchangeRateStored(); // Note: reverts on error\n uint256 seizeTokens;\n Exp memory numerator;\n Exp memory denominator;\n Exp memory ratio;\n MathError mathErr;\n\n (mathErr, numerator) = mulExp(\n liquidationIncentiveMantissa,\n priceBorrowedMantissa\n );\n if (mathErr != MathError.NO_ERROR) {\n return (uint256(Error.MATH_ERROR), 0);\n }\n\n (mathErr, denominator) = mulExp(\n priceCollateralMantissa,\n exchangeRateMantissa\n );\n if (mathErr != MathError.NO_ERROR) {\n return (uint256(Error.MATH_ERROR), 0);\n }\n\n (mathErr, ratio) = divExp(numerator, denominator);\n if (mathErr != MathError.NO_ERROR) {\n return (uint256(Error.MATH_ERROR), 0);\n }\n\n (mathErr, seizeTokens) = mulScalarTruncate(ratio, actualRepayAmount);\n if (mathErr != MathError.NO_ERROR) {\n return (uint256(Error.MATH_ERROR), 0);\n }\n\n return (uint256(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 (uint256) {\n // Check caller is admin\n if (msg.sender != admin) {\n return\n fail(\n Error.UNAUTHORIZED,\n FailureInfo.SET_PRICE_ORACLE_OWNER_CHECK\n );\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 uint256(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(uint256 newCloseFactorMantissa)\n external\n returns (uint256)\n {\n // Check caller is admin\n if (msg.sender != admin) {\n return\n fail(\n Error.UNAUTHORIZED,\n FailureInfo.SET_CLOSE_FACTOR_OWNER_CHECK\n );\n }\n\n Exp memory newCloseFactorExp = Exp({mantissa: newCloseFactorMantissa});\n Exp memory lowLimit = Exp({mantissa: closeFactorMinMantissa});\n if (lessThanOrEqualExp(newCloseFactorExp, lowLimit)) {\n return\n fail(\n Error.INVALID_CLOSE_FACTOR,\n FailureInfo.SET_CLOSE_FACTOR_VALIDATION\n );\n }\n\n Exp memory highLimit = Exp({mantissa: closeFactorMaxMantissa});\n if (lessThanExp(highLimit, newCloseFactorExp)) {\n return\n fail(\n Error.INVALID_CLOSE_FACTOR,\n FailureInfo.SET_CLOSE_FACTOR_VALIDATION\n );\n }\n\n uint256 oldCloseFactorMantissa = closeFactorMantissa;\n closeFactorMantissa = newCloseFactorMantissa;\n emit NewCloseFactor(oldCloseFactorMantissa, closeFactorMantissa);\n\n return uint256(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(\n CToken cToken,\n uint256 newCollateralFactorMantissa\n ) external returns (uint256) {\n // Check caller is admin\n if (msg.sender != admin) {\n return\n fail(\n Error.UNAUTHORIZED,\n FailureInfo.SET_COLLATERAL_FACTOR_OWNER_CHECK\n );\n }\n\n // Verify market is listed\n Market storage market = markets[address(cToken)];\n if (!market.isListed) {\n return\n fail(\n Error.MARKET_NOT_LISTED,\n FailureInfo.SET_COLLATERAL_FACTOR_NO_EXISTS\n );\n }\n\n Exp memory newCollateralFactorExp = Exp({\n mantissa: newCollateralFactorMantissa\n });\n\n // Check collateral factor <= 0.9\n Exp memory highLimit = Exp({mantissa: collateralFactorMaxMantissa});\n if (lessThanExp(highLimit, newCollateralFactorExp)) {\n return\n fail(\n Error.INVALID_COLLATERAL_FACTOR,\n FailureInfo.SET_COLLATERAL_FACTOR_VALIDATION\n );\n }\n\n // If collateral factor != 0, fail if price == 0\n if (\n newCollateralFactorMantissa != 0 &&\n oracle.getUnderlyingPrice(cToken) == 0\n ) {\n return\n fail(\n Error.PRICE_ERROR,\n FailureInfo.SET_COLLATERAL_FACTOR_WITHOUT_PRICE\n );\n }\n\n // Set market's collateral factor to new collateral factor, remember old value\n uint256 oldCollateralFactorMantissa = market.collateralFactorMantissa;\n market.collateralFactorMantissa = newCollateralFactorMantissa;\n\n // Emit event with asset, old collateral factor, and new collateral factor\n emit NewCollateralFactor(\n cToken,\n oldCollateralFactorMantissa,\n newCollateralFactorMantissa\n );\n\n return uint256(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(uint256 newMaxAssets) external returns (uint256) {\n // Check caller is admin\n if (msg.sender != admin) {\n return\n fail(\n Error.UNAUTHORIZED,\n FailureInfo.SET_MAX_ASSETS_OWNER_CHECK\n );\n }\n\n uint256 oldMaxAssets = maxAssets;\n maxAssets = newMaxAssets;\n emit NewMaxAssets(oldMaxAssets, newMaxAssets);\n\n return uint256(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(uint256 newLiquidationIncentiveMantissa)\n external\n returns (uint256)\n {\n // Check caller is admin\n if (msg.sender != admin) {\n return\n fail(\n Error.UNAUTHORIZED,\n FailureInfo.SET_LIQUIDATION_INCENTIVE_OWNER_CHECK\n );\n }\n\n // Check de-scaled min <= newLiquidationIncentive <= max\n Exp memory newLiquidationIncentive = Exp({\n mantissa: newLiquidationIncentiveMantissa\n });\n Exp memory minLiquidationIncentive = Exp({\n mantissa: liquidationIncentiveMinMantissa\n });\n if (lessThanExp(newLiquidationIncentive, minLiquidationIncentive)) {\n return\n fail(\n Error.INVALID_LIQUIDATION_INCENTIVE,\n FailureInfo.SET_LIQUIDATION_INCENTIVE_VALIDATION\n );\n }\n\n Exp memory maxLiquidationIncentive = Exp({\n mantissa: liquidationIncentiveMaxMantissa\n });\n if (lessThanExp(maxLiquidationIncentive, newLiquidationIncentive)) {\n return\n fail(\n Error.INVALID_LIQUIDATION_INCENTIVE,\n FailureInfo.SET_LIQUIDATION_INCENTIVE_VALIDATION\n );\n }\n\n // Save current value for use in log\n uint256 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(\n oldLiquidationIncentiveMantissa,\n newLiquidationIncentiveMantissa\n );\n\n return uint256(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 (uint256) {\n if (msg.sender != admin) {\n return\n fail(\n Error.UNAUTHORIZED,\n FailureInfo.SUPPORT_MARKET_OWNER_CHECK\n );\n }\n\n if (markets[address(cToken)].isListed) {\n return\n fail(\n Error.MARKET_ALREADY_LISTED,\n FailureInfo.SUPPORT_MARKET_EXISTS\n );\n }\n\n cToken.isCToken(); // Sanity check to make sure its really a CToken\n\n Market storage market = markets[address(cToken)];\n market.isListed = true;\n market.isComped = false;\n market.collateralFactorMantissa = 0;\n\n _addMarketInternal(address(cToken));\n\n emit MarketListed(cToken);\n\n return uint256(Error.NO_ERROR);\n }\n\n function _addMarketInternal(address cToken) internal {\n for (uint256 i = 0; i < allMarkets.length; i++) {\n require(allMarkets[i] != CToken(cToken), \"C510\");\n }\n allMarkets.push(CToken(cToken));\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(\n CToken[] calldata cTokens,\n uint256[] calldata newBorrowCaps\n ) external {\n require(msg.sender == admin || msg.sender == borrowCapGuardian, \"C511\");\n\n uint256 numMarkets = cTokens.length;\n uint256 numBorrowCaps = newBorrowCaps.length;\n\n require(numMarkets != 0 && numMarkets == numBorrowCaps, \"C512\");\n\n for (uint256 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, \"C513\");\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)\n public\n returns (uint256)\n {\n if (msg.sender != admin) {\n return\n fail(\n Error.UNAUTHORIZED,\n FailureInfo.SET_PAUSE_GUARDIAN_OWNER_CHECK\n );\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 uint256(Error.NO_ERROR);\n }\n\n function _setMintPaused(CToken cToken, bool state) public returns (bool) {\n require(markets[address(cToken)].isListed, \"C514\");\n require(msg.sender == pauseGuardian || msg.sender == admin, \"C515\");\n require(msg.sender == admin || state == true, \"C516\");\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, \"C514\");\n require(msg.sender == pauseGuardian || msg.sender == admin, \"C515\");\n require(msg.sender == admin || state == true, \"C516\");\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, \"C515\");\n require(msg.sender == admin || state == true, \"C516\");\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, \"C515\");\n require(msg.sender == admin || state == true, \"C516\");\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(), \"C517\");\n require(unitroller._acceptImplementation() == 0, \"C518\");\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, \"C519\");\n refreshCompSpeedsInternal();\n }\n\n function refreshCompSpeedsInternal() internal {\n CToken[] memory allMarkets_ = allMarkets;\n\n for (uint256 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 (uint256 i = 0; i < allMarkets_.length; i++) {\n CToken cToken = allMarkets_[i];\n if (markets[address(cToken)].isComped) {\n Exp memory assetPrice = Exp({\n mantissa: oracle.getUnderlyingPrice(cToken)\n });\n Exp memory utility = mul_(assetPrice, cToken.totalBorrows());\n utilities[i] = utility;\n totalUtility = add_(totalUtility, utility);\n }\n }\n\n for (uint256 i = 0; i < allMarkets_.length; i++) {\n CToken cToken = allMarkets[i];\n uint256 newSpeed = totalUtility.mantissa > 0\n ? mul_(compRate, div_(utilities[i], totalUtility))\n : 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 uint256 supplySpeed = compSpeeds[cToken];\n uint256 blockNumber = getBlockNumber();\n uint256 deltaBlocks = sub_(blockNumber, uint256(supplyState.block));\n if (deltaBlocks > 0 && supplySpeed > 0) {\n uint256 supplyTokens = CToken(cToken).totalSupply();\n uint256 compAccrued = mul_(deltaBlocks, supplySpeed);\n Double memory ratio = supplyTokens > 0\n ? fraction(compAccrued, supplyTokens)\n : Double({mantissa: 0});\n Double memory index = add_(\n Double({mantissa: supplyState.index}),\n ratio\n );\n compSupplyState[cToken] = CompMarketState({\n index: safe224(index.mantissa, \"C520\"),\n block: safe32(blockNumber, \"C521\")\n });\n } else if (deltaBlocks > 0) {\n supplyState.block = safe32(blockNumber, \"C521\");\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)\n internal\n {\n CompMarketState storage borrowState = compBorrowState[cToken];\n uint256 borrowSpeed = compSpeeds[cToken];\n uint256 blockNumber = getBlockNumber();\n uint256 deltaBlocks = sub_(blockNumber, uint256(borrowState.block));\n if (deltaBlocks > 0 && borrowSpeed > 0) {\n uint256 borrowAmount = div_(\n CToken(cToken).totalBorrows(),\n marketBorrowIndex\n );\n uint256 compAccrued = mul_(deltaBlocks, borrowSpeed);\n Double memory ratio = borrowAmount > 0\n ? fraction(compAccrued, borrowAmount)\n : Double({mantissa: 0});\n Double memory index = add_(\n Double({mantissa: borrowState.index}),\n ratio\n );\n compBorrowState[cToken] = CompMarketState({\n index: safe224(index.mantissa, \"C520\"),\n block: safe32(blockNumber, \"C521\")\n });\n } else if (deltaBlocks > 0) {\n borrowState.block = safe32(blockNumber, \"C521\");\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(\n address cToken,\n address supplier,\n bool distributeAll\n ) internal {\n CompMarketState storage supplyState = compSupplyState[cToken];\n Double memory supplyIndex = Double({mantissa: supplyState.index});\n Double memory supplierIndex = Double({\n mantissa: compSupplierIndex[cToken][supplier]\n });\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 uint256 supplierTokens = CToken(cToken).balanceOf(supplier);\n uint256 supplierDelta = mul_(supplierTokens, deltaIndex);\n uint256 supplierAccrued = add_(compAccrued[supplier], supplierDelta);\n compAccrued[supplier] = transferComp(\n supplier,\n supplierAccrued,\n distributeAll ? 0 : compClaimThreshold\n );\n emit DistributedSupplierComp(\n CToken(cToken),\n supplier,\n supplierDelta,\n supplyIndex.mantissa\n );\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(\n address cToken,\n address borrower,\n Exp memory marketBorrowIndex,\n bool distributeAll\n ) internal {\n CompMarketState storage borrowState = compBorrowState[cToken];\n Double memory borrowIndex = Double({mantissa: borrowState.index});\n Double memory borrowerIndex = Double({\n mantissa: compBorrowerIndex[cToken][borrower]\n });\n compBorrowerIndex[cToken][borrower] = borrowIndex.mantissa;\n\n if (borrowerIndex.mantissa > 0) {\n Double memory deltaIndex = sub_(borrowIndex, borrowerIndex);\n uint256 borrowerAmount = div_(\n CToken(cToken).borrowBalanceStored(borrower),\n marketBorrowIndex\n );\n uint256 borrowerDelta = mul_(borrowerAmount, deltaIndex);\n uint256 borrowerAccrued = add_(\n compAccrued[borrower],\n borrowerDelta\n );\n compAccrued[borrower] = transferComp(\n borrower,\n borrowerAccrued,\n distributeAll ? 0 : compClaimThreshold\n );\n emit DistributedBorrowerComp(\n CToken(cToken),\n borrower,\n borrowerDelta,\n borrowIndex.mantissa\n );\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(\n address user,\n uint256 userAccrued,\n uint256 threshold\n ) internal returns (uint256) {\n if (userAccrued >= threshold && userAccrued > 0) {\n TROP comp = TROP(getCompAddress());\n uint256 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(\n address[] memory holders,\n CToken[] memory cTokens,\n bool borrowers,\n bool suppliers\n ) public {\n for (uint256 i = 0; i < cTokens.length; i++) {\n CToken cToken = cTokens[i];\n require(markets[address(cToken)].isListed, \"C522\");\n if (borrowers == true) {\n Exp memory borrowIndex = Exp({mantissa: cToken.borrowIndex()});\n updateCompBorrowIndex(address(cToken), borrowIndex);\n for (uint256 j = 0; j < holders.length; j++) {\n distributeBorrowerComp(\n address(cToken),\n holders[j],\n borrowIndex,\n true\n );\n }\n }\n if (suppliers == true) {\n updateCompSupplyIndex(address(cToken));\n for (uint256 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(uint256 compRate_) public {\n require(adminOrInitializing(), \"C523\");\n\n uint256 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(), \"C524\");\n\n for (uint256 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, \"C525\");\n require(market.isComped == false, \"C526\");\n\n market.isComped = true;\n emit MarketComped(CToken(cToken), true);\n\n if (\n compSupplyState[cToken].index == 0 &&\n compSupplyState[cToken].block == 0\n ) {\n compSupplyState[cToken] = CompMarketState({\n index: compInitialIndex,\n block: safe32(getBlockNumber(), \"C521\")\n });\n }\n\n if (\n compBorrowState[cToken].index == 0 &&\n compBorrowState[cToken].block == 0\n ) {\n compBorrowState[cToken] = CompMarketState({\n index: compInitialIndex,\n block: safe32(getBlockNumber(), \"C521\")\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, \"C527\");\n\n Market storage market = markets[cToken];\n require(market.isComped == true, \"C528\");\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 virtual returns (uint256) {\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 virtual returns (address) {\n return 0xc00e94Cb662C3520282E6f5717214004A7f26888;\n }\n}\n" - }, - "contracts/ComptrollerG4.sol": { - "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity 0.8.6;\n\nimport \"./CToken.sol\";\nimport \"./ErrorReporter.sol\";\nimport \"./Exponential.sol\";\nimport \"./PriceOracle.sol\";\nimport \"./ComptrollerInterface.sol\";\nimport \"./ComptrollerStorage.sol\";\nimport \"./Unitroller.sol\";\nimport \"./Governance/TROP.sol\";\n\n/**\n * @title tropykus Comptroller Contract\n * @author tropykus\n */\ncontract ComptrollerG4 is\n ComptrollerV3Storage,\n ComptrollerInterface,\n ComptrollerErrorReporter,\n Exponential\n{\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(\n uint256 oldCloseFactorMantissa,\n uint256 newCloseFactorMantissa\n );\n\n /// @notice Emitted when a collateral factor is changed by admin\n event NewCollateralFactor(\n CToken cToken,\n uint256 oldCollateralFactorMantissa,\n uint256 newCollateralFactorMantissa\n );\n\n /// @notice Emitted when liquidation incentive is changed by admin\n event NewLiquidationIncentive(\n uint256 oldLiquidationIncentiveMantissa,\n uint256 newLiquidationIncentiveMantissa\n );\n\n /// @notice Emitted when maxAssets is changed by admin\n event NewMaxAssets(uint256 oldMaxAssets, uint256 newMaxAssets);\n\n /// @notice Emitted when price oracle is changed\n event NewPriceOracle(\n PriceOracle oldPriceOracle,\n PriceOracle newPriceOracle\n );\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(uint256 oldCompRate, uint256 newCompRate);\n\n /// @notice Emitted when a new COMP speed is calculated for a market\n event CompSpeedUpdated(CToken indexed cToken, uint256 newSpeed);\n\n /// @notice Emitted when COMP is distributed to a supplier\n event DistributedSupplierComp(\n CToken indexed cToken,\n address indexed supplier,\n uint256 compDelta,\n uint256 compSupplyIndex\n );\n\n /// @notice Emitted when COMP is distributed to a borrower\n event DistributedBorrowerComp(\n CToken indexed cToken,\n address indexed borrower,\n uint256 compDelta,\n uint256 compBorrowIndex\n );\n\n /// @notice The threshold above which the flywheel transfers COMP, in wei\n uint256 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 uint256 internal constant closeFactorMinMantissa = 0.05e18; // 0.05\n\n // closeFactorMantissa must not exceed this value\n uint256 internal constant closeFactorMaxMantissa = 0.9e18; // 0.9\n\n // No collateralFactorMantissa may exceed this value\n uint256 internal constant collateralFactorMaxMantissa = 0.9e18; // 0.9\n\n // liquidationIncentiveMantissa must be no less than this value\n uint256 internal constant liquidationIncentiveMinMantissa = 1.0e18; // 1.0\n\n // liquidationIncentiveMantissa must be no greater than this value\n uint256 internal constant liquidationIncentiveMaxMantissa = 1.5e18; // 1.5\n\n constructor() {\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)\n external\n view\n returns (CToken[] memory)\n {\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)\n external\n view\n returns (bool)\n {\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)\n public\n override\n returns (uint256[] memory)\n {\n uint256 len = cTokens.length;\n\n uint256[] memory results = new uint256[](len);\n for (uint256 i = 0; i < len; i++) {\n CToken cToken = CToken(cTokens[i]);\n\n results[i] = uint256(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)\n internal\n returns (Error)\n {\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)\n external\n override\n returns (uint256)\n {\n CToken cToken = CToken(cTokenAddress);\n /* Get sender tokensHeld and amountOwed underlying from the cToken */\n (uint256 oErr, uint256 tokensHeld, uint256 amountOwed, ) = cToken\n .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\n fail(\n Error.NONZERO_BORROW_BALANCE,\n FailureInfo.EXIT_MARKET_BALANCE_OWED\n );\n }\n\n /* Fail if the sender is not permitted to redeem all of their tokens */\n uint256 allowed = redeemAllowedInternal(\n cTokenAddress,\n msg.sender,\n tokensHeld\n );\n if (allowed != 0) {\n return\n failOpaque(\n Error.REJECTION,\n FailureInfo.EXIT_MARKET_REJECTION,\n allowed\n );\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 uint256(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 accountAssets[msg.sender] = new CToken[](0);\n CToken[] storage newMarketList = accountAssets[msg.sender];\n uint256 len = userAssetList.length;\n uint256 assetIndex = len;\n for (uint256 i = 0; i < len; i++) {\n if (userAssetList[i] == cToken) {\n assetIndex = i;\n continue;\n }\n newMarketList.push(userAssetList[i]);\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 emit MarketExited(cToken, msg.sender);\n\n return uint256(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(\n address cToken,\n address minter,\n uint256 mintAmount\n ) external override returns (uint256) {\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 uint256(Error.MARKET_NOT_LISTED);\n }\n\n // Keep the flywheel moving\n updateCompSupplyIndex(cToken);\n distributeSupplierComp(cToken, minter, false);\n\n return uint256(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(\n address cToken,\n address minter,\n uint256 actualMintAmount,\n uint256 mintTokens\n ) external override {\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(\n address cToken,\n address redeemer,\n uint256 redeemTokens\n ) external override returns (uint256) {\n uint256 allowed = redeemAllowedInternal(cToken, redeemer, redeemTokens);\n if (allowed != uint256(Error.NO_ERROR)) {\n return allowed;\n }\n\n // Keep the flywheel moving\n updateCompSupplyIndex(cToken);\n distributeSupplierComp(cToken, redeemer, false);\n\n return uint256(Error.NO_ERROR);\n }\n\n function redeemAllowedInternal(\n address cToken,\n address redeemer,\n uint256 redeemTokens\n ) internal view returns (uint256) {\n if (!markets[cToken].isListed) {\n return uint256(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 uint256(Error.NO_ERROR);\n }\n\n /* Otherwise, perform a hypothetical liquidity check to guard against shortfall */\n (\n Error err,\n ,\n uint256 shortfall\n ) = getHypotheticalAccountLiquidityInternal(\n redeemer,\n CToken(cToken),\n redeemTokens,\n 0\n );\n if (err != Error.NO_ERROR) {\n return uint256(err);\n }\n if (shortfall > 0) {\n return uint256(Error.INSUFFICIENT_LIQUIDITY);\n }\n\n return uint256(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(\n address cToken,\n address redeemer,\n uint256 redeemAmount,\n uint256 redeemTokens\n ) external pure override {\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(\n address cToken,\n address borrower,\n uint256 borrowAmount\n ) external override returns (uint256) {\n // Pausing is a very serious situation - we revert to sound the alarms\n Error err;\n uint256 shortfall;\n require(!borrowGuardianPaused[cToken], \"borrow is paused\");\n\n if (!markets[cToken].isListed) {\n return uint256(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 err = addToMarketInternal(CToken(msg.sender), borrower);\n if (err != Error.NO_ERROR) {\n return uint256(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 uint256(Error.PRICE_ERROR);\n }\n\n (err, , shortfall) = getHypotheticalAccountLiquidityInternal(\n borrower,\n CToken(cToken),\n 0,\n borrowAmount\n );\n if (err != Error.NO_ERROR) {\n return uint256(err);\n }\n if (shortfall > 0) {\n return uint256(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 uint256(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(\n address cToken,\n address borrower,\n uint256 borrowAmount\n ) external override {\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 uint256 repayAmount\n ) external override returns (uint256) {\n // Shh - currently unused\n payer;\n borrower;\n repayAmount;\n\n if (!markets[cToken].isListed) {\n return uint256(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 uint256(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 uint256 actualRepayAmount,\n uint256 borrowerIndex\n ) external override {\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 uint256 repayAmount\n ) external view override returns (uint256) {\n // Shh - currently unused\n liquidator;\n\n if (\n !markets[cTokenBorrowed].isListed ||\n !markets[cTokenCollateral].isListed\n ) {\n return uint256(Error.MARKET_NOT_LISTED);\n }\n\n /* The borrower must have shortfall in order to be liquidatable */\n (Error err, , uint256 shortfall) = getAccountLiquidityInternal(\n borrower\n );\n if (err != Error.NO_ERROR) {\n return uint256(err);\n }\n if (shortfall == 0) {\n return uint256(Error.INSUFFICIENT_SHORTFALL);\n }\n\n /* The liquidator may not repay more than what is allowed by the closeFactor */\n uint256 borrowBalance = CToken(cTokenBorrowed).borrowBalanceStored(\n borrower\n );\n (MathError mathErr, uint256 maxClose) = mulScalarTruncate(\n Exp({mantissa: closeFactorMantissa}),\n borrowBalance\n );\n if (mathErr != MathError.NO_ERROR) {\n return uint256(Error.MATH_ERROR);\n }\n if (repayAmount > maxClose) {\n return uint256(Error.TOO_MUCH_REPAY);\n }\n\n return uint256(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 uint256 actualRepayAmount,\n uint256 seizeTokens\n ) external override {\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 uint256 seizeTokens\n ) external override returns (uint256) {\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 (\n !markets[cTokenCollateral].isListed ||\n !markets[cTokenBorrowed].isListed\n ) {\n return uint256(Error.MARKET_NOT_LISTED);\n }\n\n if (\n CToken(cTokenCollateral).comptroller() !=\n CToken(cTokenBorrowed).comptroller()\n ) {\n return uint256(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 uint256(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 uint256 seizeTokens\n ) external override {\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(\n address cToken,\n address src,\n address dst,\n uint256 transferTokens\n ) external override returns (uint256) {\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 uint256 allowed = redeemAllowedInternal(cToken, src, transferTokens);\n if (allowed != uint256(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 uint256(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(\n address cToken,\n address src,\n address dst,\n uint256 transferTokens\n ) external override {\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 uint256 sumCollateral;\n uint256 sumBorrowPlusEffects;\n uint256 cTokenBalance;\n uint256 borrowBalance;\n uint256 exchangeRateMantissa;\n uint256 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)\n public\n view\n returns (\n uint256,\n uint256,\n uint256\n )\n {\n (\n Error err,\n uint256 liquidity,\n uint256 shortfall\n ) = getHypotheticalAccountLiquidityInternal(\n account,\n CToken(address(0)),\n 0,\n 0\n );\n\n return (uint256(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)\n internal\n view\n returns (\n Error,\n uint256,\n uint256\n )\n {\n return\n getHypotheticalAccountLiquidityInternal(\n account,\n CToken(address(0)),\n 0,\n 0\n );\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 uint256 redeemTokens,\n uint256 borrowAmount\n )\n public\n view\n returns (\n uint256,\n uint256,\n uint256\n )\n {\n (\n Error err,\n uint256 liquidity,\n uint256 shortfall\n ) = getHypotheticalAccountLiquidityInternal(\n account,\n CToken(cTokenModify),\n redeemTokens,\n borrowAmount\n );\n return (uint256(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 uint256 redeemTokens,\n uint256 borrowAmount\n )\n internal\n view\n returns (\n Error,\n uint256,\n uint256\n )\n {\n AccountLiquidityLocalVars memory vars; // Holds all our calculation results\n uint256 oErr;\n MathError mErr;\n\n // For each asset the account is in\n CToken[] memory assets = accountAssets[account];\n for (uint256 i = 0; i < assets.length; i++) {\n CToken asset = assets[i];\n\n // Read the balances and exchange rate from the cToken\n (\n oErr,\n vars.cTokenBalance,\n vars.borrowBalance,\n vars.exchangeRateMantissa\n ) = asset.getAccountSnapshot(account);\n if (oErr != 0) {\n // 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({\n mantissa: markets[address(asset)].collateralFactorMantissa\n });\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(\n vars.collateralFactor,\n vars.exchangeRate,\n vars.oraclePrice\n );\n if (mErr != MathError.NO_ERROR) {\n return (Error.MATH_ERROR, 0, 0);\n }\n\n // sumCollateral += tokensToDenom * cTokenBalance\n (mErr, vars.sumCollateral) = mulScalarTruncateAddUInt(\n vars.tokensToDenom,\n vars.cTokenBalance,\n vars.sumCollateral\n );\n if (mErr != MathError.NO_ERROR) {\n return (Error.MATH_ERROR, 0, 0);\n }\n\n // sumBorrowPlusEffects += oraclePrice * borrowBalance\n (mErr, vars.sumBorrowPlusEffects) = mulScalarTruncateAddUInt(\n vars.oraclePrice,\n vars.borrowBalance,\n vars.sumBorrowPlusEffects\n );\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(\n vars.tokensToDenom,\n redeemTokens,\n vars.sumBorrowPlusEffects\n );\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(\n vars.oraclePrice,\n borrowAmount,\n vars.sumBorrowPlusEffects\n );\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 (\n Error.NO_ERROR,\n vars.sumCollateral - vars.sumBorrowPlusEffects,\n 0\n );\n } else {\n return (\n Error.NO_ERROR,\n 0,\n vars.sumBorrowPlusEffects - vars.sumCollateral\n );\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(\n address cTokenBorrowed,\n address cTokenCollateral,\n uint256 actualRepayAmount\n ) external view override returns (uint256, uint256) {\n /* Read oracle prices for borrowed and collateral markets */\n uint256 priceBorrowedMantissa = oracle.getUnderlyingPrice(\n CToken(cTokenBorrowed)\n );\n uint256 priceCollateralMantissa = oracle.getUnderlyingPrice(\n CToken(cTokenCollateral)\n );\n if (priceBorrowedMantissa == 0 || priceCollateralMantissa == 0) {\n return (uint256(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 uint256 exchangeRateMantissa = CToken(cTokenCollateral)\n .exchangeRateStored(); // Note: reverts on error\n uint256 seizeTokens;\n Exp memory numerator;\n Exp memory denominator;\n Exp memory ratio;\n MathError mathErr;\n\n (mathErr, numerator) = mulExp(\n liquidationIncentiveMantissa,\n priceBorrowedMantissa\n );\n if (mathErr != MathError.NO_ERROR) {\n return (uint256(Error.MATH_ERROR), 0);\n }\n\n (mathErr, denominator) = mulExp(\n priceCollateralMantissa,\n exchangeRateMantissa\n );\n if (mathErr != MathError.NO_ERROR) {\n return (uint256(Error.MATH_ERROR), 0);\n }\n\n (mathErr, ratio) = divExp(numerator, denominator);\n if (mathErr != MathError.NO_ERROR) {\n return (uint256(Error.MATH_ERROR), 0);\n }\n\n (mathErr, seizeTokens) = mulScalarTruncate(ratio, actualRepayAmount);\n if (mathErr != MathError.NO_ERROR) {\n return (uint256(Error.MATH_ERROR), 0);\n }\n\n return (uint256(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 (uint256) {\n // Check caller is admin\n if (msg.sender != admin) {\n return\n fail(\n Error.UNAUTHORIZED,\n FailureInfo.SET_PRICE_ORACLE_OWNER_CHECK\n );\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 uint256(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(uint256 newCloseFactorMantissa)\n external\n returns (uint256)\n {\n // Check caller is admin\n if (msg.sender != admin) {\n return\n fail(\n Error.UNAUTHORIZED,\n FailureInfo.SET_CLOSE_FACTOR_OWNER_CHECK\n );\n }\n\n Exp memory newCloseFactorExp = Exp({mantissa: newCloseFactorMantissa});\n Exp memory lowLimit = Exp({mantissa: closeFactorMinMantissa});\n if (lessThanOrEqualExp(newCloseFactorExp, lowLimit)) {\n return\n fail(\n Error.INVALID_CLOSE_FACTOR,\n FailureInfo.SET_CLOSE_FACTOR_VALIDATION\n );\n }\n\n Exp memory highLimit = Exp({mantissa: closeFactorMaxMantissa});\n if (lessThanExp(highLimit, newCloseFactorExp)) {\n return\n fail(\n Error.INVALID_CLOSE_FACTOR,\n FailureInfo.SET_CLOSE_FACTOR_VALIDATION\n );\n }\n\n uint256 oldCloseFactorMantissa = closeFactorMantissa;\n closeFactorMantissa = newCloseFactorMantissa;\n emit NewCloseFactor(oldCloseFactorMantissa, closeFactorMantissa);\n\n return uint256(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(\n CToken cToken,\n uint256 newCollateralFactorMantissa\n ) external returns (uint256) {\n // Check caller is admin\n if (msg.sender != admin) {\n return\n fail(\n Error.UNAUTHORIZED,\n FailureInfo.SET_COLLATERAL_FACTOR_OWNER_CHECK\n );\n }\n\n // Verify market is listed\n Market storage market = markets[address(cToken)];\n if (!market.isListed) {\n return\n fail(\n Error.MARKET_NOT_LISTED,\n FailureInfo.SET_COLLATERAL_FACTOR_NO_EXISTS\n );\n }\n\n Exp memory newCollateralFactorExp = Exp({\n mantissa: newCollateralFactorMantissa\n });\n\n // Check collateral factor <= 0.9\n Exp memory highLimit = Exp({mantissa: collateralFactorMaxMantissa});\n if (lessThanExp(highLimit, newCollateralFactorExp)) {\n return\n fail(\n Error.INVALID_COLLATERAL_FACTOR,\n FailureInfo.SET_COLLATERAL_FACTOR_VALIDATION\n );\n }\n\n // If collateral factor != 0, fail if price == 0\n if (\n newCollateralFactorMantissa != 0 &&\n oracle.getUnderlyingPrice(cToken) == 0\n ) {\n return\n fail(\n Error.PRICE_ERROR,\n FailureInfo.SET_COLLATERAL_FACTOR_WITHOUT_PRICE\n );\n }\n\n // Set market's collateral factor to new collateral factor, remember old value\n uint256 oldCollateralFactorMantissa = market.collateralFactorMantissa;\n market.collateralFactorMantissa = newCollateralFactorMantissa;\n\n // Emit event with asset, old collateral factor, and new collateral factor\n emit NewCollateralFactor(\n cToken,\n oldCollateralFactorMantissa,\n newCollateralFactorMantissa\n );\n\n return uint256(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(uint256 newMaxAssets) external returns (uint256) {\n // Check caller is admin\n if (msg.sender != admin) {\n return\n fail(\n Error.UNAUTHORIZED,\n FailureInfo.SET_MAX_ASSETS_OWNER_CHECK\n );\n }\n\n uint256 oldMaxAssets = maxAssets;\n maxAssets = newMaxAssets;\n emit NewMaxAssets(oldMaxAssets, newMaxAssets);\n\n return uint256(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(uint256 newLiquidationIncentiveMantissa)\n external\n returns (uint256)\n {\n // Check caller is admin\n if (msg.sender != admin) {\n return\n fail(\n Error.UNAUTHORIZED,\n FailureInfo.SET_LIQUIDATION_INCENTIVE_OWNER_CHECK\n );\n }\n\n // Check de-scaled min <= newLiquidationIncentive <= max\n Exp memory newLiquidationIncentive = Exp({\n mantissa: newLiquidationIncentiveMantissa\n });\n Exp memory minLiquidationIncentive = Exp({\n mantissa: liquidationIncentiveMinMantissa\n });\n if (lessThanExp(newLiquidationIncentive, minLiquidationIncentive)) {\n return\n fail(\n Error.INVALID_LIQUIDATION_INCENTIVE,\n FailureInfo.SET_LIQUIDATION_INCENTIVE_VALIDATION\n );\n }\n\n Exp memory maxLiquidationIncentive = Exp({\n mantissa: liquidationIncentiveMaxMantissa\n });\n if (lessThanExp(maxLiquidationIncentive, newLiquidationIncentive)) {\n return\n fail(\n Error.INVALID_LIQUIDATION_INCENTIVE,\n FailureInfo.SET_LIQUIDATION_INCENTIVE_VALIDATION\n );\n }\n\n // Save current value for use in log\n uint256 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(\n oldLiquidationIncentiveMantissa,\n newLiquidationIncentiveMantissa\n );\n\n return uint256(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 (uint256) {\n if (msg.sender != admin) {\n return\n fail(\n Error.UNAUTHORIZED,\n FailureInfo.SUPPORT_MARKET_OWNER_CHECK\n );\n }\n\n if (markets[address(cToken)].isListed) {\n return\n fail(\n Error.MARKET_ALREADY_LISTED,\n FailureInfo.SUPPORT_MARKET_EXISTS\n );\n }\n\n cToken.isCToken(); // Sanity check to make sure its really a CToken\n\n Market storage market = markets[address(cToken)];\n market.isListed = true;\n market.isComped = false;\n market.collateralFactorMantissa = 0;\n\n _addMarketInternal(address(cToken));\n\n emit MarketListed(cToken);\n\n return uint256(Error.NO_ERROR);\n }\n\n function _addMarketInternal(address cToken) internal {\n for (uint256 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)\n public\n returns (uint256)\n {\n if (msg.sender != admin) {\n return\n fail(\n Error.UNAUTHORIZED,\n FailureInfo.SET_PAUSE_GUARDIAN_OWNER_CHECK\n );\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 uint256(Error.NO_ERROR);\n }\n\n function _setMintPaused(CToken cToken, bool state) public returns (bool) {\n require(\n markets[address(cToken)].isListed,\n \"cannot pause a market that is not listed\"\n );\n require(\n msg.sender == pauseGuardian || msg.sender == admin,\n \"only pause guardian and admin can pause\"\n );\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(\n markets[address(cToken)].isListed,\n \"cannot pause a market that is not listed\"\n );\n require(\n msg.sender == pauseGuardian || msg.sender == admin,\n \"only pause guardian and admin can pause\"\n );\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(\n msg.sender == pauseGuardian || msg.sender == admin,\n \"only pause guardian and admin can pause\"\n );\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(\n msg.sender == pauseGuardian || msg.sender == admin,\n \"only pause guardian and admin can pause\"\n );\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(\n msg.sender == unitroller.admin(),\n \"only unitroller admin can change brains\"\n );\n require(\n unitroller._acceptImplementation() == 0,\n \"change not authorized\"\n );\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(\n msg.sender == tx.origin,\n \"only externally owned accounts may refresh speeds\"\n );\n refreshCompSpeedsInternal();\n }\n\n function refreshCompSpeedsInternal() internal {\n CToken[] memory allMarkets_ = allMarkets;\n\n for (uint256 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 (uint256 i = 0; i < allMarkets_.length; i++) {\n CToken cToken = allMarkets_[i];\n if (markets[address(cToken)].isComped) {\n Exp memory assetPrice = Exp({\n mantissa: oracle.getUnderlyingPrice(cToken)\n });\n Exp memory utility = mul_(assetPrice, cToken.totalBorrows());\n utilities[i] = utility;\n totalUtility = add_(totalUtility, utility);\n }\n }\n\n for (uint256 i = 0; i < allMarkets_.length; i++) {\n CToken cToken = allMarkets[i];\n uint256 newSpeed = totalUtility.mantissa > 0\n ? mul_(compRate, div_(utilities[i], totalUtility))\n : 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 uint256 supplySpeed = compSpeeds[cToken];\n uint256 blockNumber = getBlockNumber();\n uint256 deltaBlocks = sub_(blockNumber, uint256(supplyState.block));\n if (deltaBlocks > 0 && supplySpeed > 0) {\n uint256 supplyTokens = CToken(cToken).totalSupply();\n uint256 compAccrued = mul_(deltaBlocks, supplySpeed);\n Double memory ratio = supplyTokens > 0\n ? fraction(compAccrued, supplyTokens)\n : Double({mantissa: 0});\n Double memory index = add_(\n Double({mantissa: supplyState.index}),\n ratio\n );\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(\n blockNumber,\n \"block number exceeds 32 bits\"\n );\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)\n internal\n {\n CompMarketState storage borrowState = compBorrowState[cToken];\n uint256 borrowSpeed = compSpeeds[cToken];\n uint256 blockNumber = getBlockNumber();\n uint256 deltaBlocks = sub_(blockNumber, uint256(borrowState.block));\n if (deltaBlocks > 0 && borrowSpeed > 0) {\n uint256 borrowAmount = div_(\n CToken(cToken).totalBorrows(),\n marketBorrowIndex\n );\n uint256 compAccrued = mul_(deltaBlocks, borrowSpeed);\n Double memory ratio = borrowAmount > 0\n ? fraction(compAccrued, borrowAmount)\n : Double({mantissa: 0});\n Double memory index = add_(\n Double({mantissa: borrowState.index}),\n ratio\n );\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(\n blockNumber,\n \"block number exceeds 32 bits\"\n );\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(\n address cToken,\n address supplier,\n bool distributeAll\n ) internal {\n CompMarketState storage supplyState = compSupplyState[cToken];\n Double memory supplyIndex = Double({mantissa: supplyState.index});\n Double memory supplierIndex = Double({\n mantissa: compSupplierIndex[cToken][supplier]\n });\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 uint256 supplierTokens = CToken(cToken).balanceOf(supplier);\n uint256 supplierDelta = mul_(supplierTokens, deltaIndex);\n uint256 supplierAccrued = add_(compAccrued[supplier], supplierDelta);\n compAccrued[supplier] = transferComp(\n supplier,\n supplierAccrued,\n distributeAll ? 0 : compClaimThreshold\n );\n emit DistributedSupplierComp(\n CToken(cToken),\n supplier,\n supplierDelta,\n supplyIndex.mantissa\n );\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(\n address cToken,\n address borrower,\n Exp memory marketBorrowIndex,\n bool distributeAll\n ) internal {\n CompMarketState storage borrowState = compBorrowState[cToken];\n Double memory borrowIndex = Double({mantissa: borrowState.index});\n Double memory borrowerIndex = Double({\n mantissa: compBorrowerIndex[cToken][borrower]\n });\n compBorrowerIndex[cToken][borrower] = borrowIndex.mantissa;\n\n if (borrowerIndex.mantissa > 0) {\n Double memory deltaIndex = sub_(borrowIndex, borrowerIndex);\n uint256 borrowerAmount = div_(\n CToken(cToken).borrowBalanceStored(borrower),\n marketBorrowIndex\n );\n uint256 borrowerDelta = mul_(borrowerAmount, deltaIndex);\n uint256 borrowerAccrued = add_(\n compAccrued[borrower],\n borrowerDelta\n );\n compAccrued[borrower] = transferComp(\n borrower,\n borrowerAccrued,\n distributeAll ? 0 : compClaimThreshold\n );\n emit DistributedBorrowerComp(\n CToken(cToken),\n borrower,\n borrowerDelta,\n borrowIndex.mantissa\n );\n }\n }\n\n /**\n * @notice Transfer TROP to the user, if they are above the threshold\n * @dev Note: If there is not enough TROP, we do not perform the transfer all.\n * @param user The address of the user to transfer TROP to\n * @param userAccrued The amount of TROP to (possibly) transfer\n * @return The amount of TROP which was NOT transferred to the user\n */\n function transferComp(\n address user,\n uint256 userAccrued,\n uint256 threshold\n ) internal returns (uint256) {\n if (userAccrued >= threshold && userAccrued > 0) {\n TROP trop = TROP(getCompAddress());\n uint256 tropRemaining = trop.balanceOf(address(this));\n if (userAccrued <= tropRemaining) {\n trop.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(\n address[] memory holders,\n CToken[] memory cTokens,\n bool borrowers,\n bool suppliers\n ) public {\n for (uint256 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 (uint256 j = 0; j < holders.length; j++) {\n distributeBorrowerComp(\n address(cToken),\n holders[j],\n borrowIndex,\n true\n );\n }\n }\n if (suppliers == true) {\n updateCompSupplyIndex(address(cToken));\n for (uint256 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(uint256 compRate_) public {\n require(adminOrInitializing(), \"only admin can change comp rate\");\n\n uint256 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 (uint256 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 (\n compSupplyState[cToken].index == 0 &&\n compSupplyState[cToken].block == 0\n ) {\n compSupplyState[cToken] = CompMarketState({\n index: compInitialIndex,\n block: safe32(getBlockNumber(), \"block number exceeds 32 bits\")\n });\n }\n\n if (\n compBorrowState[cToken].index == 0 &&\n compBorrowState[cToken].block == 0\n ) {\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 (uint256) {\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 pure returns (address) {\n return 0xc00e94Cb662C3520282E6f5717214004A7f26888;\n }\n}\n" - }, - "contracts/ComptrollerG3.sol": { - "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity 0.8.6;\n\nimport \"./CToken.sol\";\nimport \"./ErrorReporter.sol\";\nimport \"./Exponential.sol\";\nimport \"./PriceOracle.sol\";\nimport \"./ComptrollerInterface.sol\";\nimport \"./ComptrollerStorage.sol\";\nimport \"./Unitroller.sol\";\nimport \"./Governance/TROP.sol\";\n\n/**\n * @title tropykus Comptroller Contract\n * @author tropykus\n */\ncontract ComptrollerG3 is\n ComptrollerV3Storage,\n ComptrollerInterface,\n ComptrollerErrorReporter,\n Exponential\n{\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(\n uint256 oldCloseFactorMantissa,\n uint256 newCloseFactorMantissa\n );\n\n /// @notice Emitted when a collateral factor is changed by admin\n event NewCollateralFactor(\n CToken cToken,\n uint256 oldCollateralFactorMantissa,\n uint256 newCollateralFactorMantissa\n );\n\n /// @notice Emitted when liquidation incentive is changed by admin\n event NewLiquidationIncentive(\n uint256 oldLiquidationIncentiveMantissa,\n uint256 newLiquidationIncentiveMantissa\n );\n\n /// @notice Emitted when maxAssets is changed by admin\n event NewMaxAssets(uint256 oldMaxAssets, uint256 newMaxAssets);\n\n /// @notice Emitted when price oracle is changed\n event NewPriceOracle(\n PriceOracle oldPriceOracle,\n PriceOracle newPriceOracle\n );\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(uint256 oldCompRate, uint256 newCompRate);\n\n /// @notice Emitted when a new COMP speed is calculated for a market\n event CompSpeedUpdated(CToken indexed cToken, uint256 newSpeed);\n\n /// @notice Emitted when COMP is distributed to a supplier\n event DistributedSupplierComp(\n CToken indexed cToken,\n address indexed supplier,\n uint256 compDelta,\n uint256 compSupplyIndex\n );\n\n /// @notice Emitted when COMP is distributed to a borrower\n event DistributedBorrowerComp(\n CToken indexed cToken,\n address indexed borrower,\n uint256 compDelta,\n uint256 compBorrowIndex\n );\n\n /// @notice The threshold above which the flywheel transfers COMP, in wei\n uint256 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 uint256 internal constant closeFactorMinMantissa = 0.05e18; // 0.05\n\n // closeFactorMantissa must not exceed this value\n uint256 internal constant closeFactorMaxMantissa = 0.9e18; // 0.9\n\n // No collateralFactorMantissa may exceed this value\n uint256 internal constant collateralFactorMaxMantissa = 0.9e18; // 0.9\n\n // liquidationIncentiveMantissa must be no less than this value\n uint256 internal constant liquidationIncentiveMinMantissa = 1.0e18; // 1.0\n\n // liquidationIncentiveMantissa must be no greater than this value\n uint256 internal constant liquidationIncentiveMaxMantissa = 1.5e18; // 1.5\n\n constructor() {\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)\n external\n view\n returns (CToken[] memory)\n {\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)\n external\n view\n returns (bool)\n {\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)\n public\n override\n returns (uint256[] memory)\n {\n uint256 len = cTokens.length;\n\n uint256[] memory results = new uint256[](len);\n for (uint256 i = 0; i < len; i++) {\n CToken cToken = CToken(cTokens[i]);\n\n results[i] = uint256(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)\n internal\n returns (Error)\n {\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)\n external\n override\n returns (uint256)\n {\n CToken cToken = CToken(cTokenAddress);\n /* Get sender tokensHeld and amountOwed underlying from the cToken */\n (uint256 oErr, uint256 tokensHeld, uint256 amountOwed, ) = cToken\n .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\n fail(\n Error.NONZERO_BORROW_BALANCE,\n FailureInfo.EXIT_MARKET_BALANCE_OWED\n );\n }\n\n /* Fail if the sender is not permitted to redeem all of their tokens */\n uint256 allowed = redeemAllowedInternal(\n cTokenAddress,\n msg.sender,\n tokensHeld\n );\n if (allowed != 0) {\n return\n failOpaque(\n Error.REJECTION,\n FailureInfo.EXIT_MARKET_REJECTION,\n allowed\n );\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 uint256(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 accountAssets[msg.sender] = new CToken[](0);\n CToken[] storage newMarketList = accountAssets[msg.sender];\n uint256 len = userAssetList.length;\n uint256 assetIndex = len;\n for (uint256 i = 0; i < len; i++) {\n if (userAssetList[i] == cToken) {\n assetIndex = i;\n continue;\n }\n newMarketList.push(userAssetList[i]);\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 emit MarketExited(cToken, msg.sender);\n\n return uint256(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(\n address cToken,\n address minter,\n uint256 mintAmount\n ) external override returns (uint256) {\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 uint256(Error.MARKET_NOT_LISTED);\n }\n\n // Keep the flywheel moving\n updateCompSupplyIndex(cToken);\n distributeSupplierComp(cToken, minter, false);\n\n return uint256(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(\n address cToken,\n address minter,\n uint256 actualMintAmount,\n uint256 mintTokens\n ) external override {\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(\n address cToken,\n address redeemer,\n uint256 redeemTokens\n ) external override returns (uint256) {\n uint256 allowed = redeemAllowedInternal(cToken, redeemer, redeemTokens);\n if (allowed != uint256(Error.NO_ERROR)) {\n return allowed;\n }\n\n // Keep the flywheel moving\n updateCompSupplyIndex(cToken);\n distributeSupplierComp(cToken, redeemer, false);\n\n return uint256(Error.NO_ERROR);\n }\n\n function redeemAllowedInternal(\n address cToken,\n address redeemer,\n uint256 redeemTokens\n ) internal view returns (uint256) {\n if (!markets[cToken].isListed) {\n return uint256(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 uint256(Error.NO_ERROR);\n }\n\n /* Otherwise, perform a hypothetical liquidity check to guard against shortfall */\n (\n Error err,\n ,\n uint256 shortfall\n ) = getHypotheticalAccountLiquidityInternal(\n redeemer,\n CToken(cToken),\n redeemTokens,\n 0\n );\n if (err != Error.NO_ERROR) {\n return uint256(err);\n }\n if (shortfall > 0) {\n return uint256(Error.INSUFFICIENT_LIQUIDITY);\n }\n\n return uint256(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(\n address cToken,\n address redeemer,\n uint256 redeemAmount,\n uint256 redeemTokens\n ) external pure override {\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(\n address cToken,\n address borrower,\n uint256 borrowAmount\n ) external override returns (uint256) {\n // Pausing is a very serious situation - we revert to sound the alarms\n Error err;\n uint256 shortfall;\n require(!borrowGuardianPaused[cToken], \"borrow is paused\");\n\n if (!markets[cToken].isListed) {\n return uint256(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 err = addToMarketInternal(CToken(msg.sender), borrower);\n if (err != Error.NO_ERROR) {\n return uint256(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 uint256(Error.PRICE_ERROR);\n }\n\n (err, , shortfall) = getHypotheticalAccountLiquidityInternal(\n borrower,\n CToken(cToken),\n 0,\n borrowAmount\n );\n if (err != Error.NO_ERROR) {\n return uint256(err);\n }\n if (shortfall > 0) {\n return uint256(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 uint256(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(\n address cToken,\n address borrower,\n uint256 borrowAmount\n ) external override {\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 uint256 repayAmount\n ) external override returns (uint256) {\n // Shh - currently unused\n payer;\n borrower;\n repayAmount;\n\n if (!markets[cToken].isListed) {\n return uint256(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 uint256(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 uint256 actualRepayAmount,\n uint256 borrowerIndex\n ) external override {\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 uint256 repayAmount\n ) external view override returns (uint256) {\n // Shh - currently unused\n liquidator;\n\n if (\n !markets[cTokenBorrowed].isListed ||\n !markets[cTokenCollateral].isListed\n ) {\n return uint256(Error.MARKET_NOT_LISTED);\n }\n\n /* The borrower must have shortfall in order to be liquidatable */\n (Error err, , uint256 shortfall) = getAccountLiquidityInternal(\n borrower\n );\n if (err != Error.NO_ERROR) {\n return uint256(err);\n }\n if (shortfall == 0) {\n return uint256(Error.INSUFFICIENT_SHORTFALL);\n }\n\n /* The liquidator may not repay more than what is allowed by the closeFactor */\n uint256 borrowBalance = CToken(cTokenBorrowed).borrowBalanceStored(\n borrower\n );\n (MathError mathErr, uint256 maxClose) = mulScalarTruncate(\n Exp({mantissa: closeFactorMantissa}),\n borrowBalance\n );\n if (mathErr != MathError.NO_ERROR) {\n return uint256(Error.MATH_ERROR);\n }\n if (repayAmount > maxClose) {\n return uint256(Error.TOO_MUCH_REPAY);\n }\n\n return uint256(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 uint256 actualRepayAmount,\n uint256 seizeTokens\n ) external override {\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 uint256 seizeTokens\n ) external override returns (uint256) {\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 (\n !markets[cTokenCollateral].isListed ||\n !markets[cTokenBorrowed].isListed\n ) {\n return uint256(Error.MARKET_NOT_LISTED);\n }\n\n if (\n CToken(cTokenCollateral).comptroller() !=\n CToken(cTokenBorrowed).comptroller()\n ) {\n return uint256(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 uint256(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 uint256 seizeTokens\n ) external override {\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(\n address cToken,\n address src,\n address dst,\n uint256 transferTokens\n ) external override returns (uint256) {\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 uint256 allowed = redeemAllowedInternal(cToken, src, transferTokens);\n if (allowed != uint256(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 uint256(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(\n address cToken,\n address src,\n address dst,\n uint256 transferTokens\n ) external override {\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 uint256 sumCollateral;\n uint256 sumBorrowPlusEffects;\n uint256 cTokenBalance;\n uint256 borrowBalance;\n uint256 exchangeRateMantissa;\n uint256 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)\n public\n view\n returns (\n uint256,\n uint256,\n uint256\n )\n {\n (\n Error err,\n uint256 liquidity,\n uint256 shortfall\n ) = getHypotheticalAccountLiquidityInternal(\n account,\n CToken(address(0)),\n 0,\n 0\n );\n\n return (uint256(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)\n internal\n view\n returns (\n Error,\n uint256,\n uint256\n )\n {\n return\n getHypotheticalAccountLiquidityInternal(\n account,\n CToken(address(0)),\n 0,\n 0\n );\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 uint256 redeemTokens,\n uint256 borrowAmount\n )\n public\n view\n returns (\n uint256,\n uint256,\n uint256\n )\n {\n (\n Error err,\n uint256 liquidity,\n uint256 shortfall\n ) = getHypotheticalAccountLiquidityInternal(\n account,\n CToken(cTokenModify),\n redeemTokens,\n borrowAmount\n );\n return (uint256(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 uint256 redeemTokens,\n uint256 borrowAmount\n )\n internal\n view\n returns (\n Error,\n uint256,\n uint256\n )\n {\n AccountLiquidityLocalVars memory vars; // Holds all our calculation results\n uint256 oErr;\n MathError mErr;\n\n // For each asset the account is in\n CToken[] memory assets = accountAssets[account];\n for (uint256 i = 0; i < assets.length; i++) {\n CToken asset = assets[i];\n\n // Read the balances and exchange rate from the cToken\n (\n oErr,\n vars.cTokenBalance,\n vars.borrowBalance,\n vars.exchangeRateMantissa\n ) = asset.getAccountSnapshot(account);\n if (oErr != 0) {\n // 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({\n mantissa: markets[address(asset)].collateralFactorMantissa\n });\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(\n vars.collateralFactor,\n vars.exchangeRate,\n vars.oraclePrice\n );\n if (mErr != MathError.NO_ERROR) {\n return (Error.MATH_ERROR, 0, 0);\n }\n\n // sumCollateral += tokensToDenom * cTokenBalance\n (mErr, vars.sumCollateral) = mulScalarTruncateAddUInt(\n vars.tokensToDenom,\n vars.cTokenBalance,\n vars.sumCollateral\n );\n if (mErr != MathError.NO_ERROR) {\n return (Error.MATH_ERROR, 0, 0);\n }\n\n // sumBorrowPlusEffects += oraclePrice * borrowBalance\n (mErr, vars.sumBorrowPlusEffects) = mulScalarTruncateAddUInt(\n vars.oraclePrice,\n vars.borrowBalance,\n vars.sumBorrowPlusEffects\n );\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(\n vars.tokensToDenom,\n redeemTokens,\n vars.sumBorrowPlusEffects\n );\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(\n vars.oraclePrice,\n borrowAmount,\n vars.sumBorrowPlusEffects\n );\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 (\n Error.NO_ERROR,\n vars.sumCollateral - vars.sumBorrowPlusEffects,\n 0\n );\n } else {\n return (\n Error.NO_ERROR,\n 0,\n vars.sumBorrowPlusEffects - vars.sumCollateral\n );\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(\n address cTokenBorrowed,\n address cTokenCollateral,\n uint256 actualRepayAmount\n ) external view override returns (uint256, uint256) {\n /* Read oracle prices for borrowed and collateral markets */\n uint256 priceBorrowedMantissa = oracle.getUnderlyingPrice(\n CToken(cTokenBorrowed)\n );\n uint256 priceCollateralMantissa = oracle.getUnderlyingPrice(\n CToken(cTokenCollateral)\n );\n if (priceBorrowedMantissa == 0 || priceCollateralMantissa == 0) {\n return (uint256(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 uint256 exchangeRateMantissa = CToken(cTokenCollateral)\n .exchangeRateStored(); // Note: reverts on error\n uint256 seizeTokens;\n Exp memory numerator;\n Exp memory denominator;\n Exp memory ratio;\n MathError mathErr;\n\n (mathErr, numerator) = mulExp(\n liquidationIncentiveMantissa,\n priceBorrowedMantissa\n );\n if (mathErr != MathError.NO_ERROR) {\n return (uint256(Error.MATH_ERROR), 0);\n }\n\n (mathErr, denominator) = mulExp(\n priceCollateralMantissa,\n exchangeRateMantissa\n );\n if (mathErr != MathError.NO_ERROR) {\n return (uint256(Error.MATH_ERROR), 0);\n }\n\n (mathErr, ratio) = divExp(numerator, denominator);\n if (mathErr != MathError.NO_ERROR) {\n return (uint256(Error.MATH_ERROR), 0);\n }\n\n (mathErr, seizeTokens) = mulScalarTruncate(ratio, actualRepayAmount);\n if (mathErr != MathError.NO_ERROR) {\n return (uint256(Error.MATH_ERROR), 0);\n }\n\n return (uint256(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 (uint256) {\n // Check caller is admin\n if (msg.sender != admin) {\n return\n fail(\n Error.UNAUTHORIZED,\n FailureInfo.SET_PRICE_ORACLE_OWNER_CHECK\n );\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 uint256(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(uint256 newCloseFactorMantissa)\n external\n returns (uint256)\n {\n // Check caller is admin\n if (msg.sender != admin) {\n return\n fail(\n Error.UNAUTHORIZED,\n FailureInfo.SET_CLOSE_FACTOR_OWNER_CHECK\n );\n }\n\n Exp memory newCloseFactorExp = Exp({mantissa: newCloseFactorMantissa});\n Exp memory lowLimit = Exp({mantissa: closeFactorMinMantissa});\n if (lessThanOrEqualExp(newCloseFactorExp, lowLimit)) {\n return\n fail(\n Error.INVALID_CLOSE_FACTOR,\n FailureInfo.SET_CLOSE_FACTOR_VALIDATION\n );\n }\n\n Exp memory highLimit = Exp({mantissa: closeFactorMaxMantissa});\n if (lessThanExp(highLimit, newCloseFactorExp)) {\n return\n fail(\n Error.INVALID_CLOSE_FACTOR,\n FailureInfo.SET_CLOSE_FACTOR_VALIDATION\n );\n }\n\n uint256 oldCloseFactorMantissa = closeFactorMantissa;\n closeFactorMantissa = newCloseFactorMantissa;\n emit NewCloseFactor(oldCloseFactorMantissa, closeFactorMantissa);\n\n return uint256(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(\n CToken cToken,\n uint256 newCollateralFactorMantissa\n ) external returns (uint256) {\n // Check caller is admin\n if (msg.sender != admin) {\n return\n fail(\n Error.UNAUTHORIZED,\n FailureInfo.SET_COLLATERAL_FACTOR_OWNER_CHECK\n );\n }\n\n // Verify market is listed\n Market storage market = markets[address(cToken)];\n if (!market.isListed) {\n return\n fail(\n Error.MARKET_NOT_LISTED,\n FailureInfo.SET_COLLATERAL_FACTOR_NO_EXISTS\n );\n }\n\n Exp memory newCollateralFactorExp = Exp({\n mantissa: newCollateralFactorMantissa\n });\n\n // Check collateral factor <= 0.9\n Exp memory highLimit = Exp({mantissa: collateralFactorMaxMantissa});\n if (lessThanExp(highLimit, newCollateralFactorExp)) {\n return\n fail(\n Error.INVALID_COLLATERAL_FACTOR,\n FailureInfo.SET_COLLATERAL_FACTOR_VALIDATION\n );\n }\n\n // If collateral factor != 0, fail if price == 0\n if (\n newCollateralFactorMantissa != 0 &&\n oracle.getUnderlyingPrice(cToken) == 0\n ) {\n return\n fail(\n Error.PRICE_ERROR,\n FailureInfo.SET_COLLATERAL_FACTOR_WITHOUT_PRICE\n );\n }\n\n // Set market's collateral factor to new collateral factor, remember old value\n uint256 oldCollateralFactorMantissa = market.collateralFactorMantissa;\n market.collateralFactorMantissa = newCollateralFactorMantissa;\n\n // Emit event with asset, old collateral factor, and new collateral factor\n emit NewCollateralFactor(\n cToken,\n oldCollateralFactorMantissa,\n newCollateralFactorMantissa\n );\n\n return uint256(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(uint256 newMaxAssets) external returns (uint256) {\n // Check caller is admin\n if (msg.sender != admin) {\n return\n fail(\n Error.UNAUTHORIZED,\n FailureInfo.SET_MAX_ASSETS_OWNER_CHECK\n );\n }\n\n uint256 oldMaxAssets = maxAssets;\n maxAssets = newMaxAssets;\n emit NewMaxAssets(oldMaxAssets, newMaxAssets);\n\n return uint256(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(uint256 newLiquidationIncentiveMantissa)\n external\n returns (uint256)\n {\n // Check caller is admin\n if (msg.sender != admin) {\n return\n fail(\n Error.UNAUTHORIZED,\n FailureInfo.SET_LIQUIDATION_INCENTIVE_OWNER_CHECK\n );\n }\n\n // Check de-scaled min <= newLiquidationIncentive <= max\n Exp memory newLiquidationIncentive = Exp({\n mantissa: newLiquidationIncentiveMantissa\n });\n Exp memory minLiquidationIncentive = Exp({\n mantissa: liquidationIncentiveMinMantissa\n });\n if (lessThanExp(newLiquidationIncentive, minLiquidationIncentive)) {\n return\n fail(\n Error.INVALID_LIQUIDATION_INCENTIVE,\n FailureInfo.SET_LIQUIDATION_INCENTIVE_VALIDATION\n );\n }\n\n Exp memory maxLiquidationIncentive = Exp({\n mantissa: liquidationIncentiveMaxMantissa\n });\n if (lessThanExp(maxLiquidationIncentive, newLiquidationIncentive)) {\n return\n fail(\n Error.INVALID_LIQUIDATION_INCENTIVE,\n FailureInfo.SET_LIQUIDATION_INCENTIVE_VALIDATION\n );\n }\n\n // Save current value for use in log\n uint256 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(\n oldLiquidationIncentiveMantissa,\n newLiquidationIncentiveMantissa\n );\n\n return uint256(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 (uint256) {\n if (msg.sender != admin) {\n return\n fail(\n Error.UNAUTHORIZED,\n FailureInfo.SUPPORT_MARKET_OWNER_CHECK\n );\n }\n\n if (markets[address(cToken)].isListed) {\n return\n fail(\n Error.MARKET_ALREADY_LISTED,\n FailureInfo.SUPPORT_MARKET_EXISTS\n );\n }\n\n cToken.isCToken(); // Sanity check to make sure its really a CToken\n\n Market storage market = markets[address(cToken)];\n market.isListed = true;\n market.isComped = false;\n market.collateralFactorMantissa = 0;\n\n _addMarketInternal(address(cToken));\n\n emit MarketListed(cToken);\n\n return uint256(Error.NO_ERROR);\n }\n\n function _addMarketInternal(address cToken) internal {\n for (uint256 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)\n public\n returns (uint256)\n {\n if (msg.sender != admin) {\n return\n fail(\n Error.UNAUTHORIZED,\n FailureInfo.SET_PAUSE_GUARDIAN_OWNER_CHECK\n );\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 uint256(Error.NO_ERROR);\n }\n\n function _setMintPaused(CToken cToken, bool state) public returns (bool) {\n require(\n markets[address(cToken)].isListed,\n \"cannot pause a market that is not listed\"\n );\n require(\n msg.sender == pauseGuardian || msg.sender == admin,\n \"only pause guardian and admin can pause\"\n );\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(\n markets[address(cToken)].isListed,\n \"cannot pause a market that is not listed\"\n );\n require(\n msg.sender == pauseGuardian || msg.sender == admin,\n \"only pause guardian and admin can pause\"\n );\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(\n msg.sender == pauseGuardian || msg.sender == admin,\n \"only pause guardian and admin can pause\"\n );\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(\n msg.sender == pauseGuardian || msg.sender == admin,\n \"only pause guardian and admin can pause\"\n );\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(\n Unitroller unitroller,\n uint256 compRate_,\n address[] memory compMarketsToAdd,\n address[] memory otherMarketsToAdd\n ) public {\n require(\n msg.sender == unitroller.admin(),\n \"only unitroller admin can change brains\"\n );\n require(\n unitroller._acceptImplementation() == 0,\n \"change not authorized\"\n );\n\n ComptrollerG3(address(unitroller))._becomeG3(\n compRate_,\n compMarketsToAdd,\n otherMarketsToAdd\n );\n }\n\n function _becomeG3(\n uint256 compRate_,\n address[] memory compMarketsToAdd,\n address[] memory otherMarketsToAdd\n ) public {\n require(\n msg.sender == comptrollerImplementation,\n \"only brains can become itself\"\n );\n\n for (uint256 i = 0; i < compMarketsToAdd.length; i++) {\n _addMarketInternal(address(compMarketsToAdd[i]));\n }\n\n for (uint256 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 /*** TROP 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 (uint256 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 (uint256 i = 0; i < allMarkets_.length; i++) {\n CToken cToken = allMarkets_[i];\n if (markets[address(cToken)].isComped) {\n Exp memory assetPrice = Exp({\n mantissa: oracle.getUnderlyingPrice(cToken)\n });\n Exp memory interestPerBlock = mul_(\n Exp({mantissa: cToken.borrowRatePerBlock()}),\n cToken.totalBorrows()\n );\n Exp memory utility = mul_(interestPerBlock, assetPrice);\n utilities[i] = utility;\n totalUtility = add_(totalUtility, utility);\n }\n }\n\n for (uint256 i = 0; i < allMarkets_.length; i++) {\n CToken cToken = allMarkets[i];\n uint256 newSpeed = totalUtility.mantissa > 0\n ? mul_(compRate, div_(utilities[i], totalUtility))\n : 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 uint256 supplySpeed = compSpeeds[cToken];\n uint256 blockNumber = getBlockNumber();\n uint256 deltaBlocks = sub_(blockNumber, uint256(supplyState.block));\n if (deltaBlocks > 0 && supplySpeed > 0) {\n uint256 supplyTokens = CToken(cToken).totalSupply();\n uint256 compAccrued = mul_(deltaBlocks, supplySpeed);\n Double memory ratio = supplyTokens > 0\n ? fraction(compAccrued, supplyTokens)\n : Double({mantissa: 0});\n Double memory index = add_(\n Double({mantissa: supplyState.index}),\n ratio\n );\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(\n blockNumber,\n \"block number exceeds 32 bits\"\n );\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)\n internal\n {\n CompMarketState storage borrowState = compBorrowState[cToken];\n uint256 borrowSpeed = compSpeeds[cToken];\n uint256 blockNumber = getBlockNumber();\n uint256 deltaBlocks = sub_(blockNumber, uint256(borrowState.block));\n if (deltaBlocks > 0 && borrowSpeed > 0) {\n uint256 borrowAmount = div_(\n CToken(cToken).totalBorrows(),\n marketBorrowIndex\n );\n uint256 compAccrued = mul_(deltaBlocks, borrowSpeed);\n Double memory ratio = borrowAmount > 0\n ? fraction(compAccrued, borrowAmount)\n : Double({mantissa: 0});\n Double memory index = add_(\n Double({mantissa: borrowState.index}),\n ratio\n );\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(\n blockNumber,\n \"block number exceeds 32 bits\"\n );\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(\n address cToken,\n address supplier,\n bool distributeAll\n ) internal {\n CompMarketState storage supplyState = compSupplyState[cToken];\n Double memory supplyIndex = Double({mantissa: supplyState.index});\n Double memory supplierIndex = Double({\n mantissa: compSupplierIndex[cToken][supplier]\n });\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 uint256 supplierTokens = CToken(cToken).balanceOf(supplier);\n uint256 supplierDelta = mul_(supplierTokens, deltaIndex);\n uint256 supplierAccrued = add_(compAccrued[supplier], supplierDelta);\n compAccrued[supplier] = transferComp(\n supplier,\n supplierAccrued,\n distributeAll ? 0 : compClaimThreshold\n );\n emit DistributedSupplierComp(\n CToken(cToken),\n supplier,\n supplierDelta,\n supplyIndex.mantissa\n );\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(\n address cToken,\n address borrower,\n Exp memory marketBorrowIndex,\n bool distributeAll\n ) internal {\n CompMarketState storage borrowState = compBorrowState[cToken];\n Double memory borrowIndex = Double({mantissa: borrowState.index});\n Double memory borrowerIndex = Double({\n mantissa: compBorrowerIndex[cToken][borrower]\n });\n compBorrowerIndex[cToken][borrower] = borrowIndex.mantissa;\n\n if (borrowerIndex.mantissa > 0) {\n Double memory deltaIndex = sub_(borrowIndex, borrowerIndex);\n uint256 borrowerAmount = div_(\n CToken(cToken).borrowBalanceStored(borrower),\n marketBorrowIndex\n );\n uint256 borrowerDelta = mul_(borrowerAmount, deltaIndex);\n uint256 borrowerAccrued = add_(\n compAccrued[borrower],\n borrowerDelta\n );\n compAccrued[borrower] = transferComp(\n borrower,\n borrowerAccrued,\n distributeAll ? 0 : compClaimThreshold\n );\n emit DistributedBorrowerComp(\n CToken(cToken),\n borrower,\n borrowerDelta,\n borrowIndex.mantissa\n );\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(\n address user,\n uint256 userAccrued,\n uint256 threshold\n ) internal returns (uint256) {\n if (userAccrued >= threshold && userAccrued > 0) {\n TROP comp = TROP(getCompAddress());\n uint256 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(\n address[] memory holders,\n CToken[] memory cTokens,\n bool borrowers,\n bool suppliers\n ) public {\n for (uint256 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 (uint256 j = 0; j < holders.length; j++) {\n distributeBorrowerComp(\n address(cToken),\n holders[j],\n borrowIndex,\n true\n );\n }\n }\n if (suppliers == true) {\n updateCompSupplyIndex(address(cToken));\n for (uint256 j = 0; j < holders.length; j++) {\n distributeSupplierComp(address(cToken), holders[j], true);\n }\n }\n }\n }\n\n /*** TROP 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(uint256 compRate_) public {\n require(adminOrInitializing(), \"only admin can change comp rate\");\n\n uint256 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 (uint256 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 (\n compSupplyState[cToken].index == 0 &&\n compSupplyState[cToken].block == 0\n ) {\n compSupplyState[cToken] = CompMarketState({\n index: compInitialIndex,\n block: safe32(getBlockNumber(), \"block number exceeds 32 bits\")\n });\n }\n\n if (\n compBorrowState[cToken].index == 0 &&\n compBorrowState[cToken].block == 0\n ) {\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 virtual returns (uint256) {\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 virtual returns (address) {\n return 0xc00e94Cb662C3520282E6f5717214004A7f26888;\n }\n}\n" - }, - "contracts/PriceOracleProxy.sol": { - "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity 0.8.6;\n\nimport \"./PriceOracle.sol\";\nimport \"./PriceOracleAdapter.sol\";\n\ncontract PriceOracleProxy is PriceOracle {\n /// @notice Address of the guardian\n address public guardian;\n /// @notice Address of the pending guardian\n address public pendingGuardian;\n /// @notice Mapping of the cTokenAddress => adapterAddress\n mapping(address => address) public tokenAdapter;\n ///@notice Emitted when pendingGuardian is changed\n event NewPendingGuardian(\n address oldPendingGuardian,\n address newPendingGuardian\n );\n ///@notice Emitted when pendingGuardian is accepted, which means gaurdian is updated\n event NewGuardian(address oldGuardian, address newGuardian);\n /// @notice Struct of the cTokensDetail\n struct CtokenDetail {\n address cToken;\n string cTokenName;\n }\n\n /// @notice Array of cTokensDetail\n CtokenDetail[] public cTokensArray;\n\n /**\n * @notice Get the length of cTokensArray\n * @return The length of cTokensArray\n */\n function cTokenArrayCount() public view returns (uint256) {\n return cTokensArray.length;\n }\n\n /// @param guardian_ The address of the guardian, which may set the\n constructor(address guardian_) {\n guardian = guardian_;\n }\n\n /**\n * @notice Get the underlying price of a listed cToken asset\n * @param cToken The cToken to get the underlying price of\n * @return The underlying asset price mantissa (scaled by 1e18)\n */\n function getUnderlyingPrice(CToken cToken)\n public\n view\n virtual\n override\n returns (uint256)\n {\n address oracleAdapter = tokenAdapter[address(cToken)];\n //validate mapping\n if (oracleAdapter == address(0)) {\n return 0;\n }\n return PriceOracleAdapter(oracleAdapter).assetPrices(address(cToken));\n }\n\n /**\n * @notice Set the underlying price of a listed cToken asset\n * @param addressToken Address of the cToken\n * @param addressAdapter Address of the OracleAdapter\n */\n function setAdapterToToken(address addressToken, address addressAdapter)\n public\n {\n //validate only guardian can set\n require(\n msg.sender == guardian,\n \"PriceOracleProxy: only guardian may set the address\"\n );\n require(\n addressToken != address(0),\n \"PriceOracleProxy: address token can not be 0\"\n );\n require(\n addressAdapter != address(0),\n \"PriceOracleProxy: address adapter can not be 0\"\n );\n //validate and set new cToken in CtokenDetail\n if (tokenAdapter[addressToken] == address(0)) {\n CtokenDetail memory _cTokenD = CtokenDetail({\n cToken: addressToken,\n cTokenName: CToken(addressToken).symbol()\n });\n\n cTokensArray.push(_cTokenD);\n }\n //set token => adapter\n tokenAdapter[addressToken] = addressAdapter;\n }\n\n /**\n * @notice Begins transfer of gaurdian rights. The newPendingGaurdian must call `_acceptAdmin` to finalize the transfer.\n * @param newPendingGuardian New pending gaurdian.\n */\n function _setPendingAdmin(address newPendingGuardian) public {\n // Check caller = gaurdian\n require(\n msg.sender == guardian,\n \"PriceOracleProxy: only guardian may set the address\"\n );\n require(\n newPendingGuardian != address(0),\n \"PriceOracleProxy: address admin can not be 0\"\n );\n // Save current value, if any, for inclusion in log\n address oldPendingGuardian = guardian;\n // Store pendingGaurdian with value newPendingGaurdian\n pendingGuardian = newPendingGuardian;\n // Emit NewPendingGaurdian(oldPendingGaurdian, newPendingGaurdian)\n emit NewPendingGuardian(oldPendingGuardian, newPendingGuardian);\n }\n\n /// @notice Accepts transfer of gaurdian rights. msg.sender must be pendingGaurdian\n function _acceptAdmin() public {\n // Check caller is pendingGaurdian and pendingGaurdian ≠ address(0)\n require(\n msg.sender == pendingGuardian,\n \"PriceOracleProxy: only guardian may set the address\"\n );\n require(\n msg.sender != address(0),\n \"PriceOracleProxy: sender can not be 0\"\n );\n\n // Save current values for inclusion in log\n address oldGuardian = guardian;\n address oldPendingGaurdian = pendingGuardian;\n\n // Store gaurdian with value pendingGaurdian\n guardian = pendingGuardian;\n\n // Clear the pending value\n pendingGuardian = address(0);\n\n emit NewGuardian(oldGuardian, guardian);\n emit NewPendingGuardian(oldPendingGaurdian, pendingGuardian);\n }\n}\n" - }, - "contracts/PriceOracleAdapter.sol": { - "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity 0.8.6;\n\nabstract contract PriceOracleAdapter {\n /// @notice Event adapter interface updated\n event PriceOracleAdapterUpdated(address oldAddress, address newAddress);\n\n /**\n * @notice Get the price\n * @return The underlying asset price mantissa (scaled by 1e18).\n * Zero means the price is unavailable.\n */\n function assetPrices(address cTokenAddress)\n external\n view\n virtual\n returns (uint256);\n}\n" - }, - "contracts/PriceOracleAdapterMoc.sol": { - "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity 0.8.6;\n\nimport \"./PriceOracleAdapter.sol\";\n\ninterface PriceProviderMoC {\n function peek() external view returns (bytes32, bool);\n}\n\ncontract PriceOracleAdapterMoc is PriceOracleAdapter {\n /// @notice Address of the guardian\n address public guardian;\n /// @notice The MoC price oracle, which will continue to serve prices\n PriceProviderMoC public priceProviderMoC;\n\n /// @notice Guardian updated\n event NewGuardian(address oldGuardian, address newGuardian);\n\n /**\n * @notice Construct a PriceOracleAdapter for a MoC oracle\n * @param guardian_ address of guardian that is allowed to manage this contract\n * @param priceProvider address of asset's MoC price provider\n */\n constructor(address guardian_, address priceProvider) {\n require(\n guardian_ != address(0),\n \"PriceOracleAdapterMoc: guardian could not be 0\"\n );\n require(\n priceProvider != address(0),\n \"PriceOracleAdapterMoc: priceProvider could not be 0\"\n );\n guardian = guardian_;\n priceProviderMoC = PriceProviderMoC(priceProvider);\n }\n\n /**\n * @notice Get the price from MoC and divide it by the rBTC price\n * @return The price\n */\n function assetPrices(address) public view override returns (uint256) {\n (bytes32 price, bool has) = priceProviderMoC.peek();\n require(has, \"PriceOracleAdapterMoc: Oracle have no Price\");\n return uint256(price);\n }\n\n /**\n * @notice Set the address of price provider\n * @param priceProviderAddress address of price provider\n */\n function setPriceProvider(address priceProviderAddress) public {\n require(\n msg.sender == guardian,\n \"PriceOracleAdapterMoc: only guardian may set the address\"\n );\n require(\n priceProviderAddress != address(0),\n \"PriceOracleAdapterMoc: address could not be 0\"\n );\n //set old address\n address oldPriceProviderAddress = address(priceProviderMoC);\n //update interface address\n priceProviderMoC = PriceProviderMoC(priceProviderAddress);\n //emit event\n emit PriceOracleAdapterUpdated(\n oldPriceProviderAddress,\n priceProviderAddress\n );\n }\n\n /**\n * @notice Set the address of the guardian\n * @param newGuardian address of the guardian\n */\n function setGuardian(address newGuardian) public {\n require(msg.sender == guardian, \"PriceOracleAdapterMoc: only guardian\");\n require(\n guardian != address(0),\n \"PriceOracleAdapterMoc: guardin address can not be 0\"\n );\n //set old address\n address oldGuardian = guardian;\n //update\n guardian = newGuardian;\n //emit event\n emit NewGuardian(oldGuardian, newGuardian);\n }\n}\n" - }, - "contracts/mocks/PriceOracleAdapterCompound.sol": { - "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity 0.8.6;\n\nimport \"../PriceOracleAdapter.sol\";\nimport \"../CErc20.sol\";\n\ninterface V1PriceOracleInterface {\n function assetPrices(address asset) external view returns (uint256);\n}\n\ncontract PriceOracleAdapterCompound is PriceOracleAdapter {\n /// @notice Address of the guardian\n address public guardian;\n /// @notice Event oracle key updateed\n event PriceOracleKeyUpdated(\n address oldAddress,\n address newAddress,\n address cTokenAddress\n );\n /// @notice The price oracle, which will continue to serve prices of compound\n V1PriceOracleInterface public priceProviderInterface;\n\n // mapping(addressCtoken => addressKeyOracle);\n mapping(address => address) public oracleKeyAddress;\n\n /// @notice Frozen SAI price (or 0 if not set yet)\n uint256 public saiPrice;\n\n constructor(address guardian_) {\n guardian = guardian_;\n }\n\n /**\n * @notice Get the price\n * @param cTokenAddress address of cToken\n * @return The price\n */\n function assetPrices(address cTokenAddress)\n public\n view\n override\n returns (uint256)\n {\n //get keyAddress or undlerlyingAddress\n address asset = (oracleKeyAddress[cTokenAddress] != address(0))\n ? address(oracleKeyAddress[cTokenAddress])\n : address(CErc20(cTokenAddress).underlying());\n return priceProviderInterface.assetPrices(asset);\n }\n\n /**\n * @notice Set the address of price provider\n * @param priceProviderAddress address of price provider\n */\n function setPriceProvider(address priceProviderAddress) public {\n require(\n msg.sender == guardian,\n \"PriceOracleAdapterCompound: only guardian may set the address\"\n );\n require(\n priceProviderAddress != address(0),\n \"PriceOracleAdapterCompound: address could not be 0\"\n );\n //set old address\n address oldBtcPriceProviderAddress = address(priceProviderInterface);\n //update interface address\n priceProviderInterface = V1PriceOracleInterface(priceProviderAddress);\n //emit event\n emit PriceOracleAdapterUpdated(\n oldBtcPriceProviderAddress,\n address(priceProviderInterface)\n );\n }\n\n /**\n * @notice Set the key oracle address of cToken address\n * @param cTokenAddress address of key ctoken\n * @param keyOracle address of key oracle\n */\n function setKeyOracle(address cTokenAddress, address keyOracle) public {\n require(\n msg.sender == guardian,\n \"PriceOracleAdapterCompound: only guardian may set the address\"\n );\n require(\n cTokenAddress != address(0),\n \"PriceOracleAdapterCompound: cTokenAddress could not be 0\"\n );\n require(\n keyOracle != address(0),\n \"PriceOracleAdapterCompound: keyOracle could not be 0\"\n );\n //set old address\n address oldBtcPriceProviderAddress = address(\n oracleKeyAddress[cTokenAddress]\n );\n //update key address\n oracleKeyAddress[cTokenAddress] = keyOracle;\n //emit event\n emit PriceOracleKeyUpdated(\n oldBtcPriceProviderAddress,\n address(oracleKeyAddress[cTokenAddress]),\n cTokenAddress\n );\n }\n\n /**\n * @notice Set the price of SAI, permanently\n * @param price The price for SAI\n */\n function setSaiPrice(uint256 price) public {\n require(msg.sender == guardian, \"only guardian may set the SAI price\");\n require(saiPrice == 0, \"SAI price may only be set once\");\n require(price < 0.1e18, \"SAI price must be < 0.1 ETH\");\n saiPrice = price;\n }\n}\n" - }, - "contracts/mocks/SimplePriceOracle.sol": { - "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity 0.8.6;\n\nimport \"../PriceOracle.sol\";\nimport \"../CErc20.sol\";\n\n/**\n * @title Simplified Oracle for testing purposes.\n * @author tropykus\n * @notice This contract is meant for testing only.\n */\ncontract SimplePriceOracle is PriceOracle {\n mapping(address => uint256) prices;\n event PricePosted(\n address asset,\n uint256 previousPriceMantissa,\n uint256 requestedPriceMantissa,\n uint256 newPriceMantissa\n );\n\n function getUnderlyingPrice(CToken cToken)\n public\n view\n override\n returns (uint256)\n {\n if (compareStrings(cToken.symbol(), \"cRBTC\")) {\n return prices[(address(cToken))];\n } else {\n return prices[address(CErc20(address(cToken)).underlying())];\n }\n }\n\n function setUnderlyingPrice(CToken cToken, uint256 underlyingPriceMantissa)\n public\n {\n address asset = address(CErc20(address(cToken)).underlying());\n emit PricePosted(\n asset,\n prices[asset],\n underlyingPriceMantissa,\n underlyingPriceMantissa\n );\n prices[asset] = underlyingPriceMantissa;\n }\n\n function setDirectPrice(address asset, uint256 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 (uint256) {\n return prices[asset];\n }\n\n function compareStrings(string memory a, string memory b)\n internal\n pure\n returns (bool)\n {\n return (keccak256(abi.encodePacked((a))) ==\n keccak256(abi.encodePacked((b))));\n }\n}\n" - }, - "contracts/mocks/MockPriceProviderMoC.sol": { - "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity 0.8.6;\n\nimport \"../CErc20.sol\";\n\n/**\n * @title A mock price provider of Money on Chain (MoC)\n * @notice You can use this contract for only simulation\n */\ncontract MockPriceProviderMoC {\n /// @notice rbtcPrice of the interface provicer MoC\n bytes32 rbtcPrice;\n /// @notice has of the interface provicer MoC\n bool has;\n /// @notice Address of the guardian\n address public guardian;\n /// @notice Event rbtcPrice updated\n event MockPriceProviderMoCUpdated(uint256 oldPrice, uint256 newPrice);\n\n constructor(address guardian_, uint256 price) {\n require(\n guardian_ != address(0),\n \"MockPriceProviderMoC: address could not be 0\"\n );\n require(\n price != uint256(0),\n \"MockPriceProviderMoC: price could not be 0\"\n );\n guardian = guardian_;\n rbtcPrice = bytes32(price);\n has = true;\n }\n\n function peek() public view returns (bytes32, bool) {\n return (rbtcPrice, has);\n }\n\n /**\n * @notice Set the rbtcPrice price provider\n * @param price uint of price provider\n */\n function setPrice(uint256 price) public {\n require(\n msg.sender == guardian,\n \"MockPriceProviderMoC: only guardian may set the address\"\n );\n require(\n price != uint256(0),\n \"MockPriceProviderMoC: price could not be 0\"\n );\n //set old price\n bytes32 oldRbtcPrice = rbtcPrice;\n //update rbtcPrice\n rbtcPrice = bytes32(price);\n //emit event\n emit MockPriceProviderMoCUpdated(\n uint256(oldRbtcPrice),\n uint256(rbtcPrice)\n );\n }\n}\n" - }, - "contracts/CErc20Immutable.sol": { - "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity 0.8.6;\n\nimport \"./CErc20.sol\";\n\n/**\n * @title tropykus CErc20Immutable Contract\n * @notice CTokens which wrap an EIP-20 underlying and are immutable\n * @author tropykus\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(\n address underlying_,\n ComptrollerInterface comptroller_,\n InterestRateModel interestRateModel_,\n uint256 initialExchangeRateMantissa_,\n string memory name_,\n string memory symbol_,\n uint8 decimals_,\n address payable admin_\n ) {\n // Creator of the contract is admin during initialization\n admin = payable(msg.sender);\n\n // Initialize the market\n initialize(\n underlying_,\n comptroller_,\n interestRateModel_,\n initialExchangeRateMantissa_,\n name_,\n symbol_,\n decimals_\n );\n\n // Set the proper admin now that initialization is done\n admin = admin_;\n }\n}\n" - }, - "contracts/CErc20Delegate.sol": { - "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity 0.8.6;\n\nimport \"./CErc20.sol\";\n\n/**\n * @title tropykus CErc20Delegate Contract\n * @notice CTokens which wrap an EIP-20 underlying and are delegated to\n * @author tropykus\n */\ncontract CErc20Delegate is CErc20, CDelegateInterface {\n /**\n * @notice Construct an empty delegate\n */\n constructor() {\n // solium-disable-previous-line no-empty-blocks\n }\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 override {\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, \"ER01\");\n }\n\n /**\n * @notice Called by the delegator on a delegate to forfeit its responsibility\n */\n function _resignImplementation() public override {\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, \"ER02\");\n }\n}\n" - }, - "contracts/CCompLikeDelegate.sol": { - "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity 0.8.6;\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 tropykus\n */\ncontract CCompLikeDelegate is CErc20Delegate {\n /**\n * @notice Construct an empty delegate\n */\n constructor() 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(\n msg.sender == admin,\n \"only the admin may set the comp-like delegate\"\n );\n CompLike(underlying).delegate(compLikeDelegatee);\n }\n}\n" - }, - "contracts/ComptrollerG2.sol": { - "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity 0.8.6;\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 tropykus Comptroller Contract\n * @author tropykus\n */\ncontract ComptrollerG2 is\n ComptrollerV2Storage,\n ComptrollerInterface,\n ComptrollerErrorReporter,\n Exponential\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(\n uint256 oldCloseFactorMantissa,\n uint256 newCloseFactorMantissa\n );\n\n /**\n * @notice Emitted when a collateral factor is changed by admin\n */\n event NewCollateralFactor(\n CToken cToken,\n uint256 oldCollateralFactorMantissa,\n uint256 newCollateralFactorMantissa\n );\n\n /**\n * @notice Emitted when liquidation incentive is changed by admin\n */\n event NewLiquidationIncentive(\n uint256 oldLiquidationIncentiveMantissa,\n uint256 newLiquidationIncentiveMantissa\n );\n\n /**\n * @notice Emitted when maxAssets is changed by admin\n */\n event NewMaxAssets(uint256 oldMaxAssets, uint256 newMaxAssets);\n\n /**\n * @notice Emitted when price oracle is changed\n */\n event NewPriceOracle(\n PriceOracle oldPriceOracle,\n PriceOracle newPriceOracle\n );\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 uint256 internal constant closeFactorMinMantissa = 0.05e18; // 0.05\n\n // closeFactorMantissa must not exceed this value\n uint256 internal constant closeFactorMaxMantissa = 0.9e18; // 0.9\n\n // No collateralFactorMantissa may exceed this value\n uint256 internal constant collateralFactorMaxMantissa = 0.9e18; // 0.9\n\n // liquidationIncentiveMantissa must be no less than this value\n uint256 internal constant liquidationIncentiveMinMantissa = 1.0e18; // 1.0\n\n // liquidationIncentiveMantissa must be no greater than this value\n uint256 internal constant liquidationIncentiveMaxMantissa = 1.5e18; // 1.5\n\n constructor() {\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)\n external\n view\n returns (CToken[] memory)\n {\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)\n external\n view\n returns (bool)\n {\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)\n public\n override\n returns (uint256[] memory)\n {\n uint256 len = cTokens.length;\n\n uint256[] memory results = new uint256[](len);\n for (uint256 i = 0; i < len; i++) {\n CToken cToken = CToken(cTokens[i]);\n\n results[i] = uint256(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)\n internal\n returns (Error)\n {\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)\n external\n override\n returns (uint256)\n {\n CToken cToken = CToken(cTokenAddress);\n /* Get sender tokensHeld and amountOwed underlying from the cToken */\n (uint256 oErr, uint256 tokensHeld, uint256 amountOwed, ) = cToken\n .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\n fail(\n Error.NONZERO_BORROW_BALANCE,\n FailureInfo.EXIT_MARKET_BALANCE_OWED\n );\n }\n\n /* Fail if the sender is not permitted to redeem all of their tokens */\n uint256 allowed = redeemAllowedInternal(\n cTokenAddress,\n msg.sender,\n tokensHeld\n );\n if (allowed != 0) {\n return\n failOpaque(\n Error.REJECTION,\n FailureInfo.EXIT_MARKET_REJECTION,\n allowed\n );\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 uint256(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 accountAssets[msg.sender] = new CToken[](0);\n CToken[] storage newMarketList = accountAssets[msg.sender];\n uint256 len = userAssetList.length;\n uint256 assetIndex = len;\n for (uint256 i = 0; i < len; i++) {\n if (userAssetList[i] == cToken) {\n assetIndex = i;\n continue;\n }\n newMarketList.push(userAssetList[i]);\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 emit MarketExited(cToken, msg.sender);\n\n return uint256(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(\n address cToken,\n address minter,\n uint256 mintAmount\n ) external view override returns (uint256) {\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 uint256(Error.MARKET_NOT_LISTED);\n }\n\n // *may include Policy Hook-type checks\n\n return uint256(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(\n address cToken,\n address minter,\n uint256 actualMintAmount,\n uint256 mintTokens\n ) external override {\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(\n address cToken,\n address redeemer,\n uint256 redeemTokens\n ) external view override returns (uint256) {\n return redeemAllowedInternal(cToken, redeemer, redeemTokens);\n }\n\n function redeemAllowedInternal(\n address cToken,\n address redeemer,\n uint256 redeemTokens\n ) internal view returns (uint256) {\n if (!markets[cToken].isListed) {\n return uint256(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 uint256(Error.NO_ERROR);\n }\n\n /* Otherwise, perform a hypothetical liquidity check to guard against shortfall */\n (\n Error err,\n ,\n uint256 shortfall\n ) = getHypotheticalAccountLiquidityInternal(\n redeemer,\n CToken(cToken),\n redeemTokens,\n 0\n );\n if (err != Error.NO_ERROR) {\n return uint256(err);\n }\n if (shortfall > 0) {\n return uint256(Error.INSUFFICIENT_LIQUIDITY);\n }\n\n return uint256(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(\n address cToken,\n address redeemer,\n uint256 redeemAmount,\n uint256 redeemTokens\n ) external pure override {\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(\n address cToken,\n address borrower,\n uint256 borrowAmount\n ) external override returns (uint256) {\n // Pausing is a very serious situation - we revert to sound the alarms\n Error err;\n uint256 shortfall;\n require(!borrowGuardianPaused[cToken], \"borrow is paused\");\n\n if (!markets[cToken].isListed) {\n return uint256(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 err = addToMarketInternal(CToken(msg.sender), borrower);\n if (err != Error.NO_ERROR) {\n return uint256(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 uint256(Error.PRICE_ERROR);\n }\n\n (err, , shortfall) = getHypotheticalAccountLiquidityInternal(\n borrower,\n CToken(cToken),\n 0,\n borrowAmount\n );\n if (err != Error.NO_ERROR) {\n return uint256(err);\n }\n if (shortfall > 0) {\n return uint256(Error.INSUFFICIENT_LIQUIDITY);\n }\n\n return uint256(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(\n address cToken,\n address borrower,\n uint256 borrowAmount\n ) external override {\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 uint256 repayAmount\n ) external view override returns (uint256) {\n // Shh - currently unused\n payer;\n borrower;\n repayAmount;\n\n if (!markets[cToken].isListed) {\n return uint256(Error.MARKET_NOT_LISTED);\n }\n\n // *may include Policy Hook-type checks\n\n return uint256(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 uint256 actualRepayAmount,\n uint256 borrowerIndex\n ) external override {\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 uint256 repayAmount\n ) external view override returns (uint256) {\n // Shh - currently unused\n liquidator;\n\n if (\n !markets[cTokenBorrowed].isListed ||\n !markets[cTokenCollateral].isListed\n ) {\n return uint256(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, , uint256 shortfall) = getAccountLiquidityInternal(\n borrower\n );\n if (err != Error.NO_ERROR) {\n return uint256(err);\n }\n if (shortfall == 0) {\n return uint256(Error.INSUFFICIENT_SHORTFALL);\n }\n\n /* The liquidator may not repay more than what is allowed by the closeFactor */\n uint256 borrowBalance = CToken(cTokenBorrowed).borrowBalanceStored(\n borrower\n );\n (MathError mathErr, uint256 maxClose) = mulScalarTruncate(\n Exp({mantissa: closeFactorMantissa}),\n borrowBalance\n );\n if (mathErr != MathError.NO_ERROR) {\n return uint256(Error.MATH_ERROR);\n }\n if (repayAmount > maxClose) {\n return uint256(Error.TOO_MUCH_REPAY);\n }\n\n return uint256(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 uint256 actualRepayAmount,\n uint256 seizeTokens\n ) external override {\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 uint256 seizeTokens\n ) external view override returns (uint256) {\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 (\n !markets[cTokenCollateral].isListed ||\n !markets[cTokenBorrowed].isListed\n ) {\n return uint256(Error.MARKET_NOT_LISTED);\n }\n\n if (\n CToken(cTokenCollateral).comptroller() !=\n CToken(cTokenBorrowed).comptroller()\n ) {\n return uint256(Error.COMPTROLLER_MISMATCH);\n }\n\n // *may include Policy Hook-type checks\n\n return uint256(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 uint256 seizeTokens\n ) external override {\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(\n address cToken,\n address src,\n address dst,\n uint256 transferTokens\n ) external view override returns (uint256) {\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(\n address cToken,\n address src,\n address dst,\n uint256 transferTokens\n ) external override {\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 uint256 sumCollateral;\n uint256 sumBorrowPlusEffects;\n uint256 cTokenBalance;\n uint256 borrowBalance;\n uint256 exchangeRateMantissa;\n uint256 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)\n public\n view\n returns (\n uint256,\n uint256,\n uint256\n )\n {\n (\n Error err,\n uint256 liquidity,\n uint256 shortfall\n ) = getHypotheticalAccountLiquidityInternal(\n account,\n CToken(address(0)),\n 0,\n 0\n );\n\n return (uint256(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)\n internal\n view\n returns (\n Error,\n uint256,\n uint256\n )\n {\n return\n getHypotheticalAccountLiquidityInternal(\n account,\n CToken(address(0)),\n 0,\n 0\n );\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 uint256 redeemTokens,\n uint256 borrowAmount\n )\n public\n view\n returns (\n uint256,\n uint256,\n uint256\n )\n {\n (\n Error err,\n uint256 liquidity,\n uint256 shortfall\n ) = getHypotheticalAccountLiquidityInternal(\n account,\n CToken(cTokenModify),\n redeemTokens,\n borrowAmount\n );\n return (uint256(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 uint256 redeemTokens,\n uint256 borrowAmount\n )\n internal\n view\n returns (\n Error,\n uint256,\n uint256\n )\n {\n AccountLiquidityLocalVars memory vars; // Holds all our calculation results\n uint256 oErr;\n MathError mErr;\n\n // For each asset the account is in\n CToken[] memory assets = accountAssets[account];\n for (uint256 i = 0; i < assets.length; i++) {\n CToken asset = assets[i];\n\n // Read the balances and exchange rate from the cToken\n (\n oErr,\n vars.cTokenBalance,\n vars.borrowBalance,\n vars.exchangeRateMantissa\n ) = asset.getAccountSnapshot(account);\n if (oErr != 0) {\n // 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({\n mantissa: markets[address(asset)].collateralFactorMantissa\n });\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(\n vars.collateralFactor,\n vars.exchangeRate,\n vars.oraclePrice\n );\n if (mErr != MathError.NO_ERROR) {\n return (Error.MATH_ERROR, 0, 0);\n }\n\n // sumCollateral += tokensToEther * cTokenBalance\n (mErr, vars.sumCollateral) = mulScalarTruncateAddUInt(\n vars.tokensToEther,\n vars.cTokenBalance,\n vars.sumCollateral\n );\n if (mErr != MathError.NO_ERROR) {\n return (Error.MATH_ERROR, 0, 0);\n }\n\n // sumBorrowPlusEffects += oraclePrice * borrowBalance\n (mErr, vars.sumBorrowPlusEffects) = mulScalarTruncateAddUInt(\n vars.oraclePrice,\n vars.borrowBalance,\n vars.sumBorrowPlusEffects\n );\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(\n vars.tokensToEther,\n redeemTokens,\n vars.sumBorrowPlusEffects\n );\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(\n vars.oraclePrice,\n borrowAmount,\n vars.sumBorrowPlusEffects\n );\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 (\n Error.NO_ERROR,\n vars.sumCollateral - vars.sumBorrowPlusEffects,\n 0\n );\n } else {\n return (\n Error.NO_ERROR,\n 0,\n vars.sumBorrowPlusEffects - vars.sumCollateral\n );\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(\n address cTokenBorrowed,\n address cTokenCollateral,\n uint256 actualRepayAmount\n ) external view override returns (uint256, uint256) {\n /* Read oracle prices for borrowed and collateral markets */\n uint256 priceBorrowedMantissa = oracle.getUnderlyingPrice(\n CToken(cTokenBorrowed)\n );\n uint256 priceCollateralMantissa = oracle.getUnderlyingPrice(\n CToken(cTokenCollateral)\n );\n if (priceBorrowedMantissa == 0 || priceCollateralMantissa == 0) {\n return (uint256(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 uint256 exchangeRateMantissa = CToken(cTokenCollateral)\n .exchangeRateStored(); // Note: reverts on error\n uint256 seizeTokens;\n Exp memory numerator;\n Exp memory denominator;\n Exp memory ratio;\n MathError mathErr;\n\n (mathErr, numerator) = mulExp(\n liquidationIncentiveMantissa,\n priceBorrowedMantissa\n );\n if (mathErr != MathError.NO_ERROR) {\n return (uint256(Error.MATH_ERROR), 0);\n }\n\n (mathErr, denominator) = mulExp(\n priceCollateralMantissa,\n exchangeRateMantissa\n );\n if (mathErr != MathError.NO_ERROR) {\n return (uint256(Error.MATH_ERROR), 0);\n }\n\n (mathErr, ratio) = divExp(numerator, denominator);\n if (mathErr != MathError.NO_ERROR) {\n return (uint256(Error.MATH_ERROR), 0);\n }\n\n (mathErr, seizeTokens) = mulScalarTruncate(ratio, actualRepayAmount);\n if (mathErr != MathError.NO_ERROR) {\n return (uint256(Error.MATH_ERROR), 0);\n }\n\n return (uint256(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 (uint256) {\n // Check caller is admin\n if (msg.sender != admin) {\n return\n fail(\n Error.UNAUTHORIZED,\n FailureInfo.SET_PRICE_ORACLE_OWNER_CHECK\n );\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 uint256(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(uint256 newCloseFactorMantissa)\n external\n returns (uint256)\n {\n // Check caller is admin\n if (msg.sender != admin) {\n return\n fail(\n Error.UNAUTHORIZED,\n FailureInfo.SET_CLOSE_FACTOR_OWNER_CHECK\n );\n }\n\n Exp memory newCloseFactorExp = Exp({mantissa: newCloseFactorMantissa});\n Exp memory lowLimit = Exp({mantissa: closeFactorMinMantissa});\n if (lessThanOrEqualExp(newCloseFactorExp, lowLimit)) {\n return\n fail(\n Error.INVALID_CLOSE_FACTOR,\n FailureInfo.SET_CLOSE_FACTOR_VALIDATION\n );\n }\n\n Exp memory highLimit = Exp({mantissa: closeFactorMaxMantissa});\n if (lessThanExp(highLimit, newCloseFactorExp)) {\n return\n fail(\n Error.INVALID_CLOSE_FACTOR,\n FailureInfo.SET_CLOSE_FACTOR_VALIDATION\n );\n }\n\n uint256 oldCloseFactorMantissa = closeFactorMantissa;\n closeFactorMantissa = newCloseFactorMantissa;\n emit NewCloseFactor(oldCloseFactorMantissa, closeFactorMantissa);\n\n return uint256(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(\n CToken cToken,\n uint256 newCollateralFactorMantissa\n ) external returns (uint256) {\n // Check caller is admin\n if (msg.sender != admin) {\n return\n fail(\n Error.UNAUTHORIZED,\n FailureInfo.SET_COLLATERAL_FACTOR_OWNER_CHECK\n );\n }\n\n // Verify market is listed\n Market storage market = markets[address(cToken)];\n if (!market.isListed) {\n return\n fail(\n Error.MARKET_NOT_LISTED,\n FailureInfo.SET_COLLATERAL_FACTOR_NO_EXISTS\n );\n }\n\n Exp memory newCollateralFactorExp = Exp({\n mantissa: newCollateralFactorMantissa\n });\n\n // Check collateral factor <= 0.9\n Exp memory highLimit = Exp({mantissa: collateralFactorMaxMantissa});\n if (lessThanExp(highLimit, newCollateralFactorExp)) {\n return\n fail(\n Error.INVALID_COLLATERAL_FACTOR,\n FailureInfo.SET_COLLATERAL_FACTOR_VALIDATION\n );\n }\n\n // If collateral factor != 0, fail if price == 0\n if (\n newCollateralFactorMantissa != 0 &&\n oracle.getUnderlyingPrice(cToken) == 0\n ) {\n return\n fail(\n Error.PRICE_ERROR,\n FailureInfo.SET_COLLATERAL_FACTOR_WITHOUT_PRICE\n );\n }\n\n // Set market's collateral factor to new collateral factor, remember old value\n uint256 oldCollateralFactorMantissa = market.collateralFactorMantissa;\n market.collateralFactorMantissa = newCollateralFactorMantissa;\n\n // Emit event with asset, old collateral factor, and new collateral factor\n emit NewCollateralFactor(\n cToken,\n oldCollateralFactorMantissa,\n newCollateralFactorMantissa\n );\n\n return uint256(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(uint256 newMaxAssets) external returns (uint256) {\n // Check caller is admin\n if (msg.sender != admin) {\n return\n fail(\n Error.UNAUTHORIZED,\n FailureInfo.SET_MAX_ASSETS_OWNER_CHECK\n );\n }\n\n uint256 oldMaxAssets = maxAssets;\n maxAssets = newMaxAssets;\n emit NewMaxAssets(oldMaxAssets, newMaxAssets);\n\n return uint256(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(uint256 newLiquidationIncentiveMantissa)\n external\n returns (uint256)\n {\n // Check caller is admin\n if (msg.sender != admin) {\n return\n fail(\n Error.UNAUTHORIZED,\n FailureInfo.SET_LIQUIDATION_INCENTIVE_OWNER_CHECK\n );\n }\n\n // Check de-scaled min <= newLiquidationIncentive <= max\n Exp memory newLiquidationIncentive = Exp({\n mantissa: newLiquidationIncentiveMantissa\n });\n Exp memory minLiquidationIncentive = Exp({\n mantissa: liquidationIncentiveMinMantissa\n });\n if (lessThanExp(newLiquidationIncentive, minLiquidationIncentive)) {\n return\n fail(\n Error.INVALID_LIQUIDATION_INCENTIVE,\n FailureInfo.SET_LIQUIDATION_INCENTIVE_VALIDATION\n );\n }\n\n Exp memory maxLiquidationIncentive = Exp({\n mantissa: liquidationIncentiveMaxMantissa\n });\n if (lessThanExp(maxLiquidationIncentive, newLiquidationIncentive)) {\n return\n fail(\n Error.INVALID_LIQUIDATION_INCENTIVE,\n FailureInfo.SET_LIQUIDATION_INCENTIVE_VALIDATION\n );\n }\n\n // Save current value for use in log\n uint256 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(\n oldLiquidationIncentiveMantissa,\n newLiquidationIncentiveMantissa\n );\n\n return uint256(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 (uint256) {\n if (msg.sender != admin) {\n return\n fail(\n Error.UNAUTHORIZED,\n FailureInfo.SUPPORT_MARKET_OWNER_CHECK\n );\n }\n\n if (markets[address(cToken)].isListed) {\n return\n fail(\n Error.MARKET_ALREADY_LISTED,\n FailureInfo.SUPPORT_MARKET_EXISTS\n );\n }\n\n cToken.isCToken(); // Sanity check to make sure its really a CToken\n\n Market storage market = markets[address(cToken)];\n market.isListed = true;\n market.isComped = false;\n market.collateralFactorMantissa = 0;\n\n emit MarketListed(cToken);\n\n return uint256(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)\n public\n returns (uint256)\n {\n if (msg.sender != admin) {\n return\n fail(\n Error.UNAUTHORIZED,\n FailureInfo.SET_PAUSE_GUARDIAN_OWNER_CHECK\n );\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 uint256(Error.NO_ERROR);\n }\n\n function _setMintPaused(CToken cToken, bool state) public returns (bool) {\n require(\n markets[address(cToken)].isListed,\n \"cannot pause a market that is not listed\"\n );\n require(\n msg.sender == pauseGuardian || msg.sender == admin,\n \"only pause guardian and admin can pause\"\n );\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(\n markets[address(cToken)].isListed,\n \"cannot pause a market that is not listed\"\n );\n require(\n msg.sender == pauseGuardian || msg.sender == admin,\n \"only pause guardian and admin can pause\"\n );\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(\n msg.sender == pauseGuardian || msg.sender == admin,\n \"only pause guardian and admin can pause\"\n );\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(\n msg.sender == pauseGuardian || msg.sender == admin,\n \"only pause guardian and admin can pause\"\n );\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(\n msg.sender == unitroller.admin(),\n \"only unitroller admin can change brains\"\n );\n\n uint256 changeStatus = unitroller._acceptImplementation();\n require(changeStatus == 0, \"change not authorized\");\n }\n}\n" - }, - "contracts/ComptrollerG1.sol": { - "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity 0.8.6;\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 tropykus Comptroller Contract\n * @author tropykus\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\n ComptrollerV1Storage,\n ComptrollerInterface,\n ComptrollerErrorReporter,\n Exponential\n{\n struct Market {\n /**\n * @notice Whether or not this market is listed\n */\n bool isListed;\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 uint256 collateralFactorMantissa;\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(\n uint256 oldCloseFactorMantissa,\n uint256 newCloseFactorMantissa\n );\n\n /**\n * @notice Emitted when a collateral factor is changed by admin\n */\n event NewCollateralFactor(\n CToken cToken,\n uint256 oldCollateralFactorMantissa,\n uint256 newCollateralFactorMantissa\n );\n\n /**\n * @notice Emitted when liquidation incentive is changed by admin\n */\n event NewLiquidationIncentive(\n uint256 oldLiquidationIncentiveMantissa,\n uint256 newLiquidationIncentiveMantissa\n );\n\n /**\n * @notice Emitted when maxAssets is changed by admin\n */\n event NewMaxAssets(uint256 oldMaxAssets, uint256 newMaxAssets);\n\n /**\n * @notice Emitted when price oracle is changed\n */\n event NewPriceOracle(\n PriceOracle oldPriceOracle,\n PriceOracle newPriceOracle\n );\n\n // closeFactorMantissa must be strictly greater than this value\n uint256 constant closeFactorMinMantissa = 5e16; // 0.05\n\n // closeFactorMantissa must not exceed this value\n uint256 constant closeFactorMaxMantissa = 9e17; // 0.9\n\n // No collateralFactorMantissa may exceed this value\n uint256 constant collateralFactorMaxMantissa = 9e17; // 0.9\n\n // liquidationIncentiveMantissa must be no less than this value\n uint256 constant liquidationIncentiveMinMantissa = mantissaOne;\n\n // liquidationIncentiveMantissa must be no greater than this value\n uint256 constant liquidationIncentiveMaxMantissa = 15e17; // 1.5\n\n constructor() {\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)\n external\n view\n returns (CToken[] memory)\n {\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)\n external\n view\n returns (bool)\n {\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)\n public\n override\n returns (uint256[] memory)\n {\n uint256 len = cTokens.length;\n\n uint256[] memory results = new uint256[](len);\n for (uint256 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] = uint256(Error.MARKET_NOT_LISTED);\n continue;\n }\n\n if (marketToJoin.accountMembership[msg.sender] == true) {\n // if already joined, move along\n results[i] = uint256(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] = uint256(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] = uint256(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)\n external\n override\n returns (uint256)\n {\n CToken cToken = CToken(cTokenAddress);\n /* Get sender tokensHeld and amountOwed underlying from the cToken */\n (uint256 oErr, uint256 tokensHeld, uint256 amountOwed, ) = cToken\n .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\n fail(\n Error.NONZERO_BORROW_BALANCE,\n FailureInfo.EXIT_MARKET_BALANCE_OWED\n );\n }\n\n /* Fail if the sender is not permitted to redeem all of their tokens */\n uint256 allowed = redeemAllowedInternal(\n cTokenAddress,\n msg.sender,\n tokensHeld\n );\n if (allowed != 0) {\n return\n failOpaque(\n Error.REJECTION,\n FailureInfo.EXIT_MARKET_REJECTION,\n allowed\n );\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 uint256(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 accountAssets[msg.sender] = new CToken[](0);\n CToken[] storage newMarketList = accountAssets[msg.sender];\n uint256 len = userAssetList.length;\n uint256 assetIndex = len;\n for (uint256 i = 0; i < len; i++) {\n if (userAssetList[i] == cToken) {\n assetIndex = i;\n continue;\n }\n newMarketList.push(userAssetList[i]);\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 emit MarketExited(cToken, msg.sender);\n\n return uint256(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(\n address cToken,\n address minter,\n uint256 mintAmount\n ) external view override returns (uint256) {\n minter; // currently unused\n mintAmount; // currently unused\n\n if (!markets[cToken].isListed) {\n return uint256(Error.MARKET_NOT_LISTED);\n }\n\n // *may include Policy Hook-type checks\n\n return uint256(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(\n address cToken,\n address minter,\n uint256 mintAmount,\n uint256 mintTokens\n ) external override {\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(\n address cToken,\n address redeemer,\n uint256 redeemTokens\n ) external view override returns (uint256) {\n return redeemAllowedInternal(cToken, redeemer, redeemTokens);\n }\n\n function redeemAllowedInternal(\n address cToken,\n address redeemer,\n uint256 redeemTokens\n ) internal view returns (uint256) {\n if (!markets[cToken].isListed) {\n return uint256(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 uint256(Error.NO_ERROR);\n }\n\n /* Otherwise, perform a hypothetical liquidity check to guard against shortfall */\n (\n Error err,\n ,\n uint256 shortfall\n ) = getHypotheticalAccountLiquidityInternal(\n redeemer,\n CToken(cToken),\n redeemTokens,\n 0\n );\n if (err != Error.NO_ERROR) {\n return uint256(err);\n }\n if (shortfall > 0) {\n return uint256(Error.INSUFFICIENT_LIQUIDITY);\n }\n\n return uint256(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(\n address cToken,\n address redeemer,\n uint256 redeemAmount,\n uint256 redeemTokens\n ) external pure override {\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(\n address cToken,\n address borrower,\n uint256 borrowAmount\n ) external view override returns (uint256) {\n if (!markets[cToken].isListed) {\n return uint256(Error.MARKET_NOT_LISTED);\n }\n\n // *may include Policy Hook-type checks\n\n if (!markets[cToken].accountMembership[borrower]) {\n return uint256(Error.MARKET_NOT_ENTERED);\n }\n\n if (oracle.getUnderlyingPrice(CToken(cToken)) == 0) {\n return uint256(Error.PRICE_ERROR);\n }\n\n (\n Error err,\n ,\n uint256 shortfall\n ) = getHypotheticalAccountLiquidityInternal(\n borrower,\n CToken(cToken),\n 0,\n borrowAmount\n );\n if (err != Error.NO_ERROR) {\n return uint256(err);\n }\n if (shortfall > 0) {\n return uint256(Error.INSUFFICIENT_LIQUIDITY);\n }\n\n return uint256(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(\n address cToken,\n address borrower,\n uint256 borrowAmount\n ) external override {\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 uint256 repayAmount\n ) external view override returns (uint256) {\n payer; // currently unused\n borrower; // currently unused\n repayAmount; // currently unused\n\n if (!markets[cToken].isListed) {\n return uint256(Error.MARKET_NOT_LISTED);\n }\n\n // *may include Policy Hook-type checks\n\n return uint256(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 uint256 repayAmount,\n uint256 borrowerIndex\n ) external override {\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 uint256 repayAmount\n ) external view override returns (uint256) {\n liquidator; // currently unused\n borrower; // currently unused\n repayAmount; // currently unused\n\n if (\n !markets[cTokenBorrowed].isListed ||\n !markets[cTokenCollateral].isListed\n ) {\n return uint256(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, , uint256 shortfall) = getAccountLiquidityInternal(\n borrower\n );\n if (err != Error.NO_ERROR) {\n return uint256(err);\n }\n if (shortfall == 0) {\n return uint256(Error.INSUFFICIENT_SHORTFALL);\n }\n\n /* The liquidator may not repay more than what is allowed by the closeFactor */\n uint256 borrowBalance = CToken(cTokenBorrowed).borrowBalanceStored(\n borrower\n );\n (MathError mathErr, uint256 maxClose) = mulScalarTruncate(\n Exp({mantissa: closeFactorMantissa}),\n borrowBalance\n );\n if (mathErr != MathError.NO_ERROR) {\n return uint256(Error.MATH_ERROR);\n }\n if (repayAmount > maxClose) {\n return uint256(Error.TOO_MUCH_REPAY);\n }\n\n return uint256(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 uint256 repayAmount,\n uint256 seizeTokens\n ) external override {\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 uint256 seizeTokens\n ) external view override returns (uint256) {\n liquidator; // currently unused\n borrower; // currently unused\n seizeTokens; // currently unused\n\n if (\n !markets[cTokenCollateral].isListed ||\n !markets[cTokenBorrowed].isListed\n ) {\n return uint256(Error.MARKET_NOT_LISTED);\n }\n\n if (\n CToken(cTokenCollateral).comptroller() !=\n CToken(cTokenBorrowed).comptroller()\n ) {\n return uint256(Error.COMPTROLLER_MISMATCH);\n }\n\n // *may include Policy Hook-type checks\n\n return uint256(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 uint256 seizeTokens\n ) external override {\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(\n address cToken,\n address src,\n address dst,\n uint256 transferTokens\n ) external view override returns (uint256) {\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(\n address cToken,\n address src,\n address dst,\n uint256 transferTokens\n ) external override {\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 uint256 sumCollateral;\n uint256 sumBorrowPlusEffects;\n uint256 cTokenBalance;\n uint256 borrowBalance;\n uint256 exchangeRateMantissa;\n uint256 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)\n public\n view\n returns (\n uint256,\n uint256,\n uint256\n )\n {\n (\n Error err,\n uint256 liquidity,\n uint256 shortfall\n ) = getHypotheticalAccountLiquidityInternal(\n account,\n CToken(address(0)),\n 0,\n 0\n );\n\n return (uint256(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)\n internal\n view\n returns (\n Error,\n uint256,\n uint256\n )\n {\n return\n getHypotheticalAccountLiquidityInternal(\n account,\n CToken(address(0)),\n 0,\n 0\n );\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 uint256 redeemTokens,\n uint256 borrowAmount\n )\n internal\n view\n returns (\n Error,\n uint256,\n uint256\n )\n {\n AccountLiquidityLocalVars memory vars; // Holds all our calculation results\n uint256 oErr;\n MathError mErr;\n\n // For each asset the account is in\n CToken[] memory assets = accountAssets[account];\n for (uint256 i = 0; i < assets.length; i++) {\n CToken asset = assets[i];\n\n // Read the balances and exchange rate from the cToken\n (\n oErr,\n vars.cTokenBalance,\n vars.borrowBalance,\n vars.exchangeRateMantissa\n ) = asset.getAccountSnapshot(account);\n if (oErr != 0) {\n // 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({\n mantissa: markets[address(asset)].collateralFactorMantissa\n });\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(\n vars.collateralFactor,\n vars.exchangeRate,\n vars.oraclePrice\n );\n if (mErr != MathError.NO_ERROR) {\n return (Error.MATH_ERROR, 0, 0);\n }\n\n // sumCollateral += tokensToEther * cTokenBalance\n (mErr, vars.sumCollateral) = mulScalarTruncateAddUInt(\n vars.tokensToEther,\n vars.cTokenBalance,\n vars.sumCollateral\n );\n if (mErr != MathError.NO_ERROR) {\n return (Error.MATH_ERROR, 0, 0);\n }\n\n // sumBorrowPlusEffects += oraclePrice * borrowBalance\n (mErr, vars.sumBorrowPlusEffects) = mulScalarTruncateAddUInt(\n vars.oraclePrice,\n vars.borrowBalance,\n vars.sumBorrowPlusEffects\n );\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(\n vars.tokensToEther,\n redeemTokens,\n vars.sumBorrowPlusEffects\n );\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(\n vars.oraclePrice,\n borrowAmount,\n vars.sumBorrowPlusEffects\n );\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 (\n Error.NO_ERROR,\n vars.sumCollateral - vars.sumBorrowPlusEffects,\n 0\n );\n } else {\n return (\n Error.NO_ERROR,\n 0,\n vars.sumBorrowPlusEffects - vars.sumCollateral\n );\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(\n address cTokenBorrowed,\n address cTokenCollateral,\n uint256 repayAmount\n ) external view override returns (uint256, uint256) {\n /* Read oracle prices for borrowed and collateral markets */\n uint256 priceBorrowedMantissa = oracle.getUnderlyingPrice(\n CToken(cTokenBorrowed)\n );\n uint256 priceCollateralMantissa = oracle.getUnderlyingPrice(\n CToken(cTokenCollateral)\n );\n if (priceBorrowedMantissa == 0 || priceCollateralMantissa == 0) {\n return (uint256(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 uint256 exchangeRateMantissa = CToken(cTokenCollateral)\n .exchangeRateStored(); // Note: reverts on error\n uint256 seizeTokens;\n Exp memory numerator;\n Exp memory denominator;\n Exp memory ratio;\n MathError mathErr;\n\n (mathErr, numerator) = mulExp(\n liquidationIncentiveMantissa,\n priceBorrowedMantissa\n );\n if (mathErr != MathError.NO_ERROR) {\n return (uint256(Error.MATH_ERROR), 0);\n }\n\n (mathErr, denominator) = mulExp(\n priceCollateralMantissa,\n exchangeRateMantissa\n );\n if (mathErr != MathError.NO_ERROR) {\n return (uint256(Error.MATH_ERROR), 0);\n }\n\n (mathErr, ratio) = divExp(numerator, denominator);\n if (mathErr != MathError.NO_ERROR) {\n return (uint256(Error.MATH_ERROR), 0);\n }\n\n (mathErr, seizeTokens) = mulScalarTruncate(ratio, repayAmount);\n if (mathErr != MathError.NO_ERROR) {\n return (uint256(Error.MATH_ERROR), 0);\n }\n\n return (uint256(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 (uint256) {\n // Check caller is admin OR currently initialzing as new unitroller implementation\n if (!adminOrInitializing()) {\n return\n fail(\n Error.UNAUTHORIZED,\n FailureInfo.SET_PRICE_ORACLE_OWNER_CHECK\n );\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 uint256(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(uint256 newCloseFactorMantissa)\n external\n returns (uint256)\n {\n // Check caller is admin OR currently initialzing as new unitroller implementation\n if (!adminOrInitializing()) {\n return\n fail(\n Error.UNAUTHORIZED,\n FailureInfo.SET_CLOSE_FACTOR_OWNER_CHECK\n );\n }\n\n Exp memory newCloseFactorExp = Exp({mantissa: newCloseFactorMantissa});\n Exp memory lowLimit = Exp({mantissa: closeFactorMinMantissa});\n if (lessThanOrEqualExp(newCloseFactorExp, lowLimit)) {\n return\n fail(\n Error.INVALID_CLOSE_FACTOR,\n FailureInfo.SET_CLOSE_FACTOR_VALIDATION\n );\n }\n\n Exp memory highLimit = Exp({mantissa: closeFactorMaxMantissa});\n if (lessThanExp(highLimit, newCloseFactorExp)) {\n return\n fail(\n Error.INVALID_CLOSE_FACTOR,\n FailureInfo.SET_CLOSE_FACTOR_VALIDATION\n );\n }\n\n uint256 oldCloseFactorMantissa = closeFactorMantissa;\n closeFactorMantissa = newCloseFactorMantissa;\n emit NewCloseFactor(oldCloseFactorMantissa, closeFactorMantissa);\n\n return uint256(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(\n CToken cToken,\n uint256 newCollateralFactorMantissa\n ) external returns (uint256) {\n // Check caller is admin\n if (msg.sender != admin) {\n return\n fail(\n Error.UNAUTHORIZED,\n FailureInfo.SET_COLLATERAL_FACTOR_OWNER_CHECK\n );\n }\n\n // Verify market is listed\n Market storage market = markets[address(cToken)];\n if (!market.isListed) {\n return\n fail(\n Error.MARKET_NOT_LISTED,\n FailureInfo.SET_COLLATERAL_FACTOR_NO_EXISTS\n );\n }\n\n Exp memory newCollateralFactorExp = Exp({\n mantissa: newCollateralFactorMantissa\n });\n\n // Check collateral factor <= 0.9\n Exp memory highLimit = Exp({mantissa: collateralFactorMaxMantissa});\n if (lessThanExp(highLimit, newCollateralFactorExp)) {\n return\n fail(\n Error.INVALID_COLLATERAL_FACTOR,\n FailureInfo.SET_COLLATERAL_FACTOR_VALIDATION\n );\n }\n\n // If collateral factor != 0, fail if price == 0\n if (\n newCollateralFactorMantissa != 0 &&\n oracle.getUnderlyingPrice(cToken) == 0\n ) {\n return\n fail(\n Error.PRICE_ERROR,\n FailureInfo.SET_COLLATERAL_FACTOR_WITHOUT_PRICE\n );\n }\n\n // Set market's collateral factor to new collateral factor, remember old value\n uint256 oldCollateralFactorMantissa = market.collateralFactorMantissa;\n market.collateralFactorMantissa = newCollateralFactorMantissa;\n\n // Emit event with asset, old collateral factor, and new collateral factor\n emit NewCollateralFactor(\n cToken,\n oldCollateralFactorMantissa,\n newCollateralFactorMantissa\n );\n\n return uint256(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(uint256 newMaxAssets) external returns (uint256) {\n // Check caller is admin OR currently initialzing as new unitroller implementation\n if (!adminOrInitializing()) {\n return\n fail(\n Error.UNAUTHORIZED,\n FailureInfo.SET_MAX_ASSETS_OWNER_CHECK\n );\n }\n\n uint256 oldMaxAssets = maxAssets;\n maxAssets = newMaxAssets;\n emit NewMaxAssets(oldMaxAssets, newMaxAssets);\n\n return uint256(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(uint256 newLiquidationIncentiveMantissa)\n external\n returns (uint256)\n {\n // Check caller is admin OR currently initialzing as new unitroller implementation\n if (!adminOrInitializing()) {\n return\n fail(\n Error.UNAUTHORIZED,\n FailureInfo.SET_LIQUIDATION_INCENTIVE_OWNER_CHECK\n );\n }\n\n // Check de-scaled 1 <= newLiquidationDiscount <= 1.5\n Exp memory newLiquidationIncentive = Exp({\n mantissa: newLiquidationIncentiveMantissa\n });\n Exp memory minLiquidationIncentive = Exp({\n mantissa: liquidationIncentiveMinMantissa\n });\n if (lessThanExp(newLiquidationIncentive, minLiquidationIncentive)) {\n return\n fail(\n Error.INVALID_LIQUIDATION_INCENTIVE,\n FailureInfo.SET_LIQUIDATION_INCENTIVE_VALIDATION\n );\n }\n\n Exp memory maxLiquidationIncentive = Exp({\n mantissa: liquidationIncentiveMaxMantissa\n });\n if (lessThanExp(maxLiquidationIncentive, newLiquidationIncentive)) {\n return\n fail(\n Error.INVALID_LIQUIDATION_INCENTIVE,\n FailureInfo.SET_LIQUIDATION_INCENTIVE_VALIDATION\n );\n }\n\n // Save current value for use in log\n uint256 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(\n oldLiquidationIncentiveMantissa,\n newLiquidationIncentiveMantissa\n );\n\n return uint256(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 (uint256) {\n if (msg.sender != admin) {\n return\n fail(\n Error.UNAUTHORIZED,\n FailureInfo.SUPPORT_MARKET_OWNER_CHECK\n );\n }\n\n if (markets[address(cToken)].isListed) {\n return\n fail(\n Error.MARKET_ALREADY_LISTED,\n FailureInfo.SUPPORT_MARKET_EXISTS\n );\n }\n\n cToken.isCToken(); // Sanity check to make sure its really a CToken\n\n Market storage market = markets[address(cToken)];\n market.isListed = true;\n market.collateralFactorMantissa = 0;\n\n emit MarketListed(cToken);\n\n return uint256(Error.NO_ERROR);\n }\n\n function _become(\n Unitroller unitroller,\n PriceOracle _oracle,\n uint256 _closeFactorMantissa,\n uint256 _maxAssets,\n bool reinitializing\n ) public virtual {\n require(\n msg.sender == unitroller.admin(),\n \"only unitroller admin can change brains\"\n );\n uint256 changeStatus = unitroller._acceptImplementation();\n\n require(changeStatus == 0, \"change not authorized\");\n\n if (!reinitializing) {\n ComptrollerG1 freshBrainedComptroller = ComptrollerG1(\n address(unitroller)\n );\n\n // Ensure invoke _setPriceOracle() = 0\n uint256 err = freshBrainedComptroller._setPriceOracle(_oracle);\n require(err == uint256(Error.NO_ERROR), \"set price oracle error\");\n\n // Ensure invoke _setCloseFactor() = 0\n err = freshBrainedComptroller._setCloseFactor(_closeFactorMantissa);\n require(err == uint256(Error.NO_ERROR), \"set close factor error\");\n\n // Ensure invoke _setMaxAssets() = 0\n err = freshBrainedComptroller._setMaxAssets(_maxAssets);\n require(err == uint256(Error.NO_ERROR), \"set max asssets error\");\n\n // Ensure invoke _setLiquidationIncentive(liquidationIncentiveMinMantissa) = 0\n err = freshBrainedComptroller._setLiquidationIncentive(\n liquidationIncentiveMinMantissa\n );\n require(\n err == uint256(Error.NO_ERROR),\n \"set liquidation incentive error\"\n );\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 = (msg.sender == comptrollerImplementation &&\n tx.origin == admin);\n //solium-disable-previous-line security/no-tx-origin\n bool isAdmin = msg.sender == admin;\n return isAdmin || initializing;\n }\n}\n" - }, - "contracts/Comptroller.sol": { - "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity 0.8.6;\n\nimport \"./CToken.sol\";\nimport \"./ErrorReporter.sol\";\nimport \"./PriceOracle.sol\";\nimport \"./ComptrollerInterface.sol\";\nimport \"./ComptrollerStorage.sol\";\nimport \"./Unitroller.sol\";\nimport \"./Governance/TROP.sol\";\n\n/**\n * @title tropykus Comptroller Contract\n * @author tropykus\n */\ncontract Comptroller is\n ComptrollerV5Storage,\n ComptrollerInterface,\n ComptrollerErrorReporter,\n ExponentialNoError\n{\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(\n uint256 oldCloseFactorMantissa,\n uint256 newCloseFactorMantissa\n );\n\n /// @notice Emitted when a collateral factor is changed by admin\n event NewCollateralFactor(\n CToken cToken,\n uint256 oldCollateralFactorMantissa,\n uint256 newCollateralFactorMantissa\n );\n\n /// @notice Emitted when liquidation incentive is changed by admin\n event NewLiquidationIncentive(\n uint256 oldLiquidationIncentiveMantissa,\n uint256 newLiquidationIncentiveMantissa\n );\n\n /// @notice Emitted when price oracle is changed\n event NewPriceOracle(\n PriceOracle oldPriceOracle,\n PriceOracle newPriceOracle\n );\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, uint256 newSpeed);\n\n /// @notice Emitted when a new COMP speed is set for a contributor\n event ContributorCompSpeedUpdated(\n address indexed contributor,\n uint256 newSpeed\n );\n\n /// @notice Emitted when COMP is distributed to a supplier\n event DistributedSupplierComp(\n CToken indexed cToken,\n address indexed supplier,\n uint256 compDelta,\n uint256 compSupplyIndex\n );\n\n /// @notice Emitted when COMP is distributed to a borrower\n event DistributedBorrowerComp(\n CToken indexed cToken,\n address indexed borrower,\n uint256 compDelta,\n uint256 compBorrowIndex\n );\n\n /// @notice Emitted when borrow cap for a cToken is changed\n event NewBorrowCap(CToken indexed cToken, uint256 newBorrowCap);\n\n /// @notice Emitted when borrow cap guardian is changed\n event NewBorrowCapGuardian(\n address oldBorrowCapGuardian,\n address newBorrowCapGuardian\n );\n\n /// @notice Emitted when COMP is granted by admin\n event CompGranted(address recipient, uint256 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 uint256 internal constant closeFactorMinMantissa = 0.05e18; // 0.05\n\n // closeFactorMantissa must not exceed this value\n uint256 internal constant closeFactorMaxMantissa = 0.9e18; // 0.9\n\n // No collateralFactorMantissa may exceed this value\n uint256 internal constant collateralFactorMaxMantissa = 0.9e18; // 0.9\n\n constructor() {\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)\n external\n view\n returns (CToken[] memory)\n {\n return accountAssets[account];\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)\n external\n view\n returns (bool)\n {\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)\n public\n override\n returns (uint256[] memory)\n {\n uint256 len = cTokens.length;\n\n uint256[] memory results = new uint256[](len);\n for (uint256 i = 0; i < len; i++) {\n CToken cToken = CToken(cTokens[i]);\n\n results[i] = uint256(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)\n internal\n returns (Error)\n {\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)\n external\n override\n returns (uint256)\n {\n CToken cToken = CToken(cTokenAddress);\n /* Get sender tokensHeld and amountOwed underlying from the cToken */\n (uint256 oErr, uint256 tokensHeld, uint256 amountOwed, ) = cToken\n .getAccountSnapshot(msg.sender);\n require(oErr == 0, \"getAccountSnapshot failed\"); // semi-opaque error code\n\n /* Fail if the sender has a borrow balance */\n if (amountOwed != 0) {\n return\n fail(\n Error.NONZERO_BORROW_BALANCE,\n FailureInfo.EXIT_MARKET_BALANCE_OWED\n );\n }\n\n /* Fail if the sender is not permitted to redeem all of their tokens */\n uint256 allowed = redeemAllowedInternal(\n cTokenAddress,\n msg.sender,\n tokensHeld\n );\n if (allowed != 0) {\n return\n failOpaque(\n Error.REJECTION,\n FailureInfo.EXIT_MARKET_REJECTION,\n allowed\n );\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 uint256(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 accountAssets[msg.sender] = new CToken[](0);\n CToken[] storage newMarketList = accountAssets[msg.sender];\n uint256 len = userAssetList.length;\n uint256 assetIndex = len;\n for (uint256 i = 0; i < len; i++) {\n if (userAssetList[i] == cToken) {\n assetIndex = i;\n continue;\n }\n newMarketList.push(userAssetList[i]);\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 emit MarketExited(cToken, msg.sender);\n\n return uint256(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(\n address cToken,\n address minter,\n uint256\n ) external override returns (uint256) {\n // Shh - currently unused mintAmount\n // Pausing is a very serious situation - we revert to sound the alarms\n require(!mintGuardianPaused[cToken], \"mint is paused\");\n\n if (!markets[cToken].isListed) {\n return uint256(Error.MARKET_NOT_LISTED);\n }\n\n // Keep the flywheel moving\n updateCompSupplyIndex(cToken);\n distributeSupplierComp(cToken, minter);\n\n return uint256(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(\n address,\n address,\n uint256,\n uint256\n ) external override {\n // Shh - we don't ever want this hook to be marked pure\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(\n address cToken,\n address redeemer,\n uint256 redeemTokens\n ) external override returns (uint256) {\n uint256 allowed = redeemAllowedInternal(cToken, redeemer, redeemTokens);\n if (allowed != uint256(Error.NO_ERROR)) {\n return allowed;\n }\n\n // Keep the flywheel moving\n updateCompSupplyIndex(cToken);\n distributeSupplierComp(cToken, redeemer);\n\n return uint256(Error.NO_ERROR);\n }\n\n function redeemAllowedInternal(\n address cToken,\n address redeemer,\n uint256 redeemTokens\n ) internal view returns (uint256) {\n if (!markets[cToken].isListed) {\n return uint256(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 uint256(Error.NO_ERROR);\n }\n\n /* Otherwise, perform a hypothetical liquidity check to guard against shortfall */\n (\n Error err,\n ,\n uint256 shortfall\n ) = getHypotheticalAccountLiquidityInternal(\n redeemer,\n CToken(cToken),\n redeemTokens,\n 0\n );\n if (err != Error.NO_ERROR) {\n return uint256(err);\n }\n if (shortfall > 0) {\n return uint256(Error.INSUFFICIENT_LIQUIDITY);\n }\n\n return uint256(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(\n address,\n address,\n uint256 redeemAmount,\n uint256 redeemTokens\n ) external pure override {\n // Shh - currently unused cToken, 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(\n address cToken,\n address borrower,\n uint256 borrowAmount\n ) external override returns (uint256) {\n // Pausing is a very serious situation - we revert to sound the alarms\n Error err;\n uint256 shortfall;\n require(!borrowGuardianPaused[cToken], \"borrow is paused\");\n\n if (!markets[cToken].isListed) {\n return uint256(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 not cToken\");\n\n // attempt to add borrower to the market\n err = addToMarketInternal(CToken(msg.sender), borrower);\n if (err != Error.NO_ERROR) {\n return uint256(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 uint256(Error.PRICE_ERROR);\n }\n\n uint256 borrowCap = borrowCaps[cToken];\n // Borrow cap of 0 corresponds to unlimited borrowing\n if (borrowCap != 0) {\n uint256 totalBorrows = CToken(cToken).totalBorrows();\n uint256 nextTotalBorrows = add_(totalBorrows, borrowAmount);\n require(nextTotalBorrows < borrowCap, \"market borrow cap reached\");\n }\n\n (err, , shortfall) = getHypotheticalAccountLiquidityInternal(\n borrower,\n CToken(cToken),\n 0,\n borrowAmount\n );\n if (err != Error.NO_ERROR) {\n return uint256(err);\n }\n if (shortfall > 0) {\n return uint256(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);\n\n return uint256(Error.NO_ERROR);\n }\n\n // /**\n // * @notice Validates borrow and reverts on rejection. May emit logs. Currently unused\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(\n address,\n address,\n uint256\n ) external override {\n // Shh - currently unused\n // Shh - we don't ever want this hook to be marked pure\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,\n address borrower,\n uint256\n ) external override returns (uint256) {\n // Shh - currently unused payer, repayAmount\n\n if (!markets[cToken].isListed) {\n return uint256(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);\n\n return uint256(Error.NO_ERROR);\n }\n\n // /**\n // * @notice Validates repayBorrow and reverts on rejection. May emit logs. Currently unused\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,\n address,\n address,\n uint256,\n uint256\n ) external override {\n // Shh - currently unused\n // Shh - we don't ever want this hook to be marked pure\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,\n address borrower,\n uint256 repayAmount\n ) external view override returns (uint256) {\n // Shh - currently unused liquidator\n\n if (\n !markets[cTokenBorrowed].isListed ||\n !markets[cTokenCollateral].isListed\n ) {\n return uint256(Error.MARKET_NOT_LISTED);\n }\n\n /* The borrower must have shortfall in order to be liquidatable */\n (Error err, , uint256 shortfall) = getAccountLiquidityInternal(\n borrower\n );\n if (err != Error.NO_ERROR) {\n return uint256(err);\n }\n if (shortfall == 0) {\n return uint256(Error.INSUFFICIENT_SHORTFALL);\n }\n\n /* The liquidator may not repay more than what is allowed by the closeFactor */\n uint256 borrowBalance = CToken(cTokenBorrowed).borrowBalanceStored(\n borrower\n );\n uint256 maxClose = mul_ScalarTruncate(\n Exp({mantissa: closeFactorMantissa}),\n borrowBalance\n );\n if (repayAmount > maxClose) {\n return uint256(Error.TOO_MUCH_REPAY);\n }\n\n return uint256(Error.NO_ERROR);\n }\n\n // /**\n // * @notice Validates liquidateBorrow and reverts on rejection. May emit logs. Currently unused\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,\n address,\n address,\n address,\n uint256,\n uint256\n ) external override {\n // Shh - currently unused\n // Shh - we don't ever want this hook to be marked pure\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 uint256\n ) external override returns (uint256) {\n // Pausing is a very serious situation - we revert to sound the alarms\n require(!seizeGuardianPaused, \"seize is paused\");\n\n // Shh - currently unused seizeTokens;\n\n if (\n !markets[cTokenCollateral].isListed ||\n !markets[cTokenBorrowed].isListed\n ) {\n return uint256(Error.MARKET_NOT_LISTED);\n }\n\n if (\n CToken(cTokenCollateral).comptroller() !=\n CToken(cTokenBorrowed).comptroller()\n ) {\n return uint256(Error.COMPTROLLER_MISMATCH);\n }\n\n // Keep the flywheel moving\n updateCompSupplyIndex(cTokenCollateral);\n distributeSupplierComp(cTokenCollateral, borrower);\n distributeSupplierComp(cTokenCollateral, liquidator);\n\n return uint256(Error.NO_ERROR);\n }\n\n // /**\n // * @notice Validates seize and reverts on rejection. May emit logs. Currently unused\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,\n address,\n address,\n address,\n uint256\n ) external override {\n // Shh - currently unused\n // Shh - we don't ever want this hook to be marked pure\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(\n address cToken,\n address src,\n address dst,\n uint256 transferTokens\n ) external override returns (uint256) {\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 uint256 allowed = redeemAllowedInternal(cToken, src, transferTokens);\n if (allowed != uint256(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 uint256(Error.NO_ERROR);\n }\n\n // /**\n // * @notice Validates transfer and reverts on rejection. May emit logs. Currently unused\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(\n address,\n address,\n address,\n uint256\n ) external override {\n // Shh - currently unused\n // Shh - we don't ever want this hook to be marked pure\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 uint256 sumCollateral;\n uint256 sumBorrowPlusEffects;\n uint256 cTokenBalance;\n uint256 borrowBalance;\n uint256 exchangeRateMantissa;\n uint256 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)\n public\n view\n returns (\n uint256,\n uint256,\n uint256\n )\n {\n (\n Error err,\n uint256 liquidity,\n uint256 shortfall\n ) = getHypotheticalAccountLiquidityInternal(\n account,\n CToken(address(0)),\n 0,\n 0\n );\n\n return (uint256(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)\n internal\n view\n returns (\n Error,\n uint256,\n uint256\n )\n {\n return\n getHypotheticalAccountLiquidityInternal(\n account,\n CToken(address(0)),\n 0,\n 0\n );\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 uint256 redeemTokens,\n uint256 borrowAmount\n )\n public\n view\n returns (\n uint256,\n uint256,\n uint256\n )\n {\n (\n Error err,\n uint256 liquidity,\n uint256 shortfall\n ) = getHypotheticalAccountLiquidityInternal(\n account,\n CToken(cTokenModify),\n redeemTokens,\n borrowAmount\n );\n return (uint256(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 uint256 redeemTokens,\n uint256 borrowAmount\n )\n internal\n view\n returns (\n Error,\n uint256,\n uint256\n )\n {\n AccountLiquidityLocalVars memory vars; // Holds all our calculation results\n uint256 oErr;\n\n // For each asset the account is in\n CToken[] memory assets = accountAssets[account];\n for (uint256 i = 0; i < assets.length; i++) {\n CToken asset = assets[i];\n\n // Read the balances and exchange rate from the cToken\n (\n oErr,\n vars.cTokenBalance,\n vars.borrowBalance,\n vars.exchangeRateMantissa\n ) = asset.getAccountSnapshot(account);\n if (oErr != 0) {\n // 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({\n mantissa: markets[address(asset)].collateralFactorMantissa\n });\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_(\n mul_(vars.collateralFactor, vars.exchangeRate),\n vars.oraclePrice\n );\n\n // sumCollateral += tokensToDenom * cTokenBalance\n vars.sumCollateral = mul_ScalarTruncateAddUInt(\n vars.tokensToDenom,\n vars.cTokenBalance,\n vars.sumCollateral\n );\n\n // sumBorrowPlusEffects += oraclePrice * borrowBalance\n vars.sumBorrowPlusEffects = mul_ScalarTruncateAddUInt(\n vars.oraclePrice,\n vars.borrowBalance,\n vars.sumBorrowPlusEffects\n );\n\n // Calculate effects of interacting with cTokenModify\n if (asset == cTokenModify) {\n // redeem effect\n // sumBorrowPlusEffects += tokensToDenom * redeemTokens\n vars.sumBorrowPlusEffects = mul_ScalarTruncateAddUInt(\n vars.tokensToDenom,\n redeemTokens,\n vars.sumBorrowPlusEffects\n );\n\n // borrow effect\n // sumBorrowPlusEffects += oraclePrice * borrowAmount\n vars.sumBorrowPlusEffects = mul_ScalarTruncateAddUInt(\n vars.oraclePrice,\n borrowAmount,\n vars.sumBorrowPlusEffects\n );\n }\n }\n\n // These are safe, as the underflow condition is checked first\n if (vars.sumCollateral > vars.sumBorrowPlusEffects) {\n return (\n Error.NO_ERROR,\n vars.sumCollateral - vars.sumBorrowPlusEffects,\n 0\n );\n } else {\n return (\n Error.NO_ERROR,\n 0,\n vars.sumBorrowPlusEffects - vars.sumCollateral\n );\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(\n address cTokenBorrowed,\n address cTokenCollateral,\n uint256 actualRepayAmount\n ) external view override returns (uint256, uint256) {\n /* Read oracle prices for borrowed and collateral markets */\n uint256 priceBorrowedMantissa = oracle.getUnderlyingPrice(\n CToken(cTokenBorrowed)\n );\n uint256 priceCollateralMantissa = oracle.getUnderlyingPrice(\n CToken(cTokenCollateral)\n );\n if (priceBorrowedMantissa == 0 || priceCollateralMantissa == 0) {\n return (uint256(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 uint256 exchangeRateMantissa = CToken(cTokenCollateral)\n .exchangeRateStored(); // Note: reverts on error\n uint256 seizeTokens;\n Exp memory numerator;\n Exp memory denominator;\n Exp memory ratio;\n\n numerator = mul_(\n Exp({mantissa: liquidationIncentiveMantissa}),\n Exp({mantissa: priceBorrowedMantissa})\n );\n denominator = mul_(\n Exp({mantissa: priceCollateralMantissa}),\n Exp({mantissa: exchangeRateMantissa})\n );\n ratio = div_(numerator, denominator);\n\n seizeTokens = mul_ScalarTruncate(ratio, actualRepayAmount);\n\n return (uint256(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 (uint256) {\n // Check caller is admin\n if (msg.sender != admin) {\n return\n fail(\n Error.UNAUTHORIZED,\n FailureInfo.SET_PRICE_ORACLE_OWNER_CHECK\n );\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 uint256(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(uint256 newCloseFactorMantissa)\n external\n returns (uint256)\n {\n // Check caller is admin\n require(msg.sender == admin, \"only admin can set close factor\");\n\n uint256 oldCloseFactorMantissa = closeFactorMantissa;\n closeFactorMantissa = newCloseFactorMantissa;\n emit NewCloseFactor(oldCloseFactorMantissa, closeFactorMantissa);\n\n return uint256(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(\n CToken cToken,\n uint256 newCollateralFactorMantissa\n ) external returns (uint256) {\n // Check caller is admin\n if (msg.sender != admin) {\n return\n fail(\n Error.UNAUTHORIZED,\n FailureInfo.SET_COLLATERAL_FACTOR_OWNER_CHECK\n );\n }\n\n // Verify market is listed\n Market storage market = markets[address(cToken)];\n if (!market.isListed) {\n return\n fail(\n Error.MARKET_NOT_LISTED,\n FailureInfo.SET_COLLATERAL_FACTOR_NO_EXISTS\n );\n }\n\n Exp memory newCollateralFactorExp = Exp({\n mantissa: newCollateralFactorMantissa\n });\n\n // Check collateral factor <= 0.9\n Exp memory highLimit = Exp({mantissa: collateralFactorMaxMantissa});\n if (lessThanExp(highLimit, newCollateralFactorExp)) {\n return\n fail(\n Error.INVALID_COLLATERAL_FACTOR,\n FailureInfo.SET_COLLATERAL_FACTOR_VALIDATION\n );\n }\n\n // If collateral factor != 0, fail if price == 0\n if (\n newCollateralFactorMantissa != 0 &&\n oracle.getUnderlyingPrice(cToken) == 0\n ) {\n return\n fail(\n Error.PRICE_ERROR,\n FailureInfo.SET_COLLATERAL_FACTOR_WITHOUT_PRICE\n );\n }\n\n // Set market's collateral factor to new collateral factor, remember old value\n uint256 oldCollateralFactorMantissa = market.collateralFactorMantissa;\n market.collateralFactorMantissa = newCollateralFactorMantissa;\n\n // Emit event with asset, old collateral factor, and new collateral factor\n emit NewCollateralFactor(\n cToken,\n oldCollateralFactorMantissa,\n newCollateralFactorMantissa\n );\n\n return uint256(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(uint256 newLiquidationIncentiveMantissa)\n external\n returns (uint256)\n {\n // Check caller is admin\n if (msg.sender != admin) {\n return\n fail(\n Error.UNAUTHORIZED,\n FailureInfo.SET_LIQUIDATION_INCENTIVE_OWNER_CHECK\n );\n }\n\n // Save current value for use in log\n uint256 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(\n oldLiquidationIncentiveMantissa,\n newLiquidationIncentiveMantissa\n );\n\n return uint256(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 (uint256) {\n if (msg.sender != admin) {\n return\n fail(\n Error.UNAUTHORIZED,\n FailureInfo.SUPPORT_MARKET_OWNER_CHECK\n );\n }\n\n if (markets[address(cToken)].isListed) {\n return\n fail(\n Error.MARKET_ALREADY_LISTED,\n FailureInfo.SUPPORT_MARKET_EXISTS\n );\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 Market storage market = markets[address(cToken)];\n market.isListed = true;\n market.isComped = false;\n market.collateralFactorMantissa = 0;\n\n _addMarketInternal(address(cToken));\n\n emit MarketListed(cToken);\n\n return uint256(Error.NO_ERROR);\n }\n\n function _addMarketInternal(address cToken) internal {\n for (uint256 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 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(\n CToken[] calldata cTokens,\n uint256[] calldata newBorrowCaps\n ) external {\n require(\n msg.sender == admin || msg.sender == borrowCapGuardian,\n \"only admin or guardian\"\n );\n\n uint256 numMarkets = cTokens.length;\n uint256 numBorrowCaps = newBorrowCaps.length;\n\n require(\n numMarkets != 0 && numMarkets == numBorrowCaps,\n \"invalid input\"\n );\n\n for (uint256 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 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)\n public\n returns (uint256)\n {\n if (msg.sender != admin) {\n return\n fail(\n Error.UNAUTHORIZED,\n FailureInfo.SET_PAUSE_GUARDIAN_OWNER_CHECK\n );\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 uint256(Error.NO_ERROR);\n }\n\n function _setMintPaused(CToken cToken, bool state) public returns (bool) {\n require(markets[address(cToken)].isListed, \"market not listed\");\n require(\n msg.sender == pauseGuardian || msg.sender == admin,\n \"only guardian and admin can pause\"\n );\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, \"market is not listed\");\n require(\n msg.sender == pauseGuardian || msg.sender == admin,\n \"only guardian and admin can pause\"\n );\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(\n msg.sender == pauseGuardian || msg.sender == admin,\n \"only guardian and admin can pause\"\n );\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(\n msg.sender == pauseGuardian || msg.sender == admin,\n \"only guardian and admin can pause\"\n );\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(\n msg.sender == unitroller.admin(),\n \"only unitroller admin can become\"\n );\n require(\n unitroller._acceptImplementation() == 0,\n \"change not authorized\"\n );\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 /*** TROP 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, uint256 compSpeed) internal {\n uint256 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 Exp memory borrowIndex = Exp({mantissa: cToken.borrowIndex()});\n updateCompSupplyIndex(address(cToken));\n updateCompBorrowIndex(address(cToken), borrowIndex);\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 (\n compSupplyState[address(cToken)].index == 0 &&\n compSupplyState[address(cToken)].block == 0\n ) {\n compSupplyState[address(cToken)] = CompMarketState({\n index: compInitialIndex,\n block: safe32(\n getBlockNumber(),\n \"block number exceeds 32 bits\"\n )\n });\n }\n\n if (\n compBorrowState[address(cToken)].index == 0 &&\n compBorrowState[address(cToken)].block == 0\n ) {\n compBorrowState[address(cToken)] = CompMarketState({\n index: compInitialIndex,\n block: safe32(\n getBlockNumber(),\n \"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 uint256 supplySpeed = compSpeeds[cToken];\n uint256 blockNumber = getBlockNumber();\n uint256 deltaBlocks = sub_(blockNumber, uint256(supplyState.block));\n if (deltaBlocks > 0 && supplySpeed > 0) {\n uint256 supplyTokens = CToken(cToken).totalSupply();\n uint256 compAccrued = mul_(deltaBlocks, supplySpeed);\n Double memory ratio = supplyTokens > 0\n ? fraction(compAccrued, supplyTokens)\n : Double({mantissa: 0});\n Double memory index = add_(\n Double({mantissa: supplyState.index}),\n ratio\n );\n compSupplyState[cToken] = CompMarketState({\n index: safe224(index.mantissa, \"index exceeds 224 bits\"),\n block: safe32(blockNumber, \"block exceeds 32 bits\")\n });\n } else if (deltaBlocks > 0) {\n supplyState.block = safe32(blockNumber, \"block 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)\n internal\n {\n CompMarketState storage borrowState = compBorrowState[cToken];\n uint256 borrowSpeed = compSpeeds[cToken];\n uint256 blockNumber = getBlockNumber();\n uint256 deltaBlocks = sub_(blockNumber, uint256(borrowState.block));\n if (deltaBlocks > 0 && borrowSpeed > 0) {\n uint256 borrowAmount = div_(\n CToken(cToken).totalBorrows(),\n marketBorrowIndex\n );\n uint256 compAccrued = mul_(deltaBlocks, borrowSpeed);\n Double memory ratio = borrowAmount > 0\n ? fraction(compAccrued, borrowAmount)\n : Double({mantissa: 0});\n Double memory index = add_(\n Double({mantissa: borrowState.index}),\n ratio\n );\n compBorrowState[cToken] = CompMarketState({\n index: safe224(index.mantissa, \"index exceeds 224 bits\"),\n block: safe32(blockNumber, \"block exceeds 32 bits\")\n });\n } else if (deltaBlocks > 0) {\n borrowState.block = safe32(blockNumber, \"block 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({\n mantissa: compSupplierIndex[cToken][supplier]\n });\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 uint256 supplierTokens = CToken(cToken).balanceOf(supplier);\n uint256 supplierDelta = mul_(supplierTokens, deltaIndex);\n uint256 supplierAccrued = add_(compAccrued[supplier], supplierDelta);\n compAccrued[supplier] = supplierAccrued;\n emit DistributedSupplierComp(\n CToken(cToken),\n supplier,\n supplierDelta,\n supplyIndex.mantissa\n );\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(\n address cToken,\n address borrower,\n Exp memory marketBorrowIndex\n ) internal {\n CompMarketState storage borrowState = compBorrowState[cToken];\n Double memory borrowIndex = Double({mantissa: borrowState.index});\n Double memory borrowerIndex = Double({\n mantissa: compBorrowerIndex[cToken][borrower]\n });\n compBorrowerIndex[cToken][borrower] = borrowIndex.mantissa;\n\n if (borrowerIndex.mantissa > 0) {\n Double memory deltaIndex = sub_(borrowIndex, borrowerIndex);\n uint256 borrowerAmount = div_(\n CToken(cToken).borrowBalanceStored(borrower),\n marketBorrowIndex\n );\n uint256 borrowerDelta = mul_(borrowerAmount, deltaIndex);\n uint256 borrowerAccrued = add_(\n compAccrued[borrower],\n borrowerDelta\n );\n compAccrued[borrower] = borrowerAccrued;\n emit DistributedBorrowerComp(\n CToken(cToken),\n borrower,\n borrowerDelta,\n borrowIndex.mantissa\n );\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 uint256 compSpeed = compContributorSpeeds[contributor];\n uint256 blockNumber = getBlockNumber();\n uint256 deltaBlocks = sub_(\n blockNumber,\n lastContributorBlock[contributor]\n );\n if (deltaBlocks > 0 && compSpeed > 0) {\n uint256 newAccrued = mul_(deltaBlocks, compSpeed);\n uint256 contributorAccrued = add_(\n compAccrued[contributor],\n newAccrued\n );\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(\n address[] memory holders,\n CToken[] memory cTokens,\n bool borrowers,\n bool suppliers\n ) public {\n for (uint256 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 (uint256 j = 0; j < holders.length; j++) {\n distributeBorrowerComp(\n address(cToken),\n holders[j],\n borrowIndex\n );\n compAccrued[holders[j]] = grantCompInternal(\n holders[j],\n compAccrued[holders[j]]\n );\n }\n }\n if (suppliers == true) {\n updateCompSupplyIndex(address(cToken));\n for (uint256 j = 0; j < holders.length; j++) {\n distributeSupplierComp(address(cToken), holders[j]);\n compAccrued[holders[j]] = grantCompInternal(\n holders[j],\n compAccrued[holders[j]]\n );\n }\n }\n }\n }\n\n /**\n * @notice Transfer TROP 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, uint256 amount)\n internal\n returns (uint256)\n {\n TROP comp = TROP(getCompAddress());\n uint256 compRemaining = comp.balanceOf(address(this));\n if (amount > 0 && amount <= compRemaining) {\n comp.transfer(user, amount);\n return 0;\n }\n return amount;\n }\n\n /*** TROP 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, uint256 amount) public {\n require(adminOrInitializing(), \"only admin can grant comp\");\n uint256 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, uint256 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, uint256 compSpeed)\n public\n {\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 virtual returns (uint256) {\n return block.number;\n }\n\n /**\n * @notice Set the address of the TROP token\n */\n function setCompAddress(address tropAddress_) public virtual {\n require(msg.sender == admin, \"only admin can set TROP\");\n tropAddress = tropAddress_;\n }\n\n /**\n * @notice Return the address of the TROP token\n * @return The address of TROP\n */\n function getCompAddress() public view virtual returns (address) {\n return tropAddress;\n }\n}\n" - }, - "contracts/Whitelist.sol": { - "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity 0.8.6;\n\nimport \"./WhitelistInterface.sol\";\n\ncontract Whitelist is WhitelistInterface {\n bool public override enabled;\n address owner;\n mapping(address => bool) public override exist;\n address[] users;\n\n modifier onlyOwner() {\n require(msg.sender == owner);\n _;\n }\n\n constructor() {\n owner = msg.sender;\n enabled = true;\n }\n\n function setStatus(bool _newStatus) external override onlyOwner {\n enabled = _newStatus;\n }\n\n function addUsers(address[] memory _users) external override onlyOwner {\n for (uint256 i = 0; i < _users.length; i++) {\n if (exist[_users[i]]) continue;\n users.push(_users[i]);\n exist[_users[i]] = true;\n }\n }\n\n function getUsers()\n external\n view\n override\n returns (address[] memory currentUsers)\n {\n currentUsers = users;\n }\n\n function removeUser(address _user) external override onlyOwner {\n if (exist[_user]) {\n exist[_user] = false;\n address[] memory oldUsers = users;\n users = new address[](0);\n for (uint256 i = 0; i < oldUsers.length; i++) {\n if (oldUsers[i] == _user) continue;\n users.push(oldUsers[i]);\n }\n }\n }\n}\n" - }, - "contracts/Timelock.sol": { - "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity 0.8.6;\n\nimport \"./SafeMath.sol\";\n\ncontract Timelock {\n using SafeMath for uint256;\n\n event NewAdmin(address indexed newAdmin);\n event NewPendingAdmin(address indexed newPendingAdmin);\n event NewDelay(uint256 indexed newDelay);\n event CancelTransaction(\n bytes32 indexed txHash,\n address indexed target,\n uint256 value,\n string signature,\n bytes data,\n uint256 eta\n );\n event ExecuteTransaction(\n bytes32 indexed txHash,\n address indexed target,\n uint256 value,\n string signature,\n bytes data,\n uint256 eta\n );\n event QueueTransaction(\n bytes32 indexed txHash,\n address indexed target,\n uint256 value,\n string signature,\n bytes data,\n uint256 eta\n );\n\n uint256 public constant GRACE_PERIOD = 14 days;\n uint256 public constant MINIMUM_DELAY = 2 days;\n uint256 public constant MAXIMUM_DELAY = 30 days;\n\n address public admin;\n address public pendingAdmin;\n uint256 public delay;\n\n mapping(bytes32 => bool) public queuedTransactions;\n\n constructor(address admin_, uint256 delay_) {\n require(\n delay_ >= MINIMUM_DELAY,\n \"Timelock::constructor: Delay must exceed minimum delay.\"\n );\n require(\n delay_ <= MAXIMUM_DELAY,\n \"Timelock::setDelay: Delay must not exceed maximum delay.\"\n );\n\n admin = admin_;\n delay = delay_;\n }\n\n fallback() external payable {}\n\n receive() external payable {}\n\n function setDelay(uint256 delay_) public {\n require(\n msg.sender == address(this),\n \"Timelock::setDelay: Call must come from Timelock.\"\n );\n require(\n delay_ >= MINIMUM_DELAY,\n \"Timelock::setDelay: Delay must exceed minimum delay.\"\n );\n require(\n delay_ <= MAXIMUM_DELAY,\n \"Timelock::setDelay: Delay must not exceed maximum delay.\"\n );\n delay = delay_;\n\n emit NewDelay(delay);\n }\n\n function acceptAdmin() public {\n require(\n msg.sender == pendingAdmin,\n \"Timelock::acceptAdmin: Call must come from pendingAdmin.\"\n );\n admin = msg.sender;\n pendingAdmin = address(0);\n\n emit NewAdmin(admin);\n }\n\n function setPendingAdmin(address pendingAdmin_) public {\n require(\n msg.sender == address(this),\n \"Timelock::setPendingAdmin: Call must come from Timelock.\"\n );\n pendingAdmin = pendingAdmin_;\n\n emit NewPendingAdmin(pendingAdmin);\n }\n\n function queueTransaction(\n address target,\n uint256 value,\n string memory signature,\n bytes memory data,\n uint256 eta\n ) public returns (bytes32) {\n require(\n msg.sender == admin,\n \"Timelock::queueTransaction: Call must come from admin.\"\n );\n require(\n eta >= getBlockTimestamp().add(delay),\n \"Timelock::queueTransaction: Estimated execution block must satisfy delay.\"\n );\n\n bytes32 txHash = keccak256(\n abi.encode(target, value, signature, data, eta)\n );\n queuedTransactions[txHash] = true;\n\n emit QueueTransaction(txHash, target, value, signature, data, eta);\n return txHash;\n }\n\n function cancelTransaction(\n address target,\n uint256 value,\n string memory signature,\n bytes memory data,\n uint256 eta\n ) public {\n require(\n msg.sender == admin,\n \"Timelock::cancelTransaction: Call must come from admin.\"\n );\n\n bytes32 txHash = keccak256(\n abi.encode(target, value, signature, data, eta)\n );\n queuedTransactions[txHash] = false;\n\n emit CancelTransaction(txHash, target, value, signature, data, eta);\n }\n\n function executeTransaction(\n address target,\n uint256 value,\n string memory signature,\n bytes memory data,\n uint256 eta\n ) public payable returns (bytes memory) {\n require(\n msg.sender == admin,\n \"Timelock::executeTransaction: Call must come from admin.\"\n );\n\n bytes32 txHash = keccak256(\n abi.encode(target, value, signature, data, eta)\n );\n require(\n queuedTransactions[txHash],\n \"Timelock::executeTransaction: Transaction hasn't been queued.\"\n );\n require(\n getBlockTimestamp() >= eta,\n \"Timelock::executeTransaction: Transaction hasn't surpassed time lock.\"\n );\n require(\n getBlockTimestamp() <= eta.add(GRACE_PERIOD),\n \"Timelock::executeTransaction: Transaction is stale.\"\n );\n\n queuedTransactions[txHash] = false;\n\n bytes memory callData;\n\n if (bytes(signature).length == 0) {\n callData = data;\n } else {\n callData = abi.encodePacked(\n bytes4(keccak256(bytes(signature))),\n data\n );\n }\n\n // solium-disable-next-line security/no-call-value\n (bool success, bytes memory returnData) = target.call{value: value}(\n callData\n );\n require(\n success,\n \"Timelock::executeTransaction: Transaction execution reverted.\"\n );\n\n emit ExecuteTransaction(txHash, target, value, signature, data, eta);\n\n return returnData;\n }\n\n function getBlockTimestamp() internal view returns (uint256) {\n // solium-disable-next-line security/no-block-members\n return block.timestamp;\n }\n}\n" - }, - "contracts/ERC20.sol": { - "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity 0.8.6;\n\nimport \"./SafeMath.sol\";\n\ninterface ERC20Base {\n event Approval(\n address indexed owner,\n address indexed spender,\n uint256 value\n );\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n function totalSupply() external view returns (uint256);\n\n function allowance(address owner, address spender)\n external\n view\n returns (uint256);\n\n function approve(address spender, uint256 value)\n external\n returns (bool);\n\n function balanceOf(address who) external view returns (uint256);\n}\n\nabstract contract ERC20 is ERC20Base {\n function transfer(address to, uint256 value)\n external\n virtual\n returns (bool);\n\n function transferFrom(\n address from,\n address to,\n uint256 value\n ) external virtual returns (bool);\n}\n\nabstract contract ERC20NS is ERC20Base {\n function transfer(address to, uint256 value) external virtual;\n\n function transferFrom(\n address from,\n address to,\n uint256 value\n ) external virtual;\n}\n\n/**\n * @title Standard ERC20 token\n * @dev Implementation of the basic standard token.\n * See https://github.com/ethereum/EIPs/issues/20\n */\ncontract StandardToken is ERC20 {\n using SafeMath for uint256;\n\n string public name;\n string public symbol;\n uint8 public decimals;\n uint256 public override totalSupply;\n mapping(address => mapping(address => uint256)) public override allowance;\n mapping(address => uint256) public override balanceOf;\n\n constructor(\n uint256 _initialAmount,\n string memory _tokenName,\n uint8 _decimalUnits,\n string memory _tokenSymbol\n ) {\n totalSupply = _initialAmount;\n balanceOf[msg.sender] = _initialAmount;\n name = _tokenName;\n symbol = _tokenSymbol;\n decimals = _decimalUnits;\n }\n\n function transfer(address dst, uint256 amount)\n external\n virtual\n override\n returns (bool)\n {\n balanceOf[msg.sender] = balanceOf[msg.sender].sub(\n amount,\n \"Insufficient balance\"\n );\n balanceOf[dst] = balanceOf[dst].add(amount, \"Balance overflow\");\n emit Transfer(msg.sender, dst, amount);\n return true;\n }\n\n function transferFrom(\n address src,\n address dst,\n uint256 amount\n ) external virtual override returns (bool) {\n allowance[src][msg.sender] = allowance[src][msg.sender].sub(\n amount,\n \"Insufficient allowance\"\n );\n balanceOf[src] = balanceOf[src].sub(amount, \"Insufficient balance\");\n balanceOf[dst] = balanceOf[dst].add(amount, \"Balance overflow\");\n emit Transfer(src, dst, amount);\n return true;\n }\n\n function approve(address _spender, uint256 amount)\n external\n override\n returns (bool)\n {\n allowance[msg.sender][_spender] = amount;\n emit Approval(msg.sender, _spender, amount);\n return true;\n }\n}\n\n/**\n * @title Non-Standard ERC20 token\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 */\ncontract NonStandardToken is ERC20NS {\n using SafeMath for uint256;\n\n string public name;\n uint8 public decimals;\n string public symbol;\n uint256 public override totalSupply;\n mapping(address => mapping(address => uint256)) public override allowance;\n mapping(address => uint256) public override balanceOf;\n\n constructor(\n uint256 _initialAmount,\n string memory _tokenName,\n uint8 _decimalUnits,\n string memory _tokenSymbol\n ) {\n totalSupply = _initialAmount;\n balanceOf[msg.sender] = _initialAmount;\n name = _tokenName;\n symbol = _tokenSymbol;\n decimals = _decimalUnits;\n }\n\n function transfer(address dst, uint256 amount) external override {\n balanceOf[msg.sender] = balanceOf[msg.sender].sub(\n amount,\n \"Insufficient balance\"\n );\n balanceOf[dst] = balanceOf[dst].add(amount, \"Balance overflow\");\n emit Transfer(msg.sender, dst, amount);\n }\n\n function transferFrom(\n address src,\n address dst,\n uint256 amount\n ) external override {\n allowance[src][msg.sender] = allowance[src][msg.sender].sub(\n amount,\n \"Insufficient allowance\"\n );\n balanceOf[src] = balanceOf[src].sub(amount, \"Insufficient balance\");\n balanceOf[dst] = balanceOf[dst].add(amount, \"Balance overflow\");\n emit Transfer(src, dst, amount);\n }\n\n function approve(address _spender, uint256 amount)\n external\n override\n returns (bool)\n {\n allowance[msg.sender][_spender] = amount;\n emit Approval(msg.sender, _spender, amount);\n return true;\n }\n}\n\ncontract ERC20Harness is StandardToken {\n using SafeMath for uint256;\n\n // To support testing, we can specify addresses for which transferFrom should fail and return false\n mapping(address => bool) public failTransferFromAddresses;\n\n // To support testing, we allow the contract to always fail `transfer`.\n mapping(address => bool) public failTransferToAddresses;\n\n constructor(\n uint256 _initialAmount,\n string memory _tokenName,\n uint8 _decimalUnits,\n string memory _tokenSymbol\n ) StandardToken(_initialAmount, _tokenName, _decimalUnits, _tokenSymbol) {}\n\n function harnessSetFailTransferFromAddress(address src, bool _fail) public {\n failTransferFromAddresses[src] = _fail;\n }\n\n function harnessSetFailTransferToAddress(address dst, bool _fail) public {\n failTransferToAddresses[dst] = _fail;\n }\n\n function harnessSetBalance(address _account, uint256 _amount) public {\n balanceOf[_account] = _amount;\n }\n\n function transfer(address dst, uint256 amount)\n external\n override\n returns (bool success)\n {\n // Added for testing purposes\n if (failTransferToAddresses[dst]) {\n return false;\n }\n balanceOf[msg.sender] = balanceOf[msg.sender].sub(\n amount,\n \"Insufficient balance\"\n );\n balanceOf[dst] = balanceOf[dst].add(amount, \"Balance overflow\");\n emit Transfer(msg.sender, dst, amount);\n return true;\n }\n\n function transferFrom(\n address src,\n address dst,\n uint256 amount\n ) external override returns (bool success) {\n // Added for testing purposes\n if (failTransferFromAddresses[src]) {\n return false;\n }\n allowance[src][msg.sender] = allowance[src][msg.sender].sub(\n amount,\n \"Insufficient allowance\"\n );\n balanceOf[src] = balanceOf[src].sub(amount, \"Insufficient balance\");\n balanceOf[dst] = balanceOf[dst].add(amount, \"Balance overflow\");\n emit Transfer(src, dst, amount);\n return true;\n }\n}\n" - } - }, - "settings": { - "optimizer": { - "enabled": true, - "runs": 200 - }, - "outputSelection": { - "*": { - "*": [ - "abi", - "evm.bytecode", - "evm.deployedBytecode", - "evm.methodIdentifiers", - "metadata", - "devdoc", - "userdoc", - "storageLayout", - "evm.gasEstimates" - ], - "": [ - "ast" - ] - } - }, - "metadata": { - "useLiteralContent": true - } - } -} \ No newline at end of file diff --git a/deployments/localhost/solcInputs/eec293f42f2aab5bd7ef36a794d2c589.json b/deployments/localhost/solcInputs/eec293f42f2aab5bd7ef36a794d2c589.json deleted file mode 100644 index 0e185c9..0000000 --- a/deployments/localhost/solcInputs/eec293f42f2aab5bd7ef36a794d2c589.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "language": "Solidity", - "sources": { - "contracts/MultiSigWallet.sol": { - "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity 0.8.6;\n\n/// @title Multisignature wallet - Allows multiple parties to agree on transactions before execution.\n/// @author Stefan George - \ncontract MultiSigWallet {\n /*\n * Events\n */\n event Confirmation(address indexed sender, uint256 indexed transactionId);\n event Revocation(address indexed sender, uint256 indexed transactionId);\n event Submission(uint256 indexed transactionId);\n event Execution(uint256 indexed transactionId);\n event ExecutionFailure(uint256 indexed transactionId);\n event Deposit(address indexed sender, uint256 value);\n event OwnerAddition(address indexed owner);\n event OwnerRemoval(address indexed owner);\n event RequirementChange(uint256 required);\n\n /*\n * views\n */\n uint256 public constant MAX_OWNER_COUNT = 50;\n\n /*\n * Storage\n */\n mapping(uint256 => Transaction) public transactions;\n mapping(uint256 => mapping(address => bool)) public confirmations;\n mapping(address => bool) public isOwner;\n address[] public owners;\n uint256 public required;\n uint256 public transactionCount;\n\n struct Transaction {\n address destination;\n uint256 value;\n bytes data;\n bool executed;\n }\n\n /*\n * Modifiers\n */\n modifier onlyWallet() {\n require(msg.sender == address(this), \"Only wallet allowed\");\n _;\n }\n\n modifier ownerDoesNotExist(address owner) {\n require(!isOwner[owner], \"The owner already exists\");\n _;\n }\n\n modifier ownerExists(address owner) {\n require(isOwner[owner], \"The owner does not exist\");\n _;\n }\n\n modifier transactionExists(uint256 transactionId) {\n require(\n transactions[transactionId].destination != address(0),\n \"Transaction does not exist\"\n );\n _;\n }\n\n modifier confirmed(uint256 transactionId, address owner) {\n require(\n confirmations[transactionId][owner],\n \"Transaction is not confirmed by owner\"\n );\n _;\n }\n\n modifier notConfirmed(uint256 transactionId, address owner) {\n require(\n !confirmations[transactionId][owner],\n \"Transaction is already confirmed by owner\"\n );\n _;\n }\n\n modifier notExecuted(uint256 transactionId) {\n require(\n !transactions[transactionId].executed,\n \"Transaction was already executed\"\n );\n _;\n }\n\n modifier notNull(address _address) {\n require(_address != address(0), \"Address cannot be empty\");\n _;\n }\n\n modifier validRequirement(uint256 ownerCount, uint256 _required) {\n // solium-disable-next-line max-len\n require(\n ownerCount <= MAX_OWNER_COUNT &&\n _required <= ownerCount &&\n _required != 0 &&\n ownerCount != 0,\n \"Required value is invalid for the current owners count\"\n );\n _;\n }\n\n /// @dev Fallback function allows to deposit ether.\n fallback() external payable {\n if (msg.value > 0) emit Deposit(msg.sender, msg.value);\n }\n\n receive() external payable {\n if (msg.value > 0) emit Deposit(msg.sender, msg.value);\n }\n\n /*\n * Public functions\n */\n /// @dev Contract constructor sets initial owners and required number of confirmations.\n /// @param _owners List of initial owners.\n /// @param _required Number of required confirmations.\n constructor(address[] memory _owners, uint256 _required)\n validRequirement(_owners.length, _required)\n {\n for (uint256 i = 0; i < _owners.length; i++) {\n require(\n !isOwner[_owners[i]] && _owners[i] != address(0),\n \"Owners addresses are invalid\"\n );\n isOwner[_owners[i]] = true;\n }\n owners = _owners;\n required = _required;\n }\n\n /// @dev Allows to add a new owner. Transaction has to be sent by wallet.\n /// @param owner Address of new owner.\n function addOwner(address owner)\n public\n onlyWallet\n ownerDoesNotExist(owner)\n notNull(owner)\n validRequirement(owners.length + 1, required)\n {\n isOwner[owner] = true;\n owners.push(owner);\n emit OwnerAddition(owner);\n }\n\n /// @dev Allows to remove an owner. Transaction has to be sent by wallet.\n /// @param owner Address of owner.\n function removeOwner(address owner) public onlyWallet ownerExists(owner) {\n isOwner[owner] = false;\n address[] memory oldOwners = owners;\n owners = new address[](0);\n for (uint256 i = 0; i < oldOwners.length; i++) {\n if (oldOwners[i] == owner) continue;\n owners.push(owners[i]);\n }\n if (required > owners.length) changeRequirement(owners.length);\n emit OwnerRemoval(owner);\n }\n\n /// @dev Allows to replace an owner with a new owner. Transaction has to be sent by wallet.\n /// @param owner Address of owner to be replaced.\n /// @param newOwner Address of new owner.\n function replaceOwner(address owner, address newOwner)\n public\n onlyWallet\n ownerExists(owner)\n ownerDoesNotExist(newOwner)\n {\n for (uint256 i = 0; i < owners.length; i++)\n if (owners[i] == owner) {\n owners[i] = newOwner;\n break;\n }\n isOwner[owner] = false;\n isOwner[newOwner] = true;\n emit OwnerRemoval(owner);\n emit OwnerAddition(newOwner);\n }\n\n /// @dev Allows to change the number of required confirmations. Transaction has to be sent by wallet.\n /// @param _required Number of required confirmations.\n function changeRequirement(uint256 _required)\n public\n onlyWallet\n validRequirement(owners.length, _required)\n {\n required = _required;\n emit RequirementChange(_required);\n }\n\n /// @dev Allows an owner to submit and confirm a transaction.\n /// @param destination Transaction target address.\n /// @param value Transaction ether value.\n /// @param data Transaction data payload.\n /// @return transactionId Returns transaction ID.\n function submitTransaction(\n address destination,\n uint256 value,\n bytes memory data\n ) public returns (uint256 transactionId) {\n transactionId = addTransaction(destination, value, data);\n confirmTransaction(transactionId);\n }\n\n /// @dev Allows an owner to confirm a transaction.\n /// @param transactionId Transaction ID.\n function confirmTransaction(uint256 transactionId)\n public\n ownerExists(msg.sender)\n transactionExists(transactionId)\n notConfirmed(transactionId, msg.sender)\n {\n confirmations[transactionId][msg.sender] = true;\n emit Confirmation(msg.sender, transactionId);\n executeTransaction(transactionId);\n }\n\n /// @dev Allows an owner to revoke a confirmation for a transaction.\n /// @param transactionId Transaction ID.\n function revokeConfirmation(uint256 transactionId)\n public\n ownerExists(msg.sender)\n confirmed(transactionId, msg.sender)\n notExecuted(transactionId)\n {\n confirmations[transactionId][msg.sender] = false;\n emit Revocation(msg.sender, transactionId);\n }\n\n /// @dev Allows anyone to execute a confirmed transaction.\n /// @param transactionId Transaction ID.\n function executeTransaction(uint256 transactionId)\n public\n ownerExists(msg.sender)\n confirmed(transactionId, msg.sender)\n notExecuted(transactionId)\n {\n if (isConfirmed(transactionId)) {\n Transaction storage txn = transactions[transactionId];\n txn.executed = true;\n if (\n external_call(\n txn.destination,\n txn.value,\n txn.data.length,\n txn.data\n )\n ) emit Execution(transactionId);\n else {\n emit ExecutionFailure(transactionId);\n txn.executed = false;\n }\n }\n }\n\n // call has been separated into its own function in order to take advantage\n // of the Solidity's code generator to produce a loop that copies tx.data into memory.\n function external_call(\n address destination,\n uint256 value,\n uint256 dataLength,\n bytes memory data\n ) internal returns (bool) {\n bool result;\n // solium-disable-next-line security/no-inline-assembly\n assembly {\n let x := mload(0x40) // \"Allocate\" memory for output (0x40 is where \"free memory\" pointer is stored by convention)\n let d := add(data, 32) // First 32 bytes are the padded length of data, so exclude that\n result := call(\n sub(gas(), 34710), // 34710 is the value that solidity is currently emitting\n // It includes callGas (700) + callVeryLow (3, to pay for SUB) + callValueTransferGas (9000) +\n // callNewAccountGas (25000, in case the destination address does not exist and needs creating)\n destination,\n value,\n d,\n dataLength, // Size of the input (in bytes) - this is what fixes the padding problem\n x,\n 0 // Output is ignored, therefore the output size is zero\n )\n }\n return result;\n }\n\n /// @dev Returns the confirmation status of a transaction.\n /// @param transactionId Transaction ID.\n /// @return result Confirmation status.\n function isConfirmed(uint256 transactionId) public view returns (bool result) {\n uint256 count = 0;\n for (uint256 i = 0; i < owners.length; i++) {\n if (confirmations[transactionId][owners[i]]) count += 1;\n if (count == required) return true;\n }\n }\n\n /*\n * Internal functions\n */\n /// @dev Adds a new transaction to the transaction mapping, if transaction does not exist yet.\n /// @param destination Transaction target address.\n /// @param value Transaction ether value.\n /// @param data Transaction data payload.\n /// @return transactionId Returns transaction ID.\n function addTransaction(\n address destination,\n uint256 value,\n bytes memory data\n ) internal notNull(destination) returns (uint256 transactionId) {\n transactionId = transactionCount;\n transactions[transactionId] = Transaction({\n destination: destination,\n value: value,\n data: data,\n executed: false\n });\n transactionCount += 1;\n emit Submission(transactionId);\n }\n\n /*\n * Web3 call functions\n */\n /// @dev Returns number of confirmations of a transaction.\n /// @param transactionId Transaction ID.\n /// @return count Number of confirmations.\n function getConfirmationCount(uint256 transactionId)\n public\n view\n returns (uint256 count)\n {\n for (uint256 i = 0; i < owners.length; i++) {\n if (confirmations[transactionId][owners[i]]) {\n count += 1;\n }\n }\n }\n\n /// @dev Returns total number of transactions after filers are applied.\n /// @param pending Include pending transactions.\n /// @param executed Include executed transactions.\n /// @return count Total number of transactions after filters are applied.\n function getTransactionCount(bool pending, bool executed)\n public\n view\n returns (uint256 count)\n {\n for (uint256 i = 0; i < transactionCount; i++) {\n if (\n (pending && !transactions[i].executed) ||\n (executed && transactions[i].executed)\n ) {\n count += 1;\n }\n }\n }\n\n /// @dev Returns list of owners.\n /// @return List of owner addresses.\n function getOwners() public view returns (address[] memory) {\n return owners;\n }\n\n /// @dev Returns array with owner addresses, which confirmed transaction.\n /// @param transactionId Transaction ID.\n /// @return _confirmations Returns array of owner addresses.\n function getConfirmations(uint256 transactionId)\n public\n view\n returns (address[] memory _confirmations)\n {\n address[] memory confirmationsTemp = new address[](owners.length);\n uint256 count = 0;\n uint256 i;\n for (i = 0; i < owners.length; i++)\n if (confirmations[transactionId][owners[i]]) {\n confirmationsTemp[count] = owners[i];\n count += 1;\n }\n _confirmations = new address[](count);\n for (i = 0; i < count; i++) _confirmations[i] = confirmationsTemp[i];\n }\n\n /// @dev Returns list of transaction IDs in defined range.\n /// @param from Index start position of transaction array.\n /// @param to Index end position of transaction array.\n /// @param pending Include pending transactions.\n /// @param executed Include executed transactions.\n /// @return _transactionIds Returns array of transaction IDs.\n function getTransactionIds(\n uint256 from,\n uint256 to,\n bool pending,\n bool executed\n ) public view returns (uint256[] memory _transactionIds) {\n uint256[] memory transactionIdsTemp = new uint256[](transactionCount);\n uint256 count = 0;\n uint256 i;\n for (i = 0; i < transactionCount; i++)\n if (\n (pending && !transactions[i].executed) ||\n (executed && transactions[i].executed)\n ) {\n transactionIdsTemp[count] = i;\n count += 1;\n }\n _transactionIds = new uint256[](to - from);\n for (i = from; i < to; i++)\n _transactionIds[i - from] = transactionIdsTemp[i];\n }\n}\n" - } - }, - "settings": { - "optimizer": { - "enabled": true, - "runs": 200 - }, - "outputSelection": { - "*": { - "*": [ - "abi", - "evm.bytecode", - "evm.deployedBytecode", - "evm.methodIdentifiers", - "metadata", - "devdoc", - "userdoc", - "storageLayout", - "evm.gasEstimates" - ], - "": [ - "ast" - ] - } - }, - "metadata": { - "useLiteralContent": true - } - } -} \ No newline at end of file diff --git a/flatten/BaseJumpRateModelV2.sol b/flatten/BaseJumpRateModelV2.sol deleted file mode 100644 index 6b2da3e..0000000 --- a/flatten/BaseJumpRateModelV2.sol +++ /dev/null @@ -1,998 +0,0 @@ -// Dependency file: contracts/CarefulMath.sol - -// SPDX-License-Identifier: UNLICENSED -// pragma solidity 0.8.6; - -/** - * @title Careful Math - * @author tropykus - * @notice Derived from OpenZeppelin's SafeMath library - * https://github.com/OpenZeppelin/openzeppelin-solidity/blob/master/contracts/math/SafeMath.sol - */ -contract CarefulMath { - - /** - * @dev Possible error codes that we can return - */ - enum MathError { - NO_ERROR, - DIVISION_BY_ZERO, - INTEGER_OVERFLOW, - INTEGER_UNDERFLOW - } - - /** - * @dev Multiplies two numbers, returns an error on overflow. - */ - function mulUInt(uint a, uint b) internal pure returns (MathError, uint) { - if (a == 0) { - return (MathError.NO_ERROR, 0); - } - - uint c = a * b; - - if (c / a != b) { - return (MathError.INTEGER_OVERFLOW, 0); - } else { - return (MathError.NO_ERROR, c); - } - } - - /** - * @dev Integer division of two numbers, truncating the quotient. - */ - function divUInt(uint a, uint b) internal pure returns (MathError, uint) { - if (b == 0) { - return (MathError.DIVISION_BY_ZERO, 0); - } - - return (MathError.NO_ERROR, a / b); - } - - /** - * @dev Subtracts two numbers, returns an error on overflow (i.e. if subtrahend is greater than minuend). - */ - function subUInt(uint a, uint b) internal pure returns (MathError, uint) { - if (b <= a) { - return (MathError.NO_ERROR, a - b); - } else { - return (MathError.INTEGER_UNDERFLOW, 0); - } - } - - /** - * @dev Adds two numbers, returns an error on overflow. - */ - function addUInt(uint a, uint b) internal pure returns (MathError, uint) { - uint c = a + b; - - if (c >= a) { - return (MathError.NO_ERROR, c); - } else { - return (MathError.INTEGER_OVERFLOW, 0); - } - } - - /** - * @dev add a and b and then subtract c - */ - function addThenSubUInt(uint a, uint b, uint c) internal pure returns (MathError, uint) { - (MathError err0, uint sum) = addUInt(a, b); - - if (err0 != MathError.NO_ERROR) { - return (err0, 0); - } - - return subUInt(sum, c); - } -} - - -// Dependency file: contracts/ExponentialNoError.sol - -// pragma solidity 0.8.6; - -/** - * @title Exponential module for storing fixed-precision decimals - * @author tropykus - * @notice Exp is a struct which stores decimals with a fixed precision of 18 decimal places. - * Thus, if we wanted to store the 5.1, mantissa would store 5.1e18. That is: - * `Exp({mantissa: 5100000000000000000})`. - */ -contract ExponentialNoError { - uint constant expScale = 1e18; - uint constant doubleScale = 1e36; - uint constant halfExpScale = expScale/2; - uint constant mantissaOne = expScale; - - struct Exp { - uint mantissa; - } - - struct Double { - uint mantissa; - } - - /** - * @dev Truncates the given exp to a whole number value. - * For example, truncate(Exp{mantissa: 15 * expScale}) = 15 - */ - function truncate(Exp memory exp) pure internal returns (uint) { - // Note: We are not using careful math here as we're performing a division that cannot fail - return exp.mantissa / expScale; - } - - /** - * @dev Multiply an Exp by a scalar, then truncate to return an unsigned integer. - */ - function mul_ScalarTruncate(Exp memory a, uint scalar) pure internal returns (uint) { - Exp memory product = mul_(a, scalar); - return truncate(product); - } - - /** - * @dev Multiply an Exp by a scalar, truncate, then add an to an unsigned integer, returning an unsigned integer. - */ - function mul_ScalarTruncateAddUInt(Exp memory a, uint scalar, uint addend) pure internal returns (uint) { - Exp memory product = mul_(a, scalar); - return add_(truncate(product), addend); - } - - /** - * @dev Checks if first Exp is less than second Exp. - */ - function lessThanExp(Exp memory left, Exp memory right) pure internal returns (bool) { - return left.mantissa < right.mantissa; - } - - /** - * @dev Checks if left Exp <= right Exp. - */ - function lessThanOrEqualExp(Exp memory left, Exp memory right) pure internal returns (bool) { - return left.mantissa <= right.mantissa; - } - - /** - * @dev Checks if left Exp > right Exp. - */ - function greaterThanExp(Exp memory left, Exp memory right) pure internal returns (bool) { - return left.mantissa > right.mantissa; - } - - /** - * @dev returns true if Exp is exactly zero - */ - function isZeroExp(Exp memory value) pure internal returns (bool) { - return value.mantissa == 0; - } - - function safe224(uint n, string memory errorMessage) pure internal returns (uint224) { - require(n < 2**224, errorMessage); - return uint224(n); - } - - function safe32(uint n, string memory errorMessage) pure internal returns (uint32) { - require(n < 2**32, errorMessage); - return uint32(n); - } - - function add_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { - return Exp({mantissa: add_(a.mantissa, b.mantissa)}); - } - - function add_(Double memory a, Double memory b) pure internal returns (Double memory) { - return Double({mantissa: add_(a.mantissa, b.mantissa)}); - } - - function add_(uint a, uint b) pure internal returns (uint) { - return add_(a, b, "addition overflow"); - } - - function add_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { - uint c = a + b; - require(c >= a, errorMessage); - return c; - } - - function sub_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { - return Exp({mantissa: sub_(a.mantissa, b.mantissa)}); - } - - function sub_(Double memory a, Double memory b) pure internal returns (Double memory) { - return Double({mantissa: sub_(a.mantissa, b.mantissa)}); - } - - function sub_(uint a, uint b) pure internal returns (uint) { - return sub_(a, b, "subtraction underflow"); - } - - function sub_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { - require(b <= a, errorMessage); - return a - b; - } - - function mul_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { - return Exp({mantissa: mul_(a.mantissa, b.mantissa) / expScale}); - } - - function mul_(Exp memory a, uint b) pure internal returns (Exp memory) { - return Exp({mantissa: mul_(a.mantissa, b)}); - } - - function mul_(uint a, Exp memory b) pure internal returns (uint) { - return mul_(a, b.mantissa) / expScale; - } - - function mul_(Double memory a, Double memory b) pure internal returns (Double memory) { - return Double({mantissa: mul_(a.mantissa, b.mantissa) / doubleScale}); - } - - function mul_(Double memory a, uint b) pure internal returns (Double memory) { - return Double({mantissa: mul_(a.mantissa, b)}); - } - - function mul_(uint a, Double memory b) pure internal returns (uint) { - return mul_(a, b.mantissa) / doubleScale; - } - - function mul_(uint a, uint b) pure internal returns (uint) { - return mul_(a, b, "multiplication overflow"); - } - - function mul_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { - if (a == 0 || b == 0) { - return 0; - } - uint c = a * b; - require(c / a == b, errorMessage); - return c; - } - - function div_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { - return Exp({mantissa: div_(mul_(a.mantissa, expScale), b.mantissa)}); - } - - function div_(Exp memory a, uint b) pure internal returns (Exp memory) { - return Exp({mantissa: div_(a.mantissa, b)}); - } - - function div_(uint a, Exp memory b) pure internal returns (uint) { - return div_(mul_(a, expScale), b.mantissa); - } - - function div_(Double memory a, Double memory b) pure internal returns (Double memory) { - return Double({mantissa: div_(mul_(a.mantissa, doubleScale), b.mantissa)}); - } - - function div_(Double memory a, uint b) pure internal returns (Double memory) { - return Double({mantissa: div_(a.mantissa, b)}); - } - - function div_(uint a, Double memory b) pure internal returns (uint) { - return div_(mul_(a, doubleScale), b.mantissa); - } - - function div_(uint a, uint b) pure internal returns (uint) { - return div_(a, b, "divide by zero"); - } - - function div_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { - require(b > 0, errorMessage); - return a / b; - } - - function fraction(uint a, uint b) pure internal returns (Double memory) { - return Double({mantissa: div_(mul_(a, doubleScale), b)}); - } -} - - -// Dependency file: contracts/Exponential.sol - -// pragma solidity 0.8.6; - -// import "contracts/CarefulMath.sol"; -// import "contracts/ExponentialNoError.sol"; - -/** - * @title Exponential module for storing fixed-precision decimals - * @author tropykus - * @dev Legacy contract for compatibility reasons with existing contracts that still use MathError - * @notice Exp is a struct which stores decimals with a fixed precision of 18 decimal places. - * Thus, if we wanted to store the 5.1, mantissa would store 5.1e18. That is: - * `Exp({mantissa: 5100000000000000000})`. - */ -contract Exponential is CarefulMath, ExponentialNoError { - /** - * @dev Creates an exponential from numerator and denominator values. - * Note: Returns an error if (`num` * 10e18) > MAX_INT, - * or if `denom` is zero. - */ - function getExp(uint num, uint denom) internal pure returns (MathError, Exp memory) { - (MathError err0, uint scaledNumerator) = mulUInt(num, expScale); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - - (MathError err1, uint rational) = divUInt(scaledNumerator, denom); - if (err1 != MathError.NO_ERROR) { - return (err1, Exp({mantissa: 0})); - } - - return (MathError.NO_ERROR, Exp({mantissa: rational})); - } - - /** - * @dev Adds two exponentials, returning a new exponential. - */ - function addExp(Exp memory a, Exp memory b) internal pure returns (MathError, Exp memory) { - (MathError error, uint result) = addUInt(a.mantissa, b.mantissa); - - return (error, Exp({mantissa: result})); - } - - /** - * @dev Subtracts two exponentials, returning a new exponential. - */ - function subExp(Exp memory a, Exp memory b) internal pure returns (MathError, Exp memory) { - (MathError error, uint result) = subUInt(a.mantissa, b.mantissa); - - return (error, Exp({mantissa: result})); - } - - /** - * @dev Multiply an Exp by a scalar, returning a new Exp. - */ - function mulScalar(Exp memory a, uint scalar) internal pure returns (MathError, Exp memory) { - (MathError err0, uint scaledMantissa) = mulUInt(a.mantissa, scalar); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - - return (MathError.NO_ERROR, Exp({mantissa: scaledMantissa})); - } - - /** - * @dev Multiply an Exp by a scalar, then truncate to return an unsigned integer. - */ - function mulScalarTruncate(Exp memory a, uint scalar) internal pure returns (MathError, uint) { - (MathError err, Exp memory product) = mulScalar(a, scalar); - if (err != MathError.NO_ERROR) { - return (err, 0); - } - - return (MathError.NO_ERROR, truncate(product)); - } - - /** - * @dev Multiply an Exp by a scalar, truncate, then add an to an unsigned integer, returning an unsigned integer. - */ - function mulScalarTruncateAddUInt(Exp memory a, uint scalar, uint addend) internal pure returns (MathError, uint) { - (MathError err, Exp memory product) = mulScalar(a, scalar); - if (err != MathError.NO_ERROR) { - return (err, 0); - } - - return addUInt(truncate(product), addend); - } - - /** - * @dev Divide an Exp by a scalar, returning a new Exp. - */ - function divScalar(Exp memory a, uint scalar) internal pure returns (MathError, Exp memory) { - (MathError err0, uint descaledMantissa) = divUInt(a.mantissa, scalar); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - - return (MathError.NO_ERROR, Exp({mantissa: descaledMantissa})); - } - - /** - * @dev Divide a scalar by an Exp, returning a new Exp. - */ - function divScalarByExp(uint scalar, Exp memory divisor) internal pure returns (MathError, Exp memory) { - /* - We are doing this as: - getExp(mulUInt(expScale, scalar), divisor.mantissa) - - How it works: - Exp = a / b; - Scalar = s; - `s / (a / b)` = `b * s / a` and since for an Exp `a = mantissa, b = expScale` - */ - (MathError err0, uint numerator) = mulUInt(expScale, scalar); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - return getExp(numerator, divisor.mantissa); - } - - /** - * @dev Divide a scalar by an Exp, then truncate to return an unsigned integer. - */ - function divScalarByExpTruncate(uint scalar, Exp memory divisor) internal pure returns (MathError, uint) { - (MathError err, Exp memory fraction) = divScalarByExp(scalar, divisor); - if (err != MathError.NO_ERROR) { - return (err, 0); - } - - return (MathError.NO_ERROR, truncate(fraction)); - } - - /** - * @dev Multiplies two exponentials, returning a new exponential. - */ - function mulExp(Exp memory a, Exp memory b) internal pure returns (MathError, Exp memory) { - - (MathError err0, uint doubleScaledProduct) = mulUInt(a.mantissa, b.mantissa); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - - // We add half the scale before dividing so that we get rounding instead of truncation. - // See "Listing 6" and text above it at https://accu.org/index.php/journals/1717 - // Without this change, a result like 6.6...e-19 will be truncated to 0 instead of being rounded to 1e-18. - (MathError err1, uint doubleScaledProductWithHalfScale) = addUInt(halfExpScale, doubleScaledProduct); - if (err1 != MathError.NO_ERROR) { - return (err1, Exp({mantissa: 0})); - } - - (MathError err2, uint product) = divUInt(doubleScaledProductWithHalfScale, expScale); - // The only error `div` can return is MathError.DIVISION_BY_ZERO but we control `expScale` and it is not zero. - assert(err2 == MathError.NO_ERROR); - - return (MathError.NO_ERROR, Exp({mantissa: product})); - } - - /** - * @dev Multiplies two exponentials given their mantissas, returning a new exponential. - */ - function mulExp(uint a, uint b) internal pure returns (MathError, Exp memory) { - return mulExp(Exp({mantissa: a}), Exp({mantissa: b})); - } - - /** - * @dev Multiplies three exponentials, returning a new exponential. - */ - function mulExp3(Exp memory a, Exp memory b, Exp memory c) internal pure returns (MathError, Exp memory) { - (MathError err, Exp memory ab) = mulExp(a, b); - if (err != MathError.NO_ERROR) { - return (err, ab); - } - return mulExp(ab, c); - } - - /** - * @dev Divides two exponentials, returning a new exponential. - * (a/scale) / (b/scale) = (a/scale) * (scale/b) = a/b, - * which we can scale as an Exp by calling getExp(a.mantissa, b.mantissa) - */ - function divExp(Exp memory a, Exp memory b) internal pure returns (MathError, Exp memory) { - return getExp(a.mantissa, b.mantissa); - } -} - - -// Dependency file: contracts/SafeMath.sol - -// pragma solidity 0.8.6; - -// From https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/math/Math.sol -// Subject to the MIT license. - -/** - * @dev Wrappers over Solidity's arithmetic operations with added overflow - * checks. - * - * Arithmetic operations in Solidity wrap on overflow. This can easily result - * in bugs, because programmers usually assume that an overflow raises an - * error, which is the standard behavior in high level programming languages. - * `SafeMath` restores this intuition by reverting the transaction when an - * operation overflows. - * - * Using this library instead of the unchecked operations eliminates an entire - * class of bugs, so it's recommended to use it always. - */ -library SafeMath { - /** - * @dev Returns the addition of two unsigned integers, reverting on overflow. - * - * Counterpart to Solidity's `+` operator. - * - * Requirements: - * - Addition cannot overflow. - */ - function add(uint256 a, uint256 b) internal pure returns (uint256) { - uint256 c = a + b; - require(c >= a, "SafeMath: addition overflow"); - - return c; - } - - /** - * @dev Returns the addition of two unsigned integers, reverting with custom message on overflow. - * - * Counterpart to Solidity's `+` operator. - * - * Requirements: - * - Addition cannot overflow. - */ - function add(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - uint256 c = a + b; - require(c >= a, errorMessage); - - return c; - } - - /** - * @dev Returns the subtraction of two unsigned integers, reverting on underflow (when the result is negative). - * - * Counterpart to Solidity's `-` operator. - * - * Requirements: - * - Subtraction cannot underflow. - */ - function sub(uint256 a, uint256 b) internal pure returns (uint256) { - return sub(a, b, "SafeMath: subtraction underflow"); - } - - /** - * @dev Returns the subtraction of two unsigned integers, reverting with custom message on underflow (when the result is negative). - * - * Counterpart to Solidity's `-` operator. - * - * Requirements: - * - Subtraction cannot underflow. - */ - function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - require(b <= a, errorMessage); - uint256 c = a - b; - - return c; - } - - /** - * @dev Returns the multiplication of two unsigned integers, reverting on overflow. - * - * Counterpart to Solidity's `*` operator. - * - * Requirements: - * - Multiplication cannot overflow. - */ - function mul(uint256 a, uint256 b) internal pure returns (uint256) { - // Gas optimization: this is cheaper than requiring 'a' not being zero, but the - // benefit is lost if 'b' is also tested. - // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 - if (a == 0) { - return 0; - } - - uint256 c = a * b; - require(c / a == b, "SafeMath: multiplication overflow"); - - return c; - } - - /** - * @dev Returns the multiplication of two unsigned integers, reverting on overflow. - * - * Counterpart to Solidity's `*` operator. - * - * Requirements: - * - Multiplication cannot overflow. - */ - function mul(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - // Gas optimization: this is cheaper than requiring 'a' not being zero, but the - // benefit is lost if 'b' is also tested. - // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 - if (a == 0) { - return 0; - } - - uint256 c = a * b; - require(c / a == b, errorMessage); - - return c; - } - - /** - * @dev Returns the integer division of two unsigned integers. - * Reverts on division by zero. The result is rounded towards zero. - * - * Counterpart to Solidity's `/` operator. Note: this function uses a - * `revert` opcode (which leaves remaining gas untouched) while Solidity - * uses an invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function div(uint256 a, uint256 b) internal pure returns (uint256) { - return div(a, b, "SafeMath: division by zero"); - } - - /** - * @dev Returns the integer division of two unsigned integers. - * Reverts with custom message on division by zero. The result is rounded towards zero. - * - * Counterpart to Solidity's `/` operator. Note: this function uses a - * `revert` opcode (which leaves remaining gas untouched) while Solidity - * uses an invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - // Solidity only automatically asserts when dividing by 0 - require(b > 0, errorMessage); - uint256 c = a / b; - // assert(a == b * c + a % b); // There is no case in which this doesn't hold - - return c; - } - - /** - * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), - * Reverts when dividing by zero. - * - * Counterpart to Solidity's `%` operator. This function uses a `revert` - * opcode (which leaves remaining gas untouched) while Solidity uses an - * invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function mod(uint256 a, uint256 b) internal pure returns (uint256) { - return mod(a, b, "SafeMath: modulo by zero"); - } - - /** - * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), - * Reverts with custom message when dividing by zero. - * - * Counterpart to Solidity's `%` operator. This function uses a `revert` - * opcode (which leaves remaining gas untouched) while Solidity uses an - * invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - require(b != 0, errorMessage); - return a % b; - } -} - - -// Dependency file: contracts/InterestRateModel.sol - -// pragma solidity 0.8.6; - -// import "contracts/Exponential.sol"; -// import "contracts/SafeMath.sol"; - -/** - * @title tropykus InterestRateModel Interface - * @author tropykus - */ -abstract contract InterestRateModel is Exponential { - using SafeMath for uint256; - - /// @notice Indicator that this is an InterestRateModel contract (for inspection) - bool public constant isInterestRateModel = true; - bool public isTropykusInterestRateModel; - - /** - * @notice The approximate number of blocks per year that is assumed by the interest rate model - */ - uint256 public constant blocksPerYear = 1051200; - - /** - * @notice Calculates the utilization rate of the market: `borrows / (cash + borrows - reserves)` - * @param cash The amount of cash in the market - * @param borrows The amount of borrows in the market - * @param reserves The amount of reserves in the market (currently unused) - * @return The utilization rate as a mantissa between [0, 1e18] - */ - function utilizationRate( - uint256 cash, - uint256 borrows, - uint256 reserves - ) public pure virtual returns (uint256) { - // Utilization rate is 0 when there are no borrows - if (borrows == 0) { - return 0; - } - - return borrows.mul(1e18).div(cash.add(borrows).sub(reserves)); - } - - /** - * @notice Calculates the current borrow interest rate per block - * @param cash The total amount of cash the market has - * @param borrows The total amount of borrows the market has outstanding - * @param reserves The total amnount of reserves the market has - * @return The borrow rate per block (as a percentage, and scaled by 1e18) - */ - function getBorrowRate( - uint256 cash, - uint256 borrows, - uint256 reserves - ) external view virtual returns (uint256); - - /** - * @notice Calculates the current supply interest rate per block - * @param cash The total amount of cash the market has - * @param borrows The total amount of borrows the market has outstanding - * @param reserves The total amnount of reserves the market has - * @param reserveFactorMantissa The current reserve factor the market has - * @return The supply rate per block (as a percentage, and scaled by 1e18) - */ - function getSupplyRate( - uint256 cash, - uint256 borrows, - uint256 reserves, - uint256 reserveFactorMantissa - ) external view virtual returns (uint256); - - function getExchangeRate( - uint256 _totalCash, - uint256 _totalBorrows, - uint256 _totalReserves, - uint256 _totalSupply - ) public pure returns (MathError, uint256) { - /* - * exchangeRate = (totalCash + totalBorrows - totalReserves) / totalSupply - */ - Exp memory exchangeRate; - MathError mathErr; - uint256 cashPlusBorrowsMinusReserves; - (mathErr, cashPlusBorrowsMinusReserves) = addThenSubUInt( - _totalCash, - _totalBorrows, - _totalReserves - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - (mathErr, exchangeRate) = getExp( - cashPlusBorrowsMinusReserves, - _totalSupply - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - - return (MathError.NO_ERROR, exchangeRate.mantissa); - } - - function isAboveOptimal( - uint256 cash, - uint256 borrows, - uint256 reserves - ) public view virtual returns (bool) { - cash; - borrows; - reserves; - return false; - } -} - - -// Root file: contracts/BaseJumpRateModelV2.sol - -pragma solidity 0.8.6; - -// import "contracts/InterestRateModel.sol"; -// import "contracts/SafeMath.sol"; - -/** - * @title Logic for tropykus JumpRateModel Contract V2. - * @author tropykus - * @notice Version 2 modifies Version 1 by enabling updateable parameters. - */ -contract BaseJumpRateModelV2 is InterestRateModel { - using SafeMath for uint256; - - event NewInterestParams( - uint256 baseRatePerBlock, - uint256 multiplierPerBlock, - uint256 jumpMultiplierPerBlock, - uint256 kink - ); - event NewAdmin(address indexed newAdmin); - event NewPendingAdmin(address indexed newPendingAdmin); - - /** - * @notice The address of the owner, i.e. the Timelock contract, which can update parameters directly - */ - address public owner; - - /** - * @notice The address of the owner, i.e. the Timelock contract, which can update parameters directly - */ - address public pendingAdmin; - - /** - * @notice The multiplier of utilization rate that gives the slope of the interest rate - */ - uint256 public multiplierPerBlock; - - /** - * @notice The base interest rate which is the y-intercept when utilization rate is 0 - */ - uint256 public baseRatePerBlock; - - /** - * @notice The multiplierPerBlock after hitting a specified utilization point - */ - uint256 public jumpMultiplierPerBlock; - - /** - * @notice The utilization point at which the jump multiplier is applied - */ - uint256 public kink; - - /** - * @notice Construct an interest rate model - * @param baseRatePerYear The approximate target base APR, as a mantissa (scaled by 1e18) - * @param multiplierPerYear The rate of increase in interest rate wrt utilization (scaled by 1e18) - * @param jumpMultiplierPerYear The multiplierPerBlock after hitting a specified utilization point - * @param kink_ The utilization point at which the jump multiplier is applied - * @param owner_ The address of the owner, i.e. the Timelock contract (which has the ability to update parameters directly) - */ - constructor( - uint256 baseRatePerYear, - uint256 multiplierPerYear, - uint256 jumpMultiplierPerYear, - uint256 kink_, - address owner_ - ) { - owner = owner_; - emit NewAdmin(owner); - updateJumpRateModelInternal( - baseRatePerYear, - multiplierPerYear, - jumpMultiplierPerYear, - kink_ - ); - } - - /** - * @notice Update the parameters of the interest rate model (only callable by owner, i.e. Timelock) - * @param baseRatePerYear The approximate target base APR, as a mantissa (scaled by 1e18) - * @param multiplierPerYear The rate of increase in interest rate wrt utilization (scaled by 1e18) - * @param jumpMultiplierPerYear The multiplierPerBlock after hitting a specified utilization point - * @param kink_ The utilization point at which the jump multiplier is applied - */ - function updateJumpRateModel( - uint256 baseRatePerYear, - uint256 multiplierPerYear, - uint256 jumpMultiplierPerYear, - uint256 kink_ - ) external { - require(msg.sender == owner, "only the owner may call this function."); - - updateJumpRateModelInternal( - baseRatePerYear, - multiplierPerYear, - jumpMultiplierPerYear, - kink_ - ); - } - - /** - * @notice Calculates the current borrow rate per block - * @param cash The amount of cash in the market - * @param borrows The amount of borrows in the market - * @param reserves The amount of reserves in the market - * @return The borrow rate percentage per block as a mantissa (scaled by 1e18) - */ - function getBorrowRate( - uint256 cash, - uint256 borrows, - uint256 reserves - ) external view override returns (uint256) { - return getBorrowRateInternal(cash, borrows, reserves); - } - - /** - * @notice Calculates the current borrow rate per block, with the error code expected by the market - * @param cash The amount of cash in the market - * @param borrows The amount of borrows in the market - * @param reserves The amount of reserves in the market - * @return The borrow rate percentage per block as a mantissa (scaled by 1e18) - */ - function getBorrowRateInternal( - uint256 cash, - uint256 borrows, - uint256 reserves - ) internal view returns (uint256) { - uint256 util = utilizationRate(cash, borrows, reserves); - - if (util <= kink) { - return util.mul(multiplierPerBlock).div(1e18).add(baseRatePerBlock); - } else { - uint256 normalRate = kink.mul(multiplierPerBlock).div(1e18).add( - baseRatePerBlock - ); - uint256 excessUtil = util.sub(kink); - return - excessUtil.mul(jumpMultiplierPerBlock).div(1e18).add( - normalRate - ); - } - } - - /** - * @notice Calculates the current supply rate per block - * @param cash The amount of cash in the market - * @param borrows The amount of borrows in the market - * @param reserves The amount of reserves in the market - * @param reserveFactorMantissa The current reserve factor for the market - * @return The supply rate percentage per block as a mantissa (scaled by 1e18) - */ - function getSupplyRate( - uint256 cash, - uint256 borrows, - uint256 reserves, - uint256 reserveFactorMantissa - ) public view override returns (uint256) { - uint256 oneMinusReserveFactor = uint256(1e18).sub( - reserveFactorMantissa - ); - uint256 borrowRate = getBorrowRateInternal(cash, borrows, reserves); - uint256 rateToPool = borrowRate.mul(oneMinusReserveFactor).div(1e18); - return - utilizationRate(cash, borrows, reserves).mul(rateToPool).div(1e18); - } - - /** - * @notice Internal function to update the parameters of the interest rate model - * @param baseRatePerYear The approximate target base APR, as a mantissa (scaled by 1e18) - * @param multiplierPerYear The rate of increase in interest rate wrt utilization (scaled by 1e18) - * @param jumpMultiplierPerYear The multiplierPerBlock after hitting a specified utilization point - * @param kink_ The utilization point at which the jump multiplier is applied - */ - function updateJumpRateModelInternal( - uint256 baseRatePerYear, - uint256 multiplierPerYear, - uint256 jumpMultiplierPerYear, - uint256 kink_ - ) internal { - baseRatePerBlock = baseRatePerYear.div(blocksPerYear); - multiplierPerBlock = (multiplierPerYear.mul(1e18)).div( - blocksPerYear.mul(kink_) - ); - jumpMultiplierPerBlock = jumpMultiplierPerYear.div(blocksPerYear); - kink = kink_; - - emit NewInterestParams( - baseRatePerBlock, - multiplierPerBlock, - jumpMultiplierPerBlock, - kink - ); - } - - function acceptAdmin() public { - require( - msg.sender == pendingAdmin, - "BaseJumpRateModelV2::acceptAdmin: Call must come from pendingAdmin." - ); - owner = msg.sender; - pendingAdmin = address(0); - - emit NewAdmin(owner); - } - - function setPendingAdmin(address pendingAdmin_) public { - require( - msg.sender == owner, - "BaseJumpRateModelV2::setPendingAdmin: Call must come from owner." - ); - pendingAdmin = pendingAdmin_; - - emit NewPendingAdmin(pendingAdmin); - } -} diff --git a/flatten/CCompLikeDelegate.sol b/flatten/CCompLikeDelegate.sol deleted file mode 100644 index 252b3f1..0000000 --- a/flatten/CCompLikeDelegate.sol +++ /dev/null @@ -1,4246 +0,0 @@ -// Dependency file: contracts/ComptrollerInterface.sol - -// SPDX-License-Identifier: UNLICENSED -// pragma solidity 0.8.6; - -abstract contract ComptrollerInterface { - /// @notice Indicator that this is a Comptroller contract (for inspection) - bool public constant isComptroller = true; - - /*** Assets You Are In ***/ - - function enterMarkets(address[] calldata cTokens) - external - virtual - returns (uint256[] memory); - - function exitMarket(address cToken) external virtual returns (uint256); - - /*** Policy Hooks ***/ - - function mintAllowed( - address cToken, - address minter, - uint256 mintAmount - ) external virtual returns (uint256); - - function mintVerify( - address cToken, - address minter, - uint256 mintAmount, - uint256 mintTokens - ) external virtual; - - function redeemAllowed( - address cToken, - address redeemer, - uint256 redeemTokens - ) external virtual returns (uint256); - - function redeemVerify( - address cToken, - address redeemer, - uint256 redeemAmount, - uint256 redeemTokens - ) external virtual; - - function borrowAllowed( - address cToken, - address borrower, - uint256 borrowAmount - ) external virtual returns (uint256); - - function borrowVerify( - address cToken, - address borrower, - uint256 borrowAmount - ) external virtual; - - function repayBorrowAllowed( - address cToken, - address payer, - address borrower, - uint256 repayAmount - ) external virtual returns (uint256); - - function repayBorrowVerify( - address cToken, - address payer, - address borrower, - uint256 repayAmount, - uint256 borrowerIndex - ) external virtual; - - function liquidateBorrowAllowed( - address cTokenBorrowed, - address cTokenCollateral, - address liquidator, - address borrower, - uint256 repayAmount - ) external virtual returns (uint256); - - function liquidateBorrowVerify( - address cTokenBorrowed, - address cTokenCollateral, - address liquidator, - address borrower, - uint256 repayAmount, - uint256 seizeTokens - ) external virtual; - - function seizeAllowed( - address cTokenCollateral, - address cTokenBorrowed, - address liquidator, - address borrower, - uint256 seizeTokens - ) external virtual returns (uint256); - - function seizeVerify( - address cTokenCollateral, - address cTokenBorrowed, - address liquidator, - address borrower, - uint256 seizeTokens - ) external virtual; - - function transferAllowed( - address cToken, - address src, - address dst, - uint256 transferTokens - ) external virtual returns (uint256); - - function transferVerify( - address cToken, - address src, - address dst, - uint256 transferTokens - ) external virtual; - - /*** Liquidity/Liquidation Calculations ***/ - - function liquidateCalculateSeizeTokens( - address cTokenBorrowed, - address cTokenCollateral, - uint256 repayAmount - ) external view virtual returns (uint256, uint256); -} - - -// Dependency file: contracts/CarefulMath.sol - -// pragma solidity 0.8.6; - -/** - * @title Careful Math - * @author tropykus - * @notice Derived from OpenZeppelin's SafeMath library - * https://github.com/OpenZeppelin/openzeppelin-solidity/blob/master/contracts/math/SafeMath.sol - */ -contract CarefulMath { - - /** - * @dev Possible error codes that we can return - */ - enum MathError { - NO_ERROR, - DIVISION_BY_ZERO, - INTEGER_OVERFLOW, - INTEGER_UNDERFLOW - } - - /** - * @dev Multiplies two numbers, returns an error on overflow. - */ - function mulUInt(uint a, uint b) internal pure returns (MathError, uint) { - if (a == 0) { - return (MathError.NO_ERROR, 0); - } - - uint c = a * b; - - if (c / a != b) { - return (MathError.INTEGER_OVERFLOW, 0); - } else { - return (MathError.NO_ERROR, c); - } - } - - /** - * @dev Integer division of two numbers, truncating the quotient. - */ - function divUInt(uint a, uint b) internal pure returns (MathError, uint) { - if (b == 0) { - return (MathError.DIVISION_BY_ZERO, 0); - } - - return (MathError.NO_ERROR, a / b); - } - - /** - * @dev Subtracts two numbers, returns an error on overflow (i.e. if subtrahend is greater than minuend). - */ - function subUInt(uint a, uint b) internal pure returns (MathError, uint) { - if (b <= a) { - return (MathError.NO_ERROR, a - b); - } else { - return (MathError.INTEGER_UNDERFLOW, 0); - } - } - - /** - * @dev Adds two numbers, returns an error on overflow. - */ - function addUInt(uint a, uint b) internal pure returns (MathError, uint) { - uint c = a + b; - - if (c >= a) { - return (MathError.NO_ERROR, c); - } else { - return (MathError.INTEGER_OVERFLOW, 0); - } - } - - /** - * @dev add a and b and then subtract c - */ - function addThenSubUInt(uint a, uint b, uint c) internal pure returns (MathError, uint) { - (MathError err0, uint sum) = addUInt(a, b); - - if (err0 != MathError.NO_ERROR) { - return (err0, 0); - } - - return subUInt(sum, c); - } -} - - -// Dependency file: contracts/ExponentialNoError.sol - -// pragma solidity 0.8.6; - -/** - * @title Exponential module for storing fixed-precision decimals - * @author tropykus - * @notice Exp is a struct which stores decimals with a fixed precision of 18 decimal places. - * Thus, if we wanted to store the 5.1, mantissa would store 5.1e18. That is: - * `Exp({mantissa: 5100000000000000000})`. - */ -contract ExponentialNoError { - uint constant expScale = 1e18; - uint constant doubleScale = 1e36; - uint constant halfExpScale = expScale/2; - uint constant mantissaOne = expScale; - - struct Exp { - uint mantissa; - } - - struct Double { - uint mantissa; - } - - /** - * @dev Truncates the given exp to a whole number value. - * For example, truncate(Exp{mantissa: 15 * expScale}) = 15 - */ - function truncate(Exp memory exp) pure internal returns (uint) { - // Note: We are not using careful math here as we're performing a division that cannot fail - return exp.mantissa / expScale; - } - - /** - * @dev Multiply an Exp by a scalar, then truncate to return an unsigned integer. - */ - function mul_ScalarTruncate(Exp memory a, uint scalar) pure internal returns (uint) { - Exp memory product = mul_(a, scalar); - return truncate(product); - } - - /** - * @dev Multiply an Exp by a scalar, truncate, then add an to an unsigned integer, returning an unsigned integer. - */ - function mul_ScalarTruncateAddUInt(Exp memory a, uint scalar, uint addend) pure internal returns (uint) { - Exp memory product = mul_(a, scalar); - return add_(truncate(product), addend); - } - - /** - * @dev Checks if first Exp is less than second Exp. - */ - function lessThanExp(Exp memory left, Exp memory right) pure internal returns (bool) { - return left.mantissa < right.mantissa; - } - - /** - * @dev Checks if left Exp <= right Exp. - */ - function lessThanOrEqualExp(Exp memory left, Exp memory right) pure internal returns (bool) { - return left.mantissa <= right.mantissa; - } - - /** - * @dev Checks if left Exp > right Exp. - */ - function greaterThanExp(Exp memory left, Exp memory right) pure internal returns (bool) { - return left.mantissa > right.mantissa; - } - - /** - * @dev returns true if Exp is exactly zero - */ - function isZeroExp(Exp memory value) pure internal returns (bool) { - return value.mantissa == 0; - } - - function safe224(uint n, string memory errorMessage) pure internal returns (uint224) { - require(n < 2**224, errorMessage); - return uint224(n); - } - - function safe32(uint n, string memory errorMessage) pure internal returns (uint32) { - require(n < 2**32, errorMessage); - return uint32(n); - } - - function add_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { - return Exp({mantissa: add_(a.mantissa, b.mantissa)}); - } - - function add_(Double memory a, Double memory b) pure internal returns (Double memory) { - return Double({mantissa: add_(a.mantissa, b.mantissa)}); - } - - function add_(uint a, uint b) pure internal returns (uint) { - return add_(a, b, "addition overflow"); - } - - function add_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { - uint c = a + b; - require(c >= a, errorMessage); - return c; - } - - function sub_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { - return Exp({mantissa: sub_(a.mantissa, b.mantissa)}); - } - - function sub_(Double memory a, Double memory b) pure internal returns (Double memory) { - return Double({mantissa: sub_(a.mantissa, b.mantissa)}); - } - - function sub_(uint a, uint b) pure internal returns (uint) { - return sub_(a, b, "subtraction underflow"); - } - - function sub_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { - require(b <= a, errorMessage); - return a - b; - } - - function mul_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { - return Exp({mantissa: mul_(a.mantissa, b.mantissa) / expScale}); - } - - function mul_(Exp memory a, uint b) pure internal returns (Exp memory) { - return Exp({mantissa: mul_(a.mantissa, b)}); - } - - function mul_(uint a, Exp memory b) pure internal returns (uint) { - return mul_(a, b.mantissa) / expScale; - } - - function mul_(Double memory a, Double memory b) pure internal returns (Double memory) { - return Double({mantissa: mul_(a.mantissa, b.mantissa) / doubleScale}); - } - - function mul_(Double memory a, uint b) pure internal returns (Double memory) { - return Double({mantissa: mul_(a.mantissa, b)}); - } - - function mul_(uint a, Double memory b) pure internal returns (uint) { - return mul_(a, b.mantissa) / doubleScale; - } - - function mul_(uint a, uint b) pure internal returns (uint) { - return mul_(a, b, "multiplication overflow"); - } - - function mul_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { - if (a == 0 || b == 0) { - return 0; - } - uint c = a * b; - require(c / a == b, errorMessage); - return c; - } - - function div_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { - return Exp({mantissa: div_(mul_(a.mantissa, expScale), b.mantissa)}); - } - - function div_(Exp memory a, uint b) pure internal returns (Exp memory) { - return Exp({mantissa: div_(a.mantissa, b)}); - } - - function div_(uint a, Exp memory b) pure internal returns (uint) { - return div_(mul_(a, expScale), b.mantissa); - } - - function div_(Double memory a, Double memory b) pure internal returns (Double memory) { - return Double({mantissa: div_(mul_(a.mantissa, doubleScale), b.mantissa)}); - } - - function div_(Double memory a, uint b) pure internal returns (Double memory) { - return Double({mantissa: div_(a.mantissa, b)}); - } - - function div_(uint a, Double memory b) pure internal returns (uint) { - return div_(mul_(a, doubleScale), b.mantissa); - } - - function div_(uint a, uint b) pure internal returns (uint) { - return div_(a, b, "divide by zero"); - } - - function div_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { - require(b > 0, errorMessage); - return a / b; - } - - function fraction(uint a, uint b) pure internal returns (Double memory) { - return Double({mantissa: div_(mul_(a, doubleScale), b)}); - } -} - - -// Dependency file: contracts/Exponential.sol - -// pragma solidity 0.8.6; - -// import "contracts/CarefulMath.sol"; -// import "contracts/ExponentialNoError.sol"; - -/** - * @title Exponential module for storing fixed-precision decimals - * @author tropykus - * @dev Legacy contract for compatibility reasons with existing contracts that still use MathError - * @notice Exp is a struct which stores decimals with a fixed precision of 18 decimal places. - * Thus, if we wanted to store the 5.1, mantissa would store 5.1e18. That is: - * `Exp({mantissa: 5100000000000000000})`. - */ -contract Exponential is CarefulMath, ExponentialNoError { - /** - * @dev Creates an exponential from numerator and denominator values. - * Note: Returns an error if (`num` * 10e18) > MAX_INT, - * or if `denom` is zero. - */ - function getExp(uint num, uint denom) internal pure returns (MathError, Exp memory) { - (MathError err0, uint scaledNumerator) = mulUInt(num, expScale); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - - (MathError err1, uint rational) = divUInt(scaledNumerator, denom); - if (err1 != MathError.NO_ERROR) { - return (err1, Exp({mantissa: 0})); - } - - return (MathError.NO_ERROR, Exp({mantissa: rational})); - } - - /** - * @dev Adds two exponentials, returning a new exponential. - */ - function addExp(Exp memory a, Exp memory b) internal pure returns (MathError, Exp memory) { - (MathError error, uint result) = addUInt(a.mantissa, b.mantissa); - - return (error, Exp({mantissa: result})); - } - - /** - * @dev Subtracts two exponentials, returning a new exponential. - */ - function subExp(Exp memory a, Exp memory b) internal pure returns (MathError, Exp memory) { - (MathError error, uint result) = subUInt(a.mantissa, b.mantissa); - - return (error, Exp({mantissa: result})); - } - - /** - * @dev Multiply an Exp by a scalar, returning a new Exp. - */ - function mulScalar(Exp memory a, uint scalar) internal pure returns (MathError, Exp memory) { - (MathError err0, uint scaledMantissa) = mulUInt(a.mantissa, scalar); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - - return (MathError.NO_ERROR, Exp({mantissa: scaledMantissa})); - } - - /** - * @dev Multiply an Exp by a scalar, then truncate to return an unsigned integer. - */ - function mulScalarTruncate(Exp memory a, uint scalar) internal pure returns (MathError, uint) { - (MathError err, Exp memory product) = mulScalar(a, scalar); - if (err != MathError.NO_ERROR) { - return (err, 0); - } - - return (MathError.NO_ERROR, truncate(product)); - } - - /** - * @dev Multiply an Exp by a scalar, truncate, then add an to an unsigned integer, returning an unsigned integer. - */ - function mulScalarTruncateAddUInt(Exp memory a, uint scalar, uint addend) internal pure returns (MathError, uint) { - (MathError err, Exp memory product) = mulScalar(a, scalar); - if (err != MathError.NO_ERROR) { - return (err, 0); - } - - return addUInt(truncate(product), addend); - } - - /** - * @dev Divide an Exp by a scalar, returning a new Exp. - */ - function divScalar(Exp memory a, uint scalar) internal pure returns (MathError, Exp memory) { - (MathError err0, uint descaledMantissa) = divUInt(a.mantissa, scalar); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - - return (MathError.NO_ERROR, Exp({mantissa: descaledMantissa})); - } - - /** - * @dev Divide a scalar by an Exp, returning a new Exp. - */ - function divScalarByExp(uint scalar, Exp memory divisor) internal pure returns (MathError, Exp memory) { - /* - We are doing this as: - getExp(mulUInt(expScale, scalar), divisor.mantissa) - - How it works: - Exp = a / b; - Scalar = s; - `s / (a / b)` = `b * s / a` and since for an Exp `a = mantissa, b = expScale` - */ - (MathError err0, uint numerator) = mulUInt(expScale, scalar); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - return getExp(numerator, divisor.mantissa); - } - - /** - * @dev Divide a scalar by an Exp, then truncate to return an unsigned integer. - */ - function divScalarByExpTruncate(uint scalar, Exp memory divisor) internal pure returns (MathError, uint) { - (MathError err, Exp memory fraction) = divScalarByExp(scalar, divisor); - if (err != MathError.NO_ERROR) { - return (err, 0); - } - - return (MathError.NO_ERROR, truncate(fraction)); - } - - /** - * @dev Multiplies two exponentials, returning a new exponential. - */ - function mulExp(Exp memory a, Exp memory b) internal pure returns (MathError, Exp memory) { - - (MathError err0, uint doubleScaledProduct) = mulUInt(a.mantissa, b.mantissa); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - - // We add half the scale before dividing so that we get rounding instead of truncation. - // See "Listing 6" and text above it at https://accu.org/index.php/journals/1717 - // Without this change, a result like 6.6...e-19 will be truncated to 0 instead of being rounded to 1e-18. - (MathError err1, uint doubleScaledProductWithHalfScale) = addUInt(halfExpScale, doubleScaledProduct); - if (err1 != MathError.NO_ERROR) { - return (err1, Exp({mantissa: 0})); - } - - (MathError err2, uint product) = divUInt(doubleScaledProductWithHalfScale, expScale); - // The only error `div` can return is MathError.DIVISION_BY_ZERO but we control `expScale` and it is not zero. - assert(err2 == MathError.NO_ERROR); - - return (MathError.NO_ERROR, Exp({mantissa: product})); - } - - /** - * @dev Multiplies two exponentials given their mantissas, returning a new exponential. - */ - function mulExp(uint a, uint b) internal pure returns (MathError, Exp memory) { - return mulExp(Exp({mantissa: a}), Exp({mantissa: b})); - } - - /** - * @dev Multiplies three exponentials, returning a new exponential. - */ - function mulExp3(Exp memory a, Exp memory b, Exp memory c) internal pure returns (MathError, Exp memory) { - (MathError err, Exp memory ab) = mulExp(a, b); - if (err != MathError.NO_ERROR) { - return (err, ab); - } - return mulExp(ab, c); - } - - /** - * @dev Divides two exponentials, returning a new exponential. - * (a/scale) / (b/scale) = (a/scale) * (scale/b) = a/b, - * which we can scale as an Exp by calling getExp(a.mantissa, b.mantissa) - */ - function divExp(Exp memory a, Exp memory b) internal pure returns (MathError, Exp memory) { - return getExp(a.mantissa, b.mantissa); - } -} - - -// Dependency file: contracts/SafeMath.sol - -// pragma solidity 0.8.6; - -// From https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/math/Math.sol -// Subject to the MIT license. - -/** - * @dev Wrappers over Solidity's arithmetic operations with added overflow - * checks. - * - * Arithmetic operations in Solidity wrap on overflow. This can easily result - * in bugs, because programmers usually assume that an overflow raises an - * error, which is the standard behavior in high level programming languages. - * `SafeMath` restores this intuition by reverting the transaction when an - * operation overflows. - * - * Using this library instead of the unchecked operations eliminates an entire - * class of bugs, so it's recommended to use it always. - */ -library SafeMath { - /** - * @dev Returns the addition of two unsigned integers, reverting on overflow. - * - * Counterpart to Solidity's `+` operator. - * - * Requirements: - * - Addition cannot overflow. - */ - function add(uint256 a, uint256 b) internal pure returns (uint256) { - uint256 c = a + b; - require(c >= a, "SafeMath: addition overflow"); - - return c; - } - - /** - * @dev Returns the addition of two unsigned integers, reverting with custom message on overflow. - * - * Counterpart to Solidity's `+` operator. - * - * Requirements: - * - Addition cannot overflow. - */ - function add(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - uint256 c = a + b; - require(c >= a, errorMessage); - - return c; - } - - /** - * @dev Returns the subtraction of two unsigned integers, reverting on underflow (when the result is negative). - * - * Counterpart to Solidity's `-` operator. - * - * Requirements: - * - Subtraction cannot underflow. - */ - function sub(uint256 a, uint256 b) internal pure returns (uint256) { - return sub(a, b, "SafeMath: subtraction underflow"); - } - - /** - * @dev Returns the subtraction of two unsigned integers, reverting with custom message on underflow (when the result is negative). - * - * Counterpart to Solidity's `-` operator. - * - * Requirements: - * - Subtraction cannot underflow. - */ - function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - require(b <= a, errorMessage); - uint256 c = a - b; - - return c; - } - - /** - * @dev Returns the multiplication of two unsigned integers, reverting on overflow. - * - * Counterpart to Solidity's `*` operator. - * - * Requirements: - * - Multiplication cannot overflow. - */ - function mul(uint256 a, uint256 b) internal pure returns (uint256) { - // Gas optimization: this is cheaper than requiring 'a' not being zero, but the - // benefit is lost if 'b' is also tested. - // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 - if (a == 0) { - return 0; - } - - uint256 c = a * b; - require(c / a == b, "SafeMath: multiplication overflow"); - - return c; - } - - /** - * @dev Returns the multiplication of two unsigned integers, reverting on overflow. - * - * Counterpart to Solidity's `*` operator. - * - * Requirements: - * - Multiplication cannot overflow. - */ - function mul(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - // Gas optimization: this is cheaper than requiring 'a' not being zero, but the - // benefit is lost if 'b' is also tested. - // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 - if (a == 0) { - return 0; - } - - uint256 c = a * b; - require(c / a == b, errorMessage); - - return c; - } - - /** - * @dev Returns the integer division of two unsigned integers. - * Reverts on division by zero. The result is rounded towards zero. - * - * Counterpart to Solidity's `/` operator. Note: this function uses a - * `revert` opcode (which leaves remaining gas untouched) while Solidity - * uses an invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function div(uint256 a, uint256 b) internal pure returns (uint256) { - return div(a, b, "SafeMath: division by zero"); - } - - /** - * @dev Returns the integer division of two unsigned integers. - * Reverts with custom message on division by zero. The result is rounded towards zero. - * - * Counterpart to Solidity's `/` operator. Note: this function uses a - * `revert` opcode (which leaves remaining gas untouched) while Solidity - * uses an invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - // Solidity only automatically asserts when dividing by 0 - require(b > 0, errorMessage); - uint256 c = a / b; - // assert(a == b * c + a % b); // There is no case in which this doesn't hold - - return c; - } - - /** - * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), - * Reverts when dividing by zero. - * - * Counterpart to Solidity's `%` operator. This function uses a `revert` - * opcode (which leaves remaining gas untouched) while Solidity uses an - * invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function mod(uint256 a, uint256 b) internal pure returns (uint256) { - return mod(a, b, "SafeMath: modulo by zero"); - } - - /** - * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), - * Reverts with custom message when dividing by zero. - * - * Counterpart to Solidity's `%` operator. This function uses a `revert` - * opcode (which leaves remaining gas untouched) while Solidity uses an - * invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - require(b != 0, errorMessage); - return a % b; - } -} - - -// Dependency file: contracts/InterestRateModel.sol - -// pragma solidity 0.8.6; - -// import "contracts/Exponential.sol"; -// import "contracts/SafeMath.sol"; - -/** - * @title tropykus InterestRateModel Interface - * @author tropykus - */ -abstract contract InterestRateModel is Exponential { - using SafeMath for uint256; - - /// @notice Indicator that this is an InterestRateModel contract (for inspection) - bool public constant isInterestRateModel = true; - bool public isTropykusInterestRateModel; - - /** - * @notice The approximate number of blocks per year that is assumed by the interest rate model - */ - uint256 public constant blocksPerYear = 1051200; - - /** - * @notice Calculates the utilization rate of the market: `borrows / (cash + borrows - reserves)` - * @param cash The amount of cash in the market - * @param borrows The amount of borrows in the market - * @param reserves The amount of reserves in the market (currently unused) - * @return The utilization rate as a mantissa between [0, 1e18] - */ - function utilizationRate( - uint256 cash, - uint256 borrows, - uint256 reserves - ) public pure virtual returns (uint256) { - // Utilization rate is 0 when there are no borrows - if (borrows == 0) { - return 0; - } - - return borrows.mul(1e18).div(cash.add(borrows).sub(reserves)); - } - - /** - * @notice Calculates the current borrow interest rate per block - * @param cash The total amount of cash the market has - * @param borrows The total amount of borrows the market has outstanding - * @param reserves The total amnount of reserves the market has - * @return The borrow rate per block (as a percentage, and scaled by 1e18) - */ - function getBorrowRate( - uint256 cash, - uint256 borrows, - uint256 reserves - ) external view virtual returns (uint256); - - /** - * @notice Calculates the current supply interest rate per block - * @param cash The total amount of cash the market has - * @param borrows The total amount of borrows the market has outstanding - * @param reserves The total amnount of reserves the market has - * @param reserveFactorMantissa The current reserve factor the market has - * @return The supply rate per block (as a percentage, and scaled by 1e18) - */ - function getSupplyRate( - uint256 cash, - uint256 borrows, - uint256 reserves, - uint256 reserveFactorMantissa - ) external view virtual returns (uint256); - - function getExchangeRate( - uint256 _totalCash, - uint256 _totalBorrows, - uint256 _totalReserves, - uint256 _totalSupply - ) public pure returns (MathError, uint256) { - /* - * exchangeRate = (totalCash + totalBorrows - totalReserves) / totalSupply - */ - Exp memory exchangeRate; - MathError mathErr; - uint256 cashPlusBorrowsMinusReserves; - (mathErr, cashPlusBorrowsMinusReserves) = addThenSubUInt( - _totalCash, - _totalBorrows, - _totalReserves - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - (mathErr, exchangeRate) = getExp( - cashPlusBorrowsMinusReserves, - _totalSupply - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - - return (MathError.NO_ERROR, exchangeRate.mantissa); - } - - function isAboveOptimal( - uint256 cash, - uint256 borrows, - uint256 reserves - ) public view virtual returns (bool) { - cash; - borrows; - reserves; - return false; - } -} - - -// Dependency file: contracts/EIP20NonStandardInterface.sol - -// pragma solidity 0.8.6; - -/** - * @title EIP20NonStandardInterface - * @dev Version of ERC20 with no return values for `transfer` and `transferFrom` - * See https://medium.com/coinmonks/missing-return-value-bug-at-least-130-tokens-affected-d67bf08521ca - */ -interface EIP20NonStandardInterface { - /** - * @notice Get the total number of tokens in circulation - * @return The supply of tokens - */ - function totalSupply() external view returns (uint256); - - /** - * @notice Gets the balance of the specified address - * @param owner The address from which the balance will be retrieved - * @return balance The balance - */ - function balanceOf(address owner) external view returns (uint256 balance); - - /// - /// !!!!!!!!!!!!!! - /// !!! NOTICE !!! `transfer` does not return a value, in violation of the ERC-20 specification - /// !!!!!!!!!!!!!! - /// - - /** - * @notice Transfer `amount` tokens from `msg.sender` to `dst` - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - */ - function transfer(address dst, uint256 amount) external; - - /// - /// !!!!!!!!!!!!!! - /// !!! NOTICE !!! `transferFrom` does not return a value, in violation of the ERC-20 specification - /// !!!!!!!!!!!!!! - /// - - /** - * @notice Transfer `amount` tokens from `src` to `dst` - * @param src The address of the source account - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - */ - function transferFrom( - address src, - address dst, - uint256 amount - ) external; - - /** - * @notice Approve `spender` to transfer up to `amount` from `src` - * @dev This will overwrite the approval amount for `spender` - * and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve) - * @param spender The address of the account which may transfer tokens - * @param amount The number of tokens that are approved - * @return success Whether or not the approval succeeded - */ - function approve(address spender, uint256 amount) - external - returns (bool success); - - /** - * @notice Get the current allowance from `owner` for `spender` - * @param owner The address of the account which owns the tokens to be spent - * @param spender The address of the account which may transfer tokens - * @return remaining The number of tokens allowed to be spent - */ - function allowance(address owner, address spender) - external - view - returns (uint256 remaining); - - event Transfer(address indexed from, address indexed to, uint256 amount); - event Approval( - address indexed owner, - address indexed spender, - uint256 amount - ); -} - - -// Dependency file: contracts/CTokenInterfaces.sol - -// pragma solidity 0.8.6; - -// import "contracts/ComptrollerInterface.sol"; -// import "contracts/InterestRateModel.sol"; -// import "contracts/EIP20NonStandardInterface.sol"; - -contract CTokenStorage { - /** - * @dev Guard variable for re-entrancy checks - */ - bool internal _notEntered; - - /** - * @notice EIP-20 token name for this token - */ - string public name; - - /** - * @notice EIP-20 token symbol for this token - */ - string public symbol; - - /** - * @notice EIP-20 token decimals for this token - */ - uint8 public decimals; - - /** - * @notice Maximum borrow rate that can ever be applied (.0005% / block) - */ - - uint256 internal constant borrowRateMaxMantissa = 0.0005e16; - - /** - * @notice Maximum fraction of interest that can be set aside for reserves - */ - uint256 internal constant reserveFactorMaxMantissa = 1e18; - - /** - * @notice Administrator for this contract - */ - address payable public admin; - - /** - * @notice Pending administrator for this contract - */ - address payable public pendingAdmin; - - /** - * @notice Contract which oversees inter-cToken operations - */ - ComptrollerInterface public comptroller; - - /** - * @notice Model which tells what the current interest rate should be - */ - InterestRateModel public interestRateModel; - - /** - * @notice Initial exchange rate used when minting the first CTokens (used when totalSupply = 0) - */ - uint256 public initialExchangeRateMantissa; - - /** - * @notice Fraction of interest currently set aside for reserves - */ - uint256 public reserveFactorMantissa; - - /** - * @notice Block number that interest was last accrued at - */ - uint256 public accrualBlockNumber; - - /** - * @notice Accumulator of the total earned interest rate since the opening of the market - */ - uint256 public borrowIndex; - - /** - * @notice Total amount of outstanding borrows of the underlying in this market - */ - uint256 public totalBorrows; - - /** - * @notice Total amount of reserves of the underlying held in this market - */ - uint256 public totalReserves; - - /** - * @notice Total number of tokens in circulation - */ - uint256 public totalSupply; - - uint256 public subsidyFund; - - struct SupplySnapshot { - uint256 tokens; - uint256 underlyingAmount; - uint256 suppliedAt; - uint256 promisedSupplyRate; - } - - /** - * @notice Official record of token balances for each account - */ - mapping(address => SupplySnapshot) internal accountTokens; - - /** - * @notice Approved token transfer amounts on behalf of others - */ - mapping(address => mapping(address => uint256)) internal transferAllowances; - - /** - * @notice Container for borrow balance information - * @member principal Total balance (with accrued interest), after applying the most recent balance-changing action - * @member interestIndex Global borrowIndex as of the most recent balance-changing action - */ - struct BorrowSnapshot { - uint256 principal; - uint256 interestIndex; - } - - /** - * @notice Mapping of account addresses to outstanding borrow balances - */ - mapping(address => BorrowSnapshot) internal accountBorrows; -} - -abstract contract CTokenInterface is CTokenStorage { - /** - * @notice Indicator that this is a CToken contract (for inspection) - */ - bool public constant isCToken = true; - - /*** Market Events ***/ - - /** - * @notice Event emitted when interest is accrued - */ - event AccrueInterest( - uint256 cashPrior, - uint256 interestAccumulated, - uint256 borrowIndex, - uint256 totalBorrows - ); - - /** - * @notice Event emitted when tokens are minted - */ - event Mint(address indexed minter, uint256 mintAmount, uint256 mintTokens); - - /** - * @notice Event emitted when tokens are redeemed - */ - event Redeem( - address indexed redeemer, - uint256 redeemAmount, - uint256 redeemTokens - ); - - /** - * @notice Event emitted when underlying is borrowed - */ - event Borrow( - address indexed borrower, - uint256 borrowAmount, - uint256 accountBorrows, - uint256 totalBorrows - ); - - /** - * @notice Event emitted when a borrow is repaid - */ - event RepayBorrow( - address indexed payer, - address indexed borrower, - uint256 repayAmount, - uint256 accountBorrows, - uint256 totalBorrows - ); - - /** - * @notice Event emitted when a borrow is liquidated - */ - event LiquidateBorrow( - address indexed liquidator, - address indexed borrower, - uint256 repayAmount, - address indexed cTokenCollateral, - uint256 seizeTokens - ); - - /*** Admin Events ***/ - - /** - * @notice Event emitted when pendingAdmin is changed - */ - event NewPendingAdmin(address oldPendingAdmin, address newPendingAdmin); - - /** - * @notice Event emitted when pendingAdmin is accepted, which means admin is updated - */ - event NewAdmin(address oldAdmin, address newAdmin); - - /** - * @notice Event emitted when comptroller is changed - */ - event NewComptroller( - ComptrollerInterface oldComptroller, - ComptrollerInterface newComptroller - ); - - /** - * @notice Event emitted when interestRateModel is changed - */ - event NewMarketInterestRateModel( - InterestRateModel oldInterestRateModel, - InterestRateModel newInterestRateModel - ); - - /** - * @notice Event emitted when the reserve factor is changed - */ - event NewReserveFactor( - uint256 oldReserveFactorMantissa, - uint256 newReserveFactorMantissa - ); - - /** - * @notice Event emitted when the reserves are added - */ - event ReservesAdded( - address benefactor, - uint256 addAmount, - uint256 newTotalReserves - ); - - event SubsidyAdded( - address benefactor, - uint256 addAmount, - uint256 newSubsidyFund - ); - - /** - * @notice Event emitted when the reserves are reduced - */ - event ReservesReduced( - address admin, - uint256 reduceAmount, - uint256 newTotalReserves - ); - - /** - * @notice EIP20 Transfer event - */ - event Transfer(address indexed from, address indexed to, uint256 amount); - - /** - * @notice EIP20 Approval event - */ - event Approval( - address indexed owner, - address indexed spender, - uint256 amount - ); - - /** - * @notice Failure event - */ - event CTokenStorageFailure(uint256 error, uint256 info, uint256 detail); - - /*** User Interface ***/ - - function transfer(address dst, uint256 amount) - external - virtual - returns (bool); - - function transferFrom( - address src, - address dst, - uint256 amount - ) external virtual returns (bool); - - function approve(address spender, uint256 amount) - external - virtual - returns (bool); - - function allowance(address owner, address spender) - external - view - virtual - returns (uint256); - - function balanceOf(address owner) external view virtual returns (uint256); - - function balanceOfUnderlying(address owner) - external - virtual - returns (uint256); - - function getAccountSnapshot(address account) - external - view - virtual - returns ( - uint256, - uint256, - uint256, - uint256 - ); - - function borrowRatePerBlock() external view virtual returns (uint256); - - function supplyRatePerBlock() external view virtual returns (uint256); - - function totalBorrowsCurrent() external virtual returns (uint256); - - function borrowBalanceCurrent(address account) - external - virtual - returns (uint256); - - function borrowBalanceStored(address account) - public - view - virtual - returns (uint256); - - function exchangeRateCurrent() public virtual returns (uint256); - - function exchangeRateStored() public view virtual returns (uint256); - - function getCash() external view virtual returns (uint256); - - function accrueInterest() public virtual returns (uint256); - - function seize( - address liquidator, - address borrower, - uint256 seizeTokens - ) external virtual returns (uint256); - - /*** Admin Functions ***/ - - function _setPendingAdmin(address payable newPendingAdmin) - external - virtual - returns (uint256); - - function _acceptAdmin() external virtual returns (uint256); - - function _setComptroller(ComptrollerInterface newComptroller) - public - virtual - returns (uint256); - - function _setReserveFactor(uint256 newReserveFactorMantissa) - external - virtual - returns (uint256); - - function _reduceReserves(uint256 reduceAmount) - external - virtual - returns (uint256); - - function _setInterestRateModel(InterestRateModel newInterestRateModel) - public - virtual - returns (uint256); -} - -contract CErc20Storage { - /** - * @notice Underlying asset for this CToken - */ - address public underlying; -} - -abstract contract CErc20Interface is CErc20Storage { - /*** User Interface ***/ - - function mint(uint256 mintAmount) external virtual returns (uint256); - - function redeem(uint256 redeemAmount) - external - virtual - returns (uint256); - - function borrow(uint256 borrowAmount) external virtual returns (uint256); - - function repayBorrow(uint256 repayAmount) - external - virtual - returns (uint256); - - function liquidateBorrow( - address borrower, - uint256 repayAmount, - CTokenInterface cTokenCollateral - ) external virtual returns (uint256); - - function sweepToken(EIP20NonStandardInterface token) external virtual; - - /*** Admin Functions ***/ - - function _addReserves(uint256 addAmount) external virtual returns (uint256); -} - -contract CDelegationStorage { - /** - * @notice Implementation address for this contract - */ - address public implementation; -} - -abstract contract CDelegatorInterface is CDelegationStorage { - /** - * @notice Emitted when implementation is changed - */ - event NewImplementation( - address oldImplementation, - address newImplementation - ); - - /** - * @notice Called by the admin to update the implementation of the delegator - * @param implementation_ The address of the new implementation for delegation - * @param allowResign Flag to indicate whether to call _resignImplementation on the old implementation - * @param becomeImplementationData The encoded bytes data to be passed to _becomeImplementation - */ - function _setImplementation( - address implementation_, - bool allowResign, - bytes memory becomeImplementationData - ) public virtual; -} - -abstract contract CDelegateInterface is CDelegationStorage { - /** - * @notice Called by the delegator on a delegate to initialize it for duty - * @dev Should revert if any issues arise which make it unfit for delegation - * @param data The encoded bytes data for any initialization - */ - function _becomeImplementation(bytes memory data) public virtual; - - /** - * @notice Called by the delegator on a delegate to forfeit its responsibility - */ - function _resignImplementation() public virtual; -} - - -// Dependency file: contracts/ErrorReporter.sol - -// pragma solidity 0.8.6; - -contract ComptrollerErrorReporter { - enum Error { - NO_ERROR, - UNAUTHORIZED, - COMPTROLLER_MISMATCH, - INSUFFICIENT_SHORTFALL, - INSUFFICIENT_LIQUIDITY, - INVALID_CLOSE_FACTOR, - INVALID_COLLATERAL_FACTOR, - INVALID_LIQUIDATION_INCENTIVE, - MARKET_NOT_ENTERED, // no longer possible - MARKET_NOT_LISTED, - MARKET_ALREADY_LISTED, - MATH_ERROR, - NONZERO_BORROW_BALANCE, - PRICE_ERROR, - REJECTION, - SNAPSHOT_ERROR, - TOO_MANY_ASSETS, - TOO_MUCH_REPAY - } - - enum FailureInfo { - ACCEPT_ADMIN_PENDING_ADMIN_CHECK, - ACCEPT_PENDING_IMPLEMENTATION_ADDRESS_CHECK, - EXIT_MARKET_BALANCE_OWED, - EXIT_MARKET_REJECTION, - SET_CLOSE_FACTOR_OWNER_CHECK, - SET_CLOSE_FACTOR_VALIDATION, - SET_COLLATERAL_FACTOR_OWNER_CHECK, - SET_COLLATERAL_FACTOR_NO_EXISTS, - SET_COLLATERAL_FACTOR_VALIDATION, - SET_COLLATERAL_FACTOR_WITHOUT_PRICE, - SET_IMPLEMENTATION_OWNER_CHECK, - SET_LIQUIDATION_INCENTIVE_OWNER_CHECK, - SET_LIQUIDATION_INCENTIVE_VALIDATION, - SET_MAX_ASSETS_OWNER_CHECK, - SET_PENDING_ADMIN_OWNER_CHECK, - SET_PENDING_IMPLEMENTATION_OWNER_CHECK, - SET_PRICE_ORACLE_OWNER_CHECK, - SUPPORT_MARKET_EXISTS, - SUPPORT_MARKET_OWNER_CHECK, - SET_PAUSE_GUARDIAN_OWNER_CHECK - } - - /** - * @dev `error` corresponds to enum Error; `info` corresponds to enum FailureInfo, and `detail` is an arbitrary - * contract-specific code that enables us to report opaque error codes from upgradeable contracts. - **/ - event Failure(uint256 error, uint256 info, uint256 detail); - - /** - * @dev use this when reporting a known error from the money market or a non-upgradeable collaborator - */ - function fail(Error err, FailureInfo info) internal returns (uint256) { - emit Failure(uint256(err), uint256(info), 0); - - return uint256(err); - } - - /** - * @dev use this when reporting an opaque error from an upgradeable collaborator contract - */ - function failOpaque( - Error err, - FailureInfo info, - uint256 opaqueError - ) internal returns (uint256) { - emit Failure(uint256(err), uint256(info), opaqueError); - - return uint256(err); - } -} - -contract TokenErrorReporter { - enum Error { - NO_ERROR, - UNAUTHORIZED, - BAD_INPUT, - COMPTROLLER_REJECTION, - COMPTROLLER_CALCULATION_ERROR, - INTEREST_RATE_MODEL_ERROR, - INVALID_ACCOUNT_PAIR, - INVALID_CLOSE_AMOUNT_REQUESTED, - INVALID_COLLATERAL_FACTOR, - MATH_ERROR, - MARKET_NOT_FRESH, - MARKET_NOT_LISTED, - TOKEN_INSUFFICIENT_ALLOWANCE, - TOKEN_INSUFFICIENT_BALANCE, - TOKEN_INSUFFICIENT_CASH, - TOKEN_TRANSFER_IN_FAILED, - TOKEN_TRANSFER_OUT_FAILED - } - - /* - * Note: FailureInfo (but not Error) is kept in alphabetical order - * This is because FailureInfo grows significantly faster, and - * the order of Error has some meaning, while the order of FailureInfo - * is entirely arbitrary. - */ - enum FailureInfo { - ACCEPT_ADMIN_PENDING_ADMIN_CHECK, - ACCRUE_INTEREST_ACCUMULATED_INTEREST_CALCULATION_FAILED, - ACCRUE_INTEREST_BORROW_RATE_CALCULATION_FAILED, - ACCRUE_INTEREST_NEW_BORROW_INDEX_CALCULATION_FAILED, - ACCRUE_INTEREST_NEW_TOTAL_BORROWS_CALCULATION_FAILED, - ACCRUE_INTEREST_NEW_TOTAL_RESERVES_CALCULATION_FAILED, - ACCRUE_INTEREST_SIMPLE_INTEREST_FACTOR_CALCULATION_FAILED, - BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED, - BORROW_ACCRUE_INTEREST_FAILED, - BORROW_CASH_NOT_AVAILABLE, - BORROW_FRESHNESS_CHECK, - BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED, - BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED, - BORROW_MARKET_NOT_LISTED, - BORROW_COMPTROLLER_REJECTION, - LIQUIDATE_ACCRUE_BORROW_INTEREST_FAILED, - LIQUIDATE_ACCRUE_COLLATERAL_INTEREST_FAILED, - LIQUIDATE_COLLATERAL_FRESHNESS_CHECK, - LIQUIDATE_COMPTROLLER_REJECTION, - LIQUIDATE_COMPTROLLER_CALCULATE_AMOUNT_SEIZE_FAILED, - LIQUIDATE_CLOSE_AMOUNT_IS_UINT_MAX, - LIQUIDATE_CLOSE_AMOUNT_IS_ZERO, - LIQUIDATE_FRESHNESS_CHECK, - LIQUIDATE_LIQUIDATOR_IS_BORROWER, - LIQUIDATE_REPAY_BORROW_FRESH_FAILED, - LIQUIDATE_SEIZE_BALANCE_INCREMENT_FAILED, - LIQUIDATE_SEIZE_BALANCE_DECREMENT_FAILED, - LIQUIDATE_SEIZE_COMPTROLLER_REJECTION, - LIQUIDATE_SEIZE_LIQUIDATOR_IS_BORROWER, - LIQUIDATE_SEIZE_TOO_MUCH, - MINT_ACCRUE_INTEREST_FAILED, - MINT_COMPTROLLER_REJECTION, - MINT_EXCHANGE_CALCULATION_FAILED, - MINT_EXCHANGE_RATE_READ_FAILED, - MINT_FRESHNESS_CHECK, - MINT_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED, - MINT_NEW_TOTAL_SUPPLY_CALCULATION_FAILED, - MINT_TRANSFER_IN_FAILED, - MINT_TRANSFER_IN_NOT_POSSIBLE, - REDEEM_ACCRUE_INTEREST_FAILED, - REDEEM_COMPTROLLER_REJECTION, - REDEEM_EXCHANGE_TOKENS_CALCULATION_FAILED, - REDEEM_EXCHANGE_AMOUNT_CALCULATION_FAILED, - REDEEM_EXCHANGE_RATE_READ_FAILED, - REDEEM_FRESHNESS_CHECK, - REDEEM_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED, - REDEEM_NEW_TOTAL_SUPPLY_CALCULATION_FAILED, - REDEEM_TRANSFER_OUT_NOT_POSSIBLE, - REDUCE_RESERVES_ACCRUE_INTEREST_FAILED, - REDUCE_RESERVES_ADMIN_CHECK, - REDUCE_RESERVES_CASH_NOT_AVAILABLE, - REDUCE_RESERVES_FRESH_CHECK, - REDUCE_RESERVES_VALIDATION, - REPAY_BEHALF_ACCRUE_INTEREST_FAILED, - REPAY_BORROW_ACCRUE_INTEREST_FAILED, - REPAY_BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED, - REPAY_BORROW_COMPTROLLER_REJECTION, - REPAY_BORROW_FRESHNESS_CHECK, - REPAY_BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED, - REPAY_BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED, - REPAY_BORROW_TRANSFER_IN_NOT_POSSIBLE, - SET_COLLATERAL_FACTOR_OWNER_CHECK, - SET_COLLATERAL_FACTOR_VALIDATION, - SET_COMPTROLLER_OWNER_CHECK, - SET_INTEREST_RATE_MODEL_ACCRUE_INTEREST_FAILED, - SET_INTEREST_RATE_MODEL_FRESH_CHECK, - SET_INTEREST_RATE_MODEL_OWNER_CHECK, - SET_MAX_ASSETS_OWNER_CHECK, - SET_ORACLE_MARKET_NOT_LISTED, - SET_PENDING_ADMIN_OWNER_CHECK, - SET_RESERVE_FACTOR_ACCRUE_INTEREST_FAILED, - SET_RESERVE_FACTOR_ADMIN_CHECK, - SET_RESERVE_FACTOR_FRESH_CHECK, - SET_RESERVE_FACTOR_BOUNDS_CHECK, - TRANSFER_COMPTROLLER_REJECTION, - TRANSFER_NOT_ALLOWED, - TRANSFER_NOT_ENOUGH, - TRANSFER_TOO_MUCH, - ADD_RESERVES_ACCRUE_INTEREST_FAILED, - ADD_RESERVES_FRESH_CHECK, - ADD_RESERVES_TRANSFER_IN_NOT_POSSIBLE, - ADD_SUBSIDY_FUND_FAILED, - ADD_SUBSIDY_FUND_FRESH_CHECK - } - - /** - * @dev `error` corresponds to enum Error; `info` corresponds to enum FailureInfo, and `detail` is an arbitrary - * contract-specific code that enables us to report opaque error codes from upgradeable contracts. - **/ - event TokenFailure(uint256 error, uint256 info, uint256 detail); - - /** - * @dev use this when reporting a known error from the money market or a non-upgradeable collaborator - */ - function fail(Error err, FailureInfo info) internal returns (uint256) { - emit TokenFailure(uint256(err), uint256(info), 0); - - return uint256(err); - } - - /** - * @dev use this when reporting an opaque error from an upgradeable collaborator contract - */ - function failOpaque( - Error err, - FailureInfo info, - uint256 opaqueError - ) internal returns (uint256) { - emit TokenFailure(uint256(err), uint256(info), opaqueError); - - return uint256(err); - } -} - - -// Dependency file: contracts/EIP20Interface.sol - -// pragma solidity 0.8.6; - -/** - * @title ERC 20 Token Standard Interface - * https://eips.ethereum.org/EIPS/eip-20 - */ -interface EIP20Interface { - function name() external view returns (string memory); - - function symbol() external view returns (string memory); - - function decimals() external view returns (uint8); - - /** - * @notice Get the total number of tokens in circulation - * @return The supply of tokens - */ - function totalSupply() external view returns (uint256); - - /** - * @notice Gets the balance of the specified address - * @param owner The address from which the balance will be retrieved - * @return balance The balance - */ - function balanceOf(address owner) external view returns (uint256 balance); - - /** - * @notice Transfer `amount` tokens from `msg.sender` to `dst` - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - * @return success Whether or not the transfer succeeded - */ - function transfer(address dst, uint256 amount) - external - returns (bool success); - - /** - * @notice Transfer `amount` tokens from `src` to `dst` - * @param src The address of the source account - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - * @return success Whether or not the transfer succeeded - */ - function transferFrom( - address src, - address dst, - uint256 amount - ) external returns (bool success); - - /** - * @notice Approve `spender` to transfer up to `amount` from `src` - * @dev This will overwrite the approval amount for `spender` - * and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve) - * @param spender The address of the account which may transfer tokens - * @param amount The number of tokens that are approved (-1 means infinite) - * @return success Whether or not the approval succeeded - */ - function approve(address spender, uint256 amount) - external - returns (bool success); - - /** - * @notice Get the current allowance from `owner` for `spender` - * @param owner The address of the account which owns the tokens to be spent - * @param spender The address of the account which may transfer tokens - * @return remaining The number of tokens allowed to be spent (-1 means infinite) - */ - function allowance(address owner, address spender) - external - view - returns (uint256 remaining); - - event Transfer(address indexed from, address indexed to, uint256 amount); - event Approval( - address indexed owner, - address indexed spender, - uint256 amount - ); -} - - -// Dependency file: contracts/WhitelistInterface.sol - -// pragma solidity 0.8.6; - -interface WhitelistInterface { - function setStatus(bool _newStatus) external; - function enabled() external view returns(bool); - - function addUsers(address[] memory _users) external; - function exist(address _user) external view returns(bool); - function getUsers() external view returns(address[] memory currentUsers); - function removeUser(address _user) external; -} - -// Dependency file: contracts/CToken.sol - -// pragma solidity 0.8.6; - -// import "contracts/ComptrollerInterface.sol"; -// import "contracts/CTokenInterfaces.sol"; -// import "contracts/ErrorReporter.sol"; -// import "contracts/Exponential.sol"; -// import "contracts/EIP20Interface.sol"; -// import "contracts/InterestRateModel.sol"; -// import "contracts/WhitelistInterface.sol"; - -/** - * @title tropykus CToken Contract - * @notice Abstract base for CTokens - * @author tropykus - */ -abstract contract CToken is CTokenInterface, Exponential, TokenErrorReporter { - address whitelist; - - /** - * @notice Initialize the money market - * @param comptroller_ The address of the Comptroller - * @param interestRateModel_ The address of the interest rate model - * @param initialExchangeRateMantissa_ The initial exchange rate, scaled by 1e18 - * @param name_ EIP-20 name of this token - * @param symbol_ EIP-20 symbol of this token - * @param decimals_ EIP-20 decimal precision of this token - */ - function initialize( - ComptrollerInterface comptroller_, - InterestRateModel interestRateModel_, - uint256 initialExchangeRateMantissa_, - string memory name_, - string memory symbol_, - uint8 decimals_ - ) public { - require(msg.sender == admin, "CT01"); - require(accrualBlockNumber == 0 && borrowIndex == 0, "CT02"); - - initialExchangeRateMantissa = initialExchangeRateMantissa_; - require(initialExchangeRateMantissa > 0, "CT03"); - - uint256 err = _setComptroller(comptroller_); - require(err == uint256(Error.NO_ERROR), "CT04"); - - accrualBlockNumber = getBlockNumber(); - borrowIndex = mantissaOne; - - err = _setInterestRateModelFresh(interestRateModel_); - require(err == uint256(Error.NO_ERROR), "CT05"); - - name = name_; - symbol = symbol_; - decimals = decimals_; - - _notEntered = true; - } - - function addWhitelist(address _whitelist) external returns (uint256) { - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_INTEREST_RATE_MODEL_OWNER_CHECK - ); - } - whitelist = _whitelist; - } - - /** - * @notice Transfer `tokens` tokens from `src` to `dst` by `spender` - * @dev Called by both `transfer` and `transferFrom` internally - * @param spender The address of the account performing the transfer - * @param src The address of the source account - * @param dst The address of the destination account - * @param tokens The number of tokens to transfer - * @return Whether or not the transfer succeeded - */ - function transferTokens( - address spender, - address src, - address dst, - uint256 tokens - ) internal returns (uint256) { - uint256 allowed = comptroller.transferAllowed( - address(this), - src, - dst, - tokens - ); - if (allowed != 0) { - return - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.TRANSFER_COMPTROLLER_REJECTION, - allowed - ); - } - - if (src == dst) { - return fail(Error.BAD_INPUT, FailureInfo.TRANSFER_NOT_ALLOWED); - } - - uint256 startingAllowance = 0; - if (spender == src) { - startingAllowance = type(uint256).max; - } else { - startingAllowance = transferAllowances[src][spender]; - } - - MathError mathErr; - uint256 allowanceNew; - uint256 srcTokensNew; - uint256 dstTokensNew; - - (mathErr, allowanceNew) = subUInt(startingAllowance, tokens); - if (mathErr != MathError.NO_ERROR) { - return fail(Error.MATH_ERROR, FailureInfo.TRANSFER_NOT_ALLOWED); - } - - (mathErr, srcTokensNew) = subUInt(accountTokens[src].tokens, tokens); - if (mathErr != MathError.NO_ERROR) { - return fail(Error.MATH_ERROR, FailureInfo.TRANSFER_NOT_ENOUGH); - } - - (mathErr, dstTokensNew) = addUInt(accountTokens[dst].tokens, tokens); - if (mathErr != MathError.NO_ERROR) { - return fail(Error.MATH_ERROR, FailureInfo.TRANSFER_TOO_MUCH); - } - - accountTokens[src].tokens = srcTokensNew; - accountTokens[dst].tokens = dstTokensNew; - - if (startingAllowance != type(uint256).max) { - transferAllowances[src][spender] = allowanceNew; - } - - emit Transfer(src, dst, tokens); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Transfer `amount` tokens from `msg.sender` to `dst` - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - * @return Whether or not the transfer succeeded - */ - function transfer(address dst, uint256 amount) - external - override - nonReentrant - returns (bool) - { - return - transferTokens(msg.sender, msg.sender, dst, amount) == - uint256(Error.NO_ERROR); - } - - /** - * @notice Transfer `amount` tokens from `src` to `dst` - * @param src The address of the source account - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - * @return Whether or not the transfer succeeded - */ - function transferFrom( - address src, - address dst, - uint256 amount - ) external override nonReentrant returns (bool) { - return - transferTokens(msg.sender, src, dst, amount) == - uint256(Error.NO_ERROR); - } - - /** - * @notice Approve `spender` to transfer up to `amount` from `src` - * @dev This will overwrite the approval amount for `spender` - * and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve) - * @param spender The address of the account which may transfer tokens - * @param amount The number of tokens that are approved (-1 means infinite) - * @return Whether or not the approval succeeded - */ - function approve(address spender, uint256 amount) - external - override - returns (bool) - { - transferAllowances[msg.sender][spender] = amount; - emit Approval(msg.sender, spender, amount); - return true; - } - - /** - * @notice Get the current allowance from `owner` for `spender` - * @param owner The address of the account which owns the tokens to be spent - * @param spender The address of the account which may transfer tokens - * @return The number of tokens allowed to be spent (-1 means infinite) - */ - function allowance(address owner, address spender) - external - view - override - returns (uint256) - { - return transferAllowances[owner][spender]; - } - - /** - * @notice Get the token balance of the `owner` - * @param owner The address of the account to query - * @return The number of tokens owned by `owner` - */ - function balanceOf(address owner) external view override returns (uint256) { - return accountTokens[owner].tokens; - } - - /** - * @notice Get the underlying balance of the `owner` - * @dev This also accrues interest in a transaction - * @param owner The address of the account to query - * @return The amount of underlying owned by `owner` - */ - function balanceOfUnderlying(address owner) - external - override - returns (uint256) - { - (MathError mErr, uint256 balance) = mulScalarTruncate( - Exp({mantissa: exchangeRateCurrent()}), - accountTokens[owner].tokens - ); - require(mErr == MathError.NO_ERROR, "CT06"); - return balance; - } - - /** - * @notice Get a snapshot of the account's balances, and the cached exchange rate - * @dev This is used by comptroller to more efficiently perform liquidity checks. - * @param account Address of the account to snapshot - * @return (possible error, token balance, borrow balance, exchange rate mantissa) - */ - function getAccountSnapshot(address account) - external - view - override - returns ( - uint256, - uint256, - uint256, - uint256 - ) - { - uint256 cTokenBalance = accountTokens[account].tokens; - uint256 borrowBalance; - uint256 exchangeRateMantissa; - - MathError mErr; - - (mErr, borrowBalance) = borrowBalanceStoredInternal(account); - if (mErr != MathError.NO_ERROR) { - return (uint256(Error.MATH_ERROR), 0, 0, 0); - } - - (mErr, exchangeRateMantissa) = exchangeRateStoredInternal(); - if (mErr != MathError.NO_ERROR) { - return (uint256(Error.MATH_ERROR), 0, 0, 0); - } - - return ( - uint256(Error.NO_ERROR), - cTokenBalance, - borrowBalance, - exchangeRateMantissa - ); - } - - /** - * @dev Function to simply retrieve block number - * This exists mainly for inheriting test contracts to stub this result. - */ - function getBlockNumber() internal view virtual returns (uint256) { - return block.number; - } - - /** - * @notice Returns the current per-block borrow interest rate for this cToken - * @return The borrow interest rate per block, scaled by 1e18 - */ - function borrowRatePerBlock() external view override returns (uint256) { - return - interestRateModel.getBorrowRate( - getCashPrior(), - totalBorrows, - totalReserves - ); - } - - /** - * @notice Returns the current per-block supply interest rate for this cToken - * @return The supply interest rate per block, scaled by 1e18 - */ - function supplyRatePerBlock() external view override returns (uint256) { - return - interestRateModel.getSupplyRate( - getCashPrior(), - totalBorrows, - totalReserves, - reserveFactorMantissa - ); - } - - /** - * @notice Returns the current total borrows plus accrued interest - * @return The total borrows with interest - */ - function totalBorrowsCurrent() - external - override - nonReentrant - returns (uint256) - { - require(accrueInterest() == uint256(Error.NO_ERROR), "CT07"); - return totalBorrows; - } - - /** - * @notice Accrue interest to updated borrowIndex and then calculate account's borrow balance using the updated borrowIndex - * @param account The address whose balance should be calculated after updating borrowIndex - * @return The calculated balance - */ - function borrowBalanceCurrent(address account) - external - override - nonReentrant - returns (uint256) - { - require(accrueInterest() == uint256(Error.NO_ERROR), "CT07"); - return borrowBalanceStored(account); - } - - /** - * @notice Return the borrow balance of account based on stored data - * @param account The address whose balance should be calculated - * @return The calculated balance - */ - function borrowBalanceStored(address account) - public - view - override - returns (uint256) - { - (MathError err, uint256 result) = borrowBalanceStoredInternal(account); - require(err == MathError.NO_ERROR, "CT08"); - return result; - } - - /** - * @notice Return the borrow balance of account based on stored data - * @param account The address whose balance should be calculated - * @return (error code, the calculated balance or 0 if error code is non-zero) - */ - function borrowBalanceStoredInternal(address account) - internal - view - returns (MathError, uint256) - { - MathError mathErr; - uint256 principalTimesIndex; - uint256 result; - - BorrowSnapshot storage borrowSnapshot = accountBorrows[account]; - - if (borrowSnapshot.principal == 0) { - return (MathError.NO_ERROR, 0); - } - - (mathErr, principalTimesIndex) = mulUInt( - borrowSnapshot.principal, - borrowIndex - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - - (mathErr, result) = divUInt( - principalTimesIndex, - borrowSnapshot.interestIndex - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - - return (MathError.NO_ERROR, result); - } - - function getBorrowerPrincipalStored(address account) - public - view - returns (uint256 borrowed) - { - borrowed = accountBorrows[account].principal; - } - - function getSupplierSnapshotStored(address account) - public - view - returns ( - uint256 tokens, - uint256 underlyingAmount, - uint256 suppliedAt, - uint256 promisedSupplyRate - ) - { - tokens = accountTokens[account].tokens; - underlyingAmount = accountTokens[account].underlyingAmount; - suppliedAt = accountTokens[account].suppliedAt; - promisedSupplyRate = accountTokens[account].promisedSupplyRate; - } - - /** - * @notice Accrue interest then return the up-to-date exchange rate - * @return Calculated exchange rate scaled by 1e18 - */ - function exchangeRateCurrent() - public - override - nonReentrant - returns (uint256) - { - require(accrueInterest() == uint256(Error.NO_ERROR), "CT07"); - return exchangeRateStored(); - } - - /** - * @notice Calculates the exchange rate from the underlying to the CToken - * @dev This function does not accrue interest before calculating the exchange rate - * @return Calculated exchange rate scaled by 1e18 - */ - function exchangeRateStored() public view override returns (uint256) { - (MathError err, uint256 result) = exchangeRateStoredInternal(); - require(err == MathError.NO_ERROR, "CT09"); - return result; - } - - /** - * @notice Calculates the exchange rate from the underlying to the CToken - * @dev This function does not accrue interest before calculating the exchange rate - * @return (error code, calculated exchange rate scaled by 1e18) - */ - function exchangeRateStoredInternal() - internal - view - virtual - returns (MathError, uint256) - { - uint256 _totalSupply = totalSupply; - if (_totalSupply == 0) { - return (MathError.NO_ERROR, initialExchangeRateMantissa); - } else { - MathError error; - uint256 exchangeRate; - uint256 totalCash = getCashPrior(); - if (interestRateModel.isTropykusInterestRateModel()) { - (error, exchangeRate) = tropykusExchangeRateStoredInternal( - msg.sender - ); - if (error == MathError.NO_ERROR) { - return (MathError.NO_ERROR, exchangeRate); - } else { - return (MathError.NO_ERROR, initialExchangeRateMantissa); - } - } - return - interestRateModel.getExchangeRate( - totalCash, - totalBorrows, - totalReserves, - totalSupply - ); - } - } - - function tropykusExchangeRateStoredInternal(address redeemer) - internal - view - returns (MathError, uint256) - { - if (totalSupply == 0) { - return (MathError.NO_ERROR, initialExchangeRateMantissa); - } else { - SupplySnapshot storage supplySnapshot = accountTokens[redeemer]; - if (supplySnapshot.suppliedAt == 0) { - return (MathError.DIVISION_BY_ZERO, 0); - } - (, uint256 interestFactorMantissa, ) = tropykusInterestAccrued( - redeemer - ); - Exp memory interestFactor = Exp({mantissa: interestFactorMantissa}); - uint256 currentUnderlying = supplySnapshot.underlyingAmount; - Exp memory redeemerUnderlying = Exp({mantissa: currentUnderlying}); - (, Exp memory realAmount) = mulExp( - interestFactor, - redeemerUnderlying - ); - (, Exp memory exchangeRate) = getExp( - realAmount.mantissa, - supplySnapshot.tokens - ); - return (MathError.NO_ERROR, exchangeRate.mantissa); - } - } - - function tropykusInterestAccrued(address account) - internal - view - returns ( - MathError, - uint256, - uint256 - ) - { - SupplySnapshot storage supplySnapshot = accountTokens[account]; - uint256 promisedSupplyRate = supplySnapshot.promisedSupplyRate; - Exp memory expectedSupplyRatePerBlock = Exp({ - mantissa: promisedSupplyRate - }); - (, uint256 delta) = subUInt( - accrualBlockNumber, - supplySnapshot.suppliedAt - ); - (, Exp memory expectedSupplyRatePerBlockWithDelta) = mulScalar( - expectedSupplyRatePerBlock, - delta - ); - (, Exp memory interestFactor) = addExp( - Exp({mantissa: 1e18}), - expectedSupplyRatePerBlockWithDelta - ); - uint256 currentUnderlying = supplySnapshot.underlyingAmount; - Exp memory redeemerUnderlying = Exp({mantissa: currentUnderlying}); - (, Exp memory realAmount) = mulExp(interestFactor, redeemerUnderlying); - (, uint256 interestEarned) = subUInt( - realAmount.mantissa, - currentUnderlying - ); - return (MathError.NO_ERROR, interestFactor.mantissa, interestEarned); - } - - /** - * @notice Get cash balance of this cToken in the underlying asset - * @return The quantity of underlying asset owned by this contract - */ - function getCash() external view override returns (uint256) { - return getCashPrior(); - } - - /** - * @notice Applies accrued interest to total borrows and reserves - * @dev This calculates interest accrued from the last checkpointed block - * up to the current block and writes new checkpoint to storage. - */ - function accrueInterest() public override returns (uint256) { - uint256 currentBlockNumber = getBlockNumber(); - uint256 accrualBlockNumberPrior = accrualBlockNumber; - - if (accrualBlockNumberPrior == currentBlockNumber) { - return uint256(Error.NO_ERROR); - } - - uint256 cashPrior = getCashPrior(); - uint256 borrowsPrior = totalBorrows; - uint256 reservesPrior = totalReserves; - uint256 borrowIndexPrior = borrowIndex; - - uint256 borrowRateMantissa = interestRateModel.getBorrowRate( - cashPrior, - borrowsPrior, - reservesPrior - ); - require(borrowRateMantissa <= borrowRateMaxMantissa, "CT10"); - - (MathError mathErr, uint256 blockDelta) = subUInt( - currentBlockNumber, - accrualBlockNumberPrior - ); - require(mathErr == MathError.NO_ERROR, "CT11"); - - Exp memory simpleInterestFactor; - uint256 interestAccumulated; - uint256 totalBorrowsNew; - uint256 totalReservesNew; - uint256 borrowIndexNew; - - (mathErr, simpleInterestFactor) = mulScalar( - Exp({mantissa: borrowRateMantissa}), - blockDelta - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .ACCRUE_INTEREST_SIMPLE_INTEREST_FACTOR_CALCULATION_FAILED, - uint256(mathErr) - ); - } - - (mathErr, interestAccumulated) = mulScalarTruncate( - simpleInterestFactor, - borrowsPrior - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .ACCRUE_INTEREST_ACCUMULATED_INTEREST_CALCULATION_FAILED, - uint256(mathErr) - ); - } - - (mathErr, totalBorrowsNew) = addUInt(interestAccumulated, borrowsPrior); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .ACCRUE_INTEREST_NEW_TOTAL_BORROWS_CALCULATION_FAILED, - uint256(mathErr) - ); - } - - (mathErr, totalReservesNew) = mulScalarTruncateAddUInt( - Exp({mantissa: reserveFactorMantissa}), - interestAccumulated, - reservesPrior - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .ACCRUE_INTEREST_NEW_TOTAL_RESERVES_CALCULATION_FAILED, - uint256(mathErr) - ); - } - - if (interestRateModel.isTropykusInterestRateModel()) { - (mathErr, totalReservesNew) = newReserves( - borrowRateMantissa, - cashPrior, - borrowsPrior, - reservesPrior, - interestAccumulated - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .ACCRUE_INTEREST_NEW_TOTAL_RESERVES_CALCULATION_FAILED, - uint256(mathErr) - ); - } - } - - (mathErr, borrowIndexNew) = mulScalarTruncateAddUInt( - simpleInterestFactor, - borrowIndexPrior, - borrowIndexPrior - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .ACCRUE_INTEREST_NEW_BORROW_INDEX_CALCULATION_FAILED, - uint256(mathErr) - ); - } - - accrualBlockNumber = currentBlockNumber; - borrowIndex = borrowIndexNew; - totalBorrows = totalBorrowsNew; - totalReserves = totalReservesNew; - - emit AccrueInterest( - cashPrior, - interestAccumulated, - borrowIndexNew, - totalBorrowsNew - ); - - return uint256(Error.NO_ERROR); - } - - function newReserves( - uint256 borrowRateMantissa, - uint256 cashPrior, - uint256 borrowsPrior, - uint256 reservesPrior, - uint256 interestAccumulated - ) internal view returns (MathError mathErr, uint256 totalReservesNew) { - uint256 newReserveFactorMantissa; - uint256 utilizationRate = interestRateModel.utilizationRate( - cashPrior, - borrowsPrior, - reservesPrior - ); - uint256 expectedSupplyRate = interestRateModel.getSupplyRate( - cashPrior, - borrowsPrior, - reservesPrior, - reserveFactorMantissa - ); - if ( - interestRateModel.isAboveOptimal( - cashPrior, - borrowsPrior, - reservesPrior - ) - ) { - (mathErr, newReserveFactorMantissa) = mulScalarTruncate( - Exp({mantissa: utilizationRate}), - borrowRateMantissa - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - (mathErr, newReserveFactorMantissa) = subUInt( - newReserveFactorMantissa, - expectedSupplyRate - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - (mathErr, totalReservesNew) = mulScalarTruncateAddUInt( - Exp({mantissa: newReserveFactorMantissa}), - interestAccumulated, - reservesPrior - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - } else { - mathErr = MathError.NO_ERROR; - totalReservesNew = reservesPrior; - } - } - - /** - * @notice Sender supplies assets into the market and receives cTokens in exchange - * @dev Accrues interest whether or not the operation succeeds, unless reverted - * @param mintAmount The amount of the underlying asset to supply - * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual mint amount. - */ - function mintInternal(uint256 mintAmount) - internal - nonReentrant - returns (uint256, uint256) - { - if (WhitelistInterface(whitelist).enabled()) { - require(WhitelistInterface(whitelist).exist(msg.sender), "CT26"); - } - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return ( - fail(Error(error), FailureInfo.MINT_ACCRUE_INTEREST_FAILED), - 0 - ); - } - return mintFresh(msg.sender, mintAmount); - } - - struct MintLocalVars { - Error err; - MathError mathErr; - uint256 exchangeRateMantissa; - uint256 mintTokens; - uint256 totalSupplyNew; - uint256 accountTokensNew; - uint256 actualMintAmount; - } - - /** - * @notice User supplies assets into the market and receives cTokens in exchange - * @dev Assumes interest has already been accrued up to the current block - * @param minter The address of the account which is supplying the assets - * @param mintAmount The amount of the underlying asset to supply - * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual mint amount. - */ - function mintFresh(address minter, uint256 mintAmount) - internal - returns (uint256, uint256) - { - uint256 allowed = comptroller.mintAllowed( - address(this), - minter, - mintAmount - ); - if (allowed != 0) { - return ( - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.MINT_COMPTROLLER_REJECTION, - allowed - ), - 0 - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return ( - fail(Error.MARKET_NOT_FRESH, FailureInfo.MINT_FRESHNESS_CHECK), - 0 - ); - } - - MintLocalVars memory vars; - - ( - vars.mathErr, - vars.exchangeRateMantissa - ) = exchangeRateStoredInternal(); - if (vars.mathErr != MathError.NO_ERROR) { - return ( - failOpaque( - Error.MATH_ERROR, - FailureInfo.MINT_EXCHANGE_RATE_READ_FAILED, - uint256(vars.mathErr) - ), - 0 - ); - } - if (interestRateModel.isTropykusInterestRateModel()) { - SupplySnapshot storage supplySnapshot = accountTokens[minter]; - (, uint256 newTotalSupply) = addUInt( - supplySnapshot.underlyingAmount, - mintAmount - ); - require(newTotalSupply <= 0.1e18, "CT24"); - } - vars.actualMintAmount = doTransferIn(minter, mintAmount); - - (vars.mathErr, vars.mintTokens) = divScalarByExpTruncate( - vars.actualMintAmount, - Exp({mantissa: vars.exchangeRateMantissa}) - ); - require(vars.mathErr == MathError.NO_ERROR, "CT12"); - - (vars.mathErr, vars.totalSupplyNew) = addUInt( - totalSupply, - vars.mintTokens - ); - require(vars.mathErr == MathError.NO_ERROR, "CT13"); - - (vars.mathErr, vars.accountTokensNew) = addUInt( - accountTokens[minter].tokens, - vars.mintTokens - ); - require(vars.mathErr == MathError.NO_ERROR, "CT14"); - - uint256 currentSupplyRate = interestRateModel.getSupplyRate( - getCashPrior(), - totalBorrows, - totalReserves, - reserveFactorMantissa - ); - - bool isTropykusInterestRateModel = interestRateModel - .isTropykusInterestRateModel(); - - if (accountTokens[minter].tokens > 0) { - Exp memory updatedUnderlying; - if (isTropykusInterestRateModel) { - (, uint256 interestFactorMantissa, ) = tropykusInterestAccrued( - minter - ); - Exp memory interestFactor = Exp({ - mantissa: interestFactorMantissa - }); - uint256 currentUnderlyingAmount = accountTokens[minter] - .underlyingAmount; - MathError mErrorNewAmount; - (mErrorNewAmount, updatedUnderlying) = mulExp( - Exp({mantissa: currentUnderlyingAmount}), - interestFactor - ); - if (mErrorNewAmount != MathError.NO_ERROR) { - return ( - failOpaque( - Error.MATH_ERROR, - FailureInfo.MINT_EXCHANGE_CALCULATION_FAILED, - uint256(mErrorNewAmount) - ), - 0 - ); - } - } else { - uint256 currentTokens = accountTokens[minter].tokens; - MathError mErrorUpdatedUnderlying; - (mErrorUpdatedUnderlying, updatedUnderlying) = mulExp( - Exp({mantissa: currentTokens}), - Exp({mantissa: vars.exchangeRateMantissa}) - ); - if (mErrorUpdatedUnderlying != MathError.NO_ERROR) { - return ( - failOpaque( - Error.MATH_ERROR, - FailureInfo.MINT_EXCHANGE_CALCULATION_FAILED, - uint256(mErrorUpdatedUnderlying) - ), - 0 - ); - } - } - (, mintAmount) = addUInt(updatedUnderlying.mantissa, mintAmount); - } - - totalSupply = vars.totalSupplyNew; - accountTokens[minter] = SupplySnapshot({ - tokens: vars.accountTokensNew, - underlyingAmount: mintAmount, - suppliedAt: accrualBlockNumber, - promisedSupplyRate: currentSupplyRate - }); - - emit Mint(minter, vars.actualMintAmount, vars.mintTokens); - emit Transfer(address(this), minter, vars.mintTokens); - - return (uint256(Error.NO_ERROR), vars.actualMintAmount); - } - - /** - * @notice Sender redeems cTokens in exchange for a specified amount of underlying asset - * @dev Accrues interest whether or not the operation succeeds, unless reverted - * @param redeemAmount The amount of underlying to receive from redeeming cTokens - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function redeemUnderlyingInternal(uint256 redeemAmount) - internal - nonReentrant - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return - fail(Error(error), FailureInfo.REDEEM_ACCRUE_INTEREST_FAILED); - } - return redeemFresh(payable(msg.sender), redeemAmount); - } - - struct RedeemLocalVars { - Error err; - MathError mathErr; - uint256 exchangeRateMantissa; - uint256 redeemTokens; - uint256 redeemAmount; - uint256 totalSupplyNew; - uint256 accountTokensNew; - uint256 newSubsidyFund; - } - - /** - * @notice User redeems cTokens in exchange for the underlying asset - * @dev Assumes interest has already been accrued up to the current block - * @param redeemer The address of the account which is redeeming the tokens - * @param redeemAmountIn The number of underlying tokens to receive from redeeming cTokens - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function redeemFresh(address payable redeemer, uint256 redeemAmountIn) - internal - returns (uint256) - { - require(redeemAmountIn > 0, "CT15"); - - RedeemLocalVars memory vars; - - SupplySnapshot storage supplySnapshot = accountTokens[redeemer]; - - ( - vars.mathErr, - vars.exchangeRateMantissa - ) = exchangeRateStoredInternal(); - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.REDEEM_EXCHANGE_RATE_READ_FAILED, - uint256(vars.mathErr) - ); - } - - uint256 interestEarned; - uint256 subsidyFundPortion; - uint256 currentUnderlying; - - bool isTropykusInterestRateModel = interestRateModel - .isTropykusInterestRateModel(); - if (isTropykusInterestRateModel) { - currentUnderlying = supplySnapshot.underlyingAmount; - (, , interestEarned) = tropykusInterestAccrued(redeemer); - } - supplySnapshot.promisedSupplyRate = interestRateModel.getSupplyRate( - getCashPrior(), - totalBorrows, - totalReserves, - reserveFactorMantissa - ); - - if ( - isTropykusInterestRateModel && - !interestRateModel.isAboveOptimal( - getCashPrior(), - totalBorrows, - totalReserves - ) - ) { - uint256 borrowRate = interestRateModel.getBorrowRate( - getCashPrior(), - totalBorrows, - totalReserves - ); - - uint256 utilizationRate = interestRateModel.utilizationRate( - getCashPrior(), - totalBorrows, - totalReserves - ); - - (, uint256 estimatedEarning) = mulScalarTruncate( - Exp({mantissa: borrowRate}), - utilizationRate - ); - - (, subsidyFundPortion) = subUInt( - supplySnapshot.promisedSupplyRate, - estimatedEarning - ); - (, Exp memory subsidyFactor) = getExp( - subsidyFundPortion, - supplySnapshot.promisedSupplyRate - ); - (, subsidyFundPortion) = mulScalarTruncate( - subsidyFactor, - interestEarned - ); - } - - vars.redeemAmount = redeemAmountIn; - - if (isTropykusInterestRateModel) { - (, Exp memory num) = mulExp( - vars.redeemAmount, - supplySnapshot.tokens - ); - (, Exp memory realTokensWithdrawAmount) = getExp( - num.mantissa, - currentUnderlying - ); - vars.redeemTokens = realTokensWithdrawAmount.mantissa; - } else { - (vars.mathErr, vars.redeemTokens) = divScalarByExpTruncate( - redeemAmountIn, - Exp({mantissa: vars.exchangeRateMantissa}) - ); - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.REDEEM_EXCHANGE_AMOUNT_CALCULATION_FAILED, - uint256(vars.mathErr) - ); - } - } - // } - - uint256 allowed = comptroller.redeemAllowed( - address(this), - redeemer, - vars.redeemTokens - ); - if (allowed != 0) { - return - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.REDEEM_COMPTROLLER_REJECTION, - allowed - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.REDEEM_FRESHNESS_CHECK - ); - } - - (vars.mathErr, vars.totalSupplyNew) = subUInt( - totalSupply, - vars.redeemTokens - ); - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.REDEEM_NEW_TOTAL_SUPPLY_CALCULATION_FAILED, - uint256(vars.mathErr) - ); - } - - (, vars.newSubsidyFund) = subUInt(subsidyFund, subsidyFundPortion); - - (vars.mathErr, vars.accountTokensNew) = subUInt( - supplySnapshot.tokens, - vars.redeemTokens - ); - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.REDEEM_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED, - uint256(vars.mathErr) - ); - } - - uint256 cash = getCashPrior(); - if (isTropykusInterestRateModel) { - cash = address(this).balance; - } - - if (cash < vars.redeemAmount) { - return - fail( - Error.TOKEN_INSUFFICIENT_CASH, - FailureInfo.REDEEM_TRANSFER_OUT_NOT_POSSIBLE - ); - } - - doTransferOut(redeemer, vars.redeemAmount); - - totalSupply = vars.totalSupplyNew; - subsidyFund = vars.newSubsidyFund; - supplySnapshot.tokens = vars.accountTokensNew; - supplySnapshot.suppliedAt = accrualBlockNumber; - (, supplySnapshot.underlyingAmount) = subUInt( - supplySnapshot.underlyingAmount, - vars.redeemAmount - ); - - emit Transfer(redeemer, address(this), vars.redeemTokens); - emit Redeem(redeemer, vars.redeemAmount, vars.redeemTokens); - - comptroller.redeemVerify( - address(this), - redeemer, - vars.redeemAmount, - vars.redeemTokens - ); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Sender borrows assets from the protocol to their own address - * @param borrowAmount The amount of the underlying asset to borrow - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function borrowInternal(uint256 borrowAmount) - internal - nonReentrant - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return - fail(Error(error), FailureInfo.BORROW_ACCRUE_INTEREST_FAILED); - } - return borrowFresh(payable(msg.sender), borrowAmount); - } - - struct BorrowLocalVars { - MathError mathErr; - uint256 accountBorrows; - uint256 accountBorrowsNew; - uint256 totalBorrowsNew; - } - - /** - * @notice Users borrow assets from the protocol to their own address - * @param borrowAmount The amount of the underlying asset to borrow - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function borrowFresh(address payable borrower, uint256 borrowAmount) - internal - returns (uint256) - { - uint256 allowed = comptroller.borrowAllowed( - address(this), - borrower, - borrowAmount - ); - if (allowed != 0) { - return - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.BORROW_COMPTROLLER_REJECTION, - allowed - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.BORROW_FRESHNESS_CHECK - ); - } - - if (getCashPrior() < borrowAmount) { - return - fail( - Error.TOKEN_INSUFFICIENT_CASH, - FailureInfo.BORROW_CASH_NOT_AVAILABLE - ); - } - - BorrowLocalVars memory vars; - - (vars.mathErr, vars.accountBorrows) = borrowBalanceStoredInternal( - borrower - ); - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED, - uint256(vars.mathErr) - ); - } - - (vars.mathErr, vars.accountBorrowsNew) = addUInt( - vars.accountBorrows, - borrowAmount - ); - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED, - uint256(vars.mathErr) - ); - } - - (vars.mathErr, vars.totalBorrowsNew) = addUInt( - totalBorrows, - borrowAmount - ); - if (interestRateModel.isTropykusInterestRateModel()) { - require(vars.totalBorrowsNew <= 0.1e18, "CT25"); - } - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED, - uint256(vars.mathErr) - ); - } - - doTransferOut(borrower, borrowAmount); - - accountBorrows[borrower].principal = vars.accountBorrowsNew; - accountBorrows[borrower].interestIndex = borrowIndex; - totalBorrows = vars.totalBorrowsNew; - - emit Borrow( - borrower, - borrowAmount, - vars.accountBorrowsNew, - vars.totalBorrowsNew - ); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Sender repays their own borrow - * @param repayAmount The amount to repay - * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual repayment amount. - */ - function repayBorrowInternal(uint256 repayAmount) - internal - nonReentrant - returns (uint256, uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return ( - fail( - Error(error), - FailureInfo.REPAY_BORROW_ACCRUE_INTEREST_FAILED - ), - 0 - ); - } - return repayBorrowFresh(msg.sender, msg.sender, repayAmount); - } - - struct RepayBorrowLocalVars { - Error err; - MathError mathErr; - uint256 repayAmount; - uint256 borrowerIndex; - uint256 accountBorrows; - uint256 accountBorrowsNew; - uint256 totalBorrowsNew; - uint256 actualRepayAmount; - } - - /** - * @notice Borrows are repaid by another user (possibly the borrower). - * @param payer the account paying off the borrow - * @param borrower the account with the debt being payed off - * @param repayAmount the amount of undelrying tokens being returned - * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual repayment amount. - */ - function repayBorrowFresh( - address payer, - address borrower, - uint256 repayAmount - ) internal returns (uint256, uint256) { - uint256 allowed = comptroller.repayBorrowAllowed( - address(this), - payer, - borrower, - repayAmount - ); - if (allowed != 0) { - return ( - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.REPAY_BORROW_COMPTROLLER_REJECTION, - allowed - ), - 0 - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return ( - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.REPAY_BORROW_FRESHNESS_CHECK - ), - 0 - ); - } - - RepayBorrowLocalVars memory vars; - - vars.borrowerIndex = accountBorrows[borrower].interestIndex; - - (vars.mathErr, vars.accountBorrows) = borrowBalanceStoredInternal( - borrower - ); - if (vars.mathErr != MathError.NO_ERROR) { - return ( - failOpaque( - Error.MATH_ERROR, - FailureInfo - .REPAY_BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED, - uint256(vars.mathErr) - ), - 0 - ); - } - - if (repayAmount == type(uint256).max) { - vars.repayAmount = vars.accountBorrows; - } else { - vars.repayAmount = repayAmount; - } - - vars.actualRepayAmount = doTransferIn(payer, vars.repayAmount); - - (vars.mathErr, vars.accountBorrowsNew) = subUInt( - vars.accountBorrows, - vars.actualRepayAmount - ); - require(vars.mathErr == MathError.NO_ERROR, "CT16"); - - (vars.mathErr, vars.totalBorrowsNew) = subUInt( - totalBorrows, - vars.actualRepayAmount - ); - require(vars.mathErr == MathError.NO_ERROR, "CT17"); - - accountBorrows[borrower].principal = vars.accountBorrowsNew; - accountBorrows[borrower].interestIndex = borrowIndex; - totalBorrows = vars.totalBorrowsNew; - - emit RepayBorrow( - payer, - borrower, - vars.actualRepayAmount, - vars.accountBorrowsNew, - vars.totalBorrowsNew - ); - - return (uint256(Error.NO_ERROR), vars.actualRepayAmount); - } - - /** - * @notice The sender liquidates the borrowers collateral. - * The collateral seized is transferred to the liquidator. - * @param borrower The borrower of this cToken to be liquidated - * @param cTokenCollateral The market in which to seize collateral from the borrower - * @param repayAmount The amount of the underlying borrowed asset to repay - * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual repayment amount. - */ - function liquidateBorrowInternal( - address borrower, - uint256 repayAmount, - CTokenInterface cTokenCollateral - ) internal nonReentrant returns (uint256, uint256) { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return ( - fail( - Error(error), - FailureInfo.LIQUIDATE_ACCRUE_BORROW_INTEREST_FAILED - ), - 0 - ); - } - - error = cTokenCollateral.accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return ( - fail( - Error(error), - FailureInfo.LIQUIDATE_ACCRUE_COLLATERAL_INTEREST_FAILED - ), - 0 - ); - } - - // liquidateBorrowFresh emits borrow-specific logs on errors, so we don't need to - return - liquidateBorrowFresh( - msg.sender, - borrower, - repayAmount, - cTokenCollateral - ); - } - - /** - * @notice The liquidator liquidates the borrowers collateral. - * The collateral seized is transferred to the liquidator. - * @param borrower The borrower of this cToken to be liquidated - * @param liquidator The address repaying the borrow and seizing collateral - * @param cTokenCollateral The market in which to seize collateral from the borrower - * @param repayAmount The amount of the underlying borrowed asset to repay - * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual repayment amount. - */ - function liquidateBorrowFresh( - address liquidator, - address borrower, - uint256 repayAmount, - CTokenInterface cTokenCollateral - ) internal returns (uint256, uint256) { - uint256 allowed = comptroller.liquidateBorrowAllowed( - address(this), - address(cTokenCollateral), - liquidator, - borrower, - repayAmount - ); - if (allowed != 0) { - return ( - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.LIQUIDATE_COMPTROLLER_REJECTION, - allowed - ), - 0 - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return ( - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.LIQUIDATE_FRESHNESS_CHECK - ), - 0 - ); - } - - if (cTokenCollateral.accrualBlockNumber() != getBlockNumber()) { - return ( - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.LIQUIDATE_COLLATERAL_FRESHNESS_CHECK - ), - 0 - ); - } - - if (borrower == liquidator) { - return ( - fail( - Error.INVALID_ACCOUNT_PAIR, - FailureInfo.LIQUIDATE_LIQUIDATOR_IS_BORROWER - ), - 0 - ); - } - - if (repayAmount == 0) { - return ( - fail( - Error.INVALID_CLOSE_AMOUNT_REQUESTED, - FailureInfo.LIQUIDATE_CLOSE_AMOUNT_IS_ZERO - ), - 0 - ); - } - - if (repayAmount == type(uint256).max) { - return ( - fail( - Error.INVALID_CLOSE_AMOUNT_REQUESTED, - FailureInfo.LIQUIDATE_CLOSE_AMOUNT_IS_UINT_MAX - ), - 0 - ); - } - - ( - uint256 repayBorrowError, - uint256 actualRepayAmount - ) = repayBorrowFresh(liquidator, borrower, repayAmount); - if (repayBorrowError != uint256(Error.NO_ERROR)) { - return ( - fail( - Error(repayBorrowError), - FailureInfo.LIQUIDATE_REPAY_BORROW_FRESH_FAILED - ), - 0 - ); - } - - (uint256 amountSeizeError, uint256 seizeTokens) = comptroller - .liquidateCalculateSeizeTokens( - address(this), - address(cTokenCollateral), - actualRepayAmount - ); - require(amountSeizeError == uint256(Error.NO_ERROR), "CT18"); - - require(cTokenCollateral.balanceOf(borrower) >= seizeTokens, "CT19"); - - uint256 seizeError; - if (address(cTokenCollateral) == address(this)) { - seizeError = seizeInternal( - address(this), - liquidator, - borrower, - seizeTokens - ); - } else { - seizeError = cTokenCollateral.seize( - liquidator, - borrower, - seizeTokens - ); - } - - require(seizeError == uint256(Error.NO_ERROR), "CT20"); - - emit LiquidateBorrow( - liquidator, - borrower, - actualRepayAmount, - address(cTokenCollateral), - seizeTokens - ); - - return (uint256(Error.NO_ERROR), actualRepayAmount); - } - - /** - * @notice Transfers collateral tokens (this market) to the liquidator. - * @dev Will fail unless called by another cToken during the process of liquidation. - * Its absolutely critical to use msg.sender as the borrowed cToken and not a parameter. - * @param liquidator The account receiving seized collateral - * @param borrower The account having collateral seized - * @param seizeTokens The number of cTokens to seize - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function seize( - address liquidator, - address borrower, - uint256 seizeTokens - ) external override nonReentrant returns (uint256) { - return seizeInternal(msg.sender, liquidator, borrower, seizeTokens); - } - - struct SeizeVars { - uint256 seizeAmount; - uint256 exchangeRate; - uint256 borrowerTokensNew; - uint256 borrowerAmountNew; - uint256 liquidatorTokensNew; - uint256 liquidatorAmountNew; - uint256 totalCash; - uint256 supplyRate; - } - - /** - * @notice Transfers collateral tokens (this market) to the liquidator. - * @dev Called only during an in-kind liquidation, or by liquidateBorrow during the liquidation of another CToken. - * Its absolutely critical to use msg.sender as the seizer cToken and not a parameter. - * @param seizerToken The contract seizing the collateral (i.e. borrowed cToken) - * @param liquidator The account receiving seized collateral - * @param borrower The account having collateral seized - * @param seizeTokens The number of cTokens to seize - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function seizeInternal( - address seizerToken, - address liquidator, - address borrower, - uint256 seizeTokens - ) internal returns (uint256) { - uint256 allowed = comptroller.seizeAllowed( - address(this), - seizerToken, - liquidator, - borrower, - seizeTokens - ); - if (allowed != 0) { - return - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.LIQUIDATE_SEIZE_COMPTROLLER_REJECTION, - allowed - ); - } - - if (borrower == liquidator) { - return - fail( - Error.INVALID_ACCOUNT_PAIR, - FailureInfo.LIQUIDATE_SEIZE_LIQUIDATOR_IS_BORROWER - ); - } - - SeizeVars memory seizeVars; - - MathError mathErr; - - (mathErr, seizeVars.borrowerTokensNew) = subUInt( - accountTokens[borrower].tokens, - seizeTokens - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.LIQUIDATE_SEIZE_BALANCE_DECREMENT_FAILED, - uint256(mathErr) - ); - } - - seizeVars.totalCash = getCashPrior(); - seizeVars.supplyRate = interestRateModel.getSupplyRate( - seizeVars.totalCash, - totalBorrows, - totalReserves, - reserveFactorMantissa - ); - - (, seizeVars.exchangeRate) = interestRateModel.getExchangeRate( - seizeVars.totalCash, - totalBorrows, - totalReserves, - totalSupply - ); - - if (interestRateModel.isTropykusInterestRateModel()) { - (, seizeVars.exchangeRate) = tropykusExchangeRateStoredInternal( - borrower - ); - } - - (, seizeVars.seizeAmount) = mulUInt( - seizeTokens, - seizeVars.exchangeRate - ); - (, seizeVars.seizeAmount) = divUInt(seizeVars.seizeAmount, 1e18); - - (, seizeVars.borrowerAmountNew) = subUInt( - accountTokens[borrower].underlyingAmount, - seizeVars.seizeAmount - ); - - (mathErr, seizeVars.liquidatorTokensNew) = addUInt( - accountTokens[liquidator].tokens, - seizeTokens - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.LIQUIDATE_SEIZE_BALANCE_INCREMENT_FAILED, - uint256(mathErr) - ); - } - - (, seizeVars.liquidatorAmountNew) = addUInt( - accountTokens[liquidator].underlyingAmount, - seizeVars.seizeAmount - ); - - accountTokens[borrower].tokens = seizeVars.borrowerTokensNew; - accountTokens[borrower].underlyingAmount = seizeVars.borrowerAmountNew; - accountTokens[borrower].suppliedAt = getBlockNumber(); - accountTokens[borrower].promisedSupplyRate = seizeVars.supplyRate; - - accountTokens[liquidator].tokens = seizeVars.liquidatorTokensNew; - accountTokens[liquidator].underlyingAmount = seizeVars - .liquidatorAmountNew; - accountTokens[liquidator].suppliedAt = getBlockNumber(); - accountTokens[liquidator].promisedSupplyRate = seizeVars.supplyRate; - - emit Transfer(borrower, liquidator, seizeTokens); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Begins transfer of admin rights. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer. - * @dev Admin function to begin change of admin. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer. - * @param newPendingAdmin New pending admin. - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setPendingAdmin(address payable newPendingAdmin) - external - override - returns (uint256) - { - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_PENDING_ADMIN_OWNER_CHECK - ); - } - - address oldPendingAdmin = pendingAdmin; - - pendingAdmin = newPendingAdmin; - - emit NewPendingAdmin(oldPendingAdmin, newPendingAdmin); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Accepts transfer of admin rights. msg.sender must be pendingAdmin - * @dev Admin function for pending admin to accept role and update admin - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _acceptAdmin() external override returns (uint256) { - if (msg.sender != pendingAdmin || msg.sender == address(0)) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.ACCEPT_ADMIN_PENDING_ADMIN_CHECK - ); - } - - address oldAdmin = admin; - address oldPendingAdmin = pendingAdmin; - - admin = pendingAdmin; - - pendingAdmin = payable(address(0)); - - emit NewAdmin(oldAdmin, admin); - emit NewPendingAdmin(oldPendingAdmin, pendingAdmin); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Sets a new comptroller for the market - * @dev Admin function to set a new comptroller - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setComptroller(ComptrollerInterface newComptroller) - public - override - returns (uint256) - { - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_COMPTROLLER_OWNER_CHECK - ); - } - - ComptrollerInterface oldComptroller = comptroller; - require(newComptroller.isComptroller(), "CT21"); - - comptroller = newComptroller; - - emit NewComptroller(oldComptroller, newComptroller); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice accrues interest and sets a new reserve factor for the protocol using _setReserveFactorFresh - * @dev Admin function to accrue interest and set a new reserve factor - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setReserveFactor(uint256 newReserveFactorMantissa) - external - override - nonReentrant - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return - fail( - Error(error), - FailureInfo.SET_RESERVE_FACTOR_ACCRUE_INTEREST_FAILED - ); - } - return _setReserveFactorFresh(newReserveFactorMantissa); - } - - /** - * @notice Sets a new reserve factor for the protocol (*requires fresh interest accrual) - * @dev Admin function to set a new reserve factor - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setReserveFactorFresh(uint256 newReserveFactorMantissa) - internal - returns (uint256) - { - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_RESERVE_FACTOR_ADMIN_CHECK - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.SET_RESERVE_FACTOR_FRESH_CHECK - ); - } - - if (newReserveFactorMantissa > reserveFactorMaxMantissa) { - return - fail( - Error.BAD_INPUT, - FailureInfo.SET_RESERVE_FACTOR_BOUNDS_CHECK - ); - } - - uint256 oldReserveFactorMantissa = reserveFactorMantissa; - reserveFactorMantissa = newReserveFactorMantissa; - - emit NewReserveFactor( - oldReserveFactorMantissa, - newReserveFactorMantissa - ); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Accrues interest and reduces reserves by transferring from msg.sender - * @param addAmount Amount of addition to reserves - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _addReservesInternal(uint256 addAmount) - internal - nonReentrant - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return - fail( - Error(error), - FailureInfo.ADD_RESERVES_ACCRUE_INTEREST_FAILED - ); - } - - uint256 totalReservesNew; - uint256 actualAddAmount; - - if (accrualBlockNumber != getBlockNumber()) { - return ( - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.ADD_RESERVES_FRESH_CHECK - ) - ); - } - - actualAddAmount = doTransferIn(msg.sender, addAmount); - - totalReservesNew = totalReserves + actualAddAmount; - - require(totalReservesNew >= totalReserves, "CT22"); - - totalReserves = totalReservesNew; - - emit ReservesAdded(msg.sender, actualAddAmount, totalReservesNew); - - return (uint256(Error.NO_ERROR)); - } - - function _addSubsidyInternal(uint256 addAmount) - internal - nonReentrant - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - // accrueInterest emits logs on errors, but on top of that we want to log the fact that an attempted reduce reserves failed. - return fail(Error(error), FailureInfo.ADD_SUBSIDY_FUND_FAILED); - } - - uint256 subsidyFundNew; - uint256 actualAddAmount; - - if (accrualBlockNumber != getBlockNumber()) { - return ( - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.ADD_SUBSIDY_FUND_FRESH_CHECK - ) - ); - } - - actualAddAmount = doTransferIn(msg.sender, addAmount); - - subsidyFundNew = subsidyFund + actualAddAmount; - - require(subsidyFundNew >= subsidyFund, "CT22"); - - subsidyFund = subsidyFundNew; - - emit SubsidyAdded(msg.sender, actualAddAmount, subsidyFundNew); - - /* Return (NO_ERROR, actualAddAmount) */ - return (uint256(Error.NO_ERROR)); - } - - /** - * @notice Accrues interest and reduces reserves by transferring to admin - * @param reduceAmount Amount of reduction to reserves - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _reduceReserves(uint256 reduceAmount) - external - override - nonReentrant - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return - fail( - Error(error), - FailureInfo.REDUCE_RESERVES_ACCRUE_INTEREST_FAILED - ); - } - return _reduceReservesFresh(reduceAmount); - } - - /** - * @notice Reduces reserves by transferring to admin - * @dev Requires fresh interest accrual - * @param reduceAmount Amount of reduction to reserves - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _reduceReservesFresh(uint256 reduceAmount) - internal - returns (uint256) - { - uint256 totalReservesNew; - - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.REDUCE_RESERVES_ADMIN_CHECK - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.REDUCE_RESERVES_FRESH_CHECK - ); - } - - if (getCashPrior() < reduceAmount) { - return - fail( - Error.TOKEN_INSUFFICIENT_CASH, - FailureInfo.REDUCE_RESERVES_CASH_NOT_AVAILABLE - ); - } - - if (reduceAmount > totalReserves) { - return - fail(Error.BAD_INPUT, FailureInfo.REDUCE_RESERVES_VALIDATION); - } - - totalReservesNew = totalReserves - reduceAmount; - require(totalReservesNew <= totalReserves, "CT23"); - - totalReserves = totalReservesNew; - - doTransferOut(admin, reduceAmount); - - emit ReservesReduced(admin, reduceAmount, totalReservesNew); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice accrues interest and updates the interest rate model using _setInterestRateModelFresh - * @dev Admin function to accrue interest and update the interest rate model - * @param newInterestRateModel the new interest rate model to use - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setInterestRateModel(InterestRateModel newInterestRateModel) - public - override - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return - fail( - Error(error), - FailureInfo.SET_INTEREST_RATE_MODEL_ACCRUE_INTEREST_FAILED - ); - } - return _setInterestRateModelFresh(newInterestRateModel); - } - - /** - * @notice updates the interest rate model (*requires fresh interest accrual) - * @dev Admin function to update the interest rate model - * @param newInterestRateModel the new interest rate model to use - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setInterestRateModelFresh(InterestRateModel newInterestRateModel) - internal - returns (uint256) - { - InterestRateModel oldInterestRateModel; - - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_INTEREST_RATE_MODEL_OWNER_CHECK - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.SET_INTEREST_RATE_MODEL_FRESH_CHECK - ); - } - - oldInterestRateModel = interestRateModel; - - require(newInterestRateModel.isInterestRateModel(), "CT21"); - - interestRateModel = newInterestRateModel; - - emit NewMarketInterestRateModel( - oldInterestRateModel, - newInterestRateModel - ); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Gets balance of this contract in terms of the underlying - * @dev This excludes the value of the current message, if any - * @return The quantity of underlying owned by this contract - */ - function getCashPrior() internal view virtual returns (uint256); - - /** - * @dev Performs a transfer in, reverting upon failure. Returns the amount actually transferred to the protocol, in case of a fee. - * This may revert due to insufficient balance or insufficient allowance. - */ - function doTransferIn(address from, uint256 amount) - internal - virtual - returns (uint256); - - /** - * @dev Performs a transfer out, ideally returning an explanatory error code upon failure tather than reverting. - * If caller has not called checked protocol's balance, may revert due to insufficient cash held in the contract. - * If caller has checked protocol's balance, and verified it is >= amount, this should not revert in normal conditions. - */ - function doTransferOut(address payable to, uint256 amount) internal virtual; - - /** - * @dev Prevents a contract from calling itself, directly or indirectly. - */ - modifier nonReentrant() { - require(_notEntered, "re-entered"); - _notEntered = false; - _; - _notEntered = true; - } -} - - -// Dependency file: contracts/CErc20.sol - -// pragma solidity 0.8.6; - -// import "contracts/CToken.sol"; -// import "contracts/CTokenInterfaces.sol"; - -/** - * @title tropykus CErc20 Contract - * @notice CTokens which wrap an EIP-20 underlying - * @author tropykus - */ -contract CErc20 is CToken, CErc20Interface { - /** - * @notice Initialize the new money market - * @param underlying_ The address of the underlying asset - * @param comptroller_ The address of the Comptroller - * @param interestRateModel_ The address of the interest rate model - * @param initialExchangeRateMantissa_ The initial exchange rate, scaled by 1e18 - * @param name_ ERC-20 name of this token - * @param symbol_ ERC-20 symbol of this token - * @param decimals_ ERC-20 decimal precision of this token - */ - function initialize( - address underlying_, - ComptrollerInterface comptroller_, - InterestRateModel interestRateModel_, - uint256 initialExchangeRateMantissa_, - string memory name_, - string memory symbol_, - uint8 decimals_ - ) public { - // CToken initialize does the bulk of the work - super.initialize( - comptroller_, - interestRateModel_, - initialExchangeRateMantissa_, - name_, - symbol_, - decimals_ - ); - - // Set underlying and sanity check it - underlying = underlying_; - EIP20Interface(underlying).totalSupply(); - } - - /*** User Interface ***/ - - /** - * @notice Sender supplies assets into the market and receives cTokens in exchange - * @dev Accrues interest whether or not the operation succeeds, unless reverted - * @param mintAmount The amount of the underlying asset to supply - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function mint(uint256 mintAmount) external override returns (uint256) { - (uint256 err, ) = mintInternal(mintAmount); - return err; - } - - /** - * @notice Sender redeems cTokens in exchange for a specified amount of underlying asset - * @dev Accrues interest whether or not the operation succeeds, unless reverted - * @param redeemAmount The amount of underlying to redeem - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function redeem(uint256 redeemAmount) - external - override - returns (uint256) - { - return redeemUnderlyingInternal(redeemAmount); - } - - /** - * @notice Sender borrows assets from the protocol to their own address - * @param borrowAmount The amount of the underlying asset to borrow - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function borrow(uint256 borrowAmount) external override returns (uint256) { - return borrowInternal(borrowAmount); - } - - /** - * @notice Sender repays their own borrow - * @param repayAmount The amount to repay - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function repayBorrow(uint256 repayAmount) - external - override - returns (uint256) - { - (uint256 err, ) = repayBorrowInternal(repayAmount); - return err; - } - - /** - * @notice The sender liquidates the borrowers collateral. - * The collateral seized is transferred to the liquidator. - * @param borrower The borrower of this cToken to be liquidated - * @param repayAmount The amount of the underlying borrowed asset to repay - * @param cTokenCollateral The market in which to seize collateral from the borrower - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function liquidateBorrow( - address borrower, - uint256 repayAmount, - CTokenInterface cTokenCollateral - ) external override returns (uint256) { - (uint256 err, ) = liquidateBorrowInternal( - borrower, - repayAmount, - cTokenCollateral - ); - return err; - } - - /** - * @notice A public function to sweep accidental ERC-20 transfers to this contract. Tokens are sent to admin (timelock) - * @param token The address of the ERC-20 token to sweep - */ - function sweepToken(EIP20NonStandardInterface token) external override { - require(address(token) != underlying, "EC01"); - uint256 balance = token.balanceOf(address(this)); - token.transfer(admin, balance); - } - - /** - * @notice The sender adds to reserves. - * @param addAmount The amount fo underlying token to add as reserves - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _addReserves(uint256 addAmount) - external - override - returns (uint256) - { - return _addReservesInternal(addAmount); - } - - /*** Safe Token ***/ - - /** - * @notice Gets balance of this contract in terms of the underlying - * @dev This excludes the value of the current message, if any - * @return The quantity of underlying tokens owned by this contract - */ - function getCashPrior() internal view override returns (uint256) { - EIP20Interface token = EIP20Interface(underlying); - return token.balanceOf(address(this)); - } - - /** - * @dev Similar to EIP20 transfer, except it handles a False result from `transferFrom` and reverts in that case. - * This will revert due to insufficient balance or insufficient allowance. - * This function returns the actual amount received, - * which may be less than `amount` if there is a fee attached to the transfer. - * - * Note: This wrapper safely handles non-standard ERC-20 tokens that do not return a value. - * See here: https://medium.com/coinmonks/missing-return-value-bug-at-least-130-tokens-affected-d67bf08521ca - */ - function doTransferIn(address from, uint256 amount) - internal - override - returns (uint256) - { - EIP20NonStandardInterface token = EIP20NonStandardInterface(underlying); - uint256 balanceBefore = EIP20Interface(underlying).balanceOf( - address(this) - ); - token.transferFrom(from, address(this), amount); - - bool success; - assembly { - switch returndatasize() - case 0 { - // This is a non-standard ERC-20 - success := not(0) // set success to true - } - case 32 { - // This is a compliant ERC-20 - returndatacopy(0, 0, 32) - success := mload(0) // Set `success = returndata` of external call - } - default { - // This is an excessively non-compliant ERC-20, revert. - revert(0, 0) - } - } - require(success, "EC02"); - - // Calculate the amount that was *actually* transferred - uint256 balanceAfter = EIP20Interface(underlying).balanceOf( - address(this) - ); - require(balanceAfter >= balanceBefore, "EC03"); - return balanceAfter - balanceBefore; // underflow already checked above, just subtract - } - - /** - * @dev Similar to EIP20 transfer, except it handles a False success from `transfer` and returns an explanatory - * error code rather than reverting. If caller has not called checked protocol's balance, this may revert due to - * insufficient cash held in this contract. If caller has checked protocol's balance prior to this call, and verified - * it is >= amount, this should not revert in normal conditions. - * - * Note: This wrapper safely handles non-standard ERC-20 tokens that do not return a value. - * See here: https://medium.com/coinmonks/missing-return-value-bug-at-least-130-tokens-affected-d67bf08521ca - */ - function doTransferOut(address payable to, uint256 amount) - internal - virtual - override - { - EIP20NonStandardInterface token = EIP20NonStandardInterface(underlying); - token.transfer(to, amount); - - bool success; - assembly { - switch returndatasize() - case 0 { - // This is a non-standard ERC-20 - success := not(0) // set success to true - } - case 32 { - // This is a complaint ERC-20 - returndatacopy(0, 0, 32) - success := mload(0) // Set `success = returndata` of external call - } - default { - // This is an excessively non-compliant ERC-20, revert. - revert(0, 0) - } - } - require(success, "CE01"); - } -} - - -// Dependency file: contracts/CErc20Delegate.sol - -// pragma solidity 0.8.6; - -// import "contracts/CErc20.sol"; - -/** - * @title tropykus CErc20Delegate Contract - * @notice CTokens which wrap an EIP-20 underlying and are delegated to - * @author tropykus - */ -contract CErc20Delegate is CErc20, CDelegateInterface { - /** - * @notice Construct an empty delegate - */ - constructor() { - // solium-disable-previous-line no-empty-blocks - } - - /** - * @notice Called by the delegator on a delegate to initialize it for duty - * @param data The encoded bytes data for any initialization - */ - function _becomeImplementation(bytes memory data) public override { - // Shh -- currently unused - data; - - // Shh -- we don't ever want this hook to be marked pure - if (false) { - implementation = address(0); - } - - require(msg.sender == admin, "ER01"); - } - - /** - * @notice Called by the delegator on a delegate to forfeit its responsibility - */ - function _resignImplementation() public override { - // Shh -- we don't ever want this hook to be marked pure - if (false) { - implementation = address(0); - } - - require(msg.sender == admin, "ER02"); - } -} - - -// Root file: contracts/CCompLikeDelegate.sol - -pragma solidity 0.8.6; - -// import "contracts/CErc20Delegate.sol"; - -interface CompLike { - function delegate(address delegatee) external; -} - -/** - * @title Compound's CCompLikeDelegate Contract - * @notice CTokens which can 'delegate votes' of their underlying ERC-20 - * @author tropykus - */ -contract CCompLikeDelegate is CErc20Delegate { - /** - * @notice Construct an empty delegate - */ - constructor() CErc20Delegate() {} - - /** - * @notice Admin call to delegate the votes of the COMP-like underlying - * @param compLikeDelegatee The address to delegate votes to - */ - function _delegateCompLikeTo(address compLikeDelegatee) external { - require( - msg.sender == admin, - "only the admin may set the comp-like delegate" - ); - CompLike(underlying).delegate(compLikeDelegatee); - } -} diff --git a/flatten/CErc20.sol b/flatten/CErc20.sol deleted file mode 100644 index 340321c..0000000 --- a/flatten/CErc20.sol +++ /dev/null @@ -1,4162 +0,0 @@ -// Dependency file: contracts/ComptrollerInterface.sol - -// SPDX-License-Identifier: UNLICENSED -// pragma solidity 0.8.6; - -abstract contract ComptrollerInterface { - /// @notice Indicator that this is a Comptroller contract (for inspection) - bool public constant isComptroller = true; - - /*** Assets You Are In ***/ - - function enterMarkets(address[] calldata cTokens) - external - virtual - returns (uint256[] memory); - - function exitMarket(address cToken) external virtual returns (uint256); - - /*** Policy Hooks ***/ - - function mintAllowed( - address cToken, - address minter, - uint256 mintAmount - ) external virtual returns (uint256); - - function mintVerify( - address cToken, - address minter, - uint256 mintAmount, - uint256 mintTokens - ) external virtual; - - function redeemAllowed( - address cToken, - address redeemer, - uint256 redeemTokens - ) external virtual returns (uint256); - - function redeemVerify( - address cToken, - address redeemer, - uint256 redeemAmount, - uint256 redeemTokens - ) external virtual; - - function borrowAllowed( - address cToken, - address borrower, - uint256 borrowAmount - ) external virtual returns (uint256); - - function borrowVerify( - address cToken, - address borrower, - uint256 borrowAmount - ) external virtual; - - function repayBorrowAllowed( - address cToken, - address payer, - address borrower, - uint256 repayAmount - ) external virtual returns (uint256); - - function repayBorrowVerify( - address cToken, - address payer, - address borrower, - uint256 repayAmount, - uint256 borrowerIndex - ) external virtual; - - function liquidateBorrowAllowed( - address cTokenBorrowed, - address cTokenCollateral, - address liquidator, - address borrower, - uint256 repayAmount - ) external virtual returns (uint256); - - function liquidateBorrowVerify( - address cTokenBorrowed, - address cTokenCollateral, - address liquidator, - address borrower, - uint256 repayAmount, - uint256 seizeTokens - ) external virtual; - - function seizeAllowed( - address cTokenCollateral, - address cTokenBorrowed, - address liquidator, - address borrower, - uint256 seizeTokens - ) external virtual returns (uint256); - - function seizeVerify( - address cTokenCollateral, - address cTokenBorrowed, - address liquidator, - address borrower, - uint256 seizeTokens - ) external virtual; - - function transferAllowed( - address cToken, - address src, - address dst, - uint256 transferTokens - ) external virtual returns (uint256); - - function transferVerify( - address cToken, - address src, - address dst, - uint256 transferTokens - ) external virtual; - - /*** Liquidity/Liquidation Calculations ***/ - - function liquidateCalculateSeizeTokens( - address cTokenBorrowed, - address cTokenCollateral, - uint256 repayAmount - ) external view virtual returns (uint256, uint256); -} - - -// Dependency file: contracts/CarefulMath.sol - -// pragma solidity 0.8.6; - -/** - * @title Careful Math - * @author tropykus - * @notice Derived from OpenZeppelin's SafeMath library - * https://github.com/OpenZeppelin/openzeppelin-solidity/blob/master/contracts/math/SafeMath.sol - */ -contract CarefulMath { - - /** - * @dev Possible error codes that we can return - */ - enum MathError { - NO_ERROR, - DIVISION_BY_ZERO, - INTEGER_OVERFLOW, - INTEGER_UNDERFLOW - } - - /** - * @dev Multiplies two numbers, returns an error on overflow. - */ - function mulUInt(uint a, uint b) internal pure returns (MathError, uint) { - if (a == 0) { - return (MathError.NO_ERROR, 0); - } - - uint c = a * b; - - if (c / a != b) { - return (MathError.INTEGER_OVERFLOW, 0); - } else { - return (MathError.NO_ERROR, c); - } - } - - /** - * @dev Integer division of two numbers, truncating the quotient. - */ - function divUInt(uint a, uint b) internal pure returns (MathError, uint) { - if (b == 0) { - return (MathError.DIVISION_BY_ZERO, 0); - } - - return (MathError.NO_ERROR, a / b); - } - - /** - * @dev Subtracts two numbers, returns an error on overflow (i.e. if subtrahend is greater than minuend). - */ - function subUInt(uint a, uint b) internal pure returns (MathError, uint) { - if (b <= a) { - return (MathError.NO_ERROR, a - b); - } else { - return (MathError.INTEGER_UNDERFLOW, 0); - } - } - - /** - * @dev Adds two numbers, returns an error on overflow. - */ - function addUInt(uint a, uint b) internal pure returns (MathError, uint) { - uint c = a + b; - - if (c >= a) { - return (MathError.NO_ERROR, c); - } else { - return (MathError.INTEGER_OVERFLOW, 0); - } - } - - /** - * @dev add a and b and then subtract c - */ - function addThenSubUInt(uint a, uint b, uint c) internal pure returns (MathError, uint) { - (MathError err0, uint sum) = addUInt(a, b); - - if (err0 != MathError.NO_ERROR) { - return (err0, 0); - } - - return subUInt(sum, c); - } -} - - -// Dependency file: contracts/ExponentialNoError.sol - -// pragma solidity 0.8.6; - -/** - * @title Exponential module for storing fixed-precision decimals - * @author tropykus - * @notice Exp is a struct which stores decimals with a fixed precision of 18 decimal places. - * Thus, if we wanted to store the 5.1, mantissa would store 5.1e18. That is: - * `Exp({mantissa: 5100000000000000000})`. - */ -contract ExponentialNoError { - uint constant expScale = 1e18; - uint constant doubleScale = 1e36; - uint constant halfExpScale = expScale/2; - uint constant mantissaOne = expScale; - - struct Exp { - uint mantissa; - } - - struct Double { - uint mantissa; - } - - /** - * @dev Truncates the given exp to a whole number value. - * For example, truncate(Exp{mantissa: 15 * expScale}) = 15 - */ - function truncate(Exp memory exp) pure internal returns (uint) { - // Note: We are not using careful math here as we're performing a division that cannot fail - return exp.mantissa / expScale; - } - - /** - * @dev Multiply an Exp by a scalar, then truncate to return an unsigned integer. - */ - function mul_ScalarTruncate(Exp memory a, uint scalar) pure internal returns (uint) { - Exp memory product = mul_(a, scalar); - return truncate(product); - } - - /** - * @dev Multiply an Exp by a scalar, truncate, then add an to an unsigned integer, returning an unsigned integer. - */ - function mul_ScalarTruncateAddUInt(Exp memory a, uint scalar, uint addend) pure internal returns (uint) { - Exp memory product = mul_(a, scalar); - return add_(truncate(product), addend); - } - - /** - * @dev Checks if first Exp is less than second Exp. - */ - function lessThanExp(Exp memory left, Exp memory right) pure internal returns (bool) { - return left.mantissa < right.mantissa; - } - - /** - * @dev Checks if left Exp <= right Exp. - */ - function lessThanOrEqualExp(Exp memory left, Exp memory right) pure internal returns (bool) { - return left.mantissa <= right.mantissa; - } - - /** - * @dev Checks if left Exp > right Exp. - */ - function greaterThanExp(Exp memory left, Exp memory right) pure internal returns (bool) { - return left.mantissa > right.mantissa; - } - - /** - * @dev returns true if Exp is exactly zero - */ - function isZeroExp(Exp memory value) pure internal returns (bool) { - return value.mantissa == 0; - } - - function safe224(uint n, string memory errorMessage) pure internal returns (uint224) { - require(n < 2**224, errorMessage); - return uint224(n); - } - - function safe32(uint n, string memory errorMessage) pure internal returns (uint32) { - require(n < 2**32, errorMessage); - return uint32(n); - } - - function add_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { - return Exp({mantissa: add_(a.mantissa, b.mantissa)}); - } - - function add_(Double memory a, Double memory b) pure internal returns (Double memory) { - return Double({mantissa: add_(a.mantissa, b.mantissa)}); - } - - function add_(uint a, uint b) pure internal returns (uint) { - return add_(a, b, "addition overflow"); - } - - function add_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { - uint c = a + b; - require(c >= a, errorMessage); - return c; - } - - function sub_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { - return Exp({mantissa: sub_(a.mantissa, b.mantissa)}); - } - - function sub_(Double memory a, Double memory b) pure internal returns (Double memory) { - return Double({mantissa: sub_(a.mantissa, b.mantissa)}); - } - - function sub_(uint a, uint b) pure internal returns (uint) { - return sub_(a, b, "subtraction underflow"); - } - - function sub_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { - require(b <= a, errorMessage); - return a - b; - } - - function mul_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { - return Exp({mantissa: mul_(a.mantissa, b.mantissa) / expScale}); - } - - function mul_(Exp memory a, uint b) pure internal returns (Exp memory) { - return Exp({mantissa: mul_(a.mantissa, b)}); - } - - function mul_(uint a, Exp memory b) pure internal returns (uint) { - return mul_(a, b.mantissa) / expScale; - } - - function mul_(Double memory a, Double memory b) pure internal returns (Double memory) { - return Double({mantissa: mul_(a.mantissa, b.mantissa) / doubleScale}); - } - - function mul_(Double memory a, uint b) pure internal returns (Double memory) { - return Double({mantissa: mul_(a.mantissa, b)}); - } - - function mul_(uint a, Double memory b) pure internal returns (uint) { - return mul_(a, b.mantissa) / doubleScale; - } - - function mul_(uint a, uint b) pure internal returns (uint) { - return mul_(a, b, "multiplication overflow"); - } - - function mul_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { - if (a == 0 || b == 0) { - return 0; - } - uint c = a * b; - require(c / a == b, errorMessage); - return c; - } - - function div_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { - return Exp({mantissa: div_(mul_(a.mantissa, expScale), b.mantissa)}); - } - - function div_(Exp memory a, uint b) pure internal returns (Exp memory) { - return Exp({mantissa: div_(a.mantissa, b)}); - } - - function div_(uint a, Exp memory b) pure internal returns (uint) { - return div_(mul_(a, expScale), b.mantissa); - } - - function div_(Double memory a, Double memory b) pure internal returns (Double memory) { - return Double({mantissa: div_(mul_(a.mantissa, doubleScale), b.mantissa)}); - } - - function div_(Double memory a, uint b) pure internal returns (Double memory) { - return Double({mantissa: div_(a.mantissa, b)}); - } - - function div_(uint a, Double memory b) pure internal returns (uint) { - return div_(mul_(a, doubleScale), b.mantissa); - } - - function div_(uint a, uint b) pure internal returns (uint) { - return div_(a, b, "divide by zero"); - } - - function div_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { - require(b > 0, errorMessage); - return a / b; - } - - function fraction(uint a, uint b) pure internal returns (Double memory) { - return Double({mantissa: div_(mul_(a, doubleScale), b)}); - } -} - - -// Dependency file: contracts/Exponential.sol - -// pragma solidity 0.8.6; - -// import "contracts/CarefulMath.sol"; -// import "contracts/ExponentialNoError.sol"; - -/** - * @title Exponential module for storing fixed-precision decimals - * @author tropykus - * @dev Legacy contract for compatibility reasons with existing contracts that still use MathError - * @notice Exp is a struct which stores decimals with a fixed precision of 18 decimal places. - * Thus, if we wanted to store the 5.1, mantissa would store 5.1e18. That is: - * `Exp({mantissa: 5100000000000000000})`. - */ -contract Exponential is CarefulMath, ExponentialNoError { - /** - * @dev Creates an exponential from numerator and denominator values. - * Note: Returns an error if (`num` * 10e18) > MAX_INT, - * or if `denom` is zero. - */ - function getExp(uint num, uint denom) internal pure returns (MathError, Exp memory) { - (MathError err0, uint scaledNumerator) = mulUInt(num, expScale); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - - (MathError err1, uint rational) = divUInt(scaledNumerator, denom); - if (err1 != MathError.NO_ERROR) { - return (err1, Exp({mantissa: 0})); - } - - return (MathError.NO_ERROR, Exp({mantissa: rational})); - } - - /** - * @dev Adds two exponentials, returning a new exponential. - */ - function addExp(Exp memory a, Exp memory b) internal pure returns (MathError, Exp memory) { - (MathError error, uint result) = addUInt(a.mantissa, b.mantissa); - - return (error, Exp({mantissa: result})); - } - - /** - * @dev Subtracts two exponentials, returning a new exponential. - */ - function subExp(Exp memory a, Exp memory b) internal pure returns (MathError, Exp memory) { - (MathError error, uint result) = subUInt(a.mantissa, b.mantissa); - - return (error, Exp({mantissa: result})); - } - - /** - * @dev Multiply an Exp by a scalar, returning a new Exp. - */ - function mulScalar(Exp memory a, uint scalar) internal pure returns (MathError, Exp memory) { - (MathError err0, uint scaledMantissa) = mulUInt(a.mantissa, scalar); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - - return (MathError.NO_ERROR, Exp({mantissa: scaledMantissa})); - } - - /** - * @dev Multiply an Exp by a scalar, then truncate to return an unsigned integer. - */ - function mulScalarTruncate(Exp memory a, uint scalar) internal pure returns (MathError, uint) { - (MathError err, Exp memory product) = mulScalar(a, scalar); - if (err != MathError.NO_ERROR) { - return (err, 0); - } - - return (MathError.NO_ERROR, truncate(product)); - } - - /** - * @dev Multiply an Exp by a scalar, truncate, then add an to an unsigned integer, returning an unsigned integer. - */ - function mulScalarTruncateAddUInt(Exp memory a, uint scalar, uint addend) internal pure returns (MathError, uint) { - (MathError err, Exp memory product) = mulScalar(a, scalar); - if (err != MathError.NO_ERROR) { - return (err, 0); - } - - return addUInt(truncate(product), addend); - } - - /** - * @dev Divide an Exp by a scalar, returning a new Exp. - */ - function divScalar(Exp memory a, uint scalar) internal pure returns (MathError, Exp memory) { - (MathError err0, uint descaledMantissa) = divUInt(a.mantissa, scalar); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - - return (MathError.NO_ERROR, Exp({mantissa: descaledMantissa})); - } - - /** - * @dev Divide a scalar by an Exp, returning a new Exp. - */ - function divScalarByExp(uint scalar, Exp memory divisor) internal pure returns (MathError, Exp memory) { - /* - We are doing this as: - getExp(mulUInt(expScale, scalar), divisor.mantissa) - - How it works: - Exp = a / b; - Scalar = s; - `s / (a / b)` = `b * s / a` and since for an Exp `a = mantissa, b = expScale` - */ - (MathError err0, uint numerator) = mulUInt(expScale, scalar); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - return getExp(numerator, divisor.mantissa); - } - - /** - * @dev Divide a scalar by an Exp, then truncate to return an unsigned integer. - */ - function divScalarByExpTruncate(uint scalar, Exp memory divisor) internal pure returns (MathError, uint) { - (MathError err, Exp memory fraction) = divScalarByExp(scalar, divisor); - if (err != MathError.NO_ERROR) { - return (err, 0); - } - - return (MathError.NO_ERROR, truncate(fraction)); - } - - /** - * @dev Multiplies two exponentials, returning a new exponential. - */ - function mulExp(Exp memory a, Exp memory b) internal pure returns (MathError, Exp memory) { - - (MathError err0, uint doubleScaledProduct) = mulUInt(a.mantissa, b.mantissa); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - - // We add half the scale before dividing so that we get rounding instead of truncation. - // See "Listing 6" and text above it at https://accu.org/index.php/journals/1717 - // Without this change, a result like 6.6...e-19 will be truncated to 0 instead of being rounded to 1e-18. - (MathError err1, uint doubleScaledProductWithHalfScale) = addUInt(halfExpScale, doubleScaledProduct); - if (err1 != MathError.NO_ERROR) { - return (err1, Exp({mantissa: 0})); - } - - (MathError err2, uint product) = divUInt(doubleScaledProductWithHalfScale, expScale); - // The only error `div` can return is MathError.DIVISION_BY_ZERO but we control `expScale` and it is not zero. - assert(err2 == MathError.NO_ERROR); - - return (MathError.NO_ERROR, Exp({mantissa: product})); - } - - /** - * @dev Multiplies two exponentials given their mantissas, returning a new exponential. - */ - function mulExp(uint a, uint b) internal pure returns (MathError, Exp memory) { - return mulExp(Exp({mantissa: a}), Exp({mantissa: b})); - } - - /** - * @dev Multiplies three exponentials, returning a new exponential. - */ - function mulExp3(Exp memory a, Exp memory b, Exp memory c) internal pure returns (MathError, Exp memory) { - (MathError err, Exp memory ab) = mulExp(a, b); - if (err != MathError.NO_ERROR) { - return (err, ab); - } - return mulExp(ab, c); - } - - /** - * @dev Divides two exponentials, returning a new exponential. - * (a/scale) / (b/scale) = (a/scale) * (scale/b) = a/b, - * which we can scale as an Exp by calling getExp(a.mantissa, b.mantissa) - */ - function divExp(Exp memory a, Exp memory b) internal pure returns (MathError, Exp memory) { - return getExp(a.mantissa, b.mantissa); - } -} - - -// Dependency file: contracts/SafeMath.sol - -// pragma solidity 0.8.6; - -// From https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/math/Math.sol -// Subject to the MIT license. - -/** - * @dev Wrappers over Solidity's arithmetic operations with added overflow - * checks. - * - * Arithmetic operations in Solidity wrap on overflow. This can easily result - * in bugs, because programmers usually assume that an overflow raises an - * error, which is the standard behavior in high level programming languages. - * `SafeMath` restores this intuition by reverting the transaction when an - * operation overflows. - * - * Using this library instead of the unchecked operations eliminates an entire - * class of bugs, so it's recommended to use it always. - */ -library SafeMath { - /** - * @dev Returns the addition of two unsigned integers, reverting on overflow. - * - * Counterpart to Solidity's `+` operator. - * - * Requirements: - * - Addition cannot overflow. - */ - function add(uint256 a, uint256 b) internal pure returns (uint256) { - uint256 c = a + b; - require(c >= a, "SafeMath: addition overflow"); - - return c; - } - - /** - * @dev Returns the addition of two unsigned integers, reverting with custom message on overflow. - * - * Counterpart to Solidity's `+` operator. - * - * Requirements: - * - Addition cannot overflow. - */ - function add(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - uint256 c = a + b; - require(c >= a, errorMessage); - - return c; - } - - /** - * @dev Returns the subtraction of two unsigned integers, reverting on underflow (when the result is negative). - * - * Counterpart to Solidity's `-` operator. - * - * Requirements: - * - Subtraction cannot underflow. - */ - function sub(uint256 a, uint256 b) internal pure returns (uint256) { - return sub(a, b, "SafeMath: subtraction underflow"); - } - - /** - * @dev Returns the subtraction of two unsigned integers, reverting with custom message on underflow (when the result is negative). - * - * Counterpart to Solidity's `-` operator. - * - * Requirements: - * - Subtraction cannot underflow. - */ - function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - require(b <= a, errorMessage); - uint256 c = a - b; - - return c; - } - - /** - * @dev Returns the multiplication of two unsigned integers, reverting on overflow. - * - * Counterpart to Solidity's `*` operator. - * - * Requirements: - * - Multiplication cannot overflow. - */ - function mul(uint256 a, uint256 b) internal pure returns (uint256) { - // Gas optimization: this is cheaper than requiring 'a' not being zero, but the - // benefit is lost if 'b' is also tested. - // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 - if (a == 0) { - return 0; - } - - uint256 c = a * b; - require(c / a == b, "SafeMath: multiplication overflow"); - - return c; - } - - /** - * @dev Returns the multiplication of two unsigned integers, reverting on overflow. - * - * Counterpart to Solidity's `*` operator. - * - * Requirements: - * - Multiplication cannot overflow. - */ - function mul(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - // Gas optimization: this is cheaper than requiring 'a' not being zero, but the - // benefit is lost if 'b' is also tested. - // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 - if (a == 0) { - return 0; - } - - uint256 c = a * b; - require(c / a == b, errorMessage); - - return c; - } - - /** - * @dev Returns the integer division of two unsigned integers. - * Reverts on division by zero. The result is rounded towards zero. - * - * Counterpart to Solidity's `/` operator. Note: this function uses a - * `revert` opcode (which leaves remaining gas untouched) while Solidity - * uses an invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function div(uint256 a, uint256 b) internal pure returns (uint256) { - return div(a, b, "SafeMath: division by zero"); - } - - /** - * @dev Returns the integer division of two unsigned integers. - * Reverts with custom message on division by zero. The result is rounded towards zero. - * - * Counterpart to Solidity's `/` operator. Note: this function uses a - * `revert` opcode (which leaves remaining gas untouched) while Solidity - * uses an invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - // Solidity only automatically asserts when dividing by 0 - require(b > 0, errorMessage); - uint256 c = a / b; - // assert(a == b * c + a % b); // There is no case in which this doesn't hold - - return c; - } - - /** - * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), - * Reverts when dividing by zero. - * - * Counterpart to Solidity's `%` operator. This function uses a `revert` - * opcode (which leaves remaining gas untouched) while Solidity uses an - * invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function mod(uint256 a, uint256 b) internal pure returns (uint256) { - return mod(a, b, "SafeMath: modulo by zero"); - } - - /** - * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), - * Reverts with custom message when dividing by zero. - * - * Counterpart to Solidity's `%` operator. This function uses a `revert` - * opcode (which leaves remaining gas untouched) while Solidity uses an - * invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - require(b != 0, errorMessage); - return a % b; - } -} - - -// Dependency file: contracts/InterestRateModel.sol - -// pragma solidity 0.8.6; - -// import "contracts/Exponential.sol"; -// import "contracts/SafeMath.sol"; - -/** - * @title tropykus InterestRateModel Interface - * @author tropykus - */ -abstract contract InterestRateModel is Exponential { - using SafeMath for uint256; - - /// @notice Indicator that this is an InterestRateModel contract (for inspection) - bool public constant isInterestRateModel = true; - bool public isTropykusInterestRateModel; - - /** - * @notice The approximate number of blocks per year that is assumed by the interest rate model - */ - uint256 public constant blocksPerYear = 1051200; - - /** - * @notice Calculates the utilization rate of the market: `borrows / (cash + borrows - reserves)` - * @param cash The amount of cash in the market - * @param borrows The amount of borrows in the market - * @param reserves The amount of reserves in the market (currently unused) - * @return The utilization rate as a mantissa between [0, 1e18] - */ - function utilizationRate( - uint256 cash, - uint256 borrows, - uint256 reserves - ) public pure virtual returns (uint256) { - // Utilization rate is 0 when there are no borrows - if (borrows == 0) { - return 0; - } - - return borrows.mul(1e18).div(cash.add(borrows).sub(reserves)); - } - - /** - * @notice Calculates the current borrow interest rate per block - * @param cash The total amount of cash the market has - * @param borrows The total amount of borrows the market has outstanding - * @param reserves The total amnount of reserves the market has - * @return The borrow rate per block (as a percentage, and scaled by 1e18) - */ - function getBorrowRate( - uint256 cash, - uint256 borrows, - uint256 reserves - ) external view virtual returns (uint256); - - /** - * @notice Calculates the current supply interest rate per block - * @param cash The total amount of cash the market has - * @param borrows The total amount of borrows the market has outstanding - * @param reserves The total amnount of reserves the market has - * @param reserveFactorMantissa The current reserve factor the market has - * @return The supply rate per block (as a percentage, and scaled by 1e18) - */ - function getSupplyRate( - uint256 cash, - uint256 borrows, - uint256 reserves, - uint256 reserveFactorMantissa - ) external view virtual returns (uint256); - - function getExchangeRate( - uint256 _totalCash, - uint256 _totalBorrows, - uint256 _totalReserves, - uint256 _totalSupply - ) public pure returns (MathError, uint256) { - /* - * exchangeRate = (totalCash + totalBorrows - totalReserves) / totalSupply - */ - Exp memory exchangeRate; - MathError mathErr; - uint256 cashPlusBorrowsMinusReserves; - (mathErr, cashPlusBorrowsMinusReserves) = addThenSubUInt( - _totalCash, - _totalBorrows, - _totalReserves - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - (mathErr, exchangeRate) = getExp( - cashPlusBorrowsMinusReserves, - _totalSupply - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - - return (MathError.NO_ERROR, exchangeRate.mantissa); - } - - function isAboveOptimal( - uint256 cash, - uint256 borrows, - uint256 reserves - ) public view virtual returns (bool) { - cash; - borrows; - reserves; - return false; - } -} - - -// Dependency file: contracts/EIP20NonStandardInterface.sol - -// pragma solidity 0.8.6; - -/** - * @title EIP20NonStandardInterface - * @dev Version of ERC20 with no return values for `transfer` and `transferFrom` - * See https://medium.com/coinmonks/missing-return-value-bug-at-least-130-tokens-affected-d67bf08521ca - */ -interface EIP20NonStandardInterface { - /** - * @notice Get the total number of tokens in circulation - * @return The supply of tokens - */ - function totalSupply() external view returns (uint256); - - /** - * @notice Gets the balance of the specified address - * @param owner The address from which the balance will be retrieved - * @return balance The balance - */ - function balanceOf(address owner) external view returns (uint256 balance); - - /// - /// !!!!!!!!!!!!!! - /// !!! NOTICE !!! `transfer` does not return a value, in violation of the ERC-20 specification - /// !!!!!!!!!!!!!! - /// - - /** - * @notice Transfer `amount` tokens from `msg.sender` to `dst` - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - */ - function transfer(address dst, uint256 amount) external; - - /// - /// !!!!!!!!!!!!!! - /// !!! NOTICE !!! `transferFrom` does not return a value, in violation of the ERC-20 specification - /// !!!!!!!!!!!!!! - /// - - /** - * @notice Transfer `amount` tokens from `src` to `dst` - * @param src The address of the source account - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - */ - function transferFrom( - address src, - address dst, - uint256 amount - ) external; - - /** - * @notice Approve `spender` to transfer up to `amount` from `src` - * @dev This will overwrite the approval amount for `spender` - * and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve) - * @param spender The address of the account which may transfer tokens - * @param amount The number of tokens that are approved - * @return success Whether or not the approval succeeded - */ - function approve(address spender, uint256 amount) - external - returns (bool success); - - /** - * @notice Get the current allowance from `owner` for `spender` - * @param owner The address of the account which owns the tokens to be spent - * @param spender The address of the account which may transfer tokens - * @return remaining The number of tokens allowed to be spent - */ - function allowance(address owner, address spender) - external - view - returns (uint256 remaining); - - event Transfer(address indexed from, address indexed to, uint256 amount); - event Approval( - address indexed owner, - address indexed spender, - uint256 amount - ); -} - - -// Dependency file: contracts/CTokenInterfaces.sol - -// pragma solidity 0.8.6; - -// import "contracts/ComptrollerInterface.sol"; -// import "contracts/InterestRateModel.sol"; -// import "contracts/EIP20NonStandardInterface.sol"; - -contract CTokenStorage { - /** - * @dev Guard variable for re-entrancy checks - */ - bool internal _notEntered; - - /** - * @notice EIP-20 token name for this token - */ - string public name; - - /** - * @notice EIP-20 token symbol for this token - */ - string public symbol; - - /** - * @notice EIP-20 token decimals for this token - */ - uint8 public decimals; - - /** - * @notice Maximum borrow rate that can ever be applied (.0005% / block) - */ - - uint256 internal constant borrowRateMaxMantissa = 0.0005e16; - - /** - * @notice Maximum fraction of interest that can be set aside for reserves - */ - uint256 internal constant reserveFactorMaxMantissa = 1e18; - - /** - * @notice Administrator for this contract - */ - address payable public admin; - - /** - * @notice Pending administrator for this contract - */ - address payable public pendingAdmin; - - /** - * @notice Contract which oversees inter-cToken operations - */ - ComptrollerInterface public comptroller; - - /** - * @notice Model which tells what the current interest rate should be - */ - InterestRateModel public interestRateModel; - - /** - * @notice Initial exchange rate used when minting the first CTokens (used when totalSupply = 0) - */ - uint256 public initialExchangeRateMantissa; - - /** - * @notice Fraction of interest currently set aside for reserves - */ - uint256 public reserveFactorMantissa; - - /** - * @notice Block number that interest was last accrued at - */ - uint256 public accrualBlockNumber; - - /** - * @notice Accumulator of the total earned interest rate since the opening of the market - */ - uint256 public borrowIndex; - - /** - * @notice Total amount of outstanding borrows of the underlying in this market - */ - uint256 public totalBorrows; - - /** - * @notice Total amount of reserves of the underlying held in this market - */ - uint256 public totalReserves; - - /** - * @notice Total number of tokens in circulation - */ - uint256 public totalSupply; - - uint256 public subsidyFund; - - struct SupplySnapshot { - uint256 tokens; - uint256 underlyingAmount; - uint256 suppliedAt; - uint256 promisedSupplyRate; - } - - /** - * @notice Official record of token balances for each account - */ - mapping(address => SupplySnapshot) internal accountTokens; - - /** - * @notice Approved token transfer amounts on behalf of others - */ - mapping(address => mapping(address => uint256)) internal transferAllowances; - - /** - * @notice Container for borrow balance information - * @member principal Total balance (with accrued interest), after applying the most recent balance-changing action - * @member interestIndex Global borrowIndex as of the most recent balance-changing action - */ - struct BorrowSnapshot { - uint256 principal; - uint256 interestIndex; - } - - /** - * @notice Mapping of account addresses to outstanding borrow balances - */ - mapping(address => BorrowSnapshot) internal accountBorrows; -} - -abstract contract CTokenInterface is CTokenStorage { - /** - * @notice Indicator that this is a CToken contract (for inspection) - */ - bool public constant isCToken = true; - - /*** Market Events ***/ - - /** - * @notice Event emitted when interest is accrued - */ - event AccrueInterest( - uint256 cashPrior, - uint256 interestAccumulated, - uint256 borrowIndex, - uint256 totalBorrows - ); - - /** - * @notice Event emitted when tokens are minted - */ - event Mint(address indexed minter, uint256 mintAmount, uint256 mintTokens); - - /** - * @notice Event emitted when tokens are redeemed - */ - event Redeem( - address indexed redeemer, - uint256 redeemAmount, - uint256 redeemTokens - ); - - /** - * @notice Event emitted when underlying is borrowed - */ - event Borrow( - address indexed borrower, - uint256 borrowAmount, - uint256 accountBorrows, - uint256 totalBorrows - ); - - /** - * @notice Event emitted when a borrow is repaid - */ - event RepayBorrow( - address indexed payer, - address indexed borrower, - uint256 repayAmount, - uint256 accountBorrows, - uint256 totalBorrows - ); - - /** - * @notice Event emitted when a borrow is liquidated - */ - event LiquidateBorrow( - address indexed liquidator, - address indexed borrower, - uint256 repayAmount, - address indexed cTokenCollateral, - uint256 seizeTokens - ); - - /*** Admin Events ***/ - - /** - * @notice Event emitted when pendingAdmin is changed - */ - event NewPendingAdmin(address oldPendingAdmin, address newPendingAdmin); - - /** - * @notice Event emitted when pendingAdmin is accepted, which means admin is updated - */ - event NewAdmin(address oldAdmin, address newAdmin); - - /** - * @notice Event emitted when comptroller is changed - */ - event NewComptroller( - ComptrollerInterface oldComptroller, - ComptrollerInterface newComptroller - ); - - /** - * @notice Event emitted when interestRateModel is changed - */ - event NewMarketInterestRateModel( - InterestRateModel oldInterestRateModel, - InterestRateModel newInterestRateModel - ); - - /** - * @notice Event emitted when the reserve factor is changed - */ - event NewReserveFactor( - uint256 oldReserveFactorMantissa, - uint256 newReserveFactorMantissa - ); - - /** - * @notice Event emitted when the reserves are added - */ - event ReservesAdded( - address benefactor, - uint256 addAmount, - uint256 newTotalReserves - ); - - event SubsidyAdded( - address benefactor, - uint256 addAmount, - uint256 newSubsidyFund - ); - - /** - * @notice Event emitted when the reserves are reduced - */ - event ReservesReduced( - address admin, - uint256 reduceAmount, - uint256 newTotalReserves - ); - - /** - * @notice EIP20 Transfer event - */ - event Transfer(address indexed from, address indexed to, uint256 amount); - - /** - * @notice EIP20 Approval event - */ - event Approval( - address indexed owner, - address indexed spender, - uint256 amount - ); - - /** - * @notice Failure event - */ - event CTokenStorageFailure(uint256 error, uint256 info, uint256 detail); - - /*** User Interface ***/ - - function transfer(address dst, uint256 amount) - external - virtual - returns (bool); - - function transferFrom( - address src, - address dst, - uint256 amount - ) external virtual returns (bool); - - function approve(address spender, uint256 amount) - external - virtual - returns (bool); - - function allowance(address owner, address spender) - external - view - virtual - returns (uint256); - - function balanceOf(address owner) external view virtual returns (uint256); - - function balanceOfUnderlying(address owner) - external - virtual - returns (uint256); - - function getAccountSnapshot(address account) - external - view - virtual - returns ( - uint256, - uint256, - uint256, - uint256 - ); - - function borrowRatePerBlock() external view virtual returns (uint256); - - function supplyRatePerBlock() external view virtual returns (uint256); - - function totalBorrowsCurrent() external virtual returns (uint256); - - function borrowBalanceCurrent(address account) - external - virtual - returns (uint256); - - function borrowBalanceStored(address account) - public - view - virtual - returns (uint256); - - function exchangeRateCurrent() public virtual returns (uint256); - - function exchangeRateStored() public view virtual returns (uint256); - - function getCash() external view virtual returns (uint256); - - function accrueInterest() public virtual returns (uint256); - - function seize( - address liquidator, - address borrower, - uint256 seizeTokens - ) external virtual returns (uint256); - - /*** Admin Functions ***/ - - function _setPendingAdmin(address payable newPendingAdmin) - external - virtual - returns (uint256); - - function _acceptAdmin() external virtual returns (uint256); - - function _setComptroller(ComptrollerInterface newComptroller) - public - virtual - returns (uint256); - - function _setReserveFactor(uint256 newReserveFactorMantissa) - external - virtual - returns (uint256); - - function _reduceReserves(uint256 reduceAmount) - external - virtual - returns (uint256); - - function _setInterestRateModel(InterestRateModel newInterestRateModel) - public - virtual - returns (uint256); -} - -contract CErc20Storage { - /** - * @notice Underlying asset for this CToken - */ - address public underlying; -} - -abstract contract CErc20Interface is CErc20Storage { - /*** User Interface ***/ - - function mint(uint256 mintAmount) external virtual returns (uint256); - - function redeem(uint256 redeemAmount) - external - virtual - returns (uint256); - - function borrow(uint256 borrowAmount) external virtual returns (uint256); - - function repayBorrow(uint256 repayAmount) - external - virtual - returns (uint256); - - function liquidateBorrow( - address borrower, - uint256 repayAmount, - CTokenInterface cTokenCollateral - ) external virtual returns (uint256); - - function sweepToken(EIP20NonStandardInterface token) external virtual; - - /*** Admin Functions ***/ - - function _addReserves(uint256 addAmount) external virtual returns (uint256); -} - -contract CDelegationStorage { - /** - * @notice Implementation address for this contract - */ - address public implementation; -} - -abstract contract CDelegatorInterface is CDelegationStorage { - /** - * @notice Emitted when implementation is changed - */ - event NewImplementation( - address oldImplementation, - address newImplementation - ); - - /** - * @notice Called by the admin to update the implementation of the delegator - * @param implementation_ The address of the new implementation for delegation - * @param allowResign Flag to indicate whether to call _resignImplementation on the old implementation - * @param becomeImplementationData The encoded bytes data to be passed to _becomeImplementation - */ - function _setImplementation( - address implementation_, - bool allowResign, - bytes memory becomeImplementationData - ) public virtual; -} - -abstract contract CDelegateInterface is CDelegationStorage { - /** - * @notice Called by the delegator on a delegate to initialize it for duty - * @dev Should revert if any issues arise which make it unfit for delegation - * @param data The encoded bytes data for any initialization - */ - function _becomeImplementation(bytes memory data) public virtual; - - /** - * @notice Called by the delegator on a delegate to forfeit its responsibility - */ - function _resignImplementation() public virtual; -} - - -// Dependency file: contracts/ErrorReporter.sol - -// pragma solidity 0.8.6; - -contract ComptrollerErrorReporter { - enum Error { - NO_ERROR, - UNAUTHORIZED, - COMPTROLLER_MISMATCH, - INSUFFICIENT_SHORTFALL, - INSUFFICIENT_LIQUIDITY, - INVALID_CLOSE_FACTOR, - INVALID_COLLATERAL_FACTOR, - INVALID_LIQUIDATION_INCENTIVE, - MARKET_NOT_ENTERED, // no longer possible - MARKET_NOT_LISTED, - MARKET_ALREADY_LISTED, - MATH_ERROR, - NONZERO_BORROW_BALANCE, - PRICE_ERROR, - REJECTION, - SNAPSHOT_ERROR, - TOO_MANY_ASSETS, - TOO_MUCH_REPAY - } - - enum FailureInfo { - ACCEPT_ADMIN_PENDING_ADMIN_CHECK, - ACCEPT_PENDING_IMPLEMENTATION_ADDRESS_CHECK, - EXIT_MARKET_BALANCE_OWED, - EXIT_MARKET_REJECTION, - SET_CLOSE_FACTOR_OWNER_CHECK, - SET_CLOSE_FACTOR_VALIDATION, - SET_COLLATERAL_FACTOR_OWNER_CHECK, - SET_COLLATERAL_FACTOR_NO_EXISTS, - SET_COLLATERAL_FACTOR_VALIDATION, - SET_COLLATERAL_FACTOR_WITHOUT_PRICE, - SET_IMPLEMENTATION_OWNER_CHECK, - SET_LIQUIDATION_INCENTIVE_OWNER_CHECK, - SET_LIQUIDATION_INCENTIVE_VALIDATION, - SET_MAX_ASSETS_OWNER_CHECK, - SET_PENDING_ADMIN_OWNER_CHECK, - SET_PENDING_IMPLEMENTATION_OWNER_CHECK, - SET_PRICE_ORACLE_OWNER_CHECK, - SUPPORT_MARKET_EXISTS, - SUPPORT_MARKET_OWNER_CHECK, - SET_PAUSE_GUARDIAN_OWNER_CHECK - } - - /** - * @dev `error` corresponds to enum Error; `info` corresponds to enum FailureInfo, and `detail` is an arbitrary - * contract-specific code that enables us to report opaque error codes from upgradeable contracts. - **/ - event Failure(uint256 error, uint256 info, uint256 detail); - - /** - * @dev use this when reporting a known error from the money market or a non-upgradeable collaborator - */ - function fail(Error err, FailureInfo info) internal returns (uint256) { - emit Failure(uint256(err), uint256(info), 0); - - return uint256(err); - } - - /** - * @dev use this when reporting an opaque error from an upgradeable collaborator contract - */ - function failOpaque( - Error err, - FailureInfo info, - uint256 opaqueError - ) internal returns (uint256) { - emit Failure(uint256(err), uint256(info), opaqueError); - - return uint256(err); - } -} - -contract TokenErrorReporter { - enum Error { - NO_ERROR, - UNAUTHORIZED, - BAD_INPUT, - COMPTROLLER_REJECTION, - COMPTROLLER_CALCULATION_ERROR, - INTEREST_RATE_MODEL_ERROR, - INVALID_ACCOUNT_PAIR, - INVALID_CLOSE_AMOUNT_REQUESTED, - INVALID_COLLATERAL_FACTOR, - MATH_ERROR, - MARKET_NOT_FRESH, - MARKET_NOT_LISTED, - TOKEN_INSUFFICIENT_ALLOWANCE, - TOKEN_INSUFFICIENT_BALANCE, - TOKEN_INSUFFICIENT_CASH, - TOKEN_TRANSFER_IN_FAILED, - TOKEN_TRANSFER_OUT_FAILED - } - - /* - * Note: FailureInfo (but not Error) is kept in alphabetical order - * This is because FailureInfo grows significantly faster, and - * the order of Error has some meaning, while the order of FailureInfo - * is entirely arbitrary. - */ - enum FailureInfo { - ACCEPT_ADMIN_PENDING_ADMIN_CHECK, - ACCRUE_INTEREST_ACCUMULATED_INTEREST_CALCULATION_FAILED, - ACCRUE_INTEREST_BORROW_RATE_CALCULATION_FAILED, - ACCRUE_INTEREST_NEW_BORROW_INDEX_CALCULATION_FAILED, - ACCRUE_INTEREST_NEW_TOTAL_BORROWS_CALCULATION_FAILED, - ACCRUE_INTEREST_NEW_TOTAL_RESERVES_CALCULATION_FAILED, - ACCRUE_INTEREST_SIMPLE_INTEREST_FACTOR_CALCULATION_FAILED, - BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED, - BORROW_ACCRUE_INTEREST_FAILED, - BORROW_CASH_NOT_AVAILABLE, - BORROW_FRESHNESS_CHECK, - BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED, - BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED, - BORROW_MARKET_NOT_LISTED, - BORROW_COMPTROLLER_REJECTION, - LIQUIDATE_ACCRUE_BORROW_INTEREST_FAILED, - LIQUIDATE_ACCRUE_COLLATERAL_INTEREST_FAILED, - LIQUIDATE_COLLATERAL_FRESHNESS_CHECK, - LIQUIDATE_COMPTROLLER_REJECTION, - LIQUIDATE_COMPTROLLER_CALCULATE_AMOUNT_SEIZE_FAILED, - LIQUIDATE_CLOSE_AMOUNT_IS_UINT_MAX, - LIQUIDATE_CLOSE_AMOUNT_IS_ZERO, - LIQUIDATE_FRESHNESS_CHECK, - LIQUIDATE_LIQUIDATOR_IS_BORROWER, - LIQUIDATE_REPAY_BORROW_FRESH_FAILED, - LIQUIDATE_SEIZE_BALANCE_INCREMENT_FAILED, - LIQUIDATE_SEIZE_BALANCE_DECREMENT_FAILED, - LIQUIDATE_SEIZE_COMPTROLLER_REJECTION, - LIQUIDATE_SEIZE_LIQUIDATOR_IS_BORROWER, - LIQUIDATE_SEIZE_TOO_MUCH, - MINT_ACCRUE_INTEREST_FAILED, - MINT_COMPTROLLER_REJECTION, - MINT_EXCHANGE_CALCULATION_FAILED, - MINT_EXCHANGE_RATE_READ_FAILED, - MINT_FRESHNESS_CHECK, - MINT_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED, - MINT_NEW_TOTAL_SUPPLY_CALCULATION_FAILED, - MINT_TRANSFER_IN_FAILED, - MINT_TRANSFER_IN_NOT_POSSIBLE, - REDEEM_ACCRUE_INTEREST_FAILED, - REDEEM_COMPTROLLER_REJECTION, - REDEEM_EXCHANGE_TOKENS_CALCULATION_FAILED, - REDEEM_EXCHANGE_AMOUNT_CALCULATION_FAILED, - REDEEM_EXCHANGE_RATE_READ_FAILED, - REDEEM_FRESHNESS_CHECK, - REDEEM_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED, - REDEEM_NEW_TOTAL_SUPPLY_CALCULATION_FAILED, - REDEEM_TRANSFER_OUT_NOT_POSSIBLE, - REDUCE_RESERVES_ACCRUE_INTEREST_FAILED, - REDUCE_RESERVES_ADMIN_CHECK, - REDUCE_RESERVES_CASH_NOT_AVAILABLE, - REDUCE_RESERVES_FRESH_CHECK, - REDUCE_RESERVES_VALIDATION, - REPAY_BEHALF_ACCRUE_INTEREST_FAILED, - REPAY_BORROW_ACCRUE_INTEREST_FAILED, - REPAY_BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED, - REPAY_BORROW_COMPTROLLER_REJECTION, - REPAY_BORROW_FRESHNESS_CHECK, - REPAY_BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED, - REPAY_BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED, - REPAY_BORROW_TRANSFER_IN_NOT_POSSIBLE, - SET_COLLATERAL_FACTOR_OWNER_CHECK, - SET_COLLATERAL_FACTOR_VALIDATION, - SET_COMPTROLLER_OWNER_CHECK, - SET_INTEREST_RATE_MODEL_ACCRUE_INTEREST_FAILED, - SET_INTEREST_RATE_MODEL_FRESH_CHECK, - SET_INTEREST_RATE_MODEL_OWNER_CHECK, - SET_MAX_ASSETS_OWNER_CHECK, - SET_ORACLE_MARKET_NOT_LISTED, - SET_PENDING_ADMIN_OWNER_CHECK, - SET_RESERVE_FACTOR_ACCRUE_INTEREST_FAILED, - SET_RESERVE_FACTOR_ADMIN_CHECK, - SET_RESERVE_FACTOR_FRESH_CHECK, - SET_RESERVE_FACTOR_BOUNDS_CHECK, - TRANSFER_COMPTROLLER_REJECTION, - TRANSFER_NOT_ALLOWED, - TRANSFER_NOT_ENOUGH, - TRANSFER_TOO_MUCH, - ADD_RESERVES_ACCRUE_INTEREST_FAILED, - ADD_RESERVES_FRESH_CHECK, - ADD_RESERVES_TRANSFER_IN_NOT_POSSIBLE, - ADD_SUBSIDY_FUND_FAILED, - ADD_SUBSIDY_FUND_FRESH_CHECK - } - - /** - * @dev `error` corresponds to enum Error; `info` corresponds to enum FailureInfo, and `detail` is an arbitrary - * contract-specific code that enables us to report opaque error codes from upgradeable contracts. - **/ - event TokenFailure(uint256 error, uint256 info, uint256 detail); - - /** - * @dev use this when reporting a known error from the money market or a non-upgradeable collaborator - */ - function fail(Error err, FailureInfo info) internal returns (uint256) { - emit TokenFailure(uint256(err), uint256(info), 0); - - return uint256(err); - } - - /** - * @dev use this when reporting an opaque error from an upgradeable collaborator contract - */ - function failOpaque( - Error err, - FailureInfo info, - uint256 opaqueError - ) internal returns (uint256) { - emit TokenFailure(uint256(err), uint256(info), opaqueError); - - return uint256(err); - } -} - - -// Dependency file: contracts/EIP20Interface.sol - -// pragma solidity 0.8.6; - -/** - * @title ERC 20 Token Standard Interface - * https://eips.ethereum.org/EIPS/eip-20 - */ -interface EIP20Interface { - function name() external view returns (string memory); - - function symbol() external view returns (string memory); - - function decimals() external view returns (uint8); - - /** - * @notice Get the total number of tokens in circulation - * @return The supply of tokens - */ - function totalSupply() external view returns (uint256); - - /** - * @notice Gets the balance of the specified address - * @param owner The address from which the balance will be retrieved - * @return balance The balance - */ - function balanceOf(address owner) external view returns (uint256 balance); - - /** - * @notice Transfer `amount` tokens from `msg.sender` to `dst` - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - * @return success Whether or not the transfer succeeded - */ - function transfer(address dst, uint256 amount) - external - returns (bool success); - - /** - * @notice Transfer `amount` tokens from `src` to `dst` - * @param src The address of the source account - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - * @return success Whether or not the transfer succeeded - */ - function transferFrom( - address src, - address dst, - uint256 amount - ) external returns (bool success); - - /** - * @notice Approve `spender` to transfer up to `amount` from `src` - * @dev This will overwrite the approval amount for `spender` - * and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve) - * @param spender The address of the account which may transfer tokens - * @param amount The number of tokens that are approved (-1 means infinite) - * @return success Whether or not the approval succeeded - */ - function approve(address spender, uint256 amount) - external - returns (bool success); - - /** - * @notice Get the current allowance from `owner` for `spender` - * @param owner The address of the account which owns the tokens to be spent - * @param spender The address of the account which may transfer tokens - * @return remaining The number of tokens allowed to be spent (-1 means infinite) - */ - function allowance(address owner, address spender) - external - view - returns (uint256 remaining); - - event Transfer(address indexed from, address indexed to, uint256 amount); - event Approval( - address indexed owner, - address indexed spender, - uint256 amount - ); -} - - -// Dependency file: contracts/WhitelistInterface.sol - -// pragma solidity 0.8.6; - -interface WhitelistInterface { - function setStatus(bool _newStatus) external; - function enabled() external view returns(bool); - - function addUsers(address[] memory _users) external; - function exist(address _user) external view returns(bool); - function getUsers() external view returns(address[] memory currentUsers); - function removeUser(address _user) external; -} - -// Dependency file: contracts/CToken.sol - -// pragma solidity 0.8.6; - -// import "contracts/ComptrollerInterface.sol"; -// import "contracts/CTokenInterfaces.sol"; -// import "contracts/ErrorReporter.sol"; -// import "contracts/Exponential.sol"; -// import "contracts/EIP20Interface.sol"; -// import "contracts/InterestRateModel.sol"; -// import "contracts/WhitelistInterface.sol"; - -/** - * @title tropykus CToken Contract - * @notice Abstract base for CTokens - * @author tropykus - */ -abstract contract CToken is CTokenInterface, Exponential, TokenErrorReporter { - address whitelist; - - /** - * @notice Initialize the money market - * @param comptroller_ The address of the Comptroller - * @param interestRateModel_ The address of the interest rate model - * @param initialExchangeRateMantissa_ The initial exchange rate, scaled by 1e18 - * @param name_ EIP-20 name of this token - * @param symbol_ EIP-20 symbol of this token - * @param decimals_ EIP-20 decimal precision of this token - */ - function initialize( - ComptrollerInterface comptroller_, - InterestRateModel interestRateModel_, - uint256 initialExchangeRateMantissa_, - string memory name_, - string memory symbol_, - uint8 decimals_ - ) public { - require(msg.sender == admin, "CT01"); - require(accrualBlockNumber == 0 && borrowIndex == 0, "CT02"); - - initialExchangeRateMantissa = initialExchangeRateMantissa_; - require(initialExchangeRateMantissa > 0, "CT03"); - - uint256 err = _setComptroller(comptroller_); - require(err == uint256(Error.NO_ERROR), "CT04"); - - accrualBlockNumber = getBlockNumber(); - borrowIndex = mantissaOne; - - err = _setInterestRateModelFresh(interestRateModel_); - require(err == uint256(Error.NO_ERROR), "CT05"); - - name = name_; - symbol = symbol_; - decimals = decimals_; - - _notEntered = true; - } - - function addWhitelist(address _whitelist) external returns (uint256) { - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_INTEREST_RATE_MODEL_OWNER_CHECK - ); - } - whitelist = _whitelist; - } - - /** - * @notice Transfer `tokens` tokens from `src` to `dst` by `spender` - * @dev Called by both `transfer` and `transferFrom` internally - * @param spender The address of the account performing the transfer - * @param src The address of the source account - * @param dst The address of the destination account - * @param tokens The number of tokens to transfer - * @return Whether or not the transfer succeeded - */ - function transferTokens( - address spender, - address src, - address dst, - uint256 tokens - ) internal returns (uint256) { - uint256 allowed = comptroller.transferAllowed( - address(this), - src, - dst, - tokens - ); - if (allowed != 0) { - return - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.TRANSFER_COMPTROLLER_REJECTION, - allowed - ); - } - - if (src == dst) { - return fail(Error.BAD_INPUT, FailureInfo.TRANSFER_NOT_ALLOWED); - } - - uint256 startingAllowance = 0; - if (spender == src) { - startingAllowance = type(uint256).max; - } else { - startingAllowance = transferAllowances[src][spender]; - } - - MathError mathErr; - uint256 allowanceNew; - uint256 srcTokensNew; - uint256 dstTokensNew; - - (mathErr, allowanceNew) = subUInt(startingAllowance, tokens); - if (mathErr != MathError.NO_ERROR) { - return fail(Error.MATH_ERROR, FailureInfo.TRANSFER_NOT_ALLOWED); - } - - (mathErr, srcTokensNew) = subUInt(accountTokens[src].tokens, tokens); - if (mathErr != MathError.NO_ERROR) { - return fail(Error.MATH_ERROR, FailureInfo.TRANSFER_NOT_ENOUGH); - } - - (mathErr, dstTokensNew) = addUInt(accountTokens[dst].tokens, tokens); - if (mathErr != MathError.NO_ERROR) { - return fail(Error.MATH_ERROR, FailureInfo.TRANSFER_TOO_MUCH); - } - - accountTokens[src].tokens = srcTokensNew; - accountTokens[dst].tokens = dstTokensNew; - - if (startingAllowance != type(uint256).max) { - transferAllowances[src][spender] = allowanceNew; - } - - emit Transfer(src, dst, tokens); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Transfer `amount` tokens from `msg.sender` to `dst` - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - * @return Whether or not the transfer succeeded - */ - function transfer(address dst, uint256 amount) - external - override - nonReentrant - returns (bool) - { - return - transferTokens(msg.sender, msg.sender, dst, amount) == - uint256(Error.NO_ERROR); - } - - /** - * @notice Transfer `amount` tokens from `src` to `dst` - * @param src The address of the source account - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - * @return Whether or not the transfer succeeded - */ - function transferFrom( - address src, - address dst, - uint256 amount - ) external override nonReentrant returns (bool) { - return - transferTokens(msg.sender, src, dst, amount) == - uint256(Error.NO_ERROR); - } - - /** - * @notice Approve `spender` to transfer up to `amount` from `src` - * @dev This will overwrite the approval amount for `spender` - * and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve) - * @param spender The address of the account which may transfer tokens - * @param amount The number of tokens that are approved (-1 means infinite) - * @return Whether or not the approval succeeded - */ - function approve(address spender, uint256 amount) - external - override - returns (bool) - { - transferAllowances[msg.sender][spender] = amount; - emit Approval(msg.sender, spender, amount); - return true; - } - - /** - * @notice Get the current allowance from `owner` for `spender` - * @param owner The address of the account which owns the tokens to be spent - * @param spender The address of the account which may transfer tokens - * @return The number of tokens allowed to be spent (-1 means infinite) - */ - function allowance(address owner, address spender) - external - view - override - returns (uint256) - { - return transferAllowances[owner][spender]; - } - - /** - * @notice Get the token balance of the `owner` - * @param owner The address of the account to query - * @return The number of tokens owned by `owner` - */ - function balanceOf(address owner) external view override returns (uint256) { - return accountTokens[owner].tokens; - } - - /** - * @notice Get the underlying balance of the `owner` - * @dev This also accrues interest in a transaction - * @param owner The address of the account to query - * @return The amount of underlying owned by `owner` - */ - function balanceOfUnderlying(address owner) - external - override - returns (uint256) - { - (MathError mErr, uint256 balance) = mulScalarTruncate( - Exp({mantissa: exchangeRateCurrent()}), - accountTokens[owner].tokens - ); - require(mErr == MathError.NO_ERROR, "CT06"); - return balance; - } - - /** - * @notice Get a snapshot of the account's balances, and the cached exchange rate - * @dev This is used by comptroller to more efficiently perform liquidity checks. - * @param account Address of the account to snapshot - * @return (possible error, token balance, borrow balance, exchange rate mantissa) - */ - function getAccountSnapshot(address account) - external - view - override - returns ( - uint256, - uint256, - uint256, - uint256 - ) - { - uint256 cTokenBalance = accountTokens[account].tokens; - uint256 borrowBalance; - uint256 exchangeRateMantissa; - - MathError mErr; - - (mErr, borrowBalance) = borrowBalanceStoredInternal(account); - if (mErr != MathError.NO_ERROR) { - return (uint256(Error.MATH_ERROR), 0, 0, 0); - } - - (mErr, exchangeRateMantissa) = exchangeRateStoredInternal(); - if (mErr != MathError.NO_ERROR) { - return (uint256(Error.MATH_ERROR), 0, 0, 0); - } - - return ( - uint256(Error.NO_ERROR), - cTokenBalance, - borrowBalance, - exchangeRateMantissa - ); - } - - /** - * @dev Function to simply retrieve block number - * This exists mainly for inheriting test contracts to stub this result. - */ - function getBlockNumber() internal view virtual returns (uint256) { - return block.number; - } - - /** - * @notice Returns the current per-block borrow interest rate for this cToken - * @return The borrow interest rate per block, scaled by 1e18 - */ - function borrowRatePerBlock() external view override returns (uint256) { - return - interestRateModel.getBorrowRate( - getCashPrior(), - totalBorrows, - totalReserves - ); - } - - /** - * @notice Returns the current per-block supply interest rate for this cToken - * @return The supply interest rate per block, scaled by 1e18 - */ - function supplyRatePerBlock() external view override returns (uint256) { - return - interestRateModel.getSupplyRate( - getCashPrior(), - totalBorrows, - totalReserves, - reserveFactorMantissa - ); - } - - /** - * @notice Returns the current total borrows plus accrued interest - * @return The total borrows with interest - */ - function totalBorrowsCurrent() - external - override - nonReentrant - returns (uint256) - { - require(accrueInterest() == uint256(Error.NO_ERROR), "CT07"); - return totalBorrows; - } - - /** - * @notice Accrue interest to updated borrowIndex and then calculate account's borrow balance using the updated borrowIndex - * @param account The address whose balance should be calculated after updating borrowIndex - * @return The calculated balance - */ - function borrowBalanceCurrent(address account) - external - override - nonReentrant - returns (uint256) - { - require(accrueInterest() == uint256(Error.NO_ERROR), "CT07"); - return borrowBalanceStored(account); - } - - /** - * @notice Return the borrow balance of account based on stored data - * @param account The address whose balance should be calculated - * @return The calculated balance - */ - function borrowBalanceStored(address account) - public - view - override - returns (uint256) - { - (MathError err, uint256 result) = borrowBalanceStoredInternal(account); - require(err == MathError.NO_ERROR, "CT08"); - return result; - } - - /** - * @notice Return the borrow balance of account based on stored data - * @param account The address whose balance should be calculated - * @return (error code, the calculated balance or 0 if error code is non-zero) - */ - function borrowBalanceStoredInternal(address account) - internal - view - returns (MathError, uint256) - { - MathError mathErr; - uint256 principalTimesIndex; - uint256 result; - - BorrowSnapshot storage borrowSnapshot = accountBorrows[account]; - - if (borrowSnapshot.principal == 0) { - return (MathError.NO_ERROR, 0); - } - - (mathErr, principalTimesIndex) = mulUInt( - borrowSnapshot.principal, - borrowIndex - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - - (mathErr, result) = divUInt( - principalTimesIndex, - borrowSnapshot.interestIndex - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - - return (MathError.NO_ERROR, result); - } - - function getBorrowerPrincipalStored(address account) - public - view - returns (uint256 borrowed) - { - borrowed = accountBorrows[account].principal; - } - - function getSupplierSnapshotStored(address account) - public - view - returns ( - uint256 tokens, - uint256 underlyingAmount, - uint256 suppliedAt, - uint256 promisedSupplyRate - ) - { - tokens = accountTokens[account].tokens; - underlyingAmount = accountTokens[account].underlyingAmount; - suppliedAt = accountTokens[account].suppliedAt; - promisedSupplyRate = accountTokens[account].promisedSupplyRate; - } - - /** - * @notice Accrue interest then return the up-to-date exchange rate - * @return Calculated exchange rate scaled by 1e18 - */ - function exchangeRateCurrent() - public - override - nonReentrant - returns (uint256) - { - require(accrueInterest() == uint256(Error.NO_ERROR), "CT07"); - return exchangeRateStored(); - } - - /** - * @notice Calculates the exchange rate from the underlying to the CToken - * @dev This function does not accrue interest before calculating the exchange rate - * @return Calculated exchange rate scaled by 1e18 - */ - function exchangeRateStored() public view override returns (uint256) { - (MathError err, uint256 result) = exchangeRateStoredInternal(); - require(err == MathError.NO_ERROR, "CT09"); - return result; - } - - /** - * @notice Calculates the exchange rate from the underlying to the CToken - * @dev This function does not accrue interest before calculating the exchange rate - * @return (error code, calculated exchange rate scaled by 1e18) - */ - function exchangeRateStoredInternal() - internal - view - virtual - returns (MathError, uint256) - { - uint256 _totalSupply = totalSupply; - if (_totalSupply == 0) { - return (MathError.NO_ERROR, initialExchangeRateMantissa); - } else { - MathError error; - uint256 exchangeRate; - uint256 totalCash = getCashPrior(); - if (interestRateModel.isTropykusInterestRateModel()) { - (error, exchangeRate) = tropykusExchangeRateStoredInternal( - msg.sender - ); - if (error == MathError.NO_ERROR) { - return (MathError.NO_ERROR, exchangeRate); - } else { - return (MathError.NO_ERROR, initialExchangeRateMantissa); - } - } - return - interestRateModel.getExchangeRate( - totalCash, - totalBorrows, - totalReserves, - totalSupply - ); - } - } - - function tropykusExchangeRateStoredInternal(address redeemer) - internal - view - returns (MathError, uint256) - { - if (totalSupply == 0) { - return (MathError.NO_ERROR, initialExchangeRateMantissa); - } else { - SupplySnapshot storage supplySnapshot = accountTokens[redeemer]; - if (supplySnapshot.suppliedAt == 0) { - return (MathError.DIVISION_BY_ZERO, 0); - } - (, uint256 interestFactorMantissa, ) = tropykusInterestAccrued( - redeemer - ); - Exp memory interestFactor = Exp({mantissa: interestFactorMantissa}); - uint256 currentUnderlying = supplySnapshot.underlyingAmount; - Exp memory redeemerUnderlying = Exp({mantissa: currentUnderlying}); - (, Exp memory realAmount) = mulExp( - interestFactor, - redeemerUnderlying - ); - (, Exp memory exchangeRate) = getExp( - realAmount.mantissa, - supplySnapshot.tokens - ); - return (MathError.NO_ERROR, exchangeRate.mantissa); - } - } - - function tropykusInterestAccrued(address account) - internal - view - returns ( - MathError, - uint256, - uint256 - ) - { - SupplySnapshot storage supplySnapshot = accountTokens[account]; - uint256 promisedSupplyRate = supplySnapshot.promisedSupplyRate; - Exp memory expectedSupplyRatePerBlock = Exp({ - mantissa: promisedSupplyRate - }); - (, uint256 delta) = subUInt( - accrualBlockNumber, - supplySnapshot.suppliedAt - ); - (, Exp memory expectedSupplyRatePerBlockWithDelta) = mulScalar( - expectedSupplyRatePerBlock, - delta - ); - (, Exp memory interestFactor) = addExp( - Exp({mantissa: 1e18}), - expectedSupplyRatePerBlockWithDelta - ); - uint256 currentUnderlying = supplySnapshot.underlyingAmount; - Exp memory redeemerUnderlying = Exp({mantissa: currentUnderlying}); - (, Exp memory realAmount) = mulExp(interestFactor, redeemerUnderlying); - (, uint256 interestEarned) = subUInt( - realAmount.mantissa, - currentUnderlying - ); - return (MathError.NO_ERROR, interestFactor.mantissa, interestEarned); - } - - /** - * @notice Get cash balance of this cToken in the underlying asset - * @return The quantity of underlying asset owned by this contract - */ - function getCash() external view override returns (uint256) { - return getCashPrior(); - } - - /** - * @notice Applies accrued interest to total borrows and reserves - * @dev This calculates interest accrued from the last checkpointed block - * up to the current block and writes new checkpoint to storage. - */ - function accrueInterest() public override returns (uint256) { - uint256 currentBlockNumber = getBlockNumber(); - uint256 accrualBlockNumberPrior = accrualBlockNumber; - - if (accrualBlockNumberPrior == currentBlockNumber) { - return uint256(Error.NO_ERROR); - } - - uint256 cashPrior = getCashPrior(); - uint256 borrowsPrior = totalBorrows; - uint256 reservesPrior = totalReserves; - uint256 borrowIndexPrior = borrowIndex; - - uint256 borrowRateMantissa = interestRateModel.getBorrowRate( - cashPrior, - borrowsPrior, - reservesPrior - ); - require(borrowRateMantissa <= borrowRateMaxMantissa, "CT10"); - - (MathError mathErr, uint256 blockDelta) = subUInt( - currentBlockNumber, - accrualBlockNumberPrior - ); - require(mathErr == MathError.NO_ERROR, "CT11"); - - Exp memory simpleInterestFactor; - uint256 interestAccumulated; - uint256 totalBorrowsNew; - uint256 totalReservesNew; - uint256 borrowIndexNew; - - (mathErr, simpleInterestFactor) = mulScalar( - Exp({mantissa: borrowRateMantissa}), - blockDelta - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .ACCRUE_INTEREST_SIMPLE_INTEREST_FACTOR_CALCULATION_FAILED, - uint256(mathErr) - ); - } - - (mathErr, interestAccumulated) = mulScalarTruncate( - simpleInterestFactor, - borrowsPrior - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .ACCRUE_INTEREST_ACCUMULATED_INTEREST_CALCULATION_FAILED, - uint256(mathErr) - ); - } - - (mathErr, totalBorrowsNew) = addUInt(interestAccumulated, borrowsPrior); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .ACCRUE_INTEREST_NEW_TOTAL_BORROWS_CALCULATION_FAILED, - uint256(mathErr) - ); - } - - (mathErr, totalReservesNew) = mulScalarTruncateAddUInt( - Exp({mantissa: reserveFactorMantissa}), - interestAccumulated, - reservesPrior - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .ACCRUE_INTEREST_NEW_TOTAL_RESERVES_CALCULATION_FAILED, - uint256(mathErr) - ); - } - - if (interestRateModel.isTropykusInterestRateModel()) { - (mathErr, totalReservesNew) = newReserves( - borrowRateMantissa, - cashPrior, - borrowsPrior, - reservesPrior, - interestAccumulated - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .ACCRUE_INTEREST_NEW_TOTAL_RESERVES_CALCULATION_FAILED, - uint256(mathErr) - ); - } - } - - (mathErr, borrowIndexNew) = mulScalarTruncateAddUInt( - simpleInterestFactor, - borrowIndexPrior, - borrowIndexPrior - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .ACCRUE_INTEREST_NEW_BORROW_INDEX_CALCULATION_FAILED, - uint256(mathErr) - ); - } - - accrualBlockNumber = currentBlockNumber; - borrowIndex = borrowIndexNew; - totalBorrows = totalBorrowsNew; - totalReserves = totalReservesNew; - - emit AccrueInterest( - cashPrior, - interestAccumulated, - borrowIndexNew, - totalBorrowsNew - ); - - return uint256(Error.NO_ERROR); - } - - function newReserves( - uint256 borrowRateMantissa, - uint256 cashPrior, - uint256 borrowsPrior, - uint256 reservesPrior, - uint256 interestAccumulated - ) internal view returns (MathError mathErr, uint256 totalReservesNew) { - uint256 newReserveFactorMantissa; - uint256 utilizationRate = interestRateModel.utilizationRate( - cashPrior, - borrowsPrior, - reservesPrior - ); - uint256 expectedSupplyRate = interestRateModel.getSupplyRate( - cashPrior, - borrowsPrior, - reservesPrior, - reserveFactorMantissa - ); - if ( - interestRateModel.isAboveOptimal( - cashPrior, - borrowsPrior, - reservesPrior - ) - ) { - (mathErr, newReserveFactorMantissa) = mulScalarTruncate( - Exp({mantissa: utilizationRate}), - borrowRateMantissa - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - (mathErr, newReserveFactorMantissa) = subUInt( - newReserveFactorMantissa, - expectedSupplyRate - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - (mathErr, totalReservesNew) = mulScalarTruncateAddUInt( - Exp({mantissa: newReserveFactorMantissa}), - interestAccumulated, - reservesPrior - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - } else { - mathErr = MathError.NO_ERROR; - totalReservesNew = reservesPrior; - } - } - - /** - * @notice Sender supplies assets into the market and receives cTokens in exchange - * @dev Accrues interest whether or not the operation succeeds, unless reverted - * @param mintAmount The amount of the underlying asset to supply - * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual mint amount. - */ - function mintInternal(uint256 mintAmount) - internal - nonReentrant - returns (uint256, uint256) - { - if (WhitelistInterface(whitelist).enabled()) { - require(WhitelistInterface(whitelist).exist(msg.sender), "CT26"); - } - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return ( - fail(Error(error), FailureInfo.MINT_ACCRUE_INTEREST_FAILED), - 0 - ); - } - return mintFresh(msg.sender, mintAmount); - } - - struct MintLocalVars { - Error err; - MathError mathErr; - uint256 exchangeRateMantissa; - uint256 mintTokens; - uint256 totalSupplyNew; - uint256 accountTokensNew; - uint256 actualMintAmount; - } - - /** - * @notice User supplies assets into the market and receives cTokens in exchange - * @dev Assumes interest has already been accrued up to the current block - * @param minter The address of the account which is supplying the assets - * @param mintAmount The amount of the underlying asset to supply - * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual mint amount. - */ - function mintFresh(address minter, uint256 mintAmount) - internal - returns (uint256, uint256) - { - uint256 allowed = comptroller.mintAllowed( - address(this), - minter, - mintAmount - ); - if (allowed != 0) { - return ( - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.MINT_COMPTROLLER_REJECTION, - allowed - ), - 0 - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return ( - fail(Error.MARKET_NOT_FRESH, FailureInfo.MINT_FRESHNESS_CHECK), - 0 - ); - } - - MintLocalVars memory vars; - - ( - vars.mathErr, - vars.exchangeRateMantissa - ) = exchangeRateStoredInternal(); - if (vars.mathErr != MathError.NO_ERROR) { - return ( - failOpaque( - Error.MATH_ERROR, - FailureInfo.MINT_EXCHANGE_RATE_READ_FAILED, - uint256(vars.mathErr) - ), - 0 - ); - } - if (interestRateModel.isTropykusInterestRateModel()) { - SupplySnapshot storage supplySnapshot = accountTokens[minter]; - (, uint256 newTotalSupply) = addUInt( - supplySnapshot.underlyingAmount, - mintAmount - ); - require(newTotalSupply <= 0.1e18, "CT24"); - } - vars.actualMintAmount = doTransferIn(minter, mintAmount); - - (vars.mathErr, vars.mintTokens) = divScalarByExpTruncate( - vars.actualMintAmount, - Exp({mantissa: vars.exchangeRateMantissa}) - ); - require(vars.mathErr == MathError.NO_ERROR, "CT12"); - - (vars.mathErr, vars.totalSupplyNew) = addUInt( - totalSupply, - vars.mintTokens - ); - require(vars.mathErr == MathError.NO_ERROR, "CT13"); - - (vars.mathErr, vars.accountTokensNew) = addUInt( - accountTokens[minter].tokens, - vars.mintTokens - ); - require(vars.mathErr == MathError.NO_ERROR, "CT14"); - - uint256 currentSupplyRate = interestRateModel.getSupplyRate( - getCashPrior(), - totalBorrows, - totalReserves, - reserveFactorMantissa - ); - - bool isTropykusInterestRateModel = interestRateModel - .isTropykusInterestRateModel(); - - if (accountTokens[minter].tokens > 0) { - Exp memory updatedUnderlying; - if (isTropykusInterestRateModel) { - (, uint256 interestFactorMantissa, ) = tropykusInterestAccrued( - minter - ); - Exp memory interestFactor = Exp({ - mantissa: interestFactorMantissa - }); - uint256 currentUnderlyingAmount = accountTokens[minter] - .underlyingAmount; - MathError mErrorNewAmount; - (mErrorNewAmount, updatedUnderlying) = mulExp( - Exp({mantissa: currentUnderlyingAmount}), - interestFactor - ); - if (mErrorNewAmount != MathError.NO_ERROR) { - return ( - failOpaque( - Error.MATH_ERROR, - FailureInfo.MINT_EXCHANGE_CALCULATION_FAILED, - uint256(mErrorNewAmount) - ), - 0 - ); - } - } else { - uint256 currentTokens = accountTokens[minter].tokens; - MathError mErrorUpdatedUnderlying; - (mErrorUpdatedUnderlying, updatedUnderlying) = mulExp( - Exp({mantissa: currentTokens}), - Exp({mantissa: vars.exchangeRateMantissa}) - ); - if (mErrorUpdatedUnderlying != MathError.NO_ERROR) { - return ( - failOpaque( - Error.MATH_ERROR, - FailureInfo.MINT_EXCHANGE_CALCULATION_FAILED, - uint256(mErrorUpdatedUnderlying) - ), - 0 - ); - } - } - (, mintAmount) = addUInt(updatedUnderlying.mantissa, mintAmount); - } - - totalSupply = vars.totalSupplyNew; - accountTokens[minter] = SupplySnapshot({ - tokens: vars.accountTokensNew, - underlyingAmount: mintAmount, - suppliedAt: accrualBlockNumber, - promisedSupplyRate: currentSupplyRate - }); - - emit Mint(minter, vars.actualMintAmount, vars.mintTokens); - emit Transfer(address(this), minter, vars.mintTokens); - - return (uint256(Error.NO_ERROR), vars.actualMintAmount); - } - - /** - * @notice Sender redeems cTokens in exchange for a specified amount of underlying asset - * @dev Accrues interest whether or not the operation succeeds, unless reverted - * @param redeemAmount The amount of underlying to receive from redeeming cTokens - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function redeemUnderlyingInternal(uint256 redeemAmount) - internal - nonReentrant - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return - fail(Error(error), FailureInfo.REDEEM_ACCRUE_INTEREST_FAILED); - } - return redeemFresh(payable(msg.sender), redeemAmount); - } - - struct RedeemLocalVars { - Error err; - MathError mathErr; - uint256 exchangeRateMantissa; - uint256 redeemTokens; - uint256 redeemAmount; - uint256 totalSupplyNew; - uint256 accountTokensNew; - uint256 newSubsidyFund; - } - - /** - * @notice User redeems cTokens in exchange for the underlying asset - * @dev Assumes interest has already been accrued up to the current block - * @param redeemer The address of the account which is redeeming the tokens - * @param redeemAmountIn The number of underlying tokens to receive from redeeming cTokens - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function redeemFresh(address payable redeemer, uint256 redeemAmountIn) - internal - returns (uint256) - { - require(redeemAmountIn > 0, "CT15"); - - RedeemLocalVars memory vars; - - SupplySnapshot storage supplySnapshot = accountTokens[redeemer]; - - ( - vars.mathErr, - vars.exchangeRateMantissa - ) = exchangeRateStoredInternal(); - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.REDEEM_EXCHANGE_RATE_READ_FAILED, - uint256(vars.mathErr) - ); - } - - uint256 interestEarned; - uint256 subsidyFundPortion; - uint256 currentUnderlying; - - bool isTropykusInterestRateModel = interestRateModel - .isTropykusInterestRateModel(); - if (isTropykusInterestRateModel) { - currentUnderlying = supplySnapshot.underlyingAmount; - (, , interestEarned) = tropykusInterestAccrued(redeemer); - } - supplySnapshot.promisedSupplyRate = interestRateModel.getSupplyRate( - getCashPrior(), - totalBorrows, - totalReserves, - reserveFactorMantissa - ); - - if ( - isTropykusInterestRateModel && - !interestRateModel.isAboveOptimal( - getCashPrior(), - totalBorrows, - totalReserves - ) - ) { - uint256 borrowRate = interestRateModel.getBorrowRate( - getCashPrior(), - totalBorrows, - totalReserves - ); - - uint256 utilizationRate = interestRateModel.utilizationRate( - getCashPrior(), - totalBorrows, - totalReserves - ); - - (, uint256 estimatedEarning) = mulScalarTruncate( - Exp({mantissa: borrowRate}), - utilizationRate - ); - - (, subsidyFundPortion) = subUInt( - supplySnapshot.promisedSupplyRate, - estimatedEarning - ); - (, Exp memory subsidyFactor) = getExp( - subsidyFundPortion, - supplySnapshot.promisedSupplyRate - ); - (, subsidyFundPortion) = mulScalarTruncate( - subsidyFactor, - interestEarned - ); - } - - vars.redeemAmount = redeemAmountIn; - - if (isTropykusInterestRateModel) { - (, Exp memory num) = mulExp( - vars.redeemAmount, - supplySnapshot.tokens - ); - (, Exp memory realTokensWithdrawAmount) = getExp( - num.mantissa, - currentUnderlying - ); - vars.redeemTokens = realTokensWithdrawAmount.mantissa; - } else { - (vars.mathErr, vars.redeemTokens) = divScalarByExpTruncate( - redeemAmountIn, - Exp({mantissa: vars.exchangeRateMantissa}) - ); - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.REDEEM_EXCHANGE_AMOUNT_CALCULATION_FAILED, - uint256(vars.mathErr) - ); - } - } - // } - - uint256 allowed = comptroller.redeemAllowed( - address(this), - redeemer, - vars.redeemTokens - ); - if (allowed != 0) { - return - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.REDEEM_COMPTROLLER_REJECTION, - allowed - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.REDEEM_FRESHNESS_CHECK - ); - } - - (vars.mathErr, vars.totalSupplyNew) = subUInt( - totalSupply, - vars.redeemTokens - ); - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.REDEEM_NEW_TOTAL_SUPPLY_CALCULATION_FAILED, - uint256(vars.mathErr) - ); - } - - (, vars.newSubsidyFund) = subUInt(subsidyFund, subsidyFundPortion); - - (vars.mathErr, vars.accountTokensNew) = subUInt( - supplySnapshot.tokens, - vars.redeemTokens - ); - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.REDEEM_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED, - uint256(vars.mathErr) - ); - } - - uint256 cash = getCashPrior(); - if (isTropykusInterestRateModel) { - cash = address(this).balance; - } - - if (cash < vars.redeemAmount) { - return - fail( - Error.TOKEN_INSUFFICIENT_CASH, - FailureInfo.REDEEM_TRANSFER_OUT_NOT_POSSIBLE - ); - } - - doTransferOut(redeemer, vars.redeemAmount); - - totalSupply = vars.totalSupplyNew; - subsidyFund = vars.newSubsidyFund; - supplySnapshot.tokens = vars.accountTokensNew; - supplySnapshot.suppliedAt = accrualBlockNumber; - (, supplySnapshot.underlyingAmount) = subUInt( - supplySnapshot.underlyingAmount, - vars.redeemAmount - ); - - emit Transfer(redeemer, address(this), vars.redeemTokens); - emit Redeem(redeemer, vars.redeemAmount, vars.redeemTokens); - - comptroller.redeemVerify( - address(this), - redeemer, - vars.redeemAmount, - vars.redeemTokens - ); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Sender borrows assets from the protocol to their own address - * @param borrowAmount The amount of the underlying asset to borrow - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function borrowInternal(uint256 borrowAmount) - internal - nonReentrant - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return - fail(Error(error), FailureInfo.BORROW_ACCRUE_INTEREST_FAILED); - } - return borrowFresh(payable(msg.sender), borrowAmount); - } - - struct BorrowLocalVars { - MathError mathErr; - uint256 accountBorrows; - uint256 accountBorrowsNew; - uint256 totalBorrowsNew; - } - - /** - * @notice Users borrow assets from the protocol to their own address - * @param borrowAmount The amount of the underlying asset to borrow - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function borrowFresh(address payable borrower, uint256 borrowAmount) - internal - returns (uint256) - { - uint256 allowed = comptroller.borrowAllowed( - address(this), - borrower, - borrowAmount - ); - if (allowed != 0) { - return - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.BORROW_COMPTROLLER_REJECTION, - allowed - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.BORROW_FRESHNESS_CHECK - ); - } - - if (getCashPrior() < borrowAmount) { - return - fail( - Error.TOKEN_INSUFFICIENT_CASH, - FailureInfo.BORROW_CASH_NOT_AVAILABLE - ); - } - - BorrowLocalVars memory vars; - - (vars.mathErr, vars.accountBorrows) = borrowBalanceStoredInternal( - borrower - ); - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED, - uint256(vars.mathErr) - ); - } - - (vars.mathErr, vars.accountBorrowsNew) = addUInt( - vars.accountBorrows, - borrowAmount - ); - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED, - uint256(vars.mathErr) - ); - } - - (vars.mathErr, vars.totalBorrowsNew) = addUInt( - totalBorrows, - borrowAmount - ); - if (interestRateModel.isTropykusInterestRateModel()) { - require(vars.totalBorrowsNew <= 0.1e18, "CT25"); - } - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED, - uint256(vars.mathErr) - ); - } - - doTransferOut(borrower, borrowAmount); - - accountBorrows[borrower].principal = vars.accountBorrowsNew; - accountBorrows[borrower].interestIndex = borrowIndex; - totalBorrows = vars.totalBorrowsNew; - - emit Borrow( - borrower, - borrowAmount, - vars.accountBorrowsNew, - vars.totalBorrowsNew - ); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Sender repays their own borrow - * @param repayAmount The amount to repay - * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual repayment amount. - */ - function repayBorrowInternal(uint256 repayAmount) - internal - nonReentrant - returns (uint256, uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return ( - fail( - Error(error), - FailureInfo.REPAY_BORROW_ACCRUE_INTEREST_FAILED - ), - 0 - ); - } - return repayBorrowFresh(msg.sender, msg.sender, repayAmount); - } - - struct RepayBorrowLocalVars { - Error err; - MathError mathErr; - uint256 repayAmount; - uint256 borrowerIndex; - uint256 accountBorrows; - uint256 accountBorrowsNew; - uint256 totalBorrowsNew; - uint256 actualRepayAmount; - } - - /** - * @notice Borrows are repaid by another user (possibly the borrower). - * @param payer the account paying off the borrow - * @param borrower the account with the debt being payed off - * @param repayAmount the amount of undelrying tokens being returned - * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual repayment amount. - */ - function repayBorrowFresh( - address payer, - address borrower, - uint256 repayAmount - ) internal returns (uint256, uint256) { - uint256 allowed = comptroller.repayBorrowAllowed( - address(this), - payer, - borrower, - repayAmount - ); - if (allowed != 0) { - return ( - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.REPAY_BORROW_COMPTROLLER_REJECTION, - allowed - ), - 0 - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return ( - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.REPAY_BORROW_FRESHNESS_CHECK - ), - 0 - ); - } - - RepayBorrowLocalVars memory vars; - - vars.borrowerIndex = accountBorrows[borrower].interestIndex; - - (vars.mathErr, vars.accountBorrows) = borrowBalanceStoredInternal( - borrower - ); - if (vars.mathErr != MathError.NO_ERROR) { - return ( - failOpaque( - Error.MATH_ERROR, - FailureInfo - .REPAY_BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED, - uint256(vars.mathErr) - ), - 0 - ); - } - - if (repayAmount == type(uint256).max) { - vars.repayAmount = vars.accountBorrows; - } else { - vars.repayAmount = repayAmount; - } - - vars.actualRepayAmount = doTransferIn(payer, vars.repayAmount); - - (vars.mathErr, vars.accountBorrowsNew) = subUInt( - vars.accountBorrows, - vars.actualRepayAmount - ); - require(vars.mathErr == MathError.NO_ERROR, "CT16"); - - (vars.mathErr, vars.totalBorrowsNew) = subUInt( - totalBorrows, - vars.actualRepayAmount - ); - require(vars.mathErr == MathError.NO_ERROR, "CT17"); - - accountBorrows[borrower].principal = vars.accountBorrowsNew; - accountBorrows[borrower].interestIndex = borrowIndex; - totalBorrows = vars.totalBorrowsNew; - - emit RepayBorrow( - payer, - borrower, - vars.actualRepayAmount, - vars.accountBorrowsNew, - vars.totalBorrowsNew - ); - - return (uint256(Error.NO_ERROR), vars.actualRepayAmount); - } - - /** - * @notice The sender liquidates the borrowers collateral. - * The collateral seized is transferred to the liquidator. - * @param borrower The borrower of this cToken to be liquidated - * @param cTokenCollateral The market in which to seize collateral from the borrower - * @param repayAmount The amount of the underlying borrowed asset to repay - * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual repayment amount. - */ - function liquidateBorrowInternal( - address borrower, - uint256 repayAmount, - CTokenInterface cTokenCollateral - ) internal nonReentrant returns (uint256, uint256) { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return ( - fail( - Error(error), - FailureInfo.LIQUIDATE_ACCRUE_BORROW_INTEREST_FAILED - ), - 0 - ); - } - - error = cTokenCollateral.accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return ( - fail( - Error(error), - FailureInfo.LIQUIDATE_ACCRUE_COLLATERAL_INTEREST_FAILED - ), - 0 - ); - } - - // liquidateBorrowFresh emits borrow-specific logs on errors, so we don't need to - return - liquidateBorrowFresh( - msg.sender, - borrower, - repayAmount, - cTokenCollateral - ); - } - - /** - * @notice The liquidator liquidates the borrowers collateral. - * The collateral seized is transferred to the liquidator. - * @param borrower The borrower of this cToken to be liquidated - * @param liquidator The address repaying the borrow and seizing collateral - * @param cTokenCollateral The market in which to seize collateral from the borrower - * @param repayAmount The amount of the underlying borrowed asset to repay - * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual repayment amount. - */ - function liquidateBorrowFresh( - address liquidator, - address borrower, - uint256 repayAmount, - CTokenInterface cTokenCollateral - ) internal returns (uint256, uint256) { - uint256 allowed = comptroller.liquidateBorrowAllowed( - address(this), - address(cTokenCollateral), - liquidator, - borrower, - repayAmount - ); - if (allowed != 0) { - return ( - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.LIQUIDATE_COMPTROLLER_REJECTION, - allowed - ), - 0 - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return ( - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.LIQUIDATE_FRESHNESS_CHECK - ), - 0 - ); - } - - if (cTokenCollateral.accrualBlockNumber() != getBlockNumber()) { - return ( - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.LIQUIDATE_COLLATERAL_FRESHNESS_CHECK - ), - 0 - ); - } - - if (borrower == liquidator) { - return ( - fail( - Error.INVALID_ACCOUNT_PAIR, - FailureInfo.LIQUIDATE_LIQUIDATOR_IS_BORROWER - ), - 0 - ); - } - - if (repayAmount == 0) { - return ( - fail( - Error.INVALID_CLOSE_AMOUNT_REQUESTED, - FailureInfo.LIQUIDATE_CLOSE_AMOUNT_IS_ZERO - ), - 0 - ); - } - - if (repayAmount == type(uint256).max) { - return ( - fail( - Error.INVALID_CLOSE_AMOUNT_REQUESTED, - FailureInfo.LIQUIDATE_CLOSE_AMOUNT_IS_UINT_MAX - ), - 0 - ); - } - - ( - uint256 repayBorrowError, - uint256 actualRepayAmount - ) = repayBorrowFresh(liquidator, borrower, repayAmount); - if (repayBorrowError != uint256(Error.NO_ERROR)) { - return ( - fail( - Error(repayBorrowError), - FailureInfo.LIQUIDATE_REPAY_BORROW_FRESH_FAILED - ), - 0 - ); - } - - (uint256 amountSeizeError, uint256 seizeTokens) = comptroller - .liquidateCalculateSeizeTokens( - address(this), - address(cTokenCollateral), - actualRepayAmount - ); - require(amountSeizeError == uint256(Error.NO_ERROR), "CT18"); - - require(cTokenCollateral.balanceOf(borrower) >= seizeTokens, "CT19"); - - uint256 seizeError; - if (address(cTokenCollateral) == address(this)) { - seizeError = seizeInternal( - address(this), - liquidator, - borrower, - seizeTokens - ); - } else { - seizeError = cTokenCollateral.seize( - liquidator, - borrower, - seizeTokens - ); - } - - require(seizeError == uint256(Error.NO_ERROR), "CT20"); - - emit LiquidateBorrow( - liquidator, - borrower, - actualRepayAmount, - address(cTokenCollateral), - seizeTokens - ); - - return (uint256(Error.NO_ERROR), actualRepayAmount); - } - - /** - * @notice Transfers collateral tokens (this market) to the liquidator. - * @dev Will fail unless called by another cToken during the process of liquidation. - * Its absolutely critical to use msg.sender as the borrowed cToken and not a parameter. - * @param liquidator The account receiving seized collateral - * @param borrower The account having collateral seized - * @param seizeTokens The number of cTokens to seize - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function seize( - address liquidator, - address borrower, - uint256 seizeTokens - ) external override nonReentrant returns (uint256) { - return seizeInternal(msg.sender, liquidator, borrower, seizeTokens); - } - - struct SeizeVars { - uint256 seizeAmount; - uint256 exchangeRate; - uint256 borrowerTokensNew; - uint256 borrowerAmountNew; - uint256 liquidatorTokensNew; - uint256 liquidatorAmountNew; - uint256 totalCash; - uint256 supplyRate; - } - - /** - * @notice Transfers collateral tokens (this market) to the liquidator. - * @dev Called only during an in-kind liquidation, or by liquidateBorrow during the liquidation of another CToken. - * Its absolutely critical to use msg.sender as the seizer cToken and not a parameter. - * @param seizerToken The contract seizing the collateral (i.e. borrowed cToken) - * @param liquidator The account receiving seized collateral - * @param borrower The account having collateral seized - * @param seizeTokens The number of cTokens to seize - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function seizeInternal( - address seizerToken, - address liquidator, - address borrower, - uint256 seizeTokens - ) internal returns (uint256) { - uint256 allowed = comptroller.seizeAllowed( - address(this), - seizerToken, - liquidator, - borrower, - seizeTokens - ); - if (allowed != 0) { - return - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.LIQUIDATE_SEIZE_COMPTROLLER_REJECTION, - allowed - ); - } - - if (borrower == liquidator) { - return - fail( - Error.INVALID_ACCOUNT_PAIR, - FailureInfo.LIQUIDATE_SEIZE_LIQUIDATOR_IS_BORROWER - ); - } - - SeizeVars memory seizeVars; - - MathError mathErr; - - (mathErr, seizeVars.borrowerTokensNew) = subUInt( - accountTokens[borrower].tokens, - seizeTokens - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.LIQUIDATE_SEIZE_BALANCE_DECREMENT_FAILED, - uint256(mathErr) - ); - } - - seizeVars.totalCash = getCashPrior(); - seizeVars.supplyRate = interestRateModel.getSupplyRate( - seizeVars.totalCash, - totalBorrows, - totalReserves, - reserveFactorMantissa - ); - - (, seizeVars.exchangeRate) = interestRateModel.getExchangeRate( - seizeVars.totalCash, - totalBorrows, - totalReserves, - totalSupply - ); - - if (interestRateModel.isTropykusInterestRateModel()) { - (, seizeVars.exchangeRate) = tropykusExchangeRateStoredInternal( - borrower - ); - } - - (, seizeVars.seizeAmount) = mulUInt( - seizeTokens, - seizeVars.exchangeRate - ); - (, seizeVars.seizeAmount) = divUInt(seizeVars.seizeAmount, 1e18); - - (, seizeVars.borrowerAmountNew) = subUInt( - accountTokens[borrower].underlyingAmount, - seizeVars.seizeAmount - ); - - (mathErr, seizeVars.liquidatorTokensNew) = addUInt( - accountTokens[liquidator].tokens, - seizeTokens - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.LIQUIDATE_SEIZE_BALANCE_INCREMENT_FAILED, - uint256(mathErr) - ); - } - - (, seizeVars.liquidatorAmountNew) = addUInt( - accountTokens[liquidator].underlyingAmount, - seizeVars.seizeAmount - ); - - accountTokens[borrower].tokens = seizeVars.borrowerTokensNew; - accountTokens[borrower].underlyingAmount = seizeVars.borrowerAmountNew; - accountTokens[borrower].suppliedAt = getBlockNumber(); - accountTokens[borrower].promisedSupplyRate = seizeVars.supplyRate; - - accountTokens[liquidator].tokens = seizeVars.liquidatorTokensNew; - accountTokens[liquidator].underlyingAmount = seizeVars - .liquidatorAmountNew; - accountTokens[liquidator].suppliedAt = getBlockNumber(); - accountTokens[liquidator].promisedSupplyRate = seizeVars.supplyRate; - - emit Transfer(borrower, liquidator, seizeTokens); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Begins transfer of admin rights. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer. - * @dev Admin function to begin change of admin. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer. - * @param newPendingAdmin New pending admin. - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setPendingAdmin(address payable newPendingAdmin) - external - override - returns (uint256) - { - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_PENDING_ADMIN_OWNER_CHECK - ); - } - - address oldPendingAdmin = pendingAdmin; - - pendingAdmin = newPendingAdmin; - - emit NewPendingAdmin(oldPendingAdmin, newPendingAdmin); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Accepts transfer of admin rights. msg.sender must be pendingAdmin - * @dev Admin function for pending admin to accept role and update admin - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _acceptAdmin() external override returns (uint256) { - if (msg.sender != pendingAdmin || msg.sender == address(0)) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.ACCEPT_ADMIN_PENDING_ADMIN_CHECK - ); - } - - address oldAdmin = admin; - address oldPendingAdmin = pendingAdmin; - - admin = pendingAdmin; - - pendingAdmin = payable(address(0)); - - emit NewAdmin(oldAdmin, admin); - emit NewPendingAdmin(oldPendingAdmin, pendingAdmin); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Sets a new comptroller for the market - * @dev Admin function to set a new comptroller - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setComptroller(ComptrollerInterface newComptroller) - public - override - returns (uint256) - { - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_COMPTROLLER_OWNER_CHECK - ); - } - - ComptrollerInterface oldComptroller = comptroller; - require(newComptroller.isComptroller(), "CT21"); - - comptroller = newComptroller; - - emit NewComptroller(oldComptroller, newComptroller); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice accrues interest and sets a new reserve factor for the protocol using _setReserveFactorFresh - * @dev Admin function to accrue interest and set a new reserve factor - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setReserveFactor(uint256 newReserveFactorMantissa) - external - override - nonReentrant - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return - fail( - Error(error), - FailureInfo.SET_RESERVE_FACTOR_ACCRUE_INTEREST_FAILED - ); - } - return _setReserveFactorFresh(newReserveFactorMantissa); - } - - /** - * @notice Sets a new reserve factor for the protocol (*requires fresh interest accrual) - * @dev Admin function to set a new reserve factor - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setReserveFactorFresh(uint256 newReserveFactorMantissa) - internal - returns (uint256) - { - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_RESERVE_FACTOR_ADMIN_CHECK - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.SET_RESERVE_FACTOR_FRESH_CHECK - ); - } - - if (newReserveFactorMantissa > reserveFactorMaxMantissa) { - return - fail( - Error.BAD_INPUT, - FailureInfo.SET_RESERVE_FACTOR_BOUNDS_CHECK - ); - } - - uint256 oldReserveFactorMantissa = reserveFactorMantissa; - reserveFactorMantissa = newReserveFactorMantissa; - - emit NewReserveFactor( - oldReserveFactorMantissa, - newReserveFactorMantissa - ); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Accrues interest and reduces reserves by transferring from msg.sender - * @param addAmount Amount of addition to reserves - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _addReservesInternal(uint256 addAmount) - internal - nonReentrant - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return - fail( - Error(error), - FailureInfo.ADD_RESERVES_ACCRUE_INTEREST_FAILED - ); - } - - uint256 totalReservesNew; - uint256 actualAddAmount; - - if (accrualBlockNumber != getBlockNumber()) { - return ( - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.ADD_RESERVES_FRESH_CHECK - ) - ); - } - - actualAddAmount = doTransferIn(msg.sender, addAmount); - - totalReservesNew = totalReserves + actualAddAmount; - - require(totalReservesNew >= totalReserves, "CT22"); - - totalReserves = totalReservesNew; - - emit ReservesAdded(msg.sender, actualAddAmount, totalReservesNew); - - return (uint256(Error.NO_ERROR)); - } - - function _addSubsidyInternal(uint256 addAmount) - internal - nonReentrant - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - // accrueInterest emits logs on errors, but on top of that we want to log the fact that an attempted reduce reserves failed. - return fail(Error(error), FailureInfo.ADD_SUBSIDY_FUND_FAILED); - } - - uint256 subsidyFundNew; - uint256 actualAddAmount; - - if (accrualBlockNumber != getBlockNumber()) { - return ( - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.ADD_SUBSIDY_FUND_FRESH_CHECK - ) - ); - } - - actualAddAmount = doTransferIn(msg.sender, addAmount); - - subsidyFundNew = subsidyFund + actualAddAmount; - - require(subsidyFundNew >= subsidyFund, "CT22"); - - subsidyFund = subsidyFundNew; - - emit SubsidyAdded(msg.sender, actualAddAmount, subsidyFundNew); - - /* Return (NO_ERROR, actualAddAmount) */ - return (uint256(Error.NO_ERROR)); - } - - /** - * @notice Accrues interest and reduces reserves by transferring to admin - * @param reduceAmount Amount of reduction to reserves - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _reduceReserves(uint256 reduceAmount) - external - override - nonReentrant - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return - fail( - Error(error), - FailureInfo.REDUCE_RESERVES_ACCRUE_INTEREST_FAILED - ); - } - return _reduceReservesFresh(reduceAmount); - } - - /** - * @notice Reduces reserves by transferring to admin - * @dev Requires fresh interest accrual - * @param reduceAmount Amount of reduction to reserves - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _reduceReservesFresh(uint256 reduceAmount) - internal - returns (uint256) - { - uint256 totalReservesNew; - - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.REDUCE_RESERVES_ADMIN_CHECK - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.REDUCE_RESERVES_FRESH_CHECK - ); - } - - if (getCashPrior() < reduceAmount) { - return - fail( - Error.TOKEN_INSUFFICIENT_CASH, - FailureInfo.REDUCE_RESERVES_CASH_NOT_AVAILABLE - ); - } - - if (reduceAmount > totalReserves) { - return - fail(Error.BAD_INPUT, FailureInfo.REDUCE_RESERVES_VALIDATION); - } - - totalReservesNew = totalReserves - reduceAmount; - require(totalReservesNew <= totalReserves, "CT23"); - - totalReserves = totalReservesNew; - - doTransferOut(admin, reduceAmount); - - emit ReservesReduced(admin, reduceAmount, totalReservesNew); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice accrues interest and updates the interest rate model using _setInterestRateModelFresh - * @dev Admin function to accrue interest and update the interest rate model - * @param newInterestRateModel the new interest rate model to use - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setInterestRateModel(InterestRateModel newInterestRateModel) - public - override - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return - fail( - Error(error), - FailureInfo.SET_INTEREST_RATE_MODEL_ACCRUE_INTEREST_FAILED - ); - } - return _setInterestRateModelFresh(newInterestRateModel); - } - - /** - * @notice updates the interest rate model (*requires fresh interest accrual) - * @dev Admin function to update the interest rate model - * @param newInterestRateModel the new interest rate model to use - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setInterestRateModelFresh(InterestRateModel newInterestRateModel) - internal - returns (uint256) - { - InterestRateModel oldInterestRateModel; - - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_INTEREST_RATE_MODEL_OWNER_CHECK - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.SET_INTEREST_RATE_MODEL_FRESH_CHECK - ); - } - - oldInterestRateModel = interestRateModel; - - require(newInterestRateModel.isInterestRateModel(), "CT21"); - - interestRateModel = newInterestRateModel; - - emit NewMarketInterestRateModel( - oldInterestRateModel, - newInterestRateModel - ); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Gets balance of this contract in terms of the underlying - * @dev This excludes the value of the current message, if any - * @return The quantity of underlying owned by this contract - */ - function getCashPrior() internal view virtual returns (uint256); - - /** - * @dev Performs a transfer in, reverting upon failure. Returns the amount actually transferred to the protocol, in case of a fee. - * This may revert due to insufficient balance or insufficient allowance. - */ - function doTransferIn(address from, uint256 amount) - internal - virtual - returns (uint256); - - /** - * @dev Performs a transfer out, ideally returning an explanatory error code upon failure tather than reverting. - * If caller has not called checked protocol's balance, may revert due to insufficient cash held in the contract. - * If caller has checked protocol's balance, and verified it is >= amount, this should not revert in normal conditions. - */ - function doTransferOut(address payable to, uint256 amount) internal virtual; - - /** - * @dev Prevents a contract from calling itself, directly or indirectly. - */ - modifier nonReentrant() { - require(_notEntered, "re-entered"); - _notEntered = false; - _; - _notEntered = true; - } -} - - -// Root file: contracts/CErc20.sol - -pragma solidity 0.8.6; - -// import "contracts/CToken.sol"; -// import "contracts/CTokenInterfaces.sol"; - -/** - * @title tropykus CErc20 Contract - * @notice CTokens which wrap an EIP-20 underlying - * @author tropykus - */ -contract CErc20 is CToken, CErc20Interface { - /** - * @notice Initialize the new money market - * @param underlying_ The address of the underlying asset - * @param comptroller_ The address of the Comptroller - * @param interestRateModel_ The address of the interest rate model - * @param initialExchangeRateMantissa_ The initial exchange rate, scaled by 1e18 - * @param name_ ERC-20 name of this token - * @param symbol_ ERC-20 symbol of this token - * @param decimals_ ERC-20 decimal precision of this token - */ - function initialize( - address underlying_, - ComptrollerInterface comptroller_, - InterestRateModel interestRateModel_, - uint256 initialExchangeRateMantissa_, - string memory name_, - string memory symbol_, - uint8 decimals_ - ) public { - // CToken initialize does the bulk of the work - super.initialize( - comptroller_, - interestRateModel_, - initialExchangeRateMantissa_, - name_, - symbol_, - decimals_ - ); - - // Set underlying and sanity check it - underlying = underlying_; - EIP20Interface(underlying).totalSupply(); - } - - /*** User Interface ***/ - - /** - * @notice Sender supplies assets into the market and receives cTokens in exchange - * @dev Accrues interest whether or not the operation succeeds, unless reverted - * @param mintAmount The amount of the underlying asset to supply - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function mint(uint256 mintAmount) external override returns (uint256) { - (uint256 err, ) = mintInternal(mintAmount); - return err; - } - - /** - * @notice Sender redeems cTokens in exchange for a specified amount of underlying asset - * @dev Accrues interest whether or not the operation succeeds, unless reverted - * @param redeemAmount The amount of underlying to redeem - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function redeem(uint256 redeemAmount) - external - override - returns (uint256) - { - return redeemUnderlyingInternal(redeemAmount); - } - - /** - * @notice Sender borrows assets from the protocol to their own address - * @param borrowAmount The amount of the underlying asset to borrow - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function borrow(uint256 borrowAmount) external override returns (uint256) { - return borrowInternal(borrowAmount); - } - - /** - * @notice Sender repays their own borrow - * @param repayAmount The amount to repay - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function repayBorrow(uint256 repayAmount) - external - override - returns (uint256) - { - (uint256 err, ) = repayBorrowInternal(repayAmount); - return err; - } - - /** - * @notice The sender liquidates the borrowers collateral. - * The collateral seized is transferred to the liquidator. - * @param borrower The borrower of this cToken to be liquidated - * @param repayAmount The amount of the underlying borrowed asset to repay - * @param cTokenCollateral The market in which to seize collateral from the borrower - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function liquidateBorrow( - address borrower, - uint256 repayAmount, - CTokenInterface cTokenCollateral - ) external override returns (uint256) { - (uint256 err, ) = liquidateBorrowInternal( - borrower, - repayAmount, - cTokenCollateral - ); - return err; - } - - /** - * @notice A public function to sweep accidental ERC-20 transfers to this contract. Tokens are sent to admin (timelock) - * @param token The address of the ERC-20 token to sweep - */ - function sweepToken(EIP20NonStandardInterface token) external override { - require(address(token) != underlying, "EC01"); - uint256 balance = token.balanceOf(address(this)); - token.transfer(admin, balance); - } - - /** - * @notice The sender adds to reserves. - * @param addAmount The amount fo underlying token to add as reserves - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _addReserves(uint256 addAmount) - external - override - returns (uint256) - { - return _addReservesInternal(addAmount); - } - - /*** Safe Token ***/ - - /** - * @notice Gets balance of this contract in terms of the underlying - * @dev This excludes the value of the current message, if any - * @return The quantity of underlying tokens owned by this contract - */ - function getCashPrior() internal view override returns (uint256) { - EIP20Interface token = EIP20Interface(underlying); - return token.balanceOf(address(this)); - } - - /** - * @dev Similar to EIP20 transfer, except it handles a False result from `transferFrom` and reverts in that case. - * This will revert due to insufficient balance or insufficient allowance. - * This function returns the actual amount received, - * which may be less than `amount` if there is a fee attached to the transfer. - * - * Note: This wrapper safely handles non-standard ERC-20 tokens that do not return a value. - * See here: https://medium.com/coinmonks/missing-return-value-bug-at-least-130-tokens-affected-d67bf08521ca - */ - function doTransferIn(address from, uint256 amount) - internal - override - returns (uint256) - { - EIP20NonStandardInterface token = EIP20NonStandardInterface(underlying); - uint256 balanceBefore = EIP20Interface(underlying).balanceOf( - address(this) - ); - token.transferFrom(from, address(this), amount); - - bool success; - assembly { - switch returndatasize() - case 0 { - // This is a non-standard ERC-20 - success := not(0) // set success to true - } - case 32 { - // This is a compliant ERC-20 - returndatacopy(0, 0, 32) - success := mload(0) // Set `success = returndata` of external call - } - default { - // This is an excessively non-compliant ERC-20, revert. - revert(0, 0) - } - } - require(success, "EC02"); - - // Calculate the amount that was *actually* transferred - uint256 balanceAfter = EIP20Interface(underlying).balanceOf( - address(this) - ); - require(balanceAfter >= balanceBefore, "EC03"); - return balanceAfter - balanceBefore; // underflow already checked above, just subtract - } - - /** - * @dev Similar to EIP20 transfer, except it handles a False success from `transfer` and returns an explanatory - * error code rather than reverting. If caller has not called checked protocol's balance, this may revert due to - * insufficient cash held in this contract. If caller has checked protocol's balance prior to this call, and verified - * it is >= amount, this should not revert in normal conditions. - * - * Note: This wrapper safely handles non-standard ERC-20 tokens that do not return a value. - * See here: https://medium.com/coinmonks/missing-return-value-bug-at-least-130-tokens-affected-d67bf08521ca - */ - function doTransferOut(address payable to, uint256 amount) - internal - virtual - override - { - EIP20NonStandardInterface token = EIP20NonStandardInterface(underlying); - token.transfer(to, amount); - - bool success; - assembly { - switch returndatasize() - case 0 { - // This is a non-standard ERC-20 - success := not(0) // set success to true - } - case 32 { - // This is a complaint ERC-20 - returndatacopy(0, 0, 32) - success := mload(0) // Set `success = returndata` of external call - } - default { - // This is an excessively non-compliant ERC-20, revert. - revert(0, 0) - } - } - require(success, "CE01"); - } -} diff --git a/flatten/CErc20Delegate.sol b/flatten/CErc20Delegate.sol deleted file mode 100644 index 53f8da5..0000000 --- a/flatten/CErc20Delegate.sol +++ /dev/null @@ -1,4211 +0,0 @@ -// Dependency file: contracts/ComptrollerInterface.sol - -// SPDX-License-Identifier: UNLICENSED -// pragma solidity 0.8.6; - -abstract contract ComptrollerInterface { - /// @notice Indicator that this is a Comptroller contract (for inspection) - bool public constant isComptroller = true; - - /*** Assets You Are In ***/ - - function enterMarkets(address[] calldata cTokens) - external - virtual - returns (uint256[] memory); - - function exitMarket(address cToken) external virtual returns (uint256); - - /*** Policy Hooks ***/ - - function mintAllowed( - address cToken, - address minter, - uint256 mintAmount - ) external virtual returns (uint256); - - function mintVerify( - address cToken, - address minter, - uint256 mintAmount, - uint256 mintTokens - ) external virtual; - - function redeemAllowed( - address cToken, - address redeemer, - uint256 redeemTokens - ) external virtual returns (uint256); - - function redeemVerify( - address cToken, - address redeemer, - uint256 redeemAmount, - uint256 redeemTokens - ) external virtual; - - function borrowAllowed( - address cToken, - address borrower, - uint256 borrowAmount - ) external virtual returns (uint256); - - function borrowVerify( - address cToken, - address borrower, - uint256 borrowAmount - ) external virtual; - - function repayBorrowAllowed( - address cToken, - address payer, - address borrower, - uint256 repayAmount - ) external virtual returns (uint256); - - function repayBorrowVerify( - address cToken, - address payer, - address borrower, - uint256 repayAmount, - uint256 borrowerIndex - ) external virtual; - - function liquidateBorrowAllowed( - address cTokenBorrowed, - address cTokenCollateral, - address liquidator, - address borrower, - uint256 repayAmount - ) external virtual returns (uint256); - - function liquidateBorrowVerify( - address cTokenBorrowed, - address cTokenCollateral, - address liquidator, - address borrower, - uint256 repayAmount, - uint256 seizeTokens - ) external virtual; - - function seizeAllowed( - address cTokenCollateral, - address cTokenBorrowed, - address liquidator, - address borrower, - uint256 seizeTokens - ) external virtual returns (uint256); - - function seizeVerify( - address cTokenCollateral, - address cTokenBorrowed, - address liquidator, - address borrower, - uint256 seizeTokens - ) external virtual; - - function transferAllowed( - address cToken, - address src, - address dst, - uint256 transferTokens - ) external virtual returns (uint256); - - function transferVerify( - address cToken, - address src, - address dst, - uint256 transferTokens - ) external virtual; - - /*** Liquidity/Liquidation Calculations ***/ - - function liquidateCalculateSeizeTokens( - address cTokenBorrowed, - address cTokenCollateral, - uint256 repayAmount - ) external view virtual returns (uint256, uint256); -} - - -// Dependency file: contracts/CarefulMath.sol - -// pragma solidity 0.8.6; - -/** - * @title Careful Math - * @author tropykus - * @notice Derived from OpenZeppelin's SafeMath library - * https://github.com/OpenZeppelin/openzeppelin-solidity/blob/master/contracts/math/SafeMath.sol - */ -contract CarefulMath { - - /** - * @dev Possible error codes that we can return - */ - enum MathError { - NO_ERROR, - DIVISION_BY_ZERO, - INTEGER_OVERFLOW, - INTEGER_UNDERFLOW - } - - /** - * @dev Multiplies two numbers, returns an error on overflow. - */ - function mulUInt(uint a, uint b) internal pure returns (MathError, uint) { - if (a == 0) { - return (MathError.NO_ERROR, 0); - } - - uint c = a * b; - - if (c / a != b) { - return (MathError.INTEGER_OVERFLOW, 0); - } else { - return (MathError.NO_ERROR, c); - } - } - - /** - * @dev Integer division of two numbers, truncating the quotient. - */ - function divUInt(uint a, uint b) internal pure returns (MathError, uint) { - if (b == 0) { - return (MathError.DIVISION_BY_ZERO, 0); - } - - return (MathError.NO_ERROR, a / b); - } - - /** - * @dev Subtracts two numbers, returns an error on overflow (i.e. if subtrahend is greater than minuend). - */ - function subUInt(uint a, uint b) internal pure returns (MathError, uint) { - if (b <= a) { - return (MathError.NO_ERROR, a - b); - } else { - return (MathError.INTEGER_UNDERFLOW, 0); - } - } - - /** - * @dev Adds two numbers, returns an error on overflow. - */ - function addUInt(uint a, uint b) internal pure returns (MathError, uint) { - uint c = a + b; - - if (c >= a) { - return (MathError.NO_ERROR, c); - } else { - return (MathError.INTEGER_OVERFLOW, 0); - } - } - - /** - * @dev add a and b and then subtract c - */ - function addThenSubUInt(uint a, uint b, uint c) internal pure returns (MathError, uint) { - (MathError err0, uint sum) = addUInt(a, b); - - if (err0 != MathError.NO_ERROR) { - return (err0, 0); - } - - return subUInt(sum, c); - } -} - - -// Dependency file: contracts/ExponentialNoError.sol - -// pragma solidity 0.8.6; - -/** - * @title Exponential module for storing fixed-precision decimals - * @author tropykus - * @notice Exp is a struct which stores decimals with a fixed precision of 18 decimal places. - * Thus, if we wanted to store the 5.1, mantissa would store 5.1e18. That is: - * `Exp({mantissa: 5100000000000000000})`. - */ -contract ExponentialNoError { - uint constant expScale = 1e18; - uint constant doubleScale = 1e36; - uint constant halfExpScale = expScale/2; - uint constant mantissaOne = expScale; - - struct Exp { - uint mantissa; - } - - struct Double { - uint mantissa; - } - - /** - * @dev Truncates the given exp to a whole number value. - * For example, truncate(Exp{mantissa: 15 * expScale}) = 15 - */ - function truncate(Exp memory exp) pure internal returns (uint) { - // Note: We are not using careful math here as we're performing a division that cannot fail - return exp.mantissa / expScale; - } - - /** - * @dev Multiply an Exp by a scalar, then truncate to return an unsigned integer. - */ - function mul_ScalarTruncate(Exp memory a, uint scalar) pure internal returns (uint) { - Exp memory product = mul_(a, scalar); - return truncate(product); - } - - /** - * @dev Multiply an Exp by a scalar, truncate, then add an to an unsigned integer, returning an unsigned integer. - */ - function mul_ScalarTruncateAddUInt(Exp memory a, uint scalar, uint addend) pure internal returns (uint) { - Exp memory product = mul_(a, scalar); - return add_(truncate(product), addend); - } - - /** - * @dev Checks if first Exp is less than second Exp. - */ - function lessThanExp(Exp memory left, Exp memory right) pure internal returns (bool) { - return left.mantissa < right.mantissa; - } - - /** - * @dev Checks if left Exp <= right Exp. - */ - function lessThanOrEqualExp(Exp memory left, Exp memory right) pure internal returns (bool) { - return left.mantissa <= right.mantissa; - } - - /** - * @dev Checks if left Exp > right Exp. - */ - function greaterThanExp(Exp memory left, Exp memory right) pure internal returns (bool) { - return left.mantissa > right.mantissa; - } - - /** - * @dev returns true if Exp is exactly zero - */ - function isZeroExp(Exp memory value) pure internal returns (bool) { - return value.mantissa == 0; - } - - function safe224(uint n, string memory errorMessage) pure internal returns (uint224) { - require(n < 2**224, errorMessage); - return uint224(n); - } - - function safe32(uint n, string memory errorMessage) pure internal returns (uint32) { - require(n < 2**32, errorMessage); - return uint32(n); - } - - function add_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { - return Exp({mantissa: add_(a.mantissa, b.mantissa)}); - } - - function add_(Double memory a, Double memory b) pure internal returns (Double memory) { - return Double({mantissa: add_(a.mantissa, b.mantissa)}); - } - - function add_(uint a, uint b) pure internal returns (uint) { - return add_(a, b, "addition overflow"); - } - - function add_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { - uint c = a + b; - require(c >= a, errorMessage); - return c; - } - - function sub_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { - return Exp({mantissa: sub_(a.mantissa, b.mantissa)}); - } - - function sub_(Double memory a, Double memory b) pure internal returns (Double memory) { - return Double({mantissa: sub_(a.mantissa, b.mantissa)}); - } - - function sub_(uint a, uint b) pure internal returns (uint) { - return sub_(a, b, "subtraction underflow"); - } - - function sub_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { - require(b <= a, errorMessage); - return a - b; - } - - function mul_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { - return Exp({mantissa: mul_(a.mantissa, b.mantissa) / expScale}); - } - - function mul_(Exp memory a, uint b) pure internal returns (Exp memory) { - return Exp({mantissa: mul_(a.mantissa, b)}); - } - - function mul_(uint a, Exp memory b) pure internal returns (uint) { - return mul_(a, b.mantissa) / expScale; - } - - function mul_(Double memory a, Double memory b) pure internal returns (Double memory) { - return Double({mantissa: mul_(a.mantissa, b.mantissa) / doubleScale}); - } - - function mul_(Double memory a, uint b) pure internal returns (Double memory) { - return Double({mantissa: mul_(a.mantissa, b)}); - } - - function mul_(uint a, Double memory b) pure internal returns (uint) { - return mul_(a, b.mantissa) / doubleScale; - } - - function mul_(uint a, uint b) pure internal returns (uint) { - return mul_(a, b, "multiplication overflow"); - } - - function mul_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { - if (a == 0 || b == 0) { - return 0; - } - uint c = a * b; - require(c / a == b, errorMessage); - return c; - } - - function div_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { - return Exp({mantissa: div_(mul_(a.mantissa, expScale), b.mantissa)}); - } - - function div_(Exp memory a, uint b) pure internal returns (Exp memory) { - return Exp({mantissa: div_(a.mantissa, b)}); - } - - function div_(uint a, Exp memory b) pure internal returns (uint) { - return div_(mul_(a, expScale), b.mantissa); - } - - function div_(Double memory a, Double memory b) pure internal returns (Double memory) { - return Double({mantissa: div_(mul_(a.mantissa, doubleScale), b.mantissa)}); - } - - function div_(Double memory a, uint b) pure internal returns (Double memory) { - return Double({mantissa: div_(a.mantissa, b)}); - } - - function div_(uint a, Double memory b) pure internal returns (uint) { - return div_(mul_(a, doubleScale), b.mantissa); - } - - function div_(uint a, uint b) pure internal returns (uint) { - return div_(a, b, "divide by zero"); - } - - function div_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { - require(b > 0, errorMessage); - return a / b; - } - - function fraction(uint a, uint b) pure internal returns (Double memory) { - return Double({mantissa: div_(mul_(a, doubleScale), b)}); - } -} - - -// Dependency file: contracts/Exponential.sol - -// pragma solidity 0.8.6; - -// import "contracts/CarefulMath.sol"; -// import "contracts/ExponentialNoError.sol"; - -/** - * @title Exponential module for storing fixed-precision decimals - * @author tropykus - * @dev Legacy contract for compatibility reasons with existing contracts that still use MathError - * @notice Exp is a struct which stores decimals with a fixed precision of 18 decimal places. - * Thus, if we wanted to store the 5.1, mantissa would store 5.1e18. That is: - * `Exp({mantissa: 5100000000000000000})`. - */ -contract Exponential is CarefulMath, ExponentialNoError { - /** - * @dev Creates an exponential from numerator and denominator values. - * Note: Returns an error if (`num` * 10e18) > MAX_INT, - * or if `denom` is zero. - */ - function getExp(uint num, uint denom) internal pure returns (MathError, Exp memory) { - (MathError err0, uint scaledNumerator) = mulUInt(num, expScale); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - - (MathError err1, uint rational) = divUInt(scaledNumerator, denom); - if (err1 != MathError.NO_ERROR) { - return (err1, Exp({mantissa: 0})); - } - - return (MathError.NO_ERROR, Exp({mantissa: rational})); - } - - /** - * @dev Adds two exponentials, returning a new exponential. - */ - function addExp(Exp memory a, Exp memory b) internal pure returns (MathError, Exp memory) { - (MathError error, uint result) = addUInt(a.mantissa, b.mantissa); - - return (error, Exp({mantissa: result})); - } - - /** - * @dev Subtracts two exponentials, returning a new exponential. - */ - function subExp(Exp memory a, Exp memory b) internal pure returns (MathError, Exp memory) { - (MathError error, uint result) = subUInt(a.mantissa, b.mantissa); - - return (error, Exp({mantissa: result})); - } - - /** - * @dev Multiply an Exp by a scalar, returning a new Exp. - */ - function mulScalar(Exp memory a, uint scalar) internal pure returns (MathError, Exp memory) { - (MathError err0, uint scaledMantissa) = mulUInt(a.mantissa, scalar); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - - return (MathError.NO_ERROR, Exp({mantissa: scaledMantissa})); - } - - /** - * @dev Multiply an Exp by a scalar, then truncate to return an unsigned integer. - */ - function mulScalarTruncate(Exp memory a, uint scalar) internal pure returns (MathError, uint) { - (MathError err, Exp memory product) = mulScalar(a, scalar); - if (err != MathError.NO_ERROR) { - return (err, 0); - } - - return (MathError.NO_ERROR, truncate(product)); - } - - /** - * @dev Multiply an Exp by a scalar, truncate, then add an to an unsigned integer, returning an unsigned integer. - */ - function mulScalarTruncateAddUInt(Exp memory a, uint scalar, uint addend) internal pure returns (MathError, uint) { - (MathError err, Exp memory product) = mulScalar(a, scalar); - if (err != MathError.NO_ERROR) { - return (err, 0); - } - - return addUInt(truncate(product), addend); - } - - /** - * @dev Divide an Exp by a scalar, returning a new Exp. - */ - function divScalar(Exp memory a, uint scalar) internal pure returns (MathError, Exp memory) { - (MathError err0, uint descaledMantissa) = divUInt(a.mantissa, scalar); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - - return (MathError.NO_ERROR, Exp({mantissa: descaledMantissa})); - } - - /** - * @dev Divide a scalar by an Exp, returning a new Exp. - */ - function divScalarByExp(uint scalar, Exp memory divisor) internal pure returns (MathError, Exp memory) { - /* - We are doing this as: - getExp(mulUInt(expScale, scalar), divisor.mantissa) - - How it works: - Exp = a / b; - Scalar = s; - `s / (a / b)` = `b * s / a` and since for an Exp `a = mantissa, b = expScale` - */ - (MathError err0, uint numerator) = mulUInt(expScale, scalar); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - return getExp(numerator, divisor.mantissa); - } - - /** - * @dev Divide a scalar by an Exp, then truncate to return an unsigned integer. - */ - function divScalarByExpTruncate(uint scalar, Exp memory divisor) internal pure returns (MathError, uint) { - (MathError err, Exp memory fraction) = divScalarByExp(scalar, divisor); - if (err != MathError.NO_ERROR) { - return (err, 0); - } - - return (MathError.NO_ERROR, truncate(fraction)); - } - - /** - * @dev Multiplies two exponentials, returning a new exponential. - */ - function mulExp(Exp memory a, Exp memory b) internal pure returns (MathError, Exp memory) { - - (MathError err0, uint doubleScaledProduct) = mulUInt(a.mantissa, b.mantissa); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - - // We add half the scale before dividing so that we get rounding instead of truncation. - // See "Listing 6" and text above it at https://accu.org/index.php/journals/1717 - // Without this change, a result like 6.6...e-19 will be truncated to 0 instead of being rounded to 1e-18. - (MathError err1, uint doubleScaledProductWithHalfScale) = addUInt(halfExpScale, doubleScaledProduct); - if (err1 != MathError.NO_ERROR) { - return (err1, Exp({mantissa: 0})); - } - - (MathError err2, uint product) = divUInt(doubleScaledProductWithHalfScale, expScale); - // The only error `div` can return is MathError.DIVISION_BY_ZERO but we control `expScale` and it is not zero. - assert(err2 == MathError.NO_ERROR); - - return (MathError.NO_ERROR, Exp({mantissa: product})); - } - - /** - * @dev Multiplies two exponentials given their mantissas, returning a new exponential. - */ - function mulExp(uint a, uint b) internal pure returns (MathError, Exp memory) { - return mulExp(Exp({mantissa: a}), Exp({mantissa: b})); - } - - /** - * @dev Multiplies three exponentials, returning a new exponential. - */ - function mulExp3(Exp memory a, Exp memory b, Exp memory c) internal pure returns (MathError, Exp memory) { - (MathError err, Exp memory ab) = mulExp(a, b); - if (err != MathError.NO_ERROR) { - return (err, ab); - } - return mulExp(ab, c); - } - - /** - * @dev Divides two exponentials, returning a new exponential. - * (a/scale) / (b/scale) = (a/scale) * (scale/b) = a/b, - * which we can scale as an Exp by calling getExp(a.mantissa, b.mantissa) - */ - function divExp(Exp memory a, Exp memory b) internal pure returns (MathError, Exp memory) { - return getExp(a.mantissa, b.mantissa); - } -} - - -// Dependency file: contracts/SafeMath.sol - -// pragma solidity 0.8.6; - -// From https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/math/Math.sol -// Subject to the MIT license. - -/** - * @dev Wrappers over Solidity's arithmetic operations with added overflow - * checks. - * - * Arithmetic operations in Solidity wrap on overflow. This can easily result - * in bugs, because programmers usually assume that an overflow raises an - * error, which is the standard behavior in high level programming languages. - * `SafeMath` restores this intuition by reverting the transaction when an - * operation overflows. - * - * Using this library instead of the unchecked operations eliminates an entire - * class of bugs, so it's recommended to use it always. - */ -library SafeMath { - /** - * @dev Returns the addition of two unsigned integers, reverting on overflow. - * - * Counterpart to Solidity's `+` operator. - * - * Requirements: - * - Addition cannot overflow. - */ - function add(uint256 a, uint256 b) internal pure returns (uint256) { - uint256 c = a + b; - require(c >= a, "SafeMath: addition overflow"); - - return c; - } - - /** - * @dev Returns the addition of two unsigned integers, reverting with custom message on overflow. - * - * Counterpart to Solidity's `+` operator. - * - * Requirements: - * - Addition cannot overflow. - */ - function add(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - uint256 c = a + b; - require(c >= a, errorMessage); - - return c; - } - - /** - * @dev Returns the subtraction of two unsigned integers, reverting on underflow (when the result is negative). - * - * Counterpart to Solidity's `-` operator. - * - * Requirements: - * - Subtraction cannot underflow. - */ - function sub(uint256 a, uint256 b) internal pure returns (uint256) { - return sub(a, b, "SafeMath: subtraction underflow"); - } - - /** - * @dev Returns the subtraction of two unsigned integers, reverting with custom message on underflow (when the result is negative). - * - * Counterpart to Solidity's `-` operator. - * - * Requirements: - * - Subtraction cannot underflow. - */ - function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - require(b <= a, errorMessage); - uint256 c = a - b; - - return c; - } - - /** - * @dev Returns the multiplication of two unsigned integers, reverting on overflow. - * - * Counterpart to Solidity's `*` operator. - * - * Requirements: - * - Multiplication cannot overflow. - */ - function mul(uint256 a, uint256 b) internal pure returns (uint256) { - // Gas optimization: this is cheaper than requiring 'a' not being zero, but the - // benefit is lost if 'b' is also tested. - // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 - if (a == 0) { - return 0; - } - - uint256 c = a * b; - require(c / a == b, "SafeMath: multiplication overflow"); - - return c; - } - - /** - * @dev Returns the multiplication of two unsigned integers, reverting on overflow. - * - * Counterpart to Solidity's `*` operator. - * - * Requirements: - * - Multiplication cannot overflow. - */ - function mul(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - // Gas optimization: this is cheaper than requiring 'a' not being zero, but the - // benefit is lost if 'b' is also tested. - // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 - if (a == 0) { - return 0; - } - - uint256 c = a * b; - require(c / a == b, errorMessage); - - return c; - } - - /** - * @dev Returns the integer division of two unsigned integers. - * Reverts on division by zero. The result is rounded towards zero. - * - * Counterpart to Solidity's `/` operator. Note: this function uses a - * `revert` opcode (which leaves remaining gas untouched) while Solidity - * uses an invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function div(uint256 a, uint256 b) internal pure returns (uint256) { - return div(a, b, "SafeMath: division by zero"); - } - - /** - * @dev Returns the integer division of two unsigned integers. - * Reverts with custom message on division by zero. The result is rounded towards zero. - * - * Counterpart to Solidity's `/` operator. Note: this function uses a - * `revert` opcode (which leaves remaining gas untouched) while Solidity - * uses an invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - // Solidity only automatically asserts when dividing by 0 - require(b > 0, errorMessage); - uint256 c = a / b; - // assert(a == b * c + a % b); // There is no case in which this doesn't hold - - return c; - } - - /** - * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), - * Reverts when dividing by zero. - * - * Counterpart to Solidity's `%` operator. This function uses a `revert` - * opcode (which leaves remaining gas untouched) while Solidity uses an - * invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function mod(uint256 a, uint256 b) internal pure returns (uint256) { - return mod(a, b, "SafeMath: modulo by zero"); - } - - /** - * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), - * Reverts with custom message when dividing by zero. - * - * Counterpart to Solidity's `%` operator. This function uses a `revert` - * opcode (which leaves remaining gas untouched) while Solidity uses an - * invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - require(b != 0, errorMessage); - return a % b; - } -} - - -// Dependency file: contracts/InterestRateModel.sol - -// pragma solidity 0.8.6; - -// import "contracts/Exponential.sol"; -// import "contracts/SafeMath.sol"; - -/** - * @title tropykus InterestRateModel Interface - * @author tropykus - */ -abstract contract InterestRateModel is Exponential { - using SafeMath for uint256; - - /// @notice Indicator that this is an InterestRateModel contract (for inspection) - bool public constant isInterestRateModel = true; - bool public isTropykusInterestRateModel; - - /** - * @notice The approximate number of blocks per year that is assumed by the interest rate model - */ - uint256 public constant blocksPerYear = 1051200; - - /** - * @notice Calculates the utilization rate of the market: `borrows / (cash + borrows - reserves)` - * @param cash The amount of cash in the market - * @param borrows The amount of borrows in the market - * @param reserves The amount of reserves in the market (currently unused) - * @return The utilization rate as a mantissa between [0, 1e18] - */ - function utilizationRate( - uint256 cash, - uint256 borrows, - uint256 reserves - ) public pure virtual returns (uint256) { - // Utilization rate is 0 when there are no borrows - if (borrows == 0) { - return 0; - } - - return borrows.mul(1e18).div(cash.add(borrows).sub(reserves)); - } - - /** - * @notice Calculates the current borrow interest rate per block - * @param cash The total amount of cash the market has - * @param borrows The total amount of borrows the market has outstanding - * @param reserves The total amnount of reserves the market has - * @return The borrow rate per block (as a percentage, and scaled by 1e18) - */ - function getBorrowRate( - uint256 cash, - uint256 borrows, - uint256 reserves - ) external view virtual returns (uint256); - - /** - * @notice Calculates the current supply interest rate per block - * @param cash The total amount of cash the market has - * @param borrows The total amount of borrows the market has outstanding - * @param reserves The total amnount of reserves the market has - * @param reserveFactorMantissa The current reserve factor the market has - * @return The supply rate per block (as a percentage, and scaled by 1e18) - */ - function getSupplyRate( - uint256 cash, - uint256 borrows, - uint256 reserves, - uint256 reserveFactorMantissa - ) external view virtual returns (uint256); - - function getExchangeRate( - uint256 _totalCash, - uint256 _totalBorrows, - uint256 _totalReserves, - uint256 _totalSupply - ) public pure returns (MathError, uint256) { - /* - * exchangeRate = (totalCash + totalBorrows - totalReserves) / totalSupply - */ - Exp memory exchangeRate; - MathError mathErr; - uint256 cashPlusBorrowsMinusReserves; - (mathErr, cashPlusBorrowsMinusReserves) = addThenSubUInt( - _totalCash, - _totalBorrows, - _totalReserves - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - (mathErr, exchangeRate) = getExp( - cashPlusBorrowsMinusReserves, - _totalSupply - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - - return (MathError.NO_ERROR, exchangeRate.mantissa); - } - - function isAboveOptimal( - uint256 cash, - uint256 borrows, - uint256 reserves - ) public view virtual returns (bool) { - cash; - borrows; - reserves; - return false; - } -} - - -// Dependency file: contracts/EIP20NonStandardInterface.sol - -// pragma solidity 0.8.6; - -/** - * @title EIP20NonStandardInterface - * @dev Version of ERC20 with no return values for `transfer` and `transferFrom` - * See https://medium.com/coinmonks/missing-return-value-bug-at-least-130-tokens-affected-d67bf08521ca - */ -interface EIP20NonStandardInterface { - /** - * @notice Get the total number of tokens in circulation - * @return The supply of tokens - */ - function totalSupply() external view returns (uint256); - - /** - * @notice Gets the balance of the specified address - * @param owner The address from which the balance will be retrieved - * @return balance The balance - */ - function balanceOf(address owner) external view returns (uint256 balance); - - /// - /// !!!!!!!!!!!!!! - /// !!! NOTICE !!! `transfer` does not return a value, in violation of the ERC-20 specification - /// !!!!!!!!!!!!!! - /// - - /** - * @notice Transfer `amount` tokens from `msg.sender` to `dst` - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - */ - function transfer(address dst, uint256 amount) external; - - /// - /// !!!!!!!!!!!!!! - /// !!! NOTICE !!! `transferFrom` does not return a value, in violation of the ERC-20 specification - /// !!!!!!!!!!!!!! - /// - - /** - * @notice Transfer `amount` tokens from `src` to `dst` - * @param src The address of the source account - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - */ - function transferFrom( - address src, - address dst, - uint256 amount - ) external; - - /** - * @notice Approve `spender` to transfer up to `amount` from `src` - * @dev This will overwrite the approval amount for `spender` - * and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve) - * @param spender The address of the account which may transfer tokens - * @param amount The number of tokens that are approved - * @return success Whether or not the approval succeeded - */ - function approve(address spender, uint256 amount) - external - returns (bool success); - - /** - * @notice Get the current allowance from `owner` for `spender` - * @param owner The address of the account which owns the tokens to be spent - * @param spender The address of the account which may transfer tokens - * @return remaining The number of tokens allowed to be spent - */ - function allowance(address owner, address spender) - external - view - returns (uint256 remaining); - - event Transfer(address indexed from, address indexed to, uint256 amount); - event Approval( - address indexed owner, - address indexed spender, - uint256 amount - ); -} - - -// Dependency file: contracts/CTokenInterfaces.sol - -// pragma solidity 0.8.6; - -// import "contracts/ComptrollerInterface.sol"; -// import "contracts/InterestRateModel.sol"; -// import "contracts/EIP20NonStandardInterface.sol"; - -contract CTokenStorage { - /** - * @dev Guard variable for re-entrancy checks - */ - bool internal _notEntered; - - /** - * @notice EIP-20 token name for this token - */ - string public name; - - /** - * @notice EIP-20 token symbol for this token - */ - string public symbol; - - /** - * @notice EIP-20 token decimals for this token - */ - uint8 public decimals; - - /** - * @notice Maximum borrow rate that can ever be applied (.0005% / block) - */ - - uint256 internal constant borrowRateMaxMantissa = 0.0005e16; - - /** - * @notice Maximum fraction of interest that can be set aside for reserves - */ - uint256 internal constant reserveFactorMaxMantissa = 1e18; - - /** - * @notice Administrator for this contract - */ - address payable public admin; - - /** - * @notice Pending administrator for this contract - */ - address payable public pendingAdmin; - - /** - * @notice Contract which oversees inter-cToken operations - */ - ComptrollerInterface public comptroller; - - /** - * @notice Model which tells what the current interest rate should be - */ - InterestRateModel public interestRateModel; - - /** - * @notice Initial exchange rate used when minting the first CTokens (used when totalSupply = 0) - */ - uint256 public initialExchangeRateMantissa; - - /** - * @notice Fraction of interest currently set aside for reserves - */ - uint256 public reserveFactorMantissa; - - /** - * @notice Block number that interest was last accrued at - */ - uint256 public accrualBlockNumber; - - /** - * @notice Accumulator of the total earned interest rate since the opening of the market - */ - uint256 public borrowIndex; - - /** - * @notice Total amount of outstanding borrows of the underlying in this market - */ - uint256 public totalBorrows; - - /** - * @notice Total amount of reserves of the underlying held in this market - */ - uint256 public totalReserves; - - /** - * @notice Total number of tokens in circulation - */ - uint256 public totalSupply; - - uint256 public subsidyFund; - - struct SupplySnapshot { - uint256 tokens; - uint256 underlyingAmount; - uint256 suppliedAt; - uint256 promisedSupplyRate; - } - - /** - * @notice Official record of token balances for each account - */ - mapping(address => SupplySnapshot) internal accountTokens; - - /** - * @notice Approved token transfer amounts on behalf of others - */ - mapping(address => mapping(address => uint256)) internal transferAllowances; - - /** - * @notice Container for borrow balance information - * @member principal Total balance (with accrued interest), after applying the most recent balance-changing action - * @member interestIndex Global borrowIndex as of the most recent balance-changing action - */ - struct BorrowSnapshot { - uint256 principal; - uint256 interestIndex; - } - - /** - * @notice Mapping of account addresses to outstanding borrow balances - */ - mapping(address => BorrowSnapshot) internal accountBorrows; -} - -abstract contract CTokenInterface is CTokenStorage { - /** - * @notice Indicator that this is a CToken contract (for inspection) - */ - bool public constant isCToken = true; - - /*** Market Events ***/ - - /** - * @notice Event emitted when interest is accrued - */ - event AccrueInterest( - uint256 cashPrior, - uint256 interestAccumulated, - uint256 borrowIndex, - uint256 totalBorrows - ); - - /** - * @notice Event emitted when tokens are minted - */ - event Mint(address indexed minter, uint256 mintAmount, uint256 mintTokens); - - /** - * @notice Event emitted when tokens are redeemed - */ - event Redeem( - address indexed redeemer, - uint256 redeemAmount, - uint256 redeemTokens - ); - - /** - * @notice Event emitted when underlying is borrowed - */ - event Borrow( - address indexed borrower, - uint256 borrowAmount, - uint256 accountBorrows, - uint256 totalBorrows - ); - - /** - * @notice Event emitted when a borrow is repaid - */ - event RepayBorrow( - address indexed payer, - address indexed borrower, - uint256 repayAmount, - uint256 accountBorrows, - uint256 totalBorrows - ); - - /** - * @notice Event emitted when a borrow is liquidated - */ - event LiquidateBorrow( - address indexed liquidator, - address indexed borrower, - uint256 repayAmount, - address indexed cTokenCollateral, - uint256 seizeTokens - ); - - /*** Admin Events ***/ - - /** - * @notice Event emitted when pendingAdmin is changed - */ - event NewPendingAdmin(address oldPendingAdmin, address newPendingAdmin); - - /** - * @notice Event emitted when pendingAdmin is accepted, which means admin is updated - */ - event NewAdmin(address oldAdmin, address newAdmin); - - /** - * @notice Event emitted when comptroller is changed - */ - event NewComptroller( - ComptrollerInterface oldComptroller, - ComptrollerInterface newComptroller - ); - - /** - * @notice Event emitted when interestRateModel is changed - */ - event NewMarketInterestRateModel( - InterestRateModel oldInterestRateModel, - InterestRateModel newInterestRateModel - ); - - /** - * @notice Event emitted when the reserve factor is changed - */ - event NewReserveFactor( - uint256 oldReserveFactorMantissa, - uint256 newReserveFactorMantissa - ); - - /** - * @notice Event emitted when the reserves are added - */ - event ReservesAdded( - address benefactor, - uint256 addAmount, - uint256 newTotalReserves - ); - - event SubsidyAdded( - address benefactor, - uint256 addAmount, - uint256 newSubsidyFund - ); - - /** - * @notice Event emitted when the reserves are reduced - */ - event ReservesReduced( - address admin, - uint256 reduceAmount, - uint256 newTotalReserves - ); - - /** - * @notice EIP20 Transfer event - */ - event Transfer(address indexed from, address indexed to, uint256 amount); - - /** - * @notice EIP20 Approval event - */ - event Approval( - address indexed owner, - address indexed spender, - uint256 amount - ); - - /** - * @notice Failure event - */ - event CTokenStorageFailure(uint256 error, uint256 info, uint256 detail); - - /*** User Interface ***/ - - function transfer(address dst, uint256 amount) - external - virtual - returns (bool); - - function transferFrom( - address src, - address dst, - uint256 amount - ) external virtual returns (bool); - - function approve(address spender, uint256 amount) - external - virtual - returns (bool); - - function allowance(address owner, address spender) - external - view - virtual - returns (uint256); - - function balanceOf(address owner) external view virtual returns (uint256); - - function balanceOfUnderlying(address owner) - external - virtual - returns (uint256); - - function getAccountSnapshot(address account) - external - view - virtual - returns ( - uint256, - uint256, - uint256, - uint256 - ); - - function borrowRatePerBlock() external view virtual returns (uint256); - - function supplyRatePerBlock() external view virtual returns (uint256); - - function totalBorrowsCurrent() external virtual returns (uint256); - - function borrowBalanceCurrent(address account) - external - virtual - returns (uint256); - - function borrowBalanceStored(address account) - public - view - virtual - returns (uint256); - - function exchangeRateCurrent() public virtual returns (uint256); - - function exchangeRateStored() public view virtual returns (uint256); - - function getCash() external view virtual returns (uint256); - - function accrueInterest() public virtual returns (uint256); - - function seize( - address liquidator, - address borrower, - uint256 seizeTokens - ) external virtual returns (uint256); - - /*** Admin Functions ***/ - - function _setPendingAdmin(address payable newPendingAdmin) - external - virtual - returns (uint256); - - function _acceptAdmin() external virtual returns (uint256); - - function _setComptroller(ComptrollerInterface newComptroller) - public - virtual - returns (uint256); - - function _setReserveFactor(uint256 newReserveFactorMantissa) - external - virtual - returns (uint256); - - function _reduceReserves(uint256 reduceAmount) - external - virtual - returns (uint256); - - function _setInterestRateModel(InterestRateModel newInterestRateModel) - public - virtual - returns (uint256); -} - -contract CErc20Storage { - /** - * @notice Underlying asset for this CToken - */ - address public underlying; -} - -abstract contract CErc20Interface is CErc20Storage { - /*** User Interface ***/ - - function mint(uint256 mintAmount) external virtual returns (uint256); - - function redeem(uint256 redeemAmount) - external - virtual - returns (uint256); - - function borrow(uint256 borrowAmount) external virtual returns (uint256); - - function repayBorrow(uint256 repayAmount) - external - virtual - returns (uint256); - - function liquidateBorrow( - address borrower, - uint256 repayAmount, - CTokenInterface cTokenCollateral - ) external virtual returns (uint256); - - function sweepToken(EIP20NonStandardInterface token) external virtual; - - /*** Admin Functions ***/ - - function _addReserves(uint256 addAmount) external virtual returns (uint256); -} - -contract CDelegationStorage { - /** - * @notice Implementation address for this contract - */ - address public implementation; -} - -abstract contract CDelegatorInterface is CDelegationStorage { - /** - * @notice Emitted when implementation is changed - */ - event NewImplementation( - address oldImplementation, - address newImplementation - ); - - /** - * @notice Called by the admin to update the implementation of the delegator - * @param implementation_ The address of the new implementation for delegation - * @param allowResign Flag to indicate whether to call _resignImplementation on the old implementation - * @param becomeImplementationData The encoded bytes data to be passed to _becomeImplementation - */ - function _setImplementation( - address implementation_, - bool allowResign, - bytes memory becomeImplementationData - ) public virtual; -} - -abstract contract CDelegateInterface is CDelegationStorage { - /** - * @notice Called by the delegator on a delegate to initialize it for duty - * @dev Should revert if any issues arise which make it unfit for delegation - * @param data The encoded bytes data for any initialization - */ - function _becomeImplementation(bytes memory data) public virtual; - - /** - * @notice Called by the delegator on a delegate to forfeit its responsibility - */ - function _resignImplementation() public virtual; -} - - -// Dependency file: contracts/ErrorReporter.sol - -// pragma solidity 0.8.6; - -contract ComptrollerErrorReporter { - enum Error { - NO_ERROR, - UNAUTHORIZED, - COMPTROLLER_MISMATCH, - INSUFFICIENT_SHORTFALL, - INSUFFICIENT_LIQUIDITY, - INVALID_CLOSE_FACTOR, - INVALID_COLLATERAL_FACTOR, - INVALID_LIQUIDATION_INCENTIVE, - MARKET_NOT_ENTERED, // no longer possible - MARKET_NOT_LISTED, - MARKET_ALREADY_LISTED, - MATH_ERROR, - NONZERO_BORROW_BALANCE, - PRICE_ERROR, - REJECTION, - SNAPSHOT_ERROR, - TOO_MANY_ASSETS, - TOO_MUCH_REPAY - } - - enum FailureInfo { - ACCEPT_ADMIN_PENDING_ADMIN_CHECK, - ACCEPT_PENDING_IMPLEMENTATION_ADDRESS_CHECK, - EXIT_MARKET_BALANCE_OWED, - EXIT_MARKET_REJECTION, - SET_CLOSE_FACTOR_OWNER_CHECK, - SET_CLOSE_FACTOR_VALIDATION, - SET_COLLATERAL_FACTOR_OWNER_CHECK, - SET_COLLATERAL_FACTOR_NO_EXISTS, - SET_COLLATERAL_FACTOR_VALIDATION, - SET_COLLATERAL_FACTOR_WITHOUT_PRICE, - SET_IMPLEMENTATION_OWNER_CHECK, - SET_LIQUIDATION_INCENTIVE_OWNER_CHECK, - SET_LIQUIDATION_INCENTIVE_VALIDATION, - SET_MAX_ASSETS_OWNER_CHECK, - SET_PENDING_ADMIN_OWNER_CHECK, - SET_PENDING_IMPLEMENTATION_OWNER_CHECK, - SET_PRICE_ORACLE_OWNER_CHECK, - SUPPORT_MARKET_EXISTS, - SUPPORT_MARKET_OWNER_CHECK, - SET_PAUSE_GUARDIAN_OWNER_CHECK - } - - /** - * @dev `error` corresponds to enum Error; `info` corresponds to enum FailureInfo, and `detail` is an arbitrary - * contract-specific code that enables us to report opaque error codes from upgradeable contracts. - **/ - event Failure(uint256 error, uint256 info, uint256 detail); - - /** - * @dev use this when reporting a known error from the money market or a non-upgradeable collaborator - */ - function fail(Error err, FailureInfo info) internal returns (uint256) { - emit Failure(uint256(err), uint256(info), 0); - - return uint256(err); - } - - /** - * @dev use this when reporting an opaque error from an upgradeable collaborator contract - */ - function failOpaque( - Error err, - FailureInfo info, - uint256 opaqueError - ) internal returns (uint256) { - emit Failure(uint256(err), uint256(info), opaqueError); - - return uint256(err); - } -} - -contract TokenErrorReporter { - enum Error { - NO_ERROR, - UNAUTHORIZED, - BAD_INPUT, - COMPTROLLER_REJECTION, - COMPTROLLER_CALCULATION_ERROR, - INTEREST_RATE_MODEL_ERROR, - INVALID_ACCOUNT_PAIR, - INVALID_CLOSE_AMOUNT_REQUESTED, - INVALID_COLLATERAL_FACTOR, - MATH_ERROR, - MARKET_NOT_FRESH, - MARKET_NOT_LISTED, - TOKEN_INSUFFICIENT_ALLOWANCE, - TOKEN_INSUFFICIENT_BALANCE, - TOKEN_INSUFFICIENT_CASH, - TOKEN_TRANSFER_IN_FAILED, - TOKEN_TRANSFER_OUT_FAILED - } - - /* - * Note: FailureInfo (but not Error) is kept in alphabetical order - * This is because FailureInfo grows significantly faster, and - * the order of Error has some meaning, while the order of FailureInfo - * is entirely arbitrary. - */ - enum FailureInfo { - ACCEPT_ADMIN_PENDING_ADMIN_CHECK, - ACCRUE_INTEREST_ACCUMULATED_INTEREST_CALCULATION_FAILED, - ACCRUE_INTEREST_BORROW_RATE_CALCULATION_FAILED, - ACCRUE_INTEREST_NEW_BORROW_INDEX_CALCULATION_FAILED, - ACCRUE_INTEREST_NEW_TOTAL_BORROWS_CALCULATION_FAILED, - ACCRUE_INTEREST_NEW_TOTAL_RESERVES_CALCULATION_FAILED, - ACCRUE_INTEREST_SIMPLE_INTEREST_FACTOR_CALCULATION_FAILED, - BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED, - BORROW_ACCRUE_INTEREST_FAILED, - BORROW_CASH_NOT_AVAILABLE, - BORROW_FRESHNESS_CHECK, - BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED, - BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED, - BORROW_MARKET_NOT_LISTED, - BORROW_COMPTROLLER_REJECTION, - LIQUIDATE_ACCRUE_BORROW_INTEREST_FAILED, - LIQUIDATE_ACCRUE_COLLATERAL_INTEREST_FAILED, - LIQUIDATE_COLLATERAL_FRESHNESS_CHECK, - LIQUIDATE_COMPTROLLER_REJECTION, - LIQUIDATE_COMPTROLLER_CALCULATE_AMOUNT_SEIZE_FAILED, - LIQUIDATE_CLOSE_AMOUNT_IS_UINT_MAX, - LIQUIDATE_CLOSE_AMOUNT_IS_ZERO, - LIQUIDATE_FRESHNESS_CHECK, - LIQUIDATE_LIQUIDATOR_IS_BORROWER, - LIQUIDATE_REPAY_BORROW_FRESH_FAILED, - LIQUIDATE_SEIZE_BALANCE_INCREMENT_FAILED, - LIQUIDATE_SEIZE_BALANCE_DECREMENT_FAILED, - LIQUIDATE_SEIZE_COMPTROLLER_REJECTION, - LIQUIDATE_SEIZE_LIQUIDATOR_IS_BORROWER, - LIQUIDATE_SEIZE_TOO_MUCH, - MINT_ACCRUE_INTEREST_FAILED, - MINT_COMPTROLLER_REJECTION, - MINT_EXCHANGE_CALCULATION_FAILED, - MINT_EXCHANGE_RATE_READ_FAILED, - MINT_FRESHNESS_CHECK, - MINT_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED, - MINT_NEW_TOTAL_SUPPLY_CALCULATION_FAILED, - MINT_TRANSFER_IN_FAILED, - MINT_TRANSFER_IN_NOT_POSSIBLE, - REDEEM_ACCRUE_INTEREST_FAILED, - REDEEM_COMPTROLLER_REJECTION, - REDEEM_EXCHANGE_TOKENS_CALCULATION_FAILED, - REDEEM_EXCHANGE_AMOUNT_CALCULATION_FAILED, - REDEEM_EXCHANGE_RATE_READ_FAILED, - REDEEM_FRESHNESS_CHECK, - REDEEM_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED, - REDEEM_NEW_TOTAL_SUPPLY_CALCULATION_FAILED, - REDEEM_TRANSFER_OUT_NOT_POSSIBLE, - REDUCE_RESERVES_ACCRUE_INTEREST_FAILED, - REDUCE_RESERVES_ADMIN_CHECK, - REDUCE_RESERVES_CASH_NOT_AVAILABLE, - REDUCE_RESERVES_FRESH_CHECK, - REDUCE_RESERVES_VALIDATION, - REPAY_BEHALF_ACCRUE_INTEREST_FAILED, - REPAY_BORROW_ACCRUE_INTEREST_FAILED, - REPAY_BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED, - REPAY_BORROW_COMPTROLLER_REJECTION, - REPAY_BORROW_FRESHNESS_CHECK, - REPAY_BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED, - REPAY_BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED, - REPAY_BORROW_TRANSFER_IN_NOT_POSSIBLE, - SET_COLLATERAL_FACTOR_OWNER_CHECK, - SET_COLLATERAL_FACTOR_VALIDATION, - SET_COMPTROLLER_OWNER_CHECK, - SET_INTEREST_RATE_MODEL_ACCRUE_INTEREST_FAILED, - SET_INTEREST_RATE_MODEL_FRESH_CHECK, - SET_INTEREST_RATE_MODEL_OWNER_CHECK, - SET_MAX_ASSETS_OWNER_CHECK, - SET_ORACLE_MARKET_NOT_LISTED, - SET_PENDING_ADMIN_OWNER_CHECK, - SET_RESERVE_FACTOR_ACCRUE_INTEREST_FAILED, - SET_RESERVE_FACTOR_ADMIN_CHECK, - SET_RESERVE_FACTOR_FRESH_CHECK, - SET_RESERVE_FACTOR_BOUNDS_CHECK, - TRANSFER_COMPTROLLER_REJECTION, - TRANSFER_NOT_ALLOWED, - TRANSFER_NOT_ENOUGH, - TRANSFER_TOO_MUCH, - ADD_RESERVES_ACCRUE_INTEREST_FAILED, - ADD_RESERVES_FRESH_CHECK, - ADD_RESERVES_TRANSFER_IN_NOT_POSSIBLE, - ADD_SUBSIDY_FUND_FAILED, - ADD_SUBSIDY_FUND_FRESH_CHECK - } - - /** - * @dev `error` corresponds to enum Error; `info` corresponds to enum FailureInfo, and `detail` is an arbitrary - * contract-specific code that enables us to report opaque error codes from upgradeable contracts. - **/ - event TokenFailure(uint256 error, uint256 info, uint256 detail); - - /** - * @dev use this when reporting a known error from the money market or a non-upgradeable collaborator - */ - function fail(Error err, FailureInfo info) internal returns (uint256) { - emit TokenFailure(uint256(err), uint256(info), 0); - - return uint256(err); - } - - /** - * @dev use this when reporting an opaque error from an upgradeable collaborator contract - */ - function failOpaque( - Error err, - FailureInfo info, - uint256 opaqueError - ) internal returns (uint256) { - emit TokenFailure(uint256(err), uint256(info), opaqueError); - - return uint256(err); - } -} - - -// Dependency file: contracts/EIP20Interface.sol - -// pragma solidity 0.8.6; - -/** - * @title ERC 20 Token Standard Interface - * https://eips.ethereum.org/EIPS/eip-20 - */ -interface EIP20Interface { - function name() external view returns (string memory); - - function symbol() external view returns (string memory); - - function decimals() external view returns (uint8); - - /** - * @notice Get the total number of tokens in circulation - * @return The supply of tokens - */ - function totalSupply() external view returns (uint256); - - /** - * @notice Gets the balance of the specified address - * @param owner The address from which the balance will be retrieved - * @return balance The balance - */ - function balanceOf(address owner) external view returns (uint256 balance); - - /** - * @notice Transfer `amount` tokens from `msg.sender` to `dst` - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - * @return success Whether or not the transfer succeeded - */ - function transfer(address dst, uint256 amount) - external - returns (bool success); - - /** - * @notice Transfer `amount` tokens from `src` to `dst` - * @param src The address of the source account - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - * @return success Whether or not the transfer succeeded - */ - function transferFrom( - address src, - address dst, - uint256 amount - ) external returns (bool success); - - /** - * @notice Approve `spender` to transfer up to `amount` from `src` - * @dev This will overwrite the approval amount for `spender` - * and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve) - * @param spender The address of the account which may transfer tokens - * @param amount The number of tokens that are approved (-1 means infinite) - * @return success Whether or not the approval succeeded - */ - function approve(address spender, uint256 amount) - external - returns (bool success); - - /** - * @notice Get the current allowance from `owner` for `spender` - * @param owner The address of the account which owns the tokens to be spent - * @param spender The address of the account which may transfer tokens - * @return remaining The number of tokens allowed to be spent (-1 means infinite) - */ - function allowance(address owner, address spender) - external - view - returns (uint256 remaining); - - event Transfer(address indexed from, address indexed to, uint256 amount); - event Approval( - address indexed owner, - address indexed spender, - uint256 amount - ); -} - - -// Dependency file: contracts/WhitelistInterface.sol - -// pragma solidity 0.8.6; - -interface WhitelistInterface { - function setStatus(bool _newStatus) external; - function enabled() external view returns(bool); - - function addUsers(address[] memory _users) external; - function exist(address _user) external view returns(bool); - function getUsers() external view returns(address[] memory currentUsers); - function removeUser(address _user) external; -} - -// Dependency file: contracts/CToken.sol - -// pragma solidity 0.8.6; - -// import "contracts/ComptrollerInterface.sol"; -// import "contracts/CTokenInterfaces.sol"; -// import "contracts/ErrorReporter.sol"; -// import "contracts/Exponential.sol"; -// import "contracts/EIP20Interface.sol"; -// import "contracts/InterestRateModel.sol"; -// import "contracts/WhitelistInterface.sol"; - -/** - * @title tropykus CToken Contract - * @notice Abstract base for CTokens - * @author tropykus - */ -abstract contract CToken is CTokenInterface, Exponential, TokenErrorReporter { - address whitelist; - - /** - * @notice Initialize the money market - * @param comptroller_ The address of the Comptroller - * @param interestRateModel_ The address of the interest rate model - * @param initialExchangeRateMantissa_ The initial exchange rate, scaled by 1e18 - * @param name_ EIP-20 name of this token - * @param symbol_ EIP-20 symbol of this token - * @param decimals_ EIP-20 decimal precision of this token - */ - function initialize( - ComptrollerInterface comptroller_, - InterestRateModel interestRateModel_, - uint256 initialExchangeRateMantissa_, - string memory name_, - string memory symbol_, - uint8 decimals_ - ) public { - require(msg.sender == admin, "CT01"); - require(accrualBlockNumber == 0 && borrowIndex == 0, "CT02"); - - initialExchangeRateMantissa = initialExchangeRateMantissa_; - require(initialExchangeRateMantissa > 0, "CT03"); - - uint256 err = _setComptroller(comptroller_); - require(err == uint256(Error.NO_ERROR), "CT04"); - - accrualBlockNumber = getBlockNumber(); - borrowIndex = mantissaOne; - - err = _setInterestRateModelFresh(interestRateModel_); - require(err == uint256(Error.NO_ERROR), "CT05"); - - name = name_; - symbol = symbol_; - decimals = decimals_; - - _notEntered = true; - } - - function addWhitelist(address _whitelist) external returns (uint256) { - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_INTEREST_RATE_MODEL_OWNER_CHECK - ); - } - whitelist = _whitelist; - } - - /** - * @notice Transfer `tokens` tokens from `src` to `dst` by `spender` - * @dev Called by both `transfer` and `transferFrom` internally - * @param spender The address of the account performing the transfer - * @param src The address of the source account - * @param dst The address of the destination account - * @param tokens The number of tokens to transfer - * @return Whether or not the transfer succeeded - */ - function transferTokens( - address spender, - address src, - address dst, - uint256 tokens - ) internal returns (uint256) { - uint256 allowed = comptroller.transferAllowed( - address(this), - src, - dst, - tokens - ); - if (allowed != 0) { - return - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.TRANSFER_COMPTROLLER_REJECTION, - allowed - ); - } - - if (src == dst) { - return fail(Error.BAD_INPUT, FailureInfo.TRANSFER_NOT_ALLOWED); - } - - uint256 startingAllowance = 0; - if (spender == src) { - startingAllowance = type(uint256).max; - } else { - startingAllowance = transferAllowances[src][spender]; - } - - MathError mathErr; - uint256 allowanceNew; - uint256 srcTokensNew; - uint256 dstTokensNew; - - (mathErr, allowanceNew) = subUInt(startingAllowance, tokens); - if (mathErr != MathError.NO_ERROR) { - return fail(Error.MATH_ERROR, FailureInfo.TRANSFER_NOT_ALLOWED); - } - - (mathErr, srcTokensNew) = subUInt(accountTokens[src].tokens, tokens); - if (mathErr != MathError.NO_ERROR) { - return fail(Error.MATH_ERROR, FailureInfo.TRANSFER_NOT_ENOUGH); - } - - (mathErr, dstTokensNew) = addUInt(accountTokens[dst].tokens, tokens); - if (mathErr != MathError.NO_ERROR) { - return fail(Error.MATH_ERROR, FailureInfo.TRANSFER_TOO_MUCH); - } - - accountTokens[src].tokens = srcTokensNew; - accountTokens[dst].tokens = dstTokensNew; - - if (startingAllowance != type(uint256).max) { - transferAllowances[src][spender] = allowanceNew; - } - - emit Transfer(src, dst, tokens); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Transfer `amount` tokens from `msg.sender` to `dst` - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - * @return Whether or not the transfer succeeded - */ - function transfer(address dst, uint256 amount) - external - override - nonReentrant - returns (bool) - { - return - transferTokens(msg.sender, msg.sender, dst, amount) == - uint256(Error.NO_ERROR); - } - - /** - * @notice Transfer `amount` tokens from `src` to `dst` - * @param src The address of the source account - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - * @return Whether or not the transfer succeeded - */ - function transferFrom( - address src, - address dst, - uint256 amount - ) external override nonReentrant returns (bool) { - return - transferTokens(msg.sender, src, dst, amount) == - uint256(Error.NO_ERROR); - } - - /** - * @notice Approve `spender` to transfer up to `amount` from `src` - * @dev This will overwrite the approval amount for `spender` - * and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve) - * @param spender The address of the account which may transfer tokens - * @param amount The number of tokens that are approved (-1 means infinite) - * @return Whether or not the approval succeeded - */ - function approve(address spender, uint256 amount) - external - override - returns (bool) - { - transferAllowances[msg.sender][spender] = amount; - emit Approval(msg.sender, spender, amount); - return true; - } - - /** - * @notice Get the current allowance from `owner` for `spender` - * @param owner The address of the account which owns the tokens to be spent - * @param spender The address of the account which may transfer tokens - * @return The number of tokens allowed to be spent (-1 means infinite) - */ - function allowance(address owner, address spender) - external - view - override - returns (uint256) - { - return transferAllowances[owner][spender]; - } - - /** - * @notice Get the token balance of the `owner` - * @param owner The address of the account to query - * @return The number of tokens owned by `owner` - */ - function balanceOf(address owner) external view override returns (uint256) { - return accountTokens[owner].tokens; - } - - /** - * @notice Get the underlying balance of the `owner` - * @dev This also accrues interest in a transaction - * @param owner The address of the account to query - * @return The amount of underlying owned by `owner` - */ - function balanceOfUnderlying(address owner) - external - override - returns (uint256) - { - (MathError mErr, uint256 balance) = mulScalarTruncate( - Exp({mantissa: exchangeRateCurrent()}), - accountTokens[owner].tokens - ); - require(mErr == MathError.NO_ERROR, "CT06"); - return balance; - } - - /** - * @notice Get a snapshot of the account's balances, and the cached exchange rate - * @dev This is used by comptroller to more efficiently perform liquidity checks. - * @param account Address of the account to snapshot - * @return (possible error, token balance, borrow balance, exchange rate mantissa) - */ - function getAccountSnapshot(address account) - external - view - override - returns ( - uint256, - uint256, - uint256, - uint256 - ) - { - uint256 cTokenBalance = accountTokens[account].tokens; - uint256 borrowBalance; - uint256 exchangeRateMantissa; - - MathError mErr; - - (mErr, borrowBalance) = borrowBalanceStoredInternal(account); - if (mErr != MathError.NO_ERROR) { - return (uint256(Error.MATH_ERROR), 0, 0, 0); - } - - (mErr, exchangeRateMantissa) = exchangeRateStoredInternal(); - if (mErr != MathError.NO_ERROR) { - return (uint256(Error.MATH_ERROR), 0, 0, 0); - } - - return ( - uint256(Error.NO_ERROR), - cTokenBalance, - borrowBalance, - exchangeRateMantissa - ); - } - - /** - * @dev Function to simply retrieve block number - * This exists mainly for inheriting test contracts to stub this result. - */ - function getBlockNumber() internal view virtual returns (uint256) { - return block.number; - } - - /** - * @notice Returns the current per-block borrow interest rate for this cToken - * @return The borrow interest rate per block, scaled by 1e18 - */ - function borrowRatePerBlock() external view override returns (uint256) { - return - interestRateModel.getBorrowRate( - getCashPrior(), - totalBorrows, - totalReserves - ); - } - - /** - * @notice Returns the current per-block supply interest rate for this cToken - * @return The supply interest rate per block, scaled by 1e18 - */ - function supplyRatePerBlock() external view override returns (uint256) { - return - interestRateModel.getSupplyRate( - getCashPrior(), - totalBorrows, - totalReserves, - reserveFactorMantissa - ); - } - - /** - * @notice Returns the current total borrows plus accrued interest - * @return The total borrows with interest - */ - function totalBorrowsCurrent() - external - override - nonReentrant - returns (uint256) - { - require(accrueInterest() == uint256(Error.NO_ERROR), "CT07"); - return totalBorrows; - } - - /** - * @notice Accrue interest to updated borrowIndex and then calculate account's borrow balance using the updated borrowIndex - * @param account The address whose balance should be calculated after updating borrowIndex - * @return The calculated balance - */ - function borrowBalanceCurrent(address account) - external - override - nonReentrant - returns (uint256) - { - require(accrueInterest() == uint256(Error.NO_ERROR), "CT07"); - return borrowBalanceStored(account); - } - - /** - * @notice Return the borrow balance of account based on stored data - * @param account The address whose balance should be calculated - * @return The calculated balance - */ - function borrowBalanceStored(address account) - public - view - override - returns (uint256) - { - (MathError err, uint256 result) = borrowBalanceStoredInternal(account); - require(err == MathError.NO_ERROR, "CT08"); - return result; - } - - /** - * @notice Return the borrow balance of account based on stored data - * @param account The address whose balance should be calculated - * @return (error code, the calculated balance or 0 if error code is non-zero) - */ - function borrowBalanceStoredInternal(address account) - internal - view - returns (MathError, uint256) - { - MathError mathErr; - uint256 principalTimesIndex; - uint256 result; - - BorrowSnapshot storage borrowSnapshot = accountBorrows[account]; - - if (borrowSnapshot.principal == 0) { - return (MathError.NO_ERROR, 0); - } - - (mathErr, principalTimesIndex) = mulUInt( - borrowSnapshot.principal, - borrowIndex - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - - (mathErr, result) = divUInt( - principalTimesIndex, - borrowSnapshot.interestIndex - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - - return (MathError.NO_ERROR, result); - } - - function getBorrowerPrincipalStored(address account) - public - view - returns (uint256 borrowed) - { - borrowed = accountBorrows[account].principal; - } - - function getSupplierSnapshotStored(address account) - public - view - returns ( - uint256 tokens, - uint256 underlyingAmount, - uint256 suppliedAt, - uint256 promisedSupplyRate - ) - { - tokens = accountTokens[account].tokens; - underlyingAmount = accountTokens[account].underlyingAmount; - suppliedAt = accountTokens[account].suppliedAt; - promisedSupplyRate = accountTokens[account].promisedSupplyRate; - } - - /** - * @notice Accrue interest then return the up-to-date exchange rate - * @return Calculated exchange rate scaled by 1e18 - */ - function exchangeRateCurrent() - public - override - nonReentrant - returns (uint256) - { - require(accrueInterest() == uint256(Error.NO_ERROR), "CT07"); - return exchangeRateStored(); - } - - /** - * @notice Calculates the exchange rate from the underlying to the CToken - * @dev This function does not accrue interest before calculating the exchange rate - * @return Calculated exchange rate scaled by 1e18 - */ - function exchangeRateStored() public view override returns (uint256) { - (MathError err, uint256 result) = exchangeRateStoredInternal(); - require(err == MathError.NO_ERROR, "CT09"); - return result; - } - - /** - * @notice Calculates the exchange rate from the underlying to the CToken - * @dev This function does not accrue interest before calculating the exchange rate - * @return (error code, calculated exchange rate scaled by 1e18) - */ - function exchangeRateStoredInternal() - internal - view - virtual - returns (MathError, uint256) - { - uint256 _totalSupply = totalSupply; - if (_totalSupply == 0) { - return (MathError.NO_ERROR, initialExchangeRateMantissa); - } else { - MathError error; - uint256 exchangeRate; - uint256 totalCash = getCashPrior(); - if (interestRateModel.isTropykusInterestRateModel()) { - (error, exchangeRate) = tropykusExchangeRateStoredInternal( - msg.sender - ); - if (error == MathError.NO_ERROR) { - return (MathError.NO_ERROR, exchangeRate); - } else { - return (MathError.NO_ERROR, initialExchangeRateMantissa); - } - } - return - interestRateModel.getExchangeRate( - totalCash, - totalBorrows, - totalReserves, - totalSupply - ); - } - } - - function tropykusExchangeRateStoredInternal(address redeemer) - internal - view - returns (MathError, uint256) - { - if (totalSupply == 0) { - return (MathError.NO_ERROR, initialExchangeRateMantissa); - } else { - SupplySnapshot storage supplySnapshot = accountTokens[redeemer]; - if (supplySnapshot.suppliedAt == 0) { - return (MathError.DIVISION_BY_ZERO, 0); - } - (, uint256 interestFactorMantissa, ) = tropykusInterestAccrued( - redeemer - ); - Exp memory interestFactor = Exp({mantissa: interestFactorMantissa}); - uint256 currentUnderlying = supplySnapshot.underlyingAmount; - Exp memory redeemerUnderlying = Exp({mantissa: currentUnderlying}); - (, Exp memory realAmount) = mulExp( - interestFactor, - redeemerUnderlying - ); - (, Exp memory exchangeRate) = getExp( - realAmount.mantissa, - supplySnapshot.tokens - ); - return (MathError.NO_ERROR, exchangeRate.mantissa); - } - } - - function tropykusInterestAccrued(address account) - internal - view - returns ( - MathError, - uint256, - uint256 - ) - { - SupplySnapshot storage supplySnapshot = accountTokens[account]; - uint256 promisedSupplyRate = supplySnapshot.promisedSupplyRate; - Exp memory expectedSupplyRatePerBlock = Exp({ - mantissa: promisedSupplyRate - }); - (, uint256 delta) = subUInt( - accrualBlockNumber, - supplySnapshot.suppliedAt - ); - (, Exp memory expectedSupplyRatePerBlockWithDelta) = mulScalar( - expectedSupplyRatePerBlock, - delta - ); - (, Exp memory interestFactor) = addExp( - Exp({mantissa: 1e18}), - expectedSupplyRatePerBlockWithDelta - ); - uint256 currentUnderlying = supplySnapshot.underlyingAmount; - Exp memory redeemerUnderlying = Exp({mantissa: currentUnderlying}); - (, Exp memory realAmount) = mulExp(interestFactor, redeemerUnderlying); - (, uint256 interestEarned) = subUInt( - realAmount.mantissa, - currentUnderlying - ); - return (MathError.NO_ERROR, interestFactor.mantissa, interestEarned); - } - - /** - * @notice Get cash balance of this cToken in the underlying asset - * @return The quantity of underlying asset owned by this contract - */ - function getCash() external view override returns (uint256) { - return getCashPrior(); - } - - /** - * @notice Applies accrued interest to total borrows and reserves - * @dev This calculates interest accrued from the last checkpointed block - * up to the current block and writes new checkpoint to storage. - */ - function accrueInterest() public override returns (uint256) { - uint256 currentBlockNumber = getBlockNumber(); - uint256 accrualBlockNumberPrior = accrualBlockNumber; - - if (accrualBlockNumberPrior == currentBlockNumber) { - return uint256(Error.NO_ERROR); - } - - uint256 cashPrior = getCashPrior(); - uint256 borrowsPrior = totalBorrows; - uint256 reservesPrior = totalReserves; - uint256 borrowIndexPrior = borrowIndex; - - uint256 borrowRateMantissa = interestRateModel.getBorrowRate( - cashPrior, - borrowsPrior, - reservesPrior - ); - require(borrowRateMantissa <= borrowRateMaxMantissa, "CT10"); - - (MathError mathErr, uint256 blockDelta) = subUInt( - currentBlockNumber, - accrualBlockNumberPrior - ); - require(mathErr == MathError.NO_ERROR, "CT11"); - - Exp memory simpleInterestFactor; - uint256 interestAccumulated; - uint256 totalBorrowsNew; - uint256 totalReservesNew; - uint256 borrowIndexNew; - - (mathErr, simpleInterestFactor) = mulScalar( - Exp({mantissa: borrowRateMantissa}), - blockDelta - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .ACCRUE_INTEREST_SIMPLE_INTEREST_FACTOR_CALCULATION_FAILED, - uint256(mathErr) - ); - } - - (mathErr, interestAccumulated) = mulScalarTruncate( - simpleInterestFactor, - borrowsPrior - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .ACCRUE_INTEREST_ACCUMULATED_INTEREST_CALCULATION_FAILED, - uint256(mathErr) - ); - } - - (mathErr, totalBorrowsNew) = addUInt(interestAccumulated, borrowsPrior); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .ACCRUE_INTEREST_NEW_TOTAL_BORROWS_CALCULATION_FAILED, - uint256(mathErr) - ); - } - - (mathErr, totalReservesNew) = mulScalarTruncateAddUInt( - Exp({mantissa: reserveFactorMantissa}), - interestAccumulated, - reservesPrior - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .ACCRUE_INTEREST_NEW_TOTAL_RESERVES_CALCULATION_FAILED, - uint256(mathErr) - ); - } - - if (interestRateModel.isTropykusInterestRateModel()) { - (mathErr, totalReservesNew) = newReserves( - borrowRateMantissa, - cashPrior, - borrowsPrior, - reservesPrior, - interestAccumulated - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .ACCRUE_INTEREST_NEW_TOTAL_RESERVES_CALCULATION_FAILED, - uint256(mathErr) - ); - } - } - - (mathErr, borrowIndexNew) = mulScalarTruncateAddUInt( - simpleInterestFactor, - borrowIndexPrior, - borrowIndexPrior - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .ACCRUE_INTEREST_NEW_BORROW_INDEX_CALCULATION_FAILED, - uint256(mathErr) - ); - } - - accrualBlockNumber = currentBlockNumber; - borrowIndex = borrowIndexNew; - totalBorrows = totalBorrowsNew; - totalReserves = totalReservesNew; - - emit AccrueInterest( - cashPrior, - interestAccumulated, - borrowIndexNew, - totalBorrowsNew - ); - - return uint256(Error.NO_ERROR); - } - - function newReserves( - uint256 borrowRateMantissa, - uint256 cashPrior, - uint256 borrowsPrior, - uint256 reservesPrior, - uint256 interestAccumulated - ) internal view returns (MathError mathErr, uint256 totalReservesNew) { - uint256 newReserveFactorMantissa; - uint256 utilizationRate = interestRateModel.utilizationRate( - cashPrior, - borrowsPrior, - reservesPrior - ); - uint256 expectedSupplyRate = interestRateModel.getSupplyRate( - cashPrior, - borrowsPrior, - reservesPrior, - reserveFactorMantissa - ); - if ( - interestRateModel.isAboveOptimal( - cashPrior, - borrowsPrior, - reservesPrior - ) - ) { - (mathErr, newReserveFactorMantissa) = mulScalarTruncate( - Exp({mantissa: utilizationRate}), - borrowRateMantissa - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - (mathErr, newReserveFactorMantissa) = subUInt( - newReserveFactorMantissa, - expectedSupplyRate - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - (mathErr, totalReservesNew) = mulScalarTruncateAddUInt( - Exp({mantissa: newReserveFactorMantissa}), - interestAccumulated, - reservesPrior - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - } else { - mathErr = MathError.NO_ERROR; - totalReservesNew = reservesPrior; - } - } - - /** - * @notice Sender supplies assets into the market and receives cTokens in exchange - * @dev Accrues interest whether or not the operation succeeds, unless reverted - * @param mintAmount The amount of the underlying asset to supply - * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual mint amount. - */ - function mintInternal(uint256 mintAmount) - internal - nonReentrant - returns (uint256, uint256) - { - if (WhitelistInterface(whitelist).enabled()) { - require(WhitelistInterface(whitelist).exist(msg.sender), "CT26"); - } - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return ( - fail(Error(error), FailureInfo.MINT_ACCRUE_INTEREST_FAILED), - 0 - ); - } - return mintFresh(msg.sender, mintAmount); - } - - struct MintLocalVars { - Error err; - MathError mathErr; - uint256 exchangeRateMantissa; - uint256 mintTokens; - uint256 totalSupplyNew; - uint256 accountTokensNew; - uint256 actualMintAmount; - } - - /** - * @notice User supplies assets into the market and receives cTokens in exchange - * @dev Assumes interest has already been accrued up to the current block - * @param minter The address of the account which is supplying the assets - * @param mintAmount The amount of the underlying asset to supply - * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual mint amount. - */ - function mintFresh(address minter, uint256 mintAmount) - internal - returns (uint256, uint256) - { - uint256 allowed = comptroller.mintAllowed( - address(this), - minter, - mintAmount - ); - if (allowed != 0) { - return ( - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.MINT_COMPTROLLER_REJECTION, - allowed - ), - 0 - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return ( - fail(Error.MARKET_NOT_FRESH, FailureInfo.MINT_FRESHNESS_CHECK), - 0 - ); - } - - MintLocalVars memory vars; - - ( - vars.mathErr, - vars.exchangeRateMantissa - ) = exchangeRateStoredInternal(); - if (vars.mathErr != MathError.NO_ERROR) { - return ( - failOpaque( - Error.MATH_ERROR, - FailureInfo.MINT_EXCHANGE_RATE_READ_FAILED, - uint256(vars.mathErr) - ), - 0 - ); - } - if (interestRateModel.isTropykusInterestRateModel()) { - SupplySnapshot storage supplySnapshot = accountTokens[minter]; - (, uint256 newTotalSupply) = addUInt( - supplySnapshot.underlyingAmount, - mintAmount - ); - require(newTotalSupply <= 0.1e18, "CT24"); - } - vars.actualMintAmount = doTransferIn(minter, mintAmount); - - (vars.mathErr, vars.mintTokens) = divScalarByExpTruncate( - vars.actualMintAmount, - Exp({mantissa: vars.exchangeRateMantissa}) - ); - require(vars.mathErr == MathError.NO_ERROR, "CT12"); - - (vars.mathErr, vars.totalSupplyNew) = addUInt( - totalSupply, - vars.mintTokens - ); - require(vars.mathErr == MathError.NO_ERROR, "CT13"); - - (vars.mathErr, vars.accountTokensNew) = addUInt( - accountTokens[minter].tokens, - vars.mintTokens - ); - require(vars.mathErr == MathError.NO_ERROR, "CT14"); - - uint256 currentSupplyRate = interestRateModel.getSupplyRate( - getCashPrior(), - totalBorrows, - totalReserves, - reserveFactorMantissa - ); - - bool isTropykusInterestRateModel = interestRateModel - .isTropykusInterestRateModel(); - - if (accountTokens[minter].tokens > 0) { - Exp memory updatedUnderlying; - if (isTropykusInterestRateModel) { - (, uint256 interestFactorMantissa, ) = tropykusInterestAccrued( - minter - ); - Exp memory interestFactor = Exp({ - mantissa: interestFactorMantissa - }); - uint256 currentUnderlyingAmount = accountTokens[minter] - .underlyingAmount; - MathError mErrorNewAmount; - (mErrorNewAmount, updatedUnderlying) = mulExp( - Exp({mantissa: currentUnderlyingAmount}), - interestFactor - ); - if (mErrorNewAmount != MathError.NO_ERROR) { - return ( - failOpaque( - Error.MATH_ERROR, - FailureInfo.MINT_EXCHANGE_CALCULATION_FAILED, - uint256(mErrorNewAmount) - ), - 0 - ); - } - } else { - uint256 currentTokens = accountTokens[minter].tokens; - MathError mErrorUpdatedUnderlying; - (mErrorUpdatedUnderlying, updatedUnderlying) = mulExp( - Exp({mantissa: currentTokens}), - Exp({mantissa: vars.exchangeRateMantissa}) - ); - if (mErrorUpdatedUnderlying != MathError.NO_ERROR) { - return ( - failOpaque( - Error.MATH_ERROR, - FailureInfo.MINT_EXCHANGE_CALCULATION_FAILED, - uint256(mErrorUpdatedUnderlying) - ), - 0 - ); - } - } - (, mintAmount) = addUInt(updatedUnderlying.mantissa, mintAmount); - } - - totalSupply = vars.totalSupplyNew; - accountTokens[minter] = SupplySnapshot({ - tokens: vars.accountTokensNew, - underlyingAmount: mintAmount, - suppliedAt: accrualBlockNumber, - promisedSupplyRate: currentSupplyRate - }); - - emit Mint(minter, vars.actualMintAmount, vars.mintTokens); - emit Transfer(address(this), minter, vars.mintTokens); - - return (uint256(Error.NO_ERROR), vars.actualMintAmount); - } - - /** - * @notice Sender redeems cTokens in exchange for a specified amount of underlying asset - * @dev Accrues interest whether or not the operation succeeds, unless reverted - * @param redeemAmount The amount of underlying to receive from redeeming cTokens - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function redeemUnderlyingInternal(uint256 redeemAmount) - internal - nonReentrant - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return - fail(Error(error), FailureInfo.REDEEM_ACCRUE_INTEREST_FAILED); - } - return redeemFresh(payable(msg.sender), redeemAmount); - } - - struct RedeemLocalVars { - Error err; - MathError mathErr; - uint256 exchangeRateMantissa; - uint256 redeemTokens; - uint256 redeemAmount; - uint256 totalSupplyNew; - uint256 accountTokensNew; - uint256 newSubsidyFund; - } - - /** - * @notice User redeems cTokens in exchange for the underlying asset - * @dev Assumes interest has already been accrued up to the current block - * @param redeemer The address of the account which is redeeming the tokens - * @param redeemAmountIn The number of underlying tokens to receive from redeeming cTokens - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function redeemFresh(address payable redeemer, uint256 redeemAmountIn) - internal - returns (uint256) - { - require(redeemAmountIn > 0, "CT15"); - - RedeemLocalVars memory vars; - - SupplySnapshot storage supplySnapshot = accountTokens[redeemer]; - - ( - vars.mathErr, - vars.exchangeRateMantissa - ) = exchangeRateStoredInternal(); - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.REDEEM_EXCHANGE_RATE_READ_FAILED, - uint256(vars.mathErr) - ); - } - - uint256 interestEarned; - uint256 subsidyFundPortion; - uint256 currentUnderlying; - - bool isTropykusInterestRateModel = interestRateModel - .isTropykusInterestRateModel(); - if (isTropykusInterestRateModel) { - currentUnderlying = supplySnapshot.underlyingAmount; - (, , interestEarned) = tropykusInterestAccrued(redeemer); - } - supplySnapshot.promisedSupplyRate = interestRateModel.getSupplyRate( - getCashPrior(), - totalBorrows, - totalReserves, - reserveFactorMantissa - ); - - if ( - isTropykusInterestRateModel && - !interestRateModel.isAboveOptimal( - getCashPrior(), - totalBorrows, - totalReserves - ) - ) { - uint256 borrowRate = interestRateModel.getBorrowRate( - getCashPrior(), - totalBorrows, - totalReserves - ); - - uint256 utilizationRate = interestRateModel.utilizationRate( - getCashPrior(), - totalBorrows, - totalReserves - ); - - (, uint256 estimatedEarning) = mulScalarTruncate( - Exp({mantissa: borrowRate}), - utilizationRate - ); - - (, subsidyFundPortion) = subUInt( - supplySnapshot.promisedSupplyRate, - estimatedEarning - ); - (, Exp memory subsidyFactor) = getExp( - subsidyFundPortion, - supplySnapshot.promisedSupplyRate - ); - (, subsidyFundPortion) = mulScalarTruncate( - subsidyFactor, - interestEarned - ); - } - - vars.redeemAmount = redeemAmountIn; - - if (isTropykusInterestRateModel) { - (, Exp memory num) = mulExp( - vars.redeemAmount, - supplySnapshot.tokens - ); - (, Exp memory realTokensWithdrawAmount) = getExp( - num.mantissa, - currentUnderlying - ); - vars.redeemTokens = realTokensWithdrawAmount.mantissa; - } else { - (vars.mathErr, vars.redeemTokens) = divScalarByExpTruncate( - redeemAmountIn, - Exp({mantissa: vars.exchangeRateMantissa}) - ); - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.REDEEM_EXCHANGE_AMOUNT_CALCULATION_FAILED, - uint256(vars.mathErr) - ); - } - } - // } - - uint256 allowed = comptroller.redeemAllowed( - address(this), - redeemer, - vars.redeemTokens - ); - if (allowed != 0) { - return - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.REDEEM_COMPTROLLER_REJECTION, - allowed - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.REDEEM_FRESHNESS_CHECK - ); - } - - (vars.mathErr, vars.totalSupplyNew) = subUInt( - totalSupply, - vars.redeemTokens - ); - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.REDEEM_NEW_TOTAL_SUPPLY_CALCULATION_FAILED, - uint256(vars.mathErr) - ); - } - - (, vars.newSubsidyFund) = subUInt(subsidyFund, subsidyFundPortion); - - (vars.mathErr, vars.accountTokensNew) = subUInt( - supplySnapshot.tokens, - vars.redeemTokens - ); - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.REDEEM_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED, - uint256(vars.mathErr) - ); - } - - uint256 cash = getCashPrior(); - if (isTropykusInterestRateModel) { - cash = address(this).balance; - } - - if (cash < vars.redeemAmount) { - return - fail( - Error.TOKEN_INSUFFICIENT_CASH, - FailureInfo.REDEEM_TRANSFER_OUT_NOT_POSSIBLE - ); - } - - doTransferOut(redeemer, vars.redeemAmount); - - totalSupply = vars.totalSupplyNew; - subsidyFund = vars.newSubsidyFund; - supplySnapshot.tokens = vars.accountTokensNew; - supplySnapshot.suppliedAt = accrualBlockNumber; - (, supplySnapshot.underlyingAmount) = subUInt( - supplySnapshot.underlyingAmount, - vars.redeemAmount - ); - - emit Transfer(redeemer, address(this), vars.redeemTokens); - emit Redeem(redeemer, vars.redeemAmount, vars.redeemTokens); - - comptroller.redeemVerify( - address(this), - redeemer, - vars.redeemAmount, - vars.redeemTokens - ); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Sender borrows assets from the protocol to their own address - * @param borrowAmount The amount of the underlying asset to borrow - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function borrowInternal(uint256 borrowAmount) - internal - nonReentrant - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return - fail(Error(error), FailureInfo.BORROW_ACCRUE_INTEREST_FAILED); - } - return borrowFresh(payable(msg.sender), borrowAmount); - } - - struct BorrowLocalVars { - MathError mathErr; - uint256 accountBorrows; - uint256 accountBorrowsNew; - uint256 totalBorrowsNew; - } - - /** - * @notice Users borrow assets from the protocol to their own address - * @param borrowAmount The amount of the underlying asset to borrow - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function borrowFresh(address payable borrower, uint256 borrowAmount) - internal - returns (uint256) - { - uint256 allowed = comptroller.borrowAllowed( - address(this), - borrower, - borrowAmount - ); - if (allowed != 0) { - return - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.BORROW_COMPTROLLER_REJECTION, - allowed - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.BORROW_FRESHNESS_CHECK - ); - } - - if (getCashPrior() < borrowAmount) { - return - fail( - Error.TOKEN_INSUFFICIENT_CASH, - FailureInfo.BORROW_CASH_NOT_AVAILABLE - ); - } - - BorrowLocalVars memory vars; - - (vars.mathErr, vars.accountBorrows) = borrowBalanceStoredInternal( - borrower - ); - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED, - uint256(vars.mathErr) - ); - } - - (vars.mathErr, vars.accountBorrowsNew) = addUInt( - vars.accountBorrows, - borrowAmount - ); - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED, - uint256(vars.mathErr) - ); - } - - (vars.mathErr, vars.totalBorrowsNew) = addUInt( - totalBorrows, - borrowAmount - ); - if (interestRateModel.isTropykusInterestRateModel()) { - require(vars.totalBorrowsNew <= 0.1e18, "CT25"); - } - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED, - uint256(vars.mathErr) - ); - } - - doTransferOut(borrower, borrowAmount); - - accountBorrows[borrower].principal = vars.accountBorrowsNew; - accountBorrows[borrower].interestIndex = borrowIndex; - totalBorrows = vars.totalBorrowsNew; - - emit Borrow( - borrower, - borrowAmount, - vars.accountBorrowsNew, - vars.totalBorrowsNew - ); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Sender repays their own borrow - * @param repayAmount The amount to repay - * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual repayment amount. - */ - function repayBorrowInternal(uint256 repayAmount) - internal - nonReentrant - returns (uint256, uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return ( - fail( - Error(error), - FailureInfo.REPAY_BORROW_ACCRUE_INTEREST_FAILED - ), - 0 - ); - } - return repayBorrowFresh(msg.sender, msg.sender, repayAmount); - } - - struct RepayBorrowLocalVars { - Error err; - MathError mathErr; - uint256 repayAmount; - uint256 borrowerIndex; - uint256 accountBorrows; - uint256 accountBorrowsNew; - uint256 totalBorrowsNew; - uint256 actualRepayAmount; - } - - /** - * @notice Borrows are repaid by another user (possibly the borrower). - * @param payer the account paying off the borrow - * @param borrower the account with the debt being payed off - * @param repayAmount the amount of undelrying tokens being returned - * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual repayment amount. - */ - function repayBorrowFresh( - address payer, - address borrower, - uint256 repayAmount - ) internal returns (uint256, uint256) { - uint256 allowed = comptroller.repayBorrowAllowed( - address(this), - payer, - borrower, - repayAmount - ); - if (allowed != 0) { - return ( - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.REPAY_BORROW_COMPTROLLER_REJECTION, - allowed - ), - 0 - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return ( - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.REPAY_BORROW_FRESHNESS_CHECK - ), - 0 - ); - } - - RepayBorrowLocalVars memory vars; - - vars.borrowerIndex = accountBorrows[borrower].interestIndex; - - (vars.mathErr, vars.accountBorrows) = borrowBalanceStoredInternal( - borrower - ); - if (vars.mathErr != MathError.NO_ERROR) { - return ( - failOpaque( - Error.MATH_ERROR, - FailureInfo - .REPAY_BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED, - uint256(vars.mathErr) - ), - 0 - ); - } - - if (repayAmount == type(uint256).max) { - vars.repayAmount = vars.accountBorrows; - } else { - vars.repayAmount = repayAmount; - } - - vars.actualRepayAmount = doTransferIn(payer, vars.repayAmount); - - (vars.mathErr, vars.accountBorrowsNew) = subUInt( - vars.accountBorrows, - vars.actualRepayAmount - ); - require(vars.mathErr == MathError.NO_ERROR, "CT16"); - - (vars.mathErr, vars.totalBorrowsNew) = subUInt( - totalBorrows, - vars.actualRepayAmount - ); - require(vars.mathErr == MathError.NO_ERROR, "CT17"); - - accountBorrows[borrower].principal = vars.accountBorrowsNew; - accountBorrows[borrower].interestIndex = borrowIndex; - totalBorrows = vars.totalBorrowsNew; - - emit RepayBorrow( - payer, - borrower, - vars.actualRepayAmount, - vars.accountBorrowsNew, - vars.totalBorrowsNew - ); - - return (uint256(Error.NO_ERROR), vars.actualRepayAmount); - } - - /** - * @notice The sender liquidates the borrowers collateral. - * The collateral seized is transferred to the liquidator. - * @param borrower The borrower of this cToken to be liquidated - * @param cTokenCollateral The market in which to seize collateral from the borrower - * @param repayAmount The amount of the underlying borrowed asset to repay - * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual repayment amount. - */ - function liquidateBorrowInternal( - address borrower, - uint256 repayAmount, - CTokenInterface cTokenCollateral - ) internal nonReentrant returns (uint256, uint256) { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return ( - fail( - Error(error), - FailureInfo.LIQUIDATE_ACCRUE_BORROW_INTEREST_FAILED - ), - 0 - ); - } - - error = cTokenCollateral.accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return ( - fail( - Error(error), - FailureInfo.LIQUIDATE_ACCRUE_COLLATERAL_INTEREST_FAILED - ), - 0 - ); - } - - // liquidateBorrowFresh emits borrow-specific logs on errors, so we don't need to - return - liquidateBorrowFresh( - msg.sender, - borrower, - repayAmount, - cTokenCollateral - ); - } - - /** - * @notice The liquidator liquidates the borrowers collateral. - * The collateral seized is transferred to the liquidator. - * @param borrower The borrower of this cToken to be liquidated - * @param liquidator The address repaying the borrow and seizing collateral - * @param cTokenCollateral The market in which to seize collateral from the borrower - * @param repayAmount The amount of the underlying borrowed asset to repay - * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual repayment amount. - */ - function liquidateBorrowFresh( - address liquidator, - address borrower, - uint256 repayAmount, - CTokenInterface cTokenCollateral - ) internal returns (uint256, uint256) { - uint256 allowed = comptroller.liquidateBorrowAllowed( - address(this), - address(cTokenCollateral), - liquidator, - borrower, - repayAmount - ); - if (allowed != 0) { - return ( - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.LIQUIDATE_COMPTROLLER_REJECTION, - allowed - ), - 0 - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return ( - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.LIQUIDATE_FRESHNESS_CHECK - ), - 0 - ); - } - - if (cTokenCollateral.accrualBlockNumber() != getBlockNumber()) { - return ( - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.LIQUIDATE_COLLATERAL_FRESHNESS_CHECK - ), - 0 - ); - } - - if (borrower == liquidator) { - return ( - fail( - Error.INVALID_ACCOUNT_PAIR, - FailureInfo.LIQUIDATE_LIQUIDATOR_IS_BORROWER - ), - 0 - ); - } - - if (repayAmount == 0) { - return ( - fail( - Error.INVALID_CLOSE_AMOUNT_REQUESTED, - FailureInfo.LIQUIDATE_CLOSE_AMOUNT_IS_ZERO - ), - 0 - ); - } - - if (repayAmount == type(uint256).max) { - return ( - fail( - Error.INVALID_CLOSE_AMOUNT_REQUESTED, - FailureInfo.LIQUIDATE_CLOSE_AMOUNT_IS_UINT_MAX - ), - 0 - ); - } - - ( - uint256 repayBorrowError, - uint256 actualRepayAmount - ) = repayBorrowFresh(liquidator, borrower, repayAmount); - if (repayBorrowError != uint256(Error.NO_ERROR)) { - return ( - fail( - Error(repayBorrowError), - FailureInfo.LIQUIDATE_REPAY_BORROW_FRESH_FAILED - ), - 0 - ); - } - - (uint256 amountSeizeError, uint256 seizeTokens) = comptroller - .liquidateCalculateSeizeTokens( - address(this), - address(cTokenCollateral), - actualRepayAmount - ); - require(amountSeizeError == uint256(Error.NO_ERROR), "CT18"); - - require(cTokenCollateral.balanceOf(borrower) >= seizeTokens, "CT19"); - - uint256 seizeError; - if (address(cTokenCollateral) == address(this)) { - seizeError = seizeInternal( - address(this), - liquidator, - borrower, - seizeTokens - ); - } else { - seizeError = cTokenCollateral.seize( - liquidator, - borrower, - seizeTokens - ); - } - - require(seizeError == uint256(Error.NO_ERROR), "CT20"); - - emit LiquidateBorrow( - liquidator, - borrower, - actualRepayAmount, - address(cTokenCollateral), - seizeTokens - ); - - return (uint256(Error.NO_ERROR), actualRepayAmount); - } - - /** - * @notice Transfers collateral tokens (this market) to the liquidator. - * @dev Will fail unless called by another cToken during the process of liquidation. - * Its absolutely critical to use msg.sender as the borrowed cToken and not a parameter. - * @param liquidator The account receiving seized collateral - * @param borrower The account having collateral seized - * @param seizeTokens The number of cTokens to seize - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function seize( - address liquidator, - address borrower, - uint256 seizeTokens - ) external override nonReentrant returns (uint256) { - return seizeInternal(msg.sender, liquidator, borrower, seizeTokens); - } - - struct SeizeVars { - uint256 seizeAmount; - uint256 exchangeRate; - uint256 borrowerTokensNew; - uint256 borrowerAmountNew; - uint256 liquidatorTokensNew; - uint256 liquidatorAmountNew; - uint256 totalCash; - uint256 supplyRate; - } - - /** - * @notice Transfers collateral tokens (this market) to the liquidator. - * @dev Called only during an in-kind liquidation, or by liquidateBorrow during the liquidation of another CToken. - * Its absolutely critical to use msg.sender as the seizer cToken and not a parameter. - * @param seizerToken The contract seizing the collateral (i.e. borrowed cToken) - * @param liquidator The account receiving seized collateral - * @param borrower The account having collateral seized - * @param seizeTokens The number of cTokens to seize - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function seizeInternal( - address seizerToken, - address liquidator, - address borrower, - uint256 seizeTokens - ) internal returns (uint256) { - uint256 allowed = comptroller.seizeAllowed( - address(this), - seizerToken, - liquidator, - borrower, - seizeTokens - ); - if (allowed != 0) { - return - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.LIQUIDATE_SEIZE_COMPTROLLER_REJECTION, - allowed - ); - } - - if (borrower == liquidator) { - return - fail( - Error.INVALID_ACCOUNT_PAIR, - FailureInfo.LIQUIDATE_SEIZE_LIQUIDATOR_IS_BORROWER - ); - } - - SeizeVars memory seizeVars; - - MathError mathErr; - - (mathErr, seizeVars.borrowerTokensNew) = subUInt( - accountTokens[borrower].tokens, - seizeTokens - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.LIQUIDATE_SEIZE_BALANCE_DECREMENT_FAILED, - uint256(mathErr) - ); - } - - seizeVars.totalCash = getCashPrior(); - seizeVars.supplyRate = interestRateModel.getSupplyRate( - seizeVars.totalCash, - totalBorrows, - totalReserves, - reserveFactorMantissa - ); - - (, seizeVars.exchangeRate) = interestRateModel.getExchangeRate( - seizeVars.totalCash, - totalBorrows, - totalReserves, - totalSupply - ); - - if (interestRateModel.isTropykusInterestRateModel()) { - (, seizeVars.exchangeRate) = tropykusExchangeRateStoredInternal( - borrower - ); - } - - (, seizeVars.seizeAmount) = mulUInt( - seizeTokens, - seizeVars.exchangeRate - ); - (, seizeVars.seizeAmount) = divUInt(seizeVars.seizeAmount, 1e18); - - (, seizeVars.borrowerAmountNew) = subUInt( - accountTokens[borrower].underlyingAmount, - seizeVars.seizeAmount - ); - - (mathErr, seizeVars.liquidatorTokensNew) = addUInt( - accountTokens[liquidator].tokens, - seizeTokens - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.LIQUIDATE_SEIZE_BALANCE_INCREMENT_FAILED, - uint256(mathErr) - ); - } - - (, seizeVars.liquidatorAmountNew) = addUInt( - accountTokens[liquidator].underlyingAmount, - seizeVars.seizeAmount - ); - - accountTokens[borrower].tokens = seizeVars.borrowerTokensNew; - accountTokens[borrower].underlyingAmount = seizeVars.borrowerAmountNew; - accountTokens[borrower].suppliedAt = getBlockNumber(); - accountTokens[borrower].promisedSupplyRate = seizeVars.supplyRate; - - accountTokens[liquidator].tokens = seizeVars.liquidatorTokensNew; - accountTokens[liquidator].underlyingAmount = seizeVars - .liquidatorAmountNew; - accountTokens[liquidator].suppliedAt = getBlockNumber(); - accountTokens[liquidator].promisedSupplyRate = seizeVars.supplyRate; - - emit Transfer(borrower, liquidator, seizeTokens); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Begins transfer of admin rights. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer. - * @dev Admin function to begin change of admin. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer. - * @param newPendingAdmin New pending admin. - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setPendingAdmin(address payable newPendingAdmin) - external - override - returns (uint256) - { - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_PENDING_ADMIN_OWNER_CHECK - ); - } - - address oldPendingAdmin = pendingAdmin; - - pendingAdmin = newPendingAdmin; - - emit NewPendingAdmin(oldPendingAdmin, newPendingAdmin); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Accepts transfer of admin rights. msg.sender must be pendingAdmin - * @dev Admin function for pending admin to accept role and update admin - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _acceptAdmin() external override returns (uint256) { - if (msg.sender != pendingAdmin || msg.sender == address(0)) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.ACCEPT_ADMIN_PENDING_ADMIN_CHECK - ); - } - - address oldAdmin = admin; - address oldPendingAdmin = pendingAdmin; - - admin = pendingAdmin; - - pendingAdmin = payable(address(0)); - - emit NewAdmin(oldAdmin, admin); - emit NewPendingAdmin(oldPendingAdmin, pendingAdmin); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Sets a new comptroller for the market - * @dev Admin function to set a new comptroller - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setComptroller(ComptrollerInterface newComptroller) - public - override - returns (uint256) - { - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_COMPTROLLER_OWNER_CHECK - ); - } - - ComptrollerInterface oldComptroller = comptroller; - require(newComptroller.isComptroller(), "CT21"); - - comptroller = newComptroller; - - emit NewComptroller(oldComptroller, newComptroller); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice accrues interest and sets a new reserve factor for the protocol using _setReserveFactorFresh - * @dev Admin function to accrue interest and set a new reserve factor - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setReserveFactor(uint256 newReserveFactorMantissa) - external - override - nonReentrant - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return - fail( - Error(error), - FailureInfo.SET_RESERVE_FACTOR_ACCRUE_INTEREST_FAILED - ); - } - return _setReserveFactorFresh(newReserveFactorMantissa); - } - - /** - * @notice Sets a new reserve factor for the protocol (*requires fresh interest accrual) - * @dev Admin function to set a new reserve factor - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setReserveFactorFresh(uint256 newReserveFactorMantissa) - internal - returns (uint256) - { - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_RESERVE_FACTOR_ADMIN_CHECK - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.SET_RESERVE_FACTOR_FRESH_CHECK - ); - } - - if (newReserveFactorMantissa > reserveFactorMaxMantissa) { - return - fail( - Error.BAD_INPUT, - FailureInfo.SET_RESERVE_FACTOR_BOUNDS_CHECK - ); - } - - uint256 oldReserveFactorMantissa = reserveFactorMantissa; - reserveFactorMantissa = newReserveFactorMantissa; - - emit NewReserveFactor( - oldReserveFactorMantissa, - newReserveFactorMantissa - ); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Accrues interest and reduces reserves by transferring from msg.sender - * @param addAmount Amount of addition to reserves - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _addReservesInternal(uint256 addAmount) - internal - nonReentrant - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return - fail( - Error(error), - FailureInfo.ADD_RESERVES_ACCRUE_INTEREST_FAILED - ); - } - - uint256 totalReservesNew; - uint256 actualAddAmount; - - if (accrualBlockNumber != getBlockNumber()) { - return ( - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.ADD_RESERVES_FRESH_CHECK - ) - ); - } - - actualAddAmount = doTransferIn(msg.sender, addAmount); - - totalReservesNew = totalReserves + actualAddAmount; - - require(totalReservesNew >= totalReserves, "CT22"); - - totalReserves = totalReservesNew; - - emit ReservesAdded(msg.sender, actualAddAmount, totalReservesNew); - - return (uint256(Error.NO_ERROR)); - } - - function _addSubsidyInternal(uint256 addAmount) - internal - nonReentrant - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - // accrueInterest emits logs on errors, but on top of that we want to log the fact that an attempted reduce reserves failed. - return fail(Error(error), FailureInfo.ADD_SUBSIDY_FUND_FAILED); - } - - uint256 subsidyFundNew; - uint256 actualAddAmount; - - if (accrualBlockNumber != getBlockNumber()) { - return ( - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.ADD_SUBSIDY_FUND_FRESH_CHECK - ) - ); - } - - actualAddAmount = doTransferIn(msg.sender, addAmount); - - subsidyFundNew = subsidyFund + actualAddAmount; - - require(subsidyFundNew >= subsidyFund, "CT22"); - - subsidyFund = subsidyFundNew; - - emit SubsidyAdded(msg.sender, actualAddAmount, subsidyFundNew); - - /* Return (NO_ERROR, actualAddAmount) */ - return (uint256(Error.NO_ERROR)); - } - - /** - * @notice Accrues interest and reduces reserves by transferring to admin - * @param reduceAmount Amount of reduction to reserves - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _reduceReserves(uint256 reduceAmount) - external - override - nonReentrant - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return - fail( - Error(error), - FailureInfo.REDUCE_RESERVES_ACCRUE_INTEREST_FAILED - ); - } - return _reduceReservesFresh(reduceAmount); - } - - /** - * @notice Reduces reserves by transferring to admin - * @dev Requires fresh interest accrual - * @param reduceAmount Amount of reduction to reserves - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _reduceReservesFresh(uint256 reduceAmount) - internal - returns (uint256) - { - uint256 totalReservesNew; - - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.REDUCE_RESERVES_ADMIN_CHECK - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.REDUCE_RESERVES_FRESH_CHECK - ); - } - - if (getCashPrior() < reduceAmount) { - return - fail( - Error.TOKEN_INSUFFICIENT_CASH, - FailureInfo.REDUCE_RESERVES_CASH_NOT_AVAILABLE - ); - } - - if (reduceAmount > totalReserves) { - return - fail(Error.BAD_INPUT, FailureInfo.REDUCE_RESERVES_VALIDATION); - } - - totalReservesNew = totalReserves - reduceAmount; - require(totalReservesNew <= totalReserves, "CT23"); - - totalReserves = totalReservesNew; - - doTransferOut(admin, reduceAmount); - - emit ReservesReduced(admin, reduceAmount, totalReservesNew); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice accrues interest and updates the interest rate model using _setInterestRateModelFresh - * @dev Admin function to accrue interest and update the interest rate model - * @param newInterestRateModel the new interest rate model to use - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setInterestRateModel(InterestRateModel newInterestRateModel) - public - override - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return - fail( - Error(error), - FailureInfo.SET_INTEREST_RATE_MODEL_ACCRUE_INTEREST_FAILED - ); - } - return _setInterestRateModelFresh(newInterestRateModel); - } - - /** - * @notice updates the interest rate model (*requires fresh interest accrual) - * @dev Admin function to update the interest rate model - * @param newInterestRateModel the new interest rate model to use - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setInterestRateModelFresh(InterestRateModel newInterestRateModel) - internal - returns (uint256) - { - InterestRateModel oldInterestRateModel; - - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_INTEREST_RATE_MODEL_OWNER_CHECK - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.SET_INTEREST_RATE_MODEL_FRESH_CHECK - ); - } - - oldInterestRateModel = interestRateModel; - - require(newInterestRateModel.isInterestRateModel(), "CT21"); - - interestRateModel = newInterestRateModel; - - emit NewMarketInterestRateModel( - oldInterestRateModel, - newInterestRateModel - ); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Gets balance of this contract in terms of the underlying - * @dev This excludes the value of the current message, if any - * @return The quantity of underlying owned by this contract - */ - function getCashPrior() internal view virtual returns (uint256); - - /** - * @dev Performs a transfer in, reverting upon failure. Returns the amount actually transferred to the protocol, in case of a fee. - * This may revert due to insufficient balance or insufficient allowance. - */ - function doTransferIn(address from, uint256 amount) - internal - virtual - returns (uint256); - - /** - * @dev Performs a transfer out, ideally returning an explanatory error code upon failure tather than reverting. - * If caller has not called checked protocol's balance, may revert due to insufficient cash held in the contract. - * If caller has checked protocol's balance, and verified it is >= amount, this should not revert in normal conditions. - */ - function doTransferOut(address payable to, uint256 amount) internal virtual; - - /** - * @dev Prevents a contract from calling itself, directly or indirectly. - */ - modifier nonReentrant() { - require(_notEntered, "re-entered"); - _notEntered = false; - _; - _notEntered = true; - } -} - - -// Dependency file: contracts/CErc20.sol - -// pragma solidity 0.8.6; - -// import "contracts/CToken.sol"; -// import "contracts/CTokenInterfaces.sol"; - -/** - * @title tropykus CErc20 Contract - * @notice CTokens which wrap an EIP-20 underlying - * @author tropykus - */ -contract CErc20 is CToken, CErc20Interface { - /** - * @notice Initialize the new money market - * @param underlying_ The address of the underlying asset - * @param comptroller_ The address of the Comptroller - * @param interestRateModel_ The address of the interest rate model - * @param initialExchangeRateMantissa_ The initial exchange rate, scaled by 1e18 - * @param name_ ERC-20 name of this token - * @param symbol_ ERC-20 symbol of this token - * @param decimals_ ERC-20 decimal precision of this token - */ - function initialize( - address underlying_, - ComptrollerInterface comptroller_, - InterestRateModel interestRateModel_, - uint256 initialExchangeRateMantissa_, - string memory name_, - string memory symbol_, - uint8 decimals_ - ) public { - // CToken initialize does the bulk of the work - super.initialize( - comptroller_, - interestRateModel_, - initialExchangeRateMantissa_, - name_, - symbol_, - decimals_ - ); - - // Set underlying and sanity check it - underlying = underlying_; - EIP20Interface(underlying).totalSupply(); - } - - /*** User Interface ***/ - - /** - * @notice Sender supplies assets into the market and receives cTokens in exchange - * @dev Accrues interest whether or not the operation succeeds, unless reverted - * @param mintAmount The amount of the underlying asset to supply - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function mint(uint256 mintAmount) external override returns (uint256) { - (uint256 err, ) = mintInternal(mintAmount); - return err; - } - - /** - * @notice Sender redeems cTokens in exchange for a specified amount of underlying asset - * @dev Accrues interest whether or not the operation succeeds, unless reverted - * @param redeemAmount The amount of underlying to redeem - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function redeem(uint256 redeemAmount) - external - override - returns (uint256) - { - return redeemUnderlyingInternal(redeemAmount); - } - - /** - * @notice Sender borrows assets from the protocol to their own address - * @param borrowAmount The amount of the underlying asset to borrow - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function borrow(uint256 borrowAmount) external override returns (uint256) { - return borrowInternal(borrowAmount); - } - - /** - * @notice Sender repays their own borrow - * @param repayAmount The amount to repay - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function repayBorrow(uint256 repayAmount) - external - override - returns (uint256) - { - (uint256 err, ) = repayBorrowInternal(repayAmount); - return err; - } - - /** - * @notice The sender liquidates the borrowers collateral. - * The collateral seized is transferred to the liquidator. - * @param borrower The borrower of this cToken to be liquidated - * @param repayAmount The amount of the underlying borrowed asset to repay - * @param cTokenCollateral The market in which to seize collateral from the borrower - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function liquidateBorrow( - address borrower, - uint256 repayAmount, - CTokenInterface cTokenCollateral - ) external override returns (uint256) { - (uint256 err, ) = liquidateBorrowInternal( - borrower, - repayAmount, - cTokenCollateral - ); - return err; - } - - /** - * @notice A public function to sweep accidental ERC-20 transfers to this contract. Tokens are sent to admin (timelock) - * @param token The address of the ERC-20 token to sweep - */ - function sweepToken(EIP20NonStandardInterface token) external override { - require(address(token) != underlying, "EC01"); - uint256 balance = token.balanceOf(address(this)); - token.transfer(admin, balance); - } - - /** - * @notice The sender adds to reserves. - * @param addAmount The amount fo underlying token to add as reserves - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _addReserves(uint256 addAmount) - external - override - returns (uint256) - { - return _addReservesInternal(addAmount); - } - - /*** Safe Token ***/ - - /** - * @notice Gets balance of this contract in terms of the underlying - * @dev This excludes the value of the current message, if any - * @return The quantity of underlying tokens owned by this contract - */ - function getCashPrior() internal view override returns (uint256) { - EIP20Interface token = EIP20Interface(underlying); - return token.balanceOf(address(this)); - } - - /** - * @dev Similar to EIP20 transfer, except it handles a False result from `transferFrom` and reverts in that case. - * This will revert due to insufficient balance or insufficient allowance. - * This function returns the actual amount received, - * which may be less than `amount` if there is a fee attached to the transfer. - * - * Note: This wrapper safely handles non-standard ERC-20 tokens that do not return a value. - * See here: https://medium.com/coinmonks/missing-return-value-bug-at-least-130-tokens-affected-d67bf08521ca - */ - function doTransferIn(address from, uint256 amount) - internal - override - returns (uint256) - { - EIP20NonStandardInterface token = EIP20NonStandardInterface(underlying); - uint256 balanceBefore = EIP20Interface(underlying).balanceOf( - address(this) - ); - token.transferFrom(from, address(this), amount); - - bool success; - assembly { - switch returndatasize() - case 0 { - // This is a non-standard ERC-20 - success := not(0) // set success to true - } - case 32 { - // This is a compliant ERC-20 - returndatacopy(0, 0, 32) - success := mload(0) // Set `success = returndata` of external call - } - default { - // This is an excessively non-compliant ERC-20, revert. - revert(0, 0) - } - } - require(success, "EC02"); - - // Calculate the amount that was *actually* transferred - uint256 balanceAfter = EIP20Interface(underlying).balanceOf( - address(this) - ); - require(balanceAfter >= balanceBefore, "EC03"); - return balanceAfter - balanceBefore; // underflow already checked above, just subtract - } - - /** - * @dev Similar to EIP20 transfer, except it handles a False success from `transfer` and returns an explanatory - * error code rather than reverting. If caller has not called checked protocol's balance, this may revert due to - * insufficient cash held in this contract. If caller has checked protocol's balance prior to this call, and verified - * it is >= amount, this should not revert in normal conditions. - * - * Note: This wrapper safely handles non-standard ERC-20 tokens that do not return a value. - * See here: https://medium.com/coinmonks/missing-return-value-bug-at-least-130-tokens-affected-d67bf08521ca - */ - function doTransferOut(address payable to, uint256 amount) - internal - virtual - override - { - EIP20NonStandardInterface token = EIP20NonStandardInterface(underlying); - token.transfer(to, amount); - - bool success; - assembly { - switch returndatasize() - case 0 { - // This is a non-standard ERC-20 - success := not(0) // set success to true - } - case 32 { - // This is a complaint ERC-20 - returndatacopy(0, 0, 32) - success := mload(0) // Set `success = returndata` of external call - } - default { - // This is an excessively non-compliant ERC-20, revert. - revert(0, 0) - } - } - require(success, "CE01"); - } -} - - -// Root file: contracts/CErc20Delegate.sol - -pragma solidity 0.8.6; - -// import "contracts/CErc20.sol"; - -/** - * @title tropykus CErc20Delegate Contract - * @notice CTokens which wrap an EIP-20 underlying and are delegated to - * @author tropykus - */ -contract CErc20Delegate is CErc20, CDelegateInterface { - /** - * @notice Construct an empty delegate - */ - constructor() { - // solium-disable-previous-line no-empty-blocks - } - - /** - * @notice Called by the delegator on a delegate to initialize it for duty - * @param data The encoded bytes data for any initialization - */ - function _becomeImplementation(bytes memory data) public override { - // Shh -- currently unused - data; - - // Shh -- we don't ever want this hook to be marked pure - if (false) { - implementation = address(0); - } - - require(msg.sender == admin, "ER01"); - } - - /** - * @notice Called by the delegator on a delegate to forfeit its responsibility - */ - function _resignImplementation() public override { - // Shh -- we don't ever want this hook to be marked pure - if (false) { - implementation = address(0); - } - - require(msg.sender == admin, "ER02"); - } -} diff --git a/flatten/CErc20Delegator.sol b/flatten/CErc20Delegator.sol deleted file mode 100644 index 102f726..0000000 --- a/flatten/CErc20Delegator.sol +++ /dev/null @@ -1,2128 +0,0 @@ -// Dependency file: contracts/ComptrollerInterface.sol - -// SPDX-License-Identifier: UNLICENSED -// pragma solidity 0.8.6; - -abstract contract ComptrollerInterface { - /// @notice Indicator that this is a Comptroller contract (for inspection) - bool public constant isComptroller = true; - - /*** Assets You Are In ***/ - - function enterMarkets(address[] calldata cTokens) - external - virtual - returns (uint256[] memory); - - function exitMarket(address cToken) external virtual returns (uint256); - - /*** Policy Hooks ***/ - - function mintAllowed( - address cToken, - address minter, - uint256 mintAmount - ) external virtual returns (uint256); - - function mintVerify( - address cToken, - address minter, - uint256 mintAmount, - uint256 mintTokens - ) external virtual; - - function redeemAllowed( - address cToken, - address redeemer, - uint256 redeemTokens - ) external virtual returns (uint256); - - function redeemVerify( - address cToken, - address redeemer, - uint256 redeemAmount, - uint256 redeemTokens - ) external virtual; - - function borrowAllowed( - address cToken, - address borrower, - uint256 borrowAmount - ) external virtual returns (uint256); - - function borrowVerify( - address cToken, - address borrower, - uint256 borrowAmount - ) external virtual; - - function repayBorrowAllowed( - address cToken, - address payer, - address borrower, - uint256 repayAmount - ) external virtual returns (uint256); - - function repayBorrowVerify( - address cToken, - address payer, - address borrower, - uint256 repayAmount, - uint256 borrowerIndex - ) external virtual; - - function liquidateBorrowAllowed( - address cTokenBorrowed, - address cTokenCollateral, - address liquidator, - address borrower, - uint256 repayAmount - ) external virtual returns (uint256); - - function liquidateBorrowVerify( - address cTokenBorrowed, - address cTokenCollateral, - address liquidator, - address borrower, - uint256 repayAmount, - uint256 seizeTokens - ) external virtual; - - function seizeAllowed( - address cTokenCollateral, - address cTokenBorrowed, - address liquidator, - address borrower, - uint256 seizeTokens - ) external virtual returns (uint256); - - function seizeVerify( - address cTokenCollateral, - address cTokenBorrowed, - address liquidator, - address borrower, - uint256 seizeTokens - ) external virtual; - - function transferAllowed( - address cToken, - address src, - address dst, - uint256 transferTokens - ) external virtual returns (uint256); - - function transferVerify( - address cToken, - address src, - address dst, - uint256 transferTokens - ) external virtual; - - /*** Liquidity/Liquidation Calculations ***/ - - function liquidateCalculateSeizeTokens( - address cTokenBorrowed, - address cTokenCollateral, - uint256 repayAmount - ) external view virtual returns (uint256, uint256); -} - - -// Dependency file: contracts/CarefulMath.sol - -// pragma solidity 0.8.6; - -/** - * @title Careful Math - * @author tropykus - * @notice Derived from OpenZeppelin's SafeMath library - * https://github.com/OpenZeppelin/openzeppelin-solidity/blob/master/contracts/math/SafeMath.sol - */ -contract CarefulMath { - - /** - * @dev Possible error codes that we can return - */ - enum MathError { - NO_ERROR, - DIVISION_BY_ZERO, - INTEGER_OVERFLOW, - INTEGER_UNDERFLOW - } - - /** - * @dev Multiplies two numbers, returns an error on overflow. - */ - function mulUInt(uint a, uint b) internal pure returns (MathError, uint) { - if (a == 0) { - return (MathError.NO_ERROR, 0); - } - - uint c = a * b; - - if (c / a != b) { - return (MathError.INTEGER_OVERFLOW, 0); - } else { - return (MathError.NO_ERROR, c); - } - } - - /** - * @dev Integer division of two numbers, truncating the quotient. - */ - function divUInt(uint a, uint b) internal pure returns (MathError, uint) { - if (b == 0) { - return (MathError.DIVISION_BY_ZERO, 0); - } - - return (MathError.NO_ERROR, a / b); - } - - /** - * @dev Subtracts two numbers, returns an error on overflow (i.e. if subtrahend is greater than minuend). - */ - function subUInt(uint a, uint b) internal pure returns (MathError, uint) { - if (b <= a) { - return (MathError.NO_ERROR, a - b); - } else { - return (MathError.INTEGER_UNDERFLOW, 0); - } - } - - /** - * @dev Adds two numbers, returns an error on overflow. - */ - function addUInt(uint a, uint b) internal pure returns (MathError, uint) { - uint c = a + b; - - if (c >= a) { - return (MathError.NO_ERROR, c); - } else { - return (MathError.INTEGER_OVERFLOW, 0); - } - } - - /** - * @dev add a and b and then subtract c - */ - function addThenSubUInt(uint a, uint b, uint c) internal pure returns (MathError, uint) { - (MathError err0, uint sum) = addUInt(a, b); - - if (err0 != MathError.NO_ERROR) { - return (err0, 0); - } - - return subUInt(sum, c); - } -} - - -// Dependency file: contracts/ExponentialNoError.sol - -// pragma solidity 0.8.6; - -/** - * @title Exponential module for storing fixed-precision decimals - * @author tropykus - * @notice Exp is a struct which stores decimals with a fixed precision of 18 decimal places. - * Thus, if we wanted to store the 5.1, mantissa would store 5.1e18. That is: - * `Exp({mantissa: 5100000000000000000})`. - */ -contract ExponentialNoError { - uint constant expScale = 1e18; - uint constant doubleScale = 1e36; - uint constant halfExpScale = expScale/2; - uint constant mantissaOne = expScale; - - struct Exp { - uint mantissa; - } - - struct Double { - uint mantissa; - } - - /** - * @dev Truncates the given exp to a whole number value. - * For example, truncate(Exp{mantissa: 15 * expScale}) = 15 - */ - function truncate(Exp memory exp) pure internal returns (uint) { - // Note: We are not using careful math here as we're performing a division that cannot fail - return exp.mantissa / expScale; - } - - /** - * @dev Multiply an Exp by a scalar, then truncate to return an unsigned integer. - */ - function mul_ScalarTruncate(Exp memory a, uint scalar) pure internal returns (uint) { - Exp memory product = mul_(a, scalar); - return truncate(product); - } - - /** - * @dev Multiply an Exp by a scalar, truncate, then add an to an unsigned integer, returning an unsigned integer. - */ - function mul_ScalarTruncateAddUInt(Exp memory a, uint scalar, uint addend) pure internal returns (uint) { - Exp memory product = mul_(a, scalar); - return add_(truncate(product), addend); - } - - /** - * @dev Checks if first Exp is less than second Exp. - */ - function lessThanExp(Exp memory left, Exp memory right) pure internal returns (bool) { - return left.mantissa < right.mantissa; - } - - /** - * @dev Checks if left Exp <= right Exp. - */ - function lessThanOrEqualExp(Exp memory left, Exp memory right) pure internal returns (bool) { - return left.mantissa <= right.mantissa; - } - - /** - * @dev Checks if left Exp > right Exp. - */ - function greaterThanExp(Exp memory left, Exp memory right) pure internal returns (bool) { - return left.mantissa > right.mantissa; - } - - /** - * @dev returns true if Exp is exactly zero - */ - function isZeroExp(Exp memory value) pure internal returns (bool) { - return value.mantissa == 0; - } - - function safe224(uint n, string memory errorMessage) pure internal returns (uint224) { - require(n < 2**224, errorMessage); - return uint224(n); - } - - function safe32(uint n, string memory errorMessage) pure internal returns (uint32) { - require(n < 2**32, errorMessage); - return uint32(n); - } - - function add_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { - return Exp({mantissa: add_(a.mantissa, b.mantissa)}); - } - - function add_(Double memory a, Double memory b) pure internal returns (Double memory) { - return Double({mantissa: add_(a.mantissa, b.mantissa)}); - } - - function add_(uint a, uint b) pure internal returns (uint) { - return add_(a, b, "addition overflow"); - } - - function add_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { - uint c = a + b; - require(c >= a, errorMessage); - return c; - } - - function sub_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { - return Exp({mantissa: sub_(a.mantissa, b.mantissa)}); - } - - function sub_(Double memory a, Double memory b) pure internal returns (Double memory) { - return Double({mantissa: sub_(a.mantissa, b.mantissa)}); - } - - function sub_(uint a, uint b) pure internal returns (uint) { - return sub_(a, b, "subtraction underflow"); - } - - function sub_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { - require(b <= a, errorMessage); - return a - b; - } - - function mul_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { - return Exp({mantissa: mul_(a.mantissa, b.mantissa) / expScale}); - } - - function mul_(Exp memory a, uint b) pure internal returns (Exp memory) { - return Exp({mantissa: mul_(a.mantissa, b)}); - } - - function mul_(uint a, Exp memory b) pure internal returns (uint) { - return mul_(a, b.mantissa) / expScale; - } - - function mul_(Double memory a, Double memory b) pure internal returns (Double memory) { - return Double({mantissa: mul_(a.mantissa, b.mantissa) / doubleScale}); - } - - function mul_(Double memory a, uint b) pure internal returns (Double memory) { - return Double({mantissa: mul_(a.mantissa, b)}); - } - - function mul_(uint a, Double memory b) pure internal returns (uint) { - return mul_(a, b.mantissa) / doubleScale; - } - - function mul_(uint a, uint b) pure internal returns (uint) { - return mul_(a, b, "multiplication overflow"); - } - - function mul_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { - if (a == 0 || b == 0) { - return 0; - } - uint c = a * b; - require(c / a == b, errorMessage); - return c; - } - - function div_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { - return Exp({mantissa: div_(mul_(a.mantissa, expScale), b.mantissa)}); - } - - function div_(Exp memory a, uint b) pure internal returns (Exp memory) { - return Exp({mantissa: div_(a.mantissa, b)}); - } - - function div_(uint a, Exp memory b) pure internal returns (uint) { - return div_(mul_(a, expScale), b.mantissa); - } - - function div_(Double memory a, Double memory b) pure internal returns (Double memory) { - return Double({mantissa: div_(mul_(a.mantissa, doubleScale), b.mantissa)}); - } - - function div_(Double memory a, uint b) pure internal returns (Double memory) { - return Double({mantissa: div_(a.mantissa, b)}); - } - - function div_(uint a, Double memory b) pure internal returns (uint) { - return div_(mul_(a, doubleScale), b.mantissa); - } - - function div_(uint a, uint b) pure internal returns (uint) { - return div_(a, b, "divide by zero"); - } - - function div_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { - require(b > 0, errorMessage); - return a / b; - } - - function fraction(uint a, uint b) pure internal returns (Double memory) { - return Double({mantissa: div_(mul_(a, doubleScale), b)}); - } -} - - -// Dependency file: contracts/Exponential.sol - -// pragma solidity 0.8.6; - -// import "contracts/CarefulMath.sol"; -// import "contracts/ExponentialNoError.sol"; - -/** - * @title Exponential module for storing fixed-precision decimals - * @author tropykus - * @dev Legacy contract for compatibility reasons with existing contracts that still use MathError - * @notice Exp is a struct which stores decimals with a fixed precision of 18 decimal places. - * Thus, if we wanted to store the 5.1, mantissa would store 5.1e18. That is: - * `Exp({mantissa: 5100000000000000000})`. - */ -contract Exponential is CarefulMath, ExponentialNoError { - /** - * @dev Creates an exponential from numerator and denominator values. - * Note: Returns an error if (`num` * 10e18) > MAX_INT, - * or if `denom` is zero. - */ - function getExp(uint num, uint denom) internal pure returns (MathError, Exp memory) { - (MathError err0, uint scaledNumerator) = mulUInt(num, expScale); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - - (MathError err1, uint rational) = divUInt(scaledNumerator, denom); - if (err1 != MathError.NO_ERROR) { - return (err1, Exp({mantissa: 0})); - } - - return (MathError.NO_ERROR, Exp({mantissa: rational})); - } - - /** - * @dev Adds two exponentials, returning a new exponential. - */ - function addExp(Exp memory a, Exp memory b) internal pure returns (MathError, Exp memory) { - (MathError error, uint result) = addUInt(a.mantissa, b.mantissa); - - return (error, Exp({mantissa: result})); - } - - /** - * @dev Subtracts two exponentials, returning a new exponential. - */ - function subExp(Exp memory a, Exp memory b) internal pure returns (MathError, Exp memory) { - (MathError error, uint result) = subUInt(a.mantissa, b.mantissa); - - return (error, Exp({mantissa: result})); - } - - /** - * @dev Multiply an Exp by a scalar, returning a new Exp. - */ - function mulScalar(Exp memory a, uint scalar) internal pure returns (MathError, Exp memory) { - (MathError err0, uint scaledMantissa) = mulUInt(a.mantissa, scalar); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - - return (MathError.NO_ERROR, Exp({mantissa: scaledMantissa})); - } - - /** - * @dev Multiply an Exp by a scalar, then truncate to return an unsigned integer. - */ - function mulScalarTruncate(Exp memory a, uint scalar) internal pure returns (MathError, uint) { - (MathError err, Exp memory product) = mulScalar(a, scalar); - if (err != MathError.NO_ERROR) { - return (err, 0); - } - - return (MathError.NO_ERROR, truncate(product)); - } - - /** - * @dev Multiply an Exp by a scalar, truncate, then add an to an unsigned integer, returning an unsigned integer. - */ - function mulScalarTruncateAddUInt(Exp memory a, uint scalar, uint addend) internal pure returns (MathError, uint) { - (MathError err, Exp memory product) = mulScalar(a, scalar); - if (err != MathError.NO_ERROR) { - return (err, 0); - } - - return addUInt(truncate(product), addend); - } - - /** - * @dev Divide an Exp by a scalar, returning a new Exp. - */ - function divScalar(Exp memory a, uint scalar) internal pure returns (MathError, Exp memory) { - (MathError err0, uint descaledMantissa) = divUInt(a.mantissa, scalar); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - - return (MathError.NO_ERROR, Exp({mantissa: descaledMantissa})); - } - - /** - * @dev Divide a scalar by an Exp, returning a new Exp. - */ - function divScalarByExp(uint scalar, Exp memory divisor) internal pure returns (MathError, Exp memory) { - /* - We are doing this as: - getExp(mulUInt(expScale, scalar), divisor.mantissa) - - How it works: - Exp = a / b; - Scalar = s; - `s / (a / b)` = `b * s / a` and since for an Exp `a = mantissa, b = expScale` - */ - (MathError err0, uint numerator) = mulUInt(expScale, scalar); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - return getExp(numerator, divisor.mantissa); - } - - /** - * @dev Divide a scalar by an Exp, then truncate to return an unsigned integer. - */ - function divScalarByExpTruncate(uint scalar, Exp memory divisor) internal pure returns (MathError, uint) { - (MathError err, Exp memory fraction) = divScalarByExp(scalar, divisor); - if (err != MathError.NO_ERROR) { - return (err, 0); - } - - return (MathError.NO_ERROR, truncate(fraction)); - } - - /** - * @dev Multiplies two exponentials, returning a new exponential. - */ - function mulExp(Exp memory a, Exp memory b) internal pure returns (MathError, Exp memory) { - - (MathError err0, uint doubleScaledProduct) = mulUInt(a.mantissa, b.mantissa); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - - // We add half the scale before dividing so that we get rounding instead of truncation. - // See "Listing 6" and text above it at https://accu.org/index.php/journals/1717 - // Without this change, a result like 6.6...e-19 will be truncated to 0 instead of being rounded to 1e-18. - (MathError err1, uint doubleScaledProductWithHalfScale) = addUInt(halfExpScale, doubleScaledProduct); - if (err1 != MathError.NO_ERROR) { - return (err1, Exp({mantissa: 0})); - } - - (MathError err2, uint product) = divUInt(doubleScaledProductWithHalfScale, expScale); - // The only error `div` can return is MathError.DIVISION_BY_ZERO but we control `expScale` and it is not zero. - assert(err2 == MathError.NO_ERROR); - - return (MathError.NO_ERROR, Exp({mantissa: product})); - } - - /** - * @dev Multiplies two exponentials given their mantissas, returning a new exponential. - */ - function mulExp(uint a, uint b) internal pure returns (MathError, Exp memory) { - return mulExp(Exp({mantissa: a}), Exp({mantissa: b})); - } - - /** - * @dev Multiplies three exponentials, returning a new exponential. - */ - function mulExp3(Exp memory a, Exp memory b, Exp memory c) internal pure returns (MathError, Exp memory) { - (MathError err, Exp memory ab) = mulExp(a, b); - if (err != MathError.NO_ERROR) { - return (err, ab); - } - return mulExp(ab, c); - } - - /** - * @dev Divides two exponentials, returning a new exponential. - * (a/scale) / (b/scale) = (a/scale) * (scale/b) = a/b, - * which we can scale as an Exp by calling getExp(a.mantissa, b.mantissa) - */ - function divExp(Exp memory a, Exp memory b) internal pure returns (MathError, Exp memory) { - return getExp(a.mantissa, b.mantissa); - } -} - - -// Dependency file: contracts/SafeMath.sol - -// pragma solidity 0.8.6; - -// From https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/math/Math.sol -// Subject to the MIT license. - -/** - * @dev Wrappers over Solidity's arithmetic operations with added overflow - * checks. - * - * Arithmetic operations in Solidity wrap on overflow. This can easily result - * in bugs, because programmers usually assume that an overflow raises an - * error, which is the standard behavior in high level programming languages. - * `SafeMath` restores this intuition by reverting the transaction when an - * operation overflows. - * - * Using this library instead of the unchecked operations eliminates an entire - * class of bugs, so it's recommended to use it always. - */ -library SafeMath { - /** - * @dev Returns the addition of two unsigned integers, reverting on overflow. - * - * Counterpart to Solidity's `+` operator. - * - * Requirements: - * - Addition cannot overflow. - */ - function add(uint256 a, uint256 b) internal pure returns (uint256) { - uint256 c = a + b; - require(c >= a, "SafeMath: addition overflow"); - - return c; - } - - /** - * @dev Returns the addition of two unsigned integers, reverting with custom message on overflow. - * - * Counterpart to Solidity's `+` operator. - * - * Requirements: - * - Addition cannot overflow. - */ - function add(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - uint256 c = a + b; - require(c >= a, errorMessage); - - return c; - } - - /** - * @dev Returns the subtraction of two unsigned integers, reverting on underflow (when the result is negative). - * - * Counterpart to Solidity's `-` operator. - * - * Requirements: - * - Subtraction cannot underflow. - */ - function sub(uint256 a, uint256 b) internal pure returns (uint256) { - return sub(a, b, "SafeMath: subtraction underflow"); - } - - /** - * @dev Returns the subtraction of two unsigned integers, reverting with custom message on underflow (when the result is negative). - * - * Counterpart to Solidity's `-` operator. - * - * Requirements: - * - Subtraction cannot underflow. - */ - function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - require(b <= a, errorMessage); - uint256 c = a - b; - - return c; - } - - /** - * @dev Returns the multiplication of two unsigned integers, reverting on overflow. - * - * Counterpart to Solidity's `*` operator. - * - * Requirements: - * - Multiplication cannot overflow. - */ - function mul(uint256 a, uint256 b) internal pure returns (uint256) { - // Gas optimization: this is cheaper than requiring 'a' not being zero, but the - // benefit is lost if 'b' is also tested. - // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 - if (a == 0) { - return 0; - } - - uint256 c = a * b; - require(c / a == b, "SafeMath: multiplication overflow"); - - return c; - } - - /** - * @dev Returns the multiplication of two unsigned integers, reverting on overflow. - * - * Counterpart to Solidity's `*` operator. - * - * Requirements: - * - Multiplication cannot overflow. - */ - function mul(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - // Gas optimization: this is cheaper than requiring 'a' not being zero, but the - // benefit is lost if 'b' is also tested. - // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 - if (a == 0) { - return 0; - } - - uint256 c = a * b; - require(c / a == b, errorMessage); - - return c; - } - - /** - * @dev Returns the integer division of two unsigned integers. - * Reverts on division by zero. The result is rounded towards zero. - * - * Counterpart to Solidity's `/` operator. Note: this function uses a - * `revert` opcode (which leaves remaining gas untouched) while Solidity - * uses an invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function div(uint256 a, uint256 b) internal pure returns (uint256) { - return div(a, b, "SafeMath: division by zero"); - } - - /** - * @dev Returns the integer division of two unsigned integers. - * Reverts with custom message on division by zero. The result is rounded towards zero. - * - * Counterpart to Solidity's `/` operator. Note: this function uses a - * `revert` opcode (which leaves remaining gas untouched) while Solidity - * uses an invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - // Solidity only automatically asserts when dividing by 0 - require(b > 0, errorMessage); - uint256 c = a / b; - // assert(a == b * c + a % b); // There is no case in which this doesn't hold - - return c; - } - - /** - * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), - * Reverts when dividing by zero. - * - * Counterpart to Solidity's `%` operator. This function uses a `revert` - * opcode (which leaves remaining gas untouched) while Solidity uses an - * invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function mod(uint256 a, uint256 b) internal pure returns (uint256) { - return mod(a, b, "SafeMath: modulo by zero"); - } - - /** - * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), - * Reverts with custom message when dividing by zero. - * - * Counterpart to Solidity's `%` operator. This function uses a `revert` - * opcode (which leaves remaining gas untouched) while Solidity uses an - * invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - require(b != 0, errorMessage); - return a % b; - } -} - - -// Dependency file: contracts/InterestRateModel.sol - -// pragma solidity 0.8.6; - -// import "contracts/Exponential.sol"; -// import "contracts/SafeMath.sol"; - -/** - * @title tropykus InterestRateModel Interface - * @author tropykus - */ -abstract contract InterestRateModel is Exponential { - using SafeMath for uint256; - - /// @notice Indicator that this is an InterestRateModel contract (for inspection) - bool public constant isInterestRateModel = true; - bool public isTropykusInterestRateModel; - - /** - * @notice The approximate number of blocks per year that is assumed by the interest rate model - */ - uint256 public constant blocksPerYear = 1051200; - - /** - * @notice Calculates the utilization rate of the market: `borrows / (cash + borrows - reserves)` - * @param cash The amount of cash in the market - * @param borrows The amount of borrows in the market - * @param reserves The amount of reserves in the market (currently unused) - * @return The utilization rate as a mantissa between [0, 1e18] - */ - function utilizationRate( - uint256 cash, - uint256 borrows, - uint256 reserves - ) public pure virtual returns (uint256) { - // Utilization rate is 0 when there are no borrows - if (borrows == 0) { - return 0; - } - - return borrows.mul(1e18).div(cash.add(borrows).sub(reserves)); - } - - /** - * @notice Calculates the current borrow interest rate per block - * @param cash The total amount of cash the market has - * @param borrows The total amount of borrows the market has outstanding - * @param reserves The total amnount of reserves the market has - * @return The borrow rate per block (as a percentage, and scaled by 1e18) - */ - function getBorrowRate( - uint256 cash, - uint256 borrows, - uint256 reserves - ) external view virtual returns (uint256); - - /** - * @notice Calculates the current supply interest rate per block - * @param cash The total amount of cash the market has - * @param borrows The total amount of borrows the market has outstanding - * @param reserves The total amnount of reserves the market has - * @param reserveFactorMantissa The current reserve factor the market has - * @return The supply rate per block (as a percentage, and scaled by 1e18) - */ - function getSupplyRate( - uint256 cash, - uint256 borrows, - uint256 reserves, - uint256 reserveFactorMantissa - ) external view virtual returns (uint256); - - function getExchangeRate( - uint256 _totalCash, - uint256 _totalBorrows, - uint256 _totalReserves, - uint256 _totalSupply - ) public pure returns (MathError, uint256) { - /* - * exchangeRate = (totalCash + totalBorrows - totalReserves) / totalSupply - */ - Exp memory exchangeRate; - MathError mathErr; - uint256 cashPlusBorrowsMinusReserves; - (mathErr, cashPlusBorrowsMinusReserves) = addThenSubUInt( - _totalCash, - _totalBorrows, - _totalReserves - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - (mathErr, exchangeRate) = getExp( - cashPlusBorrowsMinusReserves, - _totalSupply - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - - return (MathError.NO_ERROR, exchangeRate.mantissa); - } - - function isAboveOptimal( - uint256 cash, - uint256 borrows, - uint256 reserves - ) public view virtual returns (bool) { - cash; - borrows; - reserves; - return false; - } -} - - -// Dependency file: contracts/EIP20NonStandardInterface.sol - -// pragma solidity 0.8.6; - -/** - * @title EIP20NonStandardInterface - * @dev Version of ERC20 with no return values for `transfer` and `transferFrom` - * See https://medium.com/coinmonks/missing-return-value-bug-at-least-130-tokens-affected-d67bf08521ca - */ -interface EIP20NonStandardInterface { - /** - * @notice Get the total number of tokens in circulation - * @return The supply of tokens - */ - function totalSupply() external view returns (uint256); - - /** - * @notice Gets the balance of the specified address - * @param owner The address from which the balance will be retrieved - * @return balance The balance - */ - function balanceOf(address owner) external view returns (uint256 balance); - - /// - /// !!!!!!!!!!!!!! - /// !!! NOTICE !!! `transfer` does not return a value, in violation of the ERC-20 specification - /// !!!!!!!!!!!!!! - /// - - /** - * @notice Transfer `amount` tokens from `msg.sender` to `dst` - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - */ - function transfer(address dst, uint256 amount) external; - - /// - /// !!!!!!!!!!!!!! - /// !!! NOTICE !!! `transferFrom` does not return a value, in violation of the ERC-20 specification - /// !!!!!!!!!!!!!! - /// - - /** - * @notice Transfer `amount` tokens from `src` to `dst` - * @param src The address of the source account - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - */ - function transferFrom( - address src, - address dst, - uint256 amount - ) external; - - /** - * @notice Approve `spender` to transfer up to `amount` from `src` - * @dev This will overwrite the approval amount for `spender` - * and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve) - * @param spender The address of the account which may transfer tokens - * @param amount The number of tokens that are approved - * @return success Whether or not the approval succeeded - */ - function approve(address spender, uint256 amount) - external - returns (bool success); - - /** - * @notice Get the current allowance from `owner` for `spender` - * @param owner The address of the account which owns the tokens to be spent - * @param spender The address of the account which may transfer tokens - * @return remaining The number of tokens allowed to be spent - */ - function allowance(address owner, address spender) - external - view - returns (uint256 remaining); - - event Transfer(address indexed from, address indexed to, uint256 amount); - event Approval( - address indexed owner, - address indexed spender, - uint256 amount - ); -} - - -// Dependency file: contracts/CTokenInterfaces.sol - -// pragma solidity 0.8.6; - -// import "contracts/ComptrollerInterface.sol"; -// import "contracts/InterestRateModel.sol"; -// import "contracts/EIP20NonStandardInterface.sol"; - -contract CTokenStorage { - /** - * @dev Guard variable for re-entrancy checks - */ - bool internal _notEntered; - - /** - * @notice EIP-20 token name for this token - */ - string public name; - - /** - * @notice EIP-20 token symbol for this token - */ - string public symbol; - - /** - * @notice EIP-20 token decimals for this token - */ - uint8 public decimals; - - /** - * @notice Maximum borrow rate that can ever be applied (.0005% / block) - */ - - uint256 internal constant borrowRateMaxMantissa = 0.0005e16; - - /** - * @notice Maximum fraction of interest that can be set aside for reserves - */ - uint256 internal constant reserveFactorMaxMantissa = 1e18; - - /** - * @notice Administrator for this contract - */ - address payable public admin; - - /** - * @notice Pending administrator for this contract - */ - address payable public pendingAdmin; - - /** - * @notice Contract which oversees inter-cToken operations - */ - ComptrollerInterface public comptroller; - - /** - * @notice Model which tells what the current interest rate should be - */ - InterestRateModel public interestRateModel; - - /** - * @notice Initial exchange rate used when minting the first CTokens (used when totalSupply = 0) - */ - uint256 public initialExchangeRateMantissa; - - /** - * @notice Fraction of interest currently set aside for reserves - */ - uint256 public reserveFactorMantissa; - - /** - * @notice Block number that interest was last accrued at - */ - uint256 public accrualBlockNumber; - - /** - * @notice Accumulator of the total earned interest rate since the opening of the market - */ - uint256 public borrowIndex; - - /** - * @notice Total amount of outstanding borrows of the underlying in this market - */ - uint256 public totalBorrows; - - /** - * @notice Total amount of reserves of the underlying held in this market - */ - uint256 public totalReserves; - - /** - * @notice Total number of tokens in circulation - */ - uint256 public totalSupply; - - uint256 public subsidyFund; - - struct SupplySnapshot { - uint256 tokens; - uint256 underlyingAmount; - uint256 suppliedAt; - uint256 promisedSupplyRate; - } - - /** - * @notice Official record of token balances for each account - */ - mapping(address => SupplySnapshot) internal accountTokens; - - /** - * @notice Approved token transfer amounts on behalf of others - */ - mapping(address => mapping(address => uint256)) internal transferAllowances; - - /** - * @notice Container for borrow balance information - * @member principal Total balance (with accrued interest), after applying the most recent balance-changing action - * @member interestIndex Global borrowIndex as of the most recent balance-changing action - */ - struct BorrowSnapshot { - uint256 principal; - uint256 interestIndex; - } - - /** - * @notice Mapping of account addresses to outstanding borrow balances - */ - mapping(address => BorrowSnapshot) internal accountBorrows; -} - -abstract contract CTokenInterface is CTokenStorage { - /** - * @notice Indicator that this is a CToken contract (for inspection) - */ - bool public constant isCToken = true; - - /*** Market Events ***/ - - /** - * @notice Event emitted when interest is accrued - */ - event AccrueInterest( - uint256 cashPrior, - uint256 interestAccumulated, - uint256 borrowIndex, - uint256 totalBorrows - ); - - /** - * @notice Event emitted when tokens are minted - */ - event Mint(address indexed minter, uint256 mintAmount, uint256 mintTokens); - - /** - * @notice Event emitted when tokens are redeemed - */ - event Redeem( - address indexed redeemer, - uint256 redeemAmount, - uint256 redeemTokens - ); - - /** - * @notice Event emitted when underlying is borrowed - */ - event Borrow( - address indexed borrower, - uint256 borrowAmount, - uint256 accountBorrows, - uint256 totalBorrows - ); - - /** - * @notice Event emitted when a borrow is repaid - */ - event RepayBorrow( - address indexed payer, - address indexed borrower, - uint256 repayAmount, - uint256 accountBorrows, - uint256 totalBorrows - ); - - /** - * @notice Event emitted when a borrow is liquidated - */ - event LiquidateBorrow( - address indexed liquidator, - address indexed borrower, - uint256 repayAmount, - address indexed cTokenCollateral, - uint256 seizeTokens - ); - - /*** Admin Events ***/ - - /** - * @notice Event emitted when pendingAdmin is changed - */ - event NewPendingAdmin(address oldPendingAdmin, address newPendingAdmin); - - /** - * @notice Event emitted when pendingAdmin is accepted, which means admin is updated - */ - event NewAdmin(address oldAdmin, address newAdmin); - - /** - * @notice Event emitted when comptroller is changed - */ - event NewComptroller( - ComptrollerInterface oldComptroller, - ComptrollerInterface newComptroller - ); - - /** - * @notice Event emitted when interestRateModel is changed - */ - event NewMarketInterestRateModel( - InterestRateModel oldInterestRateModel, - InterestRateModel newInterestRateModel - ); - - /** - * @notice Event emitted when the reserve factor is changed - */ - event NewReserveFactor( - uint256 oldReserveFactorMantissa, - uint256 newReserveFactorMantissa - ); - - /** - * @notice Event emitted when the reserves are added - */ - event ReservesAdded( - address benefactor, - uint256 addAmount, - uint256 newTotalReserves - ); - - event SubsidyAdded( - address benefactor, - uint256 addAmount, - uint256 newSubsidyFund - ); - - /** - * @notice Event emitted when the reserves are reduced - */ - event ReservesReduced( - address admin, - uint256 reduceAmount, - uint256 newTotalReserves - ); - - /** - * @notice EIP20 Transfer event - */ - event Transfer(address indexed from, address indexed to, uint256 amount); - - /** - * @notice EIP20 Approval event - */ - event Approval( - address indexed owner, - address indexed spender, - uint256 amount - ); - - /** - * @notice Failure event - */ - event CTokenStorageFailure(uint256 error, uint256 info, uint256 detail); - - /*** User Interface ***/ - - function transfer(address dst, uint256 amount) - external - virtual - returns (bool); - - function transferFrom( - address src, - address dst, - uint256 amount - ) external virtual returns (bool); - - function approve(address spender, uint256 amount) - external - virtual - returns (bool); - - function allowance(address owner, address spender) - external - view - virtual - returns (uint256); - - function balanceOf(address owner) external view virtual returns (uint256); - - function balanceOfUnderlying(address owner) - external - virtual - returns (uint256); - - function getAccountSnapshot(address account) - external - view - virtual - returns ( - uint256, - uint256, - uint256, - uint256 - ); - - function borrowRatePerBlock() external view virtual returns (uint256); - - function supplyRatePerBlock() external view virtual returns (uint256); - - function totalBorrowsCurrent() external virtual returns (uint256); - - function borrowBalanceCurrent(address account) - external - virtual - returns (uint256); - - function borrowBalanceStored(address account) - public - view - virtual - returns (uint256); - - function exchangeRateCurrent() public virtual returns (uint256); - - function exchangeRateStored() public view virtual returns (uint256); - - function getCash() external view virtual returns (uint256); - - function accrueInterest() public virtual returns (uint256); - - function seize( - address liquidator, - address borrower, - uint256 seizeTokens - ) external virtual returns (uint256); - - /*** Admin Functions ***/ - - function _setPendingAdmin(address payable newPendingAdmin) - external - virtual - returns (uint256); - - function _acceptAdmin() external virtual returns (uint256); - - function _setComptroller(ComptrollerInterface newComptroller) - public - virtual - returns (uint256); - - function _setReserveFactor(uint256 newReserveFactorMantissa) - external - virtual - returns (uint256); - - function _reduceReserves(uint256 reduceAmount) - external - virtual - returns (uint256); - - function _setInterestRateModel(InterestRateModel newInterestRateModel) - public - virtual - returns (uint256); -} - -contract CErc20Storage { - /** - * @notice Underlying asset for this CToken - */ - address public underlying; -} - -abstract contract CErc20Interface is CErc20Storage { - /*** User Interface ***/ - - function mint(uint256 mintAmount) external virtual returns (uint256); - - function redeem(uint256 redeemAmount) - external - virtual - returns (uint256); - - function borrow(uint256 borrowAmount) external virtual returns (uint256); - - function repayBorrow(uint256 repayAmount) - external - virtual - returns (uint256); - - function liquidateBorrow( - address borrower, - uint256 repayAmount, - CTokenInterface cTokenCollateral - ) external virtual returns (uint256); - - function sweepToken(EIP20NonStandardInterface token) external virtual; - - /*** Admin Functions ***/ - - function _addReserves(uint256 addAmount) external virtual returns (uint256); -} - -contract CDelegationStorage { - /** - * @notice Implementation address for this contract - */ - address public implementation; -} - -abstract contract CDelegatorInterface is CDelegationStorage { - /** - * @notice Emitted when implementation is changed - */ - event NewImplementation( - address oldImplementation, - address newImplementation - ); - - /** - * @notice Called by the admin to update the implementation of the delegator - * @param implementation_ The address of the new implementation for delegation - * @param allowResign Flag to indicate whether to call _resignImplementation on the old implementation - * @param becomeImplementationData The encoded bytes data to be passed to _becomeImplementation - */ - function _setImplementation( - address implementation_, - bool allowResign, - bytes memory becomeImplementationData - ) public virtual; -} - -abstract contract CDelegateInterface is CDelegationStorage { - /** - * @notice Called by the delegator on a delegate to initialize it for duty - * @dev Should revert if any issues arise which make it unfit for delegation - * @param data The encoded bytes data for any initialization - */ - function _becomeImplementation(bytes memory data) public virtual; - - /** - * @notice Called by the delegator on a delegate to forfeit its responsibility - */ - function _resignImplementation() public virtual; -} - - -// Root file: contracts/CErc20Delegator.sol - -pragma solidity 0.8.6; - -// import "contracts/CTokenInterfaces.sol"; - -/** - * @title tropykus CErc20Delegator Contract - * @notice CTokens which wrap an EIP-20 underlying and delegate to an implementation - * @author tropykus - */ -contract CErc20Delegator is - CTokenInterface, - CErc20Interface, - CDelegatorInterface -{ - /** - * @notice Construct a new money market - * @param underlying_ The address of the underlying asset - * @param comptroller_ The address of the Comptroller - * @param interestRateModel_ The address of the interest rate model - * @param initialExchangeRateMantissa_ The initial exchange rate, scaled by 1e18 - * @param name_ ERC-20 name of this token - * @param symbol_ ERC-20 symbol of this token - * @param decimals_ ERC-20 decimal precision of this token - * @param admin_ Address of the administrator of this token - * @param implementation_ The address of the implementation the contract delegates to - * @param becomeImplementationData The encoded args for becomeImplementation - */ - constructor( - address underlying_, - ComptrollerInterface comptroller_, - InterestRateModel interestRateModel_, - uint256 initialExchangeRateMantissa_, - string memory name_, - string memory symbol_, - uint8 decimals_, - address payable admin_, - address implementation_, - bytes memory becomeImplementationData - ) { - // Creator of the contract is admin during initialization - admin = payable(msg.sender); - - // First delegate gets to initialize the delegator (i.e. storage contract) - delegateTo( - implementation_, - abi.encodeWithSignature( - "initialize(address,address,address,uint256,string,string,uint8)", - underlying_, - comptroller_, - interestRateModel_, - initialExchangeRateMantissa_, - name_, - symbol_, - decimals_ - ) - ); - - // New implementations always get set via the settor (post-initialize) - _setImplementation(implementation_, false, becomeImplementationData); - - // Set the proper admin now that initialization is done - admin = admin_; - } - - /** - * @notice Called by the admin to update the implementation of the delegator - * @param implementation_ The address of the new implementation for delegation - * @param allowResign Flag to indicate whether to call _resignImplementation on the old implementation - * @param becomeImplementationData The encoded bytes data to be passed to _becomeImplementation - */ - function _setImplementation( - address implementation_, - bool allowResign, - bytes memory becomeImplementationData - ) public override { - require( - msg.sender == admin, - "CErc20Delegator::_setImplementation: Caller must be admin" - ); - - if (allowResign) { - delegateToImplementation( - abi.encodeWithSignature("_resignImplementation()") - ); - } - - address oldImplementation = implementation; - implementation = implementation_; - - delegateToImplementation( - abi.encodeWithSignature( - "_becomeImplementation(bytes)", - becomeImplementationData - ) - ); - - emit NewImplementation(oldImplementation, implementation); - } - - /** - * @notice Sender supplies assets into the market and receives cTokens in exchange - * @dev Accrues interest whether or not the operation succeeds, unless reverted - * @param mintAmount The amount of the underlying asset to supply - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function mint(uint256 mintAmount) external override returns (uint256) { - bytes memory data = delegateToImplementation( - abi.encodeWithSignature("mint(uint256)", mintAmount) - ); - return abi.decode(data, (uint256)); - } - - /** - * @notice Sender redeems cTokens in exchange for a specified amount of underlying asset - * @dev Accrues interest whether or not the operation succeeds, unless reverted - * @param redeemAmount The amount of underlying to redeem - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function redeem(uint256 redeemAmount) - external - override - returns (uint256) - { - bytes memory data = delegateToImplementation( - abi.encodeWithSignature("redeemUnderlying(uint256)", redeemAmount) - ); - return abi.decode(data, (uint256)); - } - - /** - * @notice Sender borrows assets from the protocol to their own address - * @param borrowAmount The amount of the underlying asset to borrow - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function borrow(uint256 borrowAmount) external override returns (uint256) { - bytes memory data = delegateToImplementation( - abi.encodeWithSignature("borrow(uint256)", borrowAmount) - ); - return abi.decode(data, (uint256)); - } - - /** - * @notice Sender repays their own borrow - * @param repayAmount The amount to repay - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function repayBorrow(uint256 repayAmount) - external - override - returns (uint256) - { - bytes memory data = delegateToImplementation( - abi.encodeWithSignature("repayBorrow(uint256)", repayAmount) - ); - return abi.decode(data, (uint256)); - } - - /** - * @notice The sender liquidates the borrowers collateral. - * The collateral seized is transferred to the liquidator. - * @param borrower The borrower of this cToken to be liquidated - * @param cTokenCollateral The market in which to seize collateral from the borrower - * @param repayAmount The amount of the underlying borrowed asset to repay - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function liquidateBorrow( - address borrower, - uint256 repayAmount, - CTokenInterface cTokenCollateral - ) external override returns (uint256) { - bytes memory data = delegateToImplementation( - abi.encodeWithSignature( - "liquidateBorrow(address,uint256,address)", - borrower, - repayAmount, - cTokenCollateral - ) - ); - return abi.decode(data, (uint256)); - } - - /** - * @notice Transfer `amount` tokens from `msg.sender` to `dst` - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - * @return Whether or not the transfer succeeded - */ - function transfer(address dst, uint256 amount) - external - override - returns (bool) - { - bytes memory data = delegateToImplementation( - abi.encodeWithSignature("transfer(address,uint256)", dst, amount) - ); - return abi.decode(data, (bool)); - } - - /** - * @notice Transfer `amount` tokens from `src` to `dst` - * @param src The address of the source account - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - * @return Whether or not the transfer succeeded - */ - function transferFrom( - address src, - address dst, - uint256 amount - ) external override returns (bool) { - bytes memory data = delegateToImplementation( - abi.encodeWithSignature( - "transferFrom(address,address,uint256)", - src, - dst, - amount - ) - ); - return abi.decode(data, (bool)); - } - - /** - * @notice Approve `spender` to transfer up to `amount` from `src` - * @dev This will overwrite the approval amount for `spender` - * and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve) - * @param spender The address of the account which may transfer tokens - * @param amount The number of tokens that are approved (-1 means infinite) - * @return Whether or not the approval succeeded - */ - function approve(address spender, uint256 amount) - external - override - returns (bool) - { - bytes memory data = delegateToImplementation( - abi.encodeWithSignature("approve(address,uint256)", spender, amount) - ); - return abi.decode(data, (bool)); - } - - /** - * @notice Get the current allowance from `owner` for `spender` - * @param owner The address of the account which owns the tokens to be spent - * @param spender The address of the account which may transfer tokens - * @return The number of tokens allowed to be spent (-1 means infinite) - */ - function allowance(address owner, address spender) - external - view - override - returns (uint256) - { - bytes memory data = delegateToViewImplementation( - abi.encodeWithSignature( - "allowance(address,address)", - owner, - spender - ) - ); - return abi.decode(data, (uint256)); - } - - /** - * @notice Get the token balance of the `owner` - * @param owner The address of the account to query - * @return The number of tokens owned by `owner` - */ - function balanceOf(address owner) external view override returns (uint256) { - bytes memory data = delegateToViewImplementation( - abi.encodeWithSignature("balanceOf(address)", owner) - ); - return abi.decode(data, (uint256)); - } - - /** - * @notice Get the underlying balance of the `owner` - * @dev This also accrues interest in a transaction - * @param owner The address of the account to query - * @return The amount of underlying owned by `owner` - */ - function balanceOfUnderlying(address owner) - external - override - returns (uint256) - { - bytes memory data = delegateToImplementation( - abi.encodeWithSignature("balanceOfUnderlying(address)", owner) - ); - return abi.decode(data, (uint256)); - } - - /** - * @notice Get a snapshot of the account's balances, and the cached exchange rate - * @dev This is used by comptroller to more efficiently perform liquidity checks. - * @param account Address of the account to snapshot - * @return (possible error, token balance, borrow balance, exchange rate mantissa) - */ - function getAccountSnapshot(address account) - external - view - override - returns ( - uint256, - uint256, - uint256, - uint256 - ) - { - bytes memory data = delegateToViewImplementation( - abi.encodeWithSignature("getAccountSnapshot(address)", account) - ); - return abi.decode(data, (uint256, uint256, uint256, uint256)); - } - - /** - * @notice Returns the current per-block borrow interest rate for this cToken - * @return The borrow interest rate per block, scaled by 1e18 - */ - function borrowRatePerBlock() external view override returns (uint256) { - bytes memory data = delegateToViewImplementation( - abi.encodeWithSignature("borrowRatePerBlock()") - ); - return abi.decode(data, (uint256)); - } - - /** - * @notice Returns the current per-block supply interest rate for this cToken - * @return The supply interest rate per block, scaled by 1e18 - */ - function supplyRatePerBlock() external view override returns (uint256) { - bytes memory data = delegateToViewImplementation( - abi.encodeWithSignature("supplyRatePerBlock()") - ); - return abi.decode(data, (uint256)); - } - - /** - * @notice Returns the current total borrows plus accrued interest - * @return The total borrows with interest - */ - function totalBorrowsCurrent() external override returns (uint256) { - bytes memory data = delegateToImplementation( - abi.encodeWithSignature("totalBorrowsCurrent()") - ); - return abi.decode(data, (uint256)); - } - - /** - * @notice Accrue interest to updated borrowIndex and then calculate account's borrow balance using the updated borrowIndex - * @param account The address whose balance should be calculated after updating borrowIndex - * @return The calculated balance - */ - function borrowBalanceCurrent(address account) - external - override - returns (uint256) - { - bytes memory data = delegateToImplementation( - abi.encodeWithSignature("borrowBalanceCurrent(address)", account) - ); - return abi.decode(data, (uint256)); - } - - /** - * @notice Return the borrow balance of account based on stored data - * @param account The address whose balance should be calculated - * @return The calculated balance - */ - function borrowBalanceStored(address account) - public - view - override - returns (uint256) - { - bytes memory data = delegateToViewImplementation( - abi.encodeWithSignature("borrowBalanceStored(address)", account) - ); - return abi.decode(data, (uint256)); - } - - /** - * @notice Accrue interest then return the up-to-date exchange rate - * @return Calculated exchange rate scaled by 1e18 - */ - function exchangeRateCurrent() public override returns (uint256) { - bytes memory data = delegateToImplementation( - abi.encodeWithSignature("exchangeRateCurrent()") - ); - return abi.decode(data, (uint256)); - } - - /** - * @notice Calculates the exchange rate from the underlying to the CToken - * @dev This function does not accrue interest before calculating the exchange rate - * @return Calculated exchange rate scaled by 1e18 - */ - function exchangeRateStored() public view override returns (uint256) { - bytes memory data = delegateToViewImplementation( - abi.encodeWithSignature("exchangeRateStored()") - ); - return abi.decode(data, (uint256)); - } - - /** - * @notice Get cash balance of this cToken in the underlying asset - * @return The quantity of underlying asset owned by this contract - */ - function getCash() external view override returns (uint256) { - bytes memory data = delegateToViewImplementation( - abi.encodeWithSignature("getCash()") - ); - return abi.decode(data, (uint256)); - } - - /** - * @notice Applies accrued interest to total borrows and reserves. - * @dev This calculates interest accrued from the last checkpointed block - * up to the current block and writes new checkpoint to storage. - */ - function accrueInterest() public override returns (uint256) { - bytes memory data = delegateToImplementation( - abi.encodeWithSignature("accrueInterest()") - ); - return abi.decode(data, (uint256)); - } - - /** - * @notice Transfers collateral tokens (this market) to the liquidator. - * @dev Will fail unless called by another cToken during the process of liquidation. - * Its absolutely critical to use msg.sender as the borrowed cToken and not a parameter. - * @param liquidator The account receiving seized collateral - * @param borrower The account having collateral seized - * @param seizeTokens The number of cTokens to seize - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function seize( - address liquidator, - address borrower, - uint256 seizeTokens - ) external override returns (uint256) { - bytes memory data = delegateToImplementation( - abi.encodeWithSignature( - "seize(address,address,uint256)", - liquidator, - borrower, - seizeTokens - ) - ); - return abi.decode(data, (uint256)); - } - - /** - * @notice A public function to sweep accidental ERC-20 transfers to this contract. Tokens are sent to admin (timelock) - * @param token The address of the ERC-20 token to sweep - */ - function sweepToken(EIP20NonStandardInterface token) external override { - delegateToImplementation( - abi.encodeWithSignature("sweepToken(address)", token) - ); - } - - /*** Admin Functions ***/ - - /** - * @notice Begins transfer of admin rights. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer. - * @dev Admin function to begin change of admin. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer. - * @param newPendingAdmin New pending admin. - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setPendingAdmin(address payable newPendingAdmin) - external - override - returns (uint256) - { - bytes memory data = delegateToImplementation( - abi.encodeWithSignature( - "_setPendingAdmin(address)", - newPendingAdmin - ) - ); - return abi.decode(data, (uint256)); - } - - /** - * @notice Sets a new comptroller for the market - * @dev Admin function to set a new comptroller - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setComptroller(ComptrollerInterface newComptroller) - public - override - returns (uint256) - { - bytes memory data = delegateToImplementation( - abi.encodeWithSignature("_setComptroller(address)", newComptroller) - ); - return abi.decode(data, (uint256)); - } - - /** - * @notice accrues interest and sets a new reserve factor for the protocol using _setReserveFactorFresh - * @dev Admin function to accrue interest and set a new reserve factor - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setReserveFactor(uint256 newReserveFactorMantissa) - external - override - returns (uint256) - { - bytes memory data = delegateToImplementation( - abi.encodeWithSignature( - "_setReserveFactor(uint256)", - newReserveFactorMantissa - ) - ); - return abi.decode(data, (uint256)); - } - - /** - * @notice Accepts transfer of admin rights. msg.sender must be pendingAdmin - * @dev Admin function for pending admin to accept role and update admin - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _acceptAdmin() external override returns (uint256) { - bytes memory data = delegateToImplementation( - abi.encodeWithSignature("_acceptAdmin()") - ); - return abi.decode(data, (uint256)); - } - - /** - * @notice Accrues interest and adds reserves by transferring from admin - * @param addAmount Amount of reserves to add - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _addReserves(uint256 addAmount) - external - override - returns (uint256) - { - bytes memory data = delegateToImplementation( - abi.encodeWithSignature("_addReserves(uint256)", addAmount) - ); - return abi.decode(data, (uint256)); - } - - /** - * @notice Accrues interest and reduces reserves by transferring to admin - * @param reduceAmount Amount of reduction to reserves - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _reduceReserves(uint256 reduceAmount) - external - override - returns (uint256) - { - bytes memory data = delegateToImplementation( - abi.encodeWithSignature("_reduceReserves(uint256)", reduceAmount) - ); - return abi.decode(data, (uint256)); - } - - /** - * @notice Accrues interest and updates the interest rate model using _setInterestRateModelFresh - * @dev Admin function to accrue interest and update the interest rate model - * @param newInterestRateModel the new interest rate model to use - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setInterestRateModel(InterestRateModel newInterestRateModel) - public - override - returns (uint256) - { - bytes memory data = delegateToImplementation( - abi.encodeWithSignature( - "_setInterestRateModel(address)", - newInterestRateModel - ) - ); - return abi.decode(data, (uint256)); - } - - /** - * @notice Internal method to delegate execution to another contract - * @dev It returns to the external caller whatever the implementation returns or forwards reverts - * @param callee The contract to delegatecall - * @param data The raw data to delegatecall - * @return The returned bytes from the delegatecall - */ - function delegateTo(address callee, bytes memory data) - internal - returns (bytes memory) - { - (bool success, bytes memory returnData) = callee.delegatecall(data); - assembly { - if eq(success, 0) { - revert(add(returnData, 0x20), returndatasize()) - } - } - return returnData; - } - - /** - * @notice Delegates execution to the implementation contract - * @dev It returns to the external caller whatever the implementation returns or forwards reverts - * @param data The raw data to delegatecall - * @return The returned bytes from the delegatecall - */ - function delegateToImplementation(bytes memory data) - public - returns (bytes memory) - { - return delegateTo(implementation, data); - } - - /** - * @notice Delegates execution to an implementation contract - * @dev It returns to the external caller whatever the implementation returns or forwards reverts - * There are an additional 2 prefix uints from the wrapper returndata, which we ignore since we make an extra hop. - * @param data The raw data to delegatecall - * @return The returned bytes from the delegatecall - */ - function delegateToViewImplementation(bytes memory data) - public - view - returns (bytes memory) - { - (bool success, bytes memory returnData) = address(this).staticcall( - abi.encodeWithSignature("delegateToImplementation(bytes)", data) - ); - assembly { - if eq(success, 0) { - revert(add(returnData, 0x20), returndatasize()) - } - } - return abi.decode(returnData, (bytes)); - } - - /** - * @notice Delegates execution to an implementation contract - * @dev It returns to the external caller whatever the implementation returns or forwards reverts - */ - function internalFallback() public payable { - require( - msg.value == 0, - "CErc20Delegator:fallback: cannot send value to fallback" - ); - - // delegate all other functions to current implementation - (bool success, ) = implementation.delegatecall(msg.data); - - assembly { - let free_mem_ptr := mload(0x40) - returndatacopy(free_mem_ptr, 0, returndatasize()) - - switch success - case 0 { - revert(free_mem_ptr, returndatasize()) - } - default { - return(free_mem_ptr, returndatasize()) - } - } - } - - fallback() external payable { - internalFallback(); - } - - receive() external payable { - internalFallback(); - } -} diff --git a/flatten/CErc20Immutable.sol b/flatten/CErc20Immutable.sol deleted file mode 100644 index b137cf1..0000000 --- a/flatten/CErc20Immutable.sol +++ /dev/null @@ -1,4215 +0,0 @@ -// Dependency file: contracts/ComptrollerInterface.sol - -// SPDX-License-Identifier: UNLICENSED -// pragma solidity 0.8.6; - -abstract contract ComptrollerInterface { - /// @notice Indicator that this is a Comptroller contract (for inspection) - bool public constant isComptroller = true; - - /*** Assets You Are In ***/ - - function enterMarkets(address[] calldata cTokens) - external - virtual - returns (uint256[] memory); - - function exitMarket(address cToken) external virtual returns (uint256); - - /*** Policy Hooks ***/ - - function mintAllowed( - address cToken, - address minter, - uint256 mintAmount - ) external virtual returns (uint256); - - function mintVerify( - address cToken, - address minter, - uint256 mintAmount, - uint256 mintTokens - ) external virtual; - - function redeemAllowed( - address cToken, - address redeemer, - uint256 redeemTokens - ) external virtual returns (uint256); - - function redeemVerify( - address cToken, - address redeemer, - uint256 redeemAmount, - uint256 redeemTokens - ) external virtual; - - function borrowAllowed( - address cToken, - address borrower, - uint256 borrowAmount - ) external virtual returns (uint256); - - function borrowVerify( - address cToken, - address borrower, - uint256 borrowAmount - ) external virtual; - - function repayBorrowAllowed( - address cToken, - address payer, - address borrower, - uint256 repayAmount - ) external virtual returns (uint256); - - function repayBorrowVerify( - address cToken, - address payer, - address borrower, - uint256 repayAmount, - uint256 borrowerIndex - ) external virtual; - - function liquidateBorrowAllowed( - address cTokenBorrowed, - address cTokenCollateral, - address liquidator, - address borrower, - uint256 repayAmount - ) external virtual returns (uint256); - - function liquidateBorrowVerify( - address cTokenBorrowed, - address cTokenCollateral, - address liquidator, - address borrower, - uint256 repayAmount, - uint256 seizeTokens - ) external virtual; - - function seizeAllowed( - address cTokenCollateral, - address cTokenBorrowed, - address liquidator, - address borrower, - uint256 seizeTokens - ) external virtual returns (uint256); - - function seizeVerify( - address cTokenCollateral, - address cTokenBorrowed, - address liquidator, - address borrower, - uint256 seizeTokens - ) external virtual; - - function transferAllowed( - address cToken, - address src, - address dst, - uint256 transferTokens - ) external virtual returns (uint256); - - function transferVerify( - address cToken, - address src, - address dst, - uint256 transferTokens - ) external virtual; - - /*** Liquidity/Liquidation Calculations ***/ - - function liquidateCalculateSeizeTokens( - address cTokenBorrowed, - address cTokenCollateral, - uint256 repayAmount - ) external view virtual returns (uint256, uint256); -} - - -// Dependency file: contracts/CarefulMath.sol - -// pragma solidity 0.8.6; - -/** - * @title Careful Math - * @author tropykus - * @notice Derived from OpenZeppelin's SafeMath library - * https://github.com/OpenZeppelin/openzeppelin-solidity/blob/master/contracts/math/SafeMath.sol - */ -contract CarefulMath { - - /** - * @dev Possible error codes that we can return - */ - enum MathError { - NO_ERROR, - DIVISION_BY_ZERO, - INTEGER_OVERFLOW, - INTEGER_UNDERFLOW - } - - /** - * @dev Multiplies two numbers, returns an error on overflow. - */ - function mulUInt(uint a, uint b) internal pure returns (MathError, uint) { - if (a == 0) { - return (MathError.NO_ERROR, 0); - } - - uint c = a * b; - - if (c / a != b) { - return (MathError.INTEGER_OVERFLOW, 0); - } else { - return (MathError.NO_ERROR, c); - } - } - - /** - * @dev Integer division of two numbers, truncating the quotient. - */ - function divUInt(uint a, uint b) internal pure returns (MathError, uint) { - if (b == 0) { - return (MathError.DIVISION_BY_ZERO, 0); - } - - return (MathError.NO_ERROR, a / b); - } - - /** - * @dev Subtracts two numbers, returns an error on overflow (i.e. if subtrahend is greater than minuend). - */ - function subUInt(uint a, uint b) internal pure returns (MathError, uint) { - if (b <= a) { - return (MathError.NO_ERROR, a - b); - } else { - return (MathError.INTEGER_UNDERFLOW, 0); - } - } - - /** - * @dev Adds two numbers, returns an error on overflow. - */ - function addUInt(uint a, uint b) internal pure returns (MathError, uint) { - uint c = a + b; - - if (c >= a) { - return (MathError.NO_ERROR, c); - } else { - return (MathError.INTEGER_OVERFLOW, 0); - } - } - - /** - * @dev add a and b and then subtract c - */ - function addThenSubUInt(uint a, uint b, uint c) internal pure returns (MathError, uint) { - (MathError err0, uint sum) = addUInt(a, b); - - if (err0 != MathError.NO_ERROR) { - return (err0, 0); - } - - return subUInt(sum, c); - } -} - - -// Dependency file: contracts/ExponentialNoError.sol - -// pragma solidity 0.8.6; - -/** - * @title Exponential module for storing fixed-precision decimals - * @author tropykus - * @notice Exp is a struct which stores decimals with a fixed precision of 18 decimal places. - * Thus, if we wanted to store the 5.1, mantissa would store 5.1e18. That is: - * `Exp({mantissa: 5100000000000000000})`. - */ -contract ExponentialNoError { - uint constant expScale = 1e18; - uint constant doubleScale = 1e36; - uint constant halfExpScale = expScale/2; - uint constant mantissaOne = expScale; - - struct Exp { - uint mantissa; - } - - struct Double { - uint mantissa; - } - - /** - * @dev Truncates the given exp to a whole number value. - * For example, truncate(Exp{mantissa: 15 * expScale}) = 15 - */ - function truncate(Exp memory exp) pure internal returns (uint) { - // Note: We are not using careful math here as we're performing a division that cannot fail - return exp.mantissa / expScale; - } - - /** - * @dev Multiply an Exp by a scalar, then truncate to return an unsigned integer. - */ - function mul_ScalarTruncate(Exp memory a, uint scalar) pure internal returns (uint) { - Exp memory product = mul_(a, scalar); - return truncate(product); - } - - /** - * @dev Multiply an Exp by a scalar, truncate, then add an to an unsigned integer, returning an unsigned integer. - */ - function mul_ScalarTruncateAddUInt(Exp memory a, uint scalar, uint addend) pure internal returns (uint) { - Exp memory product = mul_(a, scalar); - return add_(truncate(product), addend); - } - - /** - * @dev Checks if first Exp is less than second Exp. - */ - function lessThanExp(Exp memory left, Exp memory right) pure internal returns (bool) { - return left.mantissa < right.mantissa; - } - - /** - * @dev Checks if left Exp <= right Exp. - */ - function lessThanOrEqualExp(Exp memory left, Exp memory right) pure internal returns (bool) { - return left.mantissa <= right.mantissa; - } - - /** - * @dev Checks if left Exp > right Exp. - */ - function greaterThanExp(Exp memory left, Exp memory right) pure internal returns (bool) { - return left.mantissa > right.mantissa; - } - - /** - * @dev returns true if Exp is exactly zero - */ - function isZeroExp(Exp memory value) pure internal returns (bool) { - return value.mantissa == 0; - } - - function safe224(uint n, string memory errorMessage) pure internal returns (uint224) { - require(n < 2**224, errorMessage); - return uint224(n); - } - - function safe32(uint n, string memory errorMessage) pure internal returns (uint32) { - require(n < 2**32, errorMessage); - return uint32(n); - } - - function add_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { - return Exp({mantissa: add_(a.mantissa, b.mantissa)}); - } - - function add_(Double memory a, Double memory b) pure internal returns (Double memory) { - return Double({mantissa: add_(a.mantissa, b.mantissa)}); - } - - function add_(uint a, uint b) pure internal returns (uint) { - return add_(a, b, "addition overflow"); - } - - function add_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { - uint c = a + b; - require(c >= a, errorMessage); - return c; - } - - function sub_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { - return Exp({mantissa: sub_(a.mantissa, b.mantissa)}); - } - - function sub_(Double memory a, Double memory b) pure internal returns (Double memory) { - return Double({mantissa: sub_(a.mantissa, b.mantissa)}); - } - - function sub_(uint a, uint b) pure internal returns (uint) { - return sub_(a, b, "subtraction underflow"); - } - - function sub_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { - require(b <= a, errorMessage); - return a - b; - } - - function mul_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { - return Exp({mantissa: mul_(a.mantissa, b.mantissa) / expScale}); - } - - function mul_(Exp memory a, uint b) pure internal returns (Exp memory) { - return Exp({mantissa: mul_(a.mantissa, b)}); - } - - function mul_(uint a, Exp memory b) pure internal returns (uint) { - return mul_(a, b.mantissa) / expScale; - } - - function mul_(Double memory a, Double memory b) pure internal returns (Double memory) { - return Double({mantissa: mul_(a.mantissa, b.mantissa) / doubleScale}); - } - - function mul_(Double memory a, uint b) pure internal returns (Double memory) { - return Double({mantissa: mul_(a.mantissa, b)}); - } - - function mul_(uint a, Double memory b) pure internal returns (uint) { - return mul_(a, b.mantissa) / doubleScale; - } - - function mul_(uint a, uint b) pure internal returns (uint) { - return mul_(a, b, "multiplication overflow"); - } - - function mul_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { - if (a == 0 || b == 0) { - return 0; - } - uint c = a * b; - require(c / a == b, errorMessage); - return c; - } - - function div_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { - return Exp({mantissa: div_(mul_(a.mantissa, expScale), b.mantissa)}); - } - - function div_(Exp memory a, uint b) pure internal returns (Exp memory) { - return Exp({mantissa: div_(a.mantissa, b)}); - } - - function div_(uint a, Exp memory b) pure internal returns (uint) { - return div_(mul_(a, expScale), b.mantissa); - } - - function div_(Double memory a, Double memory b) pure internal returns (Double memory) { - return Double({mantissa: div_(mul_(a.mantissa, doubleScale), b.mantissa)}); - } - - function div_(Double memory a, uint b) pure internal returns (Double memory) { - return Double({mantissa: div_(a.mantissa, b)}); - } - - function div_(uint a, Double memory b) pure internal returns (uint) { - return div_(mul_(a, doubleScale), b.mantissa); - } - - function div_(uint a, uint b) pure internal returns (uint) { - return div_(a, b, "divide by zero"); - } - - function div_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { - require(b > 0, errorMessage); - return a / b; - } - - function fraction(uint a, uint b) pure internal returns (Double memory) { - return Double({mantissa: div_(mul_(a, doubleScale), b)}); - } -} - - -// Dependency file: contracts/Exponential.sol - -// pragma solidity 0.8.6; - -// import "contracts/CarefulMath.sol"; -// import "contracts/ExponentialNoError.sol"; - -/** - * @title Exponential module for storing fixed-precision decimals - * @author tropykus - * @dev Legacy contract for compatibility reasons with existing contracts that still use MathError - * @notice Exp is a struct which stores decimals with a fixed precision of 18 decimal places. - * Thus, if we wanted to store the 5.1, mantissa would store 5.1e18. That is: - * `Exp({mantissa: 5100000000000000000})`. - */ -contract Exponential is CarefulMath, ExponentialNoError { - /** - * @dev Creates an exponential from numerator and denominator values. - * Note: Returns an error if (`num` * 10e18) > MAX_INT, - * or if `denom` is zero. - */ - function getExp(uint num, uint denom) internal pure returns (MathError, Exp memory) { - (MathError err0, uint scaledNumerator) = mulUInt(num, expScale); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - - (MathError err1, uint rational) = divUInt(scaledNumerator, denom); - if (err1 != MathError.NO_ERROR) { - return (err1, Exp({mantissa: 0})); - } - - return (MathError.NO_ERROR, Exp({mantissa: rational})); - } - - /** - * @dev Adds two exponentials, returning a new exponential. - */ - function addExp(Exp memory a, Exp memory b) internal pure returns (MathError, Exp memory) { - (MathError error, uint result) = addUInt(a.mantissa, b.mantissa); - - return (error, Exp({mantissa: result})); - } - - /** - * @dev Subtracts two exponentials, returning a new exponential. - */ - function subExp(Exp memory a, Exp memory b) internal pure returns (MathError, Exp memory) { - (MathError error, uint result) = subUInt(a.mantissa, b.mantissa); - - return (error, Exp({mantissa: result})); - } - - /** - * @dev Multiply an Exp by a scalar, returning a new Exp. - */ - function mulScalar(Exp memory a, uint scalar) internal pure returns (MathError, Exp memory) { - (MathError err0, uint scaledMantissa) = mulUInt(a.mantissa, scalar); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - - return (MathError.NO_ERROR, Exp({mantissa: scaledMantissa})); - } - - /** - * @dev Multiply an Exp by a scalar, then truncate to return an unsigned integer. - */ - function mulScalarTruncate(Exp memory a, uint scalar) internal pure returns (MathError, uint) { - (MathError err, Exp memory product) = mulScalar(a, scalar); - if (err != MathError.NO_ERROR) { - return (err, 0); - } - - return (MathError.NO_ERROR, truncate(product)); - } - - /** - * @dev Multiply an Exp by a scalar, truncate, then add an to an unsigned integer, returning an unsigned integer. - */ - function mulScalarTruncateAddUInt(Exp memory a, uint scalar, uint addend) internal pure returns (MathError, uint) { - (MathError err, Exp memory product) = mulScalar(a, scalar); - if (err != MathError.NO_ERROR) { - return (err, 0); - } - - return addUInt(truncate(product), addend); - } - - /** - * @dev Divide an Exp by a scalar, returning a new Exp. - */ - function divScalar(Exp memory a, uint scalar) internal pure returns (MathError, Exp memory) { - (MathError err0, uint descaledMantissa) = divUInt(a.mantissa, scalar); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - - return (MathError.NO_ERROR, Exp({mantissa: descaledMantissa})); - } - - /** - * @dev Divide a scalar by an Exp, returning a new Exp. - */ - function divScalarByExp(uint scalar, Exp memory divisor) internal pure returns (MathError, Exp memory) { - /* - We are doing this as: - getExp(mulUInt(expScale, scalar), divisor.mantissa) - - How it works: - Exp = a / b; - Scalar = s; - `s / (a / b)` = `b * s / a` and since for an Exp `a = mantissa, b = expScale` - */ - (MathError err0, uint numerator) = mulUInt(expScale, scalar); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - return getExp(numerator, divisor.mantissa); - } - - /** - * @dev Divide a scalar by an Exp, then truncate to return an unsigned integer. - */ - function divScalarByExpTruncate(uint scalar, Exp memory divisor) internal pure returns (MathError, uint) { - (MathError err, Exp memory fraction) = divScalarByExp(scalar, divisor); - if (err != MathError.NO_ERROR) { - return (err, 0); - } - - return (MathError.NO_ERROR, truncate(fraction)); - } - - /** - * @dev Multiplies two exponentials, returning a new exponential. - */ - function mulExp(Exp memory a, Exp memory b) internal pure returns (MathError, Exp memory) { - - (MathError err0, uint doubleScaledProduct) = mulUInt(a.mantissa, b.mantissa); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - - // We add half the scale before dividing so that we get rounding instead of truncation. - // See "Listing 6" and text above it at https://accu.org/index.php/journals/1717 - // Without this change, a result like 6.6...e-19 will be truncated to 0 instead of being rounded to 1e-18. - (MathError err1, uint doubleScaledProductWithHalfScale) = addUInt(halfExpScale, doubleScaledProduct); - if (err1 != MathError.NO_ERROR) { - return (err1, Exp({mantissa: 0})); - } - - (MathError err2, uint product) = divUInt(doubleScaledProductWithHalfScale, expScale); - // The only error `div` can return is MathError.DIVISION_BY_ZERO but we control `expScale` and it is not zero. - assert(err2 == MathError.NO_ERROR); - - return (MathError.NO_ERROR, Exp({mantissa: product})); - } - - /** - * @dev Multiplies two exponentials given their mantissas, returning a new exponential. - */ - function mulExp(uint a, uint b) internal pure returns (MathError, Exp memory) { - return mulExp(Exp({mantissa: a}), Exp({mantissa: b})); - } - - /** - * @dev Multiplies three exponentials, returning a new exponential. - */ - function mulExp3(Exp memory a, Exp memory b, Exp memory c) internal pure returns (MathError, Exp memory) { - (MathError err, Exp memory ab) = mulExp(a, b); - if (err != MathError.NO_ERROR) { - return (err, ab); - } - return mulExp(ab, c); - } - - /** - * @dev Divides two exponentials, returning a new exponential. - * (a/scale) / (b/scale) = (a/scale) * (scale/b) = a/b, - * which we can scale as an Exp by calling getExp(a.mantissa, b.mantissa) - */ - function divExp(Exp memory a, Exp memory b) internal pure returns (MathError, Exp memory) { - return getExp(a.mantissa, b.mantissa); - } -} - - -// Dependency file: contracts/SafeMath.sol - -// pragma solidity 0.8.6; - -// From https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/math/Math.sol -// Subject to the MIT license. - -/** - * @dev Wrappers over Solidity's arithmetic operations with added overflow - * checks. - * - * Arithmetic operations in Solidity wrap on overflow. This can easily result - * in bugs, because programmers usually assume that an overflow raises an - * error, which is the standard behavior in high level programming languages. - * `SafeMath` restores this intuition by reverting the transaction when an - * operation overflows. - * - * Using this library instead of the unchecked operations eliminates an entire - * class of bugs, so it's recommended to use it always. - */ -library SafeMath { - /** - * @dev Returns the addition of two unsigned integers, reverting on overflow. - * - * Counterpart to Solidity's `+` operator. - * - * Requirements: - * - Addition cannot overflow. - */ - function add(uint256 a, uint256 b) internal pure returns (uint256) { - uint256 c = a + b; - require(c >= a, "SafeMath: addition overflow"); - - return c; - } - - /** - * @dev Returns the addition of two unsigned integers, reverting with custom message on overflow. - * - * Counterpart to Solidity's `+` operator. - * - * Requirements: - * - Addition cannot overflow. - */ - function add(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - uint256 c = a + b; - require(c >= a, errorMessage); - - return c; - } - - /** - * @dev Returns the subtraction of two unsigned integers, reverting on underflow (when the result is negative). - * - * Counterpart to Solidity's `-` operator. - * - * Requirements: - * - Subtraction cannot underflow. - */ - function sub(uint256 a, uint256 b) internal pure returns (uint256) { - return sub(a, b, "SafeMath: subtraction underflow"); - } - - /** - * @dev Returns the subtraction of two unsigned integers, reverting with custom message on underflow (when the result is negative). - * - * Counterpart to Solidity's `-` operator. - * - * Requirements: - * - Subtraction cannot underflow. - */ - function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - require(b <= a, errorMessage); - uint256 c = a - b; - - return c; - } - - /** - * @dev Returns the multiplication of two unsigned integers, reverting on overflow. - * - * Counterpart to Solidity's `*` operator. - * - * Requirements: - * - Multiplication cannot overflow. - */ - function mul(uint256 a, uint256 b) internal pure returns (uint256) { - // Gas optimization: this is cheaper than requiring 'a' not being zero, but the - // benefit is lost if 'b' is also tested. - // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 - if (a == 0) { - return 0; - } - - uint256 c = a * b; - require(c / a == b, "SafeMath: multiplication overflow"); - - return c; - } - - /** - * @dev Returns the multiplication of two unsigned integers, reverting on overflow. - * - * Counterpart to Solidity's `*` operator. - * - * Requirements: - * - Multiplication cannot overflow. - */ - function mul(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - // Gas optimization: this is cheaper than requiring 'a' not being zero, but the - // benefit is lost if 'b' is also tested. - // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 - if (a == 0) { - return 0; - } - - uint256 c = a * b; - require(c / a == b, errorMessage); - - return c; - } - - /** - * @dev Returns the integer division of two unsigned integers. - * Reverts on division by zero. The result is rounded towards zero. - * - * Counterpart to Solidity's `/` operator. Note: this function uses a - * `revert` opcode (which leaves remaining gas untouched) while Solidity - * uses an invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function div(uint256 a, uint256 b) internal pure returns (uint256) { - return div(a, b, "SafeMath: division by zero"); - } - - /** - * @dev Returns the integer division of two unsigned integers. - * Reverts with custom message on division by zero. The result is rounded towards zero. - * - * Counterpart to Solidity's `/` operator. Note: this function uses a - * `revert` opcode (which leaves remaining gas untouched) while Solidity - * uses an invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - // Solidity only automatically asserts when dividing by 0 - require(b > 0, errorMessage); - uint256 c = a / b; - // assert(a == b * c + a % b); // There is no case in which this doesn't hold - - return c; - } - - /** - * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), - * Reverts when dividing by zero. - * - * Counterpart to Solidity's `%` operator. This function uses a `revert` - * opcode (which leaves remaining gas untouched) while Solidity uses an - * invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function mod(uint256 a, uint256 b) internal pure returns (uint256) { - return mod(a, b, "SafeMath: modulo by zero"); - } - - /** - * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), - * Reverts with custom message when dividing by zero. - * - * Counterpart to Solidity's `%` operator. This function uses a `revert` - * opcode (which leaves remaining gas untouched) while Solidity uses an - * invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - require(b != 0, errorMessage); - return a % b; - } -} - - -// Dependency file: contracts/InterestRateModel.sol - -// pragma solidity 0.8.6; - -// import "contracts/Exponential.sol"; -// import "contracts/SafeMath.sol"; - -/** - * @title tropykus InterestRateModel Interface - * @author tropykus - */ -abstract contract InterestRateModel is Exponential { - using SafeMath for uint256; - - /// @notice Indicator that this is an InterestRateModel contract (for inspection) - bool public constant isInterestRateModel = true; - bool public isTropykusInterestRateModel; - - /** - * @notice The approximate number of blocks per year that is assumed by the interest rate model - */ - uint256 public constant blocksPerYear = 1051200; - - /** - * @notice Calculates the utilization rate of the market: `borrows / (cash + borrows - reserves)` - * @param cash The amount of cash in the market - * @param borrows The amount of borrows in the market - * @param reserves The amount of reserves in the market (currently unused) - * @return The utilization rate as a mantissa between [0, 1e18] - */ - function utilizationRate( - uint256 cash, - uint256 borrows, - uint256 reserves - ) public pure virtual returns (uint256) { - // Utilization rate is 0 when there are no borrows - if (borrows == 0) { - return 0; - } - - return borrows.mul(1e18).div(cash.add(borrows).sub(reserves)); - } - - /** - * @notice Calculates the current borrow interest rate per block - * @param cash The total amount of cash the market has - * @param borrows The total amount of borrows the market has outstanding - * @param reserves The total amnount of reserves the market has - * @return The borrow rate per block (as a percentage, and scaled by 1e18) - */ - function getBorrowRate( - uint256 cash, - uint256 borrows, - uint256 reserves - ) external view virtual returns (uint256); - - /** - * @notice Calculates the current supply interest rate per block - * @param cash The total amount of cash the market has - * @param borrows The total amount of borrows the market has outstanding - * @param reserves The total amnount of reserves the market has - * @param reserveFactorMantissa The current reserve factor the market has - * @return The supply rate per block (as a percentage, and scaled by 1e18) - */ - function getSupplyRate( - uint256 cash, - uint256 borrows, - uint256 reserves, - uint256 reserveFactorMantissa - ) external view virtual returns (uint256); - - function getExchangeRate( - uint256 _totalCash, - uint256 _totalBorrows, - uint256 _totalReserves, - uint256 _totalSupply - ) public pure returns (MathError, uint256) { - /* - * exchangeRate = (totalCash + totalBorrows - totalReserves) / totalSupply - */ - Exp memory exchangeRate; - MathError mathErr; - uint256 cashPlusBorrowsMinusReserves; - (mathErr, cashPlusBorrowsMinusReserves) = addThenSubUInt( - _totalCash, - _totalBorrows, - _totalReserves - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - (mathErr, exchangeRate) = getExp( - cashPlusBorrowsMinusReserves, - _totalSupply - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - - return (MathError.NO_ERROR, exchangeRate.mantissa); - } - - function isAboveOptimal( - uint256 cash, - uint256 borrows, - uint256 reserves - ) public view virtual returns (bool) { - cash; - borrows; - reserves; - return false; - } -} - - -// Dependency file: contracts/EIP20NonStandardInterface.sol - -// pragma solidity 0.8.6; - -/** - * @title EIP20NonStandardInterface - * @dev Version of ERC20 with no return values for `transfer` and `transferFrom` - * See https://medium.com/coinmonks/missing-return-value-bug-at-least-130-tokens-affected-d67bf08521ca - */ -interface EIP20NonStandardInterface { - /** - * @notice Get the total number of tokens in circulation - * @return The supply of tokens - */ - function totalSupply() external view returns (uint256); - - /** - * @notice Gets the balance of the specified address - * @param owner The address from which the balance will be retrieved - * @return balance The balance - */ - function balanceOf(address owner) external view returns (uint256 balance); - - /// - /// !!!!!!!!!!!!!! - /// !!! NOTICE !!! `transfer` does not return a value, in violation of the ERC-20 specification - /// !!!!!!!!!!!!!! - /// - - /** - * @notice Transfer `amount` tokens from `msg.sender` to `dst` - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - */ - function transfer(address dst, uint256 amount) external; - - /// - /// !!!!!!!!!!!!!! - /// !!! NOTICE !!! `transferFrom` does not return a value, in violation of the ERC-20 specification - /// !!!!!!!!!!!!!! - /// - - /** - * @notice Transfer `amount` tokens from `src` to `dst` - * @param src The address of the source account - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - */ - function transferFrom( - address src, - address dst, - uint256 amount - ) external; - - /** - * @notice Approve `spender` to transfer up to `amount` from `src` - * @dev This will overwrite the approval amount for `spender` - * and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve) - * @param spender The address of the account which may transfer tokens - * @param amount The number of tokens that are approved - * @return success Whether or not the approval succeeded - */ - function approve(address spender, uint256 amount) - external - returns (bool success); - - /** - * @notice Get the current allowance from `owner` for `spender` - * @param owner The address of the account which owns the tokens to be spent - * @param spender The address of the account which may transfer tokens - * @return remaining The number of tokens allowed to be spent - */ - function allowance(address owner, address spender) - external - view - returns (uint256 remaining); - - event Transfer(address indexed from, address indexed to, uint256 amount); - event Approval( - address indexed owner, - address indexed spender, - uint256 amount - ); -} - - -// Dependency file: contracts/CTokenInterfaces.sol - -// pragma solidity 0.8.6; - -// import "contracts/ComptrollerInterface.sol"; -// import "contracts/InterestRateModel.sol"; -// import "contracts/EIP20NonStandardInterface.sol"; - -contract CTokenStorage { - /** - * @dev Guard variable for re-entrancy checks - */ - bool internal _notEntered; - - /** - * @notice EIP-20 token name for this token - */ - string public name; - - /** - * @notice EIP-20 token symbol for this token - */ - string public symbol; - - /** - * @notice EIP-20 token decimals for this token - */ - uint8 public decimals; - - /** - * @notice Maximum borrow rate that can ever be applied (.0005% / block) - */ - - uint256 internal constant borrowRateMaxMantissa = 0.0005e16; - - /** - * @notice Maximum fraction of interest that can be set aside for reserves - */ - uint256 internal constant reserveFactorMaxMantissa = 1e18; - - /** - * @notice Administrator for this contract - */ - address payable public admin; - - /** - * @notice Pending administrator for this contract - */ - address payable public pendingAdmin; - - /** - * @notice Contract which oversees inter-cToken operations - */ - ComptrollerInterface public comptroller; - - /** - * @notice Model which tells what the current interest rate should be - */ - InterestRateModel public interestRateModel; - - /** - * @notice Initial exchange rate used when minting the first CTokens (used when totalSupply = 0) - */ - uint256 public initialExchangeRateMantissa; - - /** - * @notice Fraction of interest currently set aside for reserves - */ - uint256 public reserveFactorMantissa; - - /** - * @notice Block number that interest was last accrued at - */ - uint256 public accrualBlockNumber; - - /** - * @notice Accumulator of the total earned interest rate since the opening of the market - */ - uint256 public borrowIndex; - - /** - * @notice Total amount of outstanding borrows of the underlying in this market - */ - uint256 public totalBorrows; - - /** - * @notice Total amount of reserves of the underlying held in this market - */ - uint256 public totalReserves; - - /** - * @notice Total number of tokens in circulation - */ - uint256 public totalSupply; - - uint256 public subsidyFund; - - struct SupplySnapshot { - uint256 tokens; - uint256 underlyingAmount; - uint256 suppliedAt; - uint256 promisedSupplyRate; - } - - /** - * @notice Official record of token balances for each account - */ - mapping(address => SupplySnapshot) internal accountTokens; - - /** - * @notice Approved token transfer amounts on behalf of others - */ - mapping(address => mapping(address => uint256)) internal transferAllowances; - - /** - * @notice Container for borrow balance information - * @member principal Total balance (with accrued interest), after applying the most recent balance-changing action - * @member interestIndex Global borrowIndex as of the most recent balance-changing action - */ - struct BorrowSnapshot { - uint256 principal; - uint256 interestIndex; - } - - /** - * @notice Mapping of account addresses to outstanding borrow balances - */ - mapping(address => BorrowSnapshot) internal accountBorrows; -} - -abstract contract CTokenInterface is CTokenStorage { - /** - * @notice Indicator that this is a CToken contract (for inspection) - */ - bool public constant isCToken = true; - - /*** Market Events ***/ - - /** - * @notice Event emitted when interest is accrued - */ - event AccrueInterest( - uint256 cashPrior, - uint256 interestAccumulated, - uint256 borrowIndex, - uint256 totalBorrows - ); - - /** - * @notice Event emitted when tokens are minted - */ - event Mint(address indexed minter, uint256 mintAmount, uint256 mintTokens); - - /** - * @notice Event emitted when tokens are redeemed - */ - event Redeem( - address indexed redeemer, - uint256 redeemAmount, - uint256 redeemTokens - ); - - /** - * @notice Event emitted when underlying is borrowed - */ - event Borrow( - address indexed borrower, - uint256 borrowAmount, - uint256 accountBorrows, - uint256 totalBorrows - ); - - /** - * @notice Event emitted when a borrow is repaid - */ - event RepayBorrow( - address indexed payer, - address indexed borrower, - uint256 repayAmount, - uint256 accountBorrows, - uint256 totalBorrows - ); - - /** - * @notice Event emitted when a borrow is liquidated - */ - event LiquidateBorrow( - address indexed liquidator, - address indexed borrower, - uint256 repayAmount, - address indexed cTokenCollateral, - uint256 seizeTokens - ); - - /*** Admin Events ***/ - - /** - * @notice Event emitted when pendingAdmin is changed - */ - event NewPendingAdmin(address oldPendingAdmin, address newPendingAdmin); - - /** - * @notice Event emitted when pendingAdmin is accepted, which means admin is updated - */ - event NewAdmin(address oldAdmin, address newAdmin); - - /** - * @notice Event emitted when comptroller is changed - */ - event NewComptroller( - ComptrollerInterface oldComptroller, - ComptrollerInterface newComptroller - ); - - /** - * @notice Event emitted when interestRateModel is changed - */ - event NewMarketInterestRateModel( - InterestRateModel oldInterestRateModel, - InterestRateModel newInterestRateModel - ); - - /** - * @notice Event emitted when the reserve factor is changed - */ - event NewReserveFactor( - uint256 oldReserveFactorMantissa, - uint256 newReserveFactorMantissa - ); - - /** - * @notice Event emitted when the reserves are added - */ - event ReservesAdded( - address benefactor, - uint256 addAmount, - uint256 newTotalReserves - ); - - event SubsidyAdded( - address benefactor, - uint256 addAmount, - uint256 newSubsidyFund - ); - - /** - * @notice Event emitted when the reserves are reduced - */ - event ReservesReduced( - address admin, - uint256 reduceAmount, - uint256 newTotalReserves - ); - - /** - * @notice EIP20 Transfer event - */ - event Transfer(address indexed from, address indexed to, uint256 amount); - - /** - * @notice EIP20 Approval event - */ - event Approval( - address indexed owner, - address indexed spender, - uint256 amount - ); - - /** - * @notice Failure event - */ - event CTokenStorageFailure(uint256 error, uint256 info, uint256 detail); - - /*** User Interface ***/ - - function transfer(address dst, uint256 amount) - external - virtual - returns (bool); - - function transferFrom( - address src, - address dst, - uint256 amount - ) external virtual returns (bool); - - function approve(address spender, uint256 amount) - external - virtual - returns (bool); - - function allowance(address owner, address spender) - external - view - virtual - returns (uint256); - - function balanceOf(address owner) external view virtual returns (uint256); - - function balanceOfUnderlying(address owner) - external - virtual - returns (uint256); - - function getAccountSnapshot(address account) - external - view - virtual - returns ( - uint256, - uint256, - uint256, - uint256 - ); - - function borrowRatePerBlock() external view virtual returns (uint256); - - function supplyRatePerBlock() external view virtual returns (uint256); - - function totalBorrowsCurrent() external virtual returns (uint256); - - function borrowBalanceCurrent(address account) - external - virtual - returns (uint256); - - function borrowBalanceStored(address account) - public - view - virtual - returns (uint256); - - function exchangeRateCurrent() public virtual returns (uint256); - - function exchangeRateStored() public view virtual returns (uint256); - - function getCash() external view virtual returns (uint256); - - function accrueInterest() public virtual returns (uint256); - - function seize( - address liquidator, - address borrower, - uint256 seizeTokens - ) external virtual returns (uint256); - - /*** Admin Functions ***/ - - function _setPendingAdmin(address payable newPendingAdmin) - external - virtual - returns (uint256); - - function _acceptAdmin() external virtual returns (uint256); - - function _setComptroller(ComptrollerInterface newComptroller) - public - virtual - returns (uint256); - - function _setReserveFactor(uint256 newReserveFactorMantissa) - external - virtual - returns (uint256); - - function _reduceReserves(uint256 reduceAmount) - external - virtual - returns (uint256); - - function _setInterestRateModel(InterestRateModel newInterestRateModel) - public - virtual - returns (uint256); -} - -contract CErc20Storage { - /** - * @notice Underlying asset for this CToken - */ - address public underlying; -} - -abstract contract CErc20Interface is CErc20Storage { - /*** User Interface ***/ - - function mint(uint256 mintAmount) external virtual returns (uint256); - - function redeem(uint256 redeemAmount) - external - virtual - returns (uint256); - - function borrow(uint256 borrowAmount) external virtual returns (uint256); - - function repayBorrow(uint256 repayAmount) - external - virtual - returns (uint256); - - function liquidateBorrow( - address borrower, - uint256 repayAmount, - CTokenInterface cTokenCollateral - ) external virtual returns (uint256); - - function sweepToken(EIP20NonStandardInterface token) external virtual; - - /*** Admin Functions ***/ - - function _addReserves(uint256 addAmount) external virtual returns (uint256); -} - -contract CDelegationStorage { - /** - * @notice Implementation address for this contract - */ - address public implementation; -} - -abstract contract CDelegatorInterface is CDelegationStorage { - /** - * @notice Emitted when implementation is changed - */ - event NewImplementation( - address oldImplementation, - address newImplementation - ); - - /** - * @notice Called by the admin to update the implementation of the delegator - * @param implementation_ The address of the new implementation for delegation - * @param allowResign Flag to indicate whether to call _resignImplementation on the old implementation - * @param becomeImplementationData The encoded bytes data to be passed to _becomeImplementation - */ - function _setImplementation( - address implementation_, - bool allowResign, - bytes memory becomeImplementationData - ) public virtual; -} - -abstract contract CDelegateInterface is CDelegationStorage { - /** - * @notice Called by the delegator on a delegate to initialize it for duty - * @dev Should revert if any issues arise which make it unfit for delegation - * @param data The encoded bytes data for any initialization - */ - function _becomeImplementation(bytes memory data) public virtual; - - /** - * @notice Called by the delegator on a delegate to forfeit its responsibility - */ - function _resignImplementation() public virtual; -} - - -// Dependency file: contracts/ErrorReporter.sol - -// pragma solidity 0.8.6; - -contract ComptrollerErrorReporter { - enum Error { - NO_ERROR, - UNAUTHORIZED, - COMPTROLLER_MISMATCH, - INSUFFICIENT_SHORTFALL, - INSUFFICIENT_LIQUIDITY, - INVALID_CLOSE_FACTOR, - INVALID_COLLATERAL_FACTOR, - INVALID_LIQUIDATION_INCENTIVE, - MARKET_NOT_ENTERED, // no longer possible - MARKET_NOT_LISTED, - MARKET_ALREADY_LISTED, - MATH_ERROR, - NONZERO_BORROW_BALANCE, - PRICE_ERROR, - REJECTION, - SNAPSHOT_ERROR, - TOO_MANY_ASSETS, - TOO_MUCH_REPAY - } - - enum FailureInfo { - ACCEPT_ADMIN_PENDING_ADMIN_CHECK, - ACCEPT_PENDING_IMPLEMENTATION_ADDRESS_CHECK, - EXIT_MARKET_BALANCE_OWED, - EXIT_MARKET_REJECTION, - SET_CLOSE_FACTOR_OWNER_CHECK, - SET_CLOSE_FACTOR_VALIDATION, - SET_COLLATERAL_FACTOR_OWNER_CHECK, - SET_COLLATERAL_FACTOR_NO_EXISTS, - SET_COLLATERAL_FACTOR_VALIDATION, - SET_COLLATERAL_FACTOR_WITHOUT_PRICE, - SET_IMPLEMENTATION_OWNER_CHECK, - SET_LIQUIDATION_INCENTIVE_OWNER_CHECK, - SET_LIQUIDATION_INCENTIVE_VALIDATION, - SET_MAX_ASSETS_OWNER_CHECK, - SET_PENDING_ADMIN_OWNER_CHECK, - SET_PENDING_IMPLEMENTATION_OWNER_CHECK, - SET_PRICE_ORACLE_OWNER_CHECK, - SUPPORT_MARKET_EXISTS, - SUPPORT_MARKET_OWNER_CHECK, - SET_PAUSE_GUARDIAN_OWNER_CHECK - } - - /** - * @dev `error` corresponds to enum Error; `info` corresponds to enum FailureInfo, and `detail` is an arbitrary - * contract-specific code that enables us to report opaque error codes from upgradeable contracts. - **/ - event Failure(uint256 error, uint256 info, uint256 detail); - - /** - * @dev use this when reporting a known error from the money market or a non-upgradeable collaborator - */ - function fail(Error err, FailureInfo info) internal returns (uint256) { - emit Failure(uint256(err), uint256(info), 0); - - return uint256(err); - } - - /** - * @dev use this when reporting an opaque error from an upgradeable collaborator contract - */ - function failOpaque( - Error err, - FailureInfo info, - uint256 opaqueError - ) internal returns (uint256) { - emit Failure(uint256(err), uint256(info), opaqueError); - - return uint256(err); - } -} - -contract TokenErrorReporter { - enum Error { - NO_ERROR, - UNAUTHORIZED, - BAD_INPUT, - COMPTROLLER_REJECTION, - COMPTROLLER_CALCULATION_ERROR, - INTEREST_RATE_MODEL_ERROR, - INVALID_ACCOUNT_PAIR, - INVALID_CLOSE_AMOUNT_REQUESTED, - INVALID_COLLATERAL_FACTOR, - MATH_ERROR, - MARKET_NOT_FRESH, - MARKET_NOT_LISTED, - TOKEN_INSUFFICIENT_ALLOWANCE, - TOKEN_INSUFFICIENT_BALANCE, - TOKEN_INSUFFICIENT_CASH, - TOKEN_TRANSFER_IN_FAILED, - TOKEN_TRANSFER_OUT_FAILED - } - - /* - * Note: FailureInfo (but not Error) is kept in alphabetical order - * This is because FailureInfo grows significantly faster, and - * the order of Error has some meaning, while the order of FailureInfo - * is entirely arbitrary. - */ - enum FailureInfo { - ACCEPT_ADMIN_PENDING_ADMIN_CHECK, - ACCRUE_INTEREST_ACCUMULATED_INTEREST_CALCULATION_FAILED, - ACCRUE_INTEREST_BORROW_RATE_CALCULATION_FAILED, - ACCRUE_INTEREST_NEW_BORROW_INDEX_CALCULATION_FAILED, - ACCRUE_INTEREST_NEW_TOTAL_BORROWS_CALCULATION_FAILED, - ACCRUE_INTEREST_NEW_TOTAL_RESERVES_CALCULATION_FAILED, - ACCRUE_INTEREST_SIMPLE_INTEREST_FACTOR_CALCULATION_FAILED, - BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED, - BORROW_ACCRUE_INTEREST_FAILED, - BORROW_CASH_NOT_AVAILABLE, - BORROW_FRESHNESS_CHECK, - BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED, - BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED, - BORROW_MARKET_NOT_LISTED, - BORROW_COMPTROLLER_REJECTION, - LIQUIDATE_ACCRUE_BORROW_INTEREST_FAILED, - LIQUIDATE_ACCRUE_COLLATERAL_INTEREST_FAILED, - LIQUIDATE_COLLATERAL_FRESHNESS_CHECK, - LIQUIDATE_COMPTROLLER_REJECTION, - LIQUIDATE_COMPTROLLER_CALCULATE_AMOUNT_SEIZE_FAILED, - LIQUIDATE_CLOSE_AMOUNT_IS_UINT_MAX, - LIQUIDATE_CLOSE_AMOUNT_IS_ZERO, - LIQUIDATE_FRESHNESS_CHECK, - LIQUIDATE_LIQUIDATOR_IS_BORROWER, - LIQUIDATE_REPAY_BORROW_FRESH_FAILED, - LIQUIDATE_SEIZE_BALANCE_INCREMENT_FAILED, - LIQUIDATE_SEIZE_BALANCE_DECREMENT_FAILED, - LIQUIDATE_SEIZE_COMPTROLLER_REJECTION, - LIQUIDATE_SEIZE_LIQUIDATOR_IS_BORROWER, - LIQUIDATE_SEIZE_TOO_MUCH, - MINT_ACCRUE_INTEREST_FAILED, - MINT_COMPTROLLER_REJECTION, - MINT_EXCHANGE_CALCULATION_FAILED, - MINT_EXCHANGE_RATE_READ_FAILED, - MINT_FRESHNESS_CHECK, - MINT_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED, - MINT_NEW_TOTAL_SUPPLY_CALCULATION_FAILED, - MINT_TRANSFER_IN_FAILED, - MINT_TRANSFER_IN_NOT_POSSIBLE, - REDEEM_ACCRUE_INTEREST_FAILED, - REDEEM_COMPTROLLER_REJECTION, - REDEEM_EXCHANGE_TOKENS_CALCULATION_FAILED, - REDEEM_EXCHANGE_AMOUNT_CALCULATION_FAILED, - REDEEM_EXCHANGE_RATE_READ_FAILED, - REDEEM_FRESHNESS_CHECK, - REDEEM_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED, - REDEEM_NEW_TOTAL_SUPPLY_CALCULATION_FAILED, - REDEEM_TRANSFER_OUT_NOT_POSSIBLE, - REDUCE_RESERVES_ACCRUE_INTEREST_FAILED, - REDUCE_RESERVES_ADMIN_CHECK, - REDUCE_RESERVES_CASH_NOT_AVAILABLE, - REDUCE_RESERVES_FRESH_CHECK, - REDUCE_RESERVES_VALIDATION, - REPAY_BEHALF_ACCRUE_INTEREST_FAILED, - REPAY_BORROW_ACCRUE_INTEREST_FAILED, - REPAY_BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED, - REPAY_BORROW_COMPTROLLER_REJECTION, - REPAY_BORROW_FRESHNESS_CHECK, - REPAY_BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED, - REPAY_BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED, - REPAY_BORROW_TRANSFER_IN_NOT_POSSIBLE, - SET_COLLATERAL_FACTOR_OWNER_CHECK, - SET_COLLATERAL_FACTOR_VALIDATION, - SET_COMPTROLLER_OWNER_CHECK, - SET_INTEREST_RATE_MODEL_ACCRUE_INTEREST_FAILED, - SET_INTEREST_RATE_MODEL_FRESH_CHECK, - SET_INTEREST_RATE_MODEL_OWNER_CHECK, - SET_MAX_ASSETS_OWNER_CHECK, - SET_ORACLE_MARKET_NOT_LISTED, - SET_PENDING_ADMIN_OWNER_CHECK, - SET_RESERVE_FACTOR_ACCRUE_INTEREST_FAILED, - SET_RESERVE_FACTOR_ADMIN_CHECK, - SET_RESERVE_FACTOR_FRESH_CHECK, - SET_RESERVE_FACTOR_BOUNDS_CHECK, - TRANSFER_COMPTROLLER_REJECTION, - TRANSFER_NOT_ALLOWED, - TRANSFER_NOT_ENOUGH, - TRANSFER_TOO_MUCH, - ADD_RESERVES_ACCRUE_INTEREST_FAILED, - ADD_RESERVES_FRESH_CHECK, - ADD_RESERVES_TRANSFER_IN_NOT_POSSIBLE, - ADD_SUBSIDY_FUND_FAILED, - ADD_SUBSIDY_FUND_FRESH_CHECK - } - - /** - * @dev `error` corresponds to enum Error; `info` corresponds to enum FailureInfo, and `detail` is an arbitrary - * contract-specific code that enables us to report opaque error codes from upgradeable contracts. - **/ - event TokenFailure(uint256 error, uint256 info, uint256 detail); - - /** - * @dev use this when reporting a known error from the money market or a non-upgradeable collaborator - */ - function fail(Error err, FailureInfo info) internal returns (uint256) { - emit TokenFailure(uint256(err), uint256(info), 0); - - return uint256(err); - } - - /** - * @dev use this when reporting an opaque error from an upgradeable collaborator contract - */ - function failOpaque( - Error err, - FailureInfo info, - uint256 opaqueError - ) internal returns (uint256) { - emit TokenFailure(uint256(err), uint256(info), opaqueError); - - return uint256(err); - } -} - - -// Dependency file: contracts/EIP20Interface.sol - -// pragma solidity 0.8.6; - -/** - * @title ERC 20 Token Standard Interface - * https://eips.ethereum.org/EIPS/eip-20 - */ -interface EIP20Interface { - function name() external view returns (string memory); - - function symbol() external view returns (string memory); - - function decimals() external view returns (uint8); - - /** - * @notice Get the total number of tokens in circulation - * @return The supply of tokens - */ - function totalSupply() external view returns (uint256); - - /** - * @notice Gets the balance of the specified address - * @param owner The address from which the balance will be retrieved - * @return balance The balance - */ - function balanceOf(address owner) external view returns (uint256 balance); - - /** - * @notice Transfer `amount` tokens from `msg.sender` to `dst` - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - * @return success Whether or not the transfer succeeded - */ - function transfer(address dst, uint256 amount) - external - returns (bool success); - - /** - * @notice Transfer `amount` tokens from `src` to `dst` - * @param src The address of the source account - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - * @return success Whether or not the transfer succeeded - */ - function transferFrom( - address src, - address dst, - uint256 amount - ) external returns (bool success); - - /** - * @notice Approve `spender` to transfer up to `amount` from `src` - * @dev This will overwrite the approval amount for `spender` - * and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve) - * @param spender The address of the account which may transfer tokens - * @param amount The number of tokens that are approved (-1 means infinite) - * @return success Whether or not the approval succeeded - */ - function approve(address spender, uint256 amount) - external - returns (bool success); - - /** - * @notice Get the current allowance from `owner` for `spender` - * @param owner The address of the account which owns the tokens to be spent - * @param spender The address of the account which may transfer tokens - * @return remaining The number of tokens allowed to be spent (-1 means infinite) - */ - function allowance(address owner, address spender) - external - view - returns (uint256 remaining); - - event Transfer(address indexed from, address indexed to, uint256 amount); - event Approval( - address indexed owner, - address indexed spender, - uint256 amount - ); -} - - -// Dependency file: contracts/WhitelistInterface.sol - -// pragma solidity 0.8.6; - -interface WhitelistInterface { - function setStatus(bool _newStatus) external; - function enabled() external view returns(bool); - - function addUsers(address[] memory _users) external; - function exist(address _user) external view returns(bool); - function getUsers() external view returns(address[] memory currentUsers); - function removeUser(address _user) external; -} - -// Dependency file: contracts/CToken.sol - -// pragma solidity 0.8.6; - -// import "contracts/ComptrollerInterface.sol"; -// import "contracts/CTokenInterfaces.sol"; -// import "contracts/ErrorReporter.sol"; -// import "contracts/Exponential.sol"; -// import "contracts/EIP20Interface.sol"; -// import "contracts/InterestRateModel.sol"; -// import "contracts/WhitelistInterface.sol"; - -/** - * @title tropykus CToken Contract - * @notice Abstract base for CTokens - * @author tropykus - */ -abstract contract CToken is CTokenInterface, Exponential, TokenErrorReporter { - address whitelist; - - /** - * @notice Initialize the money market - * @param comptroller_ The address of the Comptroller - * @param interestRateModel_ The address of the interest rate model - * @param initialExchangeRateMantissa_ The initial exchange rate, scaled by 1e18 - * @param name_ EIP-20 name of this token - * @param symbol_ EIP-20 symbol of this token - * @param decimals_ EIP-20 decimal precision of this token - */ - function initialize( - ComptrollerInterface comptroller_, - InterestRateModel interestRateModel_, - uint256 initialExchangeRateMantissa_, - string memory name_, - string memory symbol_, - uint8 decimals_ - ) public { - require(msg.sender == admin, "CT01"); - require(accrualBlockNumber == 0 && borrowIndex == 0, "CT02"); - - initialExchangeRateMantissa = initialExchangeRateMantissa_; - require(initialExchangeRateMantissa > 0, "CT03"); - - uint256 err = _setComptroller(comptroller_); - require(err == uint256(Error.NO_ERROR), "CT04"); - - accrualBlockNumber = getBlockNumber(); - borrowIndex = mantissaOne; - - err = _setInterestRateModelFresh(interestRateModel_); - require(err == uint256(Error.NO_ERROR), "CT05"); - - name = name_; - symbol = symbol_; - decimals = decimals_; - - _notEntered = true; - } - - function addWhitelist(address _whitelist) external returns (uint256) { - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_INTEREST_RATE_MODEL_OWNER_CHECK - ); - } - whitelist = _whitelist; - } - - /** - * @notice Transfer `tokens` tokens from `src` to `dst` by `spender` - * @dev Called by both `transfer` and `transferFrom` internally - * @param spender The address of the account performing the transfer - * @param src The address of the source account - * @param dst The address of the destination account - * @param tokens The number of tokens to transfer - * @return Whether or not the transfer succeeded - */ - function transferTokens( - address spender, - address src, - address dst, - uint256 tokens - ) internal returns (uint256) { - uint256 allowed = comptroller.transferAllowed( - address(this), - src, - dst, - tokens - ); - if (allowed != 0) { - return - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.TRANSFER_COMPTROLLER_REJECTION, - allowed - ); - } - - if (src == dst) { - return fail(Error.BAD_INPUT, FailureInfo.TRANSFER_NOT_ALLOWED); - } - - uint256 startingAllowance = 0; - if (spender == src) { - startingAllowance = type(uint256).max; - } else { - startingAllowance = transferAllowances[src][spender]; - } - - MathError mathErr; - uint256 allowanceNew; - uint256 srcTokensNew; - uint256 dstTokensNew; - - (mathErr, allowanceNew) = subUInt(startingAllowance, tokens); - if (mathErr != MathError.NO_ERROR) { - return fail(Error.MATH_ERROR, FailureInfo.TRANSFER_NOT_ALLOWED); - } - - (mathErr, srcTokensNew) = subUInt(accountTokens[src].tokens, tokens); - if (mathErr != MathError.NO_ERROR) { - return fail(Error.MATH_ERROR, FailureInfo.TRANSFER_NOT_ENOUGH); - } - - (mathErr, dstTokensNew) = addUInt(accountTokens[dst].tokens, tokens); - if (mathErr != MathError.NO_ERROR) { - return fail(Error.MATH_ERROR, FailureInfo.TRANSFER_TOO_MUCH); - } - - accountTokens[src].tokens = srcTokensNew; - accountTokens[dst].tokens = dstTokensNew; - - if (startingAllowance != type(uint256).max) { - transferAllowances[src][spender] = allowanceNew; - } - - emit Transfer(src, dst, tokens); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Transfer `amount` tokens from `msg.sender` to `dst` - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - * @return Whether or not the transfer succeeded - */ - function transfer(address dst, uint256 amount) - external - override - nonReentrant - returns (bool) - { - return - transferTokens(msg.sender, msg.sender, dst, amount) == - uint256(Error.NO_ERROR); - } - - /** - * @notice Transfer `amount` tokens from `src` to `dst` - * @param src The address of the source account - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - * @return Whether or not the transfer succeeded - */ - function transferFrom( - address src, - address dst, - uint256 amount - ) external override nonReentrant returns (bool) { - return - transferTokens(msg.sender, src, dst, amount) == - uint256(Error.NO_ERROR); - } - - /** - * @notice Approve `spender` to transfer up to `amount` from `src` - * @dev This will overwrite the approval amount for `spender` - * and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve) - * @param spender The address of the account which may transfer tokens - * @param amount The number of tokens that are approved (-1 means infinite) - * @return Whether or not the approval succeeded - */ - function approve(address spender, uint256 amount) - external - override - returns (bool) - { - transferAllowances[msg.sender][spender] = amount; - emit Approval(msg.sender, spender, amount); - return true; - } - - /** - * @notice Get the current allowance from `owner` for `spender` - * @param owner The address of the account which owns the tokens to be spent - * @param spender The address of the account which may transfer tokens - * @return The number of tokens allowed to be spent (-1 means infinite) - */ - function allowance(address owner, address spender) - external - view - override - returns (uint256) - { - return transferAllowances[owner][spender]; - } - - /** - * @notice Get the token balance of the `owner` - * @param owner The address of the account to query - * @return The number of tokens owned by `owner` - */ - function balanceOf(address owner) external view override returns (uint256) { - return accountTokens[owner].tokens; - } - - /** - * @notice Get the underlying balance of the `owner` - * @dev This also accrues interest in a transaction - * @param owner The address of the account to query - * @return The amount of underlying owned by `owner` - */ - function balanceOfUnderlying(address owner) - external - override - returns (uint256) - { - (MathError mErr, uint256 balance) = mulScalarTruncate( - Exp({mantissa: exchangeRateCurrent()}), - accountTokens[owner].tokens - ); - require(mErr == MathError.NO_ERROR, "CT06"); - return balance; - } - - /** - * @notice Get a snapshot of the account's balances, and the cached exchange rate - * @dev This is used by comptroller to more efficiently perform liquidity checks. - * @param account Address of the account to snapshot - * @return (possible error, token balance, borrow balance, exchange rate mantissa) - */ - function getAccountSnapshot(address account) - external - view - override - returns ( - uint256, - uint256, - uint256, - uint256 - ) - { - uint256 cTokenBalance = accountTokens[account].tokens; - uint256 borrowBalance; - uint256 exchangeRateMantissa; - - MathError mErr; - - (mErr, borrowBalance) = borrowBalanceStoredInternal(account); - if (mErr != MathError.NO_ERROR) { - return (uint256(Error.MATH_ERROR), 0, 0, 0); - } - - (mErr, exchangeRateMantissa) = exchangeRateStoredInternal(); - if (mErr != MathError.NO_ERROR) { - return (uint256(Error.MATH_ERROR), 0, 0, 0); - } - - return ( - uint256(Error.NO_ERROR), - cTokenBalance, - borrowBalance, - exchangeRateMantissa - ); - } - - /** - * @dev Function to simply retrieve block number - * This exists mainly for inheriting test contracts to stub this result. - */ - function getBlockNumber() internal view virtual returns (uint256) { - return block.number; - } - - /** - * @notice Returns the current per-block borrow interest rate for this cToken - * @return The borrow interest rate per block, scaled by 1e18 - */ - function borrowRatePerBlock() external view override returns (uint256) { - return - interestRateModel.getBorrowRate( - getCashPrior(), - totalBorrows, - totalReserves - ); - } - - /** - * @notice Returns the current per-block supply interest rate for this cToken - * @return The supply interest rate per block, scaled by 1e18 - */ - function supplyRatePerBlock() external view override returns (uint256) { - return - interestRateModel.getSupplyRate( - getCashPrior(), - totalBorrows, - totalReserves, - reserveFactorMantissa - ); - } - - /** - * @notice Returns the current total borrows plus accrued interest - * @return The total borrows with interest - */ - function totalBorrowsCurrent() - external - override - nonReentrant - returns (uint256) - { - require(accrueInterest() == uint256(Error.NO_ERROR), "CT07"); - return totalBorrows; - } - - /** - * @notice Accrue interest to updated borrowIndex and then calculate account's borrow balance using the updated borrowIndex - * @param account The address whose balance should be calculated after updating borrowIndex - * @return The calculated balance - */ - function borrowBalanceCurrent(address account) - external - override - nonReentrant - returns (uint256) - { - require(accrueInterest() == uint256(Error.NO_ERROR), "CT07"); - return borrowBalanceStored(account); - } - - /** - * @notice Return the borrow balance of account based on stored data - * @param account The address whose balance should be calculated - * @return The calculated balance - */ - function borrowBalanceStored(address account) - public - view - override - returns (uint256) - { - (MathError err, uint256 result) = borrowBalanceStoredInternal(account); - require(err == MathError.NO_ERROR, "CT08"); - return result; - } - - /** - * @notice Return the borrow balance of account based on stored data - * @param account The address whose balance should be calculated - * @return (error code, the calculated balance or 0 if error code is non-zero) - */ - function borrowBalanceStoredInternal(address account) - internal - view - returns (MathError, uint256) - { - MathError mathErr; - uint256 principalTimesIndex; - uint256 result; - - BorrowSnapshot storage borrowSnapshot = accountBorrows[account]; - - if (borrowSnapshot.principal == 0) { - return (MathError.NO_ERROR, 0); - } - - (mathErr, principalTimesIndex) = mulUInt( - borrowSnapshot.principal, - borrowIndex - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - - (mathErr, result) = divUInt( - principalTimesIndex, - borrowSnapshot.interestIndex - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - - return (MathError.NO_ERROR, result); - } - - function getBorrowerPrincipalStored(address account) - public - view - returns (uint256 borrowed) - { - borrowed = accountBorrows[account].principal; - } - - function getSupplierSnapshotStored(address account) - public - view - returns ( - uint256 tokens, - uint256 underlyingAmount, - uint256 suppliedAt, - uint256 promisedSupplyRate - ) - { - tokens = accountTokens[account].tokens; - underlyingAmount = accountTokens[account].underlyingAmount; - suppliedAt = accountTokens[account].suppliedAt; - promisedSupplyRate = accountTokens[account].promisedSupplyRate; - } - - /** - * @notice Accrue interest then return the up-to-date exchange rate - * @return Calculated exchange rate scaled by 1e18 - */ - function exchangeRateCurrent() - public - override - nonReentrant - returns (uint256) - { - require(accrueInterest() == uint256(Error.NO_ERROR), "CT07"); - return exchangeRateStored(); - } - - /** - * @notice Calculates the exchange rate from the underlying to the CToken - * @dev This function does not accrue interest before calculating the exchange rate - * @return Calculated exchange rate scaled by 1e18 - */ - function exchangeRateStored() public view override returns (uint256) { - (MathError err, uint256 result) = exchangeRateStoredInternal(); - require(err == MathError.NO_ERROR, "CT09"); - return result; - } - - /** - * @notice Calculates the exchange rate from the underlying to the CToken - * @dev This function does not accrue interest before calculating the exchange rate - * @return (error code, calculated exchange rate scaled by 1e18) - */ - function exchangeRateStoredInternal() - internal - view - virtual - returns (MathError, uint256) - { - uint256 _totalSupply = totalSupply; - if (_totalSupply == 0) { - return (MathError.NO_ERROR, initialExchangeRateMantissa); - } else { - MathError error; - uint256 exchangeRate; - uint256 totalCash = getCashPrior(); - if (interestRateModel.isTropykusInterestRateModel()) { - (error, exchangeRate) = tropykusExchangeRateStoredInternal( - msg.sender - ); - if (error == MathError.NO_ERROR) { - return (MathError.NO_ERROR, exchangeRate); - } else { - return (MathError.NO_ERROR, initialExchangeRateMantissa); - } - } - return - interestRateModel.getExchangeRate( - totalCash, - totalBorrows, - totalReserves, - totalSupply - ); - } - } - - function tropykusExchangeRateStoredInternal(address redeemer) - internal - view - returns (MathError, uint256) - { - if (totalSupply == 0) { - return (MathError.NO_ERROR, initialExchangeRateMantissa); - } else { - SupplySnapshot storage supplySnapshot = accountTokens[redeemer]; - if (supplySnapshot.suppliedAt == 0) { - return (MathError.DIVISION_BY_ZERO, 0); - } - (, uint256 interestFactorMantissa, ) = tropykusInterestAccrued( - redeemer - ); - Exp memory interestFactor = Exp({mantissa: interestFactorMantissa}); - uint256 currentUnderlying = supplySnapshot.underlyingAmount; - Exp memory redeemerUnderlying = Exp({mantissa: currentUnderlying}); - (, Exp memory realAmount) = mulExp( - interestFactor, - redeemerUnderlying - ); - (, Exp memory exchangeRate) = getExp( - realAmount.mantissa, - supplySnapshot.tokens - ); - return (MathError.NO_ERROR, exchangeRate.mantissa); - } - } - - function tropykusInterestAccrued(address account) - internal - view - returns ( - MathError, - uint256, - uint256 - ) - { - SupplySnapshot storage supplySnapshot = accountTokens[account]; - uint256 promisedSupplyRate = supplySnapshot.promisedSupplyRate; - Exp memory expectedSupplyRatePerBlock = Exp({ - mantissa: promisedSupplyRate - }); - (, uint256 delta) = subUInt( - accrualBlockNumber, - supplySnapshot.suppliedAt - ); - (, Exp memory expectedSupplyRatePerBlockWithDelta) = mulScalar( - expectedSupplyRatePerBlock, - delta - ); - (, Exp memory interestFactor) = addExp( - Exp({mantissa: 1e18}), - expectedSupplyRatePerBlockWithDelta - ); - uint256 currentUnderlying = supplySnapshot.underlyingAmount; - Exp memory redeemerUnderlying = Exp({mantissa: currentUnderlying}); - (, Exp memory realAmount) = mulExp(interestFactor, redeemerUnderlying); - (, uint256 interestEarned) = subUInt( - realAmount.mantissa, - currentUnderlying - ); - return (MathError.NO_ERROR, interestFactor.mantissa, interestEarned); - } - - /** - * @notice Get cash balance of this cToken in the underlying asset - * @return The quantity of underlying asset owned by this contract - */ - function getCash() external view override returns (uint256) { - return getCashPrior(); - } - - /** - * @notice Applies accrued interest to total borrows and reserves - * @dev This calculates interest accrued from the last checkpointed block - * up to the current block and writes new checkpoint to storage. - */ - function accrueInterest() public override returns (uint256) { - uint256 currentBlockNumber = getBlockNumber(); - uint256 accrualBlockNumberPrior = accrualBlockNumber; - - if (accrualBlockNumberPrior == currentBlockNumber) { - return uint256(Error.NO_ERROR); - } - - uint256 cashPrior = getCashPrior(); - uint256 borrowsPrior = totalBorrows; - uint256 reservesPrior = totalReserves; - uint256 borrowIndexPrior = borrowIndex; - - uint256 borrowRateMantissa = interestRateModel.getBorrowRate( - cashPrior, - borrowsPrior, - reservesPrior - ); - require(borrowRateMantissa <= borrowRateMaxMantissa, "CT10"); - - (MathError mathErr, uint256 blockDelta) = subUInt( - currentBlockNumber, - accrualBlockNumberPrior - ); - require(mathErr == MathError.NO_ERROR, "CT11"); - - Exp memory simpleInterestFactor; - uint256 interestAccumulated; - uint256 totalBorrowsNew; - uint256 totalReservesNew; - uint256 borrowIndexNew; - - (mathErr, simpleInterestFactor) = mulScalar( - Exp({mantissa: borrowRateMantissa}), - blockDelta - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .ACCRUE_INTEREST_SIMPLE_INTEREST_FACTOR_CALCULATION_FAILED, - uint256(mathErr) - ); - } - - (mathErr, interestAccumulated) = mulScalarTruncate( - simpleInterestFactor, - borrowsPrior - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .ACCRUE_INTEREST_ACCUMULATED_INTEREST_CALCULATION_FAILED, - uint256(mathErr) - ); - } - - (mathErr, totalBorrowsNew) = addUInt(interestAccumulated, borrowsPrior); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .ACCRUE_INTEREST_NEW_TOTAL_BORROWS_CALCULATION_FAILED, - uint256(mathErr) - ); - } - - (mathErr, totalReservesNew) = mulScalarTruncateAddUInt( - Exp({mantissa: reserveFactorMantissa}), - interestAccumulated, - reservesPrior - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .ACCRUE_INTEREST_NEW_TOTAL_RESERVES_CALCULATION_FAILED, - uint256(mathErr) - ); - } - - if (interestRateModel.isTropykusInterestRateModel()) { - (mathErr, totalReservesNew) = newReserves( - borrowRateMantissa, - cashPrior, - borrowsPrior, - reservesPrior, - interestAccumulated - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .ACCRUE_INTEREST_NEW_TOTAL_RESERVES_CALCULATION_FAILED, - uint256(mathErr) - ); - } - } - - (mathErr, borrowIndexNew) = mulScalarTruncateAddUInt( - simpleInterestFactor, - borrowIndexPrior, - borrowIndexPrior - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .ACCRUE_INTEREST_NEW_BORROW_INDEX_CALCULATION_FAILED, - uint256(mathErr) - ); - } - - accrualBlockNumber = currentBlockNumber; - borrowIndex = borrowIndexNew; - totalBorrows = totalBorrowsNew; - totalReserves = totalReservesNew; - - emit AccrueInterest( - cashPrior, - interestAccumulated, - borrowIndexNew, - totalBorrowsNew - ); - - return uint256(Error.NO_ERROR); - } - - function newReserves( - uint256 borrowRateMantissa, - uint256 cashPrior, - uint256 borrowsPrior, - uint256 reservesPrior, - uint256 interestAccumulated - ) internal view returns (MathError mathErr, uint256 totalReservesNew) { - uint256 newReserveFactorMantissa; - uint256 utilizationRate = interestRateModel.utilizationRate( - cashPrior, - borrowsPrior, - reservesPrior - ); - uint256 expectedSupplyRate = interestRateModel.getSupplyRate( - cashPrior, - borrowsPrior, - reservesPrior, - reserveFactorMantissa - ); - if ( - interestRateModel.isAboveOptimal( - cashPrior, - borrowsPrior, - reservesPrior - ) - ) { - (mathErr, newReserveFactorMantissa) = mulScalarTruncate( - Exp({mantissa: utilizationRate}), - borrowRateMantissa - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - (mathErr, newReserveFactorMantissa) = subUInt( - newReserveFactorMantissa, - expectedSupplyRate - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - (mathErr, totalReservesNew) = mulScalarTruncateAddUInt( - Exp({mantissa: newReserveFactorMantissa}), - interestAccumulated, - reservesPrior - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - } else { - mathErr = MathError.NO_ERROR; - totalReservesNew = reservesPrior; - } - } - - /** - * @notice Sender supplies assets into the market and receives cTokens in exchange - * @dev Accrues interest whether or not the operation succeeds, unless reverted - * @param mintAmount The amount of the underlying asset to supply - * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual mint amount. - */ - function mintInternal(uint256 mintAmount) - internal - nonReentrant - returns (uint256, uint256) - { - if (WhitelistInterface(whitelist).enabled()) { - require(WhitelistInterface(whitelist).exist(msg.sender), "CT26"); - } - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return ( - fail(Error(error), FailureInfo.MINT_ACCRUE_INTEREST_FAILED), - 0 - ); - } - return mintFresh(msg.sender, mintAmount); - } - - struct MintLocalVars { - Error err; - MathError mathErr; - uint256 exchangeRateMantissa; - uint256 mintTokens; - uint256 totalSupplyNew; - uint256 accountTokensNew; - uint256 actualMintAmount; - } - - /** - * @notice User supplies assets into the market and receives cTokens in exchange - * @dev Assumes interest has already been accrued up to the current block - * @param minter The address of the account which is supplying the assets - * @param mintAmount The amount of the underlying asset to supply - * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual mint amount. - */ - function mintFresh(address minter, uint256 mintAmount) - internal - returns (uint256, uint256) - { - uint256 allowed = comptroller.mintAllowed( - address(this), - minter, - mintAmount - ); - if (allowed != 0) { - return ( - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.MINT_COMPTROLLER_REJECTION, - allowed - ), - 0 - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return ( - fail(Error.MARKET_NOT_FRESH, FailureInfo.MINT_FRESHNESS_CHECK), - 0 - ); - } - - MintLocalVars memory vars; - - ( - vars.mathErr, - vars.exchangeRateMantissa - ) = exchangeRateStoredInternal(); - if (vars.mathErr != MathError.NO_ERROR) { - return ( - failOpaque( - Error.MATH_ERROR, - FailureInfo.MINT_EXCHANGE_RATE_READ_FAILED, - uint256(vars.mathErr) - ), - 0 - ); - } - if (interestRateModel.isTropykusInterestRateModel()) { - SupplySnapshot storage supplySnapshot = accountTokens[minter]; - (, uint256 newTotalSupply) = addUInt( - supplySnapshot.underlyingAmount, - mintAmount - ); - require(newTotalSupply <= 0.1e18, "CT24"); - } - vars.actualMintAmount = doTransferIn(minter, mintAmount); - - (vars.mathErr, vars.mintTokens) = divScalarByExpTruncate( - vars.actualMintAmount, - Exp({mantissa: vars.exchangeRateMantissa}) - ); - require(vars.mathErr == MathError.NO_ERROR, "CT12"); - - (vars.mathErr, vars.totalSupplyNew) = addUInt( - totalSupply, - vars.mintTokens - ); - require(vars.mathErr == MathError.NO_ERROR, "CT13"); - - (vars.mathErr, vars.accountTokensNew) = addUInt( - accountTokens[minter].tokens, - vars.mintTokens - ); - require(vars.mathErr == MathError.NO_ERROR, "CT14"); - - uint256 currentSupplyRate = interestRateModel.getSupplyRate( - getCashPrior(), - totalBorrows, - totalReserves, - reserveFactorMantissa - ); - - bool isTropykusInterestRateModel = interestRateModel - .isTropykusInterestRateModel(); - - if (accountTokens[minter].tokens > 0) { - Exp memory updatedUnderlying; - if (isTropykusInterestRateModel) { - (, uint256 interestFactorMantissa, ) = tropykusInterestAccrued( - minter - ); - Exp memory interestFactor = Exp({ - mantissa: interestFactorMantissa - }); - uint256 currentUnderlyingAmount = accountTokens[minter] - .underlyingAmount; - MathError mErrorNewAmount; - (mErrorNewAmount, updatedUnderlying) = mulExp( - Exp({mantissa: currentUnderlyingAmount}), - interestFactor - ); - if (mErrorNewAmount != MathError.NO_ERROR) { - return ( - failOpaque( - Error.MATH_ERROR, - FailureInfo.MINT_EXCHANGE_CALCULATION_FAILED, - uint256(mErrorNewAmount) - ), - 0 - ); - } - } else { - uint256 currentTokens = accountTokens[minter].tokens; - MathError mErrorUpdatedUnderlying; - (mErrorUpdatedUnderlying, updatedUnderlying) = mulExp( - Exp({mantissa: currentTokens}), - Exp({mantissa: vars.exchangeRateMantissa}) - ); - if (mErrorUpdatedUnderlying != MathError.NO_ERROR) { - return ( - failOpaque( - Error.MATH_ERROR, - FailureInfo.MINT_EXCHANGE_CALCULATION_FAILED, - uint256(mErrorUpdatedUnderlying) - ), - 0 - ); - } - } - (, mintAmount) = addUInt(updatedUnderlying.mantissa, mintAmount); - } - - totalSupply = vars.totalSupplyNew; - accountTokens[minter] = SupplySnapshot({ - tokens: vars.accountTokensNew, - underlyingAmount: mintAmount, - suppliedAt: accrualBlockNumber, - promisedSupplyRate: currentSupplyRate - }); - - emit Mint(minter, vars.actualMintAmount, vars.mintTokens); - emit Transfer(address(this), minter, vars.mintTokens); - - return (uint256(Error.NO_ERROR), vars.actualMintAmount); - } - - /** - * @notice Sender redeems cTokens in exchange for a specified amount of underlying asset - * @dev Accrues interest whether or not the operation succeeds, unless reverted - * @param redeemAmount The amount of underlying to receive from redeeming cTokens - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function redeemUnderlyingInternal(uint256 redeemAmount) - internal - nonReentrant - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return - fail(Error(error), FailureInfo.REDEEM_ACCRUE_INTEREST_FAILED); - } - return redeemFresh(payable(msg.sender), redeemAmount); - } - - struct RedeemLocalVars { - Error err; - MathError mathErr; - uint256 exchangeRateMantissa; - uint256 redeemTokens; - uint256 redeemAmount; - uint256 totalSupplyNew; - uint256 accountTokensNew; - uint256 newSubsidyFund; - } - - /** - * @notice User redeems cTokens in exchange for the underlying asset - * @dev Assumes interest has already been accrued up to the current block - * @param redeemer The address of the account which is redeeming the tokens - * @param redeemAmountIn The number of underlying tokens to receive from redeeming cTokens - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function redeemFresh(address payable redeemer, uint256 redeemAmountIn) - internal - returns (uint256) - { - require(redeemAmountIn > 0, "CT15"); - - RedeemLocalVars memory vars; - - SupplySnapshot storage supplySnapshot = accountTokens[redeemer]; - - ( - vars.mathErr, - vars.exchangeRateMantissa - ) = exchangeRateStoredInternal(); - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.REDEEM_EXCHANGE_RATE_READ_FAILED, - uint256(vars.mathErr) - ); - } - - uint256 interestEarned; - uint256 subsidyFundPortion; - uint256 currentUnderlying; - - bool isTropykusInterestRateModel = interestRateModel - .isTropykusInterestRateModel(); - if (isTropykusInterestRateModel) { - currentUnderlying = supplySnapshot.underlyingAmount; - (, , interestEarned) = tropykusInterestAccrued(redeemer); - } - supplySnapshot.promisedSupplyRate = interestRateModel.getSupplyRate( - getCashPrior(), - totalBorrows, - totalReserves, - reserveFactorMantissa - ); - - if ( - isTropykusInterestRateModel && - !interestRateModel.isAboveOptimal( - getCashPrior(), - totalBorrows, - totalReserves - ) - ) { - uint256 borrowRate = interestRateModel.getBorrowRate( - getCashPrior(), - totalBorrows, - totalReserves - ); - - uint256 utilizationRate = interestRateModel.utilizationRate( - getCashPrior(), - totalBorrows, - totalReserves - ); - - (, uint256 estimatedEarning) = mulScalarTruncate( - Exp({mantissa: borrowRate}), - utilizationRate - ); - - (, subsidyFundPortion) = subUInt( - supplySnapshot.promisedSupplyRate, - estimatedEarning - ); - (, Exp memory subsidyFactor) = getExp( - subsidyFundPortion, - supplySnapshot.promisedSupplyRate - ); - (, subsidyFundPortion) = mulScalarTruncate( - subsidyFactor, - interestEarned - ); - } - - vars.redeemAmount = redeemAmountIn; - - if (isTropykusInterestRateModel) { - (, Exp memory num) = mulExp( - vars.redeemAmount, - supplySnapshot.tokens - ); - (, Exp memory realTokensWithdrawAmount) = getExp( - num.mantissa, - currentUnderlying - ); - vars.redeemTokens = realTokensWithdrawAmount.mantissa; - } else { - (vars.mathErr, vars.redeemTokens) = divScalarByExpTruncate( - redeemAmountIn, - Exp({mantissa: vars.exchangeRateMantissa}) - ); - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.REDEEM_EXCHANGE_AMOUNT_CALCULATION_FAILED, - uint256(vars.mathErr) - ); - } - } - // } - - uint256 allowed = comptroller.redeemAllowed( - address(this), - redeemer, - vars.redeemTokens - ); - if (allowed != 0) { - return - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.REDEEM_COMPTROLLER_REJECTION, - allowed - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.REDEEM_FRESHNESS_CHECK - ); - } - - (vars.mathErr, vars.totalSupplyNew) = subUInt( - totalSupply, - vars.redeemTokens - ); - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.REDEEM_NEW_TOTAL_SUPPLY_CALCULATION_FAILED, - uint256(vars.mathErr) - ); - } - - (, vars.newSubsidyFund) = subUInt(subsidyFund, subsidyFundPortion); - - (vars.mathErr, vars.accountTokensNew) = subUInt( - supplySnapshot.tokens, - vars.redeemTokens - ); - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.REDEEM_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED, - uint256(vars.mathErr) - ); - } - - uint256 cash = getCashPrior(); - if (isTropykusInterestRateModel) { - cash = address(this).balance; - } - - if (cash < vars.redeemAmount) { - return - fail( - Error.TOKEN_INSUFFICIENT_CASH, - FailureInfo.REDEEM_TRANSFER_OUT_NOT_POSSIBLE - ); - } - - doTransferOut(redeemer, vars.redeemAmount); - - totalSupply = vars.totalSupplyNew; - subsidyFund = vars.newSubsidyFund; - supplySnapshot.tokens = vars.accountTokensNew; - supplySnapshot.suppliedAt = accrualBlockNumber; - (, supplySnapshot.underlyingAmount) = subUInt( - supplySnapshot.underlyingAmount, - vars.redeemAmount - ); - - emit Transfer(redeemer, address(this), vars.redeemTokens); - emit Redeem(redeemer, vars.redeemAmount, vars.redeemTokens); - - comptroller.redeemVerify( - address(this), - redeemer, - vars.redeemAmount, - vars.redeemTokens - ); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Sender borrows assets from the protocol to their own address - * @param borrowAmount The amount of the underlying asset to borrow - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function borrowInternal(uint256 borrowAmount) - internal - nonReentrant - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return - fail(Error(error), FailureInfo.BORROW_ACCRUE_INTEREST_FAILED); - } - return borrowFresh(payable(msg.sender), borrowAmount); - } - - struct BorrowLocalVars { - MathError mathErr; - uint256 accountBorrows; - uint256 accountBorrowsNew; - uint256 totalBorrowsNew; - } - - /** - * @notice Users borrow assets from the protocol to their own address - * @param borrowAmount The amount of the underlying asset to borrow - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function borrowFresh(address payable borrower, uint256 borrowAmount) - internal - returns (uint256) - { - uint256 allowed = comptroller.borrowAllowed( - address(this), - borrower, - borrowAmount - ); - if (allowed != 0) { - return - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.BORROW_COMPTROLLER_REJECTION, - allowed - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.BORROW_FRESHNESS_CHECK - ); - } - - if (getCashPrior() < borrowAmount) { - return - fail( - Error.TOKEN_INSUFFICIENT_CASH, - FailureInfo.BORROW_CASH_NOT_AVAILABLE - ); - } - - BorrowLocalVars memory vars; - - (vars.mathErr, vars.accountBorrows) = borrowBalanceStoredInternal( - borrower - ); - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED, - uint256(vars.mathErr) - ); - } - - (vars.mathErr, vars.accountBorrowsNew) = addUInt( - vars.accountBorrows, - borrowAmount - ); - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED, - uint256(vars.mathErr) - ); - } - - (vars.mathErr, vars.totalBorrowsNew) = addUInt( - totalBorrows, - borrowAmount - ); - if (interestRateModel.isTropykusInterestRateModel()) { - require(vars.totalBorrowsNew <= 0.1e18, "CT25"); - } - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED, - uint256(vars.mathErr) - ); - } - - doTransferOut(borrower, borrowAmount); - - accountBorrows[borrower].principal = vars.accountBorrowsNew; - accountBorrows[borrower].interestIndex = borrowIndex; - totalBorrows = vars.totalBorrowsNew; - - emit Borrow( - borrower, - borrowAmount, - vars.accountBorrowsNew, - vars.totalBorrowsNew - ); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Sender repays their own borrow - * @param repayAmount The amount to repay - * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual repayment amount. - */ - function repayBorrowInternal(uint256 repayAmount) - internal - nonReentrant - returns (uint256, uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return ( - fail( - Error(error), - FailureInfo.REPAY_BORROW_ACCRUE_INTEREST_FAILED - ), - 0 - ); - } - return repayBorrowFresh(msg.sender, msg.sender, repayAmount); - } - - struct RepayBorrowLocalVars { - Error err; - MathError mathErr; - uint256 repayAmount; - uint256 borrowerIndex; - uint256 accountBorrows; - uint256 accountBorrowsNew; - uint256 totalBorrowsNew; - uint256 actualRepayAmount; - } - - /** - * @notice Borrows are repaid by another user (possibly the borrower). - * @param payer the account paying off the borrow - * @param borrower the account with the debt being payed off - * @param repayAmount the amount of undelrying tokens being returned - * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual repayment amount. - */ - function repayBorrowFresh( - address payer, - address borrower, - uint256 repayAmount - ) internal returns (uint256, uint256) { - uint256 allowed = comptroller.repayBorrowAllowed( - address(this), - payer, - borrower, - repayAmount - ); - if (allowed != 0) { - return ( - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.REPAY_BORROW_COMPTROLLER_REJECTION, - allowed - ), - 0 - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return ( - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.REPAY_BORROW_FRESHNESS_CHECK - ), - 0 - ); - } - - RepayBorrowLocalVars memory vars; - - vars.borrowerIndex = accountBorrows[borrower].interestIndex; - - (vars.mathErr, vars.accountBorrows) = borrowBalanceStoredInternal( - borrower - ); - if (vars.mathErr != MathError.NO_ERROR) { - return ( - failOpaque( - Error.MATH_ERROR, - FailureInfo - .REPAY_BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED, - uint256(vars.mathErr) - ), - 0 - ); - } - - if (repayAmount == type(uint256).max) { - vars.repayAmount = vars.accountBorrows; - } else { - vars.repayAmount = repayAmount; - } - - vars.actualRepayAmount = doTransferIn(payer, vars.repayAmount); - - (vars.mathErr, vars.accountBorrowsNew) = subUInt( - vars.accountBorrows, - vars.actualRepayAmount - ); - require(vars.mathErr == MathError.NO_ERROR, "CT16"); - - (vars.mathErr, vars.totalBorrowsNew) = subUInt( - totalBorrows, - vars.actualRepayAmount - ); - require(vars.mathErr == MathError.NO_ERROR, "CT17"); - - accountBorrows[borrower].principal = vars.accountBorrowsNew; - accountBorrows[borrower].interestIndex = borrowIndex; - totalBorrows = vars.totalBorrowsNew; - - emit RepayBorrow( - payer, - borrower, - vars.actualRepayAmount, - vars.accountBorrowsNew, - vars.totalBorrowsNew - ); - - return (uint256(Error.NO_ERROR), vars.actualRepayAmount); - } - - /** - * @notice The sender liquidates the borrowers collateral. - * The collateral seized is transferred to the liquidator. - * @param borrower The borrower of this cToken to be liquidated - * @param cTokenCollateral The market in which to seize collateral from the borrower - * @param repayAmount The amount of the underlying borrowed asset to repay - * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual repayment amount. - */ - function liquidateBorrowInternal( - address borrower, - uint256 repayAmount, - CTokenInterface cTokenCollateral - ) internal nonReentrant returns (uint256, uint256) { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return ( - fail( - Error(error), - FailureInfo.LIQUIDATE_ACCRUE_BORROW_INTEREST_FAILED - ), - 0 - ); - } - - error = cTokenCollateral.accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return ( - fail( - Error(error), - FailureInfo.LIQUIDATE_ACCRUE_COLLATERAL_INTEREST_FAILED - ), - 0 - ); - } - - // liquidateBorrowFresh emits borrow-specific logs on errors, so we don't need to - return - liquidateBorrowFresh( - msg.sender, - borrower, - repayAmount, - cTokenCollateral - ); - } - - /** - * @notice The liquidator liquidates the borrowers collateral. - * The collateral seized is transferred to the liquidator. - * @param borrower The borrower of this cToken to be liquidated - * @param liquidator The address repaying the borrow and seizing collateral - * @param cTokenCollateral The market in which to seize collateral from the borrower - * @param repayAmount The amount of the underlying borrowed asset to repay - * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual repayment amount. - */ - function liquidateBorrowFresh( - address liquidator, - address borrower, - uint256 repayAmount, - CTokenInterface cTokenCollateral - ) internal returns (uint256, uint256) { - uint256 allowed = comptroller.liquidateBorrowAllowed( - address(this), - address(cTokenCollateral), - liquidator, - borrower, - repayAmount - ); - if (allowed != 0) { - return ( - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.LIQUIDATE_COMPTROLLER_REJECTION, - allowed - ), - 0 - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return ( - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.LIQUIDATE_FRESHNESS_CHECK - ), - 0 - ); - } - - if (cTokenCollateral.accrualBlockNumber() != getBlockNumber()) { - return ( - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.LIQUIDATE_COLLATERAL_FRESHNESS_CHECK - ), - 0 - ); - } - - if (borrower == liquidator) { - return ( - fail( - Error.INVALID_ACCOUNT_PAIR, - FailureInfo.LIQUIDATE_LIQUIDATOR_IS_BORROWER - ), - 0 - ); - } - - if (repayAmount == 0) { - return ( - fail( - Error.INVALID_CLOSE_AMOUNT_REQUESTED, - FailureInfo.LIQUIDATE_CLOSE_AMOUNT_IS_ZERO - ), - 0 - ); - } - - if (repayAmount == type(uint256).max) { - return ( - fail( - Error.INVALID_CLOSE_AMOUNT_REQUESTED, - FailureInfo.LIQUIDATE_CLOSE_AMOUNT_IS_UINT_MAX - ), - 0 - ); - } - - ( - uint256 repayBorrowError, - uint256 actualRepayAmount - ) = repayBorrowFresh(liquidator, borrower, repayAmount); - if (repayBorrowError != uint256(Error.NO_ERROR)) { - return ( - fail( - Error(repayBorrowError), - FailureInfo.LIQUIDATE_REPAY_BORROW_FRESH_FAILED - ), - 0 - ); - } - - (uint256 amountSeizeError, uint256 seizeTokens) = comptroller - .liquidateCalculateSeizeTokens( - address(this), - address(cTokenCollateral), - actualRepayAmount - ); - require(amountSeizeError == uint256(Error.NO_ERROR), "CT18"); - - require(cTokenCollateral.balanceOf(borrower) >= seizeTokens, "CT19"); - - uint256 seizeError; - if (address(cTokenCollateral) == address(this)) { - seizeError = seizeInternal( - address(this), - liquidator, - borrower, - seizeTokens - ); - } else { - seizeError = cTokenCollateral.seize( - liquidator, - borrower, - seizeTokens - ); - } - - require(seizeError == uint256(Error.NO_ERROR), "CT20"); - - emit LiquidateBorrow( - liquidator, - borrower, - actualRepayAmount, - address(cTokenCollateral), - seizeTokens - ); - - return (uint256(Error.NO_ERROR), actualRepayAmount); - } - - /** - * @notice Transfers collateral tokens (this market) to the liquidator. - * @dev Will fail unless called by another cToken during the process of liquidation. - * Its absolutely critical to use msg.sender as the borrowed cToken and not a parameter. - * @param liquidator The account receiving seized collateral - * @param borrower The account having collateral seized - * @param seizeTokens The number of cTokens to seize - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function seize( - address liquidator, - address borrower, - uint256 seizeTokens - ) external override nonReentrant returns (uint256) { - return seizeInternal(msg.sender, liquidator, borrower, seizeTokens); - } - - struct SeizeVars { - uint256 seizeAmount; - uint256 exchangeRate; - uint256 borrowerTokensNew; - uint256 borrowerAmountNew; - uint256 liquidatorTokensNew; - uint256 liquidatorAmountNew; - uint256 totalCash; - uint256 supplyRate; - } - - /** - * @notice Transfers collateral tokens (this market) to the liquidator. - * @dev Called only during an in-kind liquidation, or by liquidateBorrow during the liquidation of another CToken. - * Its absolutely critical to use msg.sender as the seizer cToken and not a parameter. - * @param seizerToken The contract seizing the collateral (i.e. borrowed cToken) - * @param liquidator The account receiving seized collateral - * @param borrower The account having collateral seized - * @param seizeTokens The number of cTokens to seize - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function seizeInternal( - address seizerToken, - address liquidator, - address borrower, - uint256 seizeTokens - ) internal returns (uint256) { - uint256 allowed = comptroller.seizeAllowed( - address(this), - seizerToken, - liquidator, - borrower, - seizeTokens - ); - if (allowed != 0) { - return - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.LIQUIDATE_SEIZE_COMPTROLLER_REJECTION, - allowed - ); - } - - if (borrower == liquidator) { - return - fail( - Error.INVALID_ACCOUNT_PAIR, - FailureInfo.LIQUIDATE_SEIZE_LIQUIDATOR_IS_BORROWER - ); - } - - SeizeVars memory seizeVars; - - MathError mathErr; - - (mathErr, seizeVars.borrowerTokensNew) = subUInt( - accountTokens[borrower].tokens, - seizeTokens - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.LIQUIDATE_SEIZE_BALANCE_DECREMENT_FAILED, - uint256(mathErr) - ); - } - - seizeVars.totalCash = getCashPrior(); - seizeVars.supplyRate = interestRateModel.getSupplyRate( - seizeVars.totalCash, - totalBorrows, - totalReserves, - reserveFactorMantissa - ); - - (, seizeVars.exchangeRate) = interestRateModel.getExchangeRate( - seizeVars.totalCash, - totalBorrows, - totalReserves, - totalSupply - ); - - if (interestRateModel.isTropykusInterestRateModel()) { - (, seizeVars.exchangeRate) = tropykusExchangeRateStoredInternal( - borrower - ); - } - - (, seizeVars.seizeAmount) = mulUInt( - seizeTokens, - seizeVars.exchangeRate - ); - (, seizeVars.seizeAmount) = divUInt(seizeVars.seizeAmount, 1e18); - - (, seizeVars.borrowerAmountNew) = subUInt( - accountTokens[borrower].underlyingAmount, - seizeVars.seizeAmount - ); - - (mathErr, seizeVars.liquidatorTokensNew) = addUInt( - accountTokens[liquidator].tokens, - seizeTokens - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.LIQUIDATE_SEIZE_BALANCE_INCREMENT_FAILED, - uint256(mathErr) - ); - } - - (, seizeVars.liquidatorAmountNew) = addUInt( - accountTokens[liquidator].underlyingAmount, - seizeVars.seizeAmount - ); - - accountTokens[borrower].tokens = seizeVars.borrowerTokensNew; - accountTokens[borrower].underlyingAmount = seizeVars.borrowerAmountNew; - accountTokens[borrower].suppliedAt = getBlockNumber(); - accountTokens[borrower].promisedSupplyRate = seizeVars.supplyRate; - - accountTokens[liquidator].tokens = seizeVars.liquidatorTokensNew; - accountTokens[liquidator].underlyingAmount = seizeVars - .liquidatorAmountNew; - accountTokens[liquidator].suppliedAt = getBlockNumber(); - accountTokens[liquidator].promisedSupplyRate = seizeVars.supplyRate; - - emit Transfer(borrower, liquidator, seizeTokens); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Begins transfer of admin rights. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer. - * @dev Admin function to begin change of admin. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer. - * @param newPendingAdmin New pending admin. - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setPendingAdmin(address payable newPendingAdmin) - external - override - returns (uint256) - { - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_PENDING_ADMIN_OWNER_CHECK - ); - } - - address oldPendingAdmin = pendingAdmin; - - pendingAdmin = newPendingAdmin; - - emit NewPendingAdmin(oldPendingAdmin, newPendingAdmin); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Accepts transfer of admin rights. msg.sender must be pendingAdmin - * @dev Admin function for pending admin to accept role and update admin - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _acceptAdmin() external override returns (uint256) { - if (msg.sender != pendingAdmin || msg.sender == address(0)) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.ACCEPT_ADMIN_PENDING_ADMIN_CHECK - ); - } - - address oldAdmin = admin; - address oldPendingAdmin = pendingAdmin; - - admin = pendingAdmin; - - pendingAdmin = payable(address(0)); - - emit NewAdmin(oldAdmin, admin); - emit NewPendingAdmin(oldPendingAdmin, pendingAdmin); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Sets a new comptroller for the market - * @dev Admin function to set a new comptroller - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setComptroller(ComptrollerInterface newComptroller) - public - override - returns (uint256) - { - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_COMPTROLLER_OWNER_CHECK - ); - } - - ComptrollerInterface oldComptroller = comptroller; - require(newComptroller.isComptroller(), "CT21"); - - comptroller = newComptroller; - - emit NewComptroller(oldComptroller, newComptroller); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice accrues interest and sets a new reserve factor for the protocol using _setReserveFactorFresh - * @dev Admin function to accrue interest and set a new reserve factor - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setReserveFactor(uint256 newReserveFactorMantissa) - external - override - nonReentrant - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return - fail( - Error(error), - FailureInfo.SET_RESERVE_FACTOR_ACCRUE_INTEREST_FAILED - ); - } - return _setReserveFactorFresh(newReserveFactorMantissa); - } - - /** - * @notice Sets a new reserve factor for the protocol (*requires fresh interest accrual) - * @dev Admin function to set a new reserve factor - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setReserveFactorFresh(uint256 newReserveFactorMantissa) - internal - returns (uint256) - { - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_RESERVE_FACTOR_ADMIN_CHECK - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.SET_RESERVE_FACTOR_FRESH_CHECK - ); - } - - if (newReserveFactorMantissa > reserveFactorMaxMantissa) { - return - fail( - Error.BAD_INPUT, - FailureInfo.SET_RESERVE_FACTOR_BOUNDS_CHECK - ); - } - - uint256 oldReserveFactorMantissa = reserveFactorMantissa; - reserveFactorMantissa = newReserveFactorMantissa; - - emit NewReserveFactor( - oldReserveFactorMantissa, - newReserveFactorMantissa - ); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Accrues interest and reduces reserves by transferring from msg.sender - * @param addAmount Amount of addition to reserves - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _addReservesInternal(uint256 addAmount) - internal - nonReentrant - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return - fail( - Error(error), - FailureInfo.ADD_RESERVES_ACCRUE_INTEREST_FAILED - ); - } - - uint256 totalReservesNew; - uint256 actualAddAmount; - - if (accrualBlockNumber != getBlockNumber()) { - return ( - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.ADD_RESERVES_FRESH_CHECK - ) - ); - } - - actualAddAmount = doTransferIn(msg.sender, addAmount); - - totalReservesNew = totalReserves + actualAddAmount; - - require(totalReservesNew >= totalReserves, "CT22"); - - totalReserves = totalReservesNew; - - emit ReservesAdded(msg.sender, actualAddAmount, totalReservesNew); - - return (uint256(Error.NO_ERROR)); - } - - function _addSubsidyInternal(uint256 addAmount) - internal - nonReentrant - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - // accrueInterest emits logs on errors, but on top of that we want to log the fact that an attempted reduce reserves failed. - return fail(Error(error), FailureInfo.ADD_SUBSIDY_FUND_FAILED); - } - - uint256 subsidyFundNew; - uint256 actualAddAmount; - - if (accrualBlockNumber != getBlockNumber()) { - return ( - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.ADD_SUBSIDY_FUND_FRESH_CHECK - ) - ); - } - - actualAddAmount = doTransferIn(msg.sender, addAmount); - - subsidyFundNew = subsidyFund + actualAddAmount; - - require(subsidyFundNew >= subsidyFund, "CT22"); - - subsidyFund = subsidyFundNew; - - emit SubsidyAdded(msg.sender, actualAddAmount, subsidyFundNew); - - /* Return (NO_ERROR, actualAddAmount) */ - return (uint256(Error.NO_ERROR)); - } - - /** - * @notice Accrues interest and reduces reserves by transferring to admin - * @param reduceAmount Amount of reduction to reserves - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _reduceReserves(uint256 reduceAmount) - external - override - nonReentrant - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return - fail( - Error(error), - FailureInfo.REDUCE_RESERVES_ACCRUE_INTEREST_FAILED - ); - } - return _reduceReservesFresh(reduceAmount); - } - - /** - * @notice Reduces reserves by transferring to admin - * @dev Requires fresh interest accrual - * @param reduceAmount Amount of reduction to reserves - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _reduceReservesFresh(uint256 reduceAmount) - internal - returns (uint256) - { - uint256 totalReservesNew; - - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.REDUCE_RESERVES_ADMIN_CHECK - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.REDUCE_RESERVES_FRESH_CHECK - ); - } - - if (getCashPrior() < reduceAmount) { - return - fail( - Error.TOKEN_INSUFFICIENT_CASH, - FailureInfo.REDUCE_RESERVES_CASH_NOT_AVAILABLE - ); - } - - if (reduceAmount > totalReserves) { - return - fail(Error.BAD_INPUT, FailureInfo.REDUCE_RESERVES_VALIDATION); - } - - totalReservesNew = totalReserves - reduceAmount; - require(totalReservesNew <= totalReserves, "CT23"); - - totalReserves = totalReservesNew; - - doTransferOut(admin, reduceAmount); - - emit ReservesReduced(admin, reduceAmount, totalReservesNew); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice accrues interest and updates the interest rate model using _setInterestRateModelFresh - * @dev Admin function to accrue interest and update the interest rate model - * @param newInterestRateModel the new interest rate model to use - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setInterestRateModel(InterestRateModel newInterestRateModel) - public - override - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return - fail( - Error(error), - FailureInfo.SET_INTEREST_RATE_MODEL_ACCRUE_INTEREST_FAILED - ); - } - return _setInterestRateModelFresh(newInterestRateModel); - } - - /** - * @notice updates the interest rate model (*requires fresh interest accrual) - * @dev Admin function to update the interest rate model - * @param newInterestRateModel the new interest rate model to use - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setInterestRateModelFresh(InterestRateModel newInterestRateModel) - internal - returns (uint256) - { - InterestRateModel oldInterestRateModel; - - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_INTEREST_RATE_MODEL_OWNER_CHECK - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.SET_INTEREST_RATE_MODEL_FRESH_CHECK - ); - } - - oldInterestRateModel = interestRateModel; - - require(newInterestRateModel.isInterestRateModel(), "CT21"); - - interestRateModel = newInterestRateModel; - - emit NewMarketInterestRateModel( - oldInterestRateModel, - newInterestRateModel - ); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Gets balance of this contract in terms of the underlying - * @dev This excludes the value of the current message, if any - * @return The quantity of underlying owned by this contract - */ - function getCashPrior() internal view virtual returns (uint256); - - /** - * @dev Performs a transfer in, reverting upon failure. Returns the amount actually transferred to the protocol, in case of a fee. - * This may revert due to insufficient balance or insufficient allowance. - */ - function doTransferIn(address from, uint256 amount) - internal - virtual - returns (uint256); - - /** - * @dev Performs a transfer out, ideally returning an explanatory error code upon failure tather than reverting. - * If caller has not called checked protocol's balance, may revert due to insufficient cash held in the contract. - * If caller has checked protocol's balance, and verified it is >= amount, this should not revert in normal conditions. - */ - function doTransferOut(address payable to, uint256 amount) internal virtual; - - /** - * @dev Prevents a contract from calling itself, directly or indirectly. - */ - modifier nonReentrant() { - require(_notEntered, "re-entered"); - _notEntered = false; - _; - _notEntered = true; - } -} - - -// Dependency file: contracts/CErc20.sol - -// pragma solidity 0.8.6; - -// import "contracts/CToken.sol"; -// import "contracts/CTokenInterfaces.sol"; - -/** - * @title tropykus CErc20 Contract - * @notice CTokens which wrap an EIP-20 underlying - * @author tropykus - */ -contract CErc20 is CToken, CErc20Interface { - /** - * @notice Initialize the new money market - * @param underlying_ The address of the underlying asset - * @param comptroller_ The address of the Comptroller - * @param interestRateModel_ The address of the interest rate model - * @param initialExchangeRateMantissa_ The initial exchange rate, scaled by 1e18 - * @param name_ ERC-20 name of this token - * @param symbol_ ERC-20 symbol of this token - * @param decimals_ ERC-20 decimal precision of this token - */ - function initialize( - address underlying_, - ComptrollerInterface comptroller_, - InterestRateModel interestRateModel_, - uint256 initialExchangeRateMantissa_, - string memory name_, - string memory symbol_, - uint8 decimals_ - ) public { - // CToken initialize does the bulk of the work - super.initialize( - comptroller_, - interestRateModel_, - initialExchangeRateMantissa_, - name_, - symbol_, - decimals_ - ); - - // Set underlying and sanity check it - underlying = underlying_; - EIP20Interface(underlying).totalSupply(); - } - - /*** User Interface ***/ - - /** - * @notice Sender supplies assets into the market and receives cTokens in exchange - * @dev Accrues interest whether or not the operation succeeds, unless reverted - * @param mintAmount The amount of the underlying asset to supply - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function mint(uint256 mintAmount) external override returns (uint256) { - (uint256 err, ) = mintInternal(mintAmount); - return err; - } - - /** - * @notice Sender redeems cTokens in exchange for a specified amount of underlying asset - * @dev Accrues interest whether or not the operation succeeds, unless reverted - * @param redeemAmount The amount of underlying to redeem - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function redeem(uint256 redeemAmount) - external - override - returns (uint256) - { - return redeemUnderlyingInternal(redeemAmount); - } - - /** - * @notice Sender borrows assets from the protocol to their own address - * @param borrowAmount The amount of the underlying asset to borrow - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function borrow(uint256 borrowAmount) external override returns (uint256) { - return borrowInternal(borrowAmount); - } - - /** - * @notice Sender repays their own borrow - * @param repayAmount The amount to repay - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function repayBorrow(uint256 repayAmount) - external - override - returns (uint256) - { - (uint256 err, ) = repayBorrowInternal(repayAmount); - return err; - } - - /** - * @notice The sender liquidates the borrowers collateral. - * The collateral seized is transferred to the liquidator. - * @param borrower The borrower of this cToken to be liquidated - * @param repayAmount The amount of the underlying borrowed asset to repay - * @param cTokenCollateral The market in which to seize collateral from the borrower - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function liquidateBorrow( - address borrower, - uint256 repayAmount, - CTokenInterface cTokenCollateral - ) external override returns (uint256) { - (uint256 err, ) = liquidateBorrowInternal( - borrower, - repayAmount, - cTokenCollateral - ); - return err; - } - - /** - * @notice A public function to sweep accidental ERC-20 transfers to this contract. Tokens are sent to admin (timelock) - * @param token The address of the ERC-20 token to sweep - */ - function sweepToken(EIP20NonStandardInterface token) external override { - require(address(token) != underlying, "EC01"); - uint256 balance = token.balanceOf(address(this)); - token.transfer(admin, balance); - } - - /** - * @notice The sender adds to reserves. - * @param addAmount The amount fo underlying token to add as reserves - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _addReserves(uint256 addAmount) - external - override - returns (uint256) - { - return _addReservesInternal(addAmount); - } - - /*** Safe Token ***/ - - /** - * @notice Gets balance of this contract in terms of the underlying - * @dev This excludes the value of the current message, if any - * @return The quantity of underlying tokens owned by this contract - */ - function getCashPrior() internal view override returns (uint256) { - EIP20Interface token = EIP20Interface(underlying); - return token.balanceOf(address(this)); - } - - /** - * @dev Similar to EIP20 transfer, except it handles a False result from `transferFrom` and reverts in that case. - * This will revert due to insufficient balance or insufficient allowance. - * This function returns the actual amount received, - * which may be less than `amount` if there is a fee attached to the transfer. - * - * Note: This wrapper safely handles non-standard ERC-20 tokens that do not return a value. - * See here: https://medium.com/coinmonks/missing-return-value-bug-at-least-130-tokens-affected-d67bf08521ca - */ - function doTransferIn(address from, uint256 amount) - internal - override - returns (uint256) - { - EIP20NonStandardInterface token = EIP20NonStandardInterface(underlying); - uint256 balanceBefore = EIP20Interface(underlying).balanceOf( - address(this) - ); - token.transferFrom(from, address(this), amount); - - bool success; - assembly { - switch returndatasize() - case 0 { - // This is a non-standard ERC-20 - success := not(0) // set success to true - } - case 32 { - // This is a compliant ERC-20 - returndatacopy(0, 0, 32) - success := mload(0) // Set `success = returndata` of external call - } - default { - // This is an excessively non-compliant ERC-20, revert. - revert(0, 0) - } - } - require(success, "EC02"); - - // Calculate the amount that was *actually* transferred - uint256 balanceAfter = EIP20Interface(underlying).balanceOf( - address(this) - ); - require(balanceAfter >= balanceBefore, "EC03"); - return balanceAfter - balanceBefore; // underflow already checked above, just subtract - } - - /** - * @dev Similar to EIP20 transfer, except it handles a False success from `transfer` and returns an explanatory - * error code rather than reverting. If caller has not called checked protocol's balance, this may revert due to - * insufficient cash held in this contract. If caller has checked protocol's balance prior to this call, and verified - * it is >= amount, this should not revert in normal conditions. - * - * Note: This wrapper safely handles non-standard ERC-20 tokens that do not return a value. - * See here: https://medium.com/coinmonks/missing-return-value-bug-at-least-130-tokens-affected-d67bf08521ca - */ - function doTransferOut(address payable to, uint256 amount) - internal - virtual - override - { - EIP20NonStandardInterface token = EIP20NonStandardInterface(underlying); - token.transfer(to, amount); - - bool success; - assembly { - switch returndatasize() - case 0 { - // This is a non-standard ERC-20 - success := not(0) // set success to true - } - case 32 { - // This is a complaint ERC-20 - returndatacopy(0, 0, 32) - success := mload(0) // Set `success = returndata` of external call - } - default { - // This is an excessively non-compliant ERC-20, revert. - revert(0, 0) - } - } - require(success, "CE01"); - } -} - - -// Root file: contracts/CErc20Immutable.sol - -pragma solidity 0.8.6; - -// import "contracts/CErc20.sol"; - -/** - * @title tropykus CErc20Immutable Contract - * @notice CTokens which wrap an EIP-20 underlying and are immutable - * @author tropykus - */ -contract CErc20Immutable is CErc20 { - /** - * @notice Construct a new money market - * @param underlying_ The address of the underlying asset - * @param comptroller_ The address of the Comptroller - * @param interestRateModel_ The address of the interest rate model - * @param initialExchangeRateMantissa_ The initial exchange rate, scaled by 1e18 - * @param name_ ERC-20 name of this token - * @param symbol_ ERC-20 symbol of this token - * @param decimals_ ERC-20 decimal precision of this token - * @param admin_ Address of the administrator of this token - */ - constructor( - address underlying_, - ComptrollerInterface comptroller_, - InterestRateModel interestRateModel_, - uint256 initialExchangeRateMantissa_, - string memory name_, - string memory symbol_, - uint8 decimals_, - address payable admin_ - ) { - // Creator of the contract is admin during initialization - admin = payable(msg.sender); - - // Initialize the market - initialize( - underlying_, - comptroller_, - interestRateModel_, - initialExchangeRateMantissa_, - name_, - symbol_, - decimals_ - ); - - // Set the proper admin now that initialization is done - admin = admin_; - } -} diff --git a/flatten/CRBTC.sol b/flatten/CRBTC.sol deleted file mode 100644 index 33d77b6..0000000 --- a/flatten/CRBTC.sol +++ /dev/null @@ -1,4118 +0,0 @@ -// Dependency file: contracts/ComptrollerInterface.sol - -// SPDX-License-Identifier: UNLICENSED -// pragma solidity 0.8.6; - -abstract contract ComptrollerInterface { - /// @notice Indicator that this is a Comptroller contract (for inspection) - bool public constant isComptroller = true; - - /*** Assets You Are In ***/ - - function enterMarkets(address[] calldata cTokens) - external - virtual - returns (uint256[] memory); - - function exitMarket(address cToken) external virtual returns (uint256); - - /*** Policy Hooks ***/ - - function mintAllowed( - address cToken, - address minter, - uint256 mintAmount - ) external virtual returns (uint256); - - function mintVerify( - address cToken, - address minter, - uint256 mintAmount, - uint256 mintTokens - ) external virtual; - - function redeemAllowed( - address cToken, - address redeemer, - uint256 redeemTokens - ) external virtual returns (uint256); - - function redeemVerify( - address cToken, - address redeemer, - uint256 redeemAmount, - uint256 redeemTokens - ) external virtual; - - function borrowAllowed( - address cToken, - address borrower, - uint256 borrowAmount - ) external virtual returns (uint256); - - function borrowVerify( - address cToken, - address borrower, - uint256 borrowAmount - ) external virtual; - - function repayBorrowAllowed( - address cToken, - address payer, - address borrower, - uint256 repayAmount - ) external virtual returns (uint256); - - function repayBorrowVerify( - address cToken, - address payer, - address borrower, - uint256 repayAmount, - uint256 borrowerIndex - ) external virtual; - - function liquidateBorrowAllowed( - address cTokenBorrowed, - address cTokenCollateral, - address liquidator, - address borrower, - uint256 repayAmount - ) external virtual returns (uint256); - - function liquidateBorrowVerify( - address cTokenBorrowed, - address cTokenCollateral, - address liquidator, - address borrower, - uint256 repayAmount, - uint256 seizeTokens - ) external virtual; - - function seizeAllowed( - address cTokenCollateral, - address cTokenBorrowed, - address liquidator, - address borrower, - uint256 seizeTokens - ) external virtual returns (uint256); - - function seizeVerify( - address cTokenCollateral, - address cTokenBorrowed, - address liquidator, - address borrower, - uint256 seizeTokens - ) external virtual; - - function transferAllowed( - address cToken, - address src, - address dst, - uint256 transferTokens - ) external virtual returns (uint256); - - function transferVerify( - address cToken, - address src, - address dst, - uint256 transferTokens - ) external virtual; - - /*** Liquidity/Liquidation Calculations ***/ - - function liquidateCalculateSeizeTokens( - address cTokenBorrowed, - address cTokenCollateral, - uint256 repayAmount - ) external view virtual returns (uint256, uint256); -} - - -// Dependency file: contracts/CarefulMath.sol - -// pragma solidity 0.8.6; - -/** - * @title Careful Math - * @author tropykus - * @notice Derived from OpenZeppelin's SafeMath library - * https://github.com/OpenZeppelin/openzeppelin-solidity/blob/master/contracts/math/SafeMath.sol - */ -contract CarefulMath { - - /** - * @dev Possible error codes that we can return - */ - enum MathError { - NO_ERROR, - DIVISION_BY_ZERO, - INTEGER_OVERFLOW, - INTEGER_UNDERFLOW - } - - /** - * @dev Multiplies two numbers, returns an error on overflow. - */ - function mulUInt(uint a, uint b) internal pure returns (MathError, uint) { - if (a == 0) { - return (MathError.NO_ERROR, 0); - } - - uint c = a * b; - - if (c / a != b) { - return (MathError.INTEGER_OVERFLOW, 0); - } else { - return (MathError.NO_ERROR, c); - } - } - - /** - * @dev Integer division of two numbers, truncating the quotient. - */ - function divUInt(uint a, uint b) internal pure returns (MathError, uint) { - if (b == 0) { - return (MathError.DIVISION_BY_ZERO, 0); - } - - return (MathError.NO_ERROR, a / b); - } - - /** - * @dev Subtracts two numbers, returns an error on overflow (i.e. if subtrahend is greater than minuend). - */ - function subUInt(uint a, uint b) internal pure returns (MathError, uint) { - if (b <= a) { - return (MathError.NO_ERROR, a - b); - } else { - return (MathError.INTEGER_UNDERFLOW, 0); - } - } - - /** - * @dev Adds two numbers, returns an error on overflow. - */ - function addUInt(uint a, uint b) internal pure returns (MathError, uint) { - uint c = a + b; - - if (c >= a) { - return (MathError.NO_ERROR, c); - } else { - return (MathError.INTEGER_OVERFLOW, 0); - } - } - - /** - * @dev add a and b and then subtract c - */ - function addThenSubUInt(uint a, uint b, uint c) internal pure returns (MathError, uint) { - (MathError err0, uint sum) = addUInt(a, b); - - if (err0 != MathError.NO_ERROR) { - return (err0, 0); - } - - return subUInt(sum, c); - } -} - - -// Dependency file: contracts/ExponentialNoError.sol - -// pragma solidity 0.8.6; - -/** - * @title Exponential module for storing fixed-precision decimals - * @author tropykus - * @notice Exp is a struct which stores decimals with a fixed precision of 18 decimal places. - * Thus, if we wanted to store the 5.1, mantissa would store 5.1e18. That is: - * `Exp({mantissa: 5100000000000000000})`. - */ -contract ExponentialNoError { - uint constant expScale = 1e18; - uint constant doubleScale = 1e36; - uint constant halfExpScale = expScale/2; - uint constant mantissaOne = expScale; - - struct Exp { - uint mantissa; - } - - struct Double { - uint mantissa; - } - - /** - * @dev Truncates the given exp to a whole number value. - * For example, truncate(Exp{mantissa: 15 * expScale}) = 15 - */ - function truncate(Exp memory exp) pure internal returns (uint) { - // Note: We are not using careful math here as we're performing a division that cannot fail - return exp.mantissa / expScale; - } - - /** - * @dev Multiply an Exp by a scalar, then truncate to return an unsigned integer. - */ - function mul_ScalarTruncate(Exp memory a, uint scalar) pure internal returns (uint) { - Exp memory product = mul_(a, scalar); - return truncate(product); - } - - /** - * @dev Multiply an Exp by a scalar, truncate, then add an to an unsigned integer, returning an unsigned integer. - */ - function mul_ScalarTruncateAddUInt(Exp memory a, uint scalar, uint addend) pure internal returns (uint) { - Exp memory product = mul_(a, scalar); - return add_(truncate(product), addend); - } - - /** - * @dev Checks if first Exp is less than second Exp. - */ - function lessThanExp(Exp memory left, Exp memory right) pure internal returns (bool) { - return left.mantissa < right.mantissa; - } - - /** - * @dev Checks if left Exp <= right Exp. - */ - function lessThanOrEqualExp(Exp memory left, Exp memory right) pure internal returns (bool) { - return left.mantissa <= right.mantissa; - } - - /** - * @dev Checks if left Exp > right Exp. - */ - function greaterThanExp(Exp memory left, Exp memory right) pure internal returns (bool) { - return left.mantissa > right.mantissa; - } - - /** - * @dev returns true if Exp is exactly zero - */ - function isZeroExp(Exp memory value) pure internal returns (bool) { - return value.mantissa == 0; - } - - function safe224(uint n, string memory errorMessage) pure internal returns (uint224) { - require(n < 2**224, errorMessage); - return uint224(n); - } - - function safe32(uint n, string memory errorMessage) pure internal returns (uint32) { - require(n < 2**32, errorMessage); - return uint32(n); - } - - function add_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { - return Exp({mantissa: add_(a.mantissa, b.mantissa)}); - } - - function add_(Double memory a, Double memory b) pure internal returns (Double memory) { - return Double({mantissa: add_(a.mantissa, b.mantissa)}); - } - - function add_(uint a, uint b) pure internal returns (uint) { - return add_(a, b, "addition overflow"); - } - - function add_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { - uint c = a + b; - require(c >= a, errorMessage); - return c; - } - - function sub_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { - return Exp({mantissa: sub_(a.mantissa, b.mantissa)}); - } - - function sub_(Double memory a, Double memory b) pure internal returns (Double memory) { - return Double({mantissa: sub_(a.mantissa, b.mantissa)}); - } - - function sub_(uint a, uint b) pure internal returns (uint) { - return sub_(a, b, "subtraction underflow"); - } - - function sub_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { - require(b <= a, errorMessage); - return a - b; - } - - function mul_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { - return Exp({mantissa: mul_(a.mantissa, b.mantissa) / expScale}); - } - - function mul_(Exp memory a, uint b) pure internal returns (Exp memory) { - return Exp({mantissa: mul_(a.mantissa, b)}); - } - - function mul_(uint a, Exp memory b) pure internal returns (uint) { - return mul_(a, b.mantissa) / expScale; - } - - function mul_(Double memory a, Double memory b) pure internal returns (Double memory) { - return Double({mantissa: mul_(a.mantissa, b.mantissa) / doubleScale}); - } - - function mul_(Double memory a, uint b) pure internal returns (Double memory) { - return Double({mantissa: mul_(a.mantissa, b)}); - } - - function mul_(uint a, Double memory b) pure internal returns (uint) { - return mul_(a, b.mantissa) / doubleScale; - } - - function mul_(uint a, uint b) pure internal returns (uint) { - return mul_(a, b, "multiplication overflow"); - } - - function mul_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { - if (a == 0 || b == 0) { - return 0; - } - uint c = a * b; - require(c / a == b, errorMessage); - return c; - } - - function div_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { - return Exp({mantissa: div_(mul_(a.mantissa, expScale), b.mantissa)}); - } - - function div_(Exp memory a, uint b) pure internal returns (Exp memory) { - return Exp({mantissa: div_(a.mantissa, b)}); - } - - function div_(uint a, Exp memory b) pure internal returns (uint) { - return div_(mul_(a, expScale), b.mantissa); - } - - function div_(Double memory a, Double memory b) pure internal returns (Double memory) { - return Double({mantissa: div_(mul_(a.mantissa, doubleScale), b.mantissa)}); - } - - function div_(Double memory a, uint b) pure internal returns (Double memory) { - return Double({mantissa: div_(a.mantissa, b)}); - } - - function div_(uint a, Double memory b) pure internal returns (uint) { - return div_(mul_(a, doubleScale), b.mantissa); - } - - function div_(uint a, uint b) pure internal returns (uint) { - return div_(a, b, "divide by zero"); - } - - function div_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { - require(b > 0, errorMessage); - return a / b; - } - - function fraction(uint a, uint b) pure internal returns (Double memory) { - return Double({mantissa: div_(mul_(a, doubleScale), b)}); - } -} - - -// Dependency file: contracts/Exponential.sol - -// pragma solidity 0.8.6; - -// import "contracts/CarefulMath.sol"; -// import "contracts/ExponentialNoError.sol"; - -/** - * @title Exponential module for storing fixed-precision decimals - * @author tropykus - * @dev Legacy contract for compatibility reasons with existing contracts that still use MathError - * @notice Exp is a struct which stores decimals with a fixed precision of 18 decimal places. - * Thus, if we wanted to store the 5.1, mantissa would store 5.1e18. That is: - * `Exp({mantissa: 5100000000000000000})`. - */ -contract Exponential is CarefulMath, ExponentialNoError { - /** - * @dev Creates an exponential from numerator and denominator values. - * Note: Returns an error if (`num` * 10e18) > MAX_INT, - * or if `denom` is zero. - */ - function getExp(uint num, uint denom) internal pure returns (MathError, Exp memory) { - (MathError err0, uint scaledNumerator) = mulUInt(num, expScale); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - - (MathError err1, uint rational) = divUInt(scaledNumerator, denom); - if (err1 != MathError.NO_ERROR) { - return (err1, Exp({mantissa: 0})); - } - - return (MathError.NO_ERROR, Exp({mantissa: rational})); - } - - /** - * @dev Adds two exponentials, returning a new exponential. - */ - function addExp(Exp memory a, Exp memory b) internal pure returns (MathError, Exp memory) { - (MathError error, uint result) = addUInt(a.mantissa, b.mantissa); - - return (error, Exp({mantissa: result})); - } - - /** - * @dev Subtracts two exponentials, returning a new exponential. - */ - function subExp(Exp memory a, Exp memory b) internal pure returns (MathError, Exp memory) { - (MathError error, uint result) = subUInt(a.mantissa, b.mantissa); - - return (error, Exp({mantissa: result})); - } - - /** - * @dev Multiply an Exp by a scalar, returning a new Exp. - */ - function mulScalar(Exp memory a, uint scalar) internal pure returns (MathError, Exp memory) { - (MathError err0, uint scaledMantissa) = mulUInt(a.mantissa, scalar); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - - return (MathError.NO_ERROR, Exp({mantissa: scaledMantissa})); - } - - /** - * @dev Multiply an Exp by a scalar, then truncate to return an unsigned integer. - */ - function mulScalarTruncate(Exp memory a, uint scalar) internal pure returns (MathError, uint) { - (MathError err, Exp memory product) = mulScalar(a, scalar); - if (err != MathError.NO_ERROR) { - return (err, 0); - } - - return (MathError.NO_ERROR, truncate(product)); - } - - /** - * @dev Multiply an Exp by a scalar, truncate, then add an to an unsigned integer, returning an unsigned integer. - */ - function mulScalarTruncateAddUInt(Exp memory a, uint scalar, uint addend) internal pure returns (MathError, uint) { - (MathError err, Exp memory product) = mulScalar(a, scalar); - if (err != MathError.NO_ERROR) { - return (err, 0); - } - - return addUInt(truncate(product), addend); - } - - /** - * @dev Divide an Exp by a scalar, returning a new Exp. - */ - function divScalar(Exp memory a, uint scalar) internal pure returns (MathError, Exp memory) { - (MathError err0, uint descaledMantissa) = divUInt(a.mantissa, scalar); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - - return (MathError.NO_ERROR, Exp({mantissa: descaledMantissa})); - } - - /** - * @dev Divide a scalar by an Exp, returning a new Exp. - */ - function divScalarByExp(uint scalar, Exp memory divisor) internal pure returns (MathError, Exp memory) { - /* - We are doing this as: - getExp(mulUInt(expScale, scalar), divisor.mantissa) - - How it works: - Exp = a / b; - Scalar = s; - `s / (a / b)` = `b * s / a` and since for an Exp `a = mantissa, b = expScale` - */ - (MathError err0, uint numerator) = mulUInt(expScale, scalar); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - return getExp(numerator, divisor.mantissa); - } - - /** - * @dev Divide a scalar by an Exp, then truncate to return an unsigned integer. - */ - function divScalarByExpTruncate(uint scalar, Exp memory divisor) internal pure returns (MathError, uint) { - (MathError err, Exp memory fraction) = divScalarByExp(scalar, divisor); - if (err != MathError.NO_ERROR) { - return (err, 0); - } - - return (MathError.NO_ERROR, truncate(fraction)); - } - - /** - * @dev Multiplies two exponentials, returning a new exponential. - */ - function mulExp(Exp memory a, Exp memory b) internal pure returns (MathError, Exp memory) { - - (MathError err0, uint doubleScaledProduct) = mulUInt(a.mantissa, b.mantissa); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - - // We add half the scale before dividing so that we get rounding instead of truncation. - // See "Listing 6" and text above it at https://accu.org/index.php/journals/1717 - // Without this change, a result like 6.6...e-19 will be truncated to 0 instead of being rounded to 1e-18. - (MathError err1, uint doubleScaledProductWithHalfScale) = addUInt(halfExpScale, doubleScaledProduct); - if (err1 != MathError.NO_ERROR) { - return (err1, Exp({mantissa: 0})); - } - - (MathError err2, uint product) = divUInt(doubleScaledProductWithHalfScale, expScale); - // The only error `div` can return is MathError.DIVISION_BY_ZERO but we control `expScale` and it is not zero. - assert(err2 == MathError.NO_ERROR); - - return (MathError.NO_ERROR, Exp({mantissa: product})); - } - - /** - * @dev Multiplies two exponentials given their mantissas, returning a new exponential. - */ - function mulExp(uint a, uint b) internal pure returns (MathError, Exp memory) { - return mulExp(Exp({mantissa: a}), Exp({mantissa: b})); - } - - /** - * @dev Multiplies three exponentials, returning a new exponential. - */ - function mulExp3(Exp memory a, Exp memory b, Exp memory c) internal pure returns (MathError, Exp memory) { - (MathError err, Exp memory ab) = mulExp(a, b); - if (err != MathError.NO_ERROR) { - return (err, ab); - } - return mulExp(ab, c); - } - - /** - * @dev Divides two exponentials, returning a new exponential. - * (a/scale) / (b/scale) = (a/scale) * (scale/b) = a/b, - * which we can scale as an Exp by calling getExp(a.mantissa, b.mantissa) - */ - function divExp(Exp memory a, Exp memory b) internal pure returns (MathError, Exp memory) { - return getExp(a.mantissa, b.mantissa); - } -} - - -// Dependency file: contracts/SafeMath.sol - -// pragma solidity 0.8.6; - -// From https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/math/Math.sol -// Subject to the MIT license. - -/** - * @dev Wrappers over Solidity's arithmetic operations with added overflow - * checks. - * - * Arithmetic operations in Solidity wrap on overflow. This can easily result - * in bugs, because programmers usually assume that an overflow raises an - * error, which is the standard behavior in high level programming languages. - * `SafeMath` restores this intuition by reverting the transaction when an - * operation overflows. - * - * Using this library instead of the unchecked operations eliminates an entire - * class of bugs, so it's recommended to use it always. - */ -library SafeMath { - /** - * @dev Returns the addition of two unsigned integers, reverting on overflow. - * - * Counterpart to Solidity's `+` operator. - * - * Requirements: - * - Addition cannot overflow. - */ - function add(uint256 a, uint256 b) internal pure returns (uint256) { - uint256 c = a + b; - require(c >= a, "SafeMath: addition overflow"); - - return c; - } - - /** - * @dev Returns the addition of two unsigned integers, reverting with custom message on overflow. - * - * Counterpart to Solidity's `+` operator. - * - * Requirements: - * - Addition cannot overflow. - */ - function add(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - uint256 c = a + b; - require(c >= a, errorMessage); - - return c; - } - - /** - * @dev Returns the subtraction of two unsigned integers, reverting on underflow (when the result is negative). - * - * Counterpart to Solidity's `-` operator. - * - * Requirements: - * - Subtraction cannot underflow. - */ - function sub(uint256 a, uint256 b) internal pure returns (uint256) { - return sub(a, b, "SafeMath: subtraction underflow"); - } - - /** - * @dev Returns the subtraction of two unsigned integers, reverting with custom message on underflow (when the result is negative). - * - * Counterpart to Solidity's `-` operator. - * - * Requirements: - * - Subtraction cannot underflow. - */ - function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - require(b <= a, errorMessage); - uint256 c = a - b; - - return c; - } - - /** - * @dev Returns the multiplication of two unsigned integers, reverting on overflow. - * - * Counterpart to Solidity's `*` operator. - * - * Requirements: - * - Multiplication cannot overflow. - */ - function mul(uint256 a, uint256 b) internal pure returns (uint256) { - // Gas optimization: this is cheaper than requiring 'a' not being zero, but the - // benefit is lost if 'b' is also tested. - // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 - if (a == 0) { - return 0; - } - - uint256 c = a * b; - require(c / a == b, "SafeMath: multiplication overflow"); - - return c; - } - - /** - * @dev Returns the multiplication of two unsigned integers, reverting on overflow. - * - * Counterpart to Solidity's `*` operator. - * - * Requirements: - * - Multiplication cannot overflow. - */ - function mul(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - // Gas optimization: this is cheaper than requiring 'a' not being zero, but the - // benefit is lost if 'b' is also tested. - // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 - if (a == 0) { - return 0; - } - - uint256 c = a * b; - require(c / a == b, errorMessage); - - return c; - } - - /** - * @dev Returns the integer division of two unsigned integers. - * Reverts on division by zero. The result is rounded towards zero. - * - * Counterpart to Solidity's `/` operator. Note: this function uses a - * `revert` opcode (which leaves remaining gas untouched) while Solidity - * uses an invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function div(uint256 a, uint256 b) internal pure returns (uint256) { - return div(a, b, "SafeMath: division by zero"); - } - - /** - * @dev Returns the integer division of two unsigned integers. - * Reverts with custom message on division by zero. The result is rounded towards zero. - * - * Counterpart to Solidity's `/` operator. Note: this function uses a - * `revert` opcode (which leaves remaining gas untouched) while Solidity - * uses an invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - // Solidity only automatically asserts when dividing by 0 - require(b > 0, errorMessage); - uint256 c = a / b; - // assert(a == b * c + a % b); // There is no case in which this doesn't hold - - return c; - } - - /** - * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), - * Reverts when dividing by zero. - * - * Counterpart to Solidity's `%` operator. This function uses a `revert` - * opcode (which leaves remaining gas untouched) while Solidity uses an - * invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function mod(uint256 a, uint256 b) internal pure returns (uint256) { - return mod(a, b, "SafeMath: modulo by zero"); - } - - /** - * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), - * Reverts with custom message when dividing by zero. - * - * Counterpart to Solidity's `%` operator. This function uses a `revert` - * opcode (which leaves remaining gas untouched) while Solidity uses an - * invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - require(b != 0, errorMessage); - return a % b; - } -} - - -// Dependency file: contracts/InterestRateModel.sol - -// pragma solidity 0.8.6; - -// import "contracts/Exponential.sol"; -// import "contracts/SafeMath.sol"; - -/** - * @title tropykus InterestRateModel Interface - * @author tropykus - */ -abstract contract InterestRateModel is Exponential { - using SafeMath for uint256; - - /// @notice Indicator that this is an InterestRateModel contract (for inspection) - bool public constant isInterestRateModel = true; - bool public isTropykusInterestRateModel; - - /** - * @notice The approximate number of blocks per year that is assumed by the interest rate model - */ - uint256 public constant blocksPerYear = 1051200; - - /** - * @notice Calculates the utilization rate of the market: `borrows / (cash + borrows - reserves)` - * @param cash The amount of cash in the market - * @param borrows The amount of borrows in the market - * @param reserves The amount of reserves in the market (currently unused) - * @return The utilization rate as a mantissa between [0, 1e18] - */ - function utilizationRate( - uint256 cash, - uint256 borrows, - uint256 reserves - ) public pure virtual returns (uint256) { - // Utilization rate is 0 when there are no borrows - if (borrows == 0) { - return 0; - } - - return borrows.mul(1e18).div(cash.add(borrows).sub(reserves)); - } - - /** - * @notice Calculates the current borrow interest rate per block - * @param cash The total amount of cash the market has - * @param borrows The total amount of borrows the market has outstanding - * @param reserves The total amnount of reserves the market has - * @return The borrow rate per block (as a percentage, and scaled by 1e18) - */ - function getBorrowRate( - uint256 cash, - uint256 borrows, - uint256 reserves - ) external view virtual returns (uint256); - - /** - * @notice Calculates the current supply interest rate per block - * @param cash The total amount of cash the market has - * @param borrows The total amount of borrows the market has outstanding - * @param reserves The total amnount of reserves the market has - * @param reserveFactorMantissa The current reserve factor the market has - * @return The supply rate per block (as a percentage, and scaled by 1e18) - */ - function getSupplyRate( - uint256 cash, - uint256 borrows, - uint256 reserves, - uint256 reserveFactorMantissa - ) external view virtual returns (uint256); - - function getExchangeRate( - uint256 _totalCash, - uint256 _totalBorrows, - uint256 _totalReserves, - uint256 _totalSupply - ) public pure returns (MathError, uint256) { - /* - * exchangeRate = (totalCash + totalBorrows - totalReserves) / totalSupply - */ - Exp memory exchangeRate; - MathError mathErr; - uint256 cashPlusBorrowsMinusReserves; - (mathErr, cashPlusBorrowsMinusReserves) = addThenSubUInt( - _totalCash, - _totalBorrows, - _totalReserves - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - (mathErr, exchangeRate) = getExp( - cashPlusBorrowsMinusReserves, - _totalSupply - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - - return (MathError.NO_ERROR, exchangeRate.mantissa); - } - - function isAboveOptimal( - uint256 cash, - uint256 borrows, - uint256 reserves - ) public view virtual returns (bool) { - cash; - borrows; - reserves; - return false; - } -} - - -// Dependency file: contracts/EIP20NonStandardInterface.sol - -// pragma solidity 0.8.6; - -/** - * @title EIP20NonStandardInterface - * @dev Version of ERC20 with no return values for `transfer` and `transferFrom` - * See https://medium.com/coinmonks/missing-return-value-bug-at-least-130-tokens-affected-d67bf08521ca - */ -interface EIP20NonStandardInterface { - /** - * @notice Get the total number of tokens in circulation - * @return The supply of tokens - */ - function totalSupply() external view returns (uint256); - - /** - * @notice Gets the balance of the specified address - * @param owner The address from which the balance will be retrieved - * @return balance The balance - */ - function balanceOf(address owner) external view returns (uint256 balance); - - /// - /// !!!!!!!!!!!!!! - /// !!! NOTICE !!! `transfer` does not return a value, in violation of the ERC-20 specification - /// !!!!!!!!!!!!!! - /// - - /** - * @notice Transfer `amount` tokens from `msg.sender` to `dst` - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - */ - function transfer(address dst, uint256 amount) external; - - /// - /// !!!!!!!!!!!!!! - /// !!! NOTICE !!! `transferFrom` does not return a value, in violation of the ERC-20 specification - /// !!!!!!!!!!!!!! - /// - - /** - * @notice Transfer `amount` tokens from `src` to `dst` - * @param src The address of the source account - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - */ - function transferFrom( - address src, - address dst, - uint256 amount - ) external; - - /** - * @notice Approve `spender` to transfer up to `amount` from `src` - * @dev This will overwrite the approval amount for `spender` - * and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve) - * @param spender The address of the account which may transfer tokens - * @param amount The number of tokens that are approved - * @return success Whether or not the approval succeeded - */ - function approve(address spender, uint256 amount) - external - returns (bool success); - - /** - * @notice Get the current allowance from `owner` for `spender` - * @param owner The address of the account which owns the tokens to be spent - * @param spender The address of the account which may transfer tokens - * @return remaining The number of tokens allowed to be spent - */ - function allowance(address owner, address spender) - external - view - returns (uint256 remaining); - - event Transfer(address indexed from, address indexed to, uint256 amount); - event Approval( - address indexed owner, - address indexed spender, - uint256 amount - ); -} - - -// Dependency file: contracts/CTokenInterfaces.sol - -// pragma solidity 0.8.6; - -// import "contracts/ComptrollerInterface.sol"; -// import "contracts/InterestRateModel.sol"; -// import "contracts/EIP20NonStandardInterface.sol"; - -contract CTokenStorage { - /** - * @dev Guard variable for re-entrancy checks - */ - bool internal _notEntered; - - /** - * @notice EIP-20 token name for this token - */ - string public name; - - /** - * @notice EIP-20 token symbol for this token - */ - string public symbol; - - /** - * @notice EIP-20 token decimals for this token - */ - uint8 public decimals; - - /** - * @notice Maximum borrow rate that can ever be applied (.0005% / block) - */ - - uint256 internal constant borrowRateMaxMantissa = 0.0005e16; - - /** - * @notice Maximum fraction of interest that can be set aside for reserves - */ - uint256 internal constant reserveFactorMaxMantissa = 1e18; - - /** - * @notice Administrator for this contract - */ - address payable public admin; - - /** - * @notice Pending administrator for this contract - */ - address payable public pendingAdmin; - - /** - * @notice Contract which oversees inter-cToken operations - */ - ComptrollerInterface public comptroller; - - /** - * @notice Model which tells what the current interest rate should be - */ - InterestRateModel public interestRateModel; - - /** - * @notice Initial exchange rate used when minting the first CTokens (used when totalSupply = 0) - */ - uint256 public initialExchangeRateMantissa; - - /** - * @notice Fraction of interest currently set aside for reserves - */ - uint256 public reserveFactorMantissa; - - /** - * @notice Block number that interest was last accrued at - */ - uint256 public accrualBlockNumber; - - /** - * @notice Accumulator of the total earned interest rate since the opening of the market - */ - uint256 public borrowIndex; - - /** - * @notice Total amount of outstanding borrows of the underlying in this market - */ - uint256 public totalBorrows; - - /** - * @notice Total amount of reserves of the underlying held in this market - */ - uint256 public totalReserves; - - /** - * @notice Total number of tokens in circulation - */ - uint256 public totalSupply; - - uint256 public subsidyFund; - - struct SupplySnapshot { - uint256 tokens; - uint256 underlyingAmount; - uint256 suppliedAt; - uint256 promisedSupplyRate; - } - - /** - * @notice Official record of token balances for each account - */ - mapping(address => SupplySnapshot) internal accountTokens; - - /** - * @notice Approved token transfer amounts on behalf of others - */ - mapping(address => mapping(address => uint256)) internal transferAllowances; - - /** - * @notice Container for borrow balance information - * @member principal Total balance (with accrued interest), after applying the most recent balance-changing action - * @member interestIndex Global borrowIndex as of the most recent balance-changing action - */ - struct BorrowSnapshot { - uint256 principal; - uint256 interestIndex; - } - - /** - * @notice Mapping of account addresses to outstanding borrow balances - */ - mapping(address => BorrowSnapshot) internal accountBorrows; -} - -abstract contract CTokenInterface is CTokenStorage { - /** - * @notice Indicator that this is a CToken contract (for inspection) - */ - bool public constant isCToken = true; - - /*** Market Events ***/ - - /** - * @notice Event emitted when interest is accrued - */ - event AccrueInterest( - uint256 cashPrior, - uint256 interestAccumulated, - uint256 borrowIndex, - uint256 totalBorrows - ); - - /** - * @notice Event emitted when tokens are minted - */ - event Mint(address indexed minter, uint256 mintAmount, uint256 mintTokens); - - /** - * @notice Event emitted when tokens are redeemed - */ - event Redeem( - address indexed redeemer, - uint256 redeemAmount, - uint256 redeemTokens - ); - - /** - * @notice Event emitted when underlying is borrowed - */ - event Borrow( - address indexed borrower, - uint256 borrowAmount, - uint256 accountBorrows, - uint256 totalBorrows - ); - - /** - * @notice Event emitted when a borrow is repaid - */ - event RepayBorrow( - address indexed payer, - address indexed borrower, - uint256 repayAmount, - uint256 accountBorrows, - uint256 totalBorrows - ); - - /** - * @notice Event emitted when a borrow is liquidated - */ - event LiquidateBorrow( - address indexed liquidator, - address indexed borrower, - uint256 repayAmount, - address indexed cTokenCollateral, - uint256 seizeTokens - ); - - /*** Admin Events ***/ - - /** - * @notice Event emitted when pendingAdmin is changed - */ - event NewPendingAdmin(address oldPendingAdmin, address newPendingAdmin); - - /** - * @notice Event emitted when pendingAdmin is accepted, which means admin is updated - */ - event NewAdmin(address oldAdmin, address newAdmin); - - /** - * @notice Event emitted when comptroller is changed - */ - event NewComptroller( - ComptrollerInterface oldComptroller, - ComptrollerInterface newComptroller - ); - - /** - * @notice Event emitted when interestRateModel is changed - */ - event NewMarketInterestRateModel( - InterestRateModel oldInterestRateModel, - InterestRateModel newInterestRateModel - ); - - /** - * @notice Event emitted when the reserve factor is changed - */ - event NewReserveFactor( - uint256 oldReserveFactorMantissa, - uint256 newReserveFactorMantissa - ); - - /** - * @notice Event emitted when the reserves are added - */ - event ReservesAdded( - address benefactor, - uint256 addAmount, - uint256 newTotalReserves - ); - - event SubsidyAdded( - address benefactor, - uint256 addAmount, - uint256 newSubsidyFund - ); - - /** - * @notice Event emitted when the reserves are reduced - */ - event ReservesReduced( - address admin, - uint256 reduceAmount, - uint256 newTotalReserves - ); - - /** - * @notice EIP20 Transfer event - */ - event Transfer(address indexed from, address indexed to, uint256 amount); - - /** - * @notice EIP20 Approval event - */ - event Approval( - address indexed owner, - address indexed spender, - uint256 amount - ); - - /** - * @notice Failure event - */ - event CTokenStorageFailure(uint256 error, uint256 info, uint256 detail); - - /*** User Interface ***/ - - function transfer(address dst, uint256 amount) - external - virtual - returns (bool); - - function transferFrom( - address src, - address dst, - uint256 amount - ) external virtual returns (bool); - - function approve(address spender, uint256 amount) - external - virtual - returns (bool); - - function allowance(address owner, address spender) - external - view - virtual - returns (uint256); - - function balanceOf(address owner) external view virtual returns (uint256); - - function balanceOfUnderlying(address owner) - external - virtual - returns (uint256); - - function getAccountSnapshot(address account) - external - view - virtual - returns ( - uint256, - uint256, - uint256, - uint256 - ); - - function borrowRatePerBlock() external view virtual returns (uint256); - - function supplyRatePerBlock() external view virtual returns (uint256); - - function totalBorrowsCurrent() external virtual returns (uint256); - - function borrowBalanceCurrent(address account) - external - virtual - returns (uint256); - - function borrowBalanceStored(address account) - public - view - virtual - returns (uint256); - - function exchangeRateCurrent() public virtual returns (uint256); - - function exchangeRateStored() public view virtual returns (uint256); - - function getCash() external view virtual returns (uint256); - - function accrueInterest() public virtual returns (uint256); - - function seize( - address liquidator, - address borrower, - uint256 seizeTokens - ) external virtual returns (uint256); - - /*** Admin Functions ***/ - - function _setPendingAdmin(address payable newPendingAdmin) - external - virtual - returns (uint256); - - function _acceptAdmin() external virtual returns (uint256); - - function _setComptroller(ComptrollerInterface newComptroller) - public - virtual - returns (uint256); - - function _setReserveFactor(uint256 newReserveFactorMantissa) - external - virtual - returns (uint256); - - function _reduceReserves(uint256 reduceAmount) - external - virtual - returns (uint256); - - function _setInterestRateModel(InterestRateModel newInterestRateModel) - public - virtual - returns (uint256); -} - -contract CErc20Storage { - /** - * @notice Underlying asset for this CToken - */ - address public underlying; -} - -abstract contract CErc20Interface is CErc20Storage { - /*** User Interface ***/ - - function mint(uint256 mintAmount) external virtual returns (uint256); - - function redeem(uint256 redeemAmount) - external - virtual - returns (uint256); - - function borrow(uint256 borrowAmount) external virtual returns (uint256); - - function repayBorrow(uint256 repayAmount) - external - virtual - returns (uint256); - - function liquidateBorrow( - address borrower, - uint256 repayAmount, - CTokenInterface cTokenCollateral - ) external virtual returns (uint256); - - function sweepToken(EIP20NonStandardInterface token) external virtual; - - /*** Admin Functions ***/ - - function _addReserves(uint256 addAmount) external virtual returns (uint256); -} - -contract CDelegationStorage { - /** - * @notice Implementation address for this contract - */ - address public implementation; -} - -abstract contract CDelegatorInterface is CDelegationStorage { - /** - * @notice Emitted when implementation is changed - */ - event NewImplementation( - address oldImplementation, - address newImplementation - ); - - /** - * @notice Called by the admin to update the implementation of the delegator - * @param implementation_ The address of the new implementation for delegation - * @param allowResign Flag to indicate whether to call _resignImplementation on the old implementation - * @param becomeImplementationData The encoded bytes data to be passed to _becomeImplementation - */ - function _setImplementation( - address implementation_, - bool allowResign, - bytes memory becomeImplementationData - ) public virtual; -} - -abstract contract CDelegateInterface is CDelegationStorage { - /** - * @notice Called by the delegator on a delegate to initialize it for duty - * @dev Should revert if any issues arise which make it unfit for delegation - * @param data The encoded bytes data for any initialization - */ - function _becomeImplementation(bytes memory data) public virtual; - - /** - * @notice Called by the delegator on a delegate to forfeit its responsibility - */ - function _resignImplementation() public virtual; -} - - -// Dependency file: contracts/ErrorReporter.sol - -// pragma solidity 0.8.6; - -contract ComptrollerErrorReporter { - enum Error { - NO_ERROR, - UNAUTHORIZED, - COMPTROLLER_MISMATCH, - INSUFFICIENT_SHORTFALL, - INSUFFICIENT_LIQUIDITY, - INVALID_CLOSE_FACTOR, - INVALID_COLLATERAL_FACTOR, - INVALID_LIQUIDATION_INCENTIVE, - MARKET_NOT_ENTERED, // no longer possible - MARKET_NOT_LISTED, - MARKET_ALREADY_LISTED, - MATH_ERROR, - NONZERO_BORROW_BALANCE, - PRICE_ERROR, - REJECTION, - SNAPSHOT_ERROR, - TOO_MANY_ASSETS, - TOO_MUCH_REPAY - } - - enum FailureInfo { - ACCEPT_ADMIN_PENDING_ADMIN_CHECK, - ACCEPT_PENDING_IMPLEMENTATION_ADDRESS_CHECK, - EXIT_MARKET_BALANCE_OWED, - EXIT_MARKET_REJECTION, - SET_CLOSE_FACTOR_OWNER_CHECK, - SET_CLOSE_FACTOR_VALIDATION, - SET_COLLATERAL_FACTOR_OWNER_CHECK, - SET_COLLATERAL_FACTOR_NO_EXISTS, - SET_COLLATERAL_FACTOR_VALIDATION, - SET_COLLATERAL_FACTOR_WITHOUT_PRICE, - SET_IMPLEMENTATION_OWNER_CHECK, - SET_LIQUIDATION_INCENTIVE_OWNER_CHECK, - SET_LIQUIDATION_INCENTIVE_VALIDATION, - SET_MAX_ASSETS_OWNER_CHECK, - SET_PENDING_ADMIN_OWNER_CHECK, - SET_PENDING_IMPLEMENTATION_OWNER_CHECK, - SET_PRICE_ORACLE_OWNER_CHECK, - SUPPORT_MARKET_EXISTS, - SUPPORT_MARKET_OWNER_CHECK, - SET_PAUSE_GUARDIAN_OWNER_CHECK - } - - /** - * @dev `error` corresponds to enum Error; `info` corresponds to enum FailureInfo, and `detail` is an arbitrary - * contract-specific code that enables us to report opaque error codes from upgradeable contracts. - **/ - event Failure(uint256 error, uint256 info, uint256 detail); - - /** - * @dev use this when reporting a known error from the money market or a non-upgradeable collaborator - */ - function fail(Error err, FailureInfo info) internal returns (uint256) { - emit Failure(uint256(err), uint256(info), 0); - - return uint256(err); - } - - /** - * @dev use this when reporting an opaque error from an upgradeable collaborator contract - */ - function failOpaque( - Error err, - FailureInfo info, - uint256 opaqueError - ) internal returns (uint256) { - emit Failure(uint256(err), uint256(info), opaqueError); - - return uint256(err); - } -} - -contract TokenErrorReporter { - enum Error { - NO_ERROR, - UNAUTHORIZED, - BAD_INPUT, - COMPTROLLER_REJECTION, - COMPTROLLER_CALCULATION_ERROR, - INTEREST_RATE_MODEL_ERROR, - INVALID_ACCOUNT_PAIR, - INVALID_CLOSE_AMOUNT_REQUESTED, - INVALID_COLLATERAL_FACTOR, - MATH_ERROR, - MARKET_NOT_FRESH, - MARKET_NOT_LISTED, - TOKEN_INSUFFICIENT_ALLOWANCE, - TOKEN_INSUFFICIENT_BALANCE, - TOKEN_INSUFFICIENT_CASH, - TOKEN_TRANSFER_IN_FAILED, - TOKEN_TRANSFER_OUT_FAILED - } - - /* - * Note: FailureInfo (but not Error) is kept in alphabetical order - * This is because FailureInfo grows significantly faster, and - * the order of Error has some meaning, while the order of FailureInfo - * is entirely arbitrary. - */ - enum FailureInfo { - ACCEPT_ADMIN_PENDING_ADMIN_CHECK, - ACCRUE_INTEREST_ACCUMULATED_INTEREST_CALCULATION_FAILED, - ACCRUE_INTEREST_BORROW_RATE_CALCULATION_FAILED, - ACCRUE_INTEREST_NEW_BORROW_INDEX_CALCULATION_FAILED, - ACCRUE_INTEREST_NEW_TOTAL_BORROWS_CALCULATION_FAILED, - ACCRUE_INTEREST_NEW_TOTAL_RESERVES_CALCULATION_FAILED, - ACCRUE_INTEREST_SIMPLE_INTEREST_FACTOR_CALCULATION_FAILED, - BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED, - BORROW_ACCRUE_INTEREST_FAILED, - BORROW_CASH_NOT_AVAILABLE, - BORROW_FRESHNESS_CHECK, - BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED, - BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED, - BORROW_MARKET_NOT_LISTED, - BORROW_COMPTROLLER_REJECTION, - LIQUIDATE_ACCRUE_BORROW_INTEREST_FAILED, - LIQUIDATE_ACCRUE_COLLATERAL_INTEREST_FAILED, - LIQUIDATE_COLLATERAL_FRESHNESS_CHECK, - LIQUIDATE_COMPTROLLER_REJECTION, - LIQUIDATE_COMPTROLLER_CALCULATE_AMOUNT_SEIZE_FAILED, - LIQUIDATE_CLOSE_AMOUNT_IS_UINT_MAX, - LIQUIDATE_CLOSE_AMOUNT_IS_ZERO, - LIQUIDATE_FRESHNESS_CHECK, - LIQUIDATE_LIQUIDATOR_IS_BORROWER, - LIQUIDATE_REPAY_BORROW_FRESH_FAILED, - LIQUIDATE_SEIZE_BALANCE_INCREMENT_FAILED, - LIQUIDATE_SEIZE_BALANCE_DECREMENT_FAILED, - LIQUIDATE_SEIZE_COMPTROLLER_REJECTION, - LIQUIDATE_SEIZE_LIQUIDATOR_IS_BORROWER, - LIQUIDATE_SEIZE_TOO_MUCH, - MINT_ACCRUE_INTEREST_FAILED, - MINT_COMPTROLLER_REJECTION, - MINT_EXCHANGE_CALCULATION_FAILED, - MINT_EXCHANGE_RATE_READ_FAILED, - MINT_FRESHNESS_CHECK, - MINT_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED, - MINT_NEW_TOTAL_SUPPLY_CALCULATION_FAILED, - MINT_TRANSFER_IN_FAILED, - MINT_TRANSFER_IN_NOT_POSSIBLE, - REDEEM_ACCRUE_INTEREST_FAILED, - REDEEM_COMPTROLLER_REJECTION, - REDEEM_EXCHANGE_TOKENS_CALCULATION_FAILED, - REDEEM_EXCHANGE_AMOUNT_CALCULATION_FAILED, - REDEEM_EXCHANGE_RATE_READ_FAILED, - REDEEM_FRESHNESS_CHECK, - REDEEM_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED, - REDEEM_NEW_TOTAL_SUPPLY_CALCULATION_FAILED, - REDEEM_TRANSFER_OUT_NOT_POSSIBLE, - REDUCE_RESERVES_ACCRUE_INTEREST_FAILED, - REDUCE_RESERVES_ADMIN_CHECK, - REDUCE_RESERVES_CASH_NOT_AVAILABLE, - REDUCE_RESERVES_FRESH_CHECK, - REDUCE_RESERVES_VALIDATION, - REPAY_BEHALF_ACCRUE_INTEREST_FAILED, - REPAY_BORROW_ACCRUE_INTEREST_FAILED, - REPAY_BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED, - REPAY_BORROW_COMPTROLLER_REJECTION, - REPAY_BORROW_FRESHNESS_CHECK, - REPAY_BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED, - REPAY_BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED, - REPAY_BORROW_TRANSFER_IN_NOT_POSSIBLE, - SET_COLLATERAL_FACTOR_OWNER_CHECK, - SET_COLLATERAL_FACTOR_VALIDATION, - SET_COMPTROLLER_OWNER_CHECK, - SET_INTEREST_RATE_MODEL_ACCRUE_INTEREST_FAILED, - SET_INTEREST_RATE_MODEL_FRESH_CHECK, - SET_INTEREST_RATE_MODEL_OWNER_CHECK, - SET_MAX_ASSETS_OWNER_CHECK, - SET_ORACLE_MARKET_NOT_LISTED, - SET_PENDING_ADMIN_OWNER_CHECK, - SET_RESERVE_FACTOR_ACCRUE_INTEREST_FAILED, - SET_RESERVE_FACTOR_ADMIN_CHECK, - SET_RESERVE_FACTOR_FRESH_CHECK, - SET_RESERVE_FACTOR_BOUNDS_CHECK, - TRANSFER_COMPTROLLER_REJECTION, - TRANSFER_NOT_ALLOWED, - TRANSFER_NOT_ENOUGH, - TRANSFER_TOO_MUCH, - ADD_RESERVES_ACCRUE_INTEREST_FAILED, - ADD_RESERVES_FRESH_CHECK, - ADD_RESERVES_TRANSFER_IN_NOT_POSSIBLE, - ADD_SUBSIDY_FUND_FAILED, - ADD_SUBSIDY_FUND_FRESH_CHECK - } - - /** - * @dev `error` corresponds to enum Error; `info` corresponds to enum FailureInfo, and `detail` is an arbitrary - * contract-specific code that enables us to report opaque error codes from upgradeable contracts. - **/ - event TokenFailure(uint256 error, uint256 info, uint256 detail); - - /** - * @dev use this when reporting a known error from the money market or a non-upgradeable collaborator - */ - function fail(Error err, FailureInfo info) internal returns (uint256) { - emit TokenFailure(uint256(err), uint256(info), 0); - - return uint256(err); - } - - /** - * @dev use this when reporting an opaque error from an upgradeable collaborator contract - */ - function failOpaque( - Error err, - FailureInfo info, - uint256 opaqueError - ) internal returns (uint256) { - emit TokenFailure(uint256(err), uint256(info), opaqueError); - - return uint256(err); - } -} - - -// Dependency file: contracts/EIP20Interface.sol - -// pragma solidity 0.8.6; - -/** - * @title ERC 20 Token Standard Interface - * https://eips.ethereum.org/EIPS/eip-20 - */ -interface EIP20Interface { - function name() external view returns (string memory); - - function symbol() external view returns (string memory); - - function decimals() external view returns (uint8); - - /** - * @notice Get the total number of tokens in circulation - * @return The supply of tokens - */ - function totalSupply() external view returns (uint256); - - /** - * @notice Gets the balance of the specified address - * @param owner The address from which the balance will be retrieved - * @return balance The balance - */ - function balanceOf(address owner) external view returns (uint256 balance); - - /** - * @notice Transfer `amount` tokens from `msg.sender` to `dst` - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - * @return success Whether or not the transfer succeeded - */ - function transfer(address dst, uint256 amount) - external - returns (bool success); - - /** - * @notice Transfer `amount` tokens from `src` to `dst` - * @param src The address of the source account - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - * @return success Whether or not the transfer succeeded - */ - function transferFrom( - address src, - address dst, - uint256 amount - ) external returns (bool success); - - /** - * @notice Approve `spender` to transfer up to `amount` from `src` - * @dev This will overwrite the approval amount for `spender` - * and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve) - * @param spender The address of the account which may transfer tokens - * @param amount The number of tokens that are approved (-1 means infinite) - * @return success Whether or not the approval succeeded - */ - function approve(address spender, uint256 amount) - external - returns (bool success); - - /** - * @notice Get the current allowance from `owner` for `spender` - * @param owner The address of the account which owns the tokens to be spent - * @param spender The address of the account which may transfer tokens - * @return remaining The number of tokens allowed to be spent (-1 means infinite) - */ - function allowance(address owner, address spender) - external - view - returns (uint256 remaining); - - event Transfer(address indexed from, address indexed to, uint256 amount); - event Approval( - address indexed owner, - address indexed spender, - uint256 amount - ); -} - - -// Dependency file: contracts/WhitelistInterface.sol - -// pragma solidity 0.8.6; - -interface WhitelistInterface { - function setStatus(bool _newStatus) external; - function enabled() external view returns(bool); - - function addUsers(address[] memory _users) external; - function exist(address _user) external view returns(bool); - function getUsers() external view returns(address[] memory currentUsers); - function removeUser(address _user) external; -} - -// Dependency file: contracts/CToken.sol - -// pragma solidity 0.8.6; - -// import "contracts/ComptrollerInterface.sol"; -// import "contracts/CTokenInterfaces.sol"; -// import "contracts/ErrorReporter.sol"; -// import "contracts/Exponential.sol"; -// import "contracts/EIP20Interface.sol"; -// import "contracts/InterestRateModel.sol"; -// import "contracts/WhitelistInterface.sol"; - -/** - * @title tropykus CToken Contract - * @notice Abstract base for CTokens - * @author tropykus - */ -abstract contract CToken is CTokenInterface, Exponential, TokenErrorReporter { - address whitelist; - - /** - * @notice Initialize the money market - * @param comptroller_ The address of the Comptroller - * @param interestRateModel_ The address of the interest rate model - * @param initialExchangeRateMantissa_ The initial exchange rate, scaled by 1e18 - * @param name_ EIP-20 name of this token - * @param symbol_ EIP-20 symbol of this token - * @param decimals_ EIP-20 decimal precision of this token - */ - function initialize( - ComptrollerInterface comptroller_, - InterestRateModel interestRateModel_, - uint256 initialExchangeRateMantissa_, - string memory name_, - string memory symbol_, - uint8 decimals_ - ) public { - require(msg.sender == admin, "CT01"); - require(accrualBlockNumber == 0 && borrowIndex == 0, "CT02"); - - initialExchangeRateMantissa = initialExchangeRateMantissa_; - require(initialExchangeRateMantissa > 0, "CT03"); - - uint256 err = _setComptroller(comptroller_); - require(err == uint256(Error.NO_ERROR), "CT04"); - - accrualBlockNumber = getBlockNumber(); - borrowIndex = mantissaOne; - - err = _setInterestRateModelFresh(interestRateModel_); - require(err == uint256(Error.NO_ERROR), "CT05"); - - name = name_; - symbol = symbol_; - decimals = decimals_; - - _notEntered = true; - } - - function addWhitelist(address _whitelist) external returns (uint256) { - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_INTEREST_RATE_MODEL_OWNER_CHECK - ); - } - whitelist = _whitelist; - } - - /** - * @notice Transfer `tokens` tokens from `src` to `dst` by `spender` - * @dev Called by both `transfer` and `transferFrom` internally - * @param spender The address of the account performing the transfer - * @param src The address of the source account - * @param dst The address of the destination account - * @param tokens The number of tokens to transfer - * @return Whether or not the transfer succeeded - */ - function transferTokens( - address spender, - address src, - address dst, - uint256 tokens - ) internal returns (uint256) { - uint256 allowed = comptroller.transferAllowed( - address(this), - src, - dst, - tokens - ); - if (allowed != 0) { - return - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.TRANSFER_COMPTROLLER_REJECTION, - allowed - ); - } - - if (src == dst) { - return fail(Error.BAD_INPUT, FailureInfo.TRANSFER_NOT_ALLOWED); - } - - uint256 startingAllowance = 0; - if (spender == src) { - startingAllowance = type(uint256).max; - } else { - startingAllowance = transferAllowances[src][spender]; - } - - MathError mathErr; - uint256 allowanceNew; - uint256 srcTokensNew; - uint256 dstTokensNew; - - (mathErr, allowanceNew) = subUInt(startingAllowance, tokens); - if (mathErr != MathError.NO_ERROR) { - return fail(Error.MATH_ERROR, FailureInfo.TRANSFER_NOT_ALLOWED); - } - - (mathErr, srcTokensNew) = subUInt(accountTokens[src].tokens, tokens); - if (mathErr != MathError.NO_ERROR) { - return fail(Error.MATH_ERROR, FailureInfo.TRANSFER_NOT_ENOUGH); - } - - (mathErr, dstTokensNew) = addUInt(accountTokens[dst].tokens, tokens); - if (mathErr != MathError.NO_ERROR) { - return fail(Error.MATH_ERROR, FailureInfo.TRANSFER_TOO_MUCH); - } - - accountTokens[src].tokens = srcTokensNew; - accountTokens[dst].tokens = dstTokensNew; - - if (startingAllowance != type(uint256).max) { - transferAllowances[src][spender] = allowanceNew; - } - - emit Transfer(src, dst, tokens); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Transfer `amount` tokens from `msg.sender` to `dst` - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - * @return Whether or not the transfer succeeded - */ - function transfer(address dst, uint256 amount) - external - override - nonReentrant - returns (bool) - { - return - transferTokens(msg.sender, msg.sender, dst, amount) == - uint256(Error.NO_ERROR); - } - - /** - * @notice Transfer `amount` tokens from `src` to `dst` - * @param src The address of the source account - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - * @return Whether or not the transfer succeeded - */ - function transferFrom( - address src, - address dst, - uint256 amount - ) external override nonReentrant returns (bool) { - return - transferTokens(msg.sender, src, dst, amount) == - uint256(Error.NO_ERROR); - } - - /** - * @notice Approve `spender` to transfer up to `amount` from `src` - * @dev This will overwrite the approval amount for `spender` - * and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve) - * @param spender The address of the account which may transfer tokens - * @param amount The number of tokens that are approved (-1 means infinite) - * @return Whether or not the approval succeeded - */ - function approve(address spender, uint256 amount) - external - override - returns (bool) - { - transferAllowances[msg.sender][spender] = amount; - emit Approval(msg.sender, spender, amount); - return true; - } - - /** - * @notice Get the current allowance from `owner` for `spender` - * @param owner The address of the account which owns the tokens to be spent - * @param spender The address of the account which may transfer tokens - * @return The number of tokens allowed to be spent (-1 means infinite) - */ - function allowance(address owner, address spender) - external - view - override - returns (uint256) - { - return transferAllowances[owner][spender]; - } - - /** - * @notice Get the token balance of the `owner` - * @param owner The address of the account to query - * @return The number of tokens owned by `owner` - */ - function balanceOf(address owner) external view override returns (uint256) { - return accountTokens[owner].tokens; - } - - /** - * @notice Get the underlying balance of the `owner` - * @dev This also accrues interest in a transaction - * @param owner The address of the account to query - * @return The amount of underlying owned by `owner` - */ - function balanceOfUnderlying(address owner) - external - override - returns (uint256) - { - (MathError mErr, uint256 balance) = mulScalarTruncate( - Exp({mantissa: exchangeRateCurrent()}), - accountTokens[owner].tokens - ); - require(mErr == MathError.NO_ERROR, "CT06"); - return balance; - } - - /** - * @notice Get a snapshot of the account's balances, and the cached exchange rate - * @dev This is used by comptroller to more efficiently perform liquidity checks. - * @param account Address of the account to snapshot - * @return (possible error, token balance, borrow balance, exchange rate mantissa) - */ - function getAccountSnapshot(address account) - external - view - override - returns ( - uint256, - uint256, - uint256, - uint256 - ) - { - uint256 cTokenBalance = accountTokens[account].tokens; - uint256 borrowBalance; - uint256 exchangeRateMantissa; - - MathError mErr; - - (mErr, borrowBalance) = borrowBalanceStoredInternal(account); - if (mErr != MathError.NO_ERROR) { - return (uint256(Error.MATH_ERROR), 0, 0, 0); - } - - (mErr, exchangeRateMantissa) = exchangeRateStoredInternal(); - if (mErr != MathError.NO_ERROR) { - return (uint256(Error.MATH_ERROR), 0, 0, 0); - } - - return ( - uint256(Error.NO_ERROR), - cTokenBalance, - borrowBalance, - exchangeRateMantissa - ); - } - - /** - * @dev Function to simply retrieve block number - * This exists mainly for inheriting test contracts to stub this result. - */ - function getBlockNumber() internal view virtual returns (uint256) { - return block.number; - } - - /** - * @notice Returns the current per-block borrow interest rate for this cToken - * @return The borrow interest rate per block, scaled by 1e18 - */ - function borrowRatePerBlock() external view override returns (uint256) { - return - interestRateModel.getBorrowRate( - getCashPrior(), - totalBorrows, - totalReserves - ); - } - - /** - * @notice Returns the current per-block supply interest rate for this cToken - * @return The supply interest rate per block, scaled by 1e18 - */ - function supplyRatePerBlock() external view override returns (uint256) { - return - interestRateModel.getSupplyRate( - getCashPrior(), - totalBorrows, - totalReserves, - reserveFactorMantissa - ); - } - - /** - * @notice Returns the current total borrows plus accrued interest - * @return The total borrows with interest - */ - function totalBorrowsCurrent() - external - override - nonReentrant - returns (uint256) - { - require(accrueInterest() == uint256(Error.NO_ERROR), "CT07"); - return totalBorrows; - } - - /** - * @notice Accrue interest to updated borrowIndex and then calculate account's borrow balance using the updated borrowIndex - * @param account The address whose balance should be calculated after updating borrowIndex - * @return The calculated balance - */ - function borrowBalanceCurrent(address account) - external - override - nonReentrant - returns (uint256) - { - require(accrueInterest() == uint256(Error.NO_ERROR), "CT07"); - return borrowBalanceStored(account); - } - - /** - * @notice Return the borrow balance of account based on stored data - * @param account The address whose balance should be calculated - * @return The calculated balance - */ - function borrowBalanceStored(address account) - public - view - override - returns (uint256) - { - (MathError err, uint256 result) = borrowBalanceStoredInternal(account); - require(err == MathError.NO_ERROR, "CT08"); - return result; - } - - /** - * @notice Return the borrow balance of account based on stored data - * @param account The address whose balance should be calculated - * @return (error code, the calculated balance or 0 if error code is non-zero) - */ - function borrowBalanceStoredInternal(address account) - internal - view - returns (MathError, uint256) - { - MathError mathErr; - uint256 principalTimesIndex; - uint256 result; - - BorrowSnapshot storage borrowSnapshot = accountBorrows[account]; - - if (borrowSnapshot.principal == 0) { - return (MathError.NO_ERROR, 0); - } - - (mathErr, principalTimesIndex) = mulUInt( - borrowSnapshot.principal, - borrowIndex - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - - (mathErr, result) = divUInt( - principalTimesIndex, - borrowSnapshot.interestIndex - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - - return (MathError.NO_ERROR, result); - } - - function getBorrowerPrincipalStored(address account) - public - view - returns (uint256 borrowed) - { - borrowed = accountBorrows[account].principal; - } - - function getSupplierSnapshotStored(address account) - public - view - returns ( - uint256 tokens, - uint256 underlyingAmount, - uint256 suppliedAt, - uint256 promisedSupplyRate - ) - { - tokens = accountTokens[account].tokens; - underlyingAmount = accountTokens[account].underlyingAmount; - suppliedAt = accountTokens[account].suppliedAt; - promisedSupplyRate = accountTokens[account].promisedSupplyRate; - } - - /** - * @notice Accrue interest then return the up-to-date exchange rate - * @return Calculated exchange rate scaled by 1e18 - */ - function exchangeRateCurrent() - public - override - nonReentrant - returns (uint256) - { - require(accrueInterest() == uint256(Error.NO_ERROR), "CT07"); - return exchangeRateStored(); - } - - /** - * @notice Calculates the exchange rate from the underlying to the CToken - * @dev This function does not accrue interest before calculating the exchange rate - * @return Calculated exchange rate scaled by 1e18 - */ - function exchangeRateStored() public view override returns (uint256) { - (MathError err, uint256 result) = exchangeRateStoredInternal(); - require(err == MathError.NO_ERROR, "CT09"); - return result; - } - - /** - * @notice Calculates the exchange rate from the underlying to the CToken - * @dev This function does not accrue interest before calculating the exchange rate - * @return (error code, calculated exchange rate scaled by 1e18) - */ - function exchangeRateStoredInternal() - internal - view - virtual - returns (MathError, uint256) - { - uint256 _totalSupply = totalSupply; - if (_totalSupply == 0) { - return (MathError.NO_ERROR, initialExchangeRateMantissa); - } else { - MathError error; - uint256 exchangeRate; - uint256 totalCash = getCashPrior(); - if (interestRateModel.isTropykusInterestRateModel()) { - (error, exchangeRate) = tropykusExchangeRateStoredInternal( - msg.sender - ); - if (error == MathError.NO_ERROR) { - return (MathError.NO_ERROR, exchangeRate); - } else { - return (MathError.NO_ERROR, initialExchangeRateMantissa); - } - } - return - interestRateModel.getExchangeRate( - totalCash, - totalBorrows, - totalReserves, - totalSupply - ); - } - } - - function tropykusExchangeRateStoredInternal(address redeemer) - internal - view - returns (MathError, uint256) - { - if (totalSupply == 0) { - return (MathError.NO_ERROR, initialExchangeRateMantissa); - } else { - SupplySnapshot storage supplySnapshot = accountTokens[redeemer]; - if (supplySnapshot.suppliedAt == 0) { - return (MathError.DIVISION_BY_ZERO, 0); - } - (, uint256 interestFactorMantissa, ) = tropykusInterestAccrued( - redeemer - ); - Exp memory interestFactor = Exp({mantissa: interestFactorMantissa}); - uint256 currentUnderlying = supplySnapshot.underlyingAmount; - Exp memory redeemerUnderlying = Exp({mantissa: currentUnderlying}); - (, Exp memory realAmount) = mulExp( - interestFactor, - redeemerUnderlying - ); - (, Exp memory exchangeRate) = getExp( - realAmount.mantissa, - supplySnapshot.tokens - ); - return (MathError.NO_ERROR, exchangeRate.mantissa); - } - } - - function tropykusInterestAccrued(address account) - internal - view - returns ( - MathError, - uint256, - uint256 - ) - { - SupplySnapshot storage supplySnapshot = accountTokens[account]; - uint256 promisedSupplyRate = supplySnapshot.promisedSupplyRate; - Exp memory expectedSupplyRatePerBlock = Exp({ - mantissa: promisedSupplyRate - }); - (, uint256 delta) = subUInt( - accrualBlockNumber, - supplySnapshot.suppliedAt - ); - (, Exp memory expectedSupplyRatePerBlockWithDelta) = mulScalar( - expectedSupplyRatePerBlock, - delta - ); - (, Exp memory interestFactor) = addExp( - Exp({mantissa: 1e18}), - expectedSupplyRatePerBlockWithDelta - ); - uint256 currentUnderlying = supplySnapshot.underlyingAmount; - Exp memory redeemerUnderlying = Exp({mantissa: currentUnderlying}); - (, Exp memory realAmount) = mulExp(interestFactor, redeemerUnderlying); - (, uint256 interestEarned) = subUInt( - realAmount.mantissa, - currentUnderlying - ); - return (MathError.NO_ERROR, interestFactor.mantissa, interestEarned); - } - - /** - * @notice Get cash balance of this cToken in the underlying asset - * @return The quantity of underlying asset owned by this contract - */ - function getCash() external view override returns (uint256) { - return getCashPrior(); - } - - /** - * @notice Applies accrued interest to total borrows and reserves - * @dev This calculates interest accrued from the last checkpointed block - * up to the current block and writes new checkpoint to storage. - */ - function accrueInterest() public override returns (uint256) { - uint256 currentBlockNumber = getBlockNumber(); - uint256 accrualBlockNumberPrior = accrualBlockNumber; - - if (accrualBlockNumberPrior == currentBlockNumber) { - return uint256(Error.NO_ERROR); - } - - uint256 cashPrior = getCashPrior(); - uint256 borrowsPrior = totalBorrows; - uint256 reservesPrior = totalReserves; - uint256 borrowIndexPrior = borrowIndex; - - uint256 borrowRateMantissa = interestRateModel.getBorrowRate( - cashPrior, - borrowsPrior, - reservesPrior - ); - require(borrowRateMantissa <= borrowRateMaxMantissa, "CT10"); - - (MathError mathErr, uint256 blockDelta) = subUInt( - currentBlockNumber, - accrualBlockNumberPrior - ); - require(mathErr == MathError.NO_ERROR, "CT11"); - - Exp memory simpleInterestFactor; - uint256 interestAccumulated; - uint256 totalBorrowsNew; - uint256 totalReservesNew; - uint256 borrowIndexNew; - - (mathErr, simpleInterestFactor) = mulScalar( - Exp({mantissa: borrowRateMantissa}), - blockDelta - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .ACCRUE_INTEREST_SIMPLE_INTEREST_FACTOR_CALCULATION_FAILED, - uint256(mathErr) - ); - } - - (mathErr, interestAccumulated) = mulScalarTruncate( - simpleInterestFactor, - borrowsPrior - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .ACCRUE_INTEREST_ACCUMULATED_INTEREST_CALCULATION_FAILED, - uint256(mathErr) - ); - } - - (mathErr, totalBorrowsNew) = addUInt(interestAccumulated, borrowsPrior); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .ACCRUE_INTEREST_NEW_TOTAL_BORROWS_CALCULATION_FAILED, - uint256(mathErr) - ); - } - - (mathErr, totalReservesNew) = mulScalarTruncateAddUInt( - Exp({mantissa: reserveFactorMantissa}), - interestAccumulated, - reservesPrior - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .ACCRUE_INTEREST_NEW_TOTAL_RESERVES_CALCULATION_FAILED, - uint256(mathErr) - ); - } - - if (interestRateModel.isTropykusInterestRateModel()) { - (mathErr, totalReservesNew) = newReserves( - borrowRateMantissa, - cashPrior, - borrowsPrior, - reservesPrior, - interestAccumulated - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .ACCRUE_INTEREST_NEW_TOTAL_RESERVES_CALCULATION_FAILED, - uint256(mathErr) - ); - } - } - - (mathErr, borrowIndexNew) = mulScalarTruncateAddUInt( - simpleInterestFactor, - borrowIndexPrior, - borrowIndexPrior - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .ACCRUE_INTEREST_NEW_BORROW_INDEX_CALCULATION_FAILED, - uint256(mathErr) - ); - } - - accrualBlockNumber = currentBlockNumber; - borrowIndex = borrowIndexNew; - totalBorrows = totalBorrowsNew; - totalReserves = totalReservesNew; - - emit AccrueInterest( - cashPrior, - interestAccumulated, - borrowIndexNew, - totalBorrowsNew - ); - - return uint256(Error.NO_ERROR); - } - - function newReserves( - uint256 borrowRateMantissa, - uint256 cashPrior, - uint256 borrowsPrior, - uint256 reservesPrior, - uint256 interestAccumulated - ) internal view returns (MathError mathErr, uint256 totalReservesNew) { - uint256 newReserveFactorMantissa; - uint256 utilizationRate = interestRateModel.utilizationRate( - cashPrior, - borrowsPrior, - reservesPrior - ); - uint256 expectedSupplyRate = interestRateModel.getSupplyRate( - cashPrior, - borrowsPrior, - reservesPrior, - reserveFactorMantissa - ); - if ( - interestRateModel.isAboveOptimal( - cashPrior, - borrowsPrior, - reservesPrior - ) - ) { - (mathErr, newReserveFactorMantissa) = mulScalarTruncate( - Exp({mantissa: utilizationRate}), - borrowRateMantissa - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - (mathErr, newReserveFactorMantissa) = subUInt( - newReserveFactorMantissa, - expectedSupplyRate - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - (mathErr, totalReservesNew) = mulScalarTruncateAddUInt( - Exp({mantissa: newReserveFactorMantissa}), - interestAccumulated, - reservesPrior - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - } else { - mathErr = MathError.NO_ERROR; - totalReservesNew = reservesPrior; - } - } - - /** - * @notice Sender supplies assets into the market and receives cTokens in exchange - * @dev Accrues interest whether or not the operation succeeds, unless reverted - * @param mintAmount The amount of the underlying asset to supply - * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual mint amount. - */ - function mintInternal(uint256 mintAmount) - internal - nonReentrant - returns (uint256, uint256) - { - if (WhitelistInterface(whitelist).enabled()) { - require(WhitelistInterface(whitelist).exist(msg.sender), "CT26"); - } - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return ( - fail(Error(error), FailureInfo.MINT_ACCRUE_INTEREST_FAILED), - 0 - ); - } - return mintFresh(msg.sender, mintAmount); - } - - struct MintLocalVars { - Error err; - MathError mathErr; - uint256 exchangeRateMantissa; - uint256 mintTokens; - uint256 totalSupplyNew; - uint256 accountTokensNew; - uint256 actualMintAmount; - } - - /** - * @notice User supplies assets into the market and receives cTokens in exchange - * @dev Assumes interest has already been accrued up to the current block - * @param minter The address of the account which is supplying the assets - * @param mintAmount The amount of the underlying asset to supply - * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual mint amount. - */ - function mintFresh(address minter, uint256 mintAmount) - internal - returns (uint256, uint256) - { - uint256 allowed = comptroller.mintAllowed( - address(this), - minter, - mintAmount - ); - if (allowed != 0) { - return ( - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.MINT_COMPTROLLER_REJECTION, - allowed - ), - 0 - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return ( - fail(Error.MARKET_NOT_FRESH, FailureInfo.MINT_FRESHNESS_CHECK), - 0 - ); - } - - MintLocalVars memory vars; - - ( - vars.mathErr, - vars.exchangeRateMantissa - ) = exchangeRateStoredInternal(); - if (vars.mathErr != MathError.NO_ERROR) { - return ( - failOpaque( - Error.MATH_ERROR, - FailureInfo.MINT_EXCHANGE_RATE_READ_FAILED, - uint256(vars.mathErr) - ), - 0 - ); - } - if (interestRateModel.isTropykusInterestRateModel()) { - SupplySnapshot storage supplySnapshot = accountTokens[minter]; - (, uint256 newTotalSupply) = addUInt( - supplySnapshot.underlyingAmount, - mintAmount - ); - require(newTotalSupply <= 0.1e18, "CT24"); - } - vars.actualMintAmount = doTransferIn(minter, mintAmount); - - (vars.mathErr, vars.mintTokens) = divScalarByExpTruncate( - vars.actualMintAmount, - Exp({mantissa: vars.exchangeRateMantissa}) - ); - require(vars.mathErr == MathError.NO_ERROR, "CT12"); - - (vars.mathErr, vars.totalSupplyNew) = addUInt( - totalSupply, - vars.mintTokens - ); - require(vars.mathErr == MathError.NO_ERROR, "CT13"); - - (vars.mathErr, vars.accountTokensNew) = addUInt( - accountTokens[minter].tokens, - vars.mintTokens - ); - require(vars.mathErr == MathError.NO_ERROR, "CT14"); - - uint256 currentSupplyRate = interestRateModel.getSupplyRate( - getCashPrior(), - totalBorrows, - totalReserves, - reserveFactorMantissa - ); - - bool isTropykusInterestRateModel = interestRateModel - .isTropykusInterestRateModel(); - - if (accountTokens[minter].tokens > 0) { - Exp memory updatedUnderlying; - if (isTropykusInterestRateModel) { - (, uint256 interestFactorMantissa, ) = tropykusInterestAccrued( - minter - ); - Exp memory interestFactor = Exp({ - mantissa: interestFactorMantissa - }); - uint256 currentUnderlyingAmount = accountTokens[minter] - .underlyingAmount; - MathError mErrorNewAmount; - (mErrorNewAmount, updatedUnderlying) = mulExp( - Exp({mantissa: currentUnderlyingAmount}), - interestFactor - ); - if (mErrorNewAmount != MathError.NO_ERROR) { - return ( - failOpaque( - Error.MATH_ERROR, - FailureInfo.MINT_EXCHANGE_CALCULATION_FAILED, - uint256(mErrorNewAmount) - ), - 0 - ); - } - } else { - uint256 currentTokens = accountTokens[minter].tokens; - MathError mErrorUpdatedUnderlying; - (mErrorUpdatedUnderlying, updatedUnderlying) = mulExp( - Exp({mantissa: currentTokens}), - Exp({mantissa: vars.exchangeRateMantissa}) - ); - if (mErrorUpdatedUnderlying != MathError.NO_ERROR) { - return ( - failOpaque( - Error.MATH_ERROR, - FailureInfo.MINT_EXCHANGE_CALCULATION_FAILED, - uint256(mErrorUpdatedUnderlying) - ), - 0 - ); - } - } - (, mintAmount) = addUInt(updatedUnderlying.mantissa, mintAmount); - } - - totalSupply = vars.totalSupplyNew; - accountTokens[minter] = SupplySnapshot({ - tokens: vars.accountTokensNew, - underlyingAmount: mintAmount, - suppliedAt: accrualBlockNumber, - promisedSupplyRate: currentSupplyRate - }); - - emit Mint(minter, vars.actualMintAmount, vars.mintTokens); - emit Transfer(address(this), minter, vars.mintTokens); - - return (uint256(Error.NO_ERROR), vars.actualMintAmount); - } - - /** - * @notice Sender redeems cTokens in exchange for a specified amount of underlying asset - * @dev Accrues interest whether or not the operation succeeds, unless reverted - * @param redeemAmount The amount of underlying to receive from redeeming cTokens - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function redeemUnderlyingInternal(uint256 redeemAmount) - internal - nonReentrant - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return - fail(Error(error), FailureInfo.REDEEM_ACCRUE_INTEREST_FAILED); - } - return redeemFresh(payable(msg.sender), redeemAmount); - } - - struct RedeemLocalVars { - Error err; - MathError mathErr; - uint256 exchangeRateMantissa; - uint256 redeemTokens; - uint256 redeemAmount; - uint256 totalSupplyNew; - uint256 accountTokensNew; - uint256 newSubsidyFund; - } - - /** - * @notice User redeems cTokens in exchange for the underlying asset - * @dev Assumes interest has already been accrued up to the current block - * @param redeemer The address of the account which is redeeming the tokens - * @param redeemAmountIn The number of underlying tokens to receive from redeeming cTokens - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function redeemFresh(address payable redeemer, uint256 redeemAmountIn) - internal - returns (uint256) - { - require(redeemAmountIn > 0, "CT15"); - - RedeemLocalVars memory vars; - - SupplySnapshot storage supplySnapshot = accountTokens[redeemer]; - - ( - vars.mathErr, - vars.exchangeRateMantissa - ) = exchangeRateStoredInternal(); - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.REDEEM_EXCHANGE_RATE_READ_FAILED, - uint256(vars.mathErr) - ); - } - - uint256 interestEarned; - uint256 subsidyFundPortion; - uint256 currentUnderlying; - - bool isTropykusInterestRateModel = interestRateModel - .isTropykusInterestRateModel(); - if (isTropykusInterestRateModel) { - currentUnderlying = supplySnapshot.underlyingAmount; - (, , interestEarned) = tropykusInterestAccrued(redeemer); - } - supplySnapshot.promisedSupplyRate = interestRateModel.getSupplyRate( - getCashPrior(), - totalBorrows, - totalReserves, - reserveFactorMantissa - ); - - if ( - isTropykusInterestRateModel && - !interestRateModel.isAboveOptimal( - getCashPrior(), - totalBorrows, - totalReserves - ) - ) { - uint256 borrowRate = interestRateModel.getBorrowRate( - getCashPrior(), - totalBorrows, - totalReserves - ); - - uint256 utilizationRate = interestRateModel.utilizationRate( - getCashPrior(), - totalBorrows, - totalReserves - ); - - (, uint256 estimatedEarning) = mulScalarTruncate( - Exp({mantissa: borrowRate}), - utilizationRate - ); - - (, subsidyFundPortion) = subUInt( - supplySnapshot.promisedSupplyRate, - estimatedEarning - ); - (, Exp memory subsidyFactor) = getExp( - subsidyFundPortion, - supplySnapshot.promisedSupplyRate - ); - (, subsidyFundPortion) = mulScalarTruncate( - subsidyFactor, - interestEarned - ); - } - - vars.redeemAmount = redeemAmountIn; - - if (isTropykusInterestRateModel) { - (, Exp memory num) = mulExp( - vars.redeemAmount, - supplySnapshot.tokens - ); - (, Exp memory realTokensWithdrawAmount) = getExp( - num.mantissa, - currentUnderlying - ); - vars.redeemTokens = realTokensWithdrawAmount.mantissa; - } else { - (vars.mathErr, vars.redeemTokens) = divScalarByExpTruncate( - redeemAmountIn, - Exp({mantissa: vars.exchangeRateMantissa}) - ); - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.REDEEM_EXCHANGE_AMOUNT_CALCULATION_FAILED, - uint256(vars.mathErr) - ); - } - } - // } - - uint256 allowed = comptroller.redeemAllowed( - address(this), - redeemer, - vars.redeemTokens - ); - if (allowed != 0) { - return - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.REDEEM_COMPTROLLER_REJECTION, - allowed - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.REDEEM_FRESHNESS_CHECK - ); - } - - (vars.mathErr, vars.totalSupplyNew) = subUInt( - totalSupply, - vars.redeemTokens - ); - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.REDEEM_NEW_TOTAL_SUPPLY_CALCULATION_FAILED, - uint256(vars.mathErr) - ); - } - - (, vars.newSubsidyFund) = subUInt(subsidyFund, subsidyFundPortion); - - (vars.mathErr, vars.accountTokensNew) = subUInt( - supplySnapshot.tokens, - vars.redeemTokens - ); - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.REDEEM_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED, - uint256(vars.mathErr) - ); - } - - uint256 cash = getCashPrior(); - if (isTropykusInterestRateModel) { - cash = address(this).balance; - } - - if (cash < vars.redeemAmount) { - return - fail( - Error.TOKEN_INSUFFICIENT_CASH, - FailureInfo.REDEEM_TRANSFER_OUT_NOT_POSSIBLE - ); - } - - doTransferOut(redeemer, vars.redeemAmount); - - totalSupply = vars.totalSupplyNew; - subsidyFund = vars.newSubsidyFund; - supplySnapshot.tokens = vars.accountTokensNew; - supplySnapshot.suppliedAt = accrualBlockNumber; - (, supplySnapshot.underlyingAmount) = subUInt( - supplySnapshot.underlyingAmount, - vars.redeemAmount - ); - - emit Transfer(redeemer, address(this), vars.redeemTokens); - emit Redeem(redeemer, vars.redeemAmount, vars.redeemTokens); - - comptroller.redeemVerify( - address(this), - redeemer, - vars.redeemAmount, - vars.redeemTokens - ); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Sender borrows assets from the protocol to their own address - * @param borrowAmount The amount of the underlying asset to borrow - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function borrowInternal(uint256 borrowAmount) - internal - nonReentrant - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return - fail(Error(error), FailureInfo.BORROW_ACCRUE_INTEREST_FAILED); - } - return borrowFresh(payable(msg.sender), borrowAmount); - } - - struct BorrowLocalVars { - MathError mathErr; - uint256 accountBorrows; - uint256 accountBorrowsNew; - uint256 totalBorrowsNew; - } - - /** - * @notice Users borrow assets from the protocol to their own address - * @param borrowAmount The amount of the underlying asset to borrow - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function borrowFresh(address payable borrower, uint256 borrowAmount) - internal - returns (uint256) - { - uint256 allowed = comptroller.borrowAllowed( - address(this), - borrower, - borrowAmount - ); - if (allowed != 0) { - return - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.BORROW_COMPTROLLER_REJECTION, - allowed - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.BORROW_FRESHNESS_CHECK - ); - } - - if (getCashPrior() < borrowAmount) { - return - fail( - Error.TOKEN_INSUFFICIENT_CASH, - FailureInfo.BORROW_CASH_NOT_AVAILABLE - ); - } - - BorrowLocalVars memory vars; - - (vars.mathErr, vars.accountBorrows) = borrowBalanceStoredInternal( - borrower - ); - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED, - uint256(vars.mathErr) - ); - } - - (vars.mathErr, vars.accountBorrowsNew) = addUInt( - vars.accountBorrows, - borrowAmount - ); - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED, - uint256(vars.mathErr) - ); - } - - (vars.mathErr, vars.totalBorrowsNew) = addUInt( - totalBorrows, - borrowAmount - ); - if (interestRateModel.isTropykusInterestRateModel()) { - require(vars.totalBorrowsNew <= 0.1e18, "CT25"); - } - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED, - uint256(vars.mathErr) - ); - } - - doTransferOut(borrower, borrowAmount); - - accountBorrows[borrower].principal = vars.accountBorrowsNew; - accountBorrows[borrower].interestIndex = borrowIndex; - totalBorrows = vars.totalBorrowsNew; - - emit Borrow( - borrower, - borrowAmount, - vars.accountBorrowsNew, - vars.totalBorrowsNew - ); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Sender repays their own borrow - * @param repayAmount The amount to repay - * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual repayment amount. - */ - function repayBorrowInternal(uint256 repayAmount) - internal - nonReentrant - returns (uint256, uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return ( - fail( - Error(error), - FailureInfo.REPAY_BORROW_ACCRUE_INTEREST_FAILED - ), - 0 - ); - } - return repayBorrowFresh(msg.sender, msg.sender, repayAmount); - } - - struct RepayBorrowLocalVars { - Error err; - MathError mathErr; - uint256 repayAmount; - uint256 borrowerIndex; - uint256 accountBorrows; - uint256 accountBorrowsNew; - uint256 totalBorrowsNew; - uint256 actualRepayAmount; - } - - /** - * @notice Borrows are repaid by another user (possibly the borrower). - * @param payer the account paying off the borrow - * @param borrower the account with the debt being payed off - * @param repayAmount the amount of undelrying tokens being returned - * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual repayment amount. - */ - function repayBorrowFresh( - address payer, - address borrower, - uint256 repayAmount - ) internal returns (uint256, uint256) { - uint256 allowed = comptroller.repayBorrowAllowed( - address(this), - payer, - borrower, - repayAmount - ); - if (allowed != 0) { - return ( - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.REPAY_BORROW_COMPTROLLER_REJECTION, - allowed - ), - 0 - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return ( - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.REPAY_BORROW_FRESHNESS_CHECK - ), - 0 - ); - } - - RepayBorrowLocalVars memory vars; - - vars.borrowerIndex = accountBorrows[borrower].interestIndex; - - (vars.mathErr, vars.accountBorrows) = borrowBalanceStoredInternal( - borrower - ); - if (vars.mathErr != MathError.NO_ERROR) { - return ( - failOpaque( - Error.MATH_ERROR, - FailureInfo - .REPAY_BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED, - uint256(vars.mathErr) - ), - 0 - ); - } - - if (repayAmount == type(uint256).max) { - vars.repayAmount = vars.accountBorrows; - } else { - vars.repayAmount = repayAmount; - } - - vars.actualRepayAmount = doTransferIn(payer, vars.repayAmount); - - (vars.mathErr, vars.accountBorrowsNew) = subUInt( - vars.accountBorrows, - vars.actualRepayAmount - ); - require(vars.mathErr == MathError.NO_ERROR, "CT16"); - - (vars.mathErr, vars.totalBorrowsNew) = subUInt( - totalBorrows, - vars.actualRepayAmount - ); - require(vars.mathErr == MathError.NO_ERROR, "CT17"); - - accountBorrows[borrower].principal = vars.accountBorrowsNew; - accountBorrows[borrower].interestIndex = borrowIndex; - totalBorrows = vars.totalBorrowsNew; - - emit RepayBorrow( - payer, - borrower, - vars.actualRepayAmount, - vars.accountBorrowsNew, - vars.totalBorrowsNew - ); - - return (uint256(Error.NO_ERROR), vars.actualRepayAmount); - } - - /** - * @notice The sender liquidates the borrowers collateral. - * The collateral seized is transferred to the liquidator. - * @param borrower The borrower of this cToken to be liquidated - * @param cTokenCollateral The market in which to seize collateral from the borrower - * @param repayAmount The amount of the underlying borrowed asset to repay - * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual repayment amount. - */ - function liquidateBorrowInternal( - address borrower, - uint256 repayAmount, - CTokenInterface cTokenCollateral - ) internal nonReentrant returns (uint256, uint256) { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return ( - fail( - Error(error), - FailureInfo.LIQUIDATE_ACCRUE_BORROW_INTEREST_FAILED - ), - 0 - ); - } - - error = cTokenCollateral.accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return ( - fail( - Error(error), - FailureInfo.LIQUIDATE_ACCRUE_COLLATERAL_INTEREST_FAILED - ), - 0 - ); - } - - // liquidateBorrowFresh emits borrow-specific logs on errors, so we don't need to - return - liquidateBorrowFresh( - msg.sender, - borrower, - repayAmount, - cTokenCollateral - ); - } - - /** - * @notice The liquidator liquidates the borrowers collateral. - * The collateral seized is transferred to the liquidator. - * @param borrower The borrower of this cToken to be liquidated - * @param liquidator The address repaying the borrow and seizing collateral - * @param cTokenCollateral The market in which to seize collateral from the borrower - * @param repayAmount The amount of the underlying borrowed asset to repay - * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual repayment amount. - */ - function liquidateBorrowFresh( - address liquidator, - address borrower, - uint256 repayAmount, - CTokenInterface cTokenCollateral - ) internal returns (uint256, uint256) { - uint256 allowed = comptroller.liquidateBorrowAllowed( - address(this), - address(cTokenCollateral), - liquidator, - borrower, - repayAmount - ); - if (allowed != 0) { - return ( - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.LIQUIDATE_COMPTROLLER_REJECTION, - allowed - ), - 0 - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return ( - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.LIQUIDATE_FRESHNESS_CHECK - ), - 0 - ); - } - - if (cTokenCollateral.accrualBlockNumber() != getBlockNumber()) { - return ( - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.LIQUIDATE_COLLATERAL_FRESHNESS_CHECK - ), - 0 - ); - } - - if (borrower == liquidator) { - return ( - fail( - Error.INVALID_ACCOUNT_PAIR, - FailureInfo.LIQUIDATE_LIQUIDATOR_IS_BORROWER - ), - 0 - ); - } - - if (repayAmount == 0) { - return ( - fail( - Error.INVALID_CLOSE_AMOUNT_REQUESTED, - FailureInfo.LIQUIDATE_CLOSE_AMOUNT_IS_ZERO - ), - 0 - ); - } - - if (repayAmount == type(uint256).max) { - return ( - fail( - Error.INVALID_CLOSE_AMOUNT_REQUESTED, - FailureInfo.LIQUIDATE_CLOSE_AMOUNT_IS_UINT_MAX - ), - 0 - ); - } - - ( - uint256 repayBorrowError, - uint256 actualRepayAmount - ) = repayBorrowFresh(liquidator, borrower, repayAmount); - if (repayBorrowError != uint256(Error.NO_ERROR)) { - return ( - fail( - Error(repayBorrowError), - FailureInfo.LIQUIDATE_REPAY_BORROW_FRESH_FAILED - ), - 0 - ); - } - - (uint256 amountSeizeError, uint256 seizeTokens) = comptroller - .liquidateCalculateSeizeTokens( - address(this), - address(cTokenCollateral), - actualRepayAmount - ); - require(amountSeizeError == uint256(Error.NO_ERROR), "CT18"); - - require(cTokenCollateral.balanceOf(borrower) >= seizeTokens, "CT19"); - - uint256 seizeError; - if (address(cTokenCollateral) == address(this)) { - seizeError = seizeInternal( - address(this), - liquidator, - borrower, - seizeTokens - ); - } else { - seizeError = cTokenCollateral.seize( - liquidator, - borrower, - seizeTokens - ); - } - - require(seizeError == uint256(Error.NO_ERROR), "CT20"); - - emit LiquidateBorrow( - liquidator, - borrower, - actualRepayAmount, - address(cTokenCollateral), - seizeTokens - ); - - return (uint256(Error.NO_ERROR), actualRepayAmount); - } - - /** - * @notice Transfers collateral tokens (this market) to the liquidator. - * @dev Will fail unless called by another cToken during the process of liquidation. - * Its absolutely critical to use msg.sender as the borrowed cToken and not a parameter. - * @param liquidator The account receiving seized collateral - * @param borrower The account having collateral seized - * @param seizeTokens The number of cTokens to seize - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function seize( - address liquidator, - address borrower, - uint256 seizeTokens - ) external override nonReentrant returns (uint256) { - return seizeInternal(msg.sender, liquidator, borrower, seizeTokens); - } - - struct SeizeVars { - uint256 seizeAmount; - uint256 exchangeRate; - uint256 borrowerTokensNew; - uint256 borrowerAmountNew; - uint256 liquidatorTokensNew; - uint256 liquidatorAmountNew; - uint256 totalCash; - uint256 supplyRate; - } - - /** - * @notice Transfers collateral tokens (this market) to the liquidator. - * @dev Called only during an in-kind liquidation, or by liquidateBorrow during the liquidation of another CToken. - * Its absolutely critical to use msg.sender as the seizer cToken and not a parameter. - * @param seizerToken The contract seizing the collateral (i.e. borrowed cToken) - * @param liquidator The account receiving seized collateral - * @param borrower The account having collateral seized - * @param seizeTokens The number of cTokens to seize - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function seizeInternal( - address seizerToken, - address liquidator, - address borrower, - uint256 seizeTokens - ) internal returns (uint256) { - uint256 allowed = comptroller.seizeAllowed( - address(this), - seizerToken, - liquidator, - borrower, - seizeTokens - ); - if (allowed != 0) { - return - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.LIQUIDATE_SEIZE_COMPTROLLER_REJECTION, - allowed - ); - } - - if (borrower == liquidator) { - return - fail( - Error.INVALID_ACCOUNT_PAIR, - FailureInfo.LIQUIDATE_SEIZE_LIQUIDATOR_IS_BORROWER - ); - } - - SeizeVars memory seizeVars; - - MathError mathErr; - - (mathErr, seizeVars.borrowerTokensNew) = subUInt( - accountTokens[borrower].tokens, - seizeTokens - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.LIQUIDATE_SEIZE_BALANCE_DECREMENT_FAILED, - uint256(mathErr) - ); - } - - seizeVars.totalCash = getCashPrior(); - seizeVars.supplyRate = interestRateModel.getSupplyRate( - seizeVars.totalCash, - totalBorrows, - totalReserves, - reserveFactorMantissa - ); - - (, seizeVars.exchangeRate) = interestRateModel.getExchangeRate( - seizeVars.totalCash, - totalBorrows, - totalReserves, - totalSupply - ); - - if (interestRateModel.isTropykusInterestRateModel()) { - (, seizeVars.exchangeRate) = tropykusExchangeRateStoredInternal( - borrower - ); - } - - (, seizeVars.seizeAmount) = mulUInt( - seizeTokens, - seizeVars.exchangeRate - ); - (, seizeVars.seizeAmount) = divUInt(seizeVars.seizeAmount, 1e18); - - (, seizeVars.borrowerAmountNew) = subUInt( - accountTokens[borrower].underlyingAmount, - seizeVars.seizeAmount - ); - - (mathErr, seizeVars.liquidatorTokensNew) = addUInt( - accountTokens[liquidator].tokens, - seizeTokens - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.LIQUIDATE_SEIZE_BALANCE_INCREMENT_FAILED, - uint256(mathErr) - ); - } - - (, seizeVars.liquidatorAmountNew) = addUInt( - accountTokens[liquidator].underlyingAmount, - seizeVars.seizeAmount - ); - - accountTokens[borrower].tokens = seizeVars.borrowerTokensNew; - accountTokens[borrower].underlyingAmount = seizeVars.borrowerAmountNew; - accountTokens[borrower].suppliedAt = getBlockNumber(); - accountTokens[borrower].promisedSupplyRate = seizeVars.supplyRate; - - accountTokens[liquidator].tokens = seizeVars.liquidatorTokensNew; - accountTokens[liquidator].underlyingAmount = seizeVars - .liquidatorAmountNew; - accountTokens[liquidator].suppliedAt = getBlockNumber(); - accountTokens[liquidator].promisedSupplyRate = seizeVars.supplyRate; - - emit Transfer(borrower, liquidator, seizeTokens); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Begins transfer of admin rights. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer. - * @dev Admin function to begin change of admin. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer. - * @param newPendingAdmin New pending admin. - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setPendingAdmin(address payable newPendingAdmin) - external - override - returns (uint256) - { - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_PENDING_ADMIN_OWNER_CHECK - ); - } - - address oldPendingAdmin = pendingAdmin; - - pendingAdmin = newPendingAdmin; - - emit NewPendingAdmin(oldPendingAdmin, newPendingAdmin); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Accepts transfer of admin rights. msg.sender must be pendingAdmin - * @dev Admin function for pending admin to accept role and update admin - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _acceptAdmin() external override returns (uint256) { - if (msg.sender != pendingAdmin || msg.sender == address(0)) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.ACCEPT_ADMIN_PENDING_ADMIN_CHECK - ); - } - - address oldAdmin = admin; - address oldPendingAdmin = pendingAdmin; - - admin = pendingAdmin; - - pendingAdmin = payable(address(0)); - - emit NewAdmin(oldAdmin, admin); - emit NewPendingAdmin(oldPendingAdmin, pendingAdmin); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Sets a new comptroller for the market - * @dev Admin function to set a new comptroller - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setComptroller(ComptrollerInterface newComptroller) - public - override - returns (uint256) - { - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_COMPTROLLER_OWNER_CHECK - ); - } - - ComptrollerInterface oldComptroller = comptroller; - require(newComptroller.isComptroller(), "CT21"); - - comptroller = newComptroller; - - emit NewComptroller(oldComptroller, newComptroller); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice accrues interest and sets a new reserve factor for the protocol using _setReserveFactorFresh - * @dev Admin function to accrue interest and set a new reserve factor - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setReserveFactor(uint256 newReserveFactorMantissa) - external - override - nonReentrant - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return - fail( - Error(error), - FailureInfo.SET_RESERVE_FACTOR_ACCRUE_INTEREST_FAILED - ); - } - return _setReserveFactorFresh(newReserveFactorMantissa); - } - - /** - * @notice Sets a new reserve factor for the protocol (*requires fresh interest accrual) - * @dev Admin function to set a new reserve factor - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setReserveFactorFresh(uint256 newReserveFactorMantissa) - internal - returns (uint256) - { - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_RESERVE_FACTOR_ADMIN_CHECK - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.SET_RESERVE_FACTOR_FRESH_CHECK - ); - } - - if (newReserveFactorMantissa > reserveFactorMaxMantissa) { - return - fail( - Error.BAD_INPUT, - FailureInfo.SET_RESERVE_FACTOR_BOUNDS_CHECK - ); - } - - uint256 oldReserveFactorMantissa = reserveFactorMantissa; - reserveFactorMantissa = newReserveFactorMantissa; - - emit NewReserveFactor( - oldReserveFactorMantissa, - newReserveFactorMantissa - ); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Accrues interest and reduces reserves by transferring from msg.sender - * @param addAmount Amount of addition to reserves - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _addReservesInternal(uint256 addAmount) - internal - nonReentrant - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return - fail( - Error(error), - FailureInfo.ADD_RESERVES_ACCRUE_INTEREST_FAILED - ); - } - - uint256 totalReservesNew; - uint256 actualAddAmount; - - if (accrualBlockNumber != getBlockNumber()) { - return ( - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.ADD_RESERVES_FRESH_CHECK - ) - ); - } - - actualAddAmount = doTransferIn(msg.sender, addAmount); - - totalReservesNew = totalReserves + actualAddAmount; - - require(totalReservesNew >= totalReserves, "CT22"); - - totalReserves = totalReservesNew; - - emit ReservesAdded(msg.sender, actualAddAmount, totalReservesNew); - - return (uint256(Error.NO_ERROR)); - } - - function _addSubsidyInternal(uint256 addAmount) - internal - nonReentrant - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - // accrueInterest emits logs on errors, but on top of that we want to log the fact that an attempted reduce reserves failed. - return fail(Error(error), FailureInfo.ADD_SUBSIDY_FUND_FAILED); - } - - uint256 subsidyFundNew; - uint256 actualAddAmount; - - if (accrualBlockNumber != getBlockNumber()) { - return ( - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.ADD_SUBSIDY_FUND_FRESH_CHECK - ) - ); - } - - actualAddAmount = doTransferIn(msg.sender, addAmount); - - subsidyFundNew = subsidyFund + actualAddAmount; - - require(subsidyFundNew >= subsidyFund, "CT22"); - - subsidyFund = subsidyFundNew; - - emit SubsidyAdded(msg.sender, actualAddAmount, subsidyFundNew); - - /* Return (NO_ERROR, actualAddAmount) */ - return (uint256(Error.NO_ERROR)); - } - - /** - * @notice Accrues interest and reduces reserves by transferring to admin - * @param reduceAmount Amount of reduction to reserves - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _reduceReserves(uint256 reduceAmount) - external - override - nonReentrant - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return - fail( - Error(error), - FailureInfo.REDUCE_RESERVES_ACCRUE_INTEREST_FAILED - ); - } - return _reduceReservesFresh(reduceAmount); - } - - /** - * @notice Reduces reserves by transferring to admin - * @dev Requires fresh interest accrual - * @param reduceAmount Amount of reduction to reserves - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _reduceReservesFresh(uint256 reduceAmount) - internal - returns (uint256) - { - uint256 totalReservesNew; - - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.REDUCE_RESERVES_ADMIN_CHECK - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.REDUCE_RESERVES_FRESH_CHECK - ); - } - - if (getCashPrior() < reduceAmount) { - return - fail( - Error.TOKEN_INSUFFICIENT_CASH, - FailureInfo.REDUCE_RESERVES_CASH_NOT_AVAILABLE - ); - } - - if (reduceAmount > totalReserves) { - return - fail(Error.BAD_INPUT, FailureInfo.REDUCE_RESERVES_VALIDATION); - } - - totalReservesNew = totalReserves - reduceAmount; - require(totalReservesNew <= totalReserves, "CT23"); - - totalReserves = totalReservesNew; - - doTransferOut(admin, reduceAmount); - - emit ReservesReduced(admin, reduceAmount, totalReservesNew); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice accrues interest and updates the interest rate model using _setInterestRateModelFresh - * @dev Admin function to accrue interest and update the interest rate model - * @param newInterestRateModel the new interest rate model to use - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setInterestRateModel(InterestRateModel newInterestRateModel) - public - override - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return - fail( - Error(error), - FailureInfo.SET_INTEREST_RATE_MODEL_ACCRUE_INTEREST_FAILED - ); - } - return _setInterestRateModelFresh(newInterestRateModel); - } - - /** - * @notice updates the interest rate model (*requires fresh interest accrual) - * @dev Admin function to update the interest rate model - * @param newInterestRateModel the new interest rate model to use - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setInterestRateModelFresh(InterestRateModel newInterestRateModel) - internal - returns (uint256) - { - InterestRateModel oldInterestRateModel; - - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_INTEREST_RATE_MODEL_OWNER_CHECK - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.SET_INTEREST_RATE_MODEL_FRESH_CHECK - ); - } - - oldInterestRateModel = interestRateModel; - - require(newInterestRateModel.isInterestRateModel(), "CT21"); - - interestRateModel = newInterestRateModel; - - emit NewMarketInterestRateModel( - oldInterestRateModel, - newInterestRateModel - ); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Gets balance of this contract in terms of the underlying - * @dev This excludes the value of the current message, if any - * @return The quantity of underlying owned by this contract - */ - function getCashPrior() internal view virtual returns (uint256); - - /** - * @dev Performs a transfer in, reverting upon failure. Returns the amount actually transferred to the protocol, in case of a fee. - * This may revert due to insufficient balance or insufficient allowance. - */ - function doTransferIn(address from, uint256 amount) - internal - virtual - returns (uint256); - - /** - * @dev Performs a transfer out, ideally returning an explanatory error code upon failure tather than reverting. - * If caller has not called checked protocol's balance, may revert due to insufficient cash held in the contract. - * If caller has checked protocol's balance, and verified it is >= amount, this should not revert in normal conditions. - */ - function doTransferOut(address payable to, uint256 amount) internal virtual; - - /** - * @dev Prevents a contract from calling itself, directly or indirectly. - */ - modifier nonReentrant() { - require(_notEntered, "re-entered"); - _notEntered = false; - _; - _notEntered = true; - } -} - - -// Root file: contracts/CRBTC.sol - -pragma solidity 0.8.6; - -// import "contracts/CToken.sol"; - -/** - * @title tropykus CRBTC Contract - * @notice CToken which wraps Ether - * @author tropykus - */ -contract CRBTC is CToken { - /** - * @notice Construct a new CRBTC money market - * @param comptroller_ The address of the Comptroller - * @param interestRateModel_ The address of the interest rate model - * @param initialExchangeRateMantissa_ The initial exchange rate, scaled by 1e18 - * @param name_ ERC-20 name of this token - * @param symbol_ ERC-20 symbol of this token - * @param decimals_ ERC-20 decimal precision of this token - * @param admin_ Address of the administrator of this token - */ - constructor( - ComptrollerInterface comptroller_, - InterestRateModel interestRateModel_, - uint256 initialExchangeRateMantissa_, - string memory name_, - string memory symbol_, - uint8 decimals_, - address payable admin_ - ) { - // Creator of the contract is admin during initialization - admin = payable(msg.sender); - - initialize( - comptroller_, - interestRateModel_, - initialExchangeRateMantissa_, - name_, - symbol_, - decimals_ - ); - - // Set the proper admin now that initialization is done - admin = admin_; - } - - /*** User Interface ***/ - - /** - * @notice Sender supplies assets into the market and receives cTokens in exchange - * @dev Reverts upon any failure - */ - function mint() external payable { - (uint256 err, ) = mintInternal(msg.value); - requireNoError(err, "RC01"); - } - - /** - * @notice Sender redeems cTokens in exchange for a specified amount of underlying asset - * @dev Accrues interest whether or not the operation succeeds, unless reverted - * @param redeemAmount The amount of underlying to redeem - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function redeem(uint256 redeemAmount) external returns (uint256) { - return redeemUnderlyingInternal(redeemAmount); - } - - /** - * @notice Sender borrows assets from the protocol to their own address - * @param borrowAmount The amount of the underlying asset to borrow - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function borrow(uint256 borrowAmount) external returns (uint256) { - return borrowInternal(borrowAmount); - } - - /** - * @notice Sender repays their own borrow - * @dev Reverts upon any failure - */ - function repayBorrow() external payable { - (uint256 err, ) = repayBorrowInternal(msg.value); - requireNoError(err, "RC02"); - } - - /** - * @notice The sender liquidates the borrowers collateral. - * The collateral seized is transferred to the liquidator. - * @dev Reverts upon any failure - * @param borrower The borrower of this cToken to be liquidated - * @param cTokenCollateral The market in which to seize collateral from the borrower - */ - function liquidateBorrow(address borrower, CToken cTokenCollateral) - external - payable - { - (uint256 err, ) = liquidateBorrowInternal( - borrower, - msg.value, - cTokenCollateral - ); - requireNoError(err, "RC04"); - } - - /** - * @notice Send Ether to CRBTC to mint - */ - fallback() external payable { - internalFallback(); - } - - receive() external payable { - internalFallback(); - } - - function internalFallback() public payable { - (uint256 err, ) = mintInternal(msg.value); - requireNoError(err, "RC01"); - } - - /*** Safe Token ***/ - - /** - * @notice Gets balance of this contract in terms of Ether, before this message - * @dev This excludes the value of the current message, if any - * @return The quantity of Ether owned by this contract - */ - function getCashPrior() internal view override returns (uint256) { - (MathError err, uint256 startingBalance) = subUInt( - address(this).balance, - msg.value - ); - if (interestRateModel.isTropykusInterestRateModel()) - (err, startingBalance) = subUInt(startingBalance, subsidyFund); - require(err == MathError.NO_ERROR, "RC05"); - return startingBalance; - } - - /** - * @notice Perform the actual transfer in, which is a no-op - * @param from Address sending the Ether - * @param amount Amount of Ether being sent - * @return The actual amount of Ether transferred - */ - function doTransferIn(address from, uint256 amount) - internal - override - returns (uint256) - { - // Sanity checks - require(msg.sender == from, "RC06"); - require(msg.value == amount, "RC07"); - return amount; - } - - function doTransferOut(address payable to, uint256 amount) - internal - virtual - override - { - /* Send the Ether, with minimal gas and revert on failure */ - to.transfer(amount); - } - - function requireNoError(uint256 errCode, string memory message) - internal - pure - { - if (errCode == uint256(Error.NO_ERROR)) { - return; - } - - bytes memory fullMessage = new bytes(bytes(message).length + 5); - uint256 i; - - for (i = 0; i < bytes(message).length; i++) { - fullMessage[i] = bytes(message)[i]; - } - - fullMessage[i + 0] = bytes1(uint8(32)); - fullMessage[i + 1] = bytes1(uint8(40)); - fullMessage[i + 2] = bytes1(uint8(48 + (errCode / 10))); - fullMessage[i + 3] = bytes1(uint8(48 + (errCode % 10))); - fullMessage[i + 4] = bytes1(uint8(41)); - - require(errCode == uint256(Error.NO_ERROR), string(fullMessage)); - } - - function addSubsidy() external payable { - _addSubsidyInternal(msg.value); - } -} diff --git a/flatten/CToken.sol b/flatten/CToken.sol deleted file mode 100644 index aba3a34..0000000 --- a/flatten/CToken.sol +++ /dev/null @@ -1,3923 +0,0 @@ -// Dependency file: contracts/ComptrollerInterface.sol - -// SPDX-License-Identifier: UNLICENSED -// pragma solidity 0.8.6; - -abstract contract ComptrollerInterface { - /// @notice Indicator that this is a Comptroller contract (for inspection) - bool public constant isComptroller = true; - - /*** Assets You Are In ***/ - - function enterMarkets(address[] calldata cTokens) - external - virtual - returns (uint256[] memory); - - function exitMarket(address cToken) external virtual returns (uint256); - - /*** Policy Hooks ***/ - - function mintAllowed( - address cToken, - address minter, - uint256 mintAmount - ) external virtual returns (uint256); - - function mintVerify( - address cToken, - address minter, - uint256 mintAmount, - uint256 mintTokens - ) external virtual; - - function redeemAllowed( - address cToken, - address redeemer, - uint256 redeemTokens - ) external virtual returns (uint256); - - function redeemVerify( - address cToken, - address redeemer, - uint256 redeemAmount, - uint256 redeemTokens - ) external virtual; - - function borrowAllowed( - address cToken, - address borrower, - uint256 borrowAmount - ) external virtual returns (uint256); - - function borrowVerify( - address cToken, - address borrower, - uint256 borrowAmount - ) external virtual; - - function repayBorrowAllowed( - address cToken, - address payer, - address borrower, - uint256 repayAmount - ) external virtual returns (uint256); - - function repayBorrowVerify( - address cToken, - address payer, - address borrower, - uint256 repayAmount, - uint256 borrowerIndex - ) external virtual; - - function liquidateBorrowAllowed( - address cTokenBorrowed, - address cTokenCollateral, - address liquidator, - address borrower, - uint256 repayAmount - ) external virtual returns (uint256); - - function liquidateBorrowVerify( - address cTokenBorrowed, - address cTokenCollateral, - address liquidator, - address borrower, - uint256 repayAmount, - uint256 seizeTokens - ) external virtual; - - function seizeAllowed( - address cTokenCollateral, - address cTokenBorrowed, - address liquidator, - address borrower, - uint256 seizeTokens - ) external virtual returns (uint256); - - function seizeVerify( - address cTokenCollateral, - address cTokenBorrowed, - address liquidator, - address borrower, - uint256 seizeTokens - ) external virtual; - - function transferAllowed( - address cToken, - address src, - address dst, - uint256 transferTokens - ) external virtual returns (uint256); - - function transferVerify( - address cToken, - address src, - address dst, - uint256 transferTokens - ) external virtual; - - /*** Liquidity/Liquidation Calculations ***/ - - function liquidateCalculateSeizeTokens( - address cTokenBorrowed, - address cTokenCollateral, - uint256 repayAmount - ) external view virtual returns (uint256, uint256); -} - - -// Dependency file: contracts/CarefulMath.sol - -// pragma solidity 0.8.6; - -/** - * @title Careful Math - * @author tropykus - * @notice Derived from OpenZeppelin's SafeMath library - * https://github.com/OpenZeppelin/openzeppelin-solidity/blob/master/contracts/math/SafeMath.sol - */ -contract CarefulMath { - - /** - * @dev Possible error codes that we can return - */ - enum MathError { - NO_ERROR, - DIVISION_BY_ZERO, - INTEGER_OVERFLOW, - INTEGER_UNDERFLOW - } - - /** - * @dev Multiplies two numbers, returns an error on overflow. - */ - function mulUInt(uint a, uint b) internal pure returns (MathError, uint) { - if (a == 0) { - return (MathError.NO_ERROR, 0); - } - - uint c = a * b; - - if (c / a != b) { - return (MathError.INTEGER_OVERFLOW, 0); - } else { - return (MathError.NO_ERROR, c); - } - } - - /** - * @dev Integer division of two numbers, truncating the quotient. - */ - function divUInt(uint a, uint b) internal pure returns (MathError, uint) { - if (b == 0) { - return (MathError.DIVISION_BY_ZERO, 0); - } - - return (MathError.NO_ERROR, a / b); - } - - /** - * @dev Subtracts two numbers, returns an error on overflow (i.e. if subtrahend is greater than minuend). - */ - function subUInt(uint a, uint b) internal pure returns (MathError, uint) { - if (b <= a) { - return (MathError.NO_ERROR, a - b); - } else { - return (MathError.INTEGER_UNDERFLOW, 0); - } - } - - /** - * @dev Adds two numbers, returns an error on overflow. - */ - function addUInt(uint a, uint b) internal pure returns (MathError, uint) { - uint c = a + b; - - if (c >= a) { - return (MathError.NO_ERROR, c); - } else { - return (MathError.INTEGER_OVERFLOW, 0); - } - } - - /** - * @dev add a and b and then subtract c - */ - function addThenSubUInt(uint a, uint b, uint c) internal pure returns (MathError, uint) { - (MathError err0, uint sum) = addUInt(a, b); - - if (err0 != MathError.NO_ERROR) { - return (err0, 0); - } - - return subUInt(sum, c); - } -} - - -// Dependency file: contracts/ExponentialNoError.sol - -// pragma solidity 0.8.6; - -/** - * @title Exponential module for storing fixed-precision decimals - * @author tropykus - * @notice Exp is a struct which stores decimals with a fixed precision of 18 decimal places. - * Thus, if we wanted to store the 5.1, mantissa would store 5.1e18. That is: - * `Exp({mantissa: 5100000000000000000})`. - */ -contract ExponentialNoError { - uint constant expScale = 1e18; - uint constant doubleScale = 1e36; - uint constant halfExpScale = expScale/2; - uint constant mantissaOne = expScale; - - struct Exp { - uint mantissa; - } - - struct Double { - uint mantissa; - } - - /** - * @dev Truncates the given exp to a whole number value. - * For example, truncate(Exp{mantissa: 15 * expScale}) = 15 - */ - function truncate(Exp memory exp) pure internal returns (uint) { - // Note: We are not using careful math here as we're performing a division that cannot fail - return exp.mantissa / expScale; - } - - /** - * @dev Multiply an Exp by a scalar, then truncate to return an unsigned integer. - */ - function mul_ScalarTruncate(Exp memory a, uint scalar) pure internal returns (uint) { - Exp memory product = mul_(a, scalar); - return truncate(product); - } - - /** - * @dev Multiply an Exp by a scalar, truncate, then add an to an unsigned integer, returning an unsigned integer. - */ - function mul_ScalarTruncateAddUInt(Exp memory a, uint scalar, uint addend) pure internal returns (uint) { - Exp memory product = mul_(a, scalar); - return add_(truncate(product), addend); - } - - /** - * @dev Checks if first Exp is less than second Exp. - */ - function lessThanExp(Exp memory left, Exp memory right) pure internal returns (bool) { - return left.mantissa < right.mantissa; - } - - /** - * @dev Checks if left Exp <= right Exp. - */ - function lessThanOrEqualExp(Exp memory left, Exp memory right) pure internal returns (bool) { - return left.mantissa <= right.mantissa; - } - - /** - * @dev Checks if left Exp > right Exp. - */ - function greaterThanExp(Exp memory left, Exp memory right) pure internal returns (bool) { - return left.mantissa > right.mantissa; - } - - /** - * @dev returns true if Exp is exactly zero - */ - function isZeroExp(Exp memory value) pure internal returns (bool) { - return value.mantissa == 0; - } - - function safe224(uint n, string memory errorMessage) pure internal returns (uint224) { - require(n < 2**224, errorMessage); - return uint224(n); - } - - function safe32(uint n, string memory errorMessage) pure internal returns (uint32) { - require(n < 2**32, errorMessage); - return uint32(n); - } - - function add_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { - return Exp({mantissa: add_(a.mantissa, b.mantissa)}); - } - - function add_(Double memory a, Double memory b) pure internal returns (Double memory) { - return Double({mantissa: add_(a.mantissa, b.mantissa)}); - } - - function add_(uint a, uint b) pure internal returns (uint) { - return add_(a, b, "addition overflow"); - } - - function add_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { - uint c = a + b; - require(c >= a, errorMessage); - return c; - } - - function sub_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { - return Exp({mantissa: sub_(a.mantissa, b.mantissa)}); - } - - function sub_(Double memory a, Double memory b) pure internal returns (Double memory) { - return Double({mantissa: sub_(a.mantissa, b.mantissa)}); - } - - function sub_(uint a, uint b) pure internal returns (uint) { - return sub_(a, b, "subtraction underflow"); - } - - function sub_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { - require(b <= a, errorMessage); - return a - b; - } - - function mul_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { - return Exp({mantissa: mul_(a.mantissa, b.mantissa) / expScale}); - } - - function mul_(Exp memory a, uint b) pure internal returns (Exp memory) { - return Exp({mantissa: mul_(a.mantissa, b)}); - } - - function mul_(uint a, Exp memory b) pure internal returns (uint) { - return mul_(a, b.mantissa) / expScale; - } - - function mul_(Double memory a, Double memory b) pure internal returns (Double memory) { - return Double({mantissa: mul_(a.mantissa, b.mantissa) / doubleScale}); - } - - function mul_(Double memory a, uint b) pure internal returns (Double memory) { - return Double({mantissa: mul_(a.mantissa, b)}); - } - - function mul_(uint a, Double memory b) pure internal returns (uint) { - return mul_(a, b.mantissa) / doubleScale; - } - - function mul_(uint a, uint b) pure internal returns (uint) { - return mul_(a, b, "multiplication overflow"); - } - - function mul_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { - if (a == 0 || b == 0) { - return 0; - } - uint c = a * b; - require(c / a == b, errorMessage); - return c; - } - - function div_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { - return Exp({mantissa: div_(mul_(a.mantissa, expScale), b.mantissa)}); - } - - function div_(Exp memory a, uint b) pure internal returns (Exp memory) { - return Exp({mantissa: div_(a.mantissa, b)}); - } - - function div_(uint a, Exp memory b) pure internal returns (uint) { - return div_(mul_(a, expScale), b.mantissa); - } - - function div_(Double memory a, Double memory b) pure internal returns (Double memory) { - return Double({mantissa: div_(mul_(a.mantissa, doubleScale), b.mantissa)}); - } - - function div_(Double memory a, uint b) pure internal returns (Double memory) { - return Double({mantissa: div_(a.mantissa, b)}); - } - - function div_(uint a, Double memory b) pure internal returns (uint) { - return div_(mul_(a, doubleScale), b.mantissa); - } - - function div_(uint a, uint b) pure internal returns (uint) { - return div_(a, b, "divide by zero"); - } - - function div_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { - require(b > 0, errorMessage); - return a / b; - } - - function fraction(uint a, uint b) pure internal returns (Double memory) { - return Double({mantissa: div_(mul_(a, doubleScale), b)}); - } -} - - -// Dependency file: contracts/Exponential.sol - -// pragma solidity 0.8.6; - -// import "contracts/CarefulMath.sol"; -// import "contracts/ExponentialNoError.sol"; - -/** - * @title Exponential module for storing fixed-precision decimals - * @author tropykus - * @dev Legacy contract for compatibility reasons with existing contracts that still use MathError - * @notice Exp is a struct which stores decimals with a fixed precision of 18 decimal places. - * Thus, if we wanted to store the 5.1, mantissa would store 5.1e18. That is: - * `Exp({mantissa: 5100000000000000000})`. - */ -contract Exponential is CarefulMath, ExponentialNoError { - /** - * @dev Creates an exponential from numerator and denominator values. - * Note: Returns an error if (`num` * 10e18) > MAX_INT, - * or if `denom` is zero. - */ - function getExp(uint num, uint denom) internal pure returns (MathError, Exp memory) { - (MathError err0, uint scaledNumerator) = mulUInt(num, expScale); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - - (MathError err1, uint rational) = divUInt(scaledNumerator, denom); - if (err1 != MathError.NO_ERROR) { - return (err1, Exp({mantissa: 0})); - } - - return (MathError.NO_ERROR, Exp({mantissa: rational})); - } - - /** - * @dev Adds two exponentials, returning a new exponential. - */ - function addExp(Exp memory a, Exp memory b) internal pure returns (MathError, Exp memory) { - (MathError error, uint result) = addUInt(a.mantissa, b.mantissa); - - return (error, Exp({mantissa: result})); - } - - /** - * @dev Subtracts two exponentials, returning a new exponential. - */ - function subExp(Exp memory a, Exp memory b) internal pure returns (MathError, Exp memory) { - (MathError error, uint result) = subUInt(a.mantissa, b.mantissa); - - return (error, Exp({mantissa: result})); - } - - /** - * @dev Multiply an Exp by a scalar, returning a new Exp. - */ - function mulScalar(Exp memory a, uint scalar) internal pure returns (MathError, Exp memory) { - (MathError err0, uint scaledMantissa) = mulUInt(a.mantissa, scalar); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - - return (MathError.NO_ERROR, Exp({mantissa: scaledMantissa})); - } - - /** - * @dev Multiply an Exp by a scalar, then truncate to return an unsigned integer. - */ - function mulScalarTruncate(Exp memory a, uint scalar) internal pure returns (MathError, uint) { - (MathError err, Exp memory product) = mulScalar(a, scalar); - if (err != MathError.NO_ERROR) { - return (err, 0); - } - - return (MathError.NO_ERROR, truncate(product)); - } - - /** - * @dev Multiply an Exp by a scalar, truncate, then add an to an unsigned integer, returning an unsigned integer. - */ - function mulScalarTruncateAddUInt(Exp memory a, uint scalar, uint addend) internal pure returns (MathError, uint) { - (MathError err, Exp memory product) = mulScalar(a, scalar); - if (err != MathError.NO_ERROR) { - return (err, 0); - } - - return addUInt(truncate(product), addend); - } - - /** - * @dev Divide an Exp by a scalar, returning a new Exp. - */ - function divScalar(Exp memory a, uint scalar) internal pure returns (MathError, Exp memory) { - (MathError err0, uint descaledMantissa) = divUInt(a.mantissa, scalar); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - - return (MathError.NO_ERROR, Exp({mantissa: descaledMantissa})); - } - - /** - * @dev Divide a scalar by an Exp, returning a new Exp. - */ - function divScalarByExp(uint scalar, Exp memory divisor) internal pure returns (MathError, Exp memory) { - /* - We are doing this as: - getExp(mulUInt(expScale, scalar), divisor.mantissa) - - How it works: - Exp = a / b; - Scalar = s; - `s / (a / b)` = `b * s / a` and since for an Exp `a = mantissa, b = expScale` - */ - (MathError err0, uint numerator) = mulUInt(expScale, scalar); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - return getExp(numerator, divisor.mantissa); - } - - /** - * @dev Divide a scalar by an Exp, then truncate to return an unsigned integer. - */ - function divScalarByExpTruncate(uint scalar, Exp memory divisor) internal pure returns (MathError, uint) { - (MathError err, Exp memory fraction) = divScalarByExp(scalar, divisor); - if (err != MathError.NO_ERROR) { - return (err, 0); - } - - return (MathError.NO_ERROR, truncate(fraction)); - } - - /** - * @dev Multiplies two exponentials, returning a new exponential. - */ - function mulExp(Exp memory a, Exp memory b) internal pure returns (MathError, Exp memory) { - - (MathError err0, uint doubleScaledProduct) = mulUInt(a.mantissa, b.mantissa); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - - // We add half the scale before dividing so that we get rounding instead of truncation. - // See "Listing 6" and text above it at https://accu.org/index.php/journals/1717 - // Without this change, a result like 6.6...e-19 will be truncated to 0 instead of being rounded to 1e-18. - (MathError err1, uint doubleScaledProductWithHalfScale) = addUInt(halfExpScale, doubleScaledProduct); - if (err1 != MathError.NO_ERROR) { - return (err1, Exp({mantissa: 0})); - } - - (MathError err2, uint product) = divUInt(doubleScaledProductWithHalfScale, expScale); - // The only error `div` can return is MathError.DIVISION_BY_ZERO but we control `expScale` and it is not zero. - assert(err2 == MathError.NO_ERROR); - - return (MathError.NO_ERROR, Exp({mantissa: product})); - } - - /** - * @dev Multiplies two exponentials given their mantissas, returning a new exponential. - */ - function mulExp(uint a, uint b) internal pure returns (MathError, Exp memory) { - return mulExp(Exp({mantissa: a}), Exp({mantissa: b})); - } - - /** - * @dev Multiplies three exponentials, returning a new exponential. - */ - function mulExp3(Exp memory a, Exp memory b, Exp memory c) internal pure returns (MathError, Exp memory) { - (MathError err, Exp memory ab) = mulExp(a, b); - if (err != MathError.NO_ERROR) { - return (err, ab); - } - return mulExp(ab, c); - } - - /** - * @dev Divides two exponentials, returning a new exponential. - * (a/scale) / (b/scale) = (a/scale) * (scale/b) = a/b, - * which we can scale as an Exp by calling getExp(a.mantissa, b.mantissa) - */ - function divExp(Exp memory a, Exp memory b) internal pure returns (MathError, Exp memory) { - return getExp(a.mantissa, b.mantissa); - } -} - - -// Dependency file: contracts/SafeMath.sol - -// pragma solidity 0.8.6; - -// From https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/math/Math.sol -// Subject to the MIT license. - -/** - * @dev Wrappers over Solidity's arithmetic operations with added overflow - * checks. - * - * Arithmetic operations in Solidity wrap on overflow. This can easily result - * in bugs, because programmers usually assume that an overflow raises an - * error, which is the standard behavior in high level programming languages. - * `SafeMath` restores this intuition by reverting the transaction when an - * operation overflows. - * - * Using this library instead of the unchecked operations eliminates an entire - * class of bugs, so it's recommended to use it always. - */ -library SafeMath { - /** - * @dev Returns the addition of two unsigned integers, reverting on overflow. - * - * Counterpart to Solidity's `+` operator. - * - * Requirements: - * - Addition cannot overflow. - */ - function add(uint256 a, uint256 b) internal pure returns (uint256) { - uint256 c = a + b; - require(c >= a, "SafeMath: addition overflow"); - - return c; - } - - /** - * @dev Returns the addition of two unsigned integers, reverting with custom message on overflow. - * - * Counterpart to Solidity's `+` operator. - * - * Requirements: - * - Addition cannot overflow. - */ - function add(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - uint256 c = a + b; - require(c >= a, errorMessage); - - return c; - } - - /** - * @dev Returns the subtraction of two unsigned integers, reverting on underflow (when the result is negative). - * - * Counterpart to Solidity's `-` operator. - * - * Requirements: - * - Subtraction cannot underflow. - */ - function sub(uint256 a, uint256 b) internal pure returns (uint256) { - return sub(a, b, "SafeMath: subtraction underflow"); - } - - /** - * @dev Returns the subtraction of two unsigned integers, reverting with custom message on underflow (when the result is negative). - * - * Counterpart to Solidity's `-` operator. - * - * Requirements: - * - Subtraction cannot underflow. - */ - function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - require(b <= a, errorMessage); - uint256 c = a - b; - - return c; - } - - /** - * @dev Returns the multiplication of two unsigned integers, reverting on overflow. - * - * Counterpart to Solidity's `*` operator. - * - * Requirements: - * - Multiplication cannot overflow. - */ - function mul(uint256 a, uint256 b) internal pure returns (uint256) { - // Gas optimization: this is cheaper than requiring 'a' not being zero, but the - // benefit is lost if 'b' is also tested. - // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 - if (a == 0) { - return 0; - } - - uint256 c = a * b; - require(c / a == b, "SafeMath: multiplication overflow"); - - return c; - } - - /** - * @dev Returns the multiplication of two unsigned integers, reverting on overflow. - * - * Counterpart to Solidity's `*` operator. - * - * Requirements: - * - Multiplication cannot overflow. - */ - function mul(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - // Gas optimization: this is cheaper than requiring 'a' not being zero, but the - // benefit is lost if 'b' is also tested. - // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 - if (a == 0) { - return 0; - } - - uint256 c = a * b; - require(c / a == b, errorMessage); - - return c; - } - - /** - * @dev Returns the integer division of two unsigned integers. - * Reverts on division by zero. The result is rounded towards zero. - * - * Counterpart to Solidity's `/` operator. Note: this function uses a - * `revert` opcode (which leaves remaining gas untouched) while Solidity - * uses an invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function div(uint256 a, uint256 b) internal pure returns (uint256) { - return div(a, b, "SafeMath: division by zero"); - } - - /** - * @dev Returns the integer division of two unsigned integers. - * Reverts with custom message on division by zero. The result is rounded towards zero. - * - * Counterpart to Solidity's `/` operator. Note: this function uses a - * `revert` opcode (which leaves remaining gas untouched) while Solidity - * uses an invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - // Solidity only automatically asserts when dividing by 0 - require(b > 0, errorMessage); - uint256 c = a / b; - // assert(a == b * c + a % b); // There is no case in which this doesn't hold - - return c; - } - - /** - * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), - * Reverts when dividing by zero. - * - * Counterpart to Solidity's `%` operator. This function uses a `revert` - * opcode (which leaves remaining gas untouched) while Solidity uses an - * invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function mod(uint256 a, uint256 b) internal pure returns (uint256) { - return mod(a, b, "SafeMath: modulo by zero"); - } - - /** - * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), - * Reverts with custom message when dividing by zero. - * - * Counterpart to Solidity's `%` operator. This function uses a `revert` - * opcode (which leaves remaining gas untouched) while Solidity uses an - * invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - require(b != 0, errorMessage); - return a % b; - } -} - - -// Dependency file: contracts/InterestRateModel.sol - -// pragma solidity 0.8.6; - -// import "contracts/Exponential.sol"; -// import "contracts/SafeMath.sol"; - -/** - * @title tropykus InterestRateModel Interface - * @author tropykus - */ -abstract contract InterestRateModel is Exponential { - using SafeMath for uint256; - - /// @notice Indicator that this is an InterestRateModel contract (for inspection) - bool public constant isInterestRateModel = true; - bool public isTropykusInterestRateModel; - - /** - * @notice The approximate number of blocks per year that is assumed by the interest rate model - */ - uint256 public constant blocksPerYear = 1051200; - - /** - * @notice Calculates the utilization rate of the market: `borrows / (cash + borrows - reserves)` - * @param cash The amount of cash in the market - * @param borrows The amount of borrows in the market - * @param reserves The amount of reserves in the market (currently unused) - * @return The utilization rate as a mantissa between [0, 1e18] - */ - function utilizationRate( - uint256 cash, - uint256 borrows, - uint256 reserves - ) public pure virtual returns (uint256) { - // Utilization rate is 0 when there are no borrows - if (borrows == 0) { - return 0; - } - - return borrows.mul(1e18).div(cash.add(borrows).sub(reserves)); - } - - /** - * @notice Calculates the current borrow interest rate per block - * @param cash The total amount of cash the market has - * @param borrows The total amount of borrows the market has outstanding - * @param reserves The total amnount of reserves the market has - * @return The borrow rate per block (as a percentage, and scaled by 1e18) - */ - function getBorrowRate( - uint256 cash, - uint256 borrows, - uint256 reserves - ) external view virtual returns (uint256); - - /** - * @notice Calculates the current supply interest rate per block - * @param cash The total amount of cash the market has - * @param borrows The total amount of borrows the market has outstanding - * @param reserves The total amnount of reserves the market has - * @param reserveFactorMantissa The current reserve factor the market has - * @return The supply rate per block (as a percentage, and scaled by 1e18) - */ - function getSupplyRate( - uint256 cash, - uint256 borrows, - uint256 reserves, - uint256 reserveFactorMantissa - ) external view virtual returns (uint256); - - function getExchangeRate( - uint256 _totalCash, - uint256 _totalBorrows, - uint256 _totalReserves, - uint256 _totalSupply - ) public pure returns (MathError, uint256) { - /* - * exchangeRate = (totalCash + totalBorrows - totalReserves) / totalSupply - */ - Exp memory exchangeRate; - MathError mathErr; - uint256 cashPlusBorrowsMinusReserves; - (mathErr, cashPlusBorrowsMinusReserves) = addThenSubUInt( - _totalCash, - _totalBorrows, - _totalReserves - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - (mathErr, exchangeRate) = getExp( - cashPlusBorrowsMinusReserves, - _totalSupply - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - - return (MathError.NO_ERROR, exchangeRate.mantissa); - } - - function isAboveOptimal( - uint256 cash, - uint256 borrows, - uint256 reserves - ) public view virtual returns (bool) { - cash; - borrows; - reserves; - return false; - } -} - - -// Dependency file: contracts/EIP20NonStandardInterface.sol - -// pragma solidity 0.8.6; - -/** - * @title EIP20NonStandardInterface - * @dev Version of ERC20 with no return values for `transfer` and `transferFrom` - * See https://medium.com/coinmonks/missing-return-value-bug-at-least-130-tokens-affected-d67bf08521ca - */ -interface EIP20NonStandardInterface { - /** - * @notice Get the total number of tokens in circulation - * @return The supply of tokens - */ - function totalSupply() external view returns (uint256); - - /** - * @notice Gets the balance of the specified address - * @param owner The address from which the balance will be retrieved - * @return balance The balance - */ - function balanceOf(address owner) external view returns (uint256 balance); - - /// - /// !!!!!!!!!!!!!! - /// !!! NOTICE !!! `transfer` does not return a value, in violation of the ERC-20 specification - /// !!!!!!!!!!!!!! - /// - - /** - * @notice Transfer `amount` tokens from `msg.sender` to `dst` - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - */ - function transfer(address dst, uint256 amount) external; - - /// - /// !!!!!!!!!!!!!! - /// !!! NOTICE !!! `transferFrom` does not return a value, in violation of the ERC-20 specification - /// !!!!!!!!!!!!!! - /// - - /** - * @notice Transfer `amount` tokens from `src` to `dst` - * @param src The address of the source account - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - */ - function transferFrom( - address src, - address dst, - uint256 amount - ) external; - - /** - * @notice Approve `spender` to transfer up to `amount` from `src` - * @dev This will overwrite the approval amount for `spender` - * and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve) - * @param spender The address of the account which may transfer tokens - * @param amount The number of tokens that are approved - * @return success Whether or not the approval succeeded - */ - function approve(address spender, uint256 amount) - external - returns (bool success); - - /** - * @notice Get the current allowance from `owner` for `spender` - * @param owner The address of the account which owns the tokens to be spent - * @param spender The address of the account which may transfer tokens - * @return remaining The number of tokens allowed to be spent - */ - function allowance(address owner, address spender) - external - view - returns (uint256 remaining); - - event Transfer(address indexed from, address indexed to, uint256 amount); - event Approval( - address indexed owner, - address indexed spender, - uint256 amount - ); -} - - -// Dependency file: contracts/CTokenInterfaces.sol - -// pragma solidity 0.8.6; - -// import "contracts/ComptrollerInterface.sol"; -// import "contracts/InterestRateModel.sol"; -// import "contracts/EIP20NonStandardInterface.sol"; - -contract CTokenStorage { - /** - * @dev Guard variable for re-entrancy checks - */ - bool internal _notEntered; - - /** - * @notice EIP-20 token name for this token - */ - string public name; - - /** - * @notice EIP-20 token symbol for this token - */ - string public symbol; - - /** - * @notice EIP-20 token decimals for this token - */ - uint8 public decimals; - - /** - * @notice Maximum borrow rate that can ever be applied (.0005% / block) - */ - - uint256 internal constant borrowRateMaxMantissa = 0.0005e16; - - /** - * @notice Maximum fraction of interest that can be set aside for reserves - */ - uint256 internal constant reserveFactorMaxMantissa = 1e18; - - /** - * @notice Administrator for this contract - */ - address payable public admin; - - /** - * @notice Pending administrator for this contract - */ - address payable public pendingAdmin; - - /** - * @notice Contract which oversees inter-cToken operations - */ - ComptrollerInterface public comptroller; - - /** - * @notice Model which tells what the current interest rate should be - */ - InterestRateModel public interestRateModel; - - /** - * @notice Initial exchange rate used when minting the first CTokens (used when totalSupply = 0) - */ - uint256 public initialExchangeRateMantissa; - - /** - * @notice Fraction of interest currently set aside for reserves - */ - uint256 public reserveFactorMantissa; - - /** - * @notice Block number that interest was last accrued at - */ - uint256 public accrualBlockNumber; - - /** - * @notice Accumulator of the total earned interest rate since the opening of the market - */ - uint256 public borrowIndex; - - /** - * @notice Total amount of outstanding borrows of the underlying in this market - */ - uint256 public totalBorrows; - - /** - * @notice Total amount of reserves of the underlying held in this market - */ - uint256 public totalReserves; - - /** - * @notice Total number of tokens in circulation - */ - uint256 public totalSupply; - - uint256 public subsidyFund; - - struct SupplySnapshot { - uint256 tokens; - uint256 underlyingAmount; - uint256 suppliedAt; - uint256 promisedSupplyRate; - } - - /** - * @notice Official record of token balances for each account - */ - mapping(address => SupplySnapshot) internal accountTokens; - - /** - * @notice Approved token transfer amounts on behalf of others - */ - mapping(address => mapping(address => uint256)) internal transferAllowances; - - /** - * @notice Container for borrow balance information - * @member principal Total balance (with accrued interest), after applying the most recent balance-changing action - * @member interestIndex Global borrowIndex as of the most recent balance-changing action - */ - struct BorrowSnapshot { - uint256 principal; - uint256 interestIndex; - } - - /** - * @notice Mapping of account addresses to outstanding borrow balances - */ - mapping(address => BorrowSnapshot) internal accountBorrows; -} - -abstract contract CTokenInterface is CTokenStorage { - /** - * @notice Indicator that this is a CToken contract (for inspection) - */ - bool public constant isCToken = true; - - /*** Market Events ***/ - - /** - * @notice Event emitted when interest is accrued - */ - event AccrueInterest( - uint256 cashPrior, - uint256 interestAccumulated, - uint256 borrowIndex, - uint256 totalBorrows - ); - - /** - * @notice Event emitted when tokens are minted - */ - event Mint(address indexed minter, uint256 mintAmount, uint256 mintTokens); - - /** - * @notice Event emitted when tokens are redeemed - */ - event Redeem( - address indexed redeemer, - uint256 redeemAmount, - uint256 redeemTokens - ); - - /** - * @notice Event emitted when underlying is borrowed - */ - event Borrow( - address indexed borrower, - uint256 borrowAmount, - uint256 accountBorrows, - uint256 totalBorrows - ); - - /** - * @notice Event emitted when a borrow is repaid - */ - event RepayBorrow( - address indexed payer, - address indexed borrower, - uint256 repayAmount, - uint256 accountBorrows, - uint256 totalBorrows - ); - - /** - * @notice Event emitted when a borrow is liquidated - */ - event LiquidateBorrow( - address indexed liquidator, - address indexed borrower, - uint256 repayAmount, - address indexed cTokenCollateral, - uint256 seizeTokens - ); - - /*** Admin Events ***/ - - /** - * @notice Event emitted when pendingAdmin is changed - */ - event NewPendingAdmin(address oldPendingAdmin, address newPendingAdmin); - - /** - * @notice Event emitted when pendingAdmin is accepted, which means admin is updated - */ - event NewAdmin(address oldAdmin, address newAdmin); - - /** - * @notice Event emitted when comptroller is changed - */ - event NewComptroller( - ComptrollerInterface oldComptroller, - ComptrollerInterface newComptroller - ); - - /** - * @notice Event emitted when interestRateModel is changed - */ - event NewMarketInterestRateModel( - InterestRateModel oldInterestRateModel, - InterestRateModel newInterestRateModel - ); - - /** - * @notice Event emitted when the reserve factor is changed - */ - event NewReserveFactor( - uint256 oldReserveFactorMantissa, - uint256 newReserveFactorMantissa - ); - - /** - * @notice Event emitted when the reserves are added - */ - event ReservesAdded( - address benefactor, - uint256 addAmount, - uint256 newTotalReserves - ); - - event SubsidyAdded( - address benefactor, - uint256 addAmount, - uint256 newSubsidyFund - ); - - /** - * @notice Event emitted when the reserves are reduced - */ - event ReservesReduced( - address admin, - uint256 reduceAmount, - uint256 newTotalReserves - ); - - /** - * @notice EIP20 Transfer event - */ - event Transfer(address indexed from, address indexed to, uint256 amount); - - /** - * @notice EIP20 Approval event - */ - event Approval( - address indexed owner, - address indexed spender, - uint256 amount - ); - - /** - * @notice Failure event - */ - event CTokenStorageFailure(uint256 error, uint256 info, uint256 detail); - - /*** User Interface ***/ - - function transfer(address dst, uint256 amount) - external - virtual - returns (bool); - - function transferFrom( - address src, - address dst, - uint256 amount - ) external virtual returns (bool); - - function approve(address spender, uint256 amount) - external - virtual - returns (bool); - - function allowance(address owner, address spender) - external - view - virtual - returns (uint256); - - function balanceOf(address owner) external view virtual returns (uint256); - - function balanceOfUnderlying(address owner) - external - virtual - returns (uint256); - - function getAccountSnapshot(address account) - external - view - virtual - returns ( - uint256, - uint256, - uint256, - uint256 - ); - - function borrowRatePerBlock() external view virtual returns (uint256); - - function supplyRatePerBlock() external view virtual returns (uint256); - - function totalBorrowsCurrent() external virtual returns (uint256); - - function borrowBalanceCurrent(address account) - external - virtual - returns (uint256); - - function borrowBalanceStored(address account) - public - view - virtual - returns (uint256); - - function exchangeRateCurrent() public virtual returns (uint256); - - function exchangeRateStored() public view virtual returns (uint256); - - function getCash() external view virtual returns (uint256); - - function accrueInterest() public virtual returns (uint256); - - function seize( - address liquidator, - address borrower, - uint256 seizeTokens - ) external virtual returns (uint256); - - /*** Admin Functions ***/ - - function _setPendingAdmin(address payable newPendingAdmin) - external - virtual - returns (uint256); - - function _acceptAdmin() external virtual returns (uint256); - - function _setComptroller(ComptrollerInterface newComptroller) - public - virtual - returns (uint256); - - function _setReserveFactor(uint256 newReserveFactorMantissa) - external - virtual - returns (uint256); - - function _reduceReserves(uint256 reduceAmount) - external - virtual - returns (uint256); - - function _setInterestRateModel(InterestRateModel newInterestRateModel) - public - virtual - returns (uint256); -} - -contract CErc20Storage { - /** - * @notice Underlying asset for this CToken - */ - address public underlying; -} - -abstract contract CErc20Interface is CErc20Storage { - /*** User Interface ***/ - - function mint(uint256 mintAmount) external virtual returns (uint256); - - function redeem(uint256 redeemAmount) - external - virtual - returns (uint256); - - function borrow(uint256 borrowAmount) external virtual returns (uint256); - - function repayBorrow(uint256 repayAmount) - external - virtual - returns (uint256); - - function liquidateBorrow( - address borrower, - uint256 repayAmount, - CTokenInterface cTokenCollateral - ) external virtual returns (uint256); - - function sweepToken(EIP20NonStandardInterface token) external virtual; - - /*** Admin Functions ***/ - - function _addReserves(uint256 addAmount) external virtual returns (uint256); -} - -contract CDelegationStorage { - /** - * @notice Implementation address for this contract - */ - address public implementation; -} - -abstract contract CDelegatorInterface is CDelegationStorage { - /** - * @notice Emitted when implementation is changed - */ - event NewImplementation( - address oldImplementation, - address newImplementation - ); - - /** - * @notice Called by the admin to update the implementation of the delegator - * @param implementation_ The address of the new implementation for delegation - * @param allowResign Flag to indicate whether to call _resignImplementation on the old implementation - * @param becomeImplementationData The encoded bytes data to be passed to _becomeImplementation - */ - function _setImplementation( - address implementation_, - bool allowResign, - bytes memory becomeImplementationData - ) public virtual; -} - -abstract contract CDelegateInterface is CDelegationStorage { - /** - * @notice Called by the delegator on a delegate to initialize it for duty - * @dev Should revert if any issues arise which make it unfit for delegation - * @param data The encoded bytes data for any initialization - */ - function _becomeImplementation(bytes memory data) public virtual; - - /** - * @notice Called by the delegator on a delegate to forfeit its responsibility - */ - function _resignImplementation() public virtual; -} - - -// Dependency file: contracts/ErrorReporter.sol - -// pragma solidity 0.8.6; - -contract ComptrollerErrorReporter { - enum Error { - NO_ERROR, - UNAUTHORIZED, - COMPTROLLER_MISMATCH, - INSUFFICIENT_SHORTFALL, - INSUFFICIENT_LIQUIDITY, - INVALID_CLOSE_FACTOR, - INVALID_COLLATERAL_FACTOR, - INVALID_LIQUIDATION_INCENTIVE, - MARKET_NOT_ENTERED, // no longer possible - MARKET_NOT_LISTED, - MARKET_ALREADY_LISTED, - MATH_ERROR, - NONZERO_BORROW_BALANCE, - PRICE_ERROR, - REJECTION, - SNAPSHOT_ERROR, - TOO_MANY_ASSETS, - TOO_MUCH_REPAY - } - - enum FailureInfo { - ACCEPT_ADMIN_PENDING_ADMIN_CHECK, - ACCEPT_PENDING_IMPLEMENTATION_ADDRESS_CHECK, - EXIT_MARKET_BALANCE_OWED, - EXIT_MARKET_REJECTION, - SET_CLOSE_FACTOR_OWNER_CHECK, - SET_CLOSE_FACTOR_VALIDATION, - SET_COLLATERAL_FACTOR_OWNER_CHECK, - SET_COLLATERAL_FACTOR_NO_EXISTS, - SET_COLLATERAL_FACTOR_VALIDATION, - SET_COLLATERAL_FACTOR_WITHOUT_PRICE, - SET_IMPLEMENTATION_OWNER_CHECK, - SET_LIQUIDATION_INCENTIVE_OWNER_CHECK, - SET_LIQUIDATION_INCENTIVE_VALIDATION, - SET_MAX_ASSETS_OWNER_CHECK, - SET_PENDING_ADMIN_OWNER_CHECK, - SET_PENDING_IMPLEMENTATION_OWNER_CHECK, - SET_PRICE_ORACLE_OWNER_CHECK, - SUPPORT_MARKET_EXISTS, - SUPPORT_MARKET_OWNER_CHECK, - SET_PAUSE_GUARDIAN_OWNER_CHECK - } - - /** - * @dev `error` corresponds to enum Error; `info` corresponds to enum FailureInfo, and `detail` is an arbitrary - * contract-specific code that enables us to report opaque error codes from upgradeable contracts. - **/ - event Failure(uint256 error, uint256 info, uint256 detail); - - /** - * @dev use this when reporting a known error from the money market or a non-upgradeable collaborator - */ - function fail(Error err, FailureInfo info) internal returns (uint256) { - emit Failure(uint256(err), uint256(info), 0); - - return uint256(err); - } - - /** - * @dev use this when reporting an opaque error from an upgradeable collaborator contract - */ - function failOpaque( - Error err, - FailureInfo info, - uint256 opaqueError - ) internal returns (uint256) { - emit Failure(uint256(err), uint256(info), opaqueError); - - return uint256(err); - } -} - -contract TokenErrorReporter { - enum Error { - NO_ERROR, - UNAUTHORIZED, - BAD_INPUT, - COMPTROLLER_REJECTION, - COMPTROLLER_CALCULATION_ERROR, - INTEREST_RATE_MODEL_ERROR, - INVALID_ACCOUNT_PAIR, - INVALID_CLOSE_AMOUNT_REQUESTED, - INVALID_COLLATERAL_FACTOR, - MATH_ERROR, - MARKET_NOT_FRESH, - MARKET_NOT_LISTED, - TOKEN_INSUFFICIENT_ALLOWANCE, - TOKEN_INSUFFICIENT_BALANCE, - TOKEN_INSUFFICIENT_CASH, - TOKEN_TRANSFER_IN_FAILED, - TOKEN_TRANSFER_OUT_FAILED - } - - /* - * Note: FailureInfo (but not Error) is kept in alphabetical order - * This is because FailureInfo grows significantly faster, and - * the order of Error has some meaning, while the order of FailureInfo - * is entirely arbitrary. - */ - enum FailureInfo { - ACCEPT_ADMIN_PENDING_ADMIN_CHECK, - ACCRUE_INTEREST_ACCUMULATED_INTEREST_CALCULATION_FAILED, - ACCRUE_INTEREST_BORROW_RATE_CALCULATION_FAILED, - ACCRUE_INTEREST_NEW_BORROW_INDEX_CALCULATION_FAILED, - ACCRUE_INTEREST_NEW_TOTAL_BORROWS_CALCULATION_FAILED, - ACCRUE_INTEREST_NEW_TOTAL_RESERVES_CALCULATION_FAILED, - ACCRUE_INTEREST_SIMPLE_INTEREST_FACTOR_CALCULATION_FAILED, - BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED, - BORROW_ACCRUE_INTEREST_FAILED, - BORROW_CASH_NOT_AVAILABLE, - BORROW_FRESHNESS_CHECK, - BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED, - BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED, - BORROW_MARKET_NOT_LISTED, - BORROW_COMPTROLLER_REJECTION, - LIQUIDATE_ACCRUE_BORROW_INTEREST_FAILED, - LIQUIDATE_ACCRUE_COLLATERAL_INTEREST_FAILED, - LIQUIDATE_COLLATERAL_FRESHNESS_CHECK, - LIQUIDATE_COMPTROLLER_REJECTION, - LIQUIDATE_COMPTROLLER_CALCULATE_AMOUNT_SEIZE_FAILED, - LIQUIDATE_CLOSE_AMOUNT_IS_UINT_MAX, - LIQUIDATE_CLOSE_AMOUNT_IS_ZERO, - LIQUIDATE_FRESHNESS_CHECK, - LIQUIDATE_LIQUIDATOR_IS_BORROWER, - LIQUIDATE_REPAY_BORROW_FRESH_FAILED, - LIQUIDATE_SEIZE_BALANCE_INCREMENT_FAILED, - LIQUIDATE_SEIZE_BALANCE_DECREMENT_FAILED, - LIQUIDATE_SEIZE_COMPTROLLER_REJECTION, - LIQUIDATE_SEIZE_LIQUIDATOR_IS_BORROWER, - LIQUIDATE_SEIZE_TOO_MUCH, - MINT_ACCRUE_INTEREST_FAILED, - MINT_COMPTROLLER_REJECTION, - MINT_EXCHANGE_CALCULATION_FAILED, - MINT_EXCHANGE_RATE_READ_FAILED, - MINT_FRESHNESS_CHECK, - MINT_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED, - MINT_NEW_TOTAL_SUPPLY_CALCULATION_FAILED, - MINT_TRANSFER_IN_FAILED, - MINT_TRANSFER_IN_NOT_POSSIBLE, - REDEEM_ACCRUE_INTEREST_FAILED, - REDEEM_COMPTROLLER_REJECTION, - REDEEM_EXCHANGE_TOKENS_CALCULATION_FAILED, - REDEEM_EXCHANGE_AMOUNT_CALCULATION_FAILED, - REDEEM_EXCHANGE_RATE_READ_FAILED, - REDEEM_FRESHNESS_CHECK, - REDEEM_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED, - REDEEM_NEW_TOTAL_SUPPLY_CALCULATION_FAILED, - REDEEM_TRANSFER_OUT_NOT_POSSIBLE, - REDUCE_RESERVES_ACCRUE_INTEREST_FAILED, - REDUCE_RESERVES_ADMIN_CHECK, - REDUCE_RESERVES_CASH_NOT_AVAILABLE, - REDUCE_RESERVES_FRESH_CHECK, - REDUCE_RESERVES_VALIDATION, - REPAY_BEHALF_ACCRUE_INTEREST_FAILED, - REPAY_BORROW_ACCRUE_INTEREST_FAILED, - REPAY_BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED, - REPAY_BORROW_COMPTROLLER_REJECTION, - REPAY_BORROW_FRESHNESS_CHECK, - REPAY_BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED, - REPAY_BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED, - REPAY_BORROW_TRANSFER_IN_NOT_POSSIBLE, - SET_COLLATERAL_FACTOR_OWNER_CHECK, - SET_COLLATERAL_FACTOR_VALIDATION, - SET_COMPTROLLER_OWNER_CHECK, - SET_INTEREST_RATE_MODEL_ACCRUE_INTEREST_FAILED, - SET_INTEREST_RATE_MODEL_FRESH_CHECK, - SET_INTEREST_RATE_MODEL_OWNER_CHECK, - SET_MAX_ASSETS_OWNER_CHECK, - SET_ORACLE_MARKET_NOT_LISTED, - SET_PENDING_ADMIN_OWNER_CHECK, - SET_RESERVE_FACTOR_ACCRUE_INTEREST_FAILED, - SET_RESERVE_FACTOR_ADMIN_CHECK, - SET_RESERVE_FACTOR_FRESH_CHECK, - SET_RESERVE_FACTOR_BOUNDS_CHECK, - TRANSFER_COMPTROLLER_REJECTION, - TRANSFER_NOT_ALLOWED, - TRANSFER_NOT_ENOUGH, - TRANSFER_TOO_MUCH, - ADD_RESERVES_ACCRUE_INTEREST_FAILED, - ADD_RESERVES_FRESH_CHECK, - ADD_RESERVES_TRANSFER_IN_NOT_POSSIBLE, - ADD_SUBSIDY_FUND_FAILED, - ADD_SUBSIDY_FUND_FRESH_CHECK - } - - /** - * @dev `error` corresponds to enum Error; `info` corresponds to enum FailureInfo, and `detail` is an arbitrary - * contract-specific code that enables us to report opaque error codes from upgradeable contracts. - **/ - event TokenFailure(uint256 error, uint256 info, uint256 detail); - - /** - * @dev use this when reporting a known error from the money market or a non-upgradeable collaborator - */ - function fail(Error err, FailureInfo info) internal returns (uint256) { - emit TokenFailure(uint256(err), uint256(info), 0); - - return uint256(err); - } - - /** - * @dev use this when reporting an opaque error from an upgradeable collaborator contract - */ - function failOpaque( - Error err, - FailureInfo info, - uint256 opaqueError - ) internal returns (uint256) { - emit TokenFailure(uint256(err), uint256(info), opaqueError); - - return uint256(err); - } -} - - -// Dependency file: contracts/EIP20Interface.sol - -// pragma solidity 0.8.6; - -/** - * @title ERC 20 Token Standard Interface - * https://eips.ethereum.org/EIPS/eip-20 - */ -interface EIP20Interface { - function name() external view returns (string memory); - - function symbol() external view returns (string memory); - - function decimals() external view returns (uint8); - - /** - * @notice Get the total number of tokens in circulation - * @return The supply of tokens - */ - function totalSupply() external view returns (uint256); - - /** - * @notice Gets the balance of the specified address - * @param owner The address from which the balance will be retrieved - * @return balance The balance - */ - function balanceOf(address owner) external view returns (uint256 balance); - - /** - * @notice Transfer `amount` tokens from `msg.sender` to `dst` - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - * @return success Whether or not the transfer succeeded - */ - function transfer(address dst, uint256 amount) - external - returns (bool success); - - /** - * @notice Transfer `amount` tokens from `src` to `dst` - * @param src The address of the source account - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - * @return success Whether or not the transfer succeeded - */ - function transferFrom( - address src, - address dst, - uint256 amount - ) external returns (bool success); - - /** - * @notice Approve `spender` to transfer up to `amount` from `src` - * @dev This will overwrite the approval amount for `spender` - * and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve) - * @param spender The address of the account which may transfer tokens - * @param amount The number of tokens that are approved (-1 means infinite) - * @return success Whether or not the approval succeeded - */ - function approve(address spender, uint256 amount) - external - returns (bool success); - - /** - * @notice Get the current allowance from `owner` for `spender` - * @param owner The address of the account which owns the tokens to be spent - * @param spender The address of the account which may transfer tokens - * @return remaining The number of tokens allowed to be spent (-1 means infinite) - */ - function allowance(address owner, address spender) - external - view - returns (uint256 remaining); - - event Transfer(address indexed from, address indexed to, uint256 amount); - event Approval( - address indexed owner, - address indexed spender, - uint256 amount - ); -} - - -// Dependency file: contracts/WhitelistInterface.sol - -// pragma solidity 0.8.6; - -interface WhitelistInterface { - function setStatus(bool _newStatus) external; - function enabled() external view returns(bool); - - function addUsers(address[] memory _users) external; - function exist(address _user) external view returns(bool); - function getUsers() external view returns(address[] memory currentUsers); - function removeUser(address _user) external; -} - -// Root file: contracts/CToken.sol - -pragma solidity 0.8.6; - -// import "contracts/ComptrollerInterface.sol"; -// import "contracts/CTokenInterfaces.sol"; -// import "contracts/ErrorReporter.sol"; -// import "contracts/Exponential.sol"; -// import "contracts/EIP20Interface.sol"; -// import "contracts/InterestRateModel.sol"; -// import "contracts/WhitelistInterface.sol"; - -/** - * @title tropykus CToken Contract - * @notice Abstract base for CTokens - * @author tropykus - */ -abstract contract CToken is CTokenInterface, Exponential, TokenErrorReporter { - address whitelist; - - /** - * @notice Initialize the money market - * @param comptroller_ The address of the Comptroller - * @param interestRateModel_ The address of the interest rate model - * @param initialExchangeRateMantissa_ The initial exchange rate, scaled by 1e18 - * @param name_ EIP-20 name of this token - * @param symbol_ EIP-20 symbol of this token - * @param decimals_ EIP-20 decimal precision of this token - */ - function initialize( - ComptrollerInterface comptroller_, - InterestRateModel interestRateModel_, - uint256 initialExchangeRateMantissa_, - string memory name_, - string memory symbol_, - uint8 decimals_ - ) public { - require(msg.sender == admin, "CT01"); - require(accrualBlockNumber == 0 && borrowIndex == 0, "CT02"); - - initialExchangeRateMantissa = initialExchangeRateMantissa_; - require(initialExchangeRateMantissa > 0, "CT03"); - - uint256 err = _setComptroller(comptroller_); - require(err == uint256(Error.NO_ERROR), "CT04"); - - accrualBlockNumber = getBlockNumber(); - borrowIndex = mantissaOne; - - err = _setInterestRateModelFresh(interestRateModel_); - require(err == uint256(Error.NO_ERROR), "CT05"); - - name = name_; - symbol = symbol_; - decimals = decimals_; - - _notEntered = true; - } - - function addWhitelist(address _whitelist) external returns (uint256) { - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_INTEREST_RATE_MODEL_OWNER_CHECK - ); - } - whitelist = _whitelist; - } - - /** - * @notice Transfer `tokens` tokens from `src` to `dst` by `spender` - * @dev Called by both `transfer` and `transferFrom` internally - * @param spender The address of the account performing the transfer - * @param src The address of the source account - * @param dst The address of the destination account - * @param tokens The number of tokens to transfer - * @return Whether or not the transfer succeeded - */ - function transferTokens( - address spender, - address src, - address dst, - uint256 tokens - ) internal returns (uint256) { - uint256 allowed = comptroller.transferAllowed( - address(this), - src, - dst, - tokens - ); - if (allowed != 0) { - return - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.TRANSFER_COMPTROLLER_REJECTION, - allowed - ); - } - - if (src == dst) { - return fail(Error.BAD_INPUT, FailureInfo.TRANSFER_NOT_ALLOWED); - } - - uint256 startingAllowance = 0; - if (spender == src) { - startingAllowance = type(uint256).max; - } else { - startingAllowance = transferAllowances[src][spender]; - } - - MathError mathErr; - uint256 allowanceNew; - uint256 srcTokensNew; - uint256 dstTokensNew; - - (mathErr, allowanceNew) = subUInt(startingAllowance, tokens); - if (mathErr != MathError.NO_ERROR) { - return fail(Error.MATH_ERROR, FailureInfo.TRANSFER_NOT_ALLOWED); - } - - (mathErr, srcTokensNew) = subUInt(accountTokens[src].tokens, tokens); - if (mathErr != MathError.NO_ERROR) { - return fail(Error.MATH_ERROR, FailureInfo.TRANSFER_NOT_ENOUGH); - } - - (mathErr, dstTokensNew) = addUInt(accountTokens[dst].tokens, tokens); - if (mathErr != MathError.NO_ERROR) { - return fail(Error.MATH_ERROR, FailureInfo.TRANSFER_TOO_MUCH); - } - - accountTokens[src].tokens = srcTokensNew; - accountTokens[dst].tokens = dstTokensNew; - - if (startingAllowance != type(uint256).max) { - transferAllowances[src][spender] = allowanceNew; - } - - emit Transfer(src, dst, tokens); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Transfer `amount` tokens from `msg.sender` to `dst` - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - * @return Whether or not the transfer succeeded - */ - function transfer(address dst, uint256 amount) - external - override - nonReentrant - returns (bool) - { - return - transferTokens(msg.sender, msg.sender, dst, amount) == - uint256(Error.NO_ERROR); - } - - /** - * @notice Transfer `amount` tokens from `src` to `dst` - * @param src The address of the source account - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - * @return Whether or not the transfer succeeded - */ - function transferFrom( - address src, - address dst, - uint256 amount - ) external override nonReentrant returns (bool) { - return - transferTokens(msg.sender, src, dst, amount) == - uint256(Error.NO_ERROR); - } - - /** - * @notice Approve `spender` to transfer up to `amount` from `src` - * @dev This will overwrite the approval amount for `spender` - * and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve) - * @param spender The address of the account which may transfer tokens - * @param amount The number of tokens that are approved (-1 means infinite) - * @return Whether or not the approval succeeded - */ - function approve(address spender, uint256 amount) - external - override - returns (bool) - { - transferAllowances[msg.sender][spender] = amount; - emit Approval(msg.sender, spender, amount); - return true; - } - - /** - * @notice Get the current allowance from `owner` for `spender` - * @param owner The address of the account which owns the tokens to be spent - * @param spender The address of the account which may transfer tokens - * @return The number of tokens allowed to be spent (-1 means infinite) - */ - function allowance(address owner, address spender) - external - view - override - returns (uint256) - { - return transferAllowances[owner][spender]; - } - - /** - * @notice Get the token balance of the `owner` - * @param owner The address of the account to query - * @return The number of tokens owned by `owner` - */ - function balanceOf(address owner) external view override returns (uint256) { - return accountTokens[owner].tokens; - } - - /** - * @notice Get the underlying balance of the `owner` - * @dev This also accrues interest in a transaction - * @param owner The address of the account to query - * @return The amount of underlying owned by `owner` - */ - function balanceOfUnderlying(address owner) - external - override - returns (uint256) - { - (MathError mErr, uint256 balance) = mulScalarTruncate( - Exp({mantissa: exchangeRateCurrent()}), - accountTokens[owner].tokens - ); - require(mErr == MathError.NO_ERROR, "CT06"); - return balance; - } - - /** - * @notice Get a snapshot of the account's balances, and the cached exchange rate - * @dev This is used by comptroller to more efficiently perform liquidity checks. - * @param account Address of the account to snapshot - * @return (possible error, token balance, borrow balance, exchange rate mantissa) - */ - function getAccountSnapshot(address account) - external - view - override - returns ( - uint256, - uint256, - uint256, - uint256 - ) - { - uint256 cTokenBalance = accountTokens[account].tokens; - uint256 borrowBalance; - uint256 exchangeRateMantissa; - - MathError mErr; - - (mErr, borrowBalance) = borrowBalanceStoredInternal(account); - if (mErr != MathError.NO_ERROR) { - return (uint256(Error.MATH_ERROR), 0, 0, 0); - } - - (mErr, exchangeRateMantissa) = exchangeRateStoredInternal(); - if (mErr != MathError.NO_ERROR) { - return (uint256(Error.MATH_ERROR), 0, 0, 0); - } - - return ( - uint256(Error.NO_ERROR), - cTokenBalance, - borrowBalance, - exchangeRateMantissa - ); - } - - /** - * @dev Function to simply retrieve block number - * This exists mainly for inheriting test contracts to stub this result. - */ - function getBlockNumber() internal view virtual returns (uint256) { - return block.number; - } - - /** - * @notice Returns the current per-block borrow interest rate for this cToken - * @return The borrow interest rate per block, scaled by 1e18 - */ - function borrowRatePerBlock() external view override returns (uint256) { - return - interestRateModel.getBorrowRate( - getCashPrior(), - totalBorrows, - totalReserves - ); - } - - /** - * @notice Returns the current per-block supply interest rate for this cToken - * @return The supply interest rate per block, scaled by 1e18 - */ - function supplyRatePerBlock() external view override returns (uint256) { - return - interestRateModel.getSupplyRate( - getCashPrior(), - totalBorrows, - totalReserves, - reserveFactorMantissa - ); - } - - /** - * @notice Returns the current total borrows plus accrued interest - * @return The total borrows with interest - */ - function totalBorrowsCurrent() - external - override - nonReentrant - returns (uint256) - { - require(accrueInterest() == uint256(Error.NO_ERROR), "CT07"); - return totalBorrows; - } - - /** - * @notice Accrue interest to updated borrowIndex and then calculate account's borrow balance using the updated borrowIndex - * @param account The address whose balance should be calculated after updating borrowIndex - * @return The calculated balance - */ - function borrowBalanceCurrent(address account) - external - override - nonReentrant - returns (uint256) - { - require(accrueInterest() == uint256(Error.NO_ERROR), "CT07"); - return borrowBalanceStored(account); - } - - /** - * @notice Return the borrow balance of account based on stored data - * @param account The address whose balance should be calculated - * @return The calculated balance - */ - function borrowBalanceStored(address account) - public - view - override - returns (uint256) - { - (MathError err, uint256 result) = borrowBalanceStoredInternal(account); - require(err == MathError.NO_ERROR, "CT08"); - return result; - } - - /** - * @notice Return the borrow balance of account based on stored data - * @param account The address whose balance should be calculated - * @return (error code, the calculated balance or 0 if error code is non-zero) - */ - function borrowBalanceStoredInternal(address account) - internal - view - returns (MathError, uint256) - { - MathError mathErr; - uint256 principalTimesIndex; - uint256 result; - - BorrowSnapshot storage borrowSnapshot = accountBorrows[account]; - - if (borrowSnapshot.principal == 0) { - return (MathError.NO_ERROR, 0); - } - - (mathErr, principalTimesIndex) = mulUInt( - borrowSnapshot.principal, - borrowIndex - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - - (mathErr, result) = divUInt( - principalTimesIndex, - borrowSnapshot.interestIndex - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - - return (MathError.NO_ERROR, result); - } - - function getBorrowerPrincipalStored(address account) - public - view - returns (uint256 borrowed) - { - borrowed = accountBorrows[account].principal; - } - - function getSupplierSnapshotStored(address account) - public - view - returns ( - uint256 tokens, - uint256 underlyingAmount, - uint256 suppliedAt, - uint256 promisedSupplyRate - ) - { - tokens = accountTokens[account].tokens; - underlyingAmount = accountTokens[account].underlyingAmount; - suppliedAt = accountTokens[account].suppliedAt; - promisedSupplyRate = accountTokens[account].promisedSupplyRate; - } - - /** - * @notice Accrue interest then return the up-to-date exchange rate - * @return Calculated exchange rate scaled by 1e18 - */ - function exchangeRateCurrent() - public - override - nonReentrant - returns (uint256) - { - require(accrueInterest() == uint256(Error.NO_ERROR), "CT07"); - return exchangeRateStored(); - } - - /** - * @notice Calculates the exchange rate from the underlying to the CToken - * @dev This function does not accrue interest before calculating the exchange rate - * @return Calculated exchange rate scaled by 1e18 - */ - function exchangeRateStored() public view override returns (uint256) { - (MathError err, uint256 result) = exchangeRateStoredInternal(); - require(err == MathError.NO_ERROR, "CT09"); - return result; - } - - /** - * @notice Calculates the exchange rate from the underlying to the CToken - * @dev This function does not accrue interest before calculating the exchange rate - * @return (error code, calculated exchange rate scaled by 1e18) - */ - function exchangeRateStoredInternal() - internal - view - virtual - returns (MathError, uint256) - { - uint256 _totalSupply = totalSupply; - if (_totalSupply == 0) { - return (MathError.NO_ERROR, initialExchangeRateMantissa); - } else { - MathError error; - uint256 exchangeRate; - uint256 totalCash = getCashPrior(); - if (interestRateModel.isTropykusInterestRateModel()) { - (error, exchangeRate) = tropykusExchangeRateStoredInternal( - msg.sender - ); - if (error == MathError.NO_ERROR) { - return (MathError.NO_ERROR, exchangeRate); - } else { - return (MathError.NO_ERROR, initialExchangeRateMantissa); - } - } - return - interestRateModel.getExchangeRate( - totalCash, - totalBorrows, - totalReserves, - totalSupply - ); - } - } - - function tropykusExchangeRateStoredInternal(address redeemer) - internal - view - returns (MathError, uint256) - { - if (totalSupply == 0) { - return (MathError.NO_ERROR, initialExchangeRateMantissa); - } else { - SupplySnapshot storage supplySnapshot = accountTokens[redeemer]; - if (supplySnapshot.suppliedAt == 0) { - return (MathError.DIVISION_BY_ZERO, 0); - } - (, uint256 interestFactorMantissa, ) = tropykusInterestAccrued( - redeemer - ); - Exp memory interestFactor = Exp({mantissa: interestFactorMantissa}); - uint256 currentUnderlying = supplySnapshot.underlyingAmount; - Exp memory redeemerUnderlying = Exp({mantissa: currentUnderlying}); - (, Exp memory realAmount) = mulExp( - interestFactor, - redeemerUnderlying - ); - (, Exp memory exchangeRate) = getExp( - realAmount.mantissa, - supplySnapshot.tokens - ); - return (MathError.NO_ERROR, exchangeRate.mantissa); - } - } - - function tropykusInterestAccrued(address account) - internal - view - returns ( - MathError, - uint256, - uint256 - ) - { - SupplySnapshot storage supplySnapshot = accountTokens[account]; - uint256 promisedSupplyRate = supplySnapshot.promisedSupplyRate; - Exp memory expectedSupplyRatePerBlock = Exp({ - mantissa: promisedSupplyRate - }); - (, uint256 delta) = subUInt( - accrualBlockNumber, - supplySnapshot.suppliedAt - ); - (, Exp memory expectedSupplyRatePerBlockWithDelta) = mulScalar( - expectedSupplyRatePerBlock, - delta - ); - (, Exp memory interestFactor) = addExp( - Exp({mantissa: 1e18}), - expectedSupplyRatePerBlockWithDelta - ); - uint256 currentUnderlying = supplySnapshot.underlyingAmount; - Exp memory redeemerUnderlying = Exp({mantissa: currentUnderlying}); - (, Exp memory realAmount) = mulExp(interestFactor, redeemerUnderlying); - (, uint256 interestEarned) = subUInt( - realAmount.mantissa, - currentUnderlying - ); - return (MathError.NO_ERROR, interestFactor.mantissa, interestEarned); - } - - /** - * @notice Get cash balance of this cToken in the underlying asset - * @return The quantity of underlying asset owned by this contract - */ - function getCash() external view override returns (uint256) { - return getCashPrior(); - } - - /** - * @notice Applies accrued interest to total borrows and reserves - * @dev This calculates interest accrued from the last checkpointed block - * up to the current block and writes new checkpoint to storage. - */ - function accrueInterest() public override returns (uint256) { - uint256 currentBlockNumber = getBlockNumber(); - uint256 accrualBlockNumberPrior = accrualBlockNumber; - - if (accrualBlockNumberPrior == currentBlockNumber) { - return uint256(Error.NO_ERROR); - } - - uint256 cashPrior = getCashPrior(); - uint256 borrowsPrior = totalBorrows; - uint256 reservesPrior = totalReserves; - uint256 borrowIndexPrior = borrowIndex; - - uint256 borrowRateMantissa = interestRateModel.getBorrowRate( - cashPrior, - borrowsPrior, - reservesPrior - ); - require(borrowRateMantissa <= borrowRateMaxMantissa, "CT10"); - - (MathError mathErr, uint256 blockDelta) = subUInt( - currentBlockNumber, - accrualBlockNumberPrior - ); - require(mathErr == MathError.NO_ERROR, "CT11"); - - Exp memory simpleInterestFactor; - uint256 interestAccumulated; - uint256 totalBorrowsNew; - uint256 totalReservesNew; - uint256 borrowIndexNew; - - (mathErr, simpleInterestFactor) = mulScalar( - Exp({mantissa: borrowRateMantissa}), - blockDelta - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .ACCRUE_INTEREST_SIMPLE_INTEREST_FACTOR_CALCULATION_FAILED, - uint256(mathErr) - ); - } - - (mathErr, interestAccumulated) = mulScalarTruncate( - simpleInterestFactor, - borrowsPrior - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .ACCRUE_INTEREST_ACCUMULATED_INTEREST_CALCULATION_FAILED, - uint256(mathErr) - ); - } - - (mathErr, totalBorrowsNew) = addUInt(interestAccumulated, borrowsPrior); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .ACCRUE_INTEREST_NEW_TOTAL_BORROWS_CALCULATION_FAILED, - uint256(mathErr) - ); - } - - (mathErr, totalReservesNew) = mulScalarTruncateAddUInt( - Exp({mantissa: reserveFactorMantissa}), - interestAccumulated, - reservesPrior - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .ACCRUE_INTEREST_NEW_TOTAL_RESERVES_CALCULATION_FAILED, - uint256(mathErr) - ); - } - - if (interestRateModel.isTropykusInterestRateModel()) { - (mathErr, totalReservesNew) = newReserves( - borrowRateMantissa, - cashPrior, - borrowsPrior, - reservesPrior, - interestAccumulated - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .ACCRUE_INTEREST_NEW_TOTAL_RESERVES_CALCULATION_FAILED, - uint256(mathErr) - ); - } - } - - (mathErr, borrowIndexNew) = mulScalarTruncateAddUInt( - simpleInterestFactor, - borrowIndexPrior, - borrowIndexPrior - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .ACCRUE_INTEREST_NEW_BORROW_INDEX_CALCULATION_FAILED, - uint256(mathErr) - ); - } - - accrualBlockNumber = currentBlockNumber; - borrowIndex = borrowIndexNew; - totalBorrows = totalBorrowsNew; - totalReserves = totalReservesNew; - - emit AccrueInterest( - cashPrior, - interestAccumulated, - borrowIndexNew, - totalBorrowsNew - ); - - return uint256(Error.NO_ERROR); - } - - function newReserves( - uint256 borrowRateMantissa, - uint256 cashPrior, - uint256 borrowsPrior, - uint256 reservesPrior, - uint256 interestAccumulated - ) internal view returns (MathError mathErr, uint256 totalReservesNew) { - uint256 newReserveFactorMantissa; - uint256 utilizationRate = interestRateModel.utilizationRate( - cashPrior, - borrowsPrior, - reservesPrior - ); - uint256 expectedSupplyRate = interestRateModel.getSupplyRate( - cashPrior, - borrowsPrior, - reservesPrior, - reserveFactorMantissa - ); - if ( - interestRateModel.isAboveOptimal( - cashPrior, - borrowsPrior, - reservesPrior - ) - ) { - (mathErr, newReserveFactorMantissa) = mulScalarTruncate( - Exp({mantissa: utilizationRate}), - borrowRateMantissa - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - (mathErr, newReserveFactorMantissa) = subUInt( - newReserveFactorMantissa, - expectedSupplyRate - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - (mathErr, totalReservesNew) = mulScalarTruncateAddUInt( - Exp({mantissa: newReserveFactorMantissa}), - interestAccumulated, - reservesPrior - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - } else { - mathErr = MathError.NO_ERROR; - totalReservesNew = reservesPrior; - } - } - - /** - * @notice Sender supplies assets into the market and receives cTokens in exchange - * @dev Accrues interest whether or not the operation succeeds, unless reverted - * @param mintAmount The amount of the underlying asset to supply - * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual mint amount. - */ - function mintInternal(uint256 mintAmount) - internal - nonReentrant - returns (uint256, uint256) - { - if (WhitelistInterface(whitelist).enabled()) { - require(WhitelistInterface(whitelist).exist(msg.sender), "CT26"); - } - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return ( - fail(Error(error), FailureInfo.MINT_ACCRUE_INTEREST_FAILED), - 0 - ); - } - return mintFresh(msg.sender, mintAmount); - } - - struct MintLocalVars { - Error err; - MathError mathErr; - uint256 exchangeRateMantissa; - uint256 mintTokens; - uint256 totalSupplyNew; - uint256 accountTokensNew; - uint256 actualMintAmount; - } - - /** - * @notice User supplies assets into the market and receives cTokens in exchange - * @dev Assumes interest has already been accrued up to the current block - * @param minter The address of the account which is supplying the assets - * @param mintAmount The amount of the underlying asset to supply - * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual mint amount. - */ - function mintFresh(address minter, uint256 mintAmount) - internal - returns (uint256, uint256) - { - uint256 allowed = comptroller.mintAllowed( - address(this), - minter, - mintAmount - ); - if (allowed != 0) { - return ( - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.MINT_COMPTROLLER_REJECTION, - allowed - ), - 0 - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return ( - fail(Error.MARKET_NOT_FRESH, FailureInfo.MINT_FRESHNESS_CHECK), - 0 - ); - } - - MintLocalVars memory vars; - - ( - vars.mathErr, - vars.exchangeRateMantissa - ) = exchangeRateStoredInternal(); - if (vars.mathErr != MathError.NO_ERROR) { - return ( - failOpaque( - Error.MATH_ERROR, - FailureInfo.MINT_EXCHANGE_RATE_READ_FAILED, - uint256(vars.mathErr) - ), - 0 - ); - } - if (interestRateModel.isTropykusInterestRateModel()) { - SupplySnapshot storage supplySnapshot = accountTokens[minter]; - (, uint256 newTotalSupply) = addUInt( - supplySnapshot.underlyingAmount, - mintAmount - ); - require(newTotalSupply <= 0.1e18, "CT24"); - } - vars.actualMintAmount = doTransferIn(minter, mintAmount); - - (vars.mathErr, vars.mintTokens) = divScalarByExpTruncate( - vars.actualMintAmount, - Exp({mantissa: vars.exchangeRateMantissa}) - ); - require(vars.mathErr == MathError.NO_ERROR, "CT12"); - - (vars.mathErr, vars.totalSupplyNew) = addUInt( - totalSupply, - vars.mintTokens - ); - require(vars.mathErr == MathError.NO_ERROR, "CT13"); - - (vars.mathErr, vars.accountTokensNew) = addUInt( - accountTokens[minter].tokens, - vars.mintTokens - ); - require(vars.mathErr == MathError.NO_ERROR, "CT14"); - - uint256 currentSupplyRate = interestRateModel.getSupplyRate( - getCashPrior(), - totalBorrows, - totalReserves, - reserveFactorMantissa - ); - - bool isTropykusInterestRateModel = interestRateModel - .isTropykusInterestRateModel(); - - if (accountTokens[minter].tokens > 0) { - Exp memory updatedUnderlying; - if (isTropykusInterestRateModel) { - (, uint256 interestFactorMantissa, ) = tropykusInterestAccrued( - minter - ); - Exp memory interestFactor = Exp({ - mantissa: interestFactorMantissa - }); - uint256 currentUnderlyingAmount = accountTokens[minter] - .underlyingAmount; - MathError mErrorNewAmount; - (mErrorNewAmount, updatedUnderlying) = mulExp( - Exp({mantissa: currentUnderlyingAmount}), - interestFactor - ); - if (mErrorNewAmount != MathError.NO_ERROR) { - return ( - failOpaque( - Error.MATH_ERROR, - FailureInfo.MINT_EXCHANGE_CALCULATION_FAILED, - uint256(mErrorNewAmount) - ), - 0 - ); - } - } else { - uint256 currentTokens = accountTokens[minter].tokens; - MathError mErrorUpdatedUnderlying; - (mErrorUpdatedUnderlying, updatedUnderlying) = mulExp( - Exp({mantissa: currentTokens}), - Exp({mantissa: vars.exchangeRateMantissa}) - ); - if (mErrorUpdatedUnderlying != MathError.NO_ERROR) { - return ( - failOpaque( - Error.MATH_ERROR, - FailureInfo.MINT_EXCHANGE_CALCULATION_FAILED, - uint256(mErrorUpdatedUnderlying) - ), - 0 - ); - } - } - (, mintAmount) = addUInt(updatedUnderlying.mantissa, mintAmount); - } - - totalSupply = vars.totalSupplyNew; - accountTokens[minter] = SupplySnapshot({ - tokens: vars.accountTokensNew, - underlyingAmount: mintAmount, - suppliedAt: accrualBlockNumber, - promisedSupplyRate: currentSupplyRate - }); - - emit Mint(minter, vars.actualMintAmount, vars.mintTokens); - emit Transfer(address(this), minter, vars.mintTokens); - - return (uint256(Error.NO_ERROR), vars.actualMintAmount); - } - - /** - * @notice Sender redeems cTokens in exchange for a specified amount of underlying asset - * @dev Accrues interest whether or not the operation succeeds, unless reverted - * @param redeemAmount The amount of underlying to receive from redeeming cTokens - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function redeemUnderlyingInternal(uint256 redeemAmount) - internal - nonReentrant - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return - fail(Error(error), FailureInfo.REDEEM_ACCRUE_INTEREST_FAILED); - } - return redeemFresh(payable(msg.sender), redeemAmount); - } - - struct RedeemLocalVars { - Error err; - MathError mathErr; - uint256 exchangeRateMantissa; - uint256 redeemTokens; - uint256 redeemAmount; - uint256 totalSupplyNew; - uint256 accountTokensNew; - uint256 newSubsidyFund; - } - - /** - * @notice User redeems cTokens in exchange for the underlying asset - * @dev Assumes interest has already been accrued up to the current block - * @param redeemer The address of the account which is redeeming the tokens - * @param redeemAmountIn The number of underlying tokens to receive from redeeming cTokens - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function redeemFresh(address payable redeemer, uint256 redeemAmountIn) - internal - returns (uint256) - { - require(redeemAmountIn > 0, "CT15"); - - RedeemLocalVars memory vars; - - SupplySnapshot storage supplySnapshot = accountTokens[redeemer]; - - ( - vars.mathErr, - vars.exchangeRateMantissa - ) = exchangeRateStoredInternal(); - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.REDEEM_EXCHANGE_RATE_READ_FAILED, - uint256(vars.mathErr) - ); - } - - uint256 interestEarned; - uint256 subsidyFundPortion; - uint256 currentUnderlying; - - bool isTropykusInterestRateModel = interestRateModel - .isTropykusInterestRateModel(); - if (isTropykusInterestRateModel) { - currentUnderlying = supplySnapshot.underlyingAmount; - (, , interestEarned) = tropykusInterestAccrued(redeemer); - } - supplySnapshot.promisedSupplyRate = interestRateModel.getSupplyRate( - getCashPrior(), - totalBorrows, - totalReserves, - reserveFactorMantissa - ); - - if ( - isTropykusInterestRateModel && - !interestRateModel.isAboveOptimal( - getCashPrior(), - totalBorrows, - totalReserves - ) - ) { - uint256 borrowRate = interestRateModel.getBorrowRate( - getCashPrior(), - totalBorrows, - totalReserves - ); - - uint256 utilizationRate = interestRateModel.utilizationRate( - getCashPrior(), - totalBorrows, - totalReserves - ); - - (, uint256 estimatedEarning) = mulScalarTruncate( - Exp({mantissa: borrowRate}), - utilizationRate - ); - - (, subsidyFundPortion) = subUInt( - supplySnapshot.promisedSupplyRate, - estimatedEarning - ); - (, Exp memory subsidyFactor) = getExp( - subsidyFundPortion, - supplySnapshot.promisedSupplyRate - ); - (, subsidyFundPortion) = mulScalarTruncate( - subsidyFactor, - interestEarned - ); - } - - vars.redeemAmount = redeemAmountIn; - - if (isTropykusInterestRateModel) { - (, Exp memory num) = mulExp( - vars.redeemAmount, - supplySnapshot.tokens - ); - (, Exp memory realTokensWithdrawAmount) = getExp( - num.mantissa, - currentUnderlying - ); - vars.redeemTokens = realTokensWithdrawAmount.mantissa; - } else { - (vars.mathErr, vars.redeemTokens) = divScalarByExpTruncate( - redeemAmountIn, - Exp({mantissa: vars.exchangeRateMantissa}) - ); - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.REDEEM_EXCHANGE_AMOUNT_CALCULATION_FAILED, - uint256(vars.mathErr) - ); - } - } - // } - - uint256 allowed = comptroller.redeemAllowed( - address(this), - redeemer, - vars.redeemTokens - ); - if (allowed != 0) { - return - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.REDEEM_COMPTROLLER_REJECTION, - allowed - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.REDEEM_FRESHNESS_CHECK - ); - } - - (vars.mathErr, vars.totalSupplyNew) = subUInt( - totalSupply, - vars.redeemTokens - ); - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.REDEEM_NEW_TOTAL_SUPPLY_CALCULATION_FAILED, - uint256(vars.mathErr) - ); - } - - (, vars.newSubsidyFund) = subUInt(subsidyFund, subsidyFundPortion); - - (vars.mathErr, vars.accountTokensNew) = subUInt( - supplySnapshot.tokens, - vars.redeemTokens - ); - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.REDEEM_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED, - uint256(vars.mathErr) - ); - } - - uint256 cash = getCashPrior(); - if (isTropykusInterestRateModel) { - cash = address(this).balance; - } - - if (cash < vars.redeemAmount) { - return - fail( - Error.TOKEN_INSUFFICIENT_CASH, - FailureInfo.REDEEM_TRANSFER_OUT_NOT_POSSIBLE - ); - } - - doTransferOut(redeemer, vars.redeemAmount); - - totalSupply = vars.totalSupplyNew; - subsidyFund = vars.newSubsidyFund; - supplySnapshot.tokens = vars.accountTokensNew; - supplySnapshot.suppliedAt = accrualBlockNumber; - (, supplySnapshot.underlyingAmount) = subUInt( - supplySnapshot.underlyingAmount, - vars.redeemAmount - ); - - emit Transfer(redeemer, address(this), vars.redeemTokens); - emit Redeem(redeemer, vars.redeemAmount, vars.redeemTokens); - - comptroller.redeemVerify( - address(this), - redeemer, - vars.redeemAmount, - vars.redeemTokens - ); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Sender borrows assets from the protocol to their own address - * @param borrowAmount The amount of the underlying asset to borrow - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function borrowInternal(uint256 borrowAmount) - internal - nonReentrant - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return - fail(Error(error), FailureInfo.BORROW_ACCRUE_INTEREST_FAILED); - } - return borrowFresh(payable(msg.sender), borrowAmount); - } - - struct BorrowLocalVars { - MathError mathErr; - uint256 accountBorrows; - uint256 accountBorrowsNew; - uint256 totalBorrowsNew; - } - - /** - * @notice Users borrow assets from the protocol to their own address - * @param borrowAmount The amount of the underlying asset to borrow - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function borrowFresh(address payable borrower, uint256 borrowAmount) - internal - returns (uint256) - { - uint256 allowed = comptroller.borrowAllowed( - address(this), - borrower, - borrowAmount - ); - if (allowed != 0) { - return - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.BORROW_COMPTROLLER_REJECTION, - allowed - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.BORROW_FRESHNESS_CHECK - ); - } - - if (getCashPrior() < borrowAmount) { - return - fail( - Error.TOKEN_INSUFFICIENT_CASH, - FailureInfo.BORROW_CASH_NOT_AVAILABLE - ); - } - - BorrowLocalVars memory vars; - - (vars.mathErr, vars.accountBorrows) = borrowBalanceStoredInternal( - borrower - ); - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED, - uint256(vars.mathErr) - ); - } - - (vars.mathErr, vars.accountBorrowsNew) = addUInt( - vars.accountBorrows, - borrowAmount - ); - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED, - uint256(vars.mathErr) - ); - } - - (vars.mathErr, vars.totalBorrowsNew) = addUInt( - totalBorrows, - borrowAmount - ); - if (interestRateModel.isTropykusInterestRateModel()) { - require(vars.totalBorrowsNew <= 0.1e18, "CT25"); - } - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED, - uint256(vars.mathErr) - ); - } - - doTransferOut(borrower, borrowAmount); - - accountBorrows[borrower].principal = vars.accountBorrowsNew; - accountBorrows[borrower].interestIndex = borrowIndex; - totalBorrows = vars.totalBorrowsNew; - - emit Borrow( - borrower, - borrowAmount, - vars.accountBorrowsNew, - vars.totalBorrowsNew - ); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Sender repays their own borrow - * @param repayAmount The amount to repay - * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual repayment amount. - */ - function repayBorrowInternal(uint256 repayAmount) - internal - nonReentrant - returns (uint256, uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return ( - fail( - Error(error), - FailureInfo.REPAY_BORROW_ACCRUE_INTEREST_FAILED - ), - 0 - ); - } - return repayBorrowFresh(msg.sender, msg.sender, repayAmount); - } - - struct RepayBorrowLocalVars { - Error err; - MathError mathErr; - uint256 repayAmount; - uint256 borrowerIndex; - uint256 accountBorrows; - uint256 accountBorrowsNew; - uint256 totalBorrowsNew; - uint256 actualRepayAmount; - } - - /** - * @notice Borrows are repaid by another user (possibly the borrower). - * @param payer the account paying off the borrow - * @param borrower the account with the debt being payed off - * @param repayAmount the amount of undelrying tokens being returned - * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual repayment amount. - */ - function repayBorrowFresh( - address payer, - address borrower, - uint256 repayAmount - ) internal returns (uint256, uint256) { - uint256 allowed = comptroller.repayBorrowAllowed( - address(this), - payer, - borrower, - repayAmount - ); - if (allowed != 0) { - return ( - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.REPAY_BORROW_COMPTROLLER_REJECTION, - allowed - ), - 0 - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return ( - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.REPAY_BORROW_FRESHNESS_CHECK - ), - 0 - ); - } - - RepayBorrowLocalVars memory vars; - - vars.borrowerIndex = accountBorrows[borrower].interestIndex; - - (vars.mathErr, vars.accountBorrows) = borrowBalanceStoredInternal( - borrower - ); - if (vars.mathErr != MathError.NO_ERROR) { - return ( - failOpaque( - Error.MATH_ERROR, - FailureInfo - .REPAY_BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED, - uint256(vars.mathErr) - ), - 0 - ); - } - - if (repayAmount == type(uint256).max) { - vars.repayAmount = vars.accountBorrows; - } else { - vars.repayAmount = repayAmount; - } - - vars.actualRepayAmount = doTransferIn(payer, vars.repayAmount); - - (vars.mathErr, vars.accountBorrowsNew) = subUInt( - vars.accountBorrows, - vars.actualRepayAmount - ); - require(vars.mathErr == MathError.NO_ERROR, "CT16"); - - (vars.mathErr, vars.totalBorrowsNew) = subUInt( - totalBorrows, - vars.actualRepayAmount - ); - require(vars.mathErr == MathError.NO_ERROR, "CT17"); - - accountBorrows[borrower].principal = vars.accountBorrowsNew; - accountBorrows[borrower].interestIndex = borrowIndex; - totalBorrows = vars.totalBorrowsNew; - - emit RepayBorrow( - payer, - borrower, - vars.actualRepayAmount, - vars.accountBorrowsNew, - vars.totalBorrowsNew - ); - - return (uint256(Error.NO_ERROR), vars.actualRepayAmount); - } - - /** - * @notice The sender liquidates the borrowers collateral. - * The collateral seized is transferred to the liquidator. - * @param borrower The borrower of this cToken to be liquidated - * @param cTokenCollateral The market in which to seize collateral from the borrower - * @param repayAmount The amount of the underlying borrowed asset to repay - * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual repayment amount. - */ - function liquidateBorrowInternal( - address borrower, - uint256 repayAmount, - CTokenInterface cTokenCollateral - ) internal nonReentrant returns (uint256, uint256) { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return ( - fail( - Error(error), - FailureInfo.LIQUIDATE_ACCRUE_BORROW_INTEREST_FAILED - ), - 0 - ); - } - - error = cTokenCollateral.accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return ( - fail( - Error(error), - FailureInfo.LIQUIDATE_ACCRUE_COLLATERAL_INTEREST_FAILED - ), - 0 - ); - } - - // liquidateBorrowFresh emits borrow-specific logs on errors, so we don't need to - return - liquidateBorrowFresh( - msg.sender, - borrower, - repayAmount, - cTokenCollateral - ); - } - - /** - * @notice The liquidator liquidates the borrowers collateral. - * The collateral seized is transferred to the liquidator. - * @param borrower The borrower of this cToken to be liquidated - * @param liquidator The address repaying the borrow and seizing collateral - * @param cTokenCollateral The market in which to seize collateral from the borrower - * @param repayAmount The amount of the underlying borrowed asset to repay - * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual repayment amount. - */ - function liquidateBorrowFresh( - address liquidator, - address borrower, - uint256 repayAmount, - CTokenInterface cTokenCollateral - ) internal returns (uint256, uint256) { - uint256 allowed = comptroller.liquidateBorrowAllowed( - address(this), - address(cTokenCollateral), - liquidator, - borrower, - repayAmount - ); - if (allowed != 0) { - return ( - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.LIQUIDATE_COMPTROLLER_REJECTION, - allowed - ), - 0 - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return ( - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.LIQUIDATE_FRESHNESS_CHECK - ), - 0 - ); - } - - if (cTokenCollateral.accrualBlockNumber() != getBlockNumber()) { - return ( - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.LIQUIDATE_COLLATERAL_FRESHNESS_CHECK - ), - 0 - ); - } - - if (borrower == liquidator) { - return ( - fail( - Error.INVALID_ACCOUNT_PAIR, - FailureInfo.LIQUIDATE_LIQUIDATOR_IS_BORROWER - ), - 0 - ); - } - - if (repayAmount == 0) { - return ( - fail( - Error.INVALID_CLOSE_AMOUNT_REQUESTED, - FailureInfo.LIQUIDATE_CLOSE_AMOUNT_IS_ZERO - ), - 0 - ); - } - - if (repayAmount == type(uint256).max) { - return ( - fail( - Error.INVALID_CLOSE_AMOUNT_REQUESTED, - FailureInfo.LIQUIDATE_CLOSE_AMOUNT_IS_UINT_MAX - ), - 0 - ); - } - - ( - uint256 repayBorrowError, - uint256 actualRepayAmount - ) = repayBorrowFresh(liquidator, borrower, repayAmount); - if (repayBorrowError != uint256(Error.NO_ERROR)) { - return ( - fail( - Error(repayBorrowError), - FailureInfo.LIQUIDATE_REPAY_BORROW_FRESH_FAILED - ), - 0 - ); - } - - (uint256 amountSeizeError, uint256 seizeTokens) = comptroller - .liquidateCalculateSeizeTokens( - address(this), - address(cTokenCollateral), - actualRepayAmount - ); - require(amountSeizeError == uint256(Error.NO_ERROR), "CT18"); - - require(cTokenCollateral.balanceOf(borrower) >= seizeTokens, "CT19"); - - uint256 seizeError; - if (address(cTokenCollateral) == address(this)) { - seizeError = seizeInternal( - address(this), - liquidator, - borrower, - seizeTokens - ); - } else { - seizeError = cTokenCollateral.seize( - liquidator, - borrower, - seizeTokens - ); - } - - require(seizeError == uint256(Error.NO_ERROR), "CT20"); - - emit LiquidateBorrow( - liquidator, - borrower, - actualRepayAmount, - address(cTokenCollateral), - seizeTokens - ); - - return (uint256(Error.NO_ERROR), actualRepayAmount); - } - - /** - * @notice Transfers collateral tokens (this market) to the liquidator. - * @dev Will fail unless called by another cToken during the process of liquidation. - * Its absolutely critical to use msg.sender as the borrowed cToken and not a parameter. - * @param liquidator The account receiving seized collateral - * @param borrower The account having collateral seized - * @param seizeTokens The number of cTokens to seize - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function seize( - address liquidator, - address borrower, - uint256 seizeTokens - ) external override nonReentrant returns (uint256) { - return seizeInternal(msg.sender, liquidator, borrower, seizeTokens); - } - - struct SeizeVars { - uint256 seizeAmount; - uint256 exchangeRate; - uint256 borrowerTokensNew; - uint256 borrowerAmountNew; - uint256 liquidatorTokensNew; - uint256 liquidatorAmountNew; - uint256 totalCash; - uint256 supplyRate; - } - - /** - * @notice Transfers collateral tokens (this market) to the liquidator. - * @dev Called only during an in-kind liquidation, or by liquidateBorrow during the liquidation of another CToken. - * Its absolutely critical to use msg.sender as the seizer cToken and not a parameter. - * @param seizerToken The contract seizing the collateral (i.e. borrowed cToken) - * @param liquidator The account receiving seized collateral - * @param borrower The account having collateral seized - * @param seizeTokens The number of cTokens to seize - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function seizeInternal( - address seizerToken, - address liquidator, - address borrower, - uint256 seizeTokens - ) internal returns (uint256) { - uint256 allowed = comptroller.seizeAllowed( - address(this), - seizerToken, - liquidator, - borrower, - seizeTokens - ); - if (allowed != 0) { - return - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.LIQUIDATE_SEIZE_COMPTROLLER_REJECTION, - allowed - ); - } - - if (borrower == liquidator) { - return - fail( - Error.INVALID_ACCOUNT_PAIR, - FailureInfo.LIQUIDATE_SEIZE_LIQUIDATOR_IS_BORROWER - ); - } - - SeizeVars memory seizeVars; - - MathError mathErr; - - (mathErr, seizeVars.borrowerTokensNew) = subUInt( - accountTokens[borrower].tokens, - seizeTokens - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.LIQUIDATE_SEIZE_BALANCE_DECREMENT_FAILED, - uint256(mathErr) - ); - } - - seizeVars.totalCash = getCashPrior(); - seizeVars.supplyRate = interestRateModel.getSupplyRate( - seizeVars.totalCash, - totalBorrows, - totalReserves, - reserveFactorMantissa - ); - - (, seizeVars.exchangeRate) = interestRateModel.getExchangeRate( - seizeVars.totalCash, - totalBorrows, - totalReserves, - totalSupply - ); - - if (interestRateModel.isTropykusInterestRateModel()) { - (, seizeVars.exchangeRate) = tropykusExchangeRateStoredInternal( - borrower - ); - } - - (, seizeVars.seizeAmount) = mulUInt( - seizeTokens, - seizeVars.exchangeRate - ); - (, seizeVars.seizeAmount) = divUInt(seizeVars.seizeAmount, 1e18); - - (, seizeVars.borrowerAmountNew) = subUInt( - accountTokens[borrower].underlyingAmount, - seizeVars.seizeAmount - ); - - (mathErr, seizeVars.liquidatorTokensNew) = addUInt( - accountTokens[liquidator].tokens, - seizeTokens - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.LIQUIDATE_SEIZE_BALANCE_INCREMENT_FAILED, - uint256(mathErr) - ); - } - - (, seizeVars.liquidatorAmountNew) = addUInt( - accountTokens[liquidator].underlyingAmount, - seizeVars.seizeAmount - ); - - accountTokens[borrower].tokens = seizeVars.borrowerTokensNew; - accountTokens[borrower].underlyingAmount = seizeVars.borrowerAmountNew; - accountTokens[borrower].suppliedAt = getBlockNumber(); - accountTokens[borrower].promisedSupplyRate = seizeVars.supplyRate; - - accountTokens[liquidator].tokens = seizeVars.liquidatorTokensNew; - accountTokens[liquidator].underlyingAmount = seizeVars - .liquidatorAmountNew; - accountTokens[liquidator].suppliedAt = getBlockNumber(); - accountTokens[liquidator].promisedSupplyRate = seizeVars.supplyRate; - - emit Transfer(borrower, liquidator, seizeTokens); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Begins transfer of admin rights. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer. - * @dev Admin function to begin change of admin. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer. - * @param newPendingAdmin New pending admin. - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setPendingAdmin(address payable newPendingAdmin) - external - override - returns (uint256) - { - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_PENDING_ADMIN_OWNER_CHECK - ); - } - - address oldPendingAdmin = pendingAdmin; - - pendingAdmin = newPendingAdmin; - - emit NewPendingAdmin(oldPendingAdmin, newPendingAdmin); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Accepts transfer of admin rights. msg.sender must be pendingAdmin - * @dev Admin function for pending admin to accept role and update admin - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _acceptAdmin() external override returns (uint256) { - if (msg.sender != pendingAdmin || msg.sender == address(0)) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.ACCEPT_ADMIN_PENDING_ADMIN_CHECK - ); - } - - address oldAdmin = admin; - address oldPendingAdmin = pendingAdmin; - - admin = pendingAdmin; - - pendingAdmin = payable(address(0)); - - emit NewAdmin(oldAdmin, admin); - emit NewPendingAdmin(oldPendingAdmin, pendingAdmin); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Sets a new comptroller for the market - * @dev Admin function to set a new comptroller - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setComptroller(ComptrollerInterface newComptroller) - public - override - returns (uint256) - { - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_COMPTROLLER_OWNER_CHECK - ); - } - - ComptrollerInterface oldComptroller = comptroller; - require(newComptroller.isComptroller(), "CT21"); - - comptroller = newComptroller; - - emit NewComptroller(oldComptroller, newComptroller); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice accrues interest and sets a new reserve factor for the protocol using _setReserveFactorFresh - * @dev Admin function to accrue interest and set a new reserve factor - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setReserveFactor(uint256 newReserveFactorMantissa) - external - override - nonReentrant - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return - fail( - Error(error), - FailureInfo.SET_RESERVE_FACTOR_ACCRUE_INTEREST_FAILED - ); - } - return _setReserveFactorFresh(newReserveFactorMantissa); - } - - /** - * @notice Sets a new reserve factor for the protocol (*requires fresh interest accrual) - * @dev Admin function to set a new reserve factor - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setReserveFactorFresh(uint256 newReserveFactorMantissa) - internal - returns (uint256) - { - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_RESERVE_FACTOR_ADMIN_CHECK - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.SET_RESERVE_FACTOR_FRESH_CHECK - ); - } - - if (newReserveFactorMantissa > reserveFactorMaxMantissa) { - return - fail( - Error.BAD_INPUT, - FailureInfo.SET_RESERVE_FACTOR_BOUNDS_CHECK - ); - } - - uint256 oldReserveFactorMantissa = reserveFactorMantissa; - reserveFactorMantissa = newReserveFactorMantissa; - - emit NewReserveFactor( - oldReserveFactorMantissa, - newReserveFactorMantissa - ); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Accrues interest and reduces reserves by transferring from msg.sender - * @param addAmount Amount of addition to reserves - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _addReservesInternal(uint256 addAmount) - internal - nonReentrant - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return - fail( - Error(error), - FailureInfo.ADD_RESERVES_ACCRUE_INTEREST_FAILED - ); - } - - uint256 totalReservesNew; - uint256 actualAddAmount; - - if (accrualBlockNumber != getBlockNumber()) { - return ( - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.ADD_RESERVES_FRESH_CHECK - ) - ); - } - - actualAddAmount = doTransferIn(msg.sender, addAmount); - - totalReservesNew = totalReserves + actualAddAmount; - - require(totalReservesNew >= totalReserves, "CT22"); - - totalReserves = totalReservesNew; - - emit ReservesAdded(msg.sender, actualAddAmount, totalReservesNew); - - return (uint256(Error.NO_ERROR)); - } - - function _addSubsidyInternal(uint256 addAmount) - internal - nonReentrant - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - // accrueInterest emits logs on errors, but on top of that we want to log the fact that an attempted reduce reserves failed. - return fail(Error(error), FailureInfo.ADD_SUBSIDY_FUND_FAILED); - } - - uint256 subsidyFundNew; - uint256 actualAddAmount; - - if (accrualBlockNumber != getBlockNumber()) { - return ( - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.ADD_SUBSIDY_FUND_FRESH_CHECK - ) - ); - } - - actualAddAmount = doTransferIn(msg.sender, addAmount); - - subsidyFundNew = subsidyFund + actualAddAmount; - - require(subsidyFundNew >= subsidyFund, "CT22"); - - subsidyFund = subsidyFundNew; - - emit SubsidyAdded(msg.sender, actualAddAmount, subsidyFundNew); - - /* Return (NO_ERROR, actualAddAmount) */ - return (uint256(Error.NO_ERROR)); - } - - /** - * @notice Accrues interest and reduces reserves by transferring to admin - * @param reduceAmount Amount of reduction to reserves - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _reduceReserves(uint256 reduceAmount) - external - override - nonReentrant - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return - fail( - Error(error), - FailureInfo.REDUCE_RESERVES_ACCRUE_INTEREST_FAILED - ); - } - return _reduceReservesFresh(reduceAmount); - } - - /** - * @notice Reduces reserves by transferring to admin - * @dev Requires fresh interest accrual - * @param reduceAmount Amount of reduction to reserves - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _reduceReservesFresh(uint256 reduceAmount) - internal - returns (uint256) - { - uint256 totalReservesNew; - - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.REDUCE_RESERVES_ADMIN_CHECK - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.REDUCE_RESERVES_FRESH_CHECK - ); - } - - if (getCashPrior() < reduceAmount) { - return - fail( - Error.TOKEN_INSUFFICIENT_CASH, - FailureInfo.REDUCE_RESERVES_CASH_NOT_AVAILABLE - ); - } - - if (reduceAmount > totalReserves) { - return - fail(Error.BAD_INPUT, FailureInfo.REDUCE_RESERVES_VALIDATION); - } - - totalReservesNew = totalReserves - reduceAmount; - require(totalReservesNew <= totalReserves, "CT23"); - - totalReserves = totalReservesNew; - - doTransferOut(admin, reduceAmount); - - emit ReservesReduced(admin, reduceAmount, totalReservesNew); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice accrues interest and updates the interest rate model using _setInterestRateModelFresh - * @dev Admin function to accrue interest and update the interest rate model - * @param newInterestRateModel the new interest rate model to use - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setInterestRateModel(InterestRateModel newInterestRateModel) - public - override - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return - fail( - Error(error), - FailureInfo.SET_INTEREST_RATE_MODEL_ACCRUE_INTEREST_FAILED - ); - } - return _setInterestRateModelFresh(newInterestRateModel); - } - - /** - * @notice updates the interest rate model (*requires fresh interest accrual) - * @dev Admin function to update the interest rate model - * @param newInterestRateModel the new interest rate model to use - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setInterestRateModelFresh(InterestRateModel newInterestRateModel) - internal - returns (uint256) - { - InterestRateModel oldInterestRateModel; - - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_INTEREST_RATE_MODEL_OWNER_CHECK - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.SET_INTEREST_RATE_MODEL_FRESH_CHECK - ); - } - - oldInterestRateModel = interestRateModel; - - require(newInterestRateModel.isInterestRateModel(), "CT21"); - - interestRateModel = newInterestRateModel; - - emit NewMarketInterestRateModel( - oldInterestRateModel, - newInterestRateModel - ); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Gets balance of this contract in terms of the underlying - * @dev This excludes the value of the current message, if any - * @return The quantity of underlying owned by this contract - */ - function getCashPrior() internal view virtual returns (uint256); - - /** - * @dev Performs a transfer in, reverting upon failure. Returns the amount actually transferred to the protocol, in case of a fee. - * This may revert due to insufficient balance or insufficient allowance. - */ - function doTransferIn(address from, uint256 amount) - internal - virtual - returns (uint256); - - /** - * @dev Performs a transfer out, ideally returning an explanatory error code upon failure tather than reverting. - * If caller has not called checked protocol's balance, may revert due to insufficient cash held in the contract. - * If caller has checked protocol's balance, and verified it is >= amount, this should not revert in normal conditions. - */ - function doTransferOut(address payable to, uint256 amount) internal virtual; - - /** - * @dev Prevents a contract from calling itself, directly or indirectly. - */ - modifier nonReentrant() { - require(_notEntered, "re-entered"); - _notEntered = false; - _; - _notEntered = true; - } -} diff --git a/flatten/CTokenInterfaces.sol b/flatten/CTokenInterfaces.sol deleted file mode 100644 index ef77d58..0000000 --- a/flatten/CTokenInterfaces.sol +++ /dev/null @@ -1,1451 +0,0 @@ -// Dependency file: contracts/ComptrollerInterface.sol - -// SPDX-License-Identifier: UNLICENSED -// pragma solidity 0.8.6; - -abstract contract ComptrollerInterface { - /// @notice Indicator that this is a Comptroller contract (for inspection) - bool public constant isComptroller = true; - - /*** Assets You Are In ***/ - - function enterMarkets(address[] calldata cTokens) - external - virtual - returns (uint256[] memory); - - function exitMarket(address cToken) external virtual returns (uint256); - - /*** Policy Hooks ***/ - - function mintAllowed( - address cToken, - address minter, - uint256 mintAmount - ) external virtual returns (uint256); - - function mintVerify( - address cToken, - address minter, - uint256 mintAmount, - uint256 mintTokens - ) external virtual; - - function redeemAllowed( - address cToken, - address redeemer, - uint256 redeemTokens - ) external virtual returns (uint256); - - function redeemVerify( - address cToken, - address redeemer, - uint256 redeemAmount, - uint256 redeemTokens - ) external virtual; - - function borrowAllowed( - address cToken, - address borrower, - uint256 borrowAmount - ) external virtual returns (uint256); - - function borrowVerify( - address cToken, - address borrower, - uint256 borrowAmount - ) external virtual; - - function repayBorrowAllowed( - address cToken, - address payer, - address borrower, - uint256 repayAmount - ) external virtual returns (uint256); - - function repayBorrowVerify( - address cToken, - address payer, - address borrower, - uint256 repayAmount, - uint256 borrowerIndex - ) external virtual; - - function liquidateBorrowAllowed( - address cTokenBorrowed, - address cTokenCollateral, - address liquidator, - address borrower, - uint256 repayAmount - ) external virtual returns (uint256); - - function liquidateBorrowVerify( - address cTokenBorrowed, - address cTokenCollateral, - address liquidator, - address borrower, - uint256 repayAmount, - uint256 seizeTokens - ) external virtual; - - function seizeAllowed( - address cTokenCollateral, - address cTokenBorrowed, - address liquidator, - address borrower, - uint256 seizeTokens - ) external virtual returns (uint256); - - function seizeVerify( - address cTokenCollateral, - address cTokenBorrowed, - address liquidator, - address borrower, - uint256 seizeTokens - ) external virtual; - - function transferAllowed( - address cToken, - address src, - address dst, - uint256 transferTokens - ) external virtual returns (uint256); - - function transferVerify( - address cToken, - address src, - address dst, - uint256 transferTokens - ) external virtual; - - /*** Liquidity/Liquidation Calculations ***/ - - function liquidateCalculateSeizeTokens( - address cTokenBorrowed, - address cTokenCollateral, - uint256 repayAmount - ) external view virtual returns (uint256, uint256); -} - - -// Dependency file: contracts/CarefulMath.sol - -// pragma solidity 0.8.6; - -/** - * @title Careful Math - * @author tropykus - * @notice Derived from OpenZeppelin's SafeMath library - * https://github.com/OpenZeppelin/openzeppelin-solidity/blob/master/contracts/math/SafeMath.sol - */ -contract CarefulMath { - - /** - * @dev Possible error codes that we can return - */ - enum MathError { - NO_ERROR, - DIVISION_BY_ZERO, - INTEGER_OVERFLOW, - INTEGER_UNDERFLOW - } - - /** - * @dev Multiplies two numbers, returns an error on overflow. - */ - function mulUInt(uint a, uint b) internal pure returns (MathError, uint) { - if (a == 0) { - return (MathError.NO_ERROR, 0); - } - - uint c = a * b; - - if (c / a != b) { - return (MathError.INTEGER_OVERFLOW, 0); - } else { - return (MathError.NO_ERROR, c); - } - } - - /** - * @dev Integer division of two numbers, truncating the quotient. - */ - function divUInt(uint a, uint b) internal pure returns (MathError, uint) { - if (b == 0) { - return (MathError.DIVISION_BY_ZERO, 0); - } - - return (MathError.NO_ERROR, a / b); - } - - /** - * @dev Subtracts two numbers, returns an error on overflow (i.e. if subtrahend is greater than minuend). - */ - function subUInt(uint a, uint b) internal pure returns (MathError, uint) { - if (b <= a) { - return (MathError.NO_ERROR, a - b); - } else { - return (MathError.INTEGER_UNDERFLOW, 0); - } - } - - /** - * @dev Adds two numbers, returns an error on overflow. - */ - function addUInt(uint a, uint b) internal pure returns (MathError, uint) { - uint c = a + b; - - if (c >= a) { - return (MathError.NO_ERROR, c); - } else { - return (MathError.INTEGER_OVERFLOW, 0); - } - } - - /** - * @dev add a and b and then subtract c - */ - function addThenSubUInt(uint a, uint b, uint c) internal pure returns (MathError, uint) { - (MathError err0, uint sum) = addUInt(a, b); - - if (err0 != MathError.NO_ERROR) { - return (err0, 0); - } - - return subUInt(sum, c); - } -} - - -// Dependency file: contracts/ExponentialNoError.sol - -// pragma solidity 0.8.6; - -/** - * @title Exponential module for storing fixed-precision decimals - * @author tropykus - * @notice Exp is a struct which stores decimals with a fixed precision of 18 decimal places. - * Thus, if we wanted to store the 5.1, mantissa would store 5.1e18. That is: - * `Exp({mantissa: 5100000000000000000})`. - */ -contract ExponentialNoError { - uint constant expScale = 1e18; - uint constant doubleScale = 1e36; - uint constant halfExpScale = expScale/2; - uint constant mantissaOne = expScale; - - struct Exp { - uint mantissa; - } - - struct Double { - uint mantissa; - } - - /** - * @dev Truncates the given exp to a whole number value. - * For example, truncate(Exp{mantissa: 15 * expScale}) = 15 - */ - function truncate(Exp memory exp) pure internal returns (uint) { - // Note: We are not using careful math here as we're performing a division that cannot fail - return exp.mantissa / expScale; - } - - /** - * @dev Multiply an Exp by a scalar, then truncate to return an unsigned integer. - */ - function mul_ScalarTruncate(Exp memory a, uint scalar) pure internal returns (uint) { - Exp memory product = mul_(a, scalar); - return truncate(product); - } - - /** - * @dev Multiply an Exp by a scalar, truncate, then add an to an unsigned integer, returning an unsigned integer. - */ - function mul_ScalarTruncateAddUInt(Exp memory a, uint scalar, uint addend) pure internal returns (uint) { - Exp memory product = mul_(a, scalar); - return add_(truncate(product), addend); - } - - /** - * @dev Checks if first Exp is less than second Exp. - */ - function lessThanExp(Exp memory left, Exp memory right) pure internal returns (bool) { - return left.mantissa < right.mantissa; - } - - /** - * @dev Checks if left Exp <= right Exp. - */ - function lessThanOrEqualExp(Exp memory left, Exp memory right) pure internal returns (bool) { - return left.mantissa <= right.mantissa; - } - - /** - * @dev Checks if left Exp > right Exp. - */ - function greaterThanExp(Exp memory left, Exp memory right) pure internal returns (bool) { - return left.mantissa > right.mantissa; - } - - /** - * @dev returns true if Exp is exactly zero - */ - function isZeroExp(Exp memory value) pure internal returns (bool) { - return value.mantissa == 0; - } - - function safe224(uint n, string memory errorMessage) pure internal returns (uint224) { - require(n < 2**224, errorMessage); - return uint224(n); - } - - function safe32(uint n, string memory errorMessage) pure internal returns (uint32) { - require(n < 2**32, errorMessage); - return uint32(n); - } - - function add_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { - return Exp({mantissa: add_(a.mantissa, b.mantissa)}); - } - - function add_(Double memory a, Double memory b) pure internal returns (Double memory) { - return Double({mantissa: add_(a.mantissa, b.mantissa)}); - } - - function add_(uint a, uint b) pure internal returns (uint) { - return add_(a, b, "addition overflow"); - } - - function add_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { - uint c = a + b; - require(c >= a, errorMessage); - return c; - } - - function sub_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { - return Exp({mantissa: sub_(a.mantissa, b.mantissa)}); - } - - function sub_(Double memory a, Double memory b) pure internal returns (Double memory) { - return Double({mantissa: sub_(a.mantissa, b.mantissa)}); - } - - function sub_(uint a, uint b) pure internal returns (uint) { - return sub_(a, b, "subtraction underflow"); - } - - function sub_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { - require(b <= a, errorMessage); - return a - b; - } - - function mul_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { - return Exp({mantissa: mul_(a.mantissa, b.mantissa) / expScale}); - } - - function mul_(Exp memory a, uint b) pure internal returns (Exp memory) { - return Exp({mantissa: mul_(a.mantissa, b)}); - } - - function mul_(uint a, Exp memory b) pure internal returns (uint) { - return mul_(a, b.mantissa) / expScale; - } - - function mul_(Double memory a, Double memory b) pure internal returns (Double memory) { - return Double({mantissa: mul_(a.mantissa, b.mantissa) / doubleScale}); - } - - function mul_(Double memory a, uint b) pure internal returns (Double memory) { - return Double({mantissa: mul_(a.mantissa, b)}); - } - - function mul_(uint a, Double memory b) pure internal returns (uint) { - return mul_(a, b.mantissa) / doubleScale; - } - - function mul_(uint a, uint b) pure internal returns (uint) { - return mul_(a, b, "multiplication overflow"); - } - - function mul_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { - if (a == 0 || b == 0) { - return 0; - } - uint c = a * b; - require(c / a == b, errorMessage); - return c; - } - - function div_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { - return Exp({mantissa: div_(mul_(a.mantissa, expScale), b.mantissa)}); - } - - function div_(Exp memory a, uint b) pure internal returns (Exp memory) { - return Exp({mantissa: div_(a.mantissa, b)}); - } - - function div_(uint a, Exp memory b) pure internal returns (uint) { - return div_(mul_(a, expScale), b.mantissa); - } - - function div_(Double memory a, Double memory b) pure internal returns (Double memory) { - return Double({mantissa: div_(mul_(a.mantissa, doubleScale), b.mantissa)}); - } - - function div_(Double memory a, uint b) pure internal returns (Double memory) { - return Double({mantissa: div_(a.mantissa, b)}); - } - - function div_(uint a, Double memory b) pure internal returns (uint) { - return div_(mul_(a, doubleScale), b.mantissa); - } - - function div_(uint a, uint b) pure internal returns (uint) { - return div_(a, b, "divide by zero"); - } - - function div_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { - require(b > 0, errorMessage); - return a / b; - } - - function fraction(uint a, uint b) pure internal returns (Double memory) { - return Double({mantissa: div_(mul_(a, doubleScale), b)}); - } -} - - -// Dependency file: contracts/Exponential.sol - -// pragma solidity 0.8.6; - -// import "contracts/CarefulMath.sol"; -// import "contracts/ExponentialNoError.sol"; - -/** - * @title Exponential module for storing fixed-precision decimals - * @author tropykus - * @dev Legacy contract for compatibility reasons with existing contracts that still use MathError - * @notice Exp is a struct which stores decimals with a fixed precision of 18 decimal places. - * Thus, if we wanted to store the 5.1, mantissa would store 5.1e18. That is: - * `Exp({mantissa: 5100000000000000000})`. - */ -contract Exponential is CarefulMath, ExponentialNoError { - /** - * @dev Creates an exponential from numerator and denominator values. - * Note: Returns an error if (`num` * 10e18) > MAX_INT, - * or if `denom` is zero. - */ - function getExp(uint num, uint denom) internal pure returns (MathError, Exp memory) { - (MathError err0, uint scaledNumerator) = mulUInt(num, expScale); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - - (MathError err1, uint rational) = divUInt(scaledNumerator, denom); - if (err1 != MathError.NO_ERROR) { - return (err1, Exp({mantissa: 0})); - } - - return (MathError.NO_ERROR, Exp({mantissa: rational})); - } - - /** - * @dev Adds two exponentials, returning a new exponential. - */ - function addExp(Exp memory a, Exp memory b) internal pure returns (MathError, Exp memory) { - (MathError error, uint result) = addUInt(a.mantissa, b.mantissa); - - return (error, Exp({mantissa: result})); - } - - /** - * @dev Subtracts two exponentials, returning a new exponential. - */ - function subExp(Exp memory a, Exp memory b) internal pure returns (MathError, Exp memory) { - (MathError error, uint result) = subUInt(a.mantissa, b.mantissa); - - return (error, Exp({mantissa: result})); - } - - /** - * @dev Multiply an Exp by a scalar, returning a new Exp. - */ - function mulScalar(Exp memory a, uint scalar) internal pure returns (MathError, Exp memory) { - (MathError err0, uint scaledMantissa) = mulUInt(a.mantissa, scalar); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - - return (MathError.NO_ERROR, Exp({mantissa: scaledMantissa})); - } - - /** - * @dev Multiply an Exp by a scalar, then truncate to return an unsigned integer. - */ - function mulScalarTruncate(Exp memory a, uint scalar) internal pure returns (MathError, uint) { - (MathError err, Exp memory product) = mulScalar(a, scalar); - if (err != MathError.NO_ERROR) { - return (err, 0); - } - - return (MathError.NO_ERROR, truncate(product)); - } - - /** - * @dev Multiply an Exp by a scalar, truncate, then add an to an unsigned integer, returning an unsigned integer. - */ - function mulScalarTruncateAddUInt(Exp memory a, uint scalar, uint addend) internal pure returns (MathError, uint) { - (MathError err, Exp memory product) = mulScalar(a, scalar); - if (err != MathError.NO_ERROR) { - return (err, 0); - } - - return addUInt(truncate(product), addend); - } - - /** - * @dev Divide an Exp by a scalar, returning a new Exp. - */ - function divScalar(Exp memory a, uint scalar) internal pure returns (MathError, Exp memory) { - (MathError err0, uint descaledMantissa) = divUInt(a.mantissa, scalar); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - - return (MathError.NO_ERROR, Exp({mantissa: descaledMantissa})); - } - - /** - * @dev Divide a scalar by an Exp, returning a new Exp. - */ - function divScalarByExp(uint scalar, Exp memory divisor) internal pure returns (MathError, Exp memory) { - /* - We are doing this as: - getExp(mulUInt(expScale, scalar), divisor.mantissa) - - How it works: - Exp = a / b; - Scalar = s; - `s / (a / b)` = `b * s / a` and since for an Exp `a = mantissa, b = expScale` - */ - (MathError err0, uint numerator) = mulUInt(expScale, scalar); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - return getExp(numerator, divisor.mantissa); - } - - /** - * @dev Divide a scalar by an Exp, then truncate to return an unsigned integer. - */ - function divScalarByExpTruncate(uint scalar, Exp memory divisor) internal pure returns (MathError, uint) { - (MathError err, Exp memory fraction) = divScalarByExp(scalar, divisor); - if (err != MathError.NO_ERROR) { - return (err, 0); - } - - return (MathError.NO_ERROR, truncate(fraction)); - } - - /** - * @dev Multiplies two exponentials, returning a new exponential. - */ - function mulExp(Exp memory a, Exp memory b) internal pure returns (MathError, Exp memory) { - - (MathError err0, uint doubleScaledProduct) = mulUInt(a.mantissa, b.mantissa); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - - // We add half the scale before dividing so that we get rounding instead of truncation. - // See "Listing 6" and text above it at https://accu.org/index.php/journals/1717 - // Without this change, a result like 6.6...e-19 will be truncated to 0 instead of being rounded to 1e-18. - (MathError err1, uint doubleScaledProductWithHalfScale) = addUInt(halfExpScale, doubleScaledProduct); - if (err1 != MathError.NO_ERROR) { - return (err1, Exp({mantissa: 0})); - } - - (MathError err2, uint product) = divUInt(doubleScaledProductWithHalfScale, expScale); - // The only error `div` can return is MathError.DIVISION_BY_ZERO but we control `expScale` and it is not zero. - assert(err2 == MathError.NO_ERROR); - - return (MathError.NO_ERROR, Exp({mantissa: product})); - } - - /** - * @dev Multiplies two exponentials given their mantissas, returning a new exponential. - */ - function mulExp(uint a, uint b) internal pure returns (MathError, Exp memory) { - return mulExp(Exp({mantissa: a}), Exp({mantissa: b})); - } - - /** - * @dev Multiplies three exponentials, returning a new exponential. - */ - function mulExp3(Exp memory a, Exp memory b, Exp memory c) internal pure returns (MathError, Exp memory) { - (MathError err, Exp memory ab) = mulExp(a, b); - if (err != MathError.NO_ERROR) { - return (err, ab); - } - return mulExp(ab, c); - } - - /** - * @dev Divides two exponentials, returning a new exponential. - * (a/scale) / (b/scale) = (a/scale) * (scale/b) = a/b, - * which we can scale as an Exp by calling getExp(a.mantissa, b.mantissa) - */ - function divExp(Exp memory a, Exp memory b) internal pure returns (MathError, Exp memory) { - return getExp(a.mantissa, b.mantissa); - } -} - - -// Dependency file: contracts/SafeMath.sol - -// pragma solidity 0.8.6; - -// From https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/math/Math.sol -// Subject to the MIT license. - -/** - * @dev Wrappers over Solidity's arithmetic operations with added overflow - * checks. - * - * Arithmetic operations in Solidity wrap on overflow. This can easily result - * in bugs, because programmers usually assume that an overflow raises an - * error, which is the standard behavior in high level programming languages. - * `SafeMath` restores this intuition by reverting the transaction when an - * operation overflows. - * - * Using this library instead of the unchecked operations eliminates an entire - * class of bugs, so it's recommended to use it always. - */ -library SafeMath { - /** - * @dev Returns the addition of two unsigned integers, reverting on overflow. - * - * Counterpart to Solidity's `+` operator. - * - * Requirements: - * - Addition cannot overflow. - */ - function add(uint256 a, uint256 b) internal pure returns (uint256) { - uint256 c = a + b; - require(c >= a, "SafeMath: addition overflow"); - - return c; - } - - /** - * @dev Returns the addition of two unsigned integers, reverting with custom message on overflow. - * - * Counterpart to Solidity's `+` operator. - * - * Requirements: - * - Addition cannot overflow. - */ - function add(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - uint256 c = a + b; - require(c >= a, errorMessage); - - return c; - } - - /** - * @dev Returns the subtraction of two unsigned integers, reverting on underflow (when the result is negative). - * - * Counterpart to Solidity's `-` operator. - * - * Requirements: - * - Subtraction cannot underflow. - */ - function sub(uint256 a, uint256 b) internal pure returns (uint256) { - return sub(a, b, "SafeMath: subtraction underflow"); - } - - /** - * @dev Returns the subtraction of two unsigned integers, reverting with custom message on underflow (when the result is negative). - * - * Counterpart to Solidity's `-` operator. - * - * Requirements: - * - Subtraction cannot underflow. - */ - function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - require(b <= a, errorMessage); - uint256 c = a - b; - - return c; - } - - /** - * @dev Returns the multiplication of two unsigned integers, reverting on overflow. - * - * Counterpart to Solidity's `*` operator. - * - * Requirements: - * - Multiplication cannot overflow. - */ - function mul(uint256 a, uint256 b) internal pure returns (uint256) { - // Gas optimization: this is cheaper than requiring 'a' not being zero, but the - // benefit is lost if 'b' is also tested. - // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 - if (a == 0) { - return 0; - } - - uint256 c = a * b; - require(c / a == b, "SafeMath: multiplication overflow"); - - return c; - } - - /** - * @dev Returns the multiplication of two unsigned integers, reverting on overflow. - * - * Counterpart to Solidity's `*` operator. - * - * Requirements: - * - Multiplication cannot overflow. - */ - function mul(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - // Gas optimization: this is cheaper than requiring 'a' not being zero, but the - // benefit is lost if 'b' is also tested. - // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 - if (a == 0) { - return 0; - } - - uint256 c = a * b; - require(c / a == b, errorMessage); - - return c; - } - - /** - * @dev Returns the integer division of two unsigned integers. - * Reverts on division by zero. The result is rounded towards zero. - * - * Counterpart to Solidity's `/` operator. Note: this function uses a - * `revert` opcode (which leaves remaining gas untouched) while Solidity - * uses an invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function div(uint256 a, uint256 b) internal pure returns (uint256) { - return div(a, b, "SafeMath: division by zero"); - } - - /** - * @dev Returns the integer division of two unsigned integers. - * Reverts with custom message on division by zero. The result is rounded towards zero. - * - * Counterpart to Solidity's `/` operator. Note: this function uses a - * `revert` opcode (which leaves remaining gas untouched) while Solidity - * uses an invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - // Solidity only automatically asserts when dividing by 0 - require(b > 0, errorMessage); - uint256 c = a / b; - // assert(a == b * c + a % b); // There is no case in which this doesn't hold - - return c; - } - - /** - * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), - * Reverts when dividing by zero. - * - * Counterpart to Solidity's `%` operator. This function uses a `revert` - * opcode (which leaves remaining gas untouched) while Solidity uses an - * invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function mod(uint256 a, uint256 b) internal pure returns (uint256) { - return mod(a, b, "SafeMath: modulo by zero"); - } - - /** - * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), - * Reverts with custom message when dividing by zero. - * - * Counterpart to Solidity's `%` operator. This function uses a `revert` - * opcode (which leaves remaining gas untouched) while Solidity uses an - * invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - require(b != 0, errorMessage); - return a % b; - } -} - - -// Dependency file: contracts/InterestRateModel.sol - -// pragma solidity 0.8.6; - -// import "contracts/Exponential.sol"; -// import "contracts/SafeMath.sol"; - -/** - * @title tropykus InterestRateModel Interface - * @author tropykus - */ -abstract contract InterestRateModel is Exponential { - using SafeMath for uint256; - - /// @notice Indicator that this is an InterestRateModel contract (for inspection) - bool public constant isInterestRateModel = true; - bool public isTropykusInterestRateModel; - - /** - * @notice The approximate number of blocks per year that is assumed by the interest rate model - */ - uint256 public constant blocksPerYear = 1051200; - - /** - * @notice Calculates the utilization rate of the market: `borrows / (cash + borrows - reserves)` - * @param cash The amount of cash in the market - * @param borrows The amount of borrows in the market - * @param reserves The amount of reserves in the market (currently unused) - * @return The utilization rate as a mantissa between [0, 1e18] - */ - function utilizationRate( - uint256 cash, - uint256 borrows, - uint256 reserves - ) public pure virtual returns (uint256) { - // Utilization rate is 0 when there are no borrows - if (borrows == 0) { - return 0; - } - - return borrows.mul(1e18).div(cash.add(borrows).sub(reserves)); - } - - /** - * @notice Calculates the current borrow interest rate per block - * @param cash The total amount of cash the market has - * @param borrows The total amount of borrows the market has outstanding - * @param reserves The total amnount of reserves the market has - * @return The borrow rate per block (as a percentage, and scaled by 1e18) - */ - function getBorrowRate( - uint256 cash, - uint256 borrows, - uint256 reserves - ) external view virtual returns (uint256); - - /** - * @notice Calculates the current supply interest rate per block - * @param cash The total amount of cash the market has - * @param borrows The total amount of borrows the market has outstanding - * @param reserves The total amnount of reserves the market has - * @param reserveFactorMantissa The current reserve factor the market has - * @return The supply rate per block (as a percentage, and scaled by 1e18) - */ - function getSupplyRate( - uint256 cash, - uint256 borrows, - uint256 reserves, - uint256 reserveFactorMantissa - ) external view virtual returns (uint256); - - function getExchangeRate( - uint256 _totalCash, - uint256 _totalBorrows, - uint256 _totalReserves, - uint256 _totalSupply - ) public pure returns (MathError, uint256) { - /* - * exchangeRate = (totalCash + totalBorrows - totalReserves) / totalSupply - */ - Exp memory exchangeRate; - MathError mathErr; - uint256 cashPlusBorrowsMinusReserves; - (mathErr, cashPlusBorrowsMinusReserves) = addThenSubUInt( - _totalCash, - _totalBorrows, - _totalReserves - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - (mathErr, exchangeRate) = getExp( - cashPlusBorrowsMinusReserves, - _totalSupply - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - - return (MathError.NO_ERROR, exchangeRate.mantissa); - } - - function isAboveOptimal( - uint256 cash, - uint256 borrows, - uint256 reserves - ) public view virtual returns (bool) { - cash; - borrows; - reserves; - return false; - } -} - - -// Dependency file: contracts/EIP20NonStandardInterface.sol - -// pragma solidity 0.8.6; - -/** - * @title EIP20NonStandardInterface - * @dev Version of ERC20 with no return values for `transfer` and `transferFrom` - * See https://medium.com/coinmonks/missing-return-value-bug-at-least-130-tokens-affected-d67bf08521ca - */ -interface EIP20NonStandardInterface { - /** - * @notice Get the total number of tokens in circulation - * @return The supply of tokens - */ - function totalSupply() external view returns (uint256); - - /** - * @notice Gets the balance of the specified address - * @param owner The address from which the balance will be retrieved - * @return balance The balance - */ - function balanceOf(address owner) external view returns (uint256 balance); - - /// - /// !!!!!!!!!!!!!! - /// !!! NOTICE !!! `transfer` does not return a value, in violation of the ERC-20 specification - /// !!!!!!!!!!!!!! - /// - - /** - * @notice Transfer `amount` tokens from `msg.sender` to `dst` - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - */ - function transfer(address dst, uint256 amount) external; - - /// - /// !!!!!!!!!!!!!! - /// !!! NOTICE !!! `transferFrom` does not return a value, in violation of the ERC-20 specification - /// !!!!!!!!!!!!!! - /// - - /** - * @notice Transfer `amount` tokens from `src` to `dst` - * @param src The address of the source account - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - */ - function transferFrom( - address src, - address dst, - uint256 amount - ) external; - - /** - * @notice Approve `spender` to transfer up to `amount` from `src` - * @dev This will overwrite the approval amount for `spender` - * and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve) - * @param spender The address of the account which may transfer tokens - * @param amount The number of tokens that are approved - * @return success Whether or not the approval succeeded - */ - function approve(address spender, uint256 amount) - external - returns (bool success); - - /** - * @notice Get the current allowance from `owner` for `spender` - * @param owner The address of the account which owns the tokens to be spent - * @param spender The address of the account which may transfer tokens - * @return remaining The number of tokens allowed to be spent - */ - function allowance(address owner, address spender) - external - view - returns (uint256 remaining); - - event Transfer(address indexed from, address indexed to, uint256 amount); - event Approval( - address indexed owner, - address indexed spender, - uint256 amount - ); -} - - -// Root file: contracts/CTokenInterfaces.sol - -pragma solidity 0.8.6; - -// import "contracts/ComptrollerInterface.sol"; -// import "contracts/InterestRateModel.sol"; -// import "contracts/EIP20NonStandardInterface.sol"; - -contract CTokenStorage { - /** - * @dev Guard variable for re-entrancy checks - */ - bool internal _notEntered; - - /** - * @notice EIP-20 token name for this token - */ - string public name; - - /** - * @notice EIP-20 token symbol for this token - */ - string public symbol; - - /** - * @notice EIP-20 token decimals for this token - */ - uint8 public decimals; - - /** - * @notice Maximum borrow rate that can ever be applied (.0005% / block) - */ - - uint256 internal constant borrowRateMaxMantissa = 0.0005e16; - - /** - * @notice Maximum fraction of interest that can be set aside for reserves - */ - uint256 internal constant reserveFactorMaxMantissa = 1e18; - - /** - * @notice Administrator for this contract - */ - address payable public admin; - - /** - * @notice Pending administrator for this contract - */ - address payable public pendingAdmin; - - /** - * @notice Contract which oversees inter-cToken operations - */ - ComptrollerInterface public comptroller; - - /** - * @notice Model which tells what the current interest rate should be - */ - InterestRateModel public interestRateModel; - - /** - * @notice Initial exchange rate used when minting the first CTokens (used when totalSupply = 0) - */ - uint256 public initialExchangeRateMantissa; - - /** - * @notice Fraction of interest currently set aside for reserves - */ - uint256 public reserveFactorMantissa; - - /** - * @notice Block number that interest was last accrued at - */ - uint256 public accrualBlockNumber; - - /** - * @notice Accumulator of the total earned interest rate since the opening of the market - */ - uint256 public borrowIndex; - - /** - * @notice Total amount of outstanding borrows of the underlying in this market - */ - uint256 public totalBorrows; - - /** - * @notice Total amount of reserves of the underlying held in this market - */ - uint256 public totalReserves; - - /** - * @notice Total number of tokens in circulation - */ - uint256 public totalSupply; - - uint256 public subsidyFund; - - struct SupplySnapshot { - uint256 tokens; - uint256 underlyingAmount; - uint256 suppliedAt; - uint256 promisedSupplyRate; - } - - /** - * @notice Official record of token balances for each account - */ - mapping(address => SupplySnapshot) internal accountTokens; - - /** - * @notice Approved token transfer amounts on behalf of others - */ - mapping(address => mapping(address => uint256)) internal transferAllowances; - - /** - * @notice Container for borrow balance information - * @member principal Total balance (with accrued interest), after applying the most recent balance-changing action - * @member interestIndex Global borrowIndex as of the most recent balance-changing action - */ - struct BorrowSnapshot { - uint256 principal; - uint256 interestIndex; - } - - /** - * @notice Mapping of account addresses to outstanding borrow balances - */ - mapping(address => BorrowSnapshot) internal accountBorrows; -} - -abstract contract CTokenInterface is CTokenStorage { - /** - * @notice Indicator that this is a CToken contract (for inspection) - */ - bool public constant isCToken = true; - - /*** Market Events ***/ - - /** - * @notice Event emitted when interest is accrued - */ - event AccrueInterest( - uint256 cashPrior, - uint256 interestAccumulated, - uint256 borrowIndex, - uint256 totalBorrows - ); - - /** - * @notice Event emitted when tokens are minted - */ - event Mint(address indexed minter, uint256 mintAmount, uint256 mintTokens); - - /** - * @notice Event emitted when tokens are redeemed - */ - event Redeem( - address indexed redeemer, - uint256 redeemAmount, - uint256 redeemTokens - ); - - /** - * @notice Event emitted when underlying is borrowed - */ - event Borrow( - address indexed borrower, - uint256 borrowAmount, - uint256 accountBorrows, - uint256 totalBorrows - ); - - /** - * @notice Event emitted when a borrow is repaid - */ - event RepayBorrow( - address indexed payer, - address indexed borrower, - uint256 repayAmount, - uint256 accountBorrows, - uint256 totalBorrows - ); - - /** - * @notice Event emitted when a borrow is liquidated - */ - event LiquidateBorrow( - address indexed liquidator, - address indexed borrower, - uint256 repayAmount, - address indexed cTokenCollateral, - uint256 seizeTokens - ); - - /*** Admin Events ***/ - - /** - * @notice Event emitted when pendingAdmin is changed - */ - event NewPendingAdmin(address oldPendingAdmin, address newPendingAdmin); - - /** - * @notice Event emitted when pendingAdmin is accepted, which means admin is updated - */ - event NewAdmin(address oldAdmin, address newAdmin); - - /** - * @notice Event emitted when comptroller is changed - */ - event NewComptroller( - ComptrollerInterface oldComptroller, - ComptrollerInterface newComptroller - ); - - /** - * @notice Event emitted when interestRateModel is changed - */ - event NewMarketInterestRateModel( - InterestRateModel oldInterestRateModel, - InterestRateModel newInterestRateModel - ); - - /** - * @notice Event emitted when the reserve factor is changed - */ - event NewReserveFactor( - uint256 oldReserveFactorMantissa, - uint256 newReserveFactorMantissa - ); - - /** - * @notice Event emitted when the reserves are added - */ - event ReservesAdded( - address benefactor, - uint256 addAmount, - uint256 newTotalReserves - ); - - event SubsidyAdded( - address benefactor, - uint256 addAmount, - uint256 newSubsidyFund - ); - - /** - * @notice Event emitted when the reserves are reduced - */ - event ReservesReduced( - address admin, - uint256 reduceAmount, - uint256 newTotalReserves - ); - - /** - * @notice EIP20 Transfer event - */ - event Transfer(address indexed from, address indexed to, uint256 amount); - - /** - * @notice EIP20 Approval event - */ - event Approval( - address indexed owner, - address indexed spender, - uint256 amount - ); - - /** - * @notice Failure event - */ - event CTokenStorageFailure(uint256 error, uint256 info, uint256 detail); - - /*** User Interface ***/ - - function transfer(address dst, uint256 amount) - external - virtual - returns (bool); - - function transferFrom( - address src, - address dst, - uint256 amount - ) external virtual returns (bool); - - function approve(address spender, uint256 amount) - external - virtual - returns (bool); - - function allowance(address owner, address spender) - external - view - virtual - returns (uint256); - - function balanceOf(address owner) external view virtual returns (uint256); - - function balanceOfUnderlying(address owner) - external - virtual - returns (uint256); - - function getAccountSnapshot(address account) - external - view - virtual - returns ( - uint256, - uint256, - uint256, - uint256 - ); - - function borrowRatePerBlock() external view virtual returns (uint256); - - function supplyRatePerBlock() external view virtual returns (uint256); - - function totalBorrowsCurrent() external virtual returns (uint256); - - function borrowBalanceCurrent(address account) - external - virtual - returns (uint256); - - function borrowBalanceStored(address account) - public - view - virtual - returns (uint256); - - function exchangeRateCurrent() public virtual returns (uint256); - - function exchangeRateStored() public view virtual returns (uint256); - - function getCash() external view virtual returns (uint256); - - function accrueInterest() public virtual returns (uint256); - - function seize( - address liquidator, - address borrower, - uint256 seizeTokens - ) external virtual returns (uint256); - - /*** Admin Functions ***/ - - function _setPendingAdmin(address payable newPendingAdmin) - external - virtual - returns (uint256); - - function _acceptAdmin() external virtual returns (uint256); - - function _setComptroller(ComptrollerInterface newComptroller) - public - virtual - returns (uint256); - - function _setReserveFactor(uint256 newReserveFactorMantissa) - external - virtual - returns (uint256); - - function _reduceReserves(uint256 reduceAmount) - external - virtual - returns (uint256); - - function _setInterestRateModel(InterestRateModel newInterestRateModel) - public - virtual - returns (uint256); -} - -contract CErc20Storage { - /** - * @notice Underlying asset for this CToken - */ - address public underlying; -} - -abstract contract CErc20Interface is CErc20Storage { - /*** User Interface ***/ - - function mint(uint256 mintAmount) external virtual returns (uint256); - - function redeem(uint256 redeemAmount) - external - virtual - returns (uint256); - - function borrow(uint256 borrowAmount) external virtual returns (uint256); - - function repayBorrow(uint256 repayAmount) - external - virtual - returns (uint256); - - function liquidateBorrow( - address borrower, - uint256 repayAmount, - CTokenInterface cTokenCollateral - ) external virtual returns (uint256); - - function sweepToken(EIP20NonStandardInterface token) external virtual; - - /*** Admin Functions ***/ - - function _addReserves(uint256 addAmount) external virtual returns (uint256); -} - -contract CDelegationStorage { - /** - * @notice Implementation address for this contract - */ - address public implementation; -} - -abstract contract CDelegatorInterface is CDelegationStorage { - /** - * @notice Emitted when implementation is changed - */ - event NewImplementation( - address oldImplementation, - address newImplementation - ); - - /** - * @notice Called by the admin to update the implementation of the delegator - * @param implementation_ The address of the new implementation for delegation - * @param allowResign Flag to indicate whether to call _resignImplementation on the old implementation - * @param becomeImplementationData The encoded bytes data to be passed to _becomeImplementation - */ - function _setImplementation( - address implementation_, - bool allowResign, - bytes memory becomeImplementationData - ) public virtual; -} - -abstract contract CDelegateInterface is CDelegationStorage { - /** - * @notice Called by the delegator on a delegate to initialize it for duty - * @dev Should revert if any issues arise which make it unfit for delegation - * @param data The encoded bytes data for any initialization - */ - function _becomeImplementation(bytes memory data) public virtual; - - /** - * @notice Called by the delegator on a delegate to forfeit its responsibility - */ - function _resignImplementation() public virtual; -} diff --git a/flatten/CarefulMath.sol b/flatten/CarefulMath.sol deleted file mode 100644 index 3547ff9..0000000 --- a/flatten/CarefulMath.sol +++ /dev/null @@ -1,88 +0,0 @@ -// Root file: contracts/CarefulMath.sol - -// SPDX-License-Identifier: UNLICENSED -pragma solidity 0.8.6; - -/** - * @title Careful Math - * @author tropykus - * @notice Derived from OpenZeppelin's SafeMath library - * https://github.com/OpenZeppelin/openzeppelin-solidity/blob/master/contracts/math/SafeMath.sol - */ -contract CarefulMath { - - /** - * @dev Possible error codes that we can return - */ - enum MathError { - NO_ERROR, - DIVISION_BY_ZERO, - INTEGER_OVERFLOW, - INTEGER_UNDERFLOW - } - - /** - * @dev Multiplies two numbers, returns an error on overflow. - */ - function mulUInt(uint a, uint b) internal pure returns (MathError, uint) { - if (a == 0) { - return (MathError.NO_ERROR, 0); - } - - uint c = a * b; - - if (c / a != b) { - return (MathError.INTEGER_OVERFLOW, 0); - } else { - return (MathError.NO_ERROR, c); - } - } - - /** - * @dev Integer division of two numbers, truncating the quotient. - */ - function divUInt(uint a, uint b) internal pure returns (MathError, uint) { - if (b == 0) { - return (MathError.DIVISION_BY_ZERO, 0); - } - - return (MathError.NO_ERROR, a / b); - } - - /** - * @dev Subtracts two numbers, returns an error on overflow (i.e. if subtrahend is greater than minuend). - */ - function subUInt(uint a, uint b) internal pure returns (MathError, uint) { - if (b <= a) { - return (MathError.NO_ERROR, a - b); - } else { - return (MathError.INTEGER_UNDERFLOW, 0); - } - } - - /** - * @dev Adds two numbers, returns an error on overflow. - */ - function addUInt(uint a, uint b) internal pure returns (MathError, uint) { - uint c = a + b; - - if (c >= a) { - return (MathError.NO_ERROR, c); - } else { - return (MathError.INTEGER_OVERFLOW, 0); - } - } - - /** - * @dev add a and b and then subtract c - */ - function addThenSubUInt(uint a, uint b, uint c) internal pure returns (MathError, uint) { - (MathError err0, uint sum) = addUInt(a, b); - - if (err0 != MathError.NO_ERROR) { - return (err0, 0); - } - - return subUInt(sum, c); - } -} diff --git a/flatten/Comptroller.sol b/flatten/Comptroller.sol deleted file mode 100644 index 481ac4d..0000000 --- a/flatten/Comptroller.sol +++ /dev/null @@ -1,6443 +0,0 @@ -// Dependency file: contracts/ComptrollerInterface.sol - -// SPDX-License-Identifier: UNLICENSED -// pragma solidity 0.8.6; - -abstract contract ComptrollerInterface { - /// @notice Indicator that this is a Comptroller contract (for inspection) - bool public constant isComptroller = true; - - /*** Assets You Are In ***/ - - function enterMarkets(address[] calldata cTokens) - external - virtual - returns (uint256[] memory); - - function exitMarket(address cToken) external virtual returns (uint256); - - /*** Policy Hooks ***/ - - function mintAllowed( - address cToken, - address minter, - uint256 mintAmount - ) external virtual returns (uint256); - - function mintVerify( - address cToken, - address minter, - uint256 mintAmount, - uint256 mintTokens - ) external virtual; - - function redeemAllowed( - address cToken, - address redeemer, - uint256 redeemTokens - ) external virtual returns (uint256); - - function redeemVerify( - address cToken, - address redeemer, - uint256 redeemAmount, - uint256 redeemTokens - ) external virtual; - - function borrowAllowed( - address cToken, - address borrower, - uint256 borrowAmount - ) external virtual returns (uint256); - - function borrowVerify( - address cToken, - address borrower, - uint256 borrowAmount - ) external virtual; - - function repayBorrowAllowed( - address cToken, - address payer, - address borrower, - uint256 repayAmount - ) external virtual returns (uint256); - - function repayBorrowVerify( - address cToken, - address payer, - address borrower, - uint256 repayAmount, - uint256 borrowerIndex - ) external virtual; - - function liquidateBorrowAllowed( - address cTokenBorrowed, - address cTokenCollateral, - address liquidator, - address borrower, - uint256 repayAmount - ) external virtual returns (uint256); - - function liquidateBorrowVerify( - address cTokenBorrowed, - address cTokenCollateral, - address liquidator, - address borrower, - uint256 repayAmount, - uint256 seizeTokens - ) external virtual; - - function seizeAllowed( - address cTokenCollateral, - address cTokenBorrowed, - address liquidator, - address borrower, - uint256 seizeTokens - ) external virtual returns (uint256); - - function seizeVerify( - address cTokenCollateral, - address cTokenBorrowed, - address liquidator, - address borrower, - uint256 seizeTokens - ) external virtual; - - function transferAllowed( - address cToken, - address src, - address dst, - uint256 transferTokens - ) external virtual returns (uint256); - - function transferVerify( - address cToken, - address src, - address dst, - uint256 transferTokens - ) external virtual; - - /*** Liquidity/Liquidation Calculations ***/ - - function liquidateCalculateSeizeTokens( - address cTokenBorrowed, - address cTokenCollateral, - uint256 repayAmount - ) external view virtual returns (uint256, uint256); -} - - -// Dependency file: contracts/CarefulMath.sol - -// pragma solidity 0.8.6; - -/** - * @title Careful Math - * @author tropykus - * @notice Derived from OpenZeppelin's SafeMath library - * https://github.com/OpenZeppelin/openzeppelin-solidity/blob/master/contracts/math/SafeMath.sol - */ -contract CarefulMath { - - /** - * @dev Possible error codes that we can return - */ - enum MathError { - NO_ERROR, - DIVISION_BY_ZERO, - INTEGER_OVERFLOW, - INTEGER_UNDERFLOW - } - - /** - * @dev Multiplies two numbers, returns an error on overflow. - */ - function mulUInt(uint a, uint b) internal pure returns (MathError, uint) { - if (a == 0) { - return (MathError.NO_ERROR, 0); - } - - uint c = a * b; - - if (c / a != b) { - return (MathError.INTEGER_OVERFLOW, 0); - } else { - return (MathError.NO_ERROR, c); - } - } - - /** - * @dev Integer division of two numbers, truncating the quotient. - */ - function divUInt(uint a, uint b) internal pure returns (MathError, uint) { - if (b == 0) { - return (MathError.DIVISION_BY_ZERO, 0); - } - - return (MathError.NO_ERROR, a / b); - } - - /** - * @dev Subtracts two numbers, returns an error on overflow (i.e. if subtrahend is greater than minuend). - */ - function subUInt(uint a, uint b) internal pure returns (MathError, uint) { - if (b <= a) { - return (MathError.NO_ERROR, a - b); - } else { - return (MathError.INTEGER_UNDERFLOW, 0); - } - } - - /** - * @dev Adds two numbers, returns an error on overflow. - */ - function addUInt(uint a, uint b) internal pure returns (MathError, uint) { - uint c = a + b; - - if (c >= a) { - return (MathError.NO_ERROR, c); - } else { - return (MathError.INTEGER_OVERFLOW, 0); - } - } - - /** - * @dev add a and b and then subtract c - */ - function addThenSubUInt(uint a, uint b, uint c) internal pure returns (MathError, uint) { - (MathError err0, uint sum) = addUInt(a, b); - - if (err0 != MathError.NO_ERROR) { - return (err0, 0); - } - - return subUInt(sum, c); - } -} - - -// Dependency file: contracts/ExponentialNoError.sol - -// pragma solidity 0.8.6; - -/** - * @title Exponential module for storing fixed-precision decimals - * @author tropykus - * @notice Exp is a struct which stores decimals with a fixed precision of 18 decimal places. - * Thus, if we wanted to store the 5.1, mantissa would store 5.1e18. That is: - * `Exp({mantissa: 5100000000000000000})`. - */ -contract ExponentialNoError { - uint constant expScale = 1e18; - uint constant doubleScale = 1e36; - uint constant halfExpScale = expScale/2; - uint constant mantissaOne = expScale; - - struct Exp { - uint mantissa; - } - - struct Double { - uint mantissa; - } - - /** - * @dev Truncates the given exp to a whole number value. - * For example, truncate(Exp{mantissa: 15 * expScale}) = 15 - */ - function truncate(Exp memory exp) pure internal returns (uint) { - // Note: We are not using careful math here as we're performing a division that cannot fail - return exp.mantissa / expScale; - } - - /** - * @dev Multiply an Exp by a scalar, then truncate to return an unsigned integer. - */ - function mul_ScalarTruncate(Exp memory a, uint scalar) pure internal returns (uint) { - Exp memory product = mul_(a, scalar); - return truncate(product); - } - - /** - * @dev Multiply an Exp by a scalar, truncate, then add an to an unsigned integer, returning an unsigned integer. - */ - function mul_ScalarTruncateAddUInt(Exp memory a, uint scalar, uint addend) pure internal returns (uint) { - Exp memory product = mul_(a, scalar); - return add_(truncate(product), addend); - } - - /** - * @dev Checks if first Exp is less than second Exp. - */ - function lessThanExp(Exp memory left, Exp memory right) pure internal returns (bool) { - return left.mantissa < right.mantissa; - } - - /** - * @dev Checks if left Exp <= right Exp. - */ - function lessThanOrEqualExp(Exp memory left, Exp memory right) pure internal returns (bool) { - return left.mantissa <= right.mantissa; - } - - /** - * @dev Checks if left Exp > right Exp. - */ - function greaterThanExp(Exp memory left, Exp memory right) pure internal returns (bool) { - return left.mantissa > right.mantissa; - } - - /** - * @dev returns true if Exp is exactly zero - */ - function isZeroExp(Exp memory value) pure internal returns (bool) { - return value.mantissa == 0; - } - - function safe224(uint n, string memory errorMessage) pure internal returns (uint224) { - require(n < 2**224, errorMessage); - return uint224(n); - } - - function safe32(uint n, string memory errorMessage) pure internal returns (uint32) { - require(n < 2**32, errorMessage); - return uint32(n); - } - - function add_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { - return Exp({mantissa: add_(a.mantissa, b.mantissa)}); - } - - function add_(Double memory a, Double memory b) pure internal returns (Double memory) { - return Double({mantissa: add_(a.mantissa, b.mantissa)}); - } - - function add_(uint a, uint b) pure internal returns (uint) { - return add_(a, b, "addition overflow"); - } - - function add_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { - uint c = a + b; - require(c >= a, errorMessage); - return c; - } - - function sub_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { - return Exp({mantissa: sub_(a.mantissa, b.mantissa)}); - } - - function sub_(Double memory a, Double memory b) pure internal returns (Double memory) { - return Double({mantissa: sub_(a.mantissa, b.mantissa)}); - } - - function sub_(uint a, uint b) pure internal returns (uint) { - return sub_(a, b, "subtraction underflow"); - } - - function sub_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { - require(b <= a, errorMessage); - return a - b; - } - - function mul_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { - return Exp({mantissa: mul_(a.mantissa, b.mantissa) / expScale}); - } - - function mul_(Exp memory a, uint b) pure internal returns (Exp memory) { - return Exp({mantissa: mul_(a.mantissa, b)}); - } - - function mul_(uint a, Exp memory b) pure internal returns (uint) { - return mul_(a, b.mantissa) / expScale; - } - - function mul_(Double memory a, Double memory b) pure internal returns (Double memory) { - return Double({mantissa: mul_(a.mantissa, b.mantissa) / doubleScale}); - } - - function mul_(Double memory a, uint b) pure internal returns (Double memory) { - return Double({mantissa: mul_(a.mantissa, b)}); - } - - function mul_(uint a, Double memory b) pure internal returns (uint) { - return mul_(a, b.mantissa) / doubleScale; - } - - function mul_(uint a, uint b) pure internal returns (uint) { - return mul_(a, b, "multiplication overflow"); - } - - function mul_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { - if (a == 0 || b == 0) { - return 0; - } - uint c = a * b; - require(c / a == b, errorMessage); - return c; - } - - function div_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { - return Exp({mantissa: div_(mul_(a.mantissa, expScale), b.mantissa)}); - } - - function div_(Exp memory a, uint b) pure internal returns (Exp memory) { - return Exp({mantissa: div_(a.mantissa, b)}); - } - - function div_(uint a, Exp memory b) pure internal returns (uint) { - return div_(mul_(a, expScale), b.mantissa); - } - - function div_(Double memory a, Double memory b) pure internal returns (Double memory) { - return Double({mantissa: div_(mul_(a.mantissa, doubleScale), b.mantissa)}); - } - - function div_(Double memory a, uint b) pure internal returns (Double memory) { - return Double({mantissa: div_(a.mantissa, b)}); - } - - function div_(uint a, Double memory b) pure internal returns (uint) { - return div_(mul_(a, doubleScale), b.mantissa); - } - - function div_(uint a, uint b) pure internal returns (uint) { - return div_(a, b, "divide by zero"); - } - - function div_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { - require(b > 0, errorMessage); - return a / b; - } - - function fraction(uint a, uint b) pure internal returns (Double memory) { - return Double({mantissa: div_(mul_(a, doubleScale), b)}); - } -} - - -// Dependency file: contracts/Exponential.sol - -// pragma solidity 0.8.6; - -// import "contracts/CarefulMath.sol"; -// import "contracts/ExponentialNoError.sol"; - -/** - * @title Exponential module for storing fixed-precision decimals - * @author tropykus - * @dev Legacy contract for compatibility reasons with existing contracts that still use MathError - * @notice Exp is a struct which stores decimals with a fixed precision of 18 decimal places. - * Thus, if we wanted to store the 5.1, mantissa would store 5.1e18. That is: - * `Exp({mantissa: 5100000000000000000})`. - */ -contract Exponential is CarefulMath, ExponentialNoError { - /** - * @dev Creates an exponential from numerator and denominator values. - * Note: Returns an error if (`num` * 10e18) > MAX_INT, - * or if `denom` is zero. - */ - function getExp(uint num, uint denom) internal pure returns (MathError, Exp memory) { - (MathError err0, uint scaledNumerator) = mulUInt(num, expScale); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - - (MathError err1, uint rational) = divUInt(scaledNumerator, denom); - if (err1 != MathError.NO_ERROR) { - return (err1, Exp({mantissa: 0})); - } - - return (MathError.NO_ERROR, Exp({mantissa: rational})); - } - - /** - * @dev Adds two exponentials, returning a new exponential. - */ - function addExp(Exp memory a, Exp memory b) internal pure returns (MathError, Exp memory) { - (MathError error, uint result) = addUInt(a.mantissa, b.mantissa); - - return (error, Exp({mantissa: result})); - } - - /** - * @dev Subtracts two exponentials, returning a new exponential. - */ - function subExp(Exp memory a, Exp memory b) internal pure returns (MathError, Exp memory) { - (MathError error, uint result) = subUInt(a.mantissa, b.mantissa); - - return (error, Exp({mantissa: result})); - } - - /** - * @dev Multiply an Exp by a scalar, returning a new Exp. - */ - function mulScalar(Exp memory a, uint scalar) internal pure returns (MathError, Exp memory) { - (MathError err0, uint scaledMantissa) = mulUInt(a.mantissa, scalar); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - - return (MathError.NO_ERROR, Exp({mantissa: scaledMantissa})); - } - - /** - * @dev Multiply an Exp by a scalar, then truncate to return an unsigned integer. - */ - function mulScalarTruncate(Exp memory a, uint scalar) internal pure returns (MathError, uint) { - (MathError err, Exp memory product) = mulScalar(a, scalar); - if (err != MathError.NO_ERROR) { - return (err, 0); - } - - return (MathError.NO_ERROR, truncate(product)); - } - - /** - * @dev Multiply an Exp by a scalar, truncate, then add an to an unsigned integer, returning an unsigned integer. - */ - function mulScalarTruncateAddUInt(Exp memory a, uint scalar, uint addend) internal pure returns (MathError, uint) { - (MathError err, Exp memory product) = mulScalar(a, scalar); - if (err != MathError.NO_ERROR) { - return (err, 0); - } - - return addUInt(truncate(product), addend); - } - - /** - * @dev Divide an Exp by a scalar, returning a new Exp. - */ - function divScalar(Exp memory a, uint scalar) internal pure returns (MathError, Exp memory) { - (MathError err0, uint descaledMantissa) = divUInt(a.mantissa, scalar); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - - return (MathError.NO_ERROR, Exp({mantissa: descaledMantissa})); - } - - /** - * @dev Divide a scalar by an Exp, returning a new Exp. - */ - function divScalarByExp(uint scalar, Exp memory divisor) internal pure returns (MathError, Exp memory) { - /* - We are doing this as: - getExp(mulUInt(expScale, scalar), divisor.mantissa) - - How it works: - Exp = a / b; - Scalar = s; - `s / (a / b)` = `b * s / a` and since for an Exp `a = mantissa, b = expScale` - */ - (MathError err0, uint numerator) = mulUInt(expScale, scalar); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - return getExp(numerator, divisor.mantissa); - } - - /** - * @dev Divide a scalar by an Exp, then truncate to return an unsigned integer. - */ - function divScalarByExpTruncate(uint scalar, Exp memory divisor) internal pure returns (MathError, uint) { - (MathError err, Exp memory fraction) = divScalarByExp(scalar, divisor); - if (err != MathError.NO_ERROR) { - return (err, 0); - } - - return (MathError.NO_ERROR, truncate(fraction)); - } - - /** - * @dev Multiplies two exponentials, returning a new exponential. - */ - function mulExp(Exp memory a, Exp memory b) internal pure returns (MathError, Exp memory) { - - (MathError err0, uint doubleScaledProduct) = mulUInt(a.mantissa, b.mantissa); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - - // We add half the scale before dividing so that we get rounding instead of truncation. - // See "Listing 6" and text above it at https://accu.org/index.php/journals/1717 - // Without this change, a result like 6.6...e-19 will be truncated to 0 instead of being rounded to 1e-18. - (MathError err1, uint doubleScaledProductWithHalfScale) = addUInt(halfExpScale, doubleScaledProduct); - if (err1 != MathError.NO_ERROR) { - return (err1, Exp({mantissa: 0})); - } - - (MathError err2, uint product) = divUInt(doubleScaledProductWithHalfScale, expScale); - // The only error `div` can return is MathError.DIVISION_BY_ZERO but we control `expScale` and it is not zero. - assert(err2 == MathError.NO_ERROR); - - return (MathError.NO_ERROR, Exp({mantissa: product})); - } - - /** - * @dev Multiplies two exponentials given their mantissas, returning a new exponential. - */ - function mulExp(uint a, uint b) internal pure returns (MathError, Exp memory) { - return mulExp(Exp({mantissa: a}), Exp({mantissa: b})); - } - - /** - * @dev Multiplies three exponentials, returning a new exponential. - */ - function mulExp3(Exp memory a, Exp memory b, Exp memory c) internal pure returns (MathError, Exp memory) { - (MathError err, Exp memory ab) = mulExp(a, b); - if (err != MathError.NO_ERROR) { - return (err, ab); - } - return mulExp(ab, c); - } - - /** - * @dev Divides two exponentials, returning a new exponential. - * (a/scale) / (b/scale) = (a/scale) * (scale/b) = a/b, - * which we can scale as an Exp by calling getExp(a.mantissa, b.mantissa) - */ - function divExp(Exp memory a, Exp memory b) internal pure returns (MathError, Exp memory) { - return getExp(a.mantissa, b.mantissa); - } -} - - -// Dependency file: contracts/SafeMath.sol - -// pragma solidity 0.8.6; - -// From https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/math/Math.sol -// Subject to the MIT license. - -/** - * @dev Wrappers over Solidity's arithmetic operations with added overflow - * checks. - * - * Arithmetic operations in Solidity wrap on overflow. This can easily result - * in bugs, because programmers usually assume that an overflow raises an - * error, which is the standard behavior in high level programming languages. - * `SafeMath` restores this intuition by reverting the transaction when an - * operation overflows. - * - * Using this library instead of the unchecked operations eliminates an entire - * class of bugs, so it's recommended to use it always. - */ -library SafeMath { - /** - * @dev Returns the addition of two unsigned integers, reverting on overflow. - * - * Counterpart to Solidity's `+` operator. - * - * Requirements: - * - Addition cannot overflow. - */ - function add(uint256 a, uint256 b) internal pure returns (uint256) { - uint256 c = a + b; - require(c >= a, "SafeMath: addition overflow"); - - return c; - } - - /** - * @dev Returns the addition of two unsigned integers, reverting with custom message on overflow. - * - * Counterpart to Solidity's `+` operator. - * - * Requirements: - * - Addition cannot overflow. - */ - function add(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - uint256 c = a + b; - require(c >= a, errorMessage); - - return c; - } - - /** - * @dev Returns the subtraction of two unsigned integers, reverting on underflow (when the result is negative). - * - * Counterpart to Solidity's `-` operator. - * - * Requirements: - * - Subtraction cannot underflow. - */ - function sub(uint256 a, uint256 b) internal pure returns (uint256) { - return sub(a, b, "SafeMath: subtraction underflow"); - } - - /** - * @dev Returns the subtraction of two unsigned integers, reverting with custom message on underflow (when the result is negative). - * - * Counterpart to Solidity's `-` operator. - * - * Requirements: - * - Subtraction cannot underflow. - */ - function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - require(b <= a, errorMessage); - uint256 c = a - b; - - return c; - } - - /** - * @dev Returns the multiplication of two unsigned integers, reverting on overflow. - * - * Counterpart to Solidity's `*` operator. - * - * Requirements: - * - Multiplication cannot overflow. - */ - function mul(uint256 a, uint256 b) internal pure returns (uint256) { - // Gas optimization: this is cheaper than requiring 'a' not being zero, but the - // benefit is lost if 'b' is also tested. - // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 - if (a == 0) { - return 0; - } - - uint256 c = a * b; - require(c / a == b, "SafeMath: multiplication overflow"); - - return c; - } - - /** - * @dev Returns the multiplication of two unsigned integers, reverting on overflow. - * - * Counterpart to Solidity's `*` operator. - * - * Requirements: - * - Multiplication cannot overflow. - */ - function mul(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - // Gas optimization: this is cheaper than requiring 'a' not being zero, but the - // benefit is lost if 'b' is also tested. - // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 - if (a == 0) { - return 0; - } - - uint256 c = a * b; - require(c / a == b, errorMessage); - - return c; - } - - /** - * @dev Returns the integer division of two unsigned integers. - * Reverts on division by zero. The result is rounded towards zero. - * - * Counterpart to Solidity's `/` operator. Note: this function uses a - * `revert` opcode (which leaves remaining gas untouched) while Solidity - * uses an invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function div(uint256 a, uint256 b) internal pure returns (uint256) { - return div(a, b, "SafeMath: division by zero"); - } - - /** - * @dev Returns the integer division of two unsigned integers. - * Reverts with custom message on division by zero. The result is rounded towards zero. - * - * Counterpart to Solidity's `/` operator. Note: this function uses a - * `revert` opcode (which leaves remaining gas untouched) while Solidity - * uses an invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - // Solidity only automatically asserts when dividing by 0 - require(b > 0, errorMessage); - uint256 c = a / b; - // assert(a == b * c + a % b); // There is no case in which this doesn't hold - - return c; - } - - /** - * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), - * Reverts when dividing by zero. - * - * Counterpart to Solidity's `%` operator. This function uses a `revert` - * opcode (which leaves remaining gas untouched) while Solidity uses an - * invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function mod(uint256 a, uint256 b) internal pure returns (uint256) { - return mod(a, b, "SafeMath: modulo by zero"); - } - - /** - * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), - * Reverts with custom message when dividing by zero. - * - * Counterpart to Solidity's `%` operator. This function uses a `revert` - * opcode (which leaves remaining gas untouched) while Solidity uses an - * invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - require(b != 0, errorMessage); - return a % b; - } -} - - -// Dependency file: contracts/InterestRateModel.sol - -// pragma solidity 0.8.6; - -// import "contracts/Exponential.sol"; -// import "contracts/SafeMath.sol"; - -/** - * @title tropykus InterestRateModel Interface - * @author tropykus - */ -abstract contract InterestRateModel is Exponential { - using SafeMath for uint256; - - /// @notice Indicator that this is an InterestRateModel contract (for inspection) - bool public constant isInterestRateModel = true; - bool public isTropykusInterestRateModel; - - /** - * @notice The approximate number of blocks per year that is assumed by the interest rate model - */ - uint256 public constant blocksPerYear = 1051200; - - /** - * @notice Calculates the utilization rate of the market: `borrows / (cash + borrows - reserves)` - * @param cash The amount of cash in the market - * @param borrows The amount of borrows in the market - * @param reserves The amount of reserves in the market (currently unused) - * @return The utilization rate as a mantissa between [0, 1e18] - */ - function utilizationRate( - uint256 cash, - uint256 borrows, - uint256 reserves - ) public pure virtual returns (uint256) { - // Utilization rate is 0 when there are no borrows - if (borrows == 0) { - return 0; - } - - return borrows.mul(1e18).div(cash.add(borrows).sub(reserves)); - } - - /** - * @notice Calculates the current borrow interest rate per block - * @param cash The total amount of cash the market has - * @param borrows The total amount of borrows the market has outstanding - * @param reserves The total amnount of reserves the market has - * @return The borrow rate per block (as a percentage, and scaled by 1e18) - */ - function getBorrowRate( - uint256 cash, - uint256 borrows, - uint256 reserves - ) external view virtual returns (uint256); - - /** - * @notice Calculates the current supply interest rate per block - * @param cash The total amount of cash the market has - * @param borrows The total amount of borrows the market has outstanding - * @param reserves The total amnount of reserves the market has - * @param reserveFactorMantissa The current reserve factor the market has - * @return The supply rate per block (as a percentage, and scaled by 1e18) - */ - function getSupplyRate( - uint256 cash, - uint256 borrows, - uint256 reserves, - uint256 reserveFactorMantissa - ) external view virtual returns (uint256); - - function getExchangeRate( - uint256 _totalCash, - uint256 _totalBorrows, - uint256 _totalReserves, - uint256 _totalSupply - ) public pure returns (MathError, uint256) { - /* - * exchangeRate = (totalCash + totalBorrows - totalReserves) / totalSupply - */ - Exp memory exchangeRate; - MathError mathErr; - uint256 cashPlusBorrowsMinusReserves; - (mathErr, cashPlusBorrowsMinusReserves) = addThenSubUInt( - _totalCash, - _totalBorrows, - _totalReserves - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - (mathErr, exchangeRate) = getExp( - cashPlusBorrowsMinusReserves, - _totalSupply - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - - return (MathError.NO_ERROR, exchangeRate.mantissa); - } - - function isAboveOptimal( - uint256 cash, - uint256 borrows, - uint256 reserves - ) public view virtual returns (bool) { - cash; - borrows; - reserves; - return false; - } -} - - -// Dependency file: contracts/EIP20NonStandardInterface.sol - -// pragma solidity 0.8.6; - -/** - * @title EIP20NonStandardInterface - * @dev Version of ERC20 with no return values for `transfer` and `transferFrom` - * See https://medium.com/coinmonks/missing-return-value-bug-at-least-130-tokens-affected-d67bf08521ca - */ -interface EIP20NonStandardInterface { - /** - * @notice Get the total number of tokens in circulation - * @return The supply of tokens - */ - function totalSupply() external view returns (uint256); - - /** - * @notice Gets the balance of the specified address - * @param owner The address from which the balance will be retrieved - * @return balance The balance - */ - function balanceOf(address owner) external view returns (uint256 balance); - - /// - /// !!!!!!!!!!!!!! - /// !!! NOTICE !!! `transfer` does not return a value, in violation of the ERC-20 specification - /// !!!!!!!!!!!!!! - /// - - /** - * @notice Transfer `amount` tokens from `msg.sender` to `dst` - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - */ - function transfer(address dst, uint256 amount) external; - - /// - /// !!!!!!!!!!!!!! - /// !!! NOTICE !!! `transferFrom` does not return a value, in violation of the ERC-20 specification - /// !!!!!!!!!!!!!! - /// - - /** - * @notice Transfer `amount` tokens from `src` to `dst` - * @param src The address of the source account - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - */ - function transferFrom( - address src, - address dst, - uint256 amount - ) external; - - /** - * @notice Approve `spender` to transfer up to `amount` from `src` - * @dev This will overwrite the approval amount for `spender` - * and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve) - * @param spender The address of the account which may transfer tokens - * @param amount The number of tokens that are approved - * @return success Whether or not the approval succeeded - */ - function approve(address spender, uint256 amount) - external - returns (bool success); - - /** - * @notice Get the current allowance from `owner` for `spender` - * @param owner The address of the account which owns the tokens to be spent - * @param spender The address of the account which may transfer tokens - * @return remaining The number of tokens allowed to be spent - */ - function allowance(address owner, address spender) - external - view - returns (uint256 remaining); - - event Transfer(address indexed from, address indexed to, uint256 amount); - event Approval( - address indexed owner, - address indexed spender, - uint256 amount - ); -} - - -// Dependency file: contracts/CTokenInterfaces.sol - -// pragma solidity 0.8.6; - -// import "contracts/ComptrollerInterface.sol"; -// import "contracts/InterestRateModel.sol"; -// import "contracts/EIP20NonStandardInterface.sol"; - -contract CTokenStorage { - /** - * @dev Guard variable for re-entrancy checks - */ - bool internal _notEntered; - - /** - * @notice EIP-20 token name for this token - */ - string public name; - - /** - * @notice EIP-20 token symbol for this token - */ - string public symbol; - - /** - * @notice EIP-20 token decimals for this token - */ - uint8 public decimals; - - /** - * @notice Maximum borrow rate that can ever be applied (.0005% / block) - */ - - uint256 internal constant borrowRateMaxMantissa = 0.0005e16; - - /** - * @notice Maximum fraction of interest that can be set aside for reserves - */ - uint256 internal constant reserveFactorMaxMantissa = 1e18; - - /** - * @notice Administrator for this contract - */ - address payable public admin; - - /** - * @notice Pending administrator for this contract - */ - address payable public pendingAdmin; - - /** - * @notice Contract which oversees inter-cToken operations - */ - ComptrollerInterface public comptroller; - - /** - * @notice Model which tells what the current interest rate should be - */ - InterestRateModel public interestRateModel; - - /** - * @notice Initial exchange rate used when minting the first CTokens (used when totalSupply = 0) - */ - uint256 public initialExchangeRateMantissa; - - /** - * @notice Fraction of interest currently set aside for reserves - */ - uint256 public reserveFactorMantissa; - - /** - * @notice Block number that interest was last accrued at - */ - uint256 public accrualBlockNumber; - - /** - * @notice Accumulator of the total earned interest rate since the opening of the market - */ - uint256 public borrowIndex; - - /** - * @notice Total amount of outstanding borrows of the underlying in this market - */ - uint256 public totalBorrows; - - /** - * @notice Total amount of reserves of the underlying held in this market - */ - uint256 public totalReserves; - - /** - * @notice Total number of tokens in circulation - */ - uint256 public totalSupply; - - uint256 public subsidyFund; - - struct SupplySnapshot { - uint256 tokens; - uint256 underlyingAmount; - uint256 suppliedAt; - uint256 promisedSupplyRate; - } - - /** - * @notice Official record of token balances for each account - */ - mapping(address => SupplySnapshot) internal accountTokens; - - /** - * @notice Approved token transfer amounts on behalf of others - */ - mapping(address => mapping(address => uint256)) internal transferAllowances; - - /** - * @notice Container for borrow balance information - * @member principal Total balance (with accrued interest), after applying the most recent balance-changing action - * @member interestIndex Global borrowIndex as of the most recent balance-changing action - */ - struct BorrowSnapshot { - uint256 principal; - uint256 interestIndex; - } - - /** - * @notice Mapping of account addresses to outstanding borrow balances - */ - mapping(address => BorrowSnapshot) internal accountBorrows; -} - -abstract contract CTokenInterface is CTokenStorage { - /** - * @notice Indicator that this is a CToken contract (for inspection) - */ - bool public constant isCToken = true; - - /*** Market Events ***/ - - /** - * @notice Event emitted when interest is accrued - */ - event AccrueInterest( - uint256 cashPrior, - uint256 interestAccumulated, - uint256 borrowIndex, - uint256 totalBorrows - ); - - /** - * @notice Event emitted when tokens are minted - */ - event Mint(address indexed minter, uint256 mintAmount, uint256 mintTokens); - - /** - * @notice Event emitted when tokens are redeemed - */ - event Redeem( - address indexed redeemer, - uint256 redeemAmount, - uint256 redeemTokens - ); - - /** - * @notice Event emitted when underlying is borrowed - */ - event Borrow( - address indexed borrower, - uint256 borrowAmount, - uint256 accountBorrows, - uint256 totalBorrows - ); - - /** - * @notice Event emitted when a borrow is repaid - */ - event RepayBorrow( - address indexed payer, - address indexed borrower, - uint256 repayAmount, - uint256 accountBorrows, - uint256 totalBorrows - ); - - /** - * @notice Event emitted when a borrow is liquidated - */ - event LiquidateBorrow( - address indexed liquidator, - address indexed borrower, - uint256 repayAmount, - address indexed cTokenCollateral, - uint256 seizeTokens - ); - - /*** Admin Events ***/ - - /** - * @notice Event emitted when pendingAdmin is changed - */ - event NewPendingAdmin(address oldPendingAdmin, address newPendingAdmin); - - /** - * @notice Event emitted when pendingAdmin is accepted, which means admin is updated - */ - event NewAdmin(address oldAdmin, address newAdmin); - - /** - * @notice Event emitted when comptroller is changed - */ - event NewComptroller( - ComptrollerInterface oldComptroller, - ComptrollerInterface newComptroller - ); - - /** - * @notice Event emitted when interestRateModel is changed - */ - event NewMarketInterestRateModel( - InterestRateModel oldInterestRateModel, - InterestRateModel newInterestRateModel - ); - - /** - * @notice Event emitted when the reserve factor is changed - */ - event NewReserveFactor( - uint256 oldReserveFactorMantissa, - uint256 newReserveFactorMantissa - ); - - /** - * @notice Event emitted when the reserves are added - */ - event ReservesAdded( - address benefactor, - uint256 addAmount, - uint256 newTotalReserves - ); - - event SubsidyAdded( - address benefactor, - uint256 addAmount, - uint256 newSubsidyFund - ); - - /** - * @notice Event emitted when the reserves are reduced - */ - event ReservesReduced( - address admin, - uint256 reduceAmount, - uint256 newTotalReserves - ); - - /** - * @notice EIP20 Transfer event - */ - event Transfer(address indexed from, address indexed to, uint256 amount); - - /** - * @notice EIP20 Approval event - */ - event Approval( - address indexed owner, - address indexed spender, - uint256 amount - ); - - /** - * @notice Failure event - */ - event CTokenStorageFailure(uint256 error, uint256 info, uint256 detail); - - /*** User Interface ***/ - - function transfer(address dst, uint256 amount) - external - virtual - returns (bool); - - function transferFrom( - address src, - address dst, - uint256 amount - ) external virtual returns (bool); - - function approve(address spender, uint256 amount) - external - virtual - returns (bool); - - function allowance(address owner, address spender) - external - view - virtual - returns (uint256); - - function balanceOf(address owner) external view virtual returns (uint256); - - function balanceOfUnderlying(address owner) - external - virtual - returns (uint256); - - function getAccountSnapshot(address account) - external - view - virtual - returns ( - uint256, - uint256, - uint256, - uint256 - ); - - function borrowRatePerBlock() external view virtual returns (uint256); - - function supplyRatePerBlock() external view virtual returns (uint256); - - function totalBorrowsCurrent() external virtual returns (uint256); - - function borrowBalanceCurrent(address account) - external - virtual - returns (uint256); - - function borrowBalanceStored(address account) - public - view - virtual - returns (uint256); - - function exchangeRateCurrent() public virtual returns (uint256); - - function exchangeRateStored() public view virtual returns (uint256); - - function getCash() external view virtual returns (uint256); - - function accrueInterest() public virtual returns (uint256); - - function seize( - address liquidator, - address borrower, - uint256 seizeTokens - ) external virtual returns (uint256); - - /*** Admin Functions ***/ - - function _setPendingAdmin(address payable newPendingAdmin) - external - virtual - returns (uint256); - - function _acceptAdmin() external virtual returns (uint256); - - function _setComptroller(ComptrollerInterface newComptroller) - public - virtual - returns (uint256); - - function _setReserveFactor(uint256 newReserveFactorMantissa) - external - virtual - returns (uint256); - - function _reduceReserves(uint256 reduceAmount) - external - virtual - returns (uint256); - - function _setInterestRateModel(InterestRateModel newInterestRateModel) - public - virtual - returns (uint256); -} - -contract CErc20Storage { - /** - * @notice Underlying asset for this CToken - */ - address public underlying; -} - -abstract contract CErc20Interface is CErc20Storage { - /*** User Interface ***/ - - function mint(uint256 mintAmount) external virtual returns (uint256); - - function redeem(uint256 redeemAmount) - external - virtual - returns (uint256); - - function borrow(uint256 borrowAmount) external virtual returns (uint256); - - function repayBorrow(uint256 repayAmount) - external - virtual - returns (uint256); - - function liquidateBorrow( - address borrower, - uint256 repayAmount, - CTokenInterface cTokenCollateral - ) external virtual returns (uint256); - - function sweepToken(EIP20NonStandardInterface token) external virtual; - - /*** Admin Functions ***/ - - function _addReserves(uint256 addAmount) external virtual returns (uint256); -} - -contract CDelegationStorage { - /** - * @notice Implementation address for this contract - */ - address public implementation; -} - -abstract contract CDelegatorInterface is CDelegationStorage { - /** - * @notice Emitted when implementation is changed - */ - event NewImplementation( - address oldImplementation, - address newImplementation - ); - - /** - * @notice Called by the admin to update the implementation of the delegator - * @param implementation_ The address of the new implementation for delegation - * @param allowResign Flag to indicate whether to call _resignImplementation on the old implementation - * @param becomeImplementationData The encoded bytes data to be passed to _becomeImplementation - */ - function _setImplementation( - address implementation_, - bool allowResign, - bytes memory becomeImplementationData - ) public virtual; -} - -abstract contract CDelegateInterface is CDelegationStorage { - /** - * @notice Called by the delegator on a delegate to initialize it for duty - * @dev Should revert if any issues arise which make it unfit for delegation - * @param data The encoded bytes data for any initialization - */ - function _becomeImplementation(bytes memory data) public virtual; - - /** - * @notice Called by the delegator on a delegate to forfeit its responsibility - */ - function _resignImplementation() public virtual; -} - - -// Dependency file: contracts/ErrorReporter.sol - -// pragma solidity 0.8.6; - -contract ComptrollerErrorReporter { - enum Error { - NO_ERROR, - UNAUTHORIZED, - COMPTROLLER_MISMATCH, - INSUFFICIENT_SHORTFALL, - INSUFFICIENT_LIQUIDITY, - INVALID_CLOSE_FACTOR, - INVALID_COLLATERAL_FACTOR, - INVALID_LIQUIDATION_INCENTIVE, - MARKET_NOT_ENTERED, // no longer possible - MARKET_NOT_LISTED, - MARKET_ALREADY_LISTED, - MATH_ERROR, - NONZERO_BORROW_BALANCE, - PRICE_ERROR, - REJECTION, - SNAPSHOT_ERROR, - TOO_MANY_ASSETS, - TOO_MUCH_REPAY - } - - enum FailureInfo { - ACCEPT_ADMIN_PENDING_ADMIN_CHECK, - ACCEPT_PENDING_IMPLEMENTATION_ADDRESS_CHECK, - EXIT_MARKET_BALANCE_OWED, - EXIT_MARKET_REJECTION, - SET_CLOSE_FACTOR_OWNER_CHECK, - SET_CLOSE_FACTOR_VALIDATION, - SET_COLLATERAL_FACTOR_OWNER_CHECK, - SET_COLLATERAL_FACTOR_NO_EXISTS, - SET_COLLATERAL_FACTOR_VALIDATION, - SET_COLLATERAL_FACTOR_WITHOUT_PRICE, - SET_IMPLEMENTATION_OWNER_CHECK, - SET_LIQUIDATION_INCENTIVE_OWNER_CHECK, - SET_LIQUIDATION_INCENTIVE_VALIDATION, - SET_MAX_ASSETS_OWNER_CHECK, - SET_PENDING_ADMIN_OWNER_CHECK, - SET_PENDING_IMPLEMENTATION_OWNER_CHECK, - SET_PRICE_ORACLE_OWNER_CHECK, - SUPPORT_MARKET_EXISTS, - SUPPORT_MARKET_OWNER_CHECK, - SET_PAUSE_GUARDIAN_OWNER_CHECK - } - - /** - * @dev `error` corresponds to enum Error; `info` corresponds to enum FailureInfo, and `detail` is an arbitrary - * contract-specific code that enables us to report opaque error codes from upgradeable contracts. - **/ - event Failure(uint256 error, uint256 info, uint256 detail); - - /** - * @dev use this when reporting a known error from the money market or a non-upgradeable collaborator - */ - function fail(Error err, FailureInfo info) internal returns (uint256) { - emit Failure(uint256(err), uint256(info), 0); - - return uint256(err); - } - - /** - * @dev use this when reporting an opaque error from an upgradeable collaborator contract - */ - function failOpaque( - Error err, - FailureInfo info, - uint256 opaqueError - ) internal returns (uint256) { - emit Failure(uint256(err), uint256(info), opaqueError); - - return uint256(err); - } -} - -contract TokenErrorReporter { - enum Error { - NO_ERROR, - UNAUTHORIZED, - BAD_INPUT, - COMPTROLLER_REJECTION, - COMPTROLLER_CALCULATION_ERROR, - INTEREST_RATE_MODEL_ERROR, - INVALID_ACCOUNT_PAIR, - INVALID_CLOSE_AMOUNT_REQUESTED, - INVALID_COLLATERAL_FACTOR, - MATH_ERROR, - MARKET_NOT_FRESH, - MARKET_NOT_LISTED, - TOKEN_INSUFFICIENT_ALLOWANCE, - TOKEN_INSUFFICIENT_BALANCE, - TOKEN_INSUFFICIENT_CASH, - TOKEN_TRANSFER_IN_FAILED, - TOKEN_TRANSFER_OUT_FAILED - } - - /* - * Note: FailureInfo (but not Error) is kept in alphabetical order - * This is because FailureInfo grows significantly faster, and - * the order of Error has some meaning, while the order of FailureInfo - * is entirely arbitrary. - */ - enum FailureInfo { - ACCEPT_ADMIN_PENDING_ADMIN_CHECK, - ACCRUE_INTEREST_ACCUMULATED_INTEREST_CALCULATION_FAILED, - ACCRUE_INTEREST_BORROW_RATE_CALCULATION_FAILED, - ACCRUE_INTEREST_NEW_BORROW_INDEX_CALCULATION_FAILED, - ACCRUE_INTEREST_NEW_TOTAL_BORROWS_CALCULATION_FAILED, - ACCRUE_INTEREST_NEW_TOTAL_RESERVES_CALCULATION_FAILED, - ACCRUE_INTEREST_SIMPLE_INTEREST_FACTOR_CALCULATION_FAILED, - BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED, - BORROW_ACCRUE_INTEREST_FAILED, - BORROW_CASH_NOT_AVAILABLE, - BORROW_FRESHNESS_CHECK, - BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED, - BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED, - BORROW_MARKET_NOT_LISTED, - BORROW_COMPTROLLER_REJECTION, - LIQUIDATE_ACCRUE_BORROW_INTEREST_FAILED, - LIQUIDATE_ACCRUE_COLLATERAL_INTEREST_FAILED, - LIQUIDATE_COLLATERAL_FRESHNESS_CHECK, - LIQUIDATE_COMPTROLLER_REJECTION, - LIQUIDATE_COMPTROLLER_CALCULATE_AMOUNT_SEIZE_FAILED, - LIQUIDATE_CLOSE_AMOUNT_IS_UINT_MAX, - LIQUIDATE_CLOSE_AMOUNT_IS_ZERO, - LIQUIDATE_FRESHNESS_CHECK, - LIQUIDATE_LIQUIDATOR_IS_BORROWER, - LIQUIDATE_REPAY_BORROW_FRESH_FAILED, - LIQUIDATE_SEIZE_BALANCE_INCREMENT_FAILED, - LIQUIDATE_SEIZE_BALANCE_DECREMENT_FAILED, - LIQUIDATE_SEIZE_COMPTROLLER_REJECTION, - LIQUIDATE_SEIZE_LIQUIDATOR_IS_BORROWER, - LIQUIDATE_SEIZE_TOO_MUCH, - MINT_ACCRUE_INTEREST_FAILED, - MINT_COMPTROLLER_REJECTION, - MINT_EXCHANGE_CALCULATION_FAILED, - MINT_EXCHANGE_RATE_READ_FAILED, - MINT_FRESHNESS_CHECK, - MINT_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED, - MINT_NEW_TOTAL_SUPPLY_CALCULATION_FAILED, - MINT_TRANSFER_IN_FAILED, - MINT_TRANSFER_IN_NOT_POSSIBLE, - REDEEM_ACCRUE_INTEREST_FAILED, - REDEEM_COMPTROLLER_REJECTION, - REDEEM_EXCHANGE_TOKENS_CALCULATION_FAILED, - REDEEM_EXCHANGE_AMOUNT_CALCULATION_FAILED, - REDEEM_EXCHANGE_RATE_READ_FAILED, - REDEEM_FRESHNESS_CHECK, - REDEEM_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED, - REDEEM_NEW_TOTAL_SUPPLY_CALCULATION_FAILED, - REDEEM_TRANSFER_OUT_NOT_POSSIBLE, - REDUCE_RESERVES_ACCRUE_INTEREST_FAILED, - REDUCE_RESERVES_ADMIN_CHECK, - REDUCE_RESERVES_CASH_NOT_AVAILABLE, - REDUCE_RESERVES_FRESH_CHECK, - REDUCE_RESERVES_VALIDATION, - REPAY_BEHALF_ACCRUE_INTEREST_FAILED, - REPAY_BORROW_ACCRUE_INTEREST_FAILED, - REPAY_BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED, - REPAY_BORROW_COMPTROLLER_REJECTION, - REPAY_BORROW_FRESHNESS_CHECK, - REPAY_BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED, - REPAY_BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED, - REPAY_BORROW_TRANSFER_IN_NOT_POSSIBLE, - SET_COLLATERAL_FACTOR_OWNER_CHECK, - SET_COLLATERAL_FACTOR_VALIDATION, - SET_COMPTROLLER_OWNER_CHECK, - SET_INTEREST_RATE_MODEL_ACCRUE_INTEREST_FAILED, - SET_INTEREST_RATE_MODEL_FRESH_CHECK, - SET_INTEREST_RATE_MODEL_OWNER_CHECK, - SET_MAX_ASSETS_OWNER_CHECK, - SET_ORACLE_MARKET_NOT_LISTED, - SET_PENDING_ADMIN_OWNER_CHECK, - SET_RESERVE_FACTOR_ACCRUE_INTEREST_FAILED, - SET_RESERVE_FACTOR_ADMIN_CHECK, - SET_RESERVE_FACTOR_FRESH_CHECK, - SET_RESERVE_FACTOR_BOUNDS_CHECK, - TRANSFER_COMPTROLLER_REJECTION, - TRANSFER_NOT_ALLOWED, - TRANSFER_NOT_ENOUGH, - TRANSFER_TOO_MUCH, - ADD_RESERVES_ACCRUE_INTEREST_FAILED, - ADD_RESERVES_FRESH_CHECK, - ADD_RESERVES_TRANSFER_IN_NOT_POSSIBLE, - ADD_SUBSIDY_FUND_FAILED, - ADD_SUBSIDY_FUND_FRESH_CHECK - } - - /** - * @dev `error` corresponds to enum Error; `info` corresponds to enum FailureInfo, and `detail` is an arbitrary - * contract-specific code that enables us to report opaque error codes from upgradeable contracts. - **/ - event TokenFailure(uint256 error, uint256 info, uint256 detail); - - /** - * @dev use this when reporting a known error from the money market or a non-upgradeable collaborator - */ - function fail(Error err, FailureInfo info) internal returns (uint256) { - emit TokenFailure(uint256(err), uint256(info), 0); - - return uint256(err); - } - - /** - * @dev use this when reporting an opaque error from an upgradeable collaborator contract - */ - function failOpaque( - Error err, - FailureInfo info, - uint256 opaqueError - ) internal returns (uint256) { - emit TokenFailure(uint256(err), uint256(info), opaqueError); - - return uint256(err); - } -} - - -// Dependency file: contracts/EIP20Interface.sol - -// pragma solidity 0.8.6; - -/** - * @title ERC 20 Token Standard Interface - * https://eips.ethereum.org/EIPS/eip-20 - */ -interface EIP20Interface { - function name() external view returns (string memory); - - function symbol() external view returns (string memory); - - function decimals() external view returns (uint8); - - /** - * @notice Get the total number of tokens in circulation - * @return The supply of tokens - */ - function totalSupply() external view returns (uint256); - - /** - * @notice Gets the balance of the specified address - * @param owner The address from which the balance will be retrieved - * @return balance The balance - */ - function balanceOf(address owner) external view returns (uint256 balance); - - /** - * @notice Transfer `amount` tokens from `msg.sender` to `dst` - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - * @return success Whether or not the transfer succeeded - */ - function transfer(address dst, uint256 amount) - external - returns (bool success); - - /** - * @notice Transfer `amount` tokens from `src` to `dst` - * @param src The address of the source account - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - * @return success Whether or not the transfer succeeded - */ - function transferFrom( - address src, - address dst, - uint256 amount - ) external returns (bool success); - - /** - * @notice Approve `spender` to transfer up to `amount` from `src` - * @dev This will overwrite the approval amount for `spender` - * and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve) - * @param spender The address of the account which may transfer tokens - * @param amount The number of tokens that are approved (-1 means infinite) - * @return success Whether or not the approval succeeded - */ - function approve(address spender, uint256 amount) - external - returns (bool success); - - /** - * @notice Get the current allowance from `owner` for `spender` - * @param owner The address of the account which owns the tokens to be spent - * @param spender The address of the account which may transfer tokens - * @return remaining The number of tokens allowed to be spent (-1 means infinite) - */ - function allowance(address owner, address spender) - external - view - returns (uint256 remaining); - - event Transfer(address indexed from, address indexed to, uint256 amount); - event Approval( - address indexed owner, - address indexed spender, - uint256 amount - ); -} - - -// Dependency file: contracts/WhitelistInterface.sol - -// pragma solidity 0.8.6; - -interface WhitelistInterface { - function setStatus(bool _newStatus) external; - function enabled() external view returns(bool); - - function addUsers(address[] memory _users) external; - function exist(address _user) external view returns(bool); - function getUsers() external view returns(address[] memory currentUsers); - function removeUser(address _user) external; -} - -// Dependency file: contracts/CToken.sol - -// pragma solidity 0.8.6; - -// import "contracts/ComptrollerInterface.sol"; -// import "contracts/CTokenInterfaces.sol"; -// import "contracts/ErrorReporter.sol"; -// import "contracts/Exponential.sol"; -// import "contracts/EIP20Interface.sol"; -// import "contracts/InterestRateModel.sol"; -// import "contracts/WhitelistInterface.sol"; - -/** - * @title tropykus CToken Contract - * @notice Abstract base for CTokens - * @author tropykus - */ -abstract contract CToken is CTokenInterface, Exponential, TokenErrorReporter { - address whitelist; - - /** - * @notice Initialize the money market - * @param comptroller_ The address of the Comptroller - * @param interestRateModel_ The address of the interest rate model - * @param initialExchangeRateMantissa_ The initial exchange rate, scaled by 1e18 - * @param name_ EIP-20 name of this token - * @param symbol_ EIP-20 symbol of this token - * @param decimals_ EIP-20 decimal precision of this token - */ - function initialize( - ComptrollerInterface comptroller_, - InterestRateModel interestRateModel_, - uint256 initialExchangeRateMantissa_, - string memory name_, - string memory symbol_, - uint8 decimals_ - ) public { - require(msg.sender == admin, "CT01"); - require(accrualBlockNumber == 0 && borrowIndex == 0, "CT02"); - - initialExchangeRateMantissa = initialExchangeRateMantissa_; - require(initialExchangeRateMantissa > 0, "CT03"); - - uint256 err = _setComptroller(comptroller_); - require(err == uint256(Error.NO_ERROR), "CT04"); - - accrualBlockNumber = getBlockNumber(); - borrowIndex = mantissaOne; - - err = _setInterestRateModelFresh(interestRateModel_); - require(err == uint256(Error.NO_ERROR), "CT05"); - - name = name_; - symbol = symbol_; - decimals = decimals_; - - _notEntered = true; - } - - function addWhitelist(address _whitelist) external returns (uint256) { - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_INTEREST_RATE_MODEL_OWNER_CHECK - ); - } - whitelist = _whitelist; - } - - /** - * @notice Transfer `tokens` tokens from `src` to `dst` by `spender` - * @dev Called by both `transfer` and `transferFrom` internally - * @param spender The address of the account performing the transfer - * @param src The address of the source account - * @param dst The address of the destination account - * @param tokens The number of tokens to transfer - * @return Whether or not the transfer succeeded - */ - function transferTokens( - address spender, - address src, - address dst, - uint256 tokens - ) internal returns (uint256) { - uint256 allowed = comptroller.transferAllowed( - address(this), - src, - dst, - tokens - ); - if (allowed != 0) { - return - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.TRANSFER_COMPTROLLER_REJECTION, - allowed - ); - } - - if (src == dst) { - return fail(Error.BAD_INPUT, FailureInfo.TRANSFER_NOT_ALLOWED); - } - - uint256 startingAllowance = 0; - if (spender == src) { - startingAllowance = type(uint256).max; - } else { - startingAllowance = transferAllowances[src][spender]; - } - - MathError mathErr; - uint256 allowanceNew; - uint256 srcTokensNew; - uint256 dstTokensNew; - - (mathErr, allowanceNew) = subUInt(startingAllowance, tokens); - if (mathErr != MathError.NO_ERROR) { - return fail(Error.MATH_ERROR, FailureInfo.TRANSFER_NOT_ALLOWED); - } - - (mathErr, srcTokensNew) = subUInt(accountTokens[src].tokens, tokens); - if (mathErr != MathError.NO_ERROR) { - return fail(Error.MATH_ERROR, FailureInfo.TRANSFER_NOT_ENOUGH); - } - - (mathErr, dstTokensNew) = addUInt(accountTokens[dst].tokens, tokens); - if (mathErr != MathError.NO_ERROR) { - return fail(Error.MATH_ERROR, FailureInfo.TRANSFER_TOO_MUCH); - } - - accountTokens[src].tokens = srcTokensNew; - accountTokens[dst].tokens = dstTokensNew; - - if (startingAllowance != type(uint256).max) { - transferAllowances[src][spender] = allowanceNew; - } - - emit Transfer(src, dst, tokens); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Transfer `amount` tokens from `msg.sender` to `dst` - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - * @return Whether or not the transfer succeeded - */ - function transfer(address dst, uint256 amount) - external - override - nonReentrant - returns (bool) - { - return - transferTokens(msg.sender, msg.sender, dst, amount) == - uint256(Error.NO_ERROR); - } - - /** - * @notice Transfer `amount` tokens from `src` to `dst` - * @param src The address of the source account - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - * @return Whether or not the transfer succeeded - */ - function transferFrom( - address src, - address dst, - uint256 amount - ) external override nonReentrant returns (bool) { - return - transferTokens(msg.sender, src, dst, amount) == - uint256(Error.NO_ERROR); - } - - /** - * @notice Approve `spender` to transfer up to `amount` from `src` - * @dev This will overwrite the approval amount for `spender` - * and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve) - * @param spender The address of the account which may transfer tokens - * @param amount The number of tokens that are approved (-1 means infinite) - * @return Whether or not the approval succeeded - */ - function approve(address spender, uint256 amount) - external - override - returns (bool) - { - transferAllowances[msg.sender][spender] = amount; - emit Approval(msg.sender, spender, amount); - return true; - } - - /** - * @notice Get the current allowance from `owner` for `spender` - * @param owner The address of the account which owns the tokens to be spent - * @param spender The address of the account which may transfer tokens - * @return The number of tokens allowed to be spent (-1 means infinite) - */ - function allowance(address owner, address spender) - external - view - override - returns (uint256) - { - return transferAllowances[owner][spender]; - } - - /** - * @notice Get the token balance of the `owner` - * @param owner The address of the account to query - * @return The number of tokens owned by `owner` - */ - function balanceOf(address owner) external view override returns (uint256) { - return accountTokens[owner].tokens; - } - - /** - * @notice Get the underlying balance of the `owner` - * @dev This also accrues interest in a transaction - * @param owner The address of the account to query - * @return The amount of underlying owned by `owner` - */ - function balanceOfUnderlying(address owner) - external - override - returns (uint256) - { - (MathError mErr, uint256 balance) = mulScalarTruncate( - Exp({mantissa: exchangeRateCurrent()}), - accountTokens[owner].tokens - ); - require(mErr == MathError.NO_ERROR, "CT06"); - return balance; - } - - /** - * @notice Get a snapshot of the account's balances, and the cached exchange rate - * @dev This is used by comptroller to more efficiently perform liquidity checks. - * @param account Address of the account to snapshot - * @return (possible error, token balance, borrow balance, exchange rate mantissa) - */ - function getAccountSnapshot(address account) - external - view - override - returns ( - uint256, - uint256, - uint256, - uint256 - ) - { - uint256 cTokenBalance = accountTokens[account].tokens; - uint256 borrowBalance; - uint256 exchangeRateMantissa; - - MathError mErr; - - (mErr, borrowBalance) = borrowBalanceStoredInternal(account); - if (mErr != MathError.NO_ERROR) { - return (uint256(Error.MATH_ERROR), 0, 0, 0); - } - - (mErr, exchangeRateMantissa) = exchangeRateStoredInternal(); - if (mErr != MathError.NO_ERROR) { - return (uint256(Error.MATH_ERROR), 0, 0, 0); - } - - return ( - uint256(Error.NO_ERROR), - cTokenBalance, - borrowBalance, - exchangeRateMantissa - ); - } - - /** - * @dev Function to simply retrieve block number - * This exists mainly for inheriting test contracts to stub this result. - */ - function getBlockNumber() internal view virtual returns (uint256) { - return block.number; - } - - /** - * @notice Returns the current per-block borrow interest rate for this cToken - * @return The borrow interest rate per block, scaled by 1e18 - */ - function borrowRatePerBlock() external view override returns (uint256) { - return - interestRateModel.getBorrowRate( - getCashPrior(), - totalBorrows, - totalReserves - ); - } - - /** - * @notice Returns the current per-block supply interest rate for this cToken - * @return The supply interest rate per block, scaled by 1e18 - */ - function supplyRatePerBlock() external view override returns (uint256) { - return - interestRateModel.getSupplyRate( - getCashPrior(), - totalBorrows, - totalReserves, - reserveFactorMantissa - ); - } - - /** - * @notice Returns the current total borrows plus accrued interest - * @return The total borrows with interest - */ - function totalBorrowsCurrent() - external - override - nonReentrant - returns (uint256) - { - require(accrueInterest() == uint256(Error.NO_ERROR), "CT07"); - return totalBorrows; - } - - /** - * @notice Accrue interest to updated borrowIndex and then calculate account's borrow balance using the updated borrowIndex - * @param account The address whose balance should be calculated after updating borrowIndex - * @return The calculated balance - */ - function borrowBalanceCurrent(address account) - external - override - nonReentrant - returns (uint256) - { - require(accrueInterest() == uint256(Error.NO_ERROR), "CT07"); - return borrowBalanceStored(account); - } - - /** - * @notice Return the borrow balance of account based on stored data - * @param account The address whose balance should be calculated - * @return The calculated balance - */ - function borrowBalanceStored(address account) - public - view - override - returns (uint256) - { - (MathError err, uint256 result) = borrowBalanceStoredInternal(account); - require(err == MathError.NO_ERROR, "CT08"); - return result; - } - - /** - * @notice Return the borrow balance of account based on stored data - * @param account The address whose balance should be calculated - * @return (error code, the calculated balance or 0 if error code is non-zero) - */ - function borrowBalanceStoredInternal(address account) - internal - view - returns (MathError, uint256) - { - MathError mathErr; - uint256 principalTimesIndex; - uint256 result; - - BorrowSnapshot storage borrowSnapshot = accountBorrows[account]; - - if (borrowSnapshot.principal == 0) { - return (MathError.NO_ERROR, 0); - } - - (mathErr, principalTimesIndex) = mulUInt( - borrowSnapshot.principal, - borrowIndex - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - - (mathErr, result) = divUInt( - principalTimesIndex, - borrowSnapshot.interestIndex - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - - return (MathError.NO_ERROR, result); - } - - function getBorrowerPrincipalStored(address account) - public - view - returns (uint256 borrowed) - { - borrowed = accountBorrows[account].principal; - } - - function getSupplierSnapshotStored(address account) - public - view - returns ( - uint256 tokens, - uint256 underlyingAmount, - uint256 suppliedAt, - uint256 promisedSupplyRate - ) - { - tokens = accountTokens[account].tokens; - underlyingAmount = accountTokens[account].underlyingAmount; - suppliedAt = accountTokens[account].suppliedAt; - promisedSupplyRate = accountTokens[account].promisedSupplyRate; - } - - /** - * @notice Accrue interest then return the up-to-date exchange rate - * @return Calculated exchange rate scaled by 1e18 - */ - function exchangeRateCurrent() - public - override - nonReentrant - returns (uint256) - { - require(accrueInterest() == uint256(Error.NO_ERROR), "CT07"); - return exchangeRateStored(); - } - - /** - * @notice Calculates the exchange rate from the underlying to the CToken - * @dev This function does not accrue interest before calculating the exchange rate - * @return Calculated exchange rate scaled by 1e18 - */ - function exchangeRateStored() public view override returns (uint256) { - (MathError err, uint256 result) = exchangeRateStoredInternal(); - require(err == MathError.NO_ERROR, "CT09"); - return result; - } - - /** - * @notice Calculates the exchange rate from the underlying to the CToken - * @dev This function does not accrue interest before calculating the exchange rate - * @return (error code, calculated exchange rate scaled by 1e18) - */ - function exchangeRateStoredInternal() - internal - view - virtual - returns (MathError, uint256) - { - uint256 _totalSupply = totalSupply; - if (_totalSupply == 0) { - return (MathError.NO_ERROR, initialExchangeRateMantissa); - } else { - MathError error; - uint256 exchangeRate; - uint256 totalCash = getCashPrior(); - if (interestRateModel.isTropykusInterestRateModel()) { - (error, exchangeRate) = tropykusExchangeRateStoredInternal( - msg.sender - ); - if (error == MathError.NO_ERROR) { - return (MathError.NO_ERROR, exchangeRate); - } else { - return (MathError.NO_ERROR, initialExchangeRateMantissa); - } - } - return - interestRateModel.getExchangeRate( - totalCash, - totalBorrows, - totalReserves, - totalSupply - ); - } - } - - function tropykusExchangeRateStoredInternal(address redeemer) - internal - view - returns (MathError, uint256) - { - if (totalSupply == 0) { - return (MathError.NO_ERROR, initialExchangeRateMantissa); - } else { - SupplySnapshot storage supplySnapshot = accountTokens[redeemer]; - if (supplySnapshot.suppliedAt == 0) { - return (MathError.DIVISION_BY_ZERO, 0); - } - (, uint256 interestFactorMantissa, ) = tropykusInterestAccrued( - redeemer - ); - Exp memory interestFactor = Exp({mantissa: interestFactorMantissa}); - uint256 currentUnderlying = supplySnapshot.underlyingAmount; - Exp memory redeemerUnderlying = Exp({mantissa: currentUnderlying}); - (, Exp memory realAmount) = mulExp( - interestFactor, - redeemerUnderlying - ); - (, Exp memory exchangeRate) = getExp( - realAmount.mantissa, - supplySnapshot.tokens - ); - return (MathError.NO_ERROR, exchangeRate.mantissa); - } - } - - function tropykusInterestAccrued(address account) - internal - view - returns ( - MathError, - uint256, - uint256 - ) - { - SupplySnapshot storage supplySnapshot = accountTokens[account]; - uint256 promisedSupplyRate = supplySnapshot.promisedSupplyRate; - Exp memory expectedSupplyRatePerBlock = Exp({ - mantissa: promisedSupplyRate - }); - (, uint256 delta) = subUInt( - accrualBlockNumber, - supplySnapshot.suppliedAt - ); - (, Exp memory expectedSupplyRatePerBlockWithDelta) = mulScalar( - expectedSupplyRatePerBlock, - delta - ); - (, Exp memory interestFactor) = addExp( - Exp({mantissa: 1e18}), - expectedSupplyRatePerBlockWithDelta - ); - uint256 currentUnderlying = supplySnapshot.underlyingAmount; - Exp memory redeemerUnderlying = Exp({mantissa: currentUnderlying}); - (, Exp memory realAmount) = mulExp(interestFactor, redeemerUnderlying); - (, uint256 interestEarned) = subUInt( - realAmount.mantissa, - currentUnderlying - ); - return (MathError.NO_ERROR, interestFactor.mantissa, interestEarned); - } - - /** - * @notice Get cash balance of this cToken in the underlying asset - * @return The quantity of underlying asset owned by this contract - */ - function getCash() external view override returns (uint256) { - return getCashPrior(); - } - - /** - * @notice Applies accrued interest to total borrows and reserves - * @dev This calculates interest accrued from the last checkpointed block - * up to the current block and writes new checkpoint to storage. - */ - function accrueInterest() public override returns (uint256) { - uint256 currentBlockNumber = getBlockNumber(); - uint256 accrualBlockNumberPrior = accrualBlockNumber; - - if (accrualBlockNumberPrior == currentBlockNumber) { - return uint256(Error.NO_ERROR); - } - - uint256 cashPrior = getCashPrior(); - uint256 borrowsPrior = totalBorrows; - uint256 reservesPrior = totalReserves; - uint256 borrowIndexPrior = borrowIndex; - - uint256 borrowRateMantissa = interestRateModel.getBorrowRate( - cashPrior, - borrowsPrior, - reservesPrior - ); - require(borrowRateMantissa <= borrowRateMaxMantissa, "CT10"); - - (MathError mathErr, uint256 blockDelta) = subUInt( - currentBlockNumber, - accrualBlockNumberPrior - ); - require(mathErr == MathError.NO_ERROR, "CT11"); - - Exp memory simpleInterestFactor; - uint256 interestAccumulated; - uint256 totalBorrowsNew; - uint256 totalReservesNew; - uint256 borrowIndexNew; - - (mathErr, simpleInterestFactor) = mulScalar( - Exp({mantissa: borrowRateMantissa}), - blockDelta - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .ACCRUE_INTEREST_SIMPLE_INTEREST_FACTOR_CALCULATION_FAILED, - uint256(mathErr) - ); - } - - (mathErr, interestAccumulated) = mulScalarTruncate( - simpleInterestFactor, - borrowsPrior - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .ACCRUE_INTEREST_ACCUMULATED_INTEREST_CALCULATION_FAILED, - uint256(mathErr) - ); - } - - (mathErr, totalBorrowsNew) = addUInt(interestAccumulated, borrowsPrior); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .ACCRUE_INTEREST_NEW_TOTAL_BORROWS_CALCULATION_FAILED, - uint256(mathErr) - ); - } - - (mathErr, totalReservesNew) = mulScalarTruncateAddUInt( - Exp({mantissa: reserveFactorMantissa}), - interestAccumulated, - reservesPrior - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .ACCRUE_INTEREST_NEW_TOTAL_RESERVES_CALCULATION_FAILED, - uint256(mathErr) - ); - } - - if (interestRateModel.isTropykusInterestRateModel()) { - (mathErr, totalReservesNew) = newReserves( - borrowRateMantissa, - cashPrior, - borrowsPrior, - reservesPrior, - interestAccumulated - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .ACCRUE_INTEREST_NEW_TOTAL_RESERVES_CALCULATION_FAILED, - uint256(mathErr) - ); - } - } - - (mathErr, borrowIndexNew) = mulScalarTruncateAddUInt( - simpleInterestFactor, - borrowIndexPrior, - borrowIndexPrior - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .ACCRUE_INTEREST_NEW_BORROW_INDEX_CALCULATION_FAILED, - uint256(mathErr) - ); - } - - accrualBlockNumber = currentBlockNumber; - borrowIndex = borrowIndexNew; - totalBorrows = totalBorrowsNew; - totalReserves = totalReservesNew; - - emit AccrueInterest( - cashPrior, - interestAccumulated, - borrowIndexNew, - totalBorrowsNew - ); - - return uint256(Error.NO_ERROR); - } - - function newReserves( - uint256 borrowRateMantissa, - uint256 cashPrior, - uint256 borrowsPrior, - uint256 reservesPrior, - uint256 interestAccumulated - ) internal view returns (MathError mathErr, uint256 totalReservesNew) { - uint256 newReserveFactorMantissa; - uint256 utilizationRate = interestRateModel.utilizationRate( - cashPrior, - borrowsPrior, - reservesPrior - ); - uint256 expectedSupplyRate = interestRateModel.getSupplyRate( - cashPrior, - borrowsPrior, - reservesPrior, - reserveFactorMantissa - ); - if ( - interestRateModel.isAboveOptimal( - cashPrior, - borrowsPrior, - reservesPrior - ) - ) { - (mathErr, newReserveFactorMantissa) = mulScalarTruncate( - Exp({mantissa: utilizationRate}), - borrowRateMantissa - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - (mathErr, newReserveFactorMantissa) = subUInt( - newReserveFactorMantissa, - expectedSupplyRate - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - (mathErr, totalReservesNew) = mulScalarTruncateAddUInt( - Exp({mantissa: newReserveFactorMantissa}), - interestAccumulated, - reservesPrior - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - } else { - mathErr = MathError.NO_ERROR; - totalReservesNew = reservesPrior; - } - } - - /** - * @notice Sender supplies assets into the market and receives cTokens in exchange - * @dev Accrues interest whether or not the operation succeeds, unless reverted - * @param mintAmount The amount of the underlying asset to supply - * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual mint amount. - */ - function mintInternal(uint256 mintAmount) - internal - nonReentrant - returns (uint256, uint256) - { - if (WhitelistInterface(whitelist).enabled()) { - require(WhitelistInterface(whitelist).exist(msg.sender), "CT26"); - } - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return ( - fail(Error(error), FailureInfo.MINT_ACCRUE_INTEREST_FAILED), - 0 - ); - } - return mintFresh(msg.sender, mintAmount); - } - - struct MintLocalVars { - Error err; - MathError mathErr; - uint256 exchangeRateMantissa; - uint256 mintTokens; - uint256 totalSupplyNew; - uint256 accountTokensNew; - uint256 actualMintAmount; - } - - /** - * @notice User supplies assets into the market and receives cTokens in exchange - * @dev Assumes interest has already been accrued up to the current block - * @param minter The address of the account which is supplying the assets - * @param mintAmount The amount of the underlying asset to supply - * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual mint amount. - */ - function mintFresh(address minter, uint256 mintAmount) - internal - returns (uint256, uint256) - { - uint256 allowed = comptroller.mintAllowed( - address(this), - minter, - mintAmount - ); - if (allowed != 0) { - return ( - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.MINT_COMPTROLLER_REJECTION, - allowed - ), - 0 - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return ( - fail(Error.MARKET_NOT_FRESH, FailureInfo.MINT_FRESHNESS_CHECK), - 0 - ); - } - - MintLocalVars memory vars; - - ( - vars.mathErr, - vars.exchangeRateMantissa - ) = exchangeRateStoredInternal(); - if (vars.mathErr != MathError.NO_ERROR) { - return ( - failOpaque( - Error.MATH_ERROR, - FailureInfo.MINT_EXCHANGE_RATE_READ_FAILED, - uint256(vars.mathErr) - ), - 0 - ); - } - if (interestRateModel.isTropykusInterestRateModel()) { - SupplySnapshot storage supplySnapshot = accountTokens[minter]; - (, uint256 newTotalSupply) = addUInt( - supplySnapshot.underlyingAmount, - mintAmount - ); - require(newTotalSupply <= 0.1e18, "CT24"); - } - vars.actualMintAmount = doTransferIn(minter, mintAmount); - - (vars.mathErr, vars.mintTokens) = divScalarByExpTruncate( - vars.actualMintAmount, - Exp({mantissa: vars.exchangeRateMantissa}) - ); - require(vars.mathErr == MathError.NO_ERROR, "CT12"); - - (vars.mathErr, vars.totalSupplyNew) = addUInt( - totalSupply, - vars.mintTokens - ); - require(vars.mathErr == MathError.NO_ERROR, "CT13"); - - (vars.mathErr, vars.accountTokensNew) = addUInt( - accountTokens[minter].tokens, - vars.mintTokens - ); - require(vars.mathErr == MathError.NO_ERROR, "CT14"); - - uint256 currentSupplyRate = interestRateModel.getSupplyRate( - getCashPrior(), - totalBorrows, - totalReserves, - reserveFactorMantissa - ); - - bool isTropykusInterestRateModel = interestRateModel - .isTropykusInterestRateModel(); - - if (accountTokens[minter].tokens > 0) { - Exp memory updatedUnderlying; - if (isTropykusInterestRateModel) { - (, uint256 interestFactorMantissa, ) = tropykusInterestAccrued( - minter - ); - Exp memory interestFactor = Exp({ - mantissa: interestFactorMantissa - }); - uint256 currentUnderlyingAmount = accountTokens[minter] - .underlyingAmount; - MathError mErrorNewAmount; - (mErrorNewAmount, updatedUnderlying) = mulExp( - Exp({mantissa: currentUnderlyingAmount}), - interestFactor - ); - if (mErrorNewAmount != MathError.NO_ERROR) { - return ( - failOpaque( - Error.MATH_ERROR, - FailureInfo.MINT_EXCHANGE_CALCULATION_FAILED, - uint256(mErrorNewAmount) - ), - 0 - ); - } - } else { - uint256 currentTokens = accountTokens[minter].tokens; - MathError mErrorUpdatedUnderlying; - (mErrorUpdatedUnderlying, updatedUnderlying) = mulExp( - Exp({mantissa: currentTokens}), - Exp({mantissa: vars.exchangeRateMantissa}) - ); - if (mErrorUpdatedUnderlying != MathError.NO_ERROR) { - return ( - failOpaque( - Error.MATH_ERROR, - FailureInfo.MINT_EXCHANGE_CALCULATION_FAILED, - uint256(mErrorUpdatedUnderlying) - ), - 0 - ); - } - } - (, mintAmount) = addUInt(updatedUnderlying.mantissa, mintAmount); - } - - totalSupply = vars.totalSupplyNew; - accountTokens[minter] = SupplySnapshot({ - tokens: vars.accountTokensNew, - underlyingAmount: mintAmount, - suppliedAt: accrualBlockNumber, - promisedSupplyRate: currentSupplyRate - }); - - emit Mint(minter, vars.actualMintAmount, vars.mintTokens); - emit Transfer(address(this), minter, vars.mintTokens); - - return (uint256(Error.NO_ERROR), vars.actualMintAmount); - } - - /** - * @notice Sender redeems cTokens in exchange for a specified amount of underlying asset - * @dev Accrues interest whether or not the operation succeeds, unless reverted - * @param redeemAmount The amount of underlying to receive from redeeming cTokens - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function redeemUnderlyingInternal(uint256 redeemAmount) - internal - nonReentrant - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return - fail(Error(error), FailureInfo.REDEEM_ACCRUE_INTEREST_FAILED); - } - return redeemFresh(payable(msg.sender), redeemAmount); - } - - struct RedeemLocalVars { - Error err; - MathError mathErr; - uint256 exchangeRateMantissa; - uint256 redeemTokens; - uint256 redeemAmount; - uint256 totalSupplyNew; - uint256 accountTokensNew; - uint256 newSubsidyFund; - } - - /** - * @notice User redeems cTokens in exchange for the underlying asset - * @dev Assumes interest has already been accrued up to the current block - * @param redeemer The address of the account which is redeeming the tokens - * @param redeemAmountIn The number of underlying tokens to receive from redeeming cTokens - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function redeemFresh(address payable redeemer, uint256 redeemAmountIn) - internal - returns (uint256) - { - require(redeemAmountIn > 0, "CT15"); - - RedeemLocalVars memory vars; - - SupplySnapshot storage supplySnapshot = accountTokens[redeemer]; - - ( - vars.mathErr, - vars.exchangeRateMantissa - ) = exchangeRateStoredInternal(); - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.REDEEM_EXCHANGE_RATE_READ_FAILED, - uint256(vars.mathErr) - ); - } - - uint256 interestEarned; - uint256 subsidyFundPortion; - uint256 currentUnderlying; - - bool isTropykusInterestRateModel = interestRateModel - .isTropykusInterestRateModel(); - if (isTropykusInterestRateModel) { - currentUnderlying = supplySnapshot.underlyingAmount; - (, , interestEarned) = tropykusInterestAccrued(redeemer); - } - supplySnapshot.promisedSupplyRate = interestRateModel.getSupplyRate( - getCashPrior(), - totalBorrows, - totalReserves, - reserveFactorMantissa - ); - - if ( - isTropykusInterestRateModel && - !interestRateModel.isAboveOptimal( - getCashPrior(), - totalBorrows, - totalReserves - ) - ) { - uint256 borrowRate = interestRateModel.getBorrowRate( - getCashPrior(), - totalBorrows, - totalReserves - ); - - uint256 utilizationRate = interestRateModel.utilizationRate( - getCashPrior(), - totalBorrows, - totalReserves - ); - - (, uint256 estimatedEarning) = mulScalarTruncate( - Exp({mantissa: borrowRate}), - utilizationRate - ); - - (, subsidyFundPortion) = subUInt( - supplySnapshot.promisedSupplyRate, - estimatedEarning - ); - (, Exp memory subsidyFactor) = getExp( - subsidyFundPortion, - supplySnapshot.promisedSupplyRate - ); - (, subsidyFundPortion) = mulScalarTruncate( - subsidyFactor, - interestEarned - ); - } - - vars.redeemAmount = redeemAmountIn; - - if (isTropykusInterestRateModel) { - (, Exp memory num) = mulExp( - vars.redeemAmount, - supplySnapshot.tokens - ); - (, Exp memory realTokensWithdrawAmount) = getExp( - num.mantissa, - currentUnderlying - ); - vars.redeemTokens = realTokensWithdrawAmount.mantissa; - } else { - (vars.mathErr, vars.redeemTokens) = divScalarByExpTruncate( - redeemAmountIn, - Exp({mantissa: vars.exchangeRateMantissa}) - ); - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.REDEEM_EXCHANGE_AMOUNT_CALCULATION_FAILED, - uint256(vars.mathErr) - ); - } - } - // } - - uint256 allowed = comptroller.redeemAllowed( - address(this), - redeemer, - vars.redeemTokens - ); - if (allowed != 0) { - return - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.REDEEM_COMPTROLLER_REJECTION, - allowed - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.REDEEM_FRESHNESS_CHECK - ); - } - - (vars.mathErr, vars.totalSupplyNew) = subUInt( - totalSupply, - vars.redeemTokens - ); - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.REDEEM_NEW_TOTAL_SUPPLY_CALCULATION_FAILED, - uint256(vars.mathErr) - ); - } - - (, vars.newSubsidyFund) = subUInt(subsidyFund, subsidyFundPortion); - - (vars.mathErr, vars.accountTokensNew) = subUInt( - supplySnapshot.tokens, - vars.redeemTokens - ); - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.REDEEM_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED, - uint256(vars.mathErr) - ); - } - - uint256 cash = getCashPrior(); - if (isTropykusInterestRateModel) { - cash = address(this).balance; - } - - if (cash < vars.redeemAmount) { - return - fail( - Error.TOKEN_INSUFFICIENT_CASH, - FailureInfo.REDEEM_TRANSFER_OUT_NOT_POSSIBLE - ); - } - - doTransferOut(redeemer, vars.redeemAmount); - - totalSupply = vars.totalSupplyNew; - subsidyFund = vars.newSubsidyFund; - supplySnapshot.tokens = vars.accountTokensNew; - supplySnapshot.suppliedAt = accrualBlockNumber; - (, supplySnapshot.underlyingAmount) = subUInt( - supplySnapshot.underlyingAmount, - vars.redeemAmount - ); - - emit Transfer(redeemer, address(this), vars.redeemTokens); - emit Redeem(redeemer, vars.redeemAmount, vars.redeemTokens); - - comptroller.redeemVerify( - address(this), - redeemer, - vars.redeemAmount, - vars.redeemTokens - ); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Sender borrows assets from the protocol to their own address - * @param borrowAmount The amount of the underlying asset to borrow - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function borrowInternal(uint256 borrowAmount) - internal - nonReentrant - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return - fail(Error(error), FailureInfo.BORROW_ACCRUE_INTEREST_FAILED); - } - return borrowFresh(payable(msg.sender), borrowAmount); - } - - struct BorrowLocalVars { - MathError mathErr; - uint256 accountBorrows; - uint256 accountBorrowsNew; - uint256 totalBorrowsNew; - } - - /** - * @notice Users borrow assets from the protocol to their own address - * @param borrowAmount The amount of the underlying asset to borrow - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function borrowFresh(address payable borrower, uint256 borrowAmount) - internal - returns (uint256) - { - uint256 allowed = comptroller.borrowAllowed( - address(this), - borrower, - borrowAmount - ); - if (allowed != 0) { - return - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.BORROW_COMPTROLLER_REJECTION, - allowed - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.BORROW_FRESHNESS_CHECK - ); - } - - if (getCashPrior() < borrowAmount) { - return - fail( - Error.TOKEN_INSUFFICIENT_CASH, - FailureInfo.BORROW_CASH_NOT_AVAILABLE - ); - } - - BorrowLocalVars memory vars; - - (vars.mathErr, vars.accountBorrows) = borrowBalanceStoredInternal( - borrower - ); - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED, - uint256(vars.mathErr) - ); - } - - (vars.mathErr, vars.accountBorrowsNew) = addUInt( - vars.accountBorrows, - borrowAmount - ); - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED, - uint256(vars.mathErr) - ); - } - - (vars.mathErr, vars.totalBorrowsNew) = addUInt( - totalBorrows, - borrowAmount - ); - if (interestRateModel.isTropykusInterestRateModel()) { - require(vars.totalBorrowsNew <= 0.1e18, "CT25"); - } - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED, - uint256(vars.mathErr) - ); - } - - doTransferOut(borrower, borrowAmount); - - accountBorrows[borrower].principal = vars.accountBorrowsNew; - accountBorrows[borrower].interestIndex = borrowIndex; - totalBorrows = vars.totalBorrowsNew; - - emit Borrow( - borrower, - borrowAmount, - vars.accountBorrowsNew, - vars.totalBorrowsNew - ); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Sender repays their own borrow - * @param repayAmount The amount to repay - * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual repayment amount. - */ - function repayBorrowInternal(uint256 repayAmount) - internal - nonReentrant - returns (uint256, uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return ( - fail( - Error(error), - FailureInfo.REPAY_BORROW_ACCRUE_INTEREST_FAILED - ), - 0 - ); - } - return repayBorrowFresh(msg.sender, msg.sender, repayAmount); - } - - struct RepayBorrowLocalVars { - Error err; - MathError mathErr; - uint256 repayAmount; - uint256 borrowerIndex; - uint256 accountBorrows; - uint256 accountBorrowsNew; - uint256 totalBorrowsNew; - uint256 actualRepayAmount; - } - - /** - * @notice Borrows are repaid by another user (possibly the borrower). - * @param payer the account paying off the borrow - * @param borrower the account with the debt being payed off - * @param repayAmount the amount of undelrying tokens being returned - * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual repayment amount. - */ - function repayBorrowFresh( - address payer, - address borrower, - uint256 repayAmount - ) internal returns (uint256, uint256) { - uint256 allowed = comptroller.repayBorrowAllowed( - address(this), - payer, - borrower, - repayAmount - ); - if (allowed != 0) { - return ( - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.REPAY_BORROW_COMPTROLLER_REJECTION, - allowed - ), - 0 - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return ( - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.REPAY_BORROW_FRESHNESS_CHECK - ), - 0 - ); - } - - RepayBorrowLocalVars memory vars; - - vars.borrowerIndex = accountBorrows[borrower].interestIndex; - - (vars.mathErr, vars.accountBorrows) = borrowBalanceStoredInternal( - borrower - ); - if (vars.mathErr != MathError.NO_ERROR) { - return ( - failOpaque( - Error.MATH_ERROR, - FailureInfo - .REPAY_BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED, - uint256(vars.mathErr) - ), - 0 - ); - } - - if (repayAmount == type(uint256).max) { - vars.repayAmount = vars.accountBorrows; - } else { - vars.repayAmount = repayAmount; - } - - vars.actualRepayAmount = doTransferIn(payer, vars.repayAmount); - - (vars.mathErr, vars.accountBorrowsNew) = subUInt( - vars.accountBorrows, - vars.actualRepayAmount - ); - require(vars.mathErr == MathError.NO_ERROR, "CT16"); - - (vars.mathErr, vars.totalBorrowsNew) = subUInt( - totalBorrows, - vars.actualRepayAmount - ); - require(vars.mathErr == MathError.NO_ERROR, "CT17"); - - accountBorrows[borrower].principal = vars.accountBorrowsNew; - accountBorrows[borrower].interestIndex = borrowIndex; - totalBorrows = vars.totalBorrowsNew; - - emit RepayBorrow( - payer, - borrower, - vars.actualRepayAmount, - vars.accountBorrowsNew, - vars.totalBorrowsNew - ); - - return (uint256(Error.NO_ERROR), vars.actualRepayAmount); - } - - /** - * @notice The sender liquidates the borrowers collateral. - * The collateral seized is transferred to the liquidator. - * @param borrower The borrower of this cToken to be liquidated - * @param cTokenCollateral The market in which to seize collateral from the borrower - * @param repayAmount The amount of the underlying borrowed asset to repay - * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual repayment amount. - */ - function liquidateBorrowInternal( - address borrower, - uint256 repayAmount, - CTokenInterface cTokenCollateral - ) internal nonReentrant returns (uint256, uint256) { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return ( - fail( - Error(error), - FailureInfo.LIQUIDATE_ACCRUE_BORROW_INTEREST_FAILED - ), - 0 - ); - } - - error = cTokenCollateral.accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return ( - fail( - Error(error), - FailureInfo.LIQUIDATE_ACCRUE_COLLATERAL_INTEREST_FAILED - ), - 0 - ); - } - - // liquidateBorrowFresh emits borrow-specific logs on errors, so we don't need to - return - liquidateBorrowFresh( - msg.sender, - borrower, - repayAmount, - cTokenCollateral - ); - } - - /** - * @notice The liquidator liquidates the borrowers collateral. - * The collateral seized is transferred to the liquidator. - * @param borrower The borrower of this cToken to be liquidated - * @param liquidator The address repaying the borrow and seizing collateral - * @param cTokenCollateral The market in which to seize collateral from the borrower - * @param repayAmount The amount of the underlying borrowed asset to repay - * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual repayment amount. - */ - function liquidateBorrowFresh( - address liquidator, - address borrower, - uint256 repayAmount, - CTokenInterface cTokenCollateral - ) internal returns (uint256, uint256) { - uint256 allowed = comptroller.liquidateBorrowAllowed( - address(this), - address(cTokenCollateral), - liquidator, - borrower, - repayAmount - ); - if (allowed != 0) { - return ( - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.LIQUIDATE_COMPTROLLER_REJECTION, - allowed - ), - 0 - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return ( - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.LIQUIDATE_FRESHNESS_CHECK - ), - 0 - ); - } - - if (cTokenCollateral.accrualBlockNumber() != getBlockNumber()) { - return ( - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.LIQUIDATE_COLLATERAL_FRESHNESS_CHECK - ), - 0 - ); - } - - if (borrower == liquidator) { - return ( - fail( - Error.INVALID_ACCOUNT_PAIR, - FailureInfo.LIQUIDATE_LIQUIDATOR_IS_BORROWER - ), - 0 - ); - } - - if (repayAmount == 0) { - return ( - fail( - Error.INVALID_CLOSE_AMOUNT_REQUESTED, - FailureInfo.LIQUIDATE_CLOSE_AMOUNT_IS_ZERO - ), - 0 - ); - } - - if (repayAmount == type(uint256).max) { - return ( - fail( - Error.INVALID_CLOSE_AMOUNT_REQUESTED, - FailureInfo.LIQUIDATE_CLOSE_AMOUNT_IS_UINT_MAX - ), - 0 - ); - } - - ( - uint256 repayBorrowError, - uint256 actualRepayAmount - ) = repayBorrowFresh(liquidator, borrower, repayAmount); - if (repayBorrowError != uint256(Error.NO_ERROR)) { - return ( - fail( - Error(repayBorrowError), - FailureInfo.LIQUIDATE_REPAY_BORROW_FRESH_FAILED - ), - 0 - ); - } - - (uint256 amountSeizeError, uint256 seizeTokens) = comptroller - .liquidateCalculateSeizeTokens( - address(this), - address(cTokenCollateral), - actualRepayAmount - ); - require(amountSeizeError == uint256(Error.NO_ERROR), "CT18"); - - require(cTokenCollateral.balanceOf(borrower) >= seizeTokens, "CT19"); - - uint256 seizeError; - if (address(cTokenCollateral) == address(this)) { - seizeError = seizeInternal( - address(this), - liquidator, - borrower, - seizeTokens - ); - } else { - seizeError = cTokenCollateral.seize( - liquidator, - borrower, - seizeTokens - ); - } - - require(seizeError == uint256(Error.NO_ERROR), "CT20"); - - emit LiquidateBorrow( - liquidator, - borrower, - actualRepayAmount, - address(cTokenCollateral), - seizeTokens - ); - - return (uint256(Error.NO_ERROR), actualRepayAmount); - } - - /** - * @notice Transfers collateral tokens (this market) to the liquidator. - * @dev Will fail unless called by another cToken during the process of liquidation. - * Its absolutely critical to use msg.sender as the borrowed cToken and not a parameter. - * @param liquidator The account receiving seized collateral - * @param borrower The account having collateral seized - * @param seizeTokens The number of cTokens to seize - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function seize( - address liquidator, - address borrower, - uint256 seizeTokens - ) external override nonReentrant returns (uint256) { - return seizeInternal(msg.sender, liquidator, borrower, seizeTokens); - } - - struct SeizeVars { - uint256 seizeAmount; - uint256 exchangeRate; - uint256 borrowerTokensNew; - uint256 borrowerAmountNew; - uint256 liquidatorTokensNew; - uint256 liquidatorAmountNew; - uint256 totalCash; - uint256 supplyRate; - } - - /** - * @notice Transfers collateral tokens (this market) to the liquidator. - * @dev Called only during an in-kind liquidation, or by liquidateBorrow during the liquidation of another CToken. - * Its absolutely critical to use msg.sender as the seizer cToken and not a parameter. - * @param seizerToken The contract seizing the collateral (i.e. borrowed cToken) - * @param liquidator The account receiving seized collateral - * @param borrower The account having collateral seized - * @param seizeTokens The number of cTokens to seize - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function seizeInternal( - address seizerToken, - address liquidator, - address borrower, - uint256 seizeTokens - ) internal returns (uint256) { - uint256 allowed = comptroller.seizeAllowed( - address(this), - seizerToken, - liquidator, - borrower, - seizeTokens - ); - if (allowed != 0) { - return - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.LIQUIDATE_SEIZE_COMPTROLLER_REJECTION, - allowed - ); - } - - if (borrower == liquidator) { - return - fail( - Error.INVALID_ACCOUNT_PAIR, - FailureInfo.LIQUIDATE_SEIZE_LIQUIDATOR_IS_BORROWER - ); - } - - SeizeVars memory seizeVars; - - MathError mathErr; - - (mathErr, seizeVars.borrowerTokensNew) = subUInt( - accountTokens[borrower].tokens, - seizeTokens - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.LIQUIDATE_SEIZE_BALANCE_DECREMENT_FAILED, - uint256(mathErr) - ); - } - - seizeVars.totalCash = getCashPrior(); - seizeVars.supplyRate = interestRateModel.getSupplyRate( - seizeVars.totalCash, - totalBorrows, - totalReserves, - reserveFactorMantissa - ); - - (, seizeVars.exchangeRate) = interestRateModel.getExchangeRate( - seizeVars.totalCash, - totalBorrows, - totalReserves, - totalSupply - ); - - if (interestRateModel.isTropykusInterestRateModel()) { - (, seizeVars.exchangeRate) = tropykusExchangeRateStoredInternal( - borrower - ); - } - - (, seizeVars.seizeAmount) = mulUInt( - seizeTokens, - seizeVars.exchangeRate - ); - (, seizeVars.seizeAmount) = divUInt(seizeVars.seizeAmount, 1e18); - - (, seizeVars.borrowerAmountNew) = subUInt( - accountTokens[borrower].underlyingAmount, - seizeVars.seizeAmount - ); - - (mathErr, seizeVars.liquidatorTokensNew) = addUInt( - accountTokens[liquidator].tokens, - seizeTokens - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.LIQUIDATE_SEIZE_BALANCE_INCREMENT_FAILED, - uint256(mathErr) - ); - } - - (, seizeVars.liquidatorAmountNew) = addUInt( - accountTokens[liquidator].underlyingAmount, - seizeVars.seizeAmount - ); - - accountTokens[borrower].tokens = seizeVars.borrowerTokensNew; - accountTokens[borrower].underlyingAmount = seizeVars.borrowerAmountNew; - accountTokens[borrower].suppliedAt = getBlockNumber(); - accountTokens[borrower].promisedSupplyRate = seizeVars.supplyRate; - - accountTokens[liquidator].tokens = seizeVars.liquidatorTokensNew; - accountTokens[liquidator].underlyingAmount = seizeVars - .liquidatorAmountNew; - accountTokens[liquidator].suppliedAt = getBlockNumber(); - accountTokens[liquidator].promisedSupplyRate = seizeVars.supplyRate; - - emit Transfer(borrower, liquidator, seizeTokens); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Begins transfer of admin rights. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer. - * @dev Admin function to begin change of admin. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer. - * @param newPendingAdmin New pending admin. - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setPendingAdmin(address payable newPendingAdmin) - external - override - returns (uint256) - { - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_PENDING_ADMIN_OWNER_CHECK - ); - } - - address oldPendingAdmin = pendingAdmin; - - pendingAdmin = newPendingAdmin; - - emit NewPendingAdmin(oldPendingAdmin, newPendingAdmin); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Accepts transfer of admin rights. msg.sender must be pendingAdmin - * @dev Admin function for pending admin to accept role and update admin - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _acceptAdmin() external override returns (uint256) { - if (msg.sender != pendingAdmin || msg.sender == address(0)) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.ACCEPT_ADMIN_PENDING_ADMIN_CHECK - ); - } - - address oldAdmin = admin; - address oldPendingAdmin = pendingAdmin; - - admin = pendingAdmin; - - pendingAdmin = payable(address(0)); - - emit NewAdmin(oldAdmin, admin); - emit NewPendingAdmin(oldPendingAdmin, pendingAdmin); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Sets a new comptroller for the market - * @dev Admin function to set a new comptroller - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setComptroller(ComptrollerInterface newComptroller) - public - override - returns (uint256) - { - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_COMPTROLLER_OWNER_CHECK - ); - } - - ComptrollerInterface oldComptroller = comptroller; - require(newComptroller.isComptroller(), "CT21"); - - comptroller = newComptroller; - - emit NewComptroller(oldComptroller, newComptroller); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice accrues interest and sets a new reserve factor for the protocol using _setReserveFactorFresh - * @dev Admin function to accrue interest and set a new reserve factor - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setReserveFactor(uint256 newReserveFactorMantissa) - external - override - nonReentrant - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return - fail( - Error(error), - FailureInfo.SET_RESERVE_FACTOR_ACCRUE_INTEREST_FAILED - ); - } - return _setReserveFactorFresh(newReserveFactorMantissa); - } - - /** - * @notice Sets a new reserve factor for the protocol (*requires fresh interest accrual) - * @dev Admin function to set a new reserve factor - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setReserveFactorFresh(uint256 newReserveFactorMantissa) - internal - returns (uint256) - { - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_RESERVE_FACTOR_ADMIN_CHECK - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.SET_RESERVE_FACTOR_FRESH_CHECK - ); - } - - if (newReserveFactorMantissa > reserveFactorMaxMantissa) { - return - fail( - Error.BAD_INPUT, - FailureInfo.SET_RESERVE_FACTOR_BOUNDS_CHECK - ); - } - - uint256 oldReserveFactorMantissa = reserveFactorMantissa; - reserveFactorMantissa = newReserveFactorMantissa; - - emit NewReserveFactor( - oldReserveFactorMantissa, - newReserveFactorMantissa - ); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Accrues interest and reduces reserves by transferring from msg.sender - * @param addAmount Amount of addition to reserves - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _addReservesInternal(uint256 addAmount) - internal - nonReentrant - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return - fail( - Error(error), - FailureInfo.ADD_RESERVES_ACCRUE_INTEREST_FAILED - ); - } - - uint256 totalReservesNew; - uint256 actualAddAmount; - - if (accrualBlockNumber != getBlockNumber()) { - return ( - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.ADD_RESERVES_FRESH_CHECK - ) - ); - } - - actualAddAmount = doTransferIn(msg.sender, addAmount); - - totalReservesNew = totalReserves + actualAddAmount; - - require(totalReservesNew >= totalReserves, "CT22"); - - totalReserves = totalReservesNew; - - emit ReservesAdded(msg.sender, actualAddAmount, totalReservesNew); - - return (uint256(Error.NO_ERROR)); - } - - function _addSubsidyInternal(uint256 addAmount) - internal - nonReentrant - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - // accrueInterest emits logs on errors, but on top of that we want to log the fact that an attempted reduce reserves failed. - return fail(Error(error), FailureInfo.ADD_SUBSIDY_FUND_FAILED); - } - - uint256 subsidyFundNew; - uint256 actualAddAmount; - - if (accrualBlockNumber != getBlockNumber()) { - return ( - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.ADD_SUBSIDY_FUND_FRESH_CHECK - ) - ); - } - - actualAddAmount = doTransferIn(msg.sender, addAmount); - - subsidyFundNew = subsidyFund + actualAddAmount; - - require(subsidyFundNew >= subsidyFund, "CT22"); - - subsidyFund = subsidyFundNew; - - emit SubsidyAdded(msg.sender, actualAddAmount, subsidyFundNew); - - /* Return (NO_ERROR, actualAddAmount) */ - return (uint256(Error.NO_ERROR)); - } - - /** - * @notice Accrues interest and reduces reserves by transferring to admin - * @param reduceAmount Amount of reduction to reserves - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _reduceReserves(uint256 reduceAmount) - external - override - nonReentrant - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return - fail( - Error(error), - FailureInfo.REDUCE_RESERVES_ACCRUE_INTEREST_FAILED - ); - } - return _reduceReservesFresh(reduceAmount); - } - - /** - * @notice Reduces reserves by transferring to admin - * @dev Requires fresh interest accrual - * @param reduceAmount Amount of reduction to reserves - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _reduceReservesFresh(uint256 reduceAmount) - internal - returns (uint256) - { - uint256 totalReservesNew; - - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.REDUCE_RESERVES_ADMIN_CHECK - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.REDUCE_RESERVES_FRESH_CHECK - ); - } - - if (getCashPrior() < reduceAmount) { - return - fail( - Error.TOKEN_INSUFFICIENT_CASH, - FailureInfo.REDUCE_RESERVES_CASH_NOT_AVAILABLE - ); - } - - if (reduceAmount > totalReserves) { - return - fail(Error.BAD_INPUT, FailureInfo.REDUCE_RESERVES_VALIDATION); - } - - totalReservesNew = totalReserves - reduceAmount; - require(totalReservesNew <= totalReserves, "CT23"); - - totalReserves = totalReservesNew; - - doTransferOut(admin, reduceAmount); - - emit ReservesReduced(admin, reduceAmount, totalReservesNew); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice accrues interest and updates the interest rate model using _setInterestRateModelFresh - * @dev Admin function to accrue interest and update the interest rate model - * @param newInterestRateModel the new interest rate model to use - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setInterestRateModel(InterestRateModel newInterestRateModel) - public - override - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return - fail( - Error(error), - FailureInfo.SET_INTEREST_RATE_MODEL_ACCRUE_INTEREST_FAILED - ); - } - return _setInterestRateModelFresh(newInterestRateModel); - } - - /** - * @notice updates the interest rate model (*requires fresh interest accrual) - * @dev Admin function to update the interest rate model - * @param newInterestRateModel the new interest rate model to use - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setInterestRateModelFresh(InterestRateModel newInterestRateModel) - internal - returns (uint256) - { - InterestRateModel oldInterestRateModel; - - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_INTEREST_RATE_MODEL_OWNER_CHECK - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.SET_INTEREST_RATE_MODEL_FRESH_CHECK - ); - } - - oldInterestRateModel = interestRateModel; - - require(newInterestRateModel.isInterestRateModel(), "CT21"); - - interestRateModel = newInterestRateModel; - - emit NewMarketInterestRateModel( - oldInterestRateModel, - newInterestRateModel - ); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Gets balance of this contract in terms of the underlying - * @dev This excludes the value of the current message, if any - * @return The quantity of underlying owned by this contract - */ - function getCashPrior() internal view virtual returns (uint256); - - /** - * @dev Performs a transfer in, reverting upon failure. Returns the amount actually transferred to the protocol, in case of a fee. - * This may revert due to insufficient balance or insufficient allowance. - */ - function doTransferIn(address from, uint256 amount) - internal - virtual - returns (uint256); - - /** - * @dev Performs a transfer out, ideally returning an explanatory error code upon failure tather than reverting. - * If caller has not called checked protocol's balance, may revert due to insufficient cash held in the contract. - * If caller has checked protocol's balance, and verified it is >= amount, this should not revert in normal conditions. - */ - function doTransferOut(address payable to, uint256 amount) internal virtual; - - /** - * @dev Prevents a contract from calling itself, directly or indirectly. - */ - modifier nonReentrant() { - require(_notEntered, "re-entered"); - _notEntered = false; - _; - _notEntered = true; - } -} - - -// Dependency file: contracts/PriceOracle.sol - -// pragma solidity 0.8.6; - -// import "contracts/CToken.sol"; - -abstract contract PriceOracle { - /// @notice Indicator that this is a PriceOracle contract (for inspection) - bool public constant isPriceOracle = true; - - /** - * @notice Get the underlying price of a cToken asset - * @param cToken The cToken to get the underlying price of - * @return The underlying asset price mantissa (scaled by 1e18). - * Zero means the price is unavailable. - */ - function getUnderlyingPrice(CToken cToken) - external - view - virtual - returns (uint256); -} - - -// Dependency file: contracts/ComptrollerStorage.sol - -// pragma solidity 0.8.6; - -// import "contracts/CToken.sol"; -// import "contracts/PriceOracle.sol"; - -contract UnitrollerAdminStorage { - /** - * @notice Administrator for this contract - */ - address public admin; - - /** - * @notice Pending administrator for this contract - */ - address public pendingAdmin; - - /** - * @notice Active brains of Unitroller - */ - address public comptrollerImplementation; - - /** - * @notice Pending brains of Unitroller - */ - address public pendingComptrollerImplementation; -} - -contract ComptrollerV1Storage is UnitrollerAdminStorage { - - /** - * @notice Oracle which gives the price of any given asset - */ - PriceOracle public oracle; - - /** - * @notice Multiplier used to calculate the maximum repayAmount when liquidating a borrow - */ - uint public closeFactorMantissa; - - /** - * @notice Multiplier representing the discount on collateral that a liquidator receives - */ - uint public liquidationIncentiveMantissa; - - /** - * @notice Max number of assets a single account can participate in (borrow or use as collateral) - */ - uint public maxAssets; - - /** - * @notice Per-account mapping of "assets you are in", capped by maxAssets - */ - mapping(address => CToken[]) public accountAssets; - -} - -contract ComptrollerV2Storage is ComptrollerV1Storage { - struct Market { - /// @notice Whether or not this market is listed - bool isListed; - - /** - * @notice Multiplier representing the most one can borrow against their collateral in this market. - * For instance, 0.9 to allow borrowing 90% of collateral value. - * Must be between 0 and 1, and stored as a mantissa. - */ - uint collateralFactorMantissa; - - /// @notice Per-market mapping of "accounts in this asset" - mapping(address => bool) accountMembership; - - /// @notice Whether or not this market receives COMP - bool isComped; - } - - /** - * @notice Official mapping of cTokens -> Market metadata - * @dev Used e.g. to determine if a market is supported - */ - mapping(address => Market) public markets; - - - /** - * @notice The Pause Guardian can pause certain actions as a safety mechanism. - * Actions which allow users to remove their own assets cannot be paused. - * Liquidation / seizing / transfer can only be paused globally, not by market. - */ - address public pauseGuardian; - bool public _mintGuardianPaused; - bool public _borrowGuardianPaused; - bool public transferGuardianPaused; - bool public seizeGuardianPaused; - mapping(address => bool) public mintGuardianPaused; - mapping(address => bool) public borrowGuardianPaused; -} - -contract ComptrollerV3Storage is ComptrollerV2Storage { - struct CompMarketState { - /// @notice The market's last updated compBorrowIndex or compSupplyIndex - uint224 index; - - /// @notice The block number the index was last updated at - uint32 block; - } - - /// @notice A list of all markets - CToken[] public allMarkets; - - /// @notice The rate at which the flywheel distributes COMP, per block - uint public compRate; - - /// @notice The portion of compRate that each market currently receives - mapping(address => uint) public compSpeeds; - - /// @notice The COMP market supply state for each market - mapping(address => CompMarketState) public compSupplyState; - - /// @notice The COMP market borrow state for each market - mapping(address => CompMarketState) public compBorrowState; - - /// @notice The COMP borrow index for each market for each supplier as of the last time they accrued COMP - mapping(address => mapping(address => uint)) public compSupplierIndex; - - /// @notice The COMP borrow index for each market for each borrower as of the last time they accrued COMP - mapping(address => mapping(address => uint)) public compBorrowerIndex; - - /// @notice The COMP accrued but not yet transferred to each user - mapping(address => uint) public compAccrued; -} - -contract ComptrollerV4Storage is ComptrollerV3Storage { - // @notice The borrowCapGuardian can set borrowCaps to any number for any market. Lowering the borrow cap could disable borrowing on the given market. - address public borrowCapGuardian; - - // @notice Borrow caps enforced by borrowAllowed for each cToken address. Defaults to zero which corresponds to unlimited borrowing. - mapping(address => uint) public borrowCaps; - - // @notice address of the TROP token - address public tropAddress; -} - -contract ComptrollerV5Storage is ComptrollerV4Storage { - /// @notice The portion of COMP that each contributor receives per block - mapping(address => uint) public compContributorSpeeds; - - /// @notice Last block at which a contributor's COMP rewards have been allocated - mapping(address => uint) public lastContributorBlock; -} - - -// Dependency file: contracts/Unitroller.sol - -// pragma solidity 0.8.6; - -// import "contracts/ErrorReporter.sol"; -// import "contracts/ComptrollerStorage.sol"; - -/** - * @title ComptrollerCore - * @dev Storage for the comptroller is at this address, while execution is delegated to the `comptrollerImplementation`. - * CTokens should reference this contract as their comptroller. - */ -contract Unitroller is UnitrollerAdminStorage, ComptrollerErrorReporter { - /** - * @notice Emitted when pendingComptrollerImplementation is changed - */ - event NewPendingImplementation( - address oldPendingImplementation, - address newPendingImplementation - ); - - /** - * @notice Emitted when pendingComptrollerImplementation is accepted, which means comptroller implementation is updated - */ - event NewImplementation( - address oldImplementation, - address newImplementation - ); - - /** - * @notice Emitted when pendingAdmin is changed - */ - event NewPendingAdmin(address oldPendingAdmin, address newPendingAdmin); - - /** - * @notice Emitted when pendingAdmin is accepted, which means admin is updated - */ - event NewAdmin(address oldAdmin, address newAdmin); - - constructor() { - // Set admin to caller - admin = msg.sender; - } - - /*** Admin Functions ***/ - function _setPendingImplementation(address newPendingImplementation) - public - returns (uint256) - { - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_PENDING_IMPLEMENTATION_OWNER_CHECK - ); - } - - address oldPendingImplementation = pendingComptrollerImplementation; - - pendingComptrollerImplementation = newPendingImplementation; - - emit NewPendingImplementation( - oldPendingImplementation, - pendingComptrollerImplementation - ); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Accepts new implementation of comptroller. msg.sender must be pendingImplementation - * @dev Admin function for new implementation to accept it's role as implementation - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _acceptImplementation() public returns (uint256) { - // Check caller is pendingImplementation and pendingImplementation ≠ address(0) - if ( - msg.sender != pendingComptrollerImplementation || - pendingComptrollerImplementation == address(0) - ) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.ACCEPT_PENDING_IMPLEMENTATION_ADDRESS_CHECK - ); - } - - // Save current values for inclusion in log - address oldImplementation = comptrollerImplementation; - address oldPendingImplementation = pendingComptrollerImplementation; - - comptrollerImplementation = pendingComptrollerImplementation; - - pendingComptrollerImplementation = address(0); - - emit NewImplementation(oldImplementation, comptrollerImplementation); - emit NewPendingImplementation( - oldPendingImplementation, - pendingComptrollerImplementation - ); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Begins transfer of admin rights. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer. - * @dev Admin function to begin change of admin. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer. - * @param newPendingAdmin New pending admin. - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setPendingAdmin(address newPendingAdmin) - public - returns (uint256) - { - // Check caller = admin - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_PENDING_ADMIN_OWNER_CHECK - ); - } - - // Save current value, if any, for inclusion in log - address oldPendingAdmin = pendingAdmin; - - // Store pendingAdmin with value newPendingAdmin - pendingAdmin = newPendingAdmin; - - // Emit NewPendingAdmin(oldPendingAdmin, newPendingAdmin) - emit NewPendingAdmin(oldPendingAdmin, newPendingAdmin); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Accepts transfer of admin rights. msg.sender must be pendingAdmin - * @dev Admin function for pending admin to accept role and update admin - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _acceptAdmin() public returns (uint256) { - // Check caller is pendingAdmin and pendingAdmin ≠ address(0) - if (msg.sender != pendingAdmin || msg.sender == address(0)) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.ACCEPT_ADMIN_PENDING_ADMIN_CHECK - ); - } - - // Save current values for inclusion in log - address oldAdmin = admin; - address oldPendingAdmin = pendingAdmin; - - // Store admin with value pendingAdmin - admin = pendingAdmin; - - // Clear the pending value - pendingAdmin = address(0); - - emit NewAdmin(oldAdmin, admin); - emit NewPendingAdmin(oldPendingAdmin, pendingAdmin); - - return uint256(Error.NO_ERROR); - } - - /** - * @dev Delegates execution to an implementation contract. - * It returns to the external caller whatever the implementation returns - * or forwards reverts. - */ - function internalFallback() public payable { - // delegate all other functions to current implementation - (bool success, ) = comptrollerImplementation.delegatecall(msg.data); - - assembly { - let free_mem_ptr := mload(0x40) - returndatacopy(free_mem_ptr, 0, returndatasize()) - - switch success - case 0 { - revert(free_mem_ptr, returndatasize()) - } - default { - return(free_mem_ptr, returndatasize()) - } - } - } - - fallback() external payable { - internalFallback(); - } - - receive() external payable { - internalFallback(); - } -} - - -// Dependency file: contracts/Governance/TROP.sol - -// pragma solidity 0.8.6; -pragma experimental ABIEncoderV2; - -/** - * @title TROP ERC20 tokens. - * @author tropykus - * @notice Yield farming tokens that allow to propose and vote for protocol changes using the governance system. - */ -contract TROP { - /// @notice EIP-20 token name for this token - string public constant name = "tropykus"; - - /// @notice EIP-20 token symbol for this token - string public constant symbol = "TROP"; - - /// @notice EIP-20 token decimals for this token - uint8 public constant decimals = 18; - - /// @notice Total number of tokens in circulation - uint256 public constant totalSupply = 10000000e18; // 10 million TROP - - /// @notice Allowance amounts on behalf of others - mapping(address => mapping(address => uint96)) internal allowances; - - /// @notice Official record of token balances for each account - mapping(address => uint96) internal balances; - - /// @notice A record of each accounts delegate - mapping(address => address) public delegates; - - /// @notice A checkpoint for marking number of votes from a given block - struct Checkpoint { - uint32 fromBlock; - uint96 votes; - } - - /// @notice A record of votes checkpoints for each account, by index - mapping(address => mapping(uint32 => Checkpoint)) public checkpoints; - - /// @notice The number of checkpoints for each account - mapping(address => uint32) public numCheckpoints; - - /// @notice The EIP-712 typehash for the contract's domain - bytes32 public constant DOMAIN_TYPEHASH = - keccak256( - "EIP712Domain(string name,uint256 chainId,address verifyingContract)" - ); - - /// @notice The EIP-712 typehash for the delegation struct used by the contract - bytes32 public constant DELEGATION_TYPEHASH = - keccak256("Delegation(address delegatee,uint256 nonce,uint256 expiry)"); - - /// @notice A record of states for signing / validating signatures - mapping(address => uint256) public nonces; - - /// @notice An event thats emitted when an account changes its delegate - event DelegateChanged( - address indexed delegator, - address indexed fromDelegate, - address indexed toDelegate - ); - - /// @notice An event thats emitted when a delegate account's vote balance changes - event DelegateVotesChanged( - address indexed delegate, - uint256 previousBalance, - uint256 newBalance - ); - - /// @notice The standard EIP-20 transfer event - event Transfer(address indexed from, address indexed to, uint256 amount); - - /// @notice The standard EIP-20 approval event - event Approval( - address indexed owner, - address indexed spender, - uint256 amount - ); - - /** - * @notice Construct a new TROP token - * @param account The initial account to grant all the tokens - */ - constructor(address account) { - balances[account] = uint96(totalSupply); - emit Transfer(address(0), account, totalSupply); - } - - /** - * @notice Get the number of tokens `spender` is approved to spend on behalf of `account` - * @param account The address of the account holding the funds - * @param spender The address of the account spending the funds - * @return The number of tokens approved - */ - function allowance(address account, address spender) - external - view - returns (uint256) - { - return allowances[account][spender]; - } - - /** - * @notice Approve `spender` to transfer up to `amount` from `src` - * @dev This will overwrite the approval amount for `spender` - * and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve) - * @param spender The address of the account which may transfer tokens - * @param rawAmount The number of tokens that are approved (2^256-1 means infinite) - * @return Whether or not the approval succeeded - */ - function approve(address spender, uint256 rawAmount) - external - returns (bool) - { - uint96 amount; - if (rawAmount == type(uint256).max) { - amount = type(uint96).max; - } else { - amount = safe96(rawAmount, "TROP::approve: amount exceeds 96 bits"); - } - - allowances[msg.sender][spender] = amount; - - emit Approval(msg.sender, spender, amount); - return true; - } - - /** - * @notice Get the number of tokens held by the `account` - * @param account The address of the account to get the balance of - * @return The number of tokens held - */ - function balanceOf(address account) external view returns (uint256) { - return balances[account]; - } - - /** - * @notice Transfer `amount` tokens from `msg.sender` to `dst` - * @param dst The address of the destination account - * @param rawAmount The number of tokens to transfer - * @return Whether or not the transfer succeeded - */ - function transfer(address dst, uint256 rawAmount) external returns (bool) { - uint96 amount = safe96( - rawAmount, - "TROP::transfer: amount exceeds 96 bits" - ); - _transferTokens(msg.sender, dst, amount); - return true; - } - - /** - * @notice Transfer `amount` tokens from `src` to `dst` - * @param src The address of the source account - * @param dst The address of the destination account - * @param rawAmount The number of tokens to transfer - * @return Whether or not the transfer succeeded - */ - function transferFrom( - address src, - address dst, - uint256 rawAmount - ) external returns (bool) { - address spender = msg.sender; - uint96 spenderAllowance = allowances[src][spender]; - uint96 amount = safe96( - rawAmount, - "TROP::approve: amount exceeds 96 bits" - ); - - if (spender != src && spenderAllowance != type(uint96).max) { - uint96 newAllowance = sub96( - spenderAllowance, - amount, - "TROP::transferFrom: transfer amount exceeds spender allowance" - ); - allowances[src][spender] = newAllowance; - - emit Approval(src, spender, newAllowance); - } - - _transferTokens(src, dst, amount); - return true; - } - - /** - * @notice Delegate votes from `msg.sender` to `delegatee` - * @param delegatee The address to delegate votes to - */ - function delegate(address delegatee) public { - return _delegate(msg.sender, delegatee); - } - - /** - * @notice Delegates votes from signatory to `delegatee` - * @param delegatee The address to delegate votes to - * @param nonce The contract state required to match the signature - * @param expiry The time at which to expire the signature - * @param v The recovery byte of the signature - * @param r Half of the ECDSA signature pair - * @param s Half of the ECDSA signature pair - */ - function delegateBySig( - address delegatee, - uint256 nonce, - uint256 expiry, - uint8 v, - bytes32 r, - bytes32 s - ) public { - bytes32 domainSeparator = keccak256( - abi.encode( - DOMAIN_TYPEHASH, - keccak256(bytes(name)), - getChainId(), - address(this) - ) - ); - bytes32 structHash = keccak256( - abi.encode(DELEGATION_TYPEHASH, delegatee, nonce, expiry) - ); - bytes32 digest = keccak256( - abi.encodePacked("\x19\x01", domainSeparator, structHash) - ); - address signatory = ecrecover(digest, v, r, s); - require( - signatory != 0xdcc703c0E500B653Ca82273B7BFAd8045D85a470 && - signatory != address(0), - "TROP::delegateBySig: invalid signature" - ); - require( - nonce == nonces[signatory]++, - "TROP::delegateBySig: invalid nonce" - ); - require( - block.timestamp <= expiry, - "TROP::delegateBySig: signature expired" - ); - return _delegate(signatory, delegatee); - } - - /** - * @notice Gets the current votes balance for `account` - * @param account The address to get votes balance - * @return The number of current votes for `account` - */ - function getCurrentVotes(address account) external view returns (uint96) { - uint32 nCheckpoints = numCheckpoints[account]; - return - nCheckpoints > 0 ? checkpoints[account][nCheckpoints - 1].votes : 0; - } - - /** - * @notice Determine the prior number of votes for an account as of a block number - * @dev Block number must be a finalized block or else this function will revert to prevent misinformation. - * @param account The address of the account to check - * @param blockNumber The block number to get the vote balance at - * @return The number of votes the account had as of the given block - */ - function getPriorVotes(address account, uint256 blockNumber) - public - view - returns (uint96) - { - require( - blockNumber < block.number, - "TROP::getPriorVotes: not yet determined" - ); - - uint32 nCheckpoints = numCheckpoints[account]; - if (nCheckpoints == 0) { - return 0; - } - - // First check most recent balance - if (checkpoints[account][nCheckpoints - 1].fromBlock <= blockNumber) { - return checkpoints[account][nCheckpoints - 1].votes; - } - - // Next check implicit zero balance - if (checkpoints[account][0].fromBlock > blockNumber) { - return 0; - } - - uint32 lower = 0; - uint32 upper = nCheckpoints - 1; - while (upper > lower) { - uint32 center = upper - (upper - lower) / 2; // ceil, avoiding overflow - Checkpoint memory cp = checkpoints[account][center]; - if (cp.fromBlock == blockNumber) { - return cp.votes; - } else if (cp.fromBlock < blockNumber) { - lower = center; - } else { - upper = center - 1; - } - } - return checkpoints[account][lower].votes; - } - - function _delegate(address delegator, address delegatee) internal { - address currentDelegate = delegates[delegator]; - uint96 delegatorBalance = balances[delegator]; - delegates[delegator] = delegatee; - - emit DelegateChanged(delegator, currentDelegate, delegatee); - - _moveDelegates(currentDelegate, delegatee, delegatorBalance); - } - - function _transferTokens( - address src, - address dst, - uint96 amount - ) internal { - require( - src != address(0), - "TROP::_transferTokens: cannot transfer from the zero address" - ); - require( - dst != address(0), - "TROP::_transferTokens: cannot transfer to the zero address" - ); - - balances[src] = sub96( - balances[src], - amount, - "TROP::_transferTokens: transfer amount exceeds balance" - ); - balances[dst] = add96( - balances[dst], - amount, - "TROP::_transferTokens: transfer amount overflows" - ); - emit Transfer(src, dst, amount); - - _moveDelegates(delegates[src], delegates[dst], amount); - } - - function _moveDelegates( - address srcRep, - address dstRep, - uint96 amount - ) internal { - if (srcRep != dstRep && amount > 0) { - if (srcRep != address(0)) { - uint32 srcRepNum = numCheckpoints[srcRep]; - uint96 srcRepOld = srcRepNum > 0 - ? checkpoints[srcRep][srcRepNum - 1].votes - : 0; - uint96 srcRepNew = sub96( - srcRepOld, - amount, - "TROP::_moveVotes: vote amount underflows" - ); - _writeCheckpoint(srcRep, srcRepNum, srcRepOld, srcRepNew); - } - - if (dstRep != address(0)) { - uint32 dstRepNum = numCheckpoints[dstRep]; - uint96 dstRepOld = dstRepNum > 0 - ? checkpoints[dstRep][dstRepNum - 1].votes - : 0; - uint96 dstRepNew = add96( - dstRepOld, - amount, - "TROP::_moveVotes: vote amount overflows" - ); - _writeCheckpoint(dstRep, dstRepNum, dstRepOld, dstRepNew); - } - } - } - - function _writeCheckpoint( - address delegatee, - uint32 nCheckpoints, - uint96 oldVotes, - uint96 newVotes - ) internal { - uint32 blockNumber = safe32( - block.number, - "TROP::_writeCheckpoint: block number exceeds 32 bits" - ); - - if ( - nCheckpoints > 0 && - checkpoints[delegatee][nCheckpoints - 1].fromBlock == blockNumber - ) { - checkpoints[delegatee][nCheckpoints - 1].votes = newVotes; - } else { - checkpoints[delegatee][nCheckpoints] = Checkpoint( - blockNumber, - newVotes - ); - numCheckpoints[delegatee] = nCheckpoints + 1; - } - - emit DelegateVotesChanged(delegatee, oldVotes, newVotes); - } - - function safe32(uint256 n, string memory errorMessage) - internal - pure - returns (uint32) - { - require(n < 2**32, errorMessage); - return uint32(n); - } - - function safe96(uint256 n, string memory errorMessage) - internal - pure - returns (uint96) - { - require(n < 2**96, errorMessage); - return uint96(n); - } - - function add96( - uint96 a, - uint96 b, - string memory errorMessage - ) internal pure returns (uint96) { - uint96 c = a + b; - require(c >= a, errorMessage); - return c; - } - - function sub96( - uint96 a, - uint96 b, - string memory errorMessage - ) internal pure returns (uint96) { - require(b <= a, errorMessage); - return a - b; - } - - function getChainId() internal view returns (uint256) { - uint256 chainId; - assembly { - chainId := chainid() - } - return chainId; - } -} - - -// Root file: contracts/Comptroller.sol - -pragma solidity 0.8.6; - -// import "contracts/CToken.sol"; -// import "contracts/ErrorReporter.sol"; -// import "contracts/PriceOracle.sol"; -// import "contracts/ComptrollerInterface.sol"; -// import "contracts/ComptrollerStorage.sol"; -// import "contracts/Unitroller.sol"; -// import "contracts/Governance/TROP.sol"; - -/** - * @title tropykus Comptroller Contract - * @author tropykus - */ -contract Comptroller is - ComptrollerV5Storage, - ComptrollerInterface, - ComptrollerErrorReporter, - ExponentialNoError -{ - /// @notice Emitted when an admin supports a market - event MarketListed(CToken cToken); - - /// @notice Emitted when an account enters a market - event MarketEntered(CToken cToken, address account); - - /// @notice Emitted when an account exits a market - event MarketExited(CToken cToken, address account); - - /// @notice Emitted when close factor is changed by admin - event NewCloseFactor( - uint256 oldCloseFactorMantissa, - uint256 newCloseFactorMantissa - ); - - /// @notice Emitted when a collateral factor is changed by admin - event NewCollateralFactor( - CToken cToken, - uint256 oldCollateralFactorMantissa, - uint256 newCollateralFactorMantissa - ); - - /// @notice Emitted when liquidation incentive is changed by admin - event NewLiquidationIncentive( - uint256 oldLiquidationIncentiveMantissa, - uint256 newLiquidationIncentiveMantissa - ); - - /// @notice Emitted when price oracle is changed - event NewPriceOracle( - PriceOracle oldPriceOracle, - PriceOracle newPriceOracle - ); - - /// @notice Emitted when pause guardian is changed - event NewPauseGuardian(address oldPauseGuardian, address newPauseGuardian); - - /// @notice Emitted when an action is paused globally - event ActionPaused(string action, bool pauseState); - - /// @notice Emitted when an action is paused on a market - event ActionPaused(CToken cToken, string action, bool pauseState); - - /// @notice Emitted when a new COMP speed is calculated for a market - event CompSpeedUpdated(CToken indexed cToken, uint256 newSpeed); - - /// @notice Emitted when a new COMP speed is set for a contributor - event ContributorCompSpeedUpdated( - address indexed contributor, - uint256 newSpeed - ); - - /// @notice Emitted when COMP is distributed to a supplier - event DistributedSupplierComp( - CToken indexed cToken, - address indexed supplier, - uint256 compDelta, - uint256 compSupplyIndex - ); - - /// @notice Emitted when COMP is distributed to a borrower - event DistributedBorrowerComp( - CToken indexed cToken, - address indexed borrower, - uint256 compDelta, - uint256 compBorrowIndex - ); - - /// @notice Emitted when borrow cap for a cToken is changed - event NewBorrowCap(CToken indexed cToken, uint256 newBorrowCap); - - /// @notice Emitted when borrow cap guardian is changed - event NewBorrowCapGuardian( - address oldBorrowCapGuardian, - address newBorrowCapGuardian - ); - - /// @notice Emitted when COMP is granted by admin - event CompGranted(address recipient, uint256 amount); - - /// @notice The initial COMP index for a market - uint224 public constant compInitialIndex = 1e36; - - // closeFactorMantissa must be strictly greater than this value - uint256 internal constant closeFactorMinMantissa = 0.05e18; // 0.05 - - // closeFactorMantissa must not exceed this value - uint256 internal constant closeFactorMaxMantissa = 0.9e18; // 0.9 - - // No collateralFactorMantissa may exceed this value - uint256 internal constant collateralFactorMaxMantissa = 0.9e18; // 0.9 - - constructor() { - admin = msg.sender; - } - - /*** Assets You Are In ***/ - - /** - * @notice Returns the assets an account has entered - * @param account The address of the account to pull assets for - * @return A dynamic list with the assets the account has entered - */ - function getAssetsIn(address account) - external - view - returns (CToken[] memory) - { - return accountAssets[account]; - } - - /** - * @notice Returns whether the given account is entered in the given asset - * @param account The address of the account to check - * @param cToken The cToken to check - * @return True if the account is in the asset, otherwise false. - */ - function checkMembership(address account, CToken cToken) - external - view - returns (bool) - { - return markets[address(cToken)].accountMembership[account]; - } - - /** - * @notice Add assets to be included in account liquidity calculation - * @param cTokens The list of addresses of the cToken markets to be enabled - * @return Success indicator for whether each corresponding market was entered - */ - function enterMarkets(address[] memory cTokens) - public - override - returns (uint256[] memory) - { - uint256 len = cTokens.length; - - uint256[] memory results = new uint256[](len); - for (uint256 i = 0; i < len; i++) { - CToken cToken = CToken(cTokens[i]); - - results[i] = uint256(addToMarketInternal(cToken, msg.sender)); - } - - return results; - } - - /** - * @notice Add the market to the borrower's "assets in" for liquidity calculations - * @param cToken The market to enter - * @param borrower The address of the account to modify - * @return Success indicator for whether the market was entered - */ - function addToMarketInternal(CToken cToken, address borrower) - internal - returns (Error) - { - Market storage marketToJoin = markets[address(cToken)]; - - if (!marketToJoin.isListed) { - // market is not listed, cannot join - return Error.MARKET_NOT_LISTED; - } - - if (marketToJoin.accountMembership[borrower] == true) { - // already joined - return Error.NO_ERROR; - } - - // survived the gauntlet, add to list - // NOTE: we store these somewhat redundantly as a significant optimization - // this avoids having to iterate through the list for the most common use cases - // that is, only when we need to perform liquidity checks - // and not whenever we want to check if an account is in a particular market - marketToJoin.accountMembership[borrower] = true; - accountAssets[borrower].push(cToken); - - emit MarketEntered(cToken, borrower); - - return Error.NO_ERROR; - } - - /** - * @notice Removes asset from sender's account liquidity calculation - * @dev Sender must not have an outstanding borrow balance in the asset, - * or be providing necessary collateral for an outstanding borrow. - * @param cTokenAddress The address of the asset to be removed - * @return Whether or not the account successfully exited the market - */ - function exitMarket(address cTokenAddress) - external - override - returns (uint256) - { - CToken cToken = CToken(cTokenAddress); - /* Get sender tokensHeld and amountOwed underlying from the cToken */ - (uint256 oErr, uint256 tokensHeld, uint256 amountOwed, ) = cToken - .getAccountSnapshot(msg.sender); - require(oErr == 0, "getAccountSnapshot failed"); // semi-opaque error code - - /* Fail if the sender has a borrow balance */ - if (amountOwed != 0) { - return - fail( - Error.NONZERO_BORROW_BALANCE, - FailureInfo.EXIT_MARKET_BALANCE_OWED - ); - } - - /* Fail if the sender is not permitted to redeem all of their tokens */ - uint256 allowed = redeemAllowedInternal( - cTokenAddress, - msg.sender, - tokensHeld - ); - if (allowed != 0) { - return - failOpaque( - Error.REJECTION, - FailureInfo.EXIT_MARKET_REJECTION, - allowed - ); - } - - Market storage marketToExit = markets[address(cToken)]; - - /* Return true if the sender is not already ‘in’ the market */ - if (!marketToExit.accountMembership[msg.sender]) { - return uint256(Error.NO_ERROR); - } - - /* Set cToken account membership to false */ - delete marketToExit.accountMembership[msg.sender]; - - /* Delete cToken from the account’s list of assets */ - // load into memory for faster iteration - CToken[] memory userAssetList = accountAssets[msg.sender]; - accountAssets[msg.sender] = new CToken[](0); - CToken[] storage newMarketList = accountAssets[msg.sender]; - uint256 len = userAssetList.length; - uint256 assetIndex = len; - for (uint256 i = 0; i < len; i++) { - if (userAssetList[i] == cToken) { - assetIndex = i; - continue; - } - newMarketList.push(userAssetList[i]); - } - - // We *must* have found the asset in the list or our redundant data structure is broken - assert(assetIndex < len); - - emit MarketExited(cToken, msg.sender); - - return uint256(Error.NO_ERROR); - } - - /*** Policy Hooks ***/ - - // /** - // * @notice Checks if the account should be allowed to mint tokens in the given market - // * @param cToken The market to verify the mint against - // * @param minter The account which would get the minted tokens - // * @param mintAmount The amount of underlying being supplied to the market in exchange for tokens - // * @return 0 if the mint is allowed, otherwise a semi-opaque error code (See ErrorReporter.sol) - // */ - function mintAllowed( - address cToken, - address minter, - uint256 - ) external override returns (uint256) { - // Shh - currently unused mintAmount - // Pausing is a very serious situation - we revert to sound the alarms - require(!mintGuardianPaused[cToken], "mint is paused"); - - if (!markets[cToken].isListed) { - return uint256(Error.MARKET_NOT_LISTED); - } - - // Keep the flywheel moving - updateCompSupplyIndex(cToken); - distributeSupplierComp(cToken, minter); - - return uint256(Error.NO_ERROR); - } - - // /** - // * @notice Validates mint and reverts on rejection. May emit logs. - // * @param cToken Asset being minted - // * @param minter The address minting the tokens - // * @param actualMintAmount The amount of the underlying asset being minted - // * @param mintTokens The number of tokens being minted - // */ - function mintVerify( - address, - address, - uint256, - uint256 - ) external override { - // Shh - we don't ever want this hook to be marked pure - } - - /** - * @notice Checks if the account should be allowed to redeem tokens in the given market - * @param cToken The market to verify the redeem against - * @param redeemer The account which would redeem the tokens - * @param redeemTokens The number of cTokens to exchange for the underlying asset in the market - * @return 0 if the redeem is allowed, otherwise a semi-opaque error code (See ErrorReporter.sol) - */ - function redeemAllowed( - address cToken, - address redeemer, - uint256 redeemTokens - ) external override returns (uint256) { - uint256 allowed = redeemAllowedInternal(cToken, redeemer, redeemTokens); - if (allowed != uint256(Error.NO_ERROR)) { - return allowed; - } - - // Keep the flywheel moving - updateCompSupplyIndex(cToken); - distributeSupplierComp(cToken, redeemer); - - return uint256(Error.NO_ERROR); - } - - function redeemAllowedInternal( - address cToken, - address redeemer, - uint256 redeemTokens - ) internal view returns (uint256) { - if (!markets[cToken].isListed) { - return uint256(Error.MARKET_NOT_LISTED); - } - - /* If the redeemer is not 'in' the market, then we can bypass the liquidity check */ - if (!markets[cToken].accountMembership[redeemer]) { - return uint256(Error.NO_ERROR); - } - - /* Otherwise, perform a hypothetical liquidity check to guard against shortfall */ - ( - Error err, - , - uint256 shortfall - ) = getHypotheticalAccountLiquidityInternal( - redeemer, - CToken(cToken), - redeemTokens, - 0 - ); - if (err != Error.NO_ERROR) { - return uint256(err); - } - if (shortfall > 0) { - return uint256(Error.INSUFFICIENT_LIQUIDITY); - } - - return uint256(Error.NO_ERROR); - } - - // /** - // * @notice Validates redeem and reverts on rejection. May emit logs. - // * @param cToken Asset being redeemed - // * @param redeemer The address redeeming the tokens - // * @param redeemAmount The amount of the underlying asset being redeemed - // * @param redeemTokens The number of tokens being redeemed - // */ - function redeemVerify( - address, - address, - uint256 redeemAmount, - uint256 redeemTokens - ) external pure override { - // Shh - currently unused cToken, redeemer - - // Require tokens is zero or amount is also zero - if (redeemTokens == 0 && redeemAmount > 0) { - revert("redeemTokens zero"); - } - } - - /** - * @notice Checks if the account should be allowed to borrow the underlying asset of the given market - * @param cToken The market to verify the borrow against - * @param borrower The account which would borrow the asset - * @param borrowAmount The amount of underlying the account would borrow - * @return 0 if the borrow is allowed, otherwise a semi-opaque error code (See ErrorReporter.sol) - */ - function borrowAllowed( - address cToken, - address borrower, - uint256 borrowAmount - ) external override returns (uint256) { - // Pausing is a very serious situation - we revert to sound the alarms - Error err; - uint256 shortfall; - require(!borrowGuardianPaused[cToken], "borrow is paused"); - - if (!markets[cToken].isListed) { - return uint256(Error.MARKET_NOT_LISTED); - } - - if (!markets[cToken].accountMembership[borrower]) { - // only cTokens may call borrowAllowed if borrower not in market - require(msg.sender == cToken, "sender not cToken"); - - // attempt to add borrower to the market - err = addToMarketInternal(CToken(msg.sender), borrower); - if (err != Error.NO_ERROR) { - return uint256(err); - } - - // it should be impossible to break the // important invariant - assert(markets[cToken].accountMembership[borrower]); - } - - if (oracle.getUnderlyingPrice(CToken(cToken)) == 0) { - return uint256(Error.PRICE_ERROR); - } - - uint256 borrowCap = borrowCaps[cToken]; - // Borrow cap of 0 corresponds to unlimited borrowing - if (borrowCap != 0) { - uint256 totalBorrows = CToken(cToken).totalBorrows(); - uint256 nextTotalBorrows = add_(totalBorrows, borrowAmount); - require(nextTotalBorrows < borrowCap, "market borrow cap reached"); - } - - (err, , shortfall) = getHypotheticalAccountLiquidityInternal( - borrower, - CToken(cToken), - 0, - borrowAmount - ); - if (err != Error.NO_ERROR) { - return uint256(err); - } - if (shortfall > 0) { - return uint256(Error.INSUFFICIENT_LIQUIDITY); - } - - // Keep the flywheel moving - Exp memory borrowIndex = Exp({mantissa: CToken(cToken).borrowIndex()}); - updateCompBorrowIndex(cToken, borrowIndex); - distributeBorrowerComp(cToken, borrower, borrowIndex); - - return uint256(Error.NO_ERROR); - } - - // /** - // * @notice Validates borrow and reverts on rejection. May emit logs. Currently unused - // * @param cToken Asset whose underlying is being borrowed - // * @param borrower The address borrowing the underlying - // * @param borrowAmount The amount of the underlying asset requested to borrow - // */ - function borrowVerify( - address, - address, - uint256 - ) external override { - // Shh - currently unused - // Shh - we don't ever want this hook to be marked pure - } - - // /** - // * @notice Checks if the account should be allowed to repay a borrow in the given market - // * @param cToken The market to verify the repay against - // * @param payer The account which would repay the asset - // * @param borrower The account which would borrowed the asset - // * @param repayAmount The amount of the underlying asset the account would repay - // * @return 0 if the repay is allowed, otherwise a semi-opaque error code (See ErrorReporter.sol) - // */ - function repayBorrowAllowed( - address cToken, - address, - address borrower, - uint256 - ) external override returns (uint256) { - // Shh - currently unused payer, repayAmount - - if (!markets[cToken].isListed) { - return uint256(Error.MARKET_NOT_LISTED); - } - - // Keep the flywheel moving - Exp memory borrowIndex = Exp({mantissa: CToken(cToken).borrowIndex()}); - updateCompBorrowIndex(cToken, borrowIndex); - distributeBorrowerComp(cToken, borrower, borrowIndex); - - return uint256(Error.NO_ERROR); - } - - // /** - // * @notice Validates repayBorrow and reverts on rejection. May emit logs. Currently unused - // * @param cToken Asset being repaid - // * @param payer The address repaying the borrow - // * @param borrower The address of the borrower - // * @param actualRepayAmount The amount of underlying being repaid - // */ - function repayBorrowVerify( - address, - address, - address, - uint256, - uint256 - ) external override { - // Shh - currently unused - // Shh - we don't ever want this hook to be marked pure - } - - // /** - // * @notice Checks if the liquidation should be allowed to occur - // * @param cTokenBorrowed Asset which was borrowed by the borrower - // * @param cTokenCollateral Asset which was used as collateral and will be seized - // * @param liquidator The address repaying the borrow and seizing the collateral - // * @param borrower The address of the borrower - // * @param repayAmount The amount of underlying being repaid - // */ - function liquidateBorrowAllowed( - address cTokenBorrowed, - address cTokenCollateral, - address, - address borrower, - uint256 repayAmount - ) external view override returns (uint256) { - // Shh - currently unused liquidator - - if ( - !markets[cTokenBorrowed].isListed || - !markets[cTokenCollateral].isListed - ) { - return uint256(Error.MARKET_NOT_LISTED); - } - - /* The borrower must have shortfall in order to be liquidatable */ - (Error err, , uint256 shortfall) = getAccountLiquidityInternal( - borrower - ); - if (err != Error.NO_ERROR) { - return uint256(err); - } - if (shortfall == 0) { - return uint256(Error.INSUFFICIENT_SHORTFALL); - } - - /* The liquidator may not repay more than what is allowed by the closeFactor */ - uint256 borrowBalance = CToken(cTokenBorrowed).borrowBalanceStored( - borrower - ); - uint256 maxClose = mul_ScalarTruncate( - Exp({mantissa: closeFactorMantissa}), - borrowBalance - ); - if (repayAmount > maxClose) { - return uint256(Error.TOO_MUCH_REPAY); - } - - return uint256(Error.NO_ERROR); - } - - // /** - // * @notice Validates liquidateBorrow and reverts on rejection. May emit logs. Currently unused - // * @param cTokenBorrowed Asset which was borrowed by the borrower - // * @param cTokenCollateral Asset which was used as collateral and will be seized - // * @param liquidator The address repaying the borrow and seizing the collateral - // * @param borrower The address of the borrower - // * @param actualRepayAmount The amount of underlying being repaid - // */ - function liquidateBorrowVerify( - address, - address, - address, - address, - uint256, - uint256 - ) external override { - // Shh - currently unused - // Shh - we don't ever want this hook to be marked pure - } - - // /** - // * @notice Checks if the seizing of assets should be allowed to occur - // * @param cTokenCollateral Asset which was used as collateral and will be seized - // * @param cTokenBorrowed Asset which was borrowed by the borrower - // * @param liquidator The address repaying the borrow and seizing the collateral - // * @param borrower The address of the borrower - // * @param seizeTokens The number of collateral tokens to seize - // */ - function seizeAllowed( - address cTokenCollateral, - address cTokenBorrowed, - address liquidator, - address borrower, - uint256 - ) external override returns (uint256) { - // Pausing is a very serious situation - we revert to sound the alarms - require(!seizeGuardianPaused, "seize is paused"); - - // Shh - currently unused seizeTokens; - - if ( - !markets[cTokenCollateral].isListed || - !markets[cTokenBorrowed].isListed - ) { - return uint256(Error.MARKET_NOT_LISTED); - } - - if ( - CToken(cTokenCollateral).comptroller() != - CToken(cTokenBorrowed).comptroller() - ) { - return uint256(Error.COMPTROLLER_MISMATCH); - } - - // Keep the flywheel moving - updateCompSupplyIndex(cTokenCollateral); - distributeSupplierComp(cTokenCollateral, borrower); - distributeSupplierComp(cTokenCollateral, liquidator); - - return uint256(Error.NO_ERROR); - } - - // /** - // * @notice Validates seize and reverts on rejection. May emit logs. Currently unused - // * @param cTokenCollateral Asset which was used as collateral and will be seized - // * @param cTokenBorrowed Asset which was borrowed by the borrower - // * @param liquidator The address repaying the borrow and seizing the collateral - // * @param borrower The address of the borrower - // * @param seizeTokens The number of collateral tokens to seize - // */ - function seizeVerify( - address, - address, - address, - address, - uint256 - ) external override { - // Shh - currently unused - // Shh - we don't ever want this hook to be marked pure - } - - /** - * @notice Checks if the account should be allowed to transfer tokens in the given market - * @param cToken The market to verify the transfer against - * @param src The account which sources the tokens - * @param dst The account which receives the tokens - * @param transferTokens The number of cTokens to transfer - * @return 0 if the transfer is allowed, otherwise a semi-opaque error code (See ErrorReporter.sol) - */ - function transferAllowed( - address cToken, - address src, - address dst, - uint256 transferTokens - ) external override returns (uint256) { - // Pausing is a very serious situation - we revert to sound the alarms - require(!transferGuardianPaused, "transfer is paused"); - - // Currently the only consideration is whether or not - // the src is allowed to redeem this many tokens - uint256 allowed = redeemAllowedInternal(cToken, src, transferTokens); - if (allowed != uint256(Error.NO_ERROR)) { - return allowed; - } - - // Keep the flywheel moving - updateCompSupplyIndex(cToken); - distributeSupplierComp(cToken, src); - distributeSupplierComp(cToken, dst); - - return uint256(Error.NO_ERROR); - } - - // /** - // * @notice Validates transfer and reverts on rejection. May emit logs. Currently unused - // * @param cToken Asset being transferred - // * @param src The account which sources the tokens - // * @param dst The account which receives the tokens - // * @param transferTokens The number of cTokens to transfer - // */ - function transferVerify( - address, - address, - address, - uint256 - ) external override { - // Shh - currently unused - // Shh - we don't ever want this hook to be marked pure - } - - /*** Liquidity/Liquidation Calculations ***/ - - /** - * @dev Local vars for avoiding stack-depth limits in calculating account liquidity. - * Note that `cTokenBalance` is the number of cTokens the account owns in the market, - * whereas `borrowBalance` is the amount of underlying that the account has borrowed. - */ - struct AccountLiquidityLocalVars { - uint256 sumCollateral; - uint256 sumBorrowPlusEffects; - uint256 cTokenBalance; - uint256 borrowBalance; - uint256 exchangeRateMantissa; - uint256 oraclePriceMantissa; - Exp collateralFactor; - Exp exchangeRate; - Exp oraclePrice; - Exp tokensToDenom; - } - - /** - * @notice Determine the current account liquidity wrt collateral requirements - * @return (possible error code (semi-opaque), - account liquidity in excess of collateral requirements, - * account shortfall below collateral requirements) - */ - function getAccountLiquidity(address account) - public - view - returns ( - uint256, - uint256, - uint256 - ) - { - ( - Error err, - uint256 liquidity, - uint256 shortfall - ) = getHypotheticalAccountLiquidityInternal( - account, - CToken(address(0)), - 0, - 0 - ); - - return (uint256(err), liquidity, shortfall); - } - - /** - * @notice Determine the current account liquidity wrt collateral requirements - * @return (possible error code, - account liquidity in excess of collateral requirements, - * account shortfall below collateral requirements) - */ - function getAccountLiquidityInternal(address account) - internal - view - returns ( - Error, - uint256, - uint256 - ) - { - return - getHypotheticalAccountLiquidityInternal( - account, - CToken(address(0)), - 0, - 0 - ); - } - - /** - * @notice Determine what the account liquidity would be if the given amounts were redeemed/borrowed - * @param cTokenModify The market to hypothetically redeem/borrow in - * @param account The account to determine liquidity for - * @param redeemTokens The number of tokens to hypothetically redeem - * @param borrowAmount The amount of underlying to hypothetically borrow - * @return (possible error code (semi-opaque), - hypothetical account liquidity in excess of collateral requirements, - * hypothetical account shortfall below collateral requirements) - */ - function getHypotheticalAccountLiquidity( - address account, - address cTokenModify, - uint256 redeemTokens, - uint256 borrowAmount - ) - public - view - returns ( - uint256, - uint256, - uint256 - ) - { - ( - Error err, - uint256 liquidity, - uint256 shortfall - ) = getHypotheticalAccountLiquidityInternal( - account, - CToken(cTokenModify), - redeemTokens, - borrowAmount - ); - return (uint256(err), liquidity, shortfall); - } - - /** - * @notice Determine what the account liquidity would be if the given amounts were redeemed/borrowed - * @param cTokenModify The market to hypothetically redeem/borrow in - * @param account The account to determine liquidity for - * @param redeemTokens The number of tokens to hypothetically redeem - * @param borrowAmount The amount of underlying to hypothetically borrow - * @dev Note that we calculate the exchangeRateStored for each collateral cToken using stored data, - * without calculating accumulated interest. - * @return (possible error code, - hypothetical account liquidity in excess of collateral requirements, - * hypothetical account shortfall below collateral requirements) - */ - function getHypotheticalAccountLiquidityInternal( - address account, - CToken cTokenModify, - uint256 redeemTokens, - uint256 borrowAmount - ) - internal - view - returns ( - Error, - uint256, - uint256 - ) - { - AccountLiquidityLocalVars memory vars; // Holds all our calculation results - uint256 oErr; - - // For each asset the account is in - CToken[] memory assets = accountAssets[account]; - for (uint256 i = 0; i < assets.length; i++) { - CToken asset = assets[i]; - - // Read the balances and exchange rate from the cToken - ( - oErr, - vars.cTokenBalance, - vars.borrowBalance, - vars.exchangeRateMantissa - ) = asset.getAccountSnapshot(account); - if (oErr != 0) { - // semi-opaque error code, we assume NO_ERROR == 0 is invariant between upgrades - return (Error.SNAPSHOT_ERROR, 0, 0); - } - vars.collateralFactor = Exp({ - mantissa: markets[address(asset)].collateralFactorMantissa - }); - vars.exchangeRate = Exp({mantissa: vars.exchangeRateMantissa}); - - // Get the normalized price of the asset - vars.oraclePriceMantissa = oracle.getUnderlyingPrice(asset); - if (vars.oraclePriceMantissa == 0) { - return (Error.PRICE_ERROR, 0, 0); - } - vars.oraclePrice = Exp({mantissa: vars.oraclePriceMantissa}); - - // Pre-compute a conversion factor from tokens -> ether (normalized price value) - vars.tokensToDenom = mul_( - mul_(vars.collateralFactor, vars.exchangeRate), - vars.oraclePrice - ); - - // sumCollateral += tokensToDenom * cTokenBalance - vars.sumCollateral = mul_ScalarTruncateAddUInt( - vars.tokensToDenom, - vars.cTokenBalance, - vars.sumCollateral - ); - - // sumBorrowPlusEffects += oraclePrice * borrowBalance - vars.sumBorrowPlusEffects = mul_ScalarTruncateAddUInt( - vars.oraclePrice, - vars.borrowBalance, - vars.sumBorrowPlusEffects - ); - - // Calculate effects of interacting with cTokenModify - if (asset == cTokenModify) { - // redeem effect - // sumBorrowPlusEffects += tokensToDenom * redeemTokens - vars.sumBorrowPlusEffects = mul_ScalarTruncateAddUInt( - vars.tokensToDenom, - redeemTokens, - vars.sumBorrowPlusEffects - ); - - // borrow effect - // sumBorrowPlusEffects += oraclePrice * borrowAmount - vars.sumBorrowPlusEffects = mul_ScalarTruncateAddUInt( - vars.oraclePrice, - borrowAmount, - vars.sumBorrowPlusEffects - ); - } - } - - // These are safe, as the underflow condition is checked first - if (vars.sumCollateral > vars.sumBorrowPlusEffects) { - return ( - Error.NO_ERROR, - vars.sumCollateral - vars.sumBorrowPlusEffects, - 0 - ); - } else { - return ( - Error.NO_ERROR, - 0, - vars.sumBorrowPlusEffects - vars.sumCollateral - ); - } - } - - /** - * @notice Calculate number of tokens of collateral asset to seize given an underlying amount - * @dev Used in liquidation (called in cToken.liquidateBorrowFresh) - * @param cTokenBorrowed The address of the borrowed cToken - * @param cTokenCollateral The address of the collateral cToken - * @param actualRepayAmount The amount of cTokenBorrowed underlying to convert into cTokenCollateral tokens - * @return (errorCode, number of cTokenCollateral tokens to be seized in a liquidation) - */ - function liquidateCalculateSeizeTokens( - address cTokenBorrowed, - address cTokenCollateral, - uint256 actualRepayAmount - ) external view override returns (uint256, uint256) { - /* Read oracle prices for borrowed and collateral markets */ - uint256 priceBorrowedMantissa = oracle.getUnderlyingPrice( - CToken(cTokenBorrowed) - ); - uint256 priceCollateralMantissa = oracle.getUnderlyingPrice( - CToken(cTokenCollateral) - ); - if (priceBorrowedMantissa == 0 || priceCollateralMantissa == 0) { - return (uint256(Error.PRICE_ERROR), 0); - } - - /* - * Get the exchange rate and calculate the number of collateral tokens to seize: - * seizeAmount = actualRepayAmount * liquidationIncentive * priceBorrowed / priceCollateral - * seizeTokens = seizeAmount / exchangeRate - * = actualRepayAmount * (liquidationIncentive * priceBorrowed) / (priceCollateral * exchangeRate) - */ - uint256 exchangeRateMantissa = CToken(cTokenCollateral) - .exchangeRateStored(); // Note: reverts on error - uint256 seizeTokens; - Exp memory numerator; - Exp memory denominator; - Exp memory ratio; - - numerator = mul_( - Exp({mantissa: liquidationIncentiveMantissa}), - Exp({mantissa: priceBorrowedMantissa}) - ); - denominator = mul_( - Exp({mantissa: priceCollateralMantissa}), - Exp({mantissa: exchangeRateMantissa}) - ); - ratio = div_(numerator, denominator); - - seizeTokens = mul_ScalarTruncate(ratio, actualRepayAmount); - - return (uint256(Error.NO_ERROR), seizeTokens); - } - - /*** Admin Functions ***/ - - /** - * @notice Sets a new price oracle for the comptroller - * @dev Admin function to set a new price oracle - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setPriceOracle(PriceOracle newOracle) public returns (uint256) { - // Check caller is admin - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_PRICE_ORACLE_OWNER_CHECK - ); - } - - // Track the old oracle for the comptroller - PriceOracle oldOracle = oracle; - - // Set comptroller's oracle to newOracle - oracle = newOracle; - - // Emit NewPriceOracle(oldOracle, newOracle) - emit NewPriceOracle(oldOracle, newOracle); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Sets the closeFactor used when liquidating borrows - * @dev Admin function to set closeFactor - * @param newCloseFactorMantissa New close factor, scaled by 1e18 - * @return uint 0=success, otherwise a failure - */ - function _setCloseFactor(uint256 newCloseFactorMantissa) - external - returns (uint256) - { - // Check caller is admin - require(msg.sender == admin, "only admin can set close factor"); - - uint256 oldCloseFactorMantissa = closeFactorMantissa; - closeFactorMantissa = newCloseFactorMantissa; - emit NewCloseFactor(oldCloseFactorMantissa, closeFactorMantissa); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Sets the collateralFactor for a market - * @dev Admin function to set per-market collateralFactor - * @param cToken The market to set the factor on - * @param newCollateralFactorMantissa The new collateral factor, scaled by 1e18 - * @return uint 0=success, otherwise a failure. (See ErrorReporter for details) - */ - function _setCollateralFactor( - CToken cToken, - uint256 newCollateralFactorMantissa - ) external returns (uint256) { - // Check caller is admin - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_COLLATERAL_FACTOR_OWNER_CHECK - ); - } - - // Verify market is listed - Market storage market = markets[address(cToken)]; - if (!market.isListed) { - return - fail( - Error.MARKET_NOT_LISTED, - FailureInfo.SET_COLLATERAL_FACTOR_NO_EXISTS - ); - } - - Exp memory newCollateralFactorExp = Exp({ - mantissa: newCollateralFactorMantissa - }); - - // Check collateral factor <= 0.9 - Exp memory highLimit = Exp({mantissa: collateralFactorMaxMantissa}); - if (lessThanExp(highLimit, newCollateralFactorExp)) { - return - fail( - Error.INVALID_COLLATERAL_FACTOR, - FailureInfo.SET_COLLATERAL_FACTOR_VALIDATION - ); - } - - // If collateral factor != 0, fail if price == 0 - if ( - newCollateralFactorMantissa != 0 && - oracle.getUnderlyingPrice(cToken) == 0 - ) { - return - fail( - Error.PRICE_ERROR, - FailureInfo.SET_COLLATERAL_FACTOR_WITHOUT_PRICE - ); - } - - // Set market's collateral factor to new collateral factor, remember old value - uint256 oldCollateralFactorMantissa = market.collateralFactorMantissa; - market.collateralFactorMantissa = newCollateralFactorMantissa; - - // Emit event with asset, old collateral factor, and new collateral factor - emit NewCollateralFactor( - cToken, - oldCollateralFactorMantissa, - newCollateralFactorMantissa - ); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Sets liquidationIncentive - * @dev Admin function to set liquidationIncentive - * @param newLiquidationIncentiveMantissa New liquidationIncentive scaled by 1e18 - * @return uint 0=success, otherwise a failure. (See ErrorReporter for details) - */ - function _setLiquidationIncentive(uint256 newLiquidationIncentiveMantissa) - external - returns (uint256) - { - // Check caller is admin - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_LIQUIDATION_INCENTIVE_OWNER_CHECK - ); - } - - // Save current value for use in log - uint256 oldLiquidationIncentiveMantissa = liquidationIncentiveMantissa; - - // Set liquidation incentive to new incentive - liquidationIncentiveMantissa = newLiquidationIncentiveMantissa; - - // Emit event with old incentive, new incentive - emit NewLiquidationIncentive( - oldLiquidationIncentiveMantissa, - newLiquidationIncentiveMantissa - ); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Add the market to the markets mapping and set it as listed - * @dev Admin function to set isListed and add support for the market - * @param cToken The address of the market (token) to list - * @return uint 0=success, otherwise a failure. (See enum Error for details) - */ - function _supportMarket(CToken cToken) external returns (uint256) { - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SUPPORT_MARKET_OWNER_CHECK - ); - } - - if (markets[address(cToken)].isListed) { - return - fail( - Error.MARKET_ALREADY_LISTED, - FailureInfo.SUPPORT_MARKET_EXISTS - ); - } - - cToken.isCToken(); // Sanity check to make sure its really a CToken - - // Note that isComped is not in active use anymore - Market storage market = markets[address(cToken)]; - market.isListed = true; - market.isComped = false; - market.collateralFactorMantissa = 0; - - _addMarketInternal(address(cToken)); - - emit MarketListed(cToken); - - return uint256(Error.NO_ERROR); - } - - function _addMarketInternal(address cToken) internal { - for (uint256 i = 0; i < allMarkets.length; i++) { - require(allMarkets[i] != CToken(cToken), "market already added"); - } - allMarkets.push(CToken(cToken)); - } - - /** - * @notice Set the given borrow caps for the given cToken markets. Borrowing that brings total borrows to or above borrow cap will revert. - * @dev Admin or borrowCapGuardian function to set the borrow caps. A borrow cap of 0 corresponds to unlimited borrowing. - * @param cTokens The addresses of the markets (tokens) to change the borrow caps for - * @param newBorrowCaps The new borrow cap values in underlying to be set. A value of 0 corresponds to unlimited borrowing. - */ - function _setMarketBorrowCaps( - CToken[] calldata cTokens, - uint256[] calldata newBorrowCaps - ) external { - require( - msg.sender == admin || msg.sender == borrowCapGuardian, - "only admin or guardian" - ); - - uint256 numMarkets = cTokens.length; - uint256 numBorrowCaps = newBorrowCaps.length; - - require( - numMarkets != 0 && numMarkets == numBorrowCaps, - "invalid input" - ); - - for (uint256 i = 0; i < numMarkets; i++) { - borrowCaps[address(cTokens[i])] = newBorrowCaps[i]; - emit NewBorrowCap(cTokens[i], newBorrowCaps[i]); - } - } - - /** - * @notice Admin function to change the Borrow Cap Guardian - * @param newBorrowCapGuardian The address of the new Borrow Cap Guardian - */ - function _setBorrowCapGuardian(address newBorrowCapGuardian) external { - require(msg.sender == admin, "only admin can set guardian"); - - // Save current value for inclusion in log - address oldBorrowCapGuardian = borrowCapGuardian; - - // Store borrowCapGuardian with value newBorrowCapGuardian - borrowCapGuardian = newBorrowCapGuardian; - - // Emit NewBorrowCapGuardian(OldBorrowCapGuardian, NewBorrowCapGuardian) - emit NewBorrowCapGuardian(oldBorrowCapGuardian, newBorrowCapGuardian); - } - - /** - * @notice Admin function to change the Pause Guardian - * @param newPauseGuardian The address of the new Pause Guardian - * @return uint 0=success, otherwise a failure. (See enum Error for details) - */ - function _setPauseGuardian(address newPauseGuardian) - public - returns (uint256) - { - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_PAUSE_GUARDIAN_OWNER_CHECK - ); - } - - // Save current value for inclusion in log - address oldPauseGuardian = pauseGuardian; - - // Store pauseGuardian with value newPauseGuardian - pauseGuardian = newPauseGuardian; - - // Emit NewPauseGuardian(OldPauseGuardian, NewPauseGuardian) - emit NewPauseGuardian(oldPauseGuardian, pauseGuardian); - - return uint256(Error.NO_ERROR); - } - - function _setMintPaused(CToken cToken, bool state) public returns (bool) { - require(markets[address(cToken)].isListed, "market not listed"); - require( - msg.sender == pauseGuardian || msg.sender == admin, - "only guardian and admin can pause" - ); - require(msg.sender == admin || state == true, "only admin can unpause"); - - mintGuardianPaused[address(cToken)] = state; - emit ActionPaused(cToken, "Mint", state); - return state; - } - - function _setBorrowPaused(CToken cToken, bool state) public returns (bool) { - require(markets[address(cToken)].isListed, "market is not listed"); - require( - msg.sender == pauseGuardian || msg.sender == admin, - "only guardian and admin can pause" - ); - require(msg.sender == admin || state == true, "only admin can unpause"); - - borrowGuardianPaused[address(cToken)] = state; - emit ActionPaused(cToken, "Borrow", state); - return state; - } - - function _setTransferPaused(bool state) public returns (bool) { - require( - msg.sender == pauseGuardian || msg.sender == admin, - "only guardian and admin can pause" - ); - require(msg.sender == admin || state == true, "only admin can unpause"); - - transferGuardianPaused = state; - emit ActionPaused("Transfer", state); - return state; - } - - function _setSeizePaused(bool state) public returns (bool) { - require( - msg.sender == pauseGuardian || msg.sender == admin, - "only guardian and admin can pause" - ); - require(msg.sender == admin || state == true, "only admin can unpause"); - - seizeGuardianPaused = state; - emit ActionPaused("Seize", state); - return state; - } - - function _become(Unitroller unitroller) public { - require( - msg.sender == unitroller.admin(), - "only unitroller admin can become" - ); - require( - unitroller._acceptImplementation() == 0, - "change not authorized" - ); - } - - /** - * @notice Checks caller is admin, or this contract is becoming the new implementation - */ - function adminOrInitializing() internal view returns (bool) { - return msg.sender == admin || msg.sender == comptrollerImplementation; - } - - /*** TROP Distribution ***/ - - /** - * @notice Set COMP speed for a single market - * @param cToken The market whose COMP speed to update - * @param compSpeed New COMP speed for market - */ - function setCompSpeedInternal(CToken cToken, uint256 compSpeed) internal { - uint256 currentCompSpeed = compSpeeds[address(cToken)]; - if (currentCompSpeed != 0) { - // note that COMP speed could be set to 0 to halt liquidity rewards for a market - Exp memory borrowIndex = Exp({mantissa: cToken.borrowIndex()}); - updateCompSupplyIndex(address(cToken)); - updateCompBorrowIndex(address(cToken), borrowIndex); - } else if (compSpeed != 0) { - // Add the COMP market - Market storage market = markets[address(cToken)]; - require(market.isListed == true, "comp market is not listed"); - - if ( - compSupplyState[address(cToken)].index == 0 && - compSupplyState[address(cToken)].block == 0 - ) { - compSupplyState[address(cToken)] = CompMarketState({ - index: compInitialIndex, - block: safe32( - getBlockNumber(), - "block number exceeds 32 bits" - ) - }); - } - - if ( - compBorrowState[address(cToken)].index == 0 && - compBorrowState[address(cToken)].block == 0 - ) { - compBorrowState[address(cToken)] = CompMarketState({ - index: compInitialIndex, - block: safe32( - getBlockNumber(), - "block number exceeds 32 bits" - ) - }); - } - } - - if (currentCompSpeed != compSpeed) { - compSpeeds[address(cToken)] = compSpeed; - emit CompSpeedUpdated(cToken, compSpeed); - } - } - - /** - * @notice Accrue COMP to the market by updating the supply index - * @param cToken The market whose supply index to update - */ - function updateCompSupplyIndex(address cToken) internal { - CompMarketState storage supplyState = compSupplyState[cToken]; - uint256 supplySpeed = compSpeeds[cToken]; - uint256 blockNumber = getBlockNumber(); - uint256 deltaBlocks = sub_(blockNumber, uint256(supplyState.block)); - if (deltaBlocks > 0 && supplySpeed > 0) { - uint256 supplyTokens = CToken(cToken).totalSupply(); - uint256 compAccrued = mul_(deltaBlocks, supplySpeed); - Double memory ratio = supplyTokens > 0 - ? fraction(compAccrued, supplyTokens) - : Double({mantissa: 0}); - Double memory index = add_( - Double({mantissa: supplyState.index}), - ratio - ); - compSupplyState[cToken] = CompMarketState({ - index: safe224(index.mantissa, "index exceeds 224 bits"), - block: safe32(blockNumber, "block exceeds 32 bits") - }); - } else if (deltaBlocks > 0) { - supplyState.block = safe32(blockNumber, "block exceeds 32 bits"); - } - } - - /** - * @notice Accrue COMP to the market by updating the borrow index - * @param cToken The market whose borrow index to update - */ - function updateCompBorrowIndex(address cToken, Exp memory marketBorrowIndex) - internal - { - CompMarketState storage borrowState = compBorrowState[cToken]; - uint256 borrowSpeed = compSpeeds[cToken]; - uint256 blockNumber = getBlockNumber(); - uint256 deltaBlocks = sub_(blockNumber, uint256(borrowState.block)); - if (deltaBlocks > 0 && borrowSpeed > 0) { - uint256 borrowAmount = div_( - CToken(cToken).totalBorrows(), - marketBorrowIndex - ); - uint256 compAccrued = mul_(deltaBlocks, borrowSpeed); - Double memory ratio = borrowAmount > 0 - ? fraction(compAccrued, borrowAmount) - : Double({mantissa: 0}); - Double memory index = add_( - Double({mantissa: borrowState.index}), - ratio - ); - compBorrowState[cToken] = CompMarketState({ - index: safe224(index.mantissa, "index exceeds 224 bits"), - block: safe32(blockNumber, "block exceeds 32 bits") - }); - } else if (deltaBlocks > 0) { - borrowState.block = safe32(blockNumber, "block exceeds 32 bits"); - } - } - - /** - * @notice Calculate COMP accrued by a supplier and possibly transfer it to them - * @param cToken The market in which the supplier is interacting - * @param supplier The address of the supplier to distribute COMP to - */ - function distributeSupplierComp(address cToken, address supplier) internal { - CompMarketState storage supplyState = compSupplyState[cToken]; - Double memory supplyIndex = Double({mantissa: supplyState.index}); - Double memory supplierIndex = Double({ - mantissa: compSupplierIndex[cToken][supplier] - }); - compSupplierIndex[cToken][supplier] = supplyIndex.mantissa; - - if (supplierIndex.mantissa == 0 && supplyIndex.mantissa > 0) { - supplierIndex.mantissa = compInitialIndex; - } - - Double memory deltaIndex = sub_(supplyIndex, supplierIndex); - uint256 supplierTokens = CToken(cToken).balanceOf(supplier); - uint256 supplierDelta = mul_(supplierTokens, deltaIndex); - uint256 supplierAccrued = add_(compAccrued[supplier], supplierDelta); - compAccrued[supplier] = supplierAccrued; - emit DistributedSupplierComp( - CToken(cToken), - supplier, - supplierDelta, - supplyIndex.mantissa - ); - } - - /** - * @notice Calculate COMP accrued by a borrower and possibly transfer it to them - * @dev Borrowers will not begin to accrue until after the first interaction with the protocol. - * @param cToken The market in which the borrower is interacting - * @param borrower The address of the borrower to distribute COMP to - */ - function distributeBorrowerComp( - address cToken, - address borrower, - Exp memory marketBorrowIndex - ) internal { - CompMarketState storage borrowState = compBorrowState[cToken]; - Double memory borrowIndex = Double({mantissa: borrowState.index}); - Double memory borrowerIndex = Double({ - mantissa: compBorrowerIndex[cToken][borrower] - }); - compBorrowerIndex[cToken][borrower] = borrowIndex.mantissa; - - if (borrowerIndex.mantissa > 0) { - Double memory deltaIndex = sub_(borrowIndex, borrowerIndex); - uint256 borrowerAmount = div_( - CToken(cToken).borrowBalanceStored(borrower), - marketBorrowIndex - ); - uint256 borrowerDelta = mul_(borrowerAmount, deltaIndex); - uint256 borrowerAccrued = add_( - compAccrued[borrower], - borrowerDelta - ); - compAccrued[borrower] = borrowerAccrued; - emit DistributedBorrowerComp( - CToken(cToken), - borrower, - borrowerDelta, - borrowIndex.mantissa - ); - } - } - - /** - * @notice Calculate additional accrued COMP for a contributor since last accrual - * @param contributor The address to calculate contributor rewards for - */ - function updateContributorRewards(address contributor) public { - uint256 compSpeed = compContributorSpeeds[contributor]; - uint256 blockNumber = getBlockNumber(); - uint256 deltaBlocks = sub_( - blockNumber, - lastContributorBlock[contributor] - ); - if (deltaBlocks > 0 && compSpeed > 0) { - uint256 newAccrued = mul_(deltaBlocks, compSpeed); - uint256 contributorAccrued = add_( - compAccrued[contributor], - newAccrued - ); - - compAccrued[contributor] = contributorAccrued; - lastContributorBlock[contributor] = blockNumber; - } - } - - /** - * @notice Claim all the comp accrued by holder in all markets - * @param holder The address to claim COMP for - */ - function claimComp(address holder) public { - return claimComp(holder, allMarkets); - } - - /** - * @notice Claim all the comp accrued by holder in the specified markets - * @param holder The address to claim COMP for - * @param cTokens The list of markets to claim COMP in - */ - function claimComp(address holder, CToken[] memory cTokens) public { - address[] memory holders = new address[](1); - holders[0] = holder; - claimComp(holders, cTokens, true, true); - } - - /** - * @notice Claim all comp accrued by the holders - * @param holders The addresses to claim COMP for - * @param cTokens The list of markets to claim COMP in - * @param borrowers Whether or not to claim COMP earned by borrowing - * @param suppliers Whether or not to claim COMP earned by supplying - */ - function claimComp( - address[] memory holders, - CToken[] memory cTokens, - bool borrowers, - bool suppliers - ) public { - for (uint256 i = 0; i < cTokens.length; i++) { - CToken cToken = cTokens[i]; - require(markets[address(cToken)].isListed, "market must be listed"); - if (borrowers == true) { - Exp memory borrowIndex = Exp({mantissa: cToken.borrowIndex()}); - updateCompBorrowIndex(address(cToken), borrowIndex); - for (uint256 j = 0; j < holders.length; j++) { - distributeBorrowerComp( - address(cToken), - holders[j], - borrowIndex - ); - compAccrued[holders[j]] = grantCompInternal( - holders[j], - compAccrued[holders[j]] - ); - } - } - if (suppliers == true) { - updateCompSupplyIndex(address(cToken)); - for (uint256 j = 0; j < holders.length; j++) { - distributeSupplierComp(address(cToken), holders[j]); - compAccrued[holders[j]] = grantCompInternal( - holders[j], - compAccrued[holders[j]] - ); - } - } - } - } - - /** - * @notice Transfer TROP to the user - * @dev Note: If there is not enough COMP, we do not perform the transfer all. - * @param user The address of the user to transfer COMP to - * @param amount The amount of COMP to (possibly) transfer - * @return The amount of COMP which was NOT transferred to the user - */ - function grantCompInternal(address user, uint256 amount) - internal - returns (uint256) - { - TROP comp = TROP(getCompAddress()); - uint256 compRemaining = comp.balanceOf(address(this)); - if (amount > 0 && amount <= compRemaining) { - comp.transfer(user, amount); - return 0; - } - return amount; - } - - /*** TROP Distribution Admin ***/ - - /** - * @notice Transfer COMP to the recipient - * @dev Note: If there is not enough COMP, we do not perform the transfer all. - * @param recipient The address of the recipient to transfer COMP to - * @param amount The amount of COMP to (possibly) transfer - */ - function _grantComp(address recipient, uint256 amount) public { - require(adminOrInitializing(), "only admin can grant comp"); - uint256 amountLeft = grantCompInternal(recipient, amount); - require(amountLeft == 0, "insufficient comp for grant"); - emit CompGranted(recipient, amount); - } - - /** - * @notice Set COMP speed for a single market - * @param cToken The market whose COMP speed to update - * @param compSpeed New COMP speed for market - */ - function _setCompSpeed(CToken cToken, uint256 compSpeed) public { - require(adminOrInitializing(), "only admin can set comp speed"); - setCompSpeedInternal(cToken, compSpeed); - } - - /** - * @notice Set COMP speed for a single contributor - * @param contributor The contributor whose COMP speed to update - * @param compSpeed New COMP speed for contributor - */ - function _setContributorCompSpeed(address contributor, uint256 compSpeed) - public - { - require(adminOrInitializing(), "only admin can set comp speed"); - - // note that COMP speed could be set to 0 to halt liquidity rewards for a contributor - updateContributorRewards(contributor); - if (compSpeed == 0) { - // release storage - delete lastContributorBlock[contributor]; - } else { - lastContributorBlock[contributor] = getBlockNumber(); - } - compContributorSpeeds[contributor] = compSpeed; - - emit ContributorCompSpeedUpdated(contributor, compSpeed); - } - - /** - * @notice Return all of the markets - * @dev The automatic getter may be used to access an individual market. - * @return The list of market addresses - */ - function getAllMarkets() public view returns (CToken[] memory) { - return allMarkets; - } - - function getBlockNumber() public view virtual returns (uint256) { - return block.number; - } - - /** - * @notice Set the address of the TROP token - */ - function setCompAddress(address tropAddress_) public virtual { - require(msg.sender == admin, "only admin can set TROP"); - tropAddress = tropAddress_; - } - - /** - * @notice Return the address of the TROP token - * @return The address of TROP - */ - function getCompAddress() public view virtual returns (address) { - return tropAddress; - } -} diff --git a/flatten/ComptrollerG1.sol b/flatten/ComptrollerG1.sol deleted file mode 100644 index 8912726..0000000 --- a/flatten/ComptrollerG1.sol +++ /dev/null @@ -1,5608 +0,0 @@ -// Dependency file: contracts/ComptrollerInterface.sol - -// SPDX-License-Identifier: UNLICENSED -// pragma solidity 0.8.6; - -abstract contract ComptrollerInterface { - /// @notice Indicator that this is a Comptroller contract (for inspection) - bool public constant isComptroller = true; - - /*** Assets You Are In ***/ - - function enterMarkets(address[] calldata cTokens) - external - virtual - returns (uint256[] memory); - - function exitMarket(address cToken) external virtual returns (uint256); - - /*** Policy Hooks ***/ - - function mintAllowed( - address cToken, - address minter, - uint256 mintAmount - ) external virtual returns (uint256); - - function mintVerify( - address cToken, - address minter, - uint256 mintAmount, - uint256 mintTokens - ) external virtual; - - function redeemAllowed( - address cToken, - address redeemer, - uint256 redeemTokens - ) external virtual returns (uint256); - - function redeemVerify( - address cToken, - address redeemer, - uint256 redeemAmount, - uint256 redeemTokens - ) external virtual; - - function borrowAllowed( - address cToken, - address borrower, - uint256 borrowAmount - ) external virtual returns (uint256); - - function borrowVerify( - address cToken, - address borrower, - uint256 borrowAmount - ) external virtual; - - function repayBorrowAllowed( - address cToken, - address payer, - address borrower, - uint256 repayAmount - ) external virtual returns (uint256); - - function repayBorrowVerify( - address cToken, - address payer, - address borrower, - uint256 repayAmount, - uint256 borrowerIndex - ) external virtual; - - function liquidateBorrowAllowed( - address cTokenBorrowed, - address cTokenCollateral, - address liquidator, - address borrower, - uint256 repayAmount - ) external virtual returns (uint256); - - function liquidateBorrowVerify( - address cTokenBorrowed, - address cTokenCollateral, - address liquidator, - address borrower, - uint256 repayAmount, - uint256 seizeTokens - ) external virtual; - - function seizeAllowed( - address cTokenCollateral, - address cTokenBorrowed, - address liquidator, - address borrower, - uint256 seizeTokens - ) external virtual returns (uint256); - - function seizeVerify( - address cTokenCollateral, - address cTokenBorrowed, - address liquidator, - address borrower, - uint256 seizeTokens - ) external virtual; - - function transferAllowed( - address cToken, - address src, - address dst, - uint256 transferTokens - ) external virtual returns (uint256); - - function transferVerify( - address cToken, - address src, - address dst, - uint256 transferTokens - ) external virtual; - - /*** Liquidity/Liquidation Calculations ***/ - - function liquidateCalculateSeizeTokens( - address cTokenBorrowed, - address cTokenCollateral, - uint256 repayAmount - ) external view virtual returns (uint256, uint256); -} - - -// Dependency file: contracts/CarefulMath.sol - -// pragma solidity 0.8.6; - -/** - * @title Careful Math - * @author tropykus - * @notice Derived from OpenZeppelin's SafeMath library - * https://github.com/OpenZeppelin/openzeppelin-solidity/blob/master/contracts/math/SafeMath.sol - */ -contract CarefulMath { - - /** - * @dev Possible error codes that we can return - */ - enum MathError { - NO_ERROR, - DIVISION_BY_ZERO, - INTEGER_OVERFLOW, - INTEGER_UNDERFLOW - } - - /** - * @dev Multiplies two numbers, returns an error on overflow. - */ - function mulUInt(uint a, uint b) internal pure returns (MathError, uint) { - if (a == 0) { - return (MathError.NO_ERROR, 0); - } - - uint c = a * b; - - if (c / a != b) { - return (MathError.INTEGER_OVERFLOW, 0); - } else { - return (MathError.NO_ERROR, c); - } - } - - /** - * @dev Integer division of two numbers, truncating the quotient. - */ - function divUInt(uint a, uint b) internal pure returns (MathError, uint) { - if (b == 0) { - return (MathError.DIVISION_BY_ZERO, 0); - } - - return (MathError.NO_ERROR, a / b); - } - - /** - * @dev Subtracts two numbers, returns an error on overflow (i.e. if subtrahend is greater than minuend). - */ - function subUInt(uint a, uint b) internal pure returns (MathError, uint) { - if (b <= a) { - return (MathError.NO_ERROR, a - b); - } else { - return (MathError.INTEGER_UNDERFLOW, 0); - } - } - - /** - * @dev Adds two numbers, returns an error on overflow. - */ - function addUInt(uint a, uint b) internal pure returns (MathError, uint) { - uint c = a + b; - - if (c >= a) { - return (MathError.NO_ERROR, c); - } else { - return (MathError.INTEGER_OVERFLOW, 0); - } - } - - /** - * @dev add a and b and then subtract c - */ - function addThenSubUInt(uint a, uint b, uint c) internal pure returns (MathError, uint) { - (MathError err0, uint sum) = addUInt(a, b); - - if (err0 != MathError.NO_ERROR) { - return (err0, 0); - } - - return subUInt(sum, c); - } -} - - -// Dependency file: contracts/ExponentialNoError.sol - -// pragma solidity 0.8.6; - -/** - * @title Exponential module for storing fixed-precision decimals - * @author tropykus - * @notice Exp is a struct which stores decimals with a fixed precision of 18 decimal places. - * Thus, if we wanted to store the 5.1, mantissa would store 5.1e18. That is: - * `Exp({mantissa: 5100000000000000000})`. - */ -contract ExponentialNoError { - uint constant expScale = 1e18; - uint constant doubleScale = 1e36; - uint constant halfExpScale = expScale/2; - uint constant mantissaOne = expScale; - - struct Exp { - uint mantissa; - } - - struct Double { - uint mantissa; - } - - /** - * @dev Truncates the given exp to a whole number value. - * For example, truncate(Exp{mantissa: 15 * expScale}) = 15 - */ - function truncate(Exp memory exp) pure internal returns (uint) { - // Note: We are not using careful math here as we're performing a division that cannot fail - return exp.mantissa / expScale; - } - - /** - * @dev Multiply an Exp by a scalar, then truncate to return an unsigned integer. - */ - function mul_ScalarTruncate(Exp memory a, uint scalar) pure internal returns (uint) { - Exp memory product = mul_(a, scalar); - return truncate(product); - } - - /** - * @dev Multiply an Exp by a scalar, truncate, then add an to an unsigned integer, returning an unsigned integer. - */ - function mul_ScalarTruncateAddUInt(Exp memory a, uint scalar, uint addend) pure internal returns (uint) { - Exp memory product = mul_(a, scalar); - return add_(truncate(product), addend); - } - - /** - * @dev Checks if first Exp is less than second Exp. - */ - function lessThanExp(Exp memory left, Exp memory right) pure internal returns (bool) { - return left.mantissa < right.mantissa; - } - - /** - * @dev Checks if left Exp <= right Exp. - */ - function lessThanOrEqualExp(Exp memory left, Exp memory right) pure internal returns (bool) { - return left.mantissa <= right.mantissa; - } - - /** - * @dev Checks if left Exp > right Exp. - */ - function greaterThanExp(Exp memory left, Exp memory right) pure internal returns (bool) { - return left.mantissa > right.mantissa; - } - - /** - * @dev returns true if Exp is exactly zero - */ - function isZeroExp(Exp memory value) pure internal returns (bool) { - return value.mantissa == 0; - } - - function safe224(uint n, string memory errorMessage) pure internal returns (uint224) { - require(n < 2**224, errorMessage); - return uint224(n); - } - - function safe32(uint n, string memory errorMessage) pure internal returns (uint32) { - require(n < 2**32, errorMessage); - return uint32(n); - } - - function add_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { - return Exp({mantissa: add_(a.mantissa, b.mantissa)}); - } - - function add_(Double memory a, Double memory b) pure internal returns (Double memory) { - return Double({mantissa: add_(a.mantissa, b.mantissa)}); - } - - function add_(uint a, uint b) pure internal returns (uint) { - return add_(a, b, "addition overflow"); - } - - function add_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { - uint c = a + b; - require(c >= a, errorMessage); - return c; - } - - function sub_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { - return Exp({mantissa: sub_(a.mantissa, b.mantissa)}); - } - - function sub_(Double memory a, Double memory b) pure internal returns (Double memory) { - return Double({mantissa: sub_(a.mantissa, b.mantissa)}); - } - - function sub_(uint a, uint b) pure internal returns (uint) { - return sub_(a, b, "subtraction underflow"); - } - - function sub_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { - require(b <= a, errorMessage); - return a - b; - } - - function mul_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { - return Exp({mantissa: mul_(a.mantissa, b.mantissa) / expScale}); - } - - function mul_(Exp memory a, uint b) pure internal returns (Exp memory) { - return Exp({mantissa: mul_(a.mantissa, b)}); - } - - function mul_(uint a, Exp memory b) pure internal returns (uint) { - return mul_(a, b.mantissa) / expScale; - } - - function mul_(Double memory a, Double memory b) pure internal returns (Double memory) { - return Double({mantissa: mul_(a.mantissa, b.mantissa) / doubleScale}); - } - - function mul_(Double memory a, uint b) pure internal returns (Double memory) { - return Double({mantissa: mul_(a.mantissa, b)}); - } - - function mul_(uint a, Double memory b) pure internal returns (uint) { - return mul_(a, b.mantissa) / doubleScale; - } - - function mul_(uint a, uint b) pure internal returns (uint) { - return mul_(a, b, "multiplication overflow"); - } - - function mul_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { - if (a == 0 || b == 0) { - return 0; - } - uint c = a * b; - require(c / a == b, errorMessage); - return c; - } - - function div_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { - return Exp({mantissa: div_(mul_(a.mantissa, expScale), b.mantissa)}); - } - - function div_(Exp memory a, uint b) pure internal returns (Exp memory) { - return Exp({mantissa: div_(a.mantissa, b)}); - } - - function div_(uint a, Exp memory b) pure internal returns (uint) { - return div_(mul_(a, expScale), b.mantissa); - } - - function div_(Double memory a, Double memory b) pure internal returns (Double memory) { - return Double({mantissa: div_(mul_(a.mantissa, doubleScale), b.mantissa)}); - } - - function div_(Double memory a, uint b) pure internal returns (Double memory) { - return Double({mantissa: div_(a.mantissa, b)}); - } - - function div_(uint a, Double memory b) pure internal returns (uint) { - return div_(mul_(a, doubleScale), b.mantissa); - } - - function div_(uint a, uint b) pure internal returns (uint) { - return div_(a, b, "divide by zero"); - } - - function div_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { - require(b > 0, errorMessage); - return a / b; - } - - function fraction(uint a, uint b) pure internal returns (Double memory) { - return Double({mantissa: div_(mul_(a, doubleScale), b)}); - } -} - - -// Dependency file: contracts/Exponential.sol - -// pragma solidity 0.8.6; - -// import "contracts/CarefulMath.sol"; -// import "contracts/ExponentialNoError.sol"; - -/** - * @title Exponential module for storing fixed-precision decimals - * @author tropykus - * @dev Legacy contract for compatibility reasons with existing contracts that still use MathError - * @notice Exp is a struct which stores decimals with a fixed precision of 18 decimal places. - * Thus, if we wanted to store the 5.1, mantissa would store 5.1e18. That is: - * `Exp({mantissa: 5100000000000000000})`. - */ -contract Exponential is CarefulMath, ExponentialNoError { - /** - * @dev Creates an exponential from numerator and denominator values. - * Note: Returns an error if (`num` * 10e18) > MAX_INT, - * or if `denom` is zero. - */ - function getExp(uint num, uint denom) internal pure returns (MathError, Exp memory) { - (MathError err0, uint scaledNumerator) = mulUInt(num, expScale); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - - (MathError err1, uint rational) = divUInt(scaledNumerator, denom); - if (err1 != MathError.NO_ERROR) { - return (err1, Exp({mantissa: 0})); - } - - return (MathError.NO_ERROR, Exp({mantissa: rational})); - } - - /** - * @dev Adds two exponentials, returning a new exponential. - */ - function addExp(Exp memory a, Exp memory b) internal pure returns (MathError, Exp memory) { - (MathError error, uint result) = addUInt(a.mantissa, b.mantissa); - - return (error, Exp({mantissa: result})); - } - - /** - * @dev Subtracts two exponentials, returning a new exponential. - */ - function subExp(Exp memory a, Exp memory b) internal pure returns (MathError, Exp memory) { - (MathError error, uint result) = subUInt(a.mantissa, b.mantissa); - - return (error, Exp({mantissa: result})); - } - - /** - * @dev Multiply an Exp by a scalar, returning a new Exp. - */ - function mulScalar(Exp memory a, uint scalar) internal pure returns (MathError, Exp memory) { - (MathError err0, uint scaledMantissa) = mulUInt(a.mantissa, scalar); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - - return (MathError.NO_ERROR, Exp({mantissa: scaledMantissa})); - } - - /** - * @dev Multiply an Exp by a scalar, then truncate to return an unsigned integer. - */ - function mulScalarTruncate(Exp memory a, uint scalar) internal pure returns (MathError, uint) { - (MathError err, Exp memory product) = mulScalar(a, scalar); - if (err != MathError.NO_ERROR) { - return (err, 0); - } - - return (MathError.NO_ERROR, truncate(product)); - } - - /** - * @dev Multiply an Exp by a scalar, truncate, then add an to an unsigned integer, returning an unsigned integer. - */ - function mulScalarTruncateAddUInt(Exp memory a, uint scalar, uint addend) internal pure returns (MathError, uint) { - (MathError err, Exp memory product) = mulScalar(a, scalar); - if (err != MathError.NO_ERROR) { - return (err, 0); - } - - return addUInt(truncate(product), addend); - } - - /** - * @dev Divide an Exp by a scalar, returning a new Exp. - */ - function divScalar(Exp memory a, uint scalar) internal pure returns (MathError, Exp memory) { - (MathError err0, uint descaledMantissa) = divUInt(a.mantissa, scalar); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - - return (MathError.NO_ERROR, Exp({mantissa: descaledMantissa})); - } - - /** - * @dev Divide a scalar by an Exp, returning a new Exp. - */ - function divScalarByExp(uint scalar, Exp memory divisor) internal pure returns (MathError, Exp memory) { - /* - We are doing this as: - getExp(mulUInt(expScale, scalar), divisor.mantissa) - - How it works: - Exp = a / b; - Scalar = s; - `s / (a / b)` = `b * s / a` and since for an Exp `a = mantissa, b = expScale` - */ - (MathError err0, uint numerator) = mulUInt(expScale, scalar); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - return getExp(numerator, divisor.mantissa); - } - - /** - * @dev Divide a scalar by an Exp, then truncate to return an unsigned integer. - */ - function divScalarByExpTruncate(uint scalar, Exp memory divisor) internal pure returns (MathError, uint) { - (MathError err, Exp memory fraction) = divScalarByExp(scalar, divisor); - if (err != MathError.NO_ERROR) { - return (err, 0); - } - - return (MathError.NO_ERROR, truncate(fraction)); - } - - /** - * @dev Multiplies two exponentials, returning a new exponential. - */ - function mulExp(Exp memory a, Exp memory b) internal pure returns (MathError, Exp memory) { - - (MathError err0, uint doubleScaledProduct) = mulUInt(a.mantissa, b.mantissa); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - - // We add half the scale before dividing so that we get rounding instead of truncation. - // See "Listing 6" and text above it at https://accu.org/index.php/journals/1717 - // Without this change, a result like 6.6...e-19 will be truncated to 0 instead of being rounded to 1e-18. - (MathError err1, uint doubleScaledProductWithHalfScale) = addUInt(halfExpScale, doubleScaledProduct); - if (err1 != MathError.NO_ERROR) { - return (err1, Exp({mantissa: 0})); - } - - (MathError err2, uint product) = divUInt(doubleScaledProductWithHalfScale, expScale); - // The only error `div` can return is MathError.DIVISION_BY_ZERO but we control `expScale` and it is not zero. - assert(err2 == MathError.NO_ERROR); - - return (MathError.NO_ERROR, Exp({mantissa: product})); - } - - /** - * @dev Multiplies two exponentials given their mantissas, returning a new exponential. - */ - function mulExp(uint a, uint b) internal pure returns (MathError, Exp memory) { - return mulExp(Exp({mantissa: a}), Exp({mantissa: b})); - } - - /** - * @dev Multiplies three exponentials, returning a new exponential. - */ - function mulExp3(Exp memory a, Exp memory b, Exp memory c) internal pure returns (MathError, Exp memory) { - (MathError err, Exp memory ab) = mulExp(a, b); - if (err != MathError.NO_ERROR) { - return (err, ab); - } - return mulExp(ab, c); - } - - /** - * @dev Divides two exponentials, returning a new exponential. - * (a/scale) / (b/scale) = (a/scale) * (scale/b) = a/b, - * which we can scale as an Exp by calling getExp(a.mantissa, b.mantissa) - */ - function divExp(Exp memory a, Exp memory b) internal pure returns (MathError, Exp memory) { - return getExp(a.mantissa, b.mantissa); - } -} - - -// Dependency file: contracts/SafeMath.sol - -// pragma solidity 0.8.6; - -// From https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/math/Math.sol -// Subject to the MIT license. - -/** - * @dev Wrappers over Solidity's arithmetic operations with added overflow - * checks. - * - * Arithmetic operations in Solidity wrap on overflow. This can easily result - * in bugs, because programmers usually assume that an overflow raises an - * error, which is the standard behavior in high level programming languages. - * `SafeMath` restores this intuition by reverting the transaction when an - * operation overflows. - * - * Using this library instead of the unchecked operations eliminates an entire - * class of bugs, so it's recommended to use it always. - */ -library SafeMath { - /** - * @dev Returns the addition of two unsigned integers, reverting on overflow. - * - * Counterpart to Solidity's `+` operator. - * - * Requirements: - * - Addition cannot overflow. - */ - function add(uint256 a, uint256 b) internal pure returns (uint256) { - uint256 c = a + b; - require(c >= a, "SafeMath: addition overflow"); - - return c; - } - - /** - * @dev Returns the addition of two unsigned integers, reverting with custom message on overflow. - * - * Counterpart to Solidity's `+` operator. - * - * Requirements: - * - Addition cannot overflow. - */ - function add(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - uint256 c = a + b; - require(c >= a, errorMessage); - - return c; - } - - /** - * @dev Returns the subtraction of two unsigned integers, reverting on underflow (when the result is negative). - * - * Counterpart to Solidity's `-` operator. - * - * Requirements: - * - Subtraction cannot underflow. - */ - function sub(uint256 a, uint256 b) internal pure returns (uint256) { - return sub(a, b, "SafeMath: subtraction underflow"); - } - - /** - * @dev Returns the subtraction of two unsigned integers, reverting with custom message on underflow (when the result is negative). - * - * Counterpart to Solidity's `-` operator. - * - * Requirements: - * - Subtraction cannot underflow. - */ - function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - require(b <= a, errorMessage); - uint256 c = a - b; - - return c; - } - - /** - * @dev Returns the multiplication of two unsigned integers, reverting on overflow. - * - * Counterpart to Solidity's `*` operator. - * - * Requirements: - * - Multiplication cannot overflow. - */ - function mul(uint256 a, uint256 b) internal pure returns (uint256) { - // Gas optimization: this is cheaper than requiring 'a' not being zero, but the - // benefit is lost if 'b' is also tested. - // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 - if (a == 0) { - return 0; - } - - uint256 c = a * b; - require(c / a == b, "SafeMath: multiplication overflow"); - - return c; - } - - /** - * @dev Returns the multiplication of two unsigned integers, reverting on overflow. - * - * Counterpart to Solidity's `*` operator. - * - * Requirements: - * - Multiplication cannot overflow. - */ - function mul(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - // Gas optimization: this is cheaper than requiring 'a' not being zero, but the - // benefit is lost if 'b' is also tested. - // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 - if (a == 0) { - return 0; - } - - uint256 c = a * b; - require(c / a == b, errorMessage); - - return c; - } - - /** - * @dev Returns the integer division of two unsigned integers. - * Reverts on division by zero. The result is rounded towards zero. - * - * Counterpart to Solidity's `/` operator. Note: this function uses a - * `revert` opcode (which leaves remaining gas untouched) while Solidity - * uses an invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function div(uint256 a, uint256 b) internal pure returns (uint256) { - return div(a, b, "SafeMath: division by zero"); - } - - /** - * @dev Returns the integer division of two unsigned integers. - * Reverts with custom message on division by zero. The result is rounded towards zero. - * - * Counterpart to Solidity's `/` operator. Note: this function uses a - * `revert` opcode (which leaves remaining gas untouched) while Solidity - * uses an invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - // Solidity only automatically asserts when dividing by 0 - require(b > 0, errorMessage); - uint256 c = a / b; - // assert(a == b * c + a % b); // There is no case in which this doesn't hold - - return c; - } - - /** - * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), - * Reverts when dividing by zero. - * - * Counterpart to Solidity's `%` operator. This function uses a `revert` - * opcode (which leaves remaining gas untouched) while Solidity uses an - * invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function mod(uint256 a, uint256 b) internal pure returns (uint256) { - return mod(a, b, "SafeMath: modulo by zero"); - } - - /** - * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), - * Reverts with custom message when dividing by zero. - * - * Counterpart to Solidity's `%` operator. This function uses a `revert` - * opcode (which leaves remaining gas untouched) while Solidity uses an - * invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - require(b != 0, errorMessage); - return a % b; - } -} - - -// Dependency file: contracts/InterestRateModel.sol - -// pragma solidity 0.8.6; - -// import "contracts/Exponential.sol"; -// import "contracts/SafeMath.sol"; - -/** - * @title tropykus InterestRateModel Interface - * @author tropykus - */ -abstract contract InterestRateModel is Exponential { - using SafeMath for uint256; - - /// @notice Indicator that this is an InterestRateModel contract (for inspection) - bool public constant isInterestRateModel = true; - bool public isTropykusInterestRateModel; - - /** - * @notice The approximate number of blocks per year that is assumed by the interest rate model - */ - uint256 public constant blocksPerYear = 1051200; - - /** - * @notice Calculates the utilization rate of the market: `borrows / (cash + borrows - reserves)` - * @param cash The amount of cash in the market - * @param borrows The amount of borrows in the market - * @param reserves The amount of reserves in the market (currently unused) - * @return The utilization rate as a mantissa between [0, 1e18] - */ - function utilizationRate( - uint256 cash, - uint256 borrows, - uint256 reserves - ) public pure virtual returns (uint256) { - // Utilization rate is 0 when there are no borrows - if (borrows == 0) { - return 0; - } - - return borrows.mul(1e18).div(cash.add(borrows).sub(reserves)); - } - - /** - * @notice Calculates the current borrow interest rate per block - * @param cash The total amount of cash the market has - * @param borrows The total amount of borrows the market has outstanding - * @param reserves The total amnount of reserves the market has - * @return The borrow rate per block (as a percentage, and scaled by 1e18) - */ - function getBorrowRate( - uint256 cash, - uint256 borrows, - uint256 reserves - ) external view virtual returns (uint256); - - /** - * @notice Calculates the current supply interest rate per block - * @param cash The total amount of cash the market has - * @param borrows The total amount of borrows the market has outstanding - * @param reserves The total amnount of reserves the market has - * @param reserveFactorMantissa The current reserve factor the market has - * @return The supply rate per block (as a percentage, and scaled by 1e18) - */ - function getSupplyRate( - uint256 cash, - uint256 borrows, - uint256 reserves, - uint256 reserveFactorMantissa - ) external view virtual returns (uint256); - - function getExchangeRate( - uint256 _totalCash, - uint256 _totalBorrows, - uint256 _totalReserves, - uint256 _totalSupply - ) public pure returns (MathError, uint256) { - /* - * exchangeRate = (totalCash + totalBorrows - totalReserves) / totalSupply - */ - Exp memory exchangeRate; - MathError mathErr; - uint256 cashPlusBorrowsMinusReserves; - (mathErr, cashPlusBorrowsMinusReserves) = addThenSubUInt( - _totalCash, - _totalBorrows, - _totalReserves - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - (mathErr, exchangeRate) = getExp( - cashPlusBorrowsMinusReserves, - _totalSupply - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - - return (MathError.NO_ERROR, exchangeRate.mantissa); - } - - function isAboveOptimal( - uint256 cash, - uint256 borrows, - uint256 reserves - ) public view virtual returns (bool) { - cash; - borrows; - reserves; - return false; - } -} - - -// Dependency file: contracts/EIP20NonStandardInterface.sol - -// pragma solidity 0.8.6; - -/** - * @title EIP20NonStandardInterface - * @dev Version of ERC20 with no return values for `transfer` and `transferFrom` - * See https://medium.com/coinmonks/missing-return-value-bug-at-least-130-tokens-affected-d67bf08521ca - */ -interface EIP20NonStandardInterface { - /** - * @notice Get the total number of tokens in circulation - * @return The supply of tokens - */ - function totalSupply() external view returns (uint256); - - /** - * @notice Gets the balance of the specified address - * @param owner The address from which the balance will be retrieved - * @return balance The balance - */ - function balanceOf(address owner) external view returns (uint256 balance); - - /// - /// !!!!!!!!!!!!!! - /// !!! NOTICE !!! `transfer` does not return a value, in violation of the ERC-20 specification - /// !!!!!!!!!!!!!! - /// - - /** - * @notice Transfer `amount` tokens from `msg.sender` to `dst` - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - */ - function transfer(address dst, uint256 amount) external; - - /// - /// !!!!!!!!!!!!!! - /// !!! NOTICE !!! `transferFrom` does not return a value, in violation of the ERC-20 specification - /// !!!!!!!!!!!!!! - /// - - /** - * @notice Transfer `amount` tokens from `src` to `dst` - * @param src The address of the source account - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - */ - function transferFrom( - address src, - address dst, - uint256 amount - ) external; - - /** - * @notice Approve `spender` to transfer up to `amount` from `src` - * @dev This will overwrite the approval amount for `spender` - * and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve) - * @param spender The address of the account which may transfer tokens - * @param amount The number of tokens that are approved - * @return success Whether or not the approval succeeded - */ - function approve(address spender, uint256 amount) - external - returns (bool success); - - /** - * @notice Get the current allowance from `owner` for `spender` - * @param owner The address of the account which owns the tokens to be spent - * @param spender The address of the account which may transfer tokens - * @return remaining The number of tokens allowed to be spent - */ - function allowance(address owner, address spender) - external - view - returns (uint256 remaining); - - event Transfer(address indexed from, address indexed to, uint256 amount); - event Approval( - address indexed owner, - address indexed spender, - uint256 amount - ); -} - - -// Dependency file: contracts/CTokenInterfaces.sol - -// pragma solidity 0.8.6; - -// import "contracts/ComptrollerInterface.sol"; -// import "contracts/InterestRateModel.sol"; -// import "contracts/EIP20NonStandardInterface.sol"; - -contract CTokenStorage { - /** - * @dev Guard variable for re-entrancy checks - */ - bool internal _notEntered; - - /** - * @notice EIP-20 token name for this token - */ - string public name; - - /** - * @notice EIP-20 token symbol for this token - */ - string public symbol; - - /** - * @notice EIP-20 token decimals for this token - */ - uint8 public decimals; - - /** - * @notice Maximum borrow rate that can ever be applied (.0005% / block) - */ - - uint256 internal constant borrowRateMaxMantissa = 0.0005e16; - - /** - * @notice Maximum fraction of interest that can be set aside for reserves - */ - uint256 internal constant reserveFactorMaxMantissa = 1e18; - - /** - * @notice Administrator for this contract - */ - address payable public admin; - - /** - * @notice Pending administrator for this contract - */ - address payable public pendingAdmin; - - /** - * @notice Contract which oversees inter-cToken operations - */ - ComptrollerInterface public comptroller; - - /** - * @notice Model which tells what the current interest rate should be - */ - InterestRateModel public interestRateModel; - - /** - * @notice Initial exchange rate used when minting the first CTokens (used when totalSupply = 0) - */ - uint256 public initialExchangeRateMantissa; - - /** - * @notice Fraction of interest currently set aside for reserves - */ - uint256 public reserveFactorMantissa; - - /** - * @notice Block number that interest was last accrued at - */ - uint256 public accrualBlockNumber; - - /** - * @notice Accumulator of the total earned interest rate since the opening of the market - */ - uint256 public borrowIndex; - - /** - * @notice Total amount of outstanding borrows of the underlying in this market - */ - uint256 public totalBorrows; - - /** - * @notice Total amount of reserves of the underlying held in this market - */ - uint256 public totalReserves; - - /** - * @notice Total number of tokens in circulation - */ - uint256 public totalSupply; - - uint256 public subsidyFund; - - struct SupplySnapshot { - uint256 tokens; - uint256 underlyingAmount; - uint256 suppliedAt; - uint256 promisedSupplyRate; - } - - /** - * @notice Official record of token balances for each account - */ - mapping(address => SupplySnapshot) internal accountTokens; - - /** - * @notice Approved token transfer amounts on behalf of others - */ - mapping(address => mapping(address => uint256)) internal transferAllowances; - - /** - * @notice Container for borrow balance information - * @member principal Total balance (with accrued interest), after applying the most recent balance-changing action - * @member interestIndex Global borrowIndex as of the most recent balance-changing action - */ - struct BorrowSnapshot { - uint256 principal; - uint256 interestIndex; - } - - /** - * @notice Mapping of account addresses to outstanding borrow balances - */ - mapping(address => BorrowSnapshot) internal accountBorrows; -} - -abstract contract CTokenInterface is CTokenStorage { - /** - * @notice Indicator that this is a CToken contract (for inspection) - */ - bool public constant isCToken = true; - - /*** Market Events ***/ - - /** - * @notice Event emitted when interest is accrued - */ - event AccrueInterest( - uint256 cashPrior, - uint256 interestAccumulated, - uint256 borrowIndex, - uint256 totalBorrows - ); - - /** - * @notice Event emitted when tokens are minted - */ - event Mint(address indexed minter, uint256 mintAmount, uint256 mintTokens); - - /** - * @notice Event emitted when tokens are redeemed - */ - event Redeem( - address indexed redeemer, - uint256 redeemAmount, - uint256 redeemTokens - ); - - /** - * @notice Event emitted when underlying is borrowed - */ - event Borrow( - address indexed borrower, - uint256 borrowAmount, - uint256 accountBorrows, - uint256 totalBorrows - ); - - /** - * @notice Event emitted when a borrow is repaid - */ - event RepayBorrow( - address indexed payer, - address indexed borrower, - uint256 repayAmount, - uint256 accountBorrows, - uint256 totalBorrows - ); - - /** - * @notice Event emitted when a borrow is liquidated - */ - event LiquidateBorrow( - address indexed liquidator, - address indexed borrower, - uint256 repayAmount, - address indexed cTokenCollateral, - uint256 seizeTokens - ); - - /*** Admin Events ***/ - - /** - * @notice Event emitted when pendingAdmin is changed - */ - event NewPendingAdmin(address oldPendingAdmin, address newPendingAdmin); - - /** - * @notice Event emitted when pendingAdmin is accepted, which means admin is updated - */ - event NewAdmin(address oldAdmin, address newAdmin); - - /** - * @notice Event emitted when comptroller is changed - */ - event NewComptroller( - ComptrollerInterface oldComptroller, - ComptrollerInterface newComptroller - ); - - /** - * @notice Event emitted when interestRateModel is changed - */ - event NewMarketInterestRateModel( - InterestRateModel oldInterestRateModel, - InterestRateModel newInterestRateModel - ); - - /** - * @notice Event emitted when the reserve factor is changed - */ - event NewReserveFactor( - uint256 oldReserveFactorMantissa, - uint256 newReserveFactorMantissa - ); - - /** - * @notice Event emitted when the reserves are added - */ - event ReservesAdded( - address benefactor, - uint256 addAmount, - uint256 newTotalReserves - ); - - event SubsidyAdded( - address benefactor, - uint256 addAmount, - uint256 newSubsidyFund - ); - - /** - * @notice Event emitted when the reserves are reduced - */ - event ReservesReduced( - address admin, - uint256 reduceAmount, - uint256 newTotalReserves - ); - - /** - * @notice EIP20 Transfer event - */ - event Transfer(address indexed from, address indexed to, uint256 amount); - - /** - * @notice EIP20 Approval event - */ - event Approval( - address indexed owner, - address indexed spender, - uint256 amount - ); - - /** - * @notice Failure event - */ - event CTokenStorageFailure(uint256 error, uint256 info, uint256 detail); - - /*** User Interface ***/ - - function transfer(address dst, uint256 amount) - external - virtual - returns (bool); - - function transferFrom( - address src, - address dst, - uint256 amount - ) external virtual returns (bool); - - function approve(address spender, uint256 amount) - external - virtual - returns (bool); - - function allowance(address owner, address spender) - external - view - virtual - returns (uint256); - - function balanceOf(address owner) external view virtual returns (uint256); - - function balanceOfUnderlying(address owner) - external - virtual - returns (uint256); - - function getAccountSnapshot(address account) - external - view - virtual - returns ( - uint256, - uint256, - uint256, - uint256 - ); - - function borrowRatePerBlock() external view virtual returns (uint256); - - function supplyRatePerBlock() external view virtual returns (uint256); - - function totalBorrowsCurrent() external virtual returns (uint256); - - function borrowBalanceCurrent(address account) - external - virtual - returns (uint256); - - function borrowBalanceStored(address account) - public - view - virtual - returns (uint256); - - function exchangeRateCurrent() public virtual returns (uint256); - - function exchangeRateStored() public view virtual returns (uint256); - - function getCash() external view virtual returns (uint256); - - function accrueInterest() public virtual returns (uint256); - - function seize( - address liquidator, - address borrower, - uint256 seizeTokens - ) external virtual returns (uint256); - - /*** Admin Functions ***/ - - function _setPendingAdmin(address payable newPendingAdmin) - external - virtual - returns (uint256); - - function _acceptAdmin() external virtual returns (uint256); - - function _setComptroller(ComptrollerInterface newComptroller) - public - virtual - returns (uint256); - - function _setReserveFactor(uint256 newReserveFactorMantissa) - external - virtual - returns (uint256); - - function _reduceReserves(uint256 reduceAmount) - external - virtual - returns (uint256); - - function _setInterestRateModel(InterestRateModel newInterestRateModel) - public - virtual - returns (uint256); -} - -contract CErc20Storage { - /** - * @notice Underlying asset for this CToken - */ - address public underlying; -} - -abstract contract CErc20Interface is CErc20Storage { - /*** User Interface ***/ - - function mint(uint256 mintAmount) external virtual returns (uint256); - - function redeem(uint256 redeemAmount) - external - virtual - returns (uint256); - - function borrow(uint256 borrowAmount) external virtual returns (uint256); - - function repayBorrow(uint256 repayAmount) - external - virtual - returns (uint256); - - function liquidateBorrow( - address borrower, - uint256 repayAmount, - CTokenInterface cTokenCollateral - ) external virtual returns (uint256); - - function sweepToken(EIP20NonStandardInterface token) external virtual; - - /*** Admin Functions ***/ - - function _addReserves(uint256 addAmount) external virtual returns (uint256); -} - -contract CDelegationStorage { - /** - * @notice Implementation address for this contract - */ - address public implementation; -} - -abstract contract CDelegatorInterface is CDelegationStorage { - /** - * @notice Emitted when implementation is changed - */ - event NewImplementation( - address oldImplementation, - address newImplementation - ); - - /** - * @notice Called by the admin to update the implementation of the delegator - * @param implementation_ The address of the new implementation for delegation - * @param allowResign Flag to indicate whether to call _resignImplementation on the old implementation - * @param becomeImplementationData The encoded bytes data to be passed to _becomeImplementation - */ - function _setImplementation( - address implementation_, - bool allowResign, - bytes memory becomeImplementationData - ) public virtual; -} - -abstract contract CDelegateInterface is CDelegationStorage { - /** - * @notice Called by the delegator on a delegate to initialize it for duty - * @dev Should revert if any issues arise which make it unfit for delegation - * @param data The encoded bytes data for any initialization - */ - function _becomeImplementation(bytes memory data) public virtual; - - /** - * @notice Called by the delegator on a delegate to forfeit its responsibility - */ - function _resignImplementation() public virtual; -} - - -// Dependency file: contracts/ErrorReporter.sol - -// pragma solidity 0.8.6; - -contract ComptrollerErrorReporter { - enum Error { - NO_ERROR, - UNAUTHORIZED, - COMPTROLLER_MISMATCH, - INSUFFICIENT_SHORTFALL, - INSUFFICIENT_LIQUIDITY, - INVALID_CLOSE_FACTOR, - INVALID_COLLATERAL_FACTOR, - INVALID_LIQUIDATION_INCENTIVE, - MARKET_NOT_ENTERED, // no longer possible - MARKET_NOT_LISTED, - MARKET_ALREADY_LISTED, - MATH_ERROR, - NONZERO_BORROW_BALANCE, - PRICE_ERROR, - REJECTION, - SNAPSHOT_ERROR, - TOO_MANY_ASSETS, - TOO_MUCH_REPAY - } - - enum FailureInfo { - ACCEPT_ADMIN_PENDING_ADMIN_CHECK, - ACCEPT_PENDING_IMPLEMENTATION_ADDRESS_CHECK, - EXIT_MARKET_BALANCE_OWED, - EXIT_MARKET_REJECTION, - SET_CLOSE_FACTOR_OWNER_CHECK, - SET_CLOSE_FACTOR_VALIDATION, - SET_COLLATERAL_FACTOR_OWNER_CHECK, - SET_COLLATERAL_FACTOR_NO_EXISTS, - SET_COLLATERAL_FACTOR_VALIDATION, - SET_COLLATERAL_FACTOR_WITHOUT_PRICE, - SET_IMPLEMENTATION_OWNER_CHECK, - SET_LIQUIDATION_INCENTIVE_OWNER_CHECK, - SET_LIQUIDATION_INCENTIVE_VALIDATION, - SET_MAX_ASSETS_OWNER_CHECK, - SET_PENDING_ADMIN_OWNER_CHECK, - SET_PENDING_IMPLEMENTATION_OWNER_CHECK, - SET_PRICE_ORACLE_OWNER_CHECK, - SUPPORT_MARKET_EXISTS, - SUPPORT_MARKET_OWNER_CHECK, - SET_PAUSE_GUARDIAN_OWNER_CHECK - } - - /** - * @dev `error` corresponds to enum Error; `info` corresponds to enum FailureInfo, and `detail` is an arbitrary - * contract-specific code that enables us to report opaque error codes from upgradeable contracts. - **/ - event Failure(uint256 error, uint256 info, uint256 detail); - - /** - * @dev use this when reporting a known error from the money market or a non-upgradeable collaborator - */ - function fail(Error err, FailureInfo info) internal returns (uint256) { - emit Failure(uint256(err), uint256(info), 0); - - return uint256(err); - } - - /** - * @dev use this when reporting an opaque error from an upgradeable collaborator contract - */ - function failOpaque( - Error err, - FailureInfo info, - uint256 opaqueError - ) internal returns (uint256) { - emit Failure(uint256(err), uint256(info), opaqueError); - - return uint256(err); - } -} - -contract TokenErrorReporter { - enum Error { - NO_ERROR, - UNAUTHORIZED, - BAD_INPUT, - COMPTROLLER_REJECTION, - COMPTROLLER_CALCULATION_ERROR, - INTEREST_RATE_MODEL_ERROR, - INVALID_ACCOUNT_PAIR, - INVALID_CLOSE_AMOUNT_REQUESTED, - INVALID_COLLATERAL_FACTOR, - MATH_ERROR, - MARKET_NOT_FRESH, - MARKET_NOT_LISTED, - TOKEN_INSUFFICIENT_ALLOWANCE, - TOKEN_INSUFFICIENT_BALANCE, - TOKEN_INSUFFICIENT_CASH, - TOKEN_TRANSFER_IN_FAILED, - TOKEN_TRANSFER_OUT_FAILED - } - - /* - * Note: FailureInfo (but not Error) is kept in alphabetical order - * This is because FailureInfo grows significantly faster, and - * the order of Error has some meaning, while the order of FailureInfo - * is entirely arbitrary. - */ - enum FailureInfo { - ACCEPT_ADMIN_PENDING_ADMIN_CHECK, - ACCRUE_INTEREST_ACCUMULATED_INTEREST_CALCULATION_FAILED, - ACCRUE_INTEREST_BORROW_RATE_CALCULATION_FAILED, - ACCRUE_INTEREST_NEW_BORROW_INDEX_CALCULATION_FAILED, - ACCRUE_INTEREST_NEW_TOTAL_BORROWS_CALCULATION_FAILED, - ACCRUE_INTEREST_NEW_TOTAL_RESERVES_CALCULATION_FAILED, - ACCRUE_INTEREST_SIMPLE_INTEREST_FACTOR_CALCULATION_FAILED, - BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED, - BORROW_ACCRUE_INTEREST_FAILED, - BORROW_CASH_NOT_AVAILABLE, - BORROW_FRESHNESS_CHECK, - BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED, - BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED, - BORROW_MARKET_NOT_LISTED, - BORROW_COMPTROLLER_REJECTION, - LIQUIDATE_ACCRUE_BORROW_INTEREST_FAILED, - LIQUIDATE_ACCRUE_COLLATERAL_INTEREST_FAILED, - LIQUIDATE_COLLATERAL_FRESHNESS_CHECK, - LIQUIDATE_COMPTROLLER_REJECTION, - LIQUIDATE_COMPTROLLER_CALCULATE_AMOUNT_SEIZE_FAILED, - LIQUIDATE_CLOSE_AMOUNT_IS_UINT_MAX, - LIQUIDATE_CLOSE_AMOUNT_IS_ZERO, - LIQUIDATE_FRESHNESS_CHECK, - LIQUIDATE_LIQUIDATOR_IS_BORROWER, - LIQUIDATE_REPAY_BORROW_FRESH_FAILED, - LIQUIDATE_SEIZE_BALANCE_INCREMENT_FAILED, - LIQUIDATE_SEIZE_BALANCE_DECREMENT_FAILED, - LIQUIDATE_SEIZE_COMPTROLLER_REJECTION, - LIQUIDATE_SEIZE_LIQUIDATOR_IS_BORROWER, - LIQUIDATE_SEIZE_TOO_MUCH, - MINT_ACCRUE_INTEREST_FAILED, - MINT_COMPTROLLER_REJECTION, - MINT_EXCHANGE_CALCULATION_FAILED, - MINT_EXCHANGE_RATE_READ_FAILED, - MINT_FRESHNESS_CHECK, - MINT_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED, - MINT_NEW_TOTAL_SUPPLY_CALCULATION_FAILED, - MINT_TRANSFER_IN_FAILED, - MINT_TRANSFER_IN_NOT_POSSIBLE, - REDEEM_ACCRUE_INTEREST_FAILED, - REDEEM_COMPTROLLER_REJECTION, - REDEEM_EXCHANGE_TOKENS_CALCULATION_FAILED, - REDEEM_EXCHANGE_AMOUNT_CALCULATION_FAILED, - REDEEM_EXCHANGE_RATE_READ_FAILED, - REDEEM_FRESHNESS_CHECK, - REDEEM_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED, - REDEEM_NEW_TOTAL_SUPPLY_CALCULATION_FAILED, - REDEEM_TRANSFER_OUT_NOT_POSSIBLE, - REDUCE_RESERVES_ACCRUE_INTEREST_FAILED, - REDUCE_RESERVES_ADMIN_CHECK, - REDUCE_RESERVES_CASH_NOT_AVAILABLE, - REDUCE_RESERVES_FRESH_CHECK, - REDUCE_RESERVES_VALIDATION, - REPAY_BEHALF_ACCRUE_INTEREST_FAILED, - REPAY_BORROW_ACCRUE_INTEREST_FAILED, - REPAY_BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED, - REPAY_BORROW_COMPTROLLER_REJECTION, - REPAY_BORROW_FRESHNESS_CHECK, - REPAY_BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED, - REPAY_BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED, - REPAY_BORROW_TRANSFER_IN_NOT_POSSIBLE, - SET_COLLATERAL_FACTOR_OWNER_CHECK, - SET_COLLATERAL_FACTOR_VALIDATION, - SET_COMPTROLLER_OWNER_CHECK, - SET_INTEREST_RATE_MODEL_ACCRUE_INTEREST_FAILED, - SET_INTEREST_RATE_MODEL_FRESH_CHECK, - SET_INTEREST_RATE_MODEL_OWNER_CHECK, - SET_MAX_ASSETS_OWNER_CHECK, - SET_ORACLE_MARKET_NOT_LISTED, - SET_PENDING_ADMIN_OWNER_CHECK, - SET_RESERVE_FACTOR_ACCRUE_INTEREST_FAILED, - SET_RESERVE_FACTOR_ADMIN_CHECK, - SET_RESERVE_FACTOR_FRESH_CHECK, - SET_RESERVE_FACTOR_BOUNDS_CHECK, - TRANSFER_COMPTROLLER_REJECTION, - TRANSFER_NOT_ALLOWED, - TRANSFER_NOT_ENOUGH, - TRANSFER_TOO_MUCH, - ADD_RESERVES_ACCRUE_INTEREST_FAILED, - ADD_RESERVES_FRESH_CHECK, - ADD_RESERVES_TRANSFER_IN_NOT_POSSIBLE, - ADD_SUBSIDY_FUND_FAILED, - ADD_SUBSIDY_FUND_FRESH_CHECK - } - - /** - * @dev `error` corresponds to enum Error; `info` corresponds to enum FailureInfo, and `detail` is an arbitrary - * contract-specific code that enables us to report opaque error codes from upgradeable contracts. - **/ - event TokenFailure(uint256 error, uint256 info, uint256 detail); - - /** - * @dev use this when reporting a known error from the money market or a non-upgradeable collaborator - */ - function fail(Error err, FailureInfo info) internal returns (uint256) { - emit TokenFailure(uint256(err), uint256(info), 0); - - return uint256(err); - } - - /** - * @dev use this when reporting an opaque error from an upgradeable collaborator contract - */ - function failOpaque( - Error err, - FailureInfo info, - uint256 opaqueError - ) internal returns (uint256) { - emit TokenFailure(uint256(err), uint256(info), opaqueError); - - return uint256(err); - } -} - - -// Dependency file: contracts/EIP20Interface.sol - -// pragma solidity 0.8.6; - -/** - * @title ERC 20 Token Standard Interface - * https://eips.ethereum.org/EIPS/eip-20 - */ -interface EIP20Interface { - function name() external view returns (string memory); - - function symbol() external view returns (string memory); - - function decimals() external view returns (uint8); - - /** - * @notice Get the total number of tokens in circulation - * @return The supply of tokens - */ - function totalSupply() external view returns (uint256); - - /** - * @notice Gets the balance of the specified address - * @param owner The address from which the balance will be retrieved - * @return balance The balance - */ - function balanceOf(address owner) external view returns (uint256 balance); - - /** - * @notice Transfer `amount` tokens from `msg.sender` to `dst` - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - * @return success Whether or not the transfer succeeded - */ - function transfer(address dst, uint256 amount) - external - returns (bool success); - - /** - * @notice Transfer `amount` tokens from `src` to `dst` - * @param src The address of the source account - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - * @return success Whether or not the transfer succeeded - */ - function transferFrom( - address src, - address dst, - uint256 amount - ) external returns (bool success); - - /** - * @notice Approve `spender` to transfer up to `amount` from `src` - * @dev This will overwrite the approval amount for `spender` - * and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve) - * @param spender The address of the account which may transfer tokens - * @param amount The number of tokens that are approved (-1 means infinite) - * @return success Whether or not the approval succeeded - */ - function approve(address spender, uint256 amount) - external - returns (bool success); - - /** - * @notice Get the current allowance from `owner` for `spender` - * @param owner The address of the account which owns the tokens to be spent - * @param spender The address of the account which may transfer tokens - * @return remaining The number of tokens allowed to be spent (-1 means infinite) - */ - function allowance(address owner, address spender) - external - view - returns (uint256 remaining); - - event Transfer(address indexed from, address indexed to, uint256 amount); - event Approval( - address indexed owner, - address indexed spender, - uint256 amount - ); -} - - -// Dependency file: contracts/WhitelistInterface.sol - -// pragma solidity 0.8.6; - -interface WhitelistInterface { - function setStatus(bool _newStatus) external; - function enabled() external view returns(bool); - - function addUsers(address[] memory _users) external; - function exist(address _user) external view returns(bool); - function getUsers() external view returns(address[] memory currentUsers); - function removeUser(address _user) external; -} - -// Dependency file: contracts/CToken.sol - -// pragma solidity 0.8.6; - -// import "contracts/ComptrollerInterface.sol"; -// import "contracts/CTokenInterfaces.sol"; -// import "contracts/ErrorReporter.sol"; -// import "contracts/Exponential.sol"; -// import "contracts/EIP20Interface.sol"; -// import "contracts/InterestRateModel.sol"; -// import "contracts/WhitelistInterface.sol"; - -/** - * @title tropykus CToken Contract - * @notice Abstract base for CTokens - * @author tropykus - */ -abstract contract CToken is CTokenInterface, Exponential, TokenErrorReporter { - address whitelist; - - /** - * @notice Initialize the money market - * @param comptroller_ The address of the Comptroller - * @param interestRateModel_ The address of the interest rate model - * @param initialExchangeRateMantissa_ The initial exchange rate, scaled by 1e18 - * @param name_ EIP-20 name of this token - * @param symbol_ EIP-20 symbol of this token - * @param decimals_ EIP-20 decimal precision of this token - */ - function initialize( - ComptrollerInterface comptroller_, - InterestRateModel interestRateModel_, - uint256 initialExchangeRateMantissa_, - string memory name_, - string memory symbol_, - uint8 decimals_ - ) public { - require(msg.sender == admin, "CT01"); - require(accrualBlockNumber == 0 && borrowIndex == 0, "CT02"); - - initialExchangeRateMantissa = initialExchangeRateMantissa_; - require(initialExchangeRateMantissa > 0, "CT03"); - - uint256 err = _setComptroller(comptroller_); - require(err == uint256(Error.NO_ERROR), "CT04"); - - accrualBlockNumber = getBlockNumber(); - borrowIndex = mantissaOne; - - err = _setInterestRateModelFresh(interestRateModel_); - require(err == uint256(Error.NO_ERROR), "CT05"); - - name = name_; - symbol = symbol_; - decimals = decimals_; - - _notEntered = true; - } - - function addWhitelist(address _whitelist) external returns (uint256) { - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_INTEREST_RATE_MODEL_OWNER_CHECK - ); - } - whitelist = _whitelist; - } - - /** - * @notice Transfer `tokens` tokens from `src` to `dst` by `spender` - * @dev Called by both `transfer` and `transferFrom` internally - * @param spender The address of the account performing the transfer - * @param src The address of the source account - * @param dst The address of the destination account - * @param tokens The number of tokens to transfer - * @return Whether or not the transfer succeeded - */ - function transferTokens( - address spender, - address src, - address dst, - uint256 tokens - ) internal returns (uint256) { - uint256 allowed = comptroller.transferAllowed( - address(this), - src, - dst, - tokens - ); - if (allowed != 0) { - return - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.TRANSFER_COMPTROLLER_REJECTION, - allowed - ); - } - - if (src == dst) { - return fail(Error.BAD_INPUT, FailureInfo.TRANSFER_NOT_ALLOWED); - } - - uint256 startingAllowance = 0; - if (spender == src) { - startingAllowance = type(uint256).max; - } else { - startingAllowance = transferAllowances[src][spender]; - } - - MathError mathErr; - uint256 allowanceNew; - uint256 srcTokensNew; - uint256 dstTokensNew; - - (mathErr, allowanceNew) = subUInt(startingAllowance, tokens); - if (mathErr != MathError.NO_ERROR) { - return fail(Error.MATH_ERROR, FailureInfo.TRANSFER_NOT_ALLOWED); - } - - (mathErr, srcTokensNew) = subUInt(accountTokens[src].tokens, tokens); - if (mathErr != MathError.NO_ERROR) { - return fail(Error.MATH_ERROR, FailureInfo.TRANSFER_NOT_ENOUGH); - } - - (mathErr, dstTokensNew) = addUInt(accountTokens[dst].tokens, tokens); - if (mathErr != MathError.NO_ERROR) { - return fail(Error.MATH_ERROR, FailureInfo.TRANSFER_TOO_MUCH); - } - - accountTokens[src].tokens = srcTokensNew; - accountTokens[dst].tokens = dstTokensNew; - - if (startingAllowance != type(uint256).max) { - transferAllowances[src][spender] = allowanceNew; - } - - emit Transfer(src, dst, tokens); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Transfer `amount` tokens from `msg.sender` to `dst` - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - * @return Whether or not the transfer succeeded - */ - function transfer(address dst, uint256 amount) - external - override - nonReentrant - returns (bool) - { - return - transferTokens(msg.sender, msg.sender, dst, amount) == - uint256(Error.NO_ERROR); - } - - /** - * @notice Transfer `amount` tokens from `src` to `dst` - * @param src The address of the source account - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - * @return Whether or not the transfer succeeded - */ - function transferFrom( - address src, - address dst, - uint256 amount - ) external override nonReentrant returns (bool) { - return - transferTokens(msg.sender, src, dst, amount) == - uint256(Error.NO_ERROR); - } - - /** - * @notice Approve `spender` to transfer up to `amount` from `src` - * @dev This will overwrite the approval amount for `spender` - * and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve) - * @param spender The address of the account which may transfer tokens - * @param amount The number of tokens that are approved (-1 means infinite) - * @return Whether or not the approval succeeded - */ - function approve(address spender, uint256 amount) - external - override - returns (bool) - { - transferAllowances[msg.sender][spender] = amount; - emit Approval(msg.sender, spender, amount); - return true; - } - - /** - * @notice Get the current allowance from `owner` for `spender` - * @param owner The address of the account which owns the tokens to be spent - * @param spender The address of the account which may transfer tokens - * @return The number of tokens allowed to be spent (-1 means infinite) - */ - function allowance(address owner, address spender) - external - view - override - returns (uint256) - { - return transferAllowances[owner][spender]; - } - - /** - * @notice Get the token balance of the `owner` - * @param owner The address of the account to query - * @return The number of tokens owned by `owner` - */ - function balanceOf(address owner) external view override returns (uint256) { - return accountTokens[owner].tokens; - } - - /** - * @notice Get the underlying balance of the `owner` - * @dev This also accrues interest in a transaction - * @param owner The address of the account to query - * @return The amount of underlying owned by `owner` - */ - function balanceOfUnderlying(address owner) - external - override - returns (uint256) - { - (MathError mErr, uint256 balance) = mulScalarTruncate( - Exp({mantissa: exchangeRateCurrent()}), - accountTokens[owner].tokens - ); - require(mErr == MathError.NO_ERROR, "CT06"); - return balance; - } - - /** - * @notice Get a snapshot of the account's balances, and the cached exchange rate - * @dev This is used by comptroller to more efficiently perform liquidity checks. - * @param account Address of the account to snapshot - * @return (possible error, token balance, borrow balance, exchange rate mantissa) - */ - function getAccountSnapshot(address account) - external - view - override - returns ( - uint256, - uint256, - uint256, - uint256 - ) - { - uint256 cTokenBalance = accountTokens[account].tokens; - uint256 borrowBalance; - uint256 exchangeRateMantissa; - - MathError mErr; - - (mErr, borrowBalance) = borrowBalanceStoredInternal(account); - if (mErr != MathError.NO_ERROR) { - return (uint256(Error.MATH_ERROR), 0, 0, 0); - } - - (mErr, exchangeRateMantissa) = exchangeRateStoredInternal(); - if (mErr != MathError.NO_ERROR) { - return (uint256(Error.MATH_ERROR), 0, 0, 0); - } - - return ( - uint256(Error.NO_ERROR), - cTokenBalance, - borrowBalance, - exchangeRateMantissa - ); - } - - /** - * @dev Function to simply retrieve block number - * This exists mainly for inheriting test contracts to stub this result. - */ - function getBlockNumber() internal view virtual returns (uint256) { - return block.number; - } - - /** - * @notice Returns the current per-block borrow interest rate for this cToken - * @return The borrow interest rate per block, scaled by 1e18 - */ - function borrowRatePerBlock() external view override returns (uint256) { - return - interestRateModel.getBorrowRate( - getCashPrior(), - totalBorrows, - totalReserves - ); - } - - /** - * @notice Returns the current per-block supply interest rate for this cToken - * @return The supply interest rate per block, scaled by 1e18 - */ - function supplyRatePerBlock() external view override returns (uint256) { - return - interestRateModel.getSupplyRate( - getCashPrior(), - totalBorrows, - totalReserves, - reserveFactorMantissa - ); - } - - /** - * @notice Returns the current total borrows plus accrued interest - * @return The total borrows with interest - */ - function totalBorrowsCurrent() - external - override - nonReentrant - returns (uint256) - { - require(accrueInterest() == uint256(Error.NO_ERROR), "CT07"); - return totalBorrows; - } - - /** - * @notice Accrue interest to updated borrowIndex and then calculate account's borrow balance using the updated borrowIndex - * @param account The address whose balance should be calculated after updating borrowIndex - * @return The calculated balance - */ - function borrowBalanceCurrent(address account) - external - override - nonReentrant - returns (uint256) - { - require(accrueInterest() == uint256(Error.NO_ERROR), "CT07"); - return borrowBalanceStored(account); - } - - /** - * @notice Return the borrow balance of account based on stored data - * @param account The address whose balance should be calculated - * @return The calculated balance - */ - function borrowBalanceStored(address account) - public - view - override - returns (uint256) - { - (MathError err, uint256 result) = borrowBalanceStoredInternal(account); - require(err == MathError.NO_ERROR, "CT08"); - return result; - } - - /** - * @notice Return the borrow balance of account based on stored data - * @param account The address whose balance should be calculated - * @return (error code, the calculated balance or 0 if error code is non-zero) - */ - function borrowBalanceStoredInternal(address account) - internal - view - returns (MathError, uint256) - { - MathError mathErr; - uint256 principalTimesIndex; - uint256 result; - - BorrowSnapshot storage borrowSnapshot = accountBorrows[account]; - - if (borrowSnapshot.principal == 0) { - return (MathError.NO_ERROR, 0); - } - - (mathErr, principalTimesIndex) = mulUInt( - borrowSnapshot.principal, - borrowIndex - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - - (mathErr, result) = divUInt( - principalTimesIndex, - borrowSnapshot.interestIndex - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - - return (MathError.NO_ERROR, result); - } - - function getBorrowerPrincipalStored(address account) - public - view - returns (uint256 borrowed) - { - borrowed = accountBorrows[account].principal; - } - - function getSupplierSnapshotStored(address account) - public - view - returns ( - uint256 tokens, - uint256 underlyingAmount, - uint256 suppliedAt, - uint256 promisedSupplyRate - ) - { - tokens = accountTokens[account].tokens; - underlyingAmount = accountTokens[account].underlyingAmount; - suppliedAt = accountTokens[account].suppliedAt; - promisedSupplyRate = accountTokens[account].promisedSupplyRate; - } - - /** - * @notice Accrue interest then return the up-to-date exchange rate - * @return Calculated exchange rate scaled by 1e18 - */ - function exchangeRateCurrent() - public - override - nonReentrant - returns (uint256) - { - require(accrueInterest() == uint256(Error.NO_ERROR), "CT07"); - return exchangeRateStored(); - } - - /** - * @notice Calculates the exchange rate from the underlying to the CToken - * @dev This function does not accrue interest before calculating the exchange rate - * @return Calculated exchange rate scaled by 1e18 - */ - function exchangeRateStored() public view override returns (uint256) { - (MathError err, uint256 result) = exchangeRateStoredInternal(); - require(err == MathError.NO_ERROR, "CT09"); - return result; - } - - /** - * @notice Calculates the exchange rate from the underlying to the CToken - * @dev This function does not accrue interest before calculating the exchange rate - * @return (error code, calculated exchange rate scaled by 1e18) - */ - function exchangeRateStoredInternal() - internal - view - virtual - returns (MathError, uint256) - { - uint256 _totalSupply = totalSupply; - if (_totalSupply == 0) { - return (MathError.NO_ERROR, initialExchangeRateMantissa); - } else { - MathError error; - uint256 exchangeRate; - uint256 totalCash = getCashPrior(); - if (interestRateModel.isTropykusInterestRateModel()) { - (error, exchangeRate) = tropykusExchangeRateStoredInternal( - msg.sender - ); - if (error == MathError.NO_ERROR) { - return (MathError.NO_ERROR, exchangeRate); - } else { - return (MathError.NO_ERROR, initialExchangeRateMantissa); - } - } - return - interestRateModel.getExchangeRate( - totalCash, - totalBorrows, - totalReserves, - totalSupply - ); - } - } - - function tropykusExchangeRateStoredInternal(address redeemer) - internal - view - returns (MathError, uint256) - { - if (totalSupply == 0) { - return (MathError.NO_ERROR, initialExchangeRateMantissa); - } else { - SupplySnapshot storage supplySnapshot = accountTokens[redeemer]; - if (supplySnapshot.suppliedAt == 0) { - return (MathError.DIVISION_BY_ZERO, 0); - } - (, uint256 interestFactorMantissa, ) = tropykusInterestAccrued( - redeemer - ); - Exp memory interestFactor = Exp({mantissa: interestFactorMantissa}); - uint256 currentUnderlying = supplySnapshot.underlyingAmount; - Exp memory redeemerUnderlying = Exp({mantissa: currentUnderlying}); - (, Exp memory realAmount) = mulExp( - interestFactor, - redeemerUnderlying - ); - (, Exp memory exchangeRate) = getExp( - realAmount.mantissa, - supplySnapshot.tokens - ); - return (MathError.NO_ERROR, exchangeRate.mantissa); - } - } - - function tropykusInterestAccrued(address account) - internal - view - returns ( - MathError, - uint256, - uint256 - ) - { - SupplySnapshot storage supplySnapshot = accountTokens[account]; - uint256 promisedSupplyRate = supplySnapshot.promisedSupplyRate; - Exp memory expectedSupplyRatePerBlock = Exp({ - mantissa: promisedSupplyRate - }); - (, uint256 delta) = subUInt( - accrualBlockNumber, - supplySnapshot.suppliedAt - ); - (, Exp memory expectedSupplyRatePerBlockWithDelta) = mulScalar( - expectedSupplyRatePerBlock, - delta - ); - (, Exp memory interestFactor) = addExp( - Exp({mantissa: 1e18}), - expectedSupplyRatePerBlockWithDelta - ); - uint256 currentUnderlying = supplySnapshot.underlyingAmount; - Exp memory redeemerUnderlying = Exp({mantissa: currentUnderlying}); - (, Exp memory realAmount) = mulExp(interestFactor, redeemerUnderlying); - (, uint256 interestEarned) = subUInt( - realAmount.mantissa, - currentUnderlying - ); - return (MathError.NO_ERROR, interestFactor.mantissa, interestEarned); - } - - /** - * @notice Get cash balance of this cToken in the underlying asset - * @return The quantity of underlying asset owned by this contract - */ - function getCash() external view override returns (uint256) { - return getCashPrior(); - } - - /** - * @notice Applies accrued interest to total borrows and reserves - * @dev This calculates interest accrued from the last checkpointed block - * up to the current block and writes new checkpoint to storage. - */ - function accrueInterest() public override returns (uint256) { - uint256 currentBlockNumber = getBlockNumber(); - uint256 accrualBlockNumberPrior = accrualBlockNumber; - - if (accrualBlockNumberPrior == currentBlockNumber) { - return uint256(Error.NO_ERROR); - } - - uint256 cashPrior = getCashPrior(); - uint256 borrowsPrior = totalBorrows; - uint256 reservesPrior = totalReserves; - uint256 borrowIndexPrior = borrowIndex; - - uint256 borrowRateMantissa = interestRateModel.getBorrowRate( - cashPrior, - borrowsPrior, - reservesPrior - ); - require(borrowRateMantissa <= borrowRateMaxMantissa, "CT10"); - - (MathError mathErr, uint256 blockDelta) = subUInt( - currentBlockNumber, - accrualBlockNumberPrior - ); - require(mathErr == MathError.NO_ERROR, "CT11"); - - Exp memory simpleInterestFactor; - uint256 interestAccumulated; - uint256 totalBorrowsNew; - uint256 totalReservesNew; - uint256 borrowIndexNew; - - (mathErr, simpleInterestFactor) = mulScalar( - Exp({mantissa: borrowRateMantissa}), - blockDelta - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .ACCRUE_INTEREST_SIMPLE_INTEREST_FACTOR_CALCULATION_FAILED, - uint256(mathErr) - ); - } - - (mathErr, interestAccumulated) = mulScalarTruncate( - simpleInterestFactor, - borrowsPrior - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .ACCRUE_INTEREST_ACCUMULATED_INTEREST_CALCULATION_FAILED, - uint256(mathErr) - ); - } - - (mathErr, totalBorrowsNew) = addUInt(interestAccumulated, borrowsPrior); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .ACCRUE_INTEREST_NEW_TOTAL_BORROWS_CALCULATION_FAILED, - uint256(mathErr) - ); - } - - (mathErr, totalReservesNew) = mulScalarTruncateAddUInt( - Exp({mantissa: reserveFactorMantissa}), - interestAccumulated, - reservesPrior - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .ACCRUE_INTEREST_NEW_TOTAL_RESERVES_CALCULATION_FAILED, - uint256(mathErr) - ); - } - - if (interestRateModel.isTropykusInterestRateModel()) { - (mathErr, totalReservesNew) = newReserves( - borrowRateMantissa, - cashPrior, - borrowsPrior, - reservesPrior, - interestAccumulated - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .ACCRUE_INTEREST_NEW_TOTAL_RESERVES_CALCULATION_FAILED, - uint256(mathErr) - ); - } - } - - (mathErr, borrowIndexNew) = mulScalarTruncateAddUInt( - simpleInterestFactor, - borrowIndexPrior, - borrowIndexPrior - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .ACCRUE_INTEREST_NEW_BORROW_INDEX_CALCULATION_FAILED, - uint256(mathErr) - ); - } - - accrualBlockNumber = currentBlockNumber; - borrowIndex = borrowIndexNew; - totalBorrows = totalBorrowsNew; - totalReserves = totalReservesNew; - - emit AccrueInterest( - cashPrior, - interestAccumulated, - borrowIndexNew, - totalBorrowsNew - ); - - return uint256(Error.NO_ERROR); - } - - function newReserves( - uint256 borrowRateMantissa, - uint256 cashPrior, - uint256 borrowsPrior, - uint256 reservesPrior, - uint256 interestAccumulated - ) internal view returns (MathError mathErr, uint256 totalReservesNew) { - uint256 newReserveFactorMantissa; - uint256 utilizationRate = interestRateModel.utilizationRate( - cashPrior, - borrowsPrior, - reservesPrior - ); - uint256 expectedSupplyRate = interestRateModel.getSupplyRate( - cashPrior, - borrowsPrior, - reservesPrior, - reserveFactorMantissa - ); - if ( - interestRateModel.isAboveOptimal( - cashPrior, - borrowsPrior, - reservesPrior - ) - ) { - (mathErr, newReserveFactorMantissa) = mulScalarTruncate( - Exp({mantissa: utilizationRate}), - borrowRateMantissa - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - (mathErr, newReserveFactorMantissa) = subUInt( - newReserveFactorMantissa, - expectedSupplyRate - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - (mathErr, totalReservesNew) = mulScalarTruncateAddUInt( - Exp({mantissa: newReserveFactorMantissa}), - interestAccumulated, - reservesPrior - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - } else { - mathErr = MathError.NO_ERROR; - totalReservesNew = reservesPrior; - } - } - - /** - * @notice Sender supplies assets into the market and receives cTokens in exchange - * @dev Accrues interest whether or not the operation succeeds, unless reverted - * @param mintAmount The amount of the underlying asset to supply - * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual mint amount. - */ - function mintInternal(uint256 mintAmount) - internal - nonReentrant - returns (uint256, uint256) - { - if (WhitelistInterface(whitelist).enabled()) { - require(WhitelistInterface(whitelist).exist(msg.sender), "CT26"); - } - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return ( - fail(Error(error), FailureInfo.MINT_ACCRUE_INTEREST_FAILED), - 0 - ); - } - return mintFresh(msg.sender, mintAmount); - } - - struct MintLocalVars { - Error err; - MathError mathErr; - uint256 exchangeRateMantissa; - uint256 mintTokens; - uint256 totalSupplyNew; - uint256 accountTokensNew; - uint256 actualMintAmount; - } - - /** - * @notice User supplies assets into the market and receives cTokens in exchange - * @dev Assumes interest has already been accrued up to the current block - * @param minter The address of the account which is supplying the assets - * @param mintAmount The amount of the underlying asset to supply - * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual mint amount. - */ - function mintFresh(address minter, uint256 mintAmount) - internal - returns (uint256, uint256) - { - uint256 allowed = comptroller.mintAllowed( - address(this), - minter, - mintAmount - ); - if (allowed != 0) { - return ( - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.MINT_COMPTROLLER_REJECTION, - allowed - ), - 0 - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return ( - fail(Error.MARKET_NOT_FRESH, FailureInfo.MINT_FRESHNESS_CHECK), - 0 - ); - } - - MintLocalVars memory vars; - - ( - vars.mathErr, - vars.exchangeRateMantissa - ) = exchangeRateStoredInternal(); - if (vars.mathErr != MathError.NO_ERROR) { - return ( - failOpaque( - Error.MATH_ERROR, - FailureInfo.MINT_EXCHANGE_RATE_READ_FAILED, - uint256(vars.mathErr) - ), - 0 - ); - } - if (interestRateModel.isTropykusInterestRateModel()) { - SupplySnapshot storage supplySnapshot = accountTokens[minter]; - (, uint256 newTotalSupply) = addUInt( - supplySnapshot.underlyingAmount, - mintAmount - ); - require(newTotalSupply <= 0.1e18, "CT24"); - } - vars.actualMintAmount = doTransferIn(minter, mintAmount); - - (vars.mathErr, vars.mintTokens) = divScalarByExpTruncate( - vars.actualMintAmount, - Exp({mantissa: vars.exchangeRateMantissa}) - ); - require(vars.mathErr == MathError.NO_ERROR, "CT12"); - - (vars.mathErr, vars.totalSupplyNew) = addUInt( - totalSupply, - vars.mintTokens - ); - require(vars.mathErr == MathError.NO_ERROR, "CT13"); - - (vars.mathErr, vars.accountTokensNew) = addUInt( - accountTokens[minter].tokens, - vars.mintTokens - ); - require(vars.mathErr == MathError.NO_ERROR, "CT14"); - - uint256 currentSupplyRate = interestRateModel.getSupplyRate( - getCashPrior(), - totalBorrows, - totalReserves, - reserveFactorMantissa - ); - - bool isTropykusInterestRateModel = interestRateModel - .isTropykusInterestRateModel(); - - if (accountTokens[minter].tokens > 0) { - Exp memory updatedUnderlying; - if (isTropykusInterestRateModel) { - (, uint256 interestFactorMantissa, ) = tropykusInterestAccrued( - minter - ); - Exp memory interestFactor = Exp({ - mantissa: interestFactorMantissa - }); - uint256 currentUnderlyingAmount = accountTokens[minter] - .underlyingAmount; - MathError mErrorNewAmount; - (mErrorNewAmount, updatedUnderlying) = mulExp( - Exp({mantissa: currentUnderlyingAmount}), - interestFactor - ); - if (mErrorNewAmount != MathError.NO_ERROR) { - return ( - failOpaque( - Error.MATH_ERROR, - FailureInfo.MINT_EXCHANGE_CALCULATION_FAILED, - uint256(mErrorNewAmount) - ), - 0 - ); - } - } else { - uint256 currentTokens = accountTokens[minter].tokens; - MathError mErrorUpdatedUnderlying; - (mErrorUpdatedUnderlying, updatedUnderlying) = mulExp( - Exp({mantissa: currentTokens}), - Exp({mantissa: vars.exchangeRateMantissa}) - ); - if (mErrorUpdatedUnderlying != MathError.NO_ERROR) { - return ( - failOpaque( - Error.MATH_ERROR, - FailureInfo.MINT_EXCHANGE_CALCULATION_FAILED, - uint256(mErrorUpdatedUnderlying) - ), - 0 - ); - } - } - (, mintAmount) = addUInt(updatedUnderlying.mantissa, mintAmount); - } - - totalSupply = vars.totalSupplyNew; - accountTokens[minter] = SupplySnapshot({ - tokens: vars.accountTokensNew, - underlyingAmount: mintAmount, - suppliedAt: accrualBlockNumber, - promisedSupplyRate: currentSupplyRate - }); - - emit Mint(minter, vars.actualMintAmount, vars.mintTokens); - emit Transfer(address(this), minter, vars.mintTokens); - - return (uint256(Error.NO_ERROR), vars.actualMintAmount); - } - - /** - * @notice Sender redeems cTokens in exchange for a specified amount of underlying asset - * @dev Accrues interest whether or not the operation succeeds, unless reverted - * @param redeemAmount The amount of underlying to receive from redeeming cTokens - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function redeemUnderlyingInternal(uint256 redeemAmount) - internal - nonReentrant - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return - fail(Error(error), FailureInfo.REDEEM_ACCRUE_INTEREST_FAILED); - } - return redeemFresh(payable(msg.sender), redeemAmount); - } - - struct RedeemLocalVars { - Error err; - MathError mathErr; - uint256 exchangeRateMantissa; - uint256 redeemTokens; - uint256 redeemAmount; - uint256 totalSupplyNew; - uint256 accountTokensNew; - uint256 newSubsidyFund; - } - - /** - * @notice User redeems cTokens in exchange for the underlying asset - * @dev Assumes interest has already been accrued up to the current block - * @param redeemer The address of the account which is redeeming the tokens - * @param redeemAmountIn The number of underlying tokens to receive from redeeming cTokens - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function redeemFresh(address payable redeemer, uint256 redeemAmountIn) - internal - returns (uint256) - { - require(redeemAmountIn > 0, "CT15"); - - RedeemLocalVars memory vars; - - SupplySnapshot storage supplySnapshot = accountTokens[redeemer]; - - ( - vars.mathErr, - vars.exchangeRateMantissa - ) = exchangeRateStoredInternal(); - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.REDEEM_EXCHANGE_RATE_READ_FAILED, - uint256(vars.mathErr) - ); - } - - uint256 interestEarned; - uint256 subsidyFundPortion; - uint256 currentUnderlying; - - bool isTropykusInterestRateModel = interestRateModel - .isTropykusInterestRateModel(); - if (isTropykusInterestRateModel) { - currentUnderlying = supplySnapshot.underlyingAmount; - (, , interestEarned) = tropykusInterestAccrued(redeemer); - } - supplySnapshot.promisedSupplyRate = interestRateModel.getSupplyRate( - getCashPrior(), - totalBorrows, - totalReserves, - reserveFactorMantissa - ); - - if ( - isTropykusInterestRateModel && - !interestRateModel.isAboveOptimal( - getCashPrior(), - totalBorrows, - totalReserves - ) - ) { - uint256 borrowRate = interestRateModel.getBorrowRate( - getCashPrior(), - totalBorrows, - totalReserves - ); - - uint256 utilizationRate = interestRateModel.utilizationRate( - getCashPrior(), - totalBorrows, - totalReserves - ); - - (, uint256 estimatedEarning) = mulScalarTruncate( - Exp({mantissa: borrowRate}), - utilizationRate - ); - - (, subsidyFundPortion) = subUInt( - supplySnapshot.promisedSupplyRate, - estimatedEarning - ); - (, Exp memory subsidyFactor) = getExp( - subsidyFundPortion, - supplySnapshot.promisedSupplyRate - ); - (, subsidyFundPortion) = mulScalarTruncate( - subsidyFactor, - interestEarned - ); - } - - vars.redeemAmount = redeemAmountIn; - - if (isTropykusInterestRateModel) { - (, Exp memory num) = mulExp( - vars.redeemAmount, - supplySnapshot.tokens - ); - (, Exp memory realTokensWithdrawAmount) = getExp( - num.mantissa, - currentUnderlying - ); - vars.redeemTokens = realTokensWithdrawAmount.mantissa; - } else { - (vars.mathErr, vars.redeemTokens) = divScalarByExpTruncate( - redeemAmountIn, - Exp({mantissa: vars.exchangeRateMantissa}) - ); - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.REDEEM_EXCHANGE_AMOUNT_CALCULATION_FAILED, - uint256(vars.mathErr) - ); - } - } - // } - - uint256 allowed = comptroller.redeemAllowed( - address(this), - redeemer, - vars.redeemTokens - ); - if (allowed != 0) { - return - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.REDEEM_COMPTROLLER_REJECTION, - allowed - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.REDEEM_FRESHNESS_CHECK - ); - } - - (vars.mathErr, vars.totalSupplyNew) = subUInt( - totalSupply, - vars.redeemTokens - ); - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.REDEEM_NEW_TOTAL_SUPPLY_CALCULATION_FAILED, - uint256(vars.mathErr) - ); - } - - (, vars.newSubsidyFund) = subUInt(subsidyFund, subsidyFundPortion); - - (vars.mathErr, vars.accountTokensNew) = subUInt( - supplySnapshot.tokens, - vars.redeemTokens - ); - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.REDEEM_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED, - uint256(vars.mathErr) - ); - } - - uint256 cash = getCashPrior(); - if (isTropykusInterestRateModel) { - cash = address(this).balance; - } - - if (cash < vars.redeemAmount) { - return - fail( - Error.TOKEN_INSUFFICIENT_CASH, - FailureInfo.REDEEM_TRANSFER_OUT_NOT_POSSIBLE - ); - } - - doTransferOut(redeemer, vars.redeemAmount); - - totalSupply = vars.totalSupplyNew; - subsidyFund = vars.newSubsidyFund; - supplySnapshot.tokens = vars.accountTokensNew; - supplySnapshot.suppliedAt = accrualBlockNumber; - (, supplySnapshot.underlyingAmount) = subUInt( - supplySnapshot.underlyingAmount, - vars.redeemAmount - ); - - emit Transfer(redeemer, address(this), vars.redeemTokens); - emit Redeem(redeemer, vars.redeemAmount, vars.redeemTokens); - - comptroller.redeemVerify( - address(this), - redeemer, - vars.redeemAmount, - vars.redeemTokens - ); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Sender borrows assets from the protocol to their own address - * @param borrowAmount The amount of the underlying asset to borrow - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function borrowInternal(uint256 borrowAmount) - internal - nonReentrant - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return - fail(Error(error), FailureInfo.BORROW_ACCRUE_INTEREST_FAILED); - } - return borrowFresh(payable(msg.sender), borrowAmount); - } - - struct BorrowLocalVars { - MathError mathErr; - uint256 accountBorrows; - uint256 accountBorrowsNew; - uint256 totalBorrowsNew; - } - - /** - * @notice Users borrow assets from the protocol to their own address - * @param borrowAmount The amount of the underlying asset to borrow - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function borrowFresh(address payable borrower, uint256 borrowAmount) - internal - returns (uint256) - { - uint256 allowed = comptroller.borrowAllowed( - address(this), - borrower, - borrowAmount - ); - if (allowed != 0) { - return - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.BORROW_COMPTROLLER_REJECTION, - allowed - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.BORROW_FRESHNESS_CHECK - ); - } - - if (getCashPrior() < borrowAmount) { - return - fail( - Error.TOKEN_INSUFFICIENT_CASH, - FailureInfo.BORROW_CASH_NOT_AVAILABLE - ); - } - - BorrowLocalVars memory vars; - - (vars.mathErr, vars.accountBorrows) = borrowBalanceStoredInternal( - borrower - ); - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED, - uint256(vars.mathErr) - ); - } - - (vars.mathErr, vars.accountBorrowsNew) = addUInt( - vars.accountBorrows, - borrowAmount - ); - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED, - uint256(vars.mathErr) - ); - } - - (vars.mathErr, vars.totalBorrowsNew) = addUInt( - totalBorrows, - borrowAmount - ); - if (interestRateModel.isTropykusInterestRateModel()) { - require(vars.totalBorrowsNew <= 0.1e18, "CT25"); - } - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED, - uint256(vars.mathErr) - ); - } - - doTransferOut(borrower, borrowAmount); - - accountBorrows[borrower].principal = vars.accountBorrowsNew; - accountBorrows[borrower].interestIndex = borrowIndex; - totalBorrows = vars.totalBorrowsNew; - - emit Borrow( - borrower, - borrowAmount, - vars.accountBorrowsNew, - vars.totalBorrowsNew - ); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Sender repays their own borrow - * @param repayAmount The amount to repay - * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual repayment amount. - */ - function repayBorrowInternal(uint256 repayAmount) - internal - nonReentrant - returns (uint256, uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return ( - fail( - Error(error), - FailureInfo.REPAY_BORROW_ACCRUE_INTEREST_FAILED - ), - 0 - ); - } - return repayBorrowFresh(msg.sender, msg.sender, repayAmount); - } - - struct RepayBorrowLocalVars { - Error err; - MathError mathErr; - uint256 repayAmount; - uint256 borrowerIndex; - uint256 accountBorrows; - uint256 accountBorrowsNew; - uint256 totalBorrowsNew; - uint256 actualRepayAmount; - } - - /** - * @notice Borrows are repaid by another user (possibly the borrower). - * @param payer the account paying off the borrow - * @param borrower the account with the debt being payed off - * @param repayAmount the amount of undelrying tokens being returned - * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual repayment amount. - */ - function repayBorrowFresh( - address payer, - address borrower, - uint256 repayAmount - ) internal returns (uint256, uint256) { - uint256 allowed = comptroller.repayBorrowAllowed( - address(this), - payer, - borrower, - repayAmount - ); - if (allowed != 0) { - return ( - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.REPAY_BORROW_COMPTROLLER_REJECTION, - allowed - ), - 0 - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return ( - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.REPAY_BORROW_FRESHNESS_CHECK - ), - 0 - ); - } - - RepayBorrowLocalVars memory vars; - - vars.borrowerIndex = accountBorrows[borrower].interestIndex; - - (vars.mathErr, vars.accountBorrows) = borrowBalanceStoredInternal( - borrower - ); - if (vars.mathErr != MathError.NO_ERROR) { - return ( - failOpaque( - Error.MATH_ERROR, - FailureInfo - .REPAY_BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED, - uint256(vars.mathErr) - ), - 0 - ); - } - - if (repayAmount == type(uint256).max) { - vars.repayAmount = vars.accountBorrows; - } else { - vars.repayAmount = repayAmount; - } - - vars.actualRepayAmount = doTransferIn(payer, vars.repayAmount); - - (vars.mathErr, vars.accountBorrowsNew) = subUInt( - vars.accountBorrows, - vars.actualRepayAmount - ); - require(vars.mathErr == MathError.NO_ERROR, "CT16"); - - (vars.mathErr, vars.totalBorrowsNew) = subUInt( - totalBorrows, - vars.actualRepayAmount - ); - require(vars.mathErr == MathError.NO_ERROR, "CT17"); - - accountBorrows[borrower].principal = vars.accountBorrowsNew; - accountBorrows[borrower].interestIndex = borrowIndex; - totalBorrows = vars.totalBorrowsNew; - - emit RepayBorrow( - payer, - borrower, - vars.actualRepayAmount, - vars.accountBorrowsNew, - vars.totalBorrowsNew - ); - - return (uint256(Error.NO_ERROR), vars.actualRepayAmount); - } - - /** - * @notice The sender liquidates the borrowers collateral. - * The collateral seized is transferred to the liquidator. - * @param borrower The borrower of this cToken to be liquidated - * @param cTokenCollateral The market in which to seize collateral from the borrower - * @param repayAmount The amount of the underlying borrowed asset to repay - * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual repayment amount. - */ - function liquidateBorrowInternal( - address borrower, - uint256 repayAmount, - CTokenInterface cTokenCollateral - ) internal nonReentrant returns (uint256, uint256) { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return ( - fail( - Error(error), - FailureInfo.LIQUIDATE_ACCRUE_BORROW_INTEREST_FAILED - ), - 0 - ); - } - - error = cTokenCollateral.accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return ( - fail( - Error(error), - FailureInfo.LIQUIDATE_ACCRUE_COLLATERAL_INTEREST_FAILED - ), - 0 - ); - } - - // liquidateBorrowFresh emits borrow-specific logs on errors, so we don't need to - return - liquidateBorrowFresh( - msg.sender, - borrower, - repayAmount, - cTokenCollateral - ); - } - - /** - * @notice The liquidator liquidates the borrowers collateral. - * The collateral seized is transferred to the liquidator. - * @param borrower The borrower of this cToken to be liquidated - * @param liquidator The address repaying the borrow and seizing collateral - * @param cTokenCollateral The market in which to seize collateral from the borrower - * @param repayAmount The amount of the underlying borrowed asset to repay - * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual repayment amount. - */ - function liquidateBorrowFresh( - address liquidator, - address borrower, - uint256 repayAmount, - CTokenInterface cTokenCollateral - ) internal returns (uint256, uint256) { - uint256 allowed = comptroller.liquidateBorrowAllowed( - address(this), - address(cTokenCollateral), - liquidator, - borrower, - repayAmount - ); - if (allowed != 0) { - return ( - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.LIQUIDATE_COMPTROLLER_REJECTION, - allowed - ), - 0 - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return ( - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.LIQUIDATE_FRESHNESS_CHECK - ), - 0 - ); - } - - if (cTokenCollateral.accrualBlockNumber() != getBlockNumber()) { - return ( - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.LIQUIDATE_COLLATERAL_FRESHNESS_CHECK - ), - 0 - ); - } - - if (borrower == liquidator) { - return ( - fail( - Error.INVALID_ACCOUNT_PAIR, - FailureInfo.LIQUIDATE_LIQUIDATOR_IS_BORROWER - ), - 0 - ); - } - - if (repayAmount == 0) { - return ( - fail( - Error.INVALID_CLOSE_AMOUNT_REQUESTED, - FailureInfo.LIQUIDATE_CLOSE_AMOUNT_IS_ZERO - ), - 0 - ); - } - - if (repayAmount == type(uint256).max) { - return ( - fail( - Error.INVALID_CLOSE_AMOUNT_REQUESTED, - FailureInfo.LIQUIDATE_CLOSE_AMOUNT_IS_UINT_MAX - ), - 0 - ); - } - - ( - uint256 repayBorrowError, - uint256 actualRepayAmount - ) = repayBorrowFresh(liquidator, borrower, repayAmount); - if (repayBorrowError != uint256(Error.NO_ERROR)) { - return ( - fail( - Error(repayBorrowError), - FailureInfo.LIQUIDATE_REPAY_BORROW_FRESH_FAILED - ), - 0 - ); - } - - (uint256 amountSeizeError, uint256 seizeTokens) = comptroller - .liquidateCalculateSeizeTokens( - address(this), - address(cTokenCollateral), - actualRepayAmount - ); - require(amountSeizeError == uint256(Error.NO_ERROR), "CT18"); - - require(cTokenCollateral.balanceOf(borrower) >= seizeTokens, "CT19"); - - uint256 seizeError; - if (address(cTokenCollateral) == address(this)) { - seizeError = seizeInternal( - address(this), - liquidator, - borrower, - seizeTokens - ); - } else { - seizeError = cTokenCollateral.seize( - liquidator, - borrower, - seizeTokens - ); - } - - require(seizeError == uint256(Error.NO_ERROR), "CT20"); - - emit LiquidateBorrow( - liquidator, - borrower, - actualRepayAmount, - address(cTokenCollateral), - seizeTokens - ); - - return (uint256(Error.NO_ERROR), actualRepayAmount); - } - - /** - * @notice Transfers collateral tokens (this market) to the liquidator. - * @dev Will fail unless called by another cToken during the process of liquidation. - * Its absolutely critical to use msg.sender as the borrowed cToken and not a parameter. - * @param liquidator The account receiving seized collateral - * @param borrower The account having collateral seized - * @param seizeTokens The number of cTokens to seize - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function seize( - address liquidator, - address borrower, - uint256 seizeTokens - ) external override nonReentrant returns (uint256) { - return seizeInternal(msg.sender, liquidator, borrower, seizeTokens); - } - - struct SeizeVars { - uint256 seizeAmount; - uint256 exchangeRate; - uint256 borrowerTokensNew; - uint256 borrowerAmountNew; - uint256 liquidatorTokensNew; - uint256 liquidatorAmountNew; - uint256 totalCash; - uint256 supplyRate; - } - - /** - * @notice Transfers collateral tokens (this market) to the liquidator. - * @dev Called only during an in-kind liquidation, or by liquidateBorrow during the liquidation of another CToken. - * Its absolutely critical to use msg.sender as the seizer cToken and not a parameter. - * @param seizerToken The contract seizing the collateral (i.e. borrowed cToken) - * @param liquidator The account receiving seized collateral - * @param borrower The account having collateral seized - * @param seizeTokens The number of cTokens to seize - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function seizeInternal( - address seizerToken, - address liquidator, - address borrower, - uint256 seizeTokens - ) internal returns (uint256) { - uint256 allowed = comptroller.seizeAllowed( - address(this), - seizerToken, - liquidator, - borrower, - seizeTokens - ); - if (allowed != 0) { - return - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.LIQUIDATE_SEIZE_COMPTROLLER_REJECTION, - allowed - ); - } - - if (borrower == liquidator) { - return - fail( - Error.INVALID_ACCOUNT_PAIR, - FailureInfo.LIQUIDATE_SEIZE_LIQUIDATOR_IS_BORROWER - ); - } - - SeizeVars memory seizeVars; - - MathError mathErr; - - (mathErr, seizeVars.borrowerTokensNew) = subUInt( - accountTokens[borrower].tokens, - seizeTokens - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.LIQUIDATE_SEIZE_BALANCE_DECREMENT_FAILED, - uint256(mathErr) - ); - } - - seizeVars.totalCash = getCashPrior(); - seizeVars.supplyRate = interestRateModel.getSupplyRate( - seizeVars.totalCash, - totalBorrows, - totalReserves, - reserveFactorMantissa - ); - - (, seizeVars.exchangeRate) = interestRateModel.getExchangeRate( - seizeVars.totalCash, - totalBorrows, - totalReserves, - totalSupply - ); - - if (interestRateModel.isTropykusInterestRateModel()) { - (, seizeVars.exchangeRate) = tropykusExchangeRateStoredInternal( - borrower - ); - } - - (, seizeVars.seizeAmount) = mulUInt( - seizeTokens, - seizeVars.exchangeRate - ); - (, seizeVars.seizeAmount) = divUInt(seizeVars.seizeAmount, 1e18); - - (, seizeVars.borrowerAmountNew) = subUInt( - accountTokens[borrower].underlyingAmount, - seizeVars.seizeAmount - ); - - (mathErr, seizeVars.liquidatorTokensNew) = addUInt( - accountTokens[liquidator].tokens, - seizeTokens - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.LIQUIDATE_SEIZE_BALANCE_INCREMENT_FAILED, - uint256(mathErr) - ); - } - - (, seizeVars.liquidatorAmountNew) = addUInt( - accountTokens[liquidator].underlyingAmount, - seizeVars.seizeAmount - ); - - accountTokens[borrower].tokens = seizeVars.borrowerTokensNew; - accountTokens[borrower].underlyingAmount = seizeVars.borrowerAmountNew; - accountTokens[borrower].suppliedAt = getBlockNumber(); - accountTokens[borrower].promisedSupplyRate = seizeVars.supplyRate; - - accountTokens[liquidator].tokens = seizeVars.liquidatorTokensNew; - accountTokens[liquidator].underlyingAmount = seizeVars - .liquidatorAmountNew; - accountTokens[liquidator].suppliedAt = getBlockNumber(); - accountTokens[liquidator].promisedSupplyRate = seizeVars.supplyRate; - - emit Transfer(borrower, liquidator, seizeTokens); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Begins transfer of admin rights. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer. - * @dev Admin function to begin change of admin. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer. - * @param newPendingAdmin New pending admin. - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setPendingAdmin(address payable newPendingAdmin) - external - override - returns (uint256) - { - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_PENDING_ADMIN_OWNER_CHECK - ); - } - - address oldPendingAdmin = pendingAdmin; - - pendingAdmin = newPendingAdmin; - - emit NewPendingAdmin(oldPendingAdmin, newPendingAdmin); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Accepts transfer of admin rights. msg.sender must be pendingAdmin - * @dev Admin function for pending admin to accept role and update admin - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _acceptAdmin() external override returns (uint256) { - if (msg.sender != pendingAdmin || msg.sender == address(0)) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.ACCEPT_ADMIN_PENDING_ADMIN_CHECK - ); - } - - address oldAdmin = admin; - address oldPendingAdmin = pendingAdmin; - - admin = pendingAdmin; - - pendingAdmin = payable(address(0)); - - emit NewAdmin(oldAdmin, admin); - emit NewPendingAdmin(oldPendingAdmin, pendingAdmin); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Sets a new comptroller for the market - * @dev Admin function to set a new comptroller - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setComptroller(ComptrollerInterface newComptroller) - public - override - returns (uint256) - { - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_COMPTROLLER_OWNER_CHECK - ); - } - - ComptrollerInterface oldComptroller = comptroller; - require(newComptroller.isComptroller(), "CT21"); - - comptroller = newComptroller; - - emit NewComptroller(oldComptroller, newComptroller); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice accrues interest and sets a new reserve factor for the protocol using _setReserveFactorFresh - * @dev Admin function to accrue interest and set a new reserve factor - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setReserveFactor(uint256 newReserveFactorMantissa) - external - override - nonReentrant - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return - fail( - Error(error), - FailureInfo.SET_RESERVE_FACTOR_ACCRUE_INTEREST_FAILED - ); - } - return _setReserveFactorFresh(newReserveFactorMantissa); - } - - /** - * @notice Sets a new reserve factor for the protocol (*requires fresh interest accrual) - * @dev Admin function to set a new reserve factor - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setReserveFactorFresh(uint256 newReserveFactorMantissa) - internal - returns (uint256) - { - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_RESERVE_FACTOR_ADMIN_CHECK - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.SET_RESERVE_FACTOR_FRESH_CHECK - ); - } - - if (newReserveFactorMantissa > reserveFactorMaxMantissa) { - return - fail( - Error.BAD_INPUT, - FailureInfo.SET_RESERVE_FACTOR_BOUNDS_CHECK - ); - } - - uint256 oldReserveFactorMantissa = reserveFactorMantissa; - reserveFactorMantissa = newReserveFactorMantissa; - - emit NewReserveFactor( - oldReserveFactorMantissa, - newReserveFactorMantissa - ); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Accrues interest and reduces reserves by transferring from msg.sender - * @param addAmount Amount of addition to reserves - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _addReservesInternal(uint256 addAmount) - internal - nonReentrant - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return - fail( - Error(error), - FailureInfo.ADD_RESERVES_ACCRUE_INTEREST_FAILED - ); - } - - uint256 totalReservesNew; - uint256 actualAddAmount; - - if (accrualBlockNumber != getBlockNumber()) { - return ( - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.ADD_RESERVES_FRESH_CHECK - ) - ); - } - - actualAddAmount = doTransferIn(msg.sender, addAmount); - - totalReservesNew = totalReserves + actualAddAmount; - - require(totalReservesNew >= totalReserves, "CT22"); - - totalReserves = totalReservesNew; - - emit ReservesAdded(msg.sender, actualAddAmount, totalReservesNew); - - return (uint256(Error.NO_ERROR)); - } - - function _addSubsidyInternal(uint256 addAmount) - internal - nonReentrant - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - // accrueInterest emits logs on errors, but on top of that we want to log the fact that an attempted reduce reserves failed. - return fail(Error(error), FailureInfo.ADD_SUBSIDY_FUND_FAILED); - } - - uint256 subsidyFundNew; - uint256 actualAddAmount; - - if (accrualBlockNumber != getBlockNumber()) { - return ( - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.ADD_SUBSIDY_FUND_FRESH_CHECK - ) - ); - } - - actualAddAmount = doTransferIn(msg.sender, addAmount); - - subsidyFundNew = subsidyFund + actualAddAmount; - - require(subsidyFundNew >= subsidyFund, "CT22"); - - subsidyFund = subsidyFundNew; - - emit SubsidyAdded(msg.sender, actualAddAmount, subsidyFundNew); - - /* Return (NO_ERROR, actualAddAmount) */ - return (uint256(Error.NO_ERROR)); - } - - /** - * @notice Accrues interest and reduces reserves by transferring to admin - * @param reduceAmount Amount of reduction to reserves - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _reduceReserves(uint256 reduceAmount) - external - override - nonReentrant - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return - fail( - Error(error), - FailureInfo.REDUCE_RESERVES_ACCRUE_INTEREST_FAILED - ); - } - return _reduceReservesFresh(reduceAmount); - } - - /** - * @notice Reduces reserves by transferring to admin - * @dev Requires fresh interest accrual - * @param reduceAmount Amount of reduction to reserves - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _reduceReservesFresh(uint256 reduceAmount) - internal - returns (uint256) - { - uint256 totalReservesNew; - - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.REDUCE_RESERVES_ADMIN_CHECK - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.REDUCE_RESERVES_FRESH_CHECK - ); - } - - if (getCashPrior() < reduceAmount) { - return - fail( - Error.TOKEN_INSUFFICIENT_CASH, - FailureInfo.REDUCE_RESERVES_CASH_NOT_AVAILABLE - ); - } - - if (reduceAmount > totalReserves) { - return - fail(Error.BAD_INPUT, FailureInfo.REDUCE_RESERVES_VALIDATION); - } - - totalReservesNew = totalReserves - reduceAmount; - require(totalReservesNew <= totalReserves, "CT23"); - - totalReserves = totalReservesNew; - - doTransferOut(admin, reduceAmount); - - emit ReservesReduced(admin, reduceAmount, totalReservesNew); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice accrues interest and updates the interest rate model using _setInterestRateModelFresh - * @dev Admin function to accrue interest and update the interest rate model - * @param newInterestRateModel the new interest rate model to use - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setInterestRateModel(InterestRateModel newInterestRateModel) - public - override - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return - fail( - Error(error), - FailureInfo.SET_INTEREST_RATE_MODEL_ACCRUE_INTEREST_FAILED - ); - } - return _setInterestRateModelFresh(newInterestRateModel); - } - - /** - * @notice updates the interest rate model (*requires fresh interest accrual) - * @dev Admin function to update the interest rate model - * @param newInterestRateModel the new interest rate model to use - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setInterestRateModelFresh(InterestRateModel newInterestRateModel) - internal - returns (uint256) - { - InterestRateModel oldInterestRateModel; - - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_INTEREST_RATE_MODEL_OWNER_CHECK - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.SET_INTEREST_RATE_MODEL_FRESH_CHECK - ); - } - - oldInterestRateModel = interestRateModel; - - require(newInterestRateModel.isInterestRateModel(), "CT21"); - - interestRateModel = newInterestRateModel; - - emit NewMarketInterestRateModel( - oldInterestRateModel, - newInterestRateModel - ); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Gets balance of this contract in terms of the underlying - * @dev This excludes the value of the current message, if any - * @return The quantity of underlying owned by this contract - */ - function getCashPrior() internal view virtual returns (uint256); - - /** - * @dev Performs a transfer in, reverting upon failure. Returns the amount actually transferred to the protocol, in case of a fee. - * This may revert due to insufficient balance or insufficient allowance. - */ - function doTransferIn(address from, uint256 amount) - internal - virtual - returns (uint256); - - /** - * @dev Performs a transfer out, ideally returning an explanatory error code upon failure tather than reverting. - * If caller has not called checked protocol's balance, may revert due to insufficient cash held in the contract. - * If caller has checked protocol's balance, and verified it is >= amount, this should not revert in normal conditions. - */ - function doTransferOut(address payable to, uint256 amount) internal virtual; - - /** - * @dev Prevents a contract from calling itself, directly or indirectly. - */ - modifier nonReentrant() { - require(_notEntered, "re-entered"); - _notEntered = false; - _; - _notEntered = true; - } -} - - -// Dependency file: contracts/PriceOracle.sol - -// pragma solidity 0.8.6; - -// import "contracts/CToken.sol"; - -abstract contract PriceOracle { - /// @notice Indicator that this is a PriceOracle contract (for inspection) - bool public constant isPriceOracle = true; - - /** - * @notice Get the underlying price of a cToken asset - * @param cToken The cToken to get the underlying price of - * @return The underlying asset price mantissa (scaled by 1e18). - * Zero means the price is unavailable. - */ - function getUnderlyingPrice(CToken cToken) - external - view - virtual - returns (uint256); -} - - -// Dependency file: contracts/ComptrollerStorage.sol - -// pragma solidity 0.8.6; - -// import "contracts/CToken.sol"; -// import "contracts/PriceOracle.sol"; - -contract UnitrollerAdminStorage { - /** - * @notice Administrator for this contract - */ - address public admin; - - /** - * @notice Pending administrator for this contract - */ - address public pendingAdmin; - - /** - * @notice Active brains of Unitroller - */ - address public comptrollerImplementation; - - /** - * @notice Pending brains of Unitroller - */ - address public pendingComptrollerImplementation; -} - -contract ComptrollerV1Storage is UnitrollerAdminStorage { - - /** - * @notice Oracle which gives the price of any given asset - */ - PriceOracle public oracle; - - /** - * @notice Multiplier used to calculate the maximum repayAmount when liquidating a borrow - */ - uint public closeFactorMantissa; - - /** - * @notice Multiplier representing the discount on collateral that a liquidator receives - */ - uint public liquidationIncentiveMantissa; - - /** - * @notice Max number of assets a single account can participate in (borrow or use as collateral) - */ - uint public maxAssets; - - /** - * @notice Per-account mapping of "assets you are in", capped by maxAssets - */ - mapping(address => CToken[]) public accountAssets; - -} - -contract ComptrollerV2Storage is ComptrollerV1Storage { - struct Market { - /// @notice Whether or not this market is listed - bool isListed; - - /** - * @notice Multiplier representing the most one can borrow against their collateral in this market. - * For instance, 0.9 to allow borrowing 90% of collateral value. - * Must be between 0 and 1, and stored as a mantissa. - */ - uint collateralFactorMantissa; - - /// @notice Per-market mapping of "accounts in this asset" - mapping(address => bool) accountMembership; - - /// @notice Whether or not this market receives COMP - bool isComped; - } - - /** - * @notice Official mapping of cTokens -> Market metadata - * @dev Used e.g. to determine if a market is supported - */ - mapping(address => Market) public markets; - - - /** - * @notice The Pause Guardian can pause certain actions as a safety mechanism. - * Actions which allow users to remove their own assets cannot be paused. - * Liquidation / seizing / transfer can only be paused globally, not by market. - */ - address public pauseGuardian; - bool public _mintGuardianPaused; - bool public _borrowGuardianPaused; - bool public transferGuardianPaused; - bool public seizeGuardianPaused; - mapping(address => bool) public mintGuardianPaused; - mapping(address => bool) public borrowGuardianPaused; -} - -contract ComptrollerV3Storage is ComptrollerV2Storage { - struct CompMarketState { - /// @notice The market's last updated compBorrowIndex or compSupplyIndex - uint224 index; - - /// @notice The block number the index was last updated at - uint32 block; - } - - /// @notice A list of all markets - CToken[] public allMarkets; - - /// @notice The rate at which the flywheel distributes COMP, per block - uint public compRate; - - /// @notice The portion of compRate that each market currently receives - mapping(address => uint) public compSpeeds; - - /// @notice The COMP market supply state for each market - mapping(address => CompMarketState) public compSupplyState; - - /// @notice The COMP market borrow state for each market - mapping(address => CompMarketState) public compBorrowState; - - /// @notice The COMP borrow index for each market for each supplier as of the last time they accrued COMP - mapping(address => mapping(address => uint)) public compSupplierIndex; - - /// @notice The COMP borrow index for each market for each borrower as of the last time they accrued COMP - mapping(address => mapping(address => uint)) public compBorrowerIndex; - - /// @notice The COMP accrued but not yet transferred to each user - mapping(address => uint) public compAccrued; -} - -contract ComptrollerV4Storage is ComptrollerV3Storage { - // @notice The borrowCapGuardian can set borrowCaps to any number for any market. Lowering the borrow cap could disable borrowing on the given market. - address public borrowCapGuardian; - - // @notice Borrow caps enforced by borrowAllowed for each cToken address. Defaults to zero which corresponds to unlimited borrowing. - mapping(address => uint) public borrowCaps; - - // @notice address of the TROP token - address public tropAddress; -} - -contract ComptrollerV5Storage is ComptrollerV4Storage { - /// @notice The portion of COMP that each contributor receives per block - mapping(address => uint) public compContributorSpeeds; - - /// @notice Last block at which a contributor's COMP rewards have been allocated - mapping(address => uint) public lastContributorBlock; -} - - -// Dependency file: contracts/Unitroller.sol - -// pragma solidity 0.8.6; - -// import "contracts/ErrorReporter.sol"; -// import "contracts/ComptrollerStorage.sol"; - -/** - * @title ComptrollerCore - * @dev Storage for the comptroller is at this address, while execution is delegated to the `comptrollerImplementation`. - * CTokens should reference this contract as their comptroller. - */ -contract Unitroller is UnitrollerAdminStorage, ComptrollerErrorReporter { - /** - * @notice Emitted when pendingComptrollerImplementation is changed - */ - event NewPendingImplementation( - address oldPendingImplementation, - address newPendingImplementation - ); - - /** - * @notice Emitted when pendingComptrollerImplementation is accepted, which means comptroller implementation is updated - */ - event NewImplementation( - address oldImplementation, - address newImplementation - ); - - /** - * @notice Emitted when pendingAdmin is changed - */ - event NewPendingAdmin(address oldPendingAdmin, address newPendingAdmin); - - /** - * @notice Emitted when pendingAdmin is accepted, which means admin is updated - */ - event NewAdmin(address oldAdmin, address newAdmin); - - constructor() { - // Set admin to caller - admin = msg.sender; - } - - /*** Admin Functions ***/ - function _setPendingImplementation(address newPendingImplementation) - public - returns (uint256) - { - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_PENDING_IMPLEMENTATION_OWNER_CHECK - ); - } - - address oldPendingImplementation = pendingComptrollerImplementation; - - pendingComptrollerImplementation = newPendingImplementation; - - emit NewPendingImplementation( - oldPendingImplementation, - pendingComptrollerImplementation - ); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Accepts new implementation of comptroller. msg.sender must be pendingImplementation - * @dev Admin function for new implementation to accept it's role as implementation - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _acceptImplementation() public returns (uint256) { - // Check caller is pendingImplementation and pendingImplementation ≠ address(0) - if ( - msg.sender != pendingComptrollerImplementation || - pendingComptrollerImplementation == address(0) - ) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.ACCEPT_PENDING_IMPLEMENTATION_ADDRESS_CHECK - ); - } - - // Save current values for inclusion in log - address oldImplementation = comptrollerImplementation; - address oldPendingImplementation = pendingComptrollerImplementation; - - comptrollerImplementation = pendingComptrollerImplementation; - - pendingComptrollerImplementation = address(0); - - emit NewImplementation(oldImplementation, comptrollerImplementation); - emit NewPendingImplementation( - oldPendingImplementation, - pendingComptrollerImplementation - ); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Begins transfer of admin rights. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer. - * @dev Admin function to begin change of admin. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer. - * @param newPendingAdmin New pending admin. - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setPendingAdmin(address newPendingAdmin) - public - returns (uint256) - { - // Check caller = admin - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_PENDING_ADMIN_OWNER_CHECK - ); - } - - // Save current value, if any, for inclusion in log - address oldPendingAdmin = pendingAdmin; - - // Store pendingAdmin with value newPendingAdmin - pendingAdmin = newPendingAdmin; - - // Emit NewPendingAdmin(oldPendingAdmin, newPendingAdmin) - emit NewPendingAdmin(oldPendingAdmin, newPendingAdmin); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Accepts transfer of admin rights. msg.sender must be pendingAdmin - * @dev Admin function for pending admin to accept role and update admin - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _acceptAdmin() public returns (uint256) { - // Check caller is pendingAdmin and pendingAdmin ≠ address(0) - if (msg.sender != pendingAdmin || msg.sender == address(0)) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.ACCEPT_ADMIN_PENDING_ADMIN_CHECK - ); - } - - // Save current values for inclusion in log - address oldAdmin = admin; - address oldPendingAdmin = pendingAdmin; - - // Store admin with value pendingAdmin - admin = pendingAdmin; - - // Clear the pending value - pendingAdmin = address(0); - - emit NewAdmin(oldAdmin, admin); - emit NewPendingAdmin(oldPendingAdmin, pendingAdmin); - - return uint256(Error.NO_ERROR); - } - - /** - * @dev Delegates execution to an implementation contract. - * It returns to the external caller whatever the implementation returns - * or forwards reverts. - */ - function internalFallback() public payable { - // delegate all other functions to current implementation - (bool success, ) = comptrollerImplementation.delegatecall(msg.data); - - assembly { - let free_mem_ptr := mload(0x40) - returndatacopy(free_mem_ptr, 0, returndatasize()) - - switch success - case 0 { - revert(free_mem_ptr, returndatasize()) - } - default { - return(free_mem_ptr, returndatasize()) - } - } - } - - fallback() external payable { - internalFallback(); - } - - receive() external payable { - internalFallback(); - } -} - - -// Root file: contracts/ComptrollerG1.sol - -pragma solidity 0.8.6; - -// import "contracts/CToken.sol"; -// import "contracts/ErrorReporter.sol"; -// import "contracts/Exponential.sol"; -// import "contracts/PriceOracle.sol"; -// import "contracts/ComptrollerInterface.sol"; -// import "contracts/ComptrollerStorage.sol"; -// import "contracts/Unitroller.sol"; - -/** - * @title tropykus Comptroller Contract - * @author tropykus - * @dev This was the first version of the Comptroller brains. - * We keep it so our tests can continue to do the real-life behavior of upgrading from this logic forward. - */ -contract ComptrollerG1 is - ComptrollerV1Storage, - ComptrollerInterface, - ComptrollerErrorReporter, - Exponential -{ - struct Market { - /** - * @notice Whether or not this market is listed - */ - bool isListed; - /** - * @notice Multiplier representing the most one can borrow against their collateral in this market. - * For instance, 0.9 to allow borrowing 90% of collateral value. - * Must be between 0 and 1, and stored as a mantissa. - */ - uint256 collateralFactorMantissa; - /** - * @notice Per-market mapping of "accounts in this asset" - */ - mapping(address => bool) accountMembership; - } - - /** - * @notice Official mapping of cTokens -> Market metadata - * @dev Used e.g. to determine if a market is supported - */ - mapping(address => Market) public markets; - - /** - * @notice Emitted when an admin supports a market - */ - event MarketListed(CToken cToken); - - /** - * @notice Emitted when an account enters a market - */ - event MarketEntered(CToken cToken, address account); - - /** - * @notice Emitted when an account exits a market - */ - event MarketExited(CToken cToken, address account); - - /** - * @notice Emitted when close factor is changed by admin - */ - event NewCloseFactor( - uint256 oldCloseFactorMantissa, - uint256 newCloseFactorMantissa - ); - - /** - * @notice Emitted when a collateral factor is changed by admin - */ - event NewCollateralFactor( - CToken cToken, - uint256 oldCollateralFactorMantissa, - uint256 newCollateralFactorMantissa - ); - - /** - * @notice Emitted when liquidation incentive is changed by admin - */ - event NewLiquidationIncentive( - uint256 oldLiquidationIncentiveMantissa, - uint256 newLiquidationIncentiveMantissa - ); - - /** - * @notice Emitted when maxAssets is changed by admin - */ - event NewMaxAssets(uint256 oldMaxAssets, uint256 newMaxAssets); - - /** - * @notice Emitted when price oracle is changed - */ - event NewPriceOracle( - PriceOracle oldPriceOracle, - PriceOracle newPriceOracle - ); - - // closeFactorMantissa must be strictly greater than this value - uint256 constant closeFactorMinMantissa = 5e16; // 0.05 - - // closeFactorMantissa must not exceed this value - uint256 constant closeFactorMaxMantissa = 9e17; // 0.9 - - // No collateralFactorMantissa may exceed this value - uint256 constant collateralFactorMaxMantissa = 9e17; // 0.9 - - // liquidationIncentiveMantissa must be no less than this value - uint256 constant liquidationIncentiveMinMantissa = mantissaOne; - - // liquidationIncentiveMantissa must be no greater than this value - uint256 constant liquidationIncentiveMaxMantissa = 15e17; // 1.5 - - constructor() { - admin = msg.sender; - } - - /*** Assets You Are In ***/ - - /** - * @notice Returns the assets an account has entered - * @param account The address of the account to pull assets for - * @return A dynamic list with the assets the account has entered - */ - function getAssetsIn(address account) - external - view - returns (CToken[] memory) - { - CToken[] memory assetsIn = accountAssets[account]; - - return assetsIn; - } - - /** - * @notice Returns whether the given account is entered in the given asset - * @param account The address of the account to check - * @param cToken The cToken to check - * @return True if the account is in the asset, otherwise false. - */ - function checkMembership(address account, CToken cToken) - external - view - returns (bool) - { - return markets[address(cToken)].accountMembership[account]; - } - - /** - * @notice Add assets to be included in account liquidity calculation - * @param cTokens The list of addresses of the cToken markets to be enabled - * @return Success indicator for whether each corresponding market was entered - */ - function enterMarkets(address[] memory cTokens) - public - override - returns (uint256[] memory) - { - uint256 len = cTokens.length; - - uint256[] memory results = new uint256[](len); - for (uint256 i = 0; i < len; i++) { - CToken cToken = CToken(cTokens[i]); - Market storage marketToJoin = markets[address(cToken)]; - - if (!marketToJoin.isListed) { - // if market is not listed, cannot join move along - results[i] = uint256(Error.MARKET_NOT_LISTED); - continue; - } - - if (marketToJoin.accountMembership[msg.sender] == true) { - // if already joined, move along - results[i] = uint256(Error.NO_ERROR); - continue; - } - - if (accountAssets[msg.sender].length >= maxAssets) { - // if no space, cannot join, move along - results[i] = uint256(Error.TOO_MANY_ASSETS); - continue; - } - - // survived the gauntlet, add to list - // NOTE: we store these somewhat redundantly as a significant optimization - // this avoids having to iterate through the list for the most common use cases - // that is, only when we need to perform liquidity checks - // and not whenever we want to check if an account is in a particular market - marketToJoin.accountMembership[msg.sender] = true; - accountAssets[msg.sender].push(cToken); - - emit MarketEntered(cToken, msg.sender); - - results[i] = uint256(Error.NO_ERROR); - } - - return results; - } - - /** - * @notice Removes asset from sender's account liquidity calculation - * @dev Sender must not have an outstanding borrow balance in the asset, - * or be providing neccessary collateral for an outstanding borrow. - * @param cTokenAddress The address of the asset to be removed - * @return Whether or not the account successfully exited the market - */ - function exitMarket(address cTokenAddress) - external - override - returns (uint256) - { - CToken cToken = CToken(cTokenAddress); - /* Get sender tokensHeld and amountOwed underlying from the cToken */ - (uint256 oErr, uint256 tokensHeld, uint256 amountOwed, ) = cToken - .getAccountSnapshot(msg.sender); - require(oErr == 0, "exitMarket: getAccountSnapshot failed"); // semi-opaque error code - - /* Fail if the sender has a borrow balance */ - if (amountOwed != 0) { - return - fail( - Error.NONZERO_BORROW_BALANCE, - FailureInfo.EXIT_MARKET_BALANCE_OWED - ); - } - - /* Fail if the sender is not permitted to redeem all of their tokens */ - uint256 allowed = redeemAllowedInternal( - cTokenAddress, - msg.sender, - tokensHeld - ); - if (allowed != 0) { - return - failOpaque( - Error.REJECTION, - FailureInfo.EXIT_MARKET_REJECTION, - allowed - ); - } - - Market storage marketToExit = markets[address(cToken)]; - - /* Return true if the sender is not already ‘in’ the market */ - if (!marketToExit.accountMembership[msg.sender]) { - return uint256(Error.NO_ERROR); - } - - /* Set cToken account membership to false */ - delete marketToExit.accountMembership[msg.sender]; - - /* Delete cToken from the account’s list of assets */ - // load into memory for faster iteration - CToken[] memory userAssetList = accountAssets[msg.sender]; - accountAssets[msg.sender] = new CToken[](0); - CToken[] storage newMarketList = accountAssets[msg.sender]; - uint256 len = userAssetList.length; - uint256 assetIndex = len; - for (uint256 i = 0; i < len; i++) { - if (userAssetList[i] == cToken) { - assetIndex = i; - continue; - } - newMarketList.push(userAssetList[i]); - } - - // We *must* have found the asset in the list or our redundant data structure is broken - assert(assetIndex < len); - - emit MarketExited(cToken, msg.sender); - - return uint256(Error.NO_ERROR); - } - - /*** Policy Hooks ***/ - - /** - * @notice Checks if the account should be allowed to mint tokens in the given market - * @param cToken The market to verify the mint against - * @param minter The account which would get the minted tokens - * @param mintAmount The amount of underlying being supplied to the market in exchange for tokens - * @return 0 if the mint is allowed, otherwise a semi-opaque error code (See ErrorReporter.sol) - */ - function mintAllowed( - address cToken, - address minter, - uint256 mintAmount - ) external view override returns (uint256) { - minter; // currently unused - mintAmount; // currently unused - - if (!markets[cToken].isListed) { - return uint256(Error.MARKET_NOT_LISTED); - } - - // *may include Policy Hook-type checks - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Validates mint and reverts on rejection. May emit logs. - * @param cToken Asset being minted - * @param minter The address minting the tokens - * @param mintAmount The amount of the underlying asset being minted - * @param mintTokens The number of tokens being minted - */ - function mintVerify( - address cToken, - address minter, - uint256 mintAmount, - uint256 mintTokens - ) external override { - cToken; // currently unused - minter; // currently unused - mintAmount; // currently unused - mintTokens; // currently unused - - if (false) { - maxAssets = maxAssets; // not pure - } - } - - /** - * @notice Checks if the account should be allowed to redeem tokens in the given market - * @param cToken The market to verify the redeem against - * @param redeemer The account which would redeem the tokens - * @param redeemTokens The number of cTokens to exchange for the underlying asset in the market - * @return 0 if the redeem is allowed, otherwise a semi-opaque error code (See ErrorReporter.sol) - */ - function redeemAllowed( - address cToken, - address redeemer, - uint256 redeemTokens - ) external view override returns (uint256) { - return redeemAllowedInternal(cToken, redeemer, redeemTokens); - } - - function redeemAllowedInternal( - address cToken, - address redeemer, - uint256 redeemTokens - ) internal view returns (uint256) { - if (!markets[cToken].isListed) { - return uint256(Error.MARKET_NOT_LISTED); - } - - // *may include Policy Hook-type checks - - /* If the redeemer is not 'in' the market, then we can bypass the liquidity check */ - if (!markets[cToken].accountMembership[redeemer]) { - return uint256(Error.NO_ERROR); - } - - /* Otherwise, perform a hypothetical liquidity check to guard against shortfall */ - ( - Error err, - , - uint256 shortfall - ) = getHypotheticalAccountLiquidityInternal( - redeemer, - CToken(cToken), - redeemTokens, - 0 - ); - if (err != Error.NO_ERROR) { - return uint256(err); - } - if (shortfall > 0) { - return uint256(Error.INSUFFICIENT_LIQUIDITY); - } - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Validates redeem and reverts on rejection. May emit logs. - * @param cToken Asset being redeemed - * @param redeemer The address redeeming the tokens - * @param redeemAmount The amount of the underlying asset being redeemed - * @param redeemTokens The number of tokens being redeemed - */ - function redeemVerify( - address cToken, - address redeemer, - uint256 redeemAmount, - uint256 redeemTokens - ) external pure override { - cToken; // currently unused - redeemer; // currently unused - redeemAmount; // currently unused - redeemTokens; // currently unused - - // Require tokens is zero or amount is also zero - if (redeemTokens == 0 && redeemAmount > 0) { - revert("redeemTokens zero"); - } - } - - /** - * @notice Checks if the account should be allowed to borrow the underlying asset of the given market - * @param cToken The market to verify the borrow against - * @param borrower The account which would borrow the asset - * @param borrowAmount The amount of underlying the account would borrow - * @return 0 if the borrow is allowed, otherwise a semi-opaque error code (See ErrorReporter.sol) - */ - function borrowAllowed( - address cToken, - address borrower, - uint256 borrowAmount - ) external view override returns (uint256) { - if (!markets[cToken].isListed) { - return uint256(Error.MARKET_NOT_LISTED); - } - - // *may include Policy Hook-type checks - - if (!markets[cToken].accountMembership[borrower]) { - return uint256(Error.MARKET_NOT_ENTERED); - } - - if (oracle.getUnderlyingPrice(CToken(cToken)) == 0) { - return uint256(Error.PRICE_ERROR); - } - - ( - Error err, - , - uint256 shortfall - ) = getHypotheticalAccountLiquidityInternal( - borrower, - CToken(cToken), - 0, - borrowAmount - ); - if (err != Error.NO_ERROR) { - return uint256(err); - } - if (shortfall > 0) { - return uint256(Error.INSUFFICIENT_LIQUIDITY); - } - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Validates borrow and reverts on rejection. May emit logs. - * @param cToken Asset whose underlying is being borrowed - * @param borrower The address borrowing the underlying - * @param borrowAmount The amount of the underlying asset requested to borrow - */ - function borrowVerify( - address cToken, - address borrower, - uint256 borrowAmount - ) external override { - cToken; // currently unused - borrower; // currently unused - borrowAmount; // currently unused - - if (false) { - maxAssets = maxAssets; // not pure - } - } - - /** - * @notice Checks if the account should be allowed to repay a borrow in the given market - * @param cToken The market to verify the repay against - * @param payer The account which would repay the asset - * @param borrower The account which would borrowed the asset - * @param repayAmount The amount of the underlying asset the account would repay - * @return 0 if the repay is allowed, otherwise a semi-opaque error code (See ErrorReporter.sol) - */ - function repayBorrowAllowed( - address cToken, - address payer, - address borrower, - uint256 repayAmount - ) external view override returns (uint256) { - payer; // currently unused - borrower; // currently unused - repayAmount; // currently unused - - if (!markets[cToken].isListed) { - return uint256(Error.MARKET_NOT_LISTED); - } - - // *may include Policy Hook-type checks - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Validates repayBorrow and reverts on rejection. May emit logs. - * @param cToken Asset being repaid - * @param payer The address repaying the borrow - * @param borrower The address of the borrower - * @param repayAmount The amount of underlying being repaid - */ - function repayBorrowVerify( - address cToken, - address payer, - address borrower, - uint256 repayAmount, - uint256 borrowerIndex - ) external override { - cToken; // currently unused - payer; // currently unused - borrower; // currently unused - repayAmount; // currently unused - borrowerIndex; // currently unused - - if (false) { - maxAssets = maxAssets; // not pure - } - } - - /** - * @notice Checks if the liquidation should be allowed to occur - * @param cTokenBorrowed Asset which was borrowed by the borrower - * @param cTokenCollateral Asset which was used as collateral and will be seized - * @param liquidator The address repaying the borrow and seizing the collateral - * @param borrower The address of the borrower - * @param repayAmount The amount of underlying being repaid - */ - function liquidateBorrowAllowed( - address cTokenBorrowed, - address cTokenCollateral, - address liquidator, - address borrower, - uint256 repayAmount - ) external view override returns (uint256) { - liquidator; // currently unused - borrower; // currently unused - repayAmount; // currently unused - - if ( - !markets[cTokenBorrowed].isListed || - !markets[cTokenCollateral].isListed - ) { - return uint256(Error.MARKET_NOT_LISTED); - } - - // *may include Policy Hook-type checks - - /* The borrower must have shortfall in order to be liquidatable */ - (Error err, , uint256 shortfall) = getAccountLiquidityInternal( - borrower - ); - if (err != Error.NO_ERROR) { - return uint256(err); - } - if (shortfall == 0) { - return uint256(Error.INSUFFICIENT_SHORTFALL); - } - - /* The liquidator may not repay more than what is allowed by the closeFactor */ - uint256 borrowBalance = CToken(cTokenBorrowed).borrowBalanceStored( - borrower - ); - (MathError mathErr, uint256 maxClose) = mulScalarTruncate( - Exp({mantissa: closeFactorMantissa}), - borrowBalance - ); - if (mathErr != MathError.NO_ERROR) { - return uint256(Error.MATH_ERROR); - } - if (repayAmount > maxClose) { - return uint256(Error.TOO_MUCH_REPAY); - } - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Validates liquidateBorrow and reverts on rejection. May emit logs. - * @param cTokenBorrowed Asset which was borrowed by the borrower - * @param cTokenCollateral Asset which was used as collateral and will be seized - * @param liquidator The address repaying the borrow and seizing the collateral - * @param borrower The address of the borrower - * @param repayAmount The amount of underlying being repaid - */ - function liquidateBorrowVerify( - address cTokenBorrowed, - address cTokenCollateral, - address liquidator, - address borrower, - uint256 repayAmount, - uint256 seizeTokens - ) external override { - cTokenBorrowed; // currently unused - cTokenCollateral; // currently unused - liquidator; // currently unused - borrower; // currently unused - repayAmount; // currently unused - seizeTokens; // currently unused - - if (false) { - maxAssets = maxAssets; // not pure - } - } - - /** - * @notice Checks if the seizing of assets should be allowed to occur - * @param cTokenCollateral Asset which was used as collateral and will be seized - * @param cTokenBorrowed Asset which was borrowed by the borrower - * @param liquidator The address repaying the borrow and seizing the collateral - * @param borrower The address of the borrower - * @param seizeTokens The number of collateral tokens to seize - */ - function seizeAllowed( - address cTokenCollateral, - address cTokenBorrowed, - address liquidator, - address borrower, - uint256 seizeTokens - ) external view override returns (uint256) { - liquidator; // currently unused - borrower; // currently unused - seizeTokens; // currently unused - - if ( - !markets[cTokenCollateral].isListed || - !markets[cTokenBorrowed].isListed - ) { - return uint256(Error.MARKET_NOT_LISTED); - } - - if ( - CToken(cTokenCollateral).comptroller() != - CToken(cTokenBorrowed).comptroller() - ) { - return uint256(Error.COMPTROLLER_MISMATCH); - } - - // *may include Policy Hook-type checks - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Validates seize and reverts on rejection. May emit logs. - * @param cTokenCollateral Asset which was used as collateral and will be seized - * @param cTokenBorrowed Asset which was borrowed by the borrower - * @param liquidator The address repaying the borrow and seizing the collateral - * @param borrower The address of the borrower - * @param seizeTokens The number of collateral tokens to seize - */ - function seizeVerify( - address cTokenCollateral, - address cTokenBorrowed, - address liquidator, - address borrower, - uint256 seizeTokens - ) external override { - cTokenCollateral; // currently unused - cTokenBorrowed; // currently unused - liquidator; // currently unused - borrower; // currently unused - seizeTokens; // currently unused - - if (false) { - maxAssets = maxAssets; // not pure - } - } - - /** - * @notice Checks if the account should be allowed to transfer tokens in the given market - * @param cToken The market to verify the transfer against - * @param src The account which sources the tokens - * @param dst The account which receives the tokens - * @param transferTokens The number of cTokens to transfer - * @return 0 if the transfer is allowed, otherwise a semi-opaque error code (See ErrorReporter.sol) - */ - function transferAllowed( - address cToken, - address src, - address dst, - uint256 transferTokens - ) external view override returns (uint256) { - cToken; // currently unused - src; // currently unused - dst; // currently unused - transferTokens; // currently unused - - // *may include Policy Hook-type checks - - // Currently the only consideration is whether or not - // the src is allowed to redeem this many tokens - return redeemAllowedInternal(cToken, src, transferTokens); - } - - /** - * @notice Validates transfer and reverts on rejection. May emit logs. - * @param cToken Asset being transferred - * @param src The account which sources the tokens - * @param dst The account which receives the tokens - * @param transferTokens The number of cTokens to transfer - */ - function transferVerify( - address cToken, - address src, - address dst, - uint256 transferTokens - ) external override { - cToken; // currently unused - src; // currently unused - dst; // currently unused - transferTokens; // currently unused - - if (false) { - maxAssets = maxAssets; // not pure - } - } - - /*** Liquidity/Liquidation Calculations ***/ - - /** - * @dev Local vars for avoiding stack-depth limits in calculating account liquidity. - * Note that `cTokenBalance` is the number of cTokens the account owns in the market, - * whereas `borrowBalance` is the amount of underlying that the account has borrowed. - */ - struct AccountLiquidityLocalVars { - uint256 sumCollateral; - uint256 sumBorrowPlusEffects; - uint256 cTokenBalance; - uint256 borrowBalance; - uint256 exchangeRateMantissa; - uint256 oraclePriceMantissa; - Exp collateralFactor; - Exp exchangeRate; - Exp oraclePrice; - Exp tokensToEther; - } - - /** - * @notice Determine the current account liquidity wrt collateral requirements - * @return (possible error code (semi-opaque), - account liquidity in excess of collateral requirements, - * account shortfall below collateral requirements) - */ - function getAccountLiquidity(address account) - public - view - returns ( - uint256, - uint256, - uint256 - ) - { - ( - Error err, - uint256 liquidity, - uint256 shortfall - ) = getHypotheticalAccountLiquidityInternal( - account, - CToken(address(0)), - 0, - 0 - ); - - return (uint256(err), liquidity, shortfall); - } - - /** - * @notice Determine the current account liquidity wrt collateral requirements - * @return (possible error code, - account liquidity in excess of collateral requirements, - * account shortfall below collateral requirements) - */ - function getAccountLiquidityInternal(address account) - internal - view - returns ( - Error, - uint256, - uint256 - ) - { - return - getHypotheticalAccountLiquidityInternal( - account, - CToken(address(0)), - 0, - 0 - ); - } - - /** - * @notice Determine what the account liquidity would be if the given amounts were redeemed/borrowed - * @param cTokenModify The market to hypothetically redeem/borrow in - * @param account The account to determine liquidity for - * @param redeemTokens The number of tokens to hypothetically redeem - * @param borrowAmount The amount of underlying to hypothetically borrow - * @dev Note that we calculate the exchangeRateStored for each collateral cToken using stored data, - * without calculating accumulated interest. - * @return (possible error code, - hypothetical account liquidity in excess of collateral requirements, - * hypothetical account shortfall below collateral requirements) - */ - function getHypotheticalAccountLiquidityInternal( - address account, - CToken cTokenModify, - uint256 redeemTokens, - uint256 borrowAmount - ) - internal - view - returns ( - Error, - uint256, - uint256 - ) - { - AccountLiquidityLocalVars memory vars; // Holds all our calculation results - uint256 oErr; - MathError mErr; - - // For each asset the account is in - CToken[] memory assets = accountAssets[account]; - for (uint256 i = 0; i < assets.length; i++) { - CToken asset = assets[i]; - - // Read the balances and exchange rate from the cToken - ( - oErr, - vars.cTokenBalance, - vars.borrowBalance, - vars.exchangeRateMantissa - ) = asset.getAccountSnapshot(account); - if (oErr != 0) { - // semi-opaque error code, we assume NO_ERROR == 0 is invariant between upgrades - return (Error.SNAPSHOT_ERROR, 0, 0); - } - vars.collateralFactor = Exp({ - mantissa: markets[address(asset)].collateralFactorMantissa - }); - vars.exchangeRate = Exp({mantissa: vars.exchangeRateMantissa}); - - // Get the normalized price of the asset - vars.oraclePriceMantissa = oracle.getUnderlyingPrice(asset); - if (vars.oraclePriceMantissa == 0) { - return (Error.PRICE_ERROR, 0, 0); - } - vars.oraclePrice = Exp({mantissa: vars.oraclePriceMantissa}); - - // Pre-compute a conversion factor from tokens -> ether (normalized price value) - (mErr, vars.tokensToEther) = mulExp3( - vars.collateralFactor, - vars.exchangeRate, - vars.oraclePrice - ); - if (mErr != MathError.NO_ERROR) { - return (Error.MATH_ERROR, 0, 0); - } - - // sumCollateral += tokensToEther * cTokenBalance - (mErr, vars.sumCollateral) = mulScalarTruncateAddUInt( - vars.tokensToEther, - vars.cTokenBalance, - vars.sumCollateral - ); - if (mErr != MathError.NO_ERROR) { - return (Error.MATH_ERROR, 0, 0); - } - - // sumBorrowPlusEffects += oraclePrice * borrowBalance - (mErr, vars.sumBorrowPlusEffects) = mulScalarTruncateAddUInt( - vars.oraclePrice, - vars.borrowBalance, - vars.sumBorrowPlusEffects - ); - if (mErr != MathError.NO_ERROR) { - return (Error.MATH_ERROR, 0, 0); - } - - // Calculate effects of interacting with cTokenModify - if (asset == cTokenModify) { - // redeem effect - // sumBorrowPlusEffects += tokensToEther * redeemTokens - (mErr, vars.sumBorrowPlusEffects) = mulScalarTruncateAddUInt( - vars.tokensToEther, - redeemTokens, - vars.sumBorrowPlusEffects - ); - if (mErr != MathError.NO_ERROR) { - return (Error.MATH_ERROR, 0, 0); - } - - // borrow effect - // sumBorrowPlusEffects += oraclePrice * borrowAmount - (mErr, vars.sumBorrowPlusEffects) = mulScalarTruncateAddUInt( - vars.oraclePrice, - borrowAmount, - vars.sumBorrowPlusEffects - ); - if (mErr != MathError.NO_ERROR) { - return (Error.MATH_ERROR, 0, 0); - } - } - } - - // These are safe, as the underflow condition is checked first - if (vars.sumCollateral > vars.sumBorrowPlusEffects) { - return ( - Error.NO_ERROR, - vars.sumCollateral - vars.sumBorrowPlusEffects, - 0 - ); - } else { - return ( - Error.NO_ERROR, - 0, - vars.sumBorrowPlusEffects - vars.sumCollateral - ); - } - } - - /** - * @notice Calculate number of tokens of collateral asset to seize given an underlying amount - * @dev Used in liquidation (called in cToken.liquidateBorrowFresh) - * @param cTokenBorrowed The address of the borrowed cToken - * @param cTokenCollateral The address of the collateral cToken - * @param repayAmount The amount of cTokenBorrowed underlying to convert into cTokenCollateral tokens - * @return (errorCode, number of cTokenCollateral tokens to be seized in a liquidation) - */ - function liquidateCalculateSeizeTokens( - address cTokenBorrowed, - address cTokenCollateral, - uint256 repayAmount - ) external view override returns (uint256, uint256) { - /* Read oracle prices for borrowed and collateral markets */ - uint256 priceBorrowedMantissa = oracle.getUnderlyingPrice( - CToken(cTokenBorrowed) - ); - uint256 priceCollateralMantissa = oracle.getUnderlyingPrice( - CToken(cTokenCollateral) - ); - if (priceBorrowedMantissa == 0 || priceCollateralMantissa == 0) { - return (uint256(Error.PRICE_ERROR), 0); - } - - /* - * Get the exchange rate and calculate the number of collateral tokens to seize: - * seizeAmount = repayAmount * liquidationIncentive * priceBorrowed / priceCollateral - * seizeTokens = seizeAmount / exchangeRate - * = repayAmount * (liquidationIncentive * priceBorrowed) / (priceCollateral * exchangeRate) - */ - uint256 exchangeRateMantissa = CToken(cTokenCollateral) - .exchangeRateStored(); // Note: reverts on error - uint256 seizeTokens; - Exp memory numerator; - Exp memory denominator; - Exp memory ratio; - MathError mathErr; - - (mathErr, numerator) = mulExp( - liquidationIncentiveMantissa, - priceBorrowedMantissa - ); - if (mathErr != MathError.NO_ERROR) { - return (uint256(Error.MATH_ERROR), 0); - } - - (mathErr, denominator) = mulExp( - priceCollateralMantissa, - exchangeRateMantissa - ); - if (mathErr != MathError.NO_ERROR) { - return (uint256(Error.MATH_ERROR), 0); - } - - (mathErr, ratio) = divExp(numerator, denominator); - if (mathErr != MathError.NO_ERROR) { - return (uint256(Error.MATH_ERROR), 0); - } - - (mathErr, seizeTokens) = mulScalarTruncate(ratio, repayAmount); - if (mathErr != MathError.NO_ERROR) { - return (uint256(Error.MATH_ERROR), 0); - } - - return (uint256(Error.NO_ERROR), seizeTokens); - } - - /*** Admin Functions ***/ - - /** - * @notice Sets a new price oracle for the comptroller - * @dev Admin function to set a new price oracle - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setPriceOracle(PriceOracle newOracle) public returns (uint256) { - // Check caller is admin OR currently initialzing as new unitroller implementation - if (!adminOrInitializing()) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_PRICE_ORACLE_OWNER_CHECK - ); - } - - // Track the old oracle for the comptroller - PriceOracle oldOracle = oracle; - - // Ensure invoke newOracle.isPriceOracle() returns true - // require(newOracle.isPriceOracle(), "oracle method isPriceOracle returned false"); - - // Set comptroller's oracle to newOracle - oracle = newOracle; - - // Emit NewPriceOracle(oldOracle, newOracle) - emit NewPriceOracle(oldOracle, newOracle); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Sets the closeFactor used when liquidating borrows - * @dev Admin function to set closeFactor - * @param newCloseFactorMantissa New close factor, scaled by 1e18 - * @return uint 0=success, otherwise a failure. (See ErrorReporter for details) - */ - function _setCloseFactor(uint256 newCloseFactorMantissa) - external - returns (uint256) - { - // Check caller is admin OR currently initialzing as new unitroller implementation - if (!adminOrInitializing()) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_CLOSE_FACTOR_OWNER_CHECK - ); - } - - Exp memory newCloseFactorExp = Exp({mantissa: newCloseFactorMantissa}); - Exp memory lowLimit = Exp({mantissa: closeFactorMinMantissa}); - if (lessThanOrEqualExp(newCloseFactorExp, lowLimit)) { - return - fail( - Error.INVALID_CLOSE_FACTOR, - FailureInfo.SET_CLOSE_FACTOR_VALIDATION - ); - } - - Exp memory highLimit = Exp({mantissa: closeFactorMaxMantissa}); - if (lessThanExp(highLimit, newCloseFactorExp)) { - return - fail( - Error.INVALID_CLOSE_FACTOR, - FailureInfo.SET_CLOSE_FACTOR_VALIDATION - ); - } - - uint256 oldCloseFactorMantissa = closeFactorMantissa; - closeFactorMantissa = newCloseFactorMantissa; - emit NewCloseFactor(oldCloseFactorMantissa, closeFactorMantissa); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Sets the collateralFactor for a market - * @dev Admin function to set per-market collateralFactor - * @param cToken The market to set the factor on - * @param newCollateralFactorMantissa The new collateral factor, scaled by 1e18 - * @return uint 0=success, otherwise a failure. (See ErrorReporter for details) - */ - function _setCollateralFactor( - CToken cToken, - uint256 newCollateralFactorMantissa - ) external returns (uint256) { - // Check caller is admin - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_COLLATERAL_FACTOR_OWNER_CHECK - ); - } - - // Verify market is listed - Market storage market = markets[address(cToken)]; - if (!market.isListed) { - return - fail( - Error.MARKET_NOT_LISTED, - FailureInfo.SET_COLLATERAL_FACTOR_NO_EXISTS - ); - } - - Exp memory newCollateralFactorExp = Exp({ - mantissa: newCollateralFactorMantissa - }); - - // Check collateral factor <= 0.9 - Exp memory highLimit = Exp({mantissa: collateralFactorMaxMantissa}); - if (lessThanExp(highLimit, newCollateralFactorExp)) { - return - fail( - Error.INVALID_COLLATERAL_FACTOR, - FailureInfo.SET_COLLATERAL_FACTOR_VALIDATION - ); - } - - // If collateral factor != 0, fail if price == 0 - if ( - newCollateralFactorMantissa != 0 && - oracle.getUnderlyingPrice(cToken) == 0 - ) { - return - fail( - Error.PRICE_ERROR, - FailureInfo.SET_COLLATERAL_FACTOR_WITHOUT_PRICE - ); - } - - // Set market's collateral factor to new collateral factor, remember old value - uint256 oldCollateralFactorMantissa = market.collateralFactorMantissa; - market.collateralFactorMantissa = newCollateralFactorMantissa; - - // Emit event with asset, old collateral factor, and new collateral factor - emit NewCollateralFactor( - cToken, - oldCollateralFactorMantissa, - newCollateralFactorMantissa - ); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Sets maxAssets which controls how many markets can be entered - * @dev Admin function to set maxAssets - * @param newMaxAssets New max assets - * @return uint 0=success, otherwise a failure. (See ErrorReporter for details) - */ - function _setMaxAssets(uint256 newMaxAssets) external returns (uint256) { - // Check caller is admin OR currently initialzing as new unitroller implementation - if (!adminOrInitializing()) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_MAX_ASSETS_OWNER_CHECK - ); - } - - uint256 oldMaxAssets = maxAssets; - maxAssets = newMaxAssets; - emit NewMaxAssets(oldMaxAssets, newMaxAssets); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Sets liquidationIncentive - * @dev Admin function to set liquidationIncentive - * @param newLiquidationIncentiveMantissa New liquidationIncentive scaled by 1e18 - * @return uint 0=success, otherwise a failure. (See ErrorReporter for details) - */ - function _setLiquidationIncentive(uint256 newLiquidationIncentiveMantissa) - external - returns (uint256) - { - // Check caller is admin OR currently initialzing as new unitroller implementation - if (!adminOrInitializing()) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_LIQUIDATION_INCENTIVE_OWNER_CHECK - ); - } - - // Check de-scaled 1 <= newLiquidationDiscount <= 1.5 - Exp memory newLiquidationIncentive = Exp({ - mantissa: newLiquidationIncentiveMantissa - }); - Exp memory minLiquidationIncentive = Exp({ - mantissa: liquidationIncentiveMinMantissa - }); - if (lessThanExp(newLiquidationIncentive, minLiquidationIncentive)) { - return - fail( - Error.INVALID_LIQUIDATION_INCENTIVE, - FailureInfo.SET_LIQUIDATION_INCENTIVE_VALIDATION - ); - } - - Exp memory maxLiquidationIncentive = Exp({ - mantissa: liquidationIncentiveMaxMantissa - }); - if (lessThanExp(maxLiquidationIncentive, newLiquidationIncentive)) { - return - fail( - Error.INVALID_LIQUIDATION_INCENTIVE, - FailureInfo.SET_LIQUIDATION_INCENTIVE_VALIDATION - ); - } - - // Save current value for use in log - uint256 oldLiquidationIncentiveMantissa = liquidationIncentiveMantissa; - - // Set liquidation incentive to new incentive - liquidationIncentiveMantissa = newLiquidationIncentiveMantissa; - - // Emit event with old incentive, new incentive - emit NewLiquidationIncentive( - oldLiquidationIncentiveMantissa, - newLiquidationIncentiveMantissa - ); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Add the market to the markets mapping and set it as listed - * @dev Admin function to set isListed and add support for the market - * @param cToken The address of the market (token) to list - * @return uint 0=success, otherwise a failure. (See enum Error for details) - */ - function _supportMarket(CToken cToken) external returns (uint256) { - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SUPPORT_MARKET_OWNER_CHECK - ); - } - - if (markets[address(cToken)].isListed) { - return - fail( - Error.MARKET_ALREADY_LISTED, - FailureInfo.SUPPORT_MARKET_EXISTS - ); - } - - cToken.isCToken(); // Sanity check to make sure its really a CToken - - Market storage market = markets[address(cToken)]; - market.isListed = true; - market.collateralFactorMantissa = 0; - - emit MarketListed(cToken); - - return uint256(Error.NO_ERROR); - } - - function _become( - Unitroller unitroller, - PriceOracle _oracle, - uint256 _closeFactorMantissa, - uint256 _maxAssets, - bool reinitializing - ) public virtual { - require( - msg.sender == unitroller.admin(), - "only unitroller admin can change brains" - ); - uint256 changeStatus = unitroller._acceptImplementation(); - - require(changeStatus == 0, "change not authorized"); - - if (!reinitializing) { - ComptrollerG1 freshBrainedComptroller = ComptrollerG1( - address(unitroller) - ); - - // Ensure invoke _setPriceOracle() = 0 - uint256 err = freshBrainedComptroller._setPriceOracle(_oracle); - require(err == uint256(Error.NO_ERROR), "set price oracle error"); - - // Ensure invoke _setCloseFactor() = 0 - err = freshBrainedComptroller._setCloseFactor(_closeFactorMantissa); - require(err == uint256(Error.NO_ERROR), "set close factor error"); - - // Ensure invoke _setMaxAssets() = 0 - err = freshBrainedComptroller._setMaxAssets(_maxAssets); - require(err == uint256(Error.NO_ERROR), "set max asssets error"); - - // Ensure invoke _setLiquidationIncentive(liquidationIncentiveMinMantissa) = 0 - err = freshBrainedComptroller._setLiquidationIncentive( - liquidationIncentiveMinMantissa - ); - require( - err == uint256(Error.NO_ERROR), - "set liquidation incentive error" - ); - } - } - - /** - * @dev Check that caller is admin or this contract is initializing itself as - * the new implementation. - * There should be no way to satisfy msg.sender == comptrollerImplementaiton - * without tx.origin also being admin, but both are included for extra safety - */ - function adminOrInitializing() internal view returns (bool) { - bool initializing = (msg.sender == comptrollerImplementation && - tx.origin == admin); - //solium-disable-previous-line security/no-tx-origin - bool isAdmin = msg.sender == admin; - return isAdmin || initializing; - } -} diff --git a/flatten/ComptrollerG2.sol b/flatten/ComptrollerG2.sol deleted file mode 100644 index 10db00c..0000000 --- a/flatten/ComptrollerG2.sol +++ /dev/null @@ -1,5713 +0,0 @@ -// Dependency file: contracts/ComptrollerInterface.sol - -// SPDX-License-Identifier: UNLICENSED -// pragma solidity 0.8.6; - -abstract contract ComptrollerInterface { - /// @notice Indicator that this is a Comptroller contract (for inspection) - bool public constant isComptroller = true; - - /*** Assets You Are In ***/ - - function enterMarkets(address[] calldata cTokens) - external - virtual - returns (uint256[] memory); - - function exitMarket(address cToken) external virtual returns (uint256); - - /*** Policy Hooks ***/ - - function mintAllowed( - address cToken, - address minter, - uint256 mintAmount - ) external virtual returns (uint256); - - function mintVerify( - address cToken, - address minter, - uint256 mintAmount, - uint256 mintTokens - ) external virtual; - - function redeemAllowed( - address cToken, - address redeemer, - uint256 redeemTokens - ) external virtual returns (uint256); - - function redeemVerify( - address cToken, - address redeemer, - uint256 redeemAmount, - uint256 redeemTokens - ) external virtual; - - function borrowAllowed( - address cToken, - address borrower, - uint256 borrowAmount - ) external virtual returns (uint256); - - function borrowVerify( - address cToken, - address borrower, - uint256 borrowAmount - ) external virtual; - - function repayBorrowAllowed( - address cToken, - address payer, - address borrower, - uint256 repayAmount - ) external virtual returns (uint256); - - function repayBorrowVerify( - address cToken, - address payer, - address borrower, - uint256 repayAmount, - uint256 borrowerIndex - ) external virtual; - - function liquidateBorrowAllowed( - address cTokenBorrowed, - address cTokenCollateral, - address liquidator, - address borrower, - uint256 repayAmount - ) external virtual returns (uint256); - - function liquidateBorrowVerify( - address cTokenBorrowed, - address cTokenCollateral, - address liquidator, - address borrower, - uint256 repayAmount, - uint256 seizeTokens - ) external virtual; - - function seizeAllowed( - address cTokenCollateral, - address cTokenBorrowed, - address liquidator, - address borrower, - uint256 seizeTokens - ) external virtual returns (uint256); - - function seizeVerify( - address cTokenCollateral, - address cTokenBorrowed, - address liquidator, - address borrower, - uint256 seizeTokens - ) external virtual; - - function transferAllowed( - address cToken, - address src, - address dst, - uint256 transferTokens - ) external virtual returns (uint256); - - function transferVerify( - address cToken, - address src, - address dst, - uint256 transferTokens - ) external virtual; - - /*** Liquidity/Liquidation Calculations ***/ - - function liquidateCalculateSeizeTokens( - address cTokenBorrowed, - address cTokenCollateral, - uint256 repayAmount - ) external view virtual returns (uint256, uint256); -} - - -// Dependency file: contracts/CarefulMath.sol - -// pragma solidity 0.8.6; - -/** - * @title Careful Math - * @author tropykus - * @notice Derived from OpenZeppelin's SafeMath library - * https://github.com/OpenZeppelin/openzeppelin-solidity/blob/master/contracts/math/SafeMath.sol - */ -contract CarefulMath { - - /** - * @dev Possible error codes that we can return - */ - enum MathError { - NO_ERROR, - DIVISION_BY_ZERO, - INTEGER_OVERFLOW, - INTEGER_UNDERFLOW - } - - /** - * @dev Multiplies two numbers, returns an error on overflow. - */ - function mulUInt(uint a, uint b) internal pure returns (MathError, uint) { - if (a == 0) { - return (MathError.NO_ERROR, 0); - } - - uint c = a * b; - - if (c / a != b) { - return (MathError.INTEGER_OVERFLOW, 0); - } else { - return (MathError.NO_ERROR, c); - } - } - - /** - * @dev Integer division of two numbers, truncating the quotient. - */ - function divUInt(uint a, uint b) internal pure returns (MathError, uint) { - if (b == 0) { - return (MathError.DIVISION_BY_ZERO, 0); - } - - return (MathError.NO_ERROR, a / b); - } - - /** - * @dev Subtracts two numbers, returns an error on overflow (i.e. if subtrahend is greater than minuend). - */ - function subUInt(uint a, uint b) internal pure returns (MathError, uint) { - if (b <= a) { - return (MathError.NO_ERROR, a - b); - } else { - return (MathError.INTEGER_UNDERFLOW, 0); - } - } - - /** - * @dev Adds two numbers, returns an error on overflow. - */ - function addUInt(uint a, uint b) internal pure returns (MathError, uint) { - uint c = a + b; - - if (c >= a) { - return (MathError.NO_ERROR, c); - } else { - return (MathError.INTEGER_OVERFLOW, 0); - } - } - - /** - * @dev add a and b and then subtract c - */ - function addThenSubUInt(uint a, uint b, uint c) internal pure returns (MathError, uint) { - (MathError err0, uint sum) = addUInt(a, b); - - if (err0 != MathError.NO_ERROR) { - return (err0, 0); - } - - return subUInt(sum, c); - } -} - - -// Dependency file: contracts/ExponentialNoError.sol - -// pragma solidity 0.8.6; - -/** - * @title Exponential module for storing fixed-precision decimals - * @author tropykus - * @notice Exp is a struct which stores decimals with a fixed precision of 18 decimal places. - * Thus, if we wanted to store the 5.1, mantissa would store 5.1e18. That is: - * `Exp({mantissa: 5100000000000000000})`. - */ -contract ExponentialNoError { - uint constant expScale = 1e18; - uint constant doubleScale = 1e36; - uint constant halfExpScale = expScale/2; - uint constant mantissaOne = expScale; - - struct Exp { - uint mantissa; - } - - struct Double { - uint mantissa; - } - - /** - * @dev Truncates the given exp to a whole number value. - * For example, truncate(Exp{mantissa: 15 * expScale}) = 15 - */ - function truncate(Exp memory exp) pure internal returns (uint) { - // Note: We are not using careful math here as we're performing a division that cannot fail - return exp.mantissa / expScale; - } - - /** - * @dev Multiply an Exp by a scalar, then truncate to return an unsigned integer. - */ - function mul_ScalarTruncate(Exp memory a, uint scalar) pure internal returns (uint) { - Exp memory product = mul_(a, scalar); - return truncate(product); - } - - /** - * @dev Multiply an Exp by a scalar, truncate, then add an to an unsigned integer, returning an unsigned integer. - */ - function mul_ScalarTruncateAddUInt(Exp memory a, uint scalar, uint addend) pure internal returns (uint) { - Exp memory product = mul_(a, scalar); - return add_(truncate(product), addend); - } - - /** - * @dev Checks if first Exp is less than second Exp. - */ - function lessThanExp(Exp memory left, Exp memory right) pure internal returns (bool) { - return left.mantissa < right.mantissa; - } - - /** - * @dev Checks if left Exp <= right Exp. - */ - function lessThanOrEqualExp(Exp memory left, Exp memory right) pure internal returns (bool) { - return left.mantissa <= right.mantissa; - } - - /** - * @dev Checks if left Exp > right Exp. - */ - function greaterThanExp(Exp memory left, Exp memory right) pure internal returns (bool) { - return left.mantissa > right.mantissa; - } - - /** - * @dev returns true if Exp is exactly zero - */ - function isZeroExp(Exp memory value) pure internal returns (bool) { - return value.mantissa == 0; - } - - function safe224(uint n, string memory errorMessage) pure internal returns (uint224) { - require(n < 2**224, errorMessage); - return uint224(n); - } - - function safe32(uint n, string memory errorMessage) pure internal returns (uint32) { - require(n < 2**32, errorMessage); - return uint32(n); - } - - function add_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { - return Exp({mantissa: add_(a.mantissa, b.mantissa)}); - } - - function add_(Double memory a, Double memory b) pure internal returns (Double memory) { - return Double({mantissa: add_(a.mantissa, b.mantissa)}); - } - - function add_(uint a, uint b) pure internal returns (uint) { - return add_(a, b, "addition overflow"); - } - - function add_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { - uint c = a + b; - require(c >= a, errorMessage); - return c; - } - - function sub_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { - return Exp({mantissa: sub_(a.mantissa, b.mantissa)}); - } - - function sub_(Double memory a, Double memory b) pure internal returns (Double memory) { - return Double({mantissa: sub_(a.mantissa, b.mantissa)}); - } - - function sub_(uint a, uint b) pure internal returns (uint) { - return sub_(a, b, "subtraction underflow"); - } - - function sub_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { - require(b <= a, errorMessage); - return a - b; - } - - function mul_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { - return Exp({mantissa: mul_(a.mantissa, b.mantissa) / expScale}); - } - - function mul_(Exp memory a, uint b) pure internal returns (Exp memory) { - return Exp({mantissa: mul_(a.mantissa, b)}); - } - - function mul_(uint a, Exp memory b) pure internal returns (uint) { - return mul_(a, b.mantissa) / expScale; - } - - function mul_(Double memory a, Double memory b) pure internal returns (Double memory) { - return Double({mantissa: mul_(a.mantissa, b.mantissa) / doubleScale}); - } - - function mul_(Double memory a, uint b) pure internal returns (Double memory) { - return Double({mantissa: mul_(a.mantissa, b)}); - } - - function mul_(uint a, Double memory b) pure internal returns (uint) { - return mul_(a, b.mantissa) / doubleScale; - } - - function mul_(uint a, uint b) pure internal returns (uint) { - return mul_(a, b, "multiplication overflow"); - } - - function mul_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { - if (a == 0 || b == 0) { - return 0; - } - uint c = a * b; - require(c / a == b, errorMessage); - return c; - } - - function div_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { - return Exp({mantissa: div_(mul_(a.mantissa, expScale), b.mantissa)}); - } - - function div_(Exp memory a, uint b) pure internal returns (Exp memory) { - return Exp({mantissa: div_(a.mantissa, b)}); - } - - function div_(uint a, Exp memory b) pure internal returns (uint) { - return div_(mul_(a, expScale), b.mantissa); - } - - function div_(Double memory a, Double memory b) pure internal returns (Double memory) { - return Double({mantissa: div_(mul_(a.mantissa, doubleScale), b.mantissa)}); - } - - function div_(Double memory a, uint b) pure internal returns (Double memory) { - return Double({mantissa: div_(a.mantissa, b)}); - } - - function div_(uint a, Double memory b) pure internal returns (uint) { - return div_(mul_(a, doubleScale), b.mantissa); - } - - function div_(uint a, uint b) pure internal returns (uint) { - return div_(a, b, "divide by zero"); - } - - function div_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { - require(b > 0, errorMessage); - return a / b; - } - - function fraction(uint a, uint b) pure internal returns (Double memory) { - return Double({mantissa: div_(mul_(a, doubleScale), b)}); - } -} - - -// Dependency file: contracts/Exponential.sol - -// pragma solidity 0.8.6; - -// import "contracts/CarefulMath.sol"; -// import "contracts/ExponentialNoError.sol"; - -/** - * @title Exponential module for storing fixed-precision decimals - * @author tropykus - * @dev Legacy contract for compatibility reasons with existing contracts that still use MathError - * @notice Exp is a struct which stores decimals with a fixed precision of 18 decimal places. - * Thus, if we wanted to store the 5.1, mantissa would store 5.1e18. That is: - * `Exp({mantissa: 5100000000000000000})`. - */ -contract Exponential is CarefulMath, ExponentialNoError { - /** - * @dev Creates an exponential from numerator and denominator values. - * Note: Returns an error if (`num` * 10e18) > MAX_INT, - * or if `denom` is zero. - */ - function getExp(uint num, uint denom) internal pure returns (MathError, Exp memory) { - (MathError err0, uint scaledNumerator) = mulUInt(num, expScale); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - - (MathError err1, uint rational) = divUInt(scaledNumerator, denom); - if (err1 != MathError.NO_ERROR) { - return (err1, Exp({mantissa: 0})); - } - - return (MathError.NO_ERROR, Exp({mantissa: rational})); - } - - /** - * @dev Adds two exponentials, returning a new exponential. - */ - function addExp(Exp memory a, Exp memory b) internal pure returns (MathError, Exp memory) { - (MathError error, uint result) = addUInt(a.mantissa, b.mantissa); - - return (error, Exp({mantissa: result})); - } - - /** - * @dev Subtracts two exponentials, returning a new exponential. - */ - function subExp(Exp memory a, Exp memory b) internal pure returns (MathError, Exp memory) { - (MathError error, uint result) = subUInt(a.mantissa, b.mantissa); - - return (error, Exp({mantissa: result})); - } - - /** - * @dev Multiply an Exp by a scalar, returning a new Exp. - */ - function mulScalar(Exp memory a, uint scalar) internal pure returns (MathError, Exp memory) { - (MathError err0, uint scaledMantissa) = mulUInt(a.mantissa, scalar); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - - return (MathError.NO_ERROR, Exp({mantissa: scaledMantissa})); - } - - /** - * @dev Multiply an Exp by a scalar, then truncate to return an unsigned integer. - */ - function mulScalarTruncate(Exp memory a, uint scalar) internal pure returns (MathError, uint) { - (MathError err, Exp memory product) = mulScalar(a, scalar); - if (err != MathError.NO_ERROR) { - return (err, 0); - } - - return (MathError.NO_ERROR, truncate(product)); - } - - /** - * @dev Multiply an Exp by a scalar, truncate, then add an to an unsigned integer, returning an unsigned integer. - */ - function mulScalarTruncateAddUInt(Exp memory a, uint scalar, uint addend) internal pure returns (MathError, uint) { - (MathError err, Exp memory product) = mulScalar(a, scalar); - if (err != MathError.NO_ERROR) { - return (err, 0); - } - - return addUInt(truncate(product), addend); - } - - /** - * @dev Divide an Exp by a scalar, returning a new Exp. - */ - function divScalar(Exp memory a, uint scalar) internal pure returns (MathError, Exp memory) { - (MathError err0, uint descaledMantissa) = divUInt(a.mantissa, scalar); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - - return (MathError.NO_ERROR, Exp({mantissa: descaledMantissa})); - } - - /** - * @dev Divide a scalar by an Exp, returning a new Exp. - */ - function divScalarByExp(uint scalar, Exp memory divisor) internal pure returns (MathError, Exp memory) { - /* - We are doing this as: - getExp(mulUInt(expScale, scalar), divisor.mantissa) - - How it works: - Exp = a / b; - Scalar = s; - `s / (a / b)` = `b * s / a` and since for an Exp `a = mantissa, b = expScale` - */ - (MathError err0, uint numerator) = mulUInt(expScale, scalar); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - return getExp(numerator, divisor.mantissa); - } - - /** - * @dev Divide a scalar by an Exp, then truncate to return an unsigned integer. - */ - function divScalarByExpTruncate(uint scalar, Exp memory divisor) internal pure returns (MathError, uint) { - (MathError err, Exp memory fraction) = divScalarByExp(scalar, divisor); - if (err != MathError.NO_ERROR) { - return (err, 0); - } - - return (MathError.NO_ERROR, truncate(fraction)); - } - - /** - * @dev Multiplies two exponentials, returning a new exponential. - */ - function mulExp(Exp memory a, Exp memory b) internal pure returns (MathError, Exp memory) { - - (MathError err0, uint doubleScaledProduct) = mulUInt(a.mantissa, b.mantissa); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - - // We add half the scale before dividing so that we get rounding instead of truncation. - // See "Listing 6" and text above it at https://accu.org/index.php/journals/1717 - // Without this change, a result like 6.6...e-19 will be truncated to 0 instead of being rounded to 1e-18. - (MathError err1, uint doubleScaledProductWithHalfScale) = addUInt(halfExpScale, doubleScaledProduct); - if (err1 != MathError.NO_ERROR) { - return (err1, Exp({mantissa: 0})); - } - - (MathError err2, uint product) = divUInt(doubleScaledProductWithHalfScale, expScale); - // The only error `div` can return is MathError.DIVISION_BY_ZERO but we control `expScale` and it is not zero. - assert(err2 == MathError.NO_ERROR); - - return (MathError.NO_ERROR, Exp({mantissa: product})); - } - - /** - * @dev Multiplies two exponentials given their mantissas, returning a new exponential. - */ - function mulExp(uint a, uint b) internal pure returns (MathError, Exp memory) { - return mulExp(Exp({mantissa: a}), Exp({mantissa: b})); - } - - /** - * @dev Multiplies three exponentials, returning a new exponential. - */ - function mulExp3(Exp memory a, Exp memory b, Exp memory c) internal pure returns (MathError, Exp memory) { - (MathError err, Exp memory ab) = mulExp(a, b); - if (err != MathError.NO_ERROR) { - return (err, ab); - } - return mulExp(ab, c); - } - - /** - * @dev Divides two exponentials, returning a new exponential. - * (a/scale) / (b/scale) = (a/scale) * (scale/b) = a/b, - * which we can scale as an Exp by calling getExp(a.mantissa, b.mantissa) - */ - function divExp(Exp memory a, Exp memory b) internal pure returns (MathError, Exp memory) { - return getExp(a.mantissa, b.mantissa); - } -} - - -// Dependency file: contracts/SafeMath.sol - -// pragma solidity 0.8.6; - -// From https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/math/Math.sol -// Subject to the MIT license. - -/** - * @dev Wrappers over Solidity's arithmetic operations with added overflow - * checks. - * - * Arithmetic operations in Solidity wrap on overflow. This can easily result - * in bugs, because programmers usually assume that an overflow raises an - * error, which is the standard behavior in high level programming languages. - * `SafeMath` restores this intuition by reverting the transaction when an - * operation overflows. - * - * Using this library instead of the unchecked operations eliminates an entire - * class of bugs, so it's recommended to use it always. - */ -library SafeMath { - /** - * @dev Returns the addition of two unsigned integers, reverting on overflow. - * - * Counterpart to Solidity's `+` operator. - * - * Requirements: - * - Addition cannot overflow. - */ - function add(uint256 a, uint256 b) internal pure returns (uint256) { - uint256 c = a + b; - require(c >= a, "SafeMath: addition overflow"); - - return c; - } - - /** - * @dev Returns the addition of two unsigned integers, reverting with custom message on overflow. - * - * Counterpart to Solidity's `+` operator. - * - * Requirements: - * - Addition cannot overflow. - */ - function add(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - uint256 c = a + b; - require(c >= a, errorMessage); - - return c; - } - - /** - * @dev Returns the subtraction of two unsigned integers, reverting on underflow (when the result is negative). - * - * Counterpart to Solidity's `-` operator. - * - * Requirements: - * - Subtraction cannot underflow. - */ - function sub(uint256 a, uint256 b) internal pure returns (uint256) { - return sub(a, b, "SafeMath: subtraction underflow"); - } - - /** - * @dev Returns the subtraction of two unsigned integers, reverting with custom message on underflow (when the result is negative). - * - * Counterpart to Solidity's `-` operator. - * - * Requirements: - * - Subtraction cannot underflow. - */ - function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - require(b <= a, errorMessage); - uint256 c = a - b; - - return c; - } - - /** - * @dev Returns the multiplication of two unsigned integers, reverting on overflow. - * - * Counterpart to Solidity's `*` operator. - * - * Requirements: - * - Multiplication cannot overflow. - */ - function mul(uint256 a, uint256 b) internal pure returns (uint256) { - // Gas optimization: this is cheaper than requiring 'a' not being zero, but the - // benefit is lost if 'b' is also tested. - // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 - if (a == 0) { - return 0; - } - - uint256 c = a * b; - require(c / a == b, "SafeMath: multiplication overflow"); - - return c; - } - - /** - * @dev Returns the multiplication of two unsigned integers, reverting on overflow. - * - * Counterpart to Solidity's `*` operator. - * - * Requirements: - * - Multiplication cannot overflow. - */ - function mul(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - // Gas optimization: this is cheaper than requiring 'a' not being zero, but the - // benefit is lost if 'b' is also tested. - // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 - if (a == 0) { - return 0; - } - - uint256 c = a * b; - require(c / a == b, errorMessage); - - return c; - } - - /** - * @dev Returns the integer division of two unsigned integers. - * Reverts on division by zero. The result is rounded towards zero. - * - * Counterpart to Solidity's `/` operator. Note: this function uses a - * `revert` opcode (which leaves remaining gas untouched) while Solidity - * uses an invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function div(uint256 a, uint256 b) internal pure returns (uint256) { - return div(a, b, "SafeMath: division by zero"); - } - - /** - * @dev Returns the integer division of two unsigned integers. - * Reverts with custom message on division by zero. The result is rounded towards zero. - * - * Counterpart to Solidity's `/` operator. Note: this function uses a - * `revert` opcode (which leaves remaining gas untouched) while Solidity - * uses an invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - // Solidity only automatically asserts when dividing by 0 - require(b > 0, errorMessage); - uint256 c = a / b; - // assert(a == b * c + a % b); // There is no case in which this doesn't hold - - return c; - } - - /** - * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), - * Reverts when dividing by zero. - * - * Counterpart to Solidity's `%` operator. This function uses a `revert` - * opcode (which leaves remaining gas untouched) while Solidity uses an - * invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function mod(uint256 a, uint256 b) internal pure returns (uint256) { - return mod(a, b, "SafeMath: modulo by zero"); - } - - /** - * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), - * Reverts with custom message when dividing by zero. - * - * Counterpart to Solidity's `%` operator. This function uses a `revert` - * opcode (which leaves remaining gas untouched) while Solidity uses an - * invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - require(b != 0, errorMessage); - return a % b; - } -} - - -// Dependency file: contracts/InterestRateModel.sol - -// pragma solidity 0.8.6; - -// import "contracts/Exponential.sol"; -// import "contracts/SafeMath.sol"; - -/** - * @title tropykus InterestRateModel Interface - * @author tropykus - */ -abstract contract InterestRateModel is Exponential { - using SafeMath for uint256; - - /// @notice Indicator that this is an InterestRateModel contract (for inspection) - bool public constant isInterestRateModel = true; - bool public isTropykusInterestRateModel; - - /** - * @notice The approximate number of blocks per year that is assumed by the interest rate model - */ - uint256 public constant blocksPerYear = 1051200; - - /** - * @notice Calculates the utilization rate of the market: `borrows / (cash + borrows - reserves)` - * @param cash The amount of cash in the market - * @param borrows The amount of borrows in the market - * @param reserves The amount of reserves in the market (currently unused) - * @return The utilization rate as a mantissa between [0, 1e18] - */ - function utilizationRate( - uint256 cash, - uint256 borrows, - uint256 reserves - ) public pure virtual returns (uint256) { - // Utilization rate is 0 when there are no borrows - if (borrows == 0) { - return 0; - } - - return borrows.mul(1e18).div(cash.add(borrows).sub(reserves)); - } - - /** - * @notice Calculates the current borrow interest rate per block - * @param cash The total amount of cash the market has - * @param borrows The total amount of borrows the market has outstanding - * @param reserves The total amnount of reserves the market has - * @return The borrow rate per block (as a percentage, and scaled by 1e18) - */ - function getBorrowRate( - uint256 cash, - uint256 borrows, - uint256 reserves - ) external view virtual returns (uint256); - - /** - * @notice Calculates the current supply interest rate per block - * @param cash The total amount of cash the market has - * @param borrows The total amount of borrows the market has outstanding - * @param reserves The total amnount of reserves the market has - * @param reserveFactorMantissa The current reserve factor the market has - * @return The supply rate per block (as a percentage, and scaled by 1e18) - */ - function getSupplyRate( - uint256 cash, - uint256 borrows, - uint256 reserves, - uint256 reserveFactorMantissa - ) external view virtual returns (uint256); - - function getExchangeRate( - uint256 _totalCash, - uint256 _totalBorrows, - uint256 _totalReserves, - uint256 _totalSupply - ) public pure returns (MathError, uint256) { - /* - * exchangeRate = (totalCash + totalBorrows - totalReserves) / totalSupply - */ - Exp memory exchangeRate; - MathError mathErr; - uint256 cashPlusBorrowsMinusReserves; - (mathErr, cashPlusBorrowsMinusReserves) = addThenSubUInt( - _totalCash, - _totalBorrows, - _totalReserves - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - (mathErr, exchangeRate) = getExp( - cashPlusBorrowsMinusReserves, - _totalSupply - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - - return (MathError.NO_ERROR, exchangeRate.mantissa); - } - - function isAboveOptimal( - uint256 cash, - uint256 borrows, - uint256 reserves - ) public view virtual returns (bool) { - cash; - borrows; - reserves; - return false; - } -} - - -// Dependency file: contracts/EIP20NonStandardInterface.sol - -// pragma solidity 0.8.6; - -/** - * @title EIP20NonStandardInterface - * @dev Version of ERC20 with no return values for `transfer` and `transferFrom` - * See https://medium.com/coinmonks/missing-return-value-bug-at-least-130-tokens-affected-d67bf08521ca - */ -interface EIP20NonStandardInterface { - /** - * @notice Get the total number of tokens in circulation - * @return The supply of tokens - */ - function totalSupply() external view returns (uint256); - - /** - * @notice Gets the balance of the specified address - * @param owner The address from which the balance will be retrieved - * @return balance The balance - */ - function balanceOf(address owner) external view returns (uint256 balance); - - /// - /// !!!!!!!!!!!!!! - /// !!! NOTICE !!! `transfer` does not return a value, in violation of the ERC-20 specification - /// !!!!!!!!!!!!!! - /// - - /** - * @notice Transfer `amount` tokens from `msg.sender` to `dst` - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - */ - function transfer(address dst, uint256 amount) external; - - /// - /// !!!!!!!!!!!!!! - /// !!! NOTICE !!! `transferFrom` does not return a value, in violation of the ERC-20 specification - /// !!!!!!!!!!!!!! - /// - - /** - * @notice Transfer `amount` tokens from `src` to `dst` - * @param src The address of the source account - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - */ - function transferFrom( - address src, - address dst, - uint256 amount - ) external; - - /** - * @notice Approve `spender` to transfer up to `amount` from `src` - * @dev This will overwrite the approval amount for `spender` - * and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve) - * @param spender The address of the account which may transfer tokens - * @param amount The number of tokens that are approved - * @return success Whether or not the approval succeeded - */ - function approve(address spender, uint256 amount) - external - returns (bool success); - - /** - * @notice Get the current allowance from `owner` for `spender` - * @param owner The address of the account which owns the tokens to be spent - * @param spender The address of the account which may transfer tokens - * @return remaining The number of tokens allowed to be spent - */ - function allowance(address owner, address spender) - external - view - returns (uint256 remaining); - - event Transfer(address indexed from, address indexed to, uint256 amount); - event Approval( - address indexed owner, - address indexed spender, - uint256 amount - ); -} - - -// Dependency file: contracts/CTokenInterfaces.sol - -// pragma solidity 0.8.6; - -// import "contracts/ComptrollerInterface.sol"; -// import "contracts/InterestRateModel.sol"; -// import "contracts/EIP20NonStandardInterface.sol"; - -contract CTokenStorage { - /** - * @dev Guard variable for re-entrancy checks - */ - bool internal _notEntered; - - /** - * @notice EIP-20 token name for this token - */ - string public name; - - /** - * @notice EIP-20 token symbol for this token - */ - string public symbol; - - /** - * @notice EIP-20 token decimals for this token - */ - uint8 public decimals; - - /** - * @notice Maximum borrow rate that can ever be applied (.0005% / block) - */ - - uint256 internal constant borrowRateMaxMantissa = 0.0005e16; - - /** - * @notice Maximum fraction of interest that can be set aside for reserves - */ - uint256 internal constant reserveFactorMaxMantissa = 1e18; - - /** - * @notice Administrator for this contract - */ - address payable public admin; - - /** - * @notice Pending administrator for this contract - */ - address payable public pendingAdmin; - - /** - * @notice Contract which oversees inter-cToken operations - */ - ComptrollerInterface public comptroller; - - /** - * @notice Model which tells what the current interest rate should be - */ - InterestRateModel public interestRateModel; - - /** - * @notice Initial exchange rate used when minting the first CTokens (used when totalSupply = 0) - */ - uint256 public initialExchangeRateMantissa; - - /** - * @notice Fraction of interest currently set aside for reserves - */ - uint256 public reserveFactorMantissa; - - /** - * @notice Block number that interest was last accrued at - */ - uint256 public accrualBlockNumber; - - /** - * @notice Accumulator of the total earned interest rate since the opening of the market - */ - uint256 public borrowIndex; - - /** - * @notice Total amount of outstanding borrows of the underlying in this market - */ - uint256 public totalBorrows; - - /** - * @notice Total amount of reserves of the underlying held in this market - */ - uint256 public totalReserves; - - /** - * @notice Total number of tokens in circulation - */ - uint256 public totalSupply; - - uint256 public subsidyFund; - - struct SupplySnapshot { - uint256 tokens; - uint256 underlyingAmount; - uint256 suppliedAt; - uint256 promisedSupplyRate; - } - - /** - * @notice Official record of token balances for each account - */ - mapping(address => SupplySnapshot) internal accountTokens; - - /** - * @notice Approved token transfer amounts on behalf of others - */ - mapping(address => mapping(address => uint256)) internal transferAllowances; - - /** - * @notice Container for borrow balance information - * @member principal Total balance (with accrued interest), after applying the most recent balance-changing action - * @member interestIndex Global borrowIndex as of the most recent balance-changing action - */ - struct BorrowSnapshot { - uint256 principal; - uint256 interestIndex; - } - - /** - * @notice Mapping of account addresses to outstanding borrow balances - */ - mapping(address => BorrowSnapshot) internal accountBorrows; -} - -abstract contract CTokenInterface is CTokenStorage { - /** - * @notice Indicator that this is a CToken contract (for inspection) - */ - bool public constant isCToken = true; - - /*** Market Events ***/ - - /** - * @notice Event emitted when interest is accrued - */ - event AccrueInterest( - uint256 cashPrior, - uint256 interestAccumulated, - uint256 borrowIndex, - uint256 totalBorrows - ); - - /** - * @notice Event emitted when tokens are minted - */ - event Mint(address indexed minter, uint256 mintAmount, uint256 mintTokens); - - /** - * @notice Event emitted when tokens are redeemed - */ - event Redeem( - address indexed redeemer, - uint256 redeemAmount, - uint256 redeemTokens - ); - - /** - * @notice Event emitted when underlying is borrowed - */ - event Borrow( - address indexed borrower, - uint256 borrowAmount, - uint256 accountBorrows, - uint256 totalBorrows - ); - - /** - * @notice Event emitted when a borrow is repaid - */ - event RepayBorrow( - address indexed payer, - address indexed borrower, - uint256 repayAmount, - uint256 accountBorrows, - uint256 totalBorrows - ); - - /** - * @notice Event emitted when a borrow is liquidated - */ - event LiquidateBorrow( - address indexed liquidator, - address indexed borrower, - uint256 repayAmount, - address indexed cTokenCollateral, - uint256 seizeTokens - ); - - /*** Admin Events ***/ - - /** - * @notice Event emitted when pendingAdmin is changed - */ - event NewPendingAdmin(address oldPendingAdmin, address newPendingAdmin); - - /** - * @notice Event emitted when pendingAdmin is accepted, which means admin is updated - */ - event NewAdmin(address oldAdmin, address newAdmin); - - /** - * @notice Event emitted when comptroller is changed - */ - event NewComptroller( - ComptrollerInterface oldComptroller, - ComptrollerInterface newComptroller - ); - - /** - * @notice Event emitted when interestRateModel is changed - */ - event NewMarketInterestRateModel( - InterestRateModel oldInterestRateModel, - InterestRateModel newInterestRateModel - ); - - /** - * @notice Event emitted when the reserve factor is changed - */ - event NewReserveFactor( - uint256 oldReserveFactorMantissa, - uint256 newReserveFactorMantissa - ); - - /** - * @notice Event emitted when the reserves are added - */ - event ReservesAdded( - address benefactor, - uint256 addAmount, - uint256 newTotalReserves - ); - - event SubsidyAdded( - address benefactor, - uint256 addAmount, - uint256 newSubsidyFund - ); - - /** - * @notice Event emitted when the reserves are reduced - */ - event ReservesReduced( - address admin, - uint256 reduceAmount, - uint256 newTotalReserves - ); - - /** - * @notice EIP20 Transfer event - */ - event Transfer(address indexed from, address indexed to, uint256 amount); - - /** - * @notice EIP20 Approval event - */ - event Approval( - address indexed owner, - address indexed spender, - uint256 amount - ); - - /** - * @notice Failure event - */ - event CTokenStorageFailure(uint256 error, uint256 info, uint256 detail); - - /*** User Interface ***/ - - function transfer(address dst, uint256 amount) - external - virtual - returns (bool); - - function transferFrom( - address src, - address dst, - uint256 amount - ) external virtual returns (bool); - - function approve(address spender, uint256 amount) - external - virtual - returns (bool); - - function allowance(address owner, address spender) - external - view - virtual - returns (uint256); - - function balanceOf(address owner) external view virtual returns (uint256); - - function balanceOfUnderlying(address owner) - external - virtual - returns (uint256); - - function getAccountSnapshot(address account) - external - view - virtual - returns ( - uint256, - uint256, - uint256, - uint256 - ); - - function borrowRatePerBlock() external view virtual returns (uint256); - - function supplyRatePerBlock() external view virtual returns (uint256); - - function totalBorrowsCurrent() external virtual returns (uint256); - - function borrowBalanceCurrent(address account) - external - virtual - returns (uint256); - - function borrowBalanceStored(address account) - public - view - virtual - returns (uint256); - - function exchangeRateCurrent() public virtual returns (uint256); - - function exchangeRateStored() public view virtual returns (uint256); - - function getCash() external view virtual returns (uint256); - - function accrueInterest() public virtual returns (uint256); - - function seize( - address liquidator, - address borrower, - uint256 seizeTokens - ) external virtual returns (uint256); - - /*** Admin Functions ***/ - - function _setPendingAdmin(address payable newPendingAdmin) - external - virtual - returns (uint256); - - function _acceptAdmin() external virtual returns (uint256); - - function _setComptroller(ComptrollerInterface newComptroller) - public - virtual - returns (uint256); - - function _setReserveFactor(uint256 newReserveFactorMantissa) - external - virtual - returns (uint256); - - function _reduceReserves(uint256 reduceAmount) - external - virtual - returns (uint256); - - function _setInterestRateModel(InterestRateModel newInterestRateModel) - public - virtual - returns (uint256); -} - -contract CErc20Storage { - /** - * @notice Underlying asset for this CToken - */ - address public underlying; -} - -abstract contract CErc20Interface is CErc20Storage { - /*** User Interface ***/ - - function mint(uint256 mintAmount) external virtual returns (uint256); - - function redeem(uint256 redeemAmount) - external - virtual - returns (uint256); - - function borrow(uint256 borrowAmount) external virtual returns (uint256); - - function repayBorrow(uint256 repayAmount) - external - virtual - returns (uint256); - - function liquidateBorrow( - address borrower, - uint256 repayAmount, - CTokenInterface cTokenCollateral - ) external virtual returns (uint256); - - function sweepToken(EIP20NonStandardInterface token) external virtual; - - /*** Admin Functions ***/ - - function _addReserves(uint256 addAmount) external virtual returns (uint256); -} - -contract CDelegationStorage { - /** - * @notice Implementation address for this contract - */ - address public implementation; -} - -abstract contract CDelegatorInterface is CDelegationStorage { - /** - * @notice Emitted when implementation is changed - */ - event NewImplementation( - address oldImplementation, - address newImplementation - ); - - /** - * @notice Called by the admin to update the implementation of the delegator - * @param implementation_ The address of the new implementation for delegation - * @param allowResign Flag to indicate whether to call _resignImplementation on the old implementation - * @param becomeImplementationData The encoded bytes data to be passed to _becomeImplementation - */ - function _setImplementation( - address implementation_, - bool allowResign, - bytes memory becomeImplementationData - ) public virtual; -} - -abstract contract CDelegateInterface is CDelegationStorage { - /** - * @notice Called by the delegator on a delegate to initialize it for duty - * @dev Should revert if any issues arise which make it unfit for delegation - * @param data The encoded bytes data for any initialization - */ - function _becomeImplementation(bytes memory data) public virtual; - - /** - * @notice Called by the delegator on a delegate to forfeit its responsibility - */ - function _resignImplementation() public virtual; -} - - -// Dependency file: contracts/ErrorReporter.sol - -// pragma solidity 0.8.6; - -contract ComptrollerErrorReporter { - enum Error { - NO_ERROR, - UNAUTHORIZED, - COMPTROLLER_MISMATCH, - INSUFFICIENT_SHORTFALL, - INSUFFICIENT_LIQUIDITY, - INVALID_CLOSE_FACTOR, - INVALID_COLLATERAL_FACTOR, - INVALID_LIQUIDATION_INCENTIVE, - MARKET_NOT_ENTERED, // no longer possible - MARKET_NOT_LISTED, - MARKET_ALREADY_LISTED, - MATH_ERROR, - NONZERO_BORROW_BALANCE, - PRICE_ERROR, - REJECTION, - SNAPSHOT_ERROR, - TOO_MANY_ASSETS, - TOO_MUCH_REPAY - } - - enum FailureInfo { - ACCEPT_ADMIN_PENDING_ADMIN_CHECK, - ACCEPT_PENDING_IMPLEMENTATION_ADDRESS_CHECK, - EXIT_MARKET_BALANCE_OWED, - EXIT_MARKET_REJECTION, - SET_CLOSE_FACTOR_OWNER_CHECK, - SET_CLOSE_FACTOR_VALIDATION, - SET_COLLATERAL_FACTOR_OWNER_CHECK, - SET_COLLATERAL_FACTOR_NO_EXISTS, - SET_COLLATERAL_FACTOR_VALIDATION, - SET_COLLATERAL_FACTOR_WITHOUT_PRICE, - SET_IMPLEMENTATION_OWNER_CHECK, - SET_LIQUIDATION_INCENTIVE_OWNER_CHECK, - SET_LIQUIDATION_INCENTIVE_VALIDATION, - SET_MAX_ASSETS_OWNER_CHECK, - SET_PENDING_ADMIN_OWNER_CHECK, - SET_PENDING_IMPLEMENTATION_OWNER_CHECK, - SET_PRICE_ORACLE_OWNER_CHECK, - SUPPORT_MARKET_EXISTS, - SUPPORT_MARKET_OWNER_CHECK, - SET_PAUSE_GUARDIAN_OWNER_CHECK - } - - /** - * @dev `error` corresponds to enum Error; `info` corresponds to enum FailureInfo, and `detail` is an arbitrary - * contract-specific code that enables us to report opaque error codes from upgradeable contracts. - **/ - event Failure(uint256 error, uint256 info, uint256 detail); - - /** - * @dev use this when reporting a known error from the money market or a non-upgradeable collaborator - */ - function fail(Error err, FailureInfo info) internal returns (uint256) { - emit Failure(uint256(err), uint256(info), 0); - - return uint256(err); - } - - /** - * @dev use this when reporting an opaque error from an upgradeable collaborator contract - */ - function failOpaque( - Error err, - FailureInfo info, - uint256 opaqueError - ) internal returns (uint256) { - emit Failure(uint256(err), uint256(info), opaqueError); - - return uint256(err); - } -} - -contract TokenErrorReporter { - enum Error { - NO_ERROR, - UNAUTHORIZED, - BAD_INPUT, - COMPTROLLER_REJECTION, - COMPTROLLER_CALCULATION_ERROR, - INTEREST_RATE_MODEL_ERROR, - INVALID_ACCOUNT_PAIR, - INVALID_CLOSE_AMOUNT_REQUESTED, - INVALID_COLLATERAL_FACTOR, - MATH_ERROR, - MARKET_NOT_FRESH, - MARKET_NOT_LISTED, - TOKEN_INSUFFICIENT_ALLOWANCE, - TOKEN_INSUFFICIENT_BALANCE, - TOKEN_INSUFFICIENT_CASH, - TOKEN_TRANSFER_IN_FAILED, - TOKEN_TRANSFER_OUT_FAILED - } - - /* - * Note: FailureInfo (but not Error) is kept in alphabetical order - * This is because FailureInfo grows significantly faster, and - * the order of Error has some meaning, while the order of FailureInfo - * is entirely arbitrary. - */ - enum FailureInfo { - ACCEPT_ADMIN_PENDING_ADMIN_CHECK, - ACCRUE_INTEREST_ACCUMULATED_INTEREST_CALCULATION_FAILED, - ACCRUE_INTEREST_BORROW_RATE_CALCULATION_FAILED, - ACCRUE_INTEREST_NEW_BORROW_INDEX_CALCULATION_FAILED, - ACCRUE_INTEREST_NEW_TOTAL_BORROWS_CALCULATION_FAILED, - ACCRUE_INTEREST_NEW_TOTAL_RESERVES_CALCULATION_FAILED, - ACCRUE_INTEREST_SIMPLE_INTEREST_FACTOR_CALCULATION_FAILED, - BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED, - BORROW_ACCRUE_INTEREST_FAILED, - BORROW_CASH_NOT_AVAILABLE, - BORROW_FRESHNESS_CHECK, - BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED, - BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED, - BORROW_MARKET_NOT_LISTED, - BORROW_COMPTROLLER_REJECTION, - LIQUIDATE_ACCRUE_BORROW_INTEREST_FAILED, - LIQUIDATE_ACCRUE_COLLATERAL_INTEREST_FAILED, - LIQUIDATE_COLLATERAL_FRESHNESS_CHECK, - LIQUIDATE_COMPTROLLER_REJECTION, - LIQUIDATE_COMPTROLLER_CALCULATE_AMOUNT_SEIZE_FAILED, - LIQUIDATE_CLOSE_AMOUNT_IS_UINT_MAX, - LIQUIDATE_CLOSE_AMOUNT_IS_ZERO, - LIQUIDATE_FRESHNESS_CHECK, - LIQUIDATE_LIQUIDATOR_IS_BORROWER, - LIQUIDATE_REPAY_BORROW_FRESH_FAILED, - LIQUIDATE_SEIZE_BALANCE_INCREMENT_FAILED, - LIQUIDATE_SEIZE_BALANCE_DECREMENT_FAILED, - LIQUIDATE_SEIZE_COMPTROLLER_REJECTION, - LIQUIDATE_SEIZE_LIQUIDATOR_IS_BORROWER, - LIQUIDATE_SEIZE_TOO_MUCH, - MINT_ACCRUE_INTEREST_FAILED, - MINT_COMPTROLLER_REJECTION, - MINT_EXCHANGE_CALCULATION_FAILED, - MINT_EXCHANGE_RATE_READ_FAILED, - MINT_FRESHNESS_CHECK, - MINT_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED, - MINT_NEW_TOTAL_SUPPLY_CALCULATION_FAILED, - MINT_TRANSFER_IN_FAILED, - MINT_TRANSFER_IN_NOT_POSSIBLE, - REDEEM_ACCRUE_INTEREST_FAILED, - REDEEM_COMPTROLLER_REJECTION, - REDEEM_EXCHANGE_TOKENS_CALCULATION_FAILED, - REDEEM_EXCHANGE_AMOUNT_CALCULATION_FAILED, - REDEEM_EXCHANGE_RATE_READ_FAILED, - REDEEM_FRESHNESS_CHECK, - REDEEM_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED, - REDEEM_NEW_TOTAL_SUPPLY_CALCULATION_FAILED, - REDEEM_TRANSFER_OUT_NOT_POSSIBLE, - REDUCE_RESERVES_ACCRUE_INTEREST_FAILED, - REDUCE_RESERVES_ADMIN_CHECK, - REDUCE_RESERVES_CASH_NOT_AVAILABLE, - REDUCE_RESERVES_FRESH_CHECK, - REDUCE_RESERVES_VALIDATION, - REPAY_BEHALF_ACCRUE_INTEREST_FAILED, - REPAY_BORROW_ACCRUE_INTEREST_FAILED, - REPAY_BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED, - REPAY_BORROW_COMPTROLLER_REJECTION, - REPAY_BORROW_FRESHNESS_CHECK, - REPAY_BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED, - REPAY_BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED, - REPAY_BORROW_TRANSFER_IN_NOT_POSSIBLE, - SET_COLLATERAL_FACTOR_OWNER_CHECK, - SET_COLLATERAL_FACTOR_VALIDATION, - SET_COMPTROLLER_OWNER_CHECK, - SET_INTEREST_RATE_MODEL_ACCRUE_INTEREST_FAILED, - SET_INTEREST_RATE_MODEL_FRESH_CHECK, - SET_INTEREST_RATE_MODEL_OWNER_CHECK, - SET_MAX_ASSETS_OWNER_CHECK, - SET_ORACLE_MARKET_NOT_LISTED, - SET_PENDING_ADMIN_OWNER_CHECK, - SET_RESERVE_FACTOR_ACCRUE_INTEREST_FAILED, - SET_RESERVE_FACTOR_ADMIN_CHECK, - SET_RESERVE_FACTOR_FRESH_CHECK, - SET_RESERVE_FACTOR_BOUNDS_CHECK, - TRANSFER_COMPTROLLER_REJECTION, - TRANSFER_NOT_ALLOWED, - TRANSFER_NOT_ENOUGH, - TRANSFER_TOO_MUCH, - ADD_RESERVES_ACCRUE_INTEREST_FAILED, - ADD_RESERVES_FRESH_CHECK, - ADD_RESERVES_TRANSFER_IN_NOT_POSSIBLE, - ADD_SUBSIDY_FUND_FAILED, - ADD_SUBSIDY_FUND_FRESH_CHECK - } - - /** - * @dev `error` corresponds to enum Error; `info` corresponds to enum FailureInfo, and `detail` is an arbitrary - * contract-specific code that enables us to report opaque error codes from upgradeable contracts. - **/ - event TokenFailure(uint256 error, uint256 info, uint256 detail); - - /** - * @dev use this when reporting a known error from the money market or a non-upgradeable collaborator - */ - function fail(Error err, FailureInfo info) internal returns (uint256) { - emit TokenFailure(uint256(err), uint256(info), 0); - - return uint256(err); - } - - /** - * @dev use this when reporting an opaque error from an upgradeable collaborator contract - */ - function failOpaque( - Error err, - FailureInfo info, - uint256 opaqueError - ) internal returns (uint256) { - emit TokenFailure(uint256(err), uint256(info), opaqueError); - - return uint256(err); - } -} - - -// Dependency file: contracts/EIP20Interface.sol - -// pragma solidity 0.8.6; - -/** - * @title ERC 20 Token Standard Interface - * https://eips.ethereum.org/EIPS/eip-20 - */ -interface EIP20Interface { - function name() external view returns (string memory); - - function symbol() external view returns (string memory); - - function decimals() external view returns (uint8); - - /** - * @notice Get the total number of tokens in circulation - * @return The supply of tokens - */ - function totalSupply() external view returns (uint256); - - /** - * @notice Gets the balance of the specified address - * @param owner The address from which the balance will be retrieved - * @return balance The balance - */ - function balanceOf(address owner) external view returns (uint256 balance); - - /** - * @notice Transfer `amount` tokens from `msg.sender` to `dst` - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - * @return success Whether or not the transfer succeeded - */ - function transfer(address dst, uint256 amount) - external - returns (bool success); - - /** - * @notice Transfer `amount` tokens from `src` to `dst` - * @param src The address of the source account - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - * @return success Whether or not the transfer succeeded - */ - function transferFrom( - address src, - address dst, - uint256 amount - ) external returns (bool success); - - /** - * @notice Approve `spender` to transfer up to `amount` from `src` - * @dev This will overwrite the approval amount for `spender` - * and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve) - * @param spender The address of the account which may transfer tokens - * @param amount The number of tokens that are approved (-1 means infinite) - * @return success Whether or not the approval succeeded - */ - function approve(address spender, uint256 amount) - external - returns (bool success); - - /** - * @notice Get the current allowance from `owner` for `spender` - * @param owner The address of the account which owns the tokens to be spent - * @param spender The address of the account which may transfer tokens - * @return remaining The number of tokens allowed to be spent (-1 means infinite) - */ - function allowance(address owner, address spender) - external - view - returns (uint256 remaining); - - event Transfer(address indexed from, address indexed to, uint256 amount); - event Approval( - address indexed owner, - address indexed spender, - uint256 amount - ); -} - - -// Dependency file: contracts/WhitelistInterface.sol - -// pragma solidity 0.8.6; - -interface WhitelistInterface { - function setStatus(bool _newStatus) external; - function enabled() external view returns(bool); - - function addUsers(address[] memory _users) external; - function exist(address _user) external view returns(bool); - function getUsers() external view returns(address[] memory currentUsers); - function removeUser(address _user) external; -} - -// Dependency file: contracts/CToken.sol - -// pragma solidity 0.8.6; - -// import "contracts/ComptrollerInterface.sol"; -// import "contracts/CTokenInterfaces.sol"; -// import "contracts/ErrorReporter.sol"; -// import "contracts/Exponential.sol"; -// import "contracts/EIP20Interface.sol"; -// import "contracts/InterestRateModel.sol"; -// import "contracts/WhitelistInterface.sol"; - -/** - * @title tropykus CToken Contract - * @notice Abstract base for CTokens - * @author tropykus - */ -abstract contract CToken is CTokenInterface, Exponential, TokenErrorReporter { - address whitelist; - - /** - * @notice Initialize the money market - * @param comptroller_ The address of the Comptroller - * @param interestRateModel_ The address of the interest rate model - * @param initialExchangeRateMantissa_ The initial exchange rate, scaled by 1e18 - * @param name_ EIP-20 name of this token - * @param symbol_ EIP-20 symbol of this token - * @param decimals_ EIP-20 decimal precision of this token - */ - function initialize( - ComptrollerInterface comptroller_, - InterestRateModel interestRateModel_, - uint256 initialExchangeRateMantissa_, - string memory name_, - string memory symbol_, - uint8 decimals_ - ) public { - require(msg.sender == admin, "CT01"); - require(accrualBlockNumber == 0 && borrowIndex == 0, "CT02"); - - initialExchangeRateMantissa = initialExchangeRateMantissa_; - require(initialExchangeRateMantissa > 0, "CT03"); - - uint256 err = _setComptroller(comptroller_); - require(err == uint256(Error.NO_ERROR), "CT04"); - - accrualBlockNumber = getBlockNumber(); - borrowIndex = mantissaOne; - - err = _setInterestRateModelFresh(interestRateModel_); - require(err == uint256(Error.NO_ERROR), "CT05"); - - name = name_; - symbol = symbol_; - decimals = decimals_; - - _notEntered = true; - } - - function addWhitelist(address _whitelist) external returns (uint256) { - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_INTEREST_RATE_MODEL_OWNER_CHECK - ); - } - whitelist = _whitelist; - } - - /** - * @notice Transfer `tokens` tokens from `src` to `dst` by `spender` - * @dev Called by both `transfer` and `transferFrom` internally - * @param spender The address of the account performing the transfer - * @param src The address of the source account - * @param dst The address of the destination account - * @param tokens The number of tokens to transfer - * @return Whether or not the transfer succeeded - */ - function transferTokens( - address spender, - address src, - address dst, - uint256 tokens - ) internal returns (uint256) { - uint256 allowed = comptroller.transferAllowed( - address(this), - src, - dst, - tokens - ); - if (allowed != 0) { - return - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.TRANSFER_COMPTROLLER_REJECTION, - allowed - ); - } - - if (src == dst) { - return fail(Error.BAD_INPUT, FailureInfo.TRANSFER_NOT_ALLOWED); - } - - uint256 startingAllowance = 0; - if (spender == src) { - startingAllowance = type(uint256).max; - } else { - startingAllowance = transferAllowances[src][spender]; - } - - MathError mathErr; - uint256 allowanceNew; - uint256 srcTokensNew; - uint256 dstTokensNew; - - (mathErr, allowanceNew) = subUInt(startingAllowance, tokens); - if (mathErr != MathError.NO_ERROR) { - return fail(Error.MATH_ERROR, FailureInfo.TRANSFER_NOT_ALLOWED); - } - - (mathErr, srcTokensNew) = subUInt(accountTokens[src].tokens, tokens); - if (mathErr != MathError.NO_ERROR) { - return fail(Error.MATH_ERROR, FailureInfo.TRANSFER_NOT_ENOUGH); - } - - (mathErr, dstTokensNew) = addUInt(accountTokens[dst].tokens, tokens); - if (mathErr != MathError.NO_ERROR) { - return fail(Error.MATH_ERROR, FailureInfo.TRANSFER_TOO_MUCH); - } - - accountTokens[src].tokens = srcTokensNew; - accountTokens[dst].tokens = dstTokensNew; - - if (startingAllowance != type(uint256).max) { - transferAllowances[src][spender] = allowanceNew; - } - - emit Transfer(src, dst, tokens); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Transfer `amount` tokens from `msg.sender` to `dst` - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - * @return Whether or not the transfer succeeded - */ - function transfer(address dst, uint256 amount) - external - override - nonReentrant - returns (bool) - { - return - transferTokens(msg.sender, msg.sender, dst, amount) == - uint256(Error.NO_ERROR); - } - - /** - * @notice Transfer `amount` tokens from `src` to `dst` - * @param src The address of the source account - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - * @return Whether or not the transfer succeeded - */ - function transferFrom( - address src, - address dst, - uint256 amount - ) external override nonReentrant returns (bool) { - return - transferTokens(msg.sender, src, dst, amount) == - uint256(Error.NO_ERROR); - } - - /** - * @notice Approve `spender` to transfer up to `amount` from `src` - * @dev This will overwrite the approval amount for `spender` - * and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve) - * @param spender The address of the account which may transfer tokens - * @param amount The number of tokens that are approved (-1 means infinite) - * @return Whether or not the approval succeeded - */ - function approve(address spender, uint256 amount) - external - override - returns (bool) - { - transferAllowances[msg.sender][spender] = amount; - emit Approval(msg.sender, spender, amount); - return true; - } - - /** - * @notice Get the current allowance from `owner` for `spender` - * @param owner The address of the account which owns the tokens to be spent - * @param spender The address of the account which may transfer tokens - * @return The number of tokens allowed to be spent (-1 means infinite) - */ - function allowance(address owner, address spender) - external - view - override - returns (uint256) - { - return transferAllowances[owner][spender]; - } - - /** - * @notice Get the token balance of the `owner` - * @param owner The address of the account to query - * @return The number of tokens owned by `owner` - */ - function balanceOf(address owner) external view override returns (uint256) { - return accountTokens[owner].tokens; - } - - /** - * @notice Get the underlying balance of the `owner` - * @dev This also accrues interest in a transaction - * @param owner The address of the account to query - * @return The amount of underlying owned by `owner` - */ - function balanceOfUnderlying(address owner) - external - override - returns (uint256) - { - (MathError mErr, uint256 balance) = mulScalarTruncate( - Exp({mantissa: exchangeRateCurrent()}), - accountTokens[owner].tokens - ); - require(mErr == MathError.NO_ERROR, "CT06"); - return balance; - } - - /** - * @notice Get a snapshot of the account's balances, and the cached exchange rate - * @dev This is used by comptroller to more efficiently perform liquidity checks. - * @param account Address of the account to snapshot - * @return (possible error, token balance, borrow balance, exchange rate mantissa) - */ - function getAccountSnapshot(address account) - external - view - override - returns ( - uint256, - uint256, - uint256, - uint256 - ) - { - uint256 cTokenBalance = accountTokens[account].tokens; - uint256 borrowBalance; - uint256 exchangeRateMantissa; - - MathError mErr; - - (mErr, borrowBalance) = borrowBalanceStoredInternal(account); - if (mErr != MathError.NO_ERROR) { - return (uint256(Error.MATH_ERROR), 0, 0, 0); - } - - (mErr, exchangeRateMantissa) = exchangeRateStoredInternal(); - if (mErr != MathError.NO_ERROR) { - return (uint256(Error.MATH_ERROR), 0, 0, 0); - } - - return ( - uint256(Error.NO_ERROR), - cTokenBalance, - borrowBalance, - exchangeRateMantissa - ); - } - - /** - * @dev Function to simply retrieve block number - * This exists mainly for inheriting test contracts to stub this result. - */ - function getBlockNumber() internal view virtual returns (uint256) { - return block.number; - } - - /** - * @notice Returns the current per-block borrow interest rate for this cToken - * @return The borrow interest rate per block, scaled by 1e18 - */ - function borrowRatePerBlock() external view override returns (uint256) { - return - interestRateModel.getBorrowRate( - getCashPrior(), - totalBorrows, - totalReserves - ); - } - - /** - * @notice Returns the current per-block supply interest rate for this cToken - * @return The supply interest rate per block, scaled by 1e18 - */ - function supplyRatePerBlock() external view override returns (uint256) { - return - interestRateModel.getSupplyRate( - getCashPrior(), - totalBorrows, - totalReserves, - reserveFactorMantissa - ); - } - - /** - * @notice Returns the current total borrows plus accrued interest - * @return The total borrows with interest - */ - function totalBorrowsCurrent() - external - override - nonReentrant - returns (uint256) - { - require(accrueInterest() == uint256(Error.NO_ERROR), "CT07"); - return totalBorrows; - } - - /** - * @notice Accrue interest to updated borrowIndex and then calculate account's borrow balance using the updated borrowIndex - * @param account The address whose balance should be calculated after updating borrowIndex - * @return The calculated balance - */ - function borrowBalanceCurrent(address account) - external - override - nonReentrant - returns (uint256) - { - require(accrueInterest() == uint256(Error.NO_ERROR), "CT07"); - return borrowBalanceStored(account); - } - - /** - * @notice Return the borrow balance of account based on stored data - * @param account The address whose balance should be calculated - * @return The calculated balance - */ - function borrowBalanceStored(address account) - public - view - override - returns (uint256) - { - (MathError err, uint256 result) = borrowBalanceStoredInternal(account); - require(err == MathError.NO_ERROR, "CT08"); - return result; - } - - /** - * @notice Return the borrow balance of account based on stored data - * @param account The address whose balance should be calculated - * @return (error code, the calculated balance or 0 if error code is non-zero) - */ - function borrowBalanceStoredInternal(address account) - internal - view - returns (MathError, uint256) - { - MathError mathErr; - uint256 principalTimesIndex; - uint256 result; - - BorrowSnapshot storage borrowSnapshot = accountBorrows[account]; - - if (borrowSnapshot.principal == 0) { - return (MathError.NO_ERROR, 0); - } - - (mathErr, principalTimesIndex) = mulUInt( - borrowSnapshot.principal, - borrowIndex - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - - (mathErr, result) = divUInt( - principalTimesIndex, - borrowSnapshot.interestIndex - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - - return (MathError.NO_ERROR, result); - } - - function getBorrowerPrincipalStored(address account) - public - view - returns (uint256 borrowed) - { - borrowed = accountBorrows[account].principal; - } - - function getSupplierSnapshotStored(address account) - public - view - returns ( - uint256 tokens, - uint256 underlyingAmount, - uint256 suppliedAt, - uint256 promisedSupplyRate - ) - { - tokens = accountTokens[account].tokens; - underlyingAmount = accountTokens[account].underlyingAmount; - suppliedAt = accountTokens[account].suppliedAt; - promisedSupplyRate = accountTokens[account].promisedSupplyRate; - } - - /** - * @notice Accrue interest then return the up-to-date exchange rate - * @return Calculated exchange rate scaled by 1e18 - */ - function exchangeRateCurrent() - public - override - nonReentrant - returns (uint256) - { - require(accrueInterest() == uint256(Error.NO_ERROR), "CT07"); - return exchangeRateStored(); - } - - /** - * @notice Calculates the exchange rate from the underlying to the CToken - * @dev This function does not accrue interest before calculating the exchange rate - * @return Calculated exchange rate scaled by 1e18 - */ - function exchangeRateStored() public view override returns (uint256) { - (MathError err, uint256 result) = exchangeRateStoredInternal(); - require(err == MathError.NO_ERROR, "CT09"); - return result; - } - - /** - * @notice Calculates the exchange rate from the underlying to the CToken - * @dev This function does not accrue interest before calculating the exchange rate - * @return (error code, calculated exchange rate scaled by 1e18) - */ - function exchangeRateStoredInternal() - internal - view - virtual - returns (MathError, uint256) - { - uint256 _totalSupply = totalSupply; - if (_totalSupply == 0) { - return (MathError.NO_ERROR, initialExchangeRateMantissa); - } else { - MathError error; - uint256 exchangeRate; - uint256 totalCash = getCashPrior(); - if (interestRateModel.isTropykusInterestRateModel()) { - (error, exchangeRate) = tropykusExchangeRateStoredInternal( - msg.sender - ); - if (error == MathError.NO_ERROR) { - return (MathError.NO_ERROR, exchangeRate); - } else { - return (MathError.NO_ERROR, initialExchangeRateMantissa); - } - } - return - interestRateModel.getExchangeRate( - totalCash, - totalBorrows, - totalReserves, - totalSupply - ); - } - } - - function tropykusExchangeRateStoredInternal(address redeemer) - internal - view - returns (MathError, uint256) - { - if (totalSupply == 0) { - return (MathError.NO_ERROR, initialExchangeRateMantissa); - } else { - SupplySnapshot storage supplySnapshot = accountTokens[redeemer]; - if (supplySnapshot.suppliedAt == 0) { - return (MathError.DIVISION_BY_ZERO, 0); - } - (, uint256 interestFactorMantissa, ) = tropykusInterestAccrued( - redeemer - ); - Exp memory interestFactor = Exp({mantissa: interestFactorMantissa}); - uint256 currentUnderlying = supplySnapshot.underlyingAmount; - Exp memory redeemerUnderlying = Exp({mantissa: currentUnderlying}); - (, Exp memory realAmount) = mulExp( - interestFactor, - redeemerUnderlying - ); - (, Exp memory exchangeRate) = getExp( - realAmount.mantissa, - supplySnapshot.tokens - ); - return (MathError.NO_ERROR, exchangeRate.mantissa); - } - } - - function tropykusInterestAccrued(address account) - internal - view - returns ( - MathError, - uint256, - uint256 - ) - { - SupplySnapshot storage supplySnapshot = accountTokens[account]; - uint256 promisedSupplyRate = supplySnapshot.promisedSupplyRate; - Exp memory expectedSupplyRatePerBlock = Exp({ - mantissa: promisedSupplyRate - }); - (, uint256 delta) = subUInt( - accrualBlockNumber, - supplySnapshot.suppliedAt - ); - (, Exp memory expectedSupplyRatePerBlockWithDelta) = mulScalar( - expectedSupplyRatePerBlock, - delta - ); - (, Exp memory interestFactor) = addExp( - Exp({mantissa: 1e18}), - expectedSupplyRatePerBlockWithDelta - ); - uint256 currentUnderlying = supplySnapshot.underlyingAmount; - Exp memory redeemerUnderlying = Exp({mantissa: currentUnderlying}); - (, Exp memory realAmount) = mulExp(interestFactor, redeemerUnderlying); - (, uint256 interestEarned) = subUInt( - realAmount.mantissa, - currentUnderlying - ); - return (MathError.NO_ERROR, interestFactor.mantissa, interestEarned); - } - - /** - * @notice Get cash balance of this cToken in the underlying asset - * @return The quantity of underlying asset owned by this contract - */ - function getCash() external view override returns (uint256) { - return getCashPrior(); - } - - /** - * @notice Applies accrued interest to total borrows and reserves - * @dev This calculates interest accrued from the last checkpointed block - * up to the current block and writes new checkpoint to storage. - */ - function accrueInterest() public override returns (uint256) { - uint256 currentBlockNumber = getBlockNumber(); - uint256 accrualBlockNumberPrior = accrualBlockNumber; - - if (accrualBlockNumberPrior == currentBlockNumber) { - return uint256(Error.NO_ERROR); - } - - uint256 cashPrior = getCashPrior(); - uint256 borrowsPrior = totalBorrows; - uint256 reservesPrior = totalReserves; - uint256 borrowIndexPrior = borrowIndex; - - uint256 borrowRateMantissa = interestRateModel.getBorrowRate( - cashPrior, - borrowsPrior, - reservesPrior - ); - require(borrowRateMantissa <= borrowRateMaxMantissa, "CT10"); - - (MathError mathErr, uint256 blockDelta) = subUInt( - currentBlockNumber, - accrualBlockNumberPrior - ); - require(mathErr == MathError.NO_ERROR, "CT11"); - - Exp memory simpleInterestFactor; - uint256 interestAccumulated; - uint256 totalBorrowsNew; - uint256 totalReservesNew; - uint256 borrowIndexNew; - - (mathErr, simpleInterestFactor) = mulScalar( - Exp({mantissa: borrowRateMantissa}), - blockDelta - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .ACCRUE_INTEREST_SIMPLE_INTEREST_FACTOR_CALCULATION_FAILED, - uint256(mathErr) - ); - } - - (mathErr, interestAccumulated) = mulScalarTruncate( - simpleInterestFactor, - borrowsPrior - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .ACCRUE_INTEREST_ACCUMULATED_INTEREST_CALCULATION_FAILED, - uint256(mathErr) - ); - } - - (mathErr, totalBorrowsNew) = addUInt(interestAccumulated, borrowsPrior); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .ACCRUE_INTEREST_NEW_TOTAL_BORROWS_CALCULATION_FAILED, - uint256(mathErr) - ); - } - - (mathErr, totalReservesNew) = mulScalarTruncateAddUInt( - Exp({mantissa: reserveFactorMantissa}), - interestAccumulated, - reservesPrior - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .ACCRUE_INTEREST_NEW_TOTAL_RESERVES_CALCULATION_FAILED, - uint256(mathErr) - ); - } - - if (interestRateModel.isTropykusInterestRateModel()) { - (mathErr, totalReservesNew) = newReserves( - borrowRateMantissa, - cashPrior, - borrowsPrior, - reservesPrior, - interestAccumulated - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .ACCRUE_INTEREST_NEW_TOTAL_RESERVES_CALCULATION_FAILED, - uint256(mathErr) - ); - } - } - - (mathErr, borrowIndexNew) = mulScalarTruncateAddUInt( - simpleInterestFactor, - borrowIndexPrior, - borrowIndexPrior - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .ACCRUE_INTEREST_NEW_BORROW_INDEX_CALCULATION_FAILED, - uint256(mathErr) - ); - } - - accrualBlockNumber = currentBlockNumber; - borrowIndex = borrowIndexNew; - totalBorrows = totalBorrowsNew; - totalReserves = totalReservesNew; - - emit AccrueInterest( - cashPrior, - interestAccumulated, - borrowIndexNew, - totalBorrowsNew - ); - - return uint256(Error.NO_ERROR); - } - - function newReserves( - uint256 borrowRateMantissa, - uint256 cashPrior, - uint256 borrowsPrior, - uint256 reservesPrior, - uint256 interestAccumulated - ) internal view returns (MathError mathErr, uint256 totalReservesNew) { - uint256 newReserveFactorMantissa; - uint256 utilizationRate = interestRateModel.utilizationRate( - cashPrior, - borrowsPrior, - reservesPrior - ); - uint256 expectedSupplyRate = interestRateModel.getSupplyRate( - cashPrior, - borrowsPrior, - reservesPrior, - reserveFactorMantissa - ); - if ( - interestRateModel.isAboveOptimal( - cashPrior, - borrowsPrior, - reservesPrior - ) - ) { - (mathErr, newReserveFactorMantissa) = mulScalarTruncate( - Exp({mantissa: utilizationRate}), - borrowRateMantissa - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - (mathErr, newReserveFactorMantissa) = subUInt( - newReserveFactorMantissa, - expectedSupplyRate - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - (mathErr, totalReservesNew) = mulScalarTruncateAddUInt( - Exp({mantissa: newReserveFactorMantissa}), - interestAccumulated, - reservesPrior - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - } else { - mathErr = MathError.NO_ERROR; - totalReservesNew = reservesPrior; - } - } - - /** - * @notice Sender supplies assets into the market and receives cTokens in exchange - * @dev Accrues interest whether or not the operation succeeds, unless reverted - * @param mintAmount The amount of the underlying asset to supply - * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual mint amount. - */ - function mintInternal(uint256 mintAmount) - internal - nonReentrant - returns (uint256, uint256) - { - if (WhitelistInterface(whitelist).enabled()) { - require(WhitelistInterface(whitelist).exist(msg.sender), "CT26"); - } - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return ( - fail(Error(error), FailureInfo.MINT_ACCRUE_INTEREST_FAILED), - 0 - ); - } - return mintFresh(msg.sender, mintAmount); - } - - struct MintLocalVars { - Error err; - MathError mathErr; - uint256 exchangeRateMantissa; - uint256 mintTokens; - uint256 totalSupplyNew; - uint256 accountTokensNew; - uint256 actualMintAmount; - } - - /** - * @notice User supplies assets into the market and receives cTokens in exchange - * @dev Assumes interest has already been accrued up to the current block - * @param minter The address of the account which is supplying the assets - * @param mintAmount The amount of the underlying asset to supply - * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual mint amount. - */ - function mintFresh(address minter, uint256 mintAmount) - internal - returns (uint256, uint256) - { - uint256 allowed = comptroller.mintAllowed( - address(this), - minter, - mintAmount - ); - if (allowed != 0) { - return ( - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.MINT_COMPTROLLER_REJECTION, - allowed - ), - 0 - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return ( - fail(Error.MARKET_NOT_FRESH, FailureInfo.MINT_FRESHNESS_CHECK), - 0 - ); - } - - MintLocalVars memory vars; - - ( - vars.mathErr, - vars.exchangeRateMantissa - ) = exchangeRateStoredInternal(); - if (vars.mathErr != MathError.NO_ERROR) { - return ( - failOpaque( - Error.MATH_ERROR, - FailureInfo.MINT_EXCHANGE_RATE_READ_FAILED, - uint256(vars.mathErr) - ), - 0 - ); - } - if (interestRateModel.isTropykusInterestRateModel()) { - SupplySnapshot storage supplySnapshot = accountTokens[minter]; - (, uint256 newTotalSupply) = addUInt( - supplySnapshot.underlyingAmount, - mintAmount - ); - require(newTotalSupply <= 0.1e18, "CT24"); - } - vars.actualMintAmount = doTransferIn(minter, mintAmount); - - (vars.mathErr, vars.mintTokens) = divScalarByExpTruncate( - vars.actualMintAmount, - Exp({mantissa: vars.exchangeRateMantissa}) - ); - require(vars.mathErr == MathError.NO_ERROR, "CT12"); - - (vars.mathErr, vars.totalSupplyNew) = addUInt( - totalSupply, - vars.mintTokens - ); - require(vars.mathErr == MathError.NO_ERROR, "CT13"); - - (vars.mathErr, vars.accountTokensNew) = addUInt( - accountTokens[minter].tokens, - vars.mintTokens - ); - require(vars.mathErr == MathError.NO_ERROR, "CT14"); - - uint256 currentSupplyRate = interestRateModel.getSupplyRate( - getCashPrior(), - totalBorrows, - totalReserves, - reserveFactorMantissa - ); - - bool isTropykusInterestRateModel = interestRateModel - .isTropykusInterestRateModel(); - - if (accountTokens[minter].tokens > 0) { - Exp memory updatedUnderlying; - if (isTropykusInterestRateModel) { - (, uint256 interestFactorMantissa, ) = tropykusInterestAccrued( - minter - ); - Exp memory interestFactor = Exp({ - mantissa: interestFactorMantissa - }); - uint256 currentUnderlyingAmount = accountTokens[minter] - .underlyingAmount; - MathError mErrorNewAmount; - (mErrorNewAmount, updatedUnderlying) = mulExp( - Exp({mantissa: currentUnderlyingAmount}), - interestFactor - ); - if (mErrorNewAmount != MathError.NO_ERROR) { - return ( - failOpaque( - Error.MATH_ERROR, - FailureInfo.MINT_EXCHANGE_CALCULATION_FAILED, - uint256(mErrorNewAmount) - ), - 0 - ); - } - } else { - uint256 currentTokens = accountTokens[minter].tokens; - MathError mErrorUpdatedUnderlying; - (mErrorUpdatedUnderlying, updatedUnderlying) = mulExp( - Exp({mantissa: currentTokens}), - Exp({mantissa: vars.exchangeRateMantissa}) - ); - if (mErrorUpdatedUnderlying != MathError.NO_ERROR) { - return ( - failOpaque( - Error.MATH_ERROR, - FailureInfo.MINT_EXCHANGE_CALCULATION_FAILED, - uint256(mErrorUpdatedUnderlying) - ), - 0 - ); - } - } - (, mintAmount) = addUInt(updatedUnderlying.mantissa, mintAmount); - } - - totalSupply = vars.totalSupplyNew; - accountTokens[minter] = SupplySnapshot({ - tokens: vars.accountTokensNew, - underlyingAmount: mintAmount, - suppliedAt: accrualBlockNumber, - promisedSupplyRate: currentSupplyRate - }); - - emit Mint(minter, vars.actualMintAmount, vars.mintTokens); - emit Transfer(address(this), minter, vars.mintTokens); - - return (uint256(Error.NO_ERROR), vars.actualMintAmount); - } - - /** - * @notice Sender redeems cTokens in exchange for a specified amount of underlying asset - * @dev Accrues interest whether or not the operation succeeds, unless reverted - * @param redeemAmount The amount of underlying to receive from redeeming cTokens - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function redeemUnderlyingInternal(uint256 redeemAmount) - internal - nonReentrant - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return - fail(Error(error), FailureInfo.REDEEM_ACCRUE_INTEREST_FAILED); - } - return redeemFresh(payable(msg.sender), redeemAmount); - } - - struct RedeemLocalVars { - Error err; - MathError mathErr; - uint256 exchangeRateMantissa; - uint256 redeemTokens; - uint256 redeemAmount; - uint256 totalSupplyNew; - uint256 accountTokensNew; - uint256 newSubsidyFund; - } - - /** - * @notice User redeems cTokens in exchange for the underlying asset - * @dev Assumes interest has already been accrued up to the current block - * @param redeemer The address of the account which is redeeming the tokens - * @param redeemAmountIn The number of underlying tokens to receive from redeeming cTokens - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function redeemFresh(address payable redeemer, uint256 redeemAmountIn) - internal - returns (uint256) - { - require(redeemAmountIn > 0, "CT15"); - - RedeemLocalVars memory vars; - - SupplySnapshot storage supplySnapshot = accountTokens[redeemer]; - - ( - vars.mathErr, - vars.exchangeRateMantissa - ) = exchangeRateStoredInternal(); - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.REDEEM_EXCHANGE_RATE_READ_FAILED, - uint256(vars.mathErr) - ); - } - - uint256 interestEarned; - uint256 subsidyFundPortion; - uint256 currentUnderlying; - - bool isTropykusInterestRateModel = interestRateModel - .isTropykusInterestRateModel(); - if (isTropykusInterestRateModel) { - currentUnderlying = supplySnapshot.underlyingAmount; - (, , interestEarned) = tropykusInterestAccrued(redeemer); - } - supplySnapshot.promisedSupplyRate = interestRateModel.getSupplyRate( - getCashPrior(), - totalBorrows, - totalReserves, - reserveFactorMantissa - ); - - if ( - isTropykusInterestRateModel && - !interestRateModel.isAboveOptimal( - getCashPrior(), - totalBorrows, - totalReserves - ) - ) { - uint256 borrowRate = interestRateModel.getBorrowRate( - getCashPrior(), - totalBorrows, - totalReserves - ); - - uint256 utilizationRate = interestRateModel.utilizationRate( - getCashPrior(), - totalBorrows, - totalReserves - ); - - (, uint256 estimatedEarning) = mulScalarTruncate( - Exp({mantissa: borrowRate}), - utilizationRate - ); - - (, subsidyFundPortion) = subUInt( - supplySnapshot.promisedSupplyRate, - estimatedEarning - ); - (, Exp memory subsidyFactor) = getExp( - subsidyFundPortion, - supplySnapshot.promisedSupplyRate - ); - (, subsidyFundPortion) = mulScalarTruncate( - subsidyFactor, - interestEarned - ); - } - - vars.redeemAmount = redeemAmountIn; - - if (isTropykusInterestRateModel) { - (, Exp memory num) = mulExp( - vars.redeemAmount, - supplySnapshot.tokens - ); - (, Exp memory realTokensWithdrawAmount) = getExp( - num.mantissa, - currentUnderlying - ); - vars.redeemTokens = realTokensWithdrawAmount.mantissa; - } else { - (vars.mathErr, vars.redeemTokens) = divScalarByExpTruncate( - redeemAmountIn, - Exp({mantissa: vars.exchangeRateMantissa}) - ); - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.REDEEM_EXCHANGE_AMOUNT_CALCULATION_FAILED, - uint256(vars.mathErr) - ); - } - } - // } - - uint256 allowed = comptroller.redeemAllowed( - address(this), - redeemer, - vars.redeemTokens - ); - if (allowed != 0) { - return - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.REDEEM_COMPTROLLER_REJECTION, - allowed - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.REDEEM_FRESHNESS_CHECK - ); - } - - (vars.mathErr, vars.totalSupplyNew) = subUInt( - totalSupply, - vars.redeemTokens - ); - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.REDEEM_NEW_TOTAL_SUPPLY_CALCULATION_FAILED, - uint256(vars.mathErr) - ); - } - - (, vars.newSubsidyFund) = subUInt(subsidyFund, subsidyFundPortion); - - (vars.mathErr, vars.accountTokensNew) = subUInt( - supplySnapshot.tokens, - vars.redeemTokens - ); - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.REDEEM_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED, - uint256(vars.mathErr) - ); - } - - uint256 cash = getCashPrior(); - if (isTropykusInterestRateModel) { - cash = address(this).balance; - } - - if (cash < vars.redeemAmount) { - return - fail( - Error.TOKEN_INSUFFICIENT_CASH, - FailureInfo.REDEEM_TRANSFER_OUT_NOT_POSSIBLE - ); - } - - doTransferOut(redeemer, vars.redeemAmount); - - totalSupply = vars.totalSupplyNew; - subsidyFund = vars.newSubsidyFund; - supplySnapshot.tokens = vars.accountTokensNew; - supplySnapshot.suppliedAt = accrualBlockNumber; - (, supplySnapshot.underlyingAmount) = subUInt( - supplySnapshot.underlyingAmount, - vars.redeemAmount - ); - - emit Transfer(redeemer, address(this), vars.redeemTokens); - emit Redeem(redeemer, vars.redeemAmount, vars.redeemTokens); - - comptroller.redeemVerify( - address(this), - redeemer, - vars.redeemAmount, - vars.redeemTokens - ); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Sender borrows assets from the protocol to their own address - * @param borrowAmount The amount of the underlying asset to borrow - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function borrowInternal(uint256 borrowAmount) - internal - nonReentrant - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return - fail(Error(error), FailureInfo.BORROW_ACCRUE_INTEREST_FAILED); - } - return borrowFresh(payable(msg.sender), borrowAmount); - } - - struct BorrowLocalVars { - MathError mathErr; - uint256 accountBorrows; - uint256 accountBorrowsNew; - uint256 totalBorrowsNew; - } - - /** - * @notice Users borrow assets from the protocol to their own address - * @param borrowAmount The amount of the underlying asset to borrow - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function borrowFresh(address payable borrower, uint256 borrowAmount) - internal - returns (uint256) - { - uint256 allowed = comptroller.borrowAllowed( - address(this), - borrower, - borrowAmount - ); - if (allowed != 0) { - return - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.BORROW_COMPTROLLER_REJECTION, - allowed - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.BORROW_FRESHNESS_CHECK - ); - } - - if (getCashPrior() < borrowAmount) { - return - fail( - Error.TOKEN_INSUFFICIENT_CASH, - FailureInfo.BORROW_CASH_NOT_AVAILABLE - ); - } - - BorrowLocalVars memory vars; - - (vars.mathErr, vars.accountBorrows) = borrowBalanceStoredInternal( - borrower - ); - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED, - uint256(vars.mathErr) - ); - } - - (vars.mathErr, vars.accountBorrowsNew) = addUInt( - vars.accountBorrows, - borrowAmount - ); - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED, - uint256(vars.mathErr) - ); - } - - (vars.mathErr, vars.totalBorrowsNew) = addUInt( - totalBorrows, - borrowAmount - ); - if (interestRateModel.isTropykusInterestRateModel()) { - require(vars.totalBorrowsNew <= 0.1e18, "CT25"); - } - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED, - uint256(vars.mathErr) - ); - } - - doTransferOut(borrower, borrowAmount); - - accountBorrows[borrower].principal = vars.accountBorrowsNew; - accountBorrows[borrower].interestIndex = borrowIndex; - totalBorrows = vars.totalBorrowsNew; - - emit Borrow( - borrower, - borrowAmount, - vars.accountBorrowsNew, - vars.totalBorrowsNew - ); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Sender repays their own borrow - * @param repayAmount The amount to repay - * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual repayment amount. - */ - function repayBorrowInternal(uint256 repayAmount) - internal - nonReentrant - returns (uint256, uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return ( - fail( - Error(error), - FailureInfo.REPAY_BORROW_ACCRUE_INTEREST_FAILED - ), - 0 - ); - } - return repayBorrowFresh(msg.sender, msg.sender, repayAmount); - } - - struct RepayBorrowLocalVars { - Error err; - MathError mathErr; - uint256 repayAmount; - uint256 borrowerIndex; - uint256 accountBorrows; - uint256 accountBorrowsNew; - uint256 totalBorrowsNew; - uint256 actualRepayAmount; - } - - /** - * @notice Borrows are repaid by another user (possibly the borrower). - * @param payer the account paying off the borrow - * @param borrower the account with the debt being payed off - * @param repayAmount the amount of undelrying tokens being returned - * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual repayment amount. - */ - function repayBorrowFresh( - address payer, - address borrower, - uint256 repayAmount - ) internal returns (uint256, uint256) { - uint256 allowed = comptroller.repayBorrowAllowed( - address(this), - payer, - borrower, - repayAmount - ); - if (allowed != 0) { - return ( - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.REPAY_BORROW_COMPTROLLER_REJECTION, - allowed - ), - 0 - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return ( - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.REPAY_BORROW_FRESHNESS_CHECK - ), - 0 - ); - } - - RepayBorrowLocalVars memory vars; - - vars.borrowerIndex = accountBorrows[borrower].interestIndex; - - (vars.mathErr, vars.accountBorrows) = borrowBalanceStoredInternal( - borrower - ); - if (vars.mathErr != MathError.NO_ERROR) { - return ( - failOpaque( - Error.MATH_ERROR, - FailureInfo - .REPAY_BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED, - uint256(vars.mathErr) - ), - 0 - ); - } - - if (repayAmount == type(uint256).max) { - vars.repayAmount = vars.accountBorrows; - } else { - vars.repayAmount = repayAmount; - } - - vars.actualRepayAmount = doTransferIn(payer, vars.repayAmount); - - (vars.mathErr, vars.accountBorrowsNew) = subUInt( - vars.accountBorrows, - vars.actualRepayAmount - ); - require(vars.mathErr == MathError.NO_ERROR, "CT16"); - - (vars.mathErr, vars.totalBorrowsNew) = subUInt( - totalBorrows, - vars.actualRepayAmount - ); - require(vars.mathErr == MathError.NO_ERROR, "CT17"); - - accountBorrows[borrower].principal = vars.accountBorrowsNew; - accountBorrows[borrower].interestIndex = borrowIndex; - totalBorrows = vars.totalBorrowsNew; - - emit RepayBorrow( - payer, - borrower, - vars.actualRepayAmount, - vars.accountBorrowsNew, - vars.totalBorrowsNew - ); - - return (uint256(Error.NO_ERROR), vars.actualRepayAmount); - } - - /** - * @notice The sender liquidates the borrowers collateral. - * The collateral seized is transferred to the liquidator. - * @param borrower The borrower of this cToken to be liquidated - * @param cTokenCollateral The market in which to seize collateral from the borrower - * @param repayAmount The amount of the underlying borrowed asset to repay - * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual repayment amount. - */ - function liquidateBorrowInternal( - address borrower, - uint256 repayAmount, - CTokenInterface cTokenCollateral - ) internal nonReentrant returns (uint256, uint256) { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return ( - fail( - Error(error), - FailureInfo.LIQUIDATE_ACCRUE_BORROW_INTEREST_FAILED - ), - 0 - ); - } - - error = cTokenCollateral.accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return ( - fail( - Error(error), - FailureInfo.LIQUIDATE_ACCRUE_COLLATERAL_INTEREST_FAILED - ), - 0 - ); - } - - // liquidateBorrowFresh emits borrow-specific logs on errors, so we don't need to - return - liquidateBorrowFresh( - msg.sender, - borrower, - repayAmount, - cTokenCollateral - ); - } - - /** - * @notice The liquidator liquidates the borrowers collateral. - * The collateral seized is transferred to the liquidator. - * @param borrower The borrower of this cToken to be liquidated - * @param liquidator The address repaying the borrow and seizing collateral - * @param cTokenCollateral The market in which to seize collateral from the borrower - * @param repayAmount The amount of the underlying borrowed asset to repay - * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual repayment amount. - */ - function liquidateBorrowFresh( - address liquidator, - address borrower, - uint256 repayAmount, - CTokenInterface cTokenCollateral - ) internal returns (uint256, uint256) { - uint256 allowed = comptroller.liquidateBorrowAllowed( - address(this), - address(cTokenCollateral), - liquidator, - borrower, - repayAmount - ); - if (allowed != 0) { - return ( - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.LIQUIDATE_COMPTROLLER_REJECTION, - allowed - ), - 0 - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return ( - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.LIQUIDATE_FRESHNESS_CHECK - ), - 0 - ); - } - - if (cTokenCollateral.accrualBlockNumber() != getBlockNumber()) { - return ( - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.LIQUIDATE_COLLATERAL_FRESHNESS_CHECK - ), - 0 - ); - } - - if (borrower == liquidator) { - return ( - fail( - Error.INVALID_ACCOUNT_PAIR, - FailureInfo.LIQUIDATE_LIQUIDATOR_IS_BORROWER - ), - 0 - ); - } - - if (repayAmount == 0) { - return ( - fail( - Error.INVALID_CLOSE_AMOUNT_REQUESTED, - FailureInfo.LIQUIDATE_CLOSE_AMOUNT_IS_ZERO - ), - 0 - ); - } - - if (repayAmount == type(uint256).max) { - return ( - fail( - Error.INVALID_CLOSE_AMOUNT_REQUESTED, - FailureInfo.LIQUIDATE_CLOSE_AMOUNT_IS_UINT_MAX - ), - 0 - ); - } - - ( - uint256 repayBorrowError, - uint256 actualRepayAmount - ) = repayBorrowFresh(liquidator, borrower, repayAmount); - if (repayBorrowError != uint256(Error.NO_ERROR)) { - return ( - fail( - Error(repayBorrowError), - FailureInfo.LIQUIDATE_REPAY_BORROW_FRESH_FAILED - ), - 0 - ); - } - - (uint256 amountSeizeError, uint256 seizeTokens) = comptroller - .liquidateCalculateSeizeTokens( - address(this), - address(cTokenCollateral), - actualRepayAmount - ); - require(amountSeizeError == uint256(Error.NO_ERROR), "CT18"); - - require(cTokenCollateral.balanceOf(borrower) >= seizeTokens, "CT19"); - - uint256 seizeError; - if (address(cTokenCollateral) == address(this)) { - seizeError = seizeInternal( - address(this), - liquidator, - borrower, - seizeTokens - ); - } else { - seizeError = cTokenCollateral.seize( - liquidator, - borrower, - seizeTokens - ); - } - - require(seizeError == uint256(Error.NO_ERROR), "CT20"); - - emit LiquidateBorrow( - liquidator, - borrower, - actualRepayAmount, - address(cTokenCollateral), - seizeTokens - ); - - return (uint256(Error.NO_ERROR), actualRepayAmount); - } - - /** - * @notice Transfers collateral tokens (this market) to the liquidator. - * @dev Will fail unless called by another cToken during the process of liquidation. - * Its absolutely critical to use msg.sender as the borrowed cToken and not a parameter. - * @param liquidator The account receiving seized collateral - * @param borrower The account having collateral seized - * @param seizeTokens The number of cTokens to seize - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function seize( - address liquidator, - address borrower, - uint256 seizeTokens - ) external override nonReentrant returns (uint256) { - return seizeInternal(msg.sender, liquidator, borrower, seizeTokens); - } - - struct SeizeVars { - uint256 seizeAmount; - uint256 exchangeRate; - uint256 borrowerTokensNew; - uint256 borrowerAmountNew; - uint256 liquidatorTokensNew; - uint256 liquidatorAmountNew; - uint256 totalCash; - uint256 supplyRate; - } - - /** - * @notice Transfers collateral tokens (this market) to the liquidator. - * @dev Called only during an in-kind liquidation, or by liquidateBorrow during the liquidation of another CToken. - * Its absolutely critical to use msg.sender as the seizer cToken and not a parameter. - * @param seizerToken The contract seizing the collateral (i.e. borrowed cToken) - * @param liquidator The account receiving seized collateral - * @param borrower The account having collateral seized - * @param seizeTokens The number of cTokens to seize - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function seizeInternal( - address seizerToken, - address liquidator, - address borrower, - uint256 seizeTokens - ) internal returns (uint256) { - uint256 allowed = comptroller.seizeAllowed( - address(this), - seizerToken, - liquidator, - borrower, - seizeTokens - ); - if (allowed != 0) { - return - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.LIQUIDATE_SEIZE_COMPTROLLER_REJECTION, - allowed - ); - } - - if (borrower == liquidator) { - return - fail( - Error.INVALID_ACCOUNT_PAIR, - FailureInfo.LIQUIDATE_SEIZE_LIQUIDATOR_IS_BORROWER - ); - } - - SeizeVars memory seizeVars; - - MathError mathErr; - - (mathErr, seizeVars.borrowerTokensNew) = subUInt( - accountTokens[borrower].tokens, - seizeTokens - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.LIQUIDATE_SEIZE_BALANCE_DECREMENT_FAILED, - uint256(mathErr) - ); - } - - seizeVars.totalCash = getCashPrior(); - seizeVars.supplyRate = interestRateModel.getSupplyRate( - seizeVars.totalCash, - totalBorrows, - totalReserves, - reserveFactorMantissa - ); - - (, seizeVars.exchangeRate) = interestRateModel.getExchangeRate( - seizeVars.totalCash, - totalBorrows, - totalReserves, - totalSupply - ); - - if (interestRateModel.isTropykusInterestRateModel()) { - (, seizeVars.exchangeRate) = tropykusExchangeRateStoredInternal( - borrower - ); - } - - (, seizeVars.seizeAmount) = mulUInt( - seizeTokens, - seizeVars.exchangeRate - ); - (, seizeVars.seizeAmount) = divUInt(seizeVars.seizeAmount, 1e18); - - (, seizeVars.borrowerAmountNew) = subUInt( - accountTokens[borrower].underlyingAmount, - seizeVars.seizeAmount - ); - - (mathErr, seizeVars.liquidatorTokensNew) = addUInt( - accountTokens[liquidator].tokens, - seizeTokens - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.LIQUIDATE_SEIZE_BALANCE_INCREMENT_FAILED, - uint256(mathErr) - ); - } - - (, seizeVars.liquidatorAmountNew) = addUInt( - accountTokens[liquidator].underlyingAmount, - seizeVars.seizeAmount - ); - - accountTokens[borrower].tokens = seizeVars.borrowerTokensNew; - accountTokens[borrower].underlyingAmount = seizeVars.borrowerAmountNew; - accountTokens[borrower].suppliedAt = getBlockNumber(); - accountTokens[borrower].promisedSupplyRate = seizeVars.supplyRate; - - accountTokens[liquidator].tokens = seizeVars.liquidatorTokensNew; - accountTokens[liquidator].underlyingAmount = seizeVars - .liquidatorAmountNew; - accountTokens[liquidator].suppliedAt = getBlockNumber(); - accountTokens[liquidator].promisedSupplyRate = seizeVars.supplyRate; - - emit Transfer(borrower, liquidator, seizeTokens); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Begins transfer of admin rights. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer. - * @dev Admin function to begin change of admin. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer. - * @param newPendingAdmin New pending admin. - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setPendingAdmin(address payable newPendingAdmin) - external - override - returns (uint256) - { - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_PENDING_ADMIN_OWNER_CHECK - ); - } - - address oldPendingAdmin = pendingAdmin; - - pendingAdmin = newPendingAdmin; - - emit NewPendingAdmin(oldPendingAdmin, newPendingAdmin); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Accepts transfer of admin rights. msg.sender must be pendingAdmin - * @dev Admin function for pending admin to accept role and update admin - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _acceptAdmin() external override returns (uint256) { - if (msg.sender != pendingAdmin || msg.sender == address(0)) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.ACCEPT_ADMIN_PENDING_ADMIN_CHECK - ); - } - - address oldAdmin = admin; - address oldPendingAdmin = pendingAdmin; - - admin = pendingAdmin; - - pendingAdmin = payable(address(0)); - - emit NewAdmin(oldAdmin, admin); - emit NewPendingAdmin(oldPendingAdmin, pendingAdmin); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Sets a new comptroller for the market - * @dev Admin function to set a new comptroller - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setComptroller(ComptrollerInterface newComptroller) - public - override - returns (uint256) - { - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_COMPTROLLER_OWNER_CHECK - ); - } - - ComptrollerInterface oldComptroller = comptroller; - require(newComptroller.isComptroller(), "CT21"); - - comptroller = newComptroller; - - emit NewComptroller(oldComptroller, newComptroller); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice accrues interest and sets a new reserve factor for the protocol using _setReserveFactorFresh - * @dev Admin function to accrue interest and set a new reserve factor - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setReserveFactor(uint256 newReserveFactorMantissa) - external - override - nonReentrant - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return - fail( - Error(error), - FailureInfo.SET_RESERVE_FACTOR_ACCRUE_INTEREST_FAILED - ); - } - return _setReserveFactorFresh(newReserveFactorMantissa); - } - - /** - * @notice Sets a new reserve factor for the protocol (*requires fresh interest accrual) - * @dev Admin function to set a new reserve factor - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setReserveFactorFresh(uint256 newReserveFactorMantissa) - internal - returns (uint256) - { - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_RESERVE_FACTOR_ADMIN_CHECK - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.SET_RESERVE_FACTOR_FRESH_CHECK - ); - } - - if (newReserveFactorMantissa > reserveFactorMaxMantissa) { - return - fail( - Error.BAD_INPUT, - FailureInfo.SET_RESERVE_FACTOR_BOUNDS_CHECK - ); - } - - uint256 oldReserveFactorMantissa = reserveFactorMantissa; - reserveFactorMantissa = newReserveFactorMantissa; - - emit NewReserveFactor( - oldReserveFactorMantissa, - newReserveFactorMantissa - ); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Accrues interest and reduces reserves by transferring from msg.sender - * @param addAmount Amount of addition to reserves - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _addReservesInternal(uint256 addAmount) - internal - nonReentrant - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return - fail( - Error(error), - FailureInfo.ADD_RESERVES_ACCRUE_INTEREST_FAILED - ); - } - - uint256 totalReservesNew; - uint256 actualAddAmount; - - if (accrualBlockNumber != getBlockNumber()) { - return ( - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.ADD_RESERVES_FRESH_CHECK - ) - ); - } - - actualAddAmount = doTransferIn(msg.sender, addAmount); - - totalReservesNew = totalReserves + actualAddAmount; - - require(totalReservesNew >= totalReserves, "CT22"); - - totalReserves = totalReservesNew; - - emit ReservesAdded(msg.sender, actualAddAmount, totalReservesNew); - - return (uint256(Error.NO_ERROR)); - } - - function _addSubsidyInternal(uint256 addAmount) - internal - nonReentrant - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - // accrueInterest emits logs on errors, but on top of that we want to log the fact that an attempted reduce reserves failed. - return fail(Error(error), FailureInfo.ADD_SUBSIDY_FUND_FAILED); - } - - uint256 subsidyFundNew; - uint256 actualAddAmount; - - if (accrualBlockNumber != getBlockNumber()) { - return ( - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.ADD_SUBSIDY_FUND_FRESH_CHECK - ) - ); - } - - actualAddAmount = doTransferIn(msg.sender, addAmount); - - subsidyFundNew = subsidyFund + actualAddAmount; - - require(subsidyFundNew >= subsidyFund, "CT22"); - - subsidyFund = subsidyFundNew; - - emit SubsidyAdded(msg.sender, actualAddAmount, subsidyFundNew); - - /* Return (NO_ERROR, actualAddAmount) */ - return (uint256(Error.NO_ERROR)); - } - - /** - * @notice Accrues interest and reduces reserves by transferring to admin - * @param reduceAmount Amount of reduction to reserves - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _reduceReserves(uint256 reduceAmount) - external - override - nonReentrant - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return - fail( - Error(error), - FailureInfo.REDUCE_RESERVES_ACCRUE_INTEREST_FAILED - ); - } - return _reduceReservesFresh(reduceAmount); - } - - /** - * @notice Reduces reserves by transferring to admin - * @dev Requires fresh interest accrual - * @param reduceAmount Amount of reduction to reserves - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _reduceReservesFresh(uint256 reduceAmount) - internal - returns (uint256) - { - uint256 totalReservesNew; - - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.REDUCE_RESERVES_ADMIN_CHECK - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.REDUCE_RESERVES_FRESH_CHECK - ); - } - - if (getCashPrior() < reduceAmount) { - return - fail( - Error.TOKEN_INSUFFICIENT_CASH, - FailureInfo.REDUCE_RESERVES_CASH_NOT_AVAILABLE - ); - } - - if (reduceAmount > totalReserves) { - return - fail(Error.BAD_INPUT, FailureInfo.REDUCE_RESERVES_VALIDATION); - } - - totalReservesNew = totalReserves - reduceAmount; - require(totalReservesNew <= totalReserves, "CT23"); - - totalReserves = totalReservesNew; - - doTransferOut(admin, reduceAmount); - - emit ReservesReduced(admin, reduceAmount, totalReservesNew); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice accrues interest and updates the interest rate model using _setInterestRateModelFresh - * @dev Admin function to accrue interest and update the interest rate model - * @param newInterestRateModel the new interest rate model to use - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setInterestRateModel(InterestRateModel newInterestRateModel) - public - override - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return - fail( - Error(error), - FailureInfo.SET_INTEREST_RATE_MODEL_ACCRUE_INTEREST_FAILED - ); - } - return _setInterestRateModelFresh(newInterestRateModel); - } - - /** - * @notice updates the interest rate model (*requires fresh interest accrual) - * @dev Admin function to update the interest rate model - * @param newInterestRateModel the new interest rate model to use - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setInterestRateModelFresh(InterestRateModel newInterestRateModel) - internal - returns (uint256) - { - InterestRateModel oldInterestRateModel; - - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_INTEREST_RATE_MODEL_OWNER_CHECK - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.SET_INTEREST_RATE_MODEL_FRESH_CHECK - ); - } - - oldInterestRateModel = interestRateModel; - - require(newInterestRateModel.isInterestRateModel(), "CT21"); - - interestRateModel = newInterestRateModel; - - emit NewMarketInterestRateModel( - oldInterestRateModel, - newInterestRateModel - ); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Gets balance of this contract in terms of the underlying - * @dev This excludes the value of the current message, if any - * @return The quantity of underlying owned by this contract - */ - function getCashPrior() internal view virtual returns (uint256); - - /** - * @dev Performs a transfer in, reverting upon failure. Returns the amount actually transferred to the protocol, in case of a fee. - * This may revert due to insufficient balance or insufficient allowance. - */ - function doTransferIn(address from, uint256 amount) - internal - virtual - returns (uint256); - - /** - * @dev Performs a transfer out, ideally returning an explanatory error code upon failure tather than reverting. - * If caller has not called checked protocol's balance, may revert due to insufficient cash held in the contract. - * If caller has checked protocol's balance, and verified it is >= amount, this should not revert in normal conditions. - */ - function doTransferOut(address payable to, uint256 amount) internal virtual; - - /** - * @dev Prevents a contract from calling itself, directly or indirectly. - */ - modifier nonReentrant() { - require(_notEntered, "re-entered"); - _notEntered = false; - _; - _notEntered = true; - } -} - - -// Dependency file: contracts/PriceOracle.sol - -// pragma solidity 0.8.6; - -// import "contracts/CToken.sol"; - -abstract contract PriceOracle { - /// @notice Indicator that this is a PriceOracle contract (for inspection) - bool public constant isPriceOracle = true; - - /** - * @notice Get the underlying price of a cToken asset - * @param cToken The cToken to get the underlying price of - * @return The underlying asset price mantissa (scaled by 1e18). - * Zero means the price is unavailable. - */ - function getUnderlyingPrice(CToken cToken) - external - view - virtual - returns (uint256); -} - - -// Dependency file: contracts/ComptrollerStorage.sol - -// pragma solidity 0.8.6; - -// import "contracts/CToken.sol"; -// import "contracts/PriceOracle.sol"; - -contract UnitrollerAdminStorage { - /** - * @notice Administrator for this contract - */ - address public admin; - - /** - * @notice Pending administrator for this contract - */ - address public pendingAdmin; - - /** - * @notice Active brains of Unitroller - */ - address public comptrollerImplementation; - - /** - * @notice Pending brains of Unitroller - */ - address public pendingComptrollerImplementation; -} - -contract ComptrollerV1Storage is UnitrollerAdminStorage { - - /** - * @notice Oracle which gives the price of any given asset - */ - PriceOracle public oracle; - - /** - * @notice Multiplier used to calculate the maximum repayAmount when liquidating a borrow - */ - uint public closeFactorMantissa; - - /** - * @notice Multiplier representing the discount on collateral that a liquidator receives - */ - uint public liquidationIncentiveMantissa; - - /** - * @notice Max number of assets a single account can participate in (borrow or use as collateral) - */ - uint public maxAssets; - - /** - * @notice Per-account mapping of "assets you are in", capped by maxAssets - */ - mapping(address => CToken[]) public accountAssets; - -} - -contract ComptrollerV2Storage is ComptrollerV1Storage { - struct Market { - /// @notice Whether or not this market is listed - bool isListed; - - /** - * @notice Multiplier representing the most one can borrow against their collateral in this market. - * For instance, 0.9 to allow borrowing 90% of collateral value. - * Must be between 0 and 1, and stored as a mantissa. - */ - uint collateralFactorMantissa; - - /// @notice Per-market mapping of "accounts in this asset" - mapping(address => bool) accountMembership; - - /// @notice Whether or not this market receives COMP - bool isComped; - } - - /** - * @notice Official mapping of cTokens -> Market metadata - * @dev Used e.g. to determine if a market is supported - */ - mapping(address => Market) public markets; - - - /** - * @notice The Pause Guardian can pause certain actions as a safety mechanism. - * Actions which allow users to remove their own assets cannot be paused. - * Liquidation / seizing / transfer can only be paused globally, not by market. - */ - address public pauseGuardian; - bool public _mintGuardianPaused; - bool public _borrowGuardianPaused; - bool public transferGuardianPaused; - bool public seizeGuardianPaused; - mapping(address => bool) public mintGuardianPaused; - mapping(address => bool) public borrowGuardianPaused; -} - -contract ComptrollerV3Storage is ComptrollerV2Storage { - struct CompMarketState { - /// @notice The market's last updated compBorrowIndex or compSupplyIndex - uint224 index; - - /// @notice The block number the index was last updated at - uint32 block; - } - - /// @notice A list of all markets - CToken[] public allMarkets; - - /// @notice The rate at which the flywheel distributes COMP, per block - uint public compRate; - - /// @notice The portion of compRate that each market currently receives - mapping(address => uint) public compSpeeds; - - /// @notice The COMP market supply state for each market - mapping(address => CompMarketState) public compSupplyState; - - /// @notice The COMP market borrow state for each market - mapping(address => CompMarketState) public compBorrowState; - - /// @notice The COMP borrow index for each market for each supplier as of the last time they accrued COMP - mapping(address => mapping(address => uint)) public compSupplierIndex; - - /// @notice The COMP borrow index for each market for each borrower as of the last time they accrued COMP - mapping(address => mapping(address => uint)) public compBorrowerIndex; - - /// @notice The COMP accrued but not yet transferred to each user - mapping(address => uint) public compAccrued; -} - -contract ComptrollerV4Storage is ComptrollerV3Storage { - // @notice The borrowCapGuardian can set borrowCaps to any number for any market. Lowering the borrow cap could disable borrowing on the given market. - address public borrowCapGuardian; - - // @notice Borrow caps enforced by borrowAllowed for each cToken address. Defaults to zero which corresponds to unlimited borrowing. - mapping(address => uint) public borrowCaps; - - // @notice address of the TROP token - address public tropAddress; -} - -contract ComptrollerV5Storage is ComptrollerV4Storage { - /// @notice The portion of COMP that each contributor receives per block - mapping(address => uint) public compContributorSpeeds; - - /// @notice Last block at which a contributor's COMP rewards have been allocated - mapping(address => uint) public lastContributorBlock; -} - - -// Dependency file: contracts/Unitroller.sol - -// pragma solidity 0.8.6; - -// import "contracts/ErrorReporter.sol"; -// import "contracts/ComptrollerStorage.sol"; - -/** - * @title ComptrollerCore - * @dev Storage for the comptroller is at this address, while execution is delegated to the `comptrollerImplementation`. - * CTokens should reference this contract as their comptroller. - */ -contract Unitroller is UnitrollerAdminStorage, ComptrollerErrorReporter { - /** - * @notice Emitted when pendingComptrollerImplementation is changed - */ - event NewPendingImplementation( - address oldPendingImplementation, - address newPendingImplementation - ); - - /** - * @notice Emitted when pendingComptrollerImplementation is accepted, which means comptroller implementation is updated - */ - event NewImplementation( - address oldImplementation, - address newImplementation - ); - - /** - * @notice Emitted when pendingAdmin is changed - */ - event NewPendingAdmin(address oldPendingAdmin, address newPendingAdmin); - - /** - * @notice Emitted when pendingAdmin is accepted, which means admin is updated - */ - event NewAdmin(address oldAdmin, address newAdmin); - - constructor() { - // Set admin to caller - admin = msg.sender; - } - - /*** Admin Functions ***/ - function _setPendingImplementation(address newPendingImplementation) - public - returns (uint256) - { - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_PENDING_IMPLEMENTATION_OWNER_CHECK - ); - } - - address oldPendingImplementation = pendingComptrollerImplementation; - - pendingComptrollerImplementation = newPendingImplementation; - - emit NewPendingImplementation( - oldPendingImplementation, - pendingComptrollerImplementation - ); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Accepts new implementation of comptroller. msg.sender must be pendingImplementation - * @dev Admin function for new implementation to accept it's role as implementation - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _acceptImplementation() public returns (uint256) { - // Check caller is pendingImplementation and pendingImplementation ≠ address(0) - if ( - msg.sender != pendingComptrollerImplementation || - pendingComptrollerImplementation == address(0) - ) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.ACCEPT_PENDING_IMPLEMENTATION_ADDRESS_CHECK - ); - } - - // Save current values for inclusion in log - address oldImplementation = comptrollerImplementation; - address oldPendingImplementation = pendingComptrollerImplementation; - - comptrollerImplementation = pendingComptrollerImplementation; - - pendingComptrollerImplementation = address(0); - - emit NewImplementation(oldImplementation, comptrollerImplementation); - emit NewPendingImplementation( - oldPendingImplementation, - pendingComptrollerImplementation - ); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Begins transfer of admin rights. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer. - * @dev Admin function to begin change of admin. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer. - * @param newPendingAdmin New pending admin. - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setPendingAdmin(address newPendingAdmin) - public - returns (uint256) - { - // Check caller = admin - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_PENDING_ADMIN_OWNER_CHECK - ); - } - - // Save current value, if any, for inclusion in log - address oldPendingAdmin = pendingAdmin; - - // Store pendingAdmin with value newPendingAdmin - pendingAdmin = newPendingAdmin; - - // Emit NewPendingAdmin(oldPendingAdmin, newPendingAdmin) - emit NewPendingAdmin(oldPendingAdmin, newPendingAdmin); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Accepts transfer of admin rights. msg.sender must be pendingAdmin - * @dev Admin function for pending admin to accept role and update admin - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _acceptAdmin() public returns (uint256) { - // Check caller is pendingAdmin and pendingAdmin ≠ address(0) - if (msg.sender != pendingAdmin || msg.sender == address(0)) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.ACCEPT_ADMIN_PENDING_ADMIN_CHECK - ); - } - - // Save current values for inclusion in log - address oldAdmin = admin; - address oldPendingAdmin = pendingAdmin; - - // Store admin with value pendingAdmin - admin = pendingAdmin; - - // Clear the pending value - pendingAdmin = address(0); - - emit NewAdmin(oldAdmin, admin); - emit NewPendingAdmin(oldPendingAdmin, pendingAdmin); - - return uint256(Error.NO_ERROR); - } - - /** - * @dev Delegates execution to an implementation contract. - * It returns to the external caller whatever the implementation returns - * or forwards reverts. - */ - function internalFallback() public payable { - // delegate all other functions to current implementation - (bool success, ) = comptrollerImplementation.delegatecall(msg.data); - - assembly { - let free_mem_ptr := mload(0x40) - returndatacopy(free_mem_ptr, 0, returndatasize()) - - switch success - case 0 { - revert(free_mem_ptr, returndatasize()) - } - default { - return(free_mem_ptr, returndatasize()) - } - } - } - - fallback() external payable { - internalFallback(); - } - - receive() external payable { - internalFallback(); - } -} - - -// Root file: contracts/ComptrollerG2.sol - -pragma solidity 0.8.6; - -// import "contracts/CToken.sol"; -// import "contracts/ErrorReporter.sol"; -// import "contracts/Exponential.sol"; -// import "contracts/PriceOracle.sol"; -// import "contracts/ComptrollerInterface.sol"; -// import "contracts/ComptrollerStorage.sol"; -// import "contracts/Unitroller.sol"; - -/** - * @title tropykus Comptroller Contract - * @author tropykus - */ -contract ComptrollerG2 is - ComptrollerV2Storage, - ComptrollerInterface, - ComptrollerErrorReporter, - Exponential -{ - /** - * @notice Emitted when an admin supports a market - */ - event MarketListed(CToken cToken); - - /** - * @notice Emitted when an account enters a market - */ - event MarketEntered(CToken cToken, address account); - - /** - * @notice Emitted when an account exits a market - */ - event MarketExited(CToken cToken, address account); - - /** - * @notice Emitted when close factor is changed by admin - */ - event NewCloseFactor( - uint256 oldCloseFactorMantissa, - uint256 newCloseFactorMantissa - ); - - /** - * @notice Emitted when a collateral factor is changed by admin - */ - event NewCollateralFactor( - CToken cToken, - uint256 oldCollateralFactorMantissa, - uint256 newCollateralFactorMantissa - ); - - /** - * @notice Emitted when liquidation incentive is changed by admin - */ - event NewLiquidationIncentive( - uint256 oldLiquidationIncentiveMantissa, - uint256 newLiquidationIncentiveMantissa - ); - - /** - * @notice Emitted when maxAssets is changed by admin - */ - event NewMaxAssets(uint256 oldMaxAssets, uint256 newMaxAssets); - - /** - * @notice Emitted when price oracle is changed - */ - event NewPriceOracle( - PriceOracle oldPriceOracle, - PriceOracle newPriceOracle - ); - - /** - * @notice Emitted when pause guardian is changed - */ - event NewPauseGuardian(address oldPauseGuardian, address newPauseGuardian); - - /** - * @notice Emitted when an action is paused globally - */ - event ActionPaused(string action, bool pauseState); - - /** - * @notice Emitted when an action is paused on a market - */ - event ActionPaused(CToken cToken, string action, bool pauseState); - - // closeFactorMantissa must be strictly greater than this value - uint256 internal constant closeFactorMinMantissa = 0.05e18; // 0.05 - - // closeFactorMantissa must not exceed this value - uint256 internal constant closeFactorMaxMantissa = 0.9e18; // 0.9 - - // No collateralFactorMantissa may exceed this value - uint256 internal constant collateralFactorMaxMantissa = 0.9e18; // 0.9 - - // liquidationIncentiveMantissa must be no less than this value - uint256 internal constant liquidationIncentiveMinMantissa = 1.0e18; // 1.0 - - // liquidationIncentiveMantissa must be no greater than this value - uint256 internal constant liquidationIncentiveMaxMantissa = 1.5e18; // 1.5 - - constructor() { - admin = msg.sender; - } - - /*** Assets You Are In ***/ - - /** - * @notice Returns the assets an account has entered - * @param account The address of the account to pull assets for - * @return A dynamic list with the assets the account has entered - */ - function getAssetsIn(address account) - external - view - returns (CToken[] memory) - { - CToken[] memory assetsIn = accountAssets[account]; - - return assetsIn; - } - - /** - * @notice Returns whether the given account is entered in the given asset - * @param account The address of the account to check - * @param cToken The cToken to check - * @return True if the account is in the asset, otherwise false. - */ - function checkMembership(address account, CToken cToken) - external - view - returns (bool) - { - return markets[address(cToken)].accountMembership[account]; - } - - /** - * @notice Add assets to be included in account liquidity calculation - * @param cTokens The list of addresses of the cToken markets to be enabled - * @return Success indicator for whether each corresponding market was entered - */ - function enterMarkets(address[] memory cTokens) - public - override - returns (uint256[] memory) - { - uint256 len = cTokens.length; - - uint256[] memory results = new uint256[](len); - for (uint256 i = 0; i < len; i++) { - CToken cToken = CToken(cTokens[i]); - - results[i] = uint256(addToMarketInternal(cToken, msg.sender)); - } - - return results; - } - - /** - * @notice Add the market to the borrower's "assets in" for liquidity calculations - * @param cToken The market to enter - * @param borrower The address of the account to modify - * @return Success indicator for whether the market was entered - */ - function addToMarketInternal(CToken cToken, address borrower) - internal - returns (Error) - { - Market storage marketToJoin = markets[address(cToken)]; - - if (!marketToJoin.isListed) { - // market is not listed, cannot join - return Error.MARKET_NOT_LISTED; - } - - if (marketToJoin.accountMembership[borrower] == true) { - // already joined - return Error.NO_ERROR; - } - - if (accountAssets[borrower].length >= maxAssets) { - // no space, cannot join - return Error.TOO_MANY_ASSETS; - } - - // survived the gauntlet, add to list - // NOTE: we store these somewhat redundantly as a significant optimization - // this avoids having to iterate through the list for the most common use cases - // that is, only when we need to perform liquidity checks - // and not whenever we want to check if an account is in a particular market - marketToJoin.accountMembership[borrower] = true; - accountAssets[borrower].push(cToken); - - emit MarketEntered(cToken, borrower); - - return Error.NO_ERROR; - } - - /** - * @notice Removes asset from sender's account liquidity calculation - * @dev Sender must not have an outstanding borrow balance in the asset, - * or be providing neccessary collateral for an outstanding borrow. - * @param cTokenAddress The address of the asset to be removed - * @return Whether or not the account successfully exited the market - */ - function exitMarket(address cTokenAddress) - external - override - returns (uint256) - { - CToken cToken = CToken(cTokenAddress); - /* Get sender tokensHeld and amountOwed underlying from the cToken */ - (uint256 oErr, uint256 tokensHeld, uint256 amountOwed, ) = cToken - .getAccountSnapshot(msg.sender); - require(oErr == 0, "exitMarket: getAccountSnapshot failed"); // semi-opaque error code - - /* Fail if the sender has a borrow balance */ - if (amountOwed != 0) { - return - fail( - Error.NONZERO_BORROW_BALANCE, - FailureInfo.EXIT_MARKET_BALANCE_OWED - ); - } - - /* Fail if the sender is not permitted to redeem all of their tokens */ - uint256 allowed = redeemAllowedInternal( - cTokenAddress, - msg.sender, - tokensHeld - ); - if (allowed != 0) { - return - failOpaque( - Error.REJECTION, - FailureInfo.EXIT_MARKET_REJECTION, - allowed - ); - } - - Market storage marketToExit = markets[address(cToken)]; - - /* Return true if the sender is not already ‘in’ the market */ - if (!marketToExit.accountMembership[msg.sender]) { - return uint256(Error.NO_ERROR); - } - - /* Set cToken account membership to false */ - delete marketToExit.accountMembership[msg.sender]; - - /* Delete cToken from the account’s list of assets */ - // load into memory for faster iteration - CToken[] memory userAssetList = accountAssets[msg.sender]; - accountAssets[msg.sender] = new CToken[](0); - CToken[] storage newMarketList = accountAssets[msg.sender]; - uint256 len = userAssetList.length; - uint256 assetIndex = len; - for (uint256 i = 0; i < len; i++) { - if (userAssetList[i] == cToken) { - assetIndex = i; - continue; - } - newMarketList.push(userAssetList[i]); - } - - // We *must* have found the asset in the list or our redundant data structure is broken - assert(assetIndex < len); - - emit MarketExited(cToken, msg.sender); - - return uint256(Error.NO_ERROR); - } - - /*** Policy Hooks ***/ - - /** - * @notice Checks if the account should be allowed to mint tokens in the given market - * @param cToken The market to verify the mint against - * @param minter The account which would get the minted tokens - * @param mintAmount The amount of underlying being supplied to the market in exchange for tokens - * @return 0 if the mint is allowed, otherwise a semi-opaque error code (See ErrorReporter.sol) - */ - function mintAllowed( - address cToken, - address minter, - uint256 mintAmount - ) external view override returns (uint256) { - // Pausing is a very serious situation - we revert to sound the alarms - require(!mintGuardianPaused[cToken], "mint is paused"); - - // Shh - currently unused - minter; - mintAmount; - - if (!markets[cToken].isListed) { - return uint256(Error.MARKET_NOT_LISTED); - } - - // *may include Policy Hook-type checks - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Validates mint and reverts on rejection. May emit logs. - * @param cToken Asset being minted - * @param minter The address minting the tokens - * @param actualMintAmount The amount of the underlying asset being minted - * @param mintTokens The number of tokens being minted - */ - function mintVerify( - address cToken, - address minter, - uint256 actualMintAmount, - uint256 mintTokens - ) external override { - // Shh - currently unused - cToken; - minter; - actualMintAmount; - mintTokens; - - // Shh - we don't ever want this hook to be marked pure - if (false) { - maxAssets = maxAssets; - } - } - - /** - * @notice Checks if the account should be allowed to redeem tokens in the given market - * @param cToken The market to verify the redeem against - * @param redeemer The account which would redeem the tokens - * @param redeemTokens The number of cTokens to exchange for the underlying asset in the market - * @return 0 if the redeem is allowed, otherwise a semi-opaque error code (See ErrorReporter.sol) - */ - function redeemAllowed( - address cToken, - address redeemer, - uint256 redeemTokens - ) external view override returns (uint256) { - return redeemAllowedInternal(cToken, redeemer, redeemTokens); - } - - function redeemAllowedInternal( - address cToken, - address redeemer, - uint256 redeemTokens - ) internal view returns (uint256) { - if (!markets[cToken].isListed) { - return uint256(Error.MARKET_NOT_LISTED); - } - - // *may include Policy Hook-type checks - - /* If the redeemer is not 'in' the market, then we can bypass the liquidity check */ - if (!markets[cToken].accountMembership[redeemer]) { - return uint256(Error.NO_ERROR); - } - - /* Otherwise, perform a hypothetical liquidity check to guard against shortfall */ - ( - Error err, - , - uint256 shortfall - ) = getHypotheticalAccountLiquidityInternal( - redeemer, - CToken(cToken), - redeemTokens, - 0 - ); - if (err != Error.NO_ERROR) { - return uint256(err); - } - if (shortfall > 0) { - return uint256(Error.INSUFFICIENT_LIQUIDITY); - } - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Validates redeem and reverts on rejection. May emit logs. - * @param cToken Asset being redeemed - * @param redeemer The address redeeming the tokens - * @param redeemAmount The amount of the underlying asset being redeemed - * @param redeemTokens The number of tokens being redeemed - */ - function redeemVerify( - address cToken, - address redeemer, - uint256 redeemAmount, - uint256 redeemTokens - ) external pure override { - // Shh - currently unused - cToken; - redeemer; - - // Require tokens is zero or amount is also zero - if (redeemTokens == 0 && redeemAmount > 0) { - revert("redeemTokens zero"); - } - } - - /** - * @notice Checks if the account should be allowed to borrow the underlying asset of the given market - * @param cToken The market to verify the borrow against - * @param borrower The account which would borrow the asset - * @param borrowAmount The amount of underlying the account would borrow - * @return 0 if the borrow is allowed, otherwise a semi-opaque error code (See ErrorReporter.sol) - */ - function borrowAllowed( - address cToken, - address borrower, - uint256 borrowAmount - ) external override returns (uint256) { - // Pausing is a very serious situation - we revert to sound the alarms - Error err; - uint256 shortfall; - require(!borrowGuardianPaused[cToken], "borrow is paused"); - - if (!markets[cToken].isListed) { - return uint256(Error.MARKET_NOT_LISTED); - } - - // *may include Policy Hook-type checks - - if (!markets[cToken].accountMembership[borrower]) { - // only cTokens may call borrowAllowed if borrower not in market - require(msg.sender == cToken, "sender must be cToken"); - - // attempt to add borrower to the market - err = addToMarketInternal(CToken(msg.sender), borrower); - if (err != Error.NO_ERROR) { - return uint256(err); - } - - // it should be impossible to break the // important invariant - assert(markets[cToken].accountMembership[borrower]); - } - - if (oracle.getUnderlyingPrice(CToken(cToken)) == 0) { - return uint256(Error.PRICE_ERROR); - } - - (err, , shortfall) = getHypotheticalAccountLiquidityInternal( - borrower, - CToken(cToken), - 0, - borrowAmount - ); - if (err != Error.NO_ERROR) { - return uint256(err); - } - if (shortfall > 0) { - return uint256(Error.INSUFFICIENT_LIQUIDITY); - } - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Validates borrow and reverts on rejection. May emit logs. - * @param cToken Asset whose underlying is being borrowed - * @param borrower The address borrowing the underlying - * @param borrowAmount The amount of the underlying asset requested to borrow - */ - function borrowVerify( - address cToken, - address borrower, - uint256 borrowAmount - ) external override { - // Shh - currently unused - cToken; - borrower; - borrowAmount; - - // Shh - we don't ever want this hook to be marked pure - if (false) { - maxAssets = maxAssets; - } - } - - /** - * @notice Checks if the account should be allowed to repay a borrow in the given market - * @param cToken The market to verify the repay against - * @param payer The account which would repay the asset - * @param borrower The account which would borrowed the asset - * @param repayAmount The amount of the underlying asset the account would repay - * @return 0 if the repay is allowed, otherwise a semi-opaque error code (See ErrorReporter.sol) - */ - function repayBorrowAllowed( - address cToken, - address payer, - address borrower, - uint256 repayAmount - ) external view override returns (uint256) { - // Shh - currently unused - payer; - borrower; - repayAmount; - - if (!markets[cToken].isListed) { - return uint256(Error.MARKET_NOT_LISTED); - } - - // *may include Policy Hook-type checks - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Validates repayBorrow and reverts on rejection. May emit logs. - * @param cToken Asset being repaid - * @param payer The address repaying the borrow - * @param borrower The address of the borrower - * @param actualRepayAmount The amount of underlying being repaid - */ - function repayBorrowVerify( - address cToken, - address payer, - address borrower, - uint256 actualRepayAmount, - uint256 borrowerIndex - ) external override { - // Shh - currently unused - cToken; - payer; - borrower; - actualRepayAmount; - borrowerIndex; - - // Shh - we don't ever want this hook to be marked pure - if (false) { - maxAssets = maxAssets; - } - } - - /** - * @notice Checks if the liquidation should be allowed to occur - * @param cTokenBorrowed Asset which was borrowed by the borrower - * @param cTokenCollateral Asset which was used as collateral and will be seized - * @param liquidator The address repaying the borrow and seizing the collateral - * @param borrower The address of the borrower - * @param repayAmount The amount of underlying being repaid - */ - function liquidateBorrowAllowed( - address cTokenBorrowed, - address cTokenCollateral, - address liquidator, - address borrower, - uint256 repayAmount - ) external view override returns (uint256) { - // Shh - currently unused - liquidator; - - if ( - !markets[cTokenBorrowed].isListed || - !markets[cTokenCollateral].isListed - ) { - return uint256(Error.MARKET_NOT_LISTED); - } - - // *may include Policy Hook-type checks - - /* The borrower must have shortfall in order to be liquidatable */ - (Error err, , uint256 shortfall) = getAccountLiquidityInternal( - borrower - ); - if (err != Error.NO_ERROR) { - return uint256(err); - } - if (shortfall == 0) { - return uint256(Error.INSUFFICIENT_SHORTFALL); - } - - /* The liquidator may not repay more than what is allowed by the closeFactor */ - uint256 borrowBalance = CToken(cTokenBorrowed).borrowBalanceStored( - borrower - ); - (MathError mathErr, uint256 maxClose) = mulScalarTruncate( - Exp({mantissa: closeFactorMantissa}), - borrowBalance - ); - if (mathErr != MathError.NO_ERROR) { - return uint256(Error.MATH_ERROR); - } - if (repayAmount > maxClose) { - return uint256(Error.TOO_MUCH_REPAY); - } - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Validates liquidateBorrow and reverts on rejection. May emit logs. - * @param cTokenBorrowed Asset which was borrowed by the borrower - * @param cTokenCollateral Asset which was used as collateral and will be seized - * @param liquidator The address repaying the borrow and seizing the collateral - * @param borrower The address of the borrower - * @param actualRepayAmount The amount of underlying being repaid - */ - function liquidateBorrowVerify( - address cTokenBorrowed, - address cTokenCollateral, - address liquidator, - address borrower, - uint256 actualRepayAmount, - uint256 seizeTokens - ) external override { - // Shh - currently unused - cTokenBorrowed; - cTokenCollateral; - liquidator; - borrower; - actualRepayAmount; - seizeTokens; - - // Shh - we don't ever want this hook to be marked pure - if (false) { - maxAssets = maxAssets; - } - } - - /** - * @notice Checks if the seizing of assets should be allowed to occur - * @param cTokenCollateral Asset which was used as collateral and will be seized - * @param cTokenBorrowed Asset which was borrowed by the borrower - * @param liquidator The address repaying the borrow and seizing the collateral - * @param borrower The address of the borrower - * @param seizeTokens The number of collateral tokens to seize - */ - function seizeAllowed( - address cTokenCollateral, - address cTokenBorrowed, - address liquidator, - address borrower, - uint256 seizeTokens - ) external view override returns (uint256) { - // Pausing is a very serious situation - we revert to sound the alarms - require(!seizeGuardianPaused, "seize is paused"); - - // Shh - currently unused - liquidator; - borrower; - seizeTokens; - - if ( - !markets[cTokenCollateral].isListed || - !markets[cTokenBorrowed].isListed - ) { - return uint256(Error.MARKET_NOT_LISTED); - } - - if ( - CToken(cTokenCollateral).comptroller() != - CToken(cTokenBorrowed).comptroller() - ) { - return uint256(Error.COMPTROLLER_MISMATCH); - } - - // *may include Policy Hook-type checks - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Validates seize and reverts on rejection. May emit logs. - * @param cTokenCollateral Asset which was used as collateral and will be seized - * @param cTokenBorrowed Asset which was borrowed by the borrower - * @param liquidator The address repaying the borrow and seizing the collateral - * @param borrower The address of the borrower - * @param seizeTokens The number of collateral tokens to seize - */ - function seizeVerify( - address cTokenCollateral, - address cTokenBorrowed, - address liquidator, - address borrower, - uint256 seizeTokens - ) external override { - // Shh - currently unused - cTokenCollateral; - cTokenBorrowed; - liquidator; - borrower; - seizeTokens; - - // Shh - we don't ever want this hook to be marked pure - if (false) { - maxAssets = maxAssets; - } - } - - /** - * @notice Checks if the account should be allowed to transfer tokens in the given market - * @param cToken The market to verify the transfer against - * @param src The account which sources the tokens - * @param dst The account which receives the tokens - * @param transferTokens The number of cTokens to transfer - * @return 0 if the transfer is allowed, otherwise a semi-opaque error code (See ErrorReporter.sol) - */ - function transferAllowed( - address cToken, - address src, - address dst, - uint256 transferTokens - ) external view override returns (uint256) { - // Pausing is a very serious situation - we revert to sound the alarms - require(!transferGuardianPaused, "transfer is paused"); - - // Shh - currently unused - dst; - - // *may include Policy Hook-type checks - - // Currently the only consideration is whether or not - // the src is allowed to redeem this many tokens - return redeemAllowedInternal(cToken, src, transferTokens); - } - - /** - * @notice Validates transfer and reverts on rejection. May emit logs. - * @param cToken Asset being transferred - * @param src The account which sources the tokens - * @param dst The account which receives the tokens - * @param transferTokens The number of cTokens to transfer - */ - function transferVerify( - address cToken, - address src, - address dst, - uint256 transferTokens - ) external override { - // Shh - currently unused - cToken; - src; - dst; - transferTokens; - - // Shh - we don't ever want this hook to be marked pure - if (false) { - maxAssets = maxAssets; - } - } - - /*** Liquidity/Liquidation Calculations ***/ - - /** - * @dev Local vars for avoiding stack-depth limits in calculating account liquidity. - * Note that `cTokenBalance` is the number of cTokens the account owns in the market, - * whereas `borrowBalance` is the amount of underlying that the account has borrowed. - */ - struct AccountLiquidityLocalVars { - uint256 sumCollateral; - uint256 sumBorrowPlusEffects; - uint256 cTokenBalance; - uint256 borrowBalance; - uint256 exchangeRateMantissa; - uint256 oraclePriceMantissa; - Exp collateralFactor; - Exp exchangeRate; - Exp oraclePrice; - Exp tokensToEther; - } - - /** - * @notice Determine the current account liquidity wrt collateral requirements - * @return (possible error code (semi-opaque), - account liquidity in excess of collateral requirements, - * account shortfall below collateral requirements) - */ - function getAccountLiquidity(address account) - public - view - returns ( - uint256, - uint256, - uint256 - ) - { - ( - Error err, - uint256 liquidity, - uint256 shortfall - ) = getHypotheticalAccountLiquidityInternal( - account, - CToken(address(0)), - 0, - 0 - ); - - return (uint256(err), liquidity, shortfall); - } - - /** - * @notice Determine the current account liquidity wrt collateral requirements - * @return (possible error code, - account liquidity in excess of collateral requirements, - * account shortfall below collateral requirements) - */ - function getAccountLiquidityInternal(address account) - internal - view - returns ( - Error, - uint256, - uint256 - ) - { - return - getHypotheticalAccountLiquidityInternal( - account, - CToken(address(0)), - 0, - 0 - ); - } - - /** - * @notice Determine what the account liquidity would be if the given amounts were redeemed/borrowed - * @param cTokenModify The market to hypothetically redeem/borrow in - * @param account The account to determine liquidity for - * @param redeemTokens The number of tokens to hypothetically redeem - * @param borrowAmount The amount of underlying to hypothetically borrow - * @return (possible error code (semi-opaque), - hypothetical account liquidity in excess of collateral requirements, - * hypothetical account shortfall below collateral requirements) - */ - function getHypotheticalAccountLiquidity( - address account, - address cTokenModify, - uint256 redeemTokens, - uint256 borrowAmount - ) - public - view - returns ( - uint256, - uint256, - uint256 - ) - { - ( - Error err, - uint256 liquidity, - uint256 shortfall - ) = getHypotheticalAccountLiquidityInternal( - account, - CToken(cTokenModify), - redeemTokens, - borrowAmount - ); - return (uint256(err), liquidity, shortfall); - } - - /** - * @notice Determine what the account liquidity would be if the given amounts were redeemed/borrowed - * @param cTokenModify The market to hypothetically redeem/borrow in - * @param account The account to determine liquidity for - * @param redeemTokens The number of tokens to hypothetically redeem - * @param borrowAmount The amount of underlying to hypothetically borrow - * @dev Note that we calculate the exchangeRateStored for each collateral cToken using stored data, - * without calculating accumulated interest. - * @return (possible error code, - hypothetical account liquidity in excess of collateral requirements, - * hypothetical account shortfall below collateral requirements) - */ - function getHypotheticalAccountLiquidityInternal( - address account, - CToken cTokenModify, - uint256 redeemTokens, - uint256 borrowAmount - ) - internal - view - returns ( - Error, - uint256, - uint256 - ) - { - AccountLiquidityLocalVars memory vars; // Holds all our calculation results - uint256 oErr; - MathError mErr; - - // For each asset the account is in - CToken[] memory assets = accountAssets[account]; - for (uint256 i = 0; i < assets.length; i++) { - CToken asset = assets[i]; - - // Read the balances and exchange rate from the cToken - ( - oErr, - vars.cTokenBalance, - vars.borrowBalance, - vars.exchangeRateMantissa - ) = asset.getAccountSnapshot(account); - if (oErr != 0) { - // semi-opaque error code, we assume NO_ERROR == 0 is invariant between upgrades - return (Error.SNAPSHOT_ERROR, 0, 0); - } - vars.collateralFactor = Exp({ - mantissa: markets[address(asset)].collateralFactorMantissa - }); - vars.exchangeRate = Exp({mantissa: vars.exchangeRateMantissa}); - - // Get the normalized price of the asset - vars.oraclePriceMantissa = oracle.getUnderlyingPrice(asset); - if (vars.oraclePriceMantissa == 0) { - return (Error.PRICE_ERROR, 0, 0); - } - vars.oraclePrice = Exp({mantissa: vars.oraclePriceMantissa}); - - // Pre-compute a conversion factor from tokens -> ether (normalized price value) - (mErr, vars.tokensToEther) = mulExp3( - vars.collateralFactor, - vars.exchangeRate, - vars.oraclePrice - ); - if (mErr != MathError.NO_ERROR) { - return (Error.MATH_ERROR, 0, 0); - } - - // sumCollateral += tokensToEther * cTokenBalance - (mErr, vars.sumCollateral) = mulScalarTruncateAddUInt( - vars.tokensToEther, - vars.cTokenBalance, - vars.sumCollateral - ); - if (mErr != MathError.NO_ERROR) { - return (Error.MATH_ERROR, 0, 0); - } - - // sumBorrowPlusEffects += oraclePrice * borrowBalance - (mErr, vars.sumBorrowPlusEffects) = mulScalarTruncateAddUInt( - vars.oraclePrice, - vars.borrowBalance, - vars.sumBorrowPlusEffects - ); - if (mErr != MathError.NO_ERROR) { - return (Error.MATH_ERROR, 0, 0); - } - - // Calculate effects of interacting with cTokenModify - if (asset == cTokenModify) { - // redeem effect - // sumBorrowPlusEffects += tokensToEther * redeemTokens - (mErr, vars.sumBorrowPlusEffects) = mulScalarTruncateAddUInt( - vars.tokensToEther, - redeemTokens, - vars.sumBorrowPlusEffects - ); - if (mErr != MathError.NO_ERROR) { - return (Error.MATH_ERROR, 0, 0); - } - - // borrow effect - // sumBorrowPlusEffects += oraclePrice * borrowAmount - (mErr, vars.sumBorrowPlusEffects) = mulScalarTruncateAddUInt( - vars.oraclePrice, - borrowAmount, - vars.sumBorrowPlusEffects - ); - if (mErr != MathError.NO_ERROR) { - return (Error.MATH_ERROR, 0, 0); - } - } - } - - // These are safe, as the underflow condition is checked first - if (vars.sumCollateral > vars.sumBorrowPlusEffects) { - return ( - Error.NO_ERROR, - vars.sumCollateral - vars.sumBorrowPlusEffects, - 0 - ); - } else { - return ( - Error.NO_ERROR, - 0, - vars.sumBorrowPlusEffects - vars.sumCollateral - ); - } - } - - /** - * @notice Calculate number of tokens of collateral asset to seize given an underlying amount - * @dev Used in liquidation (called in cToken.liquidateBorrowFresh) - * @param cTokenBorrowed The address of the borrowed cToken - * @param cTokenCollateral The address of the collateral cToken - * @param actualRepayAmount The amount of cTokenBorrowed underlying to convert into cTokenCollateral tokens - * @return (errorCode, number of cTokenCollateral tokens to be seized in a liquidation) - */ - function liquidateCalculateSeizeTokens( - address cTokenBorrowed, - address cTokenCollateral, - uint256 actualRepayAmount - ) external view override returns (uint256, uint256) { - /* Read oracle prices for borrowed and collateral markets */ - uint256 priceBorrowedMantissa = oracle.getUnderlyingPrice( - CToken(cTokenBorrowed) - ); - uint256 priceCollateralMantissa = oracle.getUnderlyingPrice( - CToken(cTokenCollateral) - ); - if (priceBorrowedMantissa == 0 || priceCollateralMantissa == 0) { - return (uint256(Error.PRICE_ERROR), 0); - } - - /* - * Get the exchange rate and calculate the number of collateral tokens to seize: - * seizeAmount = actualRepayAmount * liquidationIncentive * priceBorrowed / priceCollateral - * seizeTokens = seizeAmount / exchangeRate - * = actualRepayAmount * (liquidationIncentive * priceBorrowed) / (priceCollateral * exchangeRate) - */ - uint256 exchangeRateMantissa = CToken(cTokenCollateral) - .exchangeRateStored(); // Note: reverts on error - uint256 seizeTokens; - Exp memory numerator; - Exp memory denominator; - Exp memory ratio; - MathError mathErr; - - (mathErr, numerator) = mulExp( - liquidationIncentiveMantissa, - priceBorrowedMantissa - ); - if (mathErr != MathError.NO_ERROR) { - return (uint256(Error.MATH_ERROR), 0); - } - - (mathErr, denominator) = mulExp( - priceCollateralMantissa, - exchangeRateMantissa - ); - if (mathErr != MathError.NO_ERROR) { - return (uint256(Error.MATH_ERROR), 0); - } - - (mathErr, ratio) = divExp(numerator, denominator); - if (mathErr != MathError.NO_ERROR) { - return (uint256(Error.MATH_ERROR), 0); - } - - (mathErr, seizeTokens) = mulScalarTruncate(ratio, actualRepayAmount); - if (mathErr != MathError.NO_ERROR) { - return (uint256(Error.MATH_ERROR), 0); - } - - return (uint256(Error.NO_ERROR), seizeTokens); - } - - /*** Admin Functions ***/ - - /** - * @notice Sets a new price oracle for the comptroller - * @dev Admin function to set a new price oracle - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setPriceOracle(PriceOracle newOracle) public returns (uint256) { - // Check caller is admin - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_PRICE_ORACLE_OWNER_CHECK - ); - } - - // Track the old oracle for the comptroller - PriceOracle oldOracle = oracle; - - // Set comptroller's oracle to newOracle - oracle = newOracle; - - // Emit NewPriceOracle(oldOracle, newOracle) - emit NewPriceOracle(oldOracle, newOracle); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Sets the closeFactor used when liquidating borrows - * @dev Admin function to set closeFactor - * @param newCloseFactorMantissa New close factor, scaled by 1e18 - * @return uint 0=success, otherwise a failure. (See ErrorReporter for details) - */ - function _setCloseFactor(uint256 newCloseFactorMantissa) - external - returns (uint256) - { - // Check caller is admin - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_CLOSE_FACTOR_OWNER_CHECK - ); - } - - Exp memory newCloseFactorExp = Exp({mantissa: newCloseFactorMantissa}); - Exp memory lowLimit = Exp({mantissa: closeFactorMinMantissa}); - if (lessThanOrEqualExp(newCloseFactorExp, lowLimit)) { - return - fail( - Error.INVALID_CLOSE_FACTOR, - FailureInfo.SET_CLOSE_FACTOR_VALIDATION - ); - } - - Exp memory highLimit = Exp({mantissa: closeFactorMaxMantissa}); - if (lessThanExp(highLimit, newCloseFactorExp)) { - return - fail( - Error.INVALID_CLOSE_FACTOR, - FailureInfo.SET_CLOSE_FACTOR_VALIDATION - ); - } - - uint256 oldCloseFactorMantissa = closeFactorMantissa; - closeFactorMantissa = newCloseFactorMantissa; - emit NewCloseFactor(oldCloseFactorMantissa, closeFactorMantissa); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Sets the collateralFactor for a market - * @dev Admin function to set per-market collateralFactor - * @param cToken The market to set the factor on - * @param newCollateralFactorMantissa The new collateral factor, scaled by 1e18 - * @return uint 0=success, otherwise a failure. (See ErrorReporter for details) - */ - function _setCollateralFactor( - CToken cToken, - uint256 newCollateralFactorMantissa - ) external returns (uint256) { - // Check caller is admin - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_COLLATERAL_FACTOR_OWNER_CHECK - ); - } - - // Verify market is listed - Market storage market = markets[address(cToken)]; - if (!market.isListed) { - return - fail( - Error.MARKET_NOT_LISTED, - FailureInfo.SET_COLLATERAL_FACTOR_NO_EXISTS - ); - } - - Exp memory newCollateralFactorExp = Exp({ - mantissa: newCollateralFactorMantissa - }); - - // Check collateral factor <= 0.9 - Exp memory highLimit = Exp({mantissa: collateralFactorMaxMantissa}); - if (lessThanExp(highLimit, newCollateralFactorExp)) { - return - fail( - Error.INVALID_COLLATERAL_FACTOR, - FailureInfo.SET_COLLATERAL_FACTOR_VALIDATION - ); - } - - // If collateral factor != 0, fail if price == 0 - if ( - newCollateralFactorMantissa != 0 && - oracle.getUnderlyingPrice(cToken) == 0 - ) { - return - fail( - Error.PRICE_ERROR, - FailureInfo.SET_COLLATERAL_FACTOR_WITHOUT_PRICE - ); - } - - // Set market's collateral factor to new collateral factor, remember old value - uint256 oldCollateralFactorMantissa = market.collateralFactorMantissa; - market.collateralFactorMantissa = newCollateralFactorMantissa; - - // Emit event with asset, old collateral factor, and new collateral factor - emit NewCollateralFactor( - cToken, - oldCollateralFactorMantissa, - newCollateralFactorMantissa - ); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Sets maxAssets which controls how many markets can be entered - * @dev Admin function to set maxAssets - * @param newMaxAssets New max assets - * @return uint 0=success, otherwise a failure. (See ErrorReporter for details) - */ - function _setMaxAssets(uint256 newMaxAssets) external returns (uint256) { - // Check caller is admin - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_MAX_ASSETS_OWNER_CHECK - ); - } - - uint256 oldMaxAssets = maxAssets; - maxAssets = newMaxAssets; - emit NewMaxAssets(oldMaxAssets, newMaxAssets); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Sets liquidationIncentive - * @dev Admin function to set liquidationIncentive - * @param newLiquidationIncentiveMantissa New liquidationIncentive scaled by 1e18 - * @return uint 0=success, otherwise a failure. (See ErrorReporter for details) - */ - function _setLiquidationIncentive(uint256 newLiquidationIncentiveMantissa) - external - returns (uint256) - { - // Check caller is admin - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_LIQUIDATION_INCENTIVE_OWNER_CHECK - ); - } - - // Check de-scaled min <= newLiquidationIncentive <= max - Exp memory newLiquidationIncentive = Exp({ - mantissa: newLiquidationIncentiveMantissa - }); - Exp memory minLiquidationIncentive = Exp({ - mantissa: liquidationIncentiveMinMantissa - }); - if (lessThanExp(newLiquidationIncentive, minLiquidationIncentive)) { - return - fail( - Error.INVALID_LIQUIDATION_INCENTIVE, - FailureInfo.SET_LIQUIDATION_INCENTIVE_VALIDATION - ); - } - - Exp memory maxLiquidationIncentive = Exp({ - mantissa: liquidationIncentiveMaxMantissa - }); - if (lessThanExp(maxLiquidationIncentive, newLiquidationIncentive)) { - return - fail( - Error.INVALID_LIQUIDATION_INCENTIVE, - FailureInfo.SET_LIQUIDATION_INCENTIVE_VALIDATION - ); - } - - // Save current value for use in log - uint256 oldLiquidationIncentiveMantissa = liquidationIncentiveMantissa; - - // Set liquidation incentive to new incentive - liquidationIncentiveMantissa = newLiquidationIncentiveMantissa; - - // Emit event with old incentive, new incentive - emit NewLiquidationIncentive( - oldLiquidationIncentiveMantissa, - newLiquidationIncentiveMantissa - ); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Add the market to the markets mapping and set it as listed - * @dev Admin function to set isListed and add support for the market - * @param cToken The address of the market (token) to list - * @return uint 0=success, otherwise a failure. (See enum Error for details) - */ - function _supportMarket(CToken cToken) external returns (uint256) { - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SUPPORT_MARKET_OWNER_CHECK - ); - } - - if (markets[address(cToken)].isListed) { - return - fail( - Error.MARKET_ALREADY_LISTED, - FailureInfo.SUPPORT_MARKET_EXISTS - ); - } - - cToken.isCToken(); // Sanity check to make sure its really a CToken - - Market storage market = markets[address(cToken)]; - market.isListed = true; - market.isComped = false; - market.collateralFactorMantissa = 0; - - emit MarketListed(cToken); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Admin function to change the Pause Guardian - * @param newPauseGuardian The address of the new Pause Guardian - * @return uint 0=success, otherwise a failure. (See enum Error for details) - */ - function _setPauseGuardian(address newPauseGuardian) - public - returns (uint256) - { - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_PAUSE_GUARDIAN_OWNER_CHECK - ); - } - - // Save current value for inclusion in log - address oldPauseGuardian = pauseGuardian; - - // Store pauseGuardian with value newPauseGuardian - pauseGuardian = newPauseGuardian; - - // Emit NewPauseGuardian(OldPauseGuardian, NewPauseGuardian) - emit NewPauseGuardian(oldPauseGuardian, pauseGuardian); - - return uint256(Error.NO_ERROR); - } - - function _setMintPaused(CToken cToken, bool state) public returns (bool) { - require( - markets[address(cToken)].isListed, - "cannot pause a market that is not listed" - ); - require( - msg.sender == pauseGuardian || msg.sender == admin, - "only pause guardian and admin can pause" - ); - require(msg.sender == admin || state == true, "only admin can unpause"); - - mintGuardianPaused[address(cToken)] = state; - emit ActionPaused(cToken, "Mint", state); - return state; - } - - function _setBorrowPaused(CToken cToken, bool state) public returns (bool) { - require( - markets[address(cToken)].isListed, - "cannot pause a market that is not listed" - ); - require( - msg.sender == pauseGuardian || msg.sender == admin, - "only pause guardian and admin can pause" - ); - require(msg.sender == admin || state == true, "only admin can unpause"); - - borrowGuardianPaused[address(cToken)] = state; - emit ActionPaused(cToken, "Borrow", state); - return state; - } - - function _setTransferPaused(bool state) public returns (bool) { - require( - msg.sender == pauseGuardian || msg.sender == admin, - "only pause guardian and admin can pause" - ); - require(msg.sender == admin || state == true, "only admin can unpause"); - - transferGuardianPaused = state; - emit ActionPaused("Transfer", state); - return state; - } - - function _setSeizePaused(bool state) public returns (bool) { - require( - msg.sender == pauseGuardian || msg.sender == admin, - "only pause guardian and admin can pause" - ); - require(msg.sender == admin || state == true, "only admin can unpause"); - - seizeGuardianPaused = state; - emit ActionPaused("Seize", state); - return state; - } - - function _become(Unitroller unitroller) public { - require( - msg.sender == unitroller.admin(), - "only unitroller admin can change brains" - ); - - uint256 changeStatus = unitroller._acceptImplementation(); - require(changeStatus == 0, "change not authorized"); - } -} diff --git a/flatten/ComptrollerG3.sol b/flatten/ComptrollerG3.sol deleted file mode 100644 index 36c9c66..0000000 --- a/flatten/ComptrollerG3.sol +++ /dev/null @@ -1,6608 +0,0 @@ -// Dependency file: contracts/ComptrollerInterface.sol - -// SPDX-License-Identifier: UNLICENSED -// pragma solidity 0.8.6; - -abstract contract ComptrollerInterface { - /// @notice Indicator that this is a Comptroller contract (for inspection) - bool public constant isComptroller = true; - - /*** Assets You Are In ***/ - - function enterMarkets(address[] calldata cTokens) - external - virtual - returns (uint256[] memory); - - function exitMarket(address cToken) external virtual returns (uint256); - - /*** Policy Hooks ***/ - - function mintAllowed( - address cToken, - address minter, - uint256 mintAmount - ) external virtual returns (uint256); - - function mintVerify( - address cToken, - address minter, - uint256 mintAmount, - uint256 mintTokens - ) external virtual; - - function redeemAllowed( - address cToken, - address redeemer, - uint256 redeemTokens - ) external virtual returns (uint256); - - function redeemVerify( - address cToken, - address redeemer, - uint256 redeemAmount, - uint256 redeemTokens - ) external virtual; - - function borrowAllowed( - address cToken, - address borrower, - uint256 borrowAmount - ) external virtual returns (uint256); - - function borrowVerify( - address cToken, - address borrower, - uint256 borrowAmount - ) external virtual; - - function repayBorrowAllowed( - address cToken, - address payer, - address borrower, - uint256 repayAmount - ) external virtual returns (uint256); - - function repayBorrowVerify( - address cToken, - address payer, - address borrower, - uint256 repayAmount, - uint256 borrowerIndex - ) external virtual; - - function liquidateBorrowAllowed( - address cTokenBorrowed, - address cTokenCollateral, - address liquidator, - address borrower, - uint256 repayAmount - ) external virtual returns (uint256); - - function liquidateBorrowVerify( - address cTokenBorrowed, - address cTokenCollateral, - address liquidator, - address borrower, - uint256 repayAmount, - uint256 seizeTokens - ) external virtual; - - function seizeAllowed( - address cTokenCollateral, - address cTokenBorrowed, - address liquidator, - address borrower, - uint256 seizeTokens - ) external virtual returns (uint256); - - function seizeVerify( - address cTokenCollateral, - address cTokenBorrowed, - address liquidator, - address borrower, - uint256 seizeTokens - ) external virtual; - - function transferAllowed( - address cToken, - address src, - address dst, - uint256 transferTokens - ) external virtual returns (uint256); - - function transferVerify( - address cToken, - address src, - address dst, - uint256 transferTokens - ) external virtual; - - /*** Liquidity/Liquidation Calculations ***/ - - function liquidateCalculateSeizeTokens( - address cTokenBorrowed, - address cTokenCollateral, - uint256 repayAmount - ) external view virtual returns (uint256, uint256); -} - - -// Dependency file: contracts/CarefulMath.sol - -// pragma solidity 0.8.6; - -/** - * @title Careful Math - * @author tropykus - * @notice Derived from OpenZeppelin's SafeMath library - * https://github.com/OpenZeppelin/openzeppelin-solidity/blob/master/contracts/math/SafeMath.sol - */ -contract CarefulMath { - - /** - * @dev Possible error codes that we can return - */ - enum MathError { - NO_ERROR, - DIVISION_BY_ZERO, - INTEGER_OVERFLOW, - INTEGER_UNDERFLOW - } - - /** - * @dev Multiplies two numbers, returns an error on overflow. - */ - function mulUInt(uint a, uint b) internal pure returns (MathError, uint) { - if (a == 0) { - return (MathError.NO_ERROR, 0); - } - - uint c = a * b; - - if (c / a != b) { - return (MathError.INTEGER_OVERFLOW, 0); - } else { - return (MathError.NO_ERROR, c); - } - } - - /** - * @dev Integer division of two numbers, truncating the quotient. - */ - function divUInt(uint a, uint b) internal pure returns (MathError, uint) { - if (b == 0) { - return (MathError.DIVISION_BY_ZERO, 0); - } - - return (MathError.NO_ERROR, a / b); - } - - /** - * @dev Subtracts two numbers, returns an error on overflow (i.e. if subtrahend is greater than minuend). - */ - function subUInt(uint a, uint b) internal pure returns (MathError, uint) { - if (b <= a) { - return (MathError.NO_ERROR, a - b); - } else { - return (MathError.INTEGER_UNDERFLOW, 0); - } - } - - /** - * @dev Adds two numbers, returns an error on overflow. - */ - function addUInt(uint a, uint b) internal pure returns (MathError, uint) { - uint c = a + b; - - if (c >= a) { - return (MathError.NO_ERROR, c); - } else { - return (MathError.INTEGER_OVERFLOW, 0); - } - } - - /** - * @dev add a and b and then subtract c - */ - function addThenSubUInt(uint a, uint b, uint c) internal pure returns (MathError, uint) { - (MathError err0, uint sum) = addUInt(a, b); - - if (err0 != MathError.NO_ERROR) { - return (err0, 0); - } - - return subUInt(sum, c); - } -} - - -// Dependency file: contracts/ExponentialNoError.sol - -// pragma solidity 0.8.6; - -/** - * @title Exponential module for storing fixed-precision decimals - * @author tropykus - * @notice Exp is a struct which stores decimals with a fixed precision of 18 decimal places. - * Thus, if we wanted to store the 5.1, mantissa would store 5.1e18. That is: - * `Exp({mantissa: 5100000000000000000})`. - */ -contract ExponentialNoError { - uint constant expScale = 1e18; - uint constant doubleScale = 1e36; - uint constant halfExpScale = expScale/2; - uint constant mantissaOne = expScale; - - struct Exp { - uint mantissa; - } - - struct Double { - uint mantissa; - } - - /** - * @dev Truncates the given exp to a whole number value. - * For example, truncate(Exp{mantissa: 15 * expScale}) = 15 - */ - function truncate(Exp memory exp) pure internal returns (uint) { - // Note: We are not using careful math here as we're performing a division that cannot fail - return exp.mantissa / expScale; - } - - /** - * @dev Multiply an Exp by a scalar, then truncate to return an unsigned integer. - */ - function mul_ScalarTruncate(Exp memory a, uint scalar) pure internal returns (uint) { - Exp memory product = mul_(a, scalar); - return truncate(product); - } - - /** - * @dev Multiply an Exp by a scalar, truncate, then add an to an unsigned integer, returning an unsigned integer. - */ - function mul_ScalarTruncateAddUInt(Exp memory a, uint scalar, uint addend) pure internal returns (uint) { - Exp memory product = mul_(a, scalar); - return add_(truncate(product), addend); - } - - /** - * @dev Checks if first Exp is less than second Exp. - */ - function lessThanExp(Exp memory left, Exp memory right) pure internal returns (bool) { - return left.mantissa < right.mantissa; - } - - /** - * @dev Checks if left Exp <= right Exp. - */ - function lessThanOrEqualExp(Exp memory left, Exp memory right) pure internal returns (bool) { - return left.mantissa <= right.mantissa; - } - - /** - * @dev Checks if left Exp > right Exp. - */ - function greaterThanExp(Exp memory left, Exp memory right) pure internal returns (bool) { - return left.mantissa > right.mantissa; - } - - /** - * @dev returns true if Exp is exactly zero - */ - function isZeroExp(Exp memory value) pure internal returns (bool) { - return value.mantissa == 0; - } - - function safe224(uint n, string memory errorMessage) pure internal returns (uint224) { - require(n < 2**224, errorMessage); - return uint224(n); - } - - function safe32(uint n, string memory errorMessage) pure internal returns (uint32) { - require(n < 2**32, errorMessage); - return uint32(n); - } - - function add_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { - return Exp({mantissa: add_(a.mantissa, b.mantissa)}); - } - - function add_(Double memory a, Double memory b) pure internal returns (Double memory) { - return Double({mantissa: add_(a.mantissa, b.mantissa)}); - } - - function add_(uint a, uint b) pure internal returns (uint) { - return add_(a, b, "addition overflow"); - } - - function add_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { - uint c = a + b; - require(c >= a, errorMessage); - return c; - } - - function sub_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { - return Exp({mantissa: sub_(a.mantissa, b.mantissa)}); - } - - function sub_(Double memory a, Double memory b) pure internal returns (Double memory) { - return Double({mantissa: sub_(a.mantissa, b.mantissa)}); - } - - function sub_(uint a, uint b) pure internal returns (uint) { - return sub_(a, b, "subtraction underflow"); - } - - function sub_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { - require(b <= a, errorMessage); - return a - b; - } - - function mul_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { - return Exp({mantissa: mul_(a.mantissa, b.mantissa) / expScale}); - } - - function mul_(Exp memory a, uint b) pure internal returns (Exp memory) { - return Exp({mantissa: mul_(a.mantissa, b)}); - } - - function mul_(uint a, Exp memory b) pure internal returns (uint) { - return mul_(a, b.mantissa) / expScale; - } - - function mul_(Double memory a, Double memory b) pure internal returns (Double memory) { - return Double({mantissa: mul_(a.mantissa, b.mantissa) / doubleScale}); - } - - function mul_(Double memory a, uint b) pure internal returns (Double memory) { - return Double({mantissa: mul_(a.mantissa, b)}); - } - - function mul_(uint a, Double memory b) pure internal returns (uint) { - return mul_(a, b.mantissa) / doubleScale; - } - - function mul_(uint a, uint b) pure internal returns (uint) { - return mul_(a, b, "multiplication overflow"); - } - - function mul_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { - if (a == 0 || b == 0) { - return 0; - } - uint c = a * b; - require(c / a == b, errorMessage); - return c; - } - - function div_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { - return Exp({mantissa: div_(mul_(a.mantissa, expScale), b.mantissa)}); - } - - function div_(Exp memory a, uint b) pure internal returns (Exp memory) { - return Exp({mantissa: div_(a.mantissa, b)}); - } - - function div_(uint a, Exp memory b) pure internal returns (uint) { - return div_(mul_(a, expScale), b.mantissa); - } - - function div_(Double memory a, Double memory b) pure internal returns (Double memory) { - return Double({mantissa: div_(mul_(a.mantissa, doubleScale), b.mantissa)}); - } - - function div_(Double memory a, uint b) pure internal returns (Double memory) { - return Double({mantissa: div_(a.mantissa, b)}); - } - - function div_(uint a, Double memory b) pure internal returns (uint) { - return div_(mul_(a, doubleScale), b.mantissa); - } - - function div_(uint a, uint b) pure internal returns (uint) { - return div_(a, b, "divide by zero"); - } - - function div_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { - require(b > 0, errorMessage); - return a / b; - } - - function fraction(uint a, uint b) pure internal returns (Double memory) { - return Double({mantissa: div_(mul_(a, doubleScale), b)}); - } -} - - -// Dependency file: contracts/Exponential.sol - -// pragma solidity 0.8.6; - -// import "contracts/CarefulMath.sol"; -// import "contracts/ExponentialNoError.sol"; - -/** - * @title Exponential module for storing fixed-precision decimals - * @author tropykus - * @dev Legacy contract for compatibility reasons with existing contracts that still use MathError - * @notice Exp is a struct which stores decimals with a fixed precision of 18 decimal places. - * Thus, if we wanted to store the 5.1, mantissa would store 5.1e18. That is: - * `Exp({mantissa: 5100000000000000000})`. - */ -contract Exponential is CarefulMath, ExponentialNoError { - /** - * @dev Creates an exponential from numerator and denominator values. - * Note: Returns an error if (`num` * 10e18) > MAX_INT, - * or if `denom` is zero. - */ - function getExp(uint num, uint denom) internal pure returns (MathError, Exp memory) { - (MathError err0, uint scaledNumerator) = mulUInt(num, expScale); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - - (MathError err1, uint rational) = divUInt(scaledNumerator, denom); - if (err1 != MathError.NO_ERROR) { - return (err1, Exp({mantissa: 0})); - } - - return (MathError.NO_ERROR, Exp({mantissa: rational})); - } - - /** - * @dev Adds two exponentials, returning a new exponential. - */ - function addExp(Exp memory a, Exp memory b) internal pure returns (MathError, Exp memory) { - (MathError error, uint result) = addUInt(a.mantissa, b.mantissa); - - return (error, Exp({mantissa: result})); - } - - /** - * @dev Subtracts two exponentials, returning a new exponential. - */ - function subExp(Exp memory a, Exp memory b) internal pure returns (MathError, Exp memory) { - (MathError error, uint result) = subUInt(a.mantissa, b.mantissa); - - return (error, Exp({mantissa: result})); - } - - /** - * @dev Multiply an Exp by a scalar, returning a new Exp. - */ - function mulScalar(Exp memory a, uint scalar) internal pure returns (MathError, Exp memory) { - (MathError err0, uint scaledMantissa) = mulUInt(a.mantissa, scalar); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - - return (MathError.NO_ERROR, Exp({mantissa: scaledMantissa})); - } - - /** - * @dev Multiply an Exp by a scalar, then truncate to return an unsigned integer. - */ - function mulScalarTruncate(Exp memory a, uint scalar) internal pure returns (MathError, uint) { - (MathError err, Exp memory product) = mulScalar(a, scalar); - if (err != MathError.NO_ERROR) { - return (err, 0); - } - - return (MathError.NO_ERROR, truncate(product)); - } - - /** - * @dev Multiply an Exp by a scalar, truncate, then add an to an unsigned integer, returning an unsigned integer. - */ - function mulScalarTruncateAddUInt(Exp memory a, uint scalar, uint addend) internal pure returns (MathError, uint) { - (MathError err, Exp memory product) = mulScalar(a, scalar); - if (err != MathError.NO_ERROR) { - return (err, 0); - } - - return addUInt(truncate(product), addend); - } - - /** - * @dev Divide an Exp by a scalar, returning a new Exp. - */ - function divScalar(Exp memory a, uint scalar) internal pure returns (MathError, Exp memory) { - (MathError err0, uint descaledMantissa) = divUInt(a.mantissa, scalar); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - - return (MathError.NO_ERROR, Exp({mantissa: descaledMantissa})); - } - - /** - * @dev Divide a scalar by an Exp, returning a new Exp. - */ - function divScalarByExp(uint scalar, Exp memory divisor) internal pure returns (MathError, Exp memory) { - /* - We are doing this as: - getExp(mulUInt(expScale, scalar), divisor.mantissa) - - How it works: - Exp = a / b; - Scalar = s; - `s / (a / b)` = `b * s / a` and since for an Exp `a = mantissa, b = expScale` - */ - (MathError err0, uint numerator) = mulUInt(expScale, scalar); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - return getExp(numerator, divisor.mantissa); - } - - /** - * @dev Divide a scalar by an Exp, then truncate to return an unsigned integer. - */ - function divScalarByExpTruncate(uint scalar, Exp memory divisor) internal pure returns (MathError, uint) { - (MathError err, Exp memory fraction) = divScalarByExp(scalar, divisor); - if (err != MathError.NO_ERROR) { - return (err, 0); - } - - return (MathError.NO_ERROR, truncate(fraction)); - } - - /** - * @dev Multiplies two exponentials, returning a new exponential. - */ - function mulExp(Exp memory a, Exp memory b) internal pure returns (MathError, Exp memory) { - - (MathError err0, uint doubleScaledProduct) = mulUInt(a.mantissa, b.mantissa); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - - // We add half the scale before dividing so that we get rounding instead of truncation. - // See "Listing 6" and text above it at https://accu.org/index.php/journals/1717 - // Without this change, a result like 6.6...e-19 will be truncated to 0 instead of being rounded to 1e-18. - (MathError err1, uint doubleScaledProductWithHalfScale) = addUInt(halfExpScale, doubleScaledProduct); - if (err1 != MathError.NO_ERROR) { - return (err1, Exp({mantissa: 0})); - } - - (MathError err2, uint product) = divUInt(doubleScaledProductWithHalfScale, expScale); - // The only error `div` can return is MathError.DIVISION_BY_ZERO but we control `expScale` and it is not zero. - assert(err2 == MathError.NO_ERROR); - - return (MathError.NO_ERROR, Exp({mantissa: product})); - } - - /** - * @dev Multiplies two exponentials given their mantissas, returning a new exponential. - */ - function mulExp(uint a, uint b) internal pure returns (MathError, Exp memory) { - return mulExp(Exp({mantissa: a}), Exp({mantissa: b})); - } - - /** - * @dev Multiplies three exponentials, returning a new exponential. - */ - function mulExp3(Exp memory a, Exp memory b, Exp memory c) internal pure returns (MathError, Exp memory) { - (MathError err, Exp memory ab) = mulExp(a, b); - if (err != MathError.NO_ERROR) { - return (err, ab); - } - return mulExp(ab, c); - } - - /** - * @dev Divides two exponentials, returning a new exponential. - * (a/scale) / (b/scale) = (a/scale) * (scale/b) = a/b, - * which we can scale as an Exp by calling getExp(a.mantissa, b.mantissa) - */ - function divExp(Exp memory a, Exp memory b) internal pure returns (MathError, Exp memory) { - return getExp(a.mantissa, b.mantissa); - } -} - - -// Dependency file: contracts/SafeMath.sol - -// pragma solidity 0.8.6; - -// From https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/math/Math.sol -// Subject to the MIT license. - -/** - * @dev Wrappers over Solidity's arithmetic operations with added overflow - * checks. - * - * Arithmetic operations in Solidity wrap on overflow. This can easily result - * in bugs, because programmers usually assume that an overflow raises an - * error, which is the standard behavior in high level programming languages. - * `SafeMath` restores this intuition by reverting the transaction when an - * operation overflows. - * - * Using this library instead of the unchecked operations eliminates an entire - * class of bugs, so it's recommended to use it always. - */ -library SafeMath { - /** - * @dev Returns the addition of two unsigned integers, reverting on overflow. - * - * Counterpart to Solidity's `+` operator. - * - * Requirements: - * - Addition cannot overflow. - */ - function add(uint256 a, uint256 b) internal pure returns (uint256) { - uint256 c = a + b; - require(c >= a, "SafeMath: addition overflow"); - - return c; - } - - /** - * @dev Returns the addition of two unsigned integers, reverting with custom message on overflow. - * - * Counterpart to Solidity's `+` operator. - * - * Requirements: - * - Addition cannot overflow. - */ - function add(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - uint256 c = a + b; - require(c >= a, errorMessage); - - return c; - } - - /** - * @dev Returns the subtraction of two unsigned integers, reverting on underflow (when the result is negative). - * - * Counterpart to Solidity's `-` operator. - * - * Requirements: - * - Subtraction cannot underflow. - */ - function sub(uint256 a, uint256 b) internal pure returns (uint256) { - return sub(a, b, "SafeMath: subtraction underflow"); - } - - /** - * @dev Returns the subtraction of two unsigned integers, reverting with custom message on underflow (when the result is negative). - * - * Counterpart to Solidity's `-` operator. - * - * Requirements: - * - Subtraction cannot underflow. - */ - function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - require(b <= a, errorMessage); - uint256 c = a - b; - - return c; - } - - /** - * @dev Returns the multiplication of two unsigned integers, reverting on overflow. - * - * Counterpart to Solidity's `*` operator. - * - * Requirements: - * - Multiplication cannot overflow. - */ - function mul(uint256 a, uint256 b) internal pure returns (uint256) { - // Gas optimization: this is cheaper than requiring 'a' not being zero, but the - // benefit is lost if 'b' is also tested. - // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 - if (a == 0) { - return 0; - } - - uint256 c = a * b; - require(c / a == b, "SafeMath: multiplication overflow"); - - return c; - } - - /** - * @dev Returns the multiplication of two unsigned integers, reverting on overflow. - * - * Counterpart to Solidity's `*` operator. - * - * Requirements: - * - Multiplication cannot overflow. - */ - function mul(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - // Gas optimization: this is cheaper than requiring 'a' not being zero, but the - // benefit is lost if 'b' is also tested. - // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 - if (a == 0) { - return 0; - } - - uint256 c = a * b; - require(c / a == b, errorMessage); - - return c; - } - - /** - * @dev Returns the integer division of two unsigned integers. - * Reverts on division by zero. The result is rounded towards zero. - * - * Counterpart to Solidity's `/` operator. Note: this function uses a - * `revert` opcode (which leaves remaining gas untouched) while Solidity - * uses an invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function div(uint256 a, uint256 b) internal pure returns (uint256) { - return div(a, b, "SafeMath: division by zero"); - } - - /** - * @dev Returns the integer division of two unsigned integers. - * Reverts with custom message on division by zero. The result is rounded towards zero. - * - * Counterpart to Solidity's `/` operator. Note: this function uses a - * `revert` opcode (which leaves remaining gas untouched) while Solidity - * uses an invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - // Solidity only automatically asserts when dividing by 0 - require(b > 0, errorMessage); - uint256 c = a / b; - // assert(a == b * c + a % b); // There is no case in which this doesn't hold - - return c; - } - - /** - * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), - * Reverts when dividing by zero. - * - * Counterpart to Solidity's `%` operator. This function uses a `revert` - * opcode (which leaves remaining gas untouched) while Solidity uses an - * invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function mod(uint256 a, uint256 b) internal pure returns (uint256) { - return mod(a, b, "SafeMath: modulo by zero"); - } - - /** - * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), - * Reverts with custom message when dividing by zero. - * - * Counterpart to Solidity's `%` operator. This function uses a `revert` - * opcode (which leaves remaining gas untouched) while Solidity uses an - * invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - require(b != 0, errorMessage); - return a % b; - } -} - - -// Dependency file: contracts/InterestRateModel.sol - -// pragma solidity 0.8.6; - -// import "contracts/Exponential.sol"; -// import "contracts/SafeMath.sol"; - -/** - * @title tropykus InterestRateModel Interface - * @author tropykus - */ -abstract contract InterestRateModel is Exponential { - using SafeMath for uint256; - - /// @notice Indicator that this is an InterestRateModel contract (for inspection) - bool public constant isInterestRateModel = true; - bool public isTropykusInterestRateModel; - - /** - * @notice The approximate number of blocks per year that is assumed by the interest rate model - */ - uint256 public constant blocksPerYear = 1051200; - - /** - * @notice Calculates the utilization rate of the market: `borrows / (cash + borrows - reserves)` - * @param cash The amount of cash in the market - * @param borrows The amount of borrows in the market - * @param reserves The amount of reserves in the market (currently unused) - * @return The utilization rate as a mantissa between [0, 1e18] - */ - function utilizationRate( - uint256 cash, - uint256 borrows, - uint256 reserves - ) public pure virtual returns (uint256) { - // Utilization rate is 0 when there are no borrows - if (borrows == 0) { - return 0; - } - - return borrows.mul(1e18).div(cash.add(borrows).sub(reserves)); - } - - /** - * @notice Calculates the current borrow interest rate per block - * @param cash The total amount of cash the market has - * @param borrows The total amount of borrows the market has outstanding - * @param reserves The total amnount of reserves the market has - * @return The borrow rate per block (as a percentage, and scaled by 1e18) - */ - function getBorrowRate( - uint256 cash, - uint256 borrows, - uint256 reserves - ) external view virtual returns (uint256); - - /** - * @notice Calculates the current supply interest rate per block - * @param cash The total amount of cash the market has - * @param borrows The total amount of borrows the market has outstanding - * @param reserves The total amnount of reserves the market has - * @param reserveFactorMantissa The current reserve factor the market has - * @return The supply rate per block (as a percentage, and scaled by 1e18) - */ - function getSupplyRate( - uint256 cash, - uint256 borrows, - uint256 reserves, - uint256 reserveFactorMantissa - ) external view virtual returns (uint256); - - function getExchangeRate( - uint256 _totalCash, - uint256 _totalBorrows, - uint256 _totalReserves, - uint256 _totalSupply - ) public pure returns (MathError, uint256) { - /* - * exchangeRate = (totalCash + totalBorrows - totalReserves) / totalSupply - */ - Exp memory exchangeRate; - MathError mathErr; - uint256 cashPlusBorrowsMinusReserves; - (mathErr, cashPlusBorrowsMinusReserves) = addThenSubUInt( - _totalCash, - _totalBorrows, - _totalReserves - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - (mathErr, exchangeRate) = getExp( - cashPlusBorrowsMinusReserves, - _totalSupply - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - - return (MathError.NO_ERROR, exchangeRate.mantissa); - } - - function isAboveOptimal( - uint256 cash, - uint256 borrows, - uint256 reserves - ) public view virtual returns (bool) { - cash; - borrows; - reserves; - return false; - } -} - - -// Dependency file: contracts/EIP20NonStandardInterface.sol - -// pragma solidity 0.8.6; - -/** - * @title EIP20NonStandardInterface - * @dev Version of ERC20 with no return values for `transfer` and `transferFrom` - * See https://medium.com/coinmonks/missing-return-value-bug-at-least-130-tokens-affected-d67bf08521ca - */ -interface EIP20NonStandardInterface { - /** - * @notice Get the total number of tokens in circulation - * @return The supply of tokens - */ - function totalSupply() external view returns (uint256); - - /** - * @notice Gets the balance of the specified address - * @param owner The address from which the balance will be retrieved - * @return balance The balance - */ - function balanceOf(address owner) external view returns (uint256 balance); - - /// - /// !!!!!!!!!!!!!! - /// !!! NOTICE !!! `transfer` does not return a value, in violation of the ERC-20 specification - /// !!!!!!!!!!!!!! - /// - - /** - * @notice Transfer `amount` tokens from `msg.sender` to `dst` - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - */ - function transfer(address dst, uint256 amount) external; - - /// - /// !!!!!!!!!!!!!! - /// !!! NOTICE !!! `transferFrom` does not return a value, in violation of the ERC-20 specification - /// !!!!!!!!!!!!!! - /// - - /** - * @notice Transfer `amount` tokens from `src` to `dst` - * @param src The address of the source account - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - */ - function transferFrom( - address src, - address dst, - uint256 amount - ) external; - - /** - * @notice Approve `spender` to transfer up to `amount` from `src` - * @dev This will overwrite the approval amount for `spender` - * and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve) - * @param spender The address of the account which may transfer tokens - * @param amount The number of tokens that are approved - * @return success Whether or not the approval succeeded - */ - function approve(address spender, uint256 amount) - external - returns (bool success); - - /** - * @notice Get the current allowance from `owner` for `spender` - * @param owner The address of the account which owns the tokens to be spent - * @param spender The address of the account which may transfer tokens - * @return remaining The number of tokens allowed to be spent - */ - function allowance(address owner, address spender) - external - view - returns (uint256 remaining); - - event Transfer(address indexed from, address indexed to, uint256 amount); - event Approval( - address indexed owner, - address indexed spender, - uint256 amount - ); -} - - -// Dependency file: contracts/CTokenInterfaces.sol - -// pragma solidity 0.8.6; - -// import "contracts/ComptrollerInterface.sol"; -// import "contracts/InterestRateModel.sol"; -// import "contracts/EIP20NonStandardInterface.sol"; - -contract CTokenStorage { - /** - * @dev Guard variable for re-entrancy checks - */ - bool internal _notEntered; - - /** - * @notice EIP-20 token name for this token - */ - string public name; - - /** - * @notice EIP-20 token symbol for this token - */ - string public symbol; - - /** - * @notice EIP-20 token decimals for this token - */ - uint8 public decimals; - - /** - * @notice Maximum borrow rate that can ever be applied (.0005% / block) - */ - - uint256 internal constant borrowRateMaxMantissa = 0.0005e16; - - /** - * @notice Maximum fraction of interest that can be set aside for reserves - */ - uint256 internal constant reserveFactorMaxMantissa = 1e18; - - /** - * @notice Administrator for this contract - */ - address payable public admin; - - /** - * @notice Pending administrator for this contract - */ - address payable public pendingAdmin; - - /** - * @notice Contract which oversees inter-cToken operations - */ - ComptrollerInterface public comptroller; - - /** - * @notice Model which tells what the current interest rate should be - */ - InterestRateModel public interestRateModel; - - /** - * @notice Initial exchange rate used when minting the first CTokens (used when totalSupply = 0) - */ - uint256 public initialExchangeRateMantissa; - - /** - * @notice Fraction of interest currently set aside for reserves - */ - uint256 public reserveFactorMantissa; - - /** - * @notice Block number that interest was last accrued at - */ - uint256 public accrualBlockNumber; - - /** - * @notice Accumulator of the total earned interest rate since the opening of the market - */ - uint256 public borrowIndex; - - /** - * @notice Total amount of outstanding borrows of the underlying in this market - */ - uint256 public totalBorrows; - - /** - * @notice Total amount of reserves of the underlying held in this market - */ - uint256 public totalReserves; - - /** - * @notice Total number of tokens in circulation - */ - uint256 public totalSupply; - - uint256 public subsidyFund; - - struct SupplySnapshot { - uint256 tokens; - uint256 underlyingAmount; - uint256 suppliedAt; - uint256 promisedSupplyRate; - } - - /** - * @notice Official record of token balances for each account - */ - mapping(address => SupplySnapshot) internal accountTokens; - - /** - * @notice Approved token transfer amounts on behalf of others - */ - mapping(address => mapping(address => uint256)) internal transferAllowances; - - /** - * @notice Container for borrow balance information - * @member principal Total balance (with accrued interest), after applying the most recent balance-changing action - * @member interestIndex Global borrowIndex as of the most recent balance-changing action - */ - struct BorrowSnapshot { - uint256 principal; - uint256 interestIndex; - } - - /** - * @notice Mapping of account addresses to outstanding borrow balances - */ - mapping(address => BorrowSnapshot) internal accountBorrows; -} - -abstract contract CTokenInterface is CTokenStorage { - /** - * @notice Indicator that this is a CToken contract (for inspection) - */ - bool public constant isCToken = true; - - /*** Market Events ***/ - - /** - * @notice Event emitted when interest is accrued - */ - event AccrueInterest( - uint256 cashPrior, - uint256 interestAccumulated, - uint256 borrowIndex, - uint256 totalBorrows - ); - - /** - * @notice Event emitted when tokens are minted - */ - event Mint(address indexed minter, uint256 mintAmount, uint256 mintTokens); - - /** - * @notice Event emitted when tokens are redeemed - */ - event Redeem( - address indexed redeemer, - uint256 redeemAmount, - uint256 redeemTokens - ); - - /** - * @notice Event emitted when underlying is borrowed - */ - event Borrow( - address indexed borrower, - uint256 borrowAmount, - uint256 accountBorrows, - uint256 totalBorrows - ); - - /** - * @notice Event emitted when a borrow is repaid - */ - event RepayBorrow( - address indexed payer, - address indexed borrower, - uint256 repayAmount, - uint256 accountBorrows, - uint256 totalBorrows - ); - - /** - * @notice Event emitted when a borrow is liquidated - */ - event LiquidateBorrow( - address indexed liquidator, - address indexed borrower, - uint256 repayAmount, - address indexed cTokenCollateral, - uint256 seizeTokens - ); - - /*** Admin Events ***/ - - /** - * @notice Event emitted when pendingAdmin is changed - */ - event NewPendingAdmin(address oldPendingAdmin, address newPendingAdmin); - - /** - * @notice Event emitted when pendingAdmin is accepted, which means admin is updated - */ - event NewAdmin(address oldAdmin, address newAdmin); - - /** - * @notice Event emitted when comptroller is changed - */ - event NewComptroller( - ComptrollerInterface oldComptroller, - ComptrollerInterface newComptroller - ); - - /** - * @notice Event emitted when interestRateModel is changed - */ - event NewMarketInterestRateModel( - InterestRateModel oldInterestRateModel, - InterestRateModel newInterestRateModel - ); - - /** - * @notice Event emitted when the reserve factor is changed - */ - event NewReserveFactor( - uint256 oldReserveFactorMantissa, - uint256 newReserveFactorMantissa - ); - - /** - * @notice Event emitted when the reserves are added - */ - event ReservesAdded( - address benefactor, - uint256 addAmount, - uint256 newTotalReserves - ); - - event SubsidyAdded( - address benefactor, - uint256 addAmount, - uint256 newSubsidyFund - ); - - /** - * @notice Event emitted when the reserves are reduced - */ - event ReservesReduced( - address admin, - uint256 reduceAmount, - uint256 newTotalReserves - ); - - /** - * @notice EIP20 Transfer event - */ - event Transfer(address indexed from, address indexed to, uint256 amount); - - /** - * @notice EIP20 Approval event - */ - event Approval( - address indexed owner, - address indexed spender, - uint256 amount - ); - - /** - * @notice Failure event - */ - event CTokenStorageFailure(uint256 error, uint256 info, uint256 detail); - - /*** User Interface ***/ - - function transfer(address dst, uint256 amount) - external - virtual - returns (bool); - - function transferFrom( - address src, - address dst, - uint256 amount - ) external virtual returns (bool); - - function approve(address spender, uint256 amount) - external - virtual - returns (bool); - - function allowance(address owner, address spender) - external - view - virtual - returns (uint256); - - function balanceOf(address owner) external view virtual returns (uint256); - - function balanceOfUnderlying(address owner) - external - virtual - returns (uint256); - - function getAccountSnapshot(address account) - external - view - virtual - returns ( - uint256, - uint256, - uint256, - uint256 - ); - - function borrowRatePerBlock() external view virtual returns (uint256); - - function supplyRatePerBlock() external view virtual returns (uint256); - - function totalBorrowsCurrent() external virtual returns (uint256); - - function borrowBalanceCurrent(address account) - external - virtual - returns (uint256); - - function borrowBalanceStored(address account) - public - view - virtual - returns (uint256); - - function exchangeRateCurrent() public virtual returns (uint256); - - function exchangeRateStored() public view virtual returns (uint256); - - function getCash() external view virtual returns (uint256); - - function accrueInterest() public virtual returns (uint256); - - function seize( - address liquidator, - address borrower, - uint256 seizeTokens - ) external virtual returns (uint256); - - /*** Admin Functions ***/ - - function _setPendingAdmin(address payable newPendingAdmin) - external - virtual - returns (uint256); - - function _acceptAdmin() external virtual returns (uint256); - - function _setComptroller(ComptrollerInterface newComptroller) - public - virtual - returns (uint256); - - function _setReserveFactor(uint256 newReserveFactorMantissa) - external - virtual - returns (uint256); - - function _reduceReserves(uint256 reduceAmount) - external - virtual - returns (uint256); - - function _setInterestRateModel(InterestRateModel newInterestRateModel) - public - virtual - returns (uint256); -} - -contract CErc20Storage { - /** - * @notice Underlying asset for this CToken - */ - address public underlying; -} - -abstract contract CErc20Interface is CErc20Storage { - /*** User Interface ***/ - - function mint(uint256 mintAmount) external virtual returns (uint256); - - function redeem(uint256 redeemAmount) - external - virtual - returns (uint256); - - function borrow(uint256 borrowAmount) external virtual returns (uint256); - - function repayBorrow(uint256 repayAmount) - external - virtual - returns (uint256); - - function liquidateBorrow( - address borrower, - uint256 repayAmount, - CTokenInterface cTokenCollateral - ) external virtual returns (uint256); - - function sweepToken(EIP20NonStandardInterface token) external virtual; - - /*** Admin Functions ***/ - - function _addReserves(uint256 addAmount) external virtual returns (uint256); -} - -contract CDelegationStorage { - /** - * @notice Implementation address for this contract - */ - address public implementation; -} - -abstract contract CDelegatorInterface is CDelegationStorage { - /** - * @notice Emitted when implementation is changed - */ - event NewImplementation( - address oldImplementation, - address newImplementation - ); - - /** - * @notice Called by the admin to update the implementation of the delegator - * @param implementation_ The address of the new implementation for delegation - * @param allowResign Flag to indicate whether to call _resignImplementation on the old implementation - * @param becomeImplementationData The encoded bytes data to be passed to _becomeImplementation - */ - function _setImplementation( - address implementation_, - bool allowResign, - bytes memory becomeImplementationData - ) public virtual; -} - -abstract contract CDelegateInterface is CDelegationStorage { - /** - * @notice Called by the delegator on a delegate to initialize it for duty - * @dev Should revert if any issues arise which make it unfit for delegation - * @param data The encoded bytes data for any initialization - */ - function _becomeImplementation(bytes memory data) public virtual; - - /** - * @notice Called by the delegator on a delegate to forfeit its responsibility - */ - function _resignImplementation() public virtual; -} - - -// Dependency file: contracts/ErrorReporter.sol - -// pragma solidity 0.8.6; - -contract ComptrollerErrorReporter { - enum Error { - NO_ERROR, - UNAUTHORIZED, - COMPTROLLER_MISMATCH, - INSUFFICIENT_SHORTFALL, - INSUFFICIENT_LIQUIDITY, - INVALID_CLOSE_FACTOR, - INVALID_COLLATERAL_FACTOR, - INVALID_LIQUIDATION_INCENTIVE, - MARKET_NOT_ENTERED, // no longer possible - MARKET_NOT_LISTED, - MARKET_ALREADY_LISTED, - MATH_ERROR, - NONZERO_BORROW_BALANCE, - PRICE_ERROR, - REJECTION, - SNAPSHOT_ERROR, - TOO_MANY_ASSETS, - TOO_MUCH_REPAY - } - - enum FailureInfo { - ACCEPT_ADMIN_PENDING_ADMIN_CHECK, - ACCEPT_PENDING_IMPLEMENTATION_ADDRESS_CHECK, - EXIT_MARKET_BALANCE_OWED, - EXIT_MARKET_REJECTION, - SET_CLOSE_FACTOR_OWNER_CHECK, - SET_CLOSE_FACTOR_VALIDATION, - SET_COLLATERAL_FACTOR_OWNER_CHECK, - SET_COLLATERAL_FACTOR_NO_EXISTS, - SET_COLLATERAL_FACTOR_VALIDATION, - SET_COLLATERAL_FACTOR_WITHOUT_PRICE, - SET_IMPLEMENTATION_OWNER_CHECK, - SET_LIQUIDATION_INCENTIVE_OWNER_CHECK, - SET_LIQUIDATION_INCENTIVE_VALIDATION, - SET_MAX_ASSETS_OWNER_CHECK, - SET_PENDING_ADMIN_OWNER_CHECK, - SET_PENDING_IMPLEMENTATION_OWNER_CHECK, - SET_PRICE_ORACLE_OWNER_CHECK, - SUPPORT_MARKET_EXISTS, - SUPPORT_MARKET_OWNER_CHECK, - SET_PAUSE_GUARDIAN_OWNER_CHECK - } - - /** - * @dev `error` corresponds to enum Error; `info` corresponds to enum FailureInfo, and `detail` is an arbitrary - * contract-specific code that enables us to report opaque error codes from upgradeable contracts. - **/ - event Failure(uint256 error, uint256 info, uint256 detail); - - /** - * @dev use this when reporting a known error from the money market or a non-upgradeable collaborator - */ - function fail(Error err, FailureInfo info) internal returns (uint256) { - emit Failure(uint256(err), uint256(info), 0); - - return uint256(err); - } - - /** - * @dev use this when reporting an opaque error from an upgradeable collaborator contract - */ - function failOpaque( - Error err, - FailureInfo info, - uint256 opaqueError - ) internal returns (uint256) { - emit Failure(uint256(err), uint256(info), opaqueError); - - return uint256(err); - } -} - -contract TokenErrorReporter { - enum Error { - NO_ERROR, - UNAUTHORIZED, - BAD_INPUT, - COMPTROLLER_REJECTION, - COMPTROLLER_CALCULATION_ERROR, - INTEREST_RATE_MODEL_ERROR, - INVALID_ACCOUNT_PAIR, - INVALID_CLOSE_AMOUNT_REQUESTED, - INVALID_COLLATERAL_FACTOR, - MATH_ERROR, - MARKET_NOT_FRESH, - MARKET_NOT_LISTED, - TOKEN_INSUFFICIENT_ALLOWANCE, - TOKEN_INSUFFICIENT_BALANCE, - TOKEN_INSUFFICIENT_CASH, - TOKEN_TRANSFER_IN_FAILED, - TOKEN_TRANSFER_OUT_FAILED - } - - /* - * Note: FailureInfo (but not Error) is kept in alphabetical order - * This is because FailureInfo grows significantly faster, and - * the order of Error has some meaning, while the order of FailureInfo - * is entirely arbitrary. - */ - enum FailureInfo { - ACCEPT_ADMIN_PENDING_ADMIN_CHECK, - ACCRUE_INTEREST_ACCUMULATED_INTEREST_CALCULATION_FAILED, - ACCRUE_INTEREST_BORROW_RATE_CALCULATION_FAILED, - ACCRUE_INTEREST_NEW_BORROW_INDEX_CALCULATION_FAILED, - ACCRUE_INTEREST_NEW_TOTAL_BORROWS_CALCULATION_FAILED, - ACCRUE_INTEREST_NEW_TOTAL_RESERVES_CALCULATION_FAILED, - ACCRUE_INTEREST_SIMPLE_INTEREST_FACTOR_CALCULATION_FAILED, - BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED, - BORROW_ACCRUE_INTEREST_FAILED, - BORROW_CASH_NOT_AVAILABLE, - BORROW_FRESHNESS_CHECK, - BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED, - BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED, - BORROW_MARKET_NOT_LISTED, - BORROW_COMPTROLLER_REJECTION, - LIQUIDATE_ACCRUE_BORROW_INTEREST_FAILED, - LIQUIDATE_ACCRUE_COLLATERAL_INTEREST_FAILED, - LIQUIDATE_COLLATERAL_FRESHNESS_CHECK, - LIQUIDATE_COMPTROLLER_REJECTION, - LIQUIDATE_COMPTROLLER_CALCULATE_AMOUNT_SEIZE_FAILED, - LIQUIDATE_CLOSE_AMOUNT_IS_UINT_MAX, - LIQUIDATE_CLOSE_AMOUNT_IS_ZERO, - LIQUIDATE_FRESHNESS_CHECK, - LIQUIDATE_LIQUIDATOR_IS_BORROWER, - LIQUIDATE_REPAY_BORROW_FRESH_FAILED, - LIQUIDATE_SEIZE_BALANCE_INCREMENT_FAILED, - LIQUIDATE_SEIZE_BALANCE_DECREMENT_FAILED, - LIQUIDATE_SEIZE_COMPTROLLER_REJECTION, - LIQUIDATE_SEIZE_LIQUIDATOR_IS_BORROWER, - LIQUIDATE_SEIZE_TOO_MUCH, - MINT_ACCRUE_INTEREST_FAILED, - MINT_COMPTROLLER_REJECTION, - MINT_EXCHANGE_CALCULATION_FAILED, - MINT_EXCHANGE_RATE_READ_FAILED, - MINT_FRESHNESS_CHECK, - MINT_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED, - MINT_NEW_TOTAL_SUPPLY_CALCULATION_FAILED, - MINT_TRANSFER_IN_FAILED, - MINT_TRANSFER_IN_NOT_POSSIBLE, - REDEEM_ACCRUE_INTEREST_FAILED, - REDEEM_COMPTROLLER_REJECTION, - REDEEM_EXCHANGE_TOKENS_CALCULATION_FAILED, - REDEEM_EXCHANGE_AMOUNT_CALCULATION_FAILED, - REDEEM_EXCHANGE_RATE_READ_FAILED, - REDEEM_FRESHNESS_CHECK, - REDEEM_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED, - REDEEM_NEW_TOTAL_SUPPLY_CALCULATION_FAILED, - REDEEM_TRANSFER_OUT_NOT_POSSIBLE, - REDUCE_RESERVES_ACCRUE_INTEREST_FAILED, - REDUCE_RESERVES_ADMIN_CHECK, - REDUCE_RESERVES_CASH_NOT_AVAILABLE, - REDUCE_RESERVES_FRESH_CHECK, - REDUCE_RESERVES_VALIDATION, - REPAY_BEHALF_ACCRUE_INTEREST_FAILED, - REPAY_BORROW_ACCRUE_INTEREST_FAILED, - REPAY_BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED, - REPAY_BORROW_COMPTROLLER_REJECTION, - REPAY_BORROW_FRESHNESS_CHECK, - REPAY_BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED, - REPAY_BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED, - REPAY_BORROW_TRANSFER_IN_NOT_POSSIBLE, - SET_COLLATERAL_FACTOR_OWNER_CHECK, - SET_COLLATERAL_FACTOR_VALIDATION, - SET_COMPTROLLER_OWNER_CHECK, - SET_INTEREST_RATE_MODEL_ACCRUE_INTEREST_FAILED, - SET_INTEREST_RATE_MODEL_FRESH_CHECK, - SET_INTEREST_RATE_MODEL_OWNER_CHECK, - SET_MAX_ASSETS_OWNER_CHECK, - SET_ORACLE_MARKET_NOT_LISTED, - SET_PENDING_ADMIN_OWNER_CHECK, - SET_RESERVE_FACTOR_ACCRUE_INTEREST_FAILED, - SET_RESERVE_FACTOR_ADMIN_CHECK, - SET_RESERVE_FACTOR_FRESH_CHECK, - SET_RESERVE_FACTOR_BOUNDS_CHECK, - TRANSFER_COMPTROLLER_REJECTION, - TRANSFER_NOT_ALLOWED, - TRANSFER_NOT_ENOUGH, - TRANSFER_TOO_MUCH, - ADD_RESERVES_ACCRUE_INTEREST_FAILED, - ADD_RESERVES_FRESH_CHECK, - ADD_RESERVES_TRANSFER_IN_NOT_POSSIBLE, - ADD_SUBSIDY_FUND_FAILED, - ADD_SUBSIDY_FUND_FRESH_CHECK - } - - /** - * @dev `error` corresponds to enum Error; `info` corresponds to enum FailureInfo, and `detail` is an arbitrary - * contract-specific code that enables us to report opaque error codes from upgradeable contracts. - **/ - event TokenFailure(uint256 error, uint256 info, uint256 detail); - - /** - * @dev use this when reporting a known error from the money market or a non-upgradeable collaborator - */ - function fail(Error err, FailureInfo info) internal returns (uint256) { - emit TokenFailure(uint256(err), uint256(info), 0); - - return uint256(err); - } - - /** - * @dev use this when reporting an opaque error from an upgradeable collaborator contract - */ - function failOpaque( - Error err, - FailureInfo info, - uint256 opaqueError - ) internal returns (uint256) { - emit TokenFailure(uint256(err), uint256(info), opaqueError); - - return uint256(err); - } -} - - -// Dependency file: contracts/EIP20Interface.sol - -// pragma solidity 0.8.6; - -/** - * @title ERC 20 Token Standard Interface - * https://eips.ethereum.org/EIPS/eip-20 - */ -interface EIP20Interface { - function name() external view returns (string memory); - - function symbol() external view returns (string memory); - - function decimals() external view returns (uint8); - - /** - * @notice Get the total number of tokens in circulation - * @return The supply of tokens - */ - function totalSupply() external view returns (uint256); - - /** - * @notice Gets the balance of the specified address - * @param owner The address from which the balance will be retrieved - * @return balance The balance - */ - function balanceOf(address owner) external view returns (uint256 balance); - - /** - * @notice Transfer `amount` tokens from `msg.sender` to `dst` - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - * @return success Whether or not the transfer succeeded - */ - function transfer(address dst, uint256 amount) - external - returns (bool success); - - /** - * @notice Transfer `amount` tokens from `src` to `dst` - * @param src The address of the source account - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - * @return success Whether or not the transfer succeeded - */ - function transferFrom( - address src, - address dst, - uint256 amount - ) external returns (bool success); - - /** - * @notice Approve `spender` to transfer up to `amount` from `src` - * @dev This will overwrite the approval amount for `spender` - * and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve) - * @param spender The address of the account which may transfer tokens - * @param amount The number of tokens that are approved (-1 means infinite) - * @return success Whether or not the approval succeeded - */ - function approve(address spender, uint256 amount) - external - returns (bool success); - - /** - * @notice Get the current allowance from `owner` for `spender` - * @param owner The address of the account which owns the tokens to be spent - * @param spender The address of the account which may transfer tokens - * @return remaining The number of tokens allowed to be spent (-1 means infinite) - */ - function allowance(address owner, address spender) - external - view - returns (uint256 remaining); - - event Transfer(address indexed from, address indexed to, uint256 amount); - event Approval( - address indexed owner, - address indexed spender, - uint256 amount - ); -} - - -// Dependency file: contracts/WhitelistInterface.sol - -// pragma solidity 0.8.6; - -interface WhitelistInterface { - function setStatus(bool _newStatus) external; - function enabled() external view returns(bool); - - function addUsers(address[] memory _users) external; - function exist(address _user) external view returns(bool); - function getUsers() external view returns(address[] memory currentUsers); - function removeUser(address _user) external; -} - -// Dependency file: contracts/CToken.sol - -// pragma solidity 0.8.6; - -// import "contracts/ComptrollerInterface.sol"; -// import "contracts/CTokenInterfaces.sol"; -// import "contracts/ErrorReporter.sol"; -// import "contracts/Exponential.sol"; -// import "contracts/EIP20Interface.sol"; -// import "contracts/InterestRateModel.sol"; -// import "contracts/WhitelistInterface.sol"; - -/** - * @title tropykus CToken Contract - * @notice Abstract base for CTokens - * @author tropykus - */ -abstract contract CToken is CTokenInterface, Exponential, TokenErrorReporter { - address whitelist; - - /** - * @notice Initialize the money market - * @param comptroller_ The address of the Comptroller - * @param interestRateModel_ The address of the interest rate model - * @param initialExchangeRateMantissa_ The initial exchange rate, scaled by 1e18 - * @param name_ EIP-20 name of this token - * @param symbol_ EIP-20 symbol of this token - * @param decimals_ EIP-20 decimal precision of this token - */ - function initialize( - ComptrollerInterface comptroller_, - InterestRateModel interestRateModel_, - uint256 initialExchangeRateMantissa_, - string memory name_, - string memory symbol_, - uint8 decimals_ - ) public { - require(msg.sender == admin, "CT01"); - require(accrualBlockNumber == 0 && borrowIndex == 0, "CT02"); - - initialExchangeRateMantissa = initialExchangeRateMantissa_; - require(initialExchangeRateMantissa > 0, "CT03"); - - uint256 err = _setComptroller(comptroller_); - require(err == uint256(Error.NO_ERROR), "CT04"); - - accrualBlockNumber = getBlockNumber(); - borrowIndex = mantissaOne; - - err = _setInterestRateModelFresh(interestRateModel_); - require(err == uint256(Error.NO_ERROR), "CT05"); - - name = name_; - symbol = symbol_; - decimals = decimals_; - - _notEntered = true; - } - - function addWhitelist(address _whitelist) external returns (uint256) { - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_INTEREST_RATE_MODEL_OWNER_CHECK - ); - } - whitelist = _whitelist; - } - - /** - * @notice Transfer `tokens` tokens from `src` to `dst` by `spender` - * @dev Called by both `transfer` and `transferFrom` internally - * @param spender The address of the account performing the transfer - * @param src The address of the source account - * @param dst The address of the destination account - * @param tokens The number of tokens to transfer - * @return Whether or not the transfer succeeded - */ - function transferTokens( - address spender, - address src, - address dst, - uint256 tokens - ) internal returns (uint256) { - uint256 allowed = comptroller.transferAllowed( - address(this), - src, - dst, - tokens - ); - if (allowed != 0) { - return - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.TRANSFER_COMPTROLLER_REJECTION, - allowed - ); - } - - if (src == dst) { - return fail(Error.BAD_INPUT, FailureInfo.TRANSFER_NOT_ALLOWED); - } - - uint256 startingAllowance = 0; - if (spender == src) { - startingAllowance = type(uint256).max; - } else { - startingAllowance = transferAllowances[src][spender]; - } - - MathError mathErr; - uint256 allowanceNew; - uint256 srcTokensNew; - uint256 dstTokensNew; - - (mathErr, allowanceNew) = subUInt(startingAllowance, tokens); - if (mathErr != MathError.NO_ERROR) { - return fail(Error.MATH_ERROR, FailureInfo.TRANSFER_NOT_ALLOWED); - } - - (mathErr, srcTokensNew) = subUInt(accountTokens[src].tokens, tokens); - if (mathErr != MathError.NO_ERROR) { - return fail(Error.MATH_ERROR, FailureInfo.TRANSFER_NOT_ENOUGH); - } - - (mathErr, dstTokensNew) = addUInt(accountTokens[dst].tokens, tokens); - if (mathErr != MathError.NO_ERROR) { - return fail(Error.MATH_ERROR, FailureInfo.TRANSFER_TOO_MUCH); - } - - accountTokens[src].tokens = srcTokensNew; - accountTokens[dst].tokens = dstTokensNew; - - if (startingAllowance != type(uint256).max) { - transferAllowances[src][spender] = allowanceNew; - } - - emit Transfer(src, dst, tokens); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Transfer `amount` tokens from `msg.sender` to `dst` - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - * @return Whether or not the transfer succeeded - */ - function transfer(address dst, uint256 amount) - external - override - nonReentrant - returns (bool) - { - return - transferTokens(msg.sender, msg.sender, dst, amount) == - uint256(Error.NO_ERROR); - } - - /** - * @notice Transfer `amount` tokens from `src` to `dst` - * @param src The address of the source account - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - * @return Whether or not the transfer succeeded - */ - function transferFrom( - address src, - address dst, - uint256 amount - ) external override nonReentrant returns (bool) { - return - transferTokens(msg.sender, src, dst, amount) == - uint256(Error.NO_ERROR); - } - - /** - * @notice Approve `spender` to transfer up to `amount` from `src` - * @dev This will overwrite the approval amount for `spender` - * and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve) - * @param spender The address of the account which may transfer tokens - * @param amount The number of tokens that are approved (-1 means infinite) - * @return Whether or not the approval succeeded - */ - function approve(address spender, uint256 amount) - external - override - returns (bool) - { - transferAllowances[msg.sender][spender] = amount; - emit Approval(msg.sender, spender, amount); - return true; - } - - /** - * @notice Get the current allowance from `owner` for `spender` - * @param owner The address of the account which owns the tokens to be spent - * @param spender The address of the account which may transfer tokens - * @return The number of tokens allowed to be spent (-1 means infinite) - */ - function allowance(address owner, address spender) - external - view - override - returns (uint256) - { - return transferAllowances[owner][spender]; - } - - /** - * @notice Get the token balance of the `owner` - * @param owner The address of the account to query - * @return The number of tokens owned by `owner` - */ - function balanceOf(address owner) external view override returns (uint256) { - return accountTokens[owner].tokens; - } - - /** - * @notice Get the underlying balance of the `owner` - * @dev This also accrues interest in a transaction - * @param owner The address of the account to query - * @return The amount of underlying owned by `owner` - */ - function balanceOfUnderlying(address owner) - external - override - returns (uint256) - { - (MathError mErr, uint256 balance) = mulScalarTruncate( - Exp({mantissa: exchangeRateCurrent()}), - accountTokens[owner].tokens - ); - require(mErr == MathError.NO_ERROR, "CT06"); - return balance; - } - - /** - * @notice Get a snapshot of the account's balances, and the cached exchange rate - * @dev This is used by comptroller to more efficiently perform liquidity checks. - * @param account Address of the account to snapshot - * @return (possible error, token balance, borrow balance, exchange rate mantissa) - */ - function getAccountSnapshot(address account) - external - view - override - returns ( - uint256, - uint256, - uint256, - uint256 - ) - { - uint256 cTokenBalance = accountTokens[account].tokens; - uint256 borrowBalance; - uint256 exchangeRateMantissa; - - MathError mErr; - - (mErr, borrowBalance) = borrowBalanceStoredInternal(account); - if (mErr != MathError.NO_ERROR) { - return (uint256(Error.MATH_ERROR), 0, 0, 0); - } - - (mErr, exchangeRateMantissa) = exchangeRateStoredInternal(); - if (mErr != MathError.NO_ERROR) { - return (uint256(Error.MATH_ERROR), 0, 0, 0); - } - - return ( - uint256(Error.NO_ERROR), - cTokenBalance, - borrowBalance, - exchangeRateMantissa - ); - } - - /** - * @dev Function to simply retrieve block number - * This exists mainly for inheriting test contracts to stub this result. - */ - function getBlockNumber() internal view virtual returns (uint256) { - return block.number; - } - - /** - * @notice Returns the current per-block borrow interest rate for this cToken - * @return The borrow interest rate per block, scaled by 1e18 - */ - function borrowRatePerBlock() external view override returns (uint256) { - return - interestRateModel.getBorrowRate( - getCashPrior(), - totalBorrows, - totalReserves - ); - } - - /** - * @notice Returns the current per-block supply interest rate for this cToken - * @return The supply interest rate per block, scaled by 1e18 - */ - function supplyRatePerBlock() external view override returns (uint256) { - return - interestRateModel.getSupplyRate( - getCashPrior(), - totalBorrows, - totalReserves, - reserveFactorMantissa - ); - } - - /** - * @notice Returns the current total borrows plus accrued interest - * @return The total borrows with interest - */ - function totalBorrowsCurrent() - external - override - nonReentrant - returns (uint256) - { - require(accrueInterest() == uint256(Error.NO_ERROR), "CT07"); - return totalBorrows; - } - - /** - * @notice Accrue interest to updated borrowIndex and then calculate account's borrow balance using the updated borrowIndex - * @param account The address whose balance should be calculated after updating borrowIndex - * @return The calculated balance - */ - function borrowBalanceCurrent(address account) - external - override - nonReentrant - returns (uint256) - { - require(accrueInterest() == uint256(Error.NO_ERROR), "CT07"); - return borrowBalanceStored(account); - } - - /** - * @notice Return the borrow balance of account based on stored data - * @param account The address whose balance should be calculated - * @return The calculated balance - */ - function borrowBalanceStored(address account) - public - view - override - returns (uint256) - { - (MathError err, uint256 result) = borrowBalanceStoredInternal(account); - require(err == MathError.NO_ERROR, "CT08"); - return result; - } - - /** - * @notice Return the borrow balance of account based on stored data - * @param account The address whose balance should be calculated - * @return (error code, the calculated balance or 0 if error code is non-zero) - */ - function borrowBalanceStoredInternal(address account) - internal - view - returns (MathError, uint256) - { - MathError mathErr; - uint256 principalTimesIndex; - uint256 result; - - BorrowSnapshot storage borrowSnapshot = accountBorrows[account]; - - if (borrowSnapshot.principal == 0) { - return (MathError.NO_ERROR, 0); - } - - (mathErr, principalTimesIndex) = mulUInt( - borrowSnapshot.principal, - borrowIndex - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - - (mathErr, result) = divUInt( - principalTimesIndex, - borrowSnapshot.interestIndex - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - - return (MathError.NO_ERROR, result); - } - - function getBorrowerPrincipalStored(address account) - public - view - returns (uint256 borrowed) - { - borrowed = accountBorrows[account].principal; - } - - function getSupplierSnapshotStored(address account) - public - view - returns ( - uint256 tokens, - uint256 underlyingAmount, - uint256 suppliedAt, - uint256 promisedSupplyRate - ) - { - tokens = accountTokens[account].tokens; - underlyingAmount = accountTokens[account].underlyingAmount; - suppliedAt = accountTokens[account].suppliedAt; - promisedSupplyRate = accountTokens[account].promisedSupplyRate; - } - - /** - * @notice Accrue interest then return the up-to-date exchange rate - * @return Calculated exchange rate scaled by 1e18 - */ - function exchangeRateCurrent() - public - override - nonReentrant - returns (uint256) - { - require(accrueInterest() == uint256(Error.NO_ERROR), "CT07"); - return exchangeRateStored(); - } - - /** - * @notice Calculates the exchange rate from the underlying to the CToken - * @dev This function does not accrue interest before calculating the exchange rate - * @return Calculated exchange rate scaled by 1e18 - */ - function exchangeRateStored() public view override returns (uint256) { - (MathError err, uint256 result) = exchangeRateStoredInternal(); - require(err == MathError.NO_ERROR, "CT09"); - return result; - } - - /** - * @notice Calculates the exchange rate from the underlying to the CToken - * @dev This function does not accrue interest before calculating the exchange rate - * @return (error code, calculated exchange rate scaled by 1e18) - */ - function exchangeRateStoredInternal() - internal - view - virtual - returns (MathError, uint256) - { - uint256 _totalSupply = totalSupply; - if (_totalSupply == 0) { - return (MathError.NO_ERROR, initialExchangeRateMantissa); - } else { - MathError error; - uint256 exchangeRate; - uint256 totalCash = getCashPrior(); - if (interestRateModel.isTropykusInterestRateModel()) { - (error, exchangeRate) = tropykusExchangeRateStoredInternal( - msg.sender - ); - if (error == MathError.NO_ERROR) { - return (MathError.NO_ERROR, exchangeRate); - } else { - return (MathError.NO_ERROR, initialExchangeRateMantissa); - } - } - return - interestRateModel.getExchangeRate( - totalCash, - totalBorrows, - totalReserves, - totalSupply - ); - } - } - - function tropykusExchangeRateStoredInternal(address redeemer) - internal - view - returns (MathError, uint256) - { - if (totalSupply == 0) { - return (MathError.NO_ERROR, initialExchangeRateMantissa); - } else { - SupplySnapshot storage supplySnapshot = accountTokens[redeemer]; - if (supplySnapshot.suppliedAt == 0) { - return (MathError.DIVISION_BY_ZERO, 0); - } - (, uint256 interestFactorMantissa, ) = tropykusInterestAccrued( - redeemer - ); - Exp memory interestFactor = Exp({mantissa: interestFactorMantissa}); - uint256 currentUnderlying = supplySnapshot.underlyingAmount; - Exp memory redeemerUnderlying = Exp({mantissa: currentUnderlying}); - (, Exp memory realAmount) = mulExp( - interestFactor, - redeemerUnderlying - ); - (, Exp memory exchangeRate) = getExp( - realAmount.mantissa, - supplySnapshot.tokens - ); - return (MathError.NO_ERROR, exchangeRate.mantissa); - } - } - - function tropykusInterestAccrued(address account) - internal - view - returns ( - MathError, - uint256, - uint256 - ) - { - SupplySnapshot storage supplySnapshot = accountTokens[account]; - uint256 promisedSupplyRate = supplySnapshot.promisedSupplyRate; - Exp memory expectedSupplyRatePerBlock = Exp({ - mantissa: promisedSupplyRate - }); - (, uint256 delta) = subUInt( - accrualBlockNumber, - supplySnapshot.suppliedAt - ); - (, Exp memory expectedSupplyRatePerBlockWithDelta) = mulScalar( - expectedSupplyRatePerBlock, - delta - ); - (, Exp memory interestFactor) = addExp( - Exp({mantissa: 1e18}), - expectedSupplyRatePerBlockWithDelta - ); - uint256 currentUnderlying = supplySnapshot.underlyingAmount; - Exp memory redeemerUnderlying = Exp({mantissa: currentUnderlying}); - (, Exp memory realAmount) = mulExp(interestFactor, redeemerUnderlying); - (, uint256 interestEarned) = subUInt( - realAmount.mantissa, - currentUnderlying - ); - return (MathError.NO_ERROR, interestFactor.mantissa, interestEarned); - } - - /** - * @notice Get cash balance of this cToken in the underlying asset - * @return The quantity of underlying asset owned by this contract - */ - function getCash() external view override returns (uint256) { - return getCashPrior(); - } - - /** - * @notice Applies accrued interest to total borrows and reserves - * @dev This calculates interest accrued from the last checkpointed block - * up to the current block and writes new checkpoint to storage. - */ - function accrueInterest() public override returns (uint256) { - uint256 currentBlockNumber = getBlockNumber(); - uint256 accrualBlockNumberPrior = accrualBlockNumber; - - if (accrualBlockNumberPrior == currentBlockNumber) { - return uint256(Error.NO_ERROR); - } - - uint256 cashPrior = getCashPrior(); - uint256 borrowsPrior = totalBorrows; - uint256 reservesPrior = totalReserves; - uint256 borrowIndexPrior = borrowIndex; - - uint256 borrowRateMantissa = interestRateModel.getBorrowRate( - cashPrior, - borrowsPrior, - reservesPrior - ); - require(borrowRateMantissa <= borrowRateMaxMantissa, "CT10"); - - (MathError mathErr, uint256 blockDelta) = subUInt( - currentBlockNumber, - accrualBlockNumberPrior - ); - require(mathErr == MathError.NO_ERROR, "CT11"); - - Exp memory simpleInterestFactor; - uint256 interestAccumulated; - uint256 totalBorrowsNew; - uint256 totalReservesNew; - uint256 borrowIndexNew; - - (mathErr, simpleInterestFactor) = mulScalar( - Exp({mantissa: borrowRateMantissa}), - blockDelta - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .ACCRUE_INTEREST_SIMPLE_INTEREST_FACTOR_CALCULATION_FAILED, - uint256(mathErr) - ); - } - - (mathErr, interestAccumulated) = mulScalarTruncate( - simpleInterestFactor, - borrowsPrior - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .ACCRUE_INTEREST_ACCUMULATED_INTEREST_CALCULATION_FAILED, - uint256(mathErr) - ); - } - - (mathErr, totalBorrowsNew) = addUInt(interestAccumulated, borrowsPrior); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .ACCRUE_INTEREST_NEW_TOTAL_BORROWS_CALCULATION_FAILED, - uint256(mathErr) - ); - } - - (mathErr, totalReservesNew) = mulScalarTruncateAddUInt( - Exp({mantissa: reserveFactorMantissa}), - interestAccumulated, - reservesPrior - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .ACCRUE_INTEREST_NEW_TOTAL_RESERVES_CALCULATION_FAILED, - uint256(mathErr) - ); - } - - if (interestRateModel.isTropykusInterestRateModel()) { - (mathErr, totalReservesNew) = newReserves( - borrowRateMantissa, - cashPrior, - borrowsPrior, - reservesPrior, - interestAccumulated - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .ACCRUE_INTEREST_NEW_TOTAL_RESERVES_CALCULATION_FAILED, - uint256(mathErr) - ); - } - } - - (mathErr, borrowIndexNew) = mulScalarTruncateAddUInt( - simpleInterestFactor, - borrowIndexPrior, - borrowIndexPrior - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .ACCRUE_INTEREST_NEW_BORROW_INDEX_CALCULATION_FAILED, - uint256(mathErr) - ); - } - - accrualBlockNumber = currentBlockNumber; - borrowIndex = borrowIndexNew; - totalBorrows = totalBorrowsNew; - totalReserves = totalReservesNew; - - emit AccrueInterest( - cashPrior, - interestAccumulated, - borrowIndexNew, - totalBorrowsNew - ); - - return uint256(Error.NO_ERROR); - } - - function newReserves( - uint256 borrowRateMantissa, - uint256 cashPrior, - uint256 borrowsPrior, - uint256 reservesPrior, - uint256 interestAccumulated - ) internal view returns (MathError mathErr, uint256 totalReservesNew) { - uint256 newReserveFactorMantissa; - uint256 utilizationRate = interestRateModel.utilizationRate( - cashPrior, - borrowsPrior, - reservesPrior - ); - uint256 expectedSupplyRate = interestRateModel.getSupplyRate( - cashPrior, - borrowsPrior, - reservesPrior, - reserveFactorMantissa - ); - if ( - interestRateModel.isAboveOptimal( - cashPrior, - borrowsPrior, - reservesPrior - ) - ) { - (mathErr, newReserveFactorMantissa) = mulScalarTruncate( - Exp({mantissa: utilizationRate}), - borrowRateMantissa - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - (mathErr, newReserveFactorMantissa) = subUInt( - newReserveFactorMantissa, - expectedSupplyRate - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - (mathErr, totalReservesNew) = mulScalarTruncateAddUInt( - Exp({mantissa: newReserveFactorMantissa}), - interestAccumulated, - reservesPrior - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - } else { - mathErr = MathError.NO_ERROR; - totalReservesNew = reservesPrior; - } - } - - /** - * @notice Sender supplies assets into the market and receives cTokens in exchange - * @dev Accrues interest whether or not the operation succeeds, unless reverted - * @param mintAmount The amount of the underlying asset to supply - * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual mint amount. - */ - function mintInternal(uint256 mintAmount) - internal - nonReentrant - returns (uint256, uint256) - { - if (WhitelistInterface(whitelist).enabled()) { - require(WhitelistInterface(whitelist).exist(msg.sender), "CT26"); - } - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return ( - fail(Error(error), FailureInfo.MINT_ACCRUE_INTEREST_FAILED), - 0 - ); - } - return mintFresh(msg.sender, mintAmount); - } - - struct MintLocalVars { - Error err; - MathError mathErr; - uint256 exchangeRateMantissa; - uint256 mintTokens; - uint256 totalSupplyNew; - uint256 accountTokensNew; - uint256 actualMintAmount; - } - - /** - * @notice User supplies assets into the market and receives cTokens in exchange - * @dev Assumes interest has already been accrued up to the current block - * @param minter The address of the account which is supplying the assets - * @param mintAmount The amount of the underlying asset to supply - * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual mint amount. - */ - function mintFresh(address minter, uint256 mintAmount) - internal - returns (uint256, uint256) - { - uint256 allowed = comptroller.mintAllowed( - address(this), - minter, - mintAmount - ); - if (allowed != 0) { - return ( - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.MINT_COMPTROLLER_REJECTION, - allowed - ), - 0 - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return ( - fail(Error.MARKET_NOT_FRESH, FailureInfo.MINT_FRESHNESS_CHECK), - 0 - ); - } - - MintLocalVars memory vars; - - ( - vars.mathErr, - vars.exchangeRateMantissa - ) = exchangeRateStoredInternal(); - if (vars.mathErr != MathError.NO_ERROR) { - return ( - failOpaque( - Error.MATH_ERROR, - FailureInfo.MINT_EXCHANGE_RATE_READ_FAILED, - uint256(vars.mathErr) - ), - 0 - ); - } - if (interestRateModel.isTropykusInterestRateModel()) { - SupplySnapshot storage supplySnapshot = accountTokens[minter]; - (, uint256 newTotalSupply) = addUInt( - supplySnapshot.underlyingAmount, - mintAmount - ); - require(newTotalSupply <= 0.1e18, "CT24"); - } - vars.actualMintAmount = doTransferIn(minter, mintAmount); - - (vars.mathErr, vars.mintTokens) = divScalarByExpTruncate( - vars.actualMintAmount, - Exp({mantissa: vars.exchangeRateMantissa}) - ); - require(vars.mathErr == MathError.NO_ERROR, "CT12"); - - (vars.mathErr, vars.totalSupplyNew) = addUInt( - totalSupply, - vars.mintTokens - ); - require(vars.mathErr == MathError.NO_ERROR, "CT13"); - - (vars.mathErr, vars.accountTokensNew) = addUInt( - accountTokens[minter].tokens, - vars.mintTokens - ); - require(vars.mathErr == MathError.NO_ERROR, "CT14"); - - uint256 currentSupplyRate = interestRateModel.getSupplyRate( - getCashPrior(), - totalBorrows, - totalReserves, - reserveFactorMantissa - ); - - bool isTropykusInterestRateModel = interestRateModel - .isTropykusInterestRateModel(); - - if (accountTokens[minter].tokens > 0) { - Exp memory updatedUnderlying; - if (isTropykusInterestRateModel) { - (, uint256 interestFactorMantissa, ) = tropykusInterestAccrued( - minter - ); - Exp memory interestFactor = Exp({ - mantissa: interestFactorMantissa - }); - uint256 currentUnderlyingAmount = accountTokens[minter] - .underlyingAmount; - MathError mErrorNewAmount; - (mErrorNewAmount, updatedUnderlying) = mulExp( - Exp({mantissa: currentUnderlyingAmount}), - interestFactor - ); - if (mErrorNewAmount != MathError.NO_ERROR) { - return ( - failOpaque( - Error.MATH_ERROR, - FailureInfo.MINT_EXCHANGE_CALCULATION_FAILED, - uint256(mErrorNewAmount) - ), - 0 - ); - } - } else { - uint256 currentTokens = accountTokens[minter].tokens; - MathError mErrorUpdatedUnderlying; - (mErrorUpdatedUnderlying, updatedUnderlying) = mulExp( - Exp({mantissa: currentTokens}), - Exp({mantissa: vars.exchangeRateMantissa}) - ); - if (mErrorUpdatedUnderlying != MathError.NO_ERROR) { - return ( - failOpaque( - Error.MATH_ERROR, - FailureInfo.MINT_EXCHANGE_CALCULATION_FAILED, - uint256(mErrorUpdatedUnderlying) - ), - 0 - ); - } - } - (, mintAmount) = addUInt(updatedUnderlying.mantissa, mintAmount); - } - - totalSupply = vars.totalSupplyNew; - accountTokens[minter] = SupplySnapshot({ - tokens: vars.accountTokensNew, - underlyingAmount: mintAmount, - suppliedAt: accrualBlockNumber, - promisedSupplyRate: currentSupplyRate - }); - - emit Mint(minter, vars.actualMintAmount, vars.mintTokens); - emit Transfer(address(this), minter, vars.mintTokens); - - return (uint256(Error.NO_ERROR), vars.actualMintAmount); - } - - /** - * @notice Sender redeems cTokens in exchange for a specified amount of underlying asset - * @dev Accrues interest whether or not the operation succeeds, unless reverted - * @param redeemAmount The amount of underlying to receive from redeeming cTokens - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function redeemUnderlyingInternal(uint256 redeemAmount) - internal - nonReentrant - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return - fail(Error(error), FailureInfo.REDEEM_ACCRUE_INTEREST_FAILED); - } - return redeemFresh(payable(msg.sender), redeemAmount); - } - - struct RedeemLocalVars { - Error err; - MathError mathErr; - uint256 exchangeRateMantissa; - uint256 redeemTokens; - uint256 redeemAmount; - uint256 totalSupplyNew; - uint256 accountTokensNew; - uint256 newSubsidyFund; - } - - /** - * @notice User redeems cTokens in exchange for the underlying asset - * @dev Assumes interest has already been accrued up to the current block - * @param redeemer The address of the account which is redeeming the tokens - * @param redeemAmountIn The number of underlying tokens to receive from redeeming cTokens - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function redeemFresh(address payable redeemer, uint256 redeemAmountIn) - internal - returns (uint256) - { - require(redeemAmountIn > 0, "CT15"); - - RedeemLocalVars memory vars; - - SupplySnapshot storage supplySnapshot = accountTokens[redeemer]; - - ( - vars.mathErr, - vars.exchangeRateMantissa - ) = exchangeRateStoredInternal(); - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.REDEEM_EXCHANGE_RATE_READ_FAILED, - uint256(vars.mathErr) - ); - } - - uint256 interestEarned; - uint256 subsidyFundPortion; - uint256 currentUnderlying; - - bool isTropykusInterestRateModel = interestRateModel - .isTropykusInterestRateModel(); - if (isTropykusInterestRateModel) { - currentUnderlying = supplySnapshot.underlyingAmount; - (, , interestEarned) = tropykusInterestAccrued(redeemer); - } - supplySnapshot.promisedSupplyRate = interestRateModel.getSupplyRate( - getCashPrior(), - totalBorrows, - totalReserves, - reserveFactorMantissa - ); - - if ( - isTropykusInterestRateModel && - !interestRateModel.isAboveOptimal( - getCashPrior(), - totalBorrows, - totalReserves - ) - ) { - uint256 borrowRate = interestRateModel.getBorrowRate( - getCashPrior(), - totalBorrows, - totalReserves - ); - - uint256 utilizationRate = interestRateModel.utilizationRate( - getCashPrior(), - totalBorrows, - totalReserves - ); - - (, uint256 estimatedEarning) = mulScalarTruncate( - Exp({mantissa: borrowRate}), - utilizationRate - ); - - (, subsidyFundPortion) = subUInt( - supplySnapshot.promisedSupplyRate, - estimatedEarning - ); - (, Exp memory subsidyFactor) = getExp( - subsidyFundPortion, - supplySnapshot.promisedSupplyRate - ); - (, subsidyFundPortion) = mulScalarTruncate( - subsidyFactor, - interestEarned - ); - } - - vars.redeemAmount = redeemAmountIn; - - if (isTropykusInterestRateModel) { - (, Exp memory num) = mulExp( - vars.redeemAmount, - supplySnapshot.tokens - ); - (, Exp memory realTokensWithdrawAmount) = getExp( - num.mantissa, - currentUnderlying - ); - vars.redeemTokens = realTokensWithdrawAmount.mantissa; - } else { - (vars.mathErr, vars.redeemTokens) = divScalarByExpTruncate( - redeemAmountIn, - Exp({mantissa: vars.exchangeRateMantissa}) - ); - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.REDEEM_EXCHANGE_AMOUNT_CALCULATION_FAILED, - uint256(vars.mathErr) - ); - } - } - // } - - uint256 allowed = comptroller.redeemAllowed( - address(this), - redeemer, - vars.redeemTokens - ); - if (allowed != 0) { - return - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.REDEEM_COMPTROLLER_REJECTION, - allowed - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.REDEEM_FRESHNESS_CHECK - ); - } - - (vars.mathErr, vars.totalSupplyNew) = subUInt( - totalSupply, - vars.redeemTokens - ); - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.REDEEM_NEW_TOTAL_SUPPLY_CALCULATION_FAILED, - uint256(vars.mathErr) - ); - } - - (, vars.newSubsidyFund) = subUInt(subsidyFund, subsidyFundPortion); - - (vars.mathErr, vars.accountTokensNew) = subUInt( - supplySnapshot.tokens, - vars.redeemTokens - ); - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.REDEEM_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED, - uint256(vars.mathErr) - ); - } - - uint256 cash = getCashPrior(); - if (isTropykusInterestRateModel) { - cash = address(this).balance; - } - - if (cash < vars.redeemAmount) { - return - fail( - Error.TOKEN_INSUFFICIENT_CASH, - FailureInfo.REDEEM_TRANSFER_OUT_NOT_POSSIBLE - ); - } - - doTransferOut(redeemer, vars.redeemAmount); - - totalSupply = vars.totalSupplyNew; - subsidyFund = vars.newSubsidyFund; - supplySnapshot.tokens = vars.accountTokensNew; - supplySnapshot.suppliedAt = accrualBlockNumber; - (, supplySnapshot.underlyingAmount) = subUInt( - supplySnapshot.underlyingAmount, - vars.redeemAmount - ); - - emit Transfer(redeemer, address(this), vars.redeemTokens); - emit Redeem(redeemer, vars.redeemAmount, vars.redeemTokens); - - comptroller.redeemVerify( - address(this), - redeemer, - vars.redeemAmount, - vars.redeemTokens - ); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Sender borrows assets from the protocol to their own address - * @param borrowAmount The amount of the underlying asset to borrow - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function borrowInternal(uint256 borrowAmount) - internal - nonReentrant - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return - fail(Error(error), FailureInfo.BORROW_ACCRUE_INTEREST_FAILED); - } - return borrowFresh(payable(msg.sender), borrowAmount); - } - - struct BorrowLocalVars { - MathError mathErr; - uint256 accountBorrows; - uint256 accountBorrowsNew; - uint256 totalBorrowsNew; - } - - /** - * @notice Users borrow assets from the protocol to their own address - * @param borrowAmount The amount of the underlying asset to borrow - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function borrowFresh(address payable borrower, uint256 borrowAmount) - internal - returns (uint256) - { - uint256 allowed = comptroller.borrowAllowed( - address(this), - borrower, - borrowAmount - ); - if (allowed != 0) { - return - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.BORROW_COMPTROLLER_REJECTION, - allowed - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.BORROW_FRESHNESS_CHECK - ); - } - - if (getCashPrior() < borrowAmount) { - return - fail( - Error.TOKEN_INSUFFICIENT_CASH, - FailureInfo.BORROW_CASH_NOT_AVAILABLE - ); - } - - BorrowLocalVars memory vars; - - (vars.mathErr, vars.accountBorrows) = borrowBalanceStoredInternal( - borrower - ); - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED, - uint256(vars.mathErr) - ); - } - - (vars.mathErr, vars.accountBorrowsNew) = addUInt( - vars.accountBorrows, - borrowAmount - ); - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED, - uint256(vars.mathErr) - ); - } - - (vars.mathErr, vars.totalBorrowsNew) = addUInt( - totalBorrows, - borrowAmount - ); - if (interestRateModel.isTropykusInterestRateModel()) { - require(vars.totalBorrowsNew <= 0.1e18, "CT25"); - } - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED, - uint256(vars.mathErr) - ); - } - - doTransferOut(borrower, borrowAmount); - - accountBorrows[borrower].principal = vars.accountBorrowsNew; - accountBorrows[borrower].interestIndex = borrowIndex; - totalBorrows = vars.totalBorrowsNew; - - emit Borrow( - borrower, - borrowAmount, - vars.accountBorrowsNew, - vars.totalBorrowsNew - ); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Sender repays their own borrow - * @param repayAmount The amount to repay - * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual repayment amount. - */ - function repayBorrowInternal(uint256 repayAmount) - internal - nonReentrant - returns (uint256, uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return ( - fail( - Error(error), - FailureInfo.REPAY_BORROW_ACCRUE_INTEREST_FAILED - ), - 0 - ); - } - return repayBorrowFresh(msg.sender, msg.sender, repayAmount); - } - - struct RepayBorrowLocalVars { - Error err; - MathError mathErr; - uint256 repayAmount; - uint256 borrowerIndex; - uint256 accountBorrows; - uint256 accountBorrowsNew; - uint256 totalBorrowsNew; - uint256 actualRepayAmount; - } - - /** - * @notice Borrows are repaid by another user (possibly the borrower). - * @param payer the account paying off the borrow - * @param borrower the account with the debt being payed off - * @param repayAmount the amount of undelrying tokens being returned - * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual repayment amount. - */ - function repayBorrowFresh( - address payer, - address borrower, - uint256 repayAmount - ) internal returns (uint256, uint256) { - uint256 allowed = comptroller.repayBorrowAllowed( - address(this), - payer, - borrower, - repayAmount - ); - if (allowed != 0) { - return ( - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.REPAY_BORROW_COMPTROLLER_REJECTION, - allowed - ), - 0 - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return ( - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.REPAY_BORROW_FRESHNESS_CHECK - ), - 0 - ); - } - - RepayBorrowLocalVars memory vars; - - vars.borrowerIndex = accountBorrows[borrower].interestIndex; - - (vars.mathErr, vars.accountBorrows) = borrowBalanceStoredInternal( - borrower - ); - if (vars.mathErr != MathError.NO_ERROR) { - return ( - failOpaque( - Error.MATH_ERROR, - FailureInfo - .REPAY_BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED, - uint256(vars.mathErr) - ), - 0 - ); - } - - if (repayAmount == type(uint256).max) { - vars.repayAmount = vars.accountBorrows; - } else { - vars.repayAmount = repayAmount; - } - - vars.actualRepayAmount = doTransferIn(payer, vars.repayAmount); - - (vars.mathErr, vars.accountBorrowsNew) = subUInt( - vars.accountBorrows, - vars.actualRepayAmount - ); - require(vars.mathErr == MathError.NO_ERROR, "CT16"); - - (vars.mathErr, vars.totalBorrowsNew) = subUInt( - totalBorrows, - vars.actualRepayAmount - ); - require(vars.mathErr == MathError.NO_ERROR, "CT17"); - - accountBorrows[borrower].principal = vars.accountBorrowsNew; - accountBorrows[borrower].interestIndex = borrowIndex; - totalBorrows = vars.totalBorrowsNew; - - emit RepayBorrow( - payer, - borrower, - vars.actualRepayAmount, - vars.accountBorrowsNew, - vars.totalBorrowsNew - ); - - return (uint256(Error.NO_ERROR), vars.actualRepayAmount); - } - - /** - * @notice The sender liquidates the borrowers collateral. - * The collateral seized is transferred to the liquidator. - * @param borrower The borrower of this cToken to be liquidated - * @param cTokenCollateral The market in which to seize collateral from the borrower - * @param repayAmount The amount of the underlying borrowed asset to repay - * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual repayment amount. - */ - function liquidateBorrowInternal( - address borrower, - uint256 repayAmount, - CTokenInterface cTokenCollateral - ) internal nonReentrant returns (uint256, uint256) { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return ( - fail( - Error(error), - FailureInfo.LIQUIDATE_ACCRUE_BORROW_INTEREST_FAILED - ), - 0 - ); - } - - error = cTokenCollateral.accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return ( - fail( - Error(error), - FailureInfo.LIQUIDATE_ACCRUE_COLLATERAL_INTEREST_FAILED - ), - 0 - ); - } - - // liquidateBorrowFresh emits borrow-specific logs on errors, so we don't need to - return - liquidateBorrowFresh( - msg.sender, - borrower, - repayAmount, - cTokenCollateral - ); - } - - /** - * @notice The liquidator liquidates the borrowers collateral. - * The collateral seized is transferred to the liquidator. - * @param borrower The borrower of this cToken to be liquidated - * @param liquidator The address repaying the borrow and seizing collateral - * @param cTokenCollateral The market in which to seize collateral from the borrower - * @param repayAmount The amount of the underlying borrowed asset to repay - * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual repayment amount. - */ - function liquidateBorrowFresh( - address liquidator, - address borrower, - uint256 repayAmount, - CTokenInterface cTokenCollateral - ) internal returns (uint256, uint256) { - uint256 allowed = comptroller.liquidateBorrowAllowed( - address(this), - address(cTokenCollateral), - liquidator, - borrower, - repayAmount - ); - if (allowed != 0) { - return ( - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.LIQUIDATE_COMPTROLLER_REJECTION, - allowed - ), - 0 - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return ( - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.LIQUIDATE_FRESHNESS_CHECK - ), - 0 - ); - } - - if (cTokenCollateral.accrualBlockNumber() != getBlockNumber()) { - return ( - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.LIQUIDATE_COLLATERAL_FRESHNESS_CHECK - ), - 0 - ); - } - - if (borrower == liquidator) { - return ( - fail( - Error.INVALID_ACCOUNT_PAIR, - FailureInfo.LIQUIDATE_LIQUIDATOR_IS_BORROWER - ), - 0 - ); - } - - if (repayAmount == 0) { - return ( - fail( - Error.INVALID_CLOSE_AMOUNT_REQUESTED, - FailureInfo.LIQUIDATE_CLOSE_AMOUNT_IS_ZERO - ), - 0 - ); - } - - if (repayAmount == type(uint256).max) { - return ( - fail( - Error.INVALID_CLOSE_AMOUNT_REQUESTED, - FailureInfo.LIQUIDATE_CLOSE_AMOUNT_IS_UINT_MAX - ), - 0 - ); - } - - ( - uint256 repayBorrowError, - uint256 actualRepayAmount - ) = repayBorrowFresh(liquidator, borrower, repayAmount); - if (repayBorrowError != uint256(Error.NO_ERROR)) { - return ( - fail( - Error(repayBorrowError), - FailureInfo.LIQUIDATE_REPAY_BORROW_FRESH_FAILED - ), - 0 - ); - } - - (uint256 amountSeizeError, uint256 seizeTokens) = comptroller - .liquidateCalculateSeizeTokens( - address(this), - address(cTokenCollateral), - actualRepayAmount - ); - require(amountSeizeError == uint256(Error.NO_ERROR), "CT18"); - - require(cTokenCollateral.balanceOf(borrower) >= seizeTokens, "CT19"); - - uint256 seizeError; - if (address(cTokenCollateral) == address(this)) { - seizeError = seizeInternal( - address(this), - liquidator, - borrower, - seizeTokens - ); - } else { - seizeError = cTokenCollateral.seize( - liquidator, - borrower, - seizeTokens - ); - } - - require(seizeError == uint256(Error.NO_ERROR), "CT20"); - - emit LiquidateBorrow( - liquidator, - borrower, - actualRepayAmount, - address(cTokenCollateral), - seizeTokens - ); - - return (uint256(Error.NO_ERROR), actualRepayAmount); - } - - /** - * @notice Transfers collateral tokens (this market) to the liquidator. - * @dev Will fail unless called by another cToken during the process of liquidation. - * Its absolutely critical to use msg.sender as the borrowed cToken and not a parameter. - * @param liquidator The account receiving seized collateral - * @param borrower The account having collateral seized - * @param seizeTokens The number of cTokens to seize - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function seize( - address liquidator, - address borrower, - uint256 seizeTokens - ) external override nonReentrant returns (uint256) { - return seizeInternal(msg.sender, liquidator, borrower, seizeTokens); - } - - struct SeizeVars { - uint256 seizeAmount; - uint256 exchangeRate; - uint256 borrowerTokensNew; - uint256 borrowerAmountNew; - uint256 liquidatorTokensNew; - uint256 liquidatorAmountNew; - uint256 totalCash; - uint256 supplyRate; - } - - /** - * @notice Transfers collateral tokens (this market) to the liquidator. - * @dev Called only during an in-kind liquidation, or by liquidateBorrow during the liquidation of another CToken. - * Its absolutely critical to use msg.sender as the seizer cToken and not a parameter. - * @param seizerToken The contract seizing the collateral (i.e. borrowed cToken) - * @param liquidator The account receiving seized collateral - * @param borrower The account having collateral seized - * @param seizeTokens The number of cTokens to seize - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function seizeInternal( - address seizerToken, - address liquidator, - address borrower, - uint256 seizeTokens - ) internal returns (uint256) { - uint256 allowed = comptroller.seizeAllowed( - address(this), - seizerToken, - liquidator, - borrower, - seizeTokens - ); - if (allowed != 0) { - return - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.LIQUIDATE_SEIZE_COMPTROLLER_REJECTION, - allowed - ); - } - - if (borrower == liquidator) { - return - fail( - Error.INVALID_ACCOUNT_PAIR, - FailureInfo.LIQUIDATE_SEIZE_LIQUIDATOR_IS_BORROWER - ); - } - - SeizeVars memory seizeVars; - - MathError mathErr; - - (mathErr, seizeVars.borrowerTokensNew) = subUInt( - accountTokens[borrower].tokens, - seizeTokens - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.LIQUIDATE_SEIZE_BALANCE_DECREMENT_FAILED, - uint256(mathErr) - ); - } - - seizeVars.totalCash = getCashPrior(); - seizeVars.supplyRate = interestRateModel.getSupplyRate( - seizeVars.totalCash, - totalBorrows, - totalReserves, - reserveFactorMantissa - ); - - (, seizeVars.exchangeRate) = interestRateModel.getExchangeRate( - seizeVars.totalCash, - totalBorrows, - totalReserves, - totalSupply - ); - - if (interestRateModel.isTropykusInterestRateModel()) { - (, seizeVars.exchangeRate) = tropykusExchangeRateStoredInternal( - borrower - ); - } - - (, seizeVars.seizeAmount) = mulUInt( - seizeTokens, - seizeVars.exchangeRate - ); - (, seizeVars.seizeAmount) = divUInt(seizeVars.seizeAmount, 1e18); - - (, seizeVars.borrowerAmountNew) = subUInt( - accountTokens[borrower].underlyingAmount, - seizeVars.seizeAmount - ); - - (mathErr, seizeVars.liquidatorTokensNew) = addUInt( - accountTokens[liquidator].tokens, - seizeTokens - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.LIQUIDATE_SEIZE_BALANCE_INCREMENT_FAILED, - uint256(mathErr) - ); - } - - (, seizeVars.liquidatorAmountNew) = addUInt( - accountTokens[liquidator].underlyingAmount, - seizeVars.seizeAmount - ); - - accountTokens[borrower].tokens = seizeVars.borrowerTokensNew; - accountTokens[borrower].underlyingAmount = seizeVars.borrowerAmountNew; - accountTokens[borrower].suppliedAt = getBlockNumber(); - accountTokens[borrower].promisedSupplyRate = seizeVars.supplyRate; - - accountTokens[liquidator].tokens = seizeVars.liquidatorTokensNew; - accountTokens[liquidator].underlyingAmount = seizeVars - .liquidatorAmountNew; - accountTokens[liquidator].suppliedAt = getBlockNumber(); - accountTokens[liquidator].promisedSupplyRate = seizeVars.supplyRate; - - emit Transfer(borrower, liquidator, seizeTokens); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Begins transfer of admin rights. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer. - * @dev Admin function to begin change of admin. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer. - * @param newPendingAdmin New pending admin. - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setPendingAdmin(address payable newPendingAdmin) - external - override - returns (uint256) - { - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_PENDING_ADMIN_OWNER_CHECK - ); - } - - address oldPendingAdmin = pendingAdmin; - - pendingAdmin = newPendingAdmin; - - emit NewPendingAdmin(oldPendingAdmin, newPendingAdmin); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Accepts transfer of admin rights. msg.sender must be pendingAdmin - * @dev Admin function for pending admin to accept role and update admin - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _acceptAdmin() external override returns (uint256) { - if (msg.sender != pendingAdmin || msg.sender == address(0)) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.ACCEPT_ADMIN_PENDING_ADMIN_CHECK - ); - } - - address oldAdmin = admin; - address oldPendingAdmin = pendingAdmin; - - admin = pendingAdmin; - - pendingAdmin = payable(address(0)); - - emit NewAdmin(oldAdmin, admin); - emit NewPendingAdmin(oldPendingAdmin, pendingAdmin); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Sets a new comptroller for the market - * @dev Admin function to set a new comptroller - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setComptroller(ComptrollerInterface newComptroller) - public - override - returns (uint256) - { - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_COMPTROLLER_OWNER_CHECK - ); - } - - ComptrollerInterface oldComptroller = comptroller; - require(newComptroller.isComptroller(), "CT21"); - - comptroller = newComptroller; - - emit NewComptroller(oldComptroller, newComptroller); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice accrues interest and sets a new reserve factor for the protocol using _setReserveFactorFresh - * @dev Admin function to accrue interest and set a new reserve factor - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setReserveFactor(uint256 newReserveFactorMantissa) - external - override - nonReentrant - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return - fail( - Error(error), - FailureInfo.SET_RESERVE_FACTOR_ACCRUE_INTEREST_FAILED - ); - } - return _setReserveFactorFresh(newReserveFactorMantissa); - } - - /** - * @notice Sets a new reserve factor for the protocol (*requires fresh interest accrual) - * @dev Admin function to set a new reserve factor - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setReserveFactorFresh(uint256 newReserveFactorMantissa) - internal - returns (uint256) - { - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_RESERVE_FACTOR_ADMIN_CHECK - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.SET_RESERVE_FACTOR_FRESH_CHECK - ); - } - - if (newReserveFactorMantissa > reserveFactorMaxMantissa) { - return - fail( - Error.BAD_INPUT, - FailureInfo.SET_RESERVE_FACTOR_BOUNDS_CHECK - ); - } - - uint256 oldReserveFactorMantissa = reserveFactorMantissa; - reserveFactorMantissa = newReserveFactorMantissa; - - emit NewReserveFactor( - oldReserveFactorMantissa, - newReserveFactorMantissa - ); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Accrues interest and reduces reserves by transferring from msg.sender - * @param addAmount Amount of addition to reserves - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _addReservesInternal(uint256 addAmount) - internal - nonReentrant - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return - fail( - Error(error), - FailureInfo.ADD_RESERVES_ACCRUE_INTEREST_FAILED - ); - } - - uint256 totalReservesNew; - uint256 actualAddAmount; - - if (accrualBlockNumber != getBlockNumber()) { - return ( - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.ADD_RESERVES_FRESH_CHECK - ) - ); - } - - actualAddAmount = doTransferIn(msg.sender, addAmount); - - totalReservesNew = totalReserves + actualAddAmount; - - require(totalReservesNew >= totalReserves, "CT22"); - - totalReserves = totalReservesNew; - - emit ReservesAdded(msg.sender, actualAddAmount, totalReservesNew); - - return (uint256(Error.NO_ERROR)); - } - - function _addSubsidyInternal(uint256 addAmount) - internal - nonReentrant - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - // accrueInterest emits logs on errors, but on top of that we want to log the fact that an attempted reduce reserves failed. - return fail(Error(error), FailureInfo.ADD_SUBSIDY_FUND_FAILED); - } - - uint256 subsidyFundNew; - uint256 actualAddAmount; - - if (accrualBlockNumber != getBlockNumber()) { - return ( - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.ADD_SUBSIDY_FUND_FRESH_CHECK - ) - ); - } - - actualAddAmount = doTransferIn(msg.sender, addAmount); - - subsidyFundNew = subsidyFund + actualAddAmount; - - require(subsidyFundNew >= subsidyFund, "CT22"); - - subsidyFund = subsidyFundNew; - - emit SubsidyAdded(msg.sender, actualAddAmount, subsidyFundNew); - - /* Return (NO_ERROR, actualAddAmount) */ - return (uint256(Error.NO_ERROR)); - } - - /** - * @notice Accrues interest and reduces reserves by transferring to admin - * @param reduceAmount Amount of reduction to reserves - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _reduceReserves(uint256 reduceAmount) - external - override - nonReentrant - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return - fail( - Error(error), - FailureInfo.REDUCE_RESERVES_ACCRUE_INTEREST_FAILED - ); - } - return _reduceReservesFresh(reduceAmount); - } - - /** - * @notice Reduces reserves by transferring to admin - * @dev Requires fresh interest accrual - * @param reduceAmount Amount of reduction to reserves - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _reduceReservesFresh(uint256 reduceAmount) - internal - returns (uint256) - { - uint256 totalReservesNew; - - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.REDUCE_RESERVES_ADMIN_CHECK - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.REDUCE_RESERVES_FRESH_CHECK - ); - } - - if (getCashPrior() < reduceAmount) { - return - fail( - Error.TOKEN_INSUFFICIENT_CASH, - FailureInfo.REDUCE_RESERVES_CASH_NOT_AVAILABLE - ); - } - - if (reduceAmount > totalReserves) { - return - fail(Error.BAD_INPUT, FailureInfo.REDUCE_RESERVES_VALIDATION); - } - - totalReservesNew = totalReserves - reduceAmount; - require(totalReservesNew <= totalReserves, "CT23"); - - totalReserves = totalReservesNew; - - doTransferOut(admin, reduceAmount); - - emit ReservesReduced(admin, reduceAmount, totalReservesNew); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice accrues interest and updates the interest rate model using _setInterestRateModelFresh - * @dev Admin function to accrue interest and update the interest rate model - * @param newInterestRateModel the new interest rate model to use - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setInterestRateModel(InterestRateModel newInterestRateModel) - public - override - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return - fail( - Error(error), - FailureInfo.SET_INTEREST_RATE_MODEL_ACCRUE_INTEREST_FAILED - ); - } - return _setInterestRateModelFresh(newInterestRateModel); - } - - /** - * @notice updates the interest rate model (*requires fresh interest accrual) - * @dev Admin function to update the interest rate model - * @param newInterestRateModel the new interest rate model to use - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setInterestRateModelFresh(InterestRateModel newInterestRateModel) - internal - returns (uint256) - { - InterestRateModel oldInterestRateModel; - - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_INTEREST_RATE_MODEL_OWNER_CHECK - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.SET_INTEREST_RATE_MODEL_FRESH_CHECK - ); - } - - oldInterestRateModel = interestRateModel; - - require(newInterestRateModel.isInterestRateModel(), "CT21"); - - interestRateModel = newInterestRateModel; - - emit NewMarketInterestRateModel( - oldInterestRateModel, - newInterestRateModel - ); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Gets balance of this contract in terms of the underlying - * @dev This excludes the value of the current message, if any - * @return The quantity of underlying owned by this contract - */ - function getCashPrior() internal view virtual returns (uint256); - - /** - * @dev Performs a transfer in, reverting upon failure. Returns the amount actually transferred to the protocol, in case of a fee. - * This may revert due to insufficient balance or insufficient allowance. - */ - function doTransferIn(address from, uint256 amount) - internal - virtual - returns (uint256); - - /** - * @dev Performs a transfer out, ideally returning an explanatory error code upon failure tather than reverting. - * If caller has not called checked protocol's balance, may revert due to insufficient cash held in the contract. - * If caller has checked protocol's balance, and verified it is >= amount, this should not revert in normal conditions. - */ - function doTransferOut(address payable to, uint256 amount) internal virtual; - - /** - * @dev Prevents a contract from calling itself, directly or indirectly. - */ - modifier nonReentrant() { - require(_notEntered, "re-entered"); - _notEntered = false; - _; - _notEntered = true; - } -} - - -// Dependency file: contracts/PriceOracle.sol - -// pragma solidity 0.8.6; - -// import "contracts/CToken.sol"; - -abstract contract PriceOracle { - /// @notice Indicator that this is a PriceOracle contract (for inspection) - bool public constant isPriceOracle = true; - - /** - * @notice Get the underlying price of a cToken asset - * @param cToken The cToken to get the underlying price of - * @return The underlying asset price mantissa (scaled by 1e18). - * Zero means the price is unavailable. - */ - function getUnderlyingPrice(CToken cToken) - external - view - virtual - returns (uint256); -} - - -// Dependency file: contracts/ComptrollerStorage.sol - -// pragma solidity 0.8.6; - -// import "contracts/CToken.sol"; -// import "contracts/PriceOracle.sol"; - -contract UnitrollerAdminStorage { - /** - * @notice Administrator for this contract - */ - address public admin; - - /** - * @notice Pending administrator for this contract - */ - address public pendingAdmin; - - /** - * @notice Active brains of Unitroller - */ - address public comptrollerImplementation; - - /** - * @notice Pending brains of Unitroller - */ - address public pendingComptrollerImplementation; -} - -contract ComptrollerV1Storage is UnitrollerAdminStorage { - - /** - * @notice Oracle which gives the price of any given asset - */ - PriceOracle public oracle; - - /** - * @notice Multiplier used to calculate the maximum repayAmount when liquidating a borrow - */ - uint public closeFactorMantissa; - - /** - * @notice Multiplier representing the discount on collateral that a liquidator receives - */ - uint public liquidationIncentiveMantissa; - - /** - * @notice Max number of assets a single account can participate in (borrow or use as collateral) - */ - uint public maxAssets; - - /** - * @notice Per-account mapping of "assets you are in", capped by maxAssets - */ - mapping(address => CToken[]) public accountAssets; - -} - -contract ComptrollerV2Storage is ComptrollerV1Storage { - struct Market { - /// @notice Whether or not this market is listed - bool isListed; - - /** - * @notice Multiplier representing the most one can borrow against their collateral in this market. - * For instance, 0.9 to allow borrowing 90% of collateral value. - * Must be between 0 and 1, and stored as a mantissa. - */ - uint collateralFactorMantissa; - - /// @notice Per-market mapping of "accounts in this asset" - mapping(address => bool) accountMembership; - - /// @notice Whether or not this market receives COMP - bool isComped; - } - - /** - * @notice Official mapping of cTokens -> Market metadata - * @dev Used e.g. to determine if a market is supported - */ - mapping(address => Market) public markets; - - - /** - * @notice The Pause Guardian can pause certain actions as a safety mechanism. - * Actions which allow users to remove their own assets cannot be paused. - * Liquidation / seizing / transfer can only be paused globally, not by market. - */ - address public pauseGuardian; - bool public _mintGuardianPaused; - bool public _borrowGuardianPaused; - bool public transferGuardianPaused; - bool public seizeGuardianPaused; - mapping(address => bool) public mintGuardianPaused; - mapping(address => bool) public borrowGuardianPaused; -} - -contract ComptrollerV3Storage is ComptrollerV2Storage { - struct CompMarketState { - /// @notice The market's last updated compBorrowIndex or compSupplyIndex - uint224 index; - - /// @notice The block number the index was last updated at - uint32 block; - } - - /// @notice A list of all markets - CToken[] public allMarkets; - - /// @notice The rate at which the flywheel distributes COMP, per block - uint public compRate; - - /// @notice The portion of compRate that each market currently receives - mapping(address => uint) public compSpeeds; - - /// @notice The COMP market supply state for each market - mapping(address => CompMarketState) public compSupplyState; - - /// @notice The COMP market borrow state for each market - mapping(address => CompMarketState) public compBorrowState; - - /// @notice The COMP borrow index for each market for each supplier as of the last time they accrued COMP - mapping(address => mapping(address => uint)) public compSupplierIndex; - - /// @notice The COMP borrow index for each market for each borrower as of the last time they accrued COMP - mapping(address => mapping(address => uint)) public compBorrowerIndex; - - /// @notice The COMP accrued but not yet transferred to each user - mapping(address => uint) public compAccrued; -} - -contract ComptrollerV4Storage is ComptrollerV3Storage { - // @notice The borrowCapGuardian can set borrowCaps to any number for any market. Lowering the borrow cap could disable borrowing on the given market. - address public borrowCapGuardian; - - // @notice Borrow caps enforced by borrowAllowed for each cToken address. Defaults to zero which corresponds to unlimited borrowing. - mapping(address => uint) public borrowCaps; - - // @notice address of the TROP token - address public tropAddress; -} - -contract ComptrollerV5Storage is ComptrollerV4Storage { - /// @notice The portion of COMP that each contributor receives per block - mapping(address => uint) public compContributorSpeeds; - - /// @notice Last block at which a contributor's COMP rewards have been allocated - mapping(address => uint) public lastContributorBlock; -} - - -// Dependency file: contracts/Unitroller.sol - -// pragma solidity 0.8.6; - -// import "contracts/ErrorReporter.sol"; -// import "contracts/ComptrollerStorage.sol"; - -/** - * @title ComptrollerCore - * @dev Storage for the comptroller is at this address, while execution is delegated to the `comptrollerImplementation`. - * CTokens should reference this contract as their comptroller. - */ -contract Unitroller is UnitrollerAdminStorage, ComptrollerErrorReporter { - /** - * @notice Emitted when pendingComptrollerImplementation is changed - */ - event NewPendingImplementation( - address oldPendingImplementation, - address newPendingImplementation - ); - - /** - * @notice Emitted when pendingComptrollerImplementation is accepted, which means comptroller implementation is updated - */ - event NewImplementation( - address oldImplementation, - address newImplementation - ); - - /** - * @notice Emitted when pendingAdmin is changed - */ - event NewPendingAdmin(address oldPendingAdmin, address newPendingAdmin); - - /** - * @notice Emitted when pendingAdmin is accepted, which means admin is updated - */ - event NewAdmin(address oldAdmin, address newAdmin); - - constructor() { - // Set admin to caller - admin = msg.sender; - } - - /*** Admin Functions ***/ - function _setPendingImplementation(address newPendingImplementation) - public - returns (uint256) - { - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_PENDING_IMPLEMENTATION_OWNER_CHECK - ); - } - - address oldPendingImplementation = pendingComptrollerImplementation; - - pendingComptrollerImplementation = newPendingImplementation; - - emit NewPendingImplementation( - oldPendingImplementation, - pendingComptrollerImplementation - ); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Accepts new implementation of comptroller. msg.sender must be pendingImplementation - * @dev Admin function for new implementation to accept it's role as implementation - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _acceptImplementation() public returns (uint256) { - // Check caller is pendingImplementation and pendingImplementation ≠ address(0) - if ( - msg.sender != pendingComptrollerImplementation || - pendingComptrollerImplementation == address(0) - ) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.ACCEPT_PENDING_IMPLEMENTATION_ADDRESS_CHECK - ); - } - - // Save current values for inclusion in log - address oldImplementation = comptrollerImplementation; - address oldPendingImplementation = pendingComptrollerImplementation; - - comptrollerImplementation = pendingComptrollerImplementation; - - pendingComptrollerImplementation = address(0); - - emit NewImplementation(oldImplementation, comptrollerImplementation); - emit NewPendingImplementation( - oldPendingImplementation, - pendingComptrollerImplementation - ); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Begins transfer of admin rights. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer. - * @dev Admin function to begin change of admin. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer. - * @param newPendingAdmin New pending admin. - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setPendingAdmin(address newPendingAdmin) - public - returns (uint256) - { - // Check caller = admin - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_PENDING_ADMIN_OWNER_CHECK - ); - } - - // Save current value, if any, for inclusion in log - address oldPendingAdmin = pendingAdmin; - - // Store pendingAdmin with value newPendingAdmin - pendingAdmin = newPendingAdmin; - - // Emit NewPendingAdmin(oldPendingAdmin, newPendingAdmin) - emit NewPendingAdmin(oldPendingAdmin, newPendingAdmin); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Accepts transfer of admin rights. msg.sender must be pendingAdmin - * @dev Admin function for pending admin to accept role and update admin - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _acceptAdmin() public returns (uint256) { - // Check caller is pendingAdmin and pendingAdmin ≠ address(0) - if (msg.sender != pendingAdmin || msg.sender == address(0)) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.ACCEPT_ADMIN_PENDING_ADMIN_CHECK - ); - } - - // Save current values for inclusion in log - address oldAdmin = admin; - address oldPendingAdmin = pendingAdmin; - - // Store admin with value pendingAdmin - admin = pendingAdmin; - - // Clear the pending value - pendingAdmin = address(0); - - emit NewAdmin(oldAdmin, admin); - emit NewPendingAdmin(oldPendingAdmin, pendingAdmin); - - return uint256(Error.NO_ERROR); - } - - /** - * @dev Delegates execution to an implementation contract. - * It returns to the external caller whatever the implementation returns - * or forwards reverts. - */ - function internalFallback() public payable { - // delegate all other functions to current implementation - (bool success, ) = comptrollerImplementation.delegatecall(msg.data); - - assembly { - let free_mem_ptr := mload(0x40) - returndatacopy(free_mem_ptr, 0, returndatasize()) - - switch success - case 0 { - revert(free_mem_ptr, returndatasize()) - } - default { - return(free_mem_ptr, returndatasize()) - } - } - } - - fallback() external payable { - internalFallback(); - } - - receive() external payable { - internalFallback(); - } -} - - -// Dependency file: contracts/Governance/TROP.sol - -// pragma solidity 0.8.6; -pragma experimental ABIEncoderV2; - -/** - * @title TROP ERC20 tokens. - * @author tropykus - * @notice Yield farming tokens that allow to propose and vote for protocol changes using the governance system. - */ -contract TROP { - /// @notice EIP-20 token name for this token - string public constant name = "tropykus"; - - /// @notice EIP-20 token symbol for this token - string public constant symbol = "TROP"; - - /// @notice EIP-20 token decimals for this token - uint8 public constant decimals = 18; - - /// @notice Total number of tokens in circulation - uint256 public constant totalSupply = 10000000e18; // 10 million TROP - - /// @notice Allowance amounts on behalf of others - mapping(address => mapping(address => uint96)) internal allowances; - - /// @notice Official record of token balances for each account - mapping(address => uint96) internal balances; - - /// @notice A record of each accounts delegate - mapping(address => address) public delegates; - - /// @notice A checkpoint for marking number of votes from a given block - struct Checkpoint { - uint32 fromBlock; - uint96 votes; - } - - /// @notice A record of votes checkpoints for each account, by index - mapping(address => mapping(uint32 => Checkpoint)) public checkpoints; - - /// @notice The number of checkpoints for each account - mapping(address => uint32) public numCheckpoints; - - /// @notice The EIP-712 typehash for the contract's domain - bytes32 public constant DOMAIN_TYPEHASH = - keccak256( - "EIP712Domain(string name,uint256 chainId,address verifyingContract)" - ); - - /// @notice The EIP-712 typehash for the delegation struct used by the contract - bytes32 public constant DELEGATION_TYPEHASH = - keccak256("Delegation(address delegatee,uint256 nonce,uint256 expiry)"); - - /// @notice A record of states for signing / validating signatures - mapping(address => uint256) public nonces; - - /// @notice An event thats emitted when an account changes its delegate - event DelegateChanged( - address indexed delegator, - address indexed fromDelegate, - address indexed toDelegate - ); - - /// @notice An event thats emitted when a delegate account's vote balance changes - event DelegateVotesChanged( - address indexed delegate, - uint256 previousBalance, - uint256 newBalance - ); - - /// @notice The standard EIP-20 transfer event - event Transfer(address indexed from, address indexed to, uint256 amount); - - /// @notice The standard EIP-20 approval event - event Approval( - address indexed owner, - address indexed spender, - uint256 amount - ); - - /** - * @notice Construct a new TROP token - * @param account The initial account to grant all the tokens - */ - constructor(address account) { - balances[account] = uint96(totalSupply); - emit Transfer(address(0), account, totalSupply); - } - - /** - * @notice Get the number of tokens `spender` is approved to spend on behalf of `account` - * @param account The address of the account holding the funds - * @param spender The address of the account spending the funds - * @return The number of tokens approved - */ - function allowance(address account, address spender) - external - view - returns (uint256) - { - return allowances[account][spender]; - } - - /** - * @notice Approve `spender` to transfer up to `amount` from `src` - * @dev This will overwrite the approval amount for `spender` - * and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve) - * @param spender The address of the account which may transfer tokens - * @param rawAmount The number of tokens that are approved (2^256-1 means infinite) - * @return Whether or not the approval succeeded - */ - function approve(address spender, uint256 rawAmount) - external - returns (bool) - { - uint96 amount; - if (rawAmount == type(uint256).max) { - amount = type(uint96).max; - } else { - amount = safe96(rawAmount, "TROP::approve: amount exceeds 96 bits"); - } - - allowances[msg.sender][spender] = amount; - - emit Approval(msg.sender, spender, amount); - return true; - } - - /** - * @notice Get the number of tokens held by the `account` - * @param account The address of the account to get the balance of - * @return The number of tokens held - */ - function balanceOf(address account) external view returns (uint256) { - return balances[account]; - } - - /** - * @notice Transfer `amount` tokens from `msg.sender` to `dst` - * @param dst The address of the destination account - * @param rawAmount The number of tokens to transfer - * @return Whether or not the transfer succeeded - */ - function transfer(address dst, uint256 rawAmount) external returns (bool) { - uint96 amount = safe96( - rawAmount, - "TROP::transfer: amount exceeds 96 bits" - ); - _transferTokens(msg.sender, dst, amount); - return true; - } - - /** - * @notice Transfer `amount` tokens from `src` to `dst` - * @param src The address of the source account - * @param dst The address of the destination account - * @param rawAmount The number of tokens to transfer - * @return Whether or not the transfer succeeded - */ - function transferFrom( - address src, - address dst, - uint256 rawAmount - ) external returns (bool) { - address spender = msg.sender; - uint96 spenderAllowance = allowances[src][spender]; - uint96 amount = safe96( - rawAmount, - "TROP::approve: amount exceeds 96 bits" - ); - - if (spender != src && spenderAllowance != type(uint96).max) { - uint96 newAllowance = sub96( - spenderAllowance, - amount, - "TROP::transferFrom: transfer amount exceeds spender allowance" - ); - allowances[src][spender] = newAllowance; - - emit Approval(src, spender, newAllowance); - } - - _transferTokens(src, dst, amount); - return true; - } - - /** - * @notice Delegate votes from `msg.sender` to `delegatee` - * @param delegatee The address to delegate votes to - */ - function delegate(address delegatee) public { - return _delegate(msg.sender, delegatee); - } - - /** - * @notice Delegates votes from signatory to `delegatee` - * @param delegatee The address to delegate votes to - * @param nonce The contract state required to match the signature - * @param expiry The time at which to expire the signature - * @param v The recovery byte of the signature - * @param r Half of the ECDSA signature pair - * @param s Half of the ECDSA signature pair - */ - function delegateBySig( - address delegatee, - uint256 nonce, - uint256 expiry, - uint8 v, - bytes32 r, - bytes32 s - ) public { - bytes32 domainSeparator = keccak256( - abi.encode( - DOMAIN_TYPEHASH, - keccak256(bytes(name)), - getChainId(), - address(this) - ) - ); - bytes32 structHash = keccak256( - abi.encode(DELEGATION_TYPEHASH, delegatee, nonce, expiry) - ); - bytes32 digest = keccak256( - abi.encodePacked("\x19\x01", domainSeparator, structHash) - ); - address signatory = ecrecover(digest, v, r, s); - require( - signatory != 0xdcc703c0E500B653Ca82273B7BFAd8045D85a470 && - signatory != address(0), - "TROP::delegateBySig: invalid signature" - ); - require( - nonce == nonces[signatory]++, - "TROP::delegateBySig: invalid nonce" - ); - require( - block.timestamp <= expiry, - "TROP::delegateBySig: signature expired" - ); - return _delegate(signatory, delegatee); - } - - /** - * @notice Gets the current votes balance for `account` - * @param account The address to get votes balance - * @return The number of current votes for `account` - */ - function getCurrentVotes(address account) external view returns (uint96) { - uint32 nCheckpoints = numCheckpoints[account]; - return - nCheckpoints > 0 ? checkpoints[account][nCheckpoints - 1].votes : 0; - } - - /** - * @notice Determine the prior number of votes for an account as of a block number - * @dev Block number must be a finalized block or else this function will revert to prevent misinformation. - * @param account The address of the account to check - * @param blockNumber The block number to get the vote balance at - * @return The number of votes the account had as of the given block - */ - function getPriorVotes(address account, uint256 blockNumber) - public - view - returns (uint96) - { - require( - blockNumber < block.number, - "TROP::getPriorVotes: not yet determined" - ); - - uint32 nCheckpoints = numCheckpoints[account]; - if (nCheckpoints == 0) { - return 0; - } - - // First check most recent balance - if (checkpoints[account][nCheckpoints - 1].fromBlock <= blockNumber) { - return checkpoints[account][nCheckpoints - 1].votes; - } - - // Next check implicit zero balance - if (checkpoints[account][0].fromBlock > blockNumber) { - return 0; - } - - uint32 lower = 0; - uint32 upper = nCheckpoints - 1; - while (upper > lower) { - uint32 center = upper - (upper - lower) / 2; // ceil, avoiding overflow - Checkpoint memory cp = checkpoints[account][center]; - if (cp.fromBlock == blockNumber) { - return cp.votes; - } else if (cp.fromBlock < blockNumber) { - lower = center; - } else { - upper = center - 1; - } - } - return checkpoints[account][lower].votes; - } - - function _delegate(address delegator, address delegatee) internal { - address currentDelegate = delegates[delegator]; - uint96 delegatorBalance = balances[delegator]; - delegates[delegator] = delegatee; - - emit DelegateChanged(delegator, currentDelegate, delegatee); - - _moveDelegates(currentDelegate, delegatee, delegatorBalance); - } - - function _transferTokens( - address src, - address dst, - uint96 amount - ) internal { - require( - src != address(0), - "TROP::_transferTokens: cannot transfer from the zero address" - ); - require( - dst != address(0), - "TROP::_transferTokens: cannot transfer to the zero address" - ); - - balances[src] = sub96( - balances[src], - amount, - "TROP::_transferTokens: transfer amount exceeds balance" - ); - balances[dst] = add96( - balances[dst], - amount, - "TROP::_transferTokens: transfer amount overflows" - ); - emit Transfer(src, dst, amount); - - _moveDelegates(delegates[src], delegates[dst], amount); - } - - function _moveDelegates( - address srcRep, - address dstRep, - uint96 amount - ) internal { - if (srcRep != dstRep && amount > 0) { - if (srcRep != address(0)) { - uint32 srcRepNum = numCheckpoints[srcRep]; - uint96 srcRepOld = srcRepNum > 0 - ? checkpoints[srcRep][srcRepNum - 1].votes - : 0; - uint96 srcRepNew = sub96( - srcRepOld, - amount, - "TROP::_moveVotes: vote amount underflows" - ); - _writeCheckpoint(srcRep, srcRepNum, srcRepOld, srcRepNew); - } - - if (dstRep != address(0)) { - uint32 dstRepNum = numCheckpoints[dstRep]; - uint96 dstRepOld = dstRepNum > 0 - ? checkpoints[dstRep][dstRepNum - 1].votes - : 0; - uint96 dstRepNew = add96( - dstRepOld, - amount, - "TROP::_moveVotes: vote amount overflows" - ); - _writeCheckpoint(dstRep, dstRepNum, dstRepOld, dstRepNew); - } - } - } - - function _writeCheckpoint( - address delegatee, - uint32 nCheckpoints, - uint96 oldVotes, - uint96 newVotes - ) internal { - uint32 blockNumber = safe32( - block.number, - "TROP::_writeCheckpoint: block number exceeds 32 bits" - ); - - if ( - nCheckpoints > 0 && - checkpoints[delegatee][nCheckpoints - 1].fromBlock == blockNumber - ) { - checkpoints[delegatee][nCheckpoints - 1].votes = newVotes; - } else { - checkpoints[delegatee][nCheckpoints] = Checkpoint( - blockNumber, - newVotes - ); - numCheckpoints[delegatee] = nCheckpoints + 1; - } - - emit DelegateVotesChanged(delegatee, oldVotes, newVotes); - } - - function safe32(uint256 n, string memory errorMessage) - internal - pure - returns (uint32) - { - require(n < 2**32, errorMessage); - return uint32(n); - } - - function safe96(uint256 n, string memory errorMessage) - internal - pure - returns (uint96) - { - require(n < 2**96, errorMessage); - return uint96(n); - } - - function add96( - uint96 a, - uint96 b, - string memory errorMessage - ) internal pure returns (uint96) { - uint96 c = a + b; - require(c >= a, errorMessage); - return c; - } - - function sub96( - uint96 a, - uint96 b, - string memory errorMessage - ) internal pure returns (uint96) { - require(b <= a, errorMessage); - return a - b; - } - - function getChainId() internal view returns (uint256) { - uint256 chainId; - assembly { - chainId := chainid() - } - return chainId; - } -} - - -// Root file: contracts/ComptrollerG3.sol - -pragma solidity 0.8.6; - -// import "contracts/CToken.sol"; -// import "contracts/ErrorReporter.sol"; -// import "contracts/Exponential.sol"; -// import "contracts/PriceOracle.sol"; -// import "contracts/ComptrollerInterface.sol"; -// import "contracts/ComptrollerStorage.sol"; -// import "contracts/Unitroller.sol"; -// import "contracts/Governance/TROP.sol"; - -/** - * @title tropykus Comptroller Contract - * @author tropykus - */ -contract ComptrollerG3 is - ComptrollerV3Storage, - ComptrollerInterface, - ComptrollerErrorReporter, - Exponential -{ - /// @notice Emitted when an admin supports a market - event MarketListed(CToken cToken); - - /// @notice Emitted when an account enters a market - event MarketEntered(CToken cToken, address account); - - /// @notice Emitted when an account exits a market - event MarketExited(CToken cToken, address account); - - /// @notice Emitted when close factor is changed by admin - event NewCloseFactor( - uint256 oldCloseFactorMantissa, - uint256 newCloseFactorMantissa - ); - - /// @notice Emitted when a collateral factor is changed by admin - event NewCollateralFactor( - CToken cToken, - uint256 oldCollateralFactorMantissa, - uint256 newCollateralFactorMantissa - ); - - /// @notice Emitted when liquidation incentive is changed by admin - event NewLiquidationIncentive( - uint256 oldLiquidationIncentiveMantissa, - uint256 newLiquidationIncentiveMantissa - ); - - /// @notice Emitted when maxAssets is changed by admin - event NewMaxAssets(uint256 oldMaxAssets, uint256 newMaxAssets); - - /// @notice Emitted when price oracle is changed - event NewPriceOracle( - PriceOracle oldPriceOracle, - PriceOracle newPriceOracle - ); - - /// @notice Emitted when pause guardian is changed - event NewPauseGuardian(address oldPauseGuardian, address newPauseGuardian); - - /// @notice Emitted when an action is paused globally - event ActionPaused(string action, bool pauseState); - - /// @notice Emitted when an action is paused on a market - event ActionPaused(CToken cToken, string action, bool pauseState); - - /// @notice Emitted when market comped status is changed - event MarketComped(CToken cToken, bool isComped); - - /// @notice Emitted when COMP rate is changed - event NewCompRate(uint256 oldCompRate, uint256 newCompRate); - - /// @notice Emitted when a new COMP speed is calculated for a market - event CompSpeedUpdated(CToken indexed cToken, uint256 newSpeed); - - /// @notice Emitted when COMP is distributed to a supplier - event DistributedSupplierComp( - CToken indexed cToken, - address indexed supplier, - uint256 compDelta, - uint256 compSupplyIndex - ); - - /// @notice Emitted when COMP is distributed to a borrower - event DistributedBorrowerComp( - CToken indexed cToken, - address indexed borrower, - uint256 compDelta, - uint256 compBorrowIndex - ); - - /// @notice The threshold above which the flywheel transfers COMP, in wei - uint256 public constant compClaimThreshold = 0.001e18; - - /// @notice The initial COMP index for a market - uint224 public constant compInitialIndex = 1e36; - - // closeFactorMantissa must be strictly greater than this value - uint256 internal constant closeFactorMinMantissa = 0.05e18; // 0.05 - - // closeFactorMantissa must not exceed this value - uint256 internal constant closeFactorMaxMantissa = 0.9e18; // 0.9 - - // No collateralFactorMantissa may exceed this value - uint256 internal constant collateralFactorMaxMantissa = 0.9e18; // 0.9 - - // liquidationIncentiveMantissa must be no less than this value - uint256 internal constant liquidationIncentiveMinMantissa = 1.0e18; // 1.0 - - // liquidationIncentiveMantissa must be no greater than this value - uint256 internal constant liquidationIncentiveMaxMantissa = 1.5e18; // 1.5 - - constructor() { - admin = msg.sender; - } - - /*** Assets You Are In ***/ - - /** - * @notice Returns the assets an account has entered - * @param account The address of the account to pull assets for - * @return A dynamic list with the assets the account has entered - */ - function getAssetsIn(address account) - external - view - returns (CToken[] memory) - { - CToken[] memory assetsIn = accountAssets[account]; - - return assetsIn; - } - - /** - * @notice Returns whether the given account is entered in the given asset - * @param account The address of the account to check - * @param cToken The cToken to check - * @return True if the account is in the asset, otherwise false. - */ - function checkMembership(address account, CToken cToken) - external - view - returns (bool) - { - return markets[address(cToken)].accountMembership[account]; - } - - /** - * @notice Add assets to be included in account liquidity calculation - * @param cTokens The list of addresses of the cToken markets to be enabled - * @return Success indicator for whether each corresponding market was entered - */ - function enterMarkets(address[] memory cTokens) - public - override - returns (uint256[] memory) - { - uint256 len = cTokens.length; - - uint256[] memory results = new uint256[](len); - for (uint256 i = 0; i < len; i++) { - CToken cToken = CToken(cTokens[i]); - - results[i] = uint256(addToMarketInternal(cToken, msg.sender)); - } - - return results; - } - - /** - * @notice Add the market to the borrower's "assets in" for liquidity calculations - * @param cToken The market to enter - * @param borrower The address of the account to modify - * @return Success indicator for whether the market was entered - */ - function addToMarketInternal(CToken cToken, address borrower) - internal - returns (Error) - { - Market storage marketToJoin = markets[address(cToken)]; - - if (!marketToJoin.isListed) { - // market is not listed, cannot join - return Error.MARKET_NOT_LISTED; - } - - if (marketToJoin.accountMembership[borrower] == true) { - // already joined - return Error.NO_ERROR; - } - - if (accountAssets[borrower].length >= maxAssets) { - // no space, cannot join - return Error.TOO_MANY_ASSETS; - } - - // survived the gauntlet, add to list - // NOTE: we store these somewhat redundantly as a significant optimization - // this avoids having to iterate through the list for the most common use cases - // that is, only when we need to perform liquidity checks - // and not whenever we want to check if an account is in a particular market - marketToJoin.accountMembership[borrower] = true; - accountAssets[borrower].push(cToken); - - emit MarketEntered(cToken, borrower); - - return Error.NO_ERROR; - } - - /** - * @notice Removes asset from sender's account liquidity calculation - * @dev Sender must not have an outstanding borrow balance in the asset, - * or be providing neccessary collateral for an outstanding borrow. - * @param cTokenAddress The address of the asset to be removed - * @return Whether or not the account successfully exited the market - */ - function exitMarket(address cTokenAddress) - external - override - returns (uint256) - { - CToken cToken = CToken(cTokenAddress); - /* Get sender tokensHeld and amountOwed underlying from the cToken */ - (uint256 oErr, uint256 tokensHeld, uint256 amountOwed, ) = cToken - .getAccountSnapshot(msg.sender); - require(oErr == 0, "exitMarket: getAccountSnapshot failed"); // semi-opaque error code - - /* Fail if the sender has a borrow balance */ - if (amountOwed != 0) { - return - fail( - Error.NONZERO_BORROW_BALANCE, - FailureInfo.EXIT_MARKET_BALANCE_OWED - ); - } - - /* Fail if the sender is not permitted to redeem all of their tokens */ - uint256 allowed = redeemAllowedInternal( - cTokenAddress, - msg.sender, - tokensHeld - ); - if (allowed != 0) { - return - failOpaque( - Error.REJECTION, - FailureInfo.EXIT_MARKET_REJECTION, - allowed - ); - } - - Market storage marketToExit = markets[address(cToken)]; - - /* Return true if the sender is not already ‘in’ the market */ - if (!marketToExit.accountMembership[msg.sender]) { - return uint256(Error.NO_ERROR); - } - - /* Set cToken account membership to false */ - delete marketToExit.accountMembership[msg.sender]; - - /* Delete cToken from the account’s list of assets */ - // load into memory for faster iteration - CToken[] memory userAssetList = accountAssets[msg.sender]; - accountAssets[msg.sender] = new CToken[](0); - CToken[] storage newMarketList = accountAssets[msg.sender]; - uint256 len = userAssetList.length; - uint256 assetIndex = len; - for (uint256 i = 0; i < len; i++) { - if (userAssetList[i] == cToken) { - assetIndex = i; - continue; - } - newMarketList.push(userAssetList[i]); - } - - // We *must* have found the asset in the list or our redundant data structure is broken - assert(assetIndex < len); - - emit MarketExited(cToken, msg.sender); - - return uint256(Error.NO_ERROR); - } - - /*** Policy Hooks ***/ - - /** - * @notice Checks if the account should be allowed to mint tokens in the given market - * @param cToken The market to verify the mint against - * @param minter The account which would get the minted tokens - * @param mintAmount The amount of underlying being supplied to the market in exchange for tokens - * @return 0 if the mint is allowed, otherwise a semi-opaque error code (See ErrorReporter.sol) - */ - function mintAllowed( - address cToken, - address minter, - uint256 mintAmount - ) external override returns (uint256) { - // Pausing is a very serious situation - we revert to sound the alarms - require(!mintGuardianPaused[cToken], "mint is paused"); - - // Shh - currently unused - minter; - mintAmount; - - if (!markets[cToken].isListed) { - return uint256(Error.MARKET_NOT_LISTED); - } - - // Keep the flywheel moving - updateCompSupplyIndex(cToken); - distributeSupplierComp(cToken, minter, false); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Validates mint and reverts on rejection. May emit logs. - * @param cToken Asset being minted - * @param minter The address minting the tokens - * @param actualMintAmount The amount of the underlying asset being minted - * @param mintTokens The number of tokens being minted - */ - function mintVerify( - address cToken, - address minter, - uint256 actualMintAmount, - uint256 mintTokens - ) external override { - // Shh - currently unused - cToken; - minter; - actualMintAmount; - mintTokens; - - // Shh - we don't ever want this hook to be marked pure - if (false) { - maxAssets = maxAssets; - } - } - - /** - * @notice Checks if the account should be allowed to redeem tokens in the given market - * @param cToken The market to verify the redeem against - * @param redeemer The account which would redeem the tokens - * @param redeemTokens The number of cTokens to exchange for the underlying asset in the market - * @return 0 if the redeem is allowed, otherwise a semi-opaque error code (See ErrorReporter.sol) - */ - function redeemAllowed( - address cToken, - address redeemer, - uint256 redeemTokens - ) external override returns (uint256) { - uint256 allowed = redeemAllowedInternal(cToken, redeemer, redeemTokens); - if (allowed != uint256(Error.NO_ERROR)) { - return allowed; - } - - // Keep the flywheel moving - updateCompSupplyIndex(cToken); - distributeSupplierComp(cToken, redeemer, false); - - return uint256(Error.NO_ERROR); - } - - function redeemAllowedInternal( - address cToken, - address redeemer, - uint256 redeemTokens - ) internal view returns (uint256) { - if (!markets[cToken].isListed) { - return uint256(Error.MARKET_NOT_LISTED); - } - - /* If the redeemer is not 'in' the market, then we can bypass the liquidity check */ - if (!markets[cToken].accountMembership[redeemer]) { - return uint256(Error.NO_ERROR); - } - - /* Otherwise, perform a hypothetical liquidity check to guard against shortfall */ - ( - Error err, - , - uint256 shortfall - ) = getHypotheticalAccountLiquidityInternal( - redeemer, - CToken(cToken), - redeemTokens, - 0 - ); - if (err != Error.NO_ERROR) { - return uint256(err); - } - if (shortfall > 0) { - return uint256(Error.INSUFFICIENT_LIQUIDITY); - } - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Validates redeem and reverts on rejection. May emit logs. - * @param cToken Asset being redeemed - * @param redeemer The address redeeming the tokens - * @param redeemAmount The amount of the underlying asset being redeemed - * @param redeemTokens The number of tokens being redeemed - */ - function redeemVerify( - address cToken, - address redeemer, - uint256 redeemAmount, - uint256 redeemTokens - ) external pure override { - // Shh - currently unused - cToken; - redeemer; - - // Require tokens is zero or amount is also zero - if (redeemTokens == 0 && redeemAmount > 0) { - revert("redeemTokens zero"); - } - } - - /** - * @notice Checks if the account should be allowed to borrow the underlying asset of the given market - * @param cToken The market to verify the borrow against - * @param borrower The account which would borrow the asset - * @param borrowAmount The amount of underlying the account would borrow - * @return 0 if the borrow is allowed, otherwise a semi-opaque error code (See ErrorReporter.sol) - */ - function borrowAllowed( - address cToken, - address borrower, - uint256 borrowAmount - ) external override returns (uint256) { - // Pausing is a very serious situation - we revert to sound the alarms - Error err; - uint256 shortfall; - require(!borrowGuardianPaused[cToken], "borrow is paused"); - - if (!markets[cToken].isListed) { - return uint256(Error.MARKET_NOT_LISTED); - } - - if (!markets[cToken].accountMembership[borrower]) { - // only cTokens may call borrowAllowed if borrower not in market - require(msg.sender == cToken, "sender must be cToken"); - - // attempt to add borrower to the market - err = addToMarketInternal(CToken(msg.sender), borrower); - if (err != Error.NO_ERROR) { - return uint256(err); - } - - // it should be impossible to break the // important invariant - assert(markets[cToken].accountMembership[borrower]); - } - - if (oracle.getUnderlyingPrice(CToken(cToken)) == 0) { - return uint256(Error.PRICE_ERROR); - } - - (err, , shortfall) = getHypotheticalAccountLiquidityInternal( - borrower, - CToken(cToken), - 0, - borrowAmount - ); - if (err != Error.NO_ERROR) { - return uint256(err); - } - if (shortfall > 0) { - return uint256(Error.INSUFFICIENT_LIQUIDITY); - } - - // Keep the flywheel moving - Exp memory borrowIndex = Exp({mantissa: CToken(cToken).borrowIndex()}); - updateCompBorrowIndex(cToken, borrowIndex); - distributeBorrowerComp(cToken, borrower, borrowIndex, false); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Validates borrow and reverts on rejection. May emit logs. - * @param cToken Asset whose underlying is being borrowed - * @param borrower The address borrowing the underlying - * @param borrowAmount The amount of the underlying asset requested to borrow - */ - function borrowVerify( - address cToken, - address borrower, - uint256 borrowAmount - ) external override { - // Shh - currently unused - cToken; - borrower; - borrowAmount; - - // Shh - we don't ever want this hook to be marked pure - if (false) { - maxAssets = maxAssets; - } - } - - /** - * @notice Checks if the account should be allowed to repay a borrow in the given market - * @param cToken The market to verify the repay against - * @param payer The account which would repay the asset - * @param borrower The account which would borrowed the asset - * @param repayAmount The amount of the underlying asset the account would repay - * @return 0 if the repay is allowed, otherwise a semi-opaque error code (See ErrorReporter.sol) - */ - function repayBorrowAllowed( - address cToken, - address payer, - address borrower, - uint256 repayAmount - ) external override returns (uint256) { - // Shh - currently unused - payer; - borrower; - repayAmount; - - if (!markets[cToken].isListed) { - return uint256(Error.MARKET_NOT_LISTED); - } - - // Keep the flywheel moving - Exp memory borrowIndex = Exp({mantissa: CToken(cToken).borrowIndex()}); - updateCompBorrowIndex(cToken, borrowIndex); - distributeBorrowerComp(cToken, borrower, borrowIndex, false); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Validates repayBorrow and reverts on rejection. May emit logs. - * @param cToken Asset being repaid - * @param payer The address repaying the borrow - * @param borrower The address of the borrower - * @param actualRepayAmount The amount of underlying being repaid - */ - function repayBorrowVerify( - address cToken, - address payer, - address borrower, - uint256 actualRepayAmount, - uint256 borrowerIndex - ) external override { - // Shh - currently unused - cToken; - payer; - borrower; - actualRepayAmount; - borrowerIndex; - - // Shh - we don't ever want this hook to be marked pure - if (false) { - maxAssets = maxAssets; - } - } - - /** - * @notice Checks if the liquidation should be allowed to occur - * @param cTokenBorrowed Asset which was borrowed by the borrower - * @param cTokenCollateral Asset which was used as collateral and will be seized - * @param liquidator The address repaying the borrow and seizing the collateral - * @param borrower The address of the borrower - * @param repayAmount The amount of underlying being repaid - */ - function liquidateBorrowAllowed( - address cTokenBorrowed, - address cTokenCollateral, - address liquidator, - address borrower, - uint256 repayAmount - ) external view override returns (uint256) { - // Shh - currently unused - liquidator; - - if ( - !markets[cTokenBorrowed].isListed || - !markets[cTokenCollateral].isListed - ) { - return uint256(Error.MARKET_NOT_LISTED); - } - - /* The borrower must have shortfall in order to be liquidatable */ - (Error err, , uint256 shortfall) = getAccountLiquidityInternal( - borrower - ); - if (err != Error.NO_ERROR) { - return uint256(err); - } - if (shortfall == 0) { - return uint256(Error.INSUFFICIENT_SHORTFALL); - } - - /* The liquidator may not repay more than what is allowed by the closeFactor */ - uint256 borrowBalance = CToken(cTokenBorrowed).borrowBalanceStored( - borrower - ); - (MathError mathErr, uint256 maxClose) = mulScalarTruncate( - Exp({mantissa: closeFactorMantissa}), - borrowBalance - ); - if (mathErr != MathError.NO_ERROR) { - return uint256(Error.MATH_ERROR); - } - if (repayAmount > maxClose) { - return uint256(Error.TOO_MUCH_REPAY); - } - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Validates liquidateBorrow and reverts on rejection. May emit logs. - * @param cTokenBorrowed Asset which was borrowed by the borrower - * @param cTokenCollateral Asset which was used as collateral and will be seized - * @param liquidator The address repaying the borrow and seizing the collateral - * @param borrower The address of the borrower - * @param actualRepayAmount The amount of underlying being repaid - */ - function liquidateBorrowVerify( - address cTokenBorrowed, - address cTokenCollateral, - address liquidator, - address borrower, - uint256 actualRepayAmount, - uint256 seizeTokens - ) external override { - // Shh - currently unused - cTokenBorrowed; - cTokenCollateral; - liquidator; - borrower; - actualRepayAmount; - seizeTokens; - - // Shh - we don't ever want this hook to be marked pure - if (false) { - maxAssets = maxAssets; - } - } - - /** - * @notice Checks if the seizing of assets should be allowed to occur - * @param cTokenCollateral Asset which was used as collateral and will be seized - * @param cTokenBorrowed Asset which was borrowed by the borrower - * @param liquidator The address repaying the borrow and seizing the collateral - * @param borrower The address of the borrower - * @param seizeTokens The number of collateral tokens to seize - */ - function seizeAllowed( - address cTokenCollateral, - address cTokenBorrowed, - address liquidator, - address borrower, - uint256 seizeTokens - ) external override returns (uint256) { - // Pausing is a very serious situation - we revert to sound the alarms - require(!seizeGuardianPaused, "seize is paused"); - - // Shh - currently unused - seizeTokens; - - if ( - !markets[cTokenCollateral].isListed || - !markets[cTokenBorrowed].isListed - ) { - return uint256(Error.MARKET_NOT_LISTED); - } - - if ( - CToken(cTokenCollateral).comptroller() != - CToken(cTokenBorrowed).comptroller() - ) { - return uint256(Error.COMPTROLLER_MISMATCH); - } - - // Keep the flywheel moving - updateCompSupplyIndex(cTokenCollateral); - distributeSupplierComp(cTokenCollateral, borrower, false); - distributeSupplierComp(cTokenCollateral, liquidator, false); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Validates seize and reverts on rejection. May emit logs. - * @param cTokenCollateral Asset which was used as collateral and will be seized - * @param cTokenBorrowed Asset which was borrowed by the borrower - * @param liquidator The address repaying the borrow and seizing the collateral - * @param borrower The address of the borrower - * @param seizeTokens The number of collateral tokens to seize - */ - function seizeVerify( - address cTokenCollateral, - address cTokenBorrowed, - address liquidator, - address borrower, - uint256 seizeTokens - ) external override { - // Shh - currently unused - cTokenCollateral; - cTokenBorrowed; - liquidator; - borrower; - seizeTokens; - - // Shh - we don't ever want this hook to be marked pure - if (false) { - maxAssets = maxAssets; - } - } - - /** - * @notice Checks if the account should be allowed to transfer tokens in the given market - * @param cToken The market to verify the transfer against - * @param src The account which sources the tokens - * @param dst The account which receives the tokens - * @param transferTokens The number of cTokens to transfer - * @return 0 if the transfer is allowed, otherwise a semi-opaque error code (See ErrorReporter.sol) - */ - function transferAllowed( - address cToken, - address src, - address dst, - uint256 transferTokens - ) external override returns (uint256) { - // Pausing is a very serious situation - we revert to sound the alarms - require(!transferGuardianPaused, "transfer is paused"); - - // Currently the only consideration is whether or not - // the src is allowed to redeem this many tokens - uint256 allowed = redeemAllowedInternal(cToken, src, transferTokens); - if (allowed != uint256(Error.NO_ERROR)) { - return allowed; - } - - // Keep the flywheel moving - updateCompSupplyIndex(cToken); - distributeSupplierComp(cToken, src, false); - distributeSupplierComp(cToken, dst, false); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Validates transfer and reverts on rejection. May emit logs. - * @param cToken Asset being transferred - * @param src The account which sources the tokens - * @param dst The account which receives the tokens - * @param transferTokens The number of cTokens to transfer - */ - function transferVerify( - address cToken, - address src, - address dst, - uint256 transferTokens - ) external override { - // Shh - currently unused - cToken; - src; - dst; - transferTokens; - - // Shh - we don't ever want this hook to be marked pure - if (false) { - maxAssets = maxAssets; - } - } - - /*** Liquidity/Liquidation Calculations ***/ - - /** - * @dev Local vars for avoiding stack-depth limits in calculating account liquidity. - * Note that `cTokenBalance` is the number of cTokens the account owns in the market, - * whereas `borrowBalance` is the amount of underlying that the account has borrowed. - */ - struct AccountLiquidityLocalVars { - uint256 sumCollateral; - uint256 sumBorrowPlusEffects; - uint256 cTokenBalance; - uint256 borrowBalance; - uint256 exchangeRateMantissa; - uint256 oraclePriceMantissa; - Exp collateralFactor; - Exp exchangeRate; - Exp oraclePrice; - Exp tokensToDenom; - } - - /** - * @notice Determine the current account liquidity wrt collateral requirements - * @return (possible error code (semi-opaque), - account liquidity in excess of collateral requirements, - * account shortfall below collateral requirements) - */ - function getAccountLiquidity(address account) - public - view - returns ( - uint256, - uint256, - uint256 - ) - { - ( - Error err, - uint256 liquidity, - uint256 shortfall - ) = getHypotheticalAccountLiquidityInternal( - account, - CToken(address(0)), - 0, - 0 - ); - - return (uint256(err), liquidity, shortfall); - } - - /** - * @notice Determine the current account liquidity wrt collateral requirements - * @return (possible error code, - account liquidity in excess of collateral requirements, - * account shortfall below collateral requirements) - */ - function getAccountLiquidityInternal(address account) - internal - view - returns ( - Error, - uint256, - uint256 - ) - { - return - getHypotheticalAccountLiquidityInternal( - account, - CToken(address(0)), - 0, - 0 - ); - } - - /** - * @notice Determine what the account liquidity would be if the given amounts were redeemed/borrowed - * @param cTokenModify The market to hypothetically redeem/borrow in - * @param account The account to determine liquidity for - * @param redeemTokens The number of tokens to hypothetically redeem - * @param borrowAmount The amount of underlying to hypothetically borrow - * @return (possible error code (semi-opaque), - hypothetical account liquidity in excess of collateral requirements, - * hypothetical account shortfall below collateral requirements) - */ - function getHypotheticalAccountLiquidity( - address account, - address cTokenModify, - uint256 redeemTokens, - uint256 borrowAmount - ) - public - view - returns ( - uint256, - uint256, - uint256 - ) - { - ( - Error err, - uint256 liquidity, - uint256 shortfall - ) = getHypotheticalAccountLiquidityInternal( - account, - CToken(cTokenModify), - redeemTokens, - borrowAmount - ); - return (uint256(err), liquidity, shortfall); - } - - /** - * @notice Determine what the account liquidity would be if the given amounts were redeemed/borrowed - * @param cTokenModify The market to hypothetically redeem/borrow in - * @param account The account to determine liquidity for - * @param redeemTokens The number of tokens to hypothetically redeem - * @param borrowAmount The amount of underlying to hypothetically borrow - * @dev Note that we calculate the exchangeRateStored for each collateral cToken using stored data, - * without calculating accumulated interest. - * @return (possible error code, - hypothetical account liquidity in excess of collateral requirements, - * hypothetical account shortfall below collateral requirements) - */ - function getHypotheticalAccountLiquidityInternal( - address account, - CToken cTokenModify, - uint256 redeemTokens, - uint256 borrowAmount - ) - internal - view - returns ( - Error, - uint256, - uint256 - ) - { - AccountLiquidityLocalVars memory vars; // Holds all our calculation results - uint256 oErr; - MathError mErr; - - // For each asset the account is in - CToken[] memory assets = accountAssets[account]; - for (uint256 i = 0; i < assets.length; i++) { - CToken asset = assets[i]; - - // Read the balances and exchange rate from the cToken - ( - oErr, - vars.cTokenBalance, - vars.borrowBalance, - vars.exchangeRateMantissa - ) = asset.getAccountSnapshot(account); - if (oErr != 0) { - // semi-opaque error code, we assume NO_ERROR == 0 is invariant between upgrades - return (Error.SNAPSHOT_ERROR, 0, 0); - } - vars.collateralFactor = Exp({ - mantissa: markets[address(asset)].collateralFactorMantissa - }); - vars.exchangeRate = Exp({mantissa: vars.exchangeRateMantissa}); - - // Get the normalized price of the asset - vars.oraclePriceMantissa = oracle.getUnderlyingPrice(asset); - if (vars.oraclePriceMantissa == 0) { - return (Error.PRICE_ERROR, 0, 0); - } - vars.oraclePrice = Exp({mantissa: vars.oraclePriceMantissa}); - - // Pre-compute a conversion factor from tokens -> ether (normalized price value) - (mErr, vars.tokensToDenom) = mulExp3( - vars.collateralFactor, - vars.exchangeRate, - vars.oraclePrice - ); - if (mErr != MathError.NO_ERROR) { - return (Error.MATH_ERROR, 0, 0); - } - - // sumCollateral += tokensToDenom * cTokenBalance - (mErr, vars.sumCollateral) = mulScalarTruncateAddUInt( - vars.tokensToDenom, - vars.cTokenBalance, - vars.sumCollateral - ); - if (mErr != MathError.NO_ERROR) { - return (Error.MATH_ERROR, 0, 0); - } - - // sumBorrowPlusEffects += oraclePrice * borrowBalance - (mErr, vars.sumBorrowPlusEffects) = mulScalarTruncateAddUInt( - vars.oraclePrice, - vars.borrowBalance, - vars.sumBorrowPlusEffects - ); - if (mErr != MathError.NO_ERROR) { - return (Error.MATH_ERROR, 0, 0); - } - - // Calculate effects of interacting with cTokenModify - if (asset == cTokenModify) { - // redeem effect - // sumBorrowPlusEffects += tokensToDenom * redeemTokens - (mErr, vars.sumBorrowPlusEffects) = mulScalarTruncateAddUInt( - vars.tokensToDenom, - redeemTokens, - vars.sumBorrowPlusEffects - ); - if (mErr != MathError.NO_ERROR) { - return (Error.MATH_ERROR, 0, 0); - } - - // borrow effect - // sumBorrowPlusEffects += oraclePrice * borrowAmount - (mErr, vars.sumBorrowPlusEffects) = mulScalarTruncateAddUInt( - vars.oraclePrice, - borrowAmount, - vars.sumBorrowPlusEffects - ); - if (mErr != MathError.NO_ERROR) { - return (Error.MATH_ERROR, 0, 0); - } - } - } - - // These are safe, as the underflow condition is checked first - if (vars.sumCollateral > vars.sumBorrowPlusEffects) { - return ( - Error.NO_ERROR, - vars.sumCollateral - vars.sumBorrowPlusEffects, - 0 - ); - } else { - return ( - Error.NO_ERROR, - 0, - vars.sumBorrowPlusEffects - vars.sumCollateral - ); - } - } - - /** - * @notice Calculate number of tokens of collateral asset to seize given an underlying amount - * @dev Used in liquidation (called in cToken.liquidateBorrowFresh) - * @param cTokenBorrowed The address of the borrowed cToken - * @param cTokenCollateral The address of the collateral cToken - * @param actualRepayAmount The amount of cTokenBorrowed underlying to convert into cTokenCollateral tokens - * @return (errorCode, number of cTokenCollateral tokens to be seized in a liquidation) - */ - function liquidateCalculateSeizeTokens( - address cTokenBorrowed, - address cTokenCollateral, - uint256 actualRepayAmount - ) external view override returns (uint256, uint256) { - /* Read oracle prices for borrowed and collateral markets */ - uint256 priceBorrowedMantissa = oracle.getUnderlyingPrice( - CToken(cTokenBorrowed) - ); - uint256 priceCollateralMantissa = oracle.getUnderlyingPrice( - CToken(cTokenCollateral) - ); - if (priceBorrowedMantissa == 0 || priceCollateralMantissa == 0) { - return (uint256(Error.PRICE_ERROR), 0); - } - - /* - * Get the exchange rate and calculate the number of collateral tokens to seize: - * seizeAmount = actualRepayAmount * liquidationIncentive * priceBorrowed / priceCollateral - * seizeTokens = seizeAmount / exchangeRate - * = actualRepayAmount * (liquidationIncentive * priceBorrowed) / (priceCollateral * exchangeRate) - */ - uint256 exchangeRateMantissa = CToken(cTokenCollateral) - .exchangeRateStored(); // Note: reverts on error - uint256 seizeTokens; - Exp memory numerator; - Exp memory denominator; - Exp memory ratio; - MathError mathErr; - - (mathErr, numerator) = mulExp( - liquidationIncentiveMantissa, - priceBorrowedMantissa - ); - if (mathErr != MathError.NO_ERROR) { - return (uint256(Error.MATH_ERROR), 0); - } - - (mathErr, denominator) = mulExp( - priceCollateralMantissa, - exchangeRateMantissa - ); - if (mathErr != MathError.NO_ERROR) { - return (uint256(Error.MATH_ERROR), 0); - } - - (mathErr, ratio) = divExp(numerator, denominator); - if (mathErr != MathError.NO_ERROR) { - return (uint256(Error.MATH_ERROR), 0); - } - - (mathErr, seizeTokens) = mulScalarTruncate(ratio, actualRepayAmount); - if (mathErr != MathError.NO_ERROR) { - return (uint256(Error.MATH_ERROR), 0); - } - - return (uint256(Error.NO_ERROR), seizeTokens); - } - - /*** Admin Functions ***/ - - /** - * @notice Sets a new price oracle for the comptroller - * @dev Admin function to set a new price oracle - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setPriceOracle(PriceOracle newOracle) public returns (uint256) { - // Check caller is admin - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_PRICE_ORACLE_OWNER_CHECK - ); - } - - // Track the old oracle for the comptroller - PriceOracle oldOracle = oracle; - - // Set comptroller's oracle to newOracle - oracle = newOracle; - - // Emit NewPriceOracle(oldOracle, newOracle) - emit NewPriceOracle(oldOracle, newOracle); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Sets the closeFactor used when liquidating borrows - * @dev Admin function to set closeFactor - * @param newCloseFactorMantissa New close factor, scaled by 1e18 - * @return uint 0=success, otherwise a failure. (See ErrorReporter for details) - */ - function _setCloseFactor(uint256 newCloseFactorMantissa) - external - returns (uint256) - { - // Check caller is admin - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_CLOSE_FACTOR_OWNER_CHECK - ); - } - - Exp memory newCloseFactorExp = Exp({mantissa: newCloseFactorMantissa}); - Exp memory lowLimit = Exp({mantissa: closeFactorMinMantissa}); - if (lessThanOrEqualExp(newCloseFactorExp, lowLimit)) { - return - fail( - Error.INVALID_CLOSE_FACTOR, - FailureInfo.SET_CLOSE_FACTOR_VALIDATION - ); - } - - Exp memory highLimit = Exp({mantissa: closeFactorMaxMantissa}); - if (lessThanExp(highLimit, newCloseFactorExp)) { - return - fail( - Error.INVALID_CLOSE_FACTOR, - FailureInfo.SET_CLOSE_FACTOR_VALIDATION - ); - } - - uint256 oldCloseFactorMantissa = closeFactorMantissa; - closeFactorMantissa = newCloseFactorMantissa; - emit NewCloseFactor(oldCloseFactorMantissa, closeFactorMantissa); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Sets the collateralFactor for a market - * @dev Admin function to set per-market collateralFactor - * @param cToken The market to set the factor on - * @param newCollateralFactorMantissa The new collateral factor, scaled by 1e18 - * @return uint 0=success, otherwise a failure. (See ErrorReporter for details) - */ - function _setCollateralFactor( - CToken cToken, - uint256 newCollateralFactorMantissa - ) external returns (uint256) { - // Check caller is admin - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_COLLATERAL_FACTOR_OWNER_CHECK - ); - } - - // Verify market is listed - Market storage market = markets[address(cToken)]; - if (!market.isListed) { - return - fail( - Error.MARKET_NOT_LISTED, - FailureInfo.SET_COLLATERAL_FACTOR_NO_EXISTS - ); - } - - Exp memory newCollateralFactorExp = Exp({ - mantissa: newCollateralFactorMantissa - }); - - // Check collateral factor <= 0.9 - Exp memory highLimit = Exp({mantissa: collateralFactorMaxMantissa}); - if (lessThanExp(highLimit, newCollateralFactorExp)) { - return - fail( - Error.INVALID_COLLATERAL_FACTOR, - FailureInfo.SET_COLLATERAL_FACTOR_VALIDATION - ); - } - - // If collateral factor != 0, fail if price == 0 - if ( - newCollateralFactorMantissa != 0 && - oracle.getUnderlyingPrice(cToken) == 0 - ) { - return - fail( - Error.PRICE_ERROR, - FailureInfo.SET_COLLATERAL_FACTOR_WITHOUT_PRICE - ); - } - - // Set market's collateral factor to new collateral factor, remember old value - uint256 oldCollateralFactorMantissa = market.collateralFactorMantissa; - market.collateralFactorMantissa = newCollateralFactorMantissa; - - // Emit event with asset, old collateral factor, and new collateral factor - emit NewCollateralFactor( - cToken, - oldCollateralFactorMantissa, - newCollateralFactorMantissa - ); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Sets maxAssets which controls how many markets can be entered - * @dev Admin function to set maxAssets - * @param newMaxAssets New max assets - * @return uint 0=success, otherwise a failure. (See ErrorReporter for details) - */ - function _setMaxAssets(uint256 newMaxAssets) external returns (uint256) { - // Check caller is admin - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_MAX_ASSETS_OWNER_CHECK - ); - } - - uint256 oldMaxAssets = maxAssets; - maxAssets = newMaxAssets; - emit NewMaxAssets(oldMaxAssets, newMaxAssets); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Sets liquidationIncentive - * @dev Admin function to set liquidationIncentive - * @param newLiquidationIncentiveMantissa New liquidationIncentive scaled by 1e18 - * @return uint 0=success, otherwise a failure. (See ErrorReporter for details) - */ - function _setLiquidationIncentive(uint256 newLiquidationIncentiveMantissa) - external - returns (uint256) - { - // Check caller is admin - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_LIQUIDATION_INCENTIVE_OWNER_CHECK - ); - } - - // Check de-scaled min <= newLiquidationIncentive <= max - Exp memory newLiquidationIncentive = Exp({ - mantissa: newLiquidationIncentiveMantissa - }); - Exp memory minLiquidationIncentive = Exp({ - mantissa: liquidationIncentiveMinMantissa - }); - if (lessThanExp(newLiquidationIncentive, minLiquidationIncentive)) { - return - fail( - Error.INVALID_LIQUIDATION_INCENTIVE, - FailureInfo.SET_LIQUIDATION_INCENTIVE_VALIDATION - ); - } - - Exp memory maxLiquidationIncentive = Exp({ - mantissa: liquidationIncentiveMaxMantissa - }); - if (lessThanExp(maxLiquidationIncentive, newLiquidationIncentive)) { - return - fail( - Error.INVALID_LIQUIDATION_INCENTIVE, - FailureInfo.SET_LIQUIDATION_INCENTIVE_VALIDATION - ); - } - - // Save current value for use in log - uint256 oldLiquidationIncentiveMantissa = liquidationIncentiveMantissa; - - // Set liquidation incentive to new incentive - liquidationIncentiveMantissa = newLiquidationIncentiveMantissa; - - // Emit event with old incentive, new incentive - emit NewLiquidationIncentive( - oldLiquidationIncentiveMantissa, - newLiquidationIncentiveMantissa - ); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Add the market to the markets mapping and set it as listed - * @dev Admin function to set isListed and add support for the market - * @param cToken The address of the market (token) to list - * @return uint 0=success, otherwise a failure. (See enum Error for details) - */ - function _supportMarket(CToken cToken) external returns (uint256) { - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SUPPORT_MARKET_OWNER_CHECK - ); - } - - if (markets[address(cToken)].isListed) { - return - fail( - Error.MARKET_ALREADY_LISTED, - FailureInfo.SUPPORT_MARKET_EXISTS - ); - } - - cToken.isCToken(); // Sanity check to make sure its really a CToken - - Market storage market = markets[address(cToken)]; - market.isListed = true; - market.isComped = false; - market.collateralFactorMantissa = 0; - - _addMarketInternal(address(cToken)); - - emit MarketListed(cToken); - - return uint256(Error.NO_ERROR); - } - - function _addMarketInternal(address cToken) internal { - for (uint256 i = 0; i < allMarkets.length; i++) { - require(allMarkets[i] != CToken(cToken), "market already added"); - } - allMarkets.push(CToken(cToken)); - } - - /** - * @notice Admin function to change the Pause Guardian - * @param newPauseGuardian The address of the new Pause Guardian - * @return uint 0=success, otherwise a failure. (See enum Error for details) - */ - function _setPauseGuardian(address newPauseGuardian) - public - returns (uint256) - { - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_PAUSE_GUARDIAN_OWNER_CHECK - ); - } - - // Save current value for inclusion in log - address oldPauseGuardian = pauseGuardian; - - // Store pauseGuardian with value newPauseGuardian - pauseGuardian = newPauseGuardian; - - // Emit NewPauseGuardian(OldPauseGuardian, NewPauseGuardian) - emit NewPauseGuardian(oldPauseGuardian, pauseGuardian); - - return uint256(Error.NO_ERROR); - } - - function _setMintPaused(CToken cToken, bool state) public returns (bool) { - require( - markets[address(cToken)].isListed, - "cannot pause a market that is not listed" - ); - require( - msg.sender == pauseGuardian || msg.sender == admin, - "only pause guardian and admin can pause" - ); - require(msg.sender == admin || state == true, "only admin can unpause"); - - mintGuardianPaused[address(cToken)] = state; - emit ActionPaused(cToken, "Mint", state); - return state; - } - - function _setBorrowPaused(CToken cToken, bool state) public returns (bool) { - require( - markets[address(cToken)].isListed, - "cannot pause a market that is not listed" - ); - require( - msg.sender == pauseGuardian || msg.sender == admin, - "only pause guardian and admin can pause" - ); - require(msg.sender == admin || state == true, "only admin can unpause"); - - borrowGuardianPaused[address(cToken)] = state; - emit ActionPaused(cToken, "Borrow", state); - return state; - } - - function _setTransferPaused(bool state) public returns (bool) { - require( - msg.sender == pauseGuardian || msg.sender == admin, - "only pause guardian and admin can pause" - ); - require(msg.sender == admin || state == true, "only admin can unpause"); - - transferGuardianPaused = state; - emit ActionPaused("Transfer", state); - return state; - } - - function _setSeizePaused(bool state) public returns (bool) { - require( - msg.sender == pauseGuardian || msg.sender == admin, - "only pause guardian and admin can pause" - ); - require(msg.sender == admin || state == true, "only admin can unpause"); - - seizeGuardianPaused = state; - emit ActionPaused("Seize", state); - return state; - } - - function _become( - Unitroller unitroller, - uint256 compRate_, - address[] memory compMarketsToAdd, - address[] memory otherMarketsToAdd - ) public { - require( - msg.sender == unitroller.admin(), - "only unitroller admin can change brains" - ); - require( - unitroller._acceptImplementation() == 0, - "change not authorized" - ); - - ComptrollerG3(address(unitroller))._becomeG3( - compRate_, - compMarketsToAdd, - otherMarketsToAdd - ); - } - - function _becomeG3( - uint256 compRate_, - address[] memory compMarketsToAdd, - address[] memory otherMarketsToAdd - ) public { - require( - msg.sender == comptrollerImplementation, - "only brains can become itself" - ); - - for (uint256 i = 0; i < compMarketsToAdd.length; i++) { - _addMarketInternal(address(compMarketsToAdd[i])); - } - - for (uint256 i = 0; i < otherMarketsToAdd.length; i++) { - _addMarketInternal(address(otherMarketsToAdd[i])); - } - - _setCompRate(compRate_); - _addCompMarkets(compMarketsToAdd); - } - - /** - * @notice Checks caller is admin, or this contract is becoming the new implementation - */ - function adminOrInitializing() internal view returns (bool) { - return msg.sender == admin || msg.sender == comptrollerImplementation; - } - - /*** TROP Distribution ***/ - - /** - * @notice Recalculate and update COMP speeds for all COMP markets - */ - function refreshCompSpeeds() public { - CToken[] memory allMarkets_ = allMarkets; - - for (uint256 i = 0; i < allMarkets_.length; i++) { - CToken cToken = allMarkets_[i]; - Exp memory borrowIndex = Exp({mantissa: cToken.borrowIndex()}); - updateCompSupplyIndex(address(cToken)); - updateCompBorrowIndex(address(cToken), borrowIndex); - } - - Exp memory totalUtility = Exp({mantissa: 0}); - Exp[] memory utilities = new Exp[](allMarkets_.length); - for (uint256 i = 0; i < allMarkets_.length; i++) { - CToken cToken = allMarkets_[i]; - if (markets[address(cToken)].isComped) { - Exp memory assetPrice = Exp({ - mantissa: oracle.getUnderlyingPrice(cToken) - }); - Exp memory interestPerBlock = mul_( - Exp({mantissa: cToken.borrowRatePerBlock()}), - cToken.totalBorrows() - ); - Exp memory utility = mul_(interestPerBlock, assetPrice); - utilities[i] = utility; - totalUtility = add_(totalUtility, utility); - } - } - - for (uint256 i = 0; i < allMarkets_.length; i++) { - CToken cToken = allMarkets[i]; - uint256 newSpeed = totalUtility.mantissa > 0 - ? mul_(compRate, div_(utilities[i], totalUtility)) - : 0; - compSpeeds[address(cToken)] = newSpeed; - emit CompSpeedUpdated(cToken, newSpeed); - } - } - - /** - * @notice Accrue COMP to the market by updating the supply index - * @param cToken The market whose supply index to update - */ - function updateCompSupplyIndex(address cToken) internal { - CompMarketState storage supplyState = compSupplyState[cToken]; - uint256 supplySpeed = compSpeeds[cToken]; - uint256 blockNumber = getBlockNumber(); - uint256 deltaBlocks = sub_(blockNumber, uint256(supplyState.block)); - if (deltaBlocks > 0 && supplySpeed > 0) { - uint256 supplyTokens = CToken(cToken).totalSupply(); - uint256 compAccrued = mul_(deltaBlocks, supplySpeed); - Double memory ratio = supplyTokens > 0 - ? fraction(compAccrued, supplyTokens) - : Double({mantissa: 0}); - Double memory index = add_( - Double({mantissa: supplyState.index}), - ratio - ); - compSupplyState[cToken] = CompMarketState({ - index: safe224(index.mantissa, "new index exceeds 224 bits"), - block: safe32(blockNumber, "block number exceeds 32 bits") - }); - } else if (deltaBlocks > 0) { - supplyState.block = safe32( - blockNumber, - "block number exceeds 32 bits" - ); - } - } - - /** - * @notice Accrue COMP to the market by updating the borrow index - * @param cToken The market whose borrow index to update - */ - function updateCompBorrowIndex(address cToken, Exp memory marketBorrowIndex) - internal - { - CompMarketState storage borrowState = compBorrowState[cToken]; - uint256 borrowSpeed = compSpeeds[cToken]; - uint256 blockNumber = getBlockNumber(); - uint256 deltaBlocks = sub_(blockNumber, uint256(borrowState.block)); - if (deltaBlocks > 0 && borrowSpeed > 0) { - uint256 borrowAmount = div_( - CToken(cToken).totalBorrows(), - marketBorrowIndex - ); - uint256 compAccrued = mul_(deltaBlocks, borrowSpeed); - Double memory ratio = borrowAmount > 0 - ? fraction(compAccrued, borrowAmount) - : Double({mantissa: 0}); - Double memory index = add_( - Double({mantissa: borrowState.index}), - ratio - ); - compBorrowState[cToken] = CompMarketState({ - index: safe224(index.mantissa, "new index exceeds 224 bits"), - block: safe32(blockNumber, "block number exceeds 32 bits") - }); - } else if (deltaBlocks > 0) { - borrowState.block = safe32( - blockNumber, - "block number exceeds 32 bits" - ); - } - } - - /** - * @notice Calculate COMP accrued by a supplier and possibly transfer it to them - * @param cToken The market in which the supplier is interacting - * @param supplier The address of the supplier to distribute COMP to - */ - function distributeSupplierComp( - address cToken, - address supplier, - bool distributeAll - ) internal { - CompMarketState storage supplyState = compSupplyState[cToken]; - Double memory supplyIndex = Double({mantissa: supplyState.index}); - Double memory supplierIndex = Double({ - mantissa: compSupplierIndex[cToken][supplier] - }); - compSupplierIndex[cToken][supplier] = supplyIndex.mantissa; - - if (supplierIndex.mantissa == 0 && supplyIndex.mantissa > 0) { - supplierIndex.mantissa = compInitialIndex; - } - - Double memory deltaIndex = sub_(supplyIndex, supplierIndex); - uint256 supplierTokens = CToken(cToken).balanceOf(supplier); - uint256 supplierDelta = mul_(supplierTokens, deltaIndex); - uint256 supplierAccrued = add_(compAccrued[supplier], supplierDelta); - compAccrued[supplier] = transferComp( - supplier, - supplierAccrued, - distributeAll ? 0 : compClaimThreshold - ); - emit DistributedSupplierComp( - CToken(cToken), - supplier, - supplierDelta, - supplyIndex.mantissa - ); - } - - /** - * @notice Calculate COMP accrued by a borrower and possibly transfer it to them - * @dev Borrowers will not begin to accrue until after the first interaction with the protocol. - * @param cToken The market in which the borrower is interacting - * @param borrower The address of the borrower to distribute COMP to - */ - function distributeBorrowerComp( - address cToken, - address borrower, - Exp memory marketBorrowIndex, - bool distributeAll - ) internal { - CompMarketState storage borrowState = compBorrowState[cToken]; - Double memory borrowIndex = Double({mantissa: borrowState.index}); - Double memory borrowerIndex = Double({ - mantissa: compBorrowerIndex[cToken][borrower] - }); - compBorrowerIndex[cToken][borrower] = borrowIndex.mantissa; - - if (borrowerIndex.mantissa > 0) { - Double memory deltaIndex = sub_(borrowIndex, borrowerIndex); - uint256 borrowerAmount = div_( - CToken(cToken).borrowBalanceStored(borrower), - marketBorrowIndex - ); - uint256 borrowerDelta = mul_(borrowerAmount, deltaIndex); - uint256 borrowerAccrued = add_( - compAccrued[borrower], - borrowerDelta - ); - compAccrued[borrower] = transferComp( - borrower, - borrowerAccrued, - distributeAll ? 0 : compClaimThreshold - ); - emit DistributedBorrowerComp( - CToken(cToken), - borrower, - borrowerDelta, - borrowIndex.mantissa - ); - } - } - - /** - * @notice Transfer COMP to the user, if they are above the threshold - * @dev Note: If there is not enough COMP, we do not perform the transfer all. - * @param user The address of the user to transfer COMP to - * @param userAccrued The amount of COMP to (possibly) transfer - * @return The amount of COMP which was NOT transferred to the user - */ - function transferComp( - address user, - uint256 userAccrued, - uint256 threshold - ) internal returns (uint256) { - if (userAccrued >= threshold && userAccrued > 0) { - TROP comp = TROP(getCompAddress()); - uint256 compRemaining = comp.balanceOf(address(this)); - if (userAccrued <= compRemaining) { - comp.transfer(user, userAccrued); - return 0; - } - } - return userAccrued; - } - - /** - * @notice Claim all the comp accrued by holder in all markets - * @param holder The address to claim COMP for - */ - function claimComp(address holder) public { - return claimComp(holder, allMarkets); - } - - /** - * @notice Claim all the comp accrued by holder in the specified markets - * @param holder The address to claim COMP for - * @param cTokens The list of markets to claim COMP in - */ - function claimComp(address holder, CToken[] memory cTokens) public { - address[] memory holders = new address[](1); - holders[0] = holder; - claimComp(holders, cTokens, true, true); - } - - /** - * @notice Claim all comp accrued by the holders - * @param holders The addresses to claim COMP for - * @param cTokens The list of markets to claim COMP in - * @param borrowers Whether or not to claim COMP earned by borrowing - * @param suppliers Whether or not to claim COMP earned by supplying - */ - function claimComp( - address[] memory holders, - CToken[] memory cTokens, - bool borrowers, - bool suppliers - ) public { - for (uint256 i = 0; i < cTokens.length; i++) { - CToken cToken = cTokens[i]; - require(markets[address(cToken)].isListed, "market must be listed"); - if (borrowers == true) { - Exp memory borrowIndex = Exp({mantissa: cToken.borrowIndex()}); - updateCompBorrowIndex(address(cToken), borrowIndex); - for (uint256 j = 0; j < holders.length; j++) { - distributeBorrowerComp( - address(cToken), - holders[j], - borrowIndex, - true - ); - } - } - if (suppliers == true) { - updateCompSupplyIndex(address(cToken)); - for (uint256 j = 0; j < holders.length; j++) { - distributeSupplierComp(address(cToken), holders[j], true); - } - } - } - } - - /*** TROP Distribution Admin ***/ - - /** - * @notice Set the amount of COMP distributed per block - * @param compRate_ The amount of COMP wei per block to distribute - */ - function _setCompRate(uint256 compRate_) public { - require(adminOrInitializing(), "only admin can change comp rate"); - - uint256 oldRate = compRate; - compRate = compRate_; - emit NewCompRate(oldRate, compRate_); - - refreshCompSpeeds(); - } - - /** - * @notice Add markets to compMarkets, allowing them to earn COMP in the flywheel - * @param cTokens The addresses of the markets to add - */ - function _addCompMarkets(address[] memory cTokens) public { - require(adminOrInitializing(), "only admin can add comp market"); - - for (uint256 i = 0; i < cTokens.length; i++) { - _addCompMarketInternal(cTokens[i]); - } - - refreshCompSpeeds(); - } - - function _addCompMarketInternal(address cToken) internal { - Market storage market = markets[cToken]; - require(market.isListed == true, "comp market is not listed"); - require(market.isComped == false, "comp market already added"); - - market.isComped = true; - emit MarketComped(CToken(cToken), true); - - if ( - compSupplyState[cToken].index == 0 && - compSupplyState[cToken].block == 0 - ) { - compSupplyState[cToken] = CompMarketState({ - index: compInitialIndex, - block: safe32(getBlockNumber(), "block number exceeds 32 bits") - }); - } - - if ( - compBorrowState[cToken].index == 0 && - compBorrowState[cToken].block == 0 - ) { - compBorrowState[cToken] = CompMarketState({ - index: compInitialIndex, - block: safe32(getBlockNumber(), "block number exceeds 32 bits") - }); - } - } - - /** - * @notice Remove a market from compMarkets, preventing it from earning COMP in the flywheel - * @param cToken The address of the market to drop - */ - function _dropCompMarket(address cToken) public { - require(msg.sender == admin, "only admin can drop comp market"); - - Market storage market = markets[cToken]; - require(market.isComped == true, "market is not a comp market"); - - market.isComped = false; - emit MarketComped(CToken(cToken), false); - - refreshCompSpeeds(); - } - - /** - * @notice Return all of the markets - * @dev The automatic getter may be used to access an individual market. - * @return The list of market addresses - */ - function getAllMarkets() public view returns (CToken[] memory) { - return allMarkets; - } - - function getBlockNumber() public view virtual returns (uint256) { - return block.number; - } - - /** - * @notice Return the address of the COMP token - * @return The address of COMP - */ - function getCompAddress() public view virtual returns (address) { - return 0xc00e94Cb662C3520282E6f5717214004A7f26888; - } -} diff --git a/flatten/ComptrollerG4.sol b/flatten/ComptrollerG4.sol deleted file mode 100644 index 9434b30..0000000 --- a/flatten/ComptrollerG4.sol +++ /dev/null @@ -1,6579 +0,0 @@ -// Dependency file: contracts/ComptrollerInterface.sol - -// SPDX-License-Identifier: UNLICENSED -// pragma solidity 0.8.6; - -abstract contract ComptrollerInterface { - /// @notice Indicator that this is a Comptroller contract (for inspection) - bool public constant isComptroller = true; - - /*** Assets You Are In ***/ - - function enterMarkets(address[] calldata cTokens) - external - virtual - returns (uint256[] memory); - - function exitMarket(address cToken) external virtual returns (uint256); - - /*** Policy Hooks ***/ - - function mintAllowed( - address cToken, - address minter, - uint256 mintAmount - ) external virtual returns (uint256); - - function mintVerify( - address cToken, - address minter, - uint256 mintAmount, - uint256 mintTokens - ) external virtual; - - function redeemAllowed( - address cToken, - address redeemer, - uint256 redeemTokens - ) external virtual returns (uint256); - - function redeemVerify( - address cToken, - address redeemer, - uint256 redeemAmount, - uint256 redeemTokens - ) external virtual; - - function borrowAllowed( - address cToken, - address borrower, - uint256 borrowAmount - ) external virtual returns (uint256); - - function borrowVerify( - address cToken, - address borrower, - uint256 borrowAmount - ) external virtual; - - function repayBorrowAllowed( - address cToken, - address payer, - address borrower, - uint256 repayAmount - ) external virtual returns (uint256); - - function repayBorrowVerify( - address cToken, - address payer, - address borrower, - uint256 repayAmount, - uint256 borrowerIndex - ) external virtual; - - function liquidateBorrowAllowed( - address cTokenBorrowed, - address cTokenCollateral, - address liquidator, - address borrower, - uint256 repayAmount - ) external virtual returns (uint256); - - function liquidateBorrowVerify( - address cTokenBorrowed, - address cTokenCollateral, - address liquidator, - address borrower, - uint256 repayAmount, - uint256 seizeTokens - ) external virtual; - - function seizeAllowed( - address cTokenCollateral, - address cTokenBorrowed, - address liquidator, - address borrower, - uint256 seizeTokens - ) external virtual returns (uint256); - - function seizeVerify( - address cTokenCollateral, - address cTokenBorrowed, - address liquidator, - address borrower, - uint256 seizeTokens - ) external virtual; - - function transferAllowed( - address cToken, - address src, - address dst, - uint256 transferTokens - ) external virtual returns (uint256); - - function transferVerify( - address cToken, - address src, - address dst, - uint256 transferTokens - ) external virtual; - - /*** Liquidity/Liquidation Calculations ***/ - - function liquidateCalculateSeizeTokens( - address cTokenBorrowed, - address cTokenCollateral, - uint256 repayAmount - ) external view virtual returns (uint256, uint256); -} - - -// Dependency file: contracts/CarefulMath.sol - -// pragma solidity 0.8.6; - -/** - * @title Careful Math - * @author tropykus - * @notice Derived from OpenZeppelin's SafeMath library - * https://github.com/OpenZeppelin/openzeppelin-solidity/blob/master/contracts/math/SafeMath.sol - */ -contract CarefulMath { - - /** - * @dev Possible error codes that we can return - */ - enum MathError { - NO_ERROR, - DIVISION_BY_ZERO, - INTEGER_OVERFLOW, - INTEGER_UNDERFLOW - } - - /** - * @dev Multiplies two numbers, returns an error on overflow. - */ - function mulUInt(uint a, uint b) internal pure returns (MathError, uint) { - if (a == 0) { - return (MathError.NO_ERROR, 0); - } - - uint c = a * b; - - if (c / a != b) { - return (MathError.INTEGER_OVERFLOW, 0); - } else { - return (MathError.NO_ERROR, c); - } - } - - /** - * @dev Integer division of two numbers, truncating the quotient. - */ - function divUInt(uint a, uint b) internal pure returns (MathError, uint) { - if (b == 0) { - return (MathError.DIVISION_BY_ZERO, 0); - } - - return (MathError.NO_ERROR, a / b); - } - - /** - * @dev Subtracts two numbers, returns an error on overflow (i.e. if subtrahend is greater than minuend). - */ - function subUInt(uint a, uint b) internal pure returns (MathError, uint) { - if (b <= a) { - return (MathError.NO_ERROR, a - b); - } else { - return (MathError.INTEGER_UNDERFLOW, 0); - } - } - - /** - * @dev Adds two numbers, returns an error on overflow. - */ - function addUInt(uint a, uint b) internal pure returns (MathError, uint) { - uint c = a + b; - - if (c >= a) { - return (MathError.NO_ERROR, c); - } else { - return (MathError.INTEGER_OVERFLOW, 0); - } - } - - /** - * @dev add a and b and then subtract c - */ - function addThenSubUInt(uint a, uint b, uint c) internal pure returns (MathError, uint) { - (MathError err0, uint sum) = addUInt(a, b); - - if (err0 != MathError.NO_ERROR) { - return (err0, 0); - } - - return subUInt(sum, c); - } -} - - -// Dependency file: contracts/ExponentialNoError.sol - -// pragma solidity 0.8.6; - -/** - * @title Exponential module for storing fixed-precision decimals - * @author tropykus - * @notice Exp is a struct which stores decimals with a fixed precision of 18 decimal places. - * Thus, if we wanted to store the 5.1, mantissa would store 5.1e18. That is: - * `Exp({mantissa: 5100000000000000000})`. - */ -contract ExponentialNoError { - uint constant expScale = 1e18; - uint constant doubleScale = 1e36; - uint constant halfExpScale = expScale/2; - uint constant mantissaOne = expScale; - - struct Exp { - uint mantissa; - } - - struct Double { - uint mantissa; - } - - /** - * @dev Truncates the given exp to a whole number value. - * For example, truncate(Exp{mantissa: 15 * expScale}) = 15 - */ - function truncate(Exp memory exp) pure internal returns (uint) { - // Note: We are not using careful math here as we're performing a division that cannot fail - return exp.mantissa / expScale; - } - - /** - * @dev Multiply an Exp by a scalar, then truncate to return an unsigned integer. - */ - function mul_ScalarTruncate(Exp memory a, uint scalar) pure internal returns (uint) { - Exp memory product = mul_(a, scalar); - return truncate(product); - } - - /** - * @dev Multiply an Exp by a scalar, truncate, then add an to an unsigned integer, returning an unsigned integer. - */ - function mul_ScalarTruncateAddUInt(Exp memory a, uint scalar, uint addend) pure internal returns (uint) { - Exp memory product = mul_(a, scalar); - return add_(truncate(product), addend); - } - - /** - * @dev Checks if first Exp is less than second Exp. - */ - function lessThanExp(Exp memory left, Exp memory right) pure internal returns (bool) { - return left.mantissa < right.mantissa; - } - - /** - * @dev Checks if left Exp <= right Exp. - */ - function lessThanOrEqualExp(Exp memory left, Exp memory right) pure internal returns (bool) { - return left.mantissa <= right.mantissa; - } - - /** - * @dev Checks if left Exp > right Exp. - */ - function greaterThanExp(Exp memory left, Exp memory right) pure internal returns (bool) { - return left.mantissa > right.mantissa; - } - - /** - * @dev returns true if Exp is exactly zero - */ - function isZeroExp(Exp memory value) pure internal returns (bool) { - return value.mantissa == 0; - } - - function safe224(uint n, string memory errorMessage) pure internal returns (uint224) { - require(n < 2**224, errorMessage); - return uint224(n); - } - - function safe32(uint n, string memory errorMessage) pure internal returns (uint32) { - require(n < 2**32, errorMessage); - return uint32(n); - } - - function add_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { - return Exp({mantissa: add_(a.mantissa, b.mantissa)}); - } - - function add_(Double memory a, Double memory b) pure internal returns (Double memory) { - return Double({mantissa: add_(a.mantissa, b.mantissa)}); - } - - function add_(uint a, uint b) pure internal returns (uint) { - return add_(a, b, "addition overflow"); - } - - function add_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { - uint c = a + b; - require(c >= a, errorMessage); - return c; - } - - function sub_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { - return Exp({mantissa: sub_(a.mantissa, b.mantissa)}); - } - - function sub_(Double memory a, Double memory b) pure internal returns (Double memory) { - return Double({mantissa: sub_(a.mantissa, b.mantissa)}); - } - - function sub_(uint a, uint b) pure internal returns (uint) { - return sub_(a, b, "subtraction underflow"); - } - - function sub_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { - require(b <= a, errorMessage); - return a - b; - } - - function mul_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { - return Exp({mantissa: mul_(a.mantissa, b.mantissa) / expScale}); - } - - function mul_(Exp memory a, uint b) pure internal returns (Exp memory) { - return Exp({mantissa: mul_(a.mantissa, b)}); - } - - function mul_(uint a, Exp memory b) pure internal returns (uint) { - return mul_(a, b.mantissa) / expScale; - } - - function mul_(Double memory a, Double memory b) pure internal returns (Double memory) { - return Double({mantissa: mul_(a.mantissa, b.mantissa) / doubleScale}); - } - - function mul_(Double memory a, uint b) pure internal returns (Double memory) { - return Double({mantissa: mul_(a.mantissa, b)}); - } - - function mul_(uint a, Double memory b) pure internal returns (uint) { - return mul_(a, b.mantissa) / doubleScale; - } - - function mul_(uint a, uint b) pure internal returns (uint) { - return mul_(a, b, "multiplication overflow"); - } - - function mul_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { - if (a == 0 || b == 0) { - return 0; - } - uint c = a * b; - require(c / a == b, errorMessage); - return c; - } - - function div_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { - return Exp({mantissa: div_(mul_(a.mantissa, expScale), b.mantissa)}); - } - - function div_(Exp memory a, uint b) pure internal returns (Exp memory) { - return Exp({mantissa: div_(a.mantissa, b)}); - } - - function div_(uint a, Exp memory b) pure internal returns (uint) { - return div_(mul_(a, expScale), b.mantissa); - } - - function div_(Double memory a, Double memory b) pure internal returns (Double memory) { - return Double({mantissa: div_(mul_(a.mantissa, doubleScale), b.mantissa)}); - } - - function div_(Double memory a, uint b) pure internal returns (Double memory) { - return Double({mantissa: div_(a.mantissa, b)}); - } - - function div_(uint a, Double memory b) pure internal returns (uint) { - return div_(mul_(a, doubleScale), b.mantissa); - } - - function div_(uint a, uint b) pure internal returns (uint) { - return div_(a, b, "divide by zero"); - } - - function div_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { - require(b > 0, errorMessage); - return a / b; - } - - function fraction(uint a, uint b) pure internal returns (Double memory) { - return Double({mantissa: div_(mul_(a, doubleScale), b)}); - } -} - - -// Dependency file: contracts/Exponential.sol - -// pragma solidity 0.8.6; - -// import "contracts/CarefulMath.sol"; -// import "contracts/ExponentialNoError.sol"; - -/** - * @title Exponential module for storing fixed-precision decimals - * @author tropykus - * @dev Legacy contract for compatibility reasons with existing contracts that still use MathError - * @notice Exp is a struct which stores decimals with a fixed precision of 18 decimal places. - * Thus, if we wanted to store the 5.1, mantissa would store 5.1e18. That is: - * `Exp({mantissa: 5100000000000000000})`. - */ -contract Exponential is CarefulMath, ExponentialNoError { - /** - * @dev Creates an exponential from numerator and denominator values. - * Note: Returns an error if (`num` * 10e18) > MAX_INT, - * or if `denom` is zero. - */ - function getExp(uint num, uint denom) internal pure returns (MathError, Exp memory) { - (MathError err0, uint scaledNumerator) = mulUInt(num, expScale); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - - (MathError err1, uint rational) = divUInt(scaledNumerator, denom); - if (err1 != MathError.NO_ERROR) { - return (err1, Exp({mantissa: 0})); - } - - return (MathError.NO_ERROR, Exp({mantissa: rational})); - } - - /** - * @dev Adds two exponentials, returning a new exponential. - */ - function addExp(Exp memory a, Exp memory b) internal pure returns (MathError, Exp memory) { - (MathError error, uint result) = addUInt(a.mantissa, b.mantissa); - - return (error, Exp({mantissa: result})); - } - - /** - * @dev Subtracts two exponentials, returning a new exponential. - */ - function subExp(Exp memory a, Exp memory b) internal pure returns (MathError, Exp memory) { - (MathError error, uint result) = subUInt(a.mantissa, b.mantissa); - - return (error, Exp({mantissa: result})); - } - - /** - * @dev Multiply an Exp by a scalar, returning a new Exp. - */ - function mulScalar(Exp memory a, uint scalar) internal pure returns (MathError, Exp memory) { - (MathError err0, uint scaledMantissa) = mulUInt(a.mantissa, scalar); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - - return (MathError.NO_ERROR, Exp({mantissa: scaledMantissa})); - } - - /** - * @dev Multiply an Exp by a scalar, then truncate to return an unsigned integer. - */ - function mulScalarTruncate(Exp memory a, uint scalar) internal pure returns (MathError, uint) { - (MathError err, Exp memory product) = mulScalar(a, scalar); - if (err != MathError.NO_ERROR) { - return (err, 0); - } - - return (MathError.NO_ERROR, truncate(product)); - } - - /** - * @dev Multiply an Exp by a scalar, truncate, then add an to an unsigned integer, returning an unsigned integer. - */ - function mulScalarTruncateAddUInt(Exp memory a, uint scalar, uint addend) internal pure returns (MathError, uint) { - (MathError err, Exp memory product) = mulScalar(a, scalar); - if (err != MathError.NO_ERROR) { - return (err, 0); - } - - return addUInt(truncate(product), addend); - } - - /** - * @dev Divide an Exp by a scalar, returning a new Exp. - */ - function divScalar(Exp memory a, uint scalar) internal pure returns (MathError, Exp memory) { - (MathError err0, uint descaledMantissa) = divUInt(a.mantissa, scalar); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - - return (MathError.NO_ERROR, Exp({mantissa: descaledMantissa})); - } - - /** - * @dev Divide a scalar by an Exp, returning a new Exp. - */ - function divScalarByExp(uint scalar, Exp memory divisor) internal pure returns (MathError, Exp memory) { - /* - We are doing this as: - getExp(mulUInt(expScale, scalar), divisor.mantissa) - - How it works: - Exp = a / b; - Scalar = s; - `s / (a / b)` = `b * s / a` and since for an Exp `a = mantissa, b = expScale` - */ - (MathError err0, uint numerator) = mulUInt(expScale, scalar); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - return getExp(numerator, divisor.mantissa); - } - - /** - * @dev Divide a scalar by an Exp, then truncate to return an unsigned integer. - */ - function divScalarByExpTruncate(uint scalar, Exp memory divisor) internal pure returns (MathError, uint) { - (MathError err, Exp memory fraction) = divScalarByExp(scalar, divisor); - if (err != MathError.NO_ERROR) { - return (err, 0); - } - - return (MathError.NO_ERROR, truncate(fraction)); - } - - /** - * @dev Multiplies two exponentials, returning a new exponential. - */ - function mulExp(Exp memory a, Exp memory b) internal pure returns (MathError, Exp memory) { - - (MathError err0, uint doubleScaledProduct) = mulUInt(a.mantissa, b.mantissa); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - - // We add half the scale before dividing so that we get rounding instead of truncation. - // See "Listing 6" and text above it at https://accu.org/index.php/journals/1717 - // Without this change, a result like 6.6...e-19 will be truncated to 0 instead of being rounded to 1e-18. - (MathError err1, uint doubleScaledProductWithHalfScale) = addUInt(halfExpScale, doubleScaledProduct); - if (err1 != MathError.NO_ERROR) { - return (err1, Exp({mantissa: 0})); - } - - (MathError err2, uint product) = divUInt(doubleScaledProductWithHalfScale, expScale); - // The only error `div` can return is MathError.DIVISION_BY_ZERO but we control `expScale` and it is not zero. - assert(err2 == MathError.NO_ERROR); - - return (MathError.NO_ERROR, Exp({mantissa: product})); - } - - /** - * @dev Multiplies two exponentials given their mantissas, returning a new exponential. - */ - function mulExp(uint a, uint b) internal pure returns (MathError, Exp memory) { - return mulExp(Exp({mantissa: a}), Exp({mantissa: b})); - } - - /** - * @dev Multiplies three exponentials, returning a new exponential. - */ - function mulExp3(Exp memory a, Exp memory b, Exp memory c) internal pure returns (MathError, Exp memory) { - (MathError err, Exp memory ab) = mulExp(a, b); - if (err != MathError.NO_ERROR) { - return (err, ab); - } - return mulExp(ab, c); - } - - /** - * @dev Divides two exponentials, returning a new exponential. - * (a/scale) / (b/scale) = (a/scale) * (scale/b) = a/b, - * which we can scale as an Exp by calling getExp(a.mantissa, b.mantissa) - */ - function divExp(Exp memory a, Exp memory b) internal pure returns (MathError, Exp memory) { - return getExp(a.mantissa, b.mantissa); - } -} - - -// Dependency file: contracts/SafeMath.sol - -// pragma solidity 0.8.6; - -// From https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/math/Math.sol -// Subject to the MIT license. - -/** - * @dev Wrappers over Solidity's arithmetic operations with added overflow - * checks. - * - * Arithmetic operations in Solidity wrap on overflow. This can easily result - * in bugs, because programmers usually assume that an overflow raises an - * error, which is the standard behavior in high level programming languages. - * `SafeMath` restores this intuition by reverting the transaction when an - * operation overflows. - * - * Using this library instead of the unchecked operations eliminates an entire - * class of bugs, so it's recommended to use it always. - */ -library SafeMath { - /** - * @dev Returns the addition of two unsigned integers, reverting on overflow. - * - * Counterpart to Solidity's `+` operator. - * - * Requirements: - * - Addition cannot overflow. - */ - function add(uint256 a, uint256 b) internal pure returns (uint256) { - uint256 c = a + b; - require(c >= a, "SafeMath: addition overflow"); - - return c; - } - - /** - * @dev Returns the addition of two unsigned integers, reverting with custom message on overflow. - * - * Counterpart to Solidity's `+` operator. - * - * Requirements: - * - Addition cannot overflow. - */ - function add(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - uint256 c = a + b; - require(c >= a, errorMessage); - - return c; - } - - /** - * @dev Returns the subtraction of two unsigned integers, reverting on underflow (when the result is negative). - * - * Counterpart to Solidity's `-` operator. - * - * Requirements: - * - Subtraction cannot underflow. - */ - function sub(uint256 a, uint256 b) internal pure returns (uint256) { - return sub(a, b, "SafeMath: subtraction underflow"); - } - - /** - * @dev Returns the subtraction of two unsigned integers, reverting with custom message on underflow (when the result is negative). - * - * Counterpart to Solidity's `-` operator. - * - * Requirements: - * - Subtraction cannot underflow. - */ - function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - require(b <= a, errorMessage); - uint256 c = a - b; - - return c; - } - - /** - * @dev Returns the multiplication of two unsigned integers, reverting on overflow. - * - * Counterpart to Solidity's `*` operator. - * - * Requirements: - * - Multiplication cannot overflow. - */ - function mul(uint256 a, uint256 b) internal pure returns (uint256) { - // Gas optimization: this is cheaper than requiring 'a' not being zero, but the - // benefit is lost if 'b' is also tested. - // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 - if (a == 0) { - return 0; - } - - uint256 c = a * b; - require(c / a == b, "SafeMath: multiplication overflow"); - - return c; - } - - /** - * @dev Returns the multiplication of two unsigned integers, reverting on overflow. - * - * Counterpart to Solidity's `*` operator. - * - * Requirements: - * - Multiplication cannot overflow. - */ - function mul(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - // Gas optimization: this is cheaper than requiring 'a' not being zero, but the - // benefit is lost if 'b' is also tested. - // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 - if (a == 0) { - return 0; - } - - uint256 c = a * b; - require(c / a == b, errorMessage); - - return c; - } - - /** - * @dev Returns the integer division of two unsigned integers. - * Reverts on division by zero. The result is rounded towards zero. - * - * Counterpart to Solidity's `/` operator. Note: this function uses a - * `revert` opcode (which leaves remaining gas untouched) while Solidity - * uses an invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function div(uint256 a, uint256 b) internal pure returns (uint256) { - return div(a, b, "SafeMath: division by zero"); - } - - /** - * @dev Returns the integer division of two unsigned integers. - * Reverts with custom message on division by zero. The result is rounded towards zero. - * - * Counterpart to Solidity's `/` operator. Note: this function uses a - * `revert` opcode (which leaves remaining gas untouched) while Solidity - * uses an invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - // Solidity only automatically asserts when dividing by 0 - require(b > 0, errorMessage); - uint256 c = a / b; - // assert(a == b * c + a % b); // There is no case in which this doesn't hold - - return c; - } - - /** - * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), - * Reverts when dividing by zero. - * - * Counterpart to Solidity's `%` operator. This function uses a `revert` - * opcode (which leaves remaining gas untouched) while Solidity uses an - * invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function mod(uint256 a, uint256 b) internal pure returns (uint256) { - return mod(a, b, "SafeMath: modulo by zero"); - } - - /** - * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), - * Reverts with custom message when dividing by zero. - * - * Counterpart to Solidity's `%` operator. This function uses a `revert` - * opcode (which leaves remaining gas untouched) while Solidity uses an - * invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - require(b != 0, errorMessage); - return a % b; - } -} - - -// Dependency file: contracts/InterestRateModel.sol - -// pragma solidity 0.8.6; - -// import "contracts/Exponential.sol"; -// import "contracts/SafeMath.sol"; - -/** - * @title tropykus InterestRateModel Interface - * @author tropykus - */ -abstract contract InterestRateModel is Exponential { - using SafeMath for uint256; - - /// @notice Indicator that this is an InterestRateModel contract (for inspection) - bool public constant isInterestRateModel = true; - bool public isTropykusInterestRateModel; - - /** - * @notice The approximate number of blocks per year that is assumed by the interest rate model - */ - uint256 public constant blocksPerYear = 1051200; - - /** - * @notice Calculates the utilization rate of the market: `borrows / (cash + borrows - reserves)` - * @param cash The amount of cash in the market - * @param borrows The amount of borrows in the market - * @param reserves The amount of reserves in the market (currently unused) - * @return The utilization rate as a mantissa between [0, 1e18] - */ - function utilizationRate( - uint256 cash, - uint256 borrows, - uint256 reserves - ) public pure virtual returns (uint256) { - // Utilization rate is 0 when there are no borrows - if (borrows == 0) { - return 0; - } - - return borrows.mul(1e18).div(cash.add(borrows).sub(reserves)); - } - - /** - * @notice Calculates the current borrow interest rate per block - * @param cash The total amount of cash the market has - * @param borrows The total amount of borrows the market has outstanding - * @param reserves The total amnount of reserves the market has - * @return The borrow rate per block (as a percentage, and scaled by 1e18) - */ - function getBorrowRate( - uint256 cash, - uint256 borrows, - uint256 reserves - ) external view virtual returns (uint256); - - /** - * @notice Calculates the current supply interest rate per block - * @param cash The total amount of cash the market has - * @param borrows The total amount of borrows the market has outstanding - * @param reserves The total amnount of reserves the market has - * @param reserveFactorMantissa The current reserve factor the market has - * @return The supply rate per block (as a percentage, and scaled by 1e18) - */ - function getSupplyRate( - uint256 cash, - uint256 borrows, - uint256 reserves, - uint256 reserveFactorMantissa - ) external view virtual returns (uint256); - - function getExchangeRate( - uint256 _totalCash, - uint256 _totalBorrows, - uint256 _totalReserves, - uint256 _totalSupply - ) public pure returns (MathError, uint256) { - /* - * exchangeRate = (totalCash + totalBorrows - totalReserves) / totalSupply - */ - Exp memory exchangeRate; - MathError mathErr; - uint256 cashPlusBorrowsMinusReserves; - (mathErr, cashPlusBorrowsMinusReserves) = addThenSubUInt( - _totalCash, - _totalBorrows, - _totalReserves - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - (mathErr, exchangeRate) = getExp( - cashPlusBorrowsMinusReserves, - _totalSupply - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - - return (MathError.NO_ERROR, exchangeRate.mantissa); - } - - function isAboveOptimal( - uint256 cash, - uint256 borrows, - uint256 reserves - ) public view virtual returns (bool) { - cash; - borrows; - reserves; - return false; - } -} - - -// Dependency file: contracts/EIP20NonStandardInterface.sol - -// pragma solidity 0.8.6; - -/** - * @title EIP20NonStandardInterface - * @dev Version of ERC20 with no return values for `transfer` and `transferFrom` - * See https://medium.com/coinmonks/missing-return-value-bug-at-least-130-tokens-affected-d67bf08521ca - */ -interface EIP20NonStandardInterface { - /** - * @notice Get the total number of tokens in circulation - * @return The supply of tokens - */ - function totalSupply() external view returns (uint256); - - /** - * @notice Gets the balance of the specified address - * @param owner The address from which the balance will be retrieved - * @return balance The balance - */ - function balanceOf(address owner) external view returns (uint256 balance); - - /// - /// !!!!!!!!!!!!!! - /// !!! NOTICE !!! `transfer` does not return a value, in violation of the ERC-20 specification - /// !!!!!!!!!!!!!! - /// - - /** - * @notice Transfer `amount` tokens from `msg.sender` to `dst` - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - */ - function transfer(address dst, uint256 amount) external; - - /// - /// !!!!!!!!!!!!!! - /// !!! NOTICE !!! `transferFrom` does not return a value, in violation of the ERC-20 specification - /// !!!!!!!!!!!!!! - /// - - /** - * @notice Transfer `amount` tokens from `src` to `dst` - * @param src The address of the source account - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - */ - function transferFrom( - address src, - address dst, - uint256 amount - ) external; - - /** - * @notice Approve `spender` to transfer up to `amount` from `src` - * @dev This will overwrite the approval amount for `spender` - * and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve) - * @param spender The address of the account which may transfer tokens - * @param amount The number of tokens that are approved - * @return success Whether or not the approval succeeded - */ - function approve(address spender, uint256 amount) - external - returns (bool success); - - /** - * @notice Get the current allowance from `owner` for `spender` - * @param owner The address of the account which owns the tokens to be spent - * @param spender The address of the account which may transfer tokens - * @return remaining The number of tokens allowed to be spent - */ - function allowance(address owner, address spender) - external - view - returns (uint256 remaining); - - event Transfer(address indexed from, address indexed to, uint256 amount); - event Approval( - address indexed owner, - address indexed spender, - uint256 amount - ); -} - - -// Dependency file: contracts/CTokenInterfaces.sol - -// pragma solidity 0.8.6; - -// import "contracts/ComptrollerInterface.sol"; -// import "contracts/InterestRateModel.sol"; -// import "contracts/EIP20NonStandardInterface.sol"; - -contract CTokenStorage { - /** - * @dev Guard variable for re-entrancy checks - */ - bool internal _notEntered; - - /** - * @notice EIP-20 token name for this token - */ - string public name; - - /** - * @notice EIP-20 token symbol for this token - */ - string public symbol; - - /** - * @notice EIP-20 token decimals for this token - */ - uint8 public decimals; - - /** - * @notice Maximum borrow rate that can ever be applied (.0005% / block) - */ - - uint256 internal constant borrowRateMaxMantissa = 0.0005e16; - - /** - * @notice Maximum fraction of interest that can be set aside for reserves - */ - uint256 internal constant reserveFactorMaxMantissa = 1e18; - - /** - * @notice Administrator for this contract - */ - address payable public admin; - - /** - * @notice Pending administrator for this contract - */ - address payable public pendingAdmin; - - /** - * @notice Contract which oversees inter-cToken operations - */ - ComptrollerInterface public comptroller; - - /** - * @notice Model which tells what the current interest rate should be - */ - InterestRateModel public interestRateModel; - - /** - * @notice Initial exchange rate used when minting the first CTokens (used when totalSupply = 0) - */ - uint256 public initialExchangeRateMantissa; - - /** - * @notice Fraction of interest currently set aside for reserves - */ - uint256 public reserveFactorMantissa; - - /** - * @notice Block number that interest was last accrued at - */ - uint256 public accrualBlockNumber; - - /** - * @notice Accumulator of the total earned interest rate since the opening of the market - */ - uint256 public borrowIndex; - - /** - * @notice Total amount of outstanding borrows of the underlying in this market - */ - uint256 public totalBorrows; - - /** - * @notice Total amount of reserves of the underlying held in this market - */ - uint256 public totalReserves; - - /** - * @notice Total number of tokens in circulation - */ - uint256 public totalSupply; - - uint256 public subsidyFund; - - struct SupplySnapshot { - uint256 tokens; - uint256 underlyingAmount; - uint256 suppliedAt; - uint256 promisedSupplyRate; - } - - /** - * @notice Official record of token balances for each account - */ - mapping(address => SupplySnapshot) internal accountTokens; - - /** - * @notice Approved token transfer amounts on behalf of others - */ - mapping(address => mapping(address => uint256)) internal transferAllowances; - - /** - * @notice Container for borrow balance information - * @member principal Total balance (with accrued interest), after applying the most recent balance-changing action - * @member interestIndex Global borrowIndex as of the most recent balance-changing action - */ - struct BorrowSnapshot { - uint256 principal; - uint256 interestIndex; - } - - /** - * @notice Mapping of account addresses to outstanding borrow balances - */ - mapping(address => BorrowSnapshot) internal accountBorrows; -} - -abstract contract CTokenInterface is CTokenStorage { - /** - * @notice Indicator that this is a CToken contract (for inspection) - */ - bool public constant isCToken = true; - - /*** Market Events ***/ - - /** - * @notice Event emitted when interest is accrued - */ - event AccrueInterest( - uint256 cashPrior, - uint256 interestAccumulated, - uint256 borrowIndex, - uint256 totalBorrows - ); - - /** - * @notice Event emitted when tokens are minted - */ - event Mint(address indexed minter, uint256 mintAmount, uint256 mintTokens); - - /** - * @notice Event emitted when tokens are redeemed - */ - event Redeem( - address indexed redeemer, - uint256 redeemAmount, - uint256 redeemTokens - ); - - /** - * @notice Event emitted when underlying is borrowed - */ - event Borrow( - address indexed borrower, - uint256 borrowAmount, - uint256 accountBorrows, - uint256 totalBorrows - ); - - /** - * @notice Event emitted when a borrow is repaid - */ - event RepayBorrow( - address indexed payer, - address indexed borrower, - uint256 repayAmount, - uint256 accountBorrows, - uint256 totalBorrows - ); - - /** - * @notice Event emitted when a borrow is liquidated - */ - event LiquidateBorrow( - address indexed liquidator, - address indexed borrower, - uint256 repayAmount, - address indexed cTokenCollateral, - uint256 seizeTokens - ); - - /*** Admin Events ***/ - - /** - * @notice Event emitted when pendingAdmin is changed - */ - event NewPendingAdmin(address oldPendingAdmin, address newPendingAdmin); - - /** - * @notice Event emitted when pendingAdmin is accepted, which means admin is updated - */ - event NewAdmin(address oldAdmin, address newAdmin); - - /** - * @notice Event emitted when comptroller is changed - */ - event NewComptroller( - ComptrollerInterface oldComptroller, - ComptrollerInterface newComptroller - ); - - /** - * @notice Event emitted when interestRateModel is changed - */ - event NewMarketInterestRateModel( - InterestRateModel oldInterestRateModel, - InterestRateModel newInterestRateModel - ); - - /** - * @notice Event emitted when the reserve factor is changed - */ - event NewReserveFactor( - uint256 oldReserveFactorMantissa, - uint256 newReserveFactorMantissa - ); - - /** - * @notice Event emitted when the reserves are added - */ - event ReservesAdded( - address benefactor, - uint256 addAmount, - uint256 newTotalReserves - ); - - event SubsidyAdded( - address benefactor, - uint256 addAmount, - uint256 newSubsidyFund - ); - - /** - * @notice Event emitted when the reserves are reduced - */ - event ReservesReduced( - address admin, - uint256 reduceAmount, - uint256 newTotalReserves - ); - - /** - * @notice EIP20 Transfer event - */ - event Transfer(address indexed from, address indexed to, uint256 amount); - - /** - * @notice EIP20 Approval event - */ - event Approval( - address indexed owner, - address indexed spender, - uint256 amount - ); - - /** - * @notice Failure event - */ - event CTokenStorageFailure(uint256 error, uint256 info, uint256 detail); - - /*** User Interface ***/ - - function transfer(address dst, uint256 amount) - external - virtual - returns (bool); - - function transferFrom( - address src, - address dst, - uint256 amount - ) external virtual returns (bool); - - function approve(address spender, uint256 amount) - external - virtual - returns (bool); - - function allowance(address owner, address spender) - external - view - virtual - returns (uint256); - - function balanceOf(address owner) external view virtual returns (uint256); - - function balanceOfUnderlying(address owner) - external - virtual - returns (uint256); - - function getAccountSnapshot(address account) - external - view - virtual - returns ( - uint256, - uint256, - uint256, - uint256 - ); - - function borrowRatePerBlock() external view virtual returns (uint256); - - function supplyRatePerBlock() external view virtual returns (uint256); - - function totalBorrowsCurrent() external virtual returns (uint256); - - function borrowBalanceCurrent(address account) - external - virtual - returns (uint256); - - function borrowBalanceStored(address account) - public - view - virtual - returns (uint256); - - function exchangeRateCurrent() public virtual returns (uint256); - - function exchangeRateStored() public view virtual returns (uint256); - - function getCash() external view virtual returns (uint256); - - function accrueInterest() public virtual returns (uint256); - - function seize( - address liquidator, - address borrower, - uint256 seizeTokens - ) external virtual returns (uint256); - - /*** Admin Functions ***/ - - function _setPendingAdmin(address payable newPendingAdmin) - external - virtual - returns (uint256); - - function _acceptAdmin() external virtual returns (uint256); - - function _setComptroller(ComptrollerInterface newComptroller) - public - virtual - returns (uint256); - - function _setReserveFactor(uint256 newReserveFactorMantissa) - external - virtual - returns (uint256); - - function _reduceReserves(uint256 reduceAmount) - external - virtual - returns (uint256); - - function _setInterestRateModel(InterestRateModel newInterestRateModel) - public - virtual - returns (uint256); -} - -contract CErc20Storage { - /** - * @notice Underlying asset for this CToken - */ - address public underlying; -} - -abstract contract CErc20Interface is CErc20Storage { - /*** User Interface ***/ - - function mint(uint256 mintAmount) external virtual returns (uint256); - - function redeem(uint256 redeemAmount) - external - virtual - returns (uint256); - - function borrow(uint256 borrowAmount) external virtual returns (uint256); - - function repayBorrow(uint256 repayAmount) - external - virtual - returns (uint256); - - function liquidateBorrow( - address borrower, - uint256 repayAmount, - CTokenInterface cTokenCollateral - ) external virtual returns (uint256); - - function sweepToken(EIP20NonStandardInterface token) external virtual; - - /*** Admin Functions ***/ - - function _addReserves(uint256 addAmount) external virtual returns (uint256); -} - -contract CDelegationStorage { - /** - * @notice Implementation address for this contract - */ - address public implementation; -} - -abstract contract CDelegatorInterface is CDelegationStorage { - /** - * @notice Emitted when implementation is changed - */ - event NewImplementation( - address oldImplementation, - address newImplementation - ); - - /** - * @notice Called by the admin to update the implementation of the delegator - * @param implementation_ The address of the new implementation for delegation - * @param allowResign Flag to indicate whether to call _resignImplementation on the old implementation - * @param becomeImplementationData The encoded bytes data to be passed to _becomeImplementation - */ - function _setImplementation( - address implementation_, - bool allowResign, - bytes memory becomeImplementationData - ) public virtual; -} - -abstract contract CDelegateInterface is CDelegationStorage { - /** - * @notice Called by the delegator on a delegate to initialize it for duty - * @dev Should revert if any issues arise which make it unfit for delegation - * @param data The encoded bytes data for any initialization - */ - function _becomeImplementation(bytes memory data) public virtual; - - /** - * @notice Called by the delegator on a delegate to forfeit its responsibility - */ - function _resignImplementation() public virtual; -} - - -// Dependency file: contracts/ErrorReporter.sol - -// pragma solidity 0.8.6; - -contract ComptrollerErrorReporter { - enum Error { - NO_ERROR, - UNAUTHORIZED, - COMPTROLLER_MISMATCH, - INSUFFICIENT_SHORTFALL, - INSUFFICIENT_LIQUIDITY, - INVALID_CLOSE_FACTOR, - INVALID_COLLATERAL_FACTOR, - INVALID_LIQUIDATION_INCENTIVE, - MARKET_NOT_ENTERED, // no longer possible - MARKET_NOT_LISTED, - MARKET_ALREADY_LISTED, - MATH_ERROR, - NONZERO_BORROW_BALANCE, - PRICE_ERROR, - REJECTION, - SNAPSHOT_ERROR, - TOO_MANY_ASSETS, - TOO_MUCH_REPAY - } - - enum FailureInfo { - ACCEPT_ADMIN_PENDING_ADMIN_CHECK, - ACCEPT_PENDING_IMPLEMENTATION_ADDRESS_CHECK, - EXIT_MARKET_BALANCE_OWED, - EXIT_MARKET_REJECTION, - SET_CLOSE_FACTOR_OWNER_CHECK, - SET_CLOSE_FACTOR_VALIDATION, - SET_COLLATERAL_FACTOR_OWNER_CHECK, - SET_COLLATERAL_FACTOR_NO_EXISTS, - SET_COLLATERAL_FACTOR_VALIDATION, - SET_COLLATERAL_FACTOR_WITHOUT_PRICE, - SET_IMPLEMENTATION_OWNER_CHECK, - SET_LIQUIDATION_INCENTIVE_OWNER_CHECK, - SET_LIQUIDATION_INCENTIVE_VALIDATION, - SET_MAX_ASSETS_OWNER_CHECK, - SET_PENDING_ADMIN_OWNER_CHECK, - SET_PENDING_IMPLEMENTATION_OWNER_CHECK, - SET_PRICE_ORACLE_OWNER_CHECK, - SUPPORT_MARKET_EXISTS, - SUPPORT_MARKET_OWNER_CHECK, - SET_PAUSE_GUARDIAN_OWNER_CHECK - } - - /** - * @dev `error` corresponds to enum Error; `info` corresponds to enum FailureInfo, and `detail` is an arbitrary - * contract-specific code that enables us to report opaque error codes from upgradeable contracts. - **/ - event Failure(uint256 error, uint256 info, uint256 detail); - - /** - * @dev use this when reporting a known error from the money market or a non-upgradeable collaborator - */ - function fail(Error err, FailureInfo info) internal returns (uint256) { - emit Failure(uint256(err), uint256(info), 0); - - return uint256(err); - } - - /** - * @dev use this when reporting an opaque error from an upgradeable collaborator contract - */ - function failOpaque( - Error err, - FailureInfo info, - uint256 opaqueError - ) internal returns (uint256) { - emit Failure(uint256(err), uint256(info), opaqueError); - - return uint256(err); - } -} - -contract TokenErrorReporter { - enum Error { - NO_ERROR, - UNAUTHORIZED, - BAD_INPUT, - COMPTROLLER_REJECTION, - COMPTROLLER_CALCULATION_ERROR, - INTEREST_RATE_MODEL_ERROR, - INVALID_ACCOUNT_PAIR, - INVALID_CLOSE_AMOUNT_REQUESTED, - INVALID_COLLATERAL_FACTOR, - MATH_ERROR, - MARKET_NOT_FRESH, - MARKET_NOT_LISTED, - TOKEN_INSUFFICIENT_ALLOWANCE, - TOKEN_INSUFFICIENT_BALANCE, - TOKEN_INSUFFICIENT_CASH, - TOKEN_TRANSFER_IN_FAILED, - TOKEN_TRANSFER_OUT_FAILED - } - - /* - * Note: FailureInfo (but not Error) is kept in alphabetical order - * This is because FailureInfo grows significantly faster, and - * the order of Error has some meaning, while the order of FailureInfo - * is entirely arbitrary. - */ - enum FailureInfo { - ACCEPT_ADMIN_PENDING_ADMIN_CHECK, - ACCRUE_INTEREST_ACCUMULATED_INTEREST_CALCULATION_FAILED, - ACCRUE_INTEREST_BORROW_RATE_CALCULATION_FAILED, - ACCRUE_INTEREST_NEW_BORROW_INDEX_CALCULATION_FAILED, - ACCRUE_INTEREST_NEW_TOTAL_BORROWS_CALCULATION_FAILED, - ACCRUE_INTEREST_NEW_TOTAL_RESERVES_CALCULATION_FAILED, - ACCRUE_INTEREST_SIMPLE_INTEREST_FACTOR_CALCULATION_FAILED, - BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED, - BORROW_ACCRUE_INTEREST_FAILED, - BORROW_CASH_NOT_AVAILABLE, - BORROW_FRESHNESS_CHECK, - BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED, - BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED, - BORROW_MARKET_NOT_LISTED, - BORROW_COMPTROLLER_REJECTION, - LIQUIDATE_ACCRUE_BORROW_INTEREST_FAILED, - LIQUIDATE_ACCRUE_COLLATERAL_INTEREST_FAILED, - LIQUIDATE_COLLATERAL_FRESHNESS_CHECK, - LIQUIDATE_COMPTROLLER_REJECTION, - LIQUIDATE_COMPTROLLER_CALCULATE_AMOUNT_SEIZE_FAILED, - LIQUIDATE_CLOSE_AMOUNT_IS_UINT_MAX, - LIQUIDATE_CLOSE_AMOUNT_IS_ZERO, - LIQUIDATE_FRESHNESS_CHECK, - LIQUIDATE_LIQUIDATOR_IS_BORROWER, - LIQUIDATE_REPAY_BORROW_FRESH_FAILED, - LIQUIDATE_SEIZE_BALANCE_INCREMENT_FAILED, - LIQUIDATE_SEIZE_BALANCE_DECREMENT_FAILED, - LIQUIDATE_SEIZE_COMPTROLLER_REJECTION, - LIQUIDATE_SEIZE_LIQUIDATOR_IS_BORROWER, - LIQUIDATE_SEIZE_TOO_MUCH, - MINT_ACCRUE_INTEREST_FAILED, - MINT_COMPTROLLER_REJECTION, - MINT_EXCHANGE_CALCULATION_FAILED, - MINT_EXCHANGE_RATE_READ_FAILED, - MINT_FRESHNESS_CHECK, - MINT_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED, - MINT_NEW_TOTAL_SUPPLY_CALCULATION_FAILED, - MINT_TRANSFER_IN_FAILED, - MINT_TRANSFER_IN_NOT_POSSIBLE, - REDEEM_ACCRUE_INTEREST_FAILED, - REDEEM_COMPTROLLER_REJECTION, - REDEEM_EXCHANGE_TOKENS_CALCULATION_FAILED, - REDEEM_EXCHANGE_AMOUNT_CALCULATION_FAILED, - REDEEM_EXCHANGE_RATE_READ_FAILED, - REDEEM_FRESHNESS_CHECK, - REDEEM_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED, - REDEEM_NEW_TOTAL_SUPPLY_CALCULATION_FAILED, - REDEEM_TRANSFER_OUT_NOT_POSSIBLE, - REDUCE_RESERVES_ACCRUE_INTEREST_FAILED, - REDUCE_RESERVES_ADMIN_CHECK, - REDUCE_RESERVES_CASH_NOT_AVAILABLE, - REDUCE_RESERVES_FRESH_CHECK, - REDUCE_RESERVES_VALIDATION, - REPAY_BEHALF_ACCRUE_INTEREST_FAILED, - REPAY_BORROW_ACCRUE_INTEREST_FAILED, - REPAY_BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED, - REPAY_BORROW_COMPTROLLER_REJECTION, - REPAY_BORROW_FRESHNESS_CHECK, - REPAY_BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED, - REPAY_BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED, - REPAY_BORROW_TRANSFER_IN_NOT_POSSIBLE, - SET_COLLATERAL_FACTOR_OWNER_CHECK, - SET_COLLATERAL_FACTOR_VALIDATION, - SET_COMPTROLLER_OWNER_CHECK, - SET_INTEREST_RATE_MODEL_ACCRUE_INTEREST_FAILED, - SET_INTEREST_RATE_MODEL_FRESH_CHECK, - SET_INTEREST_RATE_MODEL_OWNER_CHECK, - SET_MAX_ASSETS_OWNER_CHECK, - SET_ORACLE_MARKET_NOT_LISTED, - SET_PENDING_ADMIN_OWNER_CHECK, - SET_RESERVE_FACTOR_ACCRUE_INTEREST_FAILED, - SET_RESERVE_FACTOR_ADMIN_CHECK, - SET_RESERVE_FACTOR_FRESH_CHECK, - SET_RESERVE_FACTOR_BOUNDS_CHECK, - TRANSFER_COMPTROLLER_REJECTION, - TRANSFER_NOT_ALLOWED, - TRANSFER_NOT_ENOUGH, - TRANSFER_TOO_MUCH, - ADD_RESERVES_ACCRUE_INTEREST_FAILED, - ADD_RESERVES_FRESH_CHECK, - ADD_RESERVES_TRANSFER_IN_NOT_POSSIBLE, - ADD_SUBSIDY_FUND_FAILED, - ADD_SUBSIDY_FUND_FRESH_CHECK - } - - /** - * @dev `error` corresponds to enum Error; `info` corresponds to enum FailureInfo, and `detail` is an arbitrary - * contract-specific code that enables us to report opaque error codes from upgradeable contracts. - **/ - event TokenFailure(uint256 error, uint256 info, uint256 detail); - - /** - * @dev use this when reporting a known error from the money market or a non-upgradeable collaborator - */ - function fail(Error err, FailureInfo info) internal returns (uint256) { - emit TokenFailure(uint256(err), uint256(info), 0); - - return uint256(err); - } - - /** - * @dev use this when reporting an opaque error from an upgradeable collaborator contract - */ - function failOpaque( - Error err, - FailureInfo info, - uint256 opaqueError - ) internal returns (uint256) { - emit TokenFailure(uint256(err), uint256(info), opaqueError); - - return uint256(err); - } -} - - -// Dependency file: contracts/EIP20Interface.sol - -// pragma solidity 0.8.6; - -/** - * @title ERC 20 Token Standard Interface - * https://eips.ethereum.org/EIPS/eip-20 - */ -interface EIP20Interface { - function name() external view returns (string memory); - - function symbol() external view returns (string memory); - - function decimals() external view returns (uint8); - - /** - * @notice Get the total number of tokens in circulation - * @return The supply of tokens - */ - function totalSupply() external view returns (uint256); - - /** - * @notice Gets the balance of the specified address - * @param owner The address from which the balance will be retrieved - * @return balance The balance - */ - function balanceOf(address owner) external view returns (uint256 balance); - - /** - * @notice Transfer `amount` tokens from `msg.sender` to `dst` - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - * @return success Whether or not the transfer succeeded - */ - function transfer(address dst, uint256 amount) - external - returns (bool success); - - /** - * @notice Transfer `amount` tokens from `src` to `dst` - * @param src The address of the source account - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - * @return success Whether or not the transfer succeeded - */ - function transferFrom( - address src, - address dst, - uint256 amount - ) external returns (bool success); - - /** - * @notice Approve `spender` to transfer up to `amount` from `src` - * @dev This will overwrite the approval amount for `spender` - * and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve) - * @param spender The address of the account which may transfer tokens - * @param amount The number of tokens that are approved (-1 means infinite) - * @return success Whether or not the approval succeeded - */ - function approve(address spender, uint256 amount) - external - returns (bool success); - - /** - * @notice Get the current allowance from `owner` for `spender` - * @param owner The address of the account which owns the tokens to be spent - * @param spender The address of the account which may transfer tokens - * @return remaining The number of tokens allowed to be spent (-1 means infinite) - */ - function allowance(address owner, address spender) - external - view - returns (uint256 remaining); - - event Transfer(address indexed from, address indexed to, uint256 amount); - event Approval( - address indexed owner, - address indexed spender, - uint256 amount - ); -} - - -// Dependency file: contracts/WhitelistInterface.sol - -// pragma solidity 0.8.6; - -interface WhitelistInterface { - function setStatus(bool _newStatus) external; - function enabled() external view returns(bool); - - function addUsers(address[] memory _users) external; - function exist(address _user) external view returns(bool); - function getUsers() external view returns(address[] memory currentUsers); - function removeUser(address _user) external; -} - -// Dependency file: contracts/CToken.sol - -// pragma solidity 0.8.6; - -// import "contracts/ComptrollerInterface.sol"; -// import "contracts/CTokenInterfaces.sol"; -// import "contracts/ErrorReporter.sol"; -// import "contracts/Exponential.sol"; -// import "contracts/EIP20Interface.sol"; -// import "contracts/InterestRateModel.sol"; -// import "contracts/WhitelistInterface.sol"; - -/** - * @title tropykus CToken Contract - * @notice Abstract base for CTokens - * @author tropykus - */ -abstract contract CToken is CTokenInterface, Exponential, TokenErrorReporter { - address whitelist; - - /** - * @notice Initialize the money market - * @param comptroller_ The address of the Comptroller - * @param interestRateModel_ The address of the interest rate model - * @param initialExchangeRateMantissa_ The initial exchange rate, scaled by 1e18 - * @param name_ EIP-20 name of this token - * @param symbol_ EIP-20 symbol of this token - * @param decimals_ EIP-20 decimal precision of this token - */ - function initialize( - ComptrollerInterface comptroller_, - InterestRateModel interestRateModel_, - uint256 initialExchangeRateMantissa_, - string memory name_, - string memory symbol_, - uint8 decimals_ - ) public { - require(msg.sender == admin, "CT01"); - require(accrualBlockNumber == 0 && borrowIndex == 0, "CT02"); - - initialExchangeRateMantissa = initialExchangeRateMantissa_; - require(initialExchangeRateMantissa > 0, "CT03"); - - uint256 err = _setComptroller(comptroller_); - require(err == uint256(Error.NO_ERROR), "CT04"); - - accrualBlockNumber = getBlockNumber(); - borrowIndex = mantissaOne; - - err = _setInterestRateModelFresh(interestRateModel_); - require(err == uint256(Error.NO_ERROR), "CT05"); - - name = name_; - symbol = symbol_; - decimals = decimals_; - - _notEntered = true; - } - - function addWhitelist(address _whitelist) external returns (uint256) { - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_INTEREST_RATE_MODEL_OWNER_CHECK - ); - } - whitelist = _whitelist; - } - - /** - * @notice Transfer `tokens` tokens from `src` to `dst` by `spender` - * @dev Called by both `transfer` and `transferFrom` internally - * @param spender The address of the account performing the transfer - * @param src The address of the source account - * @param dst The address of the destination account - * @param tokens The number of tokens to transfer - * @return Whether or not the transfer succeeded - */ - function transferTokens( - address spender, - address src, - address dst, - uint256 tokens - ) internal returns (uint256) { - uint256 allowed = comptroller.transferAllowed( - address(this), - src, - dst, - tokens - ); - if (allowed != 0) { - return - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.TRANSFER_COMPTROLLER_REJECTION, - allowed - ); - } - - if (src == dst) { - return fail(Error.BAD_INPUT, FailureInfo.TRANSFER_NOT_ALLOWED); - } - - uint256 startingAllowance = 0; - if (spender == src) { - startingAllowance = type(uint256).max; - } else { - startingAllowance = transferAllowances[src][spender]; - } - - MathError mathErr; - uint256 allowanceNew; - uint256 srcTokensNew; - uint256 dstTokensNew; - - (mathErr, allowanceNew) = subUInt(startingAllowance, tokens); - if (mathErr != MathError.NO_ERROR) { - return fail(Error.MATH_ERROR, FailureInfo.TRANSFER_NOT_ALLOWED); - } - - (mathErr, srcTokensNew) = subUInt(accountTokens[src].tokens, tokens); - if (mathErr != MathError.NO_ERROR) { - return fail(Error.MATH_ERROR, FailureInfo.TRANSFER_NOT_ENOUGH); - } - - (mathErr, dstTokensNew) = addUInt(accountTokens[dst].tokens, tokens); - if (mathErr != MathError.NO_ERROR) { - return fail(Error.MATH_ERROR, FailureInfo.TRANSFER_TOO_MUCH); - } - - accountTokens[src].tokens = srcTokensNew; - accountTokens[dst].tokens = dstTokensNew; - - if (startingAllowance != type(uint256).max) { - transferAllowances[src][spender] = allowanceNew; - } - - emit Transfer(src, dst, tokens); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Transfer `amount` tokens from `msg.sender` to `dst` - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - * @return Whether or not the transfer succeeded - */ - function transfer(address dst, uint256 amount) - external - override - nonReentrant - returns (bool) - { - return - transferTokens(msg.sender, msg.sender, dst, amount) == - uint256(Error.NO_ERROR); - } - - /** - * @notice Transfer `amount` tokens from `src` to `dst` - * @param src The address of the source account - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - * @return Whether or not the transfer succeeded - */ - function transferFrom( - address src, - address dst, - uint256 amount - ) external override nonReentrant returns (bool) { - return - transferTokens(msg.sender, src, dst, amount) == - uint256(Error.NO_ERROR); - } - - /** - * @notice Approve `spender` to transfer up to `amount` from `src` - * @dev This will overwrite the approval amount for `spender` - * and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve) - * @param spender The address of the account which may transfer tokens - * @param amount The number of tokens that are approved (-1 means infinite) - * @return Whether or not the approval succeeded - */ - function approve(address spender, uint256 amount) - external - override - returns (bool) - { - transferAllowances[msg.sender][spender] = amount; - emit Approval(msg.sender, spender, amount); - return true; - } - - /** - * @notice Get the current allowance from `owner` for `spender` - * @param owner The address of the account which owns the tokens to be spent - * @param spender The address of the account which may transfer tokens - * @return The number of tokens allowed to be spent (-1 means infinite) - */ - function allowance(address owner, address spender) - external - view - override - returns (uint256) - { - return transferAllowances[owner][spender]; - } - - /** - * @notice Get the token balance of the `owner` - * @param owner The address of the account to query - * @return The number of tokens owned by `owner` - */ - function balanceOf(address owner) external view override returns (uint256) { - return accountTokens[owner].tokens; - } - - /** - * @notice Get the underlying balance of the `owner` - * @dev This also accrues interest in a transaction - * @param owner The address of the account to query - * @return The amount of underlying owned by `owner` - */ - function balanceOfUnderlying(address owner) - external - override - returns (uint256) - { - (MathError mErr, uint256 balance) = mulScalarTruncate( - Exp({mantissa: exchangeRateCurrent()}), - accountTokens[owner].tokens - ); - require(mErr == MathError.NO_ERROR, "CT06"); - return balance; - } - - /** - * @notice Get a snapshot of the account's balances, and the cached exchange rate - * @dev This is used by comptroller to more efficiently perform liquidity checks. - * @param account Address of the account to snapshot - * @return (possible error, token balance, borrow balance, exchange rate mantissa) - */ - function getAccountSnapshot(address account) - external - view - override - returns ( - uint256, - uint256, - uint256, - uint256 - ) - { - uint256 cTokenBalance = accountTokens[account].tokens; - uint256 borrowBalance; - uint256 exchangeRateMantissa; - - MathError mErr; - - (mErr, borrowBalance) = borrowBalanceStoredInternal(account); - if (mErr != MathError.NO_ERROR) { - return (uint256(Error.MATH_ERROR), 0, 0, 0); - } - - (mErr, exchangeRateMantissa) = exchangeRateStoredInternal(); - if (mErr != MathError.NO_ERROR) { - return (uint256(Error.MATH_ERROR), 0, 0, 0); - } - - return ( - uint256(Error.NO_ERROR), - cTokenBalance, - borrowBalance, - exchangeRateMantissa - ); - } - - /** - * @dev Function to simply retrieve block number - * This exists mainly for inheriting test contracts to stub this result. - */ - function getBlockNumber() internal view virtual returns (uint256) { - return block.number; - } - - /** - * @notice Returns the current per-block borrow interest rate for this cToken - * @return The borrow interest rate per block, scaled by 1e18 - */ - function borrowRatePerBlock() external view override returns (uint256) { - return - interestRateModel.getBorrowRate( - getCashPrior(), - totalBorrows, - totalReserves - ); - } - - /** - * @notice Returns the current per-block supply interest rate for this cToken - * @return The supply interest rate per block, scaled by 1e18 - */ - function supplyRatePerBlock() external view override returns (uint256) { - return - interestRateModel.getSupplyRate( - getCashPrior(), - totalBorrows, - totalReserves, - reserveFactorMantissa - ); - } - - /** - * @notice Returns the current total borrows plus accrued interest - * @return The total borrows with interest - */ - function totalBorrowsCurrent() - external - override - nonReentrant - returns (uint256) - { - require(accrueInterest() == uint256(Error.NO_ERROR), "CT07"); - return totalBorrows; - } - - /** - * @notice Accrue interest to updated borrowIndex and then calculate account's borrow balance using the updated borrowIndex - * @param account The address whose balance should be calculated after updating borrowIndex - * @return The calculated balance - */ - function borrowBalanceCurrent(address account) - external - override - nonReentrant - returns (uint256) - { - require(accrueInterest() == uint256(Error.NO_ERROR), "CT07"); - return borrowBalanceStored(account); - } - - /** - * @notice Return the borrow balance of account based on stored data - * @param account The address whose balance should be calculated - * @return The calculated balance - */ - function borrowBalanceStored(address account) - public - view - override - returns (uint256) - { - (MathError err, uint256 result) = borrowBalanceStoredInternal(account); - require(err == MathError.NO_ERROR, "CT08"); - return result; - } - - /** - * @notice Return the borrow balance of account based on stored data - * @param account The address whose balance should be calculated - * @return (error code, the calculated balance or 0 if error code is non-zero) - */ - function borrowBalanceStoredInternal(address account) - internal - view - returns (MathError, uint256) - { - MathError mathErr; - uint256 principalTimesIndex; - uint256 result; - - BorrowSnapshot storage borrowSnapshot = accountBorrows[account]; - - if (borrowSnapshot.principal == 0) { - return (MathError.NO_ERROR, 0); - } - - (mathErr, principalTimesIndex) = mulUInt( - borrowSnapshot.principal, - borrowIndex - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - - (mathErr, result) = divUInt( - principalTimesIndex, - borrowSnapshot.interestIndex - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - - return (MathError.NO_ERROR, result); - } - - function getBorrowerPrincipalStored(address account) - public - view - returns (uint256 borrowed) - { - borrowed = accountBorrows[account].principal; - } - - function getSupplierSnapshotStored(address account) - public - view - returns ( - uint256 tokens, - uint256 underlyingAmount, - uint256 suppliedAt, - uint256 promisedSupplyRate - ) - { - tokens = accountTokens[account].tokens; - underlyingAmount = accountTokens[account].underlyingAmount; - suppliedAt = accountTokens[account].suppliedAt; - promisedSupplyRate = accountTokens[account].promisedSupplyRate; - } - - /** - * @notice Accrue interest then return the up-to-date exchange rate - * @return Calculated exchange rate scaled by 1e18 - */ - function exchangeRateCurrent() - public - override - nonReentrant - returns (uint256) - { - require(accrueInterest() == uint256(Error.NO_ERROR), "CT07"); - return exchangeRateStored(); - } - - /** - * @notice Calculates the exchange rate from the underlying to the CToken - * @dev This function does not accrue interest before calculating the exchange rate - * @return Calculated exchange rate scaled by 1e18 - */ - function exchangeRateStored() public view override returns (uint256) { - (MathError err, uint256 result) = exchangeRateStoredInternal(); - require(err == MathError.NO_ERROR, "CT09"); - return result; - } - - /** - * @notice Calculates the exchange rate from the underlying to the CToken - * @dev This function does not accrue interest before calculating the exchange rate - * @return (error code, calculated exchange rate scaled by 1e18) - */ - function exchangeRateStoredInternal() - internal - view - virtual - returns (MathError, uint256) - { - uint256 _totalSupply = totalSupply; - if (_totalSupply == 0) { - return (MathError.NO_ERROR, initialExchangeRateMantissa); - } else { - MathError error; - uint256 exchangeRate; - uint256 totalCash = getCashPrior(); - if (interestRateModel.isTropykusInterestRateModel()) { - (error, exchangeRate) = tropykusExchangeRateStoredInternal( - msg.sender - ); - if (error == MathError.NO_ERROR) { - return (MathError.NO_ERROR, exchangeRate); - } else { - return (MathError.NO_ERROR, initialExchangeRateMantissa); - } - } - return - interestRateModel.getExchangeRate( - totalCash, - totalBorrows, - totalReserves, - totalSupply - ); - } - } - - function tropykusExchangeRateStoredInternal(address redeemer) - internal - view - returns (MathError, uint256) - { - if (totalSupply == 0) { - return (MathError.NO_ERROR, initialExchangeRateMantissa); - } else { - SupplySnapshot storage supplySnapshot = accountTokens[redeemer]; - if (supplySnapshot.suppliedAt == 0) { - return (MathError.DIVISION_BY_ZERO, 0); - } - (, uint256 interestFactorMantissa, ) = tropykusInterestAccrued( - redeemer - ); - Exp memory interestFactor = Exp({mantissa: interestFactorMantissa}); - uint256 currentUnderlying = supplySnapshot.underlyingAmount; - Exp memory redeemerUnderlying = Exp({mantissa: currentUnderlying}); - (, Exp memory realAmount) = mulExp( - interestFactor, - redeemerUnderlying - ); - (, Exp memory exchangeRate) = getExp( - realAmount.mantissa, - supplySnapshot.tokens - ); - return (MathError.NO_ERROR, exchangeRate.mantissa); - } - } - - function tropykusInterestAccrued(address account) - internal - view - returns ( - MathError, - uint256, - uint256 - ) - { - SupplySnapshot storage supplySnapshot = accountTokens[account]; - uint256 promisedSupplyRate = supplySnapshot.promisedSupplyRate; - Exp memory expectedSupplyRatePerBlock = Exp({ - mantissa: promisedSupplyRate - }); - (, uint256 delta) = subUInt( - accrualBlockNumber, - supplySnapshot.suppliedAt - ); - (, Exp memory expectedSupplyRatePerBlockWithDelta) = mulScalar( - expectedSupplyRatePerBlock, - delta - ); - (, Exp memory interestFactor) = addExp( - Exp({mantissa: 1e18}), - expectedSupplyRatePerBlockWithDelta - ); - uint256 currentUnderlying = supplySnapshot.underlyingAmount; - Exp memory redeemerUnderlying = Exp({mantissa: currentUnderlying}); - (, Exp memory realAmount) = mulExp(interestFactor, redeemerUnderlying); - (, uint256 interestEarned) = subUInt( - realAmount.mantissa, - currentUnderlying - ); - return (MathError.NO_ERROR, interestFactor.mantissa, interestEarned); - } - - /** - * @notice Get cash balance of this cToken in the underlying asset - * @return The quantity of underlying asset owned by this contract - */ - function getCash() external view override returns (uint256) { - return getCashPrior(); - } - - /** - * @notice Applies accrued interest to total borrows and reserves - * @dev This calculates interest accrued from the last checkpointed block - * up to the current block and writes new checkpoint to storage. - */ - function accrueInterest() public override returns (uint256) { - uint256 currentBlockNumber = getBlockNumber(); - uint256 accrualBlockNumberPrior = accrualBlockNumber; - - if (accrualBlockNumberPrior == currentBlockNumber) { - return uint256(Error.NO_ERROR); - } - - uint256 cashPrior = getCashPrior(); - uint256 borrowsPrior = totalBorrows; - uint256 reservesPrior = totalReserves; - uint256 borrowIndexPrior = borrowIndex; - - uint256 borrowRateMantissa = interestRateModel.getBorrowRate( - cashPrior, - borrowsPrior, - reservesPrior - ); - require(borrowRateMantissa <= borrowRateMaxMantissa, "CT10"); - - (MathError mathErr, uint256 blockDelta) = subUInt( - currentBlockNumber, - accrualBlockNumberPrior - ); - require(mathErr == MathError.NO_ERROR, "CT11"); - - Exp memory simpleInterestFactor; - uint256 interestAccumulated; - uint256 totalBorrowsNew; - uint256 totalReservesNew; - uint256 borrowIndexNew; - - (mathErr, simpleInterestFactor) = mulScalar( - Exp({mantissa: borrowRateMantissa}), - blockDelta - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .ACCRUE_INTEREST_SIMPLE_INTEREST_FACTOR_CALCULATION_FAILED, - uint256(mathErr) - ); - } - - (mathErr, interestAccumulated) = mulScalarTruncate( - simpleInterestFactor, - borrowsPrior - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .ACCRUE_INTEREST_ACCUMULATED_INTEREST_CALCULATION_FAILED, - uint256(mathErr) - ); - } - - (mathErr, totalBorrowsNew) = addUInt(interestAccumulated, borrowsPrior); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .ACCRUE_INTEREST_NEW_TOTAL_BORROWS_CALCULATION_FAILED, - uint256(mathErr) - ); - } - - (mathErr, totalReservesNew) = mulScalarTruncateAddUInt( - Exp({mantissa: reserveFactorMantissa}), - interestAccumulated, - reservesPrior - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .ACCRUE_INTEREST_NEW_TOTAL_RESERVES_CALCULATION_FAILED, - uint256(mathErr) - ); - } - - if (interestRateModel.isTropykusInterestRateModel()) { - (mathErr, totalReservesNew) = newReserves( - borrowRateMantissa, - cashPrior, - borrowsPrior, - reservesPrior, - interestAccumulated - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .ACCRUE_INTEREST_NEW_TOTAL_RESERVES_CALCULATION_FAILED, - uint256(mathErr) - ); - } - } - - (mathErr, borrowIndexNew) = mulScalarTruncateAddUInt( - simpleInterestFactor, - borrowIndexPrior, - borrowIndexPrior - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .ACCRUE_INTEREST_NEW_BORROW_INDEX_CALCULATION_FAILED, - uint256(mathErr) - ); - } - - accrualBlockNumber = currentBlockNumber; - borrowIndex = borrowIndexNew; - totalBorrows = totalBorrowsNew; - totalReserves = totalReservesNew; - - emit AccrueInterest( - cashPrior, - interestAccumulated, - borrowIndexNew, - totalBorrowsNew - ); - - return uint256(Error.NO_ERROR); - } - - function newReserves( - uint256 borrowRateMantissa, - uint256 cashPrior, - uint256 borrowsPrior, - uint256 reservesPrior, - uint256 interestAccumulated - ) internal view returns (MathError mathErr, uint256 totalReservesNew) { - uint256 newReserveFactorMantissa; - uint256 utilizationRate = interestRateModel.utilizationRate( - cashPrior, - borrowsPrior, - reservesPrior - ); - uint256 expectedSupplyRate = interestRateModel.getSupplyRate( - cashPrior, - borrowsPrior, - reservesPrior, - reserveFactorMantissa - ); - if ( - interestRateModel.isAboveOptimal( - cashPrior, - borrowsPrior, - reservesPrior - ) - ) { - (mathErr, newReserveFactorMantissa) = mulScalarTruncate( - Exp({mantissa: utilizationRate}), - borrowRateMantissa - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - (mathErr, newReserveFactorMantissa) = subUInt( - newReserveFactorMantissa, - expectedSupplyRate - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - (mathErr, totalReservesNew) = mulScalarTruncateAddUInt( - Exp({mantissa: newReserveFactorMantissa}), - interestAccumulated, - reservesPrior - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - } else { - mathErr = MathError.NO_ERROR; - totalReservesNew = reservesPrior; - } - } - - /** - * @notice Sender supplies assets into the market and receives cTokens in exchange - * @dev Accrues interest whether or not the operation succeeds, unless reverted - * @param mintAmount The amount of the underlying asset to supply - * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual mint amount. - */ - function mintInternal(uint256 mintAmount) - internal - nonReentrant - returns (uint256, uint256) - { - if (WhitelistInterface(whitelist).enabled()) { - require(WhitelistInterface(whitelist).exist(msg.sender), "CT26"); - } - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return ( - fail(Error(error), FailureInfo.MINT_ACCRUE_INTEREST_FAILED), - 0 - ); - } - return mintFresh(msg.sender, mintAmount); - } - - struct MintLocalVars { - Error err; - MathError mathErr; - uint256 exchangeRateMantissa; - uint256 mintTokens; - uint256 totalSupplyNew; - uint256 accountTokensNew; - uint256 actualMintAmount; - } - - /** - * @notice User supplies assets into the market and receives cTokens in exchange - * @dev Assumes interest has already been accrued up to the current block - * @param minter The address of the account which is supplying the assets - * @param mintAmount The amount of the underlying asset to supply - * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual mint amount. - */ - function mintFresh(address minter, uint256 mintAmount) - internal - returns (uint256, uint256) - { - uint256 allowed = comptroller.mintAllowed( - address(this), - minter, - mintAmount - ); - if (allowed != 0) { - return ( - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.MINT_COMPTROLLER_REJECTION, - allowed - ), - 0 - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return ( - fail(Error.MARKET_NOT_FRESH, FailureInfo.MINT_FRESHNESS_CHECK), - 0 - ); - } - - MintLocalVars memory vars; - - ( - vars.mathErr, - vars.exchangeRateMantissa - ) = exchangeRateStoredInternal(); - if (vars.mathErr != MathError.NO_ERROR) { - return ( - failOpaque( - Error.MATH_ERROR, - FailureInfo.MINT_EXCHANGE_RATE_READ_FAILED, - uint256(vars.mathErr) - ), - 0 - ); - } - if (interestRateModel.isTropykusInterestRateModel()) { - SupplySnapshot storage supplySnapshot = accountTokens[minter]; - (, uint256 newTotalSupply) = addUInt( - supplySnapshot.underlyingAmount, - mintAmount - ); - require(newTotalSupply <= 0.1e18, "CT24"); - } - vars.actualMintAmount = doTransferIn(minter, mintAmount); - - (vars.mathErr, vars.mintTokens) = divScalarByExpTruncate( - vars.actualMintAmount, - Exp({mantissa: vars.exchangeRateMantissa}) - ); - require(vars.mathErr == MathError.NO_ERROR, "CT12"); - - (vars.mathErr, vars.totalSupplyNew) = addUInt( - totalSupply, - vars.mintTokens - ); - require(vars.mathErr == MathError.NO_ERROR, "CT13"); - - (vars.mathErr, vars.accountTokensNew) = addUInt( - accountTokens[minter].tokens, - vars.mintTokens - ); - require(vars.mathErr == MathError.NO_ERROR, "CT14"); - - uint256 currentSupplyRate = interestRateModel.getSupplyRate( - getCashPrior(), - totalBorrows, - totalReserves, - reserveFactorMantissa - ); - - bool isTropykusInterestRateModel = interestRateModel - .isTropykusInterestRateModel(); - - if (accountTokens[minter].tokens > 0) { - Exp memory updatedUnderlying; - if (isTropykusInterestRateModel) { - (, uint256 interestFactorMantissa, ) = tropykusInterestAccrued( - minter - ); - Exp memory interestFactor = Exp({ - mantissa: interestFactorMantissa - }); - uint256 currentUnderlyingAmount = accountTokens[minter] - .underlyingAmount; - MathError mErrorNewAmount; - (mErrorNewAmount, updatedUnderlying) = mulExp( - Exp({mantissa: currentUnderlyingAmount}), - interestFactor - ); - if (mErrorNewAmount != MathError.NO_ERROR) { - return ( - failOpaque( - Error.MATH_ERROR, - FailureInfo.MINT_EXCHANGE_CALCULATION_FAILED, - uint256(mErrorNewAmount) - ), - 0 - ); - } - } else { - uint256 currentTokens = accountTokens[minter].tokens; - MathError mErrorUpdatedUnderlying; - (mErrorUpdatedUnderlying, updatedUnderlying) = mulExp( - Exp({mantissa: currentTokens}), - Exp({mantissa: vars.exchangeRateMantissa}) - ); - if (mErrorUpdatedUnderlying != MathError.NO_ERROR) { - return ( - failOpaque( - Error.MATH_ERROR, - FailureInfo.MINT_EXCHANGE_CALCULATION_FAILED, - uint256(mErrorUpdatedUnderlying) - ), - 0 - ); - } - } - (, mintAmount) = addUInt(updatedUnderlying.mantissa, mintAmount); - } - - totalSupply = vars.totalSupplyNew; - accountTokens[minter] = SupplySnapshot({ - tokens: vars.accountTokensNew, - underlyingAmount: mintAmount, - suppliedAt: accrualBlockNumber, - promisedSupplyRate: currentSupplyRate - }); - - emit Mint(minter, vars.actualMintAmount, vars.mintTokens); - emit Transfer(address(this), minter, vars.mintTokens); - - return (uint256(Error.NO_ERROR), vars.actualMintAmount); - } - - /** - * @notice Sender redeems cTokens in exchange for a specified amount of underlying asset - * @dev Accrues interest whether or not the operation succeeds, unless reverted - * @param redeemAmount The amount of underlying to receive from redeeming cTokens - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function redeemUnderlyingInternal(uint256 redeemAmount) - internal - nonReentrant - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return - fail(Error(error), FailureInfo.REDEEM_ACCRUE_INTEREST_FAILED); - } - return redeemFresh(payable(msg.sender), redeemAmount); - } - - struct RedeemLocalVars { - Error err; - MathError mathErr; - uint256 exchangeRateMantissa; - uint256 redeemTokens; - uint256 redeemAmount; - uint256 totalSupplyNew; - uint256 accountTokensNew; - uint256 newSubsidyFund; - } - - /** - * @notice User redeems cTokens in exchange for the underlying asset - * @dev Assumes interest has already been accrued up to the current block - * @param redeemer The address of the account which is redeeming the tokens - * @param redeemAmountIn The number of underlying tokens to receive from redeeming cTokens - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function redeemFresh(address payable redeemer, uint256 redeemAmountIn) - internal - returns (uint256) - { - require(redeemAmountIn > 0, "CT15"); - - RedeemLocalVars memory vars; - - SupplySnapshot storage supplySnapshot = accountTokens[redeemer]; - - ( - vars.mathErr, - vars.exchangeRateMantissa - ) = exchangeRateStoredInternal(); - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.REDEEM_EXCHANGE_RATE_READ_FAILED, - uint256(vars.mathErr) - ); - } - - uint256 interestEarned; - uint256 subsidyFundPortion; - uint256 currentUnderlying; - - bool isTropykusInterestRateModel = interestRateModel - .isTropykusInterestRateModel(); - if (isTropykusInterestRateModel) { - currentUnderlying = supplySnapshot.underlyingAmount; - (, , interestEarned) = tropykusInterestAccrued(redeemer); - } - supplySnapshot.promisedSupplyRate = interestRateModel.getSupplyRate( - getCashPrior(), - totalBorrows, - totalReserves, - reserveFactorMantissa - ); - - if ( - isTropykusInterestRateModel && - !interestRateModel.isAboveOptimal( - getCashPrior(), - totalBorrows, - totalReserves - ) - ) { - uint256 borrowRate = interestRateModel.getBorrowRate( - getCashPrior(), - totalBorrows, - totalReserves - ); - - uint256 utilizationRate = interestRateModel.utilizationRate( - getCashPrior(), - totalBorrows, - totalReserves - ); - - (, uint256 estimatedEarning) = mulScalarTruncate( - Exp({mantissa: borrowRate}), - utilizationRate - ); - - (, subsidyFundPortion) = subUInt( - supplySnapshot.promisedSupplyRate, - estimatedEarning - ); - (, Exp memory subsidyFactor) = getExp( - subsidyFundPortion, - supplySnapshot.promisedSupplyRate - ); - (, subsidyFundPortion) = mulScalarTruncate( - subsidyFactor, - interestEarned - ); - } - - vars.redeemAmount = redeemAmountIn; - - if (isTropykusInterestRateModel) { - (, Exp memory num) = mulExp( - vars.redeemAmount, - supplySnapshot.tokens - ); - (, Exp memory realTokensWithdrawAmount) = getExp( - num.mantissa, - currentUnderlying - ); - vars.redeemTokens = realTokensWithdrawAmount.mantissa; - } else { - (vars.mathErr, vars.redeemTokens) = divScalarByExpTruncate( - redeemAmountIn, - Exp({mantissa: vars.exchangeRateMantissa}) - ); - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.REDEEM_EXCHANGE_AMOUNT_CALCULATION_FAILED, - uint256(vars.mathErr) - ); - } - } - // } - - uint256 allowed = comptroller.redeemAllowed( - address(this), - redeemer, - vars.redeemTokens - ); - if (allowed != 0) { - return - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.REDEEM_COMPTROLLER_REJECTION, - allowed - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.REDEEM_FRESHNESS_CHECK - ); - } - - (vars.mathErr, vars.totalSupplyNew) = subUInt( - totalSupply, - vars.redeemTokens - ); - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.REDEEM_NEW_TOTAL_SUPPLY_CALCULATION_FAILED, - uint256(vars.mathErr) - ); - } - - (, vars.newSubsidyFund) = subUInt(subsidyFund, subsidyFundPortion); - - (vars.mathErr, vars.accountTokensNew) = subUInt( - supplySnapshot.tokens, - vars.redeemTokens - ); - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.REDEEM_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED, - uint256(vars.mathErr) - ); - } - - uint256 cash = getCashPrior(); - if (isTropykusInterestRateModel) { - cash = address(this).balance; - } - - if (cash < vars.redeemAmount) { - return - fail( - Error.TOKEN_INSUFFICIENT_CASH, - FailureInfo.REDEEM_TRANSFER_OUT_NOT_POSSIBLE - ); - } - - doTransferOut(redeemer, vars.redeemAmount); - - totalSupply = vars.totalSupplyNew; - subsidyFund = vars.newSubsidyFund; - supplySnapshot.tokens = vars.accountTokensNew; - supplySnapshot.suppliedAt = accrualBlockNumber; - (, supplySnapshot.underlyingAmount) = subUInt( - supplySnapshot.underlyingAmount, - vars.redeemAmount - ); - - emit Transfer(redeemer, address(this), vars.redeemTokens); - emit Redeem(redeemer, vars.redeemAmount, vars.redeemTokens); - - comptroller.redeemVerify( - address(this), - redeemer, - vars.redeemAmount, - vars.redeemTokens - ); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Sender borrows assets from the protocol to their own address - * @param borrowAmount The amount of the underlying asset to borrow - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function borrowInternal(uint256 borrowAmount) - internal - nonReentrant - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return - fail(Error(error), FailureInfo.BORROW_ACCRUE_INTEREST_FAILED); - } - return borrowFresh(payable(msg.sender), borrowAmount); - } - - struct BorrowLocalVars { - MathError mathErr; - uint256 accountBorrows; - uint256 accountBorrowsNew; - uint256 totalBorrowsNew; - } - - /** - * @notice Users borrow assets from the protocol to their own address - * @param borrowAmount The amount of the underlying asset to borrow - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function borrowFresh(address payable borrower, uint256 borrowAmount) - internal - returns (uint256) - { - uint256 allowed = comptroller.borrowAllowed( - address(this), - borrower, - borrowAmount - ); - if (allowed != 0) { - return - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.BORROW_COMPTROLLER_REJECTION, - allowed - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.BORROW_FRESHNESS_CHECK - ); - } - - if (getCashPrior() < borrowAmount) { - return - fail( - Error.TOKEN_INSUFFICIENT_CASH, - FailureInfo.BORROW_CASH_NOT_AVAILABLE - ); - } - - BorrowLocalVars memory vars; - - (vars.mathErr, vars.accountBorrows) = borrowBalanceStoredInternal( - borrower - ); - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED, - uint256(vars.mathErr) - ); - } - - (vars.mathErr, vars.accountBorrowsNew) = addUInt( - vars.accountBorrows, - borrowAmount - ); - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED, - uint256(vars.mathErr) - ); - } - - (vars.mathErr, vars.totalBorrowsNew) = addUInt( - totalBorrows, - borrowAmount - ); - if (interestRateModel.isTropykusInterestRateModel()) { - require(vars.totalBorrowsNew <= 0.1e18, "CT25"); - } - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED, - uint256(vars.mathErr) - ); - } - - doTransferOut(borrower, borrowAmount); - - accountBorrows[borrower].principal = vars.accountBorrowsNew; - accountBorrows[borrower].interestIndex = borrowIndex; - totalBorrows = vars.totalBorrowsNew; - - emit Borrow( - borrower, - borrowAmount, - vars.accountBorrowsNew, - vars.totalBorrowsNew - ); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Sender repays their own borrow - * @param repayAmount The amount to repay - * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual repayment amount. - */ - function repayBorrowInternal(uint256 repayAmount) - internal - nonReentrant - returns (uint256, uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return ( - fail( - Error(error), - FailureInfo.REPAY_BORROW_ACCRUE_INTEREST_FAILED - ), - 0 - ); - } - return repayBorrowFresh(msg.sender, msg.sender, repayAmount); - } - - struct RepayBorrowLocalVars { - Error err; - MathError mathErr; - uint256 repayAmount; - uint256 borrowerIndex; - uint256 accountBorrows; - uint256 accountBorrowsNew; - uint256 totalBorrowsNew; - uint256 actualRepayAmount; - } - - /** - * @notice Borrows are repaid by another user (possibly the borrower). - * @param payer the account paying off the borrow - * @param borrower the account with the debt being payed off - * @param repayAmount the amount of undelrying tokens being returned - * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual repayment amount. - */ - function repayBorrowFresh( - address payer, - address borrower, - uint256 repayAmount - ) internal returns (uint256, uint256) { - uint256 allowed = comptroller.repayBorrowAllowed( - address(this), - payer, - borrower, - repayAmount - ); - if (allowed != 0) { - return ( - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.REPAY_BORROW_COMPTROLLER_REJECTION, - allowed - ), - 0 - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return ( - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.REPAY_BORROW_FRESHNESS_CHECK - ), - 0 - ); - } - - RepayBorrowLocalVars memory vars; - - vars.borrowerIndex = accountBorrows[borrower].interestIndex; - - (vars.mathErr, vars.accountBorrows) = borrowBalanceStoredInternal( - borrower - ); - if (vars.mathErr != MathError.NO_ERROR) { - return ( - failOpaque( - Error.MATH_ERROR, - FailureInfo - .REPAY_BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED, - uint256(vars.mathErr) - ), - 0 - ); - } - - if (repayAmount == type(uint256).max) { - vars.repayAmount = vars.accountBorrows; - } else { - vars.repayAmount = repayAmount; - } - - vars.actualRepayAmount = doTransferIn(payer, vars.repayAmount); - - (vars.mathErr, vars.accountBorrowsNew) = subUInt( - vars.accountBorrows, - vars.actualRepayAmount - ); - require(vars.mathErr == MathError.NO_ERROR, "CT16"); - - (vars.mathErr, vars.totalBorrowsNew) = subUInt( - totalBorrows, - vars.actualRepayAmount - ); - require(vars.mathErr == MathError.NO_ERROR, "CT17"); - - accountBorrows[borrower].principal = vars.accountBorrowsNew; - accountBorrows[borrower].interestIndex = borrowIndex; - totalBorrows = vars.totalBorrowsNew; - - emit RepayBorrow( - payer, - borrower, - vars.actualRepayAmount, - vars.accountBorrowsNew, - vars.totalBorrowsNew - ); - - return (uint256(Error.NO_ERROR), vars.actualRepayAmount); - } - - /** - * @notice The sender liquidates the borrowers collateral. - * The collateral seized is transferred to the liquidator. - * @param borrower The borrower of this cToken to be liquidated - * @param cTokenCollateral The market in which to seize collateral from the borrower - * @param repayAmount The amount of the underlying borrowed asset to repay - * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual repayment amount. - */ - function liquidateBorrowInternal( - address borrower, - uint256 repayAmount, - CTokenInterface cTokenCollateral - ) internal nonReentrant returns (uint256, uint256) { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return ( - fail( - Error(error), - FailureInfo.LIQUIDATE_ACCRUE_BORROW_INTEREST_FAILED - ), - 0 - ); - } - - error = cTokenCollateral.accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return ( - fail( - Error(error), - FailureInfo.LIQUIDATE_ACCRUE_COLLATERAL_INTEREST_FAILED - ), - 0 - ); - } - - // liquidateBorrowFresh emits borrow-specific logs on errors, so we don't need to - return - liquidateBorrowFresh( - msg.sender, - borrower, - repayAmount, - cTokenCollateral - ); - } - - /** - * @notice The liquidator liquidates the borrowers collateral. - * The collateral seized is transferred to the liquidator. - * @param borrower The borrower of this cToken to be liquidated - * @param liquidator The address repaying the borrow and seizing collateral - * @param cTokenCollateral The market in which to seize collateral from the borrower - * @param repayAmount The amount of the underlying borrowed asset to repay - * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual repayment amount. - */ - function liquidateBorrowFresh( - address liquidator, - address borrower, - uint256 repayAmount, - CTokenInterface cTokenCollateral - ) internal returns (uint256, uint256) { - uint256 allowed = comptroller.liquidateBorrowAllowed( - address(this), - address(cTokenCollateral), - liquidator, - borrower, - repayAmount - ); - if (allowed != 0) { - return ( - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.LIQUIDATE_COMPTROLLER_REJECTION, - allowed - ), - 0 - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return ( - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.LIQUIDATE_FRESHNESS_CHECK - ), - 0 - ); - } - - if (cTokenCollateral.accrualBlockNumber() != getBlockNumber()) { - return ( - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.LIQUIDATE_COLLATERAL_FRESHNESS_CHECK - ), - 0 - ); - } - - if (borrower == liquidator) { - return ( - fail( - Error.INVALID_ACCOUNT_PAIR, - FailureInfo.LIQUIDATE_LIQUIDATOR_IS_BORROWER - ), - 0 - ); - } - - if (repayAmount == 0) { - return ( - fail( - Error.INVALID_CLOSE_AMOUNT_REQUESTED, - FailureInfo.LIQUIDATE_CLOSE_AMOUNT_IS_ZERO - ), - 0 - ); - } - - if (repayAmount == type(uint256).max) { - return ( - fail( - Error.INVALID_CLOSE_AMOUNT_REQUESTED, - FailureInfo.LIQUIDATE_CLOSE_AMOUNT_IS_UINT_MAX - ), - 0 - ); - } - - ( - uint256 repayBorrowError, - uint256 actualRepayAmount - ) = repayBorrowFresh(liquidator, borrower, repayAmount); - if (repayBorrowError != uint256(Error.NO_ERROR)) { - return ( - fail( - Error(repayBorrowError), - FailureInfo.LIQUIDATE_REPAY_BORROW_FRESH_FAILED - ), - 0 - ); - } - - (uint256 amountSeizeError, uint256 seizeTokens) = comptroller - .liquidateCalculateSeizeTokens( - address(this), - address(cTokenCollateral), - actualRepayAmount - ); - require(amountSeizeError == uint256(Error.NO_ERROR), "CT18"); - - require(cTokenCollateral.balanceOf(borrower) >= seizeTokens, "CT19"); - - uint256 seizeError; - if (address(cTokenCollateral) == address(this)) { - seizeError = seizeInternal( - address(this), - liquidator, - borrower, - seizeTokens - ); - } else { - seizeError = cTokenCollateral.seize( - liquidator, - borrower, - seizeTokens - ); - } - - require(seizeError == uint256(Error.NO_ERROR), "CT20"); - - emit LiquidateBorrow( - liquidator, - borrower, - actualRepayAmount, - address(cTokenCollateral), - seizeTokens - ); - - return (uint256(Error.NO_ERROR), actualRepayAmount); - } - - /** - * @notice Transfers collateral tokens (this market) to the liquidator. - * @dev Will fail unless called by another cToken during the process of liquidation. - * Its absolutely critical to use msg.sender as the borrowed cToken and not a parameter. - * @param liquidator The account receiving seized collateral - * @param borrower The account having collateral seized - * @param seizeTokens The number of cTokens to seize - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function seize( - address liquidator, - address borrower, - uint256 seizeTokens - ) external override nonReentrant returns (uint256) { - return seizeInternal(msg.sender, liquidator, borrower, seizeTokens); - } - - struct SeizeVars { - uint256 seizeAmount; - uint256 exchangeRate; - uint256 borrowerTokensNew; - uint256 borrowerAmountNew; - uint256 liquidatorTokensNew; - uint256 liquidatorAmountNew; - uint256 totalCash; - uint256 supplyRate; - } - - /** - * @notice Transfers collateral tokens (this market) to the liquidator. - * @dev Called only during an in-kind liquidation, or by liquidateBorrow during the liquidation of another CToken. - * Its absolutely critical to use msg.sender as the seizer cToken and not a parameter. - * @param seizerToken The contract seizing the collateral (i.e. borrowed cToken) - * @param liquidator The account receiving seized collateral - * @param borrower The account having collateral seized - * @param seizeTokens The number of cTokens to seize - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function seizeInternal( - address seizerToken, - address liquidator, - address borrower, - uint256 seizeTokens - ) internal returns (uint256) { - uint256 allowed = comptroller.seizeAllowed( - address(this), - seizerToken, - liquidator, - borrower, - seizeTokens - ); - if (allowed != 0) { - return - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.LIQUIDATE_SEIZE_COMPTROLLER_REJECTION, - allowed - ); - } - - if (borrower == liquidator) { - return - fail( - Error.INVALID_ACCOUNT_PAIR, - FailureInfo.LIQUIDATE_SEIZE_LIQUIDATOR_IS_BORROWER - ); - } - - SeizeVars memory seizeVars; - - MathError mathErr; - - (mathErr, seizeVars.borrowerTokensNew) = subUInt( - accountTokens[borrower].tokens, - seizeTokens - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.LIQUIDATE_SEIZE_BALANCE_DECREMENT_FAILED, - uint256(mathErr) - ); - } - - seizeVars.totalCash = getCashPrior(); - seizeVars.supplyRate = interestRateModel.getSupplyRate( - seizeVars.totalCash, - totalBorrows, - totalReserves, - reserveFactorMantissa - ); - - (, seizeVars.exchangeRate) = interestRateModel.getExchangeRate( - seizeVars.totalCash, - totalBorrows, - totalReserves, - totalSupply - ); - - if (interestRateModel.isTropykusInterestRateModel()) { - (, seizeVars.exchangeRate) = tropykusExchangeRateStoredInternal( - borrower - ); - } - - (, seizeVars.seizeAmount) = mulUInt( - seizeTokens, - seizeVars.exchangeRate - ); - (, seizeVars.seizeAmount) = divUInt(seizeVars.seizeAmount, 1e18); - - (, seizeVars.borrowerAmountNew) = subUInt( - accountTokens[borrower].underlyingAmount, - seizeVars.seizeAmount - ); - - (mathErr, seizeVars.liquidatorTokensNew) = addUInt( - accountTokens[liquidator].tokens, - seizeTokens - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.LIQUIDATE_SEIZE_BALANCE_INCREMENT_FAILED, - uint256(mathErr) - ); - } - - (, seizeVars.liquidatorAmountNew) = addUInt( - accountTokens[liquidator].underlyingAmount, - seizeVars.seizeAmount - ); - - accountTokens[borrower].tokens = seizeVars.borrowerTokensNew; - accountTokens[borrower].underlyingAmount = seizeVars.borrowerAmountNew; - accountTokens[borrower].suppliedAt = getBlockNumber(); - accountTokens[borrower].promisedSupplyRate = seizeVars.supplyRate; - - accountTokens[liquidator].tokens = seizeVars.liquidatorTokensNew; - accountTokens[liquidator].underlyingAmount = seizeVars - .liquidatorAmountNew; - accountTokens[liquidator].suppliedAt = getBlockNumber(); - accountTokens[liquidator].promisedSupplyRate = seizeVars.supplyRate; - - emit Transfer(borrower, liquidator, seizeTokens); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Begins transfer of admin rights. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer. - * @dev Admin function to begin change of admin. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer. - * @param newPendingAdmin New pending admin. - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setPendingAdmin(address payable newPendingAdmin) - external - override - returns (uint256) - { - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_PENDING_ADMIN_OWNER_CHECK - ); - } - - address oldPendingAdmin = pendingAdmin; - - pendingAdmin = newPendingAdmin; - - emit NewPendingAdmin(oldPendingAdmin, newPendingAdmin); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Accepts transfer of admin rights. msg.sender must be pendingAdmin - * @dev Admin function for pending admin to accept role and update admin - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _acceptAdmin() external override returns (uint256) { - if (msg.sender != pendingAdmin || msg.sender == address(0)) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.ACCEPT_ADMIN_PENDING_ADMIN_CHECK - ); - } - - address oldAdmin = admin; - address oldPendingAdmin = pendingAdmin; - - admin = pendingAdmin; - - pendingAdmin = payable(address(0)); - - emit NewAdmin(oldAdmin, admin); - emit NewPendingAdmin(oldPendingAdmin, pendingAdmin); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Sets a new comptroller for the market - * @dev Admin function to set a new comptroller - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setComptroller(ComptrollerInterface newComptroller) - public - override - returns (uint256) - { - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_COMPTROLLER_OWNER_CHECK - ); - } - - ComptrollerInterface oldComptroller = comptroller; - require(newComptroller.isComptroller(), "CT21"); - - comptroller = newComptroller; - - emit NewComptroller(oldComptroller, newComptroller); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice accrues interest and sets a new reserve factor for the protocol using _setReserveFactorFresh - * @dev Admin function to accrue interest and set a new reserve factor - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setReserveFactor(uint256 newReserveFactorMantissa) - external - override - nonReentrant - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return - fail( - Error(error), - FailureInfo.SET_RESERVE_FACTOR_ACCRUE_INTEREST_FAILED - ); - } - return _setReserveFactorFresh(newReserveFactorMantissa); - } - - /** - * @notice Sets a new reserve factor for the protocol (*requires fresh interest accrual) - * @dev Admin function to set a new reserve factor - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setReserveFactorFresh(uint256 newReserveFactorMantissa) - internal - returns (uint256) - { - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_RESERVE_FACTOR_ADMIN_CHECK - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.SET_RESERVE_FACTOR_FRESH_CHECK - ); - } - - if (newReserveFactorMantissa > reserveFactorMaxMantissa) { - return - fail( - Error.BAD_INPUT, - FailureInfo.SET_RESERVE_FACTOR_BOUNDS_CHECK - ); - } - - uint256 oldReserveFactorMantissa = reserveFactorMantissa; - reserveFactorMantissa = newReserveFactorMantissa; - - emit NewReserveFactor( - oldReserveFactorMantissa, - newReserveFactorMantissa - ); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Accrues interest and reduces reserves by transferring from msg.sender - * @param addAmount Amount of addition to reserves - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _addReservesInternal(uint256 addAmount) - internal - nonReentrant - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return - fail( - Error(error), - FailureInfo.ADD_RESERVES_ACCRUE_INTEREST_FAILED - ); - } - - uint256 totalReservesNew; - uint256 actualAddAmount; - - if (accrualBlockNumber != getBlockNumber()) { - return ( - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.ADD_RESERVES_FRESH_CHECK - ) - ); - } - - actualAddAmount = doTransferIn(msg.sender, addAmount); - - totalReservesNew = totalReserves + actualAddAmount; - - require(totalReservesNew >= totalReserves, "CT22"); - - totalReserves = totalReservesNew; - - emit ReservesAdded(msg.sender, actualAddAmount, totalReservesNew); - - return (uint256(Error.NO_ERROR)); - } - - function _addSubsidyInternal(uint256 addAmount) - internal - nonReentrant - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - // accrueInterest emits logs on errors, but on top of that we want to log the fact that an attempted reduce reserves failed. - return fail(Error(error), FailureInfo.ADD_SUBSIDY_FUND_FAILED); - } - - uint256 subsidyFundNew; - uint256 actualAddAmount; - - if (accrualBlockNumber != getBlockNumber()) { - return ( - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.ADD_SUBSIDY_FUND_FRESH_CHECK - ) - ); - } - - actualAddAmount = doTransferIn(msg.sender, addAmount); - - subsidyFundNew = subsidyFund + actualAddAmount; - - require(subsidyFundNew >= subsidyFund, "CT22"); - - subsidyFund = subsidyFundNew; - - emit SubsidyAdded(msg.sender, actualAddAmount, subsidyFundNew); - - /* Return (NO_ERROR, actualAddAmount) */ - return (uint256(Error.NO_ERROR)); - } - - /** - * @notice Accrues interest and reduces reserves by transferring to admin - * @param reduceAmount Amount of reduction to reserves - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _reduceReserves(uint256 reduceAmount) - external - override - nonReentrant - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return - fail( - Error(error), - FailureInfo.REDUCE_RESERVES_ACCRUE_INTEREST_FAILED - ); - } - return _reduceReservesFresh(reduceAmount); - } - - /** - * @notice Reduces reserves by transferring to admin - * @dev Requires fresh interest accrual - * @param reduceAmount Amount of reduction to reserves - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _reduceReservesFresh(uint256 reduceAmount) - internal - returns (uint256) - { - uint256 totalReservesNew; - - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.REDUCE_RESERVES_ADMIN_CHECK - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.REDUCE_RESERVES_FRESH_CHECK - ); - } - - if (getCashPrior() < reduceAmount) { - return - fail( - Error.TOKEN_INSUFFICIENT_CASH, - FailureInfo.REDUCE_RESERVES_CASH_NOT_AVAILABLE - ); - } - - if (reduceAmount > totalReserves) { - return - fail(Error.BAD_INPUT, FailureInfo.REDUCE_RESERVES_VALIDATION); - } - - totalReservesNew = totalReserves - reduceAmount; - require(totalReservesNew <= totalReserves, "CT23"); - - totalReserves = totalReservesNew; - - doTransferOut(admin, reduceAmount); - - emit ReservesReduced(admin, reduceAmount, totalReservesNew); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice accrues interest and updates the interest rate model using _setInterestRateModelFresh - * @dev Admin function to accrue interest and update the interest rate model - * @param newInterestRateModel the new interest rate model to use - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setInterestRateModel(InterestRateModel newInterestRateModel) - public - override - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return - fail( - Error(error), - FailureInfo.SET_INTEREST_RATE_MODEL_ACCRUE_INTEREST_FAILED - ); - } - return _setInterestRateModelFresh(newInterestRateModel); - } - - /** - * @notice updates the interest rate model (*requires fresh interest accrual) - * @dev Admin function to update the interest rate model - * @param newInterestRateModel the new interest rate model to use - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setInterestRateModelFresh(InterestRateModel newInterestRateModel) - internal - returns (uint256) - { - InterestRateModel oldInterestRateModel; - - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_INTEREST_RATE_MODEL_OWNER_CHECK - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.SET_INTEREST_RATE_MODEL_FRESH_CHECK - ); - } - - oldInterestRateModel = interestRateModel; - - require(newInterestRateModel.isInterestRateModel(), "CT21"); - - interestRateModel = newInterestRateModel; - - emit NewMarketInterestRateModel( - oldInterestRateModel, - newInterestRateModel - ); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Gets balance of this contract in terms of the underlying - * @dev This excludes the value of the current message, if any - * @return The quantity of underlying owned by this contract - */ - function getCashPrior() internal view virtual returns (uint256); - - /** - * @dev Performs a transfer in, reverting upon failure. Returns the amount actually transferred to the protocol, in case of a fee. - * This may revert due to insufficient balance or insufficient allowance. - */ - function doTransferIn(address from, uint256 amount) - internal - virtual - returns (uint256); - - /** - * @dev Performs a transfer out, ideally returning an explanatory error code upon failure tather than reverting. - * If caller has not called checked protocol's balance, may revert due to insufficient cash held in the contract. - * If caller has checked protocol's balance, and verified it is >= amount, this should not revert in normal conditions. - */ - function doTransferOut(address payable to, uint256 amount) internal virtual; - - /** - * @dev Prevents a contract from calling itself, directly or indirectly. - */ - modifier nonReentrant() { - require(_notEntered, "re-entered"); - _notEntered = false; - _; - _notEntered = true; - } -} - - -// Dependency file: contracts/PriceOracle.sol - -// pragma solidity 0.8.6; - -// import "contracts/CToken.sol"; - -abstract contract PriceOracle { - /// @notice Indicator that this is a PriceOracle contract (for inspection) - bool public constant isPriceOracle = true; - - /** - * @notice Get the underlying price of a cToken asset - * @param cToken The cToken to get the underlying price of - * @return The underlying asset price mantissa (scaled by 1e18). - * Zero means the price is unavailable. - */ - function getUnderlyingPrice(CToken cToken) - external - view - virtual - returns (uint256); -} - - -// Dependency file: contracts/ComptrollerStorage.sol - -// pragma solidity 0.8.6; - -// import "contracts/CToken.sol"; -// import "contracts/PriceOracle.sol"; - -contract UnitrollerAdminStorage { - /** - * @notice Administrator for this contract - */ - address public admin; - - /** - * @notice Pending administrator for this contract - */ - address public pendingAdmin; - - /** - * @notice Active brains of Unitroller - */ - address public comptrollerImplementation; - - /** - * @notice Pending brains of Unitroller - */ - address public pendingComptrollerImplementation; -} - -contract ComptrollerV1Storage is UnitrollerAdminStorage { - - /** - * @notice Oracle which gives the price of any given asset - */ - PriceOracle public oracle; - - /** - * @notice Multiplier used to calculate the maximum repayAmount when liquidating a borrow - */ - uint public closeFactorMantissa; - - /** - * @notice Multiplier representing the discount on collateral that a liquidator receives - */ - uint public liquidationIncentiveMantissa; - - /** - * @notice Max number of assets a single account can participate in (borrow or use as collateral) - */ - uint public maxAssets; - - /** - * @notice Per-account mapping of "assets you are in", capped by maxAssets - */ - mapping(address => CToken[]) public accountAssets; - -} - -contract ComptrollerV2Storage is ComptrollerV1Storage { - struct Market { - /// @notice Whether or not this market is listed - bool isListed; - - /** - * @notice Multiplier representing the most one can borrow against their collateral in this market. - * For instance, 0.9 to allow borrowing 90% of collateral value. - * Must be between 0 and 1, and stored as a mantissa. - */ - uint collateralFactorMantissa; - - /// @notice Per-market mapping of "accounts in this asset" - mapping(address => bool) accountMembership; - - /// @notice Whether or not this market receives COMP - bool isComped; - } - - /** - * @notice Official mapping of cTokens -> Market metadata - * @dev Used e.g. to determine if a market is supported - */ - mapping(address => Market) public markets; - - - /** - * @notice The Pause Guardian can pause certain actions as a safety mechanism. - * Actions which allow users to remove their own assets cannot be paused. - * Liquidation / seizing / transfer can only be paused globally, not by market. - */ - address public pauseGuardian; - bool public _mintGuardianPaused; - bool public _borrowGuardianPaused; - bool public transferGuardianPaused; - bool public seizeGuardianPaused; - mapping(address => bool) public mintGuardianPaused; - mapping(address => bool) public borrowGuardianPaused; -} - -contract ComptrollerV3Storage is ComptrollerV2Storage { - struct CompMarketState { - /// @notice The market's last updated compBorrowIndex or compSupplyIndex - uint224 index; - - /// @notice The block number the index was last updated at - uint32 block; - } - - /// @notice A list of all markets - CToken[] public allMarkets; - - /// @notice The rate at which the flywheel distributes COMP, per block - uint public compRate; - - /// @notice The portion of compRate that each market currently receives - mapping(address => uint) public compSpeeds; - - /// @notice The COMP market supply state for each market - mapping(address => CompMarketState) public compSupplyState; - - /// @notice The COMP market borrow state for each market - mapping(address => CompMarketState) public compBorrowState; - - /// @notice The COMP borrow index for each market for each supplier as of the last time they accrued COMP - mapping(address => mapping(address => uint)) public compSupplierIndex; - - /// @notice The COMP borrow index for each market for each borrower as of the last time they accrued COMP - mapping(address => mapping(address => uint)) public compBorrowerIndex; - - /// @notice The COMP accrued but not yet transferred to each user - mapping(address => uint) public compAccrued; -} - -contract ComptrollerV4Storage is ComptrollerV3Storage { - // @notice The borrowCapGuardian can set borrowCaps to any number for any market. Lowering the borrow cap could disable borrowing on the given market. - address public borrowCapGuardian; - - // @notice Borrow caps enforced by borrowAllowed for each cToken address. Defaults to zero which corresponds to unlimited borrowing. - mapping(address => uint) public borrowCaps; - - // @notice address of the TROP token - address public tropAddress; -} - -contract ComptrollerV5Storage is ComptrollerV4Storage { - /// @notice The portion of COMP that each contributor receives per block - mapping(address => uint) public compContributorSpeeds; - - /// @notice Last block at which a contributor's COMP rewards have been allocated - mapping(address => uint) public lastContributorBlock; -} - - -// Dependency file: contracts/Unitroller.sol - -// pragma solidity 0.8.6; - -// import "contracts/ErrorReporter.sol"; -// import "contracts/ComptrollerStorage.sol"; - -/** - * @title ComptrollerCore - * @dev Storage for the comptroller is at this address, while execution is delegated to the `comptrollerImplementation`. - * CTokens should reference this contract as their comptroller. - */ -contract Unitroller is UnitrollerAdminStorage, ComptrollerErrorReporter { - /** - * @notice Emitted when pendingComptrollerImplementation is changed - */ - event NewPendingImplementation( - address oldPendingImplementation, - address newPendingImplementation - ); - - /** - * @notice Emitted when pendingComptrollerImplementation is accepted, which means comptroller implementation is updated - */ - event NewImplementation( - address oldImplementation, - address newImplementation - ); - - /** - * @notice Emitted when pendingAdmin is changed - */ - event NewPendingAdmin(address oldPendingAdmin, address newPendingAdmin); - - /** - * @notice Emitted when pendingAdmin is accepted, which means admin is updated - */ - event NewAdmin(address oldAdmin, address newAdmin); - - constructor() { - // Set admin to caller - admin = msg.sender; - } - - /*** Admin Functions ***/ - function _setPendingImplementation(address newPendingImplementation) - public - returns (uint256) - { - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_PENDING_IMPLEMENTATION_OWNER_CHECK - ); - } - - address oldPendingImplementation = pendingComptrollerImplementation; - - pendingComptrollerImplementation = newPendingImplementation; - - emit NewPendingImplementation( - oldPendingImplementation, - pendingComptrollerImplementation - ); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Accepts new implementation of comptroller. msg.sender must be pendingImplementation - * @dev Admin function for new implementation to accept it's role as implementation - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _acceptImplementation() public returns (uint256) { - // Check caller is pendingImplementation and pendingImplementation ≠ address(0) - if ( - msg.sender != pendingComptrollerImplementation || - pendingComptrollerImplementation == address(0) - ) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.ACCEPT_PENDING_IMPLEMENTATION_ADDRESS_CHECK - ); - } - - // Save current values for inclusion in log - address oldImplementation = comptrollerImplementation; - address oldPendingImplementation = pendingComptrollerImplementation; - - comptrollerImplementation = pendingComptrollerImplementation; - - pendingComptrollerImplementation = address(0); - - emit NewImplementation(oldImplementation, comptrollerImplementation); - emit NewPendingImplementation( - oldPendingImplementation, - pendingComptrollerImplementation - ); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Begins transfer of admin rights. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer. - * @dev Admin function to begin change of admin. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer. - * @param newPendingAdmin New pending admin. - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setPendingAdmin(address newPendingAdmin) - public - returns (uint256) - { - // Check caller = admin - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_PENDING_ADMIN_OWNER_CHECK - ); - } - - // Save current value, if any, for inclusion in log - address oldPendingAdmin = pendingAdmin; - - // Store pendingAdmin with value newPendingAdmin - pendingAdmin = newPendingAdmin; - - // Emit NewPendingAdmin(oldPendingAdmin, newPendingAdmin) - emit NewPendingAdmin(oldPendingAdmin, newPendingAdmin); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Accepts transfer of admin rights. msg.sender must be pendingAdmin - * @dev Admin function for pending admin to accept role and update admin - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _acceptAdmin() public returns (uint256) { - // Check caller is pendingAdmin and pendingAdmin ≠ address(0) - if (msg.sender != pendingAdmin || msg.sender == address(0)) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.ACCEPT_ADMIN_PENDING_ADMIN_CHECK - ); - } - - // Save current values for inclusion in log - address oldAdmin = admin; - address oldPendingAdmin = pendingAdmin; - - // Store admin with value pendingAdmin - admin = pendingAdmin; - - // Clear the pending value - pendingAdmin = address(0); - - emit NewAdmin(oldAdmin, admin); - emit NewPendingAdmin(oldPendingAdmin, pendingAdmin); - - return uint256(Error.NO_ERROR); - } - - /** - * @dev Delegates execution to an implementation contract. - * It returns to the external caller whatever the implementation returns - * or forwards reverts. - */ - function internalFallback() public payable { - // delegate all other functions to current implementation - (bool success, ) = comptrollerImplementation.delegatecall(msg.data); - - assembly { - let free_mem_ptr := mload(0x40) - returndatacopy(free_mem_ptr, 0, returndatasize()) - - switch success - case 0 { - revert(free_mem_ptr, returndatasize()) - } - default { - return(free_mem_ptr, returndatasize()) - } - } - } - - fallback() external payable { - internalFallback(); - } - - receive() external payable { - internalFallback(); - } -} - - -// Dependency file: contracts/Governance/TROP.sol - -// pragma solidity 0.8.6; -pragma experimental ABIEncoderV2; - -/** - * @title TROP ERC20 tokens. - * @author tropykus - * @notice Yield farming tokens that allow to propose and vote for protocol changes using the governance system. - */ -contract TROP { - /// @notice EIP-20 token name for this token - string public constant name = "tropykus"; - - /// @notice EIP-20 token symbol for this token - string public constant symbol = "TROP"; - - /// @notice EIP-20 token decimals for this token - uint8 public constant decimals = 18; - - /// @notice Total number of tokens in circulation - uint256 public constant totalSupply = 10000000e18; // 10 million TROP - - /// @notice Allowance amounts on behalf of others - mapping(address => mapping(address => uint96)) internal allowances; - - /// @notice Official record of token balances for each account - mapping(address => uint96) internal balances; - - /// @notice A record of each accounts delegate - mapping(address => address) public delegates; - - /// @notice A checkpoint for marking number of votes from a given block - struct Checkpoint { - uint32 fromBlock; - uint96 votes; - } - - /// @notice A record of votes checkpoints for each account, by index - mapping(address => mapping(uint32 => Checkpoint)) public checkpoints; - - /// @notice The number of checkpoints for each account - mapping(address => uint32) public numCheckpoints; - - /// @notice The EIP-712 typehash for the contract's domain - bytes32 public constant DOMAIN_TYPEHASH = - keccak256( - "EIP712Domain(string name,uint256 chainId,address verifyingContract)" - ); - - /// @notice The EIP-712 typehash for the delegation struct used by the contract - bytes32 public constant DELEGATION_TYPEHASH = - keccak256("Delegation(address delegatee,uint256 nonce,uint256 expiry)"); - - /// @notice A record of states for signing / validating signatures - mapping(address => uint256) public nonces; - - /// @notice An event thats emitted when an account changes its delegate - event DelegateChanged( - address indexed delegator, - address indexed fromDelegate, - address indexed toDelegate - ); - - /// @notice An event thats emitted when a delegate account's vote balance changes - event DelegateVotesChanged( - address indexed delegate, - uint256 previousBalance, - uint256 newBalance - ); - - /// @notice The standard EIP-20 transfer event - event Transfer(address indexed from, address indexed to, uint256 amount); - - /// @notice The standard EIP-20 approval event - event Approval( - address indexed owner, - address indexed spender, - uint256 amount - ); - - /** - * @notice Construct a new TROP token - * @param account The initial account to grant all the tokens - */ - constructor(address account) { - balances[account] = uint96(totalSupply); - emit Transfer(address(0), account, totalSupply); - } - - /** - * @notice Get the number of tokens `spender` is approved to spend on behalf of `account` - * @param account The address of the account holding the funds - * @param spender The address of the account spending the funds - * @return The number of tokens approved - */ - function allowance(address account, address spender) - external - view - returns (uint256) - { - return allowances[account][spender]; - } - - /** - * @notice Approve `spender` to transfer up to `amount` from `src` - * @dev This will overwrite the approval amount for `spender` - * and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve) - * @param spender The address of the account which may transfer tokens - * @param rawAmount The number of tokens that are approved (2^256-1 means infinite) - * @return Whether or not the approval succeeded - */ - function approve(address spender, uint256 rawAmount) - external - returns (bool) - { - uint96 amount; - if (rawAmount == type(uint256).max) { - amount = type(uint96).max; - } else { - amount = safe96(rawAmount, "TROP::approve: amount exceeds 96 bits"); - } - - allowances[msg.sender][spender] = amount; - - emit Approval(msg.sender, spender, amount); - return true; - } - - /** - * @notice Get the number of tokens held by the `account` - * @param account The address of the account to get the balance of - * @return The number of tokens held - */ - function balanceOf(address account) external view returns (uint256) { - return balances[account]; - } - - /** - * @notice Transfer `amount` tokens from `msg.sender` to `dst` - * @param dst The address of the destination account - * @param rawAmount The number of tokens to transfer - * @return Whether or not the transfer succeeded - */ - function transfer(address dst, uint256 rawAmount) external returns (bool) { - uint96 amount = safe96( - rawAmount, - "TROP::transfer: amount exceeds 96 bits" - ); - _transferTokens(msg.sender, dst, amount); - return true; - } - - /** - * @notice Transfer `amount` tokens from `src` to `dst` - * @param src The address of the source account - * @param dst The address of the destination account - * @param rawAmount The number of tokens to transfer - * @return Whether or not the transfer succeeded - */ - function transferFrom( - address src, - address dst, - uint256 rawAmount - ) external returns (bool) { - address spender = msg.sender; - uint96 spenderAllowance = allowances[src][spender]; - uint96 amount = safe96( - rawAmount, - "TROP::approve: amount exceeds 96 bits" - ); - - if (spender != src && spenderAllowance != type(uint96).max) { - uint96 newAllowance = sub96( - spenderAllowance, - amount, - "TROP::transferFrom: transfer amount exceeds spender allowance" - ); - allowances[src][spender] = newAllowance; - - emit Approval(src, spender, newAllowance); - } - - _transferTokens(src, dst, amount); - return true; - } - - /** - * @notice Delegate votes from `msg.sender` to `delegatee` - * @param delegatee The address to delegate votes to - */ - function delegate(address delegatee) public { - return _delegate(msg.sender, delegatee); - } - - /** - * @notice Delegates votes from signatory to `delegatee` - * @param delegatee The address to delegate votes to - * @param nonce The contract state required to match the signature - * @param expiry The time at which to expire the signature - * @param v The recovery byte of the signature - * @param r Half of the ECDSA signature pair - * @param s Half of the ECDSA signature pair - */ - function delegateBySig( - address delegatee, - uint256 nonce, - uint256 expiry, - uint8 v, - bytes32 r, - bytes32 s - ) public { - bytes32 domainSeparator = keccak256( - abi.encode( - DOMAIN_TYPEHASH, - keccak256(bytes(name)), - getChainId(), - address(this) - ) - ); - bytes32 structHash = keccak256( - abi.encode(DELEGATION_TYPEHASH, delegatee, nonce, expiry) - ); - bytes32 digest = keccak256( - abi.encodePacked("\x19\x01", domainSeparator, structHash) - ); - address signatory = ecrecover(digest, v, r, s); - require( - signatory != 0xdcc703c0E500B653Ca82273B7BFAd8045D85a470 && - signatory != address(0), - "TROP::delegateBySig: invalid signature" - ); - require( - nonce == nonces[signatory]++, - "TROP::delegateBySig: invalid nonce" - ); - require( - block.timestamp <= expiry, - "TROP::delegateBySig: signature expired" - ); - return _delegate(signatory, delegatee); - } - - /** - * @notice Gets the current votes balance for `account` - * @param account The address to get votes balance - * @return The number of current votes for `account` - */ - function getCurrentVotes(address account) external view returns (uint96) { - uint32 nCheckpoints = numCheckpoints[account]; - return - nCheckpoints > 0 ? checkpoints[account][nCheckpoints - 1].votes : 0; - } - - /** - * @notice Determine the prior number of votes for an account as of a block number - * @dev Block number must be a finalized block or else this function will revert to prevent misinformation. - * @param account The address of the account to check - * @param blockNumber The block number to get the vote balance at - * @return The number of votes the account had as of the given block - */ - function getPriorVotes(address account, uint256 blockNumber) - public - view - returns (uint96) - { - require( - blockNumber < block.number, - "TROP::getPriorVotes: not yet determined" - ); - - uint32 nCheckpoints = numCheckpoints[account]; - if (nCheckpoints == 0) { - return 0; - } - - // First check most recent balance - if (checkpoints[account][nCheckpoints - 1].fromBlock <= blockNumber) { - return checkpoints[account][nCheckpoints - 1].votes; - } - - // Next check implicit zero balance - if (checkpoints[account][0].fromBlock > blockNumber) { - return 0; - } - - uint32 lower = 0; - uint32 upper = nCheckpoints - 1; - while (upper > lower) { - uint32 center = upper - (upper - lower) / 2; // ceil, avoiding overflow - Checkpoint memory cp = checkpoints[account][center]; - if (cp.fromBlock == blockNumber) { - return cp.votes; - } else if (cp.fromBlock < blockNumber) { - lower = center; - } else { - upper = center - 1; - } - } - return checkpoints[account][lower].votes; - } - - function _delegate(address delegator, address delegatee) internal { - address currentDelegate = delegates[delegator]; - uint96 delegatorBalance = balances[delegator]; - delegates[delegator] = delegatee; - - emit DelegateChanged(delegator, currentDelegate, delegatee); - - _moveDelegates(currentDelegate, delegatee, delegatorBalance); - } - - function _transferTokens( - address src, - address dst, - uint96 amount - ) internal { - require( - src != address(0), - "TROP::_transferTokens: cannot transfer from the zero address" - ); - require( - dst != address(0), - "TROP::_transferTokens: cannot transfer to the zero address" - ); - - balances[src] = sub96( - balances[src], - amount, - "TROP::_transferTokens: transfer amount exceeds balance" - ); - balances[dst] = add96( - balances[dst], - amount, - "TROP::_transferTokens: transfer amount overflows" - ); - emit Transfer(src, dst, amount); - - _moveDelegates(delegates[src], delegates[dst], amount); - } - - function _moveDelegates( - address srcRep, - address dstRep, - uint96 amount - ) internal { - if (srcRep != dstRep && amount > 0) { - if (srcRep != address(0)) { - uint32 srcRepNum = numCheckpoints[srcRep]; - uint96 srcRepOld = srcRepNum > 0 - ? checkpoints[srcRep][srcRepNum - 1].votes - : 0; - uint96 srcRepNew = sub96( - srcRepOld, - amount, - "TROP::_moveVotes: vote amount underflows" - ); - _writeCheckpoint(srcRep, srcRepNum, srcRepOld, srcRepNew); - } - - if (dstRep != address(0)) { - uint32 dstRepNum = numCheckpoints[dstRep]; - uint96 dstRepOld = dstRepNum > 0 - ? checkpoints[dstRep][dstRepNum - 1].votes - : 0; - uint96 dstRepNew = add96( - dstRepOld, - amount, - "TROP::_moveVotes: vote amount overflows" - ); - _writeCheckpoint(dstRep, dstRepNum, dstRepOld, dstRepNew); - } - } - } - - function _writeCheckpoint( - address delegatee, - uint32 nCheckpoints, - uint96 oldVotes, - uint96 newVotes - ) internal { - uint32 blockNumber = safe32( - block.number, - "TROP::_writeCheckpoint: block number exceeds 32 bits" - ); - - if ( - nCheckpoints > 0 && - checkpoints[delegatee][nCheckpoints - 1].fromBlock == blockNumber - ) { - checkpoints[delegatee][nCheckpoints - 1].votes = newVotes; - } else { - checkpoints[delegatee][nCheckpoints] = Checkpoint( - blockNumber, - newVotes - ); - numCheckpoints[delegatee] = nCheckpoints + 1; - } - - emit DelegateVotesChanged(delegatee, oldVotes, newVotes); - } - - function safe32(uint256 n, string memory errorMessage) - internal - pure - returns (uint32) - { - require(n < 2**32, errorMessage); - return uint32(n); - } - - function safe96(uint256 n, string memory errorMessage) - internal - pure - returns (uint96) - { - require(n < 2**96, errorMessage); - return uint96(n); - } - - function add96( - uint96 a, - uint96 b, - string memory errorMessage - ) internal pure returns (uint96) { - uint96 c = a + b; - require(c >= a, errorMessage); - return c; - } - - function sub96( - uint96 a, - uint96 b, - string memory errorMessage - ) internal pure returns (uint96) { - require(b <= a, errorMessage); - return a - b; - } - - function getChainId() internal view returns (uint256) { - uint256 chainId; - assembly { - chainId := chainid() - } - return chainId; - } -} - - -// Root file: contracts/ComptrollerG4.sol - -pragma solidity 0.8.6; - -// import "contracts/CToken.sol"; -// import "contracts/ErrorReporter.sol"; -// import "contracts/Exponential.sol"; -// import "contracts/PriceOracle.sol"; -// import "contracts/ComptrollerInterface.sol"; -// import "contracts/ComptrollerStorage.sol"; -// import "contracts/Unitroller.sol"; -// import "contracts/Governance/TROP.sol"; - -/** - * @title tropykus Comptroller Contract - * @author tropykus - */ -contract ComptrollerG4 is - ComptrollerV3Storage, - ComptrollerInterface, - ComptrollerErrorReporter, - Exponential -{ - /// @notice Emitted when an admin supports a market - event MarketListed(CToken cToken); - - /// @notice Emitted when an account enters a market - event MarketEntered(CToken cToken, address account); - - /// @notice Emitted when an account exits a market - event MarketExited(CToken cToken, address account); - - /// @notice Emitted when close factor is changed by admin - event NewCloseFactor( - uint256 oldCloseFactorMantissa, - uint256 newCloseFactorMantissa - ); - - /// @notice Emitted when a collateral factor is changed by admin - event NewCollateralFactor( - CToken cToken, - uint256 oldCollateralFactorMantissa, - uint256 newCollateralFactorMantissa - ); - - /// @notice Emitted when liquidation incentive is changed by admin - event NewLiquidationIncentive( - uint256 oldLiquidationIncentiveMantissa, - uint256 newLiquidationIncentiveMantissa - ); - - /// @notice Emitted when maxAssets is changed by admin - event NewMaxAssets(uint256 oldMaxAssets, uint256 newMaxAssets); - - /// @notice Emitted when price oracle is changed - event NewPriceOracle( - PriceOracle oldPriceOracle, - PriceOracle newPriceOracle - ); - - /// @notice Emitted when pause guardian is changed - event NewPauseGuardian(address oldPauseGuardian, address newPauseGuardian); - - /// @notice Emitted when an action is paused globally - event ActionPaused(string action, bool pauseState); - - /// @notice Emitted when an action is paused on a market - event ActionPaused(CToken cToken, string action, bool pauseState); - - /// @notice Emitted when market comped status is changed - event MarketComped(CToken cToken, bool isComped); - - /// @notice Emitted when COMP rate is changed - event NewCompRate(uint256 oldCompRate, uint256 newCompRate); - - /// @notice Emitted when a new COMP speed is calculated for a market - event CompSpeedUpdated(CToken indexed cToken, uint256 newSpeed); - - /// @notice Emitted when COMP is distributed to a supplier - event DistributedSupplierComp( - CToken indexed cToken, - address indexed supplier, - uint256 compDelta, - uint256 compSupplyIndex - ); - - /// @notice Emitted when COMP is distributed to a borrower - event DistributedBorrowerComp( - CToken indexed cToken, - address indexed borrower, - uint256 compDelta, - uint256 compBorrowIndex - ); - - /// @notice The threshold above which the flywheel transfers COMP, in wei - uint256 public constant compClaimThreshold = 0.001e18; - - /// @notice The initial COMP index for a market - uint224 public constant compInitialIndex = 1e36; - - // closeFactorMantissa must be strictly greater than this value - uint256 internal constant closeFactorMinMantissa = 0.05e18; // 0.05 - - // closeFactorMantissa must not exceed this value - uint256 internal constant closeFactorMaxMantissa = 0.9e18; // 0.9 - - // No collateralFactorMantissa may exceed this value - uint256 internal constant collateralFactorMaxMantissa = 0.9e18; // 0.9 - - // liquidationIncentiveMantissa must be no less than this value - uint256 internal constant liquidationIncentiveMinMantissa = 1.0e18; // 1.0 - - // liquidationIncentiveMantissa must be no greater than this value - uint256 internal constant liquidationIncentiveMaxMantissa = 1.5e18; // 1.5 - - constructor() { - admin = msg.sender; - } - - /*** Assets You Are In ***/ - - /** - * @notice Returns the assets an account has entered - * @param account The address of the account to pull assets for - * @return A dynamic list with the assets the account has entered - */ - function getAssetsIn(address account) - external - view - returns (CToken[] memory) - { - CToken[] memory assetsIn = accountAssets[account]; - - return assetsIn; - } - - /** - * @notice Returns whether the given account is entered in the given asset - * @param account The address of the account to check - * @param cToken The cToken to check - * @return True if the account is in the asset, otherwise false. - */ - function checkMembership(address account, CToken cToken) - external - view - returns (bool) - { - return markets[address(cToken)].accountMembership[account]; - } - - /** - * @notice Add assets to be included in account liquidity calculation - * @param cTokens The list of addresses of the cToken markets to be enabled - * @return Success indicator for whether each corresponding market was entered - */ - function enterMarkets(address[] memory cTokens) - public - override - returns (uint256[] memory) - { - uint256 len = cTokens.length; - - uint256[] memory results = new uint256[](len); - for (uint256 i = 0; i < len; i++) { - CToken cToken = CToken(cTokens[i]); - - results[i] = uint256(addToMarketInternal(cToken, msg.sender)); - } - - return results; - } - - /** - * @notice Add the market to the borrower's "assets in" for liquidity calculations - * @param cToken The market to enter - * @param borrower The address of the account to modify - * @return Success indicator for whether the market was entered - */ - function addToMarketInternal(CToken cToken, address borrower) - internal - returns (Error) - { - Market storage marketToJoin = markets[address(cToken)]; - - if (!marketToJoin.isListed) { - // market is not listed, cannot join - return Error.MARKET_NOT_LISTED; - } - - if (marketToJoin.accountMembership[borrower] == true) { - // already joined - return Error.NO_ERROR; - } - - if (accountAssets[borrower].length >= maxAssets) { - // no space, cannot join - return Error.TOO_MANY_ASSETS; - } - - // survived the gauntlet, add to list - // NOTE: we store these somewhat redundantly as a significant optimization - // this avoids having to iterate through the list for the most common use cases - // that is, only when we need to perform liquidity checks - // and not whenever we want to check if an account is in a particular market - marketToJoin.accountMembership[borrower] = true; - accountAssets[borrower].push(cToken); - - emit MarketEntered(cToken, borrower); - - return Error.NO_ERROR; - } - - /** - * @notice Removes asset from sender's account liquidity calculation - * @dev Sender must not have an outstanding borrow balance in the asset, - * or be providing necessary collateral for an outstanding borrow. - * @param cTokenAddress The address of the asset to be removed - * @return Whether or not the account successfully exited the market - */ - function exitMarket(address cTokenAddress) - external - override - returns (uint256) - { - CToken cToken = CToken(cTokenAddress); - /* Get sender tokensHeld and amountOwed underlying from the cToken */ - (uint256 oErr, uint256 tokensHeld, uint256 amountOwed, ) = cToken - .getAccountSnapshot(msg.sender); - require(oErr == 0, "exitMarket: getAccountSnapshot failed"); // semi-opaque error code - - /* Fail if the sender has a borrow balance */ - if (amountOwed != 0) { - return - fail( - Error.NONZERO_BORROW_BALANCE, - FailureInfo.EXIT_MARKET_BALANCE_OWED - ); - } - - /* Fail if the sender is not permitted to redeem all of their tokens */ - uint256 allowed = redeemAllowedInternal( - cTokenAddress, - msg.sender, - tokensHeld - ); - if (allowed != 0) { - return - failOpaque( - Error.REJECTION, - FailureInfo.EXIT_MARKET_REJECTION, - allowed - ); - } - - Market storage marketToExit = markets[address(cToken)]; - - /* Return true if the sender is not already ‘in’ the market */ - if (!marketToExit.accountMembership[msg.sender]) { - return uint256(Error.NO_ERROR); - } - - /* Set cToken account membership to false */ - delete marketToExit.accountMembership[msg.sender]; - - /* Delete cToken from the account’s list of assets */ - // load into memory for faster iteration - CToken[] memory userAssetList = accountAssets[msg.sender]; - accountAssets[msg.sender] = new CToken[](0); - CToken[] storage newMarketList = accountAssets[msg.sender]; - uint256 len = userAssetList.length; - uint256 assetIndex = len; - for (uint256 i = 0; i < len; i++) { - if (userAssetList[i] == cToken) { - assetIndex = i; - continue; - } - newMarketList.push(userAssetList[i]); - } - - // We *must* have found the asset in the list or our redundant data structure is broken - assert(assetIndex < len); - - emit MarketExited(cToken, msg.sender); - - return uint256(Error.NO_ERROR); - } - - /*** Policy Hooks ***/ - - /** - * @notice Checks if the account should be allowed to mint tokens in the given market - * @param cToken The market to verify the mint against - * @param minter The account which would get the minted tokens - * @param mintAmount The amount of underlying being supplied to the market in exchange for tokens - * @return 0 if the mint is allowed, otherwise a semi-opaque error code (See ErrorReporter.sol) - */ - function mintAllowed( - address cToken, - address minter, - uint256 mintAmount - ) external override returns (uint256) { - // Pausing is a very serious situation - we revert to sound the alarms - require(!mintGuardianPaused[cToken], "mint is paused"); - - // Shh - currently unused - minter; - mintAmount; - - if (!markets[cToken].isListed) { - return uint256(Error.MARKET_NOT_LISTED); - } - - // Keep the flywheel moving - updateCompSupplyIndex(cToken); - distributeSupplierComp(cToken, minter, false); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Validates mint and reverts on rejection. May emit logs. - * @param cToken Asset being minted - * @param minter The address minting the tokens - * @param actualMintAmount The amount of the underlying asset being minted - * @param mintTokens The number of tokens being minted - */ - function mintVerify( - address cToken, - address minter, - uint256 actualMintAmount, - uint256 mintTokens - ) external override { - // Shh - currently unused - cToken; - minter; - actualMintAmount; - mintTokens; - - // Shh - we don't ever want this hook to be marked pure - if (false) { - maxAssets = maxAssets; - } - } - - /** - * @notice Checks if the account should be allowed to redeem tokens in the given market - * @param cToken The market to verify the redeem against - * @param redeemer The account which would redeem the tokens - * @param redeemTokens The number of cTokens to exchange for the underlying asset in the market - * @return 0 if the redeem is allowed, otherwise a semi-opaque error code (See ErrorReporter.sol) - */ - function redeemAllowed( - address cToken, - address redeemer, - uint256 redeemTokens - ) external override returns (uint256) { - uint256 allowed = redeemAllowedInternal(cToken, redeemer, redeemTokens); - if (allowed != uint256(Error.NO_ERROR)) { - return allowed; - } - - // Keep the flywheel moving - updateCompSupplyIndex(cToken); - distributeSupplierComp(cToken, redeemer, false); - - return uint256(Error.NO_ERROR); - } - - function redeemAllowedInternal( - address cToken, - address redeemer, - uint256 redeemTokens - ) internal view returns (uint256) { - if (!markets[cToken].isListed) { - return uint256(Error.MARKET_NOT_LISTED); - } - - /* If the redeemer is not 'in' the market, then we can bypass the liquidity check */ - if (!markets[cToken].accountMembership[redeemer]) { - return uint256(Error.NO_ERROR); - } - - /* Otherwise, perform a hypothetical liquidity check to guard against shortfall */ - ( - Error err, - , - uint256 shortfall - ) = getHypotheticalAccountLiquidityInternal( - redeemer, - CToken(cToken), - redeemTokens, - 0 - ); - if (err != Error.NO_ERROR) { - return uint256(err); - } - if (shortfall > 0) { - return uint256(Error.INSUFFICIENT_LIQUIDITY); - } - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Validates redeem and reverts on rejection. May emit logs. - * @param cToken Asset being redeemed - * @param redeemer The address redeeming the tokens - * @param redeemAmount The amount of the underlying asset being redeemed - * @param redeemTokens The number of tokens being redeemed - */ - function redeemVerify( - address cToken, - address redeemer, - uint256 redeemAmount, - uint256 redeemTokens - ) external pure override { - // Shh - currently unused - cToken; - redeemer; - - // Require tokens is zero or amount is also zero - if (redeemTokens == 0 && redeemAmount > 0) { - revert("redeemTokens zero"); - } - } - - /** - * @notice Checks if the account should be allowed to borrow the underlying asset of the given market - * @param cToken The market to verify the borrow against - * @param borrower The account which would borrow the asset - * @param borrowAmount The amount of underlying the account would borrow - * @return 0 if the borrow is allowed, otherwise a semi-opaque error code (See ErrorReporter.sol) - */ - function borrowAllowed( - address cToken, - address borrower, - uint256 borrowAmount - ) external override returns (uint256) { - // Pausing is a very serious situation - we revert to sound the alarms - Error err; - uint256 shortfall; - require(!borrowGuardianPaused[cToken], "borrow is paused"); - - if (!markets[cToken].isListed) { - return uint256(Error.MARKET_NOT_LISTED); - } - - if (!markets[cToken].accountMembership[borrower]) { - // only cTokens may call borrowAllowed if borrower not in market - require(msg.sender == cToken, "sender must be cToken"); - - // attempt to add borrower to the market - err = addToMarketInternal(CToken(msg.sender), borrower); - if (err != Error.NO_ERROR) { - return uint256(err); - } - - // it should be impossible to break the // important invariant - assert(markets[cToken].accountMembership[borrower]); - } - - if (oracle.getUnderlyingPrice(CToken(cToken)) == 0) { - return uint256(Error.PRICE_ERROR); - } - - (err, , shortfall) = getHypotheticalAccountLiquidityInternal( - borrower, - CToken(cToken), - 0, - borrowAmount - ); - if (err != Error.NO_ERROR) { - return uint256(err); - } - if (shortfall > 0) { - return uint256(Error.INSUFFICIENT_LIQUIDITY); - } - - // Keep the flywheel moving - Exp memory borrowIndex = Exp({mantissa: CToken(cToken).borrowIndex()}); - updateCompBorrowIndex(cToken, borrowIndex); - distributeBorrowerComp(cToken, borrower, borrowIndex, false); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Validates borrow and reverts on rejection. May emit logs. - * @param cToken Asset whose underlying is being borrowed - * @param borrower The address borrowing the underlying - * @param borrowAmount The amount of the underlying asset requested to borrow - */ - function borrowVerify( - address cToken, - address borrower, - uint256 borrowAmount - ) external override { - // Shh - currently unused - cToken; - borrower; - borrowAmount; - - // Shh - we don't ever want this hook to be marked pure - if (false) { - maxAssets = maxAssets; - } - } - - /** - * @notice Checks if the account should be allowed to repay a borrow in the given market - * @param cToken The market to verify the repay against - * @param payer The account which would repay the asset - * @param borrower The account which would borrowed the asset - * @param repayAmount The amount of the underlying asset the account would repay - * @return 0 if the repay is allowed, otherwise a semi-opaque error code (See ErrorReporter.sol) - */ - function repayBorrowAllowed( - address cToken, - address payer, - address borrower, - uint256 repayAmount - ) external override returns (uint256) { - // Shh - currently unused - payer; - borrower; - repayAmount; - - if (!markets[cToken].isListed) { - return uint256(Error.MARKET_NOT_LISTED); - } - - // Keep the flywheel moving - Exp memory borrowIndex = Exp({mantissa: CToken(cToken).borrowIndex()}); - updateCompBorrowIndex(cToken, borrowIndex); - distributeBorrowerComp(cToken, borrower, borrowIndex, false); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Validates repayBorrow and reverts on rejection. May emit logs. - * @param cToken Asset being repaid - * @param payer The address repaying the borrow - * @param borrower The address of the borrower - * @param actualRepayAmount The amount of underlying being repaid - */ - function repayBorrowVerify( - address cToken, - address payer, - address borrower, - uint256 actualRepayAmount, - uint256 borrowerIndex - ) external override { - // Shh - currently unused - cToken; - payer; - borrower; - actualRepayAmount; - borrowerIndex; - - // Shh - we don't ever want this hook to be marked pure - if (false) { - maxAssets = maxAssets; - } - } - - /** - * @notice Checks if the liquidation should be allowed to occur - * @param cTokenBorrowed Asset which was borrowed by the borrower - * @param cTokenCollateral Asset which was used as collateral and will be seized - * @param liquidator The address repaying the borrow and seizing the collateral - * @param borrower The address of the borrower - * @param repayAmount The amount of underlying being repaid - */ - function liquidateBorrowAllowed( - address cTokenBorrowed, - address cTokenCollateral, - address liquidator, - address borrower, - uint256 repayAmount - ) external view override returns (uint256) { - // Shh - currently unused - liquidator; - - if ( - !markets[cTokenBorrowed].isListed || - !markets[cTokenCollateral].isListed - ) { - return uint256(Error.MARKET_NOT_LISTED); - } - - /* The borrower must have shortfall in order to be liquidatable */ - (Error err, , uint256 shortfall) = getAccountLiquidityInternal( - borrower - ); - if (err != Error.NO_ERROR) { - return uint256(err); - } - if (shortfall == 0) { - return uint256(Error.INSUFFICIENT_SHORTFALL); - } - - /* The liquidator may not repay more than what is allowed by the closeFactor */ - uint256 borrowBalance = CToken(cTokenBorrowed).borrowBalanceStored( - borrower - ); - (MathError mathErr, uint256 maxClose) = mulScalarTruncate( - Exp({mantissa: closeFactorMantissa}), - borrowBalance - ); - if (mathErr != MathError.NO_ERROR) { - return uint256(Error.MATH_ERROR); - } - if (repayAmount > maxClose) { - return uint256(Error.TOO_MUCH_REPAY); - } - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Validates liquidateBorrow and reverts on rejection. May emit logs. - * @param cTokenBorrowed Asset which was borrowed by the borrower - * @param cTokenCollateral Asset which was used as collateral and will be seized - * @param liquidator The address repaying the borrow and seizing the collateral - * @param borrower The address of the borrower - * @param actualRepayAmount The amount of underlying being repaid - */ - function liquidateBorrowVerify( - address cTokenBorrowed, - address cTokenCollateral, - address liquidator, - address borrower, - uint256 actualRepayAmount, - uint256 seizeTokens - ) external override { - // Shh - currently unused - cTokenBorrowed; - cTokenCollateral; - liquidator; - borrower; - actualRepayAmount; - seizeTokens; - - // Shh - we don't ever want this hook to be marked pure - if (false) { - maxAssets = maxAssets; - } - } - - /** - * @notice Checks if the seizing of assets should be allowed to occur - * @param cTokenCollateral Asset which was used as collateral and will be seized - * @param cTokenBorrowed Asset which was borrowed by the borrower - * @param liquidator The address repaying the borrow and seizing the collateral - * @param borrower The address of the borrower - * @param seizeTokens The number of collateral tokens to seize - */ - function seizeAllowed( - address cTokenCollateral, - address cTokenBorrowed, - address liquidator, - address borrower, - uint256 seizeTokens - ) external override returns (uint256) { - // Pausing is a very serious situation - we revert to sound the alarms - require(!seizeGuardianPaused, "seize is paused"); - - // Shh - currently unused - seizeTokens; - - if ( - !markets[cTokenCollateral].isListed || - !markets[cTokenBorrowed].isListed - ) { - return uint256(Error.MARKET_NOT_LISTED); - } - - if ( - CToken(cTokenCollateral).comptroller() != - CToken(cTokenBorrowed).comptroller() - ) { - return uint256(Error.COMPTROLLER_MISMATCH); - } - - // Keep the flywheel moving - updateCompSupplyIndex(cTokenCollateral); - distributeSupplierComp(cTokenCollateral, borrower, false); - distributeSupplierComp(cTokenCollateral, liquidator, false); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Validates seize and reverts on rejection. May emit logs. - * @param cTokenCollateral Asset which was used as collateral and will be seized - * @param cTokenBorrowed Asset which was borrowed by the borrower - * @param liquidator The address repaying the borrow and seizing the collateral - * @param borrower The address of the borrower - * @param seizeTokens The number of collateral tokens to seize - */ - function seizeVerify( - address cTokenCollateral, - address cTokenBorrowed, - address liquidator, - address borrower, - uint256 seizeTokens - ) external override { - // Shh - currently unused - cTokenCollateral; - cTokenBorrowed; - liquidator; - borrower; - seizeTokens; - - // Shh - we don't ever want this hook to be marked pure - if (false) { - maxAssets = maxAssets; - } - } - - /** - * @notice Checks if the account should be allowed to transfer tokens in the given market - * @param cToken The market to verify the transfer against - * @param src The account which sources the tokens - * @param dst The account which receives the tokens - * @param transferTokens The number of cTokens to transfer - * @return 0 if the transfer is allowed, otherwise a semi-opaque error code (See ErrorReporter.sol) - */ - function transferAllowed( - address cToken, - address src, - address dst, - uint256 transferTokens - ) external override returns (uint256) { - // Pausing is a very serious situation - we revert to sound the alarms - require(!transferGuardianPaused, "transfer is paused"); - - // Currently the only consideration is whether or not - // the src is allowed to redeem this many tokens - uint256 allowed = redeemAllowedInternal(cToken, src, transferTokens); - if (allowed != uint256(Error.NO_ERROR)) { - return allowed; - } - - // Keep the flywheel moving - updateCompSupplyIndex(cToken); - distributeSupplierComp(cToken, src, false); - distributeSupplierComp(cToken, dst, false); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Validates transfer and reverts on rejection. May emit logs. - * @param cToken Asset being transferred - * @param src The account which sources the tokens - * @param dst The account which receives the tokens - * @param transferTokens The number of cTokens to transfer - */ - function transferVerify( - address cToken, - address src, - address dst, - uint256 transferTokens - ) external override { - // Shh - currently unused - cToken; - src; - dst; - transferTokens; - - // Shh - we don't ever want this hook to be marked pure - if (false) { - maxAssets = maxAssets; - } - } - - /*** Liquidity/Liquidation Calculations ***/ - - /** - * @dev Local vars for avoiding stack-depth limits in calculating account liquidity. - * Note that `cTokenBalance` is the number of cTokens the account owns in the market, - * whereas `borrowBalance` is the amount of underlying that the account has borrowed. - */ - struct AccountLiquidityLocalVars { - uint256 sumCollateral; - uint256 sumBorrowPlusEffects; - uint256 cTokenBalance; - uint256 borrowBalance; - uint256 exchangeRateMantissa; - uint256 oraclePriceMantissa; - Exp collateralFactor; - Exp exchangeRate; - Exp oraclePrice; - Exp tokensToDenom; - } - - /** - * @notice Determine the current account liquidity wrt collateral requirements - * @return (possible error code (semi-opaque), - account liquidity in excess of collateral requirements, - * account shortfall below collateral requirements) - */ - function getAccountLiquidity(address account) - public - view - returns ( - uint256, - uint256, - uint256 - ) - { - ( - Error err, - uint256 liquidity, - uint256 shortfall - ) = getHypotheticalAccountLiquidityInternal( - account, - CToken(address(0)), - 0, - 0 - ); - - return (uint256(err), liquidity, shortfall); - } - - /** - * @notice Determine the current account liquidity wrt collateral requirements - * @return (possible error code, - account liquidity in excess of collateral requirements, - * account shortfall below collateral requirements) - */ - function getAccountLiquidityInternal(address account) - internal - view - returns ( - Error, - uint256, - uint256 - ) - { - return - getHypotheticalAccountLiquidityInternal( - account, - CToken(address(0)), - 0, - 0 - ); - } - - /** - * @notice Determine what the account liquidity would be if the given amounts were redeemed/borrowed - * @param cTokenModify The market to hypothetically redeem/borrow in - * @param account The account to determine liquidity for - * @param redeemTokens The number of tokens to hypothetically redeem - * @param borrowAmount The amount of underlying to hypothetically borrow - * @return (possible error code (semi-opaque), - hypothetical account liquidity in excess of collateral requirements, - * hypothetical account shortfall below collateral requirements) - */ - function getHypotheticalAccountLiquidity( - address account, - address cTokenModify, - uint256 redeemTokens, - uint256 borrowAmount - ) - public - view - returns ( - uint256, - uint256, - uint256 - ) - { - ( - Error err, - uint256 liquidity, - uint256 shortfall - ) = getHypotheticalAccountLiquidityInternal( - account, - CToken(cTokenModify), - redeemTokens, - borrowAmount - ); - return (uint256(err), liquidity, shortfall); - } - - /** - * @notice Determine what the account liquidity would be if the given amounts were redeemed/borrowed - * @param cTokenModify The market to hypothetically redeem/borrow in - * @param account The account to determine liquidity for - * @param redeemTokens The number of tokens to hypothetically redeem - * @param borrowAmount The amount of underlying to hypothetically borrow - * @dev Note that we calculate the exchangeRateStored for each collateral cToken using stored data, - * without calculating accumulated interest. - * @return (possible error code, - hypothetical account liquidity in excess of collateral requirements, - * hypothetical account shortfall below collateral requirements) - */ - function getHypotheticalAccountLiquidityInternal( - address account, - CToken cTokenModify, - uint256 redeemTokens, - uint256 borrowAmount - ) - internal - view - returns ( - Error, - uint256, - uint256 - ) - { - AccountLiquidityLocalVars memory vars; // Holds all our calculation results - uint256 oErr; - MathError mErr; - - // For each asset the account is in - CToken[] memory assets = accountAssets[account]; - for (uint256 i = 0; i < assets.length; i++) { - CToken asset = assets[i]; - - // Read the balances and exchange rate from the cToken - ( - oErr, - vars.cTokenBalance, - vars.borrowBalance, - vars.exchangeRateMantissa - ) = asset.getAccountSnapshot(account); - if (oErr != 0) { - // semi-opaque error code, we assume NO_ERROR == 0 is invariant between upgrades - return (Error.SNAPSHOT_ERROR, 0, 0); - } - vars.collateralFactor = Exp({ - mantissa: markets[address(asset)].collateralFactorMantissa - }); - vars.exchangeRate = Exp({mantissa: vars.exchangeRateMantissa}); - - // Get the normalized price of the asset - vars.oraclePriceMantissa = oracle.getUnderlyingPrice(asset); - if (vars.oraclePriceMantissa == 0) { - return (Error.PRICE_ERROR, 0, 0); - } - vars.oraclePrice = Exp({mantissa: vars.oraclePriceMantissa}); - - // Pre-compute a conversion factor from tokens -> ether (normalized price value) - (mErr, vars.tokensToDenom) = mulExp3( - vars.collateralFactor, - vars.exchangeRate, - vars.oraclePrice - ); - if (mErr != MathError.NO_ERROR) { - return (Error.MATH_ERROR, 0, 0); - } - - // sumCollateral += tokensToDenom * cTokenBalance - (mErr, vars.sumCollateral) = mulScalarTruncateAddUInt( - vars.tokensToDenom, - vars.cTokenBalance, - vars.sumCollateral - ); - if (mErr != MathError.NO_ERROR) { - return (Error.MATH_ERROR, 0, 0); - } - - // sumBorrowPlusEffects += oraclePrice * borrowBalance - (mErr, vars.sumBorrowPlusEffects) = mulScalarTruncateAddUInt( - vars.oraclePrice, - vars.borrowBalance, - vars.sumBorrowPlusEffects - ); - if (mErr != MathError.NO_ERROR) { - return (Error.MATH_ERROR, 0, 0); - } - - // Calculate effects of interacting with cTokenModify - if (asset == cTokenModify) { - // redeem effect - // sumBorrowPlusEffects += tokensToDenom * redeemTokens - (mErr, vars.sumBorrowPlusEffects) = mulScalarTruncateAddUInt( - vars.tokensToDenom, - redeemTokens, - vars.sumBorrowPlusEffects - ); - if (mErr != MathError.NO_ERROR) { - return (Error.MATH_ERROR, 0, 0); - } - - // borrow effect - // sumBorrowPlusEffects += oraclePrice * borrowAmount - (mErr, vars.sumBorrowPlusEffects) = mulScalarTruncateAddUInt( - vars.oraclePrice, - borrowAmount, - vars.sumBorrowPlusEffects - ); - if (mErr != MathError.NO_ERROR) { - return (Error.MATH_ERROR, 0, 0); - } - } - } - - // These are safe, as the underflow condition is checked first - if (vars.sumCollateral > vars.sumBorrowPlusEffects) { - return ( - Error.NO_ERROR, - vars.sumCollateral - vars.sumBorrowPlusEffects, - 0 - ); - } else { - return ( - Error.NO_ERROR, - 0, - vars.sumBorrowPlusEffects - vars.sumCollateral - ); - } - } - - /** - * @notice Calculate number of tokens of collateral asset to seize given an underlying amount - * @dev Used in liquidation (called in cToken.liquidateBorrowFresh) - * @param cTokenBorrowed The address of the borrowed cToken - * @param cTokenCollateral The address of the collateral cToken - * @param actualRepayAmount The amount of cTokenBorrowed underlying to convert into cTokenCollateral tokens - * @return (errorCode, number of cTokenCollateral tokens to be seized in a liquidation) - */ - function liquidateCalculateSeizeTokens( - address cTokenBorrowed, - address cTokenCollateral, - uint256 actualRepayAmount - ) external view override returns (uint256, uint256) { - /* Read oracle prices for borrowed and collateral markets */ - uint256 priceBorrowedMantissa = oracle.getUnderlyingPrice( - CToken(cTokenBorrowed) - ); - uint256 priceCollateralMantissa = oracle.getUnderlyingPrice( - CToken(cTokenCollateral) - ); - if (priceBorrowedMantissa == 0 || priceCollateralMantissa == 0) { - return (uint256(Error.PRICE_ERROR), 0); - } - - /* - * Get the exchange rate and calculate the number of collateral tokens to seize: - * seizeAmount = actualRepayAmount * liquidationIncentive * priceBorrowed / priceCollateral - * seizeTokens = seizeAmount / exchangeRate - * = actualRepayAmount * (liquidationIncentive * priceBorrowed) / (priceCollateral * exchangeRate) - */ - uint256 exchangeRateMantissa = CToken(cTokenCollateral) - .exchangeRateStored(); // Note: reverts on error - uint256 seizeTokens; - Exp memory numerator; - Exp memory denominator; - Exp memory ratio; - MathError mathErr; - - (mathErr, numerator) = mulExp( - liquidationIncentiveMantissa, - priceBorrowedMantissa - ); - if (mathErr != MathError.NO_ERROR) { - return (uint256(Error.MATH_ERROR), 0); - } - - (mathErr, denominator) = mulExp( - priceCollateralMantissa, - exchangeRateMantissa - ); - if (mathErr != MathError.NO_ERROR) { - return (uint256(Error.MATH_ERROR), 0); - } - - (mathErr, ratio) = divExp(numerator, denominator); - if (mathErr != MathError.NO_ERROR) { - return (uint256(Error.MATH_ERROR), 0); - } - - (mathErr, seizeTokens) = mulScalarTruncate(ratio, actualRepayAmount); - if (mathErr != MathError.NO_ERROR) { - return (uint256(Error.MATH_ERROR), 0); - } - - return (uint256(Error.NO_ERROR), seizeTokens); - } - - /*** Admin Functions ***/ - - /** - * @notice Sets a new price oracle for the comptroller - * @dev Admin function to set a new price oracle - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setPriceOracle(PriceOracle newOracle) public returns (uint256) { - // Check caller is admin - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_PRICE_ORACLE_OWNER_CHECK - ); - } - - // Track the old oracle for the comptroller - PriceOracle oldOracle = oracle; - - // Set comptroller's oracle to newOracle - oracle = newOracle; - - // Emit NewPriceOracle(oldOracle, newOracle) - emit NewPriceOracle(oldOracle, newOracle); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Sets the closeFactor used when liquidating borrows - * @dev Admin function to set closeFactor - * @param newCloseFactorMantissa New close factor, scaled by 1e18 - * @return uint 0=success, otherwise a failure. (See ErrorReporter for details) - */ - function _setCloseFactor(uint256 newCloseFactorMantissa) - external - returns (uint256) - { - // Check caller is admin - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_CLOSE_FACTOR_OWNER_CHECK - ); - } - - Exp memory newCloseFactorExp = Exp({mantissa: newCloseFactorMantissa}); - Exp memory lowLimit = Exp({mantissa: closeFactorMinMantissa}); - if (lessThanOrEqualExp(newCloseFactorExp, lowLimit)) { - return - fail( - Error.INVALID_CLOSE_FACTOR, - FailureInfo.SET_CLOSE_FACTOR_VALIDATION - ); - } - - Exp memory highLimit = Exp({mantissa: closeFactorMaxMantissa}); - if (lessThanExp(highLimit, newCloseFactorExp)) { - return - fail( - Error.INVALID_CLOSE_FACTOR, - FailureInfo.SET_CLOSE_FACTOR_VALIDATION - ); - } - - uint256 oldCloseFactorMantissa = closeFactorMantissa; - closeFactorMantissa = newCloseFactorMantissa; - emit NewCloseFactor(oldCloseFactorMantissa, closeFactorMantissa); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Sets the collateralFactor for a market - * @dev Admin function to set per-market collateralFactor - * @param cToken The market to set the factor on - * @param newCollateralFactorMantissa The new collateral factor, scaled by 1e18 - * @return uint 0=success, otherwise a failure. (See ErrorReporter for details) - */ - function _setCollateralFactor( - CToken cToken, - uint256 newCollateralFactorMantissa - ) external returns (uint256) { - // Check caller is admin - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_COLLATERAL_FACTOR_OWNER_CHECK - ); - } - - // Verify market is listed - Market storage market = markets[address(cToken)]; - if (!market.isListed) { - return - fail( - Error.MARKET_NOT_LISTED, - FailureInfo.SET_COLLATERAL_FACTOR_NO_EXISTS - ); - } - - Exp memory newCollateralFactorExp = Exp({ - mantissa: newCollateralFactorMantissa - }); - - // Check collateral factor <= 0.9 - Exp memory highLimit = Exp({mantissa: collateralFactorMaxMantissa}); - if (lessThanExp(highLimit, newCollateralFactorExp)) { - return - fail( - Error.INVALID_COLLATERAL_FACTOR, - FailureInfo.SET_COLLATERAL_FACTOR_VALIDATION - ); - } - - // If collateral factor != 0, fail if price == 0 - if ( - newCollateralFactorMantissa != 0 && - oracle.getUnderlyingPrice(cToken) == 0 - ) { - return - fail( - Error.PRICE_ERROR, - FailureInfo.SET_COLLATERAL_FACTOR_WITHOUT_PRICE - ); - } - - // Set market's collateral factor to new collateral factor, remember old value - uint256 oldCollateralFactorMantissa = market.collateralFactorMantissa; - market.collateralFactorMantissa = newCollateralFactorMantissa; - - // Emit event with asset, old collateral factor, and new collateral factor - emit NewCollateralFactor( - cToken, - oldCollateralFactorMantissa, - newCollateralFactorMantissa - ); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Sets maxAssets which controls how many markets can be entered - * @dev Admin function to set maxAssets - * @param newMaxAssets New max assets - * @return uint 0=success, otherwise a failure. (See ErrorReporter for details) - */ - function _setMaxAssets(uint256 newMaxAssets) external returns (uint256) { - // Check caller is admin - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_MAX_ASSETS_OWNER_CHECK - ); - } - - uint256 oldMaxAssets = maxAssets; - maxAssets = newMaxAssets; - emit NewMaxAssets(oldMaxAssets, newMaxAssets); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Sets liquidationIncentive - * @dev Admin function to set liquidationIncentive - * @param newLiquidationIncentiveMantissa New liquidationIncentive scaled by 1e18 - * @return uint 0=success, otherwise a failure. (See ErrorReporter for details) - */ - function _setLiquidationIncentive(uint256 newLiquidationIncentiveMantissa) - external - returns (uint256) - { - // Check caller is admin - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_LIQUIDATION_INCENTIVE_OWNER_CHECK - ); - } - - // Check de-scaled min <= newLiquidationIncentive <= max - Exp memory newLiquidationIncentive = Exp({ - mantissa: newLiquidationIncentiveMantissa - }); - Exp memory minLiquidationIncentive = Exp({ - mantissa: liquidationIncentiveMinMantissa - }); - if (lessThanExp(newLiquidationIncentive, minLiquidationIncentive)) { - return - fail( - Error.INVALID_LIQUIDATION_INCENTIVE, - FailureInfo.SET_LIQUIDATION_INCENTIVE_VALIDATION - ); - } - - Exp memory maxLiquidationIncentive = Exp({ - mantissa: liquidationIncentiveMaxMantissa - }); - if (lessThanExp(maxLiquidationIncentive, newLiquidationIncentive)) { - return - fail( - Error.INVALID_LIQUIDATION_INCENTIVE, - FailureInfo.SET_LIQUIDATION_INCENTIVE_VALIDATION - ); - } - - // Save current value for use in log - uint256 oldLiquidationIncentiveMantissa = liquidationIncentiveMantissa; - - // Set liquidation incentive to new incentive - liquidationIncentiveMantissa = newLiquidationIncentiveMantissa; - - // Emit event with old incentive, new incentive - emit NewLiquidationIncentive( - oldLiquidationIncentiveMantissa, - newLiquidationIncentiveMantissa - ); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Add the market to the markets mapping and set it as listed - * @dev Admin function to set isListed and add support for the market - * @param cToken The address of the market (token) to list - * @return uint 0=success, otherwise a failure. (See enum Error for details) - */ - function _supportMarket(CToken cToken) external returns (uint256) { - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SUPPORT_MARKET_OWNER_CHECK - ); - } - - if (markets[address(cToken)].isListed) { - return - fail( - Error.MARKET_ALREADY_LISTED, - FailureInfo.SUPPORT_MARKET_EXISTS - ); - } - - cToken.isCToken(); // Sanity check to make sure its really a CToken - - Market storage market = markets[address(cToken)]; - market.isListed = true; - market.isComped = false; - market.collateralFactorMantissa = 0; - - _addMarketInternal(address(cToken)); - - emit MarketListed(cToken); - - return uint256(Error.NO_ERROR); - } - - function _addMarketInternal(address cToken) internal { - for (uint256 i = 0; i < allMarkets.length; i++) { - require(allMarkets[i] != CToken(cToken), "market already added"); - } - allMarkets.push(CToken(cToken)); - } - - /** - * @notice Admin function to change the Pause Guardian - * @param newPauseGuardian The address of the new Pause Guardian - * @return uint 0=success, otherwise a failure. (See enum Error for details) - */ - function _setPauseGuardian(address newPauseGuardian) - public - returns (uint256) - { - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_PAUSE_GUARDIAN_OWNER_CHECK - ); - } - - // Save current value for inclusion in log - address oldPauseGuardian = pauseGuardian; - - // Store pauseGuardian with value newPauseGuardian - pauseGuardian = newPauseGuardian; - - // Emit NewPauseGuardian(OldPauseGuardian, NewPauseGuardian) - emit NewPauseGuardian(oldPauseGuardian, pauseGuardian); - - return uint256(Error.NO_ERROR); - } - - function _setMintPaused(CToken cToken, bool state) public returns (bool) { - require( - markets[address(cToken)].isListed, - "cannot pause a market that is not listed" - ); - require( - msg.sender == pauseGuardian || msg.sender == admin, - "only pause guardian and admin can pause" - ); - require(msg.sender == admin || state == true, "only admin can unpause"); - - mintGuardianPaused[address(cToken)] = state; - emit ActionPaused(cToken, "Mint", state); - return state; - } - - function _setBorrowPaused(CToken cToken, bool state) public returns (bool) { - require( - markets[address(cToken)].isListed, - "cannot pause a market that is not listed" - ); - require( - msg.sender == pauseGuardian || msg.sender == admin, - "only pause guardian and admin can pause" - ); - require(msg.sender == admin || state == true, "only admin can unpause"); - - borrowGuardianPaused[address(cToken)] = state; - emit ActionPaused(cToken, "Borrow", state); - return state; - } - - function _setTransferPaused(bool state) public returns (bool) { - require( - msg.sender == pauseGuardian || msg.sender == admin, - "only pause guardian and admin can pause" - ); - require(msg.sender == admin || state == true, "only admin can unpause"); - - transferGuardianPaused = state; - emit ActionPaused("Transfer", state); - return state; - } - - function _setSeizePaused(bool state) public returns (bool) { - require( - msg.sender == pauseGuardian || msg.sender == admin, - "only pause guardian and admin can pause" - ); - require(msg.sender == admin || state == true, "only admin can unpause"); - - seizeGuardianPaused = state; - emit ActionPaused("Seize", state); - return state; - } - - function _become(Unitroller unitroller) public { - require( - msg.sender == unitroller.admin(), - "only unitroller admin can change brains" - ); - require( - unitroller._acceptImplementation() == 0, - "change not authorized" - ); - } - - /** - * @notice Checks caller is admin, or this contract is becoming the new implementation - */ - function adminOrInitializing() internal view returns (bool) { - return msg.sender == admin || msg.sender == comptrollerImplementation; - } - - /*** Comp Distribution ***/ - - /** - * @notice Recalculate and update COMP speeds for all COMP markets - */ - function refreshCompSpeeds() public { - require( - msg.sender == tx.origin, - "only externally owned accounts may refresh speeds" - ); - refreshCompSpeedsInternal(); - } - - function refreshCompSpeedsInternal() internal { - CToken[] memory allMarkets_ = allMarkets; - - for (uint256 i = 0; i < allMarkets_.length; i++) { - CToken cToken = allMarkets_[i]; - Exp memory borrowIndex = Exp({mantissa: cToken.borrowIndex()}); - updateCompSupplyIndex(address(cToken)); - updateCompBorrowIndex(address(cToken), borrowIndex); - } - - Exp memory totalUtility = Exp({mantissa: 0}); - Exp[] memory utilities = new Exp[](allMarkets_.length); - for (uint256 i = 0; i < allMarkets_.length; i++) { - CToken cToken = allMarkets_[i]; - if (markets[address(cToken)].isComped) { - Exp memory assetPrice = Exp({ - mantissa: oracle.getUnderlyingPrice(cToken) - }); - Exp memory utility = mul_(assetPrice, cToken.totalBorrows()); - utilities[i] = utility; - totalUtility = add_(totalUtility, utility); - } - } - - for (uint256 i = 0; i < allMarkets_.length; i++) { - CToken cToken = allMarkets[i]; - uint256 newSpeed = totalUtility.mantissa > 0 - ? mul_(compRate, div_(utilities[i], totalUtility)) - : 0; - compSpeeds[address(cToken)] = newSpeed; - emit CompSpeedUpdated(cToken, newSpeed); - } - } - - /** - * @notice Accrue COMP to the market by updating the supply index - * @param cToken The market whose supply index to update - */ - function updateCompSupplyIndex(address cToken) internal { - CompMarketState storage supplyState = compSupplyState[cToken]; - uint256 supplySpeed = compSpeeds[cToken]; - uint256 blockNumber = getBlockNumber(); - uint256 deltaBlocks = sub_(blockNumber, uint256(supplyState.block)); - if (deltaBlocks > 0 && supplySpeed > 0) { - uint256 supplyTokens = CToken(cToken).totalSupply(); - uint256 compAccrued = mul_(deltaBlocks, supplySpeed); - Double memory ratio = supplyTokens > 0 - ? fraction(compAccrued, supplyTokens) - : Double({mantissa: 0}); - Double memory index = add_( - Double({mantissa: supplyState.index}), - ratio - ); - compSupplyState[cToken] = CompMarketState({ - index: safe224(index.mantissa, "new index exceeds 224 bits"), - block: safe32(blockNumber, "block number exceeds 32 bits") - }); - } else if (deltaBlocks > 0) { - supplyState.block = safe32( - blockNumber, - "block number exceeds 32 bits" - ); - } - } - - /** - * @notice Accrue COMP to the market by updating the borrow index - * @param cToken The market whose borrow index to update - */ - function updateCompBorrowIndex(address cToken, Exp memory marketBorrowIndex) - internal - { - CompMarketState storage borrowState = compBorrowState[cToken]; - uint256 borrowSpeed = compSpeeds[cToken]; - uint256 blockNumber = getBlockNumber(); - uint256 deltaBlocks = sub_(blockNumber, uint256(borrowState.block)); - if (deltaBlocks > 0 && borrowSpeed > 0) { - uint256 borrowAmount = div_( - CToken(cToken).totalBorrows(), - marketBorrowIndex - ); - uint256 compAccrued = mul_(deltaBlocks, borrowSpeed); - Double memory ratio = borrowAmount > 0 - ? fraction(compAccrued, borrowAmount) - : Double({mantissa: 0}); - Double memory index = add_( - Double({mantissa: borrowState.index}), - ratio - ); - compBorrowState[cToken] = CompMarketState({ - index: safe224(index.mantissa, "new index exceeds 224 bits"), - block: safe32(blockNumber, "block number exceeds 32 bits") - }); - } else if (deltaBlocks > 0) { - borrowState.block = safe32( - blockNumber, - "block number exceeds 32 bits" - ); - } - } - - /** - * @notice Calculate COMP accrued by a supplier and possibly transfer it to them - * @param cToken The market in which the supplier is interacting - * @param supplier The address of the supplier to distribute COMP to - */ - function distributeSupplierComp( - address cToken, - address supplier, - bool distributeAll - ) internal { - CompMarketState storage supplyState = compSupplyState[cToken]; - Double memory supplyIndex = Double({mantissa: supplyState.index}); - Double memory supplierIndex = Double({ - mantissa: compSupplierIndex[cToken][supplier] - }); - compSupplierIndex[cToken][supplier] = supplyIndex.mantissa; - - if (supplierIndex.mantissa == 0 && supplyIndex.mantissa > 0) { - supplierIndex.mantissa = compInitialIndex; - } - - Double memory deltaIndex = sub_(supplyIndex, supplierIndex); - uint256 supplierTokens = CToken(cToken).balanceOf(supplier); - uint256 supplierDelta = mul_(supplierTokens, deltaIndex); - uint256 supplierAccrued = add_(compAccrued[supplier], supplierDelta); - compAccrued[supplier] = transferComp( - supplier, - supplierAccrued, - distributeAll ? 0 : compClaimThreshold - ); - emit DistributedSupplierComp( - CToken(cToken), - supplier, - supplierDelta, - supplyIndex.mantissa - ); - } - - /** - * @notice Calculate COMP accrued by a borrower and possibly transfer it to them - * @dev Borrowers will not begin to accrue until after the first interaction with the protocol. - * @param cToken The market in which the borrower is interacting - * @param borrower The address of the borrower to distribute COMP to - */ - function distributeBorrowerComp( - address cToken, - address borrower, - Exp memory marketBorrowIndex, - bool distributeAll - ) internal { - CompMarketState storage borrowState = compBorrowState[cToken]; - Double memory borrowIndex = Double({mantissa: borrowState.index}); - Double memory borrowerIndex = Double({ - mantissa: compBorrowerIndex[cToken][borrower] - }); - compBorrowerIndex[cToken][borrower] = borrowIndex.mantissa; - - if (borrowerIndex.mantissa > 0) { - Double memory deltaIndex = sub_(borrowIndex, borrowerIndex); - uint256 borrowerAmount = div_( - CToken(cToken).borrowBalanceStored(borrower), - marketBorrowIndex - ); - uint256 borrowerDelta = mul_(borrowerAmount, deltaIndex); - uint256 borrowerAccrued = add_( - compAccrued[borrower], - borrowerDelta - ); - compAccrued[borrower] = transferComp( - borrower, - borrowerAccrued, - distributeAll ? 0 : compClaimThreshold - ); - emit DistributedBorrowerComp( - CToken(cToken), - borrower, - borrowerDelta, - borrowIndex.mantissa - ); - } - } - - /** - * @notice Transfer TROP to the user, if they are above the threshold - * @dev Note: If there is not enough TROP, we do not perform the transfer all. - * @param user The address of the user to transfer TROP to - * @param userAccrued The amount of TROP to (possibly) transfer - * @return The amount of TROP which was NOT transferred to the user - */ - function transferComp( - address user, - uint256 userAccrued, - uint256 threshold - ) internal returns (uint256) { - if (userAccrued >= threshold && userAccrued > 0) { - TROP trop = TROP(getCompAddress()); - uint256 tropRemaining = trop.balanceOf(address(this)); - if (userAccrued <= tropRemaining) { - trop.transfer(user, userAccrued); - return 0; - } - } - return userAccrued; - } - - /** - * @notice Claim all the comp accrued by holder in all markets - * @param holder The address to claim COMP for - */ - function claimComp(address holder) public { - return claimComp(holder, allMarkets); - } - - /** - * @notice Claim all the comp accrued by holder in the specified markets - * @param holder The address to claim COMP for - * @param cTokens The list of markets to claim COMP in - */ - function claimComp(address holder, CToken[] memory cTokens) public { - address[] memory holders = new address[](1); - holders[0] = holder; - claimComp(holders, cTokens, true, true); - } - - /** - * @notice Claim all comp accrued by the holders - * @param holders The addresses to claim COMP for - * @param cTokens The list of markets to claim COMP in - * @param borrowers Whether or not to claim COMP earned by borrowing - * @param suppliers Whether or not to claim COMP earned by supplying - */ - function claimComp( - address[] memory holders, - CToken[] memory cTokens, - bool borrowers, - bool suppliers - ) public { - for (uint256 i = 0; i < cTokens.length; i++) { - CToken cToken = cTokens[i]; - require(markets[address(cToken)].isListed, "market must be listed"); - if (borrowers == true) { - Exp memory borrowIndex = Exp({mantissa: cToken.borrowIndex()}); - updateCompBorrowIndex(address(cToken), borrowIndex); - for (uint256 j = 0; j < holders.length; j++) { - distributeBorrowerComp( - address(cToken), - holders[j], - borrowIndex, - true - ); - } - } - if (suppliers == true) { - updateCompSupplyIndex(address(cToken)); - for (uint256 j = 0; j < holders.length; j++) { - distributeSupplierComp(address(cToken), holders[j], true); - } - } - } - } - - /*** Comp Distribution Admin ***/ - - /** - * @notice Set the amount of COMP distributed per block - * @param compRate_ The amount of COMP wei per block to distribute - */ - function _setCompRate(uint256 compRate_) public { - require(adminOrInitializing(), "only admin can change comp rate"); - - uint256 oldRate = compRate; - compRate = compRate_; - emit NewCompRate(oldRate, compRate_); - - refreshCompSpeedsInternal(); - } - - /** - * @notice Add markets to compMarkets, allowing them to earn COMP in the flywheel - * @param cTokens The addresses of the markets to add - */ - function _addCompMarkets(address[] memory cTokens) public { - require(adminOrInitializing(), "only admin can add comp market"); - - for (uint256 i = 0; i < cTokens.length; i++) { - _addCompMarketInternal(cTokens[i]); - } - - refreshCompSpeedsInternal(); - } - - function _addCompMarketInternal(address cToken) internal { - Market storage market = markets[cToken]; - require(market.isListed == true, "comp market is not listed"); - require(market.isComped == false, "comp market already added"); - - market.isComped = true; - emit MarketComped(CToken(cToken), true); - - if ( - compSupplyState[cToken].index == 0 && - compSupplyState[cToken].block == 0 - ) { - compSupplyState[cToken] = CompMarketState({ - index: compInitialIndex, - block: safe32(getBlockNumber(), "block number exceeds 32 bits") - }); - } - - if ( - compBorrowState[cToken].index == 0 && - compBorrowState[cToken].block == 0 - ) { - compBorrowState[cToken] = CompMarketState({ - index: compInitialIndex, - block: safe32(getBlockNumber(), "block number exceeds 32 bits") - }); - } - } - - /** - * @notice Remove a market from compMarkets, preventing it from earning COMP in the flywheel - * @param cToken The address of the market to drop - */ - function _dropCompMarket(address cToken) public { - require(msg.sender == admin, "only admin can drop comp market"); - - Market storage market = markets[cToken]; - require(market.isComped == true, "market is not a comp market"); - - market.isComped = false; - emit MarketComped(CToken(cToken), false); - - refreshCompSpeedsInternal(); - } - - /** - * @notice Return all of the markets - * @dev The automatic getter may be used to access an individual market. - * @return The list of market addresses - */ - function getAllMarkets() public view returns (CToken[] memory) { - return allMarkets; - } - - function getBlockNumber() public view returns (uint256) { - return block.number; - } - - /** - * @notice Return the address of the COMP token - * @return The address of COMP - */ - function getCompAddress() public pure returns (address) { - return 0xc00e94Cb662C3520282E6f5717214004A7f26888; - } -} diff --git a/flatten/ComptrollerG5.sol b/flatten/ComptrollerG5.sol deleted file mode 100644 index d0c42cf..0000000 --- a/flatten/ComptrollerG5.sol +++ /dev/null @@ -1,6607 +0,0 @@ -// Dependency file: contracts/ComptrollerInterface.sol - -// SPDX-License-Identifier: UNLICENSED -// pragma solidity 0.8.6; - -abstract contract ComptrollerInterface { - /// @notice Indicator that this is a Comptroller contract (for inspection) - bool public constant isComptroller = true; - - /*** Assets You Are In ***/ - - function enterMarkets(address[] calldata cTokens) - external - virtual - returns (uint256[] memory); - - function exitMarket(address cToken) external virtual returns (uint256); - - /*** Policy Hooks ***/ - - function mintAllowed( - address cToken, - address minter, - uint256 mintAmount - ) external virtual returns (uint256); - - function mintVerify( - address cToken, - address minter, - uint256 mintAmount, - uint256 mintTokens - ) external virtual; - - function redeemAllowed( - address cToken, - address redeemer, - uint256 redeemTokens - ) external virtual returns (uint256); - - function redeemVerify( - address cToken, - address redeemer, - uint256 redeemAmount, - uint256 redeemTokens - ) external virtual; - - function borrowAllowed( - address cToken, - address borrower, - uint256 borrowAmount - ) external virtual returns (uint256); - - function borrowVerify( - address cToken, - address borrower, - uint256 borrowAmount - ) external virtual; - - function repayBorrowAllowed( - address cToken, - address payer, - address borrower, - uint256 repayAmount - ) external virtual returns (uint256); - - function repayBorrowVerify( - address cToken, - address payer, - address borrower, - uint256 repayAmount, - uint256 borrowerIndex - ) external virtual; - - function liquidateBorrowAllowed( - address cTokenBorrowed, - address cTokenCollateral, - address liquidator, - address borrower, - uint256 repayAmount - ) external virtual returns (uint256); - - function liquidateBorrowVerify( - address cTokenBorrowed, - address cTokenCollateral, - address liquidator, - address borrower, - uint256 repayAmount, - uint256 seizeTokens - ) external virtual; - - function seizeAllowed( - address cTokenCollateral, - address cTokenBorrowed, - address liquidator, - address borrower, - uint256 seizeTokens - ) external virtual returns (uint256); - - function seizeVerify( - address cTokenCollateral, - address cTokenBorrowed, - address liquidator, - address borrower, - uint256 seizeTokens - ) external virtual; - - function transferAllowed( - address cToken, - address src, - address dst, - uint256 transferTokens - ) external virtual returns (uint256); - - function transferVerify( - address cToken, - address src, - address dst, - uint256 transferTokens - ) external virtual; - - /*** Liquidity/Liquidation Calculations ***/ - - function liquidateCalculateSeizeTokens( - address cTokenBorrowed, - address cTokenCollateral, - uint256 repayAmount - ) external view virtual returns (uint256, uint256); -} - - -// Dependency file: contracts/CarefulMath.sol - -// pragma solidity 0.8.6; - -/** - * @title Careful Math - * @author tropykus - * @notice Derived from OpenZeppelin's SafeMath library - * https://github.com/OpenZeppelin/openzeppelin-solidity/blob/master/contracts/math/SafeMath.sol - */ -contract CarefulMath { - - /** - * @dev Possible error codes that we can return - */ - enum MathError { - NO_ERROR, - DIVISION_BY_ZERO, - INTEGER_OVERFLOW, - INTEGER_UNDERFLOW - } - - /** - * @dev Multiplies two numbers, returns an error on overflow. - */ - function mulUInt(uint a, uint b) internal pure returns (MathError, uint) { - if (a == 0) { - return (MathError.NO_ERROR, 0); - } - - uint c = a * b; - - if (c / a != b) { - return (MathError.INTEGER_OVERFLOW, 0); - } else { - return (MathError.NO_ERROR, c); - } - } - - /** - * @dev Integer division of two numbers, truncating the quotient. - */ - function divUInt(uint a, uint b) internal pure returns (MathError, uint) { - if (b == 0) { - return (MathError.DIVISION_BY_ZERO, 0); - } - - return (MathError.NO_ERROR, a / b); - } - - /** - * @dev Subtracts two numbers, returns an error on overflow (i.e. if subtrahend is greater than minuend). - */ - function subUInt(uint a, uint b) internal pure returns (MathError, uint) { - if (b <= a) { - return (MathError.NO_ERROR, a - b); - } else { - return (MathError.INTEGER_UNDERFLOW, 0); - } - } - - /** - * @dev Adds two numbers, returns an error on overflow. - */ - function addUInt(uint a, uint b) internal pure returns (MathError, uint) { - uint c = a + b; - - if (c >= a) { - return (MathError.NO_ERROR, c); - } else { - return (MathError.INTEGER_OVERFLOW, 0); - } - } - - /** - * @dev add a and b and then subtract c - */ - function addThenSubUInt(uint a, uint b, uint c) internal pure returns (MathError, uint) { - (MathError err0, uint sum) = addUInt(a, b); - - if (err0 != MathError.NO_ERROR) { - return (err0, 0); - } - - return subUInt(sum, c); - } -} - - -// Dependency file: contracts/ExponentialNoError.sol - -// pragma solidity 0.8.6; - -/** - * @title Exponential module for storing fixed-precision decimals - * @author tropykus - * @notice Exp is a struct which stores decimals with a fixed precision of 18 decimal places. - * Thus, if we wanted to store the 5.1, mantissa would store 5.1e18. That is: - * `Exp({mantissa: 5100000000000000000})`. - */ -contract ExponentialNoError { - uint constant expScale = 1e18; - uint constant doubleScale = 1e36; - uint constant halfExpScale = expScale/2; - uint constant mantissaOne = expScale; - - struct Exp { - uint mantissa; - } - - struct Double { - uint mantissa; - } - - /** - * @dev Truncates the given exp to a whole number value. - * For example, truncate(Exp{mantissa: 15 * expScale}) = 15 - */ - function truncate(Exp memory exp) pure internal returns (uint) { - // Note: We are not using careful math here as we're performing a division that cannot fail - return exp.mantissa / expScale; - } - - /** - * @dev Multiply an Exp by a scalar, then truncate to return an unsigned integer. - */ - function mul_ScalarTruncate(Exp memory a, uint scalar) pure internal returns (uint) { - Exp memory product = mul_(a, scalar); - return truncate(product); - } - - /** - * @dev Multiply an Exp by a scalar, truncate, then add an to an unsigned integer, returning an unsigned integer. - */ - function mul_ScalarTruncateAddUInt(Exp memory a, uint scalar, uint addend) pure internal returns (uint) { - Exp memory product = mul_(a, scalar); - return add_(truncate(product), addend); - } - - /** - * @dev Checks if first Exp is less than second Exp. - */ - function lessThanExp(Exp memory left, Exp memory right) pure internal returns (bool) { - return left.mantissa < right.mantissa; - } - - /** - * @dev Checks if left Exp <= right Exp. - */ - function lessThanOrEqualExp(Exp memory left, Exp memory right) pure internal returns (bool) { - return left.mantissa <= right.mantissa; - } - - /** - * @dev Checks if left Exp > right Exp. - */ - function greaterThanExp(Exp memory left, Exp memory right) pure internal returns (bool) { - return left.mantissa > right.mantissa; - } - - /** - * @dev returns true if Exp is exactly zero - */ - function isZeroExp(Exp memory value) pure internal returns (bool) { - return value.mantissa == 0; - } - - function safe224(uint n, string memory errorMessage) pure internal returns (uint224) { - require(n < 2**224, errorMessage); - return uint224(n); - } - - function safe32(uint n, string memory errorMessage) pure internal returns (uint32) { - require(n < 2**32, errorMessage); - return uint32(n); - } - - function add_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { - return Exp({mantissa: add_(a.mantissa, b.mantissa)}); - } - - function add_(Double memory a, Double memory b) pure internal returns (Double memory) { - return Double({mantissa: add_(a.mantissa, b.mantissa)}); - } - - function add_(uint a, uint b) pure internal returns (uint) { - return add_(a, b, "addition overflow"); - } - - function add_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { - uint c = a + b; - require(c >= a, errorMessage); - return c; - } - - function sub_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { - return Exp({mantissa: sub_(a.mantissa, b.mantissa)}); - } - - function sub_(Double memory a, Double memory b) pure internal returns (Double memory) { - return Double({mantissa: sub_(a.mantissa, b.mantissa)}); - } - - function sub_(uint a, uint b) pure internal returns (uint) { - return sub_(a, b, "subtraction underflow"); - } - - function sub_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { - require(b <= a, errorMessage); - return a - b; - } - - function mul_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { - return Exp({mantissa: mul_(a.mantissa, b.mantissa) / expScale}); - } - - function mul_(Exp memory a, uint b) pure internal returns (Exp memory) { - return Exp({mantissa: mul_(a.mantissa, b)}); - } - - function mul_(uint a, Exp memory b) pure internal returns (uint) { - return mul_(a, b.mantissa) / expScale; - } - - function mul_(Double memory a, Double memory b) pure internal returns (Double memory) { - return Double({mantissa: mul_(a.mantissa, b.mantissa) / doubleScale}); - } - - function mul_(Double memory a, uint b) pure internal returns (Double memory) { - return Double({mantissa: mul_(a.mantissa, b)}); - } - - function mul_(uint a, Double memory b) pure internal returns (uint) { - return mul_(a, b.mantissa) / doubleScale; - } - - function mul_(uint a, uint b) pure internal returns (uint) { - return mul_(a, b, "multiplication overflow"); - } - - function mul_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { - if (a == 0 || b == 0) { - return 0; - } - uint c = a * b; - require(c / a == b, errorMessage); - return c; - } - - function div_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { - return Exp({mantissa: div_(mul_(a.mantissa, expScale), b.mantissa)}); - } - - function div_(Exp memory a, uint b) pure internal returns (Exp memory) { - return Exp({mantissa: div_(a.mantissa, b)}); - } - - function div_(uint a, Exp memory b) pure internal returns (uint) { - return div_(mul_(a, expScale), b.mantissa); - } - - function div_(Double memory a, Double memory b) pure internal returns (Double memory) { - return Double({mantissa: div_(mul_(a.mantissa, doubleScale), b.mantissa)}); - } - - function div_(Double memory a, uint b) pure internal returns (Double memory) { - return Double({mantissa: div_(a.mantissa, b)}); - } - - function div_(uint a, Double memory b) pure internal returns (uint) { - return div_(mul_(a, doubleScale), b.mantissa); - } - - function div_(uint a, uint b) pure internal returns (uint) { - return div_(a, b, "divide by zero"); - } - - function div_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { - require(b > 0, errorMessage); - return a / b; - } - - function fraction(uint a, uint b) pure internal returns (Double memory) { - return Double({mantissa: div_(mul_(a, doubleScale), b)}); - } -} - - -// Dependency file: contracts/Exponential.sol - -// pragma solidity 0.8.6; - -// import "contracts/CarefulMath.sol"; -// import "contracts/ExponentialNoError.sol"; - -/** - * @title Exponential module for storing fixed-precision decimals - * @author tropykus - * @dev Legacy contract for compatibility reasons with existing contracts that still use MathError - * @notice Exp is a struct which stores decimals with a fixed precision of 18 decimal places. - * Thus, if we wanted to store the 5.1, mantissa would store 5.1e18. That is: - * `Exp({mantissa: 5100000000000000000})`. - */ -contract Exponential is CarefulMath, ExponentialNoError { - /** - * @dev Creates an exponential from numerator and denominator values. - * Note: Returns an error if (`num` * 10e18) > MAX_INT, - * or if `denom` is zero. - */ - function getExp(uint num, uint denom) internal pure returns (MathError, Exp memory) { - (MathError err0, uint scaledNumerator) = mulUInt(num, expScale); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - - (MathError err1, uint rational) = divUInt(scaledNumerator, denom); - if (err1 != MathError.NO_ERROR) { - return (err1, Exp({mantissa: 0})); - } - - return (MathError.NO_ERROR, Exp({mantissa: rational})); - } - - /** - * @dev Adds two exponentials, returning a new exponential. - */ - function addExp(Exp memory a, Exp memory b) internal pure returns (MathError, Exp memory) { - (MathError error, uint result) = addUInt(a.mantissa, b.mantissa); - - return (error, Exp({mantissa: result})); - } - - /** - * @dev Subtracts two exponentials, returning a new exponential. - */ - function subExp(Exp memory a, Exp memory b) internal pure returns (MathError, Exp memory) { - (MathError error, uint result) = subUInt(a.mantissa, b.mantissa); - - return (error, Exp({mantissa: result})); - } - - /** - * @dev Multiply an Exp by a scalar, returning a new Exp. - */ - function mulScalar(Exp memory a, uint scalar) internal pure returns (MathError, Exp memory) { - (MathError err0, uint scaledMantissa) = mulUInt(a.mantissa, scalar); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - - return (MathError.NO_ERROR, Exp({mantissa: scaledMantissa})); - } - - /** - * @dev Multiply an Exp by a scalar, then truncate to return an unsigned integer. - */ - function mulScalarTruncate(Exp memory a, uint scalar) internal pure returns (MathError, uint) { - (MathError err, Exp memory product) = mulScalar(a, scalar); - if (err != MathError.NO_ERROR) { - return (err, 0); - } - - return (MathError.NO_ERROR, truncate(product)); - } - - /** - * @dev Multiply an Exp by a scalar, truncate, then add an to an unsigned integer, returning an unsigned integer. - */ - function mulScalarTruncateAddUInt(Exp memory a, uint scalar, uint addend) internal pure returns (MathError, uint) { - (MathError err, Exp memory product) = mulScalar(a, scalar); - if (err != MathError.NO_ERROR) { - return (err, 0); - } - - return addUInt(truncate(product), addend); - } - - /** - * @dev Divide an Exp by a scalar, returning a new Exp. - */ - function divScalar(Exp memory a, uint scalar) internal pure returns (MathError, Exp memory) { - (MathError err0, uint descaledMantissa) = divUInt(a.mantissa, scalar); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - - return (MathError.NO_ERROR, Exp({mantissa: descaledMantissa})); - } - - /** - * @dev Divide a scalar by an Exp, returning a new Exp. - */ - function divScalarByExp(uint scalar, Exp memory divisor) internal pure returns (MathError, Exp memory) { - /* - We are doing this as: - getExp(mulUInt(expScale, scalar), divisor.mantissa) - - How it works: - Exp = a / b; - Scalar = s; - `s / (a / b)` = `b * s / a` and since for an Exp `a = mantissa, b = expScale` - */ - (MathError err0, uint numerator) = mulUInt(expScale, scalar); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - return getExp(numerator, divisor.mantissa); - } - - /** - * @dev Divide a scalar by an Exp, then truncate to return an unsigned integer. - */ - function divScalarByExpTruncate(uint scalar, Exp memory divisor) internal pure returns (MathError, uint) { - (MathError err, Exp memory fraction) = divScalarByExp(scalar, divisor); - if (err != MathError.NO_ERROR) { - return (err, 0); - } - - return (MathError.NO_ERROR, truncate(fraction)); - } - - /** - * @dev Multiplies two exponentials, returning a new exponential. - */ - function mulExp(Exp memory a, Exp memory b) internal pure returns (MathError, Exp memory) { - - (MathError err0, uint doubleScaledProduct) = mulUInt(a.mantissa, b.mantissa); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - - // We add half the scale before dividing so that we get rounding instead of truncation. - // See "Listing 6" and text above it at https://accu.org/index.php/journals/1717 - // Without this change, a result like 6.6...e-19 will be truncated to 0 instead of being rounded to 1e-18. - (MathError err1, uint doubleScaledProductWithHalfScale) = addUInt(halfExpScale, doubleScaledProduct); - if (err1 != MathError.NO_ERROR) { - return (err1, Exp({mantissa: 0})); - } - - (MathError err2, uint product) = divUInt(doubleScaledProductWithHalfScale, expScale); - // The only error `div` can return is MathError.DIVISION_BY_ZERO but we control `expScale` and it is not zero. - assert(err2 == MathError.NO_ERROR); - - return (MathError.NO_ERROR, Exp({mantissa: product})); - } - - /** - * @dev Multiplies two exponentials given their mantissas, returning a new exponential. - */ - function mulExp(uint a, uint b) internal pure returns (MathError, Exp memory) { - return mulExp(Exp({mantissa: a}), Exp({mantissa: b})); - } - - /** - * @dev Multiplies three exponentials, returning a new exponential. - */ - function mulExp3(Exp memory a, Exp memory b, Exp memory c) internal pure returns (MathError, Exp memory) { - (MathError err, Exp memory ab) = mulExp(a, b); - if (err != MathError.NO_ERROR) { - return (err, ab); - } - return mulExp(ab, c); - } - - /** - * @dev Divides two exponentials, returning a new exponential. - * (a/scale) / (b/scale) = (a/scale) * (scale/b) = a/b, - * which we can scale as an Exp by calling getExp(a.mantissa, b.mantissa) - */ - function divExp(Exp memory a, Exp memory b) internal pure returns (MathError, Exp memory) { - return getExp(a.mantissa, b.mantissa); - } -} - - -// Dependency file: contracts/SafeMath.sol - -// pragma solidity 0.8.6; - -// From https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/math/Math.sol -// Subject to the MIT license. - -/** - * @dev Wrappers over Solidity's arithmetic operations with added overflow - * checks. - * - * Arithmetic operations in Solidity wrap on overflow. This can easily result - * in bugs, because programmers usually assume that an overflow raises an - * error, which is the standard behavior in high level programming languages. - * `SafeMath` restores this intuition by reverting the transaction when an - * operation overflows. - * - * Using this library instead of the unchecked operations eliminates an entire - * class of bugs, so it's recommended to use it always. - */ -library SafeMath { - /** - * @dev Returns the addition of two unsigned integers, reverting on overflow. - * - * Counterpart to Solidity's `+` operator. - * - * Requirements: - * - Addition cannot overflow. - */ - function add(uint256 a, uint256 b) internal pure returns (uint256) { - uint256 c = a + b; - require(c >= a, "SafeMath: addition overflow"); - - return c; - } - - /** - * @dev Returns the addition of two unsigned integers, reverting with custom message on overflow. - * - * Counterpart to Solidity's `+` operator. - * - * Requirements: - * - Addition cannot overflow. - */ - function add(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - uint256 c = a + b; - require(c >= a, errorMessage); - - return c; - } - - /** - * @dev Returns the subtraction of two unsigned integers, reverting on underflow (when the result is negative). - * - * Counterpart to Solidity's `-` operator. - * - * Requirements: - * - Subtraction cannot underflow. - */ - function sub(uint256 a, uint256 b) internal pure returns (uint256) { - return sub(a, b, "SafeMath: subtraction underflow"); - } - - /** - * @dev Returns the subtraction of two unsigned integers, reverting with custom message on underflow (when the result is negative). - * - * Counterpart to Solidity's `-` operator. - * - * Requirements: - * - Subtraction cannot underflow. - */ - function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - require(b <= a, errorMessage); - uint256 c = a - b; - - return c; - } - - /** - * @dev Returns the multiplication of two unsigned integers, reverting on overflow. - * - * Counterpart to Solidity's `*` operator. - * - * Requirements: - * - Multiplication cannot overflow. - */ - function mul(uint256 a, uint256 b) internal pure returns (uint256) { - // Gas optimization: this is cheaper than requiring 'a' not being zero, but the - // benefit is lost if 'b' is also tested. - // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 - if (a == 0) { - return 0; - } - - uint256 c = a * b; - require(c / a == b, "SafeMath: multiplication overflow"); - - return c; - } - - /** - * @dev Returns the multiplication of two unsigned integers, reverting on overflow. - * - * Counterpart to Solidity's `*` operator. - * - * Requirements: - * - Multiplication cannot overflow. - */ - function mul(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - // Gas optimization: this is cheaper than requiring 'a' not being zero, but the - // benefit is lost if 'b' is also tested. - // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 - if (a == 0) { - return 0; - } - - uint256 c = a * b; - require(c / a == b, errorMessage); - - return c; - } - - /** - * @dev Returns the integer division of two unsigned integers. - * Reverts on division by zero. The result is rounded towards zero. - * - * Counterpart to Solidity's `/` operator. Note: this function uses a - * `revert` opcode (which leaves remaining gas untouched) while Solidity - * uses an invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function div(uint256 a, uint256 b) internal pure returns (uint256) { - return div(a, b, "SafeMath: division by zero"); - } - - /** - * @dev Returns the integer division of two unsigned integers. - * Reverts with custom message on division by zero. The result is rounded towards zero. - * - * Counterpart to Solidity's `/` operator. Note: this function uses a - * `revert` opcode (which leaves remaining gas untouched) while Solidity - * uses an invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - // Solidity only automatically asserts when dividing by 0 - require(b > 0, errorMessage); - uint256 c = a / b; - // assert(a == b * c + a % b); // There is no case in which this doesn't hold - - return c; - } - - /** - * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), - * Reverts when dividing by zero. - * - * Counterpart to Solidity's `%` operator. This function uses a `revert` - * opcode (which leaves remaining gas untouched) while Solidity uses an - * invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function mod(uint256 a, uint256 b) internal pure returns (uint256) { - return mod(a, b, "SafeMath: modulo by zero"); - } - - /** - * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), - * Reverts with custom message when dividing by zero. - * - * Counterpart to Solidity's `%` operator. This function uses a `revert` - * opcode (which leaves remaining gas untouched) while Solidity uses an - * invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - require(b != 0, errorMessage); - return a % b; - } -} - - -// Dependency file: contracts/InterestRateModel.sol - -// pragma solidity 0.8.6; - -// import "contracts/Exponential.sol"; -// import "contracts/SafeMath.sol"; - -/** - * @title tropykus InterestRateModel Interface - * @author tropykus - */ -abstract contract InterestRateModel is Exponential { - using SafeMath for uint256; - - /// @notice Indicator that this is an InterestRateModel contract (for inspection) - bool public constant isInterestRateModel = true; - bool public isTropykusInterestRateModel; - - /** - * @notice The approximate number of blocks per year that is assumed by the interest rate model - */ - uint256 public constant blocksPerYear = 1051200; - - /** - * @notice Calculates the utilization rate of the market: `borrows / (cash + borrows - reserves)` - * @param cash The amount of cash in the market - * @param borrows The amount of borrows in the market - * @param reserves The amount of reserves in the market (currently unused) - * @return The utilization rate as a mantissa between [0, 1e18] - */ - function utilizationRate( - uint256 cash, - uint256 borrows, - uint256 reserves - ) public pure virtual returns (uint256) { - // Utilization rate is 0 when there are no borrows - if (borrows == 0) { - return 0; - } - - return borrows.mul(1e18).div(cash.add(borrows).sub(reserves)); - } - - /** - * @notice Calculates the current borrow interest rate per block - * @param cash The total amount of cash the market has - * @param borrows The total amount of borrows the market has outstanding - * @param reserves The total amnount of reserves the market has - * @return The borrow rate per block (as a percentage, and scaled by 1e18) - */ - function getBorrowRate( - uint256 cash, - uint256 borrows, - uint256 reserves - ) external view virtual returns (uint256); - - /** - * @notice Calculates the current supply interest rate per block - * @param cash The total amount of cash the market has - * @param borrows The total amount of borrows the market has outstanding - * @param reserves The total amnount of reserves the market has - * @param reserveFactorMantissa The current reserve factor the market has - * @return The supply rate per block (as a percentage, and scaled by 1e18) - */ - function getSupplyRate( - uint256 cash, - uint256 borrows, - uint256 reserves, - uint256 reserveFactorMantissa - ) external view virtual returns (uint256); - - function getExchangeRate( - uint256 _totalCash, - uint256 _totalBorrows, - uint256 _totalReserves, - uint256 _totalSupply - ) public pure returns (MathError, uint256) { - /* - * exchangeRate = (totalCash + totalBorrows - totalReserves) / totalSupply - */ - Exp memory exchangeRate; - MathError mathErr; - uint256 cashPlusBorrowsMinusReserves; - (mathErr, cashPlusBorrowsMinusReserves) = addThenSubUInt( - _totalCash, - _totalBorrows, - _totalReserves - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - (mathErr, exchangeRate) = getExp( - cashPlusBorrowsMinusReserves, - _totalSupply - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - - return (MathError.NO_ERROR, exchangeRate.mantissa); - } - - function isAboveOptimal( - uint256 cash, - uint256 borrows, - uint256 reserves - ) public view virtual returns (bool) { - cash; - borrows; - reserves; - return false; - } -} - - -// Dependency file: contracts/EIP20NonStandardInterface.sol - -// pragma solidity 0.8.6; - -/** - * @title EIP20NonStandardInterface - * @dev Version of ERC20 with no return values for `transfer` and `transferFrom` - * See https://medium.com/coinmonks/missing-return-value-bug-at-least-130-tokens-affected-d67bf08521ca - */ -interface EIP20NonStandardInterface { - /** - * @notice Get the total number of tokens in circulation - * @return The supply of tokens - */ - function totalSupply() external view returns (uint256); - - /** - * @notice Gets the balance of the specified address - * @param owner The address from which the balance will be retrieved - * @return balance The balance - */ - function balanceOf(address owner) external view returns (uint256 balance); - - /// - /// !!!!!!!!!!!!!! - /// !!! NOTICE !!! `transfer` does not return a value, in violation of the ERC-20 specification - /// !!!!!!!!!!!!!! - /// - - /** - * @notice Transfer `amount` tokens from `msg.sender` to `dst` - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - */ - function transfer(address dst, uint256 amount) external; - - /// - /// !!!!!!!!!!!!!! - /// !!! NOTICE !!! `transferFrom` does not return a value, in violation of the ERC-20 specification - /// !!!!!!!!!!!!!! - /// - - /** - * @notice Transfer `amount` tokens from `src` to `dst` - * @param src The address of the source account - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - */ - function transferFrom( - address src, - address dst, - uint256 amount - ) external; - - /** - * @notice Approve `spender` to transfer up to `amount` from `src` - * @dev This will overwrite the approval amount for `spender` - * and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve) - * @param spender The address of the account which may transfer tokens - * @param amount The number of tokens that are approved - * @return success Whether or not the approval succeeded - */ - function approve(address spender, uint256 amount) - external - returns (bool success); - - /** - * @notice Get the current allowance from `owner` for `spender` - * @param owner The address of the account which owns the tokens to be spent - * @param spender The address of the account which may transfer tokens - * @return remaining The number of tokens allowed to be spent - */ - function allowance(address owner, address spender) - external - view - returns (uint256 remaining); - - event Transfer(address indexed from, address indexed to, uint256 amount); - event Approval( - address indexed owner, - address indexed spender, - uint256 amount - ); -} - - -// Dependency file: contracts/CTokenInterfaces.sol - -// pragma solidity 0.8.6; - -// import "contracts/ComptrollerInterface.sol"; -// import "contracts/InterestRateModel.sol"; -// import "contracts/EIP20NonStandardInterface.sol"; - -contract CTokenStorage { - /** - * @dev Guard variable for re-entrancy checks - */ - bool internal _notEntered; - - /** - * @notice EIP-20 token name for this token - */ - string public name; - - /** - * @notice EIP-20 token symbol for this token - */ - string public symbol; - - /** - * @notice EIP-20 token decimals for this token - */ - uint8 public decimals; - - /** - * @notice Maximum borrow rate that can ever be applied (.0005% / block) - */ - - uint256 internal constant borrowRateMaxMantissa = 0.0005e16; - - /** - * @notice Maximum fraction of interest that can be set aside for reserves - */ - uint256 internal constant reserveFactorMaxMantissa = 1e18; - - /** - * @notice Administrator for this contract - */ - address payable public admin; - - /** - * @notice Pending administrator for this contract - */ - address payable public pendingAdmin; - - /** - * @notice Contract which oversees inter-cToken operations - */ - ComptrollerInterface public comptroller; - - /** - * @notice Model which tells what the current interest rate should be - */ - InterestRateModel public interestRateModel; - - /** - * @notice Initial exchange rate used when minting the first CTokens (used when totalSupply = 0) - */ - uint256 public initialExchangeRateMantissa; - - /** - * @notice Fraction of interest currently set aside for reserves - */ - uint256 public reserveFactorMantissa; - - /** - * @notice Block number that interest was last accrued at - */ - uint256 public accrualBlockNumber; - - /** - * @notice Accumulator of the total earned interest rate since the opening of the market - */ - uint256 public borrowIndex; - - /** - * @notice Total amount of outstanding borrows of the underlying in this market - */ - uint256 public totalBorrows; - - /** - * @notice Total amount of reserves of the underlying held in this market - */ - uint256 public totalReserves; - - /** - * @notice Total number of tokens in circulation - */ - uint256 public totalSupply; - - uint256 public subsidyFund; - - struct SupplySnapshot { - uint256 tokens; - uint256 underlyingAmount; - uint256 suppliedAt; - uint256 promisedSupplyRate; - } - - /** - * @notice Official record of token balances for each account - */ - mapping(address => SupplySnapshot) internal accountTokens; - - /** - * @notice Approved token transfer amounts on behalf of others - */ - mapping(address => mapping(address => uint256)) internal transferAllowances; - - /** - * @notice Container for borrow balance information - * @member principal Total balance (with accrued interest), after applying the most recent balance-changing action - * @member interestIndex Global borrowIndex as of the most recent balance-changing action - */ - struct BorrowSnapshot { - uint256 principal; - uint256 interestIndex; - } - - /** - * @notice Mapping of account addresses to outstanding borrow balances - */ - mapping(address => BorrowSnapshot) internal accountBorrows; -} - -abstract contract CTokenInterface is CTokenStorage { - /** - * @notice Indicator that this is a CToken contract (for inspection) - */ - bool public constant isCToken = true; - - /*** Market Events ***/ - - /** - * @notice Event emitted when interest is accrued - */ - event AccrueInterest( - uint256 cashPrior, - uint256 interestAccumulated, - uint256 borrowIndex, - uint256 totalBorrows - ); - - /** - * @notice Event emitted when tokens are minted - */ - event Mint(address indexed minter, uint256 mintAmount, uint256 mintTokens); - - /** - * @notice Event emitted when tokens are redeemed - */ - event Redeem( - address indexed redeemer, - uint256 redeemAmount, - uint256 redeemTokens - ); - - /** - * @notice Event emitted when underlying is borrowed - */ - event Borrow( - address indexed borrower, - uint256 borrowAmount, - uint256 accountBorrows, - uint256 totalBorrows - ); - - /** - * @notice Event emitted when a borrow is repaid - */ - event RepayBorrow( - address indexed payer, - address indexed borrower, - uint256 repayAmount, - uint256 accountBorrows, - uint256 totalBorrows - ); - - /** - * @notice Event emitted when a borrow is liquidated - */ - event LiquidateBorrow( - address indexed liquidator, - address indexed borrower, - uint256 repayAmount, - address indexed cTokenCollateral, - uint256 seizeTokens - ); - - /*** Admin Events ***/ - - /** - * @notice Event emitted when pendingAdmin is changed - */ - event NewPendingAdmin(address oldPendingAdmin, address newPendingAdmin); - - /** - * @notice Event emitted when pendingAdmin is accepted, which means admin is updated - */ - event NewAdmin(address oldAdmin, address newAdmin); - - /** - * @notice Event emitted when comptroller is changed - */ - event NewComptroller( - ComptrollerInterface oldComptroller, - ComptrollerInterface newComptroller - ); - - /** - * @notice Event emitted when interestRateModel is changed - */ - event NewMarketInterestRateModel( - InterestRateModel oldInterestRateModel, - InterestRateModel newInterestRateModel - ); - - /** - * @notice Event emitted when the reserve factor is changed - */ - event NewReserveFactor( - uint256 oldReserveFactorMantissa, - uint256 newReserveFactorMantissa - ); - - /** - * @notice Event emitted when the reserves are added - */ - event ReservesAdded( - address benefactor, - uint256 addAmount, - uint256 newTotalReserves - ); - - event SubsidyAdded( - address benefactor, - uint256 addAmount, - uint256 newSubsidyFund - ); - - /** - * @notice Event emitted when the reserves are reduced - */ - event ReservesReduced( - address admin, - uint256 reduceAmount, - uint256 newTotalReserves - ); - - /** - * @notice EIP20 Transfer event - */ - event Transfer(address indexed from, address indexed to, uint256 amount); - - /** - * @notice EIP20 Approval event - */ - event Approval( - address indexed owner, - address indexed spender, - uint256 amount - ); - - /** - * @notice Failure event - */ - event CTokenStorageFailure(uint256 error, uint256 info, uint256 detail); - - /*** User Interface ***/ - - function transfer(address dst, uint256 amount) - external - virtual - returns (bool); - - function transferFrom( - address src, - address dst, - uint256 amount - ) external virtual returns (bool); - - function approve(address spender, uint256 amount) - external - virtual - returns (bool); - - function allowance(address owner, address spender) - external - view - virtual - returns (uint256); - - function balanceOf(address owner) external view virtual returns (uint256); - - function balanceOfUnderlying(address owner) - external - virtual - returns (uint256); - - function getAccountSnapshot(address account) - external - view - virtual - returns ( - uint256, - uint256, - uint256, - uint256 - ); - - function borrowRatePerBlock() external view virtual returns (uint256); - - function supplyRatePerBlock() external view virtual returns (uint256); - - function totalBorrowsCurrent() external virtual returns (uint256); - - function borrowBalanceCurrent(address account) - external - virtual - returns (uint256); - - function borrowBalanceStored(address account) - public - view - virtual - returns (uint256); - - function exchangeRateCurrent() public virtual returns (uint256); - - function exchangeRateStored() public view virtual returns (uint256); - - function getCash() external view virtual returns (uint256); - - function accrueInterest() public virtual returns (uint256); - - function seize( - address liquidator, - address borrower, - uint256 seizeTokens - ) external virtual returns (uint256); - - /*** Admin Functions ***/ - - function _setPendingAdmin(address payable newPendingAdmin) - external - virtual - returns (uint256); - - function _acceptAdmin() external virtual returns (uint256); - - function _setComptroller(ComptrollerInterface newComptroller) - public - virtual - returns (uint256); - - function _setReserveFactor(uint256 newReserveFactorMantissa) - external - virtual - returns (uint256); - - function _reduceReserves(uint256 reduceAmount) - external - virtual - returns (uint256); - - function _setInterestRateModel(InterestRateModel newInterestRateModel) - public - virtual - returns (uint256); -} - -contract CErc20Storage { - /** - * @notice Underlying asset for this CToken - */ - address public underlying; -} - -abstract contract CErc20Interface is CErc20Storage { - /*** User Interface ***/ - - function mint(uint256 mintAmount) external virtual returns (uint256); - - function redeem(uint256 redeemAmount) - external - virtual - returns (uint256); - - function borrow(uint256 borrowAmount) external virtual returns (uint256); - - function repayBorrow(uint256 repayAmount) - external - virtual - returns (uint256); - - function liquidateBorrow( - address borrower, - uint256 repayAmount, - CTokenInterface cTokenCollateral - ) external virtual returns (uint256); - - function sweepToken(EIP20NonStandardInterface token) external virtual; - - /*** Admin Functions ***/ - - function _addReserves(uint256 addAmount) external virtual returns (uint256); -} - -contract CDelegationStorage { - /** - * @notice Implementation address for this contract - */ - address public implementation; -} - -abstract contract CDelegatorInterface is CDelegationStorage { - /** - * @notice Emitted when implementation is changed - */ - event NewImplementation( - address oldImplementation, - address newImplementation - ); - - /** - * @notice Called by the admin to update the implementation of the delegator - * @param implementation_ The address of the new implementation for delegation - * @param allowResign Flag to indicate whether to call _resignImplementation on the old implementation - * @param becomeImplementationData The encoded bytes data to be passed to _becomeImplementation - */ - function _setImplementation( - address implementation_, - bool allowResign, - bytes memory becomeImplementationData - ) public virtual; -} - -abstract contract CDelegateInterface is CDelegationStorage { - /** - * @notice Called by the delegator on a delegate to initialize it for duty - * @dev Should revert if any issues arise which make it unfit for delegation - * @param data The encoded bytes data for any initialization - */ - function _becomeImplementation(bytes memory data) public virtual; - - /** - * @notice Called by the delegator on a delegate to forfeit its responsibility - */ - function _resignImplementation() public virtual; -} - - -// Dependency file: contracts/ErrorReporter.sol - -// pragma solidity 0.8.6; - -contract ComptrollerErrorReporter { - enum Error { - NO_ERROR, - UNAUTHORIZED, - COMPTROLLER_MISMATCH, - INSUFFICIENT_SHORTFALL, - INSUFFICIENT_LIQUIDITY, - INVALID_CLOSE_FACTOR, - INVALID_COLLATERAL_FACTOR, - INVALID_LIQUIDATION_INCENTIVE, - MARKET_NOT_ENTERED, // no longer possible - MARKET_NOT_LISTED, - MARKET_ALREADY_LISTED, - MATH_ERROR, - NONZERO_BORROW_BALANCE, - PRICE_ERROR, - REJECTION, - SNAPSHOT_ERROR, - TOO_MANY_ASSETS, - TOO_MUCH_REPAY - } - - enum FailureInfo { - ACCEPT_ADMIN_PENDING_ADMIN_CHECK, - ACCEPT_PENDING_IMPLEMENTATION_ADDRESS_CHECK, - EXIT_MARKET_BALANCE_OWED, - EXIT_MARKET_REJECTION, - SET_CLOSE_FACTOR_OWNER_CHECK, - SET_CLOSE_FACTOR_VALIDATION, - SET_COLLATERAL_FACTOR_OWNER_CHECK, - SET_COLLATERAL_FACTOR_NO_EXISTS, - SET_COLLATERAL_FACTOR_VALIDATION, - SET_COLLATERAL_FACTOR_WITHOUT_PRICE, - SET_IMPLEMENTATION_OWNER_CHECK, - SET_LIQUIDATION_INCENTIVE_OWNER_CHECK, - SET_LIQUIDATION_INCENTIVE_VALIDATION, - SET_MAX_ASSETS_OWNER_CHECK, - SET_PENDING_ADMIN_OWNER_CHECK, - SET_PENDING_IMPLEMENTATION_OWNER_CHECK, - SET_PRICE_ORACLE_OWNER_CHECK, - SUPPORT_MARKET_EXISTS, - SUPPORT_MARKET_OWNER_CHECK, - SET_PAUSE_GUARDIAN_OWNER_CHECK - } - - /** - * @dev `error` corresponds to enum Error; `info` corresponds to enum FailureInfo, and `detail` is an arbitrary - * contract-specific code that enables us to report opaque error codes from upgradeable contracts. - **/ - event Failure(uint256 error, uint256 info, uint256 detail); - - /** - * @dev use this when reporting a known error from the money market or a non-upgradeable collaborator - */ - function fail(Error err, FailureInfo info) internal returns (uint256) { - emit Failure(uint256(err), uint256(info), 0); - - return uint256(err); - } - - /** - * @dev use this when reporting an opaque error from an upgradeable collaborator contract - */ - function failOpaque( - Error err, - FailureInfo info, - uint256 opaqueError - ) internal returns (uint256) { - emit Failure(uint256(err), uint256(info), opaqueError); - - return uint256(err); - } -} - -contract TokenErrorReporter { - enum Error { - NO_ERROR, - UNAUTHORIZED, - BAD_INPUT, - COMPTROLLER_REJECTION, - COMPTROLLER_CALCULATION_ERROR, - INTEREST_RATE_MODEL_ERROR, - INVALID_ACCOUNT_PAIR, - INVALID_CLOSE_AMOUNT_REQUESTED, - INVALID_COLLATERAL_FACTOR, - MATH_ERROR, - MARKET_NOT_FRESH, - MARKET_NOT_LISTED, - TOKEN_INSUFFICIENT_ALLOWANCE, - TOKEN_INSUFFICIENT_BALANCE, - TOKEN_INSUFFICIENT_CASH, - TOKEN_TRANSFER_IN_FAILED, - TOKEN_TRANSFER_OUT_FAILED - } - - /* - * Note: FailureInfo (but not Error) is kept in alphabetical order - * This is because FailureInfo grows significantly faster, and - * the order of Error has some meaning, while the order of FailureInfo - * is entirely arbitrary. - */ - enum FailureInfo { - ACCEPT_ADMIN_PENDING_ADMIN_CHECK, - ACCRUE_INTEREST_ACCUMULATED_INTEREST_CALCULATION_FAILED, - ACCRUE_INTEREST_BORROW_RATE_CALCULATION_FAILED, - ACCRUE_INTEREST_NEW_BORROW_INDEX_CALCULATION_FAILED, - ACCRUE_INTEREST_NEW_TOTAL_BORROWS_CALCULATION_FAILED, - ACCRUE_INTEREST_NEW_TOTAL_RESERVES_CALCULATION_FAILED, - ACCRUE_INTEREST_SIMPLE_INTEREST_FACTOR_CALCULATION_FAILED, - BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED, - BORROW_ACCRUE_INTEREST_FAILED, - BORROW_CASH_NOT_AVAILABLE, - BORROW_FRESHNESS_CHECK, - BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED, - BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED, - BORROW_MARKET_NOT_LISTED, - BORROW_COMPTROLLER_REJECTION, - LIQUIDATE_ACCRUE_BORROW_INTEREST_FAILED, - LIQUIDATE_ACCRUE_COLLATERAL_INTEREST_FAILED, - LIQUIDATE_COLLATERAL_FRESHNESS_CHECK, - LIQUIDATE_COMPTROLLER_REJECTION, - LIQUIDATE_COMPTROLLER_CALCULATE_AMOUNT_SEIZE_FAILED, - LIQUIDATE_CLOSE_AMOUNT_IS_UINT_MAX, - LIQUIDATE_CLOSE_AMOUNT_IS_ZERO, - LIQUIDATE_FRESHNESS_CHECK, - LIQUIDATE_LIQUIDATOR_IS_BORROWER, - LIQUIDATE_REPAY_BORROW_FRESH_FAILED, - LIQUIDATE_SEIZE_BALANCE_INCREMENT_FAILED, - LIQUIDATE_SEIZE_BALANCE_DECREMENT_FAILED, - LIQUIDATE_SEIZE_COMPTROLLER_REJECTION, - LIQUIDATE_SEIZE_LIQUIDATOR_IS_BORROWER, - LIQUIDATE_SEIZE_TOO_MUCH, - MINT_ACCRUE_INTEREST_FAILED, - MINT_COMPTROLLER_REJECTION, - MINT_EXCHANGE_CALCULATION_FAILED, - MINT_EXCHANGE_RATE_READ_FAILED, - MINT_FRESHNESS_CHECK, - MINT_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED, - MINT_NEW_TOTAL_SUPPLY_CALCULATION_FAILED, - MINT_TRANSFER_IN_FAILED, - MINT_TRANSFER_IN_NOT_POSSIBLE, - REDEEM_ACCRUE_INTEREST_FAILED, - REDEEM_COMPTROLLER_REJECTION, - REDEEM_EXCHANGE_TOKENS_CALCULATION_FAILED, - REDEEM_EXCHANGE_AMOUNT_CALCULATION_FAILED, - REDEEM_EXCHANGE_RATE_READ_FAILED, - REDEEM_FRESHNESS_CHECK, - REDEEM_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED, - REDEEM_NEW_TOTAL_SUPPLY_CALCULATION_FAILED, - REDEEM_TRANSFER_OUT_NOT_POSSIBLE, - REDUCE_RESERVES_ACCRUE_INTEREST_FAILED, - REDUCE_RESERVES_ADMIN_CHECK, - REDUCE_RESERVES_CASH_NOT_AVAILABLE, - REDUCE_RESERVES_FRESH_CHECK, - REDUCE_RESERVES_VALIDATION, - REPAY_BEHALF_ACCRUE_INTEREST_FAILED, - REPAY_BORROW_ACCRUE_INTEREST_FAILED, - REPAY_BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED, - REPAY_BORROW_COMPTROLLER_REJECTION, - REPAY_BORROW_FRESHNESS_CHECK, - REPAY_BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED, - REPAY_BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED, - REPAY_BORROW_TRANSFER_IN_NOT_POSSIBLE, - SET_COLLATERAL_FACTOR_OWNER_CHECK, - SET_COLLATERAL_FACTOR_VALIDATION, - SET_COMPTROLLER_OWNER_CHECK, - SET_INTEREST_RATE_MODEL_ACCRUE_INTEREST_FAILED, - SET_INTEREST_RATE_MODEL_FRESH_CHECK, - SET_INTEREST_RATE_MODEL_OWNER_CHECK, - SET_MAX_ASSETS_OWNER_CHECK, - SET_ORACLE_MARKET_NOT_LISTED, - SET_PENDING_ADMIN_OWNER_CHECK, - SET_RESERVE_FACTOR_ACCRUE_INTEREST_FAILED, - SET_RESERVE_FACTOR_ADMIN_CHECK, - SET_RESERVE_FACTOR_FRESH_CHECK, - SET_RESERVE_FACTOR_BOUNDS_CHECK, - TRANSFER_COMPTROLLER_REJECTION, - TRANSFER_NOT_ALLOWED, - TRANSFER_NOT_ENOUGH, - TRANSFER_TOO_MUCH, - ADD_RESERVES_ACCRUE_INTEREST_FAILED, - ADD_RESERVES_FRESH_CHECK, - ADD_RESERVES_TRANSFER_IN_NOT_POSSIBLE, - ADD_SUBSIDY_FUND_FAILED, - ADD_SUBSIDY_FUND_FRESH_CHECK - } - - /** - * @dev `error` corresponds to enum Error; `info` corresponds to enum FailureInfo, and `detail` is an arbitrary - * contract-specific code that enables us to report opaque error codes from upgradeable contracts. - **/ - event TokenFailure(uint256 error, uint256 info, uint256 detail); - - /** - * @dev use this when reporting a known error from the money market or a non-upgradeable collaborator - */ - function fail(Error err, FailureInfo info) internal returns (uint256) { - emit TokenFailure(uint256(err), uint256(info), 0); - - return uint256(err); - } - - /** - * @dev use this when reporting an opaque error from an upgradeable collaborator contract - */ - function failOpaque( - Error err, - FailureInfo info, - uint256 opaqueError - ) internal returns (uint256) { - emit TokenFailure(uint256(err), uint256(info), opaqueError); - - return uint256(err); - } -} - - -// Dependency file: contracts/EIP20Interface.sol - -// pragma solidity 0.8.6; - -/** - * @title ERC 20 Token Standard Interface - * https://eips.ethereum.org/EIPS/eip-20 - */ -interface EIP20Interface { - function name() external view returns (string memory); - - function symbol() external view returns (string memory); - - function decimals() external view returns (uint8); - - /** - * @notice Get the total number of tokens in circulation - * @return The supply of tokens - */ - function totalSupply() external view returns (uint256); - - /** - * @notice Gets the balance of the specified address - * @param owner The address from which the balance will be retrieved - * @return balance The balance - */ - function balanceOf(address owner) external view returns (uint256 balance); - - /** - * @notice Transfer `amount` tokens from `msg.sender` to `dst` - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - * @return success Whether or not the transfer succeeded - */ - function transfer(address dst, uint256 amount) - external - returns (bool success); - - /** - * @notice Transfer `amount` tokens from `src` to `dst` - * @param src The address of the source account - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - * @return success Whether or not the transfer succeeded - */ - function transferFrom( - address src, - address dst, - uint256 amount - ) external returns (bool success); - - /** - * @notice Approve `spender` to transfer up to `amount` from `src` - * @dev This will overwrite the approval amount for `spender` - * and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve) - * @param spender The address of the account which may transfer tokens - * @param amount The number of tokens that are approved (-1 means infinite) - * @return success Whether or not the approval succeeded - */ - function approve(address spender, uint256 amount) - external - returns (bool success); - - /** - * @notice Get the current allowance from `owner` for `spender` - * @param owner The address of the account which owns the tokens to be spent - * @param spender The address of the account which may transfer tokens - * @return remaining The number of tokens allowed to be spent (-1 means infinite) - */ - function allowance(address owner, address spender) - external - view - returns (uint256 remaining); - - event Transfer(address indexed from, address indexed to, uint256 amount); - event Approval( - address indexed owner, - address indexed spender, - uint256 amount - ); -} - - -// Dependency file: contracts/WhitelistInterface.sol - -// pragma solidity 0.8.6; - -interface WhitelistInterface { - function setStatus(bool _newStatus) external; - function enabled() external view returns(bool); - - function addUsers(address[] memory _users) external; - function exist(address _user) external view returns(bool); - function getUsers() external view returns(address[] memory currentUsers); - function removeUser(address _user) external; -} - -// Dependency file: contracts/CToken.sol - -// pragma solidity 0.8.6; - -// import "contracts/ComptrollerInterface.sol"; -// import "contracts/CTokenInterfaces.sol"; -// import "contracts/ErrorReporter.sol"; -// import "contracts/Exponential.sol"; -// import "contracts/EIP20Interface.sol"; -// import "contracts/InterestRateModel.sol"; -// import "contracts/WhitelistInterface.sol"; - -/** - * @title tropykus CToken Contract - * @notice Abstract base for CTokens - * @author tropykus - */ -abstract contract CToken is CTokenInterface, Exponential, TokenErrorReporter { - address whitelist; - - /** - * @notice Initialize the money market - * @param comptroller_ The address of the Comptroller - * @param interestRateModel_ The address of the interest rate model - * @param initialExchangeRateMantissa_ The initial exchange rate, scaled by 1e18 - * @param name_ EIP-20 name of this token - * @param symbol_ EIP-20 symbol of this token - * @param decimals_ EIP-20 decimal precision of this token - */ - function initialize( - ComptrollerInterface comptroller_, - InterestRateModel interestRateModel_, - uint256 initialExchangeRateMantissa_, - string memory name_, - string memory symbol_, - uint8 decimals_ - ) public { - require(msg.sender == admin, "CT01"); - require(accrualBlockNumber == 0 && borrowIndex == 0, "CT02"); - - initialExchangeRateMantissa = initialExchangeRateMantissa_; - require(initialExchangeRateMantissa > 0, "CT03"); - - uint256 err = _setComptroller(comptroller_); - require(err == uint256(Error.NO_ERROR), "CT04"); - - accrualBlockNumber = getBlockNumber(); - borrowIndex = mantissaOne; - - err = _setInterestRateModelFresh(interestRateModel_); - require(err == uint256(Error.NO_ERROR), "CT05"); - - name = name_; - symbol = symbol_; - decimals = decimals_; - - _notEntered = true; - } - - function addWhitelist(address _whitelist) external returns (uint256) { - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_INTEREST_RATE_MODEL_OWNER_CHECK - ); - } - whitelist = _whitelist; - } - - /** - * @notice Transfer `tokens` tokens from `src` to `dst` by `spender` - * @dev Called by both `transfer` and `transferFrom` internally - * @param spender The address of the account performing the transfer - * @param src The address of the source account - * @param dst The address of the destination account - * @param tokens The number of tokens to transfer - * @return Whether or not the transfer succeeded - */ - function transferTokens( - address spender, - address src, - address dst, - uint256 tokens - ) internal returns (uint256) { - uint256 allowed = comptroller.transferAllowed( - address(this), - src, - dst, - tokens - ); - if (allowed != 0) { - return - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.TRANSFER_COMPTROLLER_REJECTION, - allowed - ); - } - - if (src == dst) { - return fail(Error.BAD_INPUT, FailureInfo.TRANSFER_NOT_ALLOWED); - } - - uint256 startingAllowance = 0; - if (spender == src) { - startingAllowance = type(uint256).max; - } else { - startingAllowance = transferAllowances[src][spender]; - } - - MathError mathErr; - uint256 allowanceNew; - uint256 srcTokensNew; - uint256 dstTokensNew; - - (mathErr, allowanceNew) = subUInt(startingAllowance, tokens); - if (mathErr != MathError.NO_ERROR) { - return fail(Error.MATH_ERROR, FailureInfo.TRANSFER_NOT_ALLOWED); - } - - (mathErr, srcTokensNew) = subUInt(accountTokens[src].tokens, tokens); - if (mathErr != MathError.NO_ERROR) { - return fail(Error.MATH_ERROR, FailureInfo.TRANSFER_NOT_ENOUGH); - } - - (mathErr, dstTokensNew) = addUInt(accountTokens[dst].tokens, tokens); - if (mathErr != MathError.NO_ERROR) { - return fail(Error.MATH_ERROR, FailureInfo.TRANSFER_TOO_MUCH); - } - - accountTokens[src].tokens = srcTokensNew; - accountTokens[dst].tokens = dstTokensNew; - - if (startingAllowance != type(uint256).max) { - transferAllowances[src][spender] = allowanceNew; - } - - emit Transfer(src, dst, tokens); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Transfer `amount` tokens from `msg.sender` to `dst` - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - * @return Whether or not the transfer succeeded - */ - function transfer(address dst, uint256 amount) - external - override - nonReentrant - returns (bool) - { - return - transferTokens(msg.sender, msg.sender, dst, amount) == - uint256(Error.NO_ERROR); - } - - /** - * @notice Transfer `amount` tokens from `src` to `dst` - * @param src The address of the source account - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - * @return Whether or not the transfer succeeded - */ - function transferFrom( - address src, - address dst, - uint256 amount - ) external override nonReentrant returns (bool) { - return - transferTokens(msg.sender, src, dst, amount) == - uint256(Error.NO_ERROR); - } - - /** - * @notice Approve `spender` to transfer up to `amount` from `src` - * @dev This will overwrite the approval amount for `spender` - * and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve) - * @param spender The address of the account which may transfer tokens - * @param amount The number of tokens that are approved (-1 means infinite) - * @return Whether or not the approval succeeded - */ - function approve(address spender, uint256 amount) - external - override - returns (bool) - { - transferAllowances[msg.sender][spender] = amount; - emit Approval(msg.sender, spender, amount); - return true; - } - - /** - * @notice Get the current allowance from `owner` for `spender` - * @param owner The address of the account which owns the tokens to be spent - * @param spender The address of the account which may transfer tokens - * @return The number of tokens allowed to be spent (-1 means infinite) - */ - function allowance(address owner, address spender) - external - view - override - returns (uint256) - { - return transferAllowances[owner][spender]; - } - - /** - * @notice Get the token balance of the `owner` - * @param owner The address of the account to query - * @return The number of tokens owned by `owner` - */ - function balanceOf(address owner) external view override returns (uint256) { - return accountTokens[owner].tokens; - } - - /** - * @notice Get the underlying balance of the `owner` - * @dev This also accrues interest in a transaction - * @param owner The address of the account to query - * @return The amount of underlying owned by `owner` - */ - function balanceOfUnderlying(address owner) - external - override - returns (uint256) - { - (MathError mErr, uint256 balance) = mulScalarTruncate( - Exp({mantissa: exchangeRateCurrent()}), - accountTokens[owner].tokens - ); - require(mErr == MathError.NO_ERROR, "CT06"); - return balance; - } - - /** - * @notice Get a snapshot of the account's balances, and the cached exchange rate - * @dev This is used by comptroller to more efficiently perform liquidity checks. - * @param account Address of the account to snapshot - * @return (possible error, token balance, borrow balance, exchange rate mantissa) - */ - function getAccountSnapshot(address account) - external - view - override - returns ( - uint256, - uint256, - uint256, - uint256 - ) - { - uint256 cTokenBalance = accountTokens[account].tokens; - uint256 borrowBalance; - uint256 exchangeRateMantissa; - - MathError mErr; - - (mErr, borrowBalance) = borrowBalanceStoredInternal(account); - if (mErr != MathError.NO_ERROR) { - return (uint256(Error.MATH_ERROR), 0, 0, 0); - } - - (mErr, exchangeRateMantissa) = exchangeRateStoredInternal(); - if (mErr != MathError.NO_ERROR) { - return (uint256(Error.MATH_ERROR), 0, 0, 0); - } - - return ( - uint256(Error.NO_ERROR), - cTokenBalance, - borrowBalance, - exchangeRateMantissa - ); - } - - /** - * @dev Function to simply retrieve block number - * This exists mainly for inheriting test contracts to stub this result. - */ - function getBlockNumber() internal view virtual returns (uint256) { - return block.number; - } - - /** - * @notice Returns the current per-block borrow interest rate for this cToken - * @return The borrow interest rate per block, scaled by 1e18 - */ - function borrowRatePerBlock() external view override returns (uint256) { - return - interestRateModel.getBorrowRate( - getCashPrior(), - totalBorrows, - totalReserves - ); - } - - /** - * @notice Returns the current per-block supply interest rate for this cToken - * @return The supply interest rate per block, scaled by 1e18 - */ - function supplyRatePerBlock() external view override returns (uint256) { - return - interestRateModel.getSupplyRate( - getCashPrior(), - totalBorrows, - totalReserves, - reserveFactorMantissa - ); - } - - /** - * @notice Returns the current total borrows plus accrued interest - * @return The total borrows with interest - */ - function totalBorrowsCurrent() - external - override - nonReentrant - returns (uint256) - { - require(accrueInterest() == uint256(Error.NO_ERROR), "CT07"); - return totalBorrows; - } - - /** - * @notice Accrue interest to updated borrowIndex and then calculate account's borrow balance using the updated borrowIndex - * @param account The address whose balance should be calculated after updating borrowIndex - * @return The calculated balance - */ - function borrowBalanceCurrent(address account) - external - override - nonReentrant - returns (uint256) - { - require(accrueInterest() == uint256(Error.NO_ERROR), "CT07"); - return borrowBalanceStored(account); - } - - /** - * @notice Return the borrow balance of account based on stored data - * @param account The address whose balance should be calculated - * @return The calculated balance - */ - function borrowBalanceStored(address account) - public - view - override - returns (uint256) - { - (MathError err, uint256 result) = borrowBalanceStoredInternal(account); - require(err == MathError.NO_ERROR, "CT08"); - return result; - } - - /** - * @notice Return the borrow balance of account based on stored data - * @param account The address whose balance should be calculated - * @return (error code, the calculated balance or 0 if error code is non-zero) - */ - function borrowBalanceStoredInternal(address account) - internal - view - returns (MathError, uint256) - { - MathError mathErr; - uint256 principalTimesIndex; - uint256 result; - - BorrowSnapshot storage borrowSnapshot = accountBorrows[account]; - - if (borrowSnapshot.principal == 0) { - return (MathError.NO_ERROR, 0); - } - - (mathErr, principalTimesIndex) = mulUInt( - borrowSnapshot.principal, - borrowIndex - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - - (mathErr, result) = divUInt( - principalTimesIndex, - borrowSnapshot.interestIndex - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - - return (MathError.NO_ERROR, result); - } - - function getBorrowerPrincipalStored(address account) - public - view - returns (uint256 borrowed) - { - borrowed = accountBorrows[account].principal; - } - - function getSupplierSnapshotStored(address account) - public - view - returns ( - uint256 tokens, - uint256 underlyingAmount, - uint256 suppliedAt, - uint256 promisedSupplyRate - ) - { - tokens = accountTokens[account].tokens; - underlyingAmount = accountTokens[account].underlyingAmount; - suppliedAt = accountTokens[account].suppliedAt; - promisedSupplyRate = accountTokens[account].promisedSupplyRate; - } - - /** - * @notice Accrue interest then return the up-to-date exchange rate - * @return Calculated exchange rate scaled by 1e18 - */ - function exchangeRateCurrent() - public - override - nonReentrant - returns (uint256) - { - require(accrueInterest() == uint256(Error.NO_ERROR), "CT07"); - return exchangeRateStored(); - } - - /** - * @notice Calculates the exchange rate from the underlying to the CToken - * @dev This function does not accrue interest before calculating the exchange rate - * @return Calculated exchange rate scaled by 1e18 - */ - function exchangeRateStored() public view override returns (uint256) { - (MathError err, uint256 result) = exchangeRateStoredInternal(); - require(err == MathError.NO_ERROR, "CT09"); - return result; - } - - /** - * @notice Calculates the exchange rate from the underlying to the CToken - * @dev This function does not accrue interest before calculating the exchange rate - * @return (error code, calculated exchange rate scaled by 1e18) - */ - function exchangeRateStoredInternal() - internal - view - virtual - returns (MathError, uint256) - { - uint256 _totalSupply = totalSupply; - if (_totalSupply == 0) { - return (MathError.NO_ERROR, initialExchangeRateMantissa); - } else { - MathError error; - uint256 exchangeRate; - uint256 totalCash = getCashPrior(); - if (interestRateModel.isTropykusInterestRateModel()) { - (error, exchangeRate) = tropykusExchangeRateStoredInternal( - msg.sender - ); - if (error == MathError.NO_ERROR) { - return (MathError.NO_ERROR, exchangeRate); - } else { - return (MathError.NO_ERROR, initialExchangeRateMantissa); - } - } - return - interestRateModel.getExchangeRate( - totalCash, - totalBorrows, - totalReserves, - totalSupply - ); - } - } - - function tropykusExchangeRateStoredInternal(address redeemer) - internal - view - returns (MathError, uint256) - { - if (totalSupply == 0) { - return (MathError.NO_ERROR, initialExchangeRateMantissa); - } else { - SupplySnapshot storage supplySnapshot = accountTokens[redeemer]; - if (supplySnapshot.suppliedAt == 0) { - return (MathError.DIVISION_BY_ZERO, 0); - } - (, uint256 interestFactorMantissa, ) = tropykusInterestAccrued( - redeemer - ); - Exp memory interestFactor = Exp({mantissa: interestFactorMantissa}); - uint256 currentUnderlying = supplySnapshot.underlyingAmount; - Exp memory redeemerUnderlying = Exp({mantissa: currentUnderlying}); - (, Exp memory realAmount) = mulExp( - interestFactor, - redeemerUnderlying - ); - (, Exp memory exchangeRate) = getExp( - realAmount.mantissa, - supplySnapshot.tokens - ); - return (MathError.NO_ERROR, exchangeRate.mantissa); - } - } - - function tropykusInterestAccrued(address account) - internal - view - returns ( - MathError, - uint256, - uint256 - ) - { - SupplySnapshot storage supplySnapshot = accountTokens[account]; - uint256 promisedSupplyRate = supplySnapshot.promisedSupplyRate; - Exp memory expectedSupplyRatePerBlock = Exp({ - mantissa: promisedSupplyRate - }); - (, uint256 delta) = subUInt( - accrualBlockNumber, - supplySnapshot.suppliedAt - ); - (, Exp memory expectedSupplyRatePerBlockWithDelta) = mulScalar( - expectedSupplyRatePerBlock, - delta - ); - (, Exp memory interestFactor) = addExp( - Exp({mantissa: 1e18}), - expectedSupplyRatePerBlockWithDelta - ); - uint256 currentUnderlying = supplySnapshot.underlyingAmount; - Exp memory redeemerUnderlying = Exp({mantissa: currentUnderlying}); - (, Exp memory realAmount) = mulExp(interestFactor, redeemerUnderlying); - (, uint256 interestEarned) = subUInt( - realAmount.mantissa, - currentUnderlying - ); - return (MathError.NO_ERROR, interestFactor.mantissa, interestEarned); - } - - /** - * @notice Get cash balance of this cToken in the underlying asset - * @return The quantity of underlying asset owned by this contract - */ - function getCash() external view override returns (uint256) { - return getCashPrior(); - } - - /** - * @notice Applies accrued interest to total borrows and reserves - * @dev This calculates interest accrued from the last checkpointed block - * up to the current block and writes new checkpoint to storage. - */ - function accrueInterest() public override returns (uint256) { - uint256 currentBlockNumber = getBlockNumber(); - uint256 accrualBlockNumberPrior = accrualBlockNumber; - - if (accrualBlockNumberPrior == currentBlockNumber) { - return uint256(Error.NO_ERROR); - } - - uint256 cashPrior = getCashPrior(); - uint256 borrowsPrior = totalBorrows; - uint256 reservesPrior = totalReserves; - uint256 borrowIndexPrior = borrowIndex; - - uint256 borrowRateMantissa = interestRateModel.getBorrowRate( - cashPrior, - borrowsPrior, - reservesPrior - ); - require(borrowRateMantissa <= borrowRateMaxMantissa, "CT10"); - - (MathError mathErr, uint256 blockDelta) = subUInt( - currentBlockNumber, - accrualBlockNumberPrior - ); - require(mathErr == MathError.NO_ERROR, "CT11"); - - Exp memory simpleInterestFactor; - uint256 interestAccumulated; - uint256 totalBorrowsNew; - uint256 totalReservesNew; - uint256 borrowIndexNew; - - (mathErr, simpleInterestFactor) = mulScalar( - Exp({mantissa: borrowRateMantissa}), - blockDelta - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .ACCRUE_INTEREST_SIMPLE_INTEREST_FACTOR_CALCULATION_FAILED, - uint256(mathErr) - ); - } - - (mathErr, interestAccumulated) = mulScalarTruncate( - simpleInterestFactor, - borrowsPrior - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .ACCRUE_INTEREST_ACCUMULATED_INTEREST_CALCULATION_FAILED, - uint256(mathErr) - ); - } - - (mathErr, totalBorrowsNew) = addUInt(interestAccumulated, borrowsPrior); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .ACCRUE_INTEREST_NEW_TOTAL_BORROWS_CALCULATION_FAILED, - uint256(mathErr) - ); - } - - (mathErr, totalReservesNew) = mulScalarTruncateAddUInt( - Exp({mantissa: reserveFactorMantissa}), - interestAccumulated, - reservesPrior - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .ACCRUE_INTEREST_NEW_TOTAL_RESERVES_CALCULATION_FAILED, - uint256(mathErr) - ); - } - - if (interestRateModel.isTropykusInterestRateModel()) { - (mathErr, totalReservesNew) = newReserves( - borrowRateMantissa, - cashPrior, - borrowsPrior, - reservesPrior, - interestAccumulated - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .ACCRUE_INTEREST_NEW_TOTAL_RESERVES_CALCULATION_FAILED, - uint256(mathErr) - ); - } - } - - (mathErr, borrowIndexNew) = mulScalarTruncateAddUInt( - simpleInterestFactor, - borrowIndexPrior, - borrowIndexPrior - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .ACCRUE_INTEREST_NEW_BORROW_INDEX_CALCULATION_FAILED, - uint256(mathErr) - ); - } - - accrualBlockNumber = currentBlockNumber; - borrowIndex = borrowIndexNew; - totalBorrows = totalBorrowsNew; - totalReserves = totalReservesNew; - - emit AccrueInterest( - cashPrior, - interestAccumulated, - borrowIndexNew, - totalBorrowsNew - ); - - return uint256(Error.NO_ERROR); - } - - function newReserves( - uint256 borrowRateMantissa, - uint256 cashPrior, - uint256 borrowsPrior, - uint256 reservesPrior, - uint256 interestAccumulated - ) internal view returns (MathError mathErr, uint256 totalReservesNew) { - uint256 newReserveFactorMantissa; - uint256 utilizationRate = interestRateModel.utilizationRate( - cashPrior, - borrowsPrior, - reservesPrior - ); - uint256 expectedSupplyRate = interestRateModel.getSupplyRate( - cashPrior, - borrowsPrior, - reservesPrior, - reserveFactorMantissa - ); - if ( - interestRateModel.isAboveOptimal( - cashPrior, - borrowsPrior, - reservesPrior - ) - ) { - (mathErr, newReserveFactorMantissa) = mulScalarTruncate( - Exp({mantissa: utilizationRate}), - borrowRateMantissa - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - (mathErr, newReserveFactorMantissa) = subUInt( - newReserveFactorMantissa, - expectedSupplyRate - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - (mathErr, totalReservesNew) = mulScalarTruncateAddUInt( - Exp({mantissa: newReserveFactorMantissa}), - interestAccumulated, - reservesPrior - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - } else { - mathErr = MathError.NO_ERROR; - totalReservesNew = reservesPrior; - } - } - - /** - * @notice Sender supplies assets into the market and receives cTokens in exchange - * @dev Accrues interest whether or not the operation succeeds, unless reverted - * @param mintAmount The amount of the underlying asset to supply - * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual mint amount. - */ - function mintInternal(uint256 mintAmount) - internal - nonReentrant - returns (uint256, uint256) - { - if (WhitelistInterface(whitelist).enabled()) { - require(WhitelistInterface(whitelist).exist(msg.sender), "CT26"); - } - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return ( - fail(Error(error), FailureInfo.MINT_ACCRUE_INTEREST_FAILED), - 0 - ); - } - return mintFresh(msg.sender, mintAmount); - } - - struct MintLocalVars { - Error err; - MathError mathErr; - uint256 exchangeRateMantissa; - uint256 mintTokens; - uint256 totalSupplyNew; - uint256 accountTokensNew; - uint256 actualMintAmount; - } - - /** - * @notice User supplies assets into the market and receives cTokens in exchange - * @dev Assumes interest has already been accrued up to the current block - * @param minter The address of the account which is supplying the assets - * @param mintAmount The amount of the underlying asset to supply - * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual mint amount. - */ - function mintFresh(address minter, uint256 mintAmount) - internal - returns (uint256, uint256) - { - uint256 allowed = comptroller.mintAllowed( - address(this), - minter, - mintAmount - ); - if (allowed != 0) { - return ( - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.MINT_COMPTROLLER_REJECTION, - allowed - ), - 0 - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return ( - fail(Error.MARKET_NOT_FRESH, FailureInfo.MINT_FRESHNESS_CHECK), - 0 - ); - } - - MintLocalVars memory vars; - - ( - vars.mathErr, - vars.exchangeRateMantissa - ) = exchangeRateStoredInternal(); - if (vars.mathErr != MathError.NO_ERROR) { - return ( - failOpaque( - Error.MATH_ERROR, - FailureInfo.MINT_EXCHANGE_RATE_READ_FAILED, - uint256(vars.mathErr) - ), - 0 - ); - } - if (interestRateModel.isTropykusInterestRateModel()) { - SupplySnapshot storage supplySnapshot = accountTokens[minter]; - (, uint256 newTotalSupply) = addUInt( - supplySnapshot.underlyingAmount, - mintAmount - ); - require(newTotalSupply <= 0.1e18, "CT24"); - } - vars.actualMintAmount = doTransferIn(minter, mintAmount); - - (vars.mathErr, vars.mintTokens) = divScalarByExpTruncate( - vars.actualMintAmount, - Exp({mantissa: vars.exchangeRateMantissa}) - ); - require(vars.mathErr == MathError.NO_ERROR, "CT12"); - - (vars.mathErr, vars.totalSupplyNew) = addUInt( - totalSupply, - vars.mintTokens - ); - require(vars.mathErr == MathError.NO_ERROR, "CT13"); - - (vars.mathErr, vars.accountTokensNew) = addUInt( - accountTokens[minter].tokens, - vars.mintTokens - ); - require(vars.mathErr == MathError.NO_ERROR, "CT14"); - - uint256 currentSupplyRate = interestRateModel.getSupplyRate( - getCashPrior(), - totalBorrows, - totalReserves, - reserveFactorMantissa - ); - - bool isTropykusInterestRateModel = interestRateModel - .isTropykusInterestRateModel(); - - if (accountTokens[minter].tokens > 0) { - Exp memory updatedUnderlying; - if (isTropykusInterestRateModel) { - (, uint256 interestFactorMantissa, ) = tropykusInterestAccrued( - minter - ); - Exp memory interestFactor = Exp({ - mantissa: interestFactorMantissa - }); - uint256 currentUnderlyingAmount = accountTokens[minter] - .underlyingAmount; - MathError mErrorNewAmount; - (mErrorNewAmount, updatedUnderlying) = mulExp( - Exp({mantissa: currentUnderlyingAmount}), - interestFactor - ); - if (mErrorNewAmount != MathError.NO_ERROR) { - return ( - failOpaque( - Error.MATH_ERROR, - FailureInfo.MINT_EXCHANGE_CALCULATION_FAILED, - uint256(mErrorNewAmount) - ), - 0 - ); - } - } else { - uint256 currentTokens = accountTokens[minter].tokens; - MathError mErrorUpdatedUnderlying; - (mErrorUpdatedUnderlying, updatedUnderlying) = mulExp( - Exp({mantissa: currentTokens}), - Exp({mantissa: vars.exchangeRateMantissa}) - ); - if (mErrorUpdatedUnderlying != MathError.NO_ERROR) { - return ( - failOpaque( - Error.MATH_ERROR, - FailureInfo.MINT_EXCHANGE_CALCULATION_FAILED, - uint256(mErrorUpdatedUnderlying) - ), - 0 - ); - } - } - (, mintAmount) = addUInt(updatedUnderlying.mantissa, mintAmount); - } - - totalSupply = vars.totalSupplyNew; - accountTokens[minter] = SupplySnapshot({ - tokens: vars.accountTokensNew, - underlyingAmount: mintAmount, - suppliedAt: accrualBlockNumber, - promisedSupplyRate: currentSupplyRate - }); - - emit Mint(minter, vars.actualMintAmount, vars.mintTokens); - emit Transfer(address(this), minter, vars.mintTokens); - - return (uint256(Error.NO_ERROR), vars.actualMintAmount); - } - - /** - * @notice Sender redeems cTokens in exchange for a specified amount of underlying asset - * @dev Accrues interest whether or not the operation succeeds, unless reverted - * @param redeemAmount The amount of underlying to receive from redeeming cTokens - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function redeemUnderlyingInternal(uint256 redeemAmount) - internal - nonReentrant - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return - fail(Error(error), FailureInfo.REDEEM_ACCRUE_INTEREST_FAILED); - } - return redeemFresh(payable(msg.sender), redeemAmount); - } - - struct RedeemLocalVars { - Error err; - MathError mathErr; - uint256 exchangeRateMantissa; - uint256 redeemTokens; - uint256 redeemAmount; - uint256 totalSupplyNew; - uint256 accountTokensNew; - uint256 newSubsidyFund; - } - - /** - * @notice User redeems cTokens in exchange for the underlying asset - * @dev Assumes interest has already been accrued up to the current block - * @param redeemer The address of the account which is redeeming the tokens - * @param redeemAmountIn The number of underlying tokens to receive from redeeming cTokens - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function redeemFresh(address payable redeemer, uint256 redeemAmountIn) - internal - returns (uint256) - { - require(redeemAmountIn > 0, "CT15"); - - RedeemLocalVars memory vars; - - SupplySnapshot storage supplySnapshot = accountTokens[redeemer]; - - ( - vars.mathErr, - vars.exchangeRateMantissa - ) = exchangeRateStoredInternal(); - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.REDEEM_EXCHANGE_RATE_READ_FAILED, - uint256(vars.mathErr) - ); - } - - uint256 interestEarned; - uint256 subsidyFundPortion; - uint256 currentUnderlying; - - bool isTropykusInterestRateModel = interestRateModel - .isTropykusInterestRateModel(); - if (isTropykusInterestRateModel) { - currentUnderlying = supplySnapshot.underlyingAmount; - (, , interestEarned) = tropykusInterestAccrued(redeemer); - } - supplySnapshot.promisedSupplyRate = interestRateModel.getSupplyRate( - getCashPrior(), - totalBorrows, - totalReserves, - reserveFactorMantissa - ); - - if ( - isTropykusInterestRateModel && - !interestRateModel.isAboveOptimal( - getCashPrior(), - totalBorrows, - totalReserves - ) - ) { - uint256 borrowRate = interestRateModel.getBorrowRate( - getCashPrior(), - totalBorrows, - totalReserves - ); - - uint256 utilizationRate = interestRateModel.utilizationRate( - getCashPrior(), - totalBorrows, - totalReserves - ); - - (, uint256 estimatedEarning) = mulScalarTruncate( - Exp({mantissa: borrowRate}), - utilizationRate - ); - - (, subsidyFundPortion) = subUInt( - supplySnapshot.promisedSupplyRate, - estimatedEarning - ); - (, Exp memory subsidyFactor) = getExp( - subsidyFundPortion, - supplySnapshot.promisedSupplyRate - ); - (, subsidyFundPortion) = mulScalarTruncate( - subsidyFactor, - interestEarned - ); - } - - vars.redeemAmount = redeemAmountIn; - - if (isTropykusInterestRateModel) { - (, Exp memory num) = mulExp( - vars.redeemAmount, - supplySnapshot.tokens - ); - (, Exp memory realTokensWithdrawAmount) = getExp( - num.mantissa, - currentUnderlying - ); - vars.redeemTokens = realTokensWithdrawAmount.mantissa; - } else { - (vars.mathErr, vars.redeemTokens) = divScalarByExpTruncate( - redeemAmountIn, - Exp({mantissa: vars.exchangeRateMantissa}) - ); - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.REDEEM_EXCHANGE_AMOUNT_CALCULATION_FAILED, - uint256(vars.mathErr) - ); - } - } - // } - - uint256 allowed = comptroller.redeemAllowed( - address(this), - redeemer, - vars.redeemTokens - ); - if (allowed != 0) { - return - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.REDEEM_COMPTROLLER_REJECTION, - allowed - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.REDEEM_FRESHNESS_CHECK - ); - } - - (vars.mathErr, vars.totalSupplyNew) = subUInt( - totalSupply, - vars.redeemTokens - ); - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.REDEEM_NEW_TOTAL_SUPPLY_CALCULATION_FAILED, - uint256(vars.mathErr) - ); - } - - (, vars.newSubsidyFund) = subUInt(subsidyFund, subsidyFundPortion); - - (vars.mathErr, vars.accountTokensNew) = subUInt( - supplySnapshot.tokens, - vars.redeemTokens - ); - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.REDEEM_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED, - uint256(vars.mathErr) - ); - } - - uint256 cash = getCashPrior(); - if (isTropykusInterestRateModel) { - cash = address(this).balance; - } - - if (cash < vars.redeemAmount) { - return - fail( - Error.TOKEN_INSUFFICIENT_CASH, - FailureInfo.REDEEM_TRANSFER_OUT_NOT_POSSIBLE - ); - } - - doTransferOut(redeemer, vars.redeemAmount); - - totalSupply = vars.totalSupplyNew; - subsidyFund = vars.newSubsidyFund; - supplySnapshot.tokens = vars.accountTokensNew; - supplySnapshot.suppliedAt = accrualBlockNumber; - (, supplySnapshot.underlyingAmount) = subUInt( - supplySnapshot.underlyingAmount, - vars.redeemAmount - ); - - emit Transfer(redeemer, address(this), vars.redeemTokens); - emit Redeem(redeemer, vars.redeemAmount, vars.redeemTokens); - - comptroller.redeemVerify( - address(this), - redeemer, - vars.redeemAmount, - vars.redeemTokens - ); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Sender borrows assets from the protocol to their own address - * @param borrowAmount The amount of the underlying asset to borrow - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function borrowInternal(uint256 borrowAmount) - internal - nonReentrant - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return - fail(Error(error), FailureInfo.BORROW_ACCRUE_INTEREST_FAILED); - } - return borrowFresh(payable(msg.sender), borrowAmount); - } - - struct BorrowLocalVars { - MathError mathErr; - uint256 accountBorrows; - uint256 accountBorrowsNew; - uint256 totalBorrowsNew; - } - - /** - * @notice Users borrow assets from the protocol to their own address - * @param borrowAmount The amount of the underlying asset to borrow - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function borrowFresh(address payable borrower, uint256 borrowAmount) - internal - returns (uint256) - { - uint256 allowed = comptroller.borrowAllowed( - address(this), - borrower, - borrowAmount - ); - if (allowed != 0) { - return - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.BORROW_COMPTROLLER_REJECTION, - allowed - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.BORROW_FRESHNESS_CHECK - ); - } - - if (getCashPrior() < borrowAmount) { - return - fail( - Error.TOKEN_INSUFFICIENT_CASH, - FailureInfo.BORROW_CASH_NOT_AVAILABLE - ); - } - - BorrowLocalVars memory vars; - - (vars.mathErr, vars.accountBorrows) = borrowBalanceStoredInternal( - borrower - ); - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED, - uint256(vars.mathErr) - ); - } - - (vars.mathErr, vars.accountBorrowsNew) = addUInt( - vars.accountBorrows, - borrowAmount - ); - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED, - uint256(vars.mathErr) - ); - } - - (vars.mathErr, vars.totalBorrowsNew) = addUInt( - totalBorrows, - borrowAmount - ); - if (interestRateModel.isTropykusInterestRateModel()) { - require(vars.totalBorrowsNew <= 0.1e18, "CT25"); - } - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED, - uint256(vars.mathErr) - ); - } - - doTransferOut(borrower, borrowAmount); - - accountBorrows[borrower].principal = vars.accountBorrowsNew; - accountBorrows[borrower].interestIndex = borrowIndex; - totalBorrows = vars.totalBorrowsNew; - - emit Borrow( - borrower, - borrowAmount, - vars.accountBorrowsNew, - vars.totalBorrowsNew - ); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Sender repays their own borrow - * @param repayAmount The amount to repay - * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual repayment amount. - */ - function repayBorrowInternal(uint256 repayAmount) - internal - nonReentrant - returns (uint256, uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return ( - fail( - Error(error), - FailureInfo.REPAY_BORROW_ACCRUE_INTEREST_FAILED - ), - 0 - ); - } - return repayBorrowFresh(msg.sender, msg.sender, repayAmount); - } - - struct RepayBorrowLocalVars { - Error err; - MathError mathErr; - uint256 repayAmount; - uint256 borrowerIndex; - uint256 accountBorrows; - uint256 accountBorrowsNew; - uint256 totalBorrowsNew; - uint256 actualRepayAmount; - } - - /** - * @notice Borrows are repaid by another user (possibly the borrower). - * @param payer the account paying off the borrow - * @param borrower the account with the debt being payed off - * @param repayAmount the amount of undelrying tokens being returned - * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual repayment amount. - */ - function repayBorrowFresh( - address payer, - address borrower, - uint256 repayAmount - ) internal returns (uint256, uint256) { - uint256 allowed = comptroller.repayBorrowAllowed( - address(this), - payer, - borrower, - repayAmount - ); - if (allowed != 0) { - return ( - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.REPAY_BORROW_COMPTROLLER_REJECTION, - allowed - ), - 0 - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return ( - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.REPAY_BORROW_FRESHNESS_CHECK - ), - 0 - ); - } - - RepayBorrowLocalVars memory vars; - - vars.borrowerIndex = accountBorrows[borrower].interestIndex; - - (vars.mathErr, vars.accountBorrows) = borrowBalanceStoredInternal( - borrower - ); - if (vars.mathErr != MathError.NO_ERROR) { - return ( - failOpaque( - Error.MATH_ERROR, - FailureInfo - .REPAY_BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED, - uint256(vars.mathErr) - ), - 0 - ); - } - - if (repayAmount == type(uint256).max) { - vars.repayAmount = vars.accountBorrows; - } else { - vars.repayAmount = repayAmount; - } - - vars.actualRepayAmount = doTransferIn(payer, vars.repayAmount); - - (vars.mathErr, vars.accountBorrowsNew) = subUInt( - vars.accountBorrows, - vars.actualRepayAmount - ); - require(vars.mathErr == MathError.NO_ERROR, "CT16"); - - (vars.mathErr, vars.totalBorrowsNew) = subUInt( - totalBorrows, - vars.actualRepayAmount - ); - require(vars.mathErr == MathError.NO_ERROR, "CT17"); - - accountBorrows[borrower].principal = vars.accountBorrowsNew; - accountBorrows[borrower].interestIndex = borrowIndex; - totalBorrows = vars.totalBorrowsNew; - - emit RepayBorrow( - payer, - borrower, - vars.actualRepayAmount, - vars.accountBorrowsNew, - vars.totalBorrowsNew - ); - - return (uint256(Error.NO_ERROR), vars.actualRepayAmount); - } - - /** - * @notice The sender liquidates the borrowers collateral. - * The collateral seized is transferred to the liquidator. - * @param borrower The borrower of this cToken to be liquidated - * @param cTokenCollateral The market in which to seize collateral from the borrower - * @param repayAmount The amount of the underlying borrowed asset to repay - * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual repayment amount. - */ - function liquidateBorrowInternal( - address borrower, - uint256 repayAmount, - CTokenInterface cTokenCollateral - ) internal nonReentrant returns (uint256, uint256) { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return ( - fail( - Error(error), - FailureInfo.LIQUIDATE_ACCRUE_BORROW_INTEREST_FAILED - ), - 0 - ); - } - - error = cTokenCollateral.accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return ( - fail( - Error(error), - FailureInfo.LIQUIDATE_ACCRUE_COLLATERAL_INTEREST_FAILED - ), - 0 - ); - } - - // liquidateBorrowFresh emits borrow-specific logs on errors, so we don't need to - return - liquidateBorrowFresh( - msg.sender, - borrower, - repayAmount, - cTokenCollateral - ); - } - - /** - * @notice The liquidator liquidates the borrowers collateral. - * The collateral seized is transferred to the liquidator. - * @param borrower The borrower of this cToken to be liquidated - * @param liquidator The address repaying the borrow and seizing collateral - * @param cTokenCollateral The market in which to seize collateral from the borrower - * @param repayAmount The amount of the underlying borrowed asset to repay - * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual repayment amount. - */ - function liquidateBorrowFresh( - address liquidator, - address borrower, - uint256 repayAmount, - CTokenInterface cTokenCollateral - ) internal returns (uint256, uint256) { - uint256 allowed = comptroller.liquidateBorrowAllowed( - address(this), - address(cTokenCollateral), - liquidator, - borrower, - repayAmount - ); - if (allowed != 0) { - return ( - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.LIQUIDATE_COMPTROLLER_REJECTION, - allowed - ), - 0 - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return ( - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.LIQUIDATE_FRESHNESS_CHECK - ), - 0 - ); - } - - if (cTokenCollateral.accrualBlockNumber() != getBlockNumber()) { - return ( - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.LIQUIDATE_COLLATERAL_FRESHNESS_CHECK - ), - 0 - ); - } - - if (borrower == liquidator) { - return ( - fail( - Error.INVALID_ACCOUNT_PAIR, - FailureInfo.LIQUIDATE_LIQUIDATOR_IS_BORROWER - ), - 0 - ); - } - - if (repayAmount == 0) { - return ( - fail( - Error.INVALID_CLOSE_AMOUNT_REQUESTED, - FailureInfo.LIQUIDATE_CLOSE_AMOUNT_IS_ZERO - ), - 0 - ); - } - - if (repayAmount == type(uint256).max) { - return ( - fail( - Error.INVALID_CLOSE_AMOUNT_REQUESTED, - FailureInfo.LIQUIDATE_CLOSE_AMOUNT_IS_UINT_MAX - ), - 0 - ); - } - - ( - uint256 repayBorrowError, - uint256 actualRepayAmount - ) = repayBorrowFresh(liquidator, borrower, repayAmount); - if (repayBorrowError != uint256(Error.NO_ERROR)) { - return ( - fail( - Error(repayBorrowError), - FailureInfo.LIQUIDATE_REPAY_BORROW_FRESH_FAILED - ), - 0 - ); - } - - (uint256 amountSeizeError, uint256 seizeTokens) = comptroller - .liquidateCalculateSeizeTokens( - address(this), - address(cTokenCollateral), - actualRepayAmount - ); - require(amountSeizeError == uint256(Error.NO_ERROR), "CT18"); - - require(cTokenCollateral.balanceOf(borrower) >= seizeTokens, "CT19"); - - uint256 seizeError; - if (address(cTokenCollateral) == address(this)) { - seizeError = seizeInternal( - address(this), - liquidator, - borrower, - seizeTokens - ); - } else { - seizeError = cTokenCollateral.seize( - liquidator, - borrower, - seizeTokens - ); - } - - require(seizeError == uint256(Error.NO_ERROR), "CT20"); - - emit LiquidateBorrow( - liquidator, - borrower, - actualRepayAmount, - address(cTokenCollateral), - seizeTokens - ); - - return (uint256(Error.NO_ERROR), actualRepayAmount); - } - - /** - * @notice Transfers collateral tokens (this market) to the liquidator. - * @dev Will fail unless called by another cToken during the process of liquidation. - * Its absolutely critical to use msg.sender as the borrowed cToken and not a parameter. - * @param liquidator The account receiving seized collateral - * @param borrower The account having collateral seized - * @param seizeTokens The number of cTokens to seize - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function seize( - address liquidator, - address borrower, - uint256 seizeTokens - ) external override nonReentrant returns (uint256) { - return seizeInternal(msg.sender, liquidator, borrower, seizeTokens); - } - - struct SeizeVars { - uint256 seizeAmount; - uint256 exchangeRate; - uint256 borrowerTokensNew; - uint256 borrowerAmountNew; - uint256 liquidatorTokensNew; - uint256 liquidatorAmountNew; - uint256 totalCash; - uint256 supplyRate; - } - - /** - * @notice Transfers collateral tokens (this market) to the liquidator. - * @dev Called only during an in-kind liquidation, or by liquidateBorrow during the liquidation of another CToken. - * Its absolutely critical to use msg.sender as the seizer cToken and not a parameter. - * @param seizerToken The contract seizing the collateral (i.e. borrowed cToken) - * @param liquidator The account receiving seized collateral - * @param borrower The account having collateral seized - * @param seizeTokens The number of cTokens to seize - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function seizeInternal( - address seizerToken, - address liquidator, - address borrower, - uint256 seizeTokens - ) internal returns (uint256) { - uint256 allowed = comptroller.seizeAllowed( - address(this), - seizerToken, - liquidator, - borrower, - seizeTokens - ); - if (allowed != 0) { - return - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.LIQUIDATE_SEIZE_COMPTROLLER_REJECTION, - allowed - ); - } - - if (borrower == liquidator) { - return - fail( - Error.INVALID_ACCOUNT_PAIR, - FailureInfo.LIQUIDATE_SEIZE_LIQUIDATOR_IS_BORROWER - ); - } - - SeizeVars memory seizeVars; - - MathError mathErr; - - (mathErr, seizeVars.borrowerTokensNew) = subUInt( - accountTokens[borrower].tokens, - seizeTokens - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.LIQUIDATE_SEIZE_BALANCE_DECREMENT_FAILED, - uint256(mathErr) - ); - } - - seizeVars.totalCash = getCashPrior(); - seizeVars.supplyRate = interestRateModel.getSupplyRate( - seizeVars.totalCash, - totalBorrows, - totalReserves, - reserveFactorMantissa - ); - - (, seizeVars.exchangeRate) = interestRateModel.getExchangeRate( - seizeVars.totalCash, - totalBorrows, - totalReserves, - totalSupply - ); - - if (interestRateModel.isTropykusInterestRateModel()) { - (, seizeVars.exchangeRate) = tropykusExchangeRateStoredInternal( - borrower - ); - } - - (, seizeVars.seizeAmount) = mulUInt( - seizeTokens, - seizeVars.exchangeRate - ); - (, seizeVars.seizeAmount) = divUInt(seizeVars.seizeAmount, 1e18); - - (, seizeVars.borrowerAmountNew) = subUInt( - accountTokens[borrower].underlyingAmount, - seizeVars.seizeAmount - ); - - (mathErr, seizeVars.liquidatorTokensNew) = addUInt( - accountTokens[liquidator].tokens, - seizeTokens - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.LIQUIDATE_SEIZE_BALANCE_INCREMENT_FAILED, - uint256(mathErr) - ); - } - - (, seizeVars.liquidatorAmountNew) = addUInt( - accountTokens[liquidator].underlyingAmount, - seizeVars.seizeAmount - ); - - accountTokens[borrower].tokens = seizeVars.borrowerTokensNew; - accountTokens[borrower].underlyingAmount = seizeVars.borrowerAmountNew; - accountTokens[borrower].suppliedAt = getBlockNumber(); - accountTokens[borrower].promisedSupplyRate = seizeVars.supplyRate; - - accountTokens[liquidator].tokens = seizeVars.liquidatorTokensNew; - accountTokens[liquidator].underlyingAmount = seizeVars - .liquidatorAmountNew; - accountTokens[liquidator].suppliedAt = getBlockNumber(); - accountTokens[liquidator].promisedSupplyRate = seizeVars.supplyRate; - - emit Transfer(borrower, liquidator, seizeTokens); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Begins transfer of admin rights. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer. - * @dev Admin function to begin change of admin. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer. - * @param newPendingAdmin New pending admin. - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setPendingAdmin(address payable newPendingAdmin) - external - override - returns (uint256) - { - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_PENDING_ADMIN_OWNER_CHECK - ); - } - - address oldPendingAdmin = pendingAdmin; - - pendingAdmin = newPendingAdmin; - - emit NewPendingAdmin(oldPendingAdmin, newPendingAdmin); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Accepts transfer of admin rights. msg.sender must be pendingAdmin - * @dev Admin function for pending admin to accept role and update admin - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _acceptAdmin() external override returns (uint256) { - if (msg.sender != pendingAdmin || msg.sender == address(0)) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.ACCEPT_ADMIN_PENDING_ADMIN_CHECK - ); - } - - address oldAdmin = admin; - address oldPendingAdmin = pendingAdmin; - - admin = pendingAdmin; - - pendingAdmin = payable(address(0)); - - emit NewAdmin(oldAdmin, admin); - emit NewPendingAdmin(oldPendingAdmin, pendingAdmin); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Sets a new comptroller for the market - * @dev Admin function to set a new comptroller - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setComptroller(ComptrollerInterface newComptroller) - public - override - returns (uint256) - { - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_COMPTROLLER_OWNER_CHECK - ); - } - - ComptrollerInterface oldComptroller = comptroller; - require(newComptroller.isComptroller(), "CT21"); - - comptroller = newComptroller; - - emit NewComptroller(oldComptroller, newComptroller); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice accrues interest and sets a new reserve factor for the protocol using _setReserveFactorFresh - * @dev Admin function to accrue interest and set a new reserve factor - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setReserveFactor(uint256 newReserveFactorMantissa) - external - override - nonReentrant - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return - fail( - Error(error), - FailureInfo.SET_RESERVE_FACTOR_ACCRUE_INTEREST_FAILED - ); - } - return _setReserveFactorFresh(newReserveFactorMantissa); - } - - /** - * @notice Sets a new reserve factor for the protocol (*requires fresh interest accrual) - * @dev Admin function to set a new reserve factor - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setReserveFactorFresh(uint256 newReserveFactorMantissa) - internal - returns (uint256) - { - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_RESERVE_FACTOR_ADMIN_CHECK - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.SET_RESERVE_FACTOR_FRESH_CHECK - ); - } - - if (newReserveFactorMantissa > reserveFactorMaxMantissa) { - return - fail( - Error.BAD_INPUT, - FailureInfo.SET_RESERVE_FACTOR_BOUNDS_CHECK - ); - } - - uint256 oldReserveFactorMantissa = reserveFactorMantissa; - reserveFactorMantissa = newReserveFactorMantissa; - - emit NewReserveFactor( - oldReserveFactorMantissa, - newReserveFactorMantissa - ); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Accrues interest and reduces reserves by transferring from msg.sender - * @param addAmount Amount of addition to reserves - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _addReservesInternal(uint256 addAmount) - internal - nonReentrant - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return - fail( - Error(error), - FailureInfo.ADD_RESERVES_ACCRUE_INTEREST_FAILED - ); - } - - uint256 totalReservesNew; - uint256 actualAddAmount; - - if (accrualBlockNumber != getBlockNumber()) { - return ( - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.ADD_RESERVES_FRESH_CHECK - ) - ); - } - - actualAddAmount = doTransferIn(msg.sender, addAmount); - - totalReservesNew = totalReserves + actualAddAmount; - - require(totalReservesNew >= totalReserves, "CT22"); - - totalReserves = totalReservesNew; - - emit ReservesAdded(msg.sender, actualAddAmount, totalReservesNew); - - return (uint256(Error.NO_ERROR)); - } - - function _addSubsidyInternal(uint256 addAmount) - internal - nonReentrant - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - // accrueInterest emits logs on errors, but on top of that we want to log the fact that an attempted reduce reserves failed. - return fail(Error(error), FailureInfo.ADD_SUBSIDY_FUND_FAILED); - } - - uint256 subsidyFundNew; - uint256 actualAddAmount; - - if (accrualBlockNumber != getBlockNumber()) { - return ( - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.ADD_SUBSIDY_FUND_FRESH_CHECK - ) - ); - } - - actualAddAmount = doTransferIn(msg.sender, addAmount); - - subsidyFundNew = subsidyFund + actualAddAmount; - - require(subsidyFundNew >= subsidyFund, "CT22"); - - subsidyFund = subsidyFundNew; - - emit SubsidyAdded(msg.sender, actualAddAmount, subsidyFundNew); - - /* Return (NO_ERROR, actualAddAmount) */ - return (uint256(Error.NO_ERROR)); - } - - /** - * @notice Accrues interest and reduces reserves by transferring to admin - * @param reduceAmount Amount of reduction to reserves - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _reduceReserves(uint256 reduceAmount) - external - override - nonReentrant - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return - fail( - Error(error), - FailureInfo.REDUCE_RESERVES_ACCRUE_INTEREST_FAILED - ); - } - return _reduceReservesFresh(reduceAmount); - } - - /** - * @notice Reduces reserves by transferring to admin - * @dev Requires fresh interest accrual - * @param reduceAmount Amount of reduction to reserves - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _reduceReservesFresh(uint256 reduceAmount) - internal - returns (uint256) - { - uint256 totalReservesNew; - - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.REDUCE_RESERVES_ADMIN_CHECK - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.REDUCE_RESERVES_FRESH_CHECK - ); - } - - if (getCashPrior() < reduceAmount) { - return - fail( - Error.TOKEN_INSUFFICIENT_CASH, - FailureInfo.REDUCE_RESERVES_CASH_NOT_AVAILABLE - ); - } - - if (reduceAmount > totalReserves) { - return - fail(Error.BAD_INPUT, FailureInfo.REDUCE_RESERVES_VALIDATION); - } - - totalReservesNew = totalReserves - reduceAmount; - require(totalReservesNew <= totalReserves, "CT23"); - - totalReserves = totalReservesNew; - - doTransferOut(admin, reduceAmount); - - emit ReservesReduced(admin, reduceAmount, totalReservesNew); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice accrues interest and updates the interest rate model using _setInterestRateModelFresh - * @dev Admin function to accrue interest and update the interest rate model - * @param newInterestRateModel the new interest rate model to use - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setInterestRateModel(InterestRateModel newInterestRateModel) - public - override - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return - fail( - Error(error), - FailureInfo.SET_INTEREST_RATE_MODEL_ACCRUE_INTEREST_FAILED - ); - } - return _setInterestRateModelFresh(newInterestRateModel); - } - - /** - * @notice updates the interest rate model (*requires fresh interest accrual) - * @dev Admin function to update the interest rate model - * @param newInterestRateModel the new interest rate model to use - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setInterestRateModelFresh(InterestRateModel newInterestRateModel) - internal - returns (uint256) - { - InterestRateModel oldInterestRateModel; - - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_INTEREST_RATE_MODEL_OWNER_CHECK - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.SET_INTEREST_RATE_MODEL_FRESH_CHECK - ); - } - - oldInterestRateModel = interestRateModel; - - require(newInterestRateModel.isInterestRateModel(), "CT21"); - - interestRateModel = newInterestRateModel; - - emit NewMarketInterestRateModel( - oldInterestRateModel, - newInterestRateModel - ); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Gets balance of this contract in terms of the underlying - * @dev This excludes the value of the current message, if any - * @return The quantity of underlying owned by this contract - */ - function getCashPrior() internal view virtual returns (uint256); - - /** - * @dev Performs a transfer in, reverting upon failure. Returns the amount actually transferred to the protocol, in case of a fee. - * This may revert due to insufficient balance or insufficient allowance. - */ - function doTransferIn(address from, uint256 amount) - internal - virtual - returns (uint256); - - /** - * @dev Performs a transfer out, ideally returning an explanatory error code upon failure tather than reverting. - * If caller has not called checked protocol's balance, may revert due to insufficient cash held in the contract. - * If caller has checked protocol's balance, and verified it is >= amount, this should not revert in normal conditions. - */ - function doTransferOut(address payable to, uint256 amount) internal virtual; - - /** - * @dev Prevents a contract from calling itself, directly or indirectly. - */ - modifier nonReentrant() { - require(_notEntered, "re-entered"); - _notEntered = false; - _; - _notEntered = true; - } -} - - -// Dependency file: contracts/PriceOracle.sol - -// pragma solidity 0.8.6; - -// import "contracts/CToken.sol"; - -abstract contract PriceOracle { - /// @notice Indicator that this is a PriceOracle contract (for inspection) - bool public constant isPriceOracle = true; - - /** - * @notice Get the underlying price of a cToken asset - * @param cToken The cToken to get the underlying price of - * @return The underlying asset price mantissa (scaled by 1e18). - * Zero means the price is unavailable. - */ - function getUnderlyingPrice(CToken cToken) - external - view - virtual - returns (uint256); -} - - -// Dependency file: contracts/ComptrollerStorage.sol - -// pragma solidity 0.8.6; - -// import "contracts/CToken.sol"; -// import "contracts/PriceOracle.sol"; - -contract UnitrollerAdminStorage { - /** - * @notice Administrator for this contract - */ - address public admin; - - /** - * @notice Pending administrator for this contract - */ - address public pendingAdmin; - - /** - * @notice Active brains of Unitroller - */ - address public comptrollerImplementation; - - /** - * @notice Pending brains of Unitroller - */ - address public pendingComptrollerImplementation; -} - -contract ComptrollerV1Storage is UnitrollerAdminStorage { - - /** - * @notice Oracle which gives the price of any given asset - */ - PriceOracle public oracle; - - /** - * @notice Multiplier used to calculate the maximum repayAmount when liquidating a borrow - */ - uint public closeFactorMantissa; - - /** - * @notice Multiplier representing the discount on collateral that a liquidator receives - */ - uint public liquidationIncentiveMantissa; - - /** - * @notice Max number of assets a single account can participate in (borrow or use as collateral) - */ - uint public maxAssets; - - /** - * @notice Per-account mapping of "assets you are in", capped by maxAssets - */ - mapping(address => CToken[]) public accountAssets; - -} - -contract ComptrollerV2Storage is ComptrollerV1Storage { - struct Market { - /// @notice Whether or not this market is listed - bool isListed; - - /** - * @notice Multiplier representing the most one can borrow against their collateral in this market. - * For instance, 0.9 to allow borrowing 90% of collateral value. - * Must be between 0 and 1, and stored as a mantissa. - */ - uint collateralFactorMantissa; - - /// @notice Per-market mapping of "accounts in this asset" - mapping(address => bool) accountMembership; - - /// @notice Whether or not this market receives COMP - bool isComped; - } - - /** - * @notice Official mapping of cTokens -> Market metadata - * @dev Used e.g. to determine if a market is supported - */ - mapping(address => Market) public markets; - - - /** - * @notice The Pause Guardian can pause certain actions as a safety mechanism. - * Actions which allow users to remove their own assets cannot be paused. - * Liquidation / seizing / transfer can only be paused globally, not by market. - */ - address public pauseGuardian; - bool public _mintGuardianPaused; - bool public _borrowGuardianPaused; - bool public transferGuardianPaused; - bool public seizeGuardianPaused; - mapping(address => bool) public mintGuardianPaused; - mapping(address => bool) public borrowGuardianPaused; -} - -contract ComptrollerV3Storage is ComptrollerV2Storage { - struct CompMarketState { - /// @notice The market's last updated compBorrowIndex or compSupplyIndex - uint224 index; - - /// @notice The block number the index was last updated at - uint32 block; - } - - /// @notice A list of all markets - CToken[] public allMarkets; - - /// @notice The rate at which the flywheel distributes COMP, per block - uint public compRate; - - /// @notice The portion of compRate that each market currently receives - mapping(address => uint) public compSpeeds; - - /// @notice The COMP market supply state for each market - mapping(address => CompMarketState) public compSupplyState; - - /// @notice The COMP market borrow state for each market - mapping(address => CompMarketState) public compBorrowState; - - /// @notice The COMP borrow index for each market for each supplier as of the last time they accrued COMP - mapping(address => mapping(address => uint)) public compSupplierIndex; - - /// @notice The COMP borrow index for each market for each borrower as of the last time they accrued COMP - mapping(address => mapping(address => uint)) public compBorrowerIndex; - - /// @notice The COMP accrued but not yet transferred to each user - mapping(address => uint) public compAccrued; -} - -contract ComptrollerV4Storage is ComptrollerV3Storage { - // @notice The borrowCapGuardian can set borrowCaps to any number for any market. Lowering the borrow cap could disable borrowing on the given market. - address public borrowCapGuardian; - - // @notice Borrow caps enforced by borrowAllowed for each cToken address. Defaults to zero which corresponds to unlimited borrowing. - mapping(address => uint) public borrowCaps; - - // @notice address of the TROP token - address public tropAddress; -} - -contract ComptrollerV5Storage is ComptrollerV4Storage { - /// @notice The portion of COMP that each contributor receives per block - mapping(address => uint) public compContributorSpeeds; - - /// @notice Last block at which a contributor's COMP rewards have been allocated - mapping(address => uint) public lastContributorBlock; -} - - -// Dependency file: contracts/Unitroller.sol - -// pragma solidity 0.8.6; - -// import "contracts/ErrorReporter.sol"; -// import "contracts/ComptrollerStorage.sol"; - -/** - * @title ComptrollerCore - * @dev Storage for the comptroller is at this address, while execution is delegated to the `comptrollerImplementation`. - * CTokens should reference this contract as their comptroller. - */ -contract Unitroller is UnitrollerAdminStorage, ComptrollerErrorReporter { - /** - * @notice Emitted when pendingComptrollerImplementation is changed - */ - event NewPendingImplementation( - address oldPendingImplementation, - address newPendingImplementation - ); - - /** - * @notice Emitted when pendingComptrollerImplementation is accepted, which means comptroller implementation is updated - */ - event NewImplementation( - address oldImplementation, - address newImplementation - ); - - /** - * @notice Emitted when pendingAdmin is changed - */ - event NewPendingAdmin(address oldPendingAdmin, address newPendingAdmin); - - /** - * @notice Emitted when pendingAdmin is accepted, which means admin is updated - */ - event NewAdmin(address oldAdmin, address newAdmin); - - constructor() { - // Set admin to caller - admin = msg.sender; - } - - /*** Admin Functions ***/ - function _setPendingImplementation(address newPendingImplementation) - public - returns (uint256) - { - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_PENDING_IMPLEMENTATION_OWNER_CHECK - ); - } - - address oldPendingImplementation = pendingComptrollerImplementation; - - pendingComptrollerImplementation = newPendingImplementation; - - emit NewPendingImplementation( - oldPendingImplementation, - pendingComptrollerImplementation - ); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Accepts new implementation of comptroller. msg.sender must be pendingImplementation - * @dev Admin function for new implementation to accept it's role as implementation - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _acceptImplementation() public returns (uint256) { - // Check caller is pendingImplementation and pendingImplementation ≠ address(0) - if ( - msg.sender != pendingComptrollerImplementation || - pendingComptrollerImplementation == address(0) - ) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.ACCEPT_PENDING_IMPLEMENTATION_ADDRESS_CHECK - ); - } - - // Save current values for inclusion in log - address oldImplementation = comptrollerImplementation; - address oldPendingImplementation = pendingComptrollerImplementation; - - comptrollerImplementation = pendingComptrollerImplementation; - - pendingComptrollerImplementation = address(0); - - emit NewImplementation(oldImplementation, comptrollerImplementation); - emit NewPendingImplementation( - oldPendingImplementation, - pendingComptrollerImplementation - ); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Begins transfer of admin rights. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer. - * @dev Admin function to begin change of admin. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer. - * @param newPendingAdmin New pending admin. - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setPendingAdmin(address newPendingAdmin) - public - returns (uint256) - { - // Check caller = admin - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_PENDING_ADMIN_OWNER_CHECK - ); - } - - // Save current value, if any, for inclusion in log - address oldPendingAdmin = pendingAdmin; - - // Store pendingAdmin with value newPendingAdmin - pendingAdmin = newPendingAdmin; - - // Emit NewPendingAdmin(oldPendingAdmin, newPendingAdmin) - emit NewPendingAdmin(oldPendingAdmin, newPendingAdmin); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Accepts transfer of admin rights. msg.sender must be pendingAdmin - * @dev Admin function for pending admin to accept role and update admin - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _acceptAdmin() public returns (uint256) { - // Check caller is pendingAdmin and pendingAdmin ≠ address(0) - if (msg.sender != pendingAdmin || msg.sender == address(0)) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.ACCEPT_ADMIN_PENDING_ADMIN_CHECK - ); - } - - // Save current values for inclusion in log - address oldAdmin = admin; - address oldPendingAdmin = pendingAdmin; - - // Store admin with value pendingAdmin - admin = pendingAdmin; - - // Clear the pending value - pendingAdmin = address(0); - - emit NewAdmin(oldAdmin, admin); - emit NewPendingAdmin(oldPendingAdmin, pendingAdmin); - - return uint256(Error.NO_ERROR); - } - - /** - * @dev Delegates execution to an implementation contract. - * It returns to the external caller whatever the implementation returns - * or forwards reverts. - */ - function internalFallback() public payable { - // delegate all other functions to current implementation - (bool success, ) = comptrollerImplementation.delegatecall(msg.data); - - assembly { - let free_mem_ptr := mload(0x40) - returndatacopy(free_mem_ptr, 0, returndatasize()) - - switch success - case 0 { - revert(free_mem_ptr, returndatasize()) - } - default { - return(free_mem_ptr, returndatasize()) - } - } - } - - fallback() external payable { - internalFallback(); - } - - receive() external payable { - internalFallback(); - } -} - - -// Dependency file: contracts/Governance/TROP.sol - -// pragma solidity 0.8.6; -pragma experimental ABIEncoderV2; - -/** - * @title TROP ERC20 tokens. - * @author tropykus - * @notice Yield farming tokens that allow to propose and vote for protocol changes using the governance system. - */ -contract TROP { - /// @notice EIP-20 token name for this token - string public constant name = "tropykus"; - - /// @notice EIP-20 token symbol for this token - string public constant symbol = "TROP"; - - /// @notice EIP-20 token decimals for this token - uint8 public constant decimals = 18; - - /// @notice Total number of tokens in circulation - uint256 public constant totalSupply = 10000000e18; // 10 million TROP - - /// @notice Allowance amounts on behalf of others - mapping(address => mapping(address => uint96)) internal allowances; - - /// @notice Official record of token balances for each account - mapping(address => uint96) internal balances; - - /// @notice A record of each accounts delegate - mapping(address => address) public delegates; - - /// @notice A checkpoint for marking number of votes from a given block - struct Checkpoint { - uint32 fromBlock; - uint96 votes; - } - - /// @notice A record of votes checkpoints for each account, by index - mapping(address => mapping(uint32 => Checkpoint)) public checkpoints; - - /// @notice The number of checkpoints for each account - mapping(address => uint32) public numCheckpoints; - - /// @notice The EIP-712 typehash for the contract's domain - bytes32 public constant DOMAIN_TYPEHASH = - keccak256( - "EIP712Domain(string name,uint256 chainId,address verifyingContract)" - ); - - /// @notice The EIP-712 typehash for the delegation struct used by the contract - bytes32 public constant DELEGATION_TYPEHASH = - keccak256("Delegation(address delegatee,uint256 nonce,uint256 expiry)"); - - /// @notice A record of states for signing / validating signatures - mapping(address => uint256) public nonces; - - /// @notice An event thats emitted when an account changes its delegate - event DelegateChanged( - address indexed delegator, - address indexed fromDelegate, - address indexed toDelegate - ); - - /// @notice An event thats emitted when a delegate account's vote balance changes - event DelegateVotesChanged( - address indexed delegate, - uint256 previousBalance, - uint256 newBalance - ); - - /// @notice The standard EIP-20 transfer event - event Transfer(address indexed from, address indexed to, uint256 amount); - - /// @notice The standard EIP-20 approval event - event Approval( - address indexed owner, - address indexed spender, - uint256 amount - ); - - /** - * @notice Construct a new TROP token - * @param account The initial account to grant all the tokens - */ - constructor(address account) { - balances[account] = uint96(totalSupply); - emit Transfer(address(0), account, totalSupply); - } - - /** - * @notice Get the number of tokens `spender` is approved to spend on behalf of `account` - * @param account The address of the account holding the funds - * @param spender The address of the account spending the funds - * @return The number of tokens approved - */ - function allowance(address account, address spender) - external - view - returns (uint256) - { - return allowances[account][spender]; - } - - /** - * @notice Approve `spender` to transfer up to `amount` from `src` - * @dev This will overwrite the approval amount for `spender` - * and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve) - * @param spender The address of the account which may transfer tokens - * @param rawAmount The number of tokens that are approved (2^256-1 means infinite) - * @return Whether or not the approval succeeded - */ - function approve(address spender, uint256 rawAmount) - external - returns (bool) - { - uint96 amount; - if (rawAmount == type(uint256).max) { - amount = type(uint96).max; - } else { - amount = safe96(rawAmount, "TROP::approve: amount exceeds 96 bits"); - } - - allowances[msg.sender][spender] = amount; - - emit Approval(msg.sender, spender, amount); - return true; - } - - /** - * @notice Get the number of tokens held by the `account` - * @param account The address of the account to get the balance of - * @return The number of tokens held - */ - function balanceOf(address account) external view returns (uint256) { - return balances[account]; - } - - /** - * @notice Transfer `amount` tokens from `msg.sender` to `dst` - * @param dst The address of the destination account - * @param rawAmount The number of tokens to transfer - * @return Whether or not the transfer succeeded - */ - function transfer(address dst, uint256 rawAmount) external returns (bool) { - uint96 amount = safe96( - rawAmount, - "TROP::transfer: amount exceeds 96 bits" - ); - _transferTokens(msg.sender, dst, amount); - return true; - } - - /** - * @notice Transfer `amount` tokens from `src` to `dst` - * @param src The address of the source account - * @param dst The address of the destination account - * @param rawAmount The number of tokens to transfer - * @return Whether or not the transfer succeeded - */ - function transferFrom( - address src, - address dst, - uint256 rawAmount - ) external returns (bool) { - address spender = msg.sender; - uint96 spenderAllowance = allowances[src][spender]; - uint96 amount = safe96( - rawAmount, - "TROP::approve: amount exceeds 96 bits" - ); - - if (spender != src && spenderAllowance != type(uint96).max) { - uint96 newAllowance = sub96( - spenderAllowance, - amount, - "TROP::transferFrom: transfer amount exceeds spender allowance" - ); - allowances[src][spender] = newAllowance; - - emit Approval(src, spender, newAllowance); - } - - _transferTokens(src, dst, amount); - return true; - } - - /** - * @notice Delegate votes from `msg.sender` to `delegatee` - * @param delegatee The address to delegate votes to - */ - function delegate(address delegatee) public { - return _delegate(msg.sender, delegatee); - } - - /** - * @notice Delegates votes from signatory to `delegatee` - * @param delegatee The address to delegate votes to - * @param nonce The contract state required to match the signature - * @param expiry The time at which to expire the signature - * @param v The recovery byte of the signature - * @param r Half of the ECDSA signature pair - * @param s Half of the ECDSA signature pair - */ - function delegateBySig( - address delegatee, - uint256 nonce, - uint256 expiry, - uint8 v, - bytes32 r, - bytes32 s - ) public { - bytes32 domainSeparator = keccak256( - abi.encode( - DOMAIN_TYPEHASH, - keccak256(bytes(name)), - getChainId(), - address(this) - ) - ); - bytes32 structHash = keccak256( - abi.encode(DELEGATION_TYPEHASH, delegatee, nonce, expiry) - ); - bytes32 digest = keccak256( - abi.encodePacked("\x19\x01", domainSeparator, structHash) - ); - address signatory = ecrecover(digest, v, r, s); - require( - signatory != 0xdcc703c0E500B653Ca82273B7BFAd8045D85a470 && - signatory != address(0), - "TROP::delegateBySig: invalid signature" - ); - require( - nonce == nonces[signatory]++, - "TROP::delegateBySig: invalid nonce" - ); - require( - block.timestamp <= expiry, - "TROP::delegateBySig: signature expired" - ); - return _delegate(signatory, delegatee); - } - - /** - * @notice Gets the current votes balance for `account` - * @param account The address to get votes balance - * @return The number of current votes for `account` - */ - function getCurrentVotes(address account) external view returns (uint96) { - uint32 nCheckpoints = numCheckpoints[account]; - return - nCheckpoints > 0 ? checkpoints[account][nCheckpoints - 1].votes : 0; - } - - /** - * @notice Determine the prior number of votes for an account as of a block number - * @dev Block number must be a finalized block or else this function will revert to prevent misinformation. - * @param account The address of the account to check - * @param blockNumber The block number to get the vote balance at - * @return The number of votes the account had as of the given block - */ - function getPriorVotes(address account, uint256 blockNumber) - public - view - returns (uint96) - { - require( - blockNumber < block.number, - "TROP::getPriorVotes: not yet determined" - ); - - uint32 nCheckpoints = numCheckpoints[account]; - if (nCheckpoints == 0) { - return 0; - } - - // First check most recent balance - if (checkpoints[account][nCheckpoints - 1].fromBlock <= blockNumber) { - return checkpoints[account][nCheckpoints - 1].votes; - } - - // Next check implicit zero balance - if (checkpoints[account][0].fromBlock > blockNumber) { - return 0; - } - - uint32 lower = 0; - uint32 upper = nCheckpoints - 1; - while (upper > lower) { - uint32 center = upper - (upper - lower) / 2; // ceil, avoiding overflow - Checkpoint memory cp = checkpoints[account][center]; - if (cp.fromBlock == blockNumber) { - return cp.votes; - } else if (cp.fromBlock < blockNumber) { - lower = center; - } else { - upper = center - 1; - } - } - return checkpoints[account][lower].votes; - } - - function _delegate(address delegator, address delegatee) internal { - address currentDelegate = delegates[delegator]; - uint96 delegatorBalance = balances[delegator]; - delegates[delegator] = delegatee; - - emit DelegateChanged(delegator, currentDelegate, delegatee); - - _moveDelegates(currentDelegate, delegatee, delegatorBalance); - } - - function _transferTokens( - address src, - address dst, - uint96 amount - ) internal { - require( - src != address(0), - "TROP::_transferTokens: cannot transfer from the zero address" - ); - require( - dst != address(0), - "TROP::_transferTokens: cannot transfer to the zero address" - ); - - balances[src] = sub96( - balances[src], - amount, - "TROP::_transferTokens: transfer amount exceeds balance" - ); - balances[dst] = add96( - balances[dst], - amount, - "TROP::_transferTokens: transfer amount overflows" - ); - emit Transfer(src, dst, amount); - - _moveDelegates(delegates[src], delegates[dst], amount); - } - - function _moveDelegates( - address srcRep, - address dstRep, - uint96 amount - ) internal { - if (srcRep != dstRep && amount > 0) { - if (srcRep != address(0)) { - uint32 srcRepNum = numCheckpoints[srcRep]; - uint96 srcRepOld = srcRepNum > 0 - ? checkpoints[srcRep][srcRepNum - 1].votes - : 0; - uint96 srcRepNew = sub96( - srcRepOld, - amount, - "TROP::_moveVotes: vote amount underflows" - ); - _writeCheckpoint(srcRep, srcRepNum, srcRepOld, srcRepNew); - } - - if (dstRep != address(0)) { - uint32 dstRepNum = numCheckpoints[dstRep]; - uint96 dstRepOld = dstRepNum > 0 - ? checkpoints[dstRep][dstRepNum - 1].votes - : 0; - uint96 dstRepNew = add96( - dstRepOld, - amount, - "TROP::_moveVotes: vote amount overflows" - ); - _writeCheckpoint(dstRep, dstRepNum, dstRepOld, dstRepNew); - } - } - } - - function _writeCheckpoint( - address delegatee, - uint32 nCheckpoints, - uint96 oldVotes, - uint96 newVotes - ) internal { - uint32 blockNumber = safe32( - block.number, - "TROP::_writeCheckpoint: block number exceeds 32 bits" - ); - - if ( - nCheckpoints > 0 && - checkpoints[delegatee][nCheckpoints - 1].fromBlock == blockNumber - ) { - checkpoints[delegatee][nCheckpoints - 1].votes = newVotes; - } else { - checkpoints[delegatee][nCheckpoints] = Checkpoint( - blockNumber, - newVotes - ); - numCheckpoints[delegatee] = nCheckpoints + 1; - } - - emit DelegateVotesChanged(delegatee, oldVotes, newVotes); - } - - function safe32(uint256 n, string memory errorMessage) - internal - pure - returns (uint32) - { - require(n < 2**32, errorMessage); - return uint32(n); - } - - function safe96(uint256 n, string memory errorMessage) - internal - pure - returns (uint96) - { - require(n < 2**96, errorMessage); - return uint96(n); - } - - function add96( - uint96 a, - uint96 b, - string memory errorMessage - ) internal pure returns (uint96) { - uint96 c = a + b; - require(c >= a, errorMessage); - return c; - } - - function sub96( - uint96 a, - uint96 b, - string memory errorMessage - ) internal pure returns (uint96) { - require(b <= a, errorMessage); - return a - b; - } - - function getChainId() internal view returns (uint256) { - uint256 chainId; - assembly { - chainId := chainid() - } - return chainId; - } -} - - -// Root file: contracts/ComptrollerG5.sol - -pragma solidity 0.8.6; - -// import "contracts/CToken.sol"; -// import "contracts/ErrorReporter.sol"; -// import "contracts/Exponential.sol"; -// import "contracts/PriceOracle.sol"; -// import "contracts/ComptrollerInterface.sol"; -// import "contracts/ComptrollerStorage.sol"; -// import "contracts/Unitroller.sol"; -// import "contracts/Governance/TROP.sol"; - -/** - * @title tropykus Comptroller Contract - * @author tropykus - */ -contract ComptrollerG5 is - ComptrollerV4Storage, - ComptrollerInterface, - ComptrollerErrorReporter, - Exponential -{ - /// @notice Emitted when an admin supports a market - event MarketListed(CToken cToken); - - /// @notice Emitted when an account enters a market - event MarketEntered(CToken cToken, address account); - - /// @notice Emitted when an account exits a market - event MarketExited(CToken cToken, address account); - - /// @notice Emitted when close factor is changed by admin - event NewCloseFactor( - uint256 oldCloseFactorMantissa, - uint256 newCloseFactorMantissa - ); - - /// @notice Emitted when a collateral factor is changed by admin - event NewCollateralFactor( - CToken cToken, - uint256 oldCollateralFactorMantissa, - uint256 newCollateralFactorMantissa - ); - - /// @notice Emitted when liquidation incentive is changed by admin - event NewLiquidationIncentive( - uint256 oldLiquidationIncentiveMantissa, - uint256 newLiquidationIncentiveMantissa - ); - - /// @notice Emitted when maxAssets is changed by admin - event NewMaxAssets(uint256 oldMaxAssets, uint256 newMaxAssets); - - /// @notice Emitted when price oracle is changed - event NewPriceOracle( - PriceOracle oldPriceOracle, - PriceOracle newPriceOracle - ); - - /// @notice Emitted when pause guardian is changed - event NewPauseGuardian(address oldPauseGuardian, address newPauseGuardian); - - /// @notice Emitted when an action is paused globally - event ActionPaused(string action, bool pauseState); - - /// @notice Emitted when an action is paused on a market - event ActionPaused(CToken cToken, string action, bool pauseState); - - /// @notice Emitted when market comped status is changed - event MarketComped(CToken cToken, bool isComped); - - /// @notice Emitted when COMP rate is changed - event NewCompRate(uint256 oldCompRate, uint256 newCompRate); - - /// @notice Emitted when a new COMP speed is calculated for a market - event CompSpeedUpdated(CToken indexed cToken, uint256 newSpeed); - - /// @notice Emitted when COMP is distributed to a supplier - event DistributedSupplierComp( - CToken indexed cToken, - address indexed supplier, - uint256 compDelta, - uint256 compSupplyIndex - ); - - /// @notice Emitted when COMP is distributed to a borrower - event DistributedBorrowerComp( - CToken indexed cToken, - address indexed borrower, - uint256 compDelta, - uint256 compBorrowIndex - ); - - /// @notice Emitted when borrow cap for a cToken is changed - event NewBorrowCap(CToken indexed cToken, uint256 newBorrowCap); - - /// @notice Emitted when borrow cap guardian is changed - event NewBorrowCapGuardian( - address oldBorrowCapGuardian, - address newBorrowCapGuardian - ); - - /// @notice The threshold above which the flywheel transfers COMP, in wei - uint256 public constant compClaimThreshold = 0.001e18; - - /// @notice The initial COMP index for a market - uint224 public constant compInitialIndex = 1e36; - - // closeFactorMantissa must be strictly greater than this value - uint256 internal constant closeFactorMinMantissa = 0.05e18; // 0.05 - - // closeFactorMantissa must not exceed this value - uint256 internal constant closeFactorMaxMantissa = 0.9e18; // 0.9 - - // No collateralFactorMantissa may exceed this value - uint256 internal constant collateralFactorMaxMantissa = 0.9e18; // 0.9 - - // liquidationIncentiveMantissa must be no less than this value - uint256 internal constant liquidationIncentiveMinMantissa = 1.0e18; // 1.0 - - // liquidationIncentiveMantissa must be no greater than this value - uint256 internal constant liquidationIncentiveMaxMantissa = 1.5e18; // 1.5 - - constructor() { - admin = msg.sender; - } - - /*** Assets You Are In ***/ - - /** - * @notice Returns the assets an account has entered - * @param account The address of the account to pull assets for - * @return A dynamic list with the assets the account has entered - */ - function getAssetsIn(address account) - external - view - returns (CToken[] memory) - { - CToken[] memory assetsIn = accountAssets[account]; - - return assetsIn; - } - - /** - * @notice Returns whether the given account is entered in the given asset - * @param account The address of the account to check - * @param cToken The cToken to check - * @return True if the account is in the asset, otherwise false. - */ - function checkMembership(address account, CToken cToken) - external - view - returns (bool) - { - return markets[address(cToken)].accountMembership[account]; - } - - /** - * @notice Add assets to be included in account liquidity calculation - * @param cTokens The list of addresses of the cToken markets to be enabled - * @return Success indicator for whether each corresponding market was entered - */ - function enterMarkets(address[] memory cTokens) - public - override - returns (uint256[] memory) - { - uint256 len = cTokens.length; - - uint256[] memory results = new uint256[](len); - for (uint256 i = 0; i < len; i++) { - CToken cToken = CToken(cTokens[i]); - - results[i] = uint256(addToMarketInternal(cToken, msg.sender)); - } - - return results; - } - - /** - * @notice Add the market to the borrower's "assets in" for liquidity calculations - * @param cToken The market to enter - * @param borrower The address of the account to modify - * @return Success indicator for whether the market was entered - */ - function addToMarketInternal(CToken cToken, address borrower) - internal - returns (Error) - { - Market storage marketToJoin = markets[address(cToken)]; - - if (!marketToJoin.isListed) { - // market is not listed, cannot join - return Error.MARKET_NOT_LISTED; - } - - if (marketToJoin.accountMembership[borrower] == true) { - // already joined - return Error.NO_ERROR; - } - - if (accountAssets[borrower].length >= maxAssets) { - // no space, cannot join - return Error.TOO_MANY_ASSETS; - } - - // survived the gauntlet, add to list - // NOTE: we store these somewhat redundantly as a significant optimization - // this avoids having to iterate through the list for the most common use cases - // that is, only when we need to perform liquidity checks - // and not whenever we want to check if an account is in a particular market - marketToJoin.accountMembership[borrower] = true; - accountAssets[borrower].push(cToken); - - emit MarketEntered(cToken, borrower); - - return Error.NO_ERROR; - } - - /** - * @notice Removes asset from sender's account liquidity calculation - * @dev Sender must not have an outstanding borrow balance in the asset, - * or be providing necessary collateral for an outstanding borrow. - * @param cTokenAddress The address of the asset to be removed - * @return Whether or not the account successfully exited the market - */ - function exitMarket(address cTokenAddress) - external - override - returns (uint256) - { - CToken cToken = CToken(cTokenAddress); - /* Get sender tokensHeld and amountOwed underlying from the cToken */ - (uint256 oErr, uint256 tokensHeld, uint256 amountOwed, ) = cToken - .getAccountSnapshot(msg.sender); - require(oErr == 0, "C501"); // semi-opaque error code - - /* Fail if the sender has a borrow balance */ - if (amountOwed != 0) { - return - fail( - Error.NONZERO_BORROW_BALANCE, - FailureInfo.EXIT_MARKET_BALANCE_OWED - ); - } - - /* Fail if the sender is not permitted to redeem all of their tokens */ - uint256 allowed = redeemAllowedInternal( - cTokenAddress, - msg.sender, - tokensHeld - ); - if (allowed != 0) { - return - failOpaque( - Error.REJECTION, - FailureInfo.EXIT_MARKET_REJECTION, - allowed - ); - } - - Market storage marketToExit = markets[address(cToken)]; - - /* Return true if the sender is not already ‘in’ the market */ - if (!marketToExit.accountMembership[msg.sender]) { - return uint256(Error.NO_ERROR); - } - - /* Set cToken account membership to false */ - delete marketToExit.accountMembership[msg.sender]; - - /* Delete cToken from the account’s list of assets */ - // load into memory for faster iteration - CToken[] memory userAssetList = accountAssets[msg.sender]; - accountAssets[msg.sender] = new CToken[](0); - CToken[] storage newMarketList = accountAssets[msg.sender]; - uint256 len = userAssetList.length; - uint256 assetIndex = len; - for (uint256 i = 0; i < len; i++) { - if (userAssetList[i] == cToken) { - assetIndex = i; - continue; - } - newMarketList.push(userAssetList[i]); - } - - // We *must* have found the asset in the list or our redundant data structure is broken - assert(assetIndex < len); - - emit MarketExited(cToken, msg.sender); - - return uint256(Error.NO_ERROR); - } - - /*** Policy Hooks ***/ - - /** - * @notice Checks if the account should be allowed to mint tokens in the given market - * @param cToken The market to verify the mint against - * @param minter The account which would get the minted tokens - * @param mintAmount The amount of underlying being supplied to the market in exchange for tokens - * @return 0 if the mint is allowed, otherwise a semi-opaque error code (See ErrorReporter.sol) - */ - function mintAllowed( - address cToken, - address minter, - uint256 mintAmount - ) external override returns (uint256) { - // Pausing is a very serious situation - we revert to sound the alarms - require(!mintGuardianPaused[cToken], "C502"); - - // Shh - currently unused - minter; - mintAmount; - - if (!markets[cToken].isListed) { - return uint256(Error.MARKET_NOT_LISTED); - } - - // Keep the flywheel moving - updateCompSupplyIndex(cToken); - distributeSupplierComp(cToken, minter, false); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Validates mint and reverts on rejection. May emit logs. - * @param cToken Asset being minted - * @param minter The address minting the tokens - * @param actualMintAmount The amount of the underlying asset being minted - * @param mintTokens The number of tokens being minted - */ - function mintVerify( - address cToken, - address minter, - uint256 actualMintAmount, - uint256 mintTokens - ) external override { - // Shh - currently unused - cToken; - minter; - actualMintAmount; - mintTokens; - - // Shh - we don't ever want this hook to be marked pure - if (false) { - maxAssets = maxAssets; - } - } - - /** - * @notice Checks if the account should be allowed to redeem tokens in the given market - * @param cToken The market to verify the redeem against - * @param redeemer The account which would redeem the tokens - * @param redeemTokens The number of cTokens to exchange for the underlying asset in the market - * @return 0 if the redeem is allowed, otherwise a semi-opaque error code (See ErrorReporter.sol) - */ - function redeemAllowed( - address cToken, - address redeemer, - uint256 redeemTokens - ) external override returns (uint256) { - uint256 allowed = redeemAllowedInternal(cToken, redeemer, redeemTokens); - if (allowed != uint256(Error.NO_ERROR)) { - return allowed; - } - - // Keep the flywheel moving - updateCompSupplyIndex(cToken); - distributeSupplierComp(cToken, redeemer, false); - - return uint256(Error.NO_ERROR); - } - - function redeemAllowedInternal( - address cToken, - address redeemer, - uint256 redeemTokens - ) internal view returns (uint256) { - if (!markets[cToken].isListed) { - return uint256(Error.MARKET_NOT_LISTED); - } - - /* If the redeemer is not 'in' the market, then we can bypass the liquidity check */ - if (!markets[cToken].accountMembership[redeemer]) { - return uint256(Error.NO_ERROR); - } - - /* Otherwise, perform a hypothetical liquidity check to guard against shortfall */ - ( - Error err, - , - uint256 shortfall - ) = getHypotheticalAccountLiquidityInternal( - redeemer, - CToken(cToken), - redeemTokens, - 0 - ); - if (err != Error.NO_ERROR) { - return uint256(err); - } - if (shortfall > 0) { - return uint256(Error.INSUFFICIENT_LIQUIDITY); - } - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Validates redeem and reverts on rejection. May emit logs. - * @param cToken Asset being redeemed - * @param redeemer The address redeeming the tokens - * @param redeemAmount The amount of the underlying asset being redeemed - * @param redeemTokens The number of tokens being redeemed - */ - function redeemVerify( - address cToken, - address redeemer, - uint256 redeemAmount, - uint256 redeemTokens - ) external pure override { - // Shh - currently unused - cToken; - redeemer; - - // Require tokens is zero or amount is also zero - if (redeemTokens == 0 && redeemAmount > 0) { - revert("C503"); - } - } - - /** - * @notice Checks if the account should be allowed to borrow the underlying asset of the given market - * @param cToken The market to verify the borrow against - * @param borrower The account which would borrow the asset - * @param borrowAmount The amount of underlying the account would borrow - * @return 0 if the borrow is allowed, otherwise a semi-opaque error code (See ErrorReporter.sol) - */ - function borrowAllowed( - address cToken, - address borrower, - uint256 borrowAmount - ) external override returns (uint256) { - // Pausing is a very serious situation - we revert to sound the alarms - Error err; - uint256 shortfall; - require(!borrowGuardianPaused[cToken], "C504"); - - if (!markets[cToken].isListed) { - return uint256(Error.MARKET_NOT_LISTED); - } - - if (!markets[cToken].accountMembership[borrower]) { - // only cTokens may call borrowAllowed if borrower not in market - require(msg.sender == cToken, "C505"); - - // attempt to add borrower to the market - err = addToMarketInternal(CToken(msg.sender), borrower); - if (err != Error.NO_ERROR) { - return uint256(err); - } - - // it should be impossible to break the // important invariant - assert(markets[cToken].accountMembership[borrower]); - } - - if (oracle.getUnderlyingPrice(CToken(cToken)) == 0) { - return uint256(Error.PRICE_ERROR); - } - - uint256 borrowCap = borrowCaps[cToken]; - // Borrow cap of 0 corresponds to unlimited borrowing - if (borrowCap != 0) { - uint256 totalBorrows = CToken(cToken).totalBorrows(); - (MathError mathErr, uint256 nextTotalBorrows) = addUInt( - totalBorrows, - borrowAmount - ); - require(mathErr == MathError.NO_ERROR, "C506"); - require(nextTotalBorrows < borrowCap, "C507"); - } - - (err, , shortfall) = getHypotheticalAccountLiquidityInternal( - borrower, - CToken(cToken), - 0, - borrowAmount - ); - if (err != Error.NO_ERROR) { - return uint256(err); - } - if (shortfall > 0) { - return uint256(Error.INSUFFICIENT_LIQUIDITY); - } - - // Keep the flywheel moving - Exp memory borrowIndex = Exp({mantissa: CToken(cToken).borrowIndex()}); - updateCompBorrowIndex(cToken, borrowIndex); - distributeBorrowerComp(cToken, borrower, borrowIndex, false); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Validates borrow and reverts on rejection. May emit logs. - * @param cToken Asset whose underlying is being borrowed - * @param borrower The address borrowing the underlying - * @param borrowAmount The amount of the underlying asset requested to borrow - */ - function borrowVerify( - address cToken, - address borrower, - uint256 borrowAmount - ) external override { - // Shh - currently unused - cToken; - borrower; - borrowAmount; - - // Shh - we don't ever want this hook to be marked pure - if (false) { - maxAssets = maxAssets; - } - } - - /** - * @notice Checks if the account should be allowed to repay a borrow in the given market - * @param cToken The market to verify the repay against - * @param payer The account which would repay the asset - * @param borrower The account which would borrowed the asset - * @param repayAmount The amount of the underlying asset the account would repay - * @return 0 if the repay is allowed, otherwise a semi-opaque error code (See ErrorReporter.sol) - */ - function repayBorrowAllowed( - address cToken, - address payer, - address borrower, - uint256 repayAmount - ) external override returns (uint256) { - // Shh - currently unused - payer; - borrower; - repayAmount; - - if (!markets[cToken].isListed) { - return uint256(Error.MARKET_NOT_LISTED); - } - - // Keep the flywheel moving - Exp memory borrowIndex = Exp({mantissa: CToken(cToken).borrowIndex()}); - updateCompBorrowIndex(cToken, borrowIndex); - distributeBorrowerComp(cToken, borrower, borrowIndex, false); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Validates repayBorrow and reverts on rejection. May emit logs. - * @param cToken Asset being repaid - * @param payer The address repaying the borrow - * @param borrower The address of the borrower - * @param actualRepayAmount The amount of underlying being repaid - */ - function repayBorrowVerify( - address cToken, - address payer, - address borrower, - uint256 actualRepayAmount, - uint256 borrowerIndex - ) external override { - // Shh - currently unused - cToken; - payer; - borrower; - actualRepayAmount; - borrowerIndex; - - // Shh - we don't ever want this hook to be marked pure - if (false) { - maxAssets = maxAssets; - } - } - - /** - * @notice Checks if the liquidation should be allowed to occur - * @param cTokenBorrowed Asset which was borrowed by the borrower - * @param cTokenCollateral Asset which was used as collateral and will be seized - * @param liquidator The address repaying the borrow and seizing the collateral - * @param borrower The address of the borrower - * @param repayAmount The amount of underlying being repaid - */ - function liquidateBorrowAllowed( - address cTokenBorrowed, - address cTokenCollateral, - address liquidator, - address borrower, - uint256 repayAmount - ) external view override returns (uint256) { - // Shh - currently unused - liquidator; - - if ( - !markets[cTokenBorrowed].isListed || - !markets[cTokenCollateral].isListed - ) { - return uint256(Error.MARKET_NOT_LISTED); - } - - /* The borrower must have shortfall in order to be liquidatable */ - (Error err, , uint256 shortfall) = getAccountLiquidityInternal( - borrower - ); - if (err != Error.NO_ERROR) { - return uint256(err); - } - if (shortfall == 0) { - return uint256(Error.INSUFFICIENT_SHORTFALL); - } - - /* The liquidator may not repay more than what is allowed by the closeFactor */ - uint256 borrowBalance = CToken(cTokenBorrowed).borrowBalanceStored( - borrower - ); - (MathError mathErr, uint256 maxClose) = mulScalarTruncate( - Exp({mantissa: closeFactorMantissa}), - borrowBalance - ); - if (mathErr != MathError.NO_ERROR) { - return uint256(Error.MATH_ERROR); - } - if (repayAmount > maxClose) { - return uint256(Error.TOO_MUCH_REPAY); - } - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Validates liquidateBorrow and reverts on rejection. May emit logs. - * @param cTokenBorrowed Asset which was borrowed by the borrower - * @param cTokenCollateral Asset which was used as collateral and will be seized - * @param liquidator The address repaying the borrow and seizing the collateral - * @param borrower The address of the borrower - * @param actualRepayAmount The amount of underlying being repaid - */ - function liquidateBorrowVerify( - address cTokenBorrowed, - address cTokenCollateral, - address liquidator, - address borrower, - uint256 actualRepayAmount, - uint256 seizeTokens - ) external override { - // Shh - currently unused - cTokenBorrowed; - cTokenCollateral; - liquidator; - borrower; - actualRepayAmount; - seizeTokens; - - // Shh - we don't ever want this hook to be marked pure - if (false) { - maxAssets = maxAssets; - } - } - - /** - * @notice Checks if the seizing of assets should be allowed to occur - * @param cTokenCollateral Asset which was used as collateral and will be seized - * @param cTokenBorrowed Asset which was borrowed by the borrower - * @param liquidator The address repaying the borrow and seizing the collateral - * @param borrower The address of the borrower - * @param seizeTokens The number of collateral tokens to seize - */ - function seizeAllowed( - address cTokenCollateral, - address cTokenBorrowed, - address liquidator, - address borrower, - uint256 seizeTokens - ) external override returns (uint256) { - // Pausing is a very serious situation - we revert to sound the alarms - require(!seizeGuardianPaused, "C508"); - - // Shh - currently unused - seizeTokens; - - if ( - !markets[cTokenCollateral].isListed || - !markets[cTokenBorrowed].isListed - ) { - return uint256(Error.MARKET_NOT_LISTED); - } - - if ( - CToken(cTokenCollateral).comptroller() != - CToken(cTokenBorrowed).comptroller() - ) { - return uint256(Error.COMPTROLLER_MISMATCH); - } - - // Keep the flywheel moving - updateCompSupplyIndex(cTokenCollateral); - distributeSupplierComp(cTokenCollateral, borrower, false); - distributeSupplierComp(cTokenCollateral, liquidator, false); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Validates seize and reverts on rejection. May emit logs. - * @param cTokenCollateral Asset which was used as collateral and will be seized - * @param cTokenBorrowed Asset which was borrowed by the borrower - * @param liquidator The address repaying the borrow and seizing the collateral - * @param borrower The address of the borrower - * @param seizeTokens The number of collateral tokens to seize - */ - function seizeVerify( - address cTokenCollateral, - address cTokenBorrowed, - address liquidator, - address borrower, - uint256 seizeTokens - ) external override { - // Shh - currently unused - cTokenCollateral; - cTokenBorrowed; - liquidator; - borrower; - seizeTokens; - - // Shh - we don't ever want this hook to be marked pure - if (false) { - maxAssets = maxAssets; - } - } - - /** - * @notice Checks if the account should be allowed to transfer tokens in the given market - * @param cToken The market to verify the transfer against - * @param src The account which sources the tokens - * @param dst The account which receives the tokens - * @param transferTokens The number of cTokens to transfer - * @return 0 if the transfer is allowed, otherwise a semi-opaque error code (See ErrorReporter.sol) - */ - function transferAllowed( - address cToken, - address src, - address dst, - uint256 transferTokens - ) external override returns (uint256) { - // Pausing is a very serious situation - we revert to sound the alarms - require(!transferGuardianPaused, "C509"); - - // Currently the only consideration is whether or not - // the src is allowed to redeem this many tokens - uint256 allowed = redeemAllowedInternal(cToken, src, transferTokens); - if (allowed != uint256(Error.NO_ERROR)) { - return allowed; - } - - // Keep the flywheel moving - updateCompSupplyIndex(cToken); - distributeSupplierComp(cToken, src, false); - distributeSupplierComp(cToken, dst, false); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Validates transfer and reverts on rejection. May emit logs. - * @param cToken Asset being transferred - * @param src The account which sources the tokens - * @param dst The account which receives the tokens - * @param transferTokens The number of cTokens to transfer - */ - function transferVerify( - address cToken, - address src, - address dst, - uint256 transferTokens - ) external override { - // Shh - currently unused - cToken; - src; - dst; - transferTokens; - - // Shh - we don't ever want this hook to be marked pure - if (false) { - maxAssets = maxAssets; - } - } - - /*** Liquidity/Liquidation Calculations ***/ - - /** - * @dev Local vars for avoiding stack-depth limits in calculating account liquidity. - * Note that `cTokenBalance` is the number of cTokens the account owns in the market, - * whereas `borrowBalance` is the amount of underlying that the account has borrowed. - */ - struct AccountLiquidityLocalVars { - uint256 sumCollateral; - uint256 sumBorrowPlusEffects; - uint256 cTokenBalance; - uint256 borrowBalance; - uint256 exchangeRateMantissa; - uint256 oraclePriceMantissa; - Exp collateralFactor; - Exp exchangeRate; - Exp oraclePrice; - Exp tokensToDenom; - } - - /** - * @notice Determine the current account liquidity wrt collateral requirements - * @return (possible error code (semi-opaque), - account liquidity in excess of collateral requirements, - * account shortfall below collateral requirements) - */ - function getAccountLiquidity(address account) - public - view - returns ( - uint256, - uint256, - uint256 - ) - { - ( - Error err, - uint256 liquidity, - uint256 shortfall - ) = getHypotheticalAccountLiquidityInternal( - account, - CToken(address(0)), - 0, - 0 - ); - - return (uint256(err), liquidity, shortfall); - } - - /** - * @notice Determine the current account liquidity wrt collateral requirements - * @return (possible error code, - account liquidity in excess of collateral requirements, - * account shortfall below collateral requirements) - */ - function getAccountLiquidityInternal(address account) - internal - view - returns ( - Error, - uint256, - uint256 - ) - { - return - getHypotheticalAccountLiquidityInternal( - account, - CToken(address(0)), - 0, - 0 - ); - } - - /** - * @notice Determine what the account liquidity would be if the given amounts were redeemed/borrowed - * @param cTokenModify The market to hypothetically redeem/borrow in - * @param account The account to determine liquidity for - * @param redeemTokens The number of tokens to hypothetically redeem - * @param borrowAmount The amount of underlying to hypothetically borrow - * @return (possible error code (semi-opaque), - hypothetical account liquidity in excess of collateral requirements, - * hypothetical account shortfall below collateral requirements) - */ - function getHypotheticalAccountLiquidity( - address account, - address cTokenModify, - uint256 redeemTokens, - uint256 borrowAmount - ) - public - view - returns ( - uint256, - uint256, - uint256 - ) - { - ( - Error err, - uint256 liquidity, - uint256 shortfall - ) = getHypotheticalAccountLiquidityInternal( - account, - CToken(cTokenModify), - redeemTokens, - borrowAmount - ); - return (uint256(err), liquidity, shortfall); - } - - /** - * @notice Determine what the account liquidity would be if the given amounts were redeemed/borrowed - * @param cTokenModify The market to hypothetically redeem/borrow in - * @param account The account to determine liquidity for - * @param redeemTokens The number of tokens to hypothetically redeem - * @param borrowAmount The amount of underlying to hypothetically borrow - * @dev Note that we calculate the exchangeRateStored for each collateral cToken using stored data, - * without calculating accumulated interest. - * @return (possible error code, - hypothetical account liquidity in excess of collateral requirements, - * hypothetical account shortfall below collateral requirements) - */ - function getHypotheticalAccountLiquidityInternal( - address account, - CToken cTokenModify, - uint256 redeemTokens, - uint256 borrowAmount - ) - internal - view - returns ( - Error, - uint256, - uint256 - ) - { - AccountLiquidityLocalVars memory vars; // Holds all our calculation results - uint256 oErr; - MathError mErr; - - // For each asset the account is in - CToken[] memory assets = accountAssets[account]; - for (uint256 i = 0; i < assets.length; i++) { - CToken asset = assets[i]; - - // Read the balances and exchange rate from the cToken - ( - oErr, - vars.cTokenBalance, - vars.borrowBalance, - vars.exchangeRateMantissa - ) = asset.getAccountSnapshot(account); - if (oErr != 0) { - // semi-opaque error code, we assume NO_ERROR == 0 is invariant between upgrades - return (Error.SNAPSHOT_ERROR, 0, 0); - } - vars.collateralFactor = Exp({ - mantissa: markets[address(asset)].collateralFactorMantissa - }); - vars.exchangeRate = Exp({mantissa: vars.exchangeRateMantissa}); - - // Get the normalized price of the asset - vars.oraclePriceMantissa = oracle.getUnderlyingPrice(asset); - if (vars.oraclePriceMantissa == 0) { - return (Error.PRICE_ERROR, 0, 0); - } - vars.oraclePrice = Exp({mantissa: vars.oraclePriceMantissa}); - - // Pre-compute a conversion factor from tokens -> ether (normalized price value) - (mErr, vars.tokensToDenom) = mulExp3( - vars.collateralFactor, - vars.exchangeRate, - vars.oraclePrice - ); - if (mErr != MathError.NO_ERROR) { - return (Error.MATH_ERROR, 0, 0); - } - - // sumCollateral += tokensToDenom * cTokenBalance - (mErr, vars.sumCollateral) = mulScalarTruncateAddUInt( - vars.tokensToDenom, - vars.cTokenBalance, - vars.sumCollateral - ); - if (mErr != MathError.NO_ERROR) { - return (Error.MATH_ERROR, 0, 0); - } - - // sumBorrowPlusEffects += oraclePrice * borrowBalance - (mErr, vars.sumBorrowPlusEffects) = mulScalarTruncateAddUInt( - vars.oraclePrice, - vars.borrowBalance, - vars.sumBorrowPlusEffects - ); - if (mErr != MathError.NO_ERROR) { - return (Error.MATH_ERROR, 0, 0); - } - - // Calculate effects of interacting with cTokenModify - if (asset == cTokenModify) { - // redeem effect - // sumBorrowPlusEffects += tokensToDenom * redeemTokens - (mErr, vars.sumBorrowPlusEffects) = mulScalarTruncateAddUInt( - vars.tokensToDenom, - redeemTokens, - vars.sumBorrowPlusEffects - ); - if (mErr != MathError.NO_ERROR) { - return (Error.MATH_ERROR, 0, 0); - } - - // borrow effect - // sumBorrowPlusEffects += oraclePrice * borrowAmount - (mErr, vars.sumBorrowPlusEffects) = mulScalarTruncateAddUInt( - vars.oraclePrice, - borrowAmount, - vars.sumBorrowPlusEffects - ); - if (mErr != MathError.NO_ERROR) { - return (Error.MATH_ERROR, 0, 0); - } - } - } - - // These are safe, as the underflow condition is checked first - if (vars.sumCollateral > vars.sumBorrowPlusEffects) { - return ( - Error.NO_ERROR, - vars.sumCollateral - vars.sumBorrowPlusEffects, - 0 - ); - } else { - return ( - Error.NO_ERROR, - 0, - vars.sumBorrowPlusEffects - vars.sumCollateral - ); - } - } - - /** - * @notice Calculate number of tokens of collateral asset to seize given an underlying amount - * @dev Used in liquidation (called in cToken.liquidateBorrowFresh) - * @param cTokenBorrowed The address of the borrowed cToken - * @param cTokenCollateral The address of the collateral cToken - * @param actualRepayAmount The amount of cTokenBorrowed underlying to convert into cTokenCollateral tokens - * @return (errorCode, number of cTokenCollateral tokens to be seized in a liquidation) - */ - function liquidateCalculateSeizeTokens( - address cTokenBorrowed, - address cTokenCollateral, - uint256 actualRepayAmount - ) external view override returns (uint256, uint256) { - /* Read oracle prices for borrowed and collateral markets */ - uint256 priceBorrowedMantissa = oracle.getUnderlyingPrice( - CToken(cTokenBorrowed) - ); - uint256 priceCollateralMantissa = oracle.getUnderlyingPrice( - CToken(cTokenCollateral) - ); - if (priceBorrowedMantissa == 0 || priceCollateralMantissa == 0) { - return (uint256(Error.PRICE_ERROR), 0); - } - - /* - * Get the exchange rate and calculate the number of collateral tokens to seize: - * seizeAmount = actualRepayAmount * liquidationIncentive * priceBorrowed / priceCollateral - * seizeTokens = seizeAmount / exchangeRate - * = actualRepayAmount * (liquidationIncentive * priceBorrowed) / (priceCollateral * exchangeRate) - */ - uint256 exchangeRateMantissa = CToken(cTokenCollateral) - .exchangeRateStored(); // Note: reverts on error - uint256 seizeTokens; - Exp memory numerator; - Exp memory denominator; - Exp memory ratio; - MathError mathErr; - - (mathErr, numerator) = mulExp( - liquidationIncentiveMantissa, - priceBorrowedMantissa - ); - if (mathErr != MathError.NO_ERROR) { - return (uint256(Error.MATH_ERROR), 0); - } - - (mathErr, denominator) = mulExp( - priceCollateralMantissa, - exchangeRateMantissa - ); - if (mathErr != MathError.NO_ERROR) { - return (uint256(Error.MATH_ERROR), 0); - } - - (mathErr, ratio) = divExp(numerator, denominator); - if (mathErr != MathError.NO_ERROR) { - return (uint256(Error.MATH_ERROR), 0); - } - - (mathErr, seizeTokens) = mulScalarTruncate(ratio, actualRepayAmount); - if (mathErr != MathError.NO_ERROR) { - return (uint256(Error.MATH_ERROR), 0); - } - - return (uint256(Error.NO_ERROR), seizeTokens); - } - - /*** Admin Functions ***/ - - /** - * @notice Sets a new price oracle for the comptroller - * @dev Admin function to set a new price oracle - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setPriceOracle(PriceOracle newOracle) public returns (uint256) { - // Check caller is admin - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_PRICE_ORACLE_OWNER_CHECK - ); - } - - // Track the old oracle for the comptroller - PriceOracle oldOracle = oracle; - - // Set comptroller's oracle to newOracle - oracle = newOracle; - - // Emit NewPriceOracle(oldOracle, newOracle) - emit NewPriceOracle(oldOracle, newOracle); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Sets the closeFactor used when liquidating borrows - * @dev Admin function to set closeFactor - * @param newCloseFactorMantissa New close factor, scaled by 1e18 - * @return uint 0=success, otherwise a failure. (See ErrorReporter for details) - */ - function _setCloseFactor(uint256 newCloseFactorMantissa) - external - returns (uint256) - { - // Check caller is admin - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_CLOSE_FACTOR_OWNER_CHECK - ); - } - - Exp memory newCloseFactorExp = Exp({mantissa: newCloseFactorMantissa}); - Exp memory lowLimit = Exp({mantissa: closeFactorMinMantissa}); - if (lessThanOrEqualExp(newCloseFactorExp, lowLimit)) { - return - fail( - Error.INVALID_CLOSE_FACTOR, - FailureInfo.SET_CLOSE_FACTOR_VALIDATION - ); - } - - Exp memory highLimit = Exp({mantissa: closeFactorMaxMantissa}); - if (lessThanExp(highLimit, newCloseFactorExp)) { - return - fail( - Error.INVALID_CLOSE_FACTOR, - FailureInfo.SET_CLOSE_FACTOR_VALIDATION - ); - } - - uint256 oldCloseFactorMantissa = closeFactorMantissa; - closeFactorMantissa = newCloseFactorMantissa; - emit NewCloseFactor(oldCloseFactorMantissa, closeFactorMantissa); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Sets the collateralFactor for a market - * @dev Admin function to set per-market collateralFactor - * @param cToken The market to set the factor on - * @param newCollateralFactorMantissa The new collateral factor, scaled by 1e18 - * @return uint 0=success, otherwise a failure. (See ErrorReporter for details) - */ - function _setCollateralFactor( - CToken cToken, - uint256 newCollateralFactorMantissa - ) external returns (uint256) { - // Check caller is admin - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_COLLATERAL_FACTOR_OWNER_CHECK - ); - } - - // Verify market is listed - Market storage market = markets[address(cToken)]; - if (!market.isListed) { - return - fail( - Error.MARKET_NOT_LISTED, - FailureInfo.SET_COLLATERAL_FACTOR_NO_EXISTS - ); - } - - Exp memory newCollateralFactorExp = Exp({ - mantissa: newCollateralFactorMantissa - }); - - // Check collateral factor <= 0.9 - Exp memory highLimit = Exp({mantissa: collateralFactorMaxMantissa}); - if (lessThanExp(highLimit, newCollateralFactorExp)) { - return - fail( - Error.INVALID_COLLATERAL_FACTOR, - FailureInfo.SET_COLLATERAL_FACTOR_VALIDATION - ); - } - - // If collateral factor != 0, fail if price == 0 - if ( - newCollateralFactorMantissa != 0 && - oracle.getUnderlyingPrice(cToken) == 0 - ) { - return - fail( - Error.PRICE_ERROR, - FailureInfo.SET_COLLATERAL_FACTOR_WITHOUT_PRICE - ); - } - - // Set market's collateral factor to new collateral factor, remember old value - uint256 oldCollateralFactorMantissa = market.collateralFactorMantissa; - market.collateralFactorMantissa = newCollateralFactorMantissa; - - // Emit event with asset, old collateral factor, and new collateral factor - emit NewCollateralFactor( - cToken, - oldCollateralFactorMantissa, - newCollateralFactorMantissa - ); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Sets maxAssets which controls how many markets can be entered - * @dev Admin function to set maxAssets - * @param newMaxAssets New max assets - * @return uint 0=success, otherwise a failure. (See ErrorReporter for details) - */ - function _setMaxAssets(uint256 newMaxAssets) external returns (uint256) { - // Check caller is admin - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_MAX_ASSETS_OWNER_CHECK - ); - } - - uint256 oldMaxAssets = maxAssets; - maxAssets = newMaxAssets; - emit NewMaxAssets(oldMaxAssets, newMaxAssets); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Sets liquidationIncentive - * @dev Admin function to set liquidationIncentive - * @param newLiquidationIncentiveMantissa New liquidationIncentive scaled by 1e18 - * @return uint 0=success, otherwise a failure. (See ErrorReporter for details) - */ - function _setLiquidationIncentive(uint256 newLiquidationIncentiveMantissa) - external - returns (uint256) - { - // Check caller is admin - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_LIQUIDATION_INCENTIVE_OWNER_CHECK - ); - } - - // Check de-scaled min <= newLiquidationIncentive <= max - Exp memory newLiquidationIncentive = Exp({ - mantissa: newLiquidationIncentiveMantissa - }); - Exp memory minLiquidationIncentive = Exp({ - mantissa: liquidationIncentiveMinMantissa - }); - if (lessThanExp(newLiquidationIncentive, minLiquidationIncentive)) { - return - fail( - Error.INVALID_LIQUIDATION_INCENTIVE, - FailureInfo.SET_LIQUIDATION_INCENTIVE_VALIDATION - ); - } - - Exp memory maxLiquidationIncentive = Exp({ - mantissa: liquidationIncentiveMaxMantissa - }); - if (lessThanExp(maxLiquidationIncentive, newLiquidationIncentive)) { - return - fail( - Error.INVALID_LIQUIDATION_INCENTIVE, - FailureInfo.SET_LIQUIDATION_INCENTIVE_VALIDATION - ); - } - - // Save current value for use in log - uint256 oldLiquidationIncentiveMantissa = liquidationIncentiveMantissa; - - // Set liquidation incentive to new incentive - liquidationIncentiveMantissa = newLiquidationIncentiveMantissa; - - // Emit event with old incentive, new incentive - emit NewLiquidationIncentive( - oldLiquidationIncentiveMantissa, - newLiquidationIncentiveMantissa - ); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Add the market to the markets mapping and set it as listed - * @dev Admin function to set isListed and add support for the market - * @param cToken The address of the market (token) to list - * @return uint 0=success, otherwise a failure. (See enum Error for details) - */ - function _supportMarket(CToken cToken) external returns (uint256) { - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SUPPORT_MARKET_OWNER_CHECK - ); - } - - if (markets[address(cToken)].isListed) { - return - fail( - Error.MARKET_ALREADY_LISTED, - FailureInfo.SUPPORT_MARKET_EXISTS - ); - } - - cToken.isCToken(); // Sanity check to make sure its really a CToken - - Market storage market = markets[address(cToken)]; - market.isListed = true; - market.isComped = false; - market.collateralFactorMantissa = 0; - - _addMarketInternal(address(cToken)); - - emit MarketListed(cToken); - - return uint256(Error.NO_ERROR); - } - - function _addMarketInternal(address cToken) internal { - for (uint256 i = 0; i < allMarkets.length; i++) { - require(allMarkets[i] != CToken(cToken), "C510"); - } - allMarkets.push(CToken(cToken)); - } - - /** - * @notice Set the given borrow caps for the given cToken markets. Borrowing that brings total borrows to or above borrow cap will revert. - * @dev Admin or borrowCapGuardian function to set the borrow caps. A borrow cap of 0 corresponds to unlimited borrowing. - * @param cTokens The addresses of the markets (tokens) to change the borrow caps for - * @param newBorrowCaps The new borrow cap values in underlying to be set. A value of 0 corresponds to unlimited borrowing. - */ - function _setMarketBorrowCaps( - CToken[] calldata cTokens, - uint256[] calldata newBorrowCaps - ) external { - require(msg.sender == admin || msg.sender == borrowCapGuardian, "C511"); - - uint256 numMarkets = cTokens.length; - uint256 numBorrowCaps = newBorrowCaps.length; - - require(numMarkets != 0 && numMarkets == numBorrowCaps, "C512"); - - for (uint256 i = 0; i < numMarkets; i++) { - borrowCaps[address(cTokens[i])] = newBorrowCaps[i]; - emit NewBorrowCap(cTokens[i], newBorrowCaps[i]); - } - } - - /** - * @notice Admin function to change the Borrow Cap Guardian - * @param newBorrowCapGuardian The address of the new Borrow Cap Guardian - */ - function _setBorrowCapGuardian(address newBorrowCapGuardian) external { - require(msg.sender == admin, "C513"); - - // Save current value for inclusion in log - address oldBorrowCapGuardian = borrowCapGuardian; - - // Store borrowCapGuardian with value newBorrowCapGuardian - borrowCapGuardian = newBorrowCapGuardian; - - // Emit NewBorrowCapGuardian(OldBorrowCapGuardian, NewBorrowCapGuardian) - emit NewBorrowCapGuardian(oldBorrowCapGuardian, newBorrowCapGuardian); - } - - /** - * @notice Admin function to change the Pause Guardian - * @param newPauseGuardian The address of the new Pause Guardian - * @return uint 0=success, otherwise a failure. (See enum Error for details) - */ - function _setPauseGuardian(address newPauseGuardian) - public - returns (uint256) - { - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_PAUSE_GUARDIAN_OWNER_CHECK - ); - } - - // Save current value for inclusion in log - address oldPauseGuardian = pauseGuardian; - - // Store pauseGuardian with value newPauseGuardian - pauseGuardian = newPauseGuardian; - - // Emit NewPauseGuardian(OldPauseGuardian, NewPauseGuardian) - emit NewPauseGuardian(oldPauseGuardian, pauseGuardian); - - return uint256(Error.NO_ERROR); - } - - function _setMintPaused(CToken cToken, bool state) public returns (bool) { - require(markets[address(cToken)].isListed, "C514"); - require(msg.sender == pauseGuardian || msg.sender == admin, "C515"); - require(msg.sender == admin || state == true, "C516"); - - mintGuardianPaused[address(cToken)] = state; - emit ActionPaused(cToken, "Mint", state); - return state; - } - - function _setBorrowPaused(CToken cToken, bool state) public returns (bool) { - require(markets[address(cToken)].isListed, "C514"); - require(msg.sender == pauseGuardian || msg.sender == admin, "C515"); - require(msg.sender == admin || state == true, "C516"); - - borrowGuardianPaused[address(cToken)] = state; - emit ActionPaused(cToken, "Borrow", state); - return state; - } - - function _setTransferPaused(bool state) public returns (bool) { - require(msg.sender == pauseGuardian || msg.sender == admin, "C515"); - require(msg.sender == admin || state == true, "C516"); - - transferGuardianPaused = state; - emit ActionPaused("Transfer", state); - return state; - } - - function _setSeizePaused(bool state) public returns (bool) { - require(msg.sender == pauseGuardian || msg.sender == admin, "C515"); - require(msg.sender == admin || state == true, "C516"); - - seizeGuardianPaused = state; - emit ActionPaused("Seize", state); - return state; - } - - function _become(Unitroller unitroller) public { - require(msg.sender == unitroller.admin(), "C517"); - require(unitroller._acceptImplementation() == 0, "C518"); - } - - /** - * @notice Checks caller is admin, or this contract is becoming the new implementation - */ - function adminOrInitializing() internal view returns (bool) { - return msg.sender == admin || msg.sender == comptrollerImplementation; - } - - /*** Comp Distribution ***/ - - /** - * @notice Recalculate and update COMP speeds for all COMP markets - */ - function refreshCompSpeeds() public { - require(msg.sender == tx.origin, "C519"); - refreshCompSpeedsInternal(); - } - - function refreshCompSpeedsInternal() internal { - CToken[] memory allMarkets_ = allMarkets; - - for (uint256 i = 0; i < allMarkets_.length; i++) { - CToken cToken = allMarkets_[i]; - Exp memory borrowIndex = Exp({mantissa: cToken.borrowIndex()}); - updateCompSupplyIndex(address(cToken)); - updateCompBorrowIndex(address(cToken), borrowIndex); - } - - Exp memory totalUtility = Exp({mantissa: 0}); - Exp[] memory utilities = new Exp[](allMarkets_.length); - for (uint256 i = 0; i < allMarkets_.length; i++) { - CToken cToken = allMarkets_[i]; - if (markets[address(cToken)].isComped) { - Exp memory assetPrice = Exp({ - mantissa: oracle.getUnderlyingPrice(cToken) - }); - Exp memory utility = mul_(assetPrice, cToken.totalBorrows()); - utilities[i] = utility; - totalUtility = add_(totalUtility, utility); - } - } - - for (uint256 i = 0; i < allMarkets_.length; i++) { - CToken cToken = allMarkets[i]; - uint256 newSpeed = totalUtility.mantissa > 0 - ? mul_(compRate, div_(utilities[i], totalUtility)) - : 0; - compSpeeds[address(cToken)] = newSpeed; - emit CompSpeedUpdated(cToken, newSpeed); - } - } - - /** - * @notice Accrue COMP to the market by updating the supply index - * @param cToken The market whose supply index to update - */ - function updateCompSupplyIndex(address cToken) internal { - CompMarketState storage supplyState = compSupplyState[cToken]; - uint256 supplySpeed = compSpeeds[cToken]; - uint256 blockNumber = getBlockNumber(); - uint256 deltaBlocks = sub_(blockNumber, uint256(supplyState.block)); - if (deltaBlocks > 0 && supplySpeed > 0) { - uint256 supplyTokens = CToken(cToken).totalSupply(); - uint256 compAccrued = mul_(deltaBlocks, supplySpeed); - Double memory ratio = supplyTokens > 0 - ? fraction(compAccrued, supplyTokens) - : Double({mantissa: 0}); - Double memory index = add_( - Double({mantissa: supplyState.index}), - ratio - ); - compSupplyState[cToken] = CompMarketState({ - index: safe224(index.mantissa, "C520"), - block: safe32(blockNumber, "C521") - }); - } else if (deltaBlocks > 0) { - supplyState.block = safe32(blockNumber, "C521"); - } - } - - /** - * @notice Accrue COMP to the market by updating the borrow index - * @param cToken The market whose borrow index to update - */ - function updateCompBorrowIndex(address cToken, Exp memory marketBorrowIndex) - internal - { - CompMarketState storage borrowState = compBorrowState[cToken]; - uint256 borrowSpeed = compSpeeds[cToken]; - uint256 blockNumber = getBlockNumber(); - uint256 deltaBlocks = sub_(blockNumber, uint256(borrowState.block)); - if (deltaBlocks > 0 && borrowSpeed > 0) { - uint256 borrowAmount = div_( - CToken(cToken).totalBorrows(), - marketBorrowIndex - ); - uint256 compAccrued = mul_(deltaBlocks, borrowSpeed); - Double memory ratio = borrowAmount > 0 - ? fraction(compAccrued, borrowAmount) - : Double({mantissa: 0}); - Double memory index = add_( - Double({mantissa: borrowState.index}), - ratio - ); - compBorrowState[cToken] = CompMarketState({ - index: safe224(index.mantissa, "C520"), - block: safe32(blockNumber, "C521") - }); - } else if (deltaBlocks > 0) { - borrowState.block = safe32(blockNumber, "C521"); - } - } - - /** - * @notice Calculate COMP accrued by a supplier and possibly transfer it to them - * @param cToken The market in which the supplier is interacting - * @param supplier The address of the supplier to distribute COMP to - */ - function distributeSupplierComp( - address cToken, - address supplier, - bool distributeAll - ) internal { - CompMarketState storage supplyState = compSupplyState[cToken]; - Double memory supplyIndex = Double({mantissa: supplyState.index}); - Double memory supplierIndex = Double({ - mantissa: compSupplierIndex[cToken][supplier] - }); - compSupplierIndex[cToken][supplier] = supplyIndex.mantissa; - - if (supplierIndex.mantissa == 0 && supplyIndex.mantissa > 0) { - supplierIndex.mantissa = compInitialIndex; - } - - Double memory deltaIndex = sub_(supplyIndex, supplierIndex); - uint256 supplierTokens = CToken(cToken).balanceOf(supplier); - uint256 supplierDelta = mul_(supplierTokens, deltaIndex); - uint256 supplierAccrued = add_(compAccrued[supplier], supplierDelta); - compAccrued[supplier] = transferComp( - supplier, - supplierAccrued, - distributeAll ? 0 : compClaimThreshold - ); - emit DistributedSupplierComp( - CToken(cToken), - supplier, - supplierDelta, - supplyIndex.mantissa - ); - } - - /** - * @notice Calculate COMP accrued by a borrower and possibly transfer it to them - * @dev Borrowers will not begin to accrue until after the first interaction with the protocol. - * @param cToken The market in which the borrower is interacting - * @param borrower The address of the borrower to distribute COMP to - */ - function distributeBorrowerComp( - address cToken, - address borrower, - Exp memory marketBorrowIndex, - bool distributeAll - ) internal { - CompMarketState storage borrowState = compBorrowState[cToken]; - Double memory borrowIndex = Double({mantissa: borrowState.index}); - Double memory borrowerIndex = Double({ - mantissa: compBorrowerIndex[cToken][borrower] - }); - compBorrowerIndex[cToken][borrower] = borrowIndex.mantissa; - - if (borrowerIndex.mantissa > 0) { - Double memory deltaIndex = sub_(borrowIndex, borrowerIndex); - uint256 borrowerAmount = div_( - CToken(cToken).borrowBalanceStored(borrower), - marketBorrowIndex - ); - uint256 borrowerDelta = mul_(borrowerAmount, deltaIndex); - uint256 borrowerAccrued = add_( - compAccrued[borrower], - borrowerDelta - ); - compAccrued[borrower] = transferComp( - borrower, - borrowerAccrued, - distributeAll ? 0 : compClaimThreshold - ); - emit DistributedBorrowerComp( - CToken(cToken), - borrower, - borrowerDelta, - borrowIndex.mantissa - ); - } - } - - /** - * @notice Transfer COMP to the user, if they are above the threshold - * @dev Note: If there is not enough COMP, we do not perform the transfer all. - * @param user The address of the user to transfer COMP to - * @param userAccrued The amount of COMP to (possibly) transfer - * @return The amount of COMP which was NOT transferred to the user - */ - function transferComp( - address user, - uint256 userAccrued, - uint256 threshold - ) internal returns (uint256) { - if (userAccrued >= threshold && userAccrued > 0) { - TROP comp = TROP(getCompAddress()); - uint256 compRemaining = comp.balanceOf(address(this)); - if (userAccrued <= compRemaining) { - comp.transfer(user, userAccrued); - return 0; - } - } - return userAccrued; - } - - /** - * @notice Claim all the comp accrued by holder in all markets - * @param holder The address to claim COMP for - */ - function claimComp(address holder) public { - return claimComp(holder, allMarkets); - } - - /** - * @notice Claim all the comp accrued by holder in the specified markets - * @param holder The address to claim COMP for - * @param cTokens The list of markets to claim COMP in - */ - function claimComp(address holder, CToken[] memory cTokens) public { - address[] memory holders = new address[](1); - holders[0] = holder; - claimComp(holders, cTokens, true, true); - } - - /** - * @notice Claim all comp accrued by the holders - * @param holders The addresses to claim COMP for - * @param cTokens The list of markets to claim COMP in - * @param borrowers Whether or not to claim COMP earned by borrowing - * @param suppliers Whether or not to claim COMP earned by supplying - */ - function claimComp( - address[] memory holders, - CToken[] memory cTokens, - bool borrowers, - bool suppliers - ) public { - for (uint256 i = 0; i < cTokens.length; i++) { - CToken cToken = cTokens[i]; - require(markets[address(cToken)].isListed, "C522"); - if (borrowers == true) { - Exp memory borrowIndex = Exp({mantissa: cToken.borrowIndex()}); - updateCompBorrowIndex(address(cToken), borrowIndex); - for (uint256 j = 0; j < holders.length; j++) { - distributeBorrowerComp( - address(cToken), - holders[j], - borrowIndex, - true - ); - } - } - if (suppliers == true) { - updateCompSupplyIndex(address(cToken)); - for (uint256 j = 0; j < holders.length; j++) { - distributeSupplierComp(address(cToken), holders[j], true); - } - } - } - } - - /*** Comp Distribution Admin ***/ - - /** - * @notice Set the amount of COMP distributed per block - * @param compRate_ The amount of COMP wei per block to distribute - */ - function _setCompRate(uint256 compRate_) public { - require(adminOrInitializing(), "C523"); - - uint256 oldRate = compRate; - compRate = compRate_; - emit NewCompRate(oldRate, compRate_); - - refreshCompSpeedsInternal(); - } - - /** - * @notice Add markets to compMarkets, allowing them to earn COMP in the flywheel - * @param cTokens The addresses of the markets to add - */ - function _addCompMarkets(address[] memory cTokens) public { - require(adminOrInitializing(), "C524"); - - for (uint256 i = 0; i < cTokens.length; i++) { - _addCompMarketInternal(cTokens[i]); - } - - refreshCompSpeedsInternal(); - } - - function _addCompMarketInternal(address cToken) internal { - Market storage market = markets[cToken]; - require(market.isListed == true, "C525"); - require(market.isComped == false, "C526"); - - market.isComped = true; - emit MarketComped(CToken(cToken), true); - - if ( - compSupplyState[cToken].index == 0 && - compSupplyState[cToken].block == 0 - ) { - compSupplyState[cToken] = CompMarketState({ - index: compInitialIndex, - block: safe32(getBlockNumber(), "C521") - }); - } - - if ( - compBorrowState[cToken].index == 0 && - compBorrowState[cToken].block == 0 - ) { - compBorrowState[cToken] = CompMarketState({ - index: compInitialIndex, - block: safe32(getBlockNumber(), "C521") - }); - } - } - - /** - * @notice Remove a market from compMarkets, preventing it from earning COMP in the flywheel - * @param cToken The address of the market to drop - */ - function _dropCompMarket(address cToken) public { - require(msg.sender == admin, "C527"); - - Market storage market = markets[cToken]; - require(market.isComped == true, "C528"); - - market.isComped = false; - emit MarketComped(CToken(cToken), false); - - refreshCompSpeedsInternal(); - } - - /** - * @notice Return all of the markets - * @dev The automatic getter may be used to access an individual market. - * @return The list of market addresses - */ - function getAllMarkets() public view returns (CToken[] memory) { - return allMarkets; - } - - function getBlockNumber() public view virtual returns (uint256) { - return block.number; - } - - /** - * @notice Return the address of the COMP token - * @return The address of COMP - */ - function getCompAddress() public view virtual returns (address) { - return 0xc00e94Cb662C3520282E6f5717214004A7f26888; - } -} diff --git a/flatten/ComptrollerG6.sol b/flatten/ComptrollerG6.sol deleted file mode 100644 index 0e16ff7..0000000 --- a/flatten/ComptrollerG6.sol +++ /dev/null @@ -1,6605 +0,0 @@ -// Dependency file: contracts/ComptrollerInterface.sol - -// SPDX-License-Identifier: UNLICENSED -// pragma solidity 0.8.6; - -abstract contract ComptrollerInterface { - /// @notice Indicator that this is a Comptroller contract (for inspection) - bool public constant isComptroller = true; - - /*** Assets You Are In ***/ - - function enterMarkets(address[] calldata cTokens) - external - virtual - returns (uint256[] memory); - - function exitMarket(address cToken) external virtual returns (uint256); - - /*** Policy Hooks ***/ - - function mintAllowed( - address cToken, - address minter, - uint256 mintAmount - ) external virtual returns (uint256); - - function mintVerify( - address cToken, - address minter, - uint256 mintAmount, - uint256 mintTokens - ) external virtual; - - function redeemAllowed( - address cToken, - address redeemer, - uint256 redeemTokens - ) external virtual returns (uint256); - - function redeemVerify( - address cToken, - address redeemer, - uint256 redeemAmount, - uint256 redeemTokens - ) external virtual; - - function borrowAllowed( - address cToken, - address borrower, - uint256 borrowAmount - ) external virtual returns (uint256); - - function borrowVerify( - address cToken, - address borrower, - uint256 borrowAmount - ) external virtual; - - function repayBorrowAllowed( - address cToken, - address payer, - address borrower, - uint256 repayAmount - ) external virtual returns (uint256); - - function repayBorrowVerify( - address cToken, - address payer, - address borrower, - uint256 repayAmount, - uint256 borrowerIndex - ) external virtual; - - function liquidateBorrowAllowed( - address cTokenBorrowed, - address cTokenCollateral, - address liquidator, - address borrower, - uint256 repayAmount - ) external virtual returns (uint256); - - function liquidateBorrowVerify( - address cTokenBorrowed, - address cTokenCollateral, - address liquidator, - address borrower, - uint256 repayAmount, - uint256 seizeTokens - ) external virtual; - - function seizeAllowed( - address cTokenCollateral, - address cTokenBorrowed, - address liquidator, - address borrower, - uint256 seizeTokens - ) external virtual returns (uint256); - - function seizeVerify( - address cTokenCollateral, - address cTokenBorrowed, - address liquidator, - address borrower, - uint256 seizeTokens - ) external virtual; - - function transferAllowed( - address cToken, - address src, - address dst, - uint256 transferTokens - ) external virtual returns (uint256); - - function transferVerify( - address cToken, - address src, - address dst, - uint256 transferTokens - ) external virtual; - - /*** Liquidity/Liquidation Calculations ***/ - - function liquidateCalculateSeizeTokens( - address cTokenBorrowed, - address cTokenCollateral, - uint256 repayAmount - ) external view virtual returns (uint256, uint256); -} - - -// Dependency file: contracts/CarefulMath.sol - -// pragma solidity 0.8.6; - -/** - * @title Careful Math - * @author tropykus - * @notice Derived from OpenZeppelin's SafeMath library - * https://github.com/OpenZeppelin/openzeppelin-solidity/blob/master/contracts/math/SafeMath.sol - */ -contract CarefulMath { - - /** - * @dev Possible error codes that we can return - */ - enum MathError { - NO_ERROR, - DIVISION_BY_ZERO, - INTEGER_OVERFLOW, - INTEGER_UNDERFLOW - } - - /** - * @dev Multiplies two numbers, returns an error on overflow. - */ - function mulUInt(uint a, uint b) internal pure returns (MathError, uint) { - if (a == 0) { - return (MathError.NO_ERROR, 0); - } - - uint c = a * b; - - if (c / a != b) { - return (MathError.INTEGER_OVERFLOW, 0); - } else { - return (MathError.NO_ERROR, c); - } - } - - /** - * @dev Integer division of two numbers, truncating the quotient. - */ - function divUInt(uint a, uint b) internal pure returns (MathError, uint) { - if (b == 0) { - return (MathError.DIVISION_BY_ZERO, 0); - } - - return (MathError.NO_ERROR, a / b); - } - - /** - * @dev Subtracts two numbers, returns an error on overflow (i.e. if subtrahend is greater than minuend). - */ - function subUInt(uint a, uint b) internal pure returns (MathError, uint) { - if (b <= a) { - return (MathError.NO_ERROR, a - b); - } else { - return (MathError.INTEGER_UNDERFLOW, 0); - } - } - - /** - * @dev Adds two numbers, returns an error on overflow. - */ - function addUInt(uint a, uint b) internal pure returns (MathError, uint) { - uint c = a + b; - - if (c >= a) { - return (MathError.NO_ERROR, c); - } else { - return (MathError.INTEGER_OVERFLOW, 0); - } - } - - /** - * @dev add a and b and then subtract c - */ - function addThenSubUInt(uint a, uint b, uint c) internal pure returns (MathError, uint) { - (MathError err0, uint sum) = addUInt(a, b); - - if (err0 != MathError.NO_ERROR) { - return (err0, 0); - } - - return subUInt(sum, c); - } -} - - -// Dependency file: contracts/ExponentialNoError.sol - -// pragma solidity 0.8.6; - -/** - * @title Exponential module for storing fixed-precision decimals - * @author tropykus - * @notice Exp is a struct which stores decimals with a fixed precision of 18 decimal places. - * Thus, if we wanted to store the 5.1, mantissa would store 5.1e18. That is: - * `Exp({mantissa: 5100000000000000000})`. - */ -contract ExponentialNoError { - uint constant expScale = 1e18; - uint constant doubleScale = 1e36; - uint constant halfExpScale = expScale/2; - uint constant mantissaOne = expScale; - - struct Exp { - uint mantissa; - } - - struct Double { - uint mantissa; - } - - /** - * @dev Truncates the given exp to a whole number value. - * For example, truncate(Exp{mantissa: 15 * expScale}) = 15 - */ - function truncate(Exp memory exp) pure internal returns (uint) { - // Note: We are not using careful math here as we're performing a division that cannot fail - return exp.mantissa / expScale; - } - - /** - * @dev Multiply an Exp by a scalar, then truncate to return an unsigned integer. - */ - function mul_ScalarTruncate(Exp memory a, uint scalar) pure internal returns (uint) { - Exp memory product = mul_(a, scalar); - return truncate(product); - } - - /** - * @dev Multiply an Exp by a scalar, truncate, then add an to an unsigned integer, returning an unsigned integer. - */ - function mul_ScalarTruncateAddUInt(Exp memory a, uint scalar, uint addend) pure internal returns (uint) { - Exp memory product = mul_(a, scalar); - return add_(truncate(product), addend); - } - - /** - * @dev Checks if first Exp is less than second Exp. - */ - function lessThanExp(Exp memory left, Exp memory right) pure internal returns (bool) { - return left.mantissa < right.mantissa; - } - - /** - * @dev Checks if left Exp <= right Exp. - */ - function lessThanOrEqualExp(Exp memory left, Exp memory right) pure internal returns (bool) { - return left.mantissa <= right.mantissa; - } - - /** - * @dev Checks if left Exp > right Exp. - */ - function greaterThanExp(Exp memory left, Exp memory right) pure internal returns (bool) { - return left.mantissa > right.mantissa; - } - - /** - * @dev returns true if Exp is exactly zero - */ - function isZeroExp(Exp memory value) pure internal returns (bool) { - return value.mantissa == 0; - } - - function safe224(uint n, string memory errorMessage) pure internal returns (uint224) { - require(n < 2**224, errorMessage); - return uint224(n); - } - - function safe32(uint n, string memory errorMessage) pure internal returns (uint32) { - require(n < 2**32, errorMessage); - return uint32(n); - } - - function add_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { - return Exp({mantissa: add_(a.mantissa, b.mantissa)}); - } - - function add_(Double memory a, Double memory b) pure internal returns (Double memory) { - return Double({mantissa: add_(a.mantissa, b.mantissa)}); - } - - function add_(uint a, uint b) pure internal returns (uint) { - return add_(a, b, "addition overflow"); - } - - function add_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { - uint c = a + b; - require(c >= a, errorMessage); - return c; - } - - function sub_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { - return Exp({mantissa: sub_(a.mantissa, b.mantissa)}); - } - - function sub_(Double memory a, Double memory b) pure internal returns (Double memory) { - return Double({mantissa: sub_(a.mantissa, b.mantissa)}); - } - - function sub_(uint a, uint b) pure internal returns (uint) { - return sub_(a, b, "subtraction underflow"); - } - - function sub_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { - require(b <= a, errorMessage); - return a - b; - } - - function mul_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { - return Exp({mantissa: mul_(a.mantissa, b.mantissa) / expScale}); - } - - function mul_(Exp memory a, uint b) pure internal returns (Exp memory) { - return Exp({mantissa: mul_(a.mantissa, b)}); - } - - function mul_(uint a, Exp memory b) pure internal returns (uint) { - return mul_(a, b.mantissa) / expScale; - } - - function mul_(Double memory a, Double memory b) pure internal returns (Double memory) { - return Double({mantissa: mul_(a.mantissa, b.mantissa) / doubleScale}); - } - - function mul_(Double memory a, uint b) pure internal returns (Double memory) { - return Double({mantissa: mul_(a.mantissa, b)}); - } - - function mul_(uint a, Double memory b) pure internal returns (uint) { - return mul_(a, b.mantissa) / doubleScale; - } - - function mul_(uint a, uint b) pure internal returns (uint) { - return mul_(a, b, "multiplication overflow"); - } - - function mul_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { - if (a == 0 || b == 0) { - return 0; - } - uint c = a * b; - require(c / a == b, errorMessage); - return c; - } - - function div_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { - return Exp({mantissa: div_(mul_(a.mantissa, expScale), b.mantissa)}); - } - - function div_(Exp memory a, uint b) pure internal returns (Exp memory) { - return Exp({mantissa: div_(a.mantissa, b)}); - } - - function div_(uint a, Exp memory b) pure internal returns (uint) { - return div_(mul_(a, expScale), b.mantissa); - } - - function div_(Double memory a, Double memory b) pure internal returns (Double memory) { - return Double({mantissa: div_(mul_(a.mantissa, doubleScale), b.mantissa)}); - } - - function div_(Double memory a, uint b) pure internal returns (Double memory) { - return Double({mantissa: div_(a.mantissa, b)}); - } - - function div_(uint a, Double memory b) pure internal returns (uint) { - return div_(mul_(a, doubleScale), b.mantissa); - } - - function div_(uint a, uint b) pure internal returns (uint) { - return div_(a, b, "divide by zero"); - } - - function div_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { - require(b > 0, errorMessage); - return a / b; - } - - function fraction(uint a, uint b) pure internal returns (Double memory) { - return Double({mantissa: div_(mul_(a, doubleScale), b)}); - } -} - - -// Dependency file: contracts/Exponential.sol - -// pragma solidity 0.8.6; - -// import "contracts/CarefulMath.sol"; -// import "contracts/ExponentialNoError.sol"; - -/** - * @title Exponential module for storing fixed-precision decimals - * @author tropykus - * @dev Legacy contract for compatibility reasons with existing contracts that still use MathError - * @notice Exp is a struct which stores decimals with a fixed precision of 18 decimal places. - * Thus, if we wanted to store the 5.1, mantissa would store 5.1e18. That is: - * `Exp({mantissa: 5100000000000000000})`. - */ -contract Exponential is CarefulMath, ExponentialNoError { - /** - * @dev Creates an exponential from numerator and denominator values. - * Note: Returns an error if (`num` * 10e18) > MAX_INT, - * or if `denom` is zero. - */ - function getExp(uint num, uint denom) internal pure returns (MathError, Exp memory) { - (MathError err0, uint scaledNumerator) = mulUInt(num, expScale); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - - (MathError err1, uint rational) = divUInt(scaledNumerator, denom); - if (err1 != MathError.NO_ERROR) { - return (err1, Exp({mantissa: 0})); - } - - return (MathError.NO_ERROR, Exp({mantissa: rational})); - } - - /** - * @dev Adds two exponentials, returning a new exponential. - */ - function addExp(Exp memory a, Exp memory b) internal pure returns (MathError, Exp memory) { - (MathError error, uint result) = addUInt(a.mantissa, b.mantissa); - - return (error, Exp({mantissa: result})); - } - - /** - * @dev Subtracts two exponentials, returning a new exponential. - */ - function subExp(Exp memory a, Exp memory b) internal pure returns (MathError, Exp memory) { - (MathError error, uint result) = subUInt(a.mantissa, b.mantissa); - - return (error, Exp({mantissa: result})); - } - - /** - * @dev Multiply an Exp by a scalar, returning a new Exp. - */ - function mulScalar(Exp memory a, uint scalar) internal pure returns (MathError, Exp memory) { - (MathError err0, uint scaledMantissa) = mulUInt(a.mantissa, scalar); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - - return (MathError.NO_ERROR, Exp({mantissa: scaledMantissa})); - } - - /** - * @dev Multiply an Exp by a scalar, then truncate to return an unsigned integer. - */ - function mulScalarTruncate(Exp memory a, uint scalar) internal pure returns (MathError, uint) { - (MathError err, Exp memory product) = mulScalar(a, scalar); - if (err != MathError.NO_ERROR) { - return (err, 0); - } - - return (MathError.NO_ERROR, truncate(product)); - } - - /** - * @dev Multiply an Exp by a scalar, truncate, then add an to an unsigned integer, returning an unsigned integer. - */ - function mulScalarTruncateAddUInt(Exp memory a, uint scalar, uint addend) internal pure returns (MathError, uint) { - (MathError err, Exp memory product) = mulScalar(a, scalar); - if (err != MathError.NO_ERROR) { - return (err, 0); - } - - return addUInt(truncate(product), addend); - } - - /** - * @dev Divide an Exp by a scalar, returning a new Exp. - */ - function divScalar(Exp memory a, uint scalar) internal pure returns (MathError, Exp memory) { - (MathError err0, uint descaledMantissa) = divUInt(a.mantissa, scalar); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - - return (MathError.NO_ERROR, Exp({mantissa: descaledMantissa})); - } - - /** - * @dev Divide a scalar by an Exp, returning a new Exp. - */ - function divScalarByExp(uint scalar, Exp memory divisor) internal pure returns (MathError, Exp memory) { - /* - We are doing this as: - getExp(mulUInt(expScale, scalar), divisor.mantissa) - - How it works: - Exp = a / b; - Scalar = s; - `s / (a / b)` = `b * s / a` and since for an Exp `a = mantissa, b = expScale` - */ - (MathError err0, uint numerator) = mulUInt(expScale, scalar); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - return getExp(numerator, divisor.mantissa); - } - - /** - * @dev Divide a scalar by an Exp, then truncate to return an unsigned integer. - */ - function divScalarByExpTruncate(uint scalar, Exp memory divisor) internal pure returns (MathError, uint) { - (MathError err, Exp memory fraction) = divScalarByExp(scalar, divisor); - if (err != MathError.NO_ERROR) { - return (err, 0); - } - - return (MathError.NO_ERROR, truncate(fraction)); - } - - /** - * @dev Multiplies two exponentials, returning a new exponential. - */ - function mulExp(Exp memory a, Exp memory b) internal pure returns (MathError, Exp memory) { - - (MathError err0, uint doubleScaledProduct) = mulUInt(a.mantissa, b.mantissa); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - - // We add half the scale before dividing so that we get rounding instead of truncation. - // See "Listing 6" and text above it at https://accu.org/index.php/journals/1717 - // Without this change, a result like 6.6...e-19 will be truncated to 0 instead of being rounded to 1e-18. - (MathError err1, uint doubleScaledProductWithHalfScale) = addUInt(halfExpScale, doubleScaledProduct); - if (err1 != MathError.NO_ERROR) { - return (err1, Exp({mantissa: 0})); - } - - (MathError err2, uint product) = divUInt(doubleScaledProductWithHalfScale, expScale); - // The only error `div` can return is MathError.DIVISION_BY_ZERO but we control `expScale` and it is not zero. - assert(err2 == MathError.NO_ERROR); - - return (MathError.NO_ERROR, Exp({mantissa: product})); - } - - /** - * @dev Multiplies two exponentials given their mantissas, returning a new exponential. - */ - function mulExp(uint a, uint b) internal pure returns (MathError, Exp memory) { - return mulExp(Exp({mantissa: a}), Exp({mantissa: b})); - } - - /** - * @dev Multiplies three exponentials, returning a new exponential. - */ - function mulExp3(Exp memory a, Exp memory b, Exp memory c) internal pure returns (MathError, Exp memory) { - (MathError err, Exp memory ab) = mulExp(a, b); - if (err != MathError.NO_ERROR) { - return (err, ab); - } - return mulExp(ab, c); - } - - /** - * @dev Divides two exponentials, returning a new exponential. - * (a/scale) / (b/scale) = (a/scale) * (scale/b) = a/b, - * which we can scale as an Exp by calling getExp(a.mantissa, b.mantissa) - */ - function divExp(Exp memory a, Exp memory b) internal pure returns (MathError, Exp memory) { - return getExp(a.mantissa, b.mantissa); - } -} - - -// Dependency file: contracts/SafeMath.sol - -// pragma solidity 0.8.6; - -// From https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/math/Math.sol -// Subject to the MIT license. - -/** - * @dev Wrappers over Solidity's arithmetic operations with added overflow - * checks. - * - * Arithmetic operations in Solidity wrap on overflow. This can easily result - * in bugs, because programmers usually assume that an overflow raises an - * error, which is the standard behavior in high level programming languages. - * `SafeMath` restores this intuition by reverting the transaction when an - * operation overflows. - * - * Using this library instead of the unchecked operations eliminates an entire - * class of bugs, so it's recommended to use it always. - */ -library SafeMath { - /** - * @dev Returns the addition of two unsigned integers, reverting on overflow. - * - * Counterpart to Solidity's `+` operator. - * - * Requirements: - * - Addition cannot overflow. - */ - function add(uint256 a, uint256 b) internal pure returns (uint256) { - uint256 c = a + b; - require(c >= a, "SafeMath: addition overflow"); - - return c; - } - - /** - * @dev Returns the addition of two unsigned integers, reverting with custom message on overflow. - * - * Counterpart to Solidity's `+` operator. - * - * Requirements: - * - Addition cannot overflow. - */ - function add(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - uint256 c = a + b; - require(c >= a, errorMessage); - - return c; - } - - /** - * @dev Returns the subtraction of two unsigned integers, reverting on underflow (when the result is negative). - * - * Counterpart to Solidity's `-` operator. - * - * Requirements: - * - Subtraction cannot underflow. - */ - function sub(uint256 a, uint256 b) internal pure returns (uint256) { - return sub(a, b, "SafeMath: subtraction underflow"); - } - - /** - * @dev Returns the subtraction of two unsigned integers, reverting with custom message on underflow (when the result is negative). - * - * Counterpart to Solidity's `-` operator. - * - * Requirements: - * - Subtraction cannot underflow. - */ - function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - require(b <= a, errorMessage); - uint256 c = a - b; - - return c; - } - - /** - * @dev Returns the multiplication of two unsigned integers, reverting on overflow. - * - * Counterpart to Solidity's `*` operator. - * - * Requirements: - * - Multiplication cannot overflow. - */ - function mul(uint256 a, uint256 b) internal pure returns (uint256) { - // Gas optimization: this is cheaper than requiring 'a' not being zero, but the - // benefit is lost if 'b' is also tested. - // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 - if (a == 0) { - return 0; - } - - uint256 c = a * b; - require(c / a == b, "SafeMath: multiplication overflow"); - - return c; - } - - /** - * @dev Returns the multiplication of two unsigned integers, reverting on overflow. - * - * Counterpart to Solidity's `*` operator. - * - * Requirements: - * - Multiplication cannot overflow. - */ - function mul(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - // Gas optimization: this is cheaper than requiring 'a' not being zero, but the - // benefit is lost if 'b' is also tested. - // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 - if (a == 0) { - return 0; - } - - uint256 c = a * b; - require(c / a == b, errorMessage); - - return c; - } - - /** - * @dev Returns the integer division of two unsigned integers. - * Reverts on division by zero. The result is rounded towards zero. - * - * Counterpart to Solidity's `/` operator. Note: this function uses a - * `revert` opcode (which leaves remaining gas untouched) while Solidity - * uses an invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function div(uint256 a, uint256 b) internal pure returns (uint256) { - return div(a, b, "SafeMath: division by zero"); - } - - /** - * @dev Returns the integer division of two unsigned integers. - * Reverts with custom message on division by zero. The result is rounded towards zero. - * - * Counterpart to Solidity's `/` operator. Note: this function uses a - * `revert` opcode (which leaves remaining gas untouched) while Solidity - * uses an invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - // Solidity only automatically asserts when dividing by 0 - require(b > 0, errorMessage); - uint256 c = a / b; - // assert(a == b * c + a % b); // There is no case in which this doesn't hold - - return c; - } - - /** - * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), - * Reverts when dividing by zero. - * - * Counterpart to Solidity's `%` operator. This function uses a `revert` - * opcode (which leaves remaining gas untouched) while Solidity uses an - * invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function mod(uint256 a, uint256 b) internal pure returns (uint256) { - return mod(a, b, "SafeMath: modulo by zero"); - } - - /** - * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), - * Reverts with custom message when dividing by zero. - * - * Counterpart to Solidity's `%` operator. This function uses a `revert` - * opcode (which leaves remaining gas untouched) while Solidity uses an - * invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - require(b != 0, errorMessage); - return a % b; - } -} - - -// Dependency file: contracts/InterestRateModel.sol - -// pragma solidity 0.8.6; - -// import "contracts/Exponential.sol"; -// import "contracts/SafeMath.sol"; - -/** - * @title tropykus InterestRateModel Interface - * @author tropykus - */ -abstract contract InterestRateModel is Exponential { - using SafeMath for uint256; - - /// @notice Indicator that this is an InterestRateModel contract (for inspection) - bool public constant isInterestRateModel = true; - bool public isTropykusInterestRateModel; - - /** - * @notice The approximate number of blocks per year that is assumed by the interest rate model - */ - uint256 public constant blocksPerYear = 1051200; - - /** - * @notice Calculates the utilization rate of the market: `borrows / (cash + borrows - reserves)` - * @param cash The amount of cash in the market - * @param borrows The amount of borrows in the market - * @param reserves The amount of reserves in the market (currently unused) - * @return The utilization rate as a mantissa between [0, 1e18] - */ - function utilizationRate( - uint256 cash, - uint256 borrows, - uint256 reserves - ) public pure virtual returns (uint256) { - // Utilization rate is 0 when there are no borrows - if (borrows == 0) { - return 0; - } - - return borrows.mul(1e18).div(cash.add(borrows).sub(reserves)); - } - - /** - * @notice Calculates the current borrow interest rate per block - * @param cash The total amount of cash the market has - * @param borrows The total amount of borrows the market has outstanding - * @param reserves The total amnount of reserves the market has - * @return The borrow rate per block (as a percentage, and scaled by 1e18) - */ - function getBorrowRate( - uint256 cash, - uint256 borrows, - uint256 reserves - ) external view virtual returns (uint256); - - /** - * @notice Calculates the current supply interest rate per block - * @param cash The total amount of cash the market has - * @param borrows The total amount of borrows the market has outstanding - * @param reserves The total amnount of reserves the market has - * @param reserveFactorMantissa The current reserve factor the market has - * @return The supply rate per block (as a percentage, and scaled by 1e18) - */ - function getSupplyRate( - uint256 cash, - uint256 borrows, - uint256 reserves, - uint256 reserveFactorMantissa - ) external view virtual returns (uint256); - - function getExchangeRate( - uint256 _totalCash, - uint256 _totalBorrows, - uint256 _totalReserves, - uint256 _totalSupply - ) public pure returns (MathError, uint256) { - /* - * exchangeRate = (totalCash + totalBorrows - totalReserves) / totalSupply - */ - Exp memory exchangeRate; - MathError mathErr; - uint256 cashPlusBorrowsMinusReserves; - (mathErr, cashPlusBorrowsMinusReserves) = addThenSubUInt( - _totalCash, - _totalBorrows, - _totalReserves - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - (mathErr, exchangeRate) = getExp( - cashPlusBorrowsMinusReserves, - _totalSupply - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - - return (MathError.NO_ERROR, exchangeRate.mantissa); - } - - function isAboveOptimal( - uint256 cash, - uint256 borrows, - uint256 reserves - ) public view virtual returns (bool) { - cash; - borrows; - reserves; - return false; - } -} - - -// Dependency file: contracts/EIP20NonStandardInterface.sol - -// pragma solidity 0.8.6; - -/** - * @title EIP20NonStandardInterface - * @dev Version of ERC20 with no return values for `transfer` and `transferFrom` - * See https://medium.com/coinmonks/missing-return-value-bug-at-least-130-tokens-affected-d67bf08521ca - */ -interface EIP20NonStandardInterface { - /** - * @notice Get the total number of tokens in circulation - * @return The supply of tokens - */ - function totalSupply() external view returns (uint256); - - /** - * @notice Gets the balance of the specified address - * @param owner The address from which the balance will be retrieved - * @return balance The balance - */ - function balanceOf(address owner) external view returns (uint256 balance); - - /// - /// !!!!!!!!!!!!!! - /// !!! NOTICE !!! `transfer` does not return a value, in violation of the ERC-20 specification - /// !!!!!!!!!!!!!! - /// - - /** - * @notice Transfer `amount` tokens from `msg.sender` to `dst` - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - */ - function transfer(address dst, uint256 amount) external; - - /// - /// !!!!!!!!!!!!!! - /// !!! NOTICE !!! `transferFrom` does not return a value, in violation of the ERC-20 specification - /// !!!!!!!!!!!!!! - /// - - /** - * @notice Transfer `amount` tokens from `src` to `dst` - * @param src The address of the source account - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - */ - function transferFrom( - address src, - address dst, - uint256 amount - ) external; - - /** - * @notice Approve `spender` to transfer up to `amount` from `src` - * @dev This will overwrite the approval amount for `spender` - * and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve) - * @param spender The address of the account which may transfer tokens - * @param amount The number of tokens that are approved - * @return success Whether or not the approval succeeded - */ - function approve(address spender, uint256 amount) - external - returns (bool success); - - /** - * @notice Get the current allowance from `owner` for `spender` - * @param owner The address of the account which owns the tokens to be spent - * @param spender The address of the account which may transfer tokens - * @return remaining The number of tokens allowed to be spent - */ - function allowance(address owner, address spender) - external - view - returns (uint256 remaining); - - event Transfer(address indexed from, address indexed to, uint256 amount); - event Approval( - address indexed owner, - address indexed spender, - uint256 amount - ); -} - - -// Dependency file: contracts/CTokenInterfaces.sol - -// pragma solidity 0.8.6; - -// import "contracts/ComptrollerInterface.sol"; -// import "contracts/InterestRateModel.sol"; -// import "contracts/EIP20NonStandardInterface.sol"; - -contract CTokenStorage { - /** - * @dev Guard variable for re-entrancy checks - */ - bool internal _notEntered; - - /** - * @notice EIP-20 token name for this token - */ - string public name; - - /** - * @notice EIP-20 token symbol for this token - */ - string public symbol; - - /** - * @notice EIP-20 token decimals for this token - */ - uint8 public decimals; - - /** - * @notice Maximum borrow rate that can ever be applied (.0005% / block) - */ - - uint256 internal constant borrowRateMaxMantissa = 0.0005e16; - - /** - * @notice Maximum fraction of interest that can be set aside for reserves - */ - uint256 internal constant reserveFactorMaxMantissa = 1e18; - - /** - * @notice Administrator for this contract - */ - address payable public admin; - - /** - * @notice Pending administrator for this contract - */ - address payable public pendingAdmin; - - /** - * @notice Contract which oversees inter-cToken operations - */ - ComptrollerInterface public comptroller; - - /** - * @notice Model which tells what the current interest rate should be - */ - InterestRateModel public interestRateModel; - - /** - * @notice Initial exchange rate used when minting the first CTokens (used when totalSupply = 0) - */ - uint256 public initialExchangeRateMantissa; - - /** - * @notice Fraction of interest currently set aside for reserves - */ - uint256 public reserveFactorMantissa; - - /** - * @notice Block number that interest was last accrued at - */ - uint256 public accrualBlockNumber; - - /** - * @notice Accumulator of the total earned interest rate since the opening of the market - */ - uint256 public borrowIndex; - - /** - * @notice Total amount of outstanding borrows of the underlying in this market - */ - uint256 public totalBorrows; - - /** - * @notice Total amount of reserves of the underlying held in this market - */ - uint256 public totalReserves; - - /** - * @notice Total number of tokens in circulation - */ - uint256 public totalSupply; - - uint256 public subsidyFund; - - struct SupplySnapshot { - uint256 tokens; - uint256 underlyingAmount; - uint256 suppliedAt; - uint256 promisedSupplyRate; - } - - /** - * @notice Official record of token balances for each account - */ - mapping(address => SupplySnapshot) internal accountTokens; - - /** - * @notice Approved token transfer amounts on behalf of others - */ - mapping(address => mapping(address => uint256)) internal transferAllowances; - - /** - * @notice Container for borrow balance information - * @member principal Total balance (with accrued interest), after applying the most recent balance-changing action - * @member interestIndex Global borrowIndex as of the most recent balance-changing action - */ - struct BorrowSnapshot { - uint256 principal; - uint256 interestIndex; - } - - /** - * @notice Mapping of account addresses to outstanding borrow balances - */ - mapping(address => BorrowSnapshot) internal accountBorrows; -} - -abstract contract CTokenInterface is CTokenStorage { - /** - * @notice Indicator that this is a CToken contract (for inspection) - */ - bool public constant isCToken = true; - - /*** Market Events ***/ - - /** - * @notice Event emitted when interest is accrued - */ - event AccrueInterest( - uint256 cashPrior, - uint256 interestAccumulated, - uint256 borrowIndex, - uint256 totalBorrows - ); - - /** - * @notice Event emitted when tokens are minted - */ - event Mint(address indexed minter, uint256 mintAmount, uint256 mintTokens); - - /** - * @notice Event emitted when tokens are redeemed - */ - event Redeem( - address indexed redeemer, - uint256 redeemAmount, - uint256 redeemTokens - ); - - /** - * @notice Event emitted when underlying is borrowed - */ - event Borrow( - address indexed borrower, - uint256 borrowAmount, - uint256 accountBorrows, - uint256 totalBorrows - ); - - /** - * @notice Event emitted when a borrow is repaid - */ - event RepayBorrow( - address indexed payer, - address indexed borrower, - uint256 repayAmount, - uint256 accountBorrows, - uint256 totalBorrows - ); - - /** - * @notice Event emitted when a borrow is liquidated - */ - event LiquidateBorrow( - address indexed liquidator, - address indexed borrower, - uint256 repayAmount, - address indexed cTokenCollateral, - uint256 seizeTokens - ); - - /*** Admin Events ***/ - - /** - * @notice Event emitted when pendingAdmin is changed - */ - event NewPendingAdmin(address oldPendingAdmin, address newPendingAdmin); - - /** - * @notice Event emitted when pendingAdmin is accepted, which means admin is updated - */ - event NewAdmin(address oldAdmin, address newAdmin); - - /** - * @notice Event emitted when comptroller is changed - */ - event NewComptroller( - ComptrollerInterface oldComptroller, - ComptrollerInterface newComptroller - ); - - /** - * @notice Event emitted when interestRateModel is changed - */ - event NewMarketInterestRateModel( - InterestRateModel oldInterestRateModel, - InterestRateModel newInterestRateModel - ); - - /** - * @notice Event emitted when the reserve factor is changed - */ - event NewReserveFactor( - uint256 oldReserveFactorMantissa, - uint256 newReserveFactorMantissa - ); - - /** - * @notice Event emitted when the reserves are added - */ - event ReservesAdded( - address benefactor, - uint256 addAmount, - uint256 newTotalReserves - ); - - event SubsidyAdded( - address benefactor, - uint256 addAmount, - uint256 newSubsidyFund - ); - - /** - * @notice Event emitted when the reserves are reduced - */ - event ReservesReduced( - address admin, - uint256 reduceAmount, - uint256 newTotalReserves - ); - - /** - * @notice EIP20 Transfer event - */ - event Transfer(address indexed from, address indexed to, uint256 amount); - - /** - * @notice EIP20 Approval event - */ - event Approval( - address indexed owner, - address indexed spender, - uint256 amount - ); - - /** - * @notice Failure event - */ - event CTokenStorageFailure(uint256 error, uint256 info, uint256 detail); - - /*** User Interface ***/ - - function transfer(address dst, uint256 amount) - external - virtual - returns (bool); - - function transferFrom( - address src, - address dst, - uint256 amount - ) external virtual returns (bool); - - function approve(address spender, uint256 amount) - external - virtual - returns (bool); - - function allowance(address owner, address spender) - external - view - virtual - returns (uint256); - - function balanceOf(address owner) external view virtual returns (uint256); - - function balanceOfUnderlying(address owner) - external - virtual - returns (uint256); - - function getAccountSnapshot(address account) - external - view - virtual - returns ( - uint256, - uint256, - uint256, - uint256 - ); - - function borrowRatePerBlock() external view virtual returns (uint256); - - function supplyRatePerBlock() external view virtual returns (uint256); - - function totalBorrowsCurrent() external virtual returns (uint256); - - function borrowBalanceCurrent(address account) - external - virtual - returns (uint256); - - function borrowBalanceStored(address account) - public - view - virtual - returns (uint256); - - function exchangeRateCurrent() public virtual returns (uint256); - - function exchangeRateStored() public view virtual returns (uint256); - - function getCash() external view virtual returns (uint256); - - function accrueInterest() public virtual returns (uint256); - - function seize( - address liquidator, - address borrower, - uint256 seizeTokens - ) external virtual returns (uint256); - - /*** Admin Functions ***/ - - function _setPendingAdmin(address payable newPendingAdmin) - external - virtual - returns (uint256); - - function _acceptAdmin() external virtual returns (uint256); - - function _setComptroller(ComptrollerInterface newComptroller) - public - virtual - returns (uint256); - - function _setReserveFactor(uint256 newReserveFactorMantissa) - external - virtual - returns (uint256); - - function _reduceReserves(uint256 reduceAmount) - external - virtual - returns (uint256); - - function _setInterestRateModel(InterestRateModel newInterestRateModel) - public - virtual - returns (uint256); -} - -contract CErc20Storage { - /** - * @notice Underlying asset for this CToken - */ - address public underlying; -} - -abstract contract CErc20Interface is CErc20Storage { - /*** User Interface ***/ - - function mint(uint256 mintAmount) external virtual returns (uint256); - - function redeem(uint256 redeemAmount) - external - virtual - returns (uint256); - - function borrow(uint256 borrowAmount) external virtual returns (uint256); - - function repayBorrow(uint256 repayAmount) - external - virtual - returns (uint256); - - function liquidateBorrow( - address borrower, - uint256 repayAmount, - CTokenInterface cTokenCollateral - ) external virtual returns (uint256); - - function sweepToken(EIP20NonStandardInterface token) external virtual; - - /*** Admin Functions ***/ - - function _addReserves(uint256 addAmount) external virtual returns (uint256); -} - -contract CDelegationStorage { - /** - * @notice Implementation address for this contract - */ - address public implementation; -} - -abstract contract CDelegatorInterface is CDelegationStorage { - /** - * @notice Emitted when implementation is changed - */ - event NewImplementation( - address oldImplementation, - address newImplementation - ); - - /** - * @notice Called by the admin to update the implementation of the delegator - * @param implementation_ The address of the new implementation for delegation - * @param allowResign Flag to indicate whether to call _resignImplementation on the old implementation - * @param becomeImplementationData The encoded bytes data to be passed to _becomeImplementation - */ - function _setImplementation( - address implementation_, - bool allowResign, - bytes memory becomeImplementationData - ) public virtual; -} - -abstract contract CDelegateInterface is CDelegationStorage { - /** - * @notice Called by the delegator on a delegate to initialize it for duty - * @dev Should revert if any issues arise which make it unfit for delegation - * @param data The encoded bytes data for any initialization - */ - function _becomeImplementation(bytes memory data) public virtual; - - /** - * @notice Called by the delegator on a delegate to forfeit its responsibility - */ - function _resignImplementation() public virtual; -} - - -// Dependency file: contracts/ErrorReporter.sol - -// pragma solidity 0.8.6; - -contract ComptrollerErrorReporter { - enum Error { - NO_ERROR, - UNAUTHORIZED, - COMPTROLLER_MISMATCH, - INSUFFICIENT_SHORTFALL, - INSUFFICIENT_LIQUIDITY, - INVALID_CLOSE_FACTOR, - INVALID_COLLATERAL_FACTOR, - INVALID_LIQUIDATION_INCENTIVE, - MARKET_NOT_ENTERED, // no longer possible - MARKET_NOT_LISTED, - MARKET_ALREADY_LISTED, - MATH_ERROR, - NONZERO_BORROW_BALANCE, - PRICE_ERROR, - REJECTION, - SNAPSHOT_ERROR, - TOO_MANY_ASSETS, - TOO_MUCH_REPAY - } - - enum FailureInfo { - ACCEPT_ADMIN_PENDING_ADMIN_CHECK, - ACCEPT_PENDING_IMPLEMENTATION_ADDRESS_CHECK, - EXIT_MARKET_BALANCE_OWED, - EXIT_MARKET_REJECTION, - SET_CLOSE_FACTOR_OWNER_CHECK, - SET_CLOSE_FACTOR_VALIDATION, - SET_COLLATERAL_FACTOR_OWNER_CHECK, - SET_COLLATERAL_FACTOR_NO_EXISTS, - SET_COLLATERAL_FACTOR_VALIDATION, - SET_COLLATERAL_FACTOR_WITHOUT_PRICE, - SET_IMPLEMENTATION_OWNER_CHECK, - SET_LIQUIDATION_INCENTIVE_OWNER_CHECK, - SET_LIQUIDATION_INCENTIVE_VALIDATION, - SET_MAX_ASSETS_OWNER_CHECK, - SET_PENDING_ADMIN_OWNER_CHECK, - SET_PENDING_IMPLEMENTATION_OWNER_CHECK, - SET_PRICE_ORACLE_OWNER_CHECK, - SUPPORT_MARKET_EXISTS, - SUPPORT_MARKET_OWNER_CHECK, - SET_PAUSE_GUARDIAN_OWNER_CHECK - } - - /** - * @dev `error` corresponds to enum Error; `info` corresponds to enum FailureInfo, and `detail` is an arbitrary - * contract-specific code that enables us to report opaque error codes from upgradeable contracts. - **/ - event Failure(uint256 error, uint256 info, uint256 detail); - - /** - * @dev use this when reporting a known error from the money market or a non-upgradeable collaborator - */ - function fail(Error err, FailureInfo info) internal returns (uint256) { - emit Failure(uint256(err), uint256(info), 0); - - return uint256(err); - } - - /** - * @dev use this when reporting an opaque error from an upgradeable collaborator contract - */ - function failOpaque( - Error err, - FailureInfo info, - uint256 opaqueError - ) internal returns (uint256) { - emit Failure(uint256(err), uint256(info), opaqueError); - - return uint256(err); - } -} - -contract TokenErrorReporter { - enum Error { - NO_ERROR, - UNAUTHORIZED, - BAD_INPUT, - COMPTROLLER_REJECTION, - COMPTROLLER_CALCULATION_ERROR, - INTEREST_RATE_MODEL_ERROR, - INVALID_ACCOUNT_PAIR, - INVALID_CLOSE_AMOUNT_REQUESTED, - INVALID_COLLATERAL_FACTOR, - MATH_ERROR, - MARKET_NOT_FRESH, - MARKET_NOT_LISTED, - TOKEN_INSUFFICIENT_ALLOWANCE, - TOKEN_INSUFFICIENT_BALANCE, - TOKEN_INSUFFICIENT_CASH, - TOKEN_TRANSFER_IN_FAILED, - TOKEN_TRANSFER_OUT_FAILED - } - - /* - * Note: FailureInfo (but not Error) is kept in alphabetical order - * This is because FailureInfo grows significantly faster, and - * the order of Error has some meaning, while the order of FailureInfo - * is entirely arbitrary. - */ - enum FailureInfo { - ACCEPT_ADMIN_PENDING_ADMIN_CHECK, - ACCRUE_INTEREST_ACCUMULATED_INTEREST_CALCULATION_FAILED, - ACCRUE_INTEREST_BORROW_RATE_CALCULATION_FAILED, - ACCRUE_INTEREST_NEW_BORROW_INDEX_CALCULATION_FAILED, - ACCRUE_INTEREST_NEW_TOTAL_BORROWS_CALCULATION_FAILED, - ACCRUE_INTEREST_NEW_TOTAL_RESERVES_CALCULATION_FAILED, - ACCRUE_INTEREST_SIMPLE_INTEREST_FACTOR_CALCULATION_FAILED, - BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED, - BORROW_ACCRUE_INTEREST_FAILED, - BORROW_CASH_NOT_AVAILABLE, - BORROW_FRESHNESS_CHECK, - BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED, - BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED, - BORROW_MARKET_NOT_LISTED, - BORROW_COMPTROLLER_REJECTION, - LIQUIDATE_ACCRUE_BORROW_INTEREST_FAILED, - LIQUIDATE_ACCRUE_COLLATERAL_INTEREST_FAILED, - LIQUIDATE_COLLATERAL_FRESHNESS_CHECK, - LIQUIDATE_COMPTROLLER_REJECTION, - LIQUIDATE_COMPTROLLER_CALCULATE_AMOUNT_SEIZE_FAILED, - LIQUIDATE_CLOSE_AMOUNT_IS_UINT_MAX, - LIQUIDATE_CLOSE_AMOUNT_IS_ZERO, - LIQUIDATE_FRESHNESS_CHECK, - LIQUIDATE_LIQUIDATOR_IS_BORROWER, - LIQUIDATE_REPAY_BORROW_FRESH_FAILED, - LIQUIDATE_SEIZE_BALANCE_INCREMENT_FAILED, - LIQUIDATE_SEIZE_BALANCE_DECREMENT_FAILED, - LIQUIDATE_SEIZE_COMPTROLLER_REJECTION, - LIQUIDATE_SEIZE_LIQUIDATOR_IS_BORROWER, - LIQUIDATE_SEIZE_TOO_MUCH, - MINT_ACCRUE_INTEREST_FAILED, - MINT_COMPTROLLER_REJECTION, - MINT_EXCHANGE_CALCULATION_FAILED, - MINT_EXCHANGE_RATE_READ_FAILED, - MINT_FRESHNESS_CHECK, - MINT_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED, - MINT_NEW_TOTAL_SUPPLY_CALCULATION_FAILED, - MINT_TRANSFER_IN_FAILED, - MINT_TRANSFER_IN_NOT_POSSIBLE, - REDEEM_ACCRUE_INTEREST_FAILED, - REDEEM_COMPTROLLER_REJECTION, - REDEEM_EXCHANGE_TOKENS_CALCULATION_FAILED, - REDEEM_EXCHANGE_AMOUNT_CALCULATION_FAILED, - REDEEM_EXCHANGE_RATE_READ_FAILED, - REDEEM_FRESHNESS_CHECK, - REDEEM_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED, - REDEEM_NEW_TOTAL_SUPPLY_CALCULATION_FAILED, - REDEEM_TRANSFER_OUT_NOT_POSSIBLE, - REDUCE_RESERVES_ACCRUE_INTEREST_FAILED, - REDUCE_RESERVES_ADMIN_CHECK, - REDUCE_RESERVES_CASH_NOT_AVAILABLE, - REDUCE_RESERVES_FRESH_CHECK, - REDUCE_RESERVES_VALIDATION, - REPAY_BEHALF_ACCRUE_INTEREST_FAILED, - REPAY_BORROW_ACCRUE_INTEREST_FAILED, - REPAY_BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED, - REPAY_BORROW_COMPTROLLER_REJECTION, - REPAY_BORROW_FRESHNESS_CHECK, - REPAY_BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED, - REPAY_BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED, - REPAY_BORROW_TRANSFER_IN_NOT_POSSIBLE, - SET_COLLATERAL_FACTOR_OWNER_CHECK, - SET_COLLATERAL_FACTOR_VALIDATION, - SET_COMPTROLLER_OWNER_CHECK, - SET_INTEREST_RATE_MODEL_ACCRUE_INTEREST_FAILED, - SET_INTEREST_RATE_MODEL_FRESH_CHECK, - SET_INTEREST_RATE_MODEL_OWNER_CHECK, - SET_MAX_ASSETS_OWNER_CHECK, - SET_ORACLE_MARKET_NOT_LISTED, - SET_PENDING_ADMIN_OWNER_CHECK, - SET_RESERVE_FACTOR_ACCRUE_INTEREST_FAILED, - SET_RESERVE_FACTOR_ADMIN_CHECK, - SET_RESERVE_FACTOR_FRESH_CHECK, - SET_RESERVE_FACTOR_BOUNDS_CHECK, - TRANSFER_COMPTROLLER_REJECTION, - TRANSFER_NOT_ALLOWED, - TRANSFER_NOT_ENOUGH, - TRANSFER_TOO_MUCH, - ADD_RESERVES_ACCRUE_INTEREST_FAILED, - ADD_RESERVES_FRESH_CHECK, - ADD_RESERVES_TRANSFER_IN_NOT_POSSIBLE, - ADD_SUBSIDY_FUND_FAILED, - ADD_SUBSIDY_FUND_FRESH_CHECK - } - - /** - * @dev `error` corresponds to enum Error; `info` corresponds to enum FailureInfo, and `detail` is an arbitrary - * contract-specific code that enables us to report opaque error codes from upgradeable contracts. - **/ - event TokenFailure(uint256 error, uint256 info, uint256 detail); - - /** - * @dev use this when reporting a known error from the money market or a non-upgradeable collaborator - */ - function fail(Error err, FailureInfo info) internal returns (uint256) { - emit TokenFailure(uint256(err), uint256(info), 0); - - return uint256(err); - } - - /** - * @dev use this when reporting an opaque error from an upgradeable collaborator contract - */ - function failOpaque( - Error err, - FailureInfo info, - uint256 opaqueError - ) internal returns (uint256) { - emit TokenFailure(uint256(err), uint256(info), opaqueError); - - return uint256(err); - } -} - - -// Dependency file: contracts/EIP20Interface.sol - -// pragma solidity 0.8.6; - -/** - * @title ERC 20 Token Standard Interface - * https://eips.ethereum.org/EIPS/eip-20 - */ -interface EIP20Interface { - function name() external view returns (string memory); - - function symbol() external view returns (string memory); - - function decimals() external view returns (uint8); - - /** - * @notice Get the total number of tokens in circulation - * @return The supply of tokens - */ - function totalSupply() external view returns (uint256); - - /** - * @notice Gets the balance of the specified address - * @param owner The address from which the balance will be retrieved - * @return balance The balance - */ - function balanceOf(address owner) external view returns (uint256 balance); - - /** - * @notice Transfer `amount` tokens from `msg.sender` to `dst` - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - * @return success Whether or not the transfer succeeded - */ - function transfer(address dst, uint256 amount) - external - returns (bool success); - - /** - * @notice Transfer `amount` tokens from `src` to `dst` - * @param src The address of the source account - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - * @return success Whether or not the transfer succeeded - */ - function transferFrom( - address src, - address dst, - uint256 amount - ) external returns (bool success); - - /** - * @notice Approve `spender` to transfer up to `amount` from `src` - * @dev This will overwrite the approval amount for `spender` - * and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve) - * @param spender The address of the account which may transfer tokens - * @param amount The number of tokens that are approved (-1 means infinite) - * @return success Whether or not the approval succeeded - */ - function approve(address spender, uint256 amount) - external - returns (bool success); - - /** - * @notice Get the current allowance from `owner` for `spender` - * @param owner The address of the account which owns the tokens to be spent - * @param spender The address of the account which may transfer tokens - * @return remaining The number of tokens allowed to be spent (-1 means infinite) - */ - function allowance(address owner, address spender) - external - view - returns (uint256 remaining); - - event Transfer(address indexed from, address indexed to, uint256 amount); - event Approval( - address indexed owner, - address indexed spender, - uint256 amount - ); -} - - -// Dependency file: contracts/WhitelistInterface.sol - -// pragma solidity 0.8.6; - -interface WhitelistInterface { - function setStatus(bool _newStatus) external; - function enabled() external view returns(bool); - - function addUsers(address[] memory _users) external; - function exist(address _user) external view returns(bool); - function getUsers() external view returns(address[] memory currentUsers); - function removeUser(address _user) external; -} - -// Dependency file: contracts/CToken.sol - -// pragma solidity 0.8.6; - -// import "contracts/ComptrollerInterface.sol"; -// import "contracts/CTokenInterfaces.sol"; -// import "contracts/ErrorReporter.sol"; -// import "contracts/Exponential.sol"; -// import "contracts/EIP20Interface.sol"; -// import "contracts/InterestRateModel.sol"; -// import "contracts/WhitelistInterface.sol"; - -/** - * @title tropykus CToken Contract - * @notice Abstract base for CTokens - * @author tropykus - */ -abstract contract CToken is CTokenInterface, Exponential, TokenErrorReporter { - address whitelist; - - /** - * @notice Initialize the money market - * @param comptroller_ The address of the Comptroller - * @param interestRateModel_ The address of the interest rate model - * @param initialExchangeRateMantissa_ The initial exchange rate, scaled by 1e18 - * @param name_ EIP-20 name of this token - * @param symbol_ EIP-20 symbol of this token - * @param decimals_ EIP-20 decimal precision of this token - */ - function initialize( - ComptrollerInterface comptroller_, - InterestRateModel interestRateModel_, - uint256 initialExchangeRateMantissa_, - string memory name_, - string memory symbol_, - uint8 decimals_ - ) public { - require(msg.sender == admin, "CT01"); - require(accrualBlockNumber == 0 && borrowIndex == 0, "CT02"); - - initialExchangeRateMantissa = initialExchangeRateMantissa_; - require(initialExchangeRateMantissa > 0, "CT03"); - - uint256 err = _setComptroller(comptroller_); - require(err == uint256(Error.NO_ERROR), "CT04"); - - accrualBlockNumber = getBlockNumber(); - borrowIndex = mantissaOne; - - err = _setInterestRateModelFresh(interestRateModel_); - require(err == uint256(Error.NO_ERROR), "CT05"); - - name = name_; - symbol = symbol_; - decimals = decimals_; - - _notEntered = true; - } - - function addWhitelist(address _whitelist) external returns (uint256) { - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_INTEREST_RATE_MODEL_OWNER_CHECK - ); - } - whitelist = _whitelist; - } - - /** - * @notice Transfer `tokens` tokens from `src` to `dst` by `spender` - * @dev Called by both `transfer` and `transferFrom` internally - * @param spender The address of the account performing the transfer - * @param src The address of the source account - * @param dst The address of the destination account - * @param tokens The number of tokens to transfer - * @return Whether or not the transfer succeeded - */ - function transferTokens( - address spender, - address src, - address dst, - uint256 tokens - ) internal returns (uint256) { - uint256 allowed = comptroller.transferAllowed( - address(this), - src, - dst, - tokens - ); - if (allowed != 0) { - return - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.TRANSFER_COMPTROLLER_REJECTION, - allowed - ); - } - - if (src == dst) { - return fail(Error.BAD_INPUT, FailureInfo.TRANSFER_NOT_ALLOWED); - } - - uint256 startingAllowance = 0; - if (spender == src) { - startingAllowance = type(uint256).max; - } else { - startingAllowance = transferAllowances[src][spender]; - } - - MathError mathErr; - uint256 allowanceNew; - uint256 srcTokensNew; - uint256 dstTokensNew; - - (mathErr, allowanceNew) = subUInt(startingAllowance, tokens); - if (mathErr != MathError.NO_ERROR) { - return fail(Error.MATH_ERROR, FailureInfo.TRANSFER_NOT_ALLOWED); - } - - (mathErr, srcTokensNew) = subUInt(accountTokens[src].tokens, tokens); - if (mathErr != MathError.NO_ERROR) { - return fail(Error.MATH_ERROR, FailureInfo.TRANSFER_NOT_ENOUGH); - } - - (mathErr, dstTokensNew) = addUInt(accountTokens[dst].tokens, tokens); - if (mathErr != MathError.NO_ERROR) { - return fail(Error.MATH_ERROR, FailureInfo.TRANSFER_TOO_MUCH); - } - - accountTokens[src].tokens = srcTokensNew; - accountTokens[dst].tokens = dstTokensNew; - - if (startingAllowance != type(uint256).max) { - transferAllowances[src][spender] = allowanceNew; - } - - emit Transfer(src, dst, tokens); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Transfer `amount` tokens from `msg.sender` to `dst` - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - * @return Whether or not the transfer succeeded - */ - function transfer(address dst, uint256 amount) - external - override - nonReentrant - returns (bool) - { - return - transferTokens(msg.sender, msg.sender, dst, amount) == - uint256(Error.NO_ERROR); - } - - /** - * @notice Transfer `amount` tokens from `src` to `dst` - * @param src The address of the source account - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - * @return Whether or not the transfer succeeded - */ - function transferFrom( - address src, - address dst, - uint256 amount - ) external override nonReentrant returns (bool) { - return - transferTokens(msg.sender, src, dst, amount) == - uint256(Error.NO_ERROR); - } - - /** - * @notice Approve `spender` to transfer up to `amount` from `src` - * @dev This will overwrite the approval amount for `spender` - * and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve) - * @param spender The address of the account which may transfer tokens - * @param amount The number of tokens that are approved (-1 means infinite) - * @return Whether or not the approval succeeded - */ - function approve(address spender, uint256 amount) - external - override - returns (bool) - { - transferAllowances[msg.sender][spender] = amount; - emit Approval(msg.sender, spender, amount); - return true; - } - - /** - * @notice Get the current allowance from `owner` for `spender` - * @param owner The address of the account which owns the tokens to be spent - * @param spender The address of the account which may transfer tokens - * @return The number of tokens allowed to be spent (-1 means infinite) - */ - function allowance(address owner, address spender) - external - view - override - returns (uint256) - { - return transferAllowances[owner][spender]; - } - - /** - * @notice Get the token balance of the `owner` - * @param owner The address of the account to query - * @return The number of tokens owned by `owner` - */ - function balanceOf(address owner) external view override returns (uint256) { - return accountTokens[owner].tokens; - } - - /** - * @notice Get the underlying balance of the `owner` - * @dev This also accrues interest in a transaction - * @param owner The address of the account to query - * @return The amount of underlying owned by `owner` - */ - function balanceOfUnderlying(address owner) - external - override - returns (uint256) - { - (MathError mErr, uint256 balance) = mulScalarTruncate( - Exp({mantissa: exchangeRateCurrent()}), - accountTokens[owner].tokens - ); - require(mErr == MathError.NO_ERROR, "CT06"); - return balance; - } - - /** - * @notice Get a snapshot of the account's balances, and the cached exchange rate - * @dev This is used by comptroller to more efficiently perform liquidity checks. - * @param account Address of the account to snapshot - * @return (possible error, token balance, borrow balance, exchange rate mantissa) - */ - function getAccountSnapshot(address account) - external - view - override - returns ( - uint256, - uint256, - uint256, - uint256 - ) - { - uint256 cTokenBalance = accountTokens[account].tokens; - uint256 borrowBalance; - uint256 exchangeRateMantissa; - - MathError mErr; - - (mErr, borrowBalance) = borrowBalanceStoredInternal(account); - if (mErr != MathError.NO_ERROR) { - return (uint256(Error.MATH_ERROR), 0, 0, 0); - } - - (mErr, exchangeRateMantissa) = exchangeRateStoredInternal(); - if (mErr != MathError.NO_ERROR) { - return (uint256(Error.MATH_ERROR), 0, 0, 0); - } - - return ( - uint256(Error.NO_ERROR), - cTokenBalance, - borrowBalance, - exchangeRateMantissa - ); - } - - /** - * @dev Function to simply retrieve block number - * This exists mainly for inheriting test contracts to stub this result. - */ - function getBlockNumber() internal view virtual returns (uint256) { - return block.number; - } - - /** - * @notice Returns the current per-block borrow interest rate for this cToken - * @return The borrow interest rate per block, scaled by 1e18 - */ - function borrowRatePerBlock() external view override returns (uint256) { - return - interestRateModel.getBorrowRate( - getCashPrior(), - totalBorrows, - totalReserves - ); - } - - /** - * @notice Returns the current per-block supply interest rate for this cToken - * @return The supply interest rate per block, scaled by 1e18 - */ - function supplyRatePerBlock() external view override returns (uint256) { - return - interestRateModel.getSupplyRate( - getCashPrior(), - totalBorrows, - totalReserves, - reserveFactorMantissa - ); - } - - /** - * @notice Returns the current total borrows plus accrued interest - * @return The total borrows with interest - */ - function totalBorrowsCurrent() - external - override - nonReentrant - returns (uint256) - { - require(accrueInterest() == uint256(Error.NO_ERROR), "CT07"); - return totalBorrows; - } - - /** - * @notice Accrue interest to updated borrowIndex and then calculate account's borrow balance using the updated borrowIndex - * @param account The address whose balance should be calculated after updating borrowIndex - * @return The calculated balance - */ - function borrowBalanceCurrent(address account) - external - override - nonReentrant - returns (uint256) - { - require(accrueInterest() == uint256(Error.NO_ERROR), "CT07"); - return borrowBalanceStored(account); - } - - /** - * @notice Return the borrow balance of account based on stored data - * @param account The address whose balance should be calculated - * @return The calculated balance - */ - function borrowBalanceStored(address account) - public - view - override - returns (uint256) - { - (MathError err, uint256 result) = borrowBalanceStoredInternal(account); - require(err == MathError.NO_ERROR, "CT08"); - return result; - } - - /** - * @notice Return the borrow balance of account based on stored data - * @param account The address whose balance should be calculated - * @return (error code, the calculated balance or 0 if error code is non-zero) - */ - function borrowBalanceStoredInternal(address account) - internal - view - returns (MathError, uint256) - { - MathError mathErr; - uint256 principalTimesIndex; - uint256 result; - - BorrowSnapshot storage borrowSnapshot = accountBorrows[account]; - - if (borrowSnapshot.principal == 0) { - return (MathError.NO_ERROR, 0); - } - - (mathErr, principalTimesIndex) = mulUInt( - borrowSnapshot.principal, - borrowIndex - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - - (mathErr, result) = divUInt( - principalTimesIndex, - borrowSnapshot.interestIndex - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - - return (MathError.NO_ERROR, result); - } - - function getBorrowerPrincipalStored(address account) - public - view - returns (uint256 borrowed) - { - borrowed = accountBorrows[account].principal; - } - - function getSupplierSnapshotStored(address account) - public - view - returns ( - uint256 tokens, - uint256 underlyingAmount, - uint256 suppliedAt, - uint256 promisedSupplyRate - ) - { - tokens = accountTokens[account].tokens; - underlyingAmount = accountTokens[account].underlyingAmount; - suppliedAt = accountTokens[account].suppliedAt; - promisedSupplyRate = accountTokens[account].promisedSupplyRate; - } - - /** - * @notice Accrue interest then return the up-to-date exchange rate - * @return Calculated exchange rate scaled by 1e18 - */ - function exchangeRateCurrent() - public - override - nonReentrant - returns (uint256) - { - require(accrueInterest() == uint256(Error.NO_ERROR), "CT07"); - return exchangeRateStored(); - } - - /** - * @notice Calculates the exchange rate from the underlying to the CToken - * @dev This function does not accrue interest before calculating the exchange rate - * @return Calculated exchange rate scaled by 1e18 - */ - function exchangeRateStored() public view override returns (uint256) { - (MathError err, uint256 result) = exchangeRateStoredInternal(); - require(err == MathError.NO_ERROR, "CT09"); - return result; - } - - /** - * @notice Calculates the exchange rate from the underlying to the CToken - * @dev This function does not accrue interest before calculating the exchange rate - * @return (error code, calculated exchange rate scaled by 1e18) - */ - function exchangeRateStoredInternal() - internal - view - virtual - returns (MathError, uint256) - { - uint256 _totalSupply = totalSupply; - if (_totalSupply == 0) { - return (MathError.NO_ERROR, initialExchangeRateMantissa); - } else { - MathError error; - uint256 exchangeRate; - uint256 totalCash = getCashPrior(); - if (interestRateModel.isTropykusInterestRateModel()) { - (error, exchangeRate) = tropykusExchangeRateStoredInternal( - msg.sender - ); - if (error == MathError.NO_ERROR) { - return (MathError.NO_ERROR, exchangeRate); - } else { - return (MathError.NO_ERROR, initialExchangeRateMantissa); - } - } - return - interestRateModel.getExchangeRate( - totalCash, - totalBorrows, - totalReserves, - totalSupply - ); - } - } - - function tropykusExchangeRateStoredInternal(address redeemer) - internal - view - returns (MathError, uint256) - { - if (totalSupply == 0) { - return (MathError.NO_ERROR, initialExchangeRateMantissa); - } else { - SupplySnapshot storage supplySnapshot = accountTokens[redeemer]; - if (supplySnapshot.suppliedAt == 0) { - return (MathError.DIVISION_BY_ZERO, 0); - } - (, uint256 interestFactorMantissa, ) = tropykusInterestAccrued( - redeemer - ); - Exp memory interestFactor = Exp({mantissa: interestFactorMantissa}); - uint256 currentUnderlying = supplySnapshot.underlyingAmount; - Exp memory redeemerUnderlying = Exp({mantissa: currentUnderlying}); - (, Exp memory realAmount) = mulExp( - interestFactor, - redeemerUnderlying - ); - (, Exp memory exchangeRate) = getExp( - realAmount.mantissa, - supplySnapshot.tokens - ); - return (MathError.NO_ERROR, exchangeRate.mantissa); - } - } - - function tropykusInterestAccrued(address account) - internal - view - returns ( - MathError, - uint256, - uint256 - ) - { - SupplySnapshot storage supplySnapshot = accountTokens[account]; - uint256 promisedSupplyRate = supplySnapshot.promisedSupplyRate; - Exp memory expectedSupplyRatePerBlock = Exp({ - mantissa: promisedSupplyRate - }); - (, uint256 delta) = subUInt( - accrualBlockNumber, - supplySnapshot.suppliedAt - ); - (, Exp memory expectedSupplyRatePerBlockWithDelta) = mulScalar( - expectedSupplyRatePerBlock, - delta - ); - (, Exp memory interestFactor) = addExp( - Exp({mantissa: 1e18}), - expectedSupplyRatePerBlockWithDelta - ); - uint256 currentUnderlying = supplySnapshot.underlyingAmount; - Exp memory redeemerUnderlying = Exp({mantissa: currentUnderlying}); - (, Exp memory realAmount) = mulExp(interestFactor, redeemerUnderlying); - (, uint256 interestEarned) = subUInt( - realAmount.mantissa, - currentUnderlying - ); - return (MathError.NO_ERROR, interestFactor.mantissa, interestEarned); - } - - /** - * @notice Get cash balance of this cToken in the underlying asset - * @return The quantity of underlying asset owned by this contract - */ - function getCash() external view override returns (uint256) { - return getCashPrior(); - } - - /** - * @notice Applies accrued interest to total borrows and reserves - * @dev This calculates interest accrued from the last checkpointed block - * up to the current block and writes new checkpoint to storage. - */ - function accrueInterest() public override returns (uint256) { - uint256 currentBlockNumber = getBlockNumber(); - uint256 accrualBlockNumberPrior = accrualBlockNumber; - - if (accrualBlockNumberPrior == currentBlockNumber) { - return uint256(Error.NO_ERROR); - } - - uint256 cashPrior = getCashPrior(); - uint256 borrowsPrior = totalBorrows; - uint256 reservesPrior = totalReserves; - uint256 borrowIndexPrior = borrowIndex; - - uint256 borrowRateMantissa = interestRateModel.getBorrowRate( - cashPrior, - borrowsPrior, - reservesPrior - ); - require(borrowRateMantissa <= borrowRateMaxMantissa, "CT10"); - - (MathError mathErr, uint256 blockDelta) = subUInt( - currentBlockNumber, - accrualBlockNumberPrior - ); - require(mathErr == MathError.NO_ERROR, "CT11"); - - Exp memory simpleInterestFactor; - uint256 interestAccumulated; - uint256 totalBorrowsNew; - uint256 totalReservesNew; - uint256 borrowIndexNew; - - (mathErr, simpleInterestFactor) = mulScalar( - Exp({mantissa: borrowRateMantissa}), - blockDelta - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .ACCRUE_INTEREST_SIMPLE_INTEREST_FACTOR_CALCULATION_FAILED, - uint256(mathErr) - ); - } - - (mathErr, interestAccumulated) = mulScalarTruncate( - simpleInterestFactor, - borrowsPrior - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .ACCRUE_INTEREST_ACCUMULATED_INTEREST_CALCULATION_FAILED, - uint256(mathErr) - ); - } - - (mathErr, totalBorrowsNew) = addUInt(interestAccumulated, borrowsPrior); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .ACCRUE_INTEREST_NEW_TOTAL_BORROWS_CALCULATION_FAILED, - uint256(mathErr) - ); - } - - (mathErr, totalReservesNew) = mulScalarTruncateAddUInt( - Exp({mantissa: reserveFactorMantissa}), - interestAccumulated, - reservesPrior - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .ACCRUE_INTEREST_NEW_TOTAL_RESERVES_CALCULATION_FAILED, - uint256(mathErr) - ); - } - - if (interestRateModel.isTropykusInterestRateModel()) { - (mathErr, totalReservesNew) = newReserves( - borrowRateMantissa, - cashPrior, - borrowsPrior, - reservesPrior, - interestAccumulated - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .ACCRUE_INTEREST_NEW_TOTAL_RESERVES_CALCULATION_FAILED, - uint256(mathErr) - ); - } - } - - (mathErr, borrowIndexNew) = mulScalarTruncateAddUInt( - simpleInterestFactor, - borrowIndexPrior, - borrowIndexPrior - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .ACCRUE_INTEREST_NEW_BORROW_INDEX_CALCULATION_FAILED, - uint256(mathErr) - ); - } - - accrualBlockNumber = currentBlockNumber; - borrowIndex = borrowIndexNew; - totalBorrows = totalBorrowsNew; - totalReserves = totalReservesNew; - - emit AccrueInterest( - cashPrior, - interestAccumulated, - borrowIndexNew, - totalBorrowsNew - ); - - return uint256(Error.NO_ERROR); - } - - function newReserves( - uint256 borrowRateMantissa, - uint256 cashPrior, - uint256 borrowsPrior, - uint256 reservesPrior, - uint256 interestAccumulated - ) internal view returns (MathError mathErr, uint256 totalReservesNew) { - uint256 newReserveFactorMantissa; - uint256 utilizationRate = interestRateModel.utilizationRate( - cashPrior, - borrowsPrior, - reservesPrior - ); - uint256 expectedSupplyRate = interestRateModel.getSupplyRate( - cashPrior, - borrowsPrior, - reservesPrior, - reserveFactorMantissa - ); - if ( - interestRateModel.isAboveOptimal( - cashPrior, - borrowsPrior, - reservesPrior - ) - ) { - (mathErr, newReserveFactorMantissa) = mulScalarTruncate( - Exp({mantissa: utilizationRate}), - borrowRateMantissa - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - (mathErr, newReserveFactorMantissa) = subUInt( - newReserveFactorMantissa, - expectedSupplyRate - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - (mathErr, totalReservesNew) = mulScalarTruncateAddUInt( - Exp({mantissa: newReserveFactorMantissa}), - interestAccumulated, - reservesPrior - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - } else { - mathErr = MathError.NO_ERROR; - totalReservesNew = reservesPrior; - } - } - - /** - * @notice Sender supplies assets into the market and receives cTokens in exchange - * @dev Accrues interest whether or not the operation succeeds, unless reverted - * @param mintAmount The amount of the underlying asset to supply - * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual mint amount. - */ - function mintInternal(uint256 mintAmount) - internal - nonReentrant - returns (uint256, uint256) - { - if (WhitelistInterface(whitelist).enabled()) { - require(WhitelistInterface(whitelist).exist(msg.sender), "CT26"); - } - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return ( - fail(Error(error), FailureInfo.MINT_ACCRUE_INTEREST_FAILED), - 0 - ); - } - return mintFresh(msg.sender, mintAmount); - } - - struct MintLocalVars { - Error err; - MathError mathErr; - uint256 exchangeRateMantissa; - uint256 mintTokens; - uint256 totalSupplyNew; - uint256 accountTokensNew; - uint256 actualMintAmount; - } - - /** - * @notice User supplies assets into the market and receives cTokens in exchange - * @dev Assumes interest has already been accrued up to the current block - * @param minter The address of the account which is supplying the assets - * @param mintAmount The amount of the underlying asset to supply - * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual mint amount. - */ - function mintFresh(address minter, uint256 mintAmount) - internal - returns (uint256, uint256) - { - uint256 allowed = comptroller.mintAllowed( - address(this), - minter, - mintAmount - ); - if (allowed != 0) { - return ( - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.MINT_COMPTROLLER_REJECTION, - allowed - ), - 0 - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return ( - fail(Error.MARKET_NOT_FRESH, FailureInfo.MINT_FRESHNESS_CHECK), - 0 - ); - } - - MintLocalVars memory vars; - - ( - vars.mathErr, - vars.exchangeRateMantissa - ) = exchangeRateStoredInternal(); - if (vars.mathErr != MathError.NO_ERROR) { - return ( - failOpaque( - Error.MATH_ERROR, - FailureInfo.MINT_EXCHANGE_RATE_READ_FAILED, - uint256(vars.mathErr) - ), - 0 - ); - } - if (interestRateModel.isTropykusInterestRateModel()) { - SupplySnapshot storage supplySnapshot = accountTokens[minter]; - (, uint256 newTotalSupply) = addUInt( - supplySnapshot.underlyingAmount, - mintAmount - ); - require(newTotalSupply <= 0.1e18, "CT24"); - } - vars.actualMintAmount = doTransferIn(minter, mintAmount); - - (vars.mathErr, vars.mintTokens) = divScalarByExpTruncate( - vars.actualMintAmount, - Exp({mantissa: vars.exchangeRateMantissa}) - ); - require(vars.mathErr == MathError.NO_ERROR, "CT12"); - - (vars.mathErr, vars.totalSupplyNew) = addUInt( - totalSupply, - vars.mintTokens - ); - require(vars.mathErr == MathError.NO_ERROR, "CT13"); - - (vars.mathErr, vars.accountTokensNew) = addUInt( - accountTokens[minter].tokens, - vars.mintTokens - ); - require(vars.mathErr == MathError.NO_ERROR, "CT14"); - - uint256 currentSupplyRate = interestRateModel.getSupplyRate( - getCashPrior(), - totalBorrows, - totalReserves, - reserveFactorMantissa - ); - - bool isTropykusInterestRateModel = interestRateModel - .isTropykusInterestRateModel(); - - if (accountTokens[minter].tokens > 0) { - Exp memory updatedUnderlying; - if (isTropykusInterestRateModel) { - (, uint256 interestFactorMantissa, ) = tropykusInterestAccrued( - minter - ); - Exp memory interestFactor = Exp({ - mantissa: interestFactorMantissa - }); - uint256 currentUnderlyingAmount = accountTokens[minter] - .underlyingAmount; - MathError mErrorNewAmount; - (mErrorNewAmount, updatedUnderlying) = mulExp( - Exp({mantissa: currentUnderlyingAmount}), - interestFactor - ); - if (mErrorNewAmount != MathError.NO_ERROR) { - return ( - failOpaque( - Error.MATH_ERROR, - FailureInfo.MINT_EXCHANGE_CALCULATION_FAILED, - uint256(mErrorNewAmount) - ), - 0 - ); - } - } else { - uint256 currentTokens = accountTokens[minter].tokens; - MathError mErrorUpdatedUnderlying; - (mErrorUpdatedUnderlying, updatedUnderlying) = mulExp( - Exp({mantissa: currentTokens}), - Exp({mantissa: vars.exchangeRateMantissa}) - ); - if (mErrorUpdatedUnderlying != MathError.NO_ERROR) { - return ( - failOpaque( - Error.MATH_ERROR, - FailureInfo.MINT_EXCHANGE_CALCULATION_FAILED, - uint256(mErrorUpdatedUnderlying) - ), - 0 - ); - } - } - (, mintAmount) = addUInt(updatedUnderlying.mantissa, mintAmount); - } - - totalSupply = vars.totalSupplyNew; - accountTokens[minter] = SupplySnapshot({ - tokens: vars.accountTokensNew, - underlyingAmount: mintAmount, - suppliedAt: accrualBlockNumber, - promisedSupplyRate: currentSupplyRate - }); - - emit Mint(minter, vars.actualMintAmount, vars.mintTokens); - emit Transfer(address(this), minter, vars.mintTokens); - - return (uint256(Error.NO_ERROR), vars.actualMintAmount); - } - - /** - * @notice Sender redeems cTokens in exchange for a specified amount of underlying asset - * @dev Accrues interest whether or not the operation succeeds, unless reverted - * @param redeemAmount The amount of underlying to receive from redeeming cTokens - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function redeemUnderlyingInternal(uint256 redeemAmount) - internal - nonReentrant - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return - fail(Error(error), FailureInfo.REDEEM_ACCRUE_INTEREST_FAILED); - } - return redeemFresh(payable(msg.sender), redeemAmount); - } - - struct RedeemLocalVars { - Error err; - MathError mathErr; - uint256 exchangeRateMantissa; - uint256 redeemTokens; - uint256 redeemAmount; - uint256 totalSupplyNew; - uint256 accountTokensNew; - uint256 newSubsidyFund; - } - - /** - * @notice User redeems cTokens in exchange for the underlying asset - * @dev Assumes interest has already been accrued up to the current block - * @param redeemer The address of the account which is redeeming the tokens - * @param redeemAmountIn The number of underlying tokens to receive from redeeming cTokens - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function redeemFresh(address payable redeemer, uint256 redeemAmountIn) - internal - returns (uint256) - { - require(redeemAmountIn > 0, "CT15"); - - RedeemLocalVars memory vars; - - SupplySnapshot storage supplySnapshot = accountTokens[redeemer]; - - ( - vars.mathErr, - vars.exchangeRateMantissa - ) = exchangeRateStoredInternal(); - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.REDEEM_EXCHANGE_RATE_READ_FAILED, - uint256(vars.mathErr) - ); - } - - uint256 interestEarned; - uint256 subsidyFundPortion; - uint256 currentUnderlying; - - bool isTropykusInterestRateModel = interestRateModel - .isTropykusInterestRateModel(); - if (isTropykusInterestRateModel) { - currentUnderlying = supplySnapshot.underlyingAmount; - (, , interestEarned) = tropykusInterestAccrued(redeemer); - } - supplySnapshot.promisedSupplyRate = interestRateModel.getSupplyRate( - getCashPrior(), - totalBorrows, - totalReserves, - reserveFactorMantissa - ); - - if ( - isTropykusInterestRateModel && - !interestRateModel.isAboveOptimal( - getCashPrior(), - totalBorrows, - totalReserves - ) - ) { - uint256 borrowRate = interestRateModel.getBorrowRate( - getCashPrior(), - totalBorrows, - totalReserves - ); - - uint256 utilizationRate = interestRateModel.utilizationRate( - getCashPrior(), - totalBorrows, - totalReserves - ); - - (, uint256 estimatedEarning) = mulScalarTruncate( - Exp({mantissa: borrowRate}), - utilizationRate - ); - - (, subsidyFundPortion) = subUInt( - supplySnapshot.promisedSupplyRate, - estimatedEarning - ); - (, Exp memory subsidyFactor) = getExp( - subsidyFundPortion, - supplySnapshot.promisedSupplyRate - ); - (, subsidyFundPortion) = mulScalarTruncate( - subsidyFactor, - interestEarned - ); - } - - vars.redeemAmount = redeemAmountIn; - - if (isTropykusInterestRateModel) { - (, Exp memory num) = mulExp( - vars.redeemAmount, - supplySnapshot.tokens - ); - (, Exp memory realTokensWithdrawAmount) = getExp( - num.mantissa, - currentUnderlying - ); - vars.redeemTokens = realTokensWithdrawAmount.mantissa; - } else { - (vars.mathErr, vars.redeemTokens) = divScalarByExpTruncate( - redeemAmountIn, - Exp({mantissa: vars.exchangeRateMantissa}) - ); - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.REDEEM_EXCHANGE_AMOUNT_CALCULATION_FAILED, - uint256(vars.mathErr) - ); - } - } - // } - - uint256 allowed = comptroller.redeemAllowed( - address(this), - redeemer, - vars.redeemTokens - ); - if (allowed != 0) { - return - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.REDEEM_COMPTROLLER_REJECTION, - allowed - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.REDEEM_FRESHNESS_CHECK - ); - } - - (vars.mathErr, vars.totalSupplyNew) = subUInt( - totalSupply, - vars.redeemTokens - ); - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.REDEEM_NEW_TOTAL_SUPPLY_CALCULATION_FAILED, - uint256(vars.mathErr) - ); - } - - (, vars.newSubsidyFund) = subUInt(subsidyFund, subsidyFundPortion); - - (vars.mathErr, vars.accountTokensNew) = subUInt( - supplySnapshot.tokens, - vars.redeemTokens - ); - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.REDEEM_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED, - uint256(vars.mathErr) - ); - } - - uint256 cash = getCashPrior(); - if (isTropykusInterestRateModel) { - cash = address(this).balance; - } - - if (cash < vars.redeemAmount) { - return - fail( - Error.TOKEN_INSUFFICIENT_CASH, - FailureInfo.REDEEM_TRANSFER_OUT_NOT_POSSIBLE - ); - } - - doTransferOut(redeemer, vars.redeemAmount); - - totalSupply = vars.totalSupplyNew; - subsidyFund = vars.newSubsidyFund; - supplySnapshot.tokens = vars.accountTokensNew; - supplySnapshot.suppliedAt = accrualBlockNumber; - (, supplySnapshot.underlyingAmount) = subUInt( - supplySnapshot.underlyingAmount, - vars.redeemAmount - ); - - emit Transfer(redeemer, address(this), vars.redeemTokens); - emit Redeem(redeemer, vars.redeemAmount, vars.redeemTokens); - - comptroller.redeemVerify( - address(this), - redeemer, - vars.redeemAmount, - vars.redeemTokens - ); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Sender borrows assets from the protocol to their own address - * @param borrowAmount The amount of the underlying asset to borrow - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function borrowInternal(uint256 borrowAmount) - internal - nonReentrant - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return - fail(Error(error), FailureInfo.BORROW_ACCRUE_INTEREST_FAILED); - } - return borrowFresh(payable(msg.sender), borrowAmount); - } - - struct BorrowLocalVars { - MathError mathErr; - uint256 accountBorrows; - uint256 accountBorrowsNew; - uint256 totalBorrowsNew; - } - - /** - * @notice Users borrow assets from the protocol to their own address - * @param borrowAmount The amount of the underlying asset to borrow - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function borrowFresh(address payable borrower, uint256 borrowAmount) - internal - returns (uint256) - { - uint256 allowed = comptroller.borrowAllowed( - address(this), - borrower, - borrowAmount - ); - if (allowed != 0) { - return - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.BORROW_COMPTROLLER_REJECTION, - allowed - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.BORROW_FRESHNESS_CHECK - ); - } - - if (getCashPrior() < borrowAmount) { - return - fail( - Error.TOKEN_INSUFFICIENT_CASH, - FailureInfo.BORROW_CASH_NOT_AVAILABLE - ); - } - - BorrowLocalVars memory vars; - - (vars.mathErr, vars.accountBorrows) = borrowBalanceStoredInternal( - borrower - ); - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED, - uint256(vars.mathErr) - ); - } - - (vars.mathErr, vars.accountBorrowsNew) = addUInt( - vars.accountBorrows, - borrowAmount - ); - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED, - uint256(vars.mathErr) - ); - } - - (vars.mathErr, vars.totalBorrowsNew) = addUInt( - totalBorrows, - borrowAmount - ); - if (interestRateModel.isTropykusInterestRateModel()) { - require(vars.totalBorrowsNew <= 0.1e18, "CT25"); - } - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED, - uint256(vars.mathErr) - ); - } - - doTransferOut(borrower, borrowAmount); - - accountBorrows[borrower].principal = vars.accountBorrowsNew; - accountBorrows[borrower].interestIndex = borrowIndex; - totalBorrows = vars.totalBorrowsNew; - - emit Borrow( - borrower, - borrowAmount, - vars.accountBorrowsNew, - vars.totalBorrowsNew - ); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Sender repays their own borrow - * @param repayAmount The amount to repay - * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual repayment amount. - */ - function repayBorrowInternal(uint256 repayAmount) - internal - nonReentrant - returns (uint256, uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return ( - fail( - Error(error), - FailureInfo.REPAY_BORROW_ACCRUE_INTEREST_FAILED - ), - 0 - ); - } - return repayBorrowFresh(msg.sender, msg.sender, repayAmount); - } - - struct RepayBorrowLocalVars { - Error err; - MathError mathErr; - uint256 repayAmount; - uint256 borrowerIndex; - uint256 accountBorrows; - uint256 accountBorrowsNew; - uint256 totalBorrowsNew; - uint256 actualRepayAmount; - } - - /** - * @notice Borrows are repaid by another user (possibly the borrower). - * @param payer the account paying off the borrow - * @param borrower the account with the debt being payed off - * @param repayAmount the amount of undelrying tokens being returned - * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual repayment amount. - */ - function repayBorrowFresh( - address payer, - address borrower, - uint256 repayAmount - ) internal returns (uint256, uint256) { - uint256 allowed = comptroller.repayBorrowAllowed( - address(this), - payer, - borrower, - repayAmount - ); - if (allowed != 0) { - return ( - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.REPAY_BORROW_COMPTROLLER_REJECTION, - allowed - ), - 0 - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return ( - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.REPAY_BORROW_FRESHNESS_CHECK - ), - 0 - ); - } - - RepayBorrowLocalVars memory vars; - - vars.borrowerIndex = accountBorrows[borrower].interestIndex; - - (vars.mathErr, vars.accountBorrows) = borrowBalanceStoredInternal( - borrower - ); - if (vars.mathErr != MathError.NO_ERROR) { - return ( - failOpaque( - Error.MATH_ERROR, - FailureInfo - .REPAY_BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED, - uint256(vars.mathErr) - ), - 0 - ); - } - - if (repayAmount == type(uint256).max) { - vars.repayAmount = vars.accountBorrows; - } else { - vars.repayAmount = repayAmount; - } - - vars.actualRepayAmount = doTransferIn(payer, vars.repayAmount); - - (vars.mathErr, vars.accountBorrowsNew) = subUInt( - vars.accountBorrows, - vars.actualRepayAmount - ); - require(vars.mathErr == MathError.NO_ERROR, "CT16"); - - (vars.mathErr, vars.totalBorrowsNew) = subUInt( - totalBorrows, - vars.actualRepayAmount - ); - require(vars.mathErr == MathError.NO_ERROR, "CT17"); - - accountBorrows[borrower].principal = vars.accountBorrowsNew; - accountBorrows[borrower].interestIndex = borrowIndex; - totalBorrows = vars.totalBorrowsNew; - - emit RepayBorrow( - payer, - borrower, - vars.actualRepayAmount, - vars.accountBorrowsNew, - vars.totalBorrowsNew - ); - - return (uint256(Error.NO_ERROR), vars.actualRepayAmount); - } - - /** - * @notice The sender liquidates the borrowers collateral. - * The collateral seized is transferred to the liquidator. - * @param borrower The borrower of this cToken to be liquidated - * @param cTokenCollateral The market in which to seize collateral from the borrower - * @param repayAmount The amount of the underlying borrowed asset to repay - * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual repayment amount. - */ - function liquidateBorrowInternal( - address borrower, - uint256 repayAmount, - CTokenInterface cTokenCollateral - ) internal nonReentrant returns (uint256, uint256) { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return ( - fail( - Error(error), - FailureInfo.LIQUIDATE_ACCRUE_BORROW_INTEREST_FAILED - ), - 0 - ); - } - - error = cTokenCollateral.accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return ( - fail( - Error(error), - FailureInfo.LIQUIDATE_ACCRUE_COLLATERAL_INTEREST_FAILED - ), - 0 - ); - } - - // liquidateBorrowFresh emits borrow-specific logs on errors, so we don't need to - return - liquidateBorrowFresh( - msg.sender, - borrower, - repayAmount, - cTokenCollateral - ); - } - - /** - * @notice The liquidator liquidates the borrowers collateral. - * The collateral seized is transferred to the liquidator. - * @param borrower The borrower of this cToken to be liquidated - * @param liquidator The address repaying the borrow and seizing collateral - * @param cTokenCollateral The market in which to seize collateral from the borrower - * @param repayAmount The amount of the underlying borrowed asset to repay - * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual repayment amount. - */ - function liquidateBorrowFresh( - address liquidator, - address borrower, - uint256 repayAmount, - CTokenInterface cTokenCollateral - ) internal returns (uint256, uint256) { - uint256 allowed = comptroller.liquidateBorrowAllowed( - address(this), - address(cTokenCollateral), - liquidator, - borrower, - repayAmount - ); - if (allowed != 0) { - return ( - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.LIQUIDATE_COMPTROLLER_REJECTION, - allowed - ), - 0 - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return ( - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.LIQUIDATE_FRESHNESS_CHECK - ), - 0 - ); - } - - if (cTokenCollateral.accrualBlockNumber() != getBlockNumber()) { - return ( - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.LIQUIDATE_COLLATERAL_FRESHNESS_CHECK - ), - 0 - ); - } - - if (borrower == liquidator) { - return ( - fail( - Error.INVALID_ACCOUNT_PAIR, - FailureInfo.LIQUIDATE_LIQUIDATOR_IS_BORROWER - ), - 0 - ); - } - - if (repayAmount == 0) { - return ( - fail( - Error.INVALID_CLOSE_AMOUNT_REQUESTED, - FailureInfo.LIQUIDATE_CLOSE_AMOUNT_IS_ZERO - ), - 0 - ); - } - - if (repayAmount == type(uint256).max) { - return ( - fail( - Error.INVALID_CLOSE_AMOUNT_REQUESTED, - FailureInfo.LIQUIDATE_CLOSE_AMOUNT_IS_UINT_MAX - ), - 0 - ); - } - - ( - uint256 repayBorrowError, - uint256 actualRepayAmount - ) = repayBorrowFresh(liquidator, borrower, repayAmount); - if (repayBorrowError != uint256(Error.NO_ERROR)) { - return ( - fail( - Error(repayBorrowError), - FailureInfo.LIQUIDATE_REPAY_BORROW_FRESH_FAILED - ), - 0 - ); - } - - (uint256 amountSeizeError, uint256 seizeTokens) = comptroller - .liquidateCalculateSeizeTokens( - address(this), - address(cTokenCollateral), - actualRepayAmount - ); - require(amountSeizeError == uint256(Error.NO_ERROR), "CT18"); - - require(cTokenCollateral.balanceOf(borrower) >= seizeTokens, "CT19"); - - uint256 seizeError; - if (address(cTokenCollateral) == address(this)) { - seizeError = seizeInternal( - address(this), - liquidator, - borrower, - seizeTokens - ); - } else { - seizeError = cTokenCollateral.seize( - liquidator, - borrower, - seizeTokens - ); - } - - require(seizeError == uint256(Error.NO_ERROR), "CT20"); - - emit LiquidateBorrow( - liquidator, - borrower, - actualRepayAmount, - address(cTokenCollateral), - seizeTokens - ); - - return (uint256(Error.NO_ERROR), actualRepayAmount); - } - - /** - * @notice Transfers collateral tokens (this market) to the liquidator. - * @dev Will fail unless called by another cToken during the process of liquidation. - * Its absolutely critical to use msg.sender as the borrowed cToken and not a parameter. - * @param liquidator The account receiving seized collateral - * @param borrower The account having collateral seized - * @param seizeTokens The number of cTokens to seize - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function seize( - address liquidator, - address borrower, - uint256 seizeTokens - ) external override nonReentrant returns (uint256) { - return seizeInternal(msg.sender, liquidator, borrower, seizeTokens); - } - - struct SeizeVars { - uint256 seizeAmount; - uint256 exchangeRate; - uint256 borrowerTokensNew; - uint256 borrowerAmountNew; - uint256 liquidatorTokensNew; - uint256 liquidatorAmountNew; - uint256 totalCash; - uint256 supplyRate; - } - - /** - * @notice Transfers collateral tokens (this market) to the liquidator. - * @dev Called only during an in-kind liquidation, or by liquidateBorrow during the liquidation of another CToken. - * Its absolutely critical to use msg.sender as the seizer cToken and not a parameter. - * @param seizerToken The contract seizing the collateral (i.e. borrowed cToken) - * @param liquidator The account receiving seized collateral - * @param borrower The account having collateral seized - * @param seizeTokens The number of cTokens to seize - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function seizeInternal( - address seizerToken, - address liquidator, - address borrower, - uint256 seizeTokens - ) internal returns (uint256) { - uint256 allowed = comptroller.seizeAllowed( - address(this), - seizerToken, - liquidator, - borrower, - seizeTokens - ); - if (allowed != 0) { - return - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.LIQUIDATE_SEIZE_COMPTROLLER_REJECTION, - allowed - ); - } - - if (borrower == liquidator) { - return - fail( - Error.INVALID_ACCOUNT_PAIR, - FailureInfo.LIQUIDATE_SEIZE_LIQUIDATOR_IS_BORROWER - ); - } - - SeizeVars memory seizeVars; - - MathError mathErr; - - (mathErr, seizeVars.borrowerTokensNew) = subUInt( - accountTokens[borrower].tokens, - seizeTokens - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.LIQUIDATE_SEIZE_BALANCE_DECREMENT_FAILED, - uint256(mathErr) - ); - } - - seizeVars.totalCash = getCashPrior(); - seizeVars.supplyRate = interestRateModel.getSupplyRate( - seizeVars.totalCash, - totalBorrows, - totalReserves, - reserveFactorMantissa - ); - - (, seizeVars.exchangeRate) = interestRateModel.getExchangeRate( - seizeVars.totalCash, - totalBorrows, - totalReserves, - totalSupply - ); - - if (interestRateModel.isTropykusInterestRateModel()) { - (, seizeVars.exchangeRate) = tropykusExchangeRateStoredInternal( - borrower - ); - } - - (, seizeVars.seizeAmount) = mulUInt( - seizeTokens, - seizeVars.exchangeRate - ); - (, seizeVars.seizeAmount) = divUInt(seizeVars.seizeAmount, 1e18); - - (, seizeVars.borrowerAmountNew) = subUInt( - accountTokens[borrower].underlyingAmount, - seizeVars.seizeAmount - ); - - (mathErr, seizeVars.liquidatorTokensNew) = addUInt( - accountTokens[liquidator].tokens, - seizeTokens - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.LIQUIDATE_SEIZE_BALANCE_INCREMENT_FAILED, - uint256(mathErr) - ); - } - - (, seizeVars.liquidatorAmountNew) = addUInt( - accountTokens[liquidator].underlyingAmount, - seizeVars.seizeAmount - ); - - accountTokens[borrower].tokens = seizeVars.borrowerTokensNew; - accountTokens[borrower].underlyingAmount = seizeVars.borrowerAmountNew; - accountTokens[borrower].suppliedAt = getBlockNumber(); - accountTokens[borrower].promisedSupplyRate = seizeVars.supplyRate; - - accountTokens[liquidator].tokens = seizeVars.liquidatorTokensNew; - accountTokens[liquidator].underlyingAmount = seizeVars - .liquidatorAmountNew; - accountTokens[liquidator].suppliedAt = getBlockNumber(); - accountTokens[liquidator].promisedSupplyRate = seizeVars.supplyRate; - - emit Transfer(borrower, liquidator, seizeTokens); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Begins transfer of admin rights. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer. - * @dev Admin function to begin change of admin. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer. - * @param newPendingAdmin New pending admin. - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setPendingAdmin(address payable newPendingAdmin) - external - override - returns (uint256) - { - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_PENDING_ADMIN_OWNER_CHECK - ); - } - - address oldPendingAdmin = pendingAdmin; - - pendingAdmin = newPendingAdmin; - - emit NewPendingAdmin(oldPendingAdmin, newPendingAdmin); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Accepts transfer of admin rights. msg.sender must be pendingAdmin - * @dev Admin function for pending admin to accept role and update admin - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _acceptAdmin() external override returns (uint256) { - if (msg.sender != pendingAdmin || msg.sender == address(0)) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.ACCEPT_ADMIN_PENDING_ADMIN_CHECK - ); - } - - address oldAdmin = admin; - address oldPendingAdmin = pendingAdmin; - - admin = pendingAdmin; - - pendingAdmin = payable(address(0)); - - emit NewAdmin(oldAdmin, admin); - emit NewPendingAdmin(oldPendingAdmin, pendingAdmin); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Sets a new comptroller for the market - * @dev Admin function to set a new comptroller - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setComptroller(ComptrollerInterface newComptroller) - public - override - returns (uint256) - { - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_COMPTROLLER_OWNER_CHECK - ); - } - - ComptrollerInterface oldComptroller = comptroller; - require(newComptroller.isComptroller(), "CT21"); - - comptroller = newComptroller; - - emit NewComptroller(oldComptroller, newComptroller); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice accrues interest and sets a new reserve factor for the protocol using _setReserveFactorFresh - * @dev Admin function to accrue interest and set a new reserve factor - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setReserveFactor(uint256 newReserveFactorMantissa) - external - override - nonReentrant - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return - fail( - Error(error), - FailureInfo.SET_RESERVE_FACTOR_ACCRUE_INTEREST_FAILED - ); - } - return _setReserveFactorFresh(newReserveFactorMantissa); - } - - /** - * @notice Sets a new reserve factor for the protocol (*requires fresh interest accrual) - * @dev Admin function to set a new reserve factor - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setReserveFactorFresh(uint256 newReserveFactorMantissa) - internal - returns (uint256) - { - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_RESERVE_FACTOR_ADMIN_CHECK - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.SET_RESERVE_FACTOR_FRESH_CHECK - ); - } - - if (newReserveFactorMantissa > reserveFactorMaxMantissa) { - return - fail( - Error.BAD_INPUT, - FailureInfo.SET_RESERVE_FACTOR_BOUNDS_CHECK - ); - } - - uint256 oldReserveFactorMantissa = reserveFactorMantissa; - reserveFactorMantissa = newReserveFactorMantissa; - - emit NewReserveFactor( - oldReserveFactorMantissa, - newReserveFactorMantissa - ); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Accrues interest and reduces reserves by transferring from msg.sender - * @param addAmount Amount of addition to reserves - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _addReservesInternal(uint256 addAmount) - internal - nonReentrant - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return - fail( - Error(error), - FailureInfo.ADD_RESERVES_ACCRUE_INTEREST_FAILED - ); - } - - uint256 totalReservesNew; - uint256 actualAddAmount; - - if (accrualBlockNumber != getBlockNumber()) { - return ( - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.ADD_RESERVES_FRESH_CHECK - ) - ); - } - - actualAddAmount = doTransferIn(msg.sender, addAmount); - - totalReservesNew = totalReserves + actualAddAmount; - - require(totalReservesNew >= totalReserves, "CT22"); - - totalReserves = totalReservesNew; - - emit ReservesAdded(msg.sender, actualAddAmount, totalReservesNew); - - return (uint256(Error.NO_ERROR)); - } - - function _addSubsidyInternal(uint256 addAmount) - internal - nonReentrant - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - // accrueInterest emits logs on errors, but on top of that we want to log the fact that an attempted reduce reserves failed. - return fail(Error(error), FailureInfo.ADD_SUBSIDY_FUND_FAILED); - } - - uint256 subsidyFundNew; - uint256 actualAddAmount; - - if (accrualBlockNumber != getBlockNumber()) { - return ( - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.ADD_SUBSIDY_FUND_FRESH_CHECK - ) - ); - } - - actualAddAmount = doTransferIn(msg.sender, addAmount); - - subsidyFundNew = subsidyFund + actualAddAmount; - - require(subsidyFundNew >= subsidyFund, "CT22"); - - subsidyFund = subsidyFundNew; - - emit SubsidyAdded(msg.sender, actualAddAmount, subsidyFundNew); - - /* Return (NO_ERROR, actualAddAmount) */ - return (uint256(Error.NO_ERROR)); - } - - /** - * @notice Accrues interest and reduces reserves by transferring to admin - * @param reduceAmount Amount of reduction to reserves - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _reduceReserves(uint256 reduceAmount) - external - override - nonReentrant - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return - fail( - Error(error), - FailureInfo.REDUCE_RESERVES_ACCRUE_INTEREST_FAILED - ); - } - return _reduceReservesFresh(reduceAmount); - } - - /** - * @notice Reduces reserves by transferring to admin - * @dev Requires fresh interest accrual - * @param reduceAmount Amount of reduction to reserves - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _reduceReservesFresh(uint256 reduceAmount) - internal - returns (uint256) - { - uint256 totalReservesNew; - - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.REDUCE_RESERVES_ADMIN_CHECK - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.REDUCE_RESERVES_FRESH_CHECK - ); - } - - if (getCashPrior() < reduceAmount) { - return - fail( - Error.TOKEN_INSUFFICIENT_CASH, - FailureInfo.REDUCE_RESERVES_CASH_NOT_AVAILABLE - ); - } - - if (reduceAmount > totalReserves) { - return - fail(Error.BAD_INPUT, FailureInfo.REDUCE_RESERVES_VALIDATION); - } - - totalReservesNew = totalReserves - reduceAmount; - require(totalReservesNew <= totalReserves, "CT23"); - - totalReserves = totalReservesNew; - - doTransferOut(admin, reduceAmount); - - emit ReservesReduced(admin, reduceAmount, totalReservesNew); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice accrues interest and updates the interest rate model using _setInterestRateModelFresh - * @dev Admin function to accrue interest and update the interest rate model - * @param newInterestRateModel the new interest rate model to use - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setInterestRateModel(InterestRateModel newInterestRateModel) - public - override - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return - fail( - Error(error), - FailureInfo.SET_INTEREST_RATE_MODEL_ACCRUE_INTEREST_FAILED - ); - } - return _setInterestRateModelFresh(newInterestRateModel); - } - - /** - * @notice updates the interest rate model (*requires fresh interest accrual) - * @dev Admin function to update the interest rate model - * @param newInterestRateModel the new interest rate model to use - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setInterestRateModelFresh(InterestRateModel newInterestRateModel) - internal - returns (uint256) - { - InterestRateModel oldInterestRateModel; - - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_INTEREST_RATE_MODEL_OWNER_CHECK - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.SET_INTEREST_RATE_MODEL_FRESH_CHECK - ); - } - - oldInterestRateModel = interestRateModel; - - require(newInterestRateModel.isInterestRateModel(), "CT21"); - - interestRateModel = newInterestRateModel; - - emit NewMarketInterestRateModel( - oldInterestRateModel, - newInterestRateModel - ); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Gets balance of this contract in terms of the underlying - * @dev This excludes the value of the current message, if any - * @return The quantity of underlying owned by this contract - */ - function getCashPrior() internal view virtual returns (uint256); - - /** - * @dev Performs a transfer in, reverting upon failure. Returns the amount actually transferred to the protocol, in case of a fee. - * This may revert due to insufficient balance or insufficient allowance. - */ - function doTransferIn(address from, uint256 amount) - internal - virtual - returns (uint256); - - /** - * @dev Performs a transfer out, ideally returning an explanatory error code upon failure tather than reverting. - * If caller has not called checked protocol's balance, may revert due to insufficient cash held in the contract. - * If caller has checked protocol's balance, and verified it is >= amount, this should not revert in normal conditions. - */ - function doTransferOut(address payable to, uint256 amount) internal virtual; - - /** - * @dev Prevents a contract from calling itself, directly or indirectly. - */ - modifier nonReentrant() { - require(_notEntered, "re-entered"); - _notEntered = false; - _; - _notEntered = true; - } -} - - -// Dependency file: contracts/PriceOracle.sol - -// pragma solidity 0.8.6; - -// import "contracts/CToken.sol"; - -abstract contract PriceOracle { - /// @notice Indicator that this is a PriceOracle contract (for inspection) - bool public constant isPriceOracle = true; - - /** - * @notice Get the underlying price of a cToken asset - * @param cToken The cToken to get the underlying price of - * @return The underlying asset price mantissa (scaled by 1e18). - * Zero means the price is unavailable. - */ - function getUnderlyingPrice(CToken cToken) - external - view - virtual - returns (uint256); -} - - -// Dependency file: contracts/ComptrollerStorage.sol - -// pragma solidity 0.8.6; - -// import "contracts/CToken.sol"; -// import "contracts/PriceOracle.sol"; - -contract UnitrollerAdminStorage { - /** - * @notice Administrator for this contract - */ - address public admin; - - /** - * @notice Pending administrator for this contract - */ - address public pendingAdmin; - - /** - * @notice Active brains of Unitroller - */ - address public comptrollerImplementation; - - /** - * @notice Pending brains of Unitroller - */ - address public pendingComptrollerImplementation; -} - -contract ComptrollerV1Storage is UnitrollerAdminStorage { - - /** - * @notice Oracle which gives the price of any given asset - */ - PriceOracle public oracle; - - /** - * @notice Multiplier used to calculate the maximum repayAmount when liquidating a borrow - */ - uint public closeFactorMantissa; - - /** - * @notice Multiplier representing the discount on collateral that a liquidator receives - */ - uint public liquidationIncentiveMantissa; - - /** - * @notice Max number of assets a single account can participate in (borrow or use as collateral) - */ - uint public maxAssets; - - /** - * @notice Per-account mapping of "assets you are in", capped by maxAssets - */ - mapping(address => CToken[]) public accountAssets; - -} - -contract ComptrollerV2Storage is ComptrollerV1Storage { - struct Market { - /// @notice Whether or not this market is listed - bool isListed; - - /** - * @notice Multiplier representing the most one can borrow against their collateral in this market. - * For instance, 0.9 to allow borrowing 90% of collateral value. - * Must be between 0 and 1, and stored as a mantissa. - */ - uint collateralFactorMantissa; - - /// @notice Per-market mapping of "accounts in this asset" - mapping(address => bool) accountMembership; - - /// @notice Whether or not this market receives COMP - bool isComped; - } - - /** - * @notice Official mapping of cTokens -> Market metadata - * @dev Used e.g. to determine if a market is supported - */ - mapping(address => Market) public markets; - - - /** - * @notice The Pause Guardian can pause certain actions as a safety mechanism. - * Actions which allow users to remove their own assets cannot be paused. - * Liquidation / seizing / transfer can only be paused globally, not by market. - */ - address public pauseGuardian; - bool public _mintGuardianPaused; - bool public _borrowGuardianPaused; - bool public transferGuardianPaused; - bool public seizeGuardianPaused; - mapping(address => bool) public mintGuardianPaused; - mapping(address => bool) public borrowGuardianPaused; -} - -contract ComptrollerV3Storage is ComptrollerV2Storage { - struct CompMarketState { - /// @notice The market's last updated compBorrowIndex or compSupplyIndex - uint224 index; - - /// @notice The block number the index was last updated at - uint32 block; - } - - /// @notice A list of all markets - CToken[] public allMarkets; - - /// @notice The rate at which the flywheel distributes COMP, per block - uint public compRate; - - /// @notice The portion of compRate that each market currently receives - mapping(address => uint) public compSpeeds; - - /// @notice The COMP market supply state for each market - mapping(address => CompMarketState) public compSupplyState; - - /// @notice The COMP market borrow state for each market - mapping(address => CompMarketState) public compBorrowState; - - /// @notice The COMP borrow index for each market for each supplier as of the last time they accrued COMP - mapping(address => mapping(address => uint)) public compSupplierIndex; - - /// @notice The COMP borrow index for each market for each borrower as of the last time they accrued COMP - mapping(address => mapping(address => uint)) public compBorrowerIndex; - - /// @notice The COMP accrued but not yet transferred to each user - mapping(address => uint) public compAccrued; -} - -contract ComptrollerV4Storage is ComptrollerV3Storage { - // @notice The borrowCapGuardian can set borrowCaps to any number for any market. Lowering the borrow cap could disable borrowing on the given market. - address public borrowCapGuardian; - - // @notice Borrow caps enforced by borrowAllowed for each cToken address. Defaults to zero which corresponds to unlimited borrowing. - mapping(address => uint) public borrowCaps; - - // @notice address of the TROP token - address public tropAddress; -} - -contract ComptrollerV5Storage is ComptrollerV4Storage { - /// @notice The portion of COMP that each contributor receives per block - mapping(address => uint) public compContributorSpeeds; - - /// @notice Last block at which a contributor's COMP rewards have been allocated - mapping(address => uint) public lastContributorBlock; -} - - -// Dependency file: contracts/Unitroller.sol - -// pragma solidity 0.8.6; - -// import "contracts/ErrorReporter.sol"; -// import "contracts/ComptrollerStorage.sol"; - -/** - * @title ComptrollerCore - * @dev Storage for the comptroller is at this address, while execution is delegated to the `comptrollerImplementation`. - * CTokens should reference this contract as their comptroller. - */ -contract Unitroller is UnitrollerAdminStorage, ComptrollerErrorReporter { - /** - * @notice Emitted when pendingComptrollerImplementation is changed - */ - event NewPendingImplementation( - address oldPendingImplementation, - address newPendingImplementation - ); - - /** - * @notice Emitted when pendingComptrollerImplementation is accepted, which means comptroller implementation is updated - */ - event NewImplementation( - address oldImplementation, - address newImplementation - ); - - /** - * @notice Emitted when pendingAdmin is changed - */ - event NewPendingAdmin(address oldPendingAdmin, address newPendingAdmin); - - /** - * @notice Emitted when pendingAdmin is accepted, which means admin is updated - */ - event NewAdmin(address oldAdmin, address newAdmin); - - constructor() { - // Set admin to caller - admin = msg.sender; - } - - /*** Admin Functions ***/ - function _setPendingImplementation(address newPendingImplementation) - public - returns (uint256) - { - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_PENDING_IMPLEMENTATION_OWNER_CHECK - ); - } - - address oldPendingImplementation = pendingComptrollerImplementation; - - pendingComptrollerImplementation = newPendingImplementation; - - emit NewPendingImplementation( - oldPendingImplementation, - pendingComptrollerImplementation - ); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Accepts new implementation of comptroller. msg.sender must be pendingImplementation - * @dev Admin function for new implementation to accept it's role as implementation - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _acceptImplementation() public returns (uint256) { - // Check caller is pendingImplementation and pendingImplementation ≠ address(0) - if ( - msg.sender != pendingComptrollerImplementation || - pendingComptrollerImplementation == address(0) - ) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.ACCEPT_PENDING_IMPLEMENTATION_ADDRESS_CHECK - ); - } - - // Save current values for inclusion in log - address oldImplementation = comptrollerImplementation; - address oldPendingImplementation = pendingComptrollerImplementation; - - comptrollerImplementation = pendingComptrollerImplementation; - - pendingComptrollerImplementation = address(0); - - emit NewImplementation(oldImplementation, comptrollerImplementation); - emit NewPendingImplementation( - oldPendingImplementation, - pendingComptrollerImplementation - ); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Begins transfer of admin rights. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer. - * @dev Admin function to begin change of admin. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer. - * @param newPendingAdmin New pending admin. - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setPendingAdmin(address newPendingAdmin) - public - returns (uint256) - { - // Check caller = admin - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_PENDING_ADMIN_OWNER_CHECK - ); - } - - // Save current value, if any, for inclusion in log - address oldPendingAdmin = pendingAdmin; - - // Store pendingAdmin with value newPendingAdmin - pendingAdmin = newPendingAdmin; - - // Emit NewPendingAdmin(oldPendingAdmin, newPendingAdmin) - emit NewPendingAdmin(oldPendingAdmin, newPendingAdmin); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Accepts transfer of admin rights. msg.sender must be pendingAdmin - * @dev Admin function for pending admin to accept role and update admin - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _acceptAdmin() public returns (uint256) { - // Check caller is pendingAdmin and pendingAdmin ≠ address(0) - if (msg.sender != pendingAdmin || msg.sender == address(0)) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.ACCEPT_ADMIN_PENDING_ADMIN_CHECK - ); - } - - // Save current values for inclusion in log - address oldAdmin = admin; - address oldPendingAdmin = pendingAdmin; - - // Store admin with value pendingAdmin - admin = pendingAdmin; - - // Clear the pending value - pendingAdmin = address(0); - - emit NewAdmin(oldAdmin, admin); - emit NewPendingAdmin(oldPendingAdmin, pendingAdmin); - - return uint256(Error.NO_ERROR); - } - - /** - * @dev Delegates execution to an implementation contract. - * It returns to the external caller whatever the implementation returns - * or forwards reverts. - */ - function internalFallback() public payable { - // delegate all other functions to current implementation - (bool success, ) = comptrollerImplementation.delegatecall(msg.data); - - assembly { - let free_mem_ptr := mload(0x40) - returndatacopy(free_mem_ptr, 0, returndatasize()) - - switch success - case 0 { - revert(free_mem_ptr, returndatasize()) - } - default { - return(free_mem_ptr, returndatasize()) - } - } - } - - fallback() external payable { - internalFallback(); - } - - receive() external payable { - internalFallback(); - } -} - - -// Dependency file: contracts/Governance/TROP.sol - -// pragma solidity 0.8.6; -pragma experimental ABIEncoderV2; - -/** - * @title TROP ERC20 tokens. - * @author tropykus - * @notice Yield farming tokens that allow to propose and vote for protocol changes using the governance system. - */ -contract TROP { - /// @notice EIP-20 token name for this token - string public constant name = "tropykus"; - - /// @notice EIP-20 token symbol for this token - string public constant symbol = "TROP"; - - /// @notice EIP-20 token decimals for this token - uint8 public constant decimals = 18; - - /// @notice Total number of tokens in circulation - uint256 public constant totalSupply = 10000000e18; // 10 million TROP - - /// @notice Allowance amounts on behalf of others - mapping(address => mapping(address => uint96)) internal allowances; - - /// @notice Official record of token balances for each account - mapping(address => uint96) internal balances; - - /// @notice A record of each accounts delegate - mapping(address => address) public delegates; - - /// @notice A checkpoint for marking number of votes from a given block - struct Checkpoint { - uint32 fromBlock; - uint96 votes; - } - - /// @notice A record of votes checkpoints for each account, by index - mapping(address => mapping(uint32 => Checkpoint)) public checkpoints; - - /// @notice The number of checkpoints for each account - mapping(address => uint32) public numCheckpoints; - - /// @notice The EIP-712 typehash for the contract's domain - bytes32 public constant DOMAIN_TYPEHASH = - keccak256( - "EIP712Domain(string name,uint256 chainId,address verifyingContract)" - ); - - /// @notice The EIP-712 typehash for the delegation struct used by the contract - bytes32 public constant DELEGATION_TYPEHASH = - keccak256("Delegation(address delegatee,uint256 nonce,uint256 expiry)"); - - /// @notice A record of states for signing / validating signatures - mapping(address => uint256) public nonces; - - /// @notice An event thats emitted when an account changes its delegate - event DelegateChanged( - address indexed delegator, - address indexed fromDelegate, - address indexed toDelegate - ); - - /// @notice An event thats emitted when a delegate account's vote balance changes - event DelegateVotesChanged( - address indexed delegate, - uint256 previousBalance, - uint256 newBalance - ); - - /// @notice The standard EIP-20 transfer event - event Transfer(address indexed from, address indexed to, uint256 amount); - - /// @notice The standard EIP-20 approval event - event Approval( - address indexed owner, - address indexed spender, - uint256 amount - ); - - /** - * @notice Construct a new TROP token - * @param account The initial account to grant all the tokens - */ - constructor(address account) { - balances[account] = uint96(totalSupply); - emit Transfer(address(0), account, totalSupply); - } - - /** - * @notice Get the number of tokens `spender` is approved to spend on behalf of `account` - * @param account The address of the account holding the funds - * @param spender The address of the account spending the funds - * @return The number of tokens approved - */ - function allowance(address account, address spender) - external - view - returns (uint256) - { - return allowances[account][spender]; - } - - /** - * @notice Approve `spender` to transfer up to `amount` from `src` - * @dev This will overwrite the approval amount for `spender` - * and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve) - * @param spender The address of the account which may transfer tokens - * @param rawAmount The number of tokens that are approved (2^256-1 means infinite) - * @return Whether or not the approval succeeded - */ - function approve(address spender, uint256 rawAmount) - external - returns (bool) - { - uint96 amount; - if (rawAmount == type(uint256).max) { - amount = type(uint96).max; - } else { - amount = safe96(rawAmount, "TROP::approve: amount exceeds 96 bits"); - } - - allowances[msg.sender][spender] = amount; - - emit Approval(msg.sender, spender, amount); - return true; - } - - /** - * @notice Get the number of tokens held by the `account` - * @param account The address of the account to get the balance of - * @return The number of tokens held - */ - function balanceOf(address account) external view returns (uint256) { - return balances[account]; - } - - /** - * @notice Transfer `amount` tokens from `msg.sender` to `dst` - * @param dst The address of the destination account - * @param rawAmount The number of tokens to transfer - * @return Whether or not the transfer succeeded - */ - function transfer(address dst, uint256 rawAmount) external returns (bool) { - uint96 amount = safe96( - rawAmount, - "TROP::transfer: amount exceeds 96 bits" - ); - _transferTokens(msg.sender, dst, amount); - return true; - } - - /** - * @notice Transfer `amount` tokens from `src` to `dst` - * @param src The address of the source account - * @param dst The address of the destination account - * @param rawAmount The number of tokens to transfer - * @return Whether or not the transfer succeeded - */ - function transferFrom( - address src, - address dst, - uint256 rawAmount - ) external returns (bool) { - address spender = msg.sender; - uint96 spenderAllowance = allowances[src][spender]; - uint96 amount = safe96( - rawAmount, - "TROP::approve: amount exceeds 96 bits" - ); - - if (spender != src && spenderAllowance != type(uint96).max) { - uint96 newAllowance = sub96( - spenderAllowance, - amount, - "TROP::transferFrom: transfer amount exceeds spender allowance" - ); - allowances[src][spender] = newAllowance; - - emit Approval(src, spender, newAllowance); - } - - _transferTokens(src, dst, amount); - return true; - } - - /** - * @notice Delegate votes from `msg.sender` to `delegatee` - * @param delegatee The address to delegate votes to - */ - function delegate(address delegatee) public { - return _delegate(msg.sender, delegatee); - } - - /** - * @notice Delegates votes from signatory to `delegatee` - * @param delegatee The address to delegate votes to - * @param nonce The contract state required to match the signature - * @param expiry The time at which to expire the signature - * @param v The recovery byte of the signature - * @param r Half of the ECDSA signature pair - * @param s Half of the ECDSA signature pair - */ - function delegateBySig( - address delegatee, - uint256 nonce, - uint256 expiry, - uint8 v, - bytes32 r, - bytes32 s - ) public { - bytes32 domainSeparator = keccak256( - abi.encode( - DOMAIN_TYPEHASH, - keccak256(bytes(name)), - getChainId(), - address(this) - ) - ); - bytes32 structHash = keccak256( - abi.encode(DELEGATION_TYPEHASH, delegatee, nonce, expiry) - ); - bytes32 digest = keccak256( - abi.encodePacked("\x19\x01", domainSeparator, structHash) - ); - address signatory = ecrecover(digest, v, r, s); - require( - signatory != 0xdcc703c0E500B653Ca82273B7BFAd8045D85a470 && - signatory != address(0), - "TROP::delegateBySig: invalid signature" - ); - require( - nonce == nonces[signatory]++, - "TROP::delegateBySig: invalid nonce" - ); - require( - block.timestamp <= expiry, - "TROP::delegateBySig: signature expired" - ); - return _delegate(signatory, delegatee); - } - - /** - * @notice Gets the current votes balance for `account` - * @param account The address to get votes balance - * @return The number of current votes for `account` - */ - function getCurrentVotes(address account) external view returns (uint96) { - uint32 nCheckpoints = numCheckpoints[account]; - return - nCheckpoints > 0 ? checkpoints[account][nCheckpoints - 1].votes : 0; - } - - /** - * @notice Determine the prior number of votes for an account as of a block number - * @dev Block number must be a finalized block or else this function will revert to prevent misinformation. - * @param account The address of the account to check - * @param blockNumber The block number to get the vote balance at - * @return The number of votes the account had as of the given block - */ - function getPriorVotes(address account, uint256 blockNumber) - public - view - returns (uint96) - { - require( - blockNumber < block.number, - "TROP::getPriorVotes: not yet determined" - ); - - uint32 nCheckpoints = numCheckpoints[account]; - if (nCheckpoints == 0) { - return 0; - } - - // First check most recent balance - if (checkpoints[account][nCheckpoints - 1].fromBlock <= blockNumber) { - return checkpoints[account][nCheckpoints - 1].votes; - } - - // Next check implicit zero balance - if (checkpoints[account][0].fromBlock > blockNumber) { - return 0; - } - - uint32 lower = 0; - uint32 upper = nCheckpoints - 1; - while (upper > lower) { - uint32 center = upper - (upper - lower) / 2; // ceil, avoiding overflow - Checkpoint memory cp = checkpoints[account][center]; - if (cp.fromBlock == blockNumber) { - return cp.votes; - } else if (cp.fromBlock < blockNumber) { - lower = center; - } else { - upper = center - 1; - } - } - return checkpoints[account][lower].votes; - } - - function _delegate(address delegator, address delegatee) internal { - address currentDelegate = delegates[delegator]; - uint96 delegatorBalance = balances[delegator]; - delegates[delegator] = delegatee; - - emit DelegateChanged(delegator, currentDelegate, delegatee); - - _moveDelegates(currentDelegate, delegatee, delegatorBalance); - } - - function _transferTokens( - address src, - address dst, - uint96 amount - ) internal { - require( - src != address(0), - "TROP::_transferTokens: cannot transfer from the zero address" - ); - require( - dst != address(0), - "TROP::_transferTokens: cannot transfer to the zero address" - ); - - balances[src] = sub96( - balances[src], - amount, - "TROP::_transferTokens: transfer amount exceeds balance" - ); - balances[dst] = add96( - balances[dst], - amount, - "TROP::_transferTokens: transfer amount overflows" - ); - emit Transfer(src, dst, amount); - - _moveDelegates(delegates[src], delegates[dst], amount); - } - - function _moveDelegates( - address srcRep, - address dstRep, - uint96 amount - ) internal { - if (srcRep != dstRep && amount > 0) { - if (srcRep != address(0)) { - uint32 srcRepNum = numCheckpoints[srcRep]; - uint96 srcRepOld = srcRepNum > 0 - ? checkpoints[srcRep][srcRepNum - 1].votes - : 0; - uint96 srcRepNew = sub96( - srcRepOld, - amount, - "TROP::_moveVotes: vote amount underflows" - ); - _writeCheckpoint(srcRep, srcRepNum, srcRepOld, srcRepNew); - } - - if (dstRep != address(0)) { - uint32 dstRepNum = numCheckpoints[dstRep]; - uint96 dstRepOld = dstRepNum > 0 - ? checkpoints[dstRep][dstRepNum - 1].votes - : 0; - uint96 dstRepNew = add96( - dstRepOld, - amount, - "TROP::_moveVotes: vote amount overflows" - ); - _writeCheckpoint(dstRep, dstRepNum, dstRepOld, dstRepNew); - } - } - } - - function _writeCheckpoint( - address delegatee, - uint32 nCheckpoints, - uint96 oldVotes, - uint96 newVotes - ) internal { - uint32 blockNumber = safe32( - block.number, - "TROP::_writeCheckpoint: block number exceeds 32 bits" - ); - - if ( - nCheckpoints > 0 && - checkpoints[delegatee][nCheckpoints - 1].fromBlock == blockNumber - ) { - checkpoints[delegatee][nCheckpoints - 1].votes = newVotes; - } else { - checkpoints[delegatee][nCheckpoints] = Checkpoint( - blockNumber, - newVotes - ); - numCheckpoints[delegatee] = nCheckpoints + 1; - } - - emit DelegateVotesChanged(delegatee, oldVotes, newVotes); - } - - function safe32(uint256 n, string memory errorMessage) - internal - pure - returns (uint32) - { - require(n < 2**32, errorMessage); - return uint32(n); - } - - function safe96(uint256 n, string memory errorMessage) - internal - pure - returns (uint96) - { - require(n < 2**96, errorMessage); - return uint96(n); - } - - function add96( - uint96 a, - uint96 b, - string memory errorMessage - ) internal pure returns (uint96) { - uint96 c = a + b; - require(c >= a, errorMessage); - return c; - } - - function sub96( - uint96 a, - uint96 b, - string memory errorMessage - ) internal pure returns (uint96) { - require(b <= a, errorMessage); - return a - b; - } - - function getChainId() internal view returns (uint256) { - uint256 chainId; - assembly { - chainId := chainid() - } - return chainId; - } -} - - -// Root file: contracts/ComptrollerG6.sol - -pragma solidity 0.8.6; - -// import "contracts/CToken.sol"; -// import "contracts/ErrorReporter.sol"; -// import "contracts/PriceOracle.sol"; -// import "contracts/ComptrollerInterface.sol"; -// import "contracts/ComptrollerStorage.sol"; -// import "contracts/Unitroller.sol"; -// import "contracts/Governance/TROP.sol"; - -/** - * @title tropykus Comptroller Contract - * @author tropykus - */ -contract ComptrollerG6 is - ComptrollerV5Storage, - ComptrollerInterface, - ComptrollerErrorReporter, - ExponentialNoError -{ - /// @notice Emitted when an admin supports a market - event MarketListed(CToken cToken); - - /// @notice Emitted when an account enters a market - event MarketEntered(CToken cToken, address account); - - /// @notice Emitted when an account exits a market - event MarketExited(CToken cToken, address account); - - /// @notice Emitted when close factor is changed by admin - event NewCloseFactor( - uint256 oldCloseFactorMantissa, - uint256 newCloseFactorMantissa - ); - - /// @notice Emitted when a collateral factor is changed by admin - event NewCollateralFactor( - CToken cToken, - uint256 oldCollateralFactorMantissa, - uint256 newCollateralFactorMantissa - ); - - /// @notice Emitted when liquidation incentive is changed by admin - event NewLiquidationIncentive( - uint256 oldLiquidationIncentiveMantissa, - uint256 newLiquidationIncentiveMantissa - ); - - /// @notice Emitted when price oracle is changed - event NewPriceOracle( - PriceOracle oldPriceOracle, - PriceOracle newPriceOracle - ); - - /// @notice Emitted when pause guardian is changed - event NewPauseGuardian(address oldPauseGuardian, address newPauseGuardian); - - /// @notice Emitted when an action is paused globally - event ActionPaused(string action, bool pauseState); - - /// @notice Emitted when an action is paused on a market - event ActionPaused(CToken cToken, string action, bool pauseState); - - /// @notice Emitted when market comped status is changed - event MarketComped(CToken cToken, bool isComped); - - /// @notice Emitted when COMP rate is changed - event NewCompRate(uint256 oldCompRate, uint256 newCompRate); - - /// @notice Emitted when a new COMP speed is calculated for a market - event CompSpeedUpdated(CToken indexed cToken, uint256 newSpeed); - - /// @notice Emitted when a new COMP speed is set for a contributor - event ContributorCompSpeedUpdated( - address indexed contributor, - uint256 newSpeed - ); - - /// @notice Emitted when COMP is distributed to a supplier - event DistributedSupplierComp( - CToken indexed cToken, - address indexed supplier, - uint256 compDelta, - uint256 compSupplyIndex - ); - - /// @notice Emitted when COMP is distributed to a borrower - event DistributedBorrowerComp( - CToken indexed cToken, - address indexed borrower, - uint256 compDelta, - uint256 compBorrowIndex - ); - - /// @notice Emitted when borrow cap for a cToken is changed - event NewBorrowCap(CToken indexed cToken, uint256 newBorrowCap); - - /// @notice Emitted when borrow cap guardian is changed - event NewBorrowCapGuardian( - address oldBorrowCapGuardian, - address newBorrowCapGuardian - ); - - /// @notice Emitted when COMP is granted by admin - event CompGranted(address recipient, uint256 amount); - - /// @notice The threshold above which the flywheel transfers COMP, in wei - uint256 public constant compClaimThreshold = 0.001e18; - - /// @notice The initial COMP index for a market - uint224 public constant compInitialIndex = 1e36; - - // closeFactorMantissa must be strictly greater than this value - uint256 internal constant closeFactorMinMantissa = 0.05e18; // 0.05 - - // closeFactorMantissa must not exceed this value - uint256 internal constant closeFactorMaxMantissa = 0.9e18; // 0.9 - - // No collateralFactorMantissa may exceed this value - uint256 internal constant collateralFactorMaxMantissa = 0.9e18; // 0.9 - - constructor() { - admin = msg.sender; - } - - /*** Assets You Are In ***/ - - /** - * @notice Returns the assets an account has entered - * @param account The address of the account to pull assets for - * @return A dynamic list with the assets the account has entered - */ - function getAssetsIn(address account) - external - view - returns (CToken[] memory) - { - CToken[] memory assetsIn = accountAssets[account]; - - return assetsIn; - } - - /** - * @notice Returns whether the given account is entered in the given asset - * @param account The address of the account to check - * @param cToken The cToken to check - * @return True if the account is in the asset, otherwise false. - */ - function checkMembership(address account, CToken cToken) - external - view - returns (bool) - { - return markets[address(cToken)].accountMembership[account]; - } - - /** - * @notice Add assets to be included in account liquidity calculation - * @param cTokens The list of addresses of the cToken markets to be enabled - * @return Success indicator for whether each corresponding market was entered - */ - function enterMarkets(address[] memory cTokens) - public - override - returns (uint256[] memory) - { - uint256 len = cTokens.length; - - uint256[] memory results = new uint256[](len); - for (uint256 i = 0; i < len; i++) { - CToken cToken = CToken(cTokens[i]); - - results[i] = uint256(addToMarketInternal(cToken, msg.sender)); - } - - return results; - } - - /** - * @notice Add the market to the borrower's "assets in" for liquidity calculations - * @param cToken The market to enter - * @param borrower The address of the account to modify - * @return Success indicator for whether the market was entered - */ - function addToMarketInternal(CToken cToken, address borrower) - internal - returns (Error) - { - Market storage marketToJoin = markets[address(cToken)]; - - if (!marketToJoin.isListed) { - // market is not listed, cannot join - return Error.MARKET_NOT_LISTED; - } - - if (marketToJoin.accountMembership[borrower] == true) { - // already joined - return Error.NO_ERROR; - } - - // survived the gauntlet, add to list - // NOTE: we store these somewhat redundantly as a significant optimization - // this avoids having to iterate through the list for the most common use cases - // that is, only when we need to perform liquidity checks - // and not whenever we want to check if an account is in a particular market - marketToJoin.accountMembership[borrower] = true; - accountAssets[borrower].push(cToken); - - emit MarketEntered(cToken, borrower); - - return Error.NO_ERROR; - } - - /** - * @notice Removes asset from sender's account liquidity calculation - * @dev Sender must not have an outstanding borrow balance in the asset, - * or be providing necessary collateral for an outstanding borrow. - * @param cTokenAddress The address of the asset to be removed - * @return Whether or not the account successfully exited the market - */ - function exitMarket(address cTokenAddress) - external - override - returns (uint256) - { - CToken cToken = CToken(cTokenAddress); - /* Get sender tokensHeld and amountOwed underlying from the cToken */ - (uint256 oErr, uint256 tokensHeld, uint256 amountOwed, ) = cToken - .getAccountSnapshot(msg.sender); - require(oErr == 0, "exitMarket: getAccountSnapshot failed"); // semi-opaque error code - - /* Fail if the sender has a borrow balance */ - if (amountOwed != 0) { - return - fail( - Error.NONZERO_BORROW_BALANCE, - FailureInfo.EXIT_MARKET_BALANCE_OWED - ); - } - - /* Fail if the sender is not permitted to redeem all of their tokens */ - uint256 allowed = redeemAllowedInternal( - cTokenAddress, - msg.sender, - tokensHeld - ); - if (allowed != 0) { - return - failOpaque( - Error.REJECTION, - FailureInfo.EXIT_MARKET_REJECTION, - allowed - ); - } - - Market storage marketToExit = markets[address(cToken)]; - - /* Return true if the sender is not already ‘in’ the market */ - if (!marketToExit.accountMembership[msg.sender]) { - return uint256(Error.NO_ERROR); - } - - /* Set cToken account membership to false */ - delete marketToExit.accountMembership[msg.sender]; - - /* Delete cToken from the account’s list of assets */ - // load into memory for faster iteration - CToken[] memory userAssetList = accountAssets[msg.sender]; - accountAssets[msg.sender] = new CToken[](0); - CToken[] storage newMarketList = accountAssets[msg.sender]; - uint256 len = userAssetList.length; - uint256 assetIndex = len; - for (uint256 i = 0; i < len; i++) { - if (userAssetList[i] == cToken) { - assetIndex = i; - continue; - } - newMarketList.push(userAssetList[i]); - } - - // We *must* have found the asset in the list or our redundant data structure is broken - assert(assetIndex < len); - - emit MarketExited(cToken, msg.sender); - - return uint256(Error.NO_ERROR); - } - - /*** Policy Hooks ***/ - - /** - * @notice Checks if the account should be allowed to mint tokens in the given market - * @param cToken The market to verify the mint against - * @param minter The account which would get the minted tokens - * @param mintAmount The amount of underlying being supplied to the market in exchange for tokens - * @return 0 if the mint is allowed, otherwise a semi-opaque error code (See ErrorReporter.sol) - */ - function mintAllowed( - address cToken, - address minter, - uint256 mintAmount - ) external override returns (uint256) { - // Pausing is a very serious situation - we revert to sound the alarms - require(!mintGuardianPaused[cToken], "mint is paused"); - - // Shh - currently unused - minter; - mintAmount; - - if (!markets[cToken].isListed) { - return uint256(Error.MARKET_NOT_LISTED); - } - - // Keep the flywheel moving - updateCompSupplyIndex(cToken); - distributeSupplierComp(cToken, minter, false); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Validates mint and reverts on rejection. May emit logs. - * @param cToken Asset being minted - * @param minter The address minting the tokens - * @param actualMintAmount The amount of the underlying asset being minted - * @param mintTokens The number of tokens being minted - */ - function mintVerify( - address cToken, - address minter, - uint256 actualMintAmount, - uint256 mintTokens - ) external override { - // Shh - currently unused - cToken; - minter; - actualMintAmount; - mintTokens; - - // Shh - we don't ever want this hook to be marked pure - if (false) { - maxAssets = maxAssets; - } - } - - /** - * @notice Checks if the account should be allowed to redeem tokens in the given market - * @param cToken The market to verify the redeem against - * @param redeemer The account which would redeem the tokens - * @param redeemTokens The number of cTokens to exchange for the underlying asset in the market - * @return 0 if the redeem is allowed, otherwise a semi-opaque error code (See ErrorReporter.sol) - */ - function redeemAllowed( - address cToken, - address redeemer, - uint256 redeemTokens - ) external override returns (uint256) { - uint256 allowed = redeemAllowedInternal(cToken, redeemer, redeemTokens); - if (allowed != uint256(Error.NO_ERROR)) { - return allowed; - } - - // Keep the flywheel moving - updateCompSupplyIndex(cToken); - distributeSupplierComp(cToken, redeemer, false); - - return uint256(Error.NO_ERROR); - } - - function redeemAllowedInternal( - address cToken, - address redeemer, - uint256 redeemTokens - ) internal view returns (uint256) { - if (!markets[cToken].isListed) { - return uint256(Error.MARKET_NOT_LISTED); - } - - /* If the redeemer is not 'in' the market, then we can bypass the liquidity check */ - if (!markets[cToken].accountMembership[redeemer]) { - return uint256(Error.NO_ERROR); - } - - /* Otherwise, perform a hypothetical liquidity check to guard against shortfall */ - ( - Error err, - , - uint256 shortfall - ) = getHypotheticalAccountLiquidityInternal( - redeemer, - CToken(cToken), - redeemTokens, - 0 - ); - if (err != Error.NO_ERROR) { - return uint256(err); - } - if (shortfall > 0) { - return uint256(Error.INSUFFICIENT_LIQUIDITY); - } - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Validates redeem and reverts on rejection. May emit logs. - * @param cToken Asset being redeemed - * @param redeemer The address redeeming the tokens - * @param redeemAmount The amount of the underlying asset being redeemed - * @param redeemTokens The number of tokens being redeemed - */ - function redeemVerify( - address cToken, - address redeemer, - uint256 redeemAmount, - uint256 redeemTokens - ) external pure override { - // Shh - currently unused - cToken; - redeemer; - - // Require tokens is zero or amount is also zero - if (redeemTokens == 0 && redeemAmount > 0) { - revert("redeemTokens zero"); - } - } - - /** - * @notice Checks if the account should be allowed to borrow the underlying asset of the given market - * @param cToken The market to verify the borrow against - * @param borrower The account which would borrow the asset - * @param borrowAmount The amount of underlying the account would borrow - * @return 0 if the borrow is allowed, otherwise a semi-opaque error code (See ErrorReporter.sol) - */ - function borrowAllowed( - address cToken, - address borrower, - uint256 borrowAmount - ) external override returns (uint256) { - // Pausing is a very serious situation - we revert to sound the alarms - Error err; - uint256 shortfall; - require(!borrowGuardianPaused[cToken], "borrow is paused"); - - if (!markets[cToken].isListed) { - return uint256(Error.MARKET_NOT_LISTED); - } - - if (!markets[cToken].accountMembership[borrower]) { - // only cTokens may call borrowAllowed if borrower not in market - require(msg.sender == cToken, "sender must be cToken"); - - // attempt to add borrower to the market - err = addToMarketInternal(CToken(msg.sender), borrower); - if (err != Error.NO_ERROR) { - return uint256(err); - } - - // it should be impossible to break the // important invariant - assert(markets[cToken].accountMembership[borrower]); - } - - if (oracle.getUnderlyingPrice(CToken(cToken)) == 0) { - return uint256(Error.PRICE_ERROR); - } - - uint256 borrowCap = borrowCaps[cToken]; - // Borrow cap of 0 corresponds to unlimited borrowing - if (borrowCap != 0) { - uint256 totalBorrows = CToken(cToken).totalBorrows(); - uint256 nextTotalBorrows = add_(totalBorrows, borrowAmount); - require(nextTotalBorrows < borrowCap, "market borrow cap reached"); - } - - (err, , shortfall) = getHypotheticalAccountLiquidityInternal( - borrower, - CToken(cToken), - 0, - borrowAmount - ); - if (err != Error.NO_ERROR) { - return uint256(err); - } - if (shortfall > 0) { - return uint256(Error.INSUFFICIENT_LIQUIDITY); - } - - // Keep the flywheel moving - Exp memory borrowIndex = Exp({mantissa: CToken(cToken).borrowIndex()}); - updateCompBorrowIndex(cToken, borrowIndex); - distributeBorrowerComp(cToken, borrower, borrowIndex, false); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Validates borrow and reverts on rejection. May emit logs. - * @param cToken Asset whose underlying is being borrowed - * @param borrower The address borrowing the underlying - * @param borrowAmount The amount of the underlying asset requested to borrow - */ - function borrowVerify( - address cToken, - address borrower, - uint256 borrowAmount - ) external override { - // Shh - currently unused - cToken; - borrower; - borrowAmount; - - // Shh - we don't ever want this hook to be marked pure - if (false) { - maxAssets = maxAssets; - } - } - - /** - * @notice Checks if the account should be allowed to repay a borrow in the given market - * @param cToken The market to verify the repay against - * @param payer The account which would repay the asset - * @param borrower The account which would borrowed the asset - * @param repayAmount The amount of the underlying asset the account would repay - * @return 0 if the repay is allowed, otherwise a semi-opaque error code (See ErrorReporter.sol) - */ - function repayBorrowAllowed( - address cToken, - address payer, - address borrower, - uint256 repayAmount - ) external override returns (uint256) { - // Shh - currently unused - payer; - borrower; - repayAmount; - - if (!markets[cToken].isListed) { - return uint256(Error.MARKET_NOT_LISTED); - } - - // Keep the flywheel moving - Exp memory borrowIndex = Exp({mantissa: CToken(cToken).borrowIndex()}); - updateCompBorrowIndex(cToken, borrowIndex); - distributeBorrowerComp(cToken, borrower, borrowIndex, false); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Validates repayBorrow and reverts on rejection. May emit logs. - * @param cToken Asset being repaid - * @param payer The address repaying the borrow - * @param borrower The address of the borrower - * @param actualRepayAmount The amount of underlying being repaid - */ - function repayBorrowVerify( - address cToken, - address payer, - address borrower, - uint256 actualRepayAmount, - uint256 borrowerIndex - ) external override { - // Shh - currently unused - cToken; - payer; - borrower; - actualRepayAmount; - borrowerIndex; - - // Shh - we don't ever want this hook to be marked pure - if (false) { - maxAssets = maxAssets; - } - } - - /** - * @notice Checks if the liquidation should be allowed to occur - * @param cTokenBorrowed Asset which was borrowed by the borrower - * @param cTokenCollateral Asset which was used as collateral and will be seized - * @param liquidator The address repaying the borrow and seizing the collateral - * @param borrower The address of the borrower - * @param repayAmount The amount of underlying being repaid - */ - function liquidateBorrowAllowed( - address cTokenBorrowed, - address cTokenCollateral, - address liquidator, - address borrower, - uint256 repayAmount - ) external view override returns (uint256) { - // Shh - currently unused - liquidator; - - if ( - !markets[cTokenBorrowed].isListed || - !markets[cTokenCollateral].isListed - ) { - return uint256(Error.MARKET_NOT_LISTED); - } - - /* The borrower must have shortfall in order to be liquidatable */ - (Error err, , uint256 shortfall) = getAccountLiquidityInternal( - borrower - ); - if (err != Error.NO_ERROR) { - return uint256(err); - } - if (shortfall == 0) { - return uint256(Error.INSUFFICIENT_SHORTFALL); - } - - /* The liquidator may not repay more than what is allowed by the closeFactor */ - uint256 borrowBalance = CToken(cTokenBorrowed).borrowBalanceStored( - borrower - ); - uint256 maxClose = mul_ScalarTruncate( - Exp({mantissa: closeFactorMantissa}), - borrowBalance - ); - if (repayAmount > maxClose) { - return uint256(Error.TOO_MUCH_REPAY); - } - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Validates liquidateBorrow and reverts on rejection. May emit logs. - * @param cTokenBorrowed Asset which was borrowed by the borrower - * @param cTokenCollateral Asset which was used as collateral and will be seized - * @param liquidator The address repaying the borrow and seizing the collateral - * @param borrower The address of the borrower - * @param actualRepayAmount The amount of underlying being repaid - */ - function liquidateBorrowVerify( - address cTokenBorrowed, - address cTokenCollateral, - address liquidator, - address borrower, - uint256 actualRepayAmount, - uint256 seizeTokens - ) external override { - // Shh - currently unused - cTokenBorrowed; - cTokenCollateral; - liquidator; - borrower; - actualRepayAmount; - seizeTokens; - - // Shh - we don't ever want this hook to be marked pure - if (false) { - maxAssets = maxAssets; - } - } - - /** - * @notice Checks if the seizing of assets should be allowed to occur - * @param cTokenCollateral Asset which was used as collateral and will be seized - * @param cTokenBorrowed Asset which was borrowed by the borrower - * @param liquidator The address repaying the borrow and seizing the collateral - * @param borrower The address of the borrower - * @param seizeTokens The number of collateral tokens to seize - */ - function seizeAllowed( - address cTokenCollateral, - address cTokenBorrowed, - address liquidator, - address borrower, - uint256 seizeTokens - ) external override returns (uint256) { - // Pausing is a very serious situation - we revert to sound the alarms - require(!seizeGuardianPaused, "seize is paused"); - - // Shh - currently unused - seizeTokens; - - if ( - !markets[cTokenCollateral].isListed || - !markets[cTokenBorrowed].isListed - ) { - return uint256(Error.MARKET_NOT_LISTED); - } - - if ( - CToken(cTokenCollateral).comptroller() != - CToken(cTokenBorrowed).comptroller() - ) { - return uint256(Error.COMPTROLLER_MISMATCH); - } - - // Keep the flywheel moving - updateCompSupplyIndex(cTokenCollateral); - distributeSupplierComp(cTokenCollateral, borrower, false); - distributeSupplierComp(cTokenCollateral, liquidator, false); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Validates seize and reverts on rejection. May emit logs. - * @param cTokenCollateral Asset which was used as collateral and will be seized - * @param cTokenBorrowed Asset which was borrowed by the borrower - * @param liquidator The address repaying the borrow and seizing the collateral - * @param borrower The address of the borrower - * @param seizeTokens The number of collateral tokens to seize - */ - function seizeVerify( - address cTokenCollateral, - address cTokenBorrowed, - address liquidator, - address borrower, - uint256 seizeTokens - ) external override { - // Shh - currently unused - cTokenCollateral; - cTokenBorrowed; - liquidator; - borrower; - seizeTokens; - - // Shh - we don't ever want this hook to be marked pure - if (false) { - maxAssets = maxAssets; - } - } - - /** - * @notice Checks if the account should be allowed to transfer tokens in the given market - * @param cToken The market to verify the transfer against - * @param src The account which sources the tokens - * @param dst The account which receives the tokens - * @param transferTokens The number of cTokens to transfer - * @return 0 if the transfer is allowed, otherwise a semi-opaque error code (See ErrorReporter.sol) - */ - function transferAllowed( - address cToken, - address src, - address dst, - uint256 transferTokens - ) external override returns (uint256) { - // Pausing is a very serious situation - we revert to sound the alarms - require(!transferGuardianPaused, "transfer is paused"); - - // Currently the only consideration is whether or not - // the src is allowed to redeem this many tokens - uint256 allowed = redeemAllowedInternal(cToken, src, transferTokens); - if (allowed != uint256(Error.NO_ERROR)) { - return allowed; - } - - // Keep the flywheel moving - updateCompSupplyIndex(cToken); - distributeSupplierComp(cToken, src, false); - distributeSupplierComp(cToken, dst, false); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Validates transfer and reverts on rejection. May emit logs. - * @param cToken Asset being transferred - * @param src The account which sources the tokens - * @param dst The account which receives the tokens - * @param transferTokens The number of cTokens to transfer - */ - function transferVerify( - address cToken, - address src, - address dst, - uint256 transferTokens - ) external override { - // Shh - currently unused - cToken; - src; - dst; - transferTokens; - - // Shh - we don't ever want this hook to be marked pure - if (false) { - maxAssets = maxAssets; - } - } - - /*** Liquidity/Liquidation Calculations ***/ - - /** - * @dev Local vars for avoiding stack-depth limits in calculating account liquidity. - * Note that `cTokenBalance` is the number of cTokens the account owns in the market, - * whereas `borrowBalance` is the amount of underlying that the account has borrowed. - */ - struct AccountLiquidityLocalVars { - uint256 sumCollateral; - uint256 sumBorrowPlusEffects; - uint256 cTokenBalance; - uint256 borrowBalance; - uint256 exchangeRateMantissa; - uint256 oraclePriceMantissa; - Exp collateralFactor; - Exp exchangeRate; - Exp oraclePrice; - Exp tokensToDenom; - } - - /** - * @notice Determine the current account liquidity wrt collateral requirements - * @return (possible error code (semi-opaque), - account liquidity in excess of collateral requirements, - * account shortfall below collateral requirements) - */ - function getAccountLiquidity(address account) - public - view - returns ( - uint256, - uint256, - uint256 - ) - { - ( - Error err, - uint256 liquidity, - uint256 shortfall - ) = getHypotheticalAccountLiquidityInternal( - account, - CToken(address(0)), - 0, - 0 - ); - - return (uint256(err), liquidity, shortfall); - } - - /** - * @notice Determine the current account liquidity wrt collateral requirements - * @return (possible error code, - account liquidity in excess of collateral requirements, - * account shortfall below collateral requirements) - */ - function getAccountLiquidityInternal(address account) - internal - view - returns ( - Error, - uint256, - uint256 - ) - { - return - getHypotheticalAccountLiquidityInternal( - account, - CToken(address(0)), - 0, - 0 - ); - } - - /** - * @notice Determine what the account liquidity would be if the given amounts were redeemed/borrowed - * @param cTokenModify The market to hypothetically redeem/borrow in - * @param account The account to determine liquidity for - * @param redeemTokens The number of tokens to hypothetically redeem - * @param borrowAmount The amount of underlying to hypothetically borrow - * @return (possible error code (semi-opaque), - hypothetical account liquidity in excess of collateral requirements, - * hypothetical account shortfall below collateral requirements) - */ - function getHypotheticalAccountLiquidity( - address account, - address cTokenModify, - uint256 redeemTokens, - uint256 borrowAmount - ) - public - view - returns ( - uint256, - uint256, - uint256 - ) - { - ( - Error err, - uint256 liquidity, - uint256 shortfall - ) = getHypotheticalAccountLiquidityInternal( - account, - CToken(cTokenModify), - redeemTokens, - borrowAmount - ); - return (uint256(err), liquidity, shortfall); - } - - /** - * @notice Determine what the account liquidity would be if the given amounts were redeemed/borrowed - * @param cTokenModify The market to hypothetically redeem/borrow in - * @param account The account to determine liquidity for - * @param redeemTokens The number of tokens to hypothetically redeem - * @param borrowAmount The amount of underlying to hypothetically borrow - * @dev Note that we calculate the exchangeRateStored for each collateral cToken using stored data, - * without calculating accumulated interest. - * @return (possible error code, - hypothetical account liquidity in excess of collateral requirements, - * hypothetical account shortfall below collateral requirements) - */ - function getHypotheticalAccountLiquidityInternal( - address account, - CToken cTokenModify, - uint256 redeemTokens, - uint256 borrowAmount - ) - internal - view - returns ( - Error, - uint256, - uint256 - ) - { - AccountLiquidityLocalVars memory vars; // Holds all our calculation results - uint256 oErr; - - // For each asset the account is in - CToken[] memory assets = accountAssets[account]; - for (uint256 i = 0; i < assets.length; i++) { - CToken asset = assets[i]; - - // Read the balances and exchange rate from the cToken - ( - oErr, - vars.cTokenBalance, - vars.borrowBalance, - vars.exchangeRateMantissa - ) = asset.getAccountSnapshot(account); - if (oErr != 0) { - // semi-opaque error code, we assume NO_ERROR == 0 is invariant between upgrades - return (Error.SNAPSHOT_ERROR, 0, 0); - } - vars.collateralFactor = Exp({ - mantissa: markets[address(asset)].collateralFactorMantissa - }); - vars.exchangeRate = Exp({mantissa: vars.exchangeRateMantissa}); - - // Get the normalized price of the asset - vars.oraclePriceMantissa = oracle.getUnderlyingPrice(asset); - if (vars.oraclePriceMantissa == 0) { - return (Error.PRICE_ERROR, 0, 0); - } - vars.oraclePrice = Exp({mantissa: vars.oraclePriceMantissa}); - - // Pre-compute a conversion factor from tokens -> ether (normalized price value) - vars.tokensToDenom = mul_( - mul_(vars.collateralFactor, vars.exchangeRate), - vars.oraclePrice - ); - - // sumCollateral += tokensToDenom * cTokenBalance - vars.sumCollateral = mul_ScalarTruncateAddUInt( - vars.tokensToDenom, - vars.cTokenBalance, - vars.sumCollateral - ); - - // sumBorrowPlusEffects += oraclePrice * borrowBalance - vars.sumBorrowPlusEffects = mul_ScalarTruncateAddUInt( - vars.oraclePrice, - vars.borrowBalance, - vars.sumBorrowPlusEffects - ); - - // Calculate effects of interacting with cTokenModify - if (asset == cTokenModify) { - // redeem effect - // sumBorrowPlusEffects += tokensToDenom * redeemTokens - vars.sumBorrowPlusEffects = mul_ScalarTruncateAddUInt( - vars.tokensToDenom, - redeemTokens, - vars.sumBorrowPlusEffects - ); - - // borrow effect - // sumBorrowPlusEffects += oraclePrice * borrowAmount - vars.sumBorrowPlusEffects = mul_ScalarTruncateAddUInt( - vars.oraclePrice, - borrowAmount, - vars.sumBorrowPlusEffects - ); - } - } - - // These are safe, as the underflow condition is checked first - if (vars.sumCollateral > vars.sumBorrowPlusEffects) { - return ( - Error.NO_ERROR, - vars.sumCollateral - vars.sumBorrowPlusEffects, - 0 - ); - } else { - return ( - Error.NO_ERROR, - 0, - vars.sumBorrowPlusEffects - vars.sumCollateral - ); - } - } - - /** - * @notice Calculate number of tokens of collateral asset to seize given an underlying amount - * @dev Used in liquidation (called in cToken.liquidateBorrowFresh) - * @param cTokenBorrowed The address of the borrowed cToken - * @param cTokenCollateral The address of the collateral cToken - * @param actualRepayAmount The amount of cTokenBorrowed underlying to convert into cTokenCollateral tokens - * @return (errorCode, number of cTokenCollateral tokens to be seized in a liquidation) - */ - function liquidateCalculateSeizeTokens( - address cTokenBorrowed, - address cTokenCollateral, - uint256 actualRepayAmount - ) external view override returns (uint256, uint256) { - /* Read oracle prices for borrowed and collateral markets */ - uint256 priceBorrowedMantissa = oracle.getUnderlyingPrice( - CToken(cTokenBorrowed) - ); - uint256 priceCollateralMantissa = oracle.getUnderlyingPrice( - CToken(cTokenCollateral) - ); - if (priceBorrowedMantissa == 0 || priceCollateralMantissa == 0) { - return (uint256(Error.PRICE_ERROR), 0); - } - - /* - * Get the exchange rate and calculate the number of collateral tokens to seize: - * seizeAmount = actualRepayAmount * liquidationIncentive * priceBorrowed / priceCollateral - * seizeTokens = seizeAmount / exchangeRate - * = actualRepayAmount * (liquidationIncentive * priceBorrowed) / (priceCollateral * exchangeRate) - */ - uint256 exchangeRateMantissa = CToken(cTokenCollateral) - .exchangeRateStored(); // Note: reverts on error - uint256 seizeTokens; - Exp memory numerator; - Exp memory denominator; - Exp memory ratio; - - numerator = mul_( - Exp({mantissa: liquidationIncentiveMantissa}), - Exp({mantissa: priceBorrowedMantissa}) - ); - denominator = mul_( - Exp({mantissa: priceCollateralMantissa}), - Exp({mantissa: exchangeRateMantissa}) - ); - ratio = div_(numerator, denominator); - - seizeTokens = mul_ScalarTruncate(ratio, actualRepayAmount); - - return (uint256(Error.NO_ERROR), seizeTokens); - } - - /*** Admin Functions ***/ - - /** - * @notice Sets a new price oracle for the comptroller - * @dev Admin function to set a new price oracle - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setPriceOracle(PriceOracle newOracle) public returns (uint256) { - // Check caller is admin - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_PRICE_ORACLE_OWNER_CHECK - ); - } - - // Track the old oracle for the comptroller - PriceOracle oldOracle = oracle; - - // Set comptroller's oracle to newOracle - oracle = newOracle; - - // Emit NewPriceOracle(oldOracle, newOracle) - emit NewPriceOracle(oldOracle, newOracle); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Sets the closeFactor used when liquidating borrows - * @dev Admin function to set closeFactor - * @param newCloseFactorMantissa New close factor, scaled by 1e18 - * @return uint 0=success, otherwise a failure - */ - function _setCloseFactor(uint256 newCloseFactorMantissa) - external - returns (uint256) - { - // Check caller is admin - require(msg.sender == admin, "only admin can set close factor"); - - uint256 oldCloseFactorMantissa = closeFactorMantissa; - closeFactorMantissa = newCloseFactorMantissa; - emit NewCloseFactor(oldCloseFactorMantissa, closeFactorMantissa); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Sets the collateralFactor for a market - * @dev Admin function to set per-market collateralFactor - * @param cToken The market to set the factor on - * @param newCollateralFactorMantissa The new collateral factor, scaled by 1e18 - * @return uint 0=success, otherwise a failure. (See ErrorReporter for details) - */ - function _setCollateralFactor( - CToken cToken, - uint256 newCollateralFactorMantissa - ) external returns (uint256) { - // Check caller is admin - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_COLLATERAL_FACTOR_OWNER_CHECK - ); - } - - // Verify market is listed - Market storage market = markets[address(cToken)]; - if (!market.isListed) { - return - fail( - Error.MARKET_NOT_LISTED, - FailureInfo.SET_COLLATERAL_FACTOR_NO_EXISTS - ); - } - - Exp memory newCollateralFactorExp = Exp({ - mantissa: newCollateralFactorMantissa - }); - - // Check collateral factor <= 0.9 - Exp memory highLimit = Exp({mantissa: collateralFactorMaxMantissa}); - if (lessThanExp(highLimit, newCollateralFactorExp)) { - return - fail( - Error.INVALID_COLLATERAL_FACTOR, - FailureInfo.SET_COLLATERAL_FACTOR_VALIDATION - ); - } - - // If collateral factor != 0, fail if price == 0 - if ( - newCollateralFactorMantissa != 0 && - oracle.getUnderlyingPrice(cToken) == 0 - ) { - return - fail( - Error.PRICE_ERROR, - FailureInfo.SET_COLLATERAL_FACTOR_WITHOUT_PRICE - ); - } - - // Set market's collateral factor to new collateral factor, remember old value - uint256 oldCollateralFactorMantissa = market.collateralFactorMantissa; - market.collateralFactorMantissa = newCollateralFactorMantissa; - - // Emit event with asset, old collateral factor, and new collateral factor - emit NewCollateralFactor( - cToken, - oldCollateralFactorMantissa, - newCollateralFactorMantissa - ); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Sets liquidationIncentive - * @dev Admin function to set liquidationIncentive - * @param newLiquidationIncentiveMantissa New liquidationIncentive scaled by 1e18 - * @return uint 0=success, otherwise a failure. (See ErrorReporter for details) - */ - function _setLiquidationIncentive(uint256 newLiquidationIncentiveMantissa) - external - returns (uint256) - { - // Check caller is admin - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_LIQUIDATION_INCENTIVE_OWNER_CHECK - ); - } - - // Save current value for use in log - uint256 oldLiquidationIncentiveMantissa = liquidationIncentiveMantissa; - - // Set liquidation incentive to new incentive - liquidationIncentiveMantissa = newLiquidationIncentiveMantissa; - - // Emit event with old incentive, new incentive - emit NewLiquidationIncentive( - oldLiquidationIncentiveMantissa, - newLiquidationIncentiveMantissa - ); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Add the market to the markets mapping and set it as listed - * @dev Admin function to set isListed and add support for the market - * @param cToken The address of the market (token) to list - * @return uint 0=success, otherwise a failure. (See enum Error for details) - */ - function _supportMarket(CToken cToken) external returns (uint256) { - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SUPPORT_MARKET_OWNER_CHECK - ); - } - - if (markets[address(cToken)].isListed) { - return - fail( - Error.MARKET_ALREADY_LISTED, - FailureInfo.SUPPORT_MARKET_EXISTS - ); - } - - cToken.isCToken(); // Sanity check to make sure its really a CToken - - Market storage market = markets[address(cToken)]; - market.isListed = true; - market.isComped = false; - market.collateralFactorMantissa = 0; - - _addMarketInternal(address(cToken)); - - emit MarketListed(cToken); - - return uint256(Error.NO_ERROR); - } - - function _addMarketInternal(address cToken) internal { - for (uint256 i = 0; i < allMarkets.length; i++) { - require(allMarkets[i] != CToken(cToken), "market already added"); - } - allMarkets.push(CToken(cToken)); - } - - /** - * @notice Set the given borrow caps for the given cToken markets. Borrowing that brings total borrows to or above borrow cap will revert. - * @dev Admin or borrowCapGuardian function to set the borrow caps. A borrow cap of 0 corresponds to unlimited borrowing. - * @param cTokens The addresses of the markets (tokens) to change the borrow caps for - * @param newBorrowCaps The new borrow cap values in underlying to be set. A value of 0 corresponds to unlimited borrowing. - */ - function _setMarketBorrowCaps( - CToken[] calldata cTokens, - uint256[] calldata newBorrowCaps - ) external { - require( - msg.sender == admin || msg.sender == borrowCapGuardian, - "only admin or borrow cap guardian can set borrow caps" - ); - - uint256 numMarkets = cTokens.length; - uint256 numBorrowCaps = newBorrowCaps.length; - - require( - numMarkets != 0 && numMarkets == numBorrowCaps, - "invalid input" - ); - - for (uint256 i = 0; i < numMarkets; i++) { - borrowCaps[address(cTokens[i])] = newBorrowCaps[i]; - emit NewBorrowCap(cTokens[i], newBorrowCaps[i]); - } - } - - /** - * @notice Admin function to change the Borrow Cap Guardian - * @param newBorrowCapGuardian The address of the new Borrow Cap Guardian - */ - function _setBorrowCapGuardian(address newBorrowCapGuardian) external { - require(msg.sender == admin, "only admin can set borrow cap guardian"); - - // Save current value for inclusion in log - address oldBorrowCapGuardian = borrowCapGuardian; - - // Store borrowCapGuardian with value newBorrowCapGuardian - borrowCapGuardian = newBorrowCapGuardian; - - // Emit NewBorrowCapGuardian(OldBorrowCapGuardian, NewBorrowCapGuardian) - emit NewBorrowCapGuardian(oldBorrowCapGuardian, newBorrowCapGuardian); - } - - /** - * @notice Admin function to change the Pause Guardian - * @param newPauseGuardian The address of the new Pause Guardian - * @return uint 0=success, otherwise a failure. (See enum Error for details) - */ - function _setPauseGuardian(address newPauseGuardian) - public - returns (uint256) - { - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_PAUSE_GUARDIAN_OWNER_CHECK - ); - } - - // Save current value for inclusion in log - address oldPauseGuardian = pauseGuardian; - - // Store pauseGuardian with value newPauseGuardian - pauseGuardian = newPauseGuardian; - - // Emit NewPauseGuardian(OldPauseGuardian, NewPauseGuardian) - emit NewPauseGuardian(oldPauseGuardian, pauseGuardian); - - return uint256(Error.NO_ERROR); - } - - function _setMintPaused(CToken cToken, bool state) public returns (bool) { - require( - markets[address(cToken)].isListed, - "cannot pause a market that is not listed" - ); - require( - msg.sender == pauseGuardian || msg.sender == admin, - "only pause guardian and admin can pause" - ); - require(msg.sender == admin || state == true, "only admin can unpause"); - - mintGuardianPaused[address(cToken)] = state; - emit ActionPaused(cToken, "Mint", state); - return state; - } - - function _setBorrowPaused(CToken cToken, bool state) public returns (bool) { - require( - markets[address(cToken)].isListed, - "cannot pause a market that is not listed" - ); - require( - msg.sender == pauseGuardian || msg.sender == admin, - "only pause guardian and admin can pause" - ); - require(msg.sender == admin || state == true, "only admin can unpause"); - - borrowGuardianPaused[address(cToken)] = state; - emit ActionPaused(cToken, "Borrow", state); - return state; - } - - function _setTransferPaused(bool state) public returns (bool) { - require( - msg.sender == pauseGuardian || msg.sender == admin, - "only pause guardian and admin can pause" - ); - require(msg.sender == admin || state == true, "only admin can unpause"); - - transferGuardianPaused = state; - emit ActionPaused("Transfer", state); - return state; - } - - function _setSeizePaused(bool state) public returns (bool) { - require( - msg.sender == pauseGuardian || msg.sender == admin, - "only pause guardian and admin can pause" - ); - require(msg.sender == admin || state == true, "only admin can unpause"); - - seizeGuardianPaused = state; - emit ActionPaused("Seize", state); - return state; - } - - function _become(Unitroller unitroller) public { - require( - msg.sender == unitroller.admin(), - "only unitroller admin can change brains" - ); - require( - unitroller._acceptImplementation() == 0, - "change not authorized" - ); - } - - /** - * @notice Checks caller is admin, or this contract is becoming the new implementation - */ - function adminOrInitializing() internal view returns (bool) { - return msg.sender == admin || msg.sender == comptrollerImplementation; - } - - /*** Comp Distribution ***/ - - /** - * @notice Recalculate and update COMP speeds for all COMP markets - */ - function refreshCompSpeeds() public { - require( - msg.sender == tx.origin, - "only externally owned accounts may refresh speeds" - ); - refreshCompSpeedsInternal(); - } - - function refreshCompSpeedsInternal() internal { - CToken[] memory allMarkets_ = allMarkets; - - for (uint256 i = 0; i < allMarkets_.length; i++) { - CToken cToken = allMarkets_[i]; - Exp memory borrowIndex = Exp({mantissa: cToken.borrowIndex()}); - updateCompSupplyIndex(address(cToken)); - updateCompBorrowIndex(address(cToken), borrowIndex); - } - - Exp memory totalUtility = Exp({mantissa: 0}); - Exp[] memory utilities = new Exp[](allMarkets_.length); - for (uint256 i = 0; i < allMarkets_.length; i++) { - CToken cToken = allMarkets_[i]; - if (markets[address(cToken)].isComped) { - Exp memory assetPrice = Exp({ - mantissa: oracle.getUnderlyingPrice(cToken) - }); - Exp memory utility = mul_(assetPrice, cToken.totalBorrows()); - utilities[i] = utility; - totalUtility = add_(totalUtility, utility); - } - } - - for (uint256 i = 0; i < allMarkets_.length; i++) { - CToken cToken = allMarkets[i]; - uint256 newSpeed = totalUtility.mantissa > 0 - ? mul_(compRate, div_(utilities[i], totalUtility)) - : 0; - compSpeeds[address(cToken)] = newSpeed; - emit CompSpeedUpdated(cToken, newSpeed); - } - } - - /** - * @notice Accrue COMP to the market by updating the supply index - * @param cToken The market whose supply index to update - */ - function updateCompSupplyIndex(address cToken) internal { - CompMarketState storage supplyState = compSupplyState[cToken]; - uint256 supplySpeed = compSpeeds[cToken]; - uint256 blockNumber = getBlockNumber(); - uint256 deltaBlocks = sub_(blockNumber, uint256(supplyState.block)); - if (deltaBlocks > 0 && supplySpeed > 0) { - uint256 supplyTokens = CToken(cToken).totalSupply(); - uint256 compAccrued = mul_(deltaBlocks, supplySpeed); - Double memory ratio = supplyTokens > 0 - ? fraction(compAccrued, supplyTokens) - : Double({mantissa: 0}); - Double memory index = add_( - Double({mantissa: supplyState.index}), - ratio - ); - compSupplyState[cToken] = CompMarketState({ - index: safe224(index.mantissa, "new index exceeds 224 bits"), - block: safe32(blockNumber, "block number exceeds 32 bits") - }); - } else if (deltaBlocks > 0) { - supplyState.block = safe32( - blockNumber, - "block number exceeds 32 bits" - ); - } - } - - /** - * @notice Accrue COMP to the market by updating the borrow index - * @param cToken The market whose borrow index to update - */ - function updateCompBorrowIndex(address cToken, Exp memory marketBorrowIndex) - internal - { - CompMarketState storage borrowState = compBorrowState[cToken]; - uint256 borrowSpeed = compSpeeds[cToken]; - uint256 blockNumber = getBlockNumber(); - uint256 deltaBlocks = sub_(blockNumber, uint256(borrowState.block)); - if (deltaBlocks > 0 && borrowSpeed > 0) { - uint256 borrowAmount = div_( - CToken(cToken).totalBorrows(), - marketBorrowIndex - ); - uint256 compAccrued = mul_(deltaBlocks, borrowSpeed); - Double memory ratio = borrowAmount > 0 - ? fraction(compAccrued, borrowAmount) - : Double({mantissa: 0}); - Double memory index = add_( - Double({mantissa: borrowState.index}), - ratio - ); - compBorrowState[cToken] = CompMarketState({ - index: safe224(index.mantissa, "new index exceeds 224 bits"), - block: safe32(blockNumber, "block number exceeds 32 bits") - }); - } else if (deltaBlocks > 0) { - borrowState.block = safe32( - blockNumber, - "block number exceeds 32 bits" - ); - } - } - - /** - * @notice Calculate COMP accrued by a supplier and possibly transfer it to them - * @param cToken The market in which the supplier is interacting - * @param supplier The address of the supplier to distribute COMP to - */ - function distributeSupplierComp( - address cToken, - address supplier, - bool distributeAll - ) internal { - CompMarketState storage supplyState = compSupplyState[cToken]; - Double memory supplyIndex = Double({mantissa: supplyState.index}); - Double memory supplierIndex = Double({ - mantissa: compSupplierIndex[cToken][supplier] - }); - compSupplierIndex[cToken][supplier] = supplyIndex.mantissa; - - if (supplierIndex.mantissa == 0 && supplyIndex.mantissa > 0) { - supplierIndex.mantissa = compInitialIndex; - } - - Double memory deltaIndex = sub_(supplyIndex, supplierIndex); - uint256 supplierTokens = CToken(cToken).balanceOf(supplier); - uint256 supplierDelta = mul_(supplierTokens, deltaIndex); - uint256 supplierAccrued = add_(compAccrued[supplier], supplierDelta); - compAccrued[supplier] = transferComp( - supplier, - supplierAccrued, - distributeAll ? 0 : compClaimThreshold - ); - emit DistributedSupplierComp( - CToken(cToken), - supplier, - supplierDelta, - supplyIndex.mantissa - ); - } - - /** - * @notice Calculate COMP accrued by a borrower and possibly transfer it to them - * @dev Borrowers will not begin to accrue until after the first interaction with the protocol. - * @param cToken The market in which the borrower is interacting - * @param borrower The address of the borrower to distribute COMP to - */ - function distributeBorrowerComp( - address cToken, - address borrower, - Exp memory marketBorrowIndex, - bool distributeAll - ) internal { - CompMarketState storage borrowState = compBorrowState[cToken]; - Double memory borrowIndex = Double({mantissa: borrowState.index}); - Double memory borrowerIndex = Double({ - mantissa: compBorrowerIndex[cToken][borrower] - }); - compBorrowerIndex[cToken][borrower] = borrowIndex.mantissa; - - if (borrowerIndex.mantissa > 0) { - Double memory deltaIndex = sub_(borrowIndex, borrowerIndex); - uint256 borrowerAmount = div_( - CToken(cToken).borrowBalanceStored(borrower), - marketBorrowIndex - ); - uint256 borrowerDelta = mul_(borrowerAmount, deltaIndex); - uint256 borrowerAccrued = add_( - compAccrued[borrower], - borrowerDelta - ); - compAccrued[borrower] = transferComp( - borrower, - borrowerAccrued, - distributeAll ? 0 : compClaimThreshold - ); - emit DistributedBorrowerComp( - CToken(cToken), - borrower, - borrowerDelta, - borrowIndex.mantissa - ); - } - } - - /** - * @notice Transfer COMP to the user, if they are above the threshold - * @dev Note: If there is not enough COMP, we do not perform the transfer all. - * @param user The address of the user to transfer COMP to - * @param userAccrued The amount of COMP to (possibly) transfer - * @return The amount of COMP which was NOT transferred to the user - */ - function transferComp( - address user, - uint256 userAccrued, - uint256 threshold - ) internal returns (uint256) { - if (userAccrued >= threshold && userAccrued > 0) { - TROP comp = TROP(getCompAddress()); - uint256 compRemaining = comp.balanceOf(address(this)); - if (userAccrued <= compRemaining) { - comp.transfer(user, userAccrued); - return 0; - } - } - return userAccrued; - } - - /** - * @notice Calculate additional accrued COMP for a contributor since last accrual - * @param contributor The address to calculate contributor rewards for - */ - function updateContributorRewards(address contributor) public { - uint256 compSpeed = compContributorSpeeds[contributor]; - uint256 blockNumber = getBlockNumber(); - uint256 deltaBlocks = sub_( - blockNumber, - lastContributorBlock[contributor] - ); - if (deltaBlocks > 0 && compSpeed > 0) { - uint256 newAccrued = mul_(deltaBlocks, compSpeed); - uint256 contributorAccrued = add_( - compAccrued[contributor], - newAccrued - ); - - compAccrued[contributor] = contributorAccrued; - lastContributorBlock[contributor] = blockNumber; - } - } - - /** - * @notice Claim all the comp accrued by holder in all markets - * @param holder The address to claim COMP for - */ - function claimComp(address holder) public { - return claimComp(holder, allMarkets); - } - - /** - * @notice Claim all the comp accrued by holder in the specified markets - * @param holder The address to claim COMP for - * @param cTokens The list of markets to claim COMP in - */ - function claimComp(address holder, CToken[] memory cTokens) public { - address[] memory holders = new address[](1); - holders[0] = holder; - claimComp(holders, cTokens, true, true); - } - - /** - * @notice Claim all comp accrued by the holders - * @param holders The addresses to claim COMP for - * @param cTokens The list of markets to claim COMP in - * @param borrowers Whether or not to claim COMP earned by borrowing - * @param suppliers Whether or not to claim COMP earned by supplying - */ - function claimComp( - address[] memory holders, - CToken[] memory cTokens, - bool borrowers, - bool suppliers - ) public { - for (uint256 i = 0; i < cTokens.length; i++) { - CToken cToken = cTokens[i]; - require(markets[address(cToken)].isListed, "market must be listed"); - if (borrowers == true) { - Exp memory borrowIndex = Exp({mantissa: cToken.borrowIndex()}); - updateCompBorrowIndex(address(cToken), borrowIndex); - for (uint256 j = 0; j < holders.length; j++) { - distributeBorrowerComp( - address(cToken), - holders[j], - borrowIndex, - true - ); - } - } - if (suppliers == true) { - updateCompSupplyIndex(address(cToken)); - for (uint256 j = 0; j < holders.length; j++) { - distributeSupplierComp(address(cToken), holders[j], true); - } - } - } - } - - /** - * @notice Transfer COMP to the user - * @dev Note: If there is not enough COMP, we do not perform the transfer all. - * @param user The address of the user to transfer COMP to - * @param amount The amount of COMP to (possibly) transfer - * @return The amount of COMP which was NOT transferred to the user - */ - function grantCompInternal(address user, uint256 amount) - internal - returns (uint256) - { - TROP comp = TROP(getCompAddress()); - uint256 compRemaining = comp.balanceOf(address(this)); - if (amount <= compRemaining) { - comp.transfer(user, amount); - return 0; - } - return amount; - } - - /*** Comp Distribution Admin ***/ - - /** - * @notice Transfer COMP to the recipient - * @dev Note: If there is not enough COMP, we do not perform the transfer all. - * @param recipient The address of the recipient to transfer COMP to - * @param amount The amount of COMP to (possibly) transfer - */ - function _grantComp(address recipient, uint256 amount) public { - require(adminOrInitializing(), "only admin can grant comp"); - uint256 amountLeft = grantCompInternal(recipient, amount); - require(amountLeft == 0, "insufficient comp for grant"); - emit CompGranted(recipient, amount); - } - - /** - * @notice Set COMP speed for a single contributor - * @param contributor The contributor whose COMP speed to update - * @param compSpeed New COMP speed for contributor - */ - function _setContributorCompSpeed(address contributor, uint256 compSpeed) - public - { - require(adminOrInitializing(), "only admin can set comp speed"); - - // note that COMP speed could be set to 0 to halt liquidity rewards for a contributor - updateContributorRewards(contributor); - if (compSpeed == 0) { - // release storage - delete lastContributorBlock[contributor]; - } - lastContributorBlock[contributor] = getBlockNumber(); - compContributorSpeeds[contributor] = compSpeed; - - emit ContributorCompSpeedUpdated(contributor, compSpeed); - } - - /** - * @notice Set the amount of COMP distributed per block - * @param compRate_ The amount of COMP wei per block to distribute - */ - function _setCompRate(uint256 compRate_) public { - require(adminOrInitializing(), "only admin can change comp rate"); - - uint256 oldRate = compRate; - compRate = compRate_; - emit NewCompRate(oldRate, compRate_); - - refreshCompSpeedsInternal(); - } - - /** - * @notice Add markets to compMarkets, allowing them to earn COMP in the flywheel - * @param cTokens The addresses of the markets to add - */ - function _addCompMarkets(address[] memory cTokens) public { - require(adminOrInitializing(), "only admin can add comp market"); - - for (uint256 i = 0; i < cTokens.length; i++) { - _addCompMarketInternal(cTokens[i]); - } - - refreshCompSpeedsInternal(); - } - - function _addCompMarketInternal(address cToken) internal { - Market storage market = markets[cToken]; - require(market.isListed == true, "comp market is not listed"); - require(market.isComped == false, "comp market already added"); - - market.isComped = true; - emit MarketComped(CToken(cToken), true); - - if ( - compSupplyState[cToken].index == 0 && - compSupplyState[cToken].block == 0 - ) { - compSupplyState[cToken] = CompMarketState({ - index: compInitialIndex, - block: safe32(getBlockNumber(), "block number exceeds 32 bits") - }); - } - - if ( - compBorrowState[cToken].index == 0 && - compBorrowState[cToken].block == 0 - ) { - compBorrowState[cToken] = CompMarketState({ - index: compInitialIndex, - block: safe32(getBlockNumber(), "block number exceeds 32 bits") - }); - } - } - - /** - * @notice Remove a market from compMarkets, preventing it from earning COMP in the flywheel - * @param cToken The address of the market to drop - */ - function _dropCompMarket(address cToken) public { - require(msg.sender == admin, "only admin can drop comp market"); - - Market storage market = markets[cToken]; - require(market.isComped == true, "market is not a comp market"); - - market.isComped = false; - emit MarketComped(CToken(cToken), false); - - refreshCompSpeedsInternal(); - } - - /** - * @notice Return all of the markets - * @dev The automatic getter may be used to access an individual market. - * @return The list of market addresses - */ - function getAllMarkets() public view returns (CToken[] memory) { - return allMarkets; - } - - function getBlockNumber() public view virtual returns (uint256) { - return block.number; - } - - /** - * @notice Return the address of the COMP token - * @return The address of COMP - */ - function getCompAddress() public view virtual returns (address) { - return 0xc00e94Cb662C3520282E6f5717214004A7f26888; - } -} diff --git a/flatten/ComptrollerInterface.sol b/flatten/ComptrollerInterface.sol deleted file mode 100644 index f0235bd..0000000 --- a/flatten/ComptrollerInterface.sol +++ /dev/null @@ -1,128 +0,0 @@ -// Root file: contracts/ComptrollerInterface.sol - -// SPDX-License-Identifier: UNLICENSED -pragma solidity 0.8.6; - -abstract contract ComptrollerInterface { - /// @notice Indicator that this is a Comptroller contract (for inspection) - bool public constant isComptroller = true; - - /*** Assets You Are In ***/ - - function enterMarkets(address[] calldata cTokens) - external - virtual - returns (uint256[] memory); - - function exitMarket(address cToken) external virtual returns (uint256); - - /*** Policy Hooks ***/ - - function mintAllowed( - address cToken, - address minter, - uint256 mintAmount - ) external virtual returns (uint256); - - function mintVerify( - address cToken, - address minter, - uint256 mintAmount, - uint256 mintTokens - ) external virtual; - - function redeemAllowed( - address cToken, - address redeemer, - uint256 redeemTokens - ) external virtual returns (uint256); - - function redeemVerify( - address cToken, - address redeemer, - uint256 redeemAmount, - uint256 redeemTokens - ) external virtual; - - function borrowAllowed( - address cToken, - address borrower, - uint256 borrowAmount - ) external virtual returns (uint256); - - function borrowVerify( - address cToken, - address borrower, - uint256 borrowAmount - ) external virtual; - - function repayBorrowAllowed( - address cToken, - address payer, - address borrower, - uint256 repayAmount - ) external virtual returns (uint256); - - function repayBorrowVerify( - address cToken, - address payer, - address borrower, - uint256 repayAmount, - uint256 borrowerIndex - ) external virtual; - - function liquidateBorrowAllowed( - address cTokenBorrowed, - address cTokenCollateral, - address liquidator, - address borrower, - uint256 repayAmount - ) external virtual returns (uint256); - - function liquidateBorrowVerify( - address cTokenBorrowed, - address cTokenCollateral, - address liquidator, - address borrower, - uint256 repayAmount, - uint256 seizeTokens - ) external virtual; - - function seizeAllowed( - address cTokenCollateral, - address cTokenBorrowed, - address liquidator, - address borrower, - uint256 seizeTokens - ) external virtual returns (uint256); - - function seizeVerify( - address cTokenCollateral, - address cTokenBorrowed, - address liquidator, - address borrower, - uint256 seizeTokens - ) external virtual; - - function transferAllowed( - address cToken, - address src, - address dst, - uint256 transferTokens - ) external virtual returns (uint256); - - function transferVerify( - address cToken, - address src, - address dst, - uint256 transferTokens - ) external virtual; - - /*** Liquidity/Liquidation Calculations ***/ - - function liquidateCalculateSeizeTokens( - address cTokenBorrowed, - address cTokenCollateral, - uint256 repayAmount - ) external view virtual returns (uint256, uint256); -} diff --git a/flatten/ComptrollerStorage.sol b/flatten/ComptrollerStorage.sol deleted file mode 100644 index 41db2e9..0000000 --- a/flatten/ComptrollerStorage.sol +++ /dev/null @@ -1,4099 +0,0 @@ -// Dependency file: contracts/ComptrollerInterface.sol - -// SPDX-License-Identifier: UNLICENSED -// pragma solidity 0.8.6; - -abstract contract ComptrollerInterface { - /// @notice Indicator that this is a Comptroller contract (for inspection) - bool public constant isComptroller = true; - - /*** Assets You Are In ***/ - - function enterMarkets(address[] calldata cTokens) - external - virtual - returns (uint256[] memory); - - function exitMarket(address cToken) external virtual returns (uint256); - - /*** Policy Hooks ***/ - - function mintAllowed( - address cToken, - address minter, - uint256 mintAmount - ) external virtual returns (uint256); - - function mintVerify( - address cToken, - address minter, - uint256 mintAmount, - uint256 mintTokens - ) external virtual; - - function redeemAllowed( - address cToken, - address redeemer, - uint256 redeemTokens - ) external virtual returns (uint256); - - function redeemVerify( - address cToken, - address redeemer, - uint256 redeemAmount, - uint256 redeemTokens - ) external virtual; - - function borrowAllowed( - address cToken, - address borrower, - uint256 borrowAmount - ) external virtual returns (uint256); - - function borrowVerify( - address cToken, - address borrower, - uint256 borrowAmount - ) external virtual; - - function repayBorrowAllowed( - address cToken, - address payer, - address borrower, - uint256 repayAmount - ) external virtual returns (uint256); - - function repayBorrowVerify( - address cToken, - address payer, - address borrower, - uint256 repayAmount, - uint256 borrowerIndex - ) external virtual; - - function liquidateBorrowAllowed( - address cTokenBorrowed, - address cTokenCollateral, - address liquidator, - address borrower, - uint256 repayAmount - ) external virtual returns (uint256); - - function liquidateBorrowVerify( - address cTokenBorrowed, - address cTokenCollateral, - address liquidator, - address borrower, - uint256 repayAmount, - uint256 seizeTokens - ) external virtual; - - function seizeAllowed( - address cTokenCollateral, - address cTokenBorrowed, - address liquidator, - address borrower, - uint256 seizeTokens - ) external virtual returns (uint256); - - function seizeVerify( - address cTokenCollateral, - address cTokenBorrowed, - address liquidator, - address borrower, - uint256 seizeTokens - ) external virtual; - - function transferAllowed( - address cToken, - address src, - address dst, - uint256 transferTokens - ) external virtual returns (uint256); - - function transferVerify( - address cToken, - address src, - address dst, - uint256 transferTokens - ) external virtual; - - /*** Liquidity/Liquidation Calculations ***/ - - function liquidateCalculateSeizeTokens( - address cTokenBorrowed, - address cTokenCollateral, - uint256 repayAmount - ) external view virtual returns (uint256, uint256); -} - - -// Dependency file: contracts/CarefulMath.sol - -// pragma solidity 0.8.6; - -/** - * @title Careful Math - * @author tropykus - * @notice Derived from OpenZeppelin's SafeMath library - * https://github.com/OpenZeppelin/openzeppelin-solidity/blob/master/contracts/math/SafeMath.sol - */ -contract CarefulMath { - - /** - * @dev Possible error codes that we can return - */ - enum MathError { - NO_ERROR, - DIVISION_BY_ZERO, - INTEGER_OVERFLOW, - INTEGER_UNDERFLOW - } - - /** - * @dev Multiplies two numbers, returns an error on overflow. - */ - function mulUInt(uint a, uint b) internal pure returns (MathError, uint) { - if (a == 0) { - return (MathError.NO_ERROR, 0); - } - - uint c = a * b; - - if (c / a != b) { - return (MathError.INTEGER_OVERFLOW, 0); - } else { - return (MathError.NO_ERROR, c); - } - } - - /** - * @dev Integer division of two numbers, truncating the quotient. - */ - function divUInt(uint a, uint b) internal pure returns (MathError, uint) { - if (b == 0) { - return (MathError.DIVISION_BY_ZERO, 0); - } - - return (MathError.NO_ERROR, a / b); - } - - /** - * @dev Subtracts two numbers, returns an error on overflow (i.e. if subtrahend is greater than minuend). - */ - function subUInt(uint a, uint b) internal pure returns (MathError, uint) { - if (b <= a) { - return (MathError.NO_ERROR, a - b); - } else { - return (MathError.INTEGER_UNDERFLOW, 0); - } - } - - /** - * @dev Adds two numbers, returns an error on overflow. - */ - function addUInt(uint a, uint b) internal pure returns (MathError, uint) { - uint c = a + b; - - if (c >= a) { - return (MathError.NO_ERROR, c); - } else { - return (MathError.INTEGER_OVERFLOW, 0); - } - } - - /** - * @dev add a and b and then subtract c - */ - function addThenSubUInt(uint a, uint b, uint c) internal pure returns (MathError, uint) { - (MathError err0, uint sum) = addUInt(a, b); - - if (err0 != MathError.NO_ERROR) { - return (err0, 0); - } - - return subUInt(sum, c); - } -} - - -// Dependency file: contracts/ExponentialNoError.sol - -// pragma solidity 0.8.6; - -/** - * @title Exponential module for storing fixed-precision decimals - * @author tropykus - * @notice Exp is a struct which stores decimals with a fixed precision of 18 decimal places. - * Thus, if we wanted to store the 5.1, mantissa would store 5.1e18. That is: - * `Exp({mantissa: 5100000000000000000})`. - */ -contract ExponentialNoError { - uint constant expScale = 1e18; - uint constant doubleScale = 1e36; - uint constant halfExpScale = expScale/2; - uint constant mantissaOne = expScale; - - struct Exp { - uint mantissa; - } - - struct Double { - uint mantissa; - } - - /** - * @dev Truncates the given exp to a whole number value. - * For example, truncate(Exp{mantissa: 15 * expScale}) = 15 - */ - function truncate(Exp memory exp) pure internal returns (uint) { - // Note: We are not using careful math here as we're performing a division that cannot fail - return exp.mantissa / expScale; - } - - /** - * @dev Multiply an Exp by a scalar, then truncate to return an unsigned integer. - */ - function mul_ScalarTruncate(Exp memory a, uint scalar) pure internal returns (uint) { - Exp memory product = mul_(a, scalar); - return truncate(product); - } - - /** - * @dev Multiply an Exp by a scalar, truncate, then add an to an unsigned integer, returning an unsigned integer. - */ - function mul_ScalarTruncateAddUInt(Exp memory a, uint scalar, uint addend) pure internal returns (uint) { - Exp memory product = mul_(a, scalar); - return add_(truncate(product), addend); - } - - /** - * @dev Checks if first Exp is less than second Exp. - */ - function lessThanExp(Exp memory left, Exp memory right) pure internal returns (bool) { - return left.mantissa < right.mantissa; - } - - /** - * @dev Checks if left Exp <= right Exp. - */ - function lessThanOrEqualExp(Exp memory left, Exp memory right) pure internal returns (bool) { - return left.mantissa <= right.mantissa; - } - - /** - * @dev Checks if left Exp > right Exp. - */ - function greaterThanExp(Exp memory left, Exp memory right) pure internal returns (bool) { - return left.mantissa > right.mantissa; - } - - /** - * @dev returns true if Exp is exactly zero - */ - function isZeroExp(Exp memory value) pure internal returns (bool) { - return value.mantissa == 0; - } - - function safe224(uint n, string memory errorMessage) pure internal returns (uint224) { - require(n < 2**224, errorMessage); - return uint224(n); - } - - function safe32(uint n, string memory errorMessage) pure internal returns (uint32) { - require(n < 2**32, errorMessage); - return uint32(n); - } - - function add_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { - return Exp({mantissa: add_(a.mantissa, b.mantissa)}); - } - - function add_(Double memory a, Double memory b) pure internal returns (Double memory) { - return Double({mantissa: add_(a.mantissa, b.mantissa)}); - } - - function add_(uint a, uint b) pure internal returns (uint) { - return add_(a, b, "addition overflow"); - } - - function add_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { - uint c = a + b; - require(c >= a, errorMessage); - return c; - } - - function sub_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { - return Exp({mantissa: sub_(a.mantissa, b.mantissa)}); - } - - function sub_(Double memory a, Double memory b) pure internal returns (Double memory) { - return Double({mantissa: sub_(a.mantissa, b.mantissa)}); - } - - function sub_(uint a, uint b) pure internal returns (uint) { - return sub_(a, b, "subtraction underflow"); - } - - function sub_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { - require(b <= a, errorMessage); - return a - b; - } - - function mul_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { - return Exp({mantissa: mul_(a.mantissa, b.mantissa) / expScale}); - } - - function mul_(Exp memory a, uint b) pure internal returns (Exp memory) { - return Exp({mantissa: mul_(a.mantissa, b)}); - } - - function mul_(uint a, Exp memory b) pure internal returns (uint) { - return mul_(a, b.mantissa) / expScale; - } - - function mul_(Double memory a, Double memory b) pure internal returns (Double memory) { - return Double({mantissa: mul_(a.mantissa, b.mantissa) / doubleScale}); - } - - function mul_(Double memory a, uint b) pure internal returns (Double memory) { - return Double({mantissa: mul_(a.mantissa, b)}); - } - - function mul_(uint a, Double memory b) pure internal returns (uint) { - return mul_(a, b.mantissa) / doubleScale; - } - - function mul_(uint a, uint b) pure internal returns (uint) { - return mul_(a, b, "multiplication overflow"); - } - - function mul_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { - if (a == 0 || b == 0) { - return 0; - } - uint c = a * b; - require(c / a == b, errorMessage); - return c; - } - - function div_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { - return Exp({mantissa: div_(mul_(a.mantissa, expScale), b.mantissa)}); - } - - function div_(Exp memory a, uint b) pure internal returns (Exp memory) { - return Exp({mantissa: div_(a.mantissa, b)}); - } - - function div_(uint a, Exp memory b) pure internal returns (uint) { - return div_(mul_(a, expScale), b.mantissa); - } - - function div_(Double memory a, Double memory b) pure internal returns (Double memory) { - return Double({mantissa: div_(mul_(a.mantissa, doubleScale), b.mantissa)}); - } - - function div_(Double memory a, uint b) pure internal returns (Double memory) { - return Double({mantissa: div_(a.mantissa, b)}); - } - - function div_(uint a, Double memory b) pure internal returns (uint) { - return div_(mul_(a, doubleScale), b.mantissa); - } - - function div_(uint a, uint b) pure internal returns (uint) { - return div_(a, b, "divide by zero"); - } - - function div_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { - require(b > 0, errorMessage); - return a / b; - } - - function fraction(uint a, uint b) pure internal returns (Double memory) { - return Double({mantissa: div_(mul_(a, doubleScale), b)}); - } -} - - -// Dependency file: contracts/Exponential.sol - -// pragma solidity 0.8.6; - -// import "contracts/CarefulMath.sol"; -// import "contracts/ExponentialNoError.sol"; - -/** - * @title Exponential module for storing fixed-precision decimals - * @author tropykus - * @dev Legacy contract for compatibility reasons with existing contracts that still use MathError - * @notice Exp is a struct which stores decimals with a fixed precision of 18 decimal places. - * Thus, if we wanted to store the 5.1, mantissa would store 5.1e18. That is: - * `Exp({mantissa: 5100000000000000000})`. - */ -contract Exponential is CarefulMath, ExponentialNoError { - /** - * @dev Creates an exponential from numerator and denominator values. - * Note: Returns an error if (`num` * 10e18) > MAX_INT, - * or if `denom` is zero. - */ - function getExp(uint num, uint denom) internal pure returns (MathError, Exp memory) { - (MathError err0, uint scaledNumerator) = mulUInt(num, expScale); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - - (MathError err1, uint rational) = divUInt(scaledNumerator, denom); - if (err1 != MathError.NO_ERROR) { - return (err1, Exp({mantissa: 0})); - } - - return (MathError.NO_ERROR, Exp({mantissa: rational})); - } - - /** - * @dev Adds two exponentials, returning a new exponential. - */ - function addExp(Exp memory a, Exp memory b) internal pure returns (MathError, Exp memory) { - (MathError error, uint result) = addUInt(a.mantissa, b.mantissa); - - return (error, Exp({mantissa: result})); - } - - /** - * @dev Subtracts two exponentials, returning a new exponential. - */ - function subExp(Exp memory a, Exp memory b) internal pure returns (MathError, Exp memory) { - (MathError error, uint result) = subUInt(a.mantissa, b.mantissa); - - return (error, Exp({mantissa: result})); - } - - /** - * @dev Multiply an Exp by a scalar, returning a new Exp. - */ - function mulScalar(Exp memory a, uint scalar) internal pure returns (MathError, Exp memory) { - (MathError err0, uint scaledMantissa) = mulUInt(a.mantissa, scalar); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - - return (MathError.NO_ERROR, Exp({mantissa: scaledMantissa})); - } - - /** - * @dev Multiply an Exp by a scalar, then truncate to return an unsigned integer. - */ - function mulScalarTruncate(Exp memory a, uint scalar) internal pure returns (MathError, uint) { - (MathError err, Exp memory product) = mulScalar(a, scalar); - if (err != MathError.NO_ERROR) { - return (err, 0); - } - - return (MathError.NO_ERROR, truncate(product)); - } - - /** - * @dev Multiply an Exp by a scalar, truncate, then add an to an unsigned integer, returning an unsigned integer. - */ - function mulScalarTruncateAddUInt(Exp memory a, uint scalar, uint addend) internal pure returns (MathError, uint) { - (MathError err, Exp memory product) = mulScalar(a, scalar); - if (err != MathError.NO_ERROR) { - return (err, 0); - } - - return addUInt(truncate(product), addend); - } - - /** - * @dev Divide an Exp by a scalar, returning a new Exp. - */ - function divScalar(Exp memory a, uint scalar) internal pure returns (MathError, Exp memory) { - (MathError err0, uint descaledMantissa) = divUInt(a.mantissa, scalar); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - - return (MathError.NO_ERROR, Exp({mantissa: descaledMantissa})); - } - - /** - * @dev Divide a scalar by an Exp, returning a new Exp. - */ - function divScalarByExp(uint scalar, Exp memory divisor) internal pure returns (MathError, Exp memory) { - /* - We are doing this as: - getExp(mulUInt(expScale, scalar), divisor.mantissa) - - How it works: - Exp = a / b; - Scalar = s; - `s / (a / b)` = `b * s / a` and since for an Exp `a = mantissa, b = expScale` - */ - (MathError err0, uint numerator) = mulUInt(expScale, scalar); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - return getExp(numerator, divisor.mantissa); - } - - /** - * @dev Divide a scalar by an Exp, then truncate to return an unsigned integer. - */ - function divScalarByExpTruncate(uint scalar, Exp memory divisor) internal pure returns (MathError, uint) { - (MathError err, Exp memory fraction) = divScalarByExp(scalar, divisor); - if (err != MathError.NO_ERROR) { - return (err, 0); - } - - return (MathError.NO_ERROR, truncate(fraction)); - } - - /** - * @dev Multiplies two exponentials, returning a new exponential. - */ - function mulExp(Exp memory a, Exp memory b) internal pure returns (MathError, Exp memory) { - - (MathError err0, uint doubleScaledProduct) = mulUInt(a.mantissa, b.mantissa); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - - // We add half the scale before dividing so that we get rounding instead of truncation. - // See "Listing 6" and text above it at https://accu.org/index.php/journals/1717 - // Without this change, a result like 6.6...e-19 will be truncated to 0 instead of being rounded to 1e-18. - (MathError err1, uint doubleScaledProductWithHalfScale) = addUInt(halfExpScale, doubleScaledProduct); - if (err1 != MathError.NO_ERROR) { - return (err1, Exp({mantissa: 0})); - } - - (MathError err2, uint product) = divUInt(doubleScaledProductWithHalfScale, expScale); - // The only error `div` can return is MathError.DIVISION_BY_ZERO but we control `expScale` and it is not zero. - assert(err2 == MathError.NO_ERROR); - - return (MathError.NO_ERROR, Exp({mantissa: product})); - } - - /** - * @dev Multiplies two exponentials given their mantissas, returning a new exponential. - */ - function mulExp(uint a, uint b) internal pure returns (MathError, Exp memory) { - return mulExp(Exp({mantissa: a}), Exp({mantissa: b})); - } - - /** - * @dev Multiplies three exponentials, returning a new exponential. - */ - function mulExp3(Exp memory a, Exp memory b, Exp memory c) internal pure returns (MathError, Exp memory) { - (MathError err, Exp memory ab) = mulExp(a, b); - if (err != MathError.NO_ERROR) { - return (err, ab); - } - return mulExp(ab, c); - } - - /** - * @dev Divides two exponentials, returning a new exponential. - * (a/scale) / (b/scale) = (a/scale) * (scale/b) = a/b, - * which we can scale as an Exp by calling getExp(a.mantissa, b.mantissa) - */ - function divExp(Exp memory a, Exp memory b) internal pure returns (MathError, Exp memory) { - return getExp(a.mantissa, b.mantissa); - } -} - - -// Dependency file: contracts/SafeMath.sol - -// pragma solidity 0.8.6; - -// From https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/math/Math.sol -// Subject to the MIT license. - -/** - * @dev Wrappers over Solidity's arithmetic operations with added overflow - * checks. - * - * Arithmetic operations in Solidity wrap on overflow. This can easily result - * in bugs, because programmers usually assume that an overflow raises an - * error, which is the standard behavior in high level programming languages. - * `SafeMath` restores this intuition by reverting the transaction when an - * operation overflows. - * - * Using this library instead of the unchecked operations eliminates an entire - * class of bugs, so it's recommended to use it always. - */ -library SafeMath { - /** - * @dev Returns the addition of two unsigned integers, reverting on overflow. - * - * Counterpart to Solidity's `+` operator. - * - * Requirements: - * - Addition cannot overflow. - */ - function add(uint256 a, uint256 b) internal pure returns (uint256) { - uint256 c = a + b; - require(c >= a, "SafeMath: addition overflow"); - - return c; - } - - /** - * @dev Returns the addition of two unsigned integers, reverting with custom message on overflow. - * - * Counterpart to Solidity's `+` operator. - * - * Requirements: - * - Addition cannot overflow. - */ - function add(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - uint256 c = a + b; - require(c >= a, errorMessage); - - return c; - } - - /** - * @dev Returns the subtraction of two unsigned integers, reverting on underflow (when the result is negative). - * - * Counterpart to Solidity's `-` operator. - * - * Requirements: - * - Subtraction cannot underflow. - */ - function sub(uint256 a, uint256 b) internal pure returns (uint256) { - return sub(a, b, "SafeMath: subtraction underflow"); - } - - /** - * @dev Returns the subtraction of two unsigned integers, reverting with custom message on underflow (when the result is negative). - * - * Counterpart to Solidity's `-` operator. - * - * Requirements: - * - Subtraction cannot underflow. - */ - function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - require(b <= a, errorMessage); - uint256 c = a - b; - - return c; - } - - /** - * @dev Returns the multiplication of two unsigned integers, reverting on overflow. - * - * Counterpart to Solidity's `*` operator. - * - * Requirements: - * - Multiplication cannot overflow. - */ - function mul(uint256 a, uint256 b) internal pure returns (uint256) { - // Gas optimization: this is cheaper than requiring 'a' not being zero, but the - // benefit is lost if 'b' is also tested. - // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 - if (a == 0) { - return 0; - } - - uint256 c = a * b; - require(c / a == b, "SafeMath: multiplication overflow"); - - return c; - } - - /** - * @dev Returns the multiplication of two unsigned integers, reverting on overflow. - * - * Counterpart to Solidity's `*` operator. - * - * Requirements: - * - Multiplication cannot overflow. - */ - function mul(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - // Gas optimization: this is cheaper than requiring 'a' not being zero, but the - // benefit is lost if 'b' is also tested. - // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 - if (a == 0) { - return 0; - } - - uint256 c = a * b; - require(c / a == b, errorMessage); - - return c; - } - - /** - * @dev Returns the integer division of two unsigned integers. - * Reverts on division by zero. The result is rounded towards zero. - * - * Counterpart to Solidity's `/` operator. Note: this function uses a - * `revert` opcode (which leaves remaining gas untouched) while Solidity - * uses an invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function div(uint256 a, uint256 b) internal pure returns (uint256) { - return div(a, b, "SafeMath: division by zero"); - } - - /** - * @dev Returns the integer division of two unsigned integers. - * Reverts with custom message on division by zero. The result is rounded towards zero. - * - * Counterpart to Solidity's `/` operator. Note: this function uses a - * `revert` opcode (which leaves remaining gas untouched) while Solidity - * uses an invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - // Solidity only automatically asserts when dividing by 0 - require(b > 0, errorMessage); - uint256 c = a / b; - // assert(a == b * c + a % b); // There is no case in which this doesn't hold - - return c; - } - - /** - * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), - * Reverts when dividing by zero. - * - * Counterpart to Solidity's `%` operator. This function uses a `revert` - * opcode (which leaves remaining gas untouched) while Solidity uses an - * invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function mod(uint256 a, uint256 b) internal pure returns (uint256) { - return mod(a, b, "SafeMath: modulo by zero"); - } - - /** - * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), - * Reverts with custom message when dividing by zero. - * - * Counterpart to Solidity's `%` operator. This function uses a `revert` - * opcode (which leaves remaining gas untouched) while Solidity uses an - * invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - require(b != 0, errorMessage); - return a % b; - } -} - - -// Dependency file: contracts/InterestRateModel.sol - -// pragma solidity 0.8.6; - -// import "contracts/Exponential.sol"; -// import "contracts/SafeMath.sol"; - -/** - * @title tropykus InterestRateModel Interface - * @author tropykus - */ -abstract contract InterestRateModel is Exponential { - using SafeMath for uint256; - - /// @notice Indicator that this is an InterestRateModel contract (for inspection) - bool public constant isInterestRateModel = true; - bool public isTropykusInterestRateModel; - - /** - * @notice The approximate number of blocks per year that is assumed by the interest rate model - */ - uint256 public constant blocksPerYear = 1051200; - - /** - * @notice Calculates the utilization rate of the market: `borrows / (cash + borrows - reserves)` - * @param cash The amount of cash in the market - * @param borrows The amount of borrows in the market - * @param reserves The amount of reserves in the market (currently unused) - * @return The utilization rate as a mantissa between [0, 1e18] - */ - function utilizationRate( - uint256 cash, - uint256 borrows, - uint256 reserves - ) public pure virtual returns (uint256) { - // Utilization rate is 0 when there are no borrows - if (borrows == 0) { - return 0; - } - - return borrows.mul(1e18).div(cash.add(borrows).sub(reserves)); - } - - /** - * @notice Calculates the current borrow interest rate per block - * @param cash The total amount of cash the market has - * @param borrows The total amount of borrows the market has outstanding - * @param reserves The total amnount of reserves the market has - * @return The borrow rate per block (as a percentage, and scaled by 1e18) - */ - function getBorrowRate( - uint256 cash, - uint256 borrows, - uint256 reserves - ) external view virtual returns (uint256); - - /** - * @notice Calculates the current supply interest rate per block - * @param cash The total amount of cash the market has - * @param borrows The total amount of borrows the market has outstanding - * @param reserves The total amnount of reserves the market has - * @param reserveFactorMantissa The current reserve factor the market has - * @return The supply rate per block (as a percentage, and scaled by 1e18) - */ - function getSupplyRate( - uint256 cash, - uint256 borrows, - uint256 reserves, - uint256 reserveFactorMantissa - ) external view virtual returns (uint256); - - function getExchangeRate( - uint256 _totalCash, - uint256 _totalBorrows, - uint256 _totalReserves, - uint256 _totalSupply - ) public pure returns (MathError, uint256) { - /* - * exchangeRate = (totalCash + totalBorrows - totalReserves) / totalSupply - */ - Exp memory exchangeRate; - MathError mathErr; - uint256 cashPlusBorrowsMinusReserves; - (mathErr, cashPlusBorrowsMinusReserves) = addThenSubUInt( - _totalCash, - _totalBorrows, - _totalReserves - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - (mathErr, exchangeRate) = getExp( - cashPlusBorrowsMinusReserves, - _totalSupply - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - - return (MathError.NO_ERROR, exchangeRate.mantissa); - } - - function isAboveOptimal( - uint256 cash, - uint256 borrows, - uint256 reserves - ) public view virtual returns (bool) { - cash; - borrows; - reserves; - return false; - } -} - - -// Dependency file: contracts/EIP20NonStandardInterface.sol - -// pragma solidity 0.8.6; - -/** - * @title EIP20NonStandardInterface - * @dev Version of ERC20 with no return values for `transfer` and `transferFrom` - * See https://medium.com/coinmonks/missing-return-value-bug-at-least-130-tokens-affected-d67bf08521ca - */ -interface EIP20NonStandardInterface { - /** - * @notice Get the total number of tokens in circulation - * @return The supply of tokens - */ - function totalSupply() external view returns (uint256); - - /** - * @notice Gets the balance of the specified address - * @param owner The address from which the balance will be retrieved - * @return balance The balance - */ - function balanceOf(address owner) external view returns (uint256 balance); - - /// - /// !!!!!!!!!!!!!! - /// !!! NOTICE !!! `transfer` does not return a value, in violation of the ERC-20 specification - /// !!!!!!!!!!!!!! - /// - - /** - * @notice Transfer `amount` tokens from `msg.sender` to `dst` - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - */ - function transfer(address dst, uint256 amount) external; - - /// - /// !!!!!!!!!!!!!! - /// !!! NOTICE !!! `transferFrom` does not return a value, in violation of the ERC-20 specification - /// !!!!!!!!!!!!!! - /// - - /** - * @notice Transfer `amount` tokens from `src` to `dst` - * @param src The address of the source account - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - */ - function transferFrom( - address src, - address dst, - uint256 amount - ) external; - - /** - * @notice Approve `spender` to transfer up to `amount` from `src` - * @dev This will overwrite the approval amount for `spender` - * and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve) - * @param spender The address of the account which may transfer tokens - * @param amount The number of tokens that are approved - * @return success Whether or not the approval succeeded - */ - function approve(address spender, uint256 amount) - external - returns (bool success); - - /** - * @notice Get the current allowance from `owner` for `spender` - * @param owner The address of the account which owns the tokens to be spent - * @param spender The address of the account which may transfer tokens - * @return remaining The number of tokens allowed to be spent - */ - function allowance(address owner, address spender) - external - view - returns (uint256 remaining); - - event Transfer(address indexed from, address indexed to, uint256 amount); - event Approval( - address indexed owner, - address indexed spender, - uint256 amount - ); -} - - -// Dependency file: contracts/CTokenInterfaces.sol - -// pragma solidity 0.8.6; - -// import "contracts/ComptrollerInterface.sol"; -// import "contracts/InterestRateModel.sol"; -// import "contracts/EIP20NonStandardInterface.sol"; - -contract CTokenStorage { - /** - * @dev Guard variable for re-entrancy checks - */ - bool internal _notEntered; - - /** - * @notice EIP-20 token name for this token - */ - string public name; - - /** - * @notice EIP-20 token symbol for this token - */ - string public symbol; - - /** - * @notice EIP-20 token decimals for this token - */ - uint8 public decimals; - - /** - * @notice Maximum borrow rate that can ever be applied (.0005% / block) - */ - - uint256 internal constant borrowRateMaxMantissa = 0.0005e16; - - /** - * @notice Maximum fraction of interest that can be set aside for reserves - */ - uint256 internal constant reserveFactorMaxMantissa = 1e18; - - /** - * @notice Administrator for this contract - */ - address payable public admin; - - /** - * @notice Pending administrator for this contract - */ - address payable public pendingAdmin; - - /** - * @notice Contract which oversees inter-cToken operations - */ - ComptrollerInterface public comptroller; - - /** - * @notice Model which tells what the current interest rate should be - */ - InterestRateModel public interestRateModel; - - /** - * @notice Initial exchange rate used when minting the first CTokens (used when totalSupply = 0) - */ - uint256 public initialExchangeRateMantissa; - - /** - * @notice Fraction of interest currently set aside for reserves - */ - uint256 public reserveFactorMantissa; - - /** - * @notice Block number that interest was last accrued at - */ - uint256 public accrualBlockNumber; - - /** - * @notice Accumulator of the total earned interest rate since the opening of the market - */ - uint256 public borrowIndex; - - /** - * @notice Total amount of outstanding borrows of the underlying in this market - */ - uint256 public totalBorrows; - - /** - * @notice Total amount of reserves of the underlying held in this market - */ - uint256 public totalReserves; - - /** - * @notice Total number of tokens in circulation - */ - uint256 public totalSupply; - - uint256 public subsidyFund; - - struct SupplySnapshot { - uint256 tokens; - uint256 underlyingAmount; - uint256 suppliedAt; - uint256 promisedSupplyRate; - } - - /** - * @notice Official record of token balances for each account - */ - mapping(address => SupplySnapshot) internal accountTokens; - - /** - * @notice Approved token transfer amounts on behalf of others - */ - mapping(address => mapping(address => uint256)) internal transferAllowances; - - /** - * @notice Container for borrow balance information - * @member principal Total balance (with accrued interest), after applying the most recent balance-changing action - * @member interestIndex Global borrowIndex as of the most recent balance-changing action - */ - struct BorrowSnapshot { - uint256 principal; - uint256 interestIndex; - } - - /** - * @notice Mapping of account addresses to outstanding borrow balances - */ - mapping(address => BorrowSnapshot) internal accountBorrows; -} - -abstract contract CTokenInterface is CTokenStorage { - /** - * @notice Indicator that this is a CToken contract (for inspection) - */ - bool public constant isCToken = true; - - /*** Market Events ***/ - - /** - * @notice Event emitted when interest is accrued - */ - event AccrueInterest( - uint256 cashPrior, - uint256 interestAccumulated, - uint256 borrowIndex, - uint256 totalBorrows - ); - - /** - * @notice Event emitted when tokens are minted - */ - event Mint(address indexed minter, uint256 mintAmount, uint256 mintTokens); - - /** - * @notice Event emitted when tokens are redeemed - */ - event Redeem( - address indexed redeemer, - uint256 redeemAmount, - uint256 redeemTokens - ); - - /** - * @notice Event emitted when underlying is borrowed - */ - event Borrow( - address indexed borrower, - uint256 borrowAmount, - uint256 accountBorrows, - uint256 totalBorrows - ); - - /** - * @notice Event emitted when a borrow is repaid - */ - event RepayBorrow( - address indexed payer, - address indexed borrower, - uint256 repayAmount, - uint256 accountBorrows, - uint256 totalBorrows - ); - - /** - * @notice Event emitted when a borrow is liquidated - */ - event LiquidateBorrow( - address indexed liquidator, - address indexed borrower, - uint256 repayAmount, - address indexed cTokenCollateral, - uint256 seizeTokens - ); - - /*** Admin Events ***/ - - /** - * @notice Event emitted when pendingAdmin is changed - */ - event NewPendingAdmin(address oldPendingAdmin, address newPendingAdmin); - - /** - * @notice Event emitted when pendingAdmin is accepted, which means admin is updated - */ - event NewAdmin(address oldAdmin, address newAdmin); - - /** - * @notice Event emitted when comptroller is changed - */ - event NewComptroller( - ComptrollerInterface oldComptroller, - ComptrollerInterface newComptroller - ); - - /** - * @notice Event emitted when interestRateModel is changed - */ - event NewMarketInterestRateModel( - InterestRateModel oldInterestRateModel, - InterestRateModel newInterestRateModel - ); - - /** - * @notice Event emitted when the reserve factor is changed - */ - event NewReserveFactor( - uint256 oldReserveFactorMantissa, - uint256 newReserveFactorMantissa - ); - - /** - * @notice Event emitted when the reserves are added - */ - event ReservesAdded( - address benefactor, - uint256 addAmount, - uint256 newTotalReserves - ); - - event SubsidyAdded( - address benefactor, - uint256 addAmount, - uint256 newSubsidyFund - ); - - /** - * @notice Event emitted when the reserves are reduced - */ - event ReservesReduced( - address admin, - uint256 reduceAmount, - uint256 newTotalReserves - ); - - /** - * @notice EIP20 Transfer event - */ - event Transfer(address indexed from, address indexed to, uint256 amount); - - /** - * @notice EIP20 Approval event - */ - event Approval( - address indexed owner, - address indexed spender, - uint256 amount - ); - - /** - * @notice Failure event - */ - event CTokenStorageFailure(uint256 error, uint256 info, uint256 detail); - - /*** User Interface ***/ - - function transfer(address dst, uint256 amount) - external - virtual - returns (bool); - - function transferFrom( - address src, - address dst, - uint256 amount - ) external virtual returns (bool); - - function approve(address spender, uint256 amount) - external - virtual - returns (bool); - - function allowance(address owner, address spender) - external - view - virtual - returns (uint256); - - function balanceOf(address owner) external view virtual returns (uint256); - - function balanceOfUnderlying(address owner) - external - virtual - returns (uint256); - - function getAccountSnapshot(address account) - external - view - virtual - returns ( - uint256, - uint256, - uint256, - uint256 - ); - - function borrowRatePerBlock() external view virtual returns (uint256); - - function supplyRatePerBlock() external view virtual returns (uint256); - - function totalBorrowsCurrent() external virtual returns (uint256); - - function borrowBalanceCurrent(address account) - external - virtual - returns (uint256); - - function borrowBalanceStored(address account) - public - view - virtual - returns (uint256); - - function exchangeRateCurrent() public virtual returns (uint256); - - function exchangeRateStored() public view virtual returns (uint256); - - function getCash() external view virtual returns (uint256); - - function accrueInterest() public virtual returns (uint256); - - function seize( - address liquidator, - address borrower, - uint256 seizeTokens - ) external virtual returns (uint256); - - /*** Admin Functions ***/ - - function _setPendingAdmin(address payable newPendingAdmin) - external - virtual - returns (uint256); - - function _acceptAdmin() external virtual returns (uint256); - - function _setComptroller(ComptrollerInterface newComptroller) - public - virtual - returns (uint256); - - function _setReserveFactor(uint256 newReserveFactorMantissa) - external - virtual - returns (uint256); - - function _reduceReserves(uint256 reduceAmount) - external - virtual - returns (uint256); - - function _setInterestRateModel(InterestRateModel newInterestRateModel) - public - virtual - returns (uint256); -} - -contract CErc20Storage { - /** - * @notice Underlying asset for this CToken - */ - address public underlying; -} - -abstract contract CErc20Interface is CErc20Storage { - /*** User Interface ***/ - - function mint(uint256 mintAmount) external virtual returns (uint256); - - function redeem(uint256 redeemAmount) - external - virtual - returns (uint256); - - function borrow(uint256 borrowAmount) external virtual returns (uint256); - - function repayBorrow(uint256 repayAmount) - external - virtual - returns (uint256); - - function liquidateBorrow( - address borrower, - uint256 repayAmount, - CTokenInterface cTokenCollateral - ) external virtual returns (uint256); - - function sweepToken(EIP20NonStandardInterface token) external virtual; - - /*** Admin Functions ***/ - - function _addReserves(uint256 addAmount) external virtual returns (uint256); -} - -contract CDelegationStorage { - /** - * @notice Implementation address for this contract - */ - address public implementation; -} - -abstract contract CDelegatorInterface is CDelegationStorage { - /** - * @notice Emitted when implementation is changed - */ - event NewImplementation( - address oldImplementation, - address newImplementation - ); - - /** - * @notice Called by the admin to update the implementation of the delegator - * @param implementation_ The address of the new implementation for delegation - * @param allowResign Flag to indicate whether to call _resignImplementation on the old implementation - * @param becomeImplementationData The encoded bytes data to be passed to _becomeImplementation - */ - function _setImplementation( - address implementation_, - bool allowResign, - bytes memory becomeImplementationData - ) public virtual; -} - -abstract contract CDelegateInterface is CDelegationStorage { - /** - * @notice Called by the delegator on a delegate to initialize it for duty - * @dev Should revert if any issues arise which make it unfit for delegation - * @param data The encoded bytes data for any initialization - */ - function _becomeImplementation(bytes memory data) public virtual; - - /** - * @notice Called by the delegator on a delegate to forfeit its responsibility - */ - function _resignImplementation() public virtual; -} - - -// Dependency file: contracts/ErrorReporter.sol - -// pragma solidity 0.8.6; - -contract ComptrollerErrorReporter { - enum Error { - NO_ERROR, - UNAUTHORIZED, - COMPTROLLER_MISMATCH, - INSUFFICIENT_SHORTFALL, - INSUFFICIENT_LIQUIDITY, - INVALID_CLOSE_FACTOR, - INVALID_COLLATERAL_FACTOR, - INVALID_LIQUIDATION_INCENTIVE, - MARKET_NOT_ENTERED, // no longer possible - MARKET_NOT_LISTED, - MARKET_ALREADY_LISTED, - MATH_ERROR, - NONZERO_BORROW_BALANCE, - PRICE_ERROR, - REJECTION, - SNAPSHOT_ERROR, - TOO_MANY_ASSETS, - TOO_MUCH_REPAY - } - - enum FailureInfo { - ACCEPT_ADMIN_PENDING_ADMIN_CHECK, - ACCEPT_PENDING_IMPLEMENTATION_ADDRESS_CHECK, - EXIT_MARKET_BALANCE_OWED, - EXIT_MARKET_REJECTION, - SET_CLOSE_FACTOR_OWNER_CHECK, - SET_CLOSE_FACTOR_VALIDATION, - SET_COLLATERAL_FACTOR_OWNER_CHECK, - SET_COLLATERAL_FACTOR_NO_EXISTS, - SET_COLLATERAL_FACTOR_VALIDATION, - SET_COLLATERAL_FACTOR_WITHOUT_PRICE, - SET_IMPLEMENTATION_OWNER_CHECK, - SET_LIQUIDATION_INCENTIVE_OWNER_CHECK, - SET_LIQUIDATION_INCENTIVE_VALIDATION, - SET_MAX_ASSETS_OWNER_CHECK, - SET_PENDING_ADMIN_OWNER_CHECK, - SET_PENDING_IMPLEMENTATION_OWNER_CHECK, - SET_PRICE_ORACLE_OWNER_CHECK, - SUPPORT_MARKET_EXISTS, - SUPPORT_MARKET_OWNER_CHECK, - SET_PAUSE_GUARDIAN_OWNER_CHECK - } - - /** - * @dev `error` corresponds to enum Error; `info` corresponds to enum FailureInfo, and `detail` is an arbitrary - * contract-specific code that enables us to report opaque error codes from upgradeable contracts. - **/ - event Failure(uint256 error, uint256 info, uint256 detail); - - /** - * @dev use this when reporting a known error from the money market or a non-upgradeable collaborator - */ - function fail(Error err, FailureInfo info) internal returns (uint256) { - emit Failure(uint256(err), uint256(info), 0); - - return uint256(err); - } - - /** - * @dev use this when reporting an opaque error from an upgradeable collaborator contract - */ - function failOpaque( - Error err, - FailureInfo info, - uint256 opaqueError - ) internal returns (uint256) { - emit Failure(uint256(err), uint256(info), opaqueError); - - return uint256(err); - } -} - -contract TokenErrorReporter { - enum Error { - NO_ERROR, - UNAUTHORIZED, - BAD_INPUT, - COMPTROLLER_REJECTION, - COMPTROLLER_CALCULATION_ERROR, - INTEREST_RATE_MODEL_ERROR, - INVALID_ACCOUNT_PAIR, - INVALID_CLOSE_AMOUNT_REQUESTED, - INVALID_COLLATERAL_FACTOR, - MATH_ERROR, - MARKET_NOT_FRESH, - MARKET_NOT_LISTED, - TOKEN_INSUFFICIENT_ALLOWANCE, - TOKEN_INSUFFICIENT_BALANCE, - TOKEN_INSUFFICIENT_CASH, - TOKEN_TRANSFER_IN_FAILED, - TOKEN_TRANSFER_OUT_FAILED - } - - /* - * Note: FailureInfo (but not Error) is kept in alphabetical order - * This is because FailureInfo grows significantly faster, and - * the order of Error has some meaning, while the order of FailureInfo - * is entirely arbitrary. - */ - enum FailureInfo { - ACCEPT_ADMIN_PENDING_ADMIN_CHECK, - ACCRUE_INTEREST_ACCUMULATED_INTEREST_CALCULATION_FAILED, - ACCRUE_INTEREST_BORROW_RATE_CALCULATION_FAILED, - ACCRUE_INTEREST_NEW_BORROW_INDEX_CALCULATION_FAILED, - ACCRUE_INTEREST_NEW_TOTAL_BORROWS_CALCULATION_FAILED, - ACCRUE_INTEREST_NEW_TOTAL_RESERVES_CALCULATION_FAILED, - ACCRUE_INTEREST_SIMPLE_INTEREST_FACTOR_CALCULATION_FAILED, - BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED, - BORROW_ACCRUE_INTEREST_FAILED, - BORROW_CASH_NOT_AVAILABLE, - BORROW_FRESHNESS_CHECK, - BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED, - BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED, - BORROW_MARKET_NOT_LISTED, - BORROW_COMPTROLLER_REJECTION, - LIQUIDATE_ACCRUE_BORROW_INTEREST_FAILED, - LIQUIDATE_ACCRUE_COLLATERAL_INTEREST_FAILED, - LIQUIDATE_COLLATERAL_FRESHNESS_CHECK, - LIQUIDATE_COMPTROLLER_REJECTION, - LIQUIDATE_COMPTROLLER_CALCULATE_AMOUNT_SEIZE_FAILED, - LIQUIDATE_CLOSE_AMOUNT_IS_UINT_MAX, - LIQUIDATE_CLOSE_AMOUNT_IS_ZERO, - LIQUIDATE_FRESHNESS_CHECK, - LIQUIDATE_LIQUIDATOR_IS_BORROWER, - LIQUIDATE_REPAY_BORROW_FRESH_FAILED, - LIQUIDATE_SEIZE_BALANCE_INCREMENT_FAILED, - LIQUIDATE_SEIZE_BALANCE_DECREMENT_FAILED, - LIQUIDATE_SEIZE_COMPTROLLER_REJECTION, - LIQUIDATE_SEIZE_LIQUIDATOR_IS_BORROWER, - LIQUIDATE_SEIZE_TOO_MUCH, - MINT_ACCRUE_INTEREST_FAILED, - MINT_COMPTROLLER_REJECTION, - MINT_EXCHANGE_CALCULATION_FAILED, - MINT_EXCHANGE_RATE_READ_FAILED, - MINT_FRESHNESS_CHECK, - MINT_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED, - MINT_NEW_TOTAL_SUPPLY_CALCULATION_FAILED, - MINT_TRANSFER_IN_FAILED, - MINT_TRANSFER_IN_NOT_POSSIBLE, - REDEEM_ACCRUE_INTEREST_FAILED, - REDEEM_COMPTROLLER_REJECTION, - REDEEM_EXCHANGE_TOKENS_CALCULATION_FAILED, - REDEEM_EXCHANGE_AMOUNT_CALCULATION_FAILED, - REDEEM_EXCHANGE_RATE_READ_FAILED, - REDEEM_FRESHNESS_CHECK, - REDEEM_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED, - REDEEM_NEW_TOTAL_SUPPLY_CALCULATION_FAILED, - REDEEM_TRANSFER_OUT_NOT_POSSIBLE, - REDUCE_RESERVES_ACCRUE_INTEREST_FAILED, - REDUCE_RESERVES_ADMIN_CHECK, - REDUCE_RESERVES_CASH_NOT_AVAILABLE, - REDUCE_RESERVES_FRESH_CHECK, - REDUCE_RESERVES_VALIDATION, - REPAY_BEHALF_ACCRUE_INTEREST_FAILED, - REPAY_BORROW_ACCRUE_INTEREST_FAILED, - REPAY_BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED, - REPAY_BORROW_COMPTROLLER_REJECTION, - REPAY_BORROW_FRESHNESS_CHECK, - REPAY_BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED, - REPAY_BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED, - REPAY_BORROW_TRANSFER_IN_NOT_POSSIBLE, - SET_COLLATERAL_FACTOR_OWNER_CHECK, - SET_COLLATERAL_FACTOR_VALIDATION, - SET_COMPTROLLER_OWNER_CHECK, - SET_INTEREST_RATE_MODEL_ACCRUE_INTEREST_FAILED, - SET_INTEREST_RATE_MODEL_FRESH_CHECK, - SET_INTEREST_RATE_MODEL_OWNER_CHECK, - SET_MAX_ASSETS_OWNER_CHECK, - SET_ORACLE_MARKET_NOT_LISTED, - SET_PENDING_ADMIN_OWNER_CHECK, - SET_RESERVE_FACTOR_ACCRUE_INTEREST_FAILED, - SET_RESERVE_FACTOR_ADMIN_CHECK, - SET_RESERVE_FACTOR_FRESH_CHECK, - SET_RESERVE_FACTOR_BOUNDS_CHECK, - TRANSFER_COMPTROLLER_REJECTION, - TRANSFER_NOT_ALLOWED, - TRANSFER_NOT_ENOUGH, - TRANSFER_TOO_MUCH, - ADD_RESERVES_ACCRUE_INTEREST_FAILED, - ADD_RESERVES_FRESH_CHECK, - ADD_RESERVES_TRANSFER_IN_NOT_POSSIBLE, - ADD_SUBSIDY_FUND_FAILED, - ADD_SUBSIDY_FUND_FRESH_CHECK - } - - /** - * @dev `error` corresponds to enum Error; `info` corresponds to enum FailureInfo, and `detail` is an arbitrary - * contract-specific code that enables us to report opaque error codes from upgradeable contracts. - **/ - event TokenFailure(uint256 error, uint256 info, uint256 detail); - - /** - * @dev use this when reporting a known error from the money market or a non-upgradeable collaborator - */ - function fail(Error err, FailureInfo info) internal returns (uint256) { - emit TokenFailure(uint256(err), uint256(info), 0); - - return uint256(err); - } - - /** - * @dev use this when reporting an opaque error from an upgradeable collaborator contract - */ - function failOpaque( - Error err, - FailureInfo info, - uint256 opaqueError - ) internal returns (uint256) { - emit TokenFailure(uint256(err), uint256(info), opaqueError); - - return uint256(err); - } -} - - -// Dependency file: contracts/EIP20Interface.sol - -// pragma solidity 0.8.6; - -/** - * @title ERC 20 Token Standard Interface - * https://eips.ethereum.org/EIPS/eip-20 - */ -interface EIP20Interface { - function name() external view returns (string memory); - - function symbol() external view returns (string memory); - - function decimals() external view returns (uint8); - - /** - * @notice Get the total number of tokens in circulation - * @return The supply of tokens - */ - function totalSupply() external view returns (uint256); - - /** - * @notice Gets the balance of the specified address - * @param owner The address from which the balance will be retrieved - * @return balance The balance - */ - function balanceOf(address owner) external view returns (uint256 balance); - - /** - * @notice Transfer `amount` tokens from `msg.sender` to `dst` - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - * @return success Whether or not the transfer succeeded - */ - function transfer(address dst, uint256 amount) - external - returns (bool success); - - /** - * @notice Transfer `amount` tokens from `src` to `dst` - * @param src The address of the source account - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - * @return success Whether or not the transfer succeeded - */ - function transferFrom( - address src, - address dst, - uint256 amount - ) external returns (bool success); - - /** - * @notice Approve `spender` to transfer up to `amount` from `src` - * @dev This will overwrite the approval amount for `spender` - * and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve) - * @param spender The address of the account which may transfer tokens - * @param amount The number of tokens that are approved (-1 means infinite) - * @return success Whether or not the approval succeeded - */ - function approve(address spender, uint256 amount) - external - returns (bool success); - - /** - * @notice Get the current allowance from `owner` for `spender` - * @param owner The address of the account which owns the tokens to be spent - * @param spender The address of the account which may transfer tokens - * @return remaining The number of tokens allowed to be spent (-1 means infinite) - */ - function allowance(address owner, address spender) - external - view - returns (uint256 remaining); - - event Transfer(address indexed from, address indexed to, uint256 amount); - event Approval( - address indexed owner, - address indexed spender, - uint256 amount - ); -} - - -// Dependency file: contracts/WhitelistInterface.sol - -// pragma solidity 0.8.6; - -interface WhitelistInterface { - function setStatus(bool _newStatus) external; - function enabled() external view returns(bool); - - function addUsers(address[] memory _users) external; - function exist(address _user) external view returns(bool); - function getUsers() external view returns(address[] memory currentUsers); - function removeUser(address _user) external; -} - -// Dependency file: contracts/CToken.sol - -// pragma solidity 0.8.6; - -// import "contracts/ComptrollerInterface.sol"; -// import "contracts/CTokenInterfaces.sol"; -// import "contracts/ErrorReporter.sol"; -// import "contracts/Exponential.sol"; -// import "contracts/EIP20Interface.sol"; -// import "contracts/InterestRateModel.sol"; -// import "contracts/WhitelistInterface.sol"; - -/** - * @title tropykus CToken Contract - * @notice Abstract base for CTokens - * @author tropykus - */ -abstract contract CToken is CTokenInterface, Exponential, TokenErrorReporter { - address whitelist; - - /** - * @notice Initialize the money market - * @param comptroller_ The address of the Comptroller - * @param interestRateModel_ The address of the interest rate model - * @param initialExchangeRateMantissa_ The initial exchange rate, scaled by 1e18 - * @param name_ EIP-20 name of this token - * @param symbol_ EIP-20 symbol of this token - * @param decimals_ EIP-20 decimal precision of this token - */ - function initialize( - ComptrollerInterface comptroller_, - InterestRateModel interestRateModel_, - uint256 initialExchangeRateMantissa_, - string memory name_, - string memory symbol_, - uint8 decimals_ - ) public { - require(msg.sender == admin, "CT01"); - require(accrualBlockNumber == 0 && borrowIndex == 0, "CT02"); - - initialExchangeRateMantissa = initialExchangeRateMantissa_; - require(initialExchangeRateMantissa > 0, "CT03"); - - uint256 err = _setComptroller(comptroller_); - require(err == uint256(Error.NO_ERROR), "CT04"); - - accrualBlockNumber = getBlockNumber(); - borrowIndex = mantissaOne; - - err = _setInterestRateModelFresh(interestRateModel_); - require(err == uint256(Error.NO_ERROR), "CT05"); - - name = name_; - symbol = symbol_; - decimals = decimals_; - - _notEntered = true; - } - - function addWhitelist(address _whitelist) external returns (uint256) { - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_INTEREST_RATE_MODEL_OWNER_CHECK - ); - } - whitelist = _whitelist; - } - - /** - * @notice Transfer `tokens` tokens from `src` to `dst` by `spender` - * @dev Called by both `transfer` and `transferFrom` internally - * @param spender The address of the account performing the transfer - * @param src The address of the source account - * @param dst The address of the destination account - * @param tokens The number of tokens to transfer - * @return Whether or not the transfer succeeded - */ - function transferTokens( - address spender, - address src, - address dst, - uint256 tokens - ) internal returns (uint256) { - uint256 allowed = comptroller.transferAllowed( - address(this), - src, - dst, - tokens - ); - if (allowed != 0) { - return - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.TRANSFER_COMPTROLLER_REJECTION, - allowed - ); - } - - if (src == dst) { - return fail(Error.BAD_INPUT, FailureInfo.TRANSFER_NOT_ALLOWED); - } - - uint256 startingAllowance = 0; - if (spender == src) { - startingAllowance = type(uint256).max; - } else { - startingAllowance = transferAllowances[src][spender]; - } - - MathError mathErr; - uint256 allowanceNew; - uint256 srcTokensNew; - uint256 dstTokensNew; - - (mathErr, allowanceNew) = subUInt(startingAllowance, tokens); - if (mathErr != MathError.NO_ERROR) { - return fail(Error.MATH_ERROR, FailureInfo.TRANSFER_NOT_ALLOWED); - } - - (mathErr, srcTokensNew) = subUInt(accountTokens[src].tokens, tokens); - if (mathErr != MathError.NO_ERROR) { - return fail(Error.MATH_ERROR, FailureInfo.TRANSFER_NOT_ENOUGH); - } - - (mathErr, dstTokensNew) = addUInt(accountTokens[dst].tokens, tokens); - if (mathErr != MathError.NO_ERROR) { - return fail(Error.MATH_ERROR, FailureInfo.TRANSFER_TOO_MUCH); - } - - accountTokens[src].tokens = srcTokensNew; - accountTokens[dst].tokens = dstTokensNew; - - if (startingAllowance != type(uint256).max) { - transferAllowances[src][spender] = allowanceNew; - } - - emit Transfer(src, dst, tokens); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Transfer `amount` tokens from `msg.sender` to `dst` - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - * @return Whether or not the transfer succeeded - */ - function transfer(address dst, uint256 amount) - external - override - nonReentrant - returns (bool) - { - return - transferTokens(msg.sender, msg.sender, dst, amount) == - uint256(Error.NO_ERROR); - } - - /** - * @notice Transfer `amount` tokens from `src` to `dst` - * @param src The address of the source account - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - * @return Whether or not the transfer succeeded - */ - function transferFrom( - address src, - address dst, - uint256 amount - ) external override nonReentrant returns (bool) { - return - transferTokens(msg.sender, src, dst, amount) == - uint256(Error.NO_ERROR); - } - - /** - * @notice Approve `spender` to transfer up to `amount` from `src` - * @dev This will overwrite the approval amount for `spender` - * and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve) - * @param spender The address of the account which may transfer tokens - * @param amount The number of tokens that are approved (-1 means infinite) - * @return Whether or not the approval succeeded - */ - function approve(address spender, uint256 amount) - external - override - returns (bool) - { - transferAllowances[msg.sender][spender] = amount; - emit Approval(msg.sender, spender, amount); - return true; - } - - /** - * @notice Get the current allowance from `owner` for `spender` - * @param owner The address of the account which owns the tokens to be spent - * @param spender The address of the account which may transfer tokens - * @return The number of tokens allowed to be spent (-1 means infinite) - */ - function allowance(address owner, address spender) - external - view - override - returns (uint256) - { - return transferAllowances[owner][spender]; - } - - /** - * @notice Get the token balance of the `owner` - * @param owner The address of the account to query - * @return The number of tokens owned by `owner` - */ - function balanceOf(address owner) external view override returns (uint256) { - return accountTokens[owner].tokens; - } - - /** - * @notice Get the underlying balance of the `owner` - * @dev This also accrues interest in a transaction - * @param owner The address of the account to query - * @return The amount of underlying owned by `owner` - */ - function balanceOfUnderlying(address owner) - external - override - returns (uint256) - { - (MathError mErr, uint256 balance) = mulScalarTruncate( - Exp({mantissa: exchangeRateCurrent()}), - accountTokens[owner].tokens - ); - require(mErr == MathError.NO_ERROR, "CT06"); - return balance; - } - - /** - * @notice Get a snapshot of the account's balances, and the cached exchange rate - * @dev This is used by comptroller to more efficiently perform liquidity checks. - * @param account Address of the account to snapshot - * @return (possible error, token balance, borrow balance, exchange rate mantissa) - */ - function getAccountSnapshot(address account) - external - view - override - returns ( - uint256, - uint256, - uint256, - uint256 - ) - { - uint256 cTokenBalance = accountTokens[account].tokens; - uint256 borrowBalance; - uint256 exchangeRateMantissa; - - MathError mErr; - - (mErr, borrowBalance) = borrowBalanceStoredInternal(account); - if (mErr != MathError.NO_ERROR) { - return (uint256(Error.MATH_ERROR), 0, 0, 0); - } - - (mErr, exchangeRateMantissa) = exchangeRateStoredInternal(); - if (mErr != MathError.NO_ERROR) { - return (uint256(Error.MATH_ERROR), 0, 0, 0); - } - - return ( - uint256(Error.NO_ERROR), - cTokenBalance, - borrowBalance, - exchangeRateMantissa - ); - } - - /** - * @dev Function to simply retrieve block number - * This exists mainly for inheriting test contracts to stub this result. - */ - function getBlockNumber() internal view virtual returns (uint256) { - return block.number; - } - - /** - * @notice Returns the current per-block borrow interest rate for this cToken - * @return The borrow interest rate per block, scaled by 1e18 - */ - function borrowRatePerBlock() external view override returns (uint256) { - return - interestRateModel.getBorrowRate( - getCashPrior(), - totalBorrows, - totalReserves - ); - } - - /** - * @notice Returns the current per-block supply interest rate for this cToken - * @return The supply interest rate per block, scaled by 1e18 - */ - function supplyRatePerBlock() external view override returns (uint256) { - return - interestRateModel.getSupplyRate( - getCashPrior(), - totalBorrows, - totalReserves, - reserveFactorMantissa - ); - } - - /** - * @notice Returns the current total borrows plus accrued interest - * @return The total borrows with interest - */ - function totalBorrowsCurrent() - external - override - nonReentrant - returns (uint256) - { - require(accrueInterest() == uint256(Error.NO_ERROR), "CT07"); - return totalBorrows; - } - - /** - * @notice Accrue interest to updated borrowIndex and then calculate account's borrow balance using the updated borrowIndex - * @param account The address whose balance should be calculated after updating borrowIndex - * @return The calculated balance - */ - function borrowBalanceCurrent(address account) - external - override - nonReentrant - returns (uint256) - { - require(accrueInterest() == uint256(Error.NO_ERROR), "CT07"); - return borrowBalanceStored(account); - } - - /** - * @notice Return the borrow balance of account based on stored data - * @param account The address whose balance should be calculated - * @return The calculated balance - */ - function borrowBalanceStored(address account) - public - view - override - returns (uint256) - { - (MathError err, uint256 result) = borrowBalanceStoredInternal(account); - require(err == MathError.NO_ERROR, "CT08"); - return result; - } - - /** - * @notice Return the borrow balance of account based on stored data - * @param account The address whose balance should be calculated - * @return (error code, the calculated balance or 0 if error code is non-zero) - */ - function borrowBalanceStoredInternal(address account) - internal - view - returns (MathError, uint256) - { - MathError mathErr; - uint256 principalTimesIndex; - uint256 result; - - BorrowSnapshot storage borrowSnapshot = accountBorrows[account]; - - if (borrowSnapshot.principal == 0) { - return (MathError.NO_ERROR, 0); - } - - (mathErr, principalTimesIndex) = mulUInt( - borrowSnapshot.principal, - borrowIndex - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - - (mathErr, result) = divUInt( - principalTimesIndex, - borrowSnapshot.interestIndex - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - - return (MathError.NO_ERROR, result); - } - - function getBorrowerPrincipalStored(address account) - public - view - returns (uint256 borrowed) - { - borrowed = accountBorrows[account].principal; - } - - function getSupplierSnapshotStored(address account) - public - view - returns ( - uint256 tokens, - uint256 underlyingAmount, - uint256 suppliedAt, - uint256 promisedSupplyRate - ) - { - tokens = accountTokens[account].tokens; - underlyingAmount = accountTokens[account].underlyingAmount; - suppliedAt = accountTokens[account].suppliedAt; - promisedSupplyRate = accountTokens[account].promisedSupplyRate; - } - - /** - * @notice Accrue interest then return the up-to-date exchange rate - * @return Calculated exchange rate scaled by 1e18 - */ - function exchangeRateCurrent() - public - override - nonReentrant - returns (uint256) - { - require(accrueInterest() == uint256(Error.NO_ERROR), "CT07"); - return exchangeRateStored(); - } - - /** - * @notice Calculates the exchange rate from the underlying to the CToken - * @dev This function does not accrue interest before calculating the exchange rate - * @return Calculated exchange rate scaled by 1e18 - */ - function exchangeRateStored() public view override returns (uint256) { - (MathError err, uint256 result) = exchangeRateStoredInternal(); - require(err == MathError.NO_ERROR, "CT09"); - return result; - } - - /** - * @notice Calculates the exchange rate from the underlying to the CToken - * @dev This function does not accrue interest before calculating the exchange rate - * @return (error code, calculated exchange rate scaled by 1e18) - */ - function exchangeRateStoredInternal() - internal - view - virtual - returns (MathError, uint256) - { - uint256 _totalSupply = totalSupply; - if (_totalSupply == 0) { - return (MathError.NO_ERROR, initialExchangeRateMantissa); - } else { - MathError error; - uint256 exchangeRate; - uint256 totalCash = getCashPrior(); - if (interestRateModel.isTropykusInterestRateModel()) { - (error, exchangeRate) = tropykusExchangeRateStoredInternal( - msg.sender - ); - if (error == MathError.NO_ERROR) { - return (MathError.NO_ERROR, exchangeRate); - } else { - return (MathError.NO_ERROR, initialExchangeRateMantissa); - } - } - return - interestRateModel.getExchangeRate( - totalCash, - totalBorrows, - totalReserves, - totalSupply - ); - } - } - - function tropykusExchangeRateStoredInternal(address redeemer) - internal - view - returns (MathError, uint256) - { - if (totalSupply == 0) { - return (MathError.NO_ERROR, initialExchangeRateMantissa); - } else { - SupplySnapshot storage supplySnapshot = accountTokens[redeemer]; - if (supplySnapshot.suppliedAt == 0) { - return (MathError.DIVISION_BY_ZERO, 0); - } - (, uint256 interestFactorMantissa, ) = tropykusInterestAccrued( - redeemer - ); - Exp memory interestFactor = Exp({mantissa: interestFactorMantissa}); - uint256 currentUnderlying = supplySnapshot.underlyingAmount; - Exp memory redeemerUnderlying = Exp({mantissa: currentUnderlying}); - (, Exp memory realAmount) = mulExp( - interestFactor, - redeemerUnderlying - ); - (, Exp memory exchangeRate) = getExp( - realAmount.mantissa, - supplySnapshot.tokens - ); - return (MathError.NO_ERROR, exchangeRate.mantissa); - } - } - - function tropykusInterestAccrued(address account) - internal - view - returns ( - MathError, - uint256, - uint256 - ) - { - SupplySnapshot storage supplySnapshot = accountTokens[account]; - uint256 promisedSupplyRate = supplySnapshot.promisedSupplyRate; - Exp memory expectedSupplyRatePerBlock = Exp({ - mantissa: promisedSupplyRate - }); - (, uint256 delta) = subUInt( - accrualBlockNumber, - supplySnapshot.suppliedAt - ); - (, Exp memory expectedSupplyRatePerBlockWithDelta) = mulScalar( - expectedSupplyRatePerBlock, - delta - ); - (, Exp memory interestFactor) = addExp( - Exp({mantissa: 1e18}), - expectedSupplyRatePerBlockWithDelta - ); - uint256 currentUnderlying = supplySnapshot.underlyingAmount; - Exp memory redeemerUnderlying = Exp({mantissa: currentUnderlying}); - (, Exp memory realAmount) = mulExp(interestFactor, redeemerUnderlying); - (, uint256 interestEarned) = subUInt( - realAmount.mantissa, - currentUnderlying - ); - return (MathError.NO_ERROR, interestFactor.mantissa, interestEarned); - } - - /** - * @notice Get cash balance of this cToken in the underlying asset - * @return The quantity of underlying asset owned by this contract - */ - function getCash() external view override returns (uint256) { - return getCashPrior(); - } - - /** - * @notice Applies accrued interest to total borrows and reserves - * @dev This calculates interest accrued from the last checkpointed block - * up to the current block and writes new checkpoint to storage. - */ - function accrueInterest() public override returns (uint256) { - uint256 currentBlockNumber = getBlockNumber(); - uint256 accrualBlockNumberPrior = accrualBlockNumber; - - if (accrualBlockNumberPrior == currentBlockNumber) { - return uint256(Error.NO_ERROR); - } - - uint256 cashPrior = getCashPrior(); - uint256 borrowsPrior = totalBorrows; - uint256 reservesPrior = totalReserves; - uint256 borrowIndexPrior = borrowIndex; - - uint256 borrowRateMantissa = interestRateModel.getBorrowRate( - cashPrior, - borrowsPrior, - reservesPrior - ); - require(borrowRateMantissa <= borrowRateMaxMantissa, "CT10"); - - (MathError mathErr, uint256 blockDelta) = subUInt( - currentBlockNumber, - accrualBlockNumberPrior - ); - require(mathErr == MathError.NO_ERROR, "CT11"); - - Exp memory simpleInterestFactor; - uint256 interestAccumulated; - uint256 totalBorrowsNew; - uint256 totalReservesNew; - uint256 borrowIndexNew; - - (mathErr, simpleInterestFactor) = mulScalar( - Exp({mantissa: borrowRateMantissa}), - blockDelta - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .ACCRUE_INTEREST_SIMPLE_INTEREST_FACTOR_CALCULATION_FAILED, - uint256(mathErr) - ); - } - - (mathErr, interestAccumulated) = mulScalarTruncate( - simpleInterestFactor, - borrowsPrior - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .ACCRUE_INTEREST_ACCUMULATED_INTEREST_CALCULATION_FAILED, - uint256(mathErr) - ); - } - - (mathErr, totalBorrowsNew) = addUInt(interestAccumulated, borrowsPrior); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .ACCRUE_INTEREST_NEW_TOTAL_BORROWS_CALCULATION_FAILED, - uint256(mathErr) - ); - } - - (mathErr, totalReservesNew) = mulScalarTruncateAddUInt( - Exp({mantissa: reserveFactorMantissa}), - interestAccumulated, - reservesPrior - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .ACCRUE_INTEREST_NEW_TOTAL_RESERVES_CALCULATION_FAILED, - uint256(mathErr) - ); - } - - if (interestRateModel.isTropykusInterestRateModel()) { - (mathErr, totalReservesNew) = newReserves( - borrowRateMantissa, - cashPrior, - borrowsPrior, - reservesPrior, - interestAccumulated - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .ACCRUE_INTEREST_NEW_TOTAL_RESERVES_CALCULATION_FAILED, - uint256(mathErr) - ); - } - } - - (mathErr, borrowIndexNew) = mulScalarTruncateAddUInt( - simpleInterestFactor, - borrowIndexPrior, - borrowIndexPrior - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .ACCRUE_INTEREST_NEW_BORROW_INDEX_CALCULATION_FAILED, - uint256(mathErr) - ); - } - - accrualBlockNumber = currentBlockNumber; - borrowIndex = borrowIndexNew; - totalBorrows = totalBorrowsNew; - totalReserves = totalReservesNew; - - emit AccrueInterest( - cashPrior, - interestAccumulated, - borrowIndexNew, - totalBorrowsNew - ); - - return uint256(Error.NO_ERROR); - } - - function newReserves( - uint256 borrowRateMantissa, - uint256 cashPrior, - uint256 borrowsPrior, - uint256 reservesPrior, - uint256 interestAccumulated - ) internal view returns (MathError mathErr, uint256 totalReservesNew) { - uint256 newReserveFactorMantissa; - uint256 utilizationRate = interestRateModel.utilizationRate( - cashPrior, - borrowsPrior, - reservesPrior - ); - uint256 expectedSupplyRate = interestRateModel.getSupplyRate( - cashPrior, - borrowsPrior, - reservesPrior, - reserveFactorMantissa - ); - if ( - interestRateModel.isAboveOptimal( - cashPrior, - borrowsPrior, - reservesPrior - ) - ) { - (mathErr, newReserveFactorMantissa) = mulScalarTruncate( - Exp({mantissa: utilizationRate}), - borrowRateMantissa - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - (mathErr, newReserveFactorMantissa) = subUInt( - newReserveFactorMantissa, - expectedSupplyRate - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - (mathErr, totalReservesNew) = mulScalarTruncateAddUInt( - Exp({mantissa: newReserveFactorMantissa}), - interestAccumulated, - reservesPrior - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - } else { - mathErr = MathError.NO_ERROR; - totalReservesNew = reservesPrior; - } - } - - /** - * @notice Sender supplies assets into the market and receives cTokens in exchange - * @dev Accrues interest whether or not the operation succeeds, unless reverted - * @param mintAmount The amount of the underlying asset to supply - * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual mint amount. - */ - function mintInternal(uint256 mintAmount) - internal - nonReentrant - returns (uint256, uint256) - { - if (WhitelistInterface(whitelist).enabled()) { - require(WhitelistInterface(whitelist).exist(msg.sender), "CT26"); - } - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return ( - fail(Error(error), FailureInfo.MINT_ACCRUE_INTEREST_FAILED), - 0 - ); - } - return mintFresh(msg.sender, mintAmount); - } - - struct MintLocalVars { - Error err; - MathError mathErr; - uint256 exchangeRateMantissa; - uint256 mintTokens; - uint256 totalSupplyNew; - uint256 accountTokensNew; - uint256 actualMintAmount; - } - - /** - * @notice User supplies assets into the market and receives cTokens in exchange - * @dev Assumes interest has already been accrued up to the current block - * @param minter The address of the account which is supplying the assets - * @param mintAmount The amount of the underlying asset to supply - * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual mint amount. - */ - function mintFresh(address minter, uint256 mintAmount) - internal - returns (uint256, uint256) - { - uint256 allowed = comptroller.mintAllowed( - address(this), - minter, - mintAmount - ); - if (allowed != 0) { - return ( - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.MINT_COMPTROLLER_REJECTION, - allowed - ), - 0 - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return ( - fail(Error.MARKET_NOT_FRESH, FailureInfo.MINT_FRESHNESS_CHECK), - 0 - ); - } - - MintLocalVars memory vars; - - ( - vars.mathErr, - vars.exchangeRateMantissa - ) = exchangeRateStoredInternal(); - if (vars.mathErr != MathError.NO_ERROR) { - return ( - failOpaque( - Error.MATH_ERROR, - FailureInfo.MINT_EXCHANGE_RATE_READ_FAILED, - uint256(vars.mathErr) - ), - 0 - ); - } - if (interestRateModel.isTropykusInterestRateModel()) { - SupplySnapshot storage supplySnapshot = accountTokens[minter]; - (, uint256 newTotalSupply) = addUInt( - supplySnapshot.underlyingAmount, - mintAmount - ); - require(newTotalSupply <= 0.1e18, "CT24"); - } - vars.actualMintAmount = doTransferIn(minter, mintAmount); - - (vars.mathErr, vars.mintTokens) = divScalarByExpTruncate( - vars.actualMintAmount, - Exp({mantissa: vars.exchangeRateMantissa}) - ); - require(vars.mathErr == MathError.NO_ERROR, "CT12"); - - (vars.mathErr, vars.totalSupplyNew) = addUInt( - totalSupply, - vars.mintTokens - ); - require(vars.mathErr == MathError.NO_ERROR, "CT13"); - - (vars.mathErr, vars.accountTokensNew) = addUInt( - accountTokens[minter].tokens, - vars.mintTokens - ); - require(vars.mathErr == MathError.NO_ERROR, "CT14"); - - uint256 currentSupplyRate = interestRateModel.getSupplyRate( - getCashPrior(), - totalBorrows, - totalReserves, - reserveFactorMantissa - ); - - bool isTropykusInterestRateModel = interestRateModel - .isTropykusInterestRateModel(); - - if (accountTokens[minter].tokens > 0) { - Exp memory updatedUnderlying; - if (isTropykusInterestRateModel) { - (, uint256 interestFactorMantissa, ) = tropykusInterestAccrued( - minter - ); - Exp memory interestFactor = Exp({ - mantissa: interestFactorMantissa - }); - uint256 currentUnderlyingAmount = accountTokens[minter] - .underlyingAmount; - MathError mErrorNewAmount; - (mErrorNewAmount, updatedUnderlying) = mulExp( - Exp({mantissa: currentUnderlyingAmount}), - interestFactor - ); - if (mErrorNewAmount != MathError.NO_ERROR) { - return ( - failOpaque( - Error.MATH_ERROR, - FailureInfo.MINT_EXCHANGE_CALCULATION_FAILED, - uint256(mErrorNewAmount) - ), - 0 - ); - } - } else { - uint256 currentTokens = accountTokens[minter].tokens; - MathError mErrorUpdatedUnderlying; - (mErrorUpdatedUnderlying, updatedUnderlying) = mulExp( - Exp({mantissa: currentTokens}), - Exp({mantissa: vars.exchangeRateMantissa}) - ); - if (mErrorUpdatedUnderlying != MathError.NO_ERROR) { - return ( - failOpaque( - Error.MATH_ERROR, - FailureInfo.MINT_EXCHANGE_CALCULATION_FAILED, - uint256(mErrorUpdatedUnderlying) - ), - 0 - ); - } - } - (, mintAmount) = addUInt(updatedUnderlying.mantissa, mintAmount); - } - - totalSupply = vars.totalSupplyNew; - accountTokens[minter] = SupplySnapshot({ - tokens: vars.accountTokensNew, - underlyingAmount: mintAmount, - suppliedAt: accrualBlockNumber, - promisedSupplyRate: currentSupplyRate - }); - - emit Mint(minter, vars.actualMintAmount, vars.mintTokens); - emit Transfer(address(this), minter, vars.mintTokens); - - return (uint256(Error.NO_ERROR), vars.actualMintAmount); - } - - /** - * @notice Sender redeems cTokens in exchange for a specified amount of underlying asset - * @dev Accrues interest whether or not the operation succeeds, unless reverted - * @param redeemAmount The amount of underlying to receive from redeeming cTokens - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function redeemUnderlyingInternal(uint256 redeemAmount) - internal - nonReentrant - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return - fail(Error(error), FailureInfo.REDEEM_ACCRUE_INTEREST_FAILED); - } - return redeemFresh(payable(msg.sender), redeemAmount); - } - - struct RedeemLocalVars { - Error err; - MathError mathErr; - uint256 exchangeRateMantissa; - uint256 redeemTokens; - uint256 redeemAmount; - uint256 totalSupplyNew; - uint256 accountTokensNew; - uint256 newSubsidyFund; - } - - /** - * @notice User redeems cTokens in exchange for the underlying asset - * @dev Assumes interest has already been accrued up to the current block - * @param redeemer The address of the account which is redeeming the tokens - * @param redeemAmountIn The number of underlying tokens to receive from redeeming cTokens - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function redeemFresh(address payable redeemer, uint256 redeemAmountIn) - internal - returns (uint256) - { - require(redeemAmountIn > 0, "CT15"); - - RedeemLocalVars memory vars; - - SupplySnapshot storage supplySnapshot = accountTokens[redeemer]; - - ( - vars.mathErr, - vars.exchangeRateMantissa - ) = exchangeRateStoredInternal(); - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.REDEEM_EXCHANGE_RATE_READ_FAILED, - uint256(vars.mathErr) - ); - } - - uint256 interestEarned; - uint256 subsidyFundPortion; - uint256 currentUnderlying; - - bool isTropykusInterestRateModel = interestRateModel - .isTropykusInterestRateModel(); - if (isTropykusInterestRateModel) { - currentUnderlying = supplySnapshot.underlyingAmount; - (, , interestEarned) = tropykusInterestAccrued(redeemer); - } - supplySnapshot.promisedSupplyRate = interestRateModel.getSupplyRate( - getCashPrior(), - totalBorrows, - totalReserves, - reserveFactorMantissa - ); - - if ( - isTropykusInterestRateModel && - !interestRateModel.isAboveOptimal( - getCashPrior(), - totalBorrows, - totalReserves - ) - ) { - uint256 borrowRate = interestRateModel.getBorrowRate( - getCashPrior(), - totalBorrows, - totalReserves - ); - - uint256 utilizationRate = interestRateModel.utilizationRate( - getCashPrior(), - totalBorrows, - totalReserves - ); - - (, uint256 estimatedEarning) = mulScalarTruncate( - Exp({mantissa: borrowRate}), - utilizationRate - ); - - (, subsidyFundPortion) = subUInt( - supplySnapshot.promisedSupplyRate, - estimatedEarning - ); - (, Exp memory subsidyFactor) = getExp( - subsidyFundPortion, - supplySnapshot.promisedSupplyRate - ); - (, subsidyFundPortion) = mulScalarTruncate( - subsidyFactor, - interestEarned - ); - } - - vars.redeemAmount = redeemAmountIn; - - if (isTropykusInterestRateModel) { - (, Exp memory num) = mulExp( - vars.redeemAmount, - supplySnapshot.tokens - ); - (, Exp memory realTokensWithdrawAmount) = getExp( - num.mantissa, - currentUnderlying - ); - vars.redeemTokens = realTokensWithdrawAmount.mantissa; - } else { - (vars.mathErr, vars.redeemTokens) = divScalarByExpTruncate( - redeemAmountIn, - Exp({mantissa: vars.exchangeRateMantissa}) - ); - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.REDEEM_EXCHANGE_AMOUNT_CALCULATION_FAILED, - uint256(vars.mathErr) - ); - } - } - // } - - uint256 allowed = comptroller.redeemAllowed( - address(this), - redeemer, - vars.redeemTokens - ); - if (allowed != 0) { - return - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.REDEEM_COMPTROLLER_REJECTION, - allowed - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.REDEEM_FRESHNESS_CHECK - ); - } - - (vars.mathErr, vars.totalSupplyNew) = subUInt( - totalSupply, - vars.redeemTokens - ); - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.REDEEM_NEW_TOTAL_SUPPLY_CALCULATION_FAILED, - uint256(vars.mathErr) - ); - } - - (, vars.newSubsidyFund) = subUInt(subsidyFund, subsidyFundPortion); - - (vars.mathErr, vars.accountTokensNew) = subUInt( - supplySnapshot.tokens, - vars.redeemTokens - ); - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.REDEEM_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED, - uint256(vars.mathErr) - ); - } - - uint256 cash = getCashPrior(); - if (isTropykusInterestRateModel) { - cash = address(this).balance; - } - - if (cash < vars.redeemAmount) { - return - fail( - Error.TOKEN_INSUFFICIENT_CASH, - FailureInfo.REDEEM_TRANSFER_OUT_NOT_POSSIBLE - ); - } - - doTransferOut(redeemer, vars.redeemAmount); - - totalSupply = vars.totalSupplyNew; - subsidyFund = vars.newSubsidyFund; - supplySnapshot.tokens = vars.accountTokensNew; - supplySnapshot.suppliedAt = accrualBlockNumber; - (, supplySnapshot.underlyingAmount) = subUInt( - supplySnapshot.underlyingAmount, - vars.redeemAmount - ); - - emit Transfer(redeemer, address(this), vars.redeemTokens); - emit Redeem(redeemer, vars.redeemAmount, vars.redeemTokens); - - comptroller.redeemVerify( - address(this), - redeemer, - vars.redeemAmount, - vars.redeemTokens - ); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Sender borrows assets from the protocol to their own address - * @param borrowAmount The amount of the underlying asset to borrow - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function borrowInternal(uint256 borrowAmount) - internal - nonReentrant - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return - fail(Error(error), FailureInfo.BORROW_ACCRUE_INTEREST_FAILED); - } - return borrowFresh(payable(msg.sender), borrowAmount); - } - - struct BorrowLocalVars { - MathError mathErr; - uint256 accountBorrows; - uint256 accountBorrowsNew; - uint256 totalBorrowsNew; - } - - /** - * @notice Users borrow assets from the protocol to their own address - * @param borrowAmount The amount of the underlying asset to borrow - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function borrowFresh(address payable borrower, uint256 borrowAmount) - internal - returns (uint256) - { - uint256 allowed = comptroller.borrowAllowed( - address(this), - borrower, - borrowAmount - ); - if (allowed != 0) { - return - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.BORROW_COMPTROLLER_REJECTION, - allowed - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.BORROW_FRESHNESS_CHECK - ); - } - - if (getCashPrior() < borrowAmount) { - return - fail( - Error.TOKEN_INSUFFICIENT_CASH, - FailureInfo.BORROW_CASH_NOT_AVAILABLE - ); - } - - BorrowLocalVars memory vars; - - (vars.mathErr, vars.accountBorrows) = borrowBalanceStoredInternal( - borrower - ); - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED, - uint256(vars.mathErr) - ); - } - - (vars.mathErr, vars.accountBorrowsNew) = addUInt( - vars.accountBorrows, - borrowAmount - ); - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED, - uint256(vars.mathErr) - ); - } - - (vars.mathErr, vars.totalBorrowsNew) = addUInt( - totalBorrows, - borrowAmount - ); - if (interestRateModel.isTropykusInterestRateModel()) { - require(vars.totalBorrowsNew <= 0.1e18, "CT25"); - } - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED, - uint256(vars.mathErr) - ); - } - - doTransferOut(borrower, borrowAmount); - - accountBorrows[borrower].principal = vars.accountBorrowsNew; - accountBorrows[borrower].interestIndex = borrowIndex; - totalBorrows = vars.totalBorrowsNew; - - emit Borrow( - borrower, - borrowAmount, - vars.accountBorrowsNew, - vars.totalBorrowsNew - ); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Sender repays their own borrow - * @param repayAmount The amount to repay - * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual repayment amount. - */ - function repayBorrowInternal(uint256 repayAmount) - internal - nonReentrant - returns (uint256, uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return ( - fail( - Error(error), - FailureInfo.REPAY_BORROW_ACCRUE_INTEREST_FAILED - ), - 0 - ); - } - return repayBorrowFresh(msg.sender, msg.sender, repayAmount); - } - - struct RepayBorrowLocalVars { - Error err; - MathError mathErr; - uint256 repayAmount; - uint256 borrowerIndex; - uint256 accountBorrows; - uint256 accountBorrowsNew; - uint256 totalBorrowsNew; - uint256 actualRepayAmount; - } - - /** - * @notice Borrows are repaid by another user (possibly the borrower). - * @param payer the account paying off the borrow - * @param borrower the account with the debt being payed off - * @param repayAmount the amount of undelrying tokens being returned - * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual repayment amount. - */ - function repayBorrowFresh( - address payer, - address borrower, - uint256 repayAmount - ) internal returns (uint256, uint256) { - uint256 allowed = comptroller.repayBorrowAllowed( - address(this), - payer, - borrower, - repayAmount - ); - if (allowed != 0) { - return ( - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.REPAY_BORROW_COMPTROLLER_REJECTION, - allowed - ), - 0 - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return ( - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.REPAY_BORROW_FRESHNESS_CHECK - ), - 0 - ); - } - - RepayBorrowLocalVars memory vars; - - vars.borrowerIndex = accountBorrows[borrower].interestIndex; - - (vars.mathErr, vars.accountBorrows) = borrowBalanceStoredInternal( - borrower - ); - if (vars.mathErr != MathError.NO_ERROR) { - return ( - failOpaque( - Error.MATH_ERROR, - FailureInfo - .REPAY_BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED, - uint256(vars.mathErr) - ), - 0 - ); - } - - if (repayAmount == type(uint256).max) { - vars.repayAmount = vars.accountBorrows; - } else { - vars.repayAmount = repayAmount; - } - - vars.actualRepayAmount = doTransferIn(payer, vars.repayAmount); - - (vars.mathErr, vars.accountBorrowsNew) = subUInt( - vars.accountBorrows, - vars.actualRepayAmount - ); - require(vars.mathErr == MathError.NO_ERROR, "CT16"); - - (vars.mathErr, vars.totalBorrowsNew) = subUInt( - totalBorrows, - vars.actualRepayAmount - ); - require(vars.mathErr == MathError.NO_ERROR, "CT17"); - - accountBorrows[borrower].principal = vars.accountBorrowsNew; - accountBorrows[borrower].interestIndex = borrowIndex; - totalBorrows = vars.totalBorrowsNew; - - emit RepayBorrow( - payer, - borrower, - vars.actualRepayAmount, - vars.accountBorrowsNew, - vars.totalBorrowsNew - ); - - return (uint256(Error.NO_ERROR), vars.actualRepayAmount); - } - - /** - * @notice The sender liquidates the borrowers collateral. - * The collateral seized is transferred to the liquidator. - * @param borrower The borrower of this cToken to be liquidated - * @param cTokenCollateral The market in which to seize collateral from the borrower - * @param repayAmount The amount of the underlying borrowed asset to repay - * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual repayment amount. - */ - function liquidateBorrowInternal( - address borrower, - uint256 repayAmount, - CTokenInterface cTokenCollateral - ) internal nonReentrant returns (uint256, uint256) { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return ( - fail( - Error(error), - FailureInfo.LIQUIDATE_ACCRUE_BORROW_INTEREST_FAILED - ), - 0 - ); - } - - error = cTokenCollateral.accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return ( - fail( - Error(error), - FailureInfo.LIQUIDATE_ACCRUE_COLLATERAL_INTEREST_FAILED - ), - 0 - ); - } - - // liquidateBorrowFresh emits borrow-specific logs on errors, so we don't need to - return - liquidateBorrowFresh( - msg.sender, - borrower, - repayAmount, - cTokenCollateral - ); - } - - /** - * @notice The liquidator liquidates the borrowers collateral. - * The collateral seized is transferred to the liquidator. - * @param borrower The borrower of this cToken to be liquidated - * @param liquidator The address repaying the borrow and seizing collateral - * @param cTokenCollateral The market in which to seize collateral from the borrower - * @param repayAmount The amount of the underlying borrowed asset to repay - * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual repayment amount. - */ - function liquidateBorrowFresh( - address liquidator, - address borrower, - uint256 repayAmount, - CTokenInterface cTokenCollateral - ) internal returns (uint256, uint256) { - uint256 allowed = comptroller.liquidateBorrowAllowed( - address(this), - address(cTokenCollateral), - liquidator, - borrower, - repayAmount - ); - if (allowed != 0) { - return ( - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.LIQUIDATE_COMPTROLLER_REJECTION, - allowed - ), - 0 - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return ( - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.LIQUIDATE_FRESHNESS_CHECK - ), - 0 - ); - } - - if (cTokenCollateral.accrualBlockNumber() != getBlockNumber()) { - return ( - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.LIQUIDATE_COLLATERAL_FRESHNESS_CHECK - ), - 0 - ); - } - - if (borrower == liquidator) { - return ( - fail( - Error.INVALID_ACCOUNT_PAIR, - FailureInfo.LIQUIDATE_LIQUIDATOR_IS_BORROWER - ), - 0 - ); - } - - if (repayAmount == 0) { - return ( - fail( - Error.INVALID_CLOSE_AMOUNT_REQUESTED, - FailureInfo.LIQUIDATE_CLOSE_AMOUNT_IS_ZERO - ), - 0 - ); - } - - if (repayAmount == type(uint256).max) { - return ( - fail( - Error.INVALID_CLOSE_AMOUNT_REQUESTED, - FailureInfo.LIQUIDATE_CLOSE_AMOUNT_IS_UINT_MAX - ), - 0 - ); - } - - ( - uint256 repayBorrowError, - uint256 actualRepayAmount - ) = repayBorrowFresh(liquidator, borrower, repayAmount); - if (repayBorrowError != uint256(Error.NO_ERROR)) { - return ( - fail( - Error(repayBorrowError), - FailureInfo.LIQUIDATE_REPAY_BORROW_FRESH_FAILED - ), - 0 - ); - } - - (uint256 amountSeizeError, uint256 seizeTokens) = comptroller - .liquidateCalculateSeizeTokens( - address(this), - address(cTokenCollateral), - actualRepayAmount - ); - require(amountSeizeError == uint256(Error.NO_ERROR), "CT18"); - - require(cTokenCollateral.balanceOf(borrower) >= seizeTokens, "CT19"); - - uint256 seizeError; - if (address(cTokenCollateral) == address(this)) { - seizeError = seizeInternal( - address(this), - liquidator, - borrower, - seizeTokens - ); - } else { - seizeError = cTokenCollateral.seize( - liquidator, - borrower, - seizeTokens - ); - } - - require(seizeError == uint256(Error.NO_ERROR), "CT20"); - - emit LiquidateBorrow( - liquidator, - borrower, - actualRepayAmount, - address(cTokenCollateral), - seizeTokens - ); - - return (uint256(Error.NO_ERROR), actualRepayAmount); - } - - /** - * @notice Transfers collateral tokens (this market) to the liquidator. - * @dev Will fail unless called by another cToken during the process of liquidation. - * Its absolutely critical to use msg.sender as the borrowed cToken and not a parameter. - * @param liquidator The account receiving seized collateral - * @param borrower The account having collateral seized - * @param seizeTokens The number of cTokens to seize - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function seize( - address liquidator, - address borrower, - uint256 seizeTokens - ) external override nonReentrant returns (uint256) { - return seizeInternal(msg.sender, liquidator, borrower, seizeTokens); - } - - struct SeizeVars { - uint256 seizeAmount; - uint256 exchangeRate; - uint256 borrowerTokensNew; - uint256 borrowerAmountNew; - uint256 liquidatorTokensNew; - uint256 liquidatorAmountNew; - uint256 totalCash; - uint256 supplyRate; - } - - /** - * @notice Transfers collateral tokens (this market) to the liquidator. - * @dev Called only during an in-kind liquidation, or by liquidateBorrow during the liquidation of another CToken. - * Its absolutely critical to use msg.sender as the seizer cToken and not a parameter. - * @param seizerToken The contract seizing the collateral (i.e. borrowed cToken) - * @param liquidator The account receiving seized collateral - * @param borrower The account having collateral seized - * @param seizeTokens The number of cTokens to seize - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function seizeInternal( - address seizerToken, - address liquidator, - address borrower, - uint256 seizeTokens - ) internal returns (uint256) { - uint256 allowed = comptroller.seizeAllowed( - address(this), - seizerToken, - liquidator, - borrower, - seizeTokens - ); - if (allowed != 0) { - return - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.LIQUIDATE_SEIZE_COMPTROLLER_REJECTION, - allowed - ); - } - - if (borrower == liquidator) { - return - fail( - Error.INVALID_ACCOUNT_PAIR, - FailureInfo.LIQUIDATE_SEIZE_LIQUIDATOR_IS_BORROWER - ); - } - - SeizeVars memory seizeVars; - - MathError mathErr; - - (mathErr, seizeVars.borrowerTokensNew) = subUInt( - accountTokens[borrower].tokens, - seizeTokens - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.LIQUIDATE_SEIZE_BALANCE_DECREMENT_FAILED, - uint256(mathErr) - ); - } - - seizeVars.totalCash = getCashPrior(); - seizeVars.supplyRate = interestRateModel.getSupplyRate( - seizeVars.totalCash, - totalBorrows, - totalReserves, - reserveFactorMantissa - ); - - (, seizeVars.exchangeRate) = interestRateModel.getExchangeRate( - seizeVars.totalCash, - totalBorrows, - totalReserves, - totalSupply - ); - - if (interestRateModel.isTropykusInterestRateModel()) { - (, seizeVars.exchangeRate) = tropykusExchangeRateStoredInternal( - borrower - ); - } - - (, seizeVars.seizeAmount) = mulUInt( - seizeTokens, - seizeVars.exchangeRate - ); - (, seizeVars.seizeAmount) = divUInt(seizeVars.seizeAmount, 1e18); - - (, seizeVars.borrowerAmountNew) = subUInt( - accountTokens[borrower].underlyingAmount, - seizeVars.seizeAmount - ); - - (mathErr, seizeVars.liquidatorTokensNew) = addUInt( - accountTokens[liquidator].tokens, - seizeTokens - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.LIQUIDATE_SEIZE_BALANCE_INCREMENT_FAILED, - uint256(mathErr) - ); - } - - (, seizeVars.liquidatorAmountNew) = addUInt( - accountTokens[liquidator].underlyingAmount, - seizeVars.seizeAmount - ); - - accountTokens[borrower].tokens = seizeVars.borrowerTokensNew; - accountTokens[borrower].underlyingAmount = seizeVars.borrowerAmountNew; - accountTokens[borrower].suppliedAt = getBlockNumber(); - accountTokens[borrower].promisedSupplyRate = seizeVars.supplyRate; - - accountTokens[liquidator].tokens = seizeVars.liquidatorTokensNew; - accountTokens[liquidator].underlyingAmount = seizeVars - .liquidatorAmountNew; - accountTokens[liquidator].suppliedAt = getBlockNumber(); - accountTokens[liquidator].promisedSupplyRate = seizeVars.supplyRate; - - emit Transfer(borrower, liquidator, seizeTokens); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Begins transfer of admin rights. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer. - * @dev Admin function to begin change of admin. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer. - * @param newPendingAdmin New pending admin. - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setPendingAdmin(address payable newPendingAdmin) - external - override - returns (uint256) - { - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_PENDING_ADMIN_OWNER_CHECK - ); - } - - address oldPendingAdmin = pendingAdmin; - - pendingAdmin = newPendingAdmin; - - emit NewPendingAdmin(oldPendingAdmin, newPendingAdmin); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Accepts transfer of admin rights. msg.sender must be pendingAdmin - * @dev Admin function for pending admin to accept role and update admin - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _acceptAdmin() external override returns (uint256) { - if (msg.sender != pendingAdmin || msg.sender == address(0)) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.ACCEPT_ADMIN_PENDING_ADMIN_CHECK - ); - } - - address oldAdmin = admin; - address oldPendingAdmin = pendingAdmin; - - admin = pendingAdmin; - - pendingAdmin = payable(address(0)); - - emit NewAdmin(oldAdmin, admin); - emit NewPendingAdmin(oldPendingAdmin, pendingAdmin); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Sets a new comptroller for the market - * @dev Admin function to set a new comptroller - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setComptroller(ComptrollerInterface newComptroller) - public - override - returns (uint256) - { - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_COMPTROLLER_OWNER_CHECK - ); - } - - ComptrollerInterface oldComptroller = comptroller; - require(newComptroller.isComptroller(), "CT21"); - - comptroller = newComptroller; - - emit NewComptroller(oldComptroller, newComptroller); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice accrues interest and sets a new reserve factor for the protocol using _setReserveFactorFresh - * @dev Admin function to accrue interest and set a new reserve factor - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setReserveFactor(uint256 newReserveFactorMantissa) - external - override - nonReentrant - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return - fail( - Error(error), - FailureInfo.SET_RESERVE_FACTOR_ACCRUE_INTEREST_FAILED - ); - } - return _setReserveFactorFresh(newReserveFactorMantissa); - } - - /** - * @notice Sets a new reserve factor for the protocol (*requires fresh interest accrual) - * @dev Admin function to set a new reserve factor - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setReserveFactorFresh(uint256 newReserveFactorMantissa) - internal - returns (uint256) - { - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_RESERVE_FACTOR_ADMIN_CHECK - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.SET_RESERVE_FACTOR_FRESH_CHECK - ); - } - - if (newReserveFactorMantissa > reserveFactorMaxMantissa) { - return - fail( - Error.BAD_INPUT, - FailureInfo.SET_RESERVE_FACTOR_BOUNDS_CHECK - ); - } - - uint256 oldReserveFactorMantissa = reserveFactorMantissa; - reserveFactorMantissa = newReserveFactorMantissa; - - emit NewReserveFactor( - oldReserveFactorMantissa, - newReserveFactorMantissa - ); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Accrues interest and reduces reserves by transferring from msg.sender - * @param addAmount Amount of addition to reserves - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _addReservesInternal(uint256 addAmount) - internal - nonReentrant - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return - fail( - Error(error), - FailureInfo.ADD_RESERVES_ACCRUE_INTEREST_FAILED - ); - } - - uint256 totalReservesNew; - uint256 actualAddAmount; - - if (accrualBlockNumber != getBlockNumber()) { - return ( - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.ADD_RESERVES_FRESH_CHECK - ) - ); - } - - actualAddAmount = doTransferIn(msg.sender, addAmount); - - totalReservesNew = totalReserves + actualAddAmount; - - require(totalReservesNew >= totalReserves, "CT22"); - - totalReserves = totalReservesNew; - - emit ReservesAdded(msg.sender, actualAddAmount, totalReservesNew); - - return (uint256(Error.NO_ERROR)); - } - - function _addSubsidyInternal(uint256 addAmount) - internal - nonReentrant - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - // accrueInterest emits logs on errors, but on top of that we want to log the fact that an attempted reduce reserves failed. - return fail(Error(error), FailureInfo.ADD_SUBSIDY_FUND_FAILED); - } - - uint256 subsidyFundNew; - uint256 actualAddAmount; - - if (accrualBlockNumber != getBlockNumber()) { - return ( - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.ADD_SUBSIDY_FUND_FRESH_CHECK - ) - ); - } - - actualAddAmount = doTransferIn(msg.sender, addAmount); - - subsidyFundNew = subsidyFund + actualAddAmount; - - require(subsidyFundNew >= subsidyFund, "CT22"); - - subsidyFund = subsidyFundNew; - - emit SubsidyAdded(msg.sender, actualAddAmount, subsidyFundNew); - - /* Return (NO_ERROR, actualAddAmount) */ - return (uint256(Error.NO_ERROR)); - } - - /** - * @notice Accrues interest and reduces reserves by transferring to admin - * @param reduceAmount Amount of reduction to reserves - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _reduceReserves(uint256 reduceAmount) - external - override - nonReentrant - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return - fail( - Error(error), - FailureInfo.REDUCE_RESERVES_ACCRUE_INTEREST_FAILED - ); - } - return _reduceReservesFresh(reduceAmount); - } - - /** - * @notice Reduces reserves by transferring to admin - * @dev Requires fresh interest accrual - * @param reduceAmount Amount of reduction to reserves - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _reduceReservesFresh(uint256 reduceAmount) - internal - returns (uint256) - { - uint256 totalReservesNew; - - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.REDUCE_RESERVES_ADMIN_CHECK - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.REDUCE_RESERVES_FRESH_CHECK - ); - } - - if (getCashPrior() < reduceAmount) { - return - fail( - Error.TOKEN_INSUFFICIENT_CASH, - FailureInfo.REDUCE_RESERVES_CASH_NOT_AVAILABLE - ); - } - - if (reduceAmount > totalReserves) { - return - fail(Error.BAD_INPUT, FailureInfo.REDUCE_RESERVES_VALIDATION); - } - - totalReservesNew = totalReserves - reduceAmount; - require(totalReservesNew <= totalReserves, "CT23"); - - totalReserves = totalReservesNew; - - doTransferOut(admin, reduceAmount); - - emit ReservesReduced(admin, reduceAmount, totalReservesNew); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice accrues interest and updates the interest rate model using _setInterestRateModelFresh - * @dev Admin function to accrue interest and update the interest rate model - * @param newInterestRateModel the new interest rate model to use - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setInterestRateModel(InterestRateModel newInterestRateModel) - public - override - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return - fail( - Error(error), - FailureInfo.SET_INTEREST_RATE_MODEL_ACCRUE_INTEREST_FAILED - ); - } - return _setInterestRateModelFresh(newInterestRateModel); - } - - /** - * @notice updates the interest rate model (*requires fresh interest accrual) - * @dev Admin function to update the interest rate model - * @param newInterestRateModel the new interest rate model to use - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setInterestRateModelFresh(InterestRateModel newInterestRateModel) - internal - returns (uint256) - { - InterestRateModel oldInterestRateModel; - - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_INTEREST_RATE_MODEL_OWNER_CHECK - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.SET_INTEREST_RATE_MODEL_FRESH_CHECK - ); - } - - oldInterestRateModel = interestRateModel; - - require(newInterestRateModel.isInterestRateModel(), "CT21"); - - interestRateModel = newInterestRateModel; - - emit NewMarketInterestRateModel( - oldInterestRateModel, - newInterestRateModel - ); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Gets balance of this contract in terms of the underlying - * @dev This excludes the value of the current message, if any - * @return The quantity of underlying owned by this contract - */ - function getCashPrior() internal view virtual returns (uint256); - - /** - * @dev Performs a transfer in, reverting upon failure. Returns the amount actually transferred to the protocol, in case of a fee. - * This may revert due to insufficient balance or insufficient allowance. - */ - function doTransferIn(address from, uint256 amount) - internal - virtual - returns (uint256); - - /** - * @dev Performs a transfer out, ideally returning an explanatory error code upon failure tather than reverting. - * If caller has not called checked protocol's balance, may revert due to insufficient cash held in the contract. - * If caller has checked protocol's balance, and verified it is >= amount, this should not revert in normal conditions. - */ - function doTransferOut(address payable to, uint256 amount) internal virtual; - - /** - * @dev Prevents a contract from calling itself, directly or indirectly. - */ - modifier nonReentrant() { - require(_notEntered, "re-entered"); - _notEntered = false; - _; - _notEntered = true; - } -} - - -// Dependency file: contracts/PriceOracle.sol - -// pragma solidity 0.8.6; - -// import "contracts/CToken.sol"; - -abstract contract PriceOracle { - /// @notice Indicator that this is a PriceOracle contract (for inspection) - bool public constant isPriceOracle = true; - - /** - * @notice Get the underlying price of a cToken asset - * @param cToken The cToken to get the underlying price of - * @return The underlying asset price mantissa (scaled by 1e18). - * Zero means the price is unavailable. - */ - function getUnderlyingPrice(CToken cToken) - external - view - virtual - returns (uint256); -} - - -// Root file: contracts/ComptrollerStorage.sol - -pragma solidity 0.8.6; - -// import "contracts/CToken.sol"; -// import "contracts/PriceOracle.sol"; - -contract UnitrollerAdminStorage { - /** - * @notice Administrator for this contract - */ - address public admin; - - /** - * @notice Pending administrator for this contract - */ - address public pendingAdmin; - - /** - * @notice Active brains of Unitroller - */ - address public comptrollerImplementation; - - /** - * @notice Pending brains of Unitroller - */ - address public pendingComptrollerImplementation; -} - -contract ComptrollerV1Storage is UnitrollerAdminStorage { - - /** - * @notice Oracle which gives the price of any given asset - */ - PriceOracle public oracle; - - /** - * @notice Multiplier used to calculate the maximum repayAmount when liquidating a borrow - */ - uint public closeFactorMantissa; - - /** - * @notice Multiplier representing the discount on collateral that a liquidator receives - */ - uint public liquidationIncentiveMantissa; - - /** - * @notice Max number of assets a single account can participate in (borrow or use as collateral) - */ - uint public maxAssets; - - /** - * @notice Per-account mapping of "assets you are in", capped by maxAssets - */ - mapping(address => CToken[]) public accountAssets; - -} - -contract ComptrollerV2Storage is ComptrollerV1Storage { - struct Market { - /// @notice Whether or not this market is listed - bool isListed; - - /** - * @notice Multiplier representing the most one can borrow against their collateral in this market. - * For instance, 0.9 to allow borrowing 90% of collateral value. - * Must be between 0 and 1, and stored as a mantissa. - */ - uint collateralFactorMantissa; - - /// @notice Per-market mapping of "accounts in this asset" - mapping(address => bool) accountMembership; - - /// @notice Whether or not this market receives COMP - bool isComped; - } - - /** - * @notice Official mapping of cTokens -> Market metadata - * @dev Used e.g. to determine if a market is supported - */ - mapping(address => Market) public markets; - - - /** - * @notice The Pause Guardian can pause certain actions as a safety mechanism. - * Actions which allow users to remove their own assets cannot be paused. - * Liquidation / seizing / transfer can only be paused globally, not by market. - */ - address public pauseGuardian; - bool public _mintGuardianPaused; - bool public _borrowGuardianPaused; - bool public transferGuardianPaused; - bool public seizeGuardianPaused; - mapping(address => bool) public mintGuardianPaused; - mapping(address => bool) public borrowGuardianPaused; -} - -contract ComptrollerV3Storage is ComptrollerV2Storage { - struct CompMarketState { - /// @notice The market's last updated compBorrowIndex or compSupplyIndex - uint224 index; - - /// @notice The block number the index was last updated at - uint32 block; - } - - /// @notice A list of all markets - CToken[] public allMarkets; - - /// @notice The rate at which the flywheel distributes COMP, per block - uint public compRate; - - /// @notice The portion of compRate that each market currently receives - mapping(address => uint) public compSpeeds; - - /// @notice The COMP market supply state for each market - mapping(address => CompMarketState) public compSupplyState; - - /// @notice The COMP market borrow state for each market - mapping(address => CompMarketState) public compBorrowState; - - /// @notice The COMP borrow index for each market for each supplier as of the last time they accrued COMP - mapping(address => mapping(address => uint)) public compSupplierIndex; - - /// @notice The COMP borrow index for each market for each borrower as of the last time they accrued COMP - mapping(address => mapping(address => uint)) public compBorrowerIndex; - - /// @notice The COMP accrued but not yet transferred to each user - mapping(address => uint) public compAccrued; -} - -contract ComptrollerV4Storage is ComptrollerV3Storage { - // @notice The borrowCapGuardian can set borrowCaps to any number for any market. Lowering the borrow cap could disable borrowing on the given market. - address public borrowCapGuardian; - - // @notice Borrow caps enforced by borrowAllowed for each cToken address. Defaults to zero which corresponds to unlimited borrowing. - mapping(address => uint) public borrowCaps; - - // @notice address of the TROP token - address public tropAddress; -} - -contract ComptrollerV5Storage is ComptrollerV4Storage { - /// @notice The portion of COMP that each contributor receives per block - mapping(address => uint) public compContributorSpeeds; - - /// @notice Last block at which a contributor's COMP rewards have been allocated - mapping(address => uint) public lastContributorBlock; -} diff --git a/flatten/EIP20Interface.sol b/flatten/EIP20Interface.sol deleted file mode 100644 index 3b5cffe..0000000 --- a/flatten/EIP20Interface.sol +++ /dev/null @@ -1,82 +0,0 @@ -// Root file: contracts/EIP20Interface.sol - -// SPDX-License-Identifier: UNLICENSED -pragma solidity 0.8.6; - -/** - * @title ERC 20 Token Standard Interface - * https://eips.ethereum.org/EIPS/eip-20 - */ -interface EIP20Interface { - function name() external view returns (string memory); - - function symbol() external view returns (string memory); - - function decimals() external view returns (uint8); - - /** - * @notice Get the total number of tokens in circulation - * @return The supply of tokens - */ - function totalSupply() external view returns (uint256); - - /** - * @notice Gets the balance of the specified address - * @param owner The address from which the balance will be retrieved - * @return balance The balance - */ - function balanceOf(address owner) external view returns (uint256 balance); - - /** - * @notice Transfer `amount` tokens from `msg.sender` to `dst` - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - * @return success Whether or not the transfer succeeded - */ - function transfer(address dst, uint256 amount) - external - returns (bool success); - - /** - * @notice Transfer `amount` tokens from `src` to `dst` - * @param src The address of the source account - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - * @return success Whether or not the transfer succeeded - */ - function transferFrom( - address src, - address dst, - uint256 amount - ) external returns (bool success); - - /** - * @notice Approve `spender` to transfer up to `amount` from `src` - * @dev This will overwrite the approval amount for `spender` - * and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve) - * @param spender The address of the account which may transfer tokens - * @param amount The number of tokens that are approved (-1 means infinite) - * @return success Whether or not the approval succeeded - */ - function approve(address spender, uint256 amount) - external - returns (bool success); - - /** - * @notice Get the current allowance from `owner` for `spender` - * @param owner The address of the account which owns the tokens to be spent - * @param spender The address of the account which may transfer tokens - * @return remaining The number of tokens allowed to be spent (-1 means infinite) - */ - function allowance(address owner, address spender) - external - view - returns (uint256 remaining); - - event Transfer(address indexed from, address indexed to, uint256 amount); - event Approval( - address indexed owner, - address indexed spender, - uint256 amount - ); -} diff --git a/flatten/EIP20NonStandardInterface.sol b/flatten/EIP20NonStandardInterface.sol deleted file mode 100644 index 5888090..0000000 --- a/flatten/EIP20NonStandardInterface.sol +++ /dev/null @@ -1,85 +0,0 @@ -// Root file: contracts/EIP20NonStandardInterface.sol - -// SPDX-License-Identifier: UNLICENSED -pragma solidity 0.8.6; - -/** - * @title EIP20NonStandardInterface - * @dev Version of ERC20 with no return values for `transfer` and `transferFrom` - * See https://medium.com/coinmonks/missing-return-value-bug-at-least-130-tokens-affected-d67bf08521ca - */ -interface EIP20NonStandardInterface { - /** - * @notice Get the total number of tokens in circulation - * @return The supply of tokens - */ - function totalSupply() external view returns (uint256); - - /** - * @notice Gets the balance of the specified address - * @param owner The address from which the balance will be retrieved - * @return balance The balance - */ - function balanceOf(address owner) external view returns (uint256 balance); - - /// - /// !!!!!!!!!!!!!! - /// !!! NOTICE !!! `transfer` does not return a value, in violation of the ERC-20 specification - /// !!!!!!!!!!!!!! - /// - - /** - * @notice Transfer `amount` tokens from `msg.sender` to `dst` - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - */ - function transfer(address dst, uint256 amount) external; - - /// - /// !!!!!!!!!!!!!! - /// !!! NOTICE !!! `transferFrom` does not return a value, in violation of the ERC-20 specification - /// !!!!!!!!!!!!!! - /// - - /** - * @notice Transfer `amount` tokens from `src` to `dst` - * @param src The address of the source account - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - */ - function transferFrom( - address src, - address dst, - uint256 amount - ) external; - - /** - * @notice Approve `spender` to transfer up to `amount` from `src` - * @dev This will overwrite the approval amount for `spender` - * and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve) - * @param spender The address of the account which may transfer tokens - * @param amount The number of tokens that are approved - * @return success Whether or not the approval succeeded - */ - function approve(address spender, uint256 amount) - external - returns (bool success); - - /** - * @notice Get the current allowance from `owner` for `spender` - * @param owner The address of the account which owns the tokens to be spent - * @param spender The address of the account which may transfer tokens - * @return remaining The number of tokens allowed to be spent - */ - function allowance(address owner, address spender) - external - view - returns (uint256 remaining); - - event Transfer(address indexed from, address indexed to, uint256 amount); - event Approval( - address indexed owner, - address indexed spender, - uint256 amount - ); -} diff --git a/flatten/ERC20.sol b/flatten/ERC20.sol deleted file mode 100644 index ea4b2b7..0000000 --- a/flatten/ERC20.sol +++ /dev/null @@ -1,438 +0,0 @@ -// Dependency file: contracts/SafeMath.sol - -// SPDX-License-Identifier: UNLICENSED -// pragma solidity 0.8.6; - -// From https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/math/Math.sol -// Subject to the MIT license. - -/** - * @dev Wrappers over Solidity's arithmetic operations with added overflow - * checks. - * - * Arithmetic operations in Solidity wrap on overflow. This can easily result - * in bugs, because programmers usually assume that an overflow raises an - * error, which is the standard behavior in high level programming languages. - * `SafeMath` restores this intuition by reverting the transaction when an - * operation overflows. - * - * Using this library instead of the unchecked operations eliminates an entire - * class of bugs, so it's recommended to use it always. - */ -library SafeMath { - /** - * @dev Returns the addition of two unsigned integers, reverting on overflow. - * - * Counterpart to Solidity's `+` operator. - * - * Requirements: - * - Addition cannot overflow. - */ - function add(uint256 a, uint256 b) internal pure returns (uint256) { - uint256 c = a + b; - require(c >= a, "SafeMath: addition overflow"); - - return c; - } - - /** - * @dev Returns the addition of two unsigned integers, reverting with custom message on overflow. - * - * Counterpart to Solidity's `+` operator. - * - * Requirements: - * - Addition cannot overflow. - */ - function add(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - uint256 c = a + b; - require(c >= a, errorMessage); - - return c; - } - - /** - * @dev Returns the subtraction of two unsigned integers, reverting on underflow (when the result is negative). - * - * Counterpart to Solidity's `-` operator. - * - * Requirements: - * - Subtraction cannot underflow. - */ - function sub(uint256 a, uint256 b) internal pure returns (uint256) { - return sub(a, b, "SafeMath: subtraction underflow"); - } - - /** - * @dev Returns the subtraction of two unsigned integers, reverting with custom message on underflow (when the result is negative). - * - * Counterpart to Solidity's `-` operator. - * - * Requirements: - * - Subtraction cannot underflow. - */ - function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - require(b <= a, errorMessage); - uint256 c = a - b; - - return c; - } - - /** - * @dev Returns the multiplication of two unsigned integers, reverting on overflow. - * - * Counterpart to Solidity's `*` operator. - * - * Requirements: - * - Multiplication cannot overflow. - */ - function mul(uint256 a, uint256 b) internal pure returns (uint256) { - // Gas optimization: this is cheaper than requiring 'a' not being zero, but the - // benefit is lost if 'b' is also tested. - // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 - if (a == 0) { - return 0; - } - - uint256 c = a * b; - require(c / a == b, "SafeMath: multiplication overflow"); - - return c; - } - - /** - * @dev Returns the multiplication of two unsigned integers, reverting on overflow. - * - * Counterpart to Solidity's `*` operator. - * - * Requirements: - * - Multiplication cannot overflow. - */ - function mul(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - // Gas optimization: this is cheaper than requiring 'a' not being zero, but the - // benefit is lost if 'b' is also tested. - // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 - if (a == 0) { - return 0; - } - - uint256 c = a * b; - require(c / a == b, errorMessage); - - return c; - } - - /** - * @dev Returns the integer division of two unsigned integers. - * Reverts on division by zero. The result is rounded towards zero. - * - * Counterpart to Solidity's `/` operator. Note: this function uses a - * `revert` opcode (which leaves remaining gas untouched) while Solidity - * uses an invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function div(uint256 a, uint256 b) internal pure returns (uint256) { - return div(a, b, "SafeMath: division by zero"); - } - - /** - * @dev Returns the integer division of two unsigned integers. - * Reverts with custom message on division by zero. The result is rounded towards zero. - * - * Counterpart to Solidity's `/` operator. Note: this function uses a - * `revert` opcode (which leaves remaining gas untouched) while Solidity - * uses an invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - // Solidity only automatically asserts when dividing by 0 - require(b > 0, errorMessage); - uint256 c = a / b; - // assert(a == b * c + a % b); // There is no case in which this doesn't hold - - return c; - } - - /** - * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), - * Reverts when dividing by zero. - * - * Counterpart to Solidity's `%` operator. This function uses a `revert` - * opcode (which leaves remaining gas untouched) while Solidity uses an - * invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function mod(uint256 a, uint256 b) internal pure returns (uint256) { - return mod(a, b, "SafeMath: modulo by zero"); - } - - /** - * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), - * Reverts with custom message when dividing by zero. - * - * Counterpart to Solidity's `%` operator. This function uses a `revert` - * opcode (which leaves remaining gas untouched) while Solidity uses an - * invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - require(b != 0, errorMessage); - return a % b; - } -} - - -// Root file: contracts/ERC20.sol - -pragma solidity 0.8.6; - -// import "contracts/SafeMath.sol"; - -interface ERC20Base { - event Approval( - address indexed owner, - address indexed spender, - uint256 value - ); - event Transfer(address indexed from, address indexed to, uint256 value); - - function totalSupply() external view returns (uint256); - - function allowance(address owner, address spender) - external - view - returns (uint256); - - function approve(address spender, uint256 value) - external - returns (bool); - - function balanceOf(address who) external view returns (uint256); -} - -abstract contract ERC20 is ERC20Base { - function transfer(address to, uint256 value) - external - virtual - returns (bool); - - function transferFrom( - address from, - address to, - uint256 value - ) external virtual returns (bool); -} - -abstract contract ERC20NS is ERC20Base { - function transfer(address to, uint256 value) external virtual; - - function transferFrom( - address from, - address to, - uint256 value - ) external virtual; -} - -/** - * @title Standard ERC20 token - * @dev Implementation of the basic standard token. - * See https://github.com/ethereum/EIPs/issues/20 - */ -contract StandardToken is ERC20 { - using SafeMath for uint256; - - string public name; - string public symbol; - uint8 public decimals; - uint256 public override totalSupply; - mapping(address => mapping(address => uint256)) public override allowance; - mapping(address => uint256) public override balanceOf; - - constructor( - uint256 _initialAmount, - string memory _tokenName, - uint8 _decimalUnits, - string memory _tokenSymbol - ) { - totalSupply = _initialAmount; - balanceOf[msg.sender] = _initialAmount; - name = _tokenName; - symbol = _tokenSymbol; - decimals = _decimalUnits; - } - - function transfer(address dst, uint256 amount) - external - virtual - override - returns (bool) - { - balanceOf[msg.sender] = balanceOf[msg.sender].sub( - amount, - "Insufficient balance" - ); - balanceOf[dst] = balanceOf[dst].add(amount, "Balance overflow"); - emit Transfer(msg.sender, dst, amount); - return true; - } - - function transferFrom( - address src, - address dst, - uint256 amount - ) external virtual override returns (bool) { - allowance[src][msg.sender] = allowance[src][msg.sender].sub( - amount, - "Insufficient allowance" - ); - balanceOf[src] = balanceOf[src].sub(amount, "Insufficient balance"); - balanceOf[dst] = balanceOf[dst].add(amount, "Balance overflow"); - emit Transfer(src, dst, amount); - return true; - } - - function approve(address _spender, uint256 amount) - external - override - returns (bool) - { - allowance[msg.sender][_spender] = amount; - emit Approval(msg.sender, _spender, amount); - return true; - } -} - -/** - * @title Non-Standard ERC20 token - * @dev Version of ERC20 with no return values for `transfer` and `transferFrom` - * See https://medium.com/coinmonks/missing-return-value-bug-at-least-130-tokens-affected-d67bf08521ca - */ -contract NonStandardToken is ERC20NS { - using SafeMath for uint256; - - string public name; - uint8 public decimals; - string public symbol; - uint256 public override totalSupply; - mapping(address => mapping(address => uint256)) public override allowance; - mapping(address => uint256) public override balanceOf; - - constructor( - uint256 _initialAmount, - string memory _tokenName, - uint8 _decimalUnits, - string memory _tokenSymbol - ) { - totalSupply = _initialAmount; - balanceOf[msg.sender] = _initialAmount; - name = _tokenName; - symbol = _tokenSymbol; - decimals = _decimalUnits; - } - - function transfer(address dst, uint256 amount) external override { - balanceOf[msg.sender] = balanceOf[msg.sender].sub( - amount, - "Insufficient balance" - ); - balanceOf[dst] = balanceOf[dst].add(amount, "Balance overflow"); - emit Transfer(msg.sender, dst, amount); - } - - function transferFrom( - address src, - address dst, - uint256 amount - ) external override { - allowance[src][msg.sender] = allowance[src][msg.sender].sub( - amount, - "Insufficient allowance" - ); - balanceOf[src] = balanceOf[src].sub(amount, "Insufficient balance"); - balanceOf[dst] = balanceOf[dst].add(amount, "Balance overflow"); - emit Transfer(src, dst, amount); - } - - function approve(address _spender, uint256 amount) - external - override - returns (bool) - { - allowance[msg.sender][_spender] = amount; - emit Approval(msg.sender, _spender, amount); - return true; - } -} - -contract ERC20Harness is StandardToken { - using SafeMath for uint256; - - // To support testing, we can specify addresses for which transferFrom should fail and return false - mapping(address => bool) public failTransferFromAddresses; - - // To support testing, we allow the contract to always fail `transfer`. - mapping(address => bool) public failTransferToAddresses; - - constructor( - uint256 _initialAmount, - string memory _tokenName, - uint8 _decimalUnits, - string memory _tokenSymbol - ) StandardToken(_initialAmount, _tokenName, _decimalUnits, _tokenSymbol) {} - - function harnessSetFailTransferFromAddress(address src, bool _fail) public { - failTransferFromAddresses[src] = _fail; - } - - function harnessSetFailTransferToAddress(address dst, bool _fail) public { - failTransferToAddresses[dst] = _fail; - } - - function harnessSetBalance(address _account, uint256 _amount) public { - balanceOf[_account] = _amount; - } - - function transfer(address dst, uint256 amount) - external - override - returns (bool success) - { - // Added for testing purposes - if (failTransferToAddresses[dst]) { - return false; - } - balanceOf[msg.sender] = balanceOf[msg.sender].sub( - amount, - "Insufficient balance" - ); - balanceOf[dst] = balanceOf[dst].add(amount, "Balance overflow"); - emit Transfer(msg.sender, dst, amount); - return true; - } - - function transferFrom( - address src, - address dst, - uint256 amount - ) external override returns (bool success) { - // Added for testing purposes - if (failTransferFromAddresses[src]) { - return false; - } - allowance[src][msg.sender] = allowance[src][msg.sender].sub( - amount, - "Insufficient allowance" - ); - balanceOf[src] = balanceOf[src].sub(amount, "Insufficient balance"); - balanceOf[dst] = balanceOf[dst].add(amount, "Balance overflow"); - emit Transfer(src, dst, amount); - return true; - } -} diff --git a/flatten/ErrorReporter.sol b/flatten/ErrorReporter.sol deleted file mode 100644 index 381d601..0000000 --- a/flatten/ErrorReporter.sol +++ /dev/null @@ -1,220 +0,0 @@ -// Root file: contracts/ErrorReporter.sol - -// SPDX-License-Identifier: UNLICENSED -pragma solidity 0.8.6; - -contract ComptrollerErrorReporter { - enum Error { - NO_ERROR, - UNAUTHORIZED, - COMPTROLLER_MISMATCH, - INSUFFICIENT_SHORTFALL, - INSUFFICIENT_LIQUIDITY, - INVALID_CLOSE_FACTOR, - INVALID_COLLATERAL_FACTOR, - INVALID_LIQUIDATION_INCENTIVE, - MARKET_NOT_ENTERED, // no longer possible - MARKET_NOT_LISTED, - MARKET_ALREADY_LISTED, - MATH_ERROR, - NONZERO_BORROW_BALANCE, - PRICE_ERROR, - REJECTION, - SNAPSHOT_ERROR, - TOO_MANY_ASSETS, - TOO_MUCH_REPAY - } - - enum FailureInfo { - ACCEPT_ADMIN_PENDING_ADMIN_CHECK, - ACCEPT_PENDING_IMPLEMENTATION_ADDRESS_CHECK, - EXIT_MARKET_BALANCE_OWED, - EXIT_MARKET_REJECTION, - SET_CLOSE_FACTOR_OWNER_CHECK, - SET_CLOSE_FACTOR_VALIDATION, - SET_COLLATERAL_FACTOR_OWNER_CHECK, - SET_COLLATERAL_FACTOR_NO_EXISTS, - SET_COLLATERAL_FACTOR_VALIDATION, - SET_COLLATERAL_FACTOR_WITHOUT_PRICE, - SET_IMPLEMENTATION_OWNER_CHECK, - SET_LIQUIDATION_INCENTIVE_OWNER_CHECK, - SET_LIQUIDATION_INCENTIVE_VALIDATION, - SET_MAX_ASSETS_OWNER_CHECK, - SET_PENDING_ADMIN_OWNER_CHECK, - SET_PENDING_IMPLEMENTATION_OWNER_CHECK, - SET_PRICE_ORACLE_OWNER_CHECK, - SUPPORT_MARKET_EXISTS, - SUPPORT_MARKET_OWNER_CHECK, - SET_PAUSE_GUARDIAN_OWNER_CHECK - } - - /** - * @dev `error` corresponds to enum Error; `info` corresponds to enum FailureInfo, and `detail` is an arbitrary - * contract-specific code that enables us to report opaque error codes from upgradeable contracts. - **/ - event Failure(uint256 error, uint256 info, uint256 detail); - - /** - * @dev use this when reporting a known error from the money market or a non-upgradeable collaborator - */ - function fail(Error err, FailureInfo info) internal returns (uint256) { - emit Failure(uint256(err), uint256(info), 0); - - return uint256(err); - } - - /** - * @dev use this when reporting an opaque error from an upgradeable collaborator contract - */ - function failOpaque( - Error err, - FailureInfo info, - uint256 opaqueError - ) internal returns (uint256) { - emit Failure(uint256(err), uint256(info), opaqueError); - - return uint256(err); - } -} - -contract TokenErrorReporter { - enum Error { - NO_ERROR, - UNAUTHORIZED, - BAD_INPUT, - COMPTROLLER_REJECTION, - COMPTROLLER_CALCULATION_ERROR, - INTEREST_RATE_MODEL_ERROR, - INVALID_ACCOUNT_PAIR, - INVALID_CLOSE_AMOUNT_REQUESTED, - INVALID_COLLATERAL_FACTOR, - MATH_ERROR, - MARKET_NOT_FRESH, - MARKET_NOT_LISTED, - TOKEN_INSUFFICIENT_ALLOWANCE, - TOKEN_INSUFFICIENT_BALANCE, - TOKEN_INSUFFICIENT_CASH, - TOKEN_TRANSFER_IN_FAILED, - TOKEN_TRANSFER_OUT_FAILED - } - - /* - * Note: FailureInfo (but not Error) is kept in alphabetical order - * This is because FailureInfo grows significantly faster, and - * the order of Error has some meaning, while the order of FailureInfo - * is entirely arbitrary. - */ - enum FailureInfo { - ACCEPT_ADMIN_PENDING_ADMIN_CHECK, - ACCRUE_INTEREST_ACCUMULATED_INTEREST_CALCULATION_FAILED, - ACCRUE_INTEREST_BORROW_RATE_CALCULATION_FAILED, - ACCRUE_INTEREST_NEW_BORROW_INDEX_CALCULATION_FAILED, - ACCRUE_INTEREST_NEW_TOTAL_BORROWS_CALCULATION_FAILED, - ACCRUE_INTEREST_NEW_TOTAL_RESERVES_CALCULATION_FAILED, - ACCRUE_INTEREST_SIMPLE_INTEREST_FACTOR_CALCULATION_FAILED, - BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED, - BORROW_ACCRUE_INTEREST_FAILED, - BORROW_CASH_NOT_AVAILABLE, - BORROW_FRESHNESS_CHECK, - BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED, - BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED, - BORROW_MARKET_NOT_LISTED, - BORROW_COMPTROLLER_REJECTION, - LIQUIDATE_ACCRUE_BORROW_INTEREST_FAILED, - LIQUIDATE_ACCRUE_COLLATERAL_INTEREST_FAILED, - LIQUIDATE_COLLATERAL_FRESHNESS_CHECK, - LIQUIDATE_COMPTROLLER_REJECTION, - LIQUIDATE_COMPTROLLER_CALCULATE_AMOUNT_SEIZE_FAILED, - LIQUIDATE_CLOSE_AMOUNT_IS_UINT_MAX, - LIQUIDATE_CLOSE_AMOUNT_IS_ZERO, - LIQUIDATE_FRESHNESS_CHECK, - LIQUIDATE_LIQUIDATOR_IS_BORROWER, - LIQUIDATE_REPAY_BORROW_FRESH_FAILED, - LIQUIDATE_SEIZE_BALANCE_INCREMENT_FAILED, - LIQUIDATE_SEIZE_BALANCE_DECREMENT_FAILED, - LIQUIDATE_SEIZE_COMPTROLLER_REJECTION, - LIQUIDATE_SEIZE_LIQUIDATOR_IS_BORROWER, - LIQUIDATE_SEIZE_TOO_MUCH, - MINT_ACCRUE_INTEREST_FAILED, - MINT_COMPTROLLER_REJECTION, - MINT_EXCHANGE_CALCULATION_FAILED, - MINT_EXCHANGE_RATE_READ_FAILED, - MINT_FRESHNESS_CHECK, - MINT_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED, - MINT_NEW_TOTAL_SUPPLY_CALCULATION_FAILED, - MINT_TRANSFER_IN_FAILED, - MINT_TRANSFER_IN_NOT_POSSIBLE, - REDEEM_ACCRUE_INTEREST_FAILED, - REDEEM_COMPTROLLER_REJECTION, - REDEEM_EXCHANGE_TOKENS_CALCULATION_FAILED, - REDEEM_EXCHANGE_AMOUNT_CALCULATION_FAILED, - REDEEM_EXCHANGE_RATE_READ_FAILED, - REDEEM_FRESHNESS_CHECK, - REDEEM_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED, - REDEEM_NEW_TOTAL_SUPPLY_CALCULATION_FAILED, - REDEEM_TRANSFER_OUT_NOT_POSSIBLE, - REDUCE_RESERVES_ACCRUE_INTEREST_FAILED, - REDUCE_RESERVES_ADMIN_CHECK, - REDUCE_RESERVES_CASH_NOT_AVAILABLE, - REDUCE_RESERVES_FRESH_CHECK, - REDUCE_RESERVES_VALIDATION, - REPAY_BEHALF_ACCRUE_INTEREST_FAILED, - REPAY_BORROW_ACCRUE_INTEREST_FAILED, - REPAY_BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED, - REPAY_BORROW_COMPTROLLER_REJECTION, - REPAY_BORROW_FRESHNESS_CHECK, - REPAY_BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED, - REPAY_BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED, - REPAY_BORROW_TRANSFER_IN_NOT_POSSIBLE, - SET_COLLATERAL_FACTOR_OWNER_CHECK, - SET_COLLATERAL_FACTOR_VALIDATION, - SET_COMPTROLLER_OWNER_CHECK, - SET_INTEREST_RATE_MODEL_ACCRUE_INTEREST_FAILED, - SET_INTEREST_RATE_MODEL_FRESH_CHECK, - SET_INTEREST_RATE_MODEL_OWNER_CHECK, - SET_MAX_ASSETS_OWNER_CHECK, - SET_ORACLE_MARKET_NOT_LISTED, - SET_PENDING_ADMIN_OWNER_CHECK, - SET_RESERVE_FACTOR_ACCRUE_INTEREST_FAILED, - SET_RESERVE_FACTOR_ADMIN_CHECK, - SET_RESERVE_FACTOR_FRESH_CHECK, - SET_RESERVE_FACTOR_BOUNDS_CHECK, - TRANSFER_COMPTROLLER_REJECTION, - TRANSFER_NOT_ALLOWED, - TRANSFER_NOT_ENOUGH, - TRANSFER_TOO_MUCH, - ADD_RESERVES_ACCRUE_INTEREST_FAILED, - ADD_RESERVES_FRESH_CHECK, - ADD_RESERVES_TRANSFER_IN_NOT_POSSIBLE, - ADD_SUBSIDY_FUND_FAILED, - ADD_SUBSIDY_FUND_FRESH_CHECK - } - - /** - * @dev `error` corresponds to enum Error; `info` corresponds to enum FailureInfo, and `detail` is an arbitrary - * contract-specific code that enables us to report opaque error codes from upgradeable contracts. - **/ - event TokenFailure(uint256 error, uint256 info, uint256 detail); - - /** - * @dev use this when reporting a known error from the money market or a non-upgradeable collaborator - */ - function fail(Error err, FailureInfo info) internal returns (uint256) { - emit TokenFailure(uint256(err), uint256(info), 0); - - return uint256(err); - } - - /** - * @dev use this when reporting an opaque error from an upgradeable collaborator contract - */ - function failOpaque( - Error err, - FailureInfo info, - uint256 opaqueError - ) internal returns (uint256) { - emit TokenFailure(uint256(err), uint256(info), opaqueError); - - return uint256(err); - } -} diff --git a/flatten/Exponential.sol b/flatten/Exponential.sol deleted file mode 100644 index 8d48a5a..0000000 --- a/flatten/Exponential.sol +++ /dev/null @@ -1,474 +0,0 @@ -// Dependency file: contracts/CarefulMath.sol - -// SPDX-License-Identifier: UNLICENSED -// pragma solidity 0.8.6; - -/** - * @title Careful Math - * @author tropykus - * @notice Derived from OpenZeppelin's SafeMath library - * https://github.com/OpenZeppelin/openzeppelin-solidity/blob/master/contracts/math/SafeMath.sol - */ -contract CarefulMath { - - /** - * @dev Possible error codes that we can return - */ - enum MathError { - NO_ERROR, - DIVISION_BY_ZERO, - INTEGER_OVERFLOW, - INTEGER_UNDERFLOW - } - - /** - * @dev Multiplies two numbers, returns an error on overflow. - */ - function mulUInt(uint a, uint b) internal pure returns (MathError, uint) { - if (a == 0) { - return (MathError.NO_ERROR, 0); - } - - uint c = a * b; - - if (c / a != b) { - return (MathError.INTEGER_OVERFLOW, 0); - } else { - return (MathError.NO_ERROR, c); - } - } - - /** - * @dev Integer division of two numbers, truncating the quotient. - */ - function divUInt(uint a, uint b) internal pure returns (MathError, uint) { - if (b == 0) { - return (MathError.DIVISION_BY_ZERO, 0); - } - - return (MathError.NO_ERROR, a / b); - } - - /** - * @dev Subtracts two numbers, returns an error on overflow (i.e. if subtrahend is greater than minuend). - */ - function subUInt(uint a, uint b) internal pure returns (MathError, uint) { - if (b <= a) { - return (MathError.NO_ERROR, a - b); - } else { - return (MathError.INTEGER_UNDERFLOW, 0); - } - } - - /** - * @dev Adds two numbers, returns an error on overflow. - */ - function addUInt(uint a, uint b) internal pure returns (MathError, uint) { - uint c = a + b; - - if (c >= a) { - return (MathError.NO_ERROR, c); - } else { - return (MathError.INTEGER_OVERFLOW, 0); - } - } - - /** - * @dev add a and b and then subtract c - */ - function addThenSubUInt(uint a, uint b, uint c) internal pure returns (MathError, uint) { - (MathError err0, uint sum) = addUInt(a, b); - - if (err0 != MathError.NO_ERROR) { - return (err0, 0); - } - - return subUInt(sum, c); - } -} - - -// Dependency file: contracts/ExponentialNoError.sol - -// pragma solidity 0.8.6; - -/** - * @title Exponential module for storing fixed-precision decimals - * @author tropykus - * @notice Exp is a struct which stores decimals with a fixed precision of 18 decimal places. - * Thus, if we wanted to store the 5.1, mantissa would store 5.1e18. That is: - * `Exp({mantissa: 5100000000000000000})`. - */ -contract ExponentialNoError { - uint constant expScale = 1e18; - uint constant doubleScale = 1e36; - uint constant halfExpScale = expScale/2; - uint constant mantissaOne = expScale; - - struct Exp { - uint mantissa; - } - - struct Double { - uint mantissa; - } - - /** - * @dev Truncates the given exp to a whole number value. - * For example, truncate(Exp{mantissa: 15 * expScale}) = 15 - */ - function truncate(Exp memory exp) pure internal returns (uint) { - // Note: We are not using careful math here as we're performing a division that cannot fail - return exp.mantissa / expScale; - } - - /** - * @dev Multiply an Exp by a scalar, then truncate to return an unsigned integer. - */ - function mul_ScalarTruncate(Exp memory a, uint scalar) pure internal returns (uint) { - Exp memory product = mul_(a, scalar); - return truncate(product); - } - - /** - * @dev Multiply an Exp by a scalar, truncate, then add an to an unsigned integer, returning an unsigned integer. - */ - function mul_ScalarTruncateAddUInt(Exp memory a, uint scalar, uint addend) pure internal returns (uint) { - Exp memory product = mul_(a, scalar); - return add_(truncate(product), addend); - } - - /** - * @dev Checks if first Exp is less than second Exp. - */ - function lessThanExp(Exp memory left, Exp memory right) pure internal returns (bool) { - return left.mantissa < right.mantissa; - } - - /** - * @dev Checks if left Exp <= right Exp. - */ - function lessThanOrEqualExp(Exp memory left, Exp memory right) pure internal returns (bool) { - return left.mantissa <= right.mantissa; - } - - /** - * @dev Checks if left Exp > right Exp. - */ - function greaterThanExp(Exp memory left, Exp memory right) pure internal returns (bool) { - return left.mantissa > right.mantissa; - } - - /** - * @dev returns true if Exp is exactly zero - */ - function isZeroExp(Exp memory value) pure internal returns (bool) { - return value.mantissa == 0; - } - - function safe224(uint n, string memory errorMessage) pure internal returns (uint224) { - require(n < 2**224, errorMessage); - return uint224(n); - } - - function safe32(uint n, string memory errorMessage) pure internal returns (uint32) { - require(n < 2**32, errorMessage); - return uint32(n); - } - - function add_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { - return Exp({mantissa: add_(a.mantissa, b.mantissa)}); - } - - function add_(Double memory a, Double memory b) pure internal returns (Double memory) { - return Double({mantissa: add_(a.mantissa, b.mantissa)}); - } - - function add_(uint a, uint b) pure internal returns (uint) { - return add_(a, b, "addition overflow"); - } - - function add_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { - uint c = a + b; - require(c >= a, errorMessage); - return c; - } - - function sub_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { - return Exp({mantissa: sub_(a.mantissa, b.mantissa)}); - } - - function sub_(Double memory a, Double memory b) pure internal returns (Double memory) { - return Double({mantissa: sub_(a.mantissa, b.mantissa)}); - } - - function sub_(uint a, uint b) pure internal returns (uint) { - return sub_(a, b, "subtraction underflow"); - } - - function sub_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { - require(b <= a, errorMessage); - return a - b; - } - - function mul_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { - return Exp({mantissa: mul_(a.mantissa, b.mantissa) / expScale}); - } - - function mul_(Exp memory a, uint b) pure internal returns (Exp memory) { - return Exp({mantissa: mul_(a.mantissa, b)}); - } - - function mul_(uint a, Exp memory b) pure internal returns (uint) { - return mul_(a, b.mantissa) / expScale; - } - - function mul_(Double memory a, Double memory b) pure internal returns (Double memory) { - return Double({mantissa: mul_(a.mantissa, b.mantissa) / doubleScale}); - } - - function mul_(Double memory a, uint b) pure internal returns (Double memory) { - return Double({mantissa: mul_(a.mantissa, b)}); - } - - function mul_(uint a, Double memory b) pure internal returns (uint) { - return mul_(a, b.mantissa) / doubleScale; - } - - function mul_(uint a, uint b) pure internal returns (uint) { - return mul_(a, b, "multiplication overflow"); - } - - function mul_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { - if (a == 0 || b == 0) { - return 0; - } - uint c = a * b; - require(c / a == b, errorMessage); - return c; - } - - function div_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { - return Exp({mantissa: div_(mul_(a.mantissa, expScale), b.mantissa)}); - } - - function div_(Exp memory a, uint b) pure internal returns (Exp memory) { - return Exp({mantissa: div_(a.mantissa, b)}); - } - - function div_(uint a, Exp memory b) pure internal returns (uint) { - return div_(mul_(a, expScale), b.mantissa); - } - - function div_(Double memory a, Double memory b) pure internal returns (Double memory) { - return Double({mantissa: div_(mul_(a.mantissa, doubleScale), b.mantissa)}); - } - - function div_(Double memory a, uint b) pure internal returns (Double memory) { - return Double({mantissa: div_(a.mantissa, b)}); - } - - function div_(uint a, Double memory b) pure internal returns (uint) { - return div_(mul_(a, doubleScale), b.mantissa); - } - - function div_(uint a, uint b) pure internal returns (uint) { - return div_(a, b, "divide by zero"); - } - - function div_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { - require(b > 0, errorMessage); - return a / b; - } - - function fraction(uint a, uint b) pure internal returns (Double memory) { - return Double({mantissa: div_(mul_(a, doubleScale), b)}); - } -} - - -// Root file: contracts/Exponential.sol - -pragma solidity 0.8.6; - -// import "contracts/CarefulMath.sol"; -// import "contracts/ExponentialNoError.sol"; - -/** - * @title Exponential module for storing fixed-precision decimals - * @author tropykus - * @dev Legacy contract for compatibility reasons with existing contracts that still use MathError - * @notice Exp is a struct which stores decimals with a fixed precision of 18 decimal places. - * Thus, if we wanted to store the 5.1, mantissa would store 5.1e18. That is: - * `Exp({mantissa: 5100000000000000000})`. - */ -contract Exponential is CarefulMath, ExponentialNoError { - /** - * @dev Creates an exponential from numerator and denominator values. - * Note: Returns an error if (`num` * 10e18) > MAX_INT, - * or if `denom` is zero. - */ - function getExp(uint num, uint denom) internal pure returns (MathError, Exp memory) { - (MathError err0, uint scaledNumerator) = mulUInt(num, expScale); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - - (MathError err1, uint rational) = divUInt(scaledNumerator, denom); - if (err1 != MathError.NO_ERROR) { - return (err1, Exp({mantissa: 0})); - } - - return (MathError.NO_ERROR, Exp({mantissa: rational})); - } - - /** - * @dev Adds two exponentials, returning a new exponential. - */ - function addExp(Exp memory a, Exp memory b) internal pure returns (MathError, Exp memory) { - (MathError error, uint result) = addUInt(a.mantissa, b.mantissa); - - return (error, Exp({mantissa: result})); - } - - /** - * @dev Subtracts two exponentials, returning a new exponential. - */ - function subExp(Exp memory a, Exp memory b) internal pure returns (MathError, Exp memory) { - (MathError error, uint result) = subUInt(a.mantissa, b.mantissa); - - return (error, Exp({mantissa: result})); - } - - /** - * @dev Multiply an Exp by a scalar, returning a new Exp. - */ - function mulScalar(Exp memory a, uint scalar) internal pure returns (MathError, Exp memory) { - (MathError err0, uint scaledMantissa) = mulUInt(a.mantissa, scalar); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - - return (MathError.NO_ERROR, Exp({mantissa: scaledMantissa})); - } - - /** - * @dev Multiply an Exp by a scalar, then truncate to return an unsigned integer. - */ - function mulScalarTruncate(Exp memory a, uint scalar) internal pure returns (MathError, uint) { - (MathError err, Exp memory product) = mulScalar(a, scalar); - if (err != MathError.NO_ERROR) { - return (err, 0); - } - - return (MathError.NO_ERROR, truncate(product)); - } - - /** - * @dev Multiply an Exp by a scalar, truncate, then add an to an unsigned integer, returning an unsigned integer. - */ - function mulScalarTruncateAddUInt(Exp memory a, uint scalar, uint addend) internal pure returns (MathError, uint) { - (MathError err, Exp memory product) = mulScalar(a, scalar); - if (err != MathError.NO_ERROR) { - return (err, 0); - } - - return addUInt(truncate(product), addend); - } - - /** - * @dev Divide an Exp by a scalar, returning a new Exp. - */ - function divScalar(Exp memory a, uint scalar) internal pure returns (MathError, Exp memory) { - (MathError err0, uint descaledMantissa) = divUInt(a.mantissa, scalar); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - - return (MathError.NO_ERROR, Exp({mantissa: descaledMantissa})); - } - - /** - * @dev Divide a scalar by an Exp, returning a new Exp. - */ - function divScalarByExp(uint scalar, Exp memory divisor) internal pure returns (MathError, Exp memory) { - /* - We are doing this as: - getExp(mulUInt(expScale, scalar), divisor.mantissa) - - How it works: - Exp = a / b; - Scalar = s; - `s / (a / b)` = `b * s / a` and since for an Exp `a = mantissa, b = expScale` - */ - (MathError err0, uint numerator) = mulUInt(expScale, scalar); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - return getExp(numerator, divisor.mantissa); - } - - /** - * @dev Divide a scalar by an Exp, then truncate to return an unsigned integer. - */ - function divScalarByExpTruncate(uint scalar, Exp memory divisor) internal pure returns (MathError, uint) { - (MathError err, Exp memory fraction) = divScalarByExp(scalar, divisor); - if (err != MathError.NO_ERROR) { - return (err, 0); - } - - return (MathError.NO_ERROR, truncate(fraction)); - } - - /** - * @dev Multiplies two exponentials, returning a new exponential. - */ - function mulExp(Exp memory a, Exp memory b) internal pure returns (MathError, Exp memory) { - - (MathError err0, uint doubleScaledProduct) = mulUInt(a.mantissa, b.mantissa); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - - // We add half the scale before dividing so that we get rounding instead of truncation. - // See "Listing 6" and text above it at https://accu.org/index.php/journals/1717 - // Without this change, a result like 6.6...e-19 will be truncated to 0 instead of being rounded to 1e-18. - (MathError err1, uint doubleScaledProductWithHalfScale) = addUInt(halfExpScale, doubleScaledProduct); - if (err1 != MathError.NO_ERROR) { - return (err1, Exp({mantissa: 0})); - } - - (MathError err2, uint product) = divUInt(doubleScaledProductWithHalfScale, expScale); - // The only error `div` can return is MathError.DIVISION_BY_ZERO but we control `expScale` and it is not zero. - assert(err2 == MathError.NO_ERROR); - - return (MathError.NO_ERROR, Exp({mantissa: product})); - } - - /** - * @dev Multiplies two exponentials given their mantissas, returning a new exponential. - */ - function mulExp(uint a, uint b) internal pure returns (MathError, Exp memory) { - return mulExp(Exp({mantissa: a}), Exp({mantissa: b})); - } - - /** - * @dev Multiplies three exponentials, returning a new exponential. - */ - function mulExp3(Exp memory a, Exp memory b, Exp memory c) internal pure returns (MathError, Exp memory) { - (MathError err, Exp memory ab) = mulExp(a, b); - if (err != MathError.NO_ERROR) { - return (err, ab); - } - return mulExp(ab, c); - } - - /** - * @dev Divides two exponentials, returning a new exponential. - * (a/scale) / (b/scale) = (a/scale) * (scale/b) = a/b, - * which we can scale as an Exp by calling getExp(a.mantissa, b.mantissa) - */ - function divExp(Exp memory a, Exp memory b) internal pure returns (MathError, Exp memory) { - return getExp(a.mantissa, b.mantissa); - } -} diff --git a/flatten/ExponentialNoError.sol b/flatten/ExponentialNoError.sol deleted file mode 100644 index cf1cb17..0000000 --- a/flatten/ExponentialNoError.sol +++ /dev/null @@ -1,198 +0,0 @@ -// Root file: contracts/ExponentialNoError.sol - -// SPDX-License-Identifier: UNLICENSED -pragma solidity 0.8.6; - -/** - * @title Exponential module for storing fixed-precision decimals - * @author tropykus - * @notice Exp is a struct which stores decimals with a fixed precision of 18 decimal places. - * Thus, if we wanted to store the 5.1, mantissa would store 5.1e18. That is: - * `Exp({mantissa: 5100000000000000000})`. - */ -contract ExponentialNoError { - uint constant expScale = 1e18; - uint constant doubleScale = 1e36; - uint constant halfExpScale = expScale/2; - uint constant mantissaOne = expScale; - - struct Exp { - uint mantissa; - } - - struct Double { - uint mantissa; - } - - /** - * @dev Truncates the given exp to a whole number value. - * For example, truncate(Exp{mantissa: 15 * expScale}) = 15 - */ - function truncate(Exp memory exp) pure internal returns (uint) { - // Note: We are not using careful math here as we're performing a division that cannot fail - return exp.mantissa / expScale; - } - - /** - * @dev Multiply an Exp by a scalar, then truncate to return an unsigned integer. - */ - function mul_ScalarTruncate(Exp memory a, uint scalar) pure internal returns (uint) { - Exp memory product = mul_(a, scalar); - return truncate(product); - } - - /** - * @dev Multiply an Exp by a scalar, truncate, then add an to an unsigned integer, returning an unsigned integer. - */ - function mul_ScalarTruncateAddUInt(Exp memory a, uint scalar, uint addend) pure internal returns (uint) { - Exp memory product = mul_(a, scalar); - return add_(truncate(product), addend); - } - - /** - * @dev Checks if first Exp is less than second Exp. - */ - function lessThanExp(Exp memory left, Exp memory right) pure internal returns (bool) { - return left.mantissa < right.mantissa; - } - - /** - * @dev Checks if left Exp <= right Exp. - */ - function lessThanOrEqualExp(Exp memory left, Exp memory right) pure internal returns (bool) { - return left.mantissa <= right.mantissa; - } - - /** - * @dev Checks if left Exp > right Exp. - */ - function greaterThanExp(Exp memory left, Exp memory right) pure internal returns (bool) { - return left.mantissa > right.mantissa; - } - - /** - * @dev returns true if Exp is exactly zero - */ - function isZeroExp(Exp memory value) pure internal returns (bool) { - return value.mantissa == 0; - } - - function safe224(uint n, string memory errorMessage) pure internal returns (uint224) { - require(n < 2**224, errorMessage); - return uint224(n); - } - - function safe32(uint n, string memory errorMessage) pure internal returns (uint32) { - require(n < 2**32, errorMessage); - return uint32(n); - } - - function add_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { - return Exp({mantissa: add_(a.mantissa, b.mantissa)}); - } - - function add_(Double memory a, Double memory b) pure internal returns (Double memory) { - return Double({mantissa: add_(a.mantissa, b.mantissa)}); - } - - function add_(uint a, uint b) pure internal returns (uint) { - return add_(a, b, "addition overflow"); - } - - function add_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { - uint c = a + b; - require(c >= a, errorMessage); - return c; - } - - function sub_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { - return Exp({mantissa: sub_(a.mantissa, b.mantissa)}); - } - - function sub_(Double memory a, Double memory b) pure internal returns (Double memory) { - return Double({mantissa: sub_(a.mantissa, b.mantissa)}); - } - - function sub_(uint a, uint b) pure internal returns (uint) { - return sub_(a, b, "subtraction underflow"); - } - - function sub_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { - require(b <= a, errorMessage); - return a - b; - } - - function mul_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { - return Exp({mantissa: mul_(a.mantissa, b.mantissa) / expScale}); - } - - function mul_(Exp memory a, uint b) pure internal returns (Exp memory) { - return Exp({mantissa: mul_(a.mantissa, b)}); - } - - function mul_(uint a, Exp memory b) pure internal returns (uint) { - return mul_(a, b.mantissa) / expScale; - } - - function mul_(Double memory a, Double memory b) pure internal returns (Double memory) { - return Double({mantissa: mul_(a.mantissa, b.mantissa) / doubleScale}); - } - - function mul_(Double memory a, uint b) pure internal returns (Double memory) { - return Double({mantissa: mul_(a.mantissa, b)}); - } - - function mul_(uint a, Double memory b) pure internal returns (uint) { - return mul_(a, b.mantissa) / doubleScale; - } - - function mul_(uint a, uint b) pure internal returns (uint) { - return mul_(a, b, "multiplication overflow"); - } - - function mul_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { - if (a == 0 || b == 0) { - return 0; - } - uint c = a * b; - require(c / a == b, errorMessage); - return c; - } - - function div_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { - return Exp({mantissa: div_(mul_(a.mantissa, expScale), b.mantissa)}); - } - - function div_(Exp memory a, uint b) pure internal returns (Exp memory) { - return Exp({mantissa: div_(a.mantissa, b)}); - } - - function div_(uint a, Exp memory b) pure internal returns (uint) { - return div_(mul_(a, expScale), b.mantissa); - } - - function div_(Double memory a, Double memory b) pure internal returns (Double memory) { - return Double({mantissa: div_(mul_(a.mantissa, doubleScale), b.mantissa)}); - } - - function div_(Double memory a, uint b) pure internal returns (Double memory) { - return Double({mantissa: div_(a.mantissa, b)}); - } - - function div_(uint a, Double memory b) pure internal returns (uint) { - return div_(mul_(a, doubleScale), b.mantissa); - } - - function div_(uint a, uint b) pure internal returns (uint) { - return div_(a, b, "divide by zero"); - } - - function div_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { - require(b > 0, errorMessage); - return a / b; - } - - function fraction(uint a, uint b) pure internal returns (Double memory) { - return Double({mantissa: div_(mul_(a, doubleScale), b)}); - } -} diff --git a/flatten/GovernorAlpha.sol b/flatten/GovernorAlpha.sol deleted file mode 100644 index ef81dba..0000000 --- a/flatten/GovernorAlpha.sol +++ /dev/null @@ -1,548 +0,0 @@ -// Root file: contracts/Governance/GovernorAlpha.sol - -// SPDX-License-Identifier: UNLICENSED -pragma solidity 0.8.6; -pragma experimental ABIEncoderV2; - -/** - * @title Governor contract to vote on tropykus platform using TROP tokens. - * @author tropykus - * @notice This contract allows to propose and vote for protocol changes using the TROP tokens. - */ -contract GovernorAlpha { - /// @notice The name of this contract - string public constant name = "Compound Governor Alpha"; - - /// @notice The number of votes in support of a proposal required in order for a quorum to be reached and for a vote to succeed - function quorumVotes() public pure returns (uint256) { - return 400000e18; - } // 400,000 = 4% of Comp - - /// @notice The number of votes required in order for a voter to become a proposer - function proposalThreshold() public pure returns (uint256) { - return 100000e18; - } // 100,000 = 1% of Comp - - /// @notice The maximum number of actions that can be included in a proposal - function proposalMaxOperations() public pure returns (uint256) { - return 10; - } // 10 actions - - /// @notice The delay before voting on a proposal may take place, once proposed - function votingDelay() public pure returns (uint256) { - return 1; - } // 1 block - - /// @notice The duration of voting on a proposal, in blocks - function votingPeriod() public pure virtual returns (uint256) { - return 17280; - } // ~3 days in blocks (assuming 15s blocks) - - /// @notice The address of the Compound Protocol Timelock - TimelockInterface public timelock; - - /// @notice The address of the Compound governance token - CompInterface public comp; - - /// @notice The address of the Governor Guardian - address public guardian; - - /// @notice The total number of proposals - uint256 public proposalCount; - - struct Proposal { - /// @notice Unique id for looking up a proposal - uint256 id; - /// @notice Creator of the proposal - address proposer; - /// @notice The timestamp that the proposal will be available for execution, set once the vote succeeds - uint256 eta; - /// @notice the ordered list of target addresses for calls to be made - address[] targets; - /// @notice The ordered list of values (i.e. msg.value) to be passed to the calls to be made - uint256[] values; - /// @notice The ordered list of function signatures to be called - string[] signatures; - /// @notice The ordered list of calldata to be passed to each call - bytes[] calldatas; - /// @notice The block at which voting begins: holders must delegate their votes prior to this block - uint256 startBlock; - /// @notice The block at which voting ends: votes must be cast prior to this block - uint256 endBlock; - /// @notice Current number of votes in favor of this proposal - uint256 forVotes; - /// @notice Current number of votes in opposition to this proposal - uint256 againstVotes; - /// @notice Flag marking whether the proposal has been canceled - bool canceled; - /// @notice Flag marking whether the proposal has been executed - bool executed; - /// @notice Receipts of ballots for the entire set of voters - mapping(address => Receipt) receipts; - } - - /// @notice Ballot receipt record for a voter - struct Receipt { - /// @notice Whether or not a vote has been cast - bool hasVoted; - /// @notice Whether or not the voter supports the proposal - bool support; - /// @notice The number of votes the voter had, which were cast - uint96 votes; - } - - /// @notice Possible states that a proposal may be in - enum ProposalState { - Pending, - Active, - Canceled, - Defeated, - Succeeded, - Queued, - Expired, - Executed - } - - /// @notice The official record of all proposals ever proposed - mapping(uint256 => Proposal) public proposals; - - /// @notice The latest proposal for each proposer - mapping(address => uint256) public latestProposalIds; - - /// @notice The EIP-712 typehash for the contract's domain - bytes32 public constant DOMAIN_TYPEHASH = - keccak256( - "EIP712Domain(string name,uint256 chainId,address verifyingContract)" - ); - - /// @notice The EIP-712 typehash for the ballot struct used by the contract - bytes32 public constant BALLOT_TYPEHASH = - keccak256("Ballot(uint256 proposalId,bool support)"); - - /// @notice An event emitted when a new proposal is created - event ProposalCreated( - uint256 id, - address proposer, - address[] targets, - uint256[] values, - string[] signatures, - bytes[] calldatas, - uint256 startBlock, - uint256 endBlock, - string description - ); - - /// @notice An event emitted when a vote has been cast on a proposal - event VoteCast( - address voter, - uint256 proposalId, - bool support, - uint256 votes - ); - - /// @notice An event emitted when a proposal has been canceled - event ProposalCanceled(uint256 id); - - /// @notice An event emitted when a proposal has been queued in the Timelock - event ProposalQueued(uint256 id, uint256 eta); - - /// @notice An event emitted when a proposal has been executed in the Timelock - event ProposalExecuted(uint256 id); - - constructor( - address timelock_, - address comp_, - address guardian_ - ) { - timelock = TimelockInterface(timelock_); - comp = CompInterface(comp_); - guardian = guardian_; - } - - function propose( - address[] memory targets, - uint256[] memory values, - string[] memory signatures, - bytes[] memory calldatas, - string memory description - ) public returns (uint256) { - require( - comp.getPriorVotes(msg.sender, sub256(block.number, 1)) > - proposalThreshold(), - "GovernorAlpha::propose: proposer votes below proposal threshold" - ); - require( - targets.length == values.length && - targets.length == signatures.length && - targets.length == calldatas.length, - "GovernorAlpha::propose: proposal function information arity mismatch" - ); - require( - targets.length != 0, - "GovernorAlpha::propose: must provide actions" - ); - require( - targets.length <= proposalMaxOperations(), - "GovernorAlpha::propose: too many actions" - ); - - uint256 latestProposalId = latestProposalIds[msg.sender]; - if (latestProposalId != 0) { - ProposalState proposersLatestProposalState = state( - latestProposalId - ); - require( - proposersLatestProposalState != ProposalState.Active, - "GovernorAlpha::propose: one live proposal per proposer" - ); - require( - proposersLatestProposalState != ProposalState.Pending, - "GovernorAlpha::propose: one live proposal per proposer" - ); - } - - uint256 startBlock = add256(block.number, votingDelay()); - uint256 endBlock = add256(startBlock, votingPeriod()); - - proposalCount++; - Proposal storage newProposal = proposals[proposalCount]; - newProposal.id = proposalCount; - newProposal.proposer = msg.sender; - newProposal.eta = 0; - newProposal.targets = targets; - newProposal.values = values; - newProposal.signatures = signatures; - newProposal.calldatas = calldatas; - newProposal.startBlock = startBlock; - newProposal.endBlock = endBlock; - newProposal.forVotes = 0; - newProposal.againstVotes = 0; - newProposal.canceled = false; - newProposal.executed = false; - - latestProposalIds[newProposal.proposer] = newProposal.id; - - emit ProposalCreated( - newProposal.id, - msg.sender, - targets, - values, - signatures, - calldatas, - startBlock, - endBlock, - description - ); - return newProposal.id; - } - - function queue(uint256 proposalId) public { - require( - state(proposalId) == ProposalState.Succeeded, - "GovernorAlpha::queue: proposal can only be queued if it is succeeded" - ); - Proposal storage proposal = proposals[proposalId]; - uint256 eta = add256(block.timestamp, timelock.delay()); - for (uint256 i = 0; i < proposal.targets.length; i++) { - _queueOrRevert( - proposal.targets[i], - proposal.values[i], - proposal.signatures[i], - proposal.calldatas[i], - eta - ); - } - proposal.eta = eta; - emit ProposalQueued(proposalId, eta); - } - - function _queueOrRevert( - address target, - uint256 value, - string memory signature, - bytes memory data, - uint256 eta - ) internal { - require( - !timelock.queuedTransactions( - keccak256(abi.encode(target, value, signature, data, eta)) - ), - "GovernorAlpha::_queueOrRevert: proposal action already queued at eta" - ); - timelock.queueTransaction(target, value, signature, data, eta); - } - - function execute(uint256 proposalId) public payable { - require( - state(proposalId) == ProposalState.Queued, - "GovernorAlpha::execute: proposal can only be executed if it is queued" - ); - Proposal storage proposal = proposals[proposalId]; - proposal.executed = true; - for (uint256 i = 0; i < proposal.targets.length; i++) { - timelock.executeTransaction{value: proposal.values[i]}( - proposal.targets[i], - proposal.values[i], - proposal.signatures[i], - proposal.calldatas[i], - proposal.eta - ); - } - emit ProposalExecuted(proposalId); - } - - function cancel(uint256 proposalId) public { - ProposalState proposalState = state(proposalId); - require( - proposalState != ProposalState.Executed, - "GovernorAlpha::cancel: cannot cancel executed proposal" - ); - - Proposal storage proposal = proposals[proposalId]; - require( - msg.sender == guardian || - comp.getPriorVotes(proposal.proposer, sub256(block.number, 1)) < - proposalThreshold(), - "GovernorAlpha::cancel: proposer above threshold" - ); - - proposal.canceled = true; - for (uint256 i = 0; i < proposal.targets.length; i++) { - timelock.cancelTransaction( - proposal.targets[i], - proposal.values[i], - proposal.signatures[i], - proposal.calldatas[i], - proposal.eta - ); - } - - emit ProposalCanceled(proposalId); - } - - function getActions(uint256 proposalId) - public - view - returns ( - address[] memory targets, - uint256[] memory values, - string[] memory signatures, - bytes[] memory calldatas - ) - { - Proposal storage p = proposals[proposalId]; - return (p.targets, p.values, p.signatures, p.calldatas); - } - - function getReceipt(uint256 proposalId, address voter) - public - view - returns (Receipt memory) - { - return proposals[proposalId].receipts[voter]; - } - - function state(uint256 proposalId) public view returns (ProposalState) { - require( - proposalCount >= proposalId && proposalId > 0, - "GovernorAlpha::state: invalid proposal id" - ); - Proposal storage proposal = proposals[proposalId]; - if (proposal.canceled) { - return ProposalState.Canceled; - } else if (block.number <= proposal.startBlock) { - return ProposalState.Pending; - } else if (block.number <= proposal.endBlock) { - return ProposalState.Active; - } else if ( - proposal.forVotes <= proposal.againstVotes || - proposal.forVotes < quorumVotes() - ) { - return ProposalState.Defeated; - } else if (proposal.eta == 0) { - return ProposalState.Succeeded; - } else if (proposal.executed) { - return ProposalState.Executed; - } else if ( - block.timestamp >= add256(proposal.eta, timelock.GRACE_PERIOD()) - ) { - return ProposalState.Expired; - } else { - return ProposalState.Queued; - } - } - - function castVote(uint256 proposalId, bool support) public { - return _castVote(msg.sender, proposalId, support); - } - - function castVoteBySig( - uint256 proposalId, - bool support, - uint8 v, - bytes32 r, - bytes32 s - ) public { - bytes32 domainSeparator = keccak256( - abi.encode( - DOMAIN_TYPEHASH, - keccak256(bytes(name)), - getChainId(), - address(this) - ) - ); - bytes32 structHash = keccak256( - abi.encode(BALLOT_TYPEHASH, proposalId, support) - ); - bytes32 digest = keccak256( - abi.encodePacked("\x19\x01", domainSeparator, structHash) - ); - address signatory = ecrecover(digest, v, r, s); - require( - signatory != 0xdcc703c0E500B653Ca82273B7BFAd8045D85a470 && - signatory != address(0), - "GovernorAlpha::castVoteBySig: invalid signature" - ); - return _castVote(signatory, proposalId, support); - } - - function _castVote( - address voter, - uint256 proposalId, - bool support - ) internal { - require( - state(proposalId) == ProposalState.Active, - "GovernorAlpha::_castVote: voting is closed" - ); - Proposal storage proposal = proposals[proposalId]; - Receipt storage receipt = proposal.receipts[voter]; - require( - receipt.hasVoted == false, - "GovernorAlpha::_castVote: voter already voted" - ); - uint96 votes = comp.getPriorVotes(voter, proposal.startBlock); - - if (support) { - proposal.forVotes = add256(proposal.forVotes, votes); - } else { - proposal.againstVotes = add256(proposal.againstVotes, votes); - } - - receipt.hasVoted = true; - receipt.support = support; - receipt.votes = votes; - - emit VoteCast(voter, proposalId, support, votes); - } - - function __acceptAdmin() public { - require( - msg.sender == guardian, - "GovernorAlpha::__acceptAdmin: sender must be gov guardian" - ); - timelock.acceptAdmin(); - } - - function __abdicate() public { - require( - msg.sender == guardian, - "GovernorAlpha::__abdicate: sender must be gov guardian" - ); - guardian = address(0); - } - - function __queueSetTimelockPendingAdmin( - address newPendingAdmin, - uint256 eta - ) public { - require( - msg.sender == guardian, - "GovernorAlpha::__queueSetTimelockPendingAdmin: sender must be gov guardian" - ); - timelock.queueTransaction( - address(timelock), - 0, - "setPendingAdmin(address)", - abi.encode(newPendingAdmin), - eta - ); - } - - function __executeSetTimelockPendingAdmin( - address newPendingAdmin, - uint256 eta - ) public { - require( - msg.sender == guardian, - "GovernorAlpha::__executeSetTimelockPendingAdmin: sender must be gov guardian" - ); - timelock.executeTransaction( - address(timelock), - 0, - "setPendingAdmin(address)", - abi.encode(newPendingAdmin), - eta - ); - } - - function add256(uint256 a, uint256 b) internal pure returns (uint256) { - uint256 c = a + b; - require(c >= a, "addition overflow"); - return c; - } - - function sub256(uint256 a, uint256 b) internal pure returns (uint256) { - require(b <= a, "subtraction underflow"); - return a - b; - } - - function getChainId() internal view returns (uint256) { - uint256 chainId; - assembly { - chainId := chainid() - } - return chainId; - } -} - -interface TimelockInterface { - function delay() external view returns (uint256); - - function GRACE_PERIOD() external view returns (uint256); - - function acceptAdmin() external; - - function queuedTransactions(bytes32 hash) external view returns (bool); - - function queueTransaction( - address target, - uint256 value, - string calldata signature, - bytes calldata data, - uint256 eta - ) external returns (bytes32); - - function cancelTransaction( - address target, - uint256 value, - string calldata signature, - bytes calldata data, - uint256 eta - ) external; - - function executeTransaction( - address target, - uint256 value, - string calldata signature, - bytes calldata data, - uint256 eta - ) external payable returns (bytes memory); -} - -interface CompInterface { - function getPriorVotes(address account, uint256 blockNumber) - external - view - returns (uint96); -} diff --git a/flatten/HurricaneInterestRateModel.sol b/flatten/HurricaneInterestRateModel.sol deleted file mode 100644 index 4546146..0000000 --- a/flatten/HurricaneInterestRateModel.sol +++ /dev/null @@ -1,860 +0,0 @@ -// Dependency file: contracts/CarefulMath.sol - -// SPDX-License-Identifier: UNLICENSED -// pragma solidity 0.8.6; - -/** - * @title Careful Math - * @author tropykus - * @notice Derived from OpenZeppelin's SafeMath library - * https://github.com/OpenZeppelin/openzeppelin-solidity/blob/master/contracts/math/SafeMath.sol - */ -contract CarefulMath { - - /** - * @dev Possible error codes that we can return - */ - enum MathError { - NO_ERROR, - DIVISION_BY_ZERO, - INTEGER_OVERFLOW, - INTEGER_UNDERFLOW - } - - /** - * @dev Multiplies two numbers, returns an error on overflow. - */ - function mulUInt(uint a, uint b) internal pure returns (MathError, uint) { - if (a == 0) { - return (MathError.NO_ERROR, 0); - } - - uint c = a * b; - - if (c / a != b) { - return (MathError.INTEGER_OVERFLOW, 0); - } else { - return (MathError.NO_ERROR, c); - } - } - - /** - * @dev Integer division of two numbers, truncating the quotient. - */ - function divUInt(uint a, uint b) internal pure returns (MathError, uint) { - if (b == 0) { - return (MathError.DIVISION_BY_ZERO, 0); - } - - return (MathError.NO_ERROR, a / b); - } - - /** - * @dev Subtracts two numbers, returns an error on overflow (i.e. if subtrahend is greater than minuend). - */ - function subUInt(uint a, uint b) internal pure returns (MathError, uint) { - if (b <= a) { - return (MathError.NO_ERROR, a - b); - } else { - return (MathError.INTEGER_UNDERFLOW, 0); - } - } - - /** - * @dev Adds two numbers, returns an error on overflow. - */ - function addUInt(uint a, uint b) internal pure returns (MathError, uint) { - uint c = a + b; - - if (c >= a) { - return (MathError.NO_ERROR, c); - } else { - return (MathError.INTEGER_OVERFLOW, 0); - } - } - - /** - * @dev add a and b and then subtract c - */ - function addThenSubUInt(uint a, uint b, uint c) internal pure returns (MathError, uint) { - (MathError err0, uint sum) = addUInt(a, b); - - if (err0 != MathError.NO_ERROR) { - return (err0, 0); - } - - return subUInt(sum, c); - } -} - - -// Dependency file: contracts/ExponentialNoError.sol - -// pragma solidity 0.8.6; - -/** - * @title Exponential module for storing fixed-precision decimals - * @author tropykus - * @notice Exp is a struct which stores decimals with a fixed precision of 18 decimal places. - * Thus, if we wanted to store the 5.1, mantissa would store 5.1e18. That is: - * `Exp({mantissa: 5100000000000000000})`. - */ -contract ExponentialNoError { - uint constant expScale = 1e18; - uint constant doubleScale = 1e36; - uint constant halfExpScale = expScale/2; - uint constant mantissaOne = expScale; - - struct Exp { - uint mantissa; - } - - struct Double { - uint mantissa; - } - - /** - * @dev Truncates the given exp to a whole number value. - * For example, truncate(Exp{mantissa: 15 * expScale}) = 15 - */ - function truncate(Exp memory exp) pure internal returns (uint) { - // Note: We are not using careful math here as we're performing a division that cannot fail - return exp.mantissa / expScale; - } - - /** - * @dev Multiply an Exp by a scalar, then truncate to return an unsigned integer. - */ - function mul_ScalarTruncate(Exp memory a, uint scalar) pure internal returns (uint) { - Exp memory product = mul_(a, scalar); - return truncate(product); - } - - /** - * @dev Multiply an Exp by a scalar, truncate, then add an to an unsigned integer, returning an unsigned integer. - */ - function mul_ScalarTruncateAddUInt(Exp memory a, uint scalar, uint addend) pure internal returns (uint) { - Exp memory product = mul_(a, scalar); - return add_(truncate(product), addend); - } - - /** - * @dev Checks if first Exp is less than second Exp. - */ - function lessThanExp(Exp memory left, Exp memory right) pure internal returns (bool) { - return left.mantissa < right.mantissa; - } - - /** - * @dev Checks if left Exp <= right Exp. - */ - function lessThanOrEqualExp(Exp memory left, Exp memory right) pure internal returns (bool) { - return left.mantissa <= right.mantissa; - } - - /** - * @dev Checks if left Exp > right Exp. - */ - function greaterThanExp(Exp memory left, Exp memory right) pure internal returns (bool) { - return left.mantissa > right.mantissa; - } - - /** - * @dev returns true if Exp is exactly zero - */ - function isZeroExp(Exp memory value) pure internal returns (bool) { - return value.mantissa == 0; - } - - function safe224(uint n, string memory errorMessage) pure internal returns (uint224) { - require(n < 2**224, errorMessage); - return uint224(n); - } - - function safe32(uint n, string memory errorMessage) pure internal returns (uint32) { - require(n < 2**32, errorMessage); - return uint32(n); - } - - function add_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { - return Exp({mantissa: add_(a.mantissa, b.mantissa)}); - } - - function add_(Double memory a, Double memory b) pure internal returns (Double memory) { - return Double({mantissa: add_(a.mantissa, b.mantissa)}); - } - - function add_(uint a, uint b) pure internal returns (uint) { - return add_(a, b, "addition overflow"); - } - - function add_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { - uint c = a + b; - require(c >= a, errorMessage); - return c; - } - - function sub_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { - return Exp({mantissa: sub_(a.mantissa, b.mantissa)}); - } - - function sub_(Double memory a, Double memory b) pure internal returns (Double memory) { - return Double({mantissa: sub_(a.mantissa, b.mantissa)}); - } - - function sub_(uint a, uint b) pure internal returns (uint) { - return sub_(a, b, "subtraction underflow"); - } - - function sub_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { - require(b <= a, errorMessage); - return a - b; - } - - function mul_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { - return Exp({mantissa: mul_(a.mantissa, b.mantissa) / expScale}); - } - - function mul_(Exp memory a, uint b) pure internal returns (Exp memory) { - return Exp({mantissa: mul_(a.mantissa, b)}); - } - - function mul_(uint a, Exp memory b) pure internal returns (uint) { - return mul_(a, b.mantissa) / expScale; - } - - function mul_(Double memory a, Double memory b) pure internal returns (Double memory) { - return Double({mantissa: mul_(a.mantissa, b.mantissa) / doubleScale}); - } - - function mul_(Double memory a, uint b) pure internal returns (Double memory) { - return Double({mantissa: mul_(a.mantissa, b)}); - } - - function mul_(uint a, Double memory b) pure internal returns (uint) { - return mul_(a, b.mantissa) / doubleScale; - } - - function mul_(uint a, uint b) pure internal returns (uint) { - return mul_(a, b, "multiplication overflow"); - } - - function mul_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { - if (a == 0 || b == 0) { - return 0; - } - uint c = a * b; - require(c / a == b, errorMessage); - return c; - } - - function div_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { - return Exp({mantissa: div_(mul_(a.mantissa, expScale), b.mantissa)}); - } - - function div_(Exp memory a, uint b) pure internal returns (Exp memory) { - return Exp({mantissa: div_(a.mantissa, b)}); - } - - function div_(uint a, Exp memory b) pure internal returns (uint) { - return div_(mul_(a, expScale), b.mantissa); - } - - function div_(Double memory a, Double memory b) pure internal returns (Double memory) { - return Double({mantissa: div_(mul_(a.mantissa, doubleScale), b.mantissa)}); - } - - function div_(Double memory a, uint b) pure internal returns (Double memory) { - return Double({mantissa: div_(a.mantissa, b)}); - } - - function div_(uint a, Double memory b) pure internal returns (uint) { - return div_(mul_(a, doubleScale), b.mantissa); - } - - function div_(uint a, uint b) pure internal returns (uint) { - return div_(a, b, "divide by zero"); - } - - function div_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { - require(b > 0, errorMessage); - return a / b; - } - - function fraction(uint a, uint b) pure internal returns (Double memory) { - return Double({mantissa: div_(mul_(a, doubleScale), b)}); - } -} - - -// Dependency file: contracts/Exponential.sol - -// pragma solidity 0.8.6; - -// import "contracts/CarefulMath.sol"; -// import "contracts/ExponentialNoError.sol"; - -/** - * @title Exponential module for storing fixed-precision decimals - * @author tropykus - * @dev Legacy contract for compatibility reasons with existing contracts that still use MathError - * @notice Exp is a struct which stores decimals with a fixed precision of 18 decimal places. - * Thus, if we wanted to store the 5.1, mantissa would store 5.1e18. That is: - * `Exp({mantissa: 5100000000000000000})`. - */ -contract Exponential is CarefulMath, ExponentialNoError { - /** - * @dev Creates an exponential from numerator and denominator values. - * Note: Returns an error if (`num` * 10e18) > MAX_INT, - * or if `denom` is zero. - */ - function getExp(uint num, uint denom) internal pure returns (MathError, Exp memory) { - (MathError err0, uint scaledNumerator) = mulUInt(num, expScale); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - - (MathError err1, uint rational) = divUInt(scaledNumerator, denom); - if (err1 != MathError.NO_ERROR) { - return (err1, Exp({mantissa: 0})); - } - - return (MathError.NO_ERROR, Exp({mantissa: rational})); - } - - /** - * @dev Adds two exponentials, returning a new exponential. - */ - function addExp(Exp memory a, Exp memory b) internal pure returns (MathError, Exp memory) { - (MathError error, uint result) = addUInt(a.mantissa, b.mantissa); - - return (error, Exp({mantissa: result})); - } - - /** - * @dev Subtracts two exponentials, returning a new exponential. - */ - function subExp(Exp memory a, Exp memory b) internal pure returns (MathError, Exp memory) { - (MathError error, uint result) = subUInt(a.mantissa, b.mantissa); - - return (error, Exp({mantissa: result})); - } - - /** - * @dev Multiply an Exp by a scalar, returning a new Exp. - */ - function mulScalar(Exp memory a, uint scalar) internal pure returns (MathError, Exp memory) { - (MathError err0, uint scaledMantissa) = mulUInt(a.mantissa, scalar); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - - return (MathError.NO_ERROR, Exp({mantissa: scaledMantissa})); - } - - /** - * @dev Multiply an Exp by a scalar, then truncate to return an unsigned integer. - */ - function mulScalarTruncate(Exp memory a, uint scalar) internal pure returns (MathError, uint) { - (MathError err, Exp memory product) = mulScalar(a, scalar); - if (err != MathError.NO_ERROR) { - return (err, 0); - } - - return (MathError.NO_ERROR, truncate(product)); - } - - /** - * @dev Multiply an Exp by a scalar, truncate, then add an to an unsigned integer, returning an unsigned integer. - */ - function mulScalarTruncateAddUInt(Exp memory a, uint scalar, uint addend) internal pure returns (MathError, uint) { - (MathError err, Exp memory product) = mulScalar(a, scalar); - if (err != MathError.NO_ERROR) { - return (err, 0); - } - - return addUInt(truncate(product), addend); - } - - /** - * @dev Divide an Exp by a scalar, returning a new Exp. - */ - function divScalar(Exp memory a, uint scalar) internal pure returns (MathError, Exp memory) { - (MathError err0, uint descaledMantissa) = divUInt(a.mantissa, scalar); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - - return (MathError.NO_ERROR, Exp({mantissa: descaledMantissa})); - } - - /** - * @dev Divide a scalar by an Exp, returning a new Exp. - */ - function divScalarByExp(uint scalar, Exp memory divisor) internal pure returns (MathError, Exp memory) { - /* - We are doing this as: - getExp(mulUInt(expScale, scalar), divisor.mantissa) - - How it works: - Exp = a / b; - Scalar = s; - `s / (a / b)` = `b * s / a` and since for an Exp `a = mantissa, b = expScale` - */ - (MathError err0, uint numerator) = mulUInt(expScale, scalar); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - return getExp(numerator, divisor.mantissa); - } - - /** - * @dev Divide a scalar by an Exp, then truncate to return an unsigned integer. - */ - function divScalarByExpTruncate(uint scalar, Exp memory divisor) internal pure returns (MathError, uint) { - (MathError err, Exp memory fraction) = divScalarByExp(scalar, divisor); - if (err != MathError.NO_ERROR) { - return (err, 0); - } - - return (MathError.NO_ERROR, truncate(fraction)); - } - - /** - * @dev Multiplies two exponentials, returning a new exponential. - */ - function mulExp(Exp memory a, Exp memory b) internal pure returns (MathError, Exp memory) { - - (MathError err0, uint doubleScaledProduct) = mulUInt(a.mantissa, b.mantissa); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - - // We add half the scale before dividing so that we get rounding instead of truncation. - // See "Listing 6" and text above it at https://accu.org/index.php/journals/1717 - // Without this change, a result like 6.6...e-19 will be truncated to 0 instead of being rounded to 1e-18. - (MathError err1, uint doubleScaledProductWithHalfScale) = addUInt(halfExpScale, doubleScaledProduct); - if (err1 != MathError.NO_ERROR) { - return (err1, Exp({mantissa: 0})); - } - - (MathError err2, uint product) = divUInt(doubleScaledProductWithHalfScale, expScale); - // The only error `div` can return is MathError.DIVISION_BY_ZERO but we control `expScale` and it is not zero. - assert(err2 == MathError.NO_ERROR); - - return (MathError.NO_ERROR, Exp({mantissa: product})); - } - - /** - * @dev Multiplies two exponentials given their mantissas, returning a new exponential. - */ - function mulExp(uint a, uint b) internal pure returns (MathError, Exp memory) { - return mulExp(Exp({mantissa: a}), Exp({mantissa: b})); - } - - /** - * @dev Multiplies three exponentials, returning a new exponential. - */ - function mulExp3(Exp memory a, Exp memory b, Exp memory c) internal pure returns (MathError, Exp memory) { - (MathError err, Exp memory ab) = mulExp(a, b); - if (err != MathError.NO_ERROR) { - return (err, ab); - } - return mulExp(ab, c); - } - - /** - * @dev Divides two exponentials, returning a new exponential. - * (a/scale) / (b/scale) = (a/scale) * (scale/b) = a/b, - * which we can scale as an Exp by calling getExp(a.mantissa, b.mantissa) - */ - function divExp(Exp memory a, Exp memory b) internal pure returns (MathError, Exp memory) { - return getExp(a.mantissa, b.mantissa); - } -} - - -// Dependency file: contracts/SafeMath.sol - -// pragma solidity 0.8.6; - -// From https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/math/Math.sol -// Subject to the MIT license. - -/** - * @dev Wrappers over Solidity's arithmetic operations with added overflow - * checks. - * - * Arithmetic operations in Solidity wrap on overflow. This can easily result - * in bugs, because programmers usually assume that an overflow raises an - * error, which is the standard behavior in high level programming languages. - * `SafeMath` restores this intuition by reverting the transaction when an - * operation overflows. - * - * Using this library instead of the unchecked operations eliminates an entire - * class of bugs, so it's recommended to use it always. - */ -library SafeMath { - /** - * @dev Returns the addition of two unsigned integers, reverting on overflow. - * - * Counterpart to Solidity's `+` operator. - * - * Requirements: - * - Addition cannot overflow. - */ - function add(uint256 a, uint256 b) internal pure returns (uint256) { - uint256 c = a + b; - require(c >= a, "SafeMath: addition overflow"); - - return c; - } - - /** - * @dev Returns the addition of two unsigned integers, reverting with custom message on overflow. - * - * Counterpart to Solidity's `+` operator. - * - * Requirements: - * - Addition cannot overflow. - */ - function add(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - uint256 c = a + b; - require(c >= a, errorMessage); - - return c; - } - - /** - * @dev Returns the subtraction of two unsigned integers, reverting on underflow (when the result is negative). - * - * Counterpart to Solidity's `-` operator. - * - * Requirements: - * - Subtraction cannot underflow. - */ - function sub(uint256 a, uint256 b) internal pure returns (uint256) { - return sub(a, b, "SafeMath: subtraction underflow"); - } - - /** - * @dev Returns the subtraction of two unsigned integers, reverting with custom message on underflow (when the result is negative). - * - * Counterpart to Solidity's `-` operator. - * - * Requirements: - * - Subtraction cannot underflow. - */ - function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - require(b <= a, errorMessage); - uint256 c = a - b; - - return c; - } - - /** - * @dev Returns the multiplication of two unsigned integers, reverting on overflow. - * - * Counterpart to Solidity's `*` operator. - * - * Requirements: - * - Multiplication cannot overflow. - */ - function mul(uint256 a, uint256 b) internal pure returns (uint256) { - // Gas optimization: this is cheaper than requiring 'a' not being zero, but the - // benefit is lost if 'b' is also tested. - // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 - if (a == 0) { - return 0; - } - - uint256 c = a * b; - require(c / a == b, "SafeMath: multiplication overflow"); - - return c; - } - - /** - * @dev Returns the multiplication of two unsigned integers, reverting on overflow. - * - * Counterpart to Solidity's `*` operator. - * - * Requirements: - * - Multiplication cannot overflow. - */ - function mul(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - // Gas optimization: this is cheaper than requiring 'a' not being zero, but the - // benefit is lost if 'b' is also tested. - // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 - if (a == 0) { - return 0; - } - - uint256 c = a * b; - require(c / a == b, errorMessage); - - return c; - } - - /** - * @dev Returns the integer division of two unsigned integers. - * Reverts on division by zero. The result is rounded towards zero. - * - * Counterpart to Solidity's `/` operator. Note: this function uses a - * `revert` opcode (which leaves remaining gas untouched) while Solidity - * uses an invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function div(uint256 a, uint256 b) internal pure returns (uint256) { - return div(a, b, "SafeMath: division by zero"); - } - - /** - * @dev Returns the integer division of two unsigned integers. - * Reverts with custom message on division by zero. The result is rounded towards zero. - * - * Counterpart to Solidity's `/` operator. Note: this function uses a - * `revert` opcode (which leaves remaining gas untouched) while Solidity - * uses an invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - // Solidity only automatically asserts when dividing by 0 - require(b > 0, errorMessage); - uint256 c = a / b; - // assert(a == b * c + a % b); // There is no case in which this doesn't hold - - return c; - } - - /** - * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), - * Reverts when dividing by zero. - * - * Counterpart to Solidity's `%` operator. This function uses a `revert` - * opcode (which leaves remaining gas untouched) while Solidity uses an - * invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function mod(uint256 a, uint256 b) internal pure returns (uint256) { - return mod(a, b, "SafeMath: modulo by zero"); - } - - /** - * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), - * Reverts with custom message when dividing by zero. - * - * Counterpart to Solidity's `%` operator. This function uses a `revert` - * opcode (which leaves remaining gas untouched) while Solidity uses an - * invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - require(b != 0, errorMessage); - return a % b; - } -} - - -// Dependency file: contracts/InterestRateModel.sol - -// pragma solidity 0.8.6; - -// import "contracts/Exponential.sol"; -// import "contracts/SafeMath.sol"; - -/** - * @title tropykus InterestRateModel Interface - * @author tropykus - */ -abstract contract InterestRateModel is Exponential { - using SafeMath for uint256; - - /// @notice Indicator that this is an InterestRateModel contract (for inspection) - bool public constant isInterestRateModel = true; - bool public isTropykusInterestRateModel; - - /** - * @notice The approximate number of blocks per year that is assumed by the interest rate model - */ - uint256 public constant blocksPerYear = 1051200; - - /** - * @notice Calculates the utilization rate of the market: `borrows / (cash + borrows - reserves)` - * @param cash The amount of cash in the market - * @param borrows The amount of borrows in the market - * @param reserves The amount of reserves in the market (currently unused) - * @return The utilization rate as a mantissa between [0, 1e18] - */ - function utilizationRate( - uint256 cash, - uint256 borrows, - uint256 reserves - ) public pure virtual returns (uint256) { - // Utilization rate is 0 when there are no borrows - if (borrows == 0) { - return 0; - } - - return borrows.mul(1e18).div(cash.add(borrows).sub(reserves)); - } - - /** - * @notice Calculates the current borrow interest rate per block - * @param cash The total amount of cash the market has - * @param borrows The total amount of borrows the market has outstanding - * @param reserves The total amnount of reserves the market has - * @return The borrow rate per block (as a percentage, and scaled by 1e18) - */ - function getBorrowRate( - uint256 cash, - uint256 borrows, - uint256 reserves - ) external view virtual returns (uint256); - - /** - * @notice Calculates the current supply interest rate per block - * @param cash The total amount of cash the market has - * @param borrows The total amount of borrows the market has outstanding - * @param reserves The total amnount of reserves the market has - * @param reserveFactorMantissa The current reserve factor the market has - * @return The supply rate per block (as a percentage, and scaled by 1e18) - */ - function getSupplyRate( - uint256 cash, - uint256 borrows, - uint256 reserves, - uint256 reserveFactorMantissa - ) external view virtual returns (uint256); - - function getExchangeRate( - uint256 _totalCash, - uint256 _totalBorrows, - uint256 _totalReserves, - uint256 _totalSupply - ) public pure returns (MathError, uint256) { - /* - * exchangeRate = (totalCash + totalBorrows - totalReserves) / totalSupply - */ - Exp memory exchangeRate; - MathError mathErr; - uint256 cashPlusBorrowsMinusReserves; - (mathErr, cashPlusBorrowsMinusReserves) = addThenSubUInt( - _totalCash, - _totalBorrows, - _totalReserves - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - (mathErr, exchangeRate) = getExp( - cashPlusBorrowsMinusReserves, - _totalSupply - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - - return (MathError.NO_ERROR, exchangeRate.mantissa); - } - - function isAboveOptimal( - uint256 cash, - uint256 borrows, - uint256 reserves - ) public view virtual returns (bool) { - cash; - borrows; - reserves; - return false; - } -} - - -// Root file: contracts/HurricaneInterestRateModel.sol - -pragma solidity 0.8.6; - -// import "contracts/InterestRateModel.sol"; - -contract HurricaneInterestRateModel is InterestRateModel { - using SafeMath for uint256; - - address public owner; - uint256 public baseBorrowRatePerBlock; - uint256 public promisedBaseReturnRatePerBlock; - uint256 public optimalUtilizationRate; - uint256 public borrowRateSlopePerBlock; - uint256 public supplyRateSlopePerBlock; - - uint256 constant FACTOR = 1e18; - - constructor( - uint256 _baseBorrowRate, - uint256 _promisedBaseReturnRate, - uint256 _optimalUtilizationRate, - uint256 _borrowRateSlope, - uint256 _supplyRateSlope - ) { - baseBorrowRatePerBlock = _baseBorrowRate.div(blocksPerYear); - promisedBaseReturnRatePerBlock = _promisedBaseReturnRate.div( - blocksPerYear - ); - optimalUtilizationRate = _optimalUtilizationRate; - borrowRateSlopePerBlock = _borrowRateSlope.div(blocksPerYear); - supplyRateSlopePerBlock = _supplyRateSlope.div(blocksPerYear); - owner = msg.sender; - isTropykusInterestRateModel = true; - } - - modifier onlyOwner() { - require( - msg.sender == owner, - "You are not allowed to perform this action" - ); - _; - } - - function getSupplyRate( - uint256 cash, - uint256 borrows, - uint256 reserves, - uint256 reserveFactorMantissa - ) public view override returns (uint256) { - reserveFactorMantissa; - uint256 utilizationRate = utilizationRate(cash, borrows, reserves); - return - utilizationRate.mul(supplyRateSlopePerBlock).div(FACTOR).add( - promisedBaseReturnRatePerBlock - ); - } - - function getBorrowRate( - uint256 cash, - uint256 borrows, - uint256 reserves - ) public view override returns (uint256 borrowRate) { - uint256 utilizationRate = utilizationRate(cash, borrows, reserves); - borrowRate = utilizationRate - .mul(borrowRateSlopePerBlock) - .div(FACTOR) - .add(baseBorrowRatePerBlock); - } - - function isAboveOptimal( - uint256 cash, - uint256 borrows, - uint256 reserves - ) public view override returns (bool) { - uint256 utilizationRate = utilizationRate(cash, borrows, reserves); - return utilizationRate > optimalUtilizationRate; - } -} diff --git a/flatten/InterestRateModel.sol b/flatten/InterestRateModel.sol deleted file mode 100644 index 95f3a77..0000000 --- a/flatten/InterestRateModel.sol +++ /dev/null @@ -1,779 +0,0 @@ -// Dependency file: contracts/CarefulMath.sol - -// SPDX-License-Identifier: UNLICENSED -// pragma solidity 0.8.6; - -/** - * @title Careful Math - * @author tropykus - * @notice Derived from OpenZeppelin's SafeMath library - * https://github.com/OpenZeppelin/openzeppelin-solidity/blob/master/contracts/math/SafeMath.sol - */ -contract CarefulMath { - - /** - * @dev Possible error codes that we can return - */ - enum MathError { - NO_ERROR, - DIVISION_BY_ZERO, - INTEGER_OVERFLOW, - INTEGER_UNDERFLOW - } - - /** - * @dev Multiplies two numbers, returns an error on overflow. - */ - function mulUInt(uint a, uint b) internal pure returns (MathError, uint) { - if (a == 0) { - return (MathError.NO_ERROR, 0); - } - - uint c = a * b; - - if (c / a != b) { - return (MathError.INTEGER_OVERFLOW, 0); - } else { - return (MathError.NO_ERROR, c); - } - } - - /** - * @dev Integer division of two numbers, truncating the quotient. - */ - function divUInt(uint a, uint b) internal pure returns (MathError, uint) { - if (b == 0) { - return (MathError.DIVISION_BY_ZERO, 0); - } - - return (MathError.NO_ERROR, a / b); - } - - /** - * @dev Subtracts two numbers, returns an error on overflow (i.e. if subtrahend is greater than minuend). - */ - function subUInt(uint a, uint b) internal pure returns (MathError, uint) { - if (b <= a) { - return (MathError.NO_ERROR, a - b); - } else { - return (MathError.INTEGER_UNDERFLOW, 0); - } - } - - /** - * @dev Adds two numbers, returns an error on overflow. - */ - function addUInt(uint a, uint b) internal pure returns (MathError, uint) { - uint c = a + b; - - if (c >= a) { - return (MathError.NO_ERROR, c); - } else { - return (MathError.INTEGER_OVERFLOW, 0); - } - } - - /** - * @dev add a and b and then subtract c - */ - function addThenSubUInt(uint a, uint b, uint c) internal pure returns (MathError, uint) { - (MathError err0, uint sum) = addUInt(a, b); - - if (err0 != MathError.NO_ERROR) { - return (err0, 0); - } - - return subUInt(sum, c); - } -} - - -// Dependency file: contracts/ExponentialNoError.sol - -// pragma solidity 0.8.6; - -/** - * @title Exponential module for storing fixed-precision decimals - * @author tropykus - * @notice Exp is a struct which stores decimals with a fixed precision of 18 decimal places. - * Thus, if we wanted to store the 5.1, mantissa would store 5.1e18. That is: - * `Exp({mantissa: 5100000000000000000})`. - */ -contract ExponentialNoError { - uint constant expScale = 1e18; - uint constant doubleScale = 1e36; - uint constant halfExpScale = expScale/2; - uint constant mantissaOne = expScale; - - struct Exp { - uint mantissa; - } - - struct Double { - uint mantissa; - } - - /** - * @dev Truncates the given exp to a whole number value. - * For example, truncate(Exp{mantissa: 15 * expScale}) = 15 - */ - function truncate(Exp memory exp) pure internal returns (uint) { - // Note: We are not using careful math here as we're performing a division that cannot fail - return exp.mantissa / expScale; - } - - /** - * @dev Multiply an Exp by a scalar, then truncate to return an unsigned integer. - */ - function mul_ScalarTruncate(Exp memory a, uint scalar) pure internal returns (uint) { - Exp memory product = mul_(a, scalar); - return truncate(product); - } - - /** - * @dev Multiply an Exp by a scalar, truncate, then add an to an unsigned integer, returning an unsigned integer. - */ - function mul_ScalarTruncateAddUInt(Exp memory a, uint scalar, uint addend) pure internal returns (uint) { - Exp memory product = mul_(a, scalar); - return add_(truncate(product), addend); - } - - /** - * @dev Checks if first Exp is less than second Exp. - */ - function lessThanExp(Exp memory left, Exp memory right) pure internal returns (bool) { - return left.mantissa < right.mantissa; - } - - /** - * @dev Checks if left Exp <= right Exp. - */ - function lessThanOrEqualExp(Exp memory left, Exp memory right) pure internal returns (bool) { - return left.mantissa <= right.mantissa; - } - - /** - * @dev Checks if left Exp > right Exp. - */ - function greaterThanExp(Exp memory left, Exp memory right) pure internal returns (bool) { - return left.mantissa > right.mantissa; - } - - /** - * @dev returns true if Exp is exactly zero - */ - function isZeroExp(Exp memory value) pure internal returns (bool) { - return value.mantissa == 0; - } - - function safe224(uint n, string memory errorMessage) pure internal returns (uint224) { - require(n < 2**224, errorMessage); - return uint224(n); - } - - function safe32(uint n, string memory errorMessage) pure internal returns (uint32) { - require(n < 2**32, errorMessage); - return uint32(n); - } - - function add_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { - return Exp({mantissa: add_(a.mantissa, b.mantissa)}); - } - - function add_(Double memory a, Double memory b) pure internal returns (Double memory) { - return Double({mantissa: add_(a.mantissa, b.mantissa)}); - } - - function add_(uint a, uint b) pure internal returns (uint) { - return add_(a, b, "addition overflow"); - } - - function add_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { - uint c = a + b; - require(c >= a, errorMessage); - return c; - } - - function sub_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { - return Exp({mantissa: sub_(a.mantissa, b.mantissa)}); - } - - function sub_(Double memory a, Double memory b) pure internal returns (Double memory) { - return Double({mantissa: sub_(a.mantissa, b.mantissa)}); - } - - function sub_(uint a, uint b) pure internal returns (uint) { - return sub_(a, b, "subtraction underflow"); - } - - function sub_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { - require(b <= a, errorMessage); - return a - b; - } - - function mul_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { - return Exp({mantissa: mul_(a.mantissa, b.mantissa) / expScale}); - } - - function mul_(Exp memory a, uint b) pure internal returns (Exp memory) { - return Exp({mantissa: mul_(a.mantissa, b)}); - } - - function mul_(uint a, Exp memory b) pure internal returns (uint) { - return mul_(a, b.mantissa) / expScale; - } - - function mul_(Double memory a, Double memory b) pure internal returns (Double memory) { - return Double({mantissa: mul_(a.mantissa, b.mantissa) / doubleScale}); - } - - function mul_(Double memory a, uint b) pure internal returns (Double memory) { - return Double({mantissa: mul_(a.mantissa, b)}); - } - - function mul_(uint a, Double memory b) pure internal returns (uint) { - return mul_(a, b.mantissa) / doubleScale; - } - - function mul_(uint a, uint b) pure internal returns (uint) { - return mul_(a, b, "multiplication overflow"); - } - - function mul_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { - if (a == 0 || b == 0) { - return 0; - } - uint c = a * b; - require(c / a == b, errorMessage); - return c; - } - - function div_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { - return Exp({mantissa: div_(mul_(a.mantissa, expScale), b.mantissa)}); - } - - function div_(Exp memory a, uint b) pure internal returns (Exp memory) { - return Exp({mantissa: div_(a.mantissa, b)}); - } - - function div_(uint a, Exp memory b) pure internal returns (uint) { - return div_(mul_(a, expScale), b.mantissa); - } - - function div_(Double memory a, Double memory b) pure internal returns (Double memory) { - return Double({mantissa: div_(mul_(a.mantissa, doubleScale), b.mantissa)}); - } - - function div_(Double memory a, uint b) pure internal returns (Double memory) { - return Double({mantissa: div_(a.mantissa, b)}); - } - - function div_(uint a, Double memory b) pure internal returns (uint) { - return div_(mul_(a, doubleScale), b.mantissa); - } - - function div_(uint a, uint b) pure internal returns (uint) { - return div_(a, b, "divide by zero"); - } - - function div_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { - require(b > 0, errorMessage); - return a / b; - } - - function fraction(uint a, uint b) pure internal returns (Double memory) { - return Double({mantissa: div_(mul_(a, doubleScale), b)}); - } -} - - -// Dependency file: contracts/Exponential.sol - -// pragma solidity 0.8.6; - -// import "contracts/CarefulMath.sol"; -// import "contracts/ExponentialNoError.sol"; - -/** - * @title Exponential module for storing fixed-precision decimals - * @author tropykus - * @dev Legacy contract for compatibility reasons with existing contracts that still use MathError - * @notice Exp is a struct which stores decimals with a fixed precision of 18 decimal places. - * Thus, if we wanted to store the 5.1, mantissa would store 5.1e18. That is: - * `Exp({mantissa: 5100000000000000000})`. - */ -contract Exponential is CarefulMath, ExponentialNoError { - /** - * @dev Creates an exponential from numerator and denominator values. - * Note: Returns an error if (`num` * 10e18) > MAX_INT, - * or if `denom` is zero. - */ - function getExp(uint num, uint denom) internal pure returns (MathError, Exp memory) { - (MathError err0, uint scaledNumerator) = mulUInt(num, expScale); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - - (MathError err1, uint rational) = divUInt(scaledNumerator, denom); - if (err1 != MathError.NO_ERROR) { - return (err1, Exp({mantissa: 0})); - } - - return (MathError.NO_ERROR, Exp({mantissa: rational})); - } - - /** - * @dev Adds two exponentials, returning a new exponential. - */ - function addExp(Exp memory a, Exp memory b) internal pure returns (MathError, Exp memory) { - (MathError error, uint result) = addUInt(a.mantissa, b.mantissa); - - return (error, Exp({mantissa: result})); - } - - /** - * @dev Subtracts two exponentials, returning a new exponential. - */ - function subExp(Exp memory a, Exp memory b) internal pure returns (MathError, Exp memory) { - (MathError error, uint result) = subUInt(a.mantissa, b.mantissa); - - return (error, Exp({mantissa: result})); - } - - /** - * @dev Multiply an Exp by a scalar, returning a new Exp. - */ - function mulScalar(Exp memory a, uint scalar) internal pure returns (MathError, Exp memory) { - (MathError err0, uint scaledMantissa) = mulUInt(a.mantissa, scalar); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - - return (MathError.NO_ERROR, Exp({mantissa: scaledMantissa})); - } - - /** - * @dev Multiply an Exp by a scalar, then truncate to return an unsigned integer. - */ - function mulScalarTruncate(Exp memory a, uint scalar) internal pure returns (MathError, uint) { - (MathError err, Exp memory product) = mulScalar(a, scalar); - if (err != MathError.NO_ERROR) { - return (err, 0); - } - - return (MathError.NO_ERROR, truncate(product)); - } - - /** - * @dev Multiply an Exp by a scalar, truncate, then add an to an unsigned integer, returning an unsigned integer. - */ - function mulScalarTruncateAddUInt(Exp memory a, uint scalar, uint addend) internal pure returns (MathError, uint) { - (MathError err, Exp memory product) = mulScalar(a, scalar); - if (err != MathError.NO_ERROR) { - return (err, 0); - } - - return addUInt(truncate(product), addend); - } - - /** - * @dev Divide an Exp by a scalar, returning a new Exp. - */ - function divScalar(Exp memory a, uint scalar) internal pure returns (MathError, Exp memory) { - (MathError err0, uint descaledMantissa) = divUInt(a.mantissa, scalar); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - - return (MathError.NO_ERROR, Exp({mantissa: descaledMantissa})); - } - - /** - * @dev Divide a scalar by an Exp, returning a new Exp. - */ - function divScalarByExp(uint scalar, Exp memory divisor) internal pure returns (MathError, Exp memory) { - /* - We are doing this as: - getExp(mulUInt(expScale, scalar), divisor.mantissa) - - How it works: - Exp = a / b; - Scalar = s; - `s / (a / b)` = `b * s / a` and since for an Exp `a = mantissa, b = expScale` - */ - (MathError err0, uint numerator) = mulUInt(expScale, scalar); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - return getExp(numerator, divisor.mantissa); - } - - /** - * @dev Divide a scalar by an Exp, then truncate to return an unsigned integer. - */ - function divScalarByExpTruncate(uint scalar, Exp memory divisor) internal pure returns (MathError, uint) { - (MathError err, Exp memory fraction) = divScalarByExp(scalar, divisor); - if (err != MathError.NO_ERROR) { - return (err, 0); - } - - return (MathError.NO_ERROR, truncate(fraction)); - } - - /** - * @dev Multiplies two exponentials, returning a new exponential. - */ - function mulExp(Exp memory a, Exp memory b) internal pure returns (MathError, Exp memory) { - - (MathError err0, uint doubleScaledProduct) = mulUInt(a.mantissa, b.mantissa); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - - // We add half the scale before dividing so that we get rounding instead of truncation. - // See "Listing 6" and text above it at https://accu.org/index.php/journals/1717 - // Without this change, a result like 6.6...e-19 will be truncated to 0 instead of being rounded to 1e-18. - (MathError err1, uint doubleScaledProductWithHalfScale) = addUInt(halfExpScale, doubleScaledProduct); - if (err1 != MathError.NO_ERROR) { - return (err1, Exp({mantissa: 0})); - } - - (MathError err2, uint product) = divUInt(doubleScaledProductWithHalfScale, expScale); - // The only error `div` can return is MathError.DIVISION_BY_ZERO but we control `expScale` and it is not zero. - assert(err2 == MathError.NO_ERROR); - - return (MathError.NO_ERROR, Exp({mantissa: product})); - } - - /** - * @dev Multiplies two exponentials given their mantissas, returning a new exponential. - */ - function mulExp(uint a, uint b) internal pure returns (MathError, Exp memory) { - return mulExp(Exp({mantissa: a}), Exp({mantissa: b})); - } - - /** - * @dev Multiplies three exponentials, returning a new exponential. - */ - function mulExp3(Exp memory a, Exp memory b, Exp memory c) internal pure returns (MathError, Exp memory) { - (MathError err, Exp memory ab) = mulExp(a, b); - if (err != MathError.NO_ERROR) { - return (err, ab); - } - return mulExp(ab, c); - } - - /** - * @dev Divides two exponentials, returning a new exponential. - * (a/scale) / (b/scale) = (a/scale) * (scale/b) = a/b, - * which we can scale as an Exp by calling getExp(a.mantissa, b.mantissa) - */ - function divExp(Exp memory a, Exp memory b) internal pure returns (MathError, Exp memory) { - return getExp(a.mantissa, b.mantissa); - } -} - - -// Dependency file: contracts/SafeMath.sol - -// pragma solidity 0.8.6; - -// From https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/math/Math.sol -// Subject to the MIT license. - -/** - * @dev Wrappers over Solidity's arithmetic operations with added overflow - * checks. - * - * Arithmetic operations in Solidity wrap on overflow. This can easily result - * in bugs, because programmers usually assume that an overflow raises an - * error, which is the standard behavior in high level programming languages. - * `SafeMath` restores this intuition by reverting the transaction when an - * operation overflows. - * - * Using this library instead of the unchecked operations eliminates an entire - * class of bugs, so it's recommended to use it always. - */ -library SafeMath { - /** - * @dev Returns the addition of two unsigned integers, reverting on overflow. - * - * Counterpart to Solidity's `+` operator. - * - * Requirements: - * - Addition cannot overflow. - */ - function add(uint256 a, uint256 b) internal pure returns (uint256) { - uint256 c = a + b; - require(c >= a, "SafeMath: addition overflow"); - - return c; - } - - /** - * @dev Returns the addition of two unsigned integers, reverting with custom message on overflow. - * - * Counterpart to Solidity's `+` operator. - * - * Requirements: - * - Addition cannot overflow. - */ - function add(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - uint256 c = a + b; - require(c >= a, errorMessage); - - return c; - } - - /** - * @dev Returns the subtraction of two unsigned integers, reverting on underflow (when the result is negative). - * - * Counterpart to Solidity's `-` operator. - * - * Requirements: - * - Subtraction cannot underflow. - */ - function sub(uint256 a, uint256 b) internal pure returns (uint256) { - return sub(a, b, "SafeMath: subtraction underflow"); - } - - /** - * @dev Returns the subtraction of two unsigned integers, reverting with custom message on underflow (when the result is negative). - * - * Counterpart to Solidity's `-` operator. - * - * Requirements: - * - Subtraction cannot underflow. - */ - function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - require(b <= a, errorMessage); - uint256 c = a - b; - - return c; - } - - /** - * @dev Returns the multiplication of two unsigned integers, reverting on overflow. - * - * Counterpart to Solidity's `*` operator. - * - * Requirements: - * - Multiplication cannot overflow. - */ - function mul(uint256 a, uint256 b) internal pure returns (uint256) { - // Gas optimization: this is cheaper than requiring 'a' not being zero, but the - // benefit is lost if 'b' is also tested. - // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 - if (a == 0) { - return 0; - } - - uint256 c = a * b; - require(c / a == b, "SafeMath: multiplication overflow"); - - return c; - } - - /** - * @dev Returns the multiplication of two unsigned integers, reverting on overflow. - * - * Counterpart to Solidity's `*` operator. - * - * Requirements: - * - Multiplication cannot overflow. - */ - function mul(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - // Gas optimization: this is cheaper than requiring 'a' not being zero, but the - // benefit is lost if 'b' is also tested. - // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 - if (a == 0) { - return 0; - } - - uint256 c = a * b; - require(c / a == b, errorMessage); - - return c; - } - - /** - * @dev Returns the integer division of two unsigned integers. - * Reverts on division by zero. The result is rounded towards zero. - * - * Counterpart to Solidity's `/` operator. Note: this function uses a - * `revert` opcode (which leaves remaining gas untouched) while Solidity - * uses an invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function div(uint256 a, uint256 b) internal pure returns (uint256) { - return div(a, b, "SafeMath: division by zero"); - } - - /** - * @dev Returns the integer division of two unsigned integers. - * Reverts with custom message on division by zero. The result is rounded towards zero. - * - * Counterpart to Solidity's `/` operator. Note: this function uses a - * `revert` opcode (which leaves remaining gas untouched) while Solidity - * uses an invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - // Solidity only automatically asserts when dividing by 0 - require(b > 0, errorMessage); - uint256 c = a / b; - // assert(a == b * c + a % b); // There is no case in which this doesn't hold - - return c; - } - - /** - * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), - * Reverts when dividing by zero. - * - * Counterpart to Solidity's `%` operator. This function uses a `revert` - * opcode (which leaves remaining gas untouched) while Solidity uses an - * invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function mod(uint256 a, uint256 b) internal pure returns (uint256) { - return mod(a, b, "SafeMath: modulo by zero"); - } - - /** - * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), - * Reverts with custom message when dividing by zero. - * - * Counterpart to Solidity's `%` operator. This function uses a `revert` - * opcode (which leaves remaining gas untouched) while Solidity uses an - * invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - require(b != 0, errorMessage); - return a % b; - } -} - - -// Root file: contracts/InterestRateModel.sol - -pragma solidity 0.8.6; - -// import "contracts/Exponential.sol"; -// import "contracts/SafeMath.sol"; - -/** - * @title tropykus InterestRateModel Interface - * @author tropykus - */ -abstract contract InterestRateModel is Exponential { - using SafeMath for uint256; - - /// @notice Indicator that this is an InterestRateModel contract (for inspection) - bool public constant isInterestRateModel = true; - bool public isTropykusInterestRateModel; - - /** - * @notice The approximate number of blocks per year that is assumed by the interest rate model - */ - uint256 public constant blocksPerYear = 1051200; - - /** - * @notice Calculates the utilization rate of the market: `borrows / (cash + borrows - reserves)` - * @param cash The amount of cash in the market - * @param borrows The amount of borrows in the market - * @param reserves The amount of reserves in the market (currently unused) - * @return The utilization rate as a mantissa between [0, 1e18] - */ - function utilizationRate( - uint256 cash, - uint256 borrows, - uint256 reserves - ) public pure virtual returns (uint256) { - // Utilization rate is 0 when there are no borrows - if (borrows == 0) { - return 0; - } - - return borrows.mul(1e18).div(cash.add(borrows).sub(reserves)); - } - - /** - * @notice Calculates the current borrow interest rate per block - * @param cash The total amount of cash the market has - * @param borrows The total amount of borrows the market has outstanding - * @param reserves The total amnount of reserves the market has - * @return The borrow rate per block (as a percentage, and scaled by 1e18) - */ - function getBorrowRate( - uint256 cash, - uint256 borrows, - uint256 reserves - ) external view virtual returns (uint256); - - /** - * @notice Calculates the current supply interest rate per block - * @param cash The total amount of cash the market has - * @param borrows The total amount of borrows the market has outstanding - * @param reserves The total amnount of reserves the market has - * @param reserveFactorMantissa The current reserve factor the market has - * @return The supply rate per block (as a percentage, and scaled by 1e18) - */ - function getSupplyRate( - uint256 cash, - uint256 borrows, - uint256 reserves, - uint256 reserveFactorMantissa - ) external view virtual returns (uint256); - - function getExchangeRate( - uint256 _totalCash, - uint256 _totalBorrows, - uint256 _totalReserves, - uint256 _totalSupply - ) public pure returns (MathError, uint256) { - /* - * exchangeRate = (totalCash + totalBorrows - totalReserves) / totalSupply - */ - Exp memory exchangeRate; - MathError mathErr; - uint256 cashPlusBorrowsMinusReserves; - (mathErr, cashPlusBorrowsMinusReserves) = addThenSubUInt( - _totalCash, - _totalBorrows, - _totalReserves - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - (mathErr, exchangeRate) = getExp( - cashPlusBorrowsMinusReserves, - _totalSupply - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - - return (MathError.NO_ERROR, exchangeRate.mantissa); - } - - function isAboveOptimal( - uint256 cash, - uint256 borrows, - uint256 reserves - ) public view virtual returns (bool) { - cash; - borrows; - reserves; - return false; - } -} diff --git a/flatten/JumpRateModel.sol b/flatten/JumpRateModel.sol deleted file mode 100644 index 6c10d5b..0000000 --- a/flatten/JumpRateModel.sol +++ /dev/null @@ -1,919 +0,0 @@ -// Dependency file: contracts/CarefulMath.sol - -// SPDX-License-Identifier: UNLICENSED -// pragma solidity 0.8.6; - -/** - * @title Careful Math - * @author tropykus - * @notice Derived from OpenZeppelin's SafeMath library - * https://github.com/OpenZeppelin/openzeppelin-solidity/blob/master/contracts/math/SafeMath.sol - */ -contract CarefulMath { - - /** - * @dev Possible error codes that we can return - */ - enum MathError { - NO_ERROR, - DIVISION_BY_ZERO, - INTEGER_OVERFLOW, - INTEGER_UNDERFLOW - } - - /** - * @dev Multiplies two numbers, returns an error on overflow. - */ - function mulUInt(uint a, uint b) internal pure returns (MathError, uint) { - if (a == 0) { - return (MathError.NO_ERROR, 0); - } - - uint c = a * b; - - if (c / a != b) { - return (MathError.INTEGER_OVERFLOW, 0); - } else { - return (MathError.NO_ERROR, c); - } - } - - /** - * @dev Integer division of two numbers, truncating the quotient. - */ - function divUInt(uint a, uint b) internal pure returns (MathError, uint) { - if (b == 0) { - return (MathError.DIVISION_BY_ZERO, 0); - } - - return (MathError.NO_ERROR, a / b); - } - - /** - * @dev Subtracts two numbers, returns an error on overflow (i.e. if subtrahend is greater than minuend). - */ - function subUInt(uint a, uint b) internal pure returns (MathError, uint) { - if (b <= a) { - return (MathError.NO_ERROR, a - b); - } else { - return (MathError.INTEGER_UNDERFLOW, 0); - } - } - - /** - * @dev Adds two numbers, returns an error on overflow. - */ - function addUInt(uint a, uint b) internal pure returns (MathError, uint) { - uint c = a + b; - - if (c >= a) { - return (MathError.NO_ERROR, c); - } else { - return (MathError.INTEGER_OVERFLOW, 0); - } - } - - /** - * @dev add a and b and then subtract c - */ - function addThenSubUInt(uint a, uint b, uint c) internal pure returns (MathError, uint) { - (MathError err0, uint sum) = addUInt(a, b); - - if (err0 != MathError.NO_ERROR) { - return (err0, 0); - } - - return subUInt(sum, c); - } -} - - -// Dependency file: contracts/ExponentialNoError.sol - -// pragma solidity 0.8.6; - -/** - * @title Exponential module for storing fixed-precision decimals - * @author tropykus - * @notice Exp is a struct which stores decimals with a fixed precision of 18 decimal places. - * Thus, if we wanted to store the 5.1, mantissa would store 5.1e18. That is: - * `Exp({mantissa: 5100000000000000000})`. - */ -contract ExponentialNoError { - uint constant expScale = 1e18; - uint constant doubleScale = 1e36; - uint constant halfExpScale = expScale/2; - uint constant mantissaOne = expScale; - - struct Exp { - uint mantissa; - } - - struct Double { - uint mantissa; - } - - /** - * @dev Truncates the given exp to a whole number value. - * For example, truncate(Exp{mantissa: 15 * expScale}) = 15 - */ - function truncate(Exp memory exp) pure internal returns (uint) { - // Note: We are not using careful math here as we're performing a division that cannot fail - return exp.mantissa / expScale; - } - - /** - * @dev Multiply an Exp by a scalar, then truncate to return an unsigned integer. - */ - function mul_ScalarTruncate(Exp memory a, uint scalar) pure internal returns (uint) { - Exp memory product = mul_(a, scalar); - return truncate(product); - } - - /** - * @dev Multiply an Exp by a scalar, truncate, then add an to an unsigned integer, returning an unsigned integer. - */ - function mul_ScalarTruncateAddUInt(Exp memory a, uint scalar, uint addend) pure internal returns (uint) { - Exp memory product = mul_(a, scalar); - return add_(truncate(product), addend); - } - - /** - * @dev Checks if first Exp is less than second Exp. - */ - function lessThanExp(Exp memory left, Exp memory right) pure internal returns (bool) { - return left.mantissa < right.mantissa; - } - - /** - * @dev Checks if left Exp <= right Exp. - */ - function lessThanOrEqualExp(Exp memory left, Exp memory right) pure internal returns (bool) { - return left.mantissa <= right.mantissa; - } - - /** - * @dev Checks if left Exp > right Exp. - */ - function greaterThanExp(Exp memory left, Exp memory right) pure internal returns (bool) { - return left.mantissa > right.mantissa; - } - - /** - * @dev returns true if Exp is exactly zero - */ - function isZeroExp(Exp memory value) pure internal returns (bool) { - return value.mantissa == 0; - } - - function safe224(uint n, string memory errorMessage) pure internal returns (uint224) { - require(n < 2**224, errorMessage); - return uint224(n); - } - - function safe32(uint n, string memory errorMessage) pure internal returns (uint32) { - require(n < 2**32, errorMessage); - return uint32(n); - } - - function add_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { - return Exp({mantissa: add_(a.mantissa, b.mantissa)}); - } - - function add_(Double memory a, Double memory b) pure internal returns (Double memory) { - return Double({mantissa: add_(a.mantissa, b.mantissa)}); - } - - function add_(uint a, uint b) pure internal returns (uint) { - return add_(a, b, "addition overflow"); - } - - function add_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { - uint c = a + b; - require(c >= a, errorMessage); - return c; - } - - function sub_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { - return Exp({mantissa: sub_(a.mantissa, b.mantissa)}); - } - - function sub_(Double memory a, Double memory b) pure internal returns (Double memory) { - return Double({mantissa: sub_(a.mantissa, b.mantissa)}); - } - - function sub_(uint a, uint b) pure internal returns (uint) { - return sub_(a, b, "subtraction underflow"); - } - - function sub_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { - require(b <= a, errorMessage); - return a - b; - } - - function mul_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { - return Exp({mantissa: mul_(a.mantissa, b.mantissa) / expScale}); - } - - function mul_(Exp memory a, uint b) pure internal returns (Exp memory) { - return Exp({mantissa: mul_(a.mantissa, b)}); - } - - function mul_(uint a, Exp memory b) pure internal returns (uint) { - return mul_(a, b.mantissa) / expScale; - } - - function mul_(Double memory a, Double memory b) pure internal returns (Double memory) { - return Double({mantissa: mul_(a.mantissa, b.mantissa) / doubleScale}); - } - - function mul_(Double memory a, uint b) pure internal returns (Double memory) { - return Double({mantissa: mul_(a.mantissa, b)}); - } - - function mul_(uint a, Double memory b) pure internal returns (uint) { - return mul_(a, b.mantissa) / doubleScale; - } - - function mul_(uint a, uint b) pure internal returns (uint) { - return mul_(a, b, "multiplication overflow"); - } - - function mul_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { - if (a == 0 || b == 0) { - return 0; - } - uint c = a * b; - require(c / a == b, errorMessage); - return c; - } - - function div_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { - return Exp({mantissa: div_(mul_(a.mantissa, expScale), b.mantissa)}); - } - - function div_(Exp memory a, uint b) pure internal returns (Exp memory) { - return Exp({mantissa: div_(a.mantissa, b)}); - } - - function div_(uint a, Exp memory b) pure internal returns (uint) { - return div_(mul_(a, expScale), b.mantissa); - } - - function div_(Double memory a, Double memory b) pure internal returns (Double memory) { - return Double({mantissa: div_(mul_(a.mantissa, doubleScale), b.mantissa)}); - } - - function div_(Double memory a, uint b) pure internal returns (Double memory) { - return Double({mantissa: div_(a.mantissa, b)}); - } - - function div_(uint a, Double memory b) pure internal returns (uint) { - return div_(mul_(a, doubleScale), b.mantissa); - } - - function div_(uint a, uint b) pure internal returns (uint) { - return div_(a, b, "divide by zero"); - } - - function div_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { - require(b > 0, errorMessage); - return a / b; - } - - function fraction(uint a, uint b) pure internal returns (Double memory) { - return Double({mantissa: div_(mul_(a, doubleScale), b)}); - } -} - - -// Dependency file: contracts/Exponential.sol - -// pragma solidity 0.8.6; - -// import "contracts/CarefulMath.sol"; -// import "contracts/ExponentialNoError.sol"; - -/** - * @title Exponential module for storing fixed-precision decimals - * @author tropykus - * @dev Legacy contract for compatibility reasons with existing contracts that still use MathError - * @notice Exp is a struct which stores decimals with a fixed precision of 18 decimal places. - * Thus, if we wanted to store the 5.1, mantissa would store 5.1e18. That is: - * `Exp({mantissa: 5100000000000000000})`. - */ -contract Exponential is CarefulMath, ExponentialNoError { - /** - * @dev Creates an exponential from numerator and denominator values. - * Note: Returns an error if (`num` * 10e18) > MAX_INT, - * or if `denom` is zero. - */ - function getExp(uint num, uint denom) internal pure returns (MathError, Exp memory) { - (MathError err0, uint scaledNumerator) = mulUInt(num, expScale); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - - (MathError err1, uint rational) = divUInt(scaledNumerator, denom); - if (err1 != MathError.NO_ERROR) { - return (err1, Exp({mantissa: 0})); - } - - return (MathError.NO_ERROR, Exp({mantissa: rational})); - } - - /** - * @dev Adds two exponentials, returning a new exponential. - */ - function addExp(Exp memory a, Exp memory b) internal pure returns (MathError, Exp memory) { - (MathError error, uint result) = addUInt(a.mantissa, b.mantissa); - - return (error, Exp({mantissa: result})); - } - - /** - * @dev Subtracts two exponentials, returning a new exponential. - */ - function subExp(Exp memory a, Exp memory b) internal pure returns (MathError, Exp memory) { - (MathError error, uint result) = subUInt(a.mantissa, b.mantissa); - - return (error, Exp({mantissa: result})); - } - - /** - * @dev Multiply an Exp by a scalar, returning a new Exp. - */ - function mulScalar(Exp memory a, uint scalar) internal pure returns (MathError, Exp memory) { - (MathError err0, uint scaledMantissa) = mulUInt(a.mantissa, scalar); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - - return (MathError.NO_ERROR, Exp({mantissa: scaledMantissa})); - } - - /** - * @dev Multiply an Exp by a scalar, then truncate to return an unsigned integer. - */ - function mulScalarTruncate(Exp memory a, uint scalar) internal pure returns (MathError, uint) { - (MathError err, Exp memory product) = mulScalar(a, scalar); - if (err != MathError.NO_ERROR) { - return (err, 0); - } - - return (MathError.NO_ERROR, truncate(product)); - } - - /** - * @dev Multiply an Exp by a scalar, truncate, then add an to an unsigned integer, returning an unsigned integer. - */ - function mulScalarTruncateAddUInt(Exp memory a, uint scalar, uint addend) internal pure returns (MathError, uint) { - (MathError err, Exp memory product) = mulScalar(a, scalar); - if (err != MathError.NO_ERROR) { - return (err, 0); - } - - return addUInt(truncate(product), addend); - } - - /** - * @dev Divide an Exp by a scalar, returning a new Exp. - */ - function divScalar(Exp memory a, uint scalar) internal pure returns (MathError, Exp memory) { - (MathError err0, uint descaledMantissa) = divUInt(a.mantissa, scalar); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - - return (MathError.NO_ERROR, Exp({mantissa: descaledMantissa})); - } - - /** - * @dev Divide a scalar by an Exp, returning a new Exp. - */ - function divScalarByExp(uint scalar, Exp memory divisor) internal pure returns (MathError, Exp memory) { - /* - We are doing this as: - getExp(mulUInt(expScale, scalar), divisor.mantissa) - - How it works: - Exp = a / b; - Scalar = s; - `s / (a / b)` = `b * s / a` and since for an Exp `a = mantissa, b = expScale` - */ - (MathError err0, uint numerator) = mulUInt(expScale, scalar); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - return getExp(numerator, divisor.mantissa); - } - - /** - * @dev Divide a scalar by an Exp, then truncate to return an unsigned integer. - */ - function divScalarByExpTruncate(uint scalar, Exp memory divisor) internal pure returns (MathError, uint) { - (MathError err, Exp memory fraction) = divScalarByExp(scalar, divisor); - if (err != MathError.NO_ERROR) { - return (err, 0); - } - - return (MathError.NO_ERROR, truncate(fraction)); - } - - /** - * @dev Multiplies two exponentials, returning a new exponential. - */ - function mulExp(Exp memory a, Exp memory b) internal pure returns (MathError, Exp memory) { - - (MathError err0, uint doubleScaledProduct) = mulUInt(a.mantissa, b.mantissa); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - - // We add half the scale before dividing so that we get rounding instead of truncation. - // See "Listing 6" and text above it at https://accu.org/index.php/journals/1717 - // Without this change, a result like 6.6...e-19 will be truncated to 0 instead of being rounded to 1e-18. - (MathError err1, uint doubleScaledProductWithHalfScale) = addUInt(halfExpScale, doubleScaledProduct); - if (err1 != MathError.NO_ERROR) { - return (err1, Exp({mantissa: 0})); - } - - (MathError err2, uint product) = divUInt(doubleScaledProductWithHalfScale, expScale); - // The only error `div` can return is MathError.DIVISION_BY_ZERO but we control `expScale` and it is not zero. - assert(err2 == MathError.NO_ERROR); - - return (MathError.NO_ERROR, Exp({mantissa: product})); - } - - /** - * @dev Multiplies two exponentials given their mantissas, returning a new exponential. - */ - function mulExp(uint a, uint b) internal pure returns (MathError, Exp memory) { - return mulExp(Exp({mantissa: a}), Exp({mantissa: b})); - } - - /** - * @dev Multiplies three exponentials, returning a new exponential. - */ - function mulExp3(Exp memory a, Exp memory b, Exp memory c) internal pure returns (MathError, Exp memory) { - (MathError err, Exp memory ab) = mulExp(a, b); - if (err != MathError.NO_ERROR) { - return (err, ab); - } - return mulExp(ab, c); - } - - /** - * @dev Divides two exponentials, returning a new exponential. - * (a/scale) / (b/scale) = (a/scale) * (scale/b) = a/b, - * which we can scale as an Exp by calling getExp(a.mantissa, b.mantissa) - */ - function divExp(Exp memory a, Exp memory b) internal pure returns (MathError, Exp memory) { - return getExp(a.mantissa, b.mantissa); - } -} - - -// Dependency file: contracts/SafeMath.sol - -// pragma solidity 0.8.6; - -// From https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/math/Math.sol -// Subject to the MIT license. - -/** - * @dev Wrappers over Solidity's arithmetic operations with added overflow - * checks. - * - * Arithmetic operations in Solidity wrap on overflow. This can easily result - * in bugs, because programmers usually assume that an overflow raises an - * error, which is the standard behavior in high level programming languages. - * `SafeMath` restores this intuition by reverting the transaction when an - * operation overflows. - * - * Using this library instead of the unchecked operations eliminates an entire - * class of bugs, so it's recommended to use it always. - */ -library SafeMath { - /** - * @dev Returns the addition of two unsigned integers, reverting on overflow. - * - * Counterpart to Solidity's `+` operator. - * - * Requirements: - * - Addition cannot overflow. - */ - function add(uint256 a, uint256 b) internal pure returns (uint256) { - uint256 c = a + b; - require(c >= a, "SafeMath: addition overflow"); - - return c; - } - - /** - * @dev Returns the addition of two unsigned integers, reverting with custom message on overflow. - * - * Counterpart to Solidity's `+` operator. - * - * Requirements: - * - Addition cannot overflow. - */ - function add(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - uint256 c = a + b; - require(c >= a, errorMessage); - - return c; - } - - /** - * @dev Returns the subtraction of two unsigned integers, reverting on underflow (when the result is negative). - * - * Counterpart to Solidity's `-` operator. - * - * Requirements: - * - Subtraction cannot underflow. - */ - function sub(uint256 a, uint256 b) internal pure returns (uint256) { - return sub(a, b, "SafeMath: subtraction underflow"); - } - - /** - * @dev Returns the subtraction of two unsigned integers, reverting with custom message on underflow (when the result is negative). - * - * Counterpart to Solidity's `-` operator. - * - * Requirements: - * - Subtraction cannot underflow. - */ - function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - require(b <= a, errorMessage); - uint256 c = a - b; - - return c; - } - - /** - * @dev Returns the multiplication of two unsigned integers, reverting on overflow. - * - * Counterpart to Solidity's `*` operator. - * - * Requirements: - * - Multiplication cannot overflow. - */ - function mul(uint256 a, uint256 b) internal pure returns (uint256) { - // Gas optimization: this is cheaper than requiring 'a' not being zero, but the - // benefit is lost if 'b' is also tested. - // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 - if (a == 0) { - return 0; - } - - uint256 c = a * b; - require(c / a == b, "SafeMath: multiplication overflow"); - - return c; - } - - /** - * @dev Returns the multiplication of two unsigned integers, reverting on overflow. - * - * Counterpart to Solidity's `*` operator. - * - * Requirements: - * - Multiplication cannot overflow. - */ - function mul(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - // Gas optimization: this is cheaper than requiring 'a' not being zero, but the - // benefit is lost if 'b' is also tested. - // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 - if (a == 0) { - return 0; - } - - uint256 c = a * b; - require(c / a == b, errorMessage); - - return c; - } - - /** - * @dev Returns the integer division of two unsigned integers. - * Reverts on division by zero. The result is rounded towards zero. - * - * Counterpart to Solidity's `/` operator. Note: this function uses a - * `revert` opcode (which leaves remaining gas untouched) while Solidity - * uses an invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function div(uint256 a, uint256 b) internal pure returns (uint256) { - return div(a, b, "SafeMath: division by zero"); - } - - /** - * @dev Returns the integer division of two unsigned integers. - * Reverts with custom message on division by zero. The result is rounded towards zero. - * - * Counterpart to Solidity's `/` operator. Note: this function uses a - * `revert` opcode (which leaves remaining gas untouched) while Solidity - * uses an invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - // Solidity only automatically asserts when dividing by 0 - require(b > 0, errorMessage); - uint256 c = a / b; - // assert(a == b * c + a % b); // There is no case in which this doesn't hold - - return c; - } - - /** - * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), - * Reverts when dividing by zero. - * - * Counterpart to Solidity's `%` operator. This function uses a `revert` - * opcode (which leaves remaining gas untouched) while Solidity uses an - * invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function mod(uint256 a, uint256 b) internal pure returns (uint256) { - return mod(a, b, "SafeMath: modulo by zero"); - } - - /** - * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), - * Reverts with custom message when dividing by zero. - * - * Counterpart to Solidity's `%` operator. This function uses a `revert` - * opcode (which leaves remaining gas untouched) while Solidity uses an - * invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - require(b != 0, errorMessage); - return a % b; - } -} - - -// Dependency file: contracts/InterestRateModel.sol - -// pragma solidity 0.8.6; - -// import "contracts/Exponential.sol"; -// import "contracts/SafeMath.sol"; - -/** - * @title tropykus InterestRateModel Interface - * @author tropykus - */ -abstract contract InterestRateModel is Exponential { - using SafeMath for uint256; - - /// @notice Indicator that this is an InterestRateModel contract (for inspection) - bool public constant isInterestRateModel = true; - bool public isTropykusInterestRateModel; - - /** - * @notice The approximate number of blocks per year that is assumed by the interest rate model - */ - uint256 public constant blocksPerYear = 1051200; - - /** - * @notice Calculates the utilization rate of the market: `borrows / (cash + borrows - reserves)` - * @param cash The amount of cash in the market - * @param borrows The amount of borrows in the market - * @param reserves The amount of reserves in the market (currently unused) - * @return The utilization rate as a mantissa between [0, 1e18] - */ - function utilizationRate( - uint256 cash, - uint256 borrows, - uint256 reserves - ) public pure virtual returns (uint256) { - // Utilization rate is 0 when there are no borrows - if (borrows == 0) { - return 0; - } - - return borrows.mul(1e18).div(cash.add(borrows).sub(reserves)); - } - - /** - * @notice Calculates the current borrow interest rate per block - * @param cash The total amount of cash the market has - * @param borrows The total amount of borrows the market has outstanding - * @param reserves The total amnount of reserves the market has - * @return The borrow rate per block (as a percentage, and scaled by 1e18) - */ - function getBorrowRate( - uint256 cash, - uint256 borrows, - uint256 reserves - ) external view virtual returns (uint256); - - /** - * @notice Calculates the current supply interest rate per block - * @param cash The total amount of cash the market has - * @param borrows The total amount of borrows the market has outstanding - * @param reserves The total amnount of reserves the market has - * @param reserveFactorMantissa The current reserve factor the market has - * @return The supply rate per block (as a percentage, and scaled by 1e18) - */ - function getSupplyRate( - uint256 cash, - uint256 borrows, - uint256 reserves, - uint256 reserveFactorMantissa - ) external view virtual returns (uint256); - - function getExchangeRate( - uint256 _totalCash, - uint256 _totalBorrows, - uint256 _totalReserves, - uint256 _totalSupply - ) public pure returns (MathError, uint256) { - /* - * exchangeRate = (totalCash + totalBorrows - totalReserves) / totalSupply - */ - Exp memory exchangeRate; - MathError mathErr; - uint256 cashPlusBorrowsMinusReserves; - (mathErr, cashPlusBorrowsMinusReserves) = addThenSubUInt( - _totalCash, - _totalBorrows, - _totalReserves - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - (mathErr, exchangeRate) = getExp( - cashPlusBorrowsMinusReserves, - _totalSupply - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - - return (MathError.NO_ERROR, exchangeRate.mantissa); - } - - function isAboveOptimal( - uint256 cash, - uint256 borrows, - uint256 reserves - ) public view virtual returns (bool) { - cash; - borrows; - reserves; - return false; - } -} - - -// Root file: contracts/JumpRateModel.sol - -pragma solidity 0.8.6; - -// import "contracts/InterestRateModel.sol"; -// import "contracts/SafeMath.sol"; - -/** - * @title tropykus JumpRateModel Contract - * @author tropykus - */ -contract JumpRateModel is InterestRateModel { - using SafeMath for uint256; - - event NewInterestParams( - uint256 baseRatePerBlock, - uint256 multiplierPerBlock, - uint256 jumpMultiplierPerBlock, - uint256 kink - ); - - /** - * @notice The multiplier of utilization rate that gives the slope of the interest rate - */ - uint256 public multiplierPerBlock; - - /** - * @notice The base interest rate which is the y-intercept when utilization rate is 0 - */ - uint256 public baseRatePerBlock; - - /** - * @notice The multiplierPerBlock after hitting a specified utilization point - */ - uint256 public jumpMultiplierPerBlock; - - /** - * @notice The utilization point at which the jump multiplier is applied - */ - uint256 public kink; - - /** - * @notice Construct an interest rate model - * @param baseRatePerYear The approximate target base APR, as a mantissa (scaled by 1e18) - * @param multiplierPerYear The rate of increase in interest rate wrt utilization (scaled by 1e18) - * @param jumpMultiplierPerYear The multiplierPerBlock after hitting a specified utilization point - * @param kink_ The utilization point at which the jump multiplier is applied - */ - constructor( - uint256 baseRatePerYear, - uint256 multiplierPerYear, - uint256 jumpMultiplierPerYear, - uint256 kink_ - ) { - baseRatePerBlock = baseRatePerYear.div(blocksPerYear); - multiplierPerBlock = multiplierPerYear.div(blocksPerYear); - jumpMultiplierPerBlock = jumpMultiplierPerYear.div(blocksPerYear); - kink = kink_; - - emit NewInterestParams( - baseRatePerBlock, - multiplierPerBlock, - jumpMultiplierPerBlock, - kink - ); - } - - /** - * @notice Calculates the utilization rate of the market: `borrows / (cash + borrows - reserves)` - * @param cash The amount of cash in the market - * @param borrows The amount of borrows in the market - * @param reserves The amount of reserves in the market (currently unused) - * @return The utilization rate as a mantissa between [0, 1e18] - */ - function utilizationRate( - uint256 cash, - uint256 borrows, - uint256 reserves - ) public pure override returns (uint256) { - // Utilization rate is 0 when there are no borrows - if (borrows == 0) { - return 0; - } - - return borrows.mul(1e18).div(cash.add(borrows).sub(reserves)); - } - - /** - * @notice Calculates the current borrow rate per block, with the error code expected by the market - * @param cash The amount of cash in the market - * @param borrows The amount of borrows in the market - * @param reserves The amount of reserves in the market - * @return The borrow rate percentage per block as a mantissa (scaled by 1e18) - */ - function getBorrowRate( - uint256 cash, - uint256 borrows, - uint256 reserves - ) public view override returns (uint256) { - uint256 util = utilizationRate(cash, borrows, reserves); - - if (util <= kink) { - return util.mul(multiplierPerBlock).div(1e18).add(baseRatePerBlock); - } else { - uint256 normalRate = kink.mul(multiplierPerBlock).div(1e18).add( - baseRatePerBlock - ); - uint256 excessUtil = util.sub(kink); - return - excessUtil.mul(jumpMultiplierPerBlock).div(1e18).add( - normalRate - ); - } - } - - /** - * @notice Calculates the current supply rate per block - * @param cash The amount of cash in the market - * @param borrows The amount of borrows in the market - * @param reserves The amount of reserves in the market - * @param reserveFactorMantissa The current reserve factor for the market - * @return The supply rate percentage per block as a mantissa (scaled by 1e18) - */ - function getSupplyRate( - uint256 cash, - uint256 borrows, - uint256 reserves, - uint256 reserveFactorMantissa - ) public view override returns (uint256) { - uint256 oneMinusReserveFactor = uint256(1e18).sub( - reserveFactorMantissa - ); - uint256 borrowRate = getBorrowRate(cash, borrows, reserves); - uint256 rateToPool = borrowRate.mul(oneMinusReserveFactor).div(1e18); - return - utilizationRate(cash, borrows, reserves).mul(rateToPool).div(1e18); - } -} diff --git a/flatten/JumpRateModelV2.sol b/flatten/JumpRateModelV2.sol deleted file mode 100644 index 35588be..0000000 --- a/flatten/JumpRateModelV2.sol +++ /dev/null @@ -1,1030 +0,0 @@ -// Dependency file: contracts/CarefulMath.sol - -// SPDX-License-Identifier: UNLICENSED -// pragma solidity 0.8.6; - -/** - * @title Careful Math - * @author tropykus - * @notice Derived from OpenZeppelin's SafeMath library - * https://github.com/OpenZeppelin/openzeppelin-solidity/blob/master/contracts/math/SafeMath.sol - */ -contract CarefulMath { - - /** - * @dev Possible error codes that we can return - */ - enum MathError { - NO_ERROR, - DIVISION_BY_ZERO, - INTEGER_OVERFLOW, - INTEGER_UNDERFLOW - } - - /** - * @dev Multiplies two numbers, returns an error on overflow. - */ - function mulUInt(uint a, uint b) internal pure returns (MathError, uint) { - if (a == 0) { - return (MathError.NO_ERROR, 0); - } - - uint c = a * b; - - if (c / a != b) { - return (MathError.INTEGER_OVERFLOW, 0); - } else { - return (MathError.NO_ERROR, c); - } - } - - /** - * @dev Integer division of two numbers, truncating the quotient. - */ - function divUInt(uint a, uint b) internal pure returns (MathError, uint) { - if (b == 0) { - return (MathError.DIVISION_BY_ZERO, 0); - } - - return (MathError.NO_ERROR, a / b); - } - - /** - * @dev Subtracts two numbers, returns an error on overflow (i.e. if subtrahend is greater than minuend). - */ - function subUInt(uint a, uint b) internal pure returns (MathError, uint) { - if (b <= a) { - return (MathError.NO_ERROR, a - b); - } else { - return (MathError.INTEGER_UNDERFLOW, 0); - } - } - - /** - * @dev Adds two numbers, returns an error on overflow. - */ - function addUInt(uint a, uint b) internal pure returns (MathError, uint) { - uint c = a + b; - - if (c >= a) { - return (MathError.NO_ERROR, c); - } else { - return (MathError.INTEGER_OVERFLOW, 0); - } - } - - /** - * @dev add a and b and then subtract c - */ - function addThenSubUInt(uint a, uint b, uint c) internal pure returns (MathError, uint) { - (MathError err0, uint sum) = addUInt(a, b); - - if (err0 != MathError.NO_ERROR) { - return (err0, 0); - } - - return subUInt(sum, c); - } -} - - -// Dependency file: contracts/ExponentialNoError.sol - -// pragma solidity 0.8.6; - -/** - * @title Exponential module for storing fixed-precision decimals - * @author tropykus - * @notice Exp is a struct which stores decimals with a fixed precision of 18 decimal places. - * Thus, if we wanted to store the 5.1, mantissa would store 5.1e18. That is: - * `Exp({mantissa: 5100000000000000000})`. - */ -contract ExponentialNoError { - uint constant expScale = 1e18; - uint constant doubleScale = 1e36; - uint constant halfExpScale = expScale/2; - uint constant mantissaOne = expScale; - - struct Exp { - uint mantissa; - } - - struct Double { - uint mantissa; - } - - /** - * @dev Truncates the given exp to a whole number value. - * For example, truncate(Exp{mantissa: 15 * expScale}) = 15 - */ - function truncate(Exp memory exp) pure internal returns (uint) { - // Note: We are not using careful math here as we're performing a division that cannot fail - return exp.mantissa / expScale; - } - - /** - * @dev Multiply an Exp by a scalar, then truncate to return an unsigned integer. - */ - function mul_ScalarTruncate(Exp memory a, uint scalar) pure internal returns (uint) { - Exp memory product = mul_(a, scalar); - return truncate(product); - } - - /** - * @dev Multiply an Exp by a scalar, truncate, then add an to an unsigned integer, returning an unsigned integer. - */ - function mul_ScalarTruncateAddUInt(Exp memory a, uint scalar, uint addend) pure internal returns (uint) { - Exp memory product = mul_(a, scalar); - return add_(truncate(product), addend); - } - - /** - * @dev Checks if first Exp is less than second Exp. - */ - function lessThanExp(Exp memory left, Exp memory right) pure internal returns (bool) { - return left.mantissa < right.mantissa; - } - - /** - * @dev Checks if left Exp <= right Exp. - */ - function lessThanOrEqualExp(Exp memory left, Exp memory right) pure internal returns (bool) { - return left.mantissa <= right.mantissa; - } - - /** - * @dev Checks if left Exp > right Exp. - */ - function greaterThanExp(Exp memory left, Exp memory right) pure internal returns (bool) { - return left.mantissa > right.mantissa; - } - - /** - * @dev returns true if Exp is exactly zero - */ - function isZeroExp(Exp memory value) pure internal returns (bool) { - return value.mantissa == 0; - } - - function safe224(uint n, string memory errorMessage) pure internal returns (uint224) { - require(n < 2**224, errorMessage); - return uint224(n); - } - - function safe32(uint n, string memory errorMessage) pure internal returns (uint32) { - require(n < 2**32, errorMessage); - return uint32(n); - } - - function add_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { - return Exp({mantissa: add_(a.mantissa, b.mantissa)}); - } - - function add_(Double memory a, Double memory b) pure internal returns (Double memory) { - return Double({mantissa: add_(a.mantissa, b.mantissa)}); - } - - function add_(uint a, uint b) pure internal returns (uint) { - return add_(a, b, "addition overflow"); - } - - function add_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { - uint c = a + b; - require(c >= a, errorMessage); - return c; - } - - function sub_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { - return Exp({mantissa: sub_(a.mantissa, b.mantissa)}); - } - - function sub_(Double memory a, Double memory b) pure internal returns (Double memory) { - return Double({mantissa: sub_(a.mantissa, b.mantissa)}); - } - - function sub_(uint a, uint b) pure internal returns (uint) { - return sub_(a, b, "subtraction underflow"); - } - - function sub_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { - require(b <= a, errorMessage); - return a - b; - } - - function mul_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { - return Exp({mantissa: mul_(a.mantissa, b.mantissa) / expScale}); - } - - function mul_(Exp memory a, uint b) pure internal returns (Exp memory) { - return Exp({mantissa: mul_(a.mantissa, b)}); - } - - function mul_(uint a, Exp memory b) pure internal returns (uint) { - return mul_(a, b.mantissa) / expScale; - } - - function mul_(Double memory a, Double memory b) pure internal returns (Double memory) { - return Double({mantissa: mul_(a.mantissa, b.mantissa) / doubleScale}); - } - - function mul_(Double memory a, uint b) pure internal returns (Double memory) { - return Double({mantissa: mul_(a.mantissa, b)}); - } - - function mul_(uint a, Double memory b) pure internal returns (uint) { - return mul_(a, b.mantissa) / doubleScale; - } - - function mul_(uint a, uint b) pure internal returns (uint) { - return mul_(a, b, "multiplication overflow"); - } - - function mul_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { - if (a == 0 || b == 0) { - return 0; - } - uint c = a * b; - require(c / a == b, errorMessage); - return c; - } - - function div_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { - return Exp({mantissa: div_(mul_(a.mantissa, expScale), b.mantissa)}); - } - - function div_(Exp memory a, uint b) pure internal returns (Exp memory) { - return Exp({mantissa: div_(a.mantissa, b)}); - } - - function div_(uint a, Exp memory b) pure internal returns (uint) { - return div_(mul_(a, expScale), b.mantissa); - } - - function div_(Double memory a, Double memory b) pure internal returns (Double memory) { - return Double({mantissa: div_(mul_(a.mantissa, doubleScale), b.mantissa)}); - } - - function div_(Double memory a, uint b) pure internal returns (Double memory) { - return Double({mantissa: div_(a.mantissa, b)}); - } - - function div_(uint a, Double memory b) pure internal returns (uint) { - return div_(mul_(a, doubleScale), b.mantissa); - } - - function div_(uint a, uint b) pure internal returns (uint) { - return div_(a, b, "divide by zero"); - } - - function div_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { - require(b > 0, errorMessage); - return a / b; - } - - function fraction(uint a, uint b) pure internal returns (Double memory) { - return Double({mantissa: div_(mul_(a, doubleScale), b)}); - } -} - - -// Dependency file: contracts/Exponential.sol - -// pragma solidity 0.8.6; - -// import "contracts/CarefulMath.sol"; -// import "contracts/ExponentialNoError.sol"; - -/** - * @title Exponential module for storing fixed-precision decimals - * @author tropykus - * @dev Legacy contract for compatibility reasons with existing contracts that still use MathError - * @notice Exp is a struct which stores decimals with a fixed precision of 18 decimal places. - * Thus, if we wanted to store the 5.1, mantissa would store 5.1e18. That is: - * `Exp({mantissa: 5100000000000000000})`. - */ -contract Exponential is CarefulMath, ExponentialNoError { - /** - * @dev Creates an exponential from numerator and denominator values. - * Note: Returns an error if (`num` * 10e18) > MAX_INT, - * or if `denom` is zero. - */ - function getExp(uint num, uint denom) internal pure returns (MathError, Exp memory) { - (MathError err0, uint scaledNumerator) = mulUInt(num, expScale); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - - (MathError err1, uint rational) = divUInt(scaledNumerator, denom); - if (err1 != MathError.NO_ERROR) { - return (err1, Exp({mantissa: 0})); - } - - return (MathError.NO_ERROR, Exp({mantissa: rational})); - } - - /** - * @dev Adds two exponentials, returning a new exponential. - */ - function addExp(Exp memory a, Exp memory b) internal pure returns (MathError, Exp memory) { - (MathError error, uint result) = addUInt(a.mantissa, b.mantissa); - - return (error, Exp({mantissa: result})); - } - - /** - * @dev Subtracts two exponentials, returning a new exponential. - */ - function subExp(Exp memory a, Exp memory b) internal pure returns (MathError, Exp memory) { - (MathError error, uint result) = subUInt(a.mantissa, b.mantissa); - - return (error, Exp({mantissa: result})); - } - - /** - * @dev Multiply an Exp by a scalar, returning a new Exp. - */ - function mulScalar(Exp memory a, uint scalar) internal pure returns (MathError, Exp memory) { - (MathError err0, uint scaledMantissa) = mulUInt(a.mantissa, scalar); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - - return (MathError.NO_ERROR, Exp({mantissa: scaledMantissa})); - } - - /** - * @dev Multiply an Exp by a scalar, then truncate to return an unsigned integer. - */ - function mulScalarTruncate(Exp memory a, uint scalar) internal pure returns (MathError, uint) { - (MathError err, Exp memory product) = mulScalar(a, scalar); - if (err != MathError.NO_ERROR) { - return (err, 0); - } - - return (MathError.NO_ERROR, truncate(product)); - } - - /** - * @dev Multiply an Exp by a scalar, truncate, then add an to an unsigned integer, returning an unsigned integer. - */ - function mulScalarTruncateAddUInt(Exp memory a, uint scalar, uint addend) internal pure returns (MathError, uint) { - (MathError err, Exp memory product) = mulScalar(a, scalar); - if (err != MathError.NO_ERROR) { - return (err, 0); - } - - return addUInt(truncate(product), addend); - } - - /** - * @dev Divide an Exp by a scalar, returning a new Exp. - */ - function divScalar(Exp memory a, uint scalar) internal pure returns (MathError, Exp memory) { - (MathError err0, uint descaledMantissa) = divUInt(a.mantissa, scalar); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - - return (MathError.NO_ERROR, Exp({mantissa: descaledMantissa})); - } - - /** - * @dev Divide a scalar by an Exp, returning a new Exp. - */ - function divScalarByExp(uint scalar, Exp memory divisor) internal pure returns (MathError, Exp memory) { - /* - We are doing this as: - getExp(mulUInt(expScale, scalar), divisor.mantissa) - - How it works: - Exp = a / b; - Scalar = s; - `s / (a / b)` = `b * s / a` and since for an Exp `a = mantissa, b = expScale` - */ - (MathError err0, uint numerator) = mulUInt(expScale, scalar); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - return getExp(numerator, divisor.mantissa); - } - - /** - * @dev Divide a scalar by an Exp, then truncate to return an unsigned integer. - */ - function divScalarByExpTruncate(uint scalar, Exp memory divisor) internal pure returns (MathError, uint) { - (MathError err, Exp memory fraction) = divScalarByExp(scalar, divisor); - if (err != MathError.NO_ERROR) { - return (err, 0); - } - - return (MathError.NO_ERROR, truncate(fraction)); - } - - /** - * @dev Multiplies two exponentials, returning a new exponential. - */ - function mulExp(Exp memory a, Exp memory b) internal pure returns (MathError, Exp memory) { - - (MathError err0, uint doubleScaledProduct) = mulUInt(a.mantissa, b.mantissa); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - - // We add half the scale before dividing so that we get rounding instead of truncation. - // See "Listing 6" and text above it at https://accu.org/index.php/journals/1717 - // Without this change, a result like 6.6...e-19 will be truncated to 0 instead of being rounded to 1e-18. - (MathError err1, uint doubleScaledProductWithHalfScale) = addUInt(halfExpScale, doubleScaledProduct); - if (err1 != MathError.NO_ERROR) { - return (err1, Exp({mantissa: 0})); - } - - (MathError err2, uint product) = divUInt(doubleScaledProductWithHalfScale, expScale); - // The only error `div` can return is MathError.DIVISION_BY_ZERO but we control `expScale` and it is not zero. - assert(err2 == MathError.NO_ERROR); - - return (MathError.NO_ERROR, Exp({mantissa: product})); - } - - /** - * @dev Multiplies two exponentials given their mantissas, returning a new exponential. - */ - function mulExp(uint a, uint b) internal pure returns (MathError, Exp memory) { - return mulExp(Exp({mantissa: a}), Exp({mantissa: b})); - } - - /** - * @dev Multiplies three exponentials, returning a new exponential. - */ - function mulExp3(Exp memory a, Exp memory b, Exp memory c) internal pure returns (MathError, Exp memory) { - (MathError err, Exp memory ab) = mulExp(a, b); - if (err != MathError.NO_ERROR) { - return (err, ab); - } - return mulExp(ab, c); - } - - /** - * @dev Divides two exponentials, returning a new exponential. - * (a/scale) / (b/scale) = (a/scale) * (scale/b) = a/b, - * which we can scale as an Exp by calling getExp(a.mantissa, b.mantissa) - */ - function divExp(Exp memory a, Exp memory b) internal pure returns (MathError, Exp memory) { - return getExp(a.mantissa, b.mantissa); - } -} - - -// Dependency file: contracts/SafeMath.sol - -// pragma solidity 0.8.6; - -// From https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/math/Math.sol -// Subject to the MIT license. - -/** - * @dev Wrappers over Solidity's arithmetic operations with added overflow - * checks. - * - * Arithmetic operations in Solidity wrap on overflow. This can easily result - * in bugs, because programmers usually assume that an overflow raises an - * error, which is the standard behavior in high level programming languages. - * `SafeMath` restores this intuition by reverting the transaction when an - * operation overflows. - * - * Using this library instead of the unchecked operations eliminates an entire - * class of bugs, so it's recommended to use it always. - */ -library SafeMath { - /** - * @dev Returns the addition of two unsigned integers, reverting on overflow. - * - * Counterpart to Solidity's `+` operator. - * - * Requirements: - * - Addition cannot overflow. - */ - function add(uint256 a, uint256 b) internal pure returns (uint256) { - uint256 c = a + b; - require(c >= a, "SafeMath: addition overflow"); - - return c; - } - - /** - * @dev Returns the addition of two unsigned integers, reverting with custom message on overflow. - * - * Counterpart to Solidity's `+` operator. - * - * Requirements: - * - Addition cannot overflow. - */ - function add(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - uint256 c = a + b; - require(c >= a, errorMessage); - - return c; - } - - /** - * @dev Returns the subtraction of two unsigned integers, reverting on underflow (when the result is negative). - * - * Counterpart to Solidity's `-` operator. - * - * Requirements: - * - Subtraction cannot underflow. - */ - function sub(uint256 a, uint256 b) internal pure returns (uint256) { - return sub(a, b, "SafeMath: subtraction underflow"); - } - - /** - * @dev Returns the subtraction of two unsigned integers, reverting with custom message on underflow (when the result is negative). - * - * Counterpart to Solidity's `-` operator. - * - * Requirements: - * - Subtraction cannot underflow. - */ - function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - require(b <= a, errorMessage); - uint256 c = a - b; - - return c; - } - - /** - * @dev Returns the multiplication of two unsigned integers, reverting on overflow. - * - * Counterpart to Solidity's `*` operator. - * - * Requirements: - * - Multiplication cannot overflow. - */ - function mul(uint256 a, uint256 b) internal pure returns (uint256) { - // Gas optimization: this is cheaper than requiring 'a' not being zero, but the - // benefit is lost if 'b' is also tested. - // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 - if (a == 0) { - return 0; - } - - uint256 c = a * b; - require(c / a == b, "SafeMath: multiplication overflow"); - - return c; - } - - /** - * @dev Returns the multiplication of two unsigned integers, reverting on overflow. - * - * Counterpart to Solidity's `*` operator. - * - * Requirements: - * - Multiplication cannot overflow. - */ - function mul(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - // Gas optimization: this is cheaper than requiring 'a' not being zero, but the - // benefit is lost if 'b' is also tested. - // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 - if (a == 0) { - return 0; - } - - uint256 c = a * b; - require(c / a == b, errorMessage); - - return c; - } - - /** - * @dev Returns the integer division of two unsigned integers. - * Reverts on division by zero. The result is rounded towards zero. - * - * Counterpart to Solidity's `/` operator. Note: this function uses a - * `revert` opcode (which leaves remaining gas untouched) while Solidity - * uses an invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function div(uint256 a, uint256 b) internal pure returns (uint256) { - return div(a, b, "SafeMath: division by zero"); - } - - /** - * @dev Returns the integer division of two unsigned integers. - * Reverts with custom message on division by zero. The result is rounded towards zero. - * - * Counterpart to Solidity's `/` operator. Note: this function uses a - * `revert` opcode (which leaves remaining gas untouched) while Solidity - * uses an invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - // Solidity only automatically asserts when dividing by 0 - require(b > 0, errorMessage); - uint256 c = a / b; - // assert(a == b * c + a % b); // There is no case in which this doesn't hold - - return c; - } - - /** - * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), - * Reverts when dividing by zero. - * - * Counterpart to Solidity's `%` operator. This function uses a `revert` - * opcode (which leaves remaining gas untouched) while Solidity uses an - * invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function mod(uint256 a, uint256 b) internal pure returns (uint256) { - return mod(a, b, "SafeMath: modulo by zero"); - } - - /** - * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), - * Reverts with custom message when dividing by zero. - * - * Counterpart to Solidity's `%` operator. This function uses a `revert` - * opcode (which leaves remaining gas untouched) while Solidity uses an - * invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - require(b != 0, errorMessage); - return a % b; - } -} - - -// Dependency file: contracts/InterestRateModel.sol - -// pragma solidity 0.8.6; - -// import "contracts/Exponential.sol"; -// import "contracts/SafeMath.sol"; - -/** - * @title tropykus InterestRateModel Interface - * @author tropykus - */ -abstract contract InterestRateModel is Exponential { - using SafeMath for uint256; - - /// @notice Indicator that this is an InterestRateModel contract (for inspection) - bool public constant isInterestRateModel = true; - bool public isTropykusInterestRateModel; - - /** - * @notice The approximate number of blocks per year that is assumed by the interest rate model - */ - uint256 public constant blocksPerYear = 1051200; - - /** - * @notice Calculates the utilization rate of the market: `borrows / (cash + borrows - reserves)` - * @param cash The amount of cash in the market - * @param borrows The amount of borrows in the market - * @param reserves The amount of reserves in the market (currently unused) - * @return The utilization rate as a mantissa between [0, 1e18] - */ - function utilizationRate( - uint256 cash, - uint256 borrows, - uint256 reserves - ) public pure virtual returns (uint256) { - // Utilization rate is 0 when there are no borrows - if (borrows == 0) { - return 0; - } - - return borrows.mul(1e18).div(cash.add(borrows).sub(reserves)); - } - - /** - * @notice Calculates the current borrow interest rate per block - * @param cash The total amount of cash the market has - * @param borrows The total amount of borrows the market has outstanding - * @param reserves The total amnount of reserves the market has - * @return The borrow rate per block (as a percentage, and scaled by 1e18) - */ - function getBorrowRate( - uint256 cash, - uint256 borrows, - uint256 reserves - ) external view virtual returns (uint256); - - /** - * @notice Calculates the current supply interest rate per block - * @param cash The total amount of cash the market has - * @param borrows The total amount of borrows the market has outstanding - * @param reserves The total amnount of reserves the market has - * @param reserveFactorMantissa The current reserve factor the market has - * @return The supply rate per block (as a percentage, and scaled by 1e18) - */ - function getSupplyRate( - uint256 cash, - uint256 borrows, - uint256 reserves, - uint256 reserveFactorMantissa - ) external view virtual returns (uint256); - - function getExchangeRate( - uint256 _totalCash, - uint256 _totalBorrows, - uint256 _totalReserves, - uint256 _totalSupply - ) public pure returns (MathError, uint256) { - /* - * exchangeRate = (totalCash + totalBorrows - totalReserves) / totalSupply - */ - Exp memory exchangeRate; - MathError mathErr; - uint256 cashPlusBorrowsMinusReserves; - (mathErr, cashPlusBorrowsMinusReserves) = addThenSubUInt( - _totalCash, - _totalBorrows, - _totalReserves - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - (mathErr, exchangeRate) = getExp( - cashPlusBorrowsMinusReserves, - _totalSupply - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - - return (MathError.NO_ERROR, exchangeRate.mantissa); - } - - function isAboveOptimal( - uint256 cash, - uint256 borrows, - uint256 reserves - ) public view virtual returns (bool) { - cash; - borrows; - reserves; - return false; - } -} - - -// Dependency file: contracts/BaseJumpRateModelV2.sol - -// pragma solidity 0.8.6; - -// import "contracts/InterestRateModel.sol"; -// import "contracts/SafeMath.sol"; - -/** - * @title Logic for tropykus JumpRateModel Contract V2. - * @author tropykus - * @notice Version 2 modifies Version 1 by enabling updateable parameters. - */ -contract BaseJumpRateModelV2 is InterestRateModel { - using SafeMath for uint256; - - event NewInterestParams( - uint256 baseRatePerBlock, - uint256 multiplierPerBlock, - uint256 jumpMultiplierPerBlock, - uint256 kink - ); - event NewAdmin(address indexed newAdmin); - event NewPendingAdmin(address indexed newPendingAdmin); - - /** - * @notice The address of the owner, i.e. the Timelock contract, which can update parameters directly - */ - address public owner; - - /** - * @notice The address of the owner, i.e. the Timelock contract, which can update parameters directly - */ - address public pendingAdmin; - - /** - * @notice The multiplier of utilization rate that gives the slope of the interest rate - */ - uint256 public multiplierPerBlock; - - /** - * @notice The base interest rate which is the y-intercept when utilization rate is 0 - */ - uint256 public baseRatePerBlock; - - /** - * @notice The multiplierPerBlock after hitting a specified utilization point - */ - uint256 public jumpMultiplierPerBlock; - - /** - * @notice The utilization point at which the jump multiplier is applied - */ - uint256 public kink; - - /** - * @notice Construct an interest rate model - * @param baseRatePerYear The approximate target base APR, as a mantissa (scaled by 1e18) - * @param multiplierPerYear The rate of increase in interest rate wrt utilization (scaled by 1e18) - * @param jumpMultiplierPerYear The multiplierPerBlock after hitting a specified utilization point - * @param kink_ The utilization point at which the jump multiplier is applied - * @param owner_ The address of the owner, i.e. the Timelock contract (which has the ability to update parameters directly) - */ - constructor( - uint256 baseRatePerYear, - uint256 multiplierPerYear, - uint256 jumpMultiplierPerYear, - uint256 kink_, - address owner_ - ) { - owner = owner_; - emit NewAdmin(owner); - updateJumpRateModelInternal( - baseRatePerYear, - multiplierPerYear, - jumpMultiplierPerYear, - kink_ - ); - } - - /** - * @notice Update the parameters of the interest rate model (only callable by owner, i.e. Timelock) - * @param baseRatePerYear The approximate target base APR, as a mantissa (scaled by 1e18) - * @param multiplierPerYear The rate of increase in interest rate wrt utilization (scaled by 1e18) - * @param jumpMultiplierPerYear The multiplierPerBlock after hitting a specified utilization point - * @param kink_ The utilization point at which the jump multiplier is applied - */ - function updateJumpRateModel( - uint256 baseRatePerYear, - uint256 multiplierPerYear, - uint256 jumpMultiplierPerYear, - uint256 kink_ - ) external { - require(msg.sender == owner, "only the owner may call this function."); - - updateJumpRateModelInternal( - baseRatePerYear, - multiplierPerYear, - jumpMultiplierPerYear, - kink_ - ); - } - - /** - * @notice Calculates the current borrow rate per block - * @param cash The amount of cash in the market - * @param borrows The amount of borrows in the market - * @param reserves The amount of reserves in the market - * @return The borrow rate percentage per block as a mantissa (scaled by 1e18) - */ - function getBorrowRate( - uint256 cash, - uint256 borrows, - uint256 reserves - ) external view override returns (uint256) { - return getBorrowRateInternal(cash, borrows, reserves); - } - - /** - * @notice Calculates the current borrow rate per block, with the error code expected by the market - * @param cash The amount of cash in the market - * @param borrows The amount of borrows in the market - * @param reserves The amount of reserves in the market - * @return The borrow rate percentage per block as a mantissa (scaled by 1e18) - */ - function getBorrowRateInternal( - uint256 cash, - uint256 borrows, - uint256 reserves - ) internal view returns (uint256) { - uint256 util = utilizationRate(cash, borrows, reserves); - - if (util <= kink) { - return util.mul(multiplierPerBlock).div(1e18).add(baseRatePerBlock); - } else { - uint256 normalRate = kink.mul(multiplierPerBlock).div(1e18).add( - baseRatePerBlock - ); - uint256 excessUtil = util.sub(kink); - return - excessUtil.mul(jumpMultiplierPerBlock).div(1e18).add( - normalRate - ); - } - } - - /** - * @notice Calculates the current supply rate per block - * @param cash The amount of cash in the market - * @param borrows The amount of borrows in the market - * @param reserves The amount of reserves in the market - * @param reserveFactorMantissa The current reserve factor for the market - * @return The supply rate percentage per block as a mantissa (scaled by 1e18) - */ - function getSupplyRate( - uint256 cash, - uint256 borrows, - uint256 reserves, - uint256 reserveFactorMantissa - ) public view override returns (uint256) { - uint256 oneMinusReserveFactor = uint256(1e18).sub( - reserveFactorMantissa - ); - uint256 borrowRate = getBorrowRateInternal(cash, borrows, reserves); - uint256 rateToPool = borrowRate.mul(oneMinusReserveFactor).div(1e18); - return - utilizationRate(cash, borrows, reserves).mul(rateToPool).div(1e18); - } - - /** - * @notice Internal function to update the parameters of the interest rate model - * @param baseRatePerYear The approximate target base APR, as a mantissa (scaled by 1e18) - * @param multiplierPerYear The rate of increase in interest rate wrt utilization (scaled by 1e18) - * @param jumpMultiplierPerYear The multiplierPerBlock after hitting a specified utilization point - * @param kink_ The utilization point at which the jump multiplier is applied - */ - function updateJumpRateModelInternal( - uint256 baseRatePerYear, - uint256 multiplierPerYear, - uint256 jumpMultiplierPerYear, - uint256 kink_ - ) internal { - baseRatePerBlock = baseRatePerYear.div(blocksPerYear); - multiplierPerBlock = (multiplierPerYear.mul(1e18)).div( - blocksPerYear.mul(kink_) - ); - jumpMultiplierPerBlock = jumpMultiplierPerYear.div(blocksPerYear); - kink = kink_; - - emit NewInterestParams( - baseRatePerBlock, - multiplierPerBlock, - jumpMultiplierPerBlock, - kink - ); - } - - function acceptAdmin() public { - require( - msg.sender == pendingAdmin, - "BaseJumpRateModelV2::acceptAdmin: Call must come from pendingAdmin." - ); - owner = msg.sender; - pendingAdmin = address(0); - - emit NewAdmin(owner); - } - - function setPendingAdmin(address pendingAdmin_) public { - require( - msg.sender == owner, - "BaseJumpRateModelV2::setPendingAdmin: Call must come from owner." - ); - pendingAdmin = pendingAdmin_; - - emit NewPendingAdmin(pendingAdmin); - } -} - - -// Root file: contracts/JumpRateModelV2.sol - -pragma solidity 0.8.6; - -// import "contracts/BaseJumpRateModelV2.sol"; - -/** - * @title tropykus JumpRateModel Contract V2 for V2 cTokens - * @author tropykus - * @notice Supports only for V2 cTokens - */ -contract JumpRateModelV2 is BaseJumpRateModelV2 { - constructor( - uint256 baseRatePerYear, - uint256 multiplierPerYear, - uint256 jumpMultiplierPerYear, - uint256 kink_, - address owner_ - ) - BaseJumpRateModelV2( - baseRatePerYear, - multiplierPerYear, - jumpMultiplierPerYear, - kink_, - owner_ - ) - { - isTropykusInterestRateModel = false; - } -} diff --git a/flatten/LegacyInterestRateModel.sol b/flatten/LegacyInterestRateModel.sol deleted file mode 100644 index dd52c46..0000000 --- a/flatten/LegacyInterestRateModel.sol +++ /dev/null @@ -1,28 +0,0 @@ -// Root file: contracts/LegacyInterestRateModel.sol - -// SPDX-License-Identifier: UNLICENSED -pragma solidity 0.8.6; - -/** - * @title tropykus Legacy InterestRateModel Interface - * @author tropykus (modified by Arr00) - */ -abstract contract LegacyInterestRateModel { - /// @notice Indicator that this is an InterestRateModel contract (for inspection) - bool public constant isInterestRateModel = true; - - /** - * @notice Calculates the current supply interest rate per block - * @param cash The total amount of cash the market has - * @param borrows The total amount of borrows the market has outstanding - * @param reserves The total amount of reserves the market has - * @param reserveFactorMantissa The current reserve factor the market has - * @return The supply rate per block (as a percentage, and scaled by 1e18) - */ - function getSupplyRate( - uint256 cash, - uint256 borrows, - uint256 reserves, - uint256 reserveFactorMantissa - ) external view virtual returns (uint256); -} diff --git a/flatten/LegacyJumpRateModelV2.sol b/flatten/LegacyJumpRateModelV2.sol deleted file mode 100644 index c2fb9b7..0000000 --- a/flatten/LegacyJumpRateModelV2.sol +++ /dev/null @@ -1,1060 +0,0 @@ -// Dependency file: contracts/CarefulMath.sol - -// SPDX-License-Identifier: UNLICENSED -// pragma solidity 0.8.6; - -/** - * @title Careful Math - * @author tropykus - * @notice Derived from OpenZeppelin's SafeMath library - * https://github.com/OpenZeppelin/openzeppelin-solidity/blob/master/contracts/math/SafeMath.sol - */ -contract CarefulMath { - - /** - * @dev Possible error codes that we can return - */ - enum MathError { - NO_ERROR, - DIVISION_BY_ZERO, - INTEGER_OVERFLOW, - INTEGER_UNDERFLOW - } - - /** - * @dev Multiplies two numbers, returns an error on overflow. - */ - function mulUInt(uint a, uint b) internal pure returns (MathError, uint) { - if (a == 0) { - return (MathError.NO_ERROR, 0); - } - - uint c = a * b; - - if (c / a != b) { - return (MathError.INTEGER_OVERFLOW, 0); - } else { - return (MathError.NO_ERROR, c); - } - } - - /** - * @dev Integer division of two numbers, truncating the quotient. - */ - function divUInt(uint a, uint b) internal pure returns (MathError, uint) { - if (b == 0) { - return (MathError.DIVISION_BY_ZERO, 0); - } - - return (MathError.NO_ERROR, a / b); - } - - /** - * @dev Subtracts two numbers, returns an error on overflow (i.e. if subtrahend is greater than minuend). - */ - function subUInt(uint a, uint b) internal pure returns (MathError, uint) { - if (b <= a) { - return (MathError.NO_ERROR, a - b); - } else { - return (MathError.INTEGER_UNDERFLOW, 0); - } - } - - /** - * @dev Adds two numbers, returns an error on overflow. - */ - function addUInt(uint a, uint b) internal pure returns (MathError, uint) { - uint c = a + b; - - if (c >= a) { - return (MathError.NO_ERROR, c); - } else { - return (MathError.INTEGER_OVERFLOW, 0); - } - } - - /** - * @dev add a and b and then subtract c - */ - function addThenSubUInt(uint a, uint b, uint c) internal pure returns (MathError, uint) { - (MathError err0, uint sum) = addUInt(a, b); - - if (err0 != MathError.NO_ERROR) { - return (err0, 0); - } - - return subUInt(sum, c); - } -} - - -// Dependency file: contracts/ExponentialNoError.sol - -// pragma solidity 0.8.6; - -/** - * @title Exponential module for storing fixed-precision decimals - * @author tropykus - * @notice Exp is a struct which stores decimals with a fixed precision of 18 decimal places. - * Thus, if we wanted to store the 5.1, mantissa would store 5.1e18. That is: - * `Exp({mantissa: 5100000000000000000})`. - */ -contract ExponentialNoError { - uint constant expScale = 1e18; - uint constant doubleScale = 1e36; - uint constant halfExpScale = expScale/2; - uint constant mantissaOne = expScale; - - struct Exp { - uint mantissa; - } - - struct Double { - uint mantissa; - } - - /** - * @dev Truncates the given exp to a whole number value. - * For example, truncate(Exp{mantissa: 15 * expScale}) = 15 - */ - function truncate(Exp memory exp) pure internal returns (uint) { - // Note: We are not using careful math here as we're performing a division that cannot fail - return exp.mantissa / expScale; - } - - /** - * @dev Multiply an Exp by a scalar, then truncate to return an unsigned integer. - */ - function mul_ScalarTruncate(Exp memory a, uint scalar) pure internal returns (uint) { - Exp memory product = mul_(a, scalar); - return truncate(product); - } - - /** - * @dev Multiply an Exp by a scalar, truncate, then add an to an unsigned integer, returning an unsigned integer. - */ - function mul_ScalarTruncateAddUInt(Exp memory a, uint scalar, uint addend) pure internal returns (uint) { - Exp memory product = mul_(a, scalar); - return add_(truncate(product), addend); - } - - /** - * @dev Checks if first Exp is less than second Exp. - */ - function lessThanExp(Exp memory left, Exp memory right) pure internal returns (bool) { - return left.mantissa < right.mantissa; - } - - /** - * @dev Checks if left Exp <= right Exp. - */ - function lessThanOrEqualExp(Exp memory left, Exp memory right) pure internal returns (bool) { - return left.mantissa <= right.mantissa; - } - - /** - * @dev Checks if left Exp > right Exp. - */ - function greaterThanExp(Exp memory left, Exp memory right) pure internal returns (bool) { - return left.mantissa > right.mantissa; - } - - /** - * @dev returns true if Exp is exactly zero - */ - function isZeroExp(Exp memory value) pure internal returns (bool) { - return value.mantissa == 0; - } - - function safe224(uint n, string memory errorMessage) pure internal returns (uint224) { - require(n < 2**224, errorMessage); - return uint224(n); - } - - function safe32(uint n, string memory errorMessage) pure internal returns (uint32) { - require(n < 2**32, errorMessage); - return uint32(n); - } - - function add_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { - return Exp({mantissa: add_(a.mantissa, b.mantissa)}); - } - - function add_(Double memory a, Double memory b) pure internal returns (Double memory) { - return Double({mantissa: add_(a.mantissa, b.mantissa)}); - } - - function add_(uint a, uint b) pure internal returns (uint) { - return add_(a, b, "addition overflow"); - } - - function add_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { - uint c = a + b; - require(c >= a, errorMessage); - return c; - } - - function sub_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { - return Exp({mantissa: sub_(a.mantissa, b.mantissa)}); - } - - function sub_(Double memory a, Double memory b) pure internal returns (Double memory) { - return Double({mantissa: sub_(a.mantissa, b.mantissa)}); - } - - function sub_(uint a, uint b) pure internal returns (uint) { - return sub_(a, b, "subtraction underflow"); - } - - function sub_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { - require(b <= a, errorMessage); - return a - b; - } - - function mul_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { - return Exp({mantissa: mul_(a.mantissa, b.mantissa) / expScale}); - } - - function mul_(Exp memory a, uint b) pure internal returns (Exp memory) { - return Exp({mantissa: mul_(a.mantissa, b)}); - } - - function mul_(uint a, Exp memory b) pure internal returns (uint) { - return mul_(a, b.mantissa) / expScale; - } - - function mul_(Double memory a, Double memory b) pure internal returns (Double memory) { - return Double({mantissa: mul_(a.mantissa, b.mantissa) / doubleScale}); - } - - function mul_(Double memory a, uint b) pure internal returns (Double memory) { - return Double({mantissa: mul_(a.mantissa, b)}); - } - - function mul_(uint a, Double memory b) pure internal returns (uint) { - return mul_(a, b.mantissa) / doubleScale; - } - - function mul_(uint a, uint b) pure internal returns (uint) { - return mul_(a, b, "multiplication overflow"); - } - - function mul_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { - if (a == 0 || b == 0) { - return 0; - } - uint c = a * b; - require(c / a == b, errorMessage); - return c; - } - - function div_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { - return Exp({mantissa: div_(mul_(a.mantissa, expScale), b.mantissa)}); - } - - function div_(Exp memory a, uint b) pure internal returns (Exp memory) { - return Exp({mantissa: div_(a.mantissa, b)}); - } - - function div_(uint a, Exp memory b) pure internal returns (uint) { - return div_(mul_(a, expScale), b.mantissa); - } - - function div_(Double memory a, Double memory b) pure internal returns (Double memory) { - return Double({mantissa: div_(mul_(a.mantissa, doubleScale), b.mantissa)}); - } - - function div_(Double memory a, uint b) pure internal returns (Double memory) { - return Double({mantissa: div_(a.mantissa, b)}); - } - - function div_(uint a, Double memory b) pure internal returns (uint) { - return div_(mul_(a, doubleScale), b.mantissa); - } - - function div_(uint a, uint b) pure internal returns (uint) { - return div_(a, b, "divide by zero"); - } - - function div_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { - require(b > 0, errorMessage); - return a / b; - } - - function fraction(uint a, uint b) pure internal returns (Double memory) { - return Double({mantissa: div_(mul_(a, doubleScale), b)}); - } -} - - -// Dependency file: contracts/Exponential.sol - -// pragma solidity 0.8.6; - -// import "contracts/CarefulMath.sol"; -// import "contracts/ExponentialNoError.sol"; - -/** - * @title Exponential module for storing fixed-precision decimals - * @author tropykus - * @dev Legacy contract for compatibility reasons with existing contracts that still use MathError - * @notice Exp is a struct which stores decimals with a fixed precision of 18 decimal places. - * Thus, if we wanted to store the 5.1, mantissa would store 5.1e18. That is: - * `Exp({mantissa: 5100000000000000000})`. - */ -contract Exponential is CarefulMath, ExponentialNoError { - /** - * @dev Creates an exponential from numerator and denominator values. - * Note: Returns an error if (`num` * 10e18) > MAX_INT, - * or if `denom` is zero. - */ - function getExp(uint num, uint denom) internal pure returns (MathError, Exp memory) { - (MathError err0, uint scaledNumerator) = mulUInt(num, expScale); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - - (MathError err1, uint rational) = divUInt(scaledNumerator, denom); - if (err1 != MathError.NO_ERROR) { - return (err1, Exp({mantissa: 0})); - } - - return (MathError.NO_ERROR, Exp({mantissa: rational})); - } - - /** - * @dev Adds two exponentials, returning a new exponential. - */ - function addExp(Exp memory a, Exp memory b) internal pure returns (MathError, Exp memory) { - (MathError error, uint result) = addUInt(a.mantissa, b.mantissa); - - return (error, Exp({mantissa: result})); - } - - /** - * @dev Subtracts two exponentials, returning a new exponential. - */ - function subExp(Exp memory a, Exp memory b) internal pure returns (MathError, Exp memory) { - (MathError error, uint result) = subUInt(a.mantissa, b.mantissa); - - return (error, Exp({mantissa: result})); - } - - /** - * @dev Multiply an Exp by a scalar, returning a new Exp. - */ - function mulScalar(Exp memory a, uint scalar) internal pure returns (MathError, Exp memory) { - (MathError err0, uint scaledMantissa) = mulUInt(a.mantissa, scalar); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - - return (MathError.NO_ERROR, Exp({mantissa: scaledMantissa})); - } - - /** - * @dev Multiply an Exp by a scalar, then truncate to return an unsigned integer. - */ - function mulScalarTruncate(Exp memory a, uint scalar) internal pure returns (MathError, uint) { - (MathError err, Exp memory product) = mulScalar(a, scalar); - if (err != MathError.NO_ERROR) { - return (err, 0); - } - - return (MathError.NO_ERROR, truncate(product)); - } - - /** - * @dev Multiply an Exp by a scalar, truncate, then add an to an unsigned integer, returning an unsigned integer. - */ - function mulScalarTruncateAddUInt(Exp memory a, uint scalar, uint addend) internal pure returns (MathError, uint) { - (MathError err, Exp memory product) = mulScalar(a, scalar); - if (err != MathError.NO_ERROR) { - return (err, 0); - } - - return addUInt(truncate(product), addend); - } - - /** - * @dev Divide an Exp by a scalar, returning a new Exp. - */ - function divScalar(Exp memory a, uint scalar) internal pure returns (MathError, Exp memory) { - (MathError err0, uint descaledMantissa) = divUInt(a.mantissa, scalar); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - - return (MathError.NO_ERROR, Exp({mantissa: descaledMantissa})); - } - - /** - * @dev Divide a scalar by an Exp, returning a new Exp. - */ - function divScalarByExp(uint scalar, Exp memory divisor) internal pure returns (MathError, Exp memory) { - /* - We are doing this as: - getExp(mulUInt(expScale, scalar), divisor.mantissa) - - How it works: - Exp = a / b; - Scalar = s; - `s / (a / b)` = `b * s / a` and since for an Exp `a = mantissa, b = expScale` - */ - (MathError err0, uint numerator) = mulUInt(expScale, scalar); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - return getExp(numerator, divisor.mantissa); - } - - /** - * @dev Divide a scalar by an Exp, then truncate to return an unsigned integer. - */ - function divScalarByExpTruncate(uint scalar, Exp memory divisor) internal pure returns (MathError, uint) { - (MathError err, Exp memory fraction) = divScalarByExp(scalar, divisor); - if (err != MathError.NO_ERROR) { - return (err, 0); - } - - return (MathError.NO_ERROR, truncate(fraction)); - } - - /** - * @dev Multiplies two exponentials, returning a new exponential. - */ - function mulExp(Exp memory a, Exp memory b) internal pure returns (MathError, Exp memory) { - - (MathError err0, uint doubleScaledProduct) = mulUInt(a.mantissa, b.mantissa); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - - // We add half the scale before dividing so that we get rounding instead of truncation. - // See "Listing 6" and text above it at https://accu.org/index.php/journals/1717 - // Without this change, a result like 6.6...e-19 will be truncated to 0 instead of being rounded to 1e-18. - (MathError err1, uint doubleScaledProductWithHalfScale) = addUInt(halfExpScale, doubleScaledProduct); - if (err1 != MathError.NO_ERROR) { - return (err1, Exp({mantissa: 0})); - } - - (MathError err2, uint product) = divUInt(doubleScaledProductWithHalfScale, expScale); - // The only error `div` can return is MathError.DIVISION_BY_ZERO but we control `expScale` and it is not zero. - assert(err2 == MathError.NO_ERROR); - - return (MathError.NO_ERROR, Exp({mantissa: product})); - } - - /** - * @dev Multiplies two exponentials given their mantissas, returning a new exponential. - */ - function mulExp(uint a, uint b) internal pure returns (MathError, Exp memory) { - return mulExp(Exp({mantissa: a}), Exp({mantissa: b})); - } - - /** - * @dev Multiplies three exponentials, returning a new exponential. - */ - function mulExp3(Exp memory a, Exp memory b, Exp memory c) internal pure returns (MathError, Exp memory) { - (MathError err, Exp memory ab) = mulExp(a, b); - if (err != MathError.NO_ERROR) { - return (err, ab); - } - return mulExp(ab, c); - } - - /** - * @dev Divides two exponentials, returning a new exponential. - * (a/scale) / (b/scale) = (a/scale) * (scale/b) = a/b, - * which we can scale as an Exp by calling getExp(a.mantissa, b.mantissa) - */ - function divExp(Exp memory a, Exp memory b) internal pure returns (MathError, Exp memory) { - return getExp(a.mantissa, b.mantissa); - } -} - - -// Dependency file: contracts/SafeMath.sol - -// pragma solidity 0.8.6; - -// From https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/math/Math.sol -// Subject to the MIT license. - -/** - * @dev Wrappers over Solidity's arithmetic operations with added overflow - * checks. - * - * Arithmetic operations in Solidity wrap on overflow. This can easily result - * in bugs, because programmers usually assume that an overflow raises an - * error, which is the standard behavior in high level programming languages. - * `SafeMath` restores this intuition by reverting the transaction when an - * operation overflows. - * - * Using this library instead of the unchecked operations eliminates an entire - * class of bugs, so it's recommended to use it always. - */ -library SafeMath { - /** - * @dev Returns the addition of two unsigned integers, reverting on overflow. - * - * Counterpart to Solidity's `+` operator. - * - * Requirements: - * - Addition cannot overflow. - */ - function add(uint256 a, uint256 b) internal pure returns (uint256) { - uint256 c = a + b; - require(c >= a, "SafeMath: addition overflow"); - - return c; - } - - /** - * @dev Returns the addition of two unsigned integers, reverting with custom message on overflow. - * - * Counterpart to Solidity's `+` operator. - * - * Requirements: - * - Addition cannot overflow. - */ - function add(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - uint256 c = a + b; - require(c >= a, errorMessage); - - return c; - } - - /** - * @dev Returns the subtraction of two unsigned integers, reverting on underflow (when the result is negative). - * - * Counterpart to Solidity's `-` operator. - * - * Requirements: - * - Subtraction cannot underflow. - */ - function sub(uint256 a, uint256 b) internal pure returns (uint256) { - return sub(a, b, "SafeMath: subtraction underflow"); - } - - /** - * @dev Returns the subtraction of two unsigned integers, reverting with custom message on underflow (when the result is negative). - * - * Counterpart to Solidity's `-` operator. - * - * Requirements: - * - Subtraction cannot underflow. - */ - function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - require(b <= a, errorMessage); - uint256 c = a - b; - - return c; - } - - /** - * @dev Returns the multiplication of two unsigned integers, reverting on overflow. - * - * Counterpart to Solidity's `*` operator. - * - * Requirements: - * - Multiplication cannot overflow. - */ - function mul(uint256 a, uint256 b) internal pure returns (uint256) { - // Gas optimization: this is cheaper than requiring 'a' not being zero, but the - // benefit is lost if 'b' is also tested. - // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 - if (a == 0) { - return 0; - } - - uint256 c = a * b; - require(c / a == b, "SafeMath: multiplication overflow"); - - return c; - } - - /** - * @dev Returns the multiplication of two unsigned integers, reverting on overflow. - * - * Counterpart to Solidity's `*` operator. - * - * Requirements: - * - Multiplication cannot overflow. - */ - function mul(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - // Gas optimization: this is cheaper than requiring 'a' not being zero, but the - // benefit is lost if 'b' is also tested. - // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 - if (a == 0) { - return 0; - } - - uint256 c = a * b; - require(c / a == b, errorMessage); - - return c; - } - - /** - * @dev Returns the integer division of two unsigned integers. - * Reverts on division by zero. The result is rounded towards zero. - * - * Counterpart to Solidity's `/` operator. Note: this function uses a - * `revert` opcode (which leaves remaining gas untouched) while Solidity - * uses an invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function div(uint256 a, uint256 b) internal pure returns (uint256) { - return div(a, b, "SafeMath: division by zero"); - } - - /** - * @dev Returns the integer division of two unsigned integers. - * Reverts with custom message on division by zero. The result is rounded towards zero. - * - * Counterpart to Solidity's `/` operator. Note: this function uses a - * `revert` opcode (which leaves remaining gas untouched) while Solidity - * uses an invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - // Solidity only automatically asserts when dividing by 0 - require(b > 0, errorMessage); - uint256 c = a / b; - // assert(a == b * c + a % b); // There is no case in which this doesn't hold - - return c; - } - - /** - * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), - * Reverts when dividing by zero. - * - * Counterpart to Solidity's `%` operator. This function uses a `revert` - * opcode (which leaves remaining gas untouched) while Solidity uses an - * invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function mod(uint256 a, uint256 b) internal pure returns (uint256) { - return mod(a, b, "SafeMath: modulo by zero"); - } - - /** - * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), - * Reverts with custom message when dividing by zero. - * - * Counterpart to Solidity's `%` operator. This function uses a `revert` - * opcode (which leaves remaining gas untouched) while Solidity uses an - * invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - require(b != 0, errorMessage); - return a % b; - } -} - - -// Dependency file: contracts/InterestRateModel.sol - -// pragma solidity 0.8.6; - -// import "contracts/Exponential.sol"; -// import "contracts/SafeMath.sol"; - -/** - * @title tropykus InterestRateModel Interface - * @author tropykus - */ -abstract contract InterestRateModel is Exponential { - using SafeMath for uint256; - - /// @notice Indicator that this is an InterestRateModel contract (for inspection) - bool public constant isInterestRateModel = true; - bool public isTropykusInterestRateModel; - - /** - * @notice The approximate number of blocks per year that is assumed by the interest rate model - */ - uint256 public constant blocksPerYear = 1051200; - - /** - * @notice Calculates the utilization rate of the market: `borrows / (cash + borrows - reserves)` - * @param cash The amount of cash in the market - * @param borrows The amount of borrows in the market - * @param reserves The amount of reserves in the market (currently unused) - * @return The utilization rate as a mantissa between [0, 1e18] - */ - function utilizationRate( - uint256 cash, - uint256 borrows, - uint256 reserves - ) public pure virtual returns (uint256) { - // Utilization rate is 0 when there are no borrows - if (borrows == 0) { - return 0; - } - - return borrows.mul(1e18).div(cash.add(borrows).sub(reserves)); - } - - /** - * @notice Calculates the current borrow interest rate per block - * @param cash The total amount of cash the market has - * @param borrows The total amount of borrows the market has outstanding - * @param reserves The total amnount of reserves the market has - * @return The borrow rate per block (as a percentage, and scaled by 1e18) - */ - function getBorrowRate( - uint256 cash, - uint256 borrows, - uint256 reserves - ) external view virtual returns (uint256); - - /** - * @notice Calculates the current supply interest rate per block - * @param cash The total amount of cash the market has - * @param borrows The total amount of borrows the market has outstanding - * @param reserves The total amnount of reserves the market has - * @param reserveFactorMantissa The current reserve factor the market has - * @return The supply rate per block (as a percentage, and scaled by 1e18) - */ - function getSupplyRate( - uint256 cash, - uint256 borrows, - uint256 reserves, - uint256 reserveFactorMantissa - ) external view virtual returns (uint256); - - function getExchangeRate( - uint256 _totalCash, - uint256 _totalBorrows, - uint256 _totalReserves, - uint256 _totalSupply - ) public pure returns (MathError, uint256) { - /* - * exchangeRate = (totalCash + totalBorrows - totalReserves) / totalSupply - */ - Exp memory exchangeRate; - MathError mathErr; - uint256 cashPlusBorrowsMinusReserves; - (mathErr, cashPlusBorrowsMinusReserves) = addThenSubUInt( - _totalCash, - _totalBorrows, - _totalReserves - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - (mathErr, exchangeRate) = getExp( - cashPlusBorrowsMinusReserves, - _totalSupply - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - - return (MathError.NO_ERROR, exchangeRate.mantissa); - } - - function isAboveOptimal( - uint256 cash, - uint256 borrows, - uint256 reserves - ) public view virtual returns (bool) { - cash; - borrows; - reserves; - return false; - } -} - - -// Dependency file: contracts/BaseJumpRateModelV2.sol - -// pragma solidity 0.8.6; - -// import "contracts/InterestRateModel.sol"; -// import "contracts/SafeMath.sol"; - -/** - * @title Logic for tropykus JumpRateModel Contract V2. - * @author tropykus - * @notice Version 2 modifies Version 1 by enabling updateable parameters. - */ -contract BaseJumpRateModelV2 is InterestRateModel { - using SafeMath for uint256; - - event NewInterestParams( - uint256 baseRatePerBlock, - uint256 multiplierPerBlock, - uint256 jumpMultiplierPerBlock, - uint256 kink - ); - event NewAdmin(address indexed newAdmin); - event NewPendingAdmin(address indexed newPendingAdmin); - - /** - * @notice The address of the owner, i.e. the Timelock contract, which can update parameters directly - */ - address public owner; - - /** - * @notice The address of the owner, i.e. the Timelock contract, which can update parameters directly - */ - address public pendingAdmin; - - /** - * @notice The multiplier of utilization rate that gives the slope of the interest rate - */ - uint256 public multiplierPerBlock; - - /** - * @notice The base interest rate which is the y-intercept when utilization rate is 0 - */ - uint256 public baseRatePerBlock; - - /** - * @notice The multiplierPerBlock after hitting a specified utilization point - */ - uint256 public jumpMultiplierPerBlock; - - /** - * @notice The utilization point at which the jump multiplier is applied - */ - uint256 public kink; - - /** - * @notice Construct an interest rate model - * @param baseRatePerYear The approximate target base APR, as a mantissa (scaled by 1e18) - * @param multiplierPerYear The rate of increase in interest rate wrt utilization (scaled by 1e18) - * @param jumpMultiplierPerYear The multiplierPerBlock after hitting a specified utilization point - * @param kink_ The utilization point at which the jump multiplier is applied - * @param owner_ The address of the owner, i.e. the Timelock contract (which has the ability to update parameters directly) - */ - constructor( - uint256 baseRatePerYear, - uint256 multiplierPerYear, - uint256 jumpMultiplierPerYear, - uint256 kink_, - address owner_ - ) { - owner = owner_; - emit NewAdmin(owner); - updateJumpRateModelInternal( - baseRatePerYear, - multiplierPerYear, - jumpMultiplierPerYear, - kink_ - ); - } - - /** - * @notice Update the parameters of the interest rate model (only callable by owner, i.e. Timelock) - * @param baseRatePerYear The approximate target base APR, as a mantissa (scaled by 1e18) - * @param multiplierPerYear The rate of increase in interest rate wrt utilization (scaled by 1e18) - * @param jumpMultiplierPerYear The multiplierPerBlock after hitting a specified utilization point - * @param kink_ The utilization point at which the jump multiplier is applied - */ - function updateJumpRateModel( - uint256 baseRatePerYear, - uint256 multiplierPerYear, - uint256 jumpMultiplierPerYear, - uint256 kink_ - ) external { - require(msg.sender == owner, "only the owner may call this function."); - - updateJumpRateModelInternal( - baseRatePerYear, - multiplierPerYear, - jumpMultiplierPerYear, - kink_ - ); - } - - /** - * @notice Calculates the current borrow rate per block - * @param cash The amount of cash in the market - * @param borrows The amount of borrows in the market - * @param reserves The amount of reserves in the market - * @return The borrow rate percentage per block as a mantissa (scaled by 1e18) - */ - function getBorrowRate( - uint256 cash, - uint256 borrows, - uint256 reserves - ) external view override returns (uint256) { - return getBorrowRateInternal(cash, borrows, reserves); - } - - /** - * @notice Calculates the current borrow rate per block, with the error code expected by the market - * @param cash The amount of cash in the market - * @param borrows The amount of borrows in the market - * @param reserves The amount of reserves in the market - * @return The borrow rate percentage per block as a mantissa (scaled by 1e18) - */ - function getBorrowRateInternal( - uint256 cash, - uint256 borrows, - uint256 reserves - ) internal view returns (uint256) { - uint256 util = utilizationRate(cash, borrows, reserves); - - if (util <= kink) { - return util.mul(multiplierPerBlock).div(1e18).add(baseRatePerBlock); - } else { - uint256 normalRate = kink.mul(multiplierPerBlock).div(1e18).add( - baseRatePerBlock - ); - uint256 excessUtil = util.sub(kink); - return - excessUtil.mul(jumpMultiplierPerBlock).div(1e18).add( - normalRate - ); - } - } - - /** - * @notice Calculates the current supply rate per block - * @param cash The amount of cash in the market - * @param borrows The amount of borrows in the market - * @param reserves The amount of reserves in the market - * @param reserveFactorMantissa The current reserve factor for the market - * @return The supply rate percentage per block as a mantissa (scaled by 1e18) - */ - function getSupplyRate( - uint256 cash, - uint256 borrows, - uint256 reserves, - uint256 reserveFactorMantissa - ) public view override returns (uint256) { - uint256 oneMinusReserveFactor = uint256(1e18).sub( - reserveFactorMantissa - ); - uint256 borrowRate = getBorrowRateInternal(cash, borrows, reserves); - uint256 rateToPool = borrowRate.mul(oneMinusReserveFactor).div(1e18); - return - utilizationRate(cash, borrows, reserves).mul(rateToPool).div(1e18); - } - - /** - * @notice Internal function to update the parameters of the interest rate model - * @param baseRatePerYear The approximate target base APR, as a mantissa (scaled by 1e18) - * @param multiplierPerYear The rate of increase in interest rate wrt utilization (scaled by 1e18) - * @param jumpMultiplierPerYear The multiplierPerBlock after hitting a specified utilization point - * @param kink_ The utilization point at which the jump multiplier is applied - */ - function updateJumpRateModelInternal( - uint256 baseRatePerYear, - uint256 multiplierPerYear, - uint256 jumpMultiplierPerYear, - uint256 kink_ - ) internal { - baseRatePerBlock = baseRatePerYear.div(blocksPerYear); - multiplierPerBlock = (multiplierPerYear.mul(1e18)).div( - blocksPerYear.mul(kink_) - ); - jumpMultiplierPerBlock = jumpMultiplierPerYear.div(blocksPerYear); - kink = kink_; - - emit NewInterestParams( - baseRatePerBlock, - multiplierPerBlock, - jumpMultiplierPerBlock, - kink - ); - } - - function acceptAdmin() public { - require( - msg.sender == pendingAdmin, - "BaseJumpRateModelV2::acceptAdmin: Call must come from pendingAdmin." - ); - owner = msg.sender; - pendingAdmin = address(0); - - emit NewAdmin(owner); - } - - function setPendingAdmin(address pendingAdmin_) public { - require( - msg.sender == owner, - "BaseJumpRateModelV2::setPendingAdmin: Call must come from owner." - ); - pendingAdmin = pendingAdmin_; - - emit NewPendingAdmin(pendingAdmin); - } -} - - -// Dependency file: contracts/LegacyInterestRateModel.sol - -// pragma solidity 0.8.6; - -/** - * @title tropykus Legacy InterestRateModel Interface - * @author tropykus (modified by Arr00) - */ -abstract contract LegacyInterestRateModel { - /// @notice Indicator that this is an InterestRateModel contract (for inspection) - bool public constant isInterestRateModel = true; - - /** - * @notice Calculates the current supply interest rate per block - * @param cash The total amount of cash the market has - * @param borrows The total amount of borrows the market has outstanding - * @param reserves The total amount of reserves the market has - * @param reserveFactorMantissa The current reserve factor the market has - * @return The supply rate per block (as a percentage, and scaled by 1e18) - */ - function getSupplyRate( - uint256 cash, - uint256 borrows, - uint256 reserves, - uint256 reserveFactorMantissa - ) external view virtual returns (uint256); -} - - -// Root file: contracts/LegacyJumpRateModelV2.sol - -pragma solidity 0.8.6; - -// import "contracts/BaseJumpRateModelV2.sol"; -// import "contracts/LegacyInterestRateModel.sol"; - -/** - * @title tropykus JumpRateModel Contract V2 for legacy cTokens - * @author tropykus - * @notice Supports only legacy cTokens - */ -contract LegacyJumpRateModelV2 is BaseJumpRateModelV2 { - constructor( - uint256 baseRatePerYear, - uint256 multiplierPerYear, - uint256 jumpMultiplierPerYear, - uint256 kink_, - address owner_ - ) - BaseJumpRateModelV2( - baseRatePerYear, - multiplierPerYear, - jumpMultiplierPerYear, - kink_, - owner_ - ) - { - isTropykusInterestRateModel = false; - } -} diff --git a/flatten/Maximillion.sol b/flatten/Maximillion.sol deleted file mode 100644 index 315344f..0000000 --- a/flatten/Maximillion.sol +++ /dev/null @@ -1,4180 +0,0 @@ -// Dependency file: contracts/ComptrollerInterface.sol - -// SPDX-License-Identifier: UNLICENSED -// pragma solidity 0.8.6; - -abstract contract ComptrollerInterface { - /// @notice Indicator that this is a Comptroller contract (for inspection) - bool public constant isComptroller = true; - - /*** Assets You Are In ***/ - - function enterMarkets(address[] calldata cTokens) - external - virtual - returns (uint256[] memory); - - function exitMarket(address cToken) external virtual returns (uint256); - - /*** Policy Hooks ***/ - - function mintAllowed( - address cToken, - address minter, - uint256 mintAmount - ) external virtual returns (uint256); - - function mintVerify( - address cToken, - address minter, - uint256 mintAmount, - uint256 mintTokens - ) external virtual; - - function redeemAllowed( - address cToken, - address redeemer, - uint256 redeemTokens - ) external virtual returns (uint256); - - function redeemVerify( - address cToken, - address redeemer, - uint256 redeemAmount, - uint256 redeemTokens - ) external virtual; - - function borrowAllowed( - address cToken, - address borrower, - uint256 borrowAmount - ) external virtual returns (uint256); - - function borrowVerify( - address cToken, - address borrower, - uint256 borrowAmount - ) external virtual; - - function repayBorrowAllowed( - address cToken, - address payer, - address borrower, - uint256 repayAmount - ) external virtual returns (uint256); - - function repayBorrowVerify( - address cToken, - address payer, - address borrower, - uint256 repayAmount, - uint256 borrowerIndex - ) external virtual; - - function liquidateBorrowAllowed( - address cTokenBorrowed, - address cTokenCollateral, - address liquidator, - address borrower, - uint256 repayAmount - ) external virtual returns (uint256); - - function liquidateBorrowVerify( - address cTokenBorrowed, - address cTokenCollateral, - address liquidator, - address borrower, - uint256 repayAmount, - uint256 seizeTokens - ) external virtual; - - function seizeAllowed( - address cTokenCollateral, - address cTokenBorrowed, - address liquidator, - address borrower, - uint256 seizeTokens - ) external virtual returns (uint256); - - function seizeVerify( - address cTokenCollateral, - address cTokenBorrowed, - address liquidator, - address borrower, - uint256 seizeTokens - ) external virtual; - - function transferAllowed( - address cToken, - address src, - address dst, - uint256 transferTokens - ) external virtual returns (uint256); - - function transferVerify( - address cToken, - address src, - address dst, - uint256 transferTokens - ) external virtual; - - /*** Liquidity/Liquidation Calculations ***/ - - function liquidateCalculateSeizeTokens( - address cTokenBorrowed, - address cTokenCollateral, - uint256 repayAmount - ) external view virtual returns (uint256, uint256); -} - - -// Dependency file: contracts/CarefulMath.sol - -// pragma solidity 0.8.6; - -/** - * @title Careful Math - * @author tropykus - * @notice Derived from OpenZeppelin's SafeMath library - * https://github.com/OpenZeppelin/openzeppelin-solidity/blob/master/contracts/math/SafeMath.sol - */ -contract CarefulMath { - - /** - * @dev Possible error codes that we can return - */ - enum MathError { - NO_ERROR, - DIVISION_BY_ZERO, - INTEGER_OVERFLOW, - INTEGER_UNDERFLOW - } - - /** - * @dev Multiplies two numbers, returns an error on overflow. - */ - function mulUInt(uint a, uint b) internal pure returns (MathError, uint) { - if (a == 0) { - return (MathError.NO_ERROR, 0); - } - - uint c = a * b; - - if (c / a != b) { - return (MathError.INTEGER_OVERFLOW, 0); - } else { - return (MathError.NO_ERROR, c); - } - } - - /** - * @dev Integer division of two numbers, truncating the quotient. - */ - function divUInt(uint a, uint b) internal pure returns (MathError, uint) { - if (b == 0) { - return (MathError.DIVISION_BY_ZERO, 0); - } - - return (MathError.NO_ERROR, a / b); - } - - /** - * @dev Subtracts two numbers, returns an error on overflow (i.e. if subtrahend is greater than minuend). - */ - function subUInt(uint a, uint b) internal pure returns (MathError, uint) { - if (b <= a) { - return (MathError.NO_ERROR, a - b); - } else { - return (MathError.INTEGER_UNDERFLOW, 0); - } - } - - /** - * @dev Adds two numbers, returns an error on overflow. - */ - function addUInt(uint a, uint b) internal pure returns (MathError, uint) { - uint c = a + b; - - if (c >= a) { - return (MathError.NO_ERROR, c); - } else { - return (MathError.INTEGER_OVERFLOW, 0); - } - } - - /** - * @dev add a and b and then subtract c - */ - function addThenSubUInt(uint a, uint b, uint c) internal pure returns (MathError, uint) { - (MathError err0, uint sum) = addUInt(a, b); - - if (err0 != MathError.NO_ERROR) { - return (err0, 0); - } - - return subUInt(sum, c); - } -} - - -// Dependency file: contracts/ExponentialNoError.sol - -// pragma solidity 0.8.6; - -/** - * @title Exponential module for storing fixed-precision decimals - * @author tropykus - * @notice Exp is a struct which stores decimals with a fixed precision of 18 decimal places. - * Thus, if we wanted to store the 5.1, mantissa would store 5.1e18. That is: - * `Exp({mantissa: 5100000000000000000})`. - */ -contract ExponentialNoError { - uint constant expScale = 1e18; - uint constant doubleScale = 1e36; - uint constant halfExpScale = expScale/2; - uint constant mantissaOne = expScale; - - struct Exp { - uint mantissa; - } - - struct Double { - uint mantissa; - } - - /** - * @dev Truncates the given exp to a whole number value. - * For example, truncate(Exp{mantissa: 15 * expScale}) = 15 - */ - function truncate(Exp memory exp) pure internal returns (uint) { - // Note: We are not using careful math here as we're performing a division that cannot fail - return exp.mantissa / expScale; - } - - /** - * @dev Multiply an Exp by a scalar, then truncate to return an unsigned integer. - */ - function mul_ScalarTruncate(Exp memory a, uint scalar) pure internal returns (uint) { - Exp memory product = mul_(a, scalar); - return truncate(product); - } - - /** - * @dev Multiply an Exp by a scalar, truncate, then add an to an unsigned integer, returning an unsigned integer. - */ - function mul_ScalarTruncateAddUInt(Exp memory a, uint scalar, uint addend) pure internal returns (uint) { - Exp memory product = mul_(a, scalar); - return add_(truncate(product), addend); - } - - /** - * @dev Checks if first Exp is less than second Exp. - */ - function lessThanExp(Exp memory left, Exp memory right) pure internal returns (bool) { - return left.mantissa < right.mantissa; - } - - /** - * @dev Checks if left Exp <= right Exp. - */ - function lessThanOrEqualExp(Exp memory left, Exp memory right) pure internal returns (bool) { - return left.mantissa <= right.mantissa; - } - - /** - * @dev Checks if left Exp > right Exp. - */ - function greaterThanExp(Exp memory left, Exp memory right) pure internal returns (bool) { - return left.mantissa > right.mantissa; - } - - /** - * @dev returns true if Exp is exactly zero - */ - function isZeroExp(Exp memory value) pure internal returns (bool) { - return value.mantissa == 0; - } - - function safe224(uint n, string memory errorMessage) pure internal returns (uint224) { - require(n < 2**224, errorMessage); - return uint224(n); - } - - function safe32(uint n, string memory errorMessage) pure internal returns (uint32) { - require(n < 2**32, errorMessage); - return uint32(n); - } - - function add_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { - return Exp({mantissa: add_(a.mantissa, b.mantissa)}); - } - - function add_(Double memory a, Double memory b) pure internal returns (Double memory) { - return Double({mantissa: add_(a.mantissa, b.mantissa)}); - } - - function add_(uint a, uint b) pure internal returns (uint) { - return add_(a, b, "addition overflow"); - } - - function add_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { - uint c = a + b; - require(c >= a, errorMessage); - return c; - } - - function sub_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { - return Exp({mantissa: sub_(a.mantissa, b.mantissa)}); - } - - function sub_(Double memory a, Double memory b) pure internal returns (Double memory) { - return Double({mantissa: sub_(a.mantissa, b.mantissa)}); - } - - function sub_(uint a, uint b) pure internal returns (uint) { - return sub_(a, b, "subtraction underflow"); - } - - function sub_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { - require(b <= a, errorMessage); - return a - b; - } - - function mul_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { - return Exp({mantissa: mul_(a.mantissa, b.mantissa) / expScale}); - } - - function mul_(Exp memory a, uint b) pure internal returns (Exp memory) { - return Exp({mantissa: mul_(a.mantissa, b)}); - } - - function mul_(uint a, Exp memory b) pure internal returns (uint) { - return mul_(a, b.mantissa) / expScale; - } - - function mul_(Double memory a, Double memory b) pure internal returns (Double memory) { - return Double({mantissa: mul_(a.mantissa, b.mantissa) / doubleScale}); - } - - function mul_(Double memory a, uint b) pure internal returns (Double memory) { - return Double({mantissa: mul_(a.mantissa, b)}); - } - - function mul_(uint a, Double memory b) pure internal returns (uint) { - return mul_(a, b.mantissa) / doubleScale; - } - - function mul_(uint a, uint b) pure internal returns (uint) { - return mul_(a, b, "multiplication overflow"); - } - - function mul_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { - if (a == 0 || b == 0) { - return 0; - } - uint c = a * b; - require(c / a == b, errorMessage); - return c; - } - - function div_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { - return Exp({mantissa: div_(mul_(a.mantissa, expScale), b.mantissa)}); - } - - function div_(Exp memory a, uint b) pure internal returns (Exp memory) { - return Exp({mantissa: div_(a.mantissa, b)}); - } - - function div_(uint a, Exp memory b) pure internal returns (uint) { - return div_(mul_(a, expScale), b.mantissa); - } - - function div_(Double memory a, Double memory b) pure internal returns (Double memory) { - return Double({mantissa: div_(mul_(a.mantissa, doubleScale), b.mantissa)}); - } - - function div_(Double memory a, uint b) pure internal returns (Double memory) { - return Double({mantissa: div_(a.mantissa, b)}); - } - - function div_(uint a, Double memory b) pure internal returns (uint) { - return div_(mul_(a, doubleScale), b.mantissa); - } - - function div_(uint a, uint b) pure internal returns (uint) { - return div_(a, b, "divide by zero"); - } - - function div_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { - require(b > 0, errorMessage); - return a / b; - } - - function fraction(uint a, uint b) pure internal returns (Double memory) { - return Double({mantissa: div_(mul_(a, doubleScale), b)}); - } -} - - -// Dependency file: contracts/Exponential.sol - -// pragma solidity 0.8.6; - -// import "contracts/CarefulMath.sol"; -// import "contracts/ExponentialNoError.sol"; - -/** - * @title Exponential module for storing fixed-precision decimals - * @author tropykus - * @dev Legacy contract for compatibility reasons with existing contracts that still use MathError - * @notice Exp is a struct which stores decimals with a fixed precision of 18 decimal places. - * Thus, if we wanted to store the 5.1, mantissa would store 5.1e18. That is: - * `Exp({mantissa: 5100000000000000000})`. - */ -contract Exponential is CarefulMath, ExponentialNoError { - /** - * @dev Creates an exponential from numerator and denominator values. - * Note: Returns an error if (`num` * 10e18) > MAX_INT, - * or if `denom` is zero. - */ - function getExp(uint num, uint denom) internal pure returns (MathError, Exp memory) { - (MathError err0, uint scaledNumerator) = mulUInt(num, expScale); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - - (MathError err1, uint rational) = divUInt(scaledNumerator, denom); - if (err1 != MathError.NO_ERROR) { - return (err1, Exp({mantissa: 0})); - } - - return (MathError.NO_ERROR, Exp({mantissa: rational})); - } - - /** - * @dev Adds two exponentials, returning a new exponential. - */ - function addExp(Exp memory a, Exp memory b) internal pure returns (MathError, Exp memory) { - (MathError error, uint result) = addUInt(a.mantissa, b.mantissa); - - return (error, Exp({mantissa: result})); - } - - /** - * @dev Subtracts two exponentials, returning a new exponential. - */ - function subExp(Exp memory a, Exp memory b) internal pure returns (MathError, Exp memory) { - (MathError error, uint result) = subUInt(a.mantissa, b.mantissa); - - return (error, Exp({mantissa: result})); - } - - /** - * @dev Multiply an Exp by a scalar, returning a new Exp. - */ - function mulScalar(Exp memory a, uint scalar) internal pure returns (MathError, Exp memory) { - (MathError err0, uint scaledMantissa) = mulUInt(a.mantissa, scalar); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - - return (MathError.NO_ERROR, Exp({mantissa: scaledMantissa})); - } - - /** - * @dev Multiply an Exp by a scalar, then truncate to return an unsigned integer. - */ - function mulScalarTruncate(Exp memory a, uint scalar) internal pure returns (MathError, uint) { - (MathError err, Exp memory product) = mulScalar(a, scalar); - if (err != MathError.NO_ERROR) { - return (err, 0); - } - - return (MathError.NO_ERROR, truncate(product)); - } - - /** - * @dev Multiply an Exp by a scalar, truncate, then add an to an unsigned integer, returning an unsigned integer. - */ - function mulScalarTruncateAddUInt(Exp memory a, uint scalar, uint addend) internal pure returns (MathError, uint) { - (MathError err, Exp memory product) = mulScalar(a, scalar); - if (err != MathError.NO_ERROR) { - return (err, 0); - } - - return addUInt(truncate(product), addend); - } - - /** - * @dev Divide an Exp by a scalar, returning a new Exp. - */ - function divScalar(Exp memory a, uint scalar) internal pure returns (MathError, Exp memory) { - (MathError err0, uint descaledMantissa) = divUInt(a.mantissa, scalar); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - - return (MathError.NO_ERROR, Exp({mantissa: descaledMantissa})); - } - - /** - * @dev Divide a scalar by an Exp, returning a new Exp. - */ - function divScalarByExp(uint scalar, Exp memory divisor) internal pure returns (MathError, Exp memory) { - /* - We are doing this as: - getExp(mulUInt(expScale, scalar), divisor.mantissa) - - How it works: - Exp = a / b; - Scalar = s; - `s / (a / b)` = `b * s / a` and since for an Exp `a = mantissa, b = expScale` - */ - (MathError err0, uint numerator) = mulUInt(expScale, scalar); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - return getExp(numerator, divisor.mantissa); - } - - /** - * @dev Divide a scalar by an Exp, then truncate to return an unsigned integer. - */ - function divScalarByExpTruncate(uint scalar, Exp memory divisor) internal pure returns (MathError, uint) { - (MathError err, Exp memory fraction) = divScalarByExp(scalar, divisor); - if (err != MathError.NO_ERROR) { - return (err, 0); - } - - return (MathError.NO_ERROR, truncate(fraction)); - } - - /** - * @dev Multiplies two exponentials, returning a new exponential. - */ - function mulExp(Exp memory a, Exp memory b) internal pure returns (MathError, Exp memory) { - - (MathError err0, uint doubleScaledProduct) = mulUInt(a.mantissa, b.mantissa); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - - // We add half the scale before dividing so that we get rounding instead of truncation. - // See "Listing 6" and text above it at https://accu.org/index.php/journals/1717 - // Without this change, a result like 6.6...e-19 will be truncated to 0 instead of being rounded to 1e-18. - (MathError err1, uint doubleScaledProductWithHalfScale) = addUInt(halfExpScale, doubleScaledProduct); - if (err1 != MathError.NO_ERROR) { - return (err1, Exp({mantissa: 0})); - } - - (MathError err2, uint product) = divUInt(doubleScaledProductWithHalfScale, expScale); - // The only error `div` can return is MathError.DIVISION_BY_ZERO but we control `expScale` and it is not zero. - assert(err2 == MathError.NO_ERROR); - - return (MathError.NO_ERROR, Exp({mantissa: product})); - } - - /** - * @dev Multiplies two exponentials given their mantissas, returning a new exponential. - */ - function mulExp(uint a, uint b) internal pure returns (MathError, Exp memory) { - return mulExp(Exp({mantissa: a}), Exp({mantissa: b})); - } - - /** - * @dev Multiplies three exponentials, returning a new exponential. - */ - function mulExp3(Exp memory a, Exp memory b, Exp memory c) internal pure returns (MathError, Exp memory) { - (MathError err, Exp memory ab) = mulExp(a, b); - if (err != MathError.NO_ERROR) { - return (err, ab); - } - return mulExp(ab, c); - } - - /** - * @dev Divides two exponentials, returning a new exponential. - * (a/scale) / (b/scale) = (a/scale) * (scale/b) = a/b, - * which we can scale as an Exp by calling getExp(a.mantissa, b.mantissa) - */ - function divExp(Exp memory a, Exp memory b) internal pure returns (MathError, Exp memory) { - return getExp(a.mantissa, b.mantissa); - } -} - - -// Dependency file: contracts/SafeMath.sol - -// pragma solidity 0.8.6; - -// From https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/math/Math.sol -// Subject to the MIT license. - -/** - * @dev Wrappers over Solidity's arithmetic operations with added overflow - * checks. - * - * Arithmetic operations in Solidity wrap on overflow. This can easily result - * in bugs, because programmers usually assume that an overflow raises an - * error, which is the standard behavior in high level programming languages. - * `SafeMath` restores this intuition by reverting the transaction when an - * operation overflows. - * - * Using this library instead of the unchecked operations eliminates an entire - * class of bugs, so it's recommended to use it always. - */ -library SafeMath { - /** - * @dev Returns the addition of two unsigned integers, reverting on overflow. - * - * Counterpart to Solidity's `+` operator. - * - * Requirements: - * - Addition cannot overflow. - */ - function add(uint256 a, uint256 b) internal pure returns (uint256) { - uint256 c = a + b; - require(c >= a, "SafeMath: addition overflow"); - - return c; - } - - /** - * @dev Returns the addition of two unsigned integers, reverting with custom message on overflow. - * - * Counterpart to Solidity's `+` operator. - * - * Requirements: - * - Addition cannot overflow. - */ - function add(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - uint256 c = a + b; - require(c >= a, errorMessage); - - return c; - } - - /** - * @dev Returns the subtraction of two unsigned integers, reverting on underflow (when the result is negative). - * - * Counterpart to Solidity's `-` operator. - * - * Requirements: - * - Subtraction cannot underflow. - */ - function sub(uint256 a, uint256 b) internal pure returns (uint256) { - return sub(a, b, "SafeMath: subtraction underflow"); - } - - /** - * @dev Returns the subtraction of two unsigned integers, reverting with custom message on underflow (when the result is negative). - * - * Counterpart to Solidity's `-` operator. - * - * Requirements: - * - Subtraction cannot underflow. - */ - function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - require(b <= a, errorMessage); - uint256 c = a - b; - - return c; - } - - /** - * @dev Returns the multiplication of two unsigned integers, reverting on overflow. - * - * Counterpart to Solidity's `*` operator. - * - * Requirements: - * - Multiplication cannot overflow. - */ - function mul(uint256 a, uint256 b) internal pure returns (uint256) { - // Gas optimization: this is cheaper than requiring 'a' not being zero, but the - // benefit is lost if 'b' is also tested. - // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 - if (a == 0) { - return 0; - } - - uint256 c = a * b; - require(c / a == b, "SafeMath: multiplication overflow"); - - return c; - } - - /** - * @dev Returns the multiplication of two unsigned integers, reverting on overflow. - * - * Counterpart to Solidity's `*` operator. - * - * Requirements: - * - Multiplication cannot overflow. - */ - function mul(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - // Gas optimization: this is cheaper than requiring 'a' not being zero, but the - // benefit is lost if 'b' is also tested. - // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 - if (a == 0) { - return 0; - } - - uint256 c = a * b; - require(c / a == b, errorMessage); - - return c; - } - - /** - * @dev Returns the integer division of two unsigned integers. - * Reverts on division by zero. The result is rounded towards zero. - * - * Counterpart to Solidity's `/` operator. Note: this function uses a - * `revert` opcode (which leaves remaining gas untouched) while Solidity - * uses an invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function div(uint256 a, uint256 b) internal pure returns (uint256) { - return div(a, b, "SafeMath: division by zero"); - } - - /** - * @dev Returns the integer division of two unsigned integers. - * Reverts with custom message on division by zero. The result is rounded towards zero. - * - * Counterpart to Solidity's `/` operator. Note: this function uses a - * `revert` opcode (which leaves remaining gas untouched) while Solidity - * uses an invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - // Solidity only automatically asserts when dividing by 0 - require(b > 0, errorMessage); - uint256 c = a / b; - // assert(a == b * c + a % b); // There is no case in which this doesn't hold - - return c; - } - - /** - * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), - * Reverts when dividing by zero. - * - * Counterpart to Solidity's `%` operator. This function uses a `revert` - * opcode (which leaves remaining gas untouched) while Solidity uses an - * invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function mod(uint256 a, uint256 b) internal pure returns (uint256) { - return mod(a, b, "SafeMath: modulo by zero"); - } - - /** - * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), - * Reverts with custom message when dividing by zero. - * - * Counterpart to Solidity's `%` operator. This function uses a `revert` - * opcode (which leaves remaining gas untouched) while Solidity uses an - * invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - require(b != 0, errorMessage); - return a % b; - } -} - - -// Dependency file: contracts/InterestRateModel.sol - -// pragma solidity 0.8.6; - -// import "contracts/Exponential.sol"; -// import "contracts/SafeMath.sol"; - -/** - * @title tropykus InterestRateModel Interface - * @author tropykus - */ -abstract contract InterestRateModel is Exponential { - using SafeMath for uint256; - - /// @notice Indicator that this is an InterestRateModel contract (for inspection) - bool public constant isInterestRateModel = true; - bool public isTropykusInterestRateModel; - - /** - * @notice The approximate number of blocks per year that is assumed by the interest rate model - */ - uint256 public constant blocksPerYear = 1051200; - - /** - * @notice Calculates the utilization rate of the market: `borrows / (cash + borrows - reserves)` - * @param cash The amount of cash in the market - * @param borrows The amount of borrows in the market - * @param reserves The amount of reserves in the market (currently unused) - * @return The utilization rate as a mantissa between [0, 1e18] - */ - function utilizationRate( - uint256 cash, - uint256 borrows, - uint256 reserves - ) public pure virtual returns (uint256) { - // Utilization rate is 0 when there are no borrows - if (borrows == 0) { - return 0; - } - - return borrows.mul(1e18).div(cash.add(borrows).sub(reserves)); - } - - /** - * @notice Calculates the current borrow interest rate per block - * @param cash The total amount of cash the market has - * @param borrows The total amount of borrows the market has outstanding - * @param reserves The total amnount of reserves the market has - * @return The borrow rate per block (as a percentage, and scaled by 1e18) - */ - function getBorrowRate( - uint256 cash, - uint256 borrows, - uint256 reserves - ) external view virtual returns (uint256); - - /** - * @notice Calculates the current supply interest rate per block - * @param cash The total amount of cash the market has - * @param borrows The total amount of borrows the market has outstanding - * @param reserves The total amnount of reserves the market has - * @param reserveFactorMantissa The current reserve factor the market has - * @return The supply rate per block (as a percentage, and scaled by 1e18) - */ - function getSupplyRate( - uint256 cash, - uint256 borrows, - uint256 reserves, - uint256 reserveFactorMantissa - ) external view virtual returns (uint256); - - function getExchangeRate( - uint256 _totalCash, - uint256 _totalBorrows, - uint256 _totalReserves, - uint256 _totalSupply - ) public pure returns (MathError, uint256) { - /* - * exchangeRate = (totalCash + totalBorrows - totalReserves) / totalSupply - */ - Exp memory exchangeRate; - MathError mathErr; - uint256 cashPlusBorrowsMinusReserves; - (mathErr, cashPlusBorrowsMinusReserves) = addThenSubUInt( - _totalCash, - _totalBorrows, - _totalReserves - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - (mathErr, exchangeRate) = getExp( - cashPlusBorrowsMinusReserves, - _totalSupply - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - - return (MathError.NO_ERROR, exchangeRate.mantissa); - } - - function isAboveOptimal( - uint256 cash, - uint256 borrows, - uint256 reserves - ) public view virtual returns (bool) { - cash; - borrows; - reserves; - return false; - } -} - - -// Dependency file: contracts/EIP20NonStandardInterface.sol - -// pragma solidity 0.8.6; - -/** - * @title EIP20NonStandardInterface - * @dev Version of ERC20 with no return values for `transfer` and `transferFrom` - * See https://medium.com/coinmonks/missing-return-value-bug-at-least-130-tokens-affected-d67bf08521ca - */ -interface EIP20NonStandardInterface { - /** - * @notice Get the total number of tokens in circulation - * @return The supply of tokens - */ - function totalSupply() external view returns (uint256); - - /** - * @notice Gets the balance of the specified address - * @param owner The address from which the balance will be retrieved - * @return balance The balance - */ - function balanceOf(address owner) external view returns (uint256 balance); - - /// - /// !!!!!!!!!!!!!! - /// !!! NOTICE !!! `transfer` does not return a value, in violation of the ERC-20 specification - /// !!!!!!!!!!!!!! - /// - - /** - * @notice Transfer `amount` tokens from `msg.sender` to `dst` - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - */ - function transfer(address dst, uint256 amount) external; - - /// - /// !!!!!!!!!!!!!! - /// !!! NOTICE !!! `transferFrom` does not return a value, in violation of the ERC-20 specification - /// !!!!!!!!!!!!!! - /// - - /** - * @notice Transfer `amount` tokens from `src` to `dst` - * @param src The address of the source account - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - */ - function transferFrom( - address src, - address dst, - uint256 amount - ) external; - - /** - * @notice Approve `spender` to transfer up to `amount` from `src` - * @dev This will overwrite the approval amount for `spender` - * and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve) - * @param spender The address of the account which may transfer tokens - * @param amount The number of tokens that are approved - * @return success Whether or not the approval succeeded - */ - function approve(address spender, uint256 amount) - external - returns (bool success); - - /** - * @notice Get the current allowance from `owner` for `spender` - * @param owner The address of the account which owns the tokens to be spent - * @param spender The address of the account which may transfer tokens - * @return remaining The number of tokens allowed to be spent - */ - function allowance(address owner, address spender) - external - view - returns (uint256 remaining); - - event Transfer(address indexed from, address indexed to, uint256 amount); - event Approval( - address indexed owner, - address indexed spender, - uint256 amount - ); -} - - -// Dependency file: contracts/CTokenInterfaces.sol - -// pragma solidity 0.8.6; - -// import "contracts/ComptrollerInterface.sol"; -// import "contracts/InterestRateModel.sol"; -// import "contracts/EIP20NonStandardInterface.sol"; - -contract CTokenStorage { - /** - * @dev Guard variable for re-entrancy checks - */ - bool internal _notEntered; - - /** - * @notice EIP-20 token name for this token - */ - string public name; - - /** - * @notice EIP-20 token symbol for this token - */ - string public symbol; - - /** - * @notice EIP-20 token decimals for this token - */ - uint8 public decimals; - - /** - * @notice Maximum borrow rate that can ever be applied (.0005% / block) - */ - - uint256 internal constant borrowRateMaxMantissa = 0.0005e16; - - /** - * @notice Maximum fraction of interest that can be set aside for reserves - */ - uint256 internal constant reserveFactorMaxMantissa = 1e18; - - /** - * @notice Administrator for this contract - */ - address payable public admin; - - /** - * @notice Pending administrator for this contract - */ - address payable public pendingAdmin; - - /** - * @notice Contract which oversees inter-cToken operations - */ - ComptrollerInterface public comptroller; - - /** - * @notice Model which tells what the current interest rate should be - */ - InterestRateModel public interestRateModel; - - /** - * @notice Initial exchange rate used when minting the first CTokens (used when totalSupply = 0) - */ - uint256 public initialExchangeRateMantissa; - - /** - * @notice Fraction of interest currently set aside for reserves - */ - uint256 public reserveFactorMantissa; - - /** - * @notice Block number that interest was last accrued at - */ - uint256 public accrualBlockNumber; - - /** - * @notice Accumulator of the total earned interest rate since the opening of the market - */ - uint256 public borrowIndex; - - /** - * @notice Total amount of outstanding borrows of the underlying in this market - */ - uint256 public totalBorrows; - - /** - * @notice Total amount of reserves of the underlying held in this market - */ - uint256 public totalReserves; - - /** - * @notice Total number of tokens in circulation - */ - uint256 public totalSupply; - - uint256 public subsidyFund; - - struct SupplySnapshot { - uint256 tokens; - uint256 underlyingAmount; - uint256 suppliedAt; - uint256 promisedSupplyRate; - } - - /** - * @notice Official record of token balances for each account - */ - mapping(address => SupplySnapshot) internal accountTokens; - - /** - * @notice Approved token transfer amounts on behalf of others - */ - mapping(address => mapping(address => uint256)) internal transferAllowances; - - /** - * @notice Container for borrow balance information - * @member principal Total balance (with accrued interest), after applying the most recent balance-changing action - * @member interestIndex Global borrowIndex as of the most recent balance-changing action - */ - struct BorrowSnapshot { - uint256 principal; - uint256 interestIndex; - } - - /** - * @notice Mapping of account addresses to outstanding borrow balances - */ - mapping(address => BorrowSnapshot) internal accountBorrows; -} - -abstract contract CTokenInterface is CTokenStorage { - /** - * @notice Indicator that this is a CToken contract (for inspection) - */ - bool public constant isCToken = true; - - /*** Market Events ***/ - - /** - * @notice Event emitted when interest is accrued - */ - event AccrueInterest( - uint256 cashPrior, - uint256 interestAccumulated, - uint256 borrowIndex, - uint256 totalBorrows - ); - - /** - * @notice Event emitted when tokens are minted - */ - event Mint(address indexed minter, uint256 mintAmount, uint256 mintTokens); - - /** - * @notice Event emitted when tokens are redeemed - */ - event Redeem( - address indexed redeemer, - uint256 redeemAmount, - uint256 redeemTokens - ); - - /** - * @notice Event emitted when underlying is borrowed - */ - event Borrow( - address indexed borrower, - uint256 borrowAmount, - uint256 accountBorrows, - uint256 totalBorrows - ); - - /** - * @notice Event emitted when a borrow is repaid - */ - event RepayBorrow( - address indexed payer, - address indexed borrower, - uint256 repayAmount, - uint256 accountBorrows, - uint256 totalBorrows - ); - - /** - * @notice Event emitted when a borrow is liquidated - */ - event LiquidateBorrow( - address indexed liquidator, - address indexed borrower, - uint256 repayAmount, - address indexed cTokenCollateral, - uint256 seizeTokens - ); - - /*** Admin Events ***/ - - /** - * @notice Event emitted when pendingAdmin is changed - */ - event NewPendingAdmin(address oldPendingAdmin, address newPendingAdmin); - - /** - * @notice Event emitted when pendingAdmin is accepted, which means admin is updated - */ - event NewAdmin(address oldAdmin, address newAdmin); - - /** - * @notice Event emitted when comptroller is changed - */ - event NewComptroller( - ComptrollerInterface oldComptroller, - ComptrollerInterface newComptroller - ); - - /** - * @notice Event emitted when interestRateModel is changed - */ - event NewMarketInterestRateModel( - InterestRateModel oldInterestRateModel, - InterestRateModel newInterestRateModel - ); - - /** - * @notice Event emitted when the reserve factor is changed - */ - event NewReserveFactor( - uint256 oldReserveFactorMantissa, - uint256 newReserveFactorMantissa - ); - - /** - * @notice Event emitted when the reserves are added - */ - event ReservesAdded( - address benefactor, - uint256 addAmount, - uint256 newTotalReserves - ); - - event SubsidyAdded( - address benefactor, - uint256 addAmount, - uint256 newSubsidyFund - ); - - /** - * @notice Event emitted when the reserves are reduced - */ - event ReservesReduced( - address admin, - uint256 reduceAmount, - uint256 newTotalReserves - ); - - /** - * @notice EIP20 Transfer event - */ - event Transfer(address indexed from, address indexed to, uint256 amount); - - /** - * @notice EIP20 Approval event - */ - event Approval( - address indexed owner, - address indexed spender, - uint256 amount - ); - - /** - * @notice Failure event - */ - event CTokenStorageFailure(uint256 error, uint256 info, uint256 detail); - - /*** User Interface ***/ - - function transfer(address dst, uint256 amount) - external - virtual - returns (bool); - - function transferFrom( - address src, - address dst, - uint256 amount - ) external virtual returns (bool); - - function approve(address spender, uint256 amount) - external - virtual - returns (bool); - - function allowance(address owner, address spender) - external - view - virtual - returns (uint256); - - function balanceOf(address owner) external view virtual returns (uint256); - - function balanceOfUnderlying(address owner) - external - virtual - returns (uint256); - - function getAccountSnapshot(address account) - external - view - virtual - returns ( - uint256, - uint256, - uint256, - uint256 - ); - - function borrowRatePerBlock() external view virtual returns (uint256); - - function supplyRatePerBlock() external view virtual returns (uint256); - - function totalBorrowsCurrent() external virtual returns (uint256); - - function borrowBalanceCurrent(address account) - external - virtual - returns (uint256); - - function borrowBalanceStored(address account) - public - view - virtual - returns (uint256); - - function exchangeRateCurrent() public virtual returns (uint256); - - function exchangeRateStored() public view virtual returns (uint256); - - function getCash() external view virtual returns (uint256); - - function accrueInterest() public virtual returns (uint256); - - function seize( - address liquidator, - address borrower, - uint256 seizeTokens - ) external virtual returns (uint256); - - /*** Admin Functions ***/ - - function _setPendingAdmin(address payable newPendingAdmin) - external - virtual - returns (uint256); - - function _acceptAdmin() external virtual returns (uint256); - - function _setComptroller(ComptrollerInterface newComptroller) - public - virtual - returns (uint256); - - function _setReserveFactor(uint256 newReserveFactorMantissa) - external - virtual - returns (uint256); - - function _reduceReserves(uint256 reduceAmount) - external - virtual - returns (uint256); - - function _setInterestRateModel(InterestRateModel newInterestRateModel) - public - virtual - returns (uint256); -} - -contract CErc20Storage { - /** - * @notice Underlying asset for this CToken - */ - address public underlying; -} - -abstract contract CErc20Interface is CErc20Storage { - /*** User Interface ***/ - - function mint(uint256 mintAmount) external virtual returns (uint256); - - function redeem(uint256 redeemAmount) - external - virtual - returns (uint256); - - function borrow(uint256 borrowAmount) external virtual returns (uint256); - - function repayBorrow(uint256 repayAmount) - external - virtual - returns (uint256); - - function repayBorrowBehalf(address borrower, uint256 repayAmount) - external - virtual - returns (uint256); - - function liquidateBorrow( - address borrower, - uint256 repayAmount, - CTokenInterface cTokenCollateral - ) external virtual returns (uint256); - - function sweepToken(EIP20NonStandardInterface token) external virtual; - - /*** Admin Functions ***/ - - function _addReserves(uint256 addAmount) external virtual returns (uint256); -} - -contract CDelegationStorage { - /** - * @notice Implementation address for this contract - */ - address public implementation; -} - -abstract contract CDelegatorInterface is CDelegationStorage { - /** - * @notice Emitted when implementation is changed - */ - event NewImplementation( - address oldImplementation, - address newImplementation - ); - - /** - * @notice Called by the admin to update the implementation of the delegator - * @param implementation_ The address of the new implementation for delegation - * @param allowResign Flag to indicate whether to call _resignImplementation on the old implementation - * @param becomeImplementationData The encoded bytes data to be passed to _becomeImplementation - */ - function _setImplementation( - address implementation_, - bool allowResign, - bytes memory becomeImplementationData - ) public virtual; -} - -abstract contract CDelegateInterface is CDelegationStorage { - /** - * @notice Called by the delegator on a delegate to initialize it for duty - * @dev Should revert if any issues arise which make it unfit for delegation - * @param data The encoded bytes data for any initialization - */ - function _becomeImplementation(bytes memory data) public virtual; - - /** - * @notice Called by the delegator on a delegate to forfeit its responsibility - */ - function _resignImplementation() public virtual; -} - - -// Dependency file: contracts/ErrorReporter.sol - -// pragma solidity 0.8.6; - -contract ComptrollerErrorReporter { - enum Error { - NO_ERROR, - UNAUTHORIZED, - COMPTROLLER_MISMATCH, - INSUFFICIENT_SHORTFALL, - INSUFFICIENT_LIQUIDITY, - INVALID_CLOSE_FACTOR, - INVALID_COLLATERAL_FACTOR, - INVALID_LIQUIDATION_INCENTIVE, - MARKET_NOT_ENTERED, // no longer possible - MARKET_NOT_LISTED, - MARKET_ALREADY_LISTED, - MATH_ERROR, - NONZERO_BORROW_BALANCE, - PRICE_ERROR, - REJECTION, - SNAPSHOT_ERROR, - TOO_MANY_ASSETS, - TOO_MUCH_REPAY - } - - enum FailureInfo { - ACCEPT_ADMIN_PENDING_ADMIN_CHECK, - ACCEPT_PENDING_IMPLEMENTATION_ADDRESS_CHECK, - EXIT_MARKET_BALANCE_OWED, - EXIT_MARKET_REJECTION, - SET_CLOSE_FACTOR_OWNER_CHECK, - SET_CLOSE_FACTOR_VALIDATION, - SET_COLLATERAL_FACTOR_OWNER_CHECK, - SET_COLLATERAL_FACTOR_NO_EXISTS, - SET_COLLATERAL_FACTOR_VALIDATION, - SET_COLLATERAL_FACTOR_WITHOUT_PRICE, - SET_IMPLEMENTATION_OWNER_CHECK, - SET_LIQUIDATION_INCENTIVE_OWNER_CHECK, - SET_LIQUIDATION_INCENTIVE_VALIDATION, - SET_MAX_ASSETS_OWNER_CHECK, - SET_PENDING_ADMIN_OWNER_CHECK, - SET_PENDING_IMPLEMENTATION_OWNER_CHECK, - SET_PRICE_ORACLE_OWNER_CHECK, - SUPPORT_MARKET_EXISTS, - SUPPORT_MARKET_OWNER_CHECK, - SET_PAUSE_GUARDIAN_OWNER_CHECK - } - - /** - * @dev `error` corresponds to enum Error; `info` corresponds to enum FailureInfo, and `detail` is an arbitrary - * contract-specific code that enables us to report opaque error codes from upgradeable contracts. - **/ - event Failure(uint256 error, uint256 info, uint256 detail); - - /** - * @dev use this when reporting a known error from the money market or a non-upgradeable collaborator - */ - function fail(Error err, FailureInfo info) internal returns (uint256) { - emit Failure(uint256(err), uint256(info), 0); - - return uint256(err); - } - - /** - * @dev use this when reporting an opaque error from an upgradeable collaborator contract - */ - function failOpaque( - Error err, - FailureInfo info, - uint256 opaqueError - ) internal returns (uint256) { - emit Failure(uint256(err), uint256(info), opaqueError); - - return uint256(err); - } -} - -contract TokenErrorReporter { - enum Error { - NO_ERROR, - UNAUTHORIZED, - BAD_INPUT, - COMPTROLLER_REJECTION, - COMPTROLLER_CALCULATION_ERROR, - INTEREST_RATE_MODEL_ERROR, - INVALID_ACCOUNT_PAIR, - INVALID_CLOSE_AMOUNT_REQUESTED, - INVALID_COLLATERAL_FACTOR, - MATH_ERROR, - MARKET_NOT_FRESH, - MARKET_NOT_LISTED, - TOKEN_INSUFFICIENT_ALLOWANCE, - TOKEN_INSUFFICIENT_BALANCE, - TOKEN_INSUFFICIENT_CASH, - TOKEN_TRANSFER_IN_FAILED, - TOKEN_TRANSFER_OUT_FAILED - } - - /* - * Note: FailureInfo (but not Error) is kept in alphabetical order - * This is because FailureInfo grows significantly faster, and - * the order of Error has some meaning, while the order of FailureInfo - * is entirely arbitrary. - */ - enum FailureInfo { - ACCEPT_ADMIN_PENDING_ADMIN_CHECK, - ACCRUE_INTEREST_ACCUMULATED_INTEREST_CALCULATION_FAILED, - ACCRUE_INTEREST_BORROW_RATE_CALCULATION_FAILED, - ACCRUE_INTEREST_NEW_BORROW_INDEX_CALCULATION_FAILED, - ACCRUE_INTEREST_NEW_TOTAL_BORROWS_CALCULATION_FAILED, - ACCRUE_INTEREST_NEW_TOTAL_RESERVES_CALCULATION_FAILED, - ACCRUE_INTEREST_SIMPLE_INTEREST_FACTOR_CALCULATION_FAILED, - BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED, - BORROW_ACCRUE_INTEREST_FAILED, - BORROW_CASH_NOT_AVAILABLE, - BORROW_FRESHNESS_CHECK, - BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED, - BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED, - BORROW_MARKET_NOT_LISTED, - BORROW_COMPTROLLER_REJECTION, - LIQUIDATE_ACCRUE_BORROW_INTEREST_FAILED, - LIQUIDATE_ACCRUE_COLLATERAL_INTEREST_FAILED, - LIQUIDATE_COLLATERAL_FRESHNESS_CHECK, - LIQUIDATE_COMPTROLLER_REJECTION, - LIQUIDATE_COMPTROLLER_CALCULATE_AMOUNT_SEIZE_FAILED, - LIQUIDATE_CLOSE_AMOUNT_IS_UINT_MAX, - LIQUIDATE_CLOSE_AMOUNT_IS_ZERO, - LIQUIDATE_FRESHNESS_CHECK, - LIQUIDATE_LIQUIDATOR_IS_BORROWER, - LIQUIDATE_REPAY_BORROW_FRESH_FAILED, - LIQUIDATE_SEIZE_BALANCE_INCREMENT_FAILED, - LIQUIDATE_SEIZE_BALANCE_DECREMENT_FAILED, - LIQUIDATE_SEIZE_COMPTROLLER_REJECTION, - LIQUIDATE_SEIZE_LIQUIDATOR_IS_BORROWER, - LIQUIDATE_SEIZE_TOO_MUCH, - MINT_ACCRUE_INTEREST_FAILED, - MINT_COMPTROLLER_REJECTION, - MINT_EXCHANGE_CALCULATION_FAILED, - MINT_EXCHANGE_RATE_READ_FAILED, - MINT_FRESHNESS_CHECK, - MINT_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED, - MINT_NEW_TOTAL_SUPPLY_CALCULATION_FAILED, - MINT_TRANSFER_IN_FAILED, - MINT_TRANSFER_IN_NOT_POSSIBLE, - REDEEM_ACCRUE_INTEREST_FAILED, - REDEEM_COMPTROLLER_REJECTION, - REDEEM_EXCHANGE_TOKENS_CALCULATION_FAILED, - REDEEM_EXCHANGE_AMOUNT_CALCULATION_FAILED, - REDEEM_EXCHANGE_RATE_READ_FAILED, - REDEEM_FRESHNESS_CHECK, - REDEEM_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED, - REDEEM_NEW_TOTAL_SUPPLY_CALCULATION_FAILED, - REDEEM_TRANSFER_OUT_NOT_POSSIBLE, - REDUCE_RESERVES_ACCRUE_INTEREST_FAILED, - REDUCE_RESERVES_ADMIN_CHECK, - REDUCE_RESERVES_CASH_NOT_AVAILABLE, - REDUCE_RESERVES_FRESH_CHECK, - REDUCE_RESERVES_VALIDATION, - REPAY_BEHALF_ACCRUE_INTEREST_FAILED, - REPAY_BORROW_ACCRUE_INTEREST_FAILED, - REPAY_BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED, - REPAY_BORROW_COMPTROLLER_REJECTION, - REPAY_BORROW_FRESHNESS_CHECK, - REPAY_BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED, - REPAY_BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED, - REPAY_BORROW_TRANSFER_IN_NOT_POSSIBLE, - SET_COLLATERAL_FACTOR_OWNER_CHECK, - SET_COLLATERAL_FACTOR_VALIDATION, - SET_COMPTROLLER_OWNER_CHECK, - SET_INTEREST_RATE_MODEL_ACCRUE_INTEREST_FAILED, - SET_INTEREST_RATE_MODEL_FRESH_CHECK, - SET_INTEREST_RATE_MODEL_OWNER_CHECK, - SET_MAX_ASSETS_OWNER_CHECK, - SET_ORACLE_MARKET_NOT_LISTED, - SET_PENDING_ADMIN_OWNER_CHECK, - SET_RESERVE_FACTOR_ACCRUE_INTEREST_FAILED, - SET_RESERVE_FACTOR_ADMIN_CHECK, - SET_RESERVE_FACTOR_FRESH_CHECK, - SET_RESERVE_FACTOR_BOUNDS_CHECK, - TRANSFER_COMPTROLLER_REJECTION, - TRANSFER_NOT_ALLOWED, - TRANSFER_NOT_ENOUGH, - TRANSFER_TOO_MUCH, - ADD_RESERVES_ACCRUE_INTEREST_FAILED, - ADD_RESERVES_FRESH_CHECK, - ADD_RESERVES_TRANSFER_IN_NOT_POSSIBLE, - ADD_SUBSIDY_FUND_FAILED, - ADD_SUBSIDY_FUND_FRESH_CHECK - } - - /** - * @dev `error` corresponds to enum Error; `info` corresponds to enum FailureInfo, and `detail` is an arbitrary - * contract-specific code that enables us to report opaque error codes from upgradeable contracts. - **/ - event TokenFailure(uint256 error, uint256 info, uint256 detail); - - /** - * @dev use this when reporting a known error from the money market or a non-upgradeable collaborator - */ - function fail(Error err, FailureInfo info) internal returns (uint256) { - emit TokenFailure(uint256(err), uint256(info), 0); - - return uint256(err); - } - - /** - * @dev use this when reporting an opaque error from an upgradeable collaborator contract - */ - function failOpaque( - Error err, - FailureInfo info, - uint256 opaqueError - ) internal returns (uint256) { - emit TokenFailure(uint256(err), uint256(info), opaqueError); - - return uint256(err); - } -} - - -// Dependency file: contracts/EIP20Interface.sol - -// pragma solidity 0.8.6; - -/** - * @title ERC 20 Token Standard Interface - * https://eips.ethereum.org/EIPS/eip-20 - */ -interface EIP20Interface { - function name() external view returns (string memory); - - function symbol() external view returns (string memory); - - function decimals() external view returns (uint8); - - /** - * @notice Get the total number of tokens in circulation - * @return The supply of tokens - */ - function totalSupply() external view returns (uint256); - - /** - * @notice Gets the balance of the specified address - * @param owner The address from which the balance will be retrieved - * @return balance The balance - */ - function balanceOf(address owner) external view returns (uint256 balance); - - /** - * @notice Transfer `amount` tokens from `msg.sender` to `dst` - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - * @return success Whether or not the transfer succeeded - */ - function transfer(address dst, uint256 amount) - external - returns (bool success); - - /** - * @notice Transfer `amount` tokens from `src` to `dst` - * @param src The address of the source account - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - * @return success Whether or not the transfer succeeded - */ - function transferFrom( - address src, - address dst, - uint256 amount - ) external returns (bool success); - - /** - * @notice Approve `spender` to transfer up to `amount` from `src` - * @dev This will overwrite the approval amount for `spender` - * and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve) - * @param spender The address of the account which may transfer tokens - * @param amount The number of tokens that are approved (-1 means infinite) - * @return success Whether or not the approval succeeded - */ - function approve(address spender, uint256 amount) - external - returns (bool success); - - /** - * @notice Get the current allowance from `owner` for `spender` - * @param owner The address of the account which owns the tokens to be spent - * @param spender The address of the account which may transfer tokens - * @return remaining The number of tokens allowed to be spent (-1 means infinite) - */ - function allowance(address owner, address spender) - external - view - returns (uint256 remaining); - - event Transfer(address indexed from, address indexed to, uint256 amount); - event Approval( - address indexed owner, - address indexed spender, - uint256 amount - ); -} - - -// Dependency file: contracts/CToken.sol - -// pragma solidity 0.8.6; - -// import "contracts/ComptrollerInterface.sol"; -// import "contracts/CTokenInterfaces.sol"; -// import "contracts/ErrorReporter.sol"; -// import "contracts/Exponential.sol"; -// import "contracts/EIP20Interface.sol"; -// import "contracts/InterestRateModel.sol"; - -/** - * @title tropykus CToken Contract - * @notice Abstract base for CTokens - * @author tropykus - */ -abstract contract CToken is CTokenInterface, Exponential, TokenErrorReporter { - /** - * @notice Initialize the money market - * @param comptroller_ The address of the Comptroller - * @param interestRateModel_ The address of the interest rate model - * @param initialExchangeRateMantissa_ The initial exchange rate, scaled by 1e18 - * @param name_ EIP-20 name of this token - * @param symbol_ EIP-20 symbol of this token - * @param decimals_ EIP-20 decimal precision of this token - */ - function initialize( - ComptrollerInterface comptroller_, - InterestRateModel interestRateModel_, - uint256 initialExchangeRateMantissa_, - string memory name_, - string memory symbol_, - uint8 decimals_ - ) public { - require(msg.sender == admin, "CT01"); - require( - accrualBlockNumber == 0 && borrowIndex == 0, - "CT02" - ); - - initialExchangeRateMantissa = initialExchangeRateMantissa_; - require(initialExchangeRateMantissa > 0, "CT03"); - - uint256 err = _setComptroller(comptroller_); - require(err == uint256(Error.NO_ERROR), "CT04"); - - accrualBlockNumber = getBlockNumber(); - borrowIndex = mantissaOne; - - err = _setInterestRateModelFresh(interestRateModel_); - require(err == uint256(Error.NO_ERROR), "CT05"); - - name = name_; - symbol = symbol_; - decimals = decimals_; - - _notEntered = true; - } - - /** - * @notice Transfer `tokens` tokens from `src` to `dst` by `spender` - * @dev Called by both `transfer` and `transferFrom` internally - * @param spender The address of the account performing the transfer - * @param src The address of the source account - * @param dst The address of the destination account - * @param tokens The number of tokens to transfer - * @return Whether or not the transfer succeeded - */ - function transferTokens( - address spender, - address src, - address dst, - uint256 tokens - ) internal returns (uint256) { - uint256 allowed = comptroller.transferAllowed( - address(this), - src, - dst, - tokens - ); - if (allowed != 0) { - return - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.TRANSFER_COMPTROLLER_REJECTION, - allowed - ); - } - - if (src == dst) { - return fail(Error.BAD_INPUT, FailureInfo.TRANSFER_NOT_ALLOWED); - } - - uint256 startingAllowance = 0; - if (spender == src) { - startingAllowance = type(uint256).max; - } else { - startingAllowance = transferAllowances[src][spender]; - } - - MathError mathErr; - uint256 allowanceNew; - uint256 srcTokensNew; - uint256 dstTokensNew; - - (mathErr, allowanceNew) = subUInt(startingAllowance, tokens); - if (mathErr != MathError.NO_ERROR) { - return fail(Error.MATH_ERROR, FailureInfo.TRANSFER_NOT_ALLOWED); - } - - (mathErr, srcTokensNew) = subUInt(accountTokens[src].tokens, tokens); - if (mathErr != MathError.NO_ERROR) { - return fail(Error.MATH_ERROR, FailureInfo.TRANSFER_NOT_ENOUGH); - } - - (mathErr, dstTokensNew) = addUInt(accountTokens[dst].tokens, tokens); - if (mathErr != MathError.NO_ERROR) { - return fail(Error.MATH_ERROR, FailureInfo.TRANSFER_TOO_MUCH); - } - - accountTokens[src].tokens = srcTokensNew; - accountTokens[dst].tokens = dstTokensNew; - - if (startingAllowance != type(uint256).max) { - transferAllowances[src][spender] = allowanceNew; - } - - emit Transfer(src, dst, tokens); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Transfer `amount` tokens from `msg.sender` to `dst` - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - * @return Whether or not the transfer succeeded - */ - function transfer(address dst, uint256 amount) - external - override - nonReentrant - returns (bool) - { - return - transferTokens(msg.sender, msg.sender, dst, amount) == - uint256(Error.NO_ERROR); - } - - /** - * @notice Transfer `amount` tokens from `src` to `dst` - * @param src The address of the source account - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - * @return Whether or not the transfer succeeded - */ - function transferFrom( - address src, - address dst, - uint256 amount - ) external override nonReentrant returns (bool) { - return - transferTokens(msg.sender, src, dst, amount) == - uint256(Error.NO_ERROR); - } - - /** - * @notice Approve `spender` to transfer up to `amount` from `src` - * @dev This will overwrite the approval amount for `spender` - * and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve) - * @param spender The address of the account which may transfer tokens - * @param amount The number of tokens that are approved (-1 means infinite) - * @return Whether or not the approval succeeded - */ - function approve(address spender, uint256 amount) - external - override - returns (bool) - { - address src = msg.sender; - transferAllowances[src][spender] = amount; - emit Approval(src, spender, amount); - return true; - } - - /** - * @notice Get the current allowance from `owner` for `spender` - * @param owner The address of the account which owns the tokens to be spent - * @param spender The address of the account which may transfer tokens - * @return The number of tokens allowed to be spent (-1 means infinite) - */ - function allowance(address owner, address spender) - external - view - override - returns (uint256) - { - return transferAllowances[owner][spender]; - } - - /** - * @notice Get the token balance of the `owner` - * @param owner The address of the account to query - * @return The number of tokens owned by `owner` - */ - function balanceOf(address owner) external view override returns (uint256) { - return accountTokens[owner].tokens; - } - - /** - * @notice Get the underlying balance of the `owner` - * @dev This also accrues interest in a transaction - * @param owner The address of the account to query - * @return The amount of underlying owned by `owner` - */ - function balanceOfUnderlying(address owner) - external - override - returns (uint256) - { - Exp memory exchangeRate = Exp({mantissa: exchangeRateCurrent()}); - (MathError mErr, uint256 balance) = mulScalarTruncate( - exchangeRate, - accountTokens[owner].tokens - ); - require(mErr == MathError.NO_ERROR, "CT06"); - return balance; - } - - /** - * @notice Get a snapshot of the account's balances, and the cached exchange rate - * @dev This is used by comptroller to more efficiently perform liquidity checks. - * @param account Address of the account to snapshot - * @return (possible error, token balance, borrow balance, exchange rate mantissa) - */ - function getAccountSnapshot(address account) - external - view - override - returns ( - uint256, - uint256, - uint256, - uint256 - ) - { - uint256 cTokenBalance = accountTokens[account].tokens; - uint256 borrowBalance; - uint256 exchangeRateMantissa; - - MathError mErr; - - (mErr, borrowBalance) = borrowBalanceStoredInternal(account); - if (mErr != MathError.NO_ERROR) { - return (uint256(Error.MATH_ERROR), 0, 0, 0); - } - - if (interestRateModel.isTropykusInterestRateModel()) { - (mErr, exchangeRateMantissa) = tropykusExchangeRateStoredInternal( - account - ); - } else { - (mErr, exchangeRateMantissa) = exchangeRateStoredInternal(); - } - if (mErr != MathError.NO_ERROR) { - return (uint256(Error.MATH_ERROR), 0, 0, 0); - } - - return ( - uint256(Error.NO_ERROR), - cTokenBalance, - borrowBalance, - exchangeRateMantissa - ); - } - - /** - * @dev Function to simply retrieve block number - * This exists mainly for inheriting test contracts to stub this result. - */ - function getBlockNumber() internal view virtual returns (uint256) { - return block.number; - } - - /** - * @notice Returns the current per-block borrow interest rate for this cToken - * @return The borrow interest rate per block, scaled by 1e18 - */ - function borrowRatePerBlock() external view override returns (uint256) { - return - interestRateModel.getBorrowRate( - getCashPrior(), - totalBorrows, - totalReserves - ); - } - - /** - * @notice Returns the current per-block supply interest rate for this cToken - * @return The supply interest rate per block, scaled by 1e18 - */ - function supplyRatePerBlock() external view override returns (uint256) { - return - interestRateModel.getSupplyRate( - getCashPrior(), - totalBorrows, - totalReserves, - reserveFactorMantissa - ); - } - - /** - * @notice Returns the current total borrows plus accrued interest - * @return The total borrows with interest - */ - function totalBorrowsCurrent() - external - override - nonReentrant - returns (uint256) - { - require(accrueInterest() == uint256(Error.NO_ERROR), "CT07"); - return totalBorrows; - } - - /** - * @notice Accrue interest to updated borrowIndex and then calculate account's borrow balance using the updated borrowIndex - * @param account The address whose balance should be calculated after updating borrowIndex - * @return The calculated balance - */ - function borrowBalanceCurrent(address account) - external - override - nonReentrant - returns (uint256) - { - require(accrueInterest() == uint256(Error.NO_ERROR), "CT07"); - return borrowBalanceStored(account); - } - - /** - * @notice Return the borrow balance of account based on stored data - * @param account The address whose balance should be calculated - * @return The calculated balance - */ - function borrowBalanceStored(address account) - public - view - override - returns (uint256) - { - (MathError err, uint256 result) = borrowBalanceStoredInternal(account); - require(err == MathError.NO_ERROR, "CT08"); - return result; - } - - /** - * @notice Return the borrow balance of account based on stored data - * @param account The address whose balance should be calculated - * @return (error code, the calculated balance or 0 if error code is non-zero) - */ - function borrowBalanceStoredInternal(address account) - internal - view - returns (MathError, uint256) - { - MathError mathErr; - uint256 principalTimesIndex; - uint256 result; - - BorrowSnapshot storage borrowSnapshot = accountBorrows[account]; - - if (borrowSnapshot.principal == 0) { - return (MathError.NO_ERROR, 0); - } - - (mathErr, principalTimesIndex) = mulUInt( - borrowSnapshot.principal, - borrowIndex - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - - (mathErr, result) = divUInt( - principalTimesIndex, - borrowSnapshot.interestIndex - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - - return (MathError.NO_ERROR, result); - } - - function getBorrowerPrincipalStored(address account) - public - view - returns (uint256 borrowed) - { - borrowed = accountBorrows[account].principal; - } - - function getSupplierSnapshotStored(address account) - public - view - returns ( - uint256 tokens, - uint256 underlyingAmount, - uint256 suppliedAt, - uint256 promisedSupplyRate - ) - { - tokens = accountTokens[account].tokens; - underlyingAmount = accountTokens[account].underlyingAmount; - suppliedAt = accountTokens[account].suppliedAt; - promisedSupplyRate = accountTokens[account].promisedSupplyRate; - } - - /** - * @notice Accrue interest then return the up-to-date exchange rate - * @return Calculated exchange rate scaled by 1e18 - */ - function exchangeRateCurrent() - public - override - nonReentrant - returns (uint256) - { - require(accrueInterest() == uint256(Error.NO_ERROR), "CT07"); - return exchangeRateStored(); - } - - /** - * @notice Calculates the exchange rate from the underlying to the CToken - * @dev This function does not accrue interest before calculating the exchange rate - * @return Calculated exchange rate scaled by 1e18 - */ - function exchangeRateStored() public view override returns (uint256) { - (MathError err, uint256 result) = exchangeRateStoredInternal(); - require(err == MathError.NO_ERROR, "CT09"); - return result; - } - - /** - * @notice Calculates the exchange rate from the underlying to the CToken - * @dev This function does not accrue interest before calculating the exchange rate - * @return (error code, calculated exchange rate scaled by 1e18) - */ - function exchangeRateStoredInternal() - internal - view - virtual - returns (MathError, uint256) - { - uint256 _totalSupply = totalSupply; - if (_totalSupply == 0) { - return (MathError.NO_ERROR, initialExchangeRateMantissa); - } else { - uint256 totalCash = getCashPrior(); - return - interestRateModel.getExchangeRate( - totalCash, - totalBorrows, - totalReserves, - totalSupply - ); - } - } - - function tropykusExchangeRateStoredInternal(address redeemer) - internal - view - returns (MathError, uint256) - { - if (totalSupply == 0) { - return (MathError.NO_ERROR, initialExchangeRateMantissa); - } else { - SupplySnapshot storage supplySnapshot = accountTokens[redeemer]; - uint256 promisedSupplyRate = supplySnapshot.promisedSupplyRate; - Exp memory expectedSupplyRatePerBlock = Exp({ - mantissa: promisedSupplyRate - }); - (, uint256 delta) = subUInt( - accrualBlockNumber, - supplySnapshot.suppliedAt - ); - (, Exp memory expectedSupplyRatePerBlockWithDelta) = mulScalar( - expectedSupplyRatePerBlock, - delta - ); - (, Exp memory interestFactor) = addExp( - Exp({mantissa: 1e18}), - expectedSupplyRatePerBlockWithDelta - ); - uint256 currentUnderlying = supplySnapshot.underlyingAmount; - Exp memory redeemerUnderlying = Exp({mantissa: currentUnderlying}); - (, Exp memory realAmount) = mulExp( - interestFactor, - redeemerUnderlying - ); - (, Exp memory exchangeRate) = getExp( - realAmount.mantissa, - supplySnapshot.tokens - ); - return (MathError.NO_ERROR, exchangeRate.mantissa); - } - } - - /** - * @notice Get cash balance of this cToken in the underlying asset - * @return The quantity of underlying asset owned by this contract - */ - function getCash() external view override returns (uint256) { - return getCashPrior(); - } - - /** - * @notice Applies accrued interest to total borrows and reserves - * @dev This calculates interest accrued from the last checkpointed block - * up to the current block and writes new checkpoint to storage. - */ - function accrueInterest() public override returns (uint256) { - uint256 currentBlockNumber = getBlockNumber(); - uint256 accrualBlockNumberPrior = accrualBlockNumber; - - if (accrualBlockNumberPrior == currentBlockNumber) { - return uint256(Error.NO_ERROR); - } - - uint256 cashPrior = getCashPrior(); - uint256 borrowsPrior = totalBorrows; - uint256 reservesPrior = totalReserves; - uint256 borrowIndexPrior = borrowIndex; - - uint256 borrowRateMantissa = interestRateModel.getBorrowRate( - cashPrior, - borrowsPrior, - reservesPrior - ); - require(borrowRateMantissa <= borrowRateMaxMantissa, "CT10"); - - (MathError mathErr, uint256 blockDelta) = subUInt( - currentBlockNumber, - accrualBlockNumberPrior - ); - require(mathErr == MathError.NO_ERROR, "CT11"); - - Exp memory simpleInterestFactor; - uint256 interestAccumulated; - uint256 totalBorrowsNew; - uint256 totalReservesNew; - uint256 borrowIndexNew; - - (mathErr, simpleInterestFactor) = mulScalar( - Exp({mantissa: borrowRateMantissa}), - blockDelta - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .ACCRUE_INTEREST_SIMPLE_INTEREST_FACTOR_CALCULATION_FAILED, - uint256(mathErr) - ); - } - - (mathErr, interestAccumulated) = mulScalarTruncate( - simpleInterestFactor, - borrowsPrior - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .ACCRUE_INTEREST_ACCUMULATED_INTEREST_CALCULATION_FAILED, - uint256(mathErr) - ); - } - - (mathErr, totalBorrowsNew) = addUInt(interestAccumulated, borrowsPrior); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .ACCRUE_INTEREST_NEW_TOTAL_BORROWS_CALCULATION_FAILED, - uint256(mathErr) - ); - } - - (mathErr, totalReservesNew) = mulScalarTruncateAddUInt( - Exp({mantissa: reserveFactorMantissa}), - interestAccumulated, - reservesPrior - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .ACCRUE_INTEREST_NEW_TOTAL_RESERVES_CALCULATION_FAILED, - uint256(mathErr) - ); - } - - if (interestRateModel.isTropykusInterestRateModel()) { - (mathErr, totalReservesNew) = newReserves( - borrowRateMantissa, - cashPrior, - borrowsPrior, - reservesPrior, - interestAccumulated - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .ACCRUE_INTEREST_NEW_TOTAL_RESERVES_CALCULATION_FAILED, - uint256(mathErr) - ); - } - } - - (mathErr, borrowIndexNew) = mulScalarTruncateAddUInt( - simpleInterestFactor, - borrowIndexPrior, - borrowIndexPrior - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .ACCRUE_INTEREST_NEW_BORROW_INDEX_CALCULATION_FAILED, - uint256(mathErr) - ); - } - - accrualBlockNumber = currentBlockNumber; - borrowIndex = borrowIndexNew; - totalBorrows = totalBorrowsNew; - totalReserves = totalReservesNew; - - emit AccrueInterest( - cashPrior, - interestAccumulated, - borrowIndexNew, - totalBorrowsNew - ); - - return uint256(Error.NO_ERROR); - } - - function newReserves( - uint256 borrowRateMantissa, - uint256 cashPrior, - uint256 borrowsPrior, - uint256 reservesPrior, - uint256 interestAccumulated - ) internal view returns (MathError mathErr, uint256 totalReservesNew) { - uint256 newReserveFactorMantissa; - uint256 utilizationRate = interestRateModel.utilizationRate( - cashPrior, - borrowsPrior, - reservesPrior - ); - uint256 expectedSupplyRate = interestRateModel.getSupplyRate( - cashPrior, - borrowsPrior, - reservesPrior, - reserveFactorMantissa - ); - if ( - interestRateModel.isAboveOptimal( - cashPrior, - borrowsPrior, - reservesPrior - ) - ) { - (mathErr, newReserveFactorMantissa) = mulScalarTruncate( - Exp({mantissa: utilizationRate}), - borrowRateMantissa - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - (mathErr, newReserveFactorMantissa) = subUInt( - newReserveFactorMantissa, - expectedSupplyRate - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - (mathErr, totalReservesNew) = mulScalarTruncateAddUInt( - Exp({mantissa: newReserveFactorMantissa}), - interestAccumulated, - reservesPrior - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - } else { - mathErr = MathError.NO_ERROR; - totalReservesNew = reservesPrior; - } - } - - /** - * @notice Sender supplies assets into the market and receives cTokens in exchange - * @dev Accrues interest whether or not the operation succeeds, unless reverted - * @param mintAmount The amount of the underlying asset to supply - * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual mint amount. - */ - function mintInternal(uint256 mintAmount) - internal - nonReentrant - returns (uint256, uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return ( - fail(Error(error), FailureInfo.MINT_ACCRUE_INTEREST_FAILED), - 0 - ); - } - return mintFresh(msg.sender, mintAmount); - } - - struct MintLocalVars { - Error err; - MathError mathErr; - uint256 exchangeRateMantissa; - uint256 mintTokens; - uint256 totalSupplyNew; - uint256 accountTokensNew; - uint256 actualMintAmount; - } - - /** - * @notice User supplies assets into the market and receives cTokens in exchange - * @dev Assumes interest has already been accrued up to the current block - * @param minter The address of the account which is supplying the assets - * @param mintAmount The amount of the underlying asset to supply - * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual mint amount. - */ - function mintFresh(address minter, uint256 mintAmount) - internal - returns (uint256, uint256) - { - uint256 allowed = comptroller.mintAllowed( - address(this), - minter, - mintAmount - ); - if (allowed != 0) { - return ( - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.MINT_COMPTROLLER_REJECTION, - allowed - ), - 0 - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return ( - fail(Error.MARKET_NOT_FRESH, FailureInfo.MINT_FRESHNESS_CHECK), - 0 - ); - } - - MintLocalVars memory vars; - - ( - vars.mathErr, - vars.exchangeRateMantissa - ) = exchangeRateStoredInternal(); - if (vars.mathErr != MathError.NO_ERROR) { - return ( - failOpaque( - Error.MATH_ERROR, - FailureInfo.MINT_EXCHANGE_RATE_READ_FAILED, - uint256(vars.mathErr) - ), - 0 - ); - } - - vars.actualMintAmount = doTransferIn(minter, mintAmount); - - (vars.mathErr, vars.mintTokens) = divScalarByExpTruncate( - vars.actualMintAmount, - Exp({mantissa: vars.exchangeRateMantissa}) - ); - require(vars.mathErr == MathError.NO_ERROR, "CT12"); - - (vars.mathErr, vars.totalSupplyNew) = addUInt( - totalSupply, - vars.mintTokens - ); - require(vars.mathErr == MathError.NO_ERROR, "CT13"); - - (vars.mathErr, vars.accountTokensNew) = addUInt( - accountTokens[minter].tokens, - vars.mintTokens - ); - require(vars.mathErr == MathError.NO_ERROR, "CT14"); - - uint256 currentSupplyRate = interestRateModel.getSupplyRate( - getCashPrior(), - totalBorrows, - totalReserves, - reserveFactorMantissa - ); - - bool isTropykusInterestRateModel = interestRateModel - .isTropykusInterestRateModel(); - - if (accountTokens[minter].tokens > 0) { - Exp memory updatedUnderlying; - if (isTropykusInterestRateModel) { - Exp memory promisedSupplyRatePerBlock = Exp({ - mantissa: accountTokens[minter].promisedSupplyRate - }); - (, uint256 delta) = subUInt( - accrualBlockNumber, - accountTokens[minter].suppliedAt - ); - (, Exp memory promisedSupplyRatePerBlockWithDelta) = mulScalar( - promisedSupplyRatePerBlock, - delta - ); - (, Exp memory interestFactor) = addExp( - Exp({mantissa: 1e18}), - promisedSupplyRatePerBlockWithDelta - ); - uint256 currentUnderlyingAmount = accountTokens[minter] - .underlyingAmount; - MathError mErrorNewAmount; - (mErrorNewAmount, updatedUnderlying) = mulExp( - Exp({mantissa: currentUnderlyingAmount}), - interestFactor - ); - if (mErrorNewAmount != MathError.NO_ERROR) { - return ( - failOpaque( - Error.MATH_ERROR, - FailureInfo.MINT_EXCHANGE_CALCULATION_FAILED, - uint256(mErrorNewAmount) - ), - 0 - ); - } - } else { - uint256 currentTokens = accountTokens[minter].tokens; - MathError mErrorUpdatedUnderlying; - (mErrorUpdatedUnderlying, updatedUnderlying) = mulExp( - Exp({mantissa: currentTokens}), - Exp({mantissa: vars.exchangeRateMantissa}) - ); - if (mErrorUpdatedUnderlying != MathError.NO_ERROR) { - return ( - failOpaque( - Error.MATH_ERROR, - FailureInfo.MINT_EXCHANGE_CALCULATION_FAILED, - uint256(mErrorUpdatedUnderlying) - ), - 0 - ); - } - } - (, mintAmount) = addUInt(updatedUnderlying.mantissa, mintAmount); - } - - totalSupply = vars.totalSupplyNew; - accountTokens[minter] = SupplySnapshot({ - tokens: vars.accountTokensNew, - underlyingAmount: mintAmount, - suppliedAt: accrualBlockNumber, - promisedSupplyRate: currentSupplyRate - }); - - emit Mint(minter, vars.actualMintAmount, vars.mintTokens); - emit Transfer(address(this), minter, vars.mintTokens); - - return (uint256(Error.NO_ERROR), vars.actualMintAmount); - } - - /** - * @notice Sender redeems cTokens in exchange for a specified amount of underlying asset - * @dev Accrues interest whether or not the operation succeeds, unless reverted - * @param redeemAmount The amount of underlying to receive from redeeming cTokens - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function redeemUnderlyingInternal(uint256 redeemAmount) - internal - nonReentrant - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return - fail(Error(error), FailureInfo.REDEEM_ACCRUE_INTEREST_FAILED); - } - return redeemFresh(payable(msg.sender), redeemAmount); - } - - struct RedeemLocalVars { - Error err; - MathError mathErr; - uint256 exchangeRateMantissa; - uint256 redeemTokens; - uint256 redeemAmount; - uint256 totalSupplyNew; - uint256 accountTokensNew; - uint256 newSubsidyFund; - } - - /** - * @notice User redeems cTokens in exchange for the underlying asset - * @dev Assumes interest has already been accrued up to the current block - * @param redeemer The address of the account which is redeeming the tokens - * @param redeemAmountIn The number of underlying tokens to receive from redeeming cTokens - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function redeemFresh( - address payable redeemer, - uint256 redeemAmountIn - ) internal returns (uint256) { - require(redeemAmountIn > 0, "CT15"); - - RedeemLocalVars memory vars; - - SupplySnapshot storage supplySnapshot = accountTokens[redeemer]; - - ( - vars.mathErr, - vars.exchangeRateMantissa - ) = exchangeRateStoredInternal(); - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.REDEEM_EXCHANGE_RATE_READ_FAILED, - uint256(vars.mathErr) - ); - } - - uint256 interestEarned; - uint256 subsidyFundPortion; - uint256 currentUnderlying; - - bool isTropykusInterestRateModel = interestRateModel - .isTropykusInterestRateModel(); - if (isTropykusInterestRateModel) { - uint256 promisedSupplyRate = supplySnapshot.promisedSupplyRate; - Exp memory expectedSupplyRatePerBlock = Exp({ - mantissa: promisedSupplyRate - }); - (, uint256 delta) = subUInt( - accrualBlockNumber, - supplySnapshot.suppliedAt - ); - (, Exp memory expectedSupplyRatePerBlockWithDelta) = mulScalar( - expectedSupplyRatePerBlock, - delta - ); - (, Exp memory interestFactor) = addExp( - Exp({mantissa: 1e18}), - expectedSupplyRatePerBlockWithDelta - ); - currentUnderlying = supplySnapshot.underlyingAmount; - Exp memory redeemerUnderlying = Exp({mantissa: currentUnderlying}); - (, Exp memory realAmount) = mulExp( - interestFactor, - redeemerUnderlying - ); - supplySnapshot.underlyingAmount = realAmount.mantissa; - (, interestEarned) = subUInt( - realAmount.mantissa, - currentUnderlying - ); - } - supplySnapshot.promisedSupplyRate = interestRateModel.getSupplyRate( - getCashPrior(), - totalBorrows, - totalReserves, - reserveFactorMantissa - ); - - if ( - isTropykusInterestRateModel && - !interestRateModel.isAboveOptimal( - getCashPrior(), - totalBorrows, - totalReserves - ) - ) { - uint256 borrowRate = interestRateModel.getBorrowRate( - getCashPrior(), - totalBorrows, - totalReserves - ); - - uint256 utilizationRate = interestRateModel.utilizationRate( - getCashPrior(), - totalBorrows, - totalReserves - ); - - (, uint256 estimatedEarning) = mulScalarTruncate( - Exp({mantissa: borrowRate}), - utilizationRate - ); - - (, subsidyFundPortion) = subUInt( - supplySnapshot.promisedSupplyRate, - estimatedEarning - ); - (, Exp memory subsidyFactor) = getExp( - subsidyFundPortion, - supplySnapshot.promisedSupplyRate - ); - (, subsidyFundPortion) = mulScalarTruncate( - subsidyFactor, - interestEarned - ); - } - - // if (redeemTokensIn > 0) { - // vars.redeemTokens = redeemTokensIn; - // if (isTropykusInterestRateModel) { - // (, Exp memory num) = mulExp( - // vars.redeemTokens, - // currentUnderlying - // ); - // (, Exp memory realUnderlyingWithdrawAmount) = getExp( - // num.mantissa, - // supplySnapshot.tokens - // ); - // vars.redeemAmount = realUnderlyingWithdrawAmount.mantissa; - // } else { - // (vars.mathErr, vars.redeemAmount) = mulScalarTruncate( - // Exp({mantissa: vars.exchangeRateMantissa}), - // redeemTokensIn - // ); - // if (vars.mathErr != MathError.NO_ERROR) { - // return - // failOpaque( - // Error.MATH_ERROR, - // FailureInfo - // .REDEEM_EXCHANGE_TOKENS_CALCULATION_FAILED, - // uint256(vars.mathErr) - // ); - // } - // } - // } else { - vars.redeemAmount = redeemAmountIn; - - if (isTropykusInterestRateModel) { - (, Exp memory num) = mulExp( - vars.redeemAmount, - supplySnapshot.tokens - ); - (, Exp memory realTokensWithdrawAmount) = getExp( - num.mantissa, - currentUnderlying - ); - vars.redeemTokens = realTokensWithdrawAmount.mantissa; - } else { - (vars.mathErr, vars.redeemTokens) = divScalarByExpTruncate( - redeemAmountIn, - Exp({mantissa: vars.exchangeRateMantissa}) - ); - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .REDEEM_EXCHANGE_AMOUNT_CALCULATION_FAILED, - uint256(vars.mathErr) - ); - } - } - // } - - uint256 allowed = comptroller.redeemAllowed( - address(this), - redeemer, - vars.redeemTokens - ); - if (allowed != 0) { - return - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.REDEEM_COMPTROLLER_REJECTION, - allowed - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.REDEEM_FRESHNESS_CHECK - ); - } - - (vars.mathErr, vars.totalSupplyNew) = subUInt( - totalSupply, - vars.redeemTokens - ); - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.REDEEM_NEW_TOTAL_SUPPLY_CALCULATION_FAILED, - uint256(vars.mathErr) - ); - } - - (, vars.newSubsidyFund) = subUInt(subsidyFund, subsidyFundPortion); - - (vars.mathErr, vars.accountTokensNew) = subUInt( - supplySnapshot.tokens, - vars.redeemTokens - ); - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.REDEEM_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED, - uint256(vars.mathErr) - ); - } - - uint256 cash = getCashPrior(); - if (isTropykusInterestRateModel) { - cash = address(this).balance; - } - - if (cash < vars.redeemAmount) { - return - fail( - Error.TOKEN_INSUFFICIENT_CASH, - FailureInfo.REDEEM_TRANSFER_OUT_NOT_POSSIBLE - ); - } - - doTransferOut(redeemer, vars.redeemAmount); - - totalSupply = vars.totalSupplyNew; - subsidyFund = vars.newSubsidyFund; - supplySnapshot.tokens = vars.accountTokensNew; - supplySnapshot.suppliedAt = accrualBlockNumber; - (, supplySnapshot.underlyingAmount) = subUInt( - supplySnapshot.underlyingAmount, - vars.redeemAmount - ); - - emit Transfer(redeemer, address(this), vars.redeemTokens); - emit Redeem(redeemer, vars.redeemAmount, vars.redeemTokens); - - comptroller.redeemVerify( - address(this), - redeemer, - vars.redeemAmount, - vars.redeemTokens - ); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Sender borrows assets from the protocol to their own address - * @param borrowAmount The amount of the underlying asset to borrow - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function borrowInternal(uint256 borrowAmount) - internal - nonReentrant - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return - fail(Error(error), FailureInfo.BORROW_ACCRUE_INTEREST_FAILED); - } - return borrowFresh(payable(msg.sender), borrowAmount); - } - - struct BorrowLocalVars { - MathError mathErr; - uint256 accountBorrows; - uint256 accountBorrowsNew; - uint256 totalBorrowsNew; - } - - /** - * @notice Users borrow assets from the protocol to their own address - * @param borrowAmount The amount of the underlying asset to borrow - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function borrowFresh(address payable borrower, uint256 borrowAmount) - internal - returns (uint256) - { - uint256 allowed = comptroller.borrowAllowed( - address(this), - borrower, - borrowAmount - ); - if (allowed != 0) { - return - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.BORROW_COMPTROLLER_REJECTION, - allowed - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.BORROW_FRESHNESS_CHECK - ); - } - - if (getCashPrior() < borrowAmount) { - return - fail( - Error.TOKEN_INSUFFICIENT_CASH, - FailureInfo.BORROW_CASH_NOT_AVAILABLE - ); - } - - BorrowLocalVars memory vars; - - (vars.mathErr, vars.accountBorrows) = borrowBalanceStoredInternal( - borrower - ); - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED, - uint256(vars.mathErr) - ); - } - - (vars.mathErr, vars.accountBorrowsNew) = addUInt( - vars.accountBorrows, - borrowAmount - ); - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED, - uint256(vars.mathErr) - ); - } - - (vars.mathErr, vars.totalBorrowsNew) = addUInt( - totalBorrows, - borrowAmount - ); - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED, - uint256(vars.mathErr) - ); - } - - doTransferOut(borrower, borrowAmount); - - accountBorrows[borrower].principal = vars.accountBorrowsNew; - accountBorrows[borrower].interestIndex = borrowIndex; - totalBorrows = vars.totalBorrowsNew; - - emit Borrow( - borrower, - borrowAmount, - vars.accountBorrowsNew, - vars.totalBorrowsNew - ); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Sender repays their own borrow - * @param repayAmount The amount to repay - * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual repayment amount. - */ - function repayBorrowInternal(uint256 repayAmount) - internal - nonReentrant - returns (uint256, uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return ( - fail( - Error(error), - FailureInfo.REPAY_BORROW_ACCRUE_INTEREST_FAILED - ), - 0 - ); - } - return repayBorrowFresh(msg.sender, msg.sender, repayAmount); - } - - /** - * @notice Sender repays a borrow belonging to borrower - * @param borrower the account with the debt being payed off - * @param repayAmount The amount to repay - * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual repayment amount. - */ - function repayBorrowBehalfInternal(address borrower, uint256 repayAmount) - internal - nonReentrant - returns (uint256, uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return ( - fail( - Error(error), - FailureInfo.REPAY_BEHALF_ACCRUE_INTEREST_FAILED - ), - 0 - ); - } - return repayBorrowFresh(msg.sender, borrower, repayAmount); - } - - struct RepayBorrowLocalVars { - Error err; - MathError mathErr; - uint256 repayAmount; - uint256 borrowerIndex; - uint256 accountBorrows; - uint256 accountBorrowsNew; - uint256 totalBorrowsNew; - uint256 actualRepayAmount; - } - - /** - * @notice Borrows are repaid by another user (possibly the borrower). - * @param payer the account paying off the borrow - * @param borrower the account with the debt being payed off - * @param repayAmount the amount of undelrying tokens being returned - * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual repayment amount. - */ - function repayBorrowFresh( - address payer, - address borrower, - uint256 repayAmount - ) internal returns (uint256, uint256) { - uint256 allowed = comptroller.repayBorrowAllowed( - address(this), - payer, - borrower, - repayAmount - ); - if (allowed != 0) { - return ( - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.REPAY_BORROW_COMPTROLLER_REJECTION, - allowed - ), - 0 - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return ( - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.REPAY_BORROW_FRESHNESS_CHECK - ), - 0 - ); - } - - RepayBorrowLocalVars memory vars; - - vars.borrowerIndex = accountBorrows[borrower].interestIndex; - - (vars.mathErr, vars.accountBorrows) = borrowBalanceStoredInternal( - borrower - ); - if (vars.mathErr != MathError.NO_ERROR) { - return ( - failOpaque( - Error.MATH_ERROR, - FailureInfo - .REPAY_BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED, - uint256(vars.mathErr) - ), - 0 - ); - } - - if (repayAmount == type(uint256).max) { - vars.repayAmount = vars.accountBorrows; - } else { - vars.repayAmount = repayAmount; - } - - vars.actualRepayAmount = doTransferIn(payer, vars.repayAmount); - - (vars.mathErr, vars.accountBorrowsNew) = subUInt( - vars.accountBorrows, - vars.actualRepayAmount - ); - require(vars.mathErr == MathError.NO_ERROR, "CT16"); - - (vars.mathErr, vars.totalBorrowsNew) = subUInt( - totalBorrows, - vars.actualRepayAmount - ); - require(vars.mathErr == MathError.NO_ERROR, "CT17"); - - accountBorrows[borrower].principal = vars.accountBorrowsNew; - accountBorrows[borrower].interestIndex = borrowIndex; - totalBorrows = vars.totalBorrowsNew; - - emit RepayBorrow( - payer, - borrower, - vars.actualRepayAmount, - vars.accountBorrowsNew, - vars.totalBorrowsNew - ); - - return (uint256(Error.NO_ERROR), vars.actualRepayAmount); - } - - /** - * @notice The sender liquidates the borrowers collateral. - * The collateral seized is transferred to the liquidator. - * @param borrower The borrower of this cToken to be liquidated - * @param cTokenCollateral The market in which to seize collateral from the borrower - * @param repayAmount The amount of the underlying borrowed asset to repay - * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual repayment amount. - */ - function liquidateBorrowInternal( - address borrower, - uint256 repayAmount, - CTokenInterface cTokenCollateral - ) internal nonReentrant returns (uint256, uint256) { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return ( - fail( - Error(error), - FailureInfo.LIQUIDATE_ACCRUE_BORROW_INTEREST_FAILED - ), - 0 - ); - } - - error = cTokenCollateral.accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return ( - fail( - Error(error), - FailureInfo.LIQUIDATE_ACCRUE_COLLATERAL_INTEREST_FAILED - ), - 0 - ); - } - - // liquidateBorrowFresh emits borrow-specific logs on errors, so we don't need to - return - liquidateBorrowFresh( - msg.sender, - borrower, - repayAmount, - cTokenCollateral - ); - } - - /** - * @notice The liquidator liquidates the borrowers collateral. - * The collateral seized is transferred to the liquidator. - * @param borrower The borrower of this cToken to be liquidated - * @param liquidator The address repaying the borrow and seizing collateral - * @param cTokenCollateral The market in which to seize collateral from the borrower - * @param repayAmount The amount of the underlying borrowed asset to repay - * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual repayment amount. - */ - function liquidateBorrowFresh( - address liquidator, - address borrower, - uint256 repayAmount, - CTokenInterface cTokenCollateral - ) internal returns (uint256, uint256) { - uint256 allowed = comptroller.liquidateBorrowAllowed( - address(this), - address(cTokenCollateral), - liquidator, - borrower, - repayAmount - ); - if (allowed != 0) { - return ( - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.LIQUIDATE_COMPTROLLER_REJECTION, - allowed - ), - 0 - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return ( - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.LIQUIDATE_FRESHNESS_CHECK - ), - 0 - ); - } - - if (cTokenCollateral.accrualBlockNumber() != getBlockNumber()) { - return ( - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.LIQUIDATE_COLLATERAL_FRESHNESS_CHECK - ), - 0 - ); - } - - if (borrower == liquidator) { - return ( - fail( - Error.INVALID_ACCOUNT_PAIR, - FailureInfo.LIQUIDATE_LIQUIDATOR_IS_BORROWER - ), - 0 - ); - } - - if (repayAmount == 0) { - return ( - fail( - Error.INVALID_CLOSE_AMOUNT_REQUESTED, - FailureInfo.LIQUIDATE_CLOSE_AMOUNT_IS_ZERO - ), - 0 - ); - } - - if (repayAmount == type(uint256).max) { - return ( - fail( - Error.INVALID_CLOSE_AMOUNT_REQUESTED, - FailureInfo.LIQUIDATE_CLOSE_AMOUNT_IS_UINT_MAX - ), - 0 - ); - } - - ( - uint256 repayBorrowError, - uint256 actualRepayAmount - ) = repayBorrowFresh(liquidator, borrower, repayAmount); - if (repayBorrowError != uint256(Error.NO_ERROR)) { - return ( - fail( - Error(repayBorrowError), - FailureInfo.LIQUIDATE_REPAY_BORROW_FRESH_FAILED - ), - 0 - ); - } - - (uint256 amountSeizeError, uint256 seizeTokens) = comptroller - .liquidateCalculateSeizeTokens( - address(this), - address(cTokenCollateral), - actualRepayAmount - ); - require(amountSeizeError == uint256(Error.NO_ERROR), "CT18"); - - require(cTokenCollateral.balanceOf(borrower) >= seizeTokens, "CT19"); - - uint256 seizeError; - if (address(cTokenCollateral) == address(this)) { - seizeError = seizeInternal( - address(this), - liquidator, - borrower, - seizeTokens - ); - } else { - seizeError = cTokenCollateral.seize( - liquidator, - borrower, - seizeTokens - ); - } - - require(seizeError == uint256(Error.NO_ERROR), "CT20"); - - emit LiquidateBorrow( - liquidator, - borrower, - actualRepayAmount, - address(cTokenCollateral), - seizeTokens - ); - - return (uint256(Error.NO_ERROR), actualRepayAmount); - } - - /** - * @notice Transfers collateral tokens (this market) to the liquidator. - * @dev Will fail unless called by another cToken during the process of liquidation. - * Its absolutely critical to use msg.sender as the borrowed cToken and not a parameter. - * @param liquidator The account receiving seized collateral - * @param borrower The account having collateral seized - * @param seizeTokens The number of cTokens to seize - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function seize( - address liquidator, - address borrower, - uint256 seizeTokens - ) external override nonReentrant returns (uint256) { - return seizeInternal(msg.sender, liquidator, borrower, seizeTokens); - } - - /** - * @notice Transfers collateral tokens (this market) to the liquidator. - * @dev Called only during an in-kind liquidation, or by liquidateBorrow during the liquidation of another CToken. - * Its absolutely critical to use msg.sender as the seizer cToken and not a parameter. - * @param seizerToken The contract seizing the collateral (i.e. borrowed cToken) - * @param liquidator The account receiving seized collateral - * @param borrower The account having collateral seized - * @param seizeTokens The number of cTokens to seize - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function seizeInternal( - address seizerToken, - address liquidator, - address borrower, - uint256 seizeTokens - ) internal returns (uint256) { - uint256 allowed = comptroller.seizeAllowed( - address(this), - seizerToken, - liquidator, - borrower, - seizeTokens - ); - if (allowed != 0) { - return - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.LIQUIDATE_SEIZE_COMPTROLLER_REJECTION, - allowed - ); - } - - if (borrower == liquidator) { - return - fail( - Error.INVALID_ACCOUNT_PAIR, - FailureInfo.LIQUIDATE_SEIZE_LIQUIDATOR_IS_BORROWER - ); - } - - MathError mathErr; - uint256 borrowerTokensNew; - uint256 liquidatorTokensNew; - - (mathErr, borrowerTokensNew) = subUInt( - accountTokens[borrower].tokens, - seizeTokens - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.LIQUIDATE_SEIZE_BALANCE_DECREMENT_FAILED, - uint256(mathErr) - ); - } - - (mathErr, liquidatorTokensNew) = addUInt( - accountTokens[liquidator].tokens, - seizeTokens - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.LIQUIDATE_SEIZE_BALANCE_INCREMENT_FAILED, - uint256(mathErr) - ); - } - - accountTokens[borrower].tokens = borrowerTokensNew; - accountTokens[liquidator].tokens = liquidatorTokensNew; - - emit Transfer(borrower, liquidator, seizeTokens); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Begins transfer of admin rights. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer. - * @dev Admin function to begin change of admin. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer. - * @param newPendingAdmin New pending admin. - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setPendingAdmin(address payable newPendingAdmin) - external - override - returns (uint256) - { - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_PENDING_ADMIN_OWNER_CHECK - ); - } - - address oldPendingAdmin = pendingAdmin; - - pendingAdmin = newPendingAdmin; - - emit NewPendingAdmin(oldPendingAdmin, newPendingAdmin); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Accepts transfer of admin rights. msg.sender must be pendingAdmin - * @dev Admin function for pending admin to accept role and update admin - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _acceptAdmin() external override returns (uint256) { - if (msg.sender != pendingAdmin || msg.sender == address(0)) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.ACCEPT_ADMIN_PENDING_ADMIN_CHECK - ); - } - - address oldAdmin = admin; - address oldPendingAdmin = pendingAdmin; - - admin = pendingAdmin; - - pendingAdmin = payable(address(0)); - - emit NewAdmin(oldAdmin, admin); - emit NewPendingAdmin(oldPendingAdmin, pendingAdmin); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Sets a new comptroller for the market - * @dev Admin function to set a new comptroller - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setComptroller(ComptrollerInterface newComptroller) - public - override - returns (uint256) - { - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_COMPTROLLER_OWNER_CHECK - ); - } - - ComptrollerInterface oldComptroller = comptroller; - require(newComptroller.isComptroller(), "CT21"); - - comptroller = newComptroller; - - emit NewComptroller(oldComptroller, newComptroller); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice accrues interest and sets a new reserve factor for the protocol using _setReserveFactorFresh - * @dev Admin function to accrue interest and set a new reserve factor - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setReserveFactor(uint256 newReserveFactorMantissa) - external - override - nonReentrant - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return - fail( - Error(error), - FailureInfo.SET_RESERVE_FACTOR_ACCRUE_INTEREST_FAILED - ); - } - return _setReserveFactorFresh(newReserveFactorMantissa); - } - - /** - * @notice Sets a new reserve factor for the protocol (*requires fresh interest accrual) - * @dev Admin function to set a new reserve factor - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setReserveFactorFresh(uint256 newReserveFactorMantissa) - internal - returns (uint256) - { - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_RESERVE_FACTOR_ADMIN_CHECK - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.SET_RESERVE_FACTOR_FRESH_CHECK - ); - } - - if (newReserveFactorMantissa > reserveFactorMaxMantissa) { - return - fail( - Error.BAD_INPUT, - FailureInfo.SET_RESERVE_FACTOR_BOUNDS_CHECK - ); - } - - uint256 oldReserveFactorMantissa = reserveFactorMantissa; - reserveFactorMantissa = newReserveFactorMantissa; - - emit NewReserveFactor( - oldReserveFactorMantissa, - newReserveFactorMantissa - ); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Accrues interest and reduces reserves by transferring from msg.sender - * @param addAmount Amount of addition to reserves - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _addReservesInternal(uint256 addAmount) - internal - nonReentrant - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return - fail( - Error(error), - FailureInfo.ADD_RESERVES_ACCRUE_INTEREST_FAILED - ); - } - - (error, ) = _addReservesFresh(addAmount); - return error; - } - - /** - * @notice Add reserves by transferring from caller - * @dev Requires fresh interest accrual - * @param addAmount Amount of addition to reserves - * @return (uint, uint) An error code (0=success, otherwise a failure (see ErrorReporter.sol for details)) and the actual amount added, net token fees - */ - function _addReservesFresh(uint256 addAmount) - internal - returns (uint256, uint256) - { - uint256 totalReservesNew; - uint256 actualAddAmount; - - if (accrualBlockNumber != getBlockNumber()) { - return ( - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.ADD_RESERVES_FRESH_CHECK - ), - actualAddAmount - ); - } - - actualAddAmount = doTransferIn(msg.sender, addAmount); - - totalReservesNew = totalReserves + actualAddAmount; - - require(totalReservesNew >= totalReserves, "CT22"); - - totalReserves = totalReservesNew; - - emit ReservesAdded(msg.sender, actualAddAmount, totalReservesNew); - - return (uint256(Error.NO_ERROR), actualAddAmount); - } - - function _addSubsidyInternal(uint256 addAmount) - internal - nonReentrant - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - // accrueInterest emits logs on errors, but on top of that we want to log the fact that an attempted reduce reserves failed. - return fail(Error(error), FailureInfo.ADD_SUBSIDY_FUND_FAILED); - } - - (error, ) = _addSubsidyFresh(addAmount); - return error; - } - - /** - * @notice Add reserves by transferring from caller - * @dev Requires fresh interest accrual - * @param addAmount Amount of addition to reserves - * @return (uint, uint) An error code (0=success, otherwise a failure (see ErrorReporter.sol for details)) and the actual amount added, net token fees - */ - function _addSubsidyFresh(uint256 addAmount) - internal - returns (uint256, uint256) - { - uint256 subsidyFundNew; - uint256 actualAddAmount; - - if (accrualBlockNumber != getBlockNumber()) { - return ( - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.ADD_SUBSIDY_FUND_FRESH_CHECK - ), - actualAddAmount - ); - } - - actualAddAmount = doTransferIn(msg.sender, addAmount); - - subsidyFundNew = subsidyFund + actualAddAmount; - - require(subsidyFundNew >= subsidyFund, "CT22"); - - subsidyFund = subsidyFundNew; - - emit SubsidyAdded(msg.sender, actualAddAmount, subsidyFundNew); - - /* Return (NO_ERROR, actualAddAmount) */ - return (uint256(Error.NO_ERROR), actualAddAmount); - } - - /** - * @notice Accrues interest and reduces reserves by transferring to admin - * @param reduceAmount Amount of reduction to reserves - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _reduceReserves(uint256 reduceAmount) - external - override - nonReentrant - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return - fail( - Error(error), - FailureInfo.REDUCE_RESERVES_ACCRUE_INTEREST_FAILED - ); - } - return _reduceReservesFresh(reduceAmount); - } - - /** - * @notice Reduces reserves by transferring to admin - * @dev Requires fresh interest accrual - * @param reduceAmount Amount of reduction to reserves - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _reduceReservesFresh(uint256 reduceAmount) - internal - returns (uint256) - { - uint256 totalReservesNew; - - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.REDUCE_RESERVES_ADMIN_CHECK - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.REDUCE_RESERVES_FRESH_CHECK - ); - } - - if (getCashPrior() < reduceAmount) { - return - fail( - Error.TOKEN_INSUFFICIENT_CASH, - FailureInfo.REDUCE_RESERVES_CASH_NOT_AVAILABLE - ); - } - - if (reduceAmount > totalReserves) { - return - fail(Error.BAD_INPUT, FailureInfo.REDUCE_RESERVES_VALIDATION); - } - - totalReservesNew = totalReserves - reduceAmount; - require(totalReservesNew <= totalReserves, "CT23"); - - totalReserves = totalReservesNew; - - doTransferOut(admin, reduceAmount); - - emit ReservesReduced(admin, reduceAmount, totalReservesNew); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice accrues interest and updates the interest rate model using _setInterestRateModelFresh - * @dev Admin function to accrue interest and update the interest rate model - * @param newInterestRateModel the new interest rate model to use - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setInterestRateModel(InterestRateModel newInterestRateModel) - public - override - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return - fail( - Error(error), - FailureInfo.SET_INTEREST_RATE_MODEL_ACCRUE_INTEREST_FAILED - ); - } - return _setInterestRateModelFresh(newInterestRateModel); - } - - /** - * @notice updates the interest rate model (*requires fresh interest accrual) - * @dev Admin function to update the interest rate model - * @param newInterestRateModel the new interest rate model to use - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setInterestRateModelFresh(InterestRateModel newInterestRateModel) - internal - returns (uint256) - { - InterestRateModel oldInterestRateModel; - - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_INTEREST_RATE_MODEL_OWNER_CHECK - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.SET_INTEREST_RATE_MODEL_FRESH_CHECK - ); - } - - oldInterestRateModel = interestRateModel; - - require(newInterestRateModel.isInterestRateModel(), "CT21"); - - interestRateModel = newInterestRateModel; - - emit NewMarketInterestRateModel( - oldInterestRateModel, - newInterestRateModel - ); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Gets balance of this contract in terms of the underlying - * @dev This excludes the value of the current message, if any - * @return The quantity of underlying owned by this contract - */ - function getCashPrior() internal view virtual returns (uint256); - - /** - * @dev Performs a transfer in, reverting upon failure. Returns the amount actually transferred to the protocol, in case of a fee. - * This may revert due to insufficient balance or insufficient allowance. - */ - function doTransferIn(address from, uint256 amount) - internal - virtual - returns (uint256); - - /** - * @dev Performs a transfer out, ideally returning an explanatory error code upon failure tather than reverting. - * If caller has not called checked protocol's balance, may revert due to insufficient cash held in the contract. - * If caller has checked protocol's balance, and verified it is >= amount, this should not revert in normal conditions. - */ - function doTransferOut(address payable to, uint256 amount) internal virtual; - - /** - * @dev Prevents a contract from calling itself, directly or indirectly. - */ - modifier nonReentrant() { - require(_notEntered, "re-entered"); - _notEntered = false; - _; - _notEntered = true; - } -} - - -// Dependency file: contracts/CRBTC.sol - -// pragma solidity 0.8.6; - -// import "contracts/CToken.sol"; - -/** - * @title tropykus CRBTC Contract - * @notice CToken which wraps Ether - * @author tropykus - */ -contract CRBTC is CToken { - /** - * @notice Construct a new CRBTC money market - * @param comptroller_ The address of the Comptroller - * @param interestRateModel_ The address of the interest rate model - * @param initialExchangeRateMantissa_ The initial exchange rate, scaled by 1e18 - * @param name_ ERC-20 name of this token - * @param symbol_ ERC-20 symbol of this token - * @param decimals_ ERC-20 decimal precision of this token - * @param admin_ Address of the administrator of this token - */ - constructor( - ComptrollerInterface comptroller_, - InterestRateModel interestRateModel_, - uint256 initialExchangeRateMantissa_, - string memory name_, - string memory symbol_, - uint8 decimals_, - address payable admin_ - ) { - // Creator of the contract is admin during initialization - admin = payable(msg.sender); - - initialize( - comptroller_, - interestRateModel_, - initialExchangeRateMantissa_, - name_, - symbol_, - decimals_ - ); - - // Set the proper admin now that initialization is done - admin = admin_; - } - - /*** User Interface ***/ - - /** - * @notice Sender supplies assets into the market and receives cTokens in exchange - * @dev Reverts upon any failure - */ - function mint() external payable { - (uint256 err, ) = mintInternal(msg.value); - requireNoError(err, "RC01"); - } - - /** - * @notice Sender redeems cTokens in exchange for a specified amount of underlying asset - * @dev Accrues interest whether or not the operation succeeds, unless reverted - * @param redeemAmount The amount of underlying to redeem - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function redeem(uint256 redeemAmount) external returns (uint256) { - return redeemUnderlyingInternal(redeemAmount); - } - - /** - * @notice Sender borrows assets from the protocol to their own address - * @param borrowAmount The amount of the underlying asset to borrow - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function borrow(uint256 borrowAmount) external returns (uint256) { - return borrowInternal(borrowAmount); - } - - /** - * @notice Sender repays their own borrow - * @dev Reverts upon any failure - */ - function repayBorrow() external payable { - (uint256 err, ) = repayBorrowInternal(msg.value); - requireNoError(err, "RC02"); - } - - /** - * @notice Sender repays a borrow belonging to borrower - * @dev Reverts upon any failure - * @param borrower the account with the debt being payed off - */ - function repayBorrowBehalf(address borrower) external payable { - (uint256 err, ) = repayBorrowBehalfInternal(borrower, msg.value); - requireNoError(err, "RC03"); - } - - /** - * @notice The sender liquidates the borrowers collateral. - * The collateral seized is transferred to the liquidator. - * @dev Reverts upon any failure - * @param borrower The borrower of this cToken to be liquidated - * @param cTokenCollateral The market in which to seize collateral from the borrower - */ - function liquidateBorrow(address borrower, CToken cTokenCollateral) - external - payable - { - (uint256 err, ) = liquidateBorrowInternal( - borrower, - msg.value, - cTokenCollateral - ); - requireNoError(err, "RC04"); - } - - /** - * @notice Send Ether to CRBTC to mint - */ - fallback() external payable { - internalFallback(); - } - - receive() external payable { - internalFallback(); - } - - function internalFallback() public payable { - (uint256 err, ) = mintInternal(msg.value); - requireNoError(err, "RC01"); - } - - /*** Safe Token ***/ - - /** - * @notice Gets balance of this contract in terms of Ether, before this message - * @dev This excludes the value of the current message, if any - * @return The quantity of Ether owned by this contract - */ - function getCashPrior() internal view override returns (uint256) { - (MathError err, uint256 startingBalance) = subUInt( - address(this).balance, - msg.value - ); - if (interestRateModel.isTropykusInterestRateModel()) - (err, startingBalance) = subUInt(startingBalance, subsidyFund); - require(err == MathError.NO_ERROR, "RC05"); - return startingBalance; - } - - /** - * @notice Perform the actual transfer in, which is a no-op - * @param from Address sending the Ether - * @param amount Amount of Ether being sent - * @return The actual amount of Ether transferred - */ - function doTransferIn(address from, uint256 amount) - internal - override - returns (uint256) - { - // Sanity checks - require(msg.sender == from, "RC06"); - require(msg.value == amount, "RC07"); - return amount; - } - - function doTransferOut(address payable to, uint256 amount) - internal - virtual - override - { - /* Send the Ether, with minimal gas and revert on failure */ - to.transfer(amount); - } - - function requireNoError(uint256 errCode, string memory message) - internal - pure - { - if (errCode == uint256(Error.NO_ERROR)) { - return; - } - - bytes memory fullMessage = new bytes(bytes(message).length + 5); - uint256 i; - - for (i = 0; i < bytes(message).length; i++) { - fullMessage[i] = bytes(message)[i]; - } - - fullMessage[i + 0] = bytes1(uint8(32)); - fullMessage[i + 1] = bytes1(uint8(40)); - fullMessage[i + 2] = bytes1(uint8(48 + (errCode / 10))); - fullMessage[i + 3] = bytes1(uint8(48 + (errCode % 10))); - fullMessage[i + 4] = bytes1(uint8(41)); - - require(errCode == uint256(Error.NO_ERROR), string(fullMessage)); - } - - function addSubsidy() external payable { - _addSubsidyInternal(msg.value); - } -} - - -// Root file: contracts/Maximillion.sol - -pragma solidity 0.8.6; - -// import "contracts/CRBTC.sol"; - -/** - * @title tropykus Maximillion Contract - * @author tropykus - */ -contract Maximillion { - /** - * @notice The default cRBTC market to repay in - */ - CRBTC public cRBTC; - - /** - * @notice Construct a Maximillion to repay max in a CRBTC market - */ - constructor(CRBTC cRBTC_) { - cRBTC = cRBTC_; - } - - /** - * @notice msg.sender sends Ether to repay an account's borrow in the cRBTC market - * @dev The provided Ether is applied towards the borrow balance, any excess is refunded - * @param borrower The address of the borrower account to repay on behalf of - */ - function repayBehalf(address borrower) public payable { - repayBehalfExplicit(borrower, cRBTC); - } - - /** - * @notice msg.sender sends Ether to repay an account's borrow in a cRBTC market - * @dev The provided Ether is applied towards the borrow balance, any excess is refunded - * @param borrower The address of the borrower account to repay on behalf of - * @param cRBTC_ The address of the cRBTC contract to repay in - */ - function repayBehalfExplicit(address borrower, CRBTC cRBTC_) - public - payable - { - uint256 received = msg.value; - uint256 borrows = cRBTC_.borrowBalanceCurrent(borrower); - if (received > borrows) { - address payable sender = payable(msg.sender); - cRBTC_.repayBorrowBehalf{value: borrows}(borrower); - sender.transfer(received - borrows); - } else { - cRBTC_.repayBorrowBehalf{value: received}(borrower); - } - } -} diff --git a/flatten/MockPriceProviderMoC.sol b/flatten/MockPriceProviderMoC.sol deleted file mode 100644 index e80d7cb..0000000 --- a/flatten/MockPriceProviderMoC.sol +++ /dev/null @@ -1,4226 +0,0 @@ -// Dependency file: contracts/ComptrollerInterface.sol - -// SPDX-License-Identifier: UNLICENSED -// pragma solidity 0.8.6; - -abstract contract ComptrollerInterface { - /// @notice Indicator that this is a Comptroller contract (for inspection) - bool public constant isComptroller = true; - - /*** Assets You Are In ***/ - - function enterMarkets(address[] calldata cTokens) - external - virtual - returns (uint256[] memory); - - function exitMarket(address cToken) external virtual returns (uint256); - - /*** Policy Hooks ***/ - - function mintAllowed( - address cToken, - address minter, - uint256 mintAmount - ) external virtual returns (uint256); - - function mintVerify( - address cToken, - address minter, - uint256 mintAmount, - uint256 mintTokens - ) external virtual; - - function redeemAllowed( - address cToken, - address redeemer, - uint256 redeemTokens - ) external virtual returns (uint256); - - function redeemVerify( - address cToken, - address redeemer, - uint256 redeemAmount, - uint256 redeemTokens - ) external virtual; - - function borrowAllowed( - address cToken, - address borrower, - uint256 borrowAmount - ) external virtual returns (uint256); - - function borrowVerify( - address cToken, - address borrower, - uint256 borrowAmount - ) external virtual; - - function repayBorrowAllowed( - address cToken, - address payer, - address borrower, - uint256 repayAmount - ) external virtual returns (uint256); - - function repayBorrowVerify( - address cToken, - address payer, - address borrower, - uint256 repayAmount, - uint256 borrowerIndex - ) external virtual; - - function liquidateBorrowAllowed( - address cTokenBorrowed, - address cTokenCollateral, - address liquidator, - address borrower, - uint256 repayAmount - ) external virtual returns (uint256); - - function liquidateBorrowVerify( - address cTokenBorrowed, - address cTokenCollateral, - address liquidator, - address borrower, - uint256 repayAmount, - uint256 seizeTokens - ) external virtual; - - function seizeAllowed( - address cTokenCollateral, - address cTokenBorrowed, - address liquidator, - address borrower, - uint256 seizeTokens - ) external virtual returns (uint256); - - function seizeVerify( - address cTokenCollateral, - address cTokenBorrowed, - address liquidator, - address borrower, - uint256 seizeTokens - ) external virtual; - - function transferAllowed( - address cToken, - address src, - address dst, - uint256 transferTokens - ) external virtual returns (uint256); - - function transferVerify( - address cToken, - address src, - address dst, - uint256 transferTokens - ) external virtual; - - /*** Liquidity/Liquidation Calculations ***/ - - function liquidateCalculateSeizeTokens( - address cTokenBorrowed, - address cTokenCollateral, - uint256 repayAmount - ) external view virtual returns (uint256, uint256); -} - - -// Dependency file: contracts/CarefulMath.sol - -// pragma solidity 0.8.6; - -/** - * @title Careful Math - * @author tropykus - * @notice Derived from OpenZeppelin's SafeMath library - * https://github.com/OpenZeppelin/openzeppelin-solidity/blob/master/contracts/math/SafeMath.sol - */ -contract CarefulMath { - - /** - * @dev Possible error codes that we can return - */ - enum MathError { - NO_ERROR, - DIVISION_BY_ZERO, - INTEGER_OVERFLOW, - INTEGER_UNDERFLOW - } - - /** - * @dev Multiplies two numbers, returns an error on overflow. - */ - function mulUInt(uint a, uint b) internal pure returns (MathError, uint) { - if (a == 0) { - return (MathError.NO_ERROR, 0); - } - - uint c = a * b; - - if (c / a != b) { - return (MathError.INTEGER_OVERFLOW, 0); - } else { - return (MathError.NO_ERROR, c); - } - } - - /** - * @dev Integer division of two numbers, truncating the quotient. - */ - function divUInt(uint a, uint b) internal pure returns (MathError, uint) { - if (b == 0) { - return (MathError.DIVISION_BY_ZERO, 0); - } - - return (MathError.NO_ERROR, a / b); - } - - /** - * @dev Subtracts two numbers, returns an error on overflow (i.e. if subtrahend is greater than minuend). - */ - function subUInt(uint a, uint b) internal pure returns (MathError, uint) { - if (b <= a) { - return (MathError.NO_ERROR, a - b); - } else { - return (MathError.INTEGER_UNDERFLOW, 0); - } - } - - /** - * @dev Adds two numbers, returns an error on overflow. - */ - function addUInt(uint a, uint b) internal pure returns (MathError, uint) { - uint c = a + b; - - if (c >= a) { - return (MathError.NO_ERROR, c); - } else { - return (MathError.INTEGER_OVERFLOW, 0); - } - } - - /** - * @dev add a and b and then subtract c - */ - function addThenSubUInt(uint a, uint b, uint c) internal pure returns (MathError, uint) { - (MathError err0, uint sum) = addUInt(a, b); - - if (err0 != MathError.NO_ERROR) { - return (err0, 0); - } - - return subUInt(sum, c); - } -} - - -// Dependency file: contracts/ExponentialNoError.sol - -// pragma solidity 0.8.6; - -/** - * @title Exponential module for storing fixed-precision decimals - * @author tropykus - * @notice Exp is a struct which stores decimals with a fixed precision of 18 decimal places. - * Thus, if we wanted to store the 5.1, mantissa would store 5.1e18. That is: - * `Exp({mantissa: 5100000000000000000})`. - */ -contract ExponentialNoError { - uint constant expScale = 1e18; - uint constant doubleScale = 1e36; - uint constant halfExpScale = expScale/2; - uint constant mantissaOne = expScale; - - struct Exp { - uint mantissa; - } - - struct Double { - uint mantissa; - } - - /** - * @dev Truncates the given exp to a whole number value. - * For example, truncate(Exp{mantissa: 15 * expScale}) = 15 - */ - function truncate(Exp memory exp) pure internal returns (uint) { - // Note: We are not using careful math here as we're performing a division that cannot fail - return exp.mantissa / expScale; - } - - /** - * @dev Multiply an Exp by a scalar, then truncate to return an unsigned integer. - */ - function mul_ScalarTruncate(Exp memory a, uint scalar) pure internal returns (uint) { - Exp memory product = mul_(a, scalar); - return truncate(product); - } - - /** - * @dev Multiply an Exp by a scalar, truncate, then add an to an unsigned integer, returning an unsigned integer. - */ - function mul_ScalarTruncateAddUInt(Exp memory a, uint scalar, uint addend) pure internal returns (uint) { - Exp memory product = mul_(a, scalar); - return add_(truncate(product), addend); - } - - /** - * @dev Checks if first Exp is less than second Exp. - */ - function lessThanExp(Exp memory left, Exp memory right) pure internal returns (bool) { - return left.mantissa < right.mantissa; - } - - /** - * @dev Checks if left Exp <= right Exp. - */ - function lessThanOrEqualExp(Exp memory left, Exp memory right) pure internal returns (bool) { - return left.mantissa <= right.mantissa; - } - - /** - * @dev Checks if left Exp > right Exp. - */ - function greaterThanExp(Exp memory left, Exp memory right) pure internal returns (bool) { - return left.mantissa > right.mantissa; - } - - /** - * @dev returns true if Exp is exactly zero - */ - function isZeroExp(Exp memory value) pure internal returns (bool) { - return value.mantissa == 0; - } - - function safe224(uint n, string memory errorMessage) pure internal returns (uint224) { - require(n < 2**224, errorMessage); - return uint224(n); - } - - function safe32(uint n, string memory errorMessage) pure internal returns (uint32) { - require(n < 2**32, errorMessage); - return uint32(n); - } - - function add_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { - return Exp({mantissa: add_(a.mantissa, b.mantissa)}); - } - - function add_(Double memory a, Double memory b) pure internal returns (Double memory) { - return Double({mantissa: add_(a.mantissa, b.mantissa)}); - } - - function add_(uint a, uint b) pure internal returns (uint) { - return add_(a, b, "addition overflow"); - } - - function add_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { - uint c = a + b; - require(c >= a, errorMessage); - return c; - } - - function sub_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { - return Exp({mantissa: sub_(a.mantissa, b.mantissa)}); - } - - function sub_(Double memory a, Double memory b) pure internal returns (Double memory) { - return Double({mantissa: sub_(a.mantissa, b.mantissa)}); - } - - function sub_(uint a, uint b) pure internal returns (uint) { - return sub_(a, b, "subtraction underflow"); - } - - function sub_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { - require(b <= a, errorMessage); - return a - b; - } - - function mul_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { - return Exp({mantissa: mul_(a.mantissa, b.mantissa) / expScale}); - } - - function mul_(Exp memory a, uint b) pure internal returns (Exp memory) { - return Exp({mantissa: mul_(a.mantissa, b)}); - } - - function mul_(uint a, Exp memory b) pure internal returns (uint) { - return mul_(a, b.mantissa) / expScale; - } - - function mul_(Double memory a, Double memory b) pure internal returns (Double memory) { - return Double({mantissa: mul_(a.mantissa, b.mantissa) / doubleScale}); - } - - function mul_(Double memory a, uint b) pure internal returns (Double memory) { - return Double({mantissa: mul_(a.mantissa, b)}); - } - - function mul_(uint a, Double memory b) pure internal returns (uint) { - return mul_(a, b.mantissa) / doubleScale; - } - - function mul_(uint a, uint b) pure internal returns (uint) { - return mul_(a, b, "multiplication overflow"); - } - - function mul_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { - if (a == 0 || b == 0) { - return 0; - } - uint c = a * b; - require(c / a == b, errorMessage); - return c; - } - - function div_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { - return Exp({mantissa: div_(mul_(a.mantissa, expScale), b.mantissa)}); - } - - function div_(Exp memory a, uint b) pure internal returns (Exp memory) { - return Exp({mantissa: div_(a.mantissa, b)}); - } - - function div_(uint a, Exp memory b) pure internal returns (uint) { - return div_(mul_(a, expScale), b.mantissa); - } - - function div_(Double memory a, Double memory b) pure internal returns (Double memory) { - return Double({mantissa: div_(mul_(a.mantissa, doubleScale), b.mantissa)}); - } - - function div_(Double memory a, uint b) pure internal returns (Double memory) { - return Double({mantissa: div_(a.mantissa, b)}); - } - - function div_(uint a, Double memory b) pure internal returns (uint) { - return div_(mul_(a, doubleScale), b.mantissa); - } - - function div_(uint a, uint b) pure internal returns (uint) { - return div_(a, b, "divide by zero"); - } - - function div_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { - require(b > 0, errorMessage); - return a / b; - } - - function fraction(uint a, uint b) pure internal returns (Double memory) { - return Double({mantissa: div_(mul_(a, doubleScale), b)}); - } -} - - -// Dependency file: contracts/Exponential.sol - -// pragma solidity 0.8.6; - -// import "contracts/CarefulMath.sol"; -// import "contracts/ExponentialNoError.sol"; - -/** - * @title Exponential module for storing fixed-precision decimals - * @author tropykus - * @dev Legacy contract for compatibility reasons with existing contracts that still use MathError - * @notice Exp is a struct which stores decimals with a fixed precision of 18 decimal places. - * Thus, if we wanted to store the 5.1, mantissa would store 5.1e18. That is: - * `Exp({mantissa: 5100000000000000000})`. - */ -contract Exponential is CarefulMath, ExponentialNoError { - /** - * @dev Creates an exponential from numerator and denominator values. - * Note: Returns an error if (`num` * 10e18) > MAX_INT, - * or if `denom` is zero. - */ - function getExp(uint num, uint denom) internal pure returns (MathError, Exp memory) { - (MathError err0, uint scaledNumerator) = mulUInt(num, expScale); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - - (MathError err1, uint rational) = divUInt(scaledNumerator, denom); - if (err1 != MathError.NO_ERROR) { - return (err1, Exp({mantissa: 0})); - } - - return (MathError.NO_ERROR, Exp({mantissa: rational})); - } - - /** - * @dev Adds two exponentials, returning a new exponential. - */ - function addExp(Exp memory a, Exp memory b) internal pure returns (MathError, Exp memory) { - (MathError error, uint result) = addUInt(a.mantissa, b.mantissa); - - return (error, Exp({mantissa: result})); - } - - /** - * @dev Subtracts two exponentials, returning a new exponential. - */ - function subExp(Exp memory a, Exp memory b) internal pure returns (MathError, Exp memory) { - (MathError error, uint result) = subUInt(a.mantissa, b.mantissa); - - return (error, Exp({mantissa: result})); - } - - /** - * @dev Multiply an Exp by a scalar, returning a new Exp. - */ - function mulScalar(Exp memory a, uint scalar) internal pure returns (MathError, Exp memory) { - (MathError err0, uint scaledMantissa) = mulUInt(a.mantissa, scalar); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - - return (MathError.NO_ERROR, Exp({mantissa: scaledMantissa})); - } - - /** - * @dev Multiply an Exp by a scalar, then truncate to return an unsigned integer. - */ - function mulScalarTruncate(Exp memory a, uint scalar) internal pure returns (MathError, uint) { - (MathError err, Exp memory product) = mulScalar(a, scalar); - if (err != MathError.NO_ERROR) { - return (err, 0); - } - - return (MathError.NO_ERROR, truncate(product)); - } - - /** - * @dev Multiply an Exp by a scalar, truncate, then add an to an unsigned integer, returning an unsigned integer. - */ - function mulScalarTruncateAddUInt(Exp memory a, uint scalar, uint addend) internal pure returns (MathError, uint) { - (MathError err, Exp memory product) = mulScalar(a, scalar); - if (err != MathError.NO_ERROR) { - return (err, 0); - } - - return addUInt(truncate(product), addend); - } - - /** - * @dev Divide an Exp by a scalar, returning a new Exp. - */ - function divScalar(Exp memory a, uint scalar) internal pure returns (MathError, Exp memory) { - (MathError err0, uint descaledMantissa) = divUInt(a.mantissa, scalar); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - - return (MathError.NO_ERROR, Exp({mantissa: descaledMantissa})); - } - - /** - * @dev Divide a scalar by an Exp, returning a new Exp. - */ - function divScalarByExp(uint scalar, Exp memory divisor) internal pure returns (MathError, Exp memory) { - /* - We are doing this as: - getExp(mulUInt(expScale, scalar), divisor.mantissa) - - How it works: - Exp = a / b; - Scalar = s; - `s / (a / b)` = `b * s / a` and since for an Exp `a = mantissa, b = expScale` - */ - (MathError err0, uint numerator) = mulUInt(expScale, scalar); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - return getExp(numerator, divisor.mantissa); - } - - /** - * @dev Divide a scalar by an Exp, then truncate to return an unsigned integer. - */ - function divScalarByExpTruncate(uint scalar, Exp memory divisor) internal pure returns (MathError, uint) { - (MathError err, Exp memory fraction) = divScalarByExp(scalar, divisor); - if (err != MathError.NO_ERROR) { - return (err, 0); - } - - return (MathError.NO_ERROR, truncate(fraction)); - } - - /** - * @dev Multiplies two exponentials, returning a new exponential. - */ - function mulExp(Exp memory a, Exp memory b) internal pure returns (MathError, Exp memory) { - - (MathError err0, uint doubleScaledProduct) = mulUInt(a.mantissa, b.mantissa); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - - // We add half the scale before dividing so that we get rounding instead of truncation. - // See "Listing 6" and text above it at https://accu.org/index.php/journals/1717 - // Without this change, a result like 6.6...e-19 will be truncated to 0 instead of being rounded to 1e-18. - (MathError err1, uint doubleScaledProductWithHalfScale) = addUInt(halfExpScale, doubleScaledProduct); - if (err1 != MathError.NO_ERROR) { - return (err1, Exp({mantissa: 0})); - } - - (MathError err2, uint product) = divUInt(doubleScaledProductWithHalfScale, expScale); - // The only error `div` can return is MathError.DIVISION_BY_ZERO but we control `expScale` and it is not zero. - assert(err2 == MathError.NO_ERROR); - - return (MathError.NO_ERROR, Exp({mantissa: product})); - } - - /** - * @dev Multiplies two exponentials given their mantissas, returning a new exponential. - */ - function mulExp(uint a, uint b) internal pure returns (MathError, Exp memory) { - return mulExp(Exp({mantissa: a}), Exp({mantissa: b})); - } - - /** - * @dev Multiplies three exponentials, returning a new exponential. - */ - function mulExp3(Exp memory a, Exp memory b, Exp memory c) internal pure returns (MathError, Exp memory) { - (MathError err, Exp memory ab) = mulExp(a, b); - if (err != MathError.NO_ERROR) { - return (err, ab); - } - return mulExp(ab, c); - } - - /** - * @dev Divides two exponentials, returning a new exponential. - * (a/scale) / (b/scale) = (a/scale) * (scale/b) = a/b, - * which we can scale as an Exp by calling getExp(a.mantissa, b.mantissa) - */ - function divExp(Exp memory a, Exp memory b) internal pure returns (MathError, Exp memory) { - return getExp(a.mantissa, b.mantissa); - } -} - - -// Dependency file: contracts/SafeMath.sol - -// pragma solidity 0.8.6; - -// From https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/math/Math.sol -// Subject to the MIT license. - -/** - * @dev Wrappers over Solidity's arithmetic operations with added overflow - * checks. - * - * Arithmetic operations in Solidity wrap on overflow. This can easily result - * in bugs, because programmers usually assume that an overflow raises an - * error, which is the standard behavior in high level programming languages. - * `SafeMath` restores this intuition by reverting the transaction when an - * operation overflows. - * - * Using this library instead of the unchecked operations eliminates an entire - * class of bugs, so it's recommended to use it always. - */ -library SafeMath { - /** - * @dev Returns the addition of two unsigned integers, reverting on overflow. - * - * Counterpart to Solidity's `+` operator. - * - * Requirements: - * - Addition cannot overflow. - */ - function add(uint256 a, uint256 b) internal pure returns (uint256) { - uint256 c = a + b; - require(c >= a, "SafeMath: addition overflow"); - - return c; - } - - /** - * @dev Returns the addition of two unsigned integers, reverting with custom message on overflow. - * - * Counterpart to Solidity's `+` operator. - * - * Requirements: - * - Addition cannot overflow. - */ - function add(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - uint256 c = a + b; - require(c >= a, errorMessage); - - return c; - } - - /** - * @dev Returns the subtraction of two unsigned integers, reverting on underflow (when the result is negative). - * - * Counterpart to Solidity's `-` operator. - * - * Requirements: - * - Subtraction cannot underflow. - */ - function sub(uint256 a, uint256 b) internal pure returns (uint256) { - return sub(a, b, "SafeMath: subtraction underflow"); - } - - /** - * @dev Returns the subtraction of two unsigned integers, reverting with custom message on underflow (when the result is negative). - * - * Counterpart to Solidity's `-` operator. - * - * Requirements: - * - Subtraction cannot underflow. - */ - function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - require(b <= a, errorMessage); - uint256 c = a - b; - - return c; - } - - /** - * @dev Returns the multiplication of two unsigned integers, reverting on overflow. - * - * Counterpart to Solidity's `*` operator. - * - * Requirements: - * - Multiplication cannot overflow. - */ - function mul(uint256 a, uint256 b) internal pure returns (uint256) { - // Gas optimization: this is cheaper than requiring 'a' not being zero, but the - // benefit is lost if 'b' is also tested. - // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 - if (a == 0) { - return 0; - } - - uint256 c = a * b; - require(c / a == b, "SafeMath: multiplication overflow"); - - return c; - } - - /** - * @dev Returns the multiplication of two unsigned integers, reverting on overflow. - * - * Counterpart to Solidity's `*` operator. - * - * Requirements: - * - Multiplication cannot overflow. - */ - function mul(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - // Gas optimization: this is cheaper than requiring 'a' not being zero, but the - // benefit is lost if 'b' is also tested. - // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 - if (a == 0) { - return 0; - } - - uint256 c = a * b; - require(c / a == b, errorMessage); - - return c; - } - - /** - * @dev Returns the integer division of two unsigned integers. - * Reverts on division by zero. The result is rounded towards zero. - * - * Counterpart to Solidity's `/` operator. Note: this function uses a - * `revert` opcode (which leaves remaining gas untouched) while Solidity - * uses an invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function div(uint256 a, uint256 b) internal pure returns (uint256) { - return div(a, b, "SafeMath: division by zero"); - } - - /** - * @dev Returns the integer division of two unsigned integers. - * Reverts with custom message on division by zero. The result is rounded towards zero. - * - * Counterpart to Solidity's `/` operator. Note: this function uses a - * `revert` opcode (which leaves remaining gas untouched) while Solidity - * uses an invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - // Solidity only automatically asserts when dividing by 0 - require(b > 0, errorMessage); - uint256 c = a / b; - // assert(a == b * c + a % b); // There is no case in which this doesn't hold - - return c; - } - - /** - * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), - * Reverts when dividing by zero. - * - * Counterpart to Solidity's `%` operator. This function uses a `revert` - * opcode (which leaves remaining gas untouched) while Solidity uses an - * invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function mod(uint256 a, uint256 b) internal pure returns (uint256) { - return mod(a, b, "SafeMath: modulo by zero"); - } - - /** - * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), - * Reverts with custom message when dividing by zero. - * - * Counterpart to Solidity's `%` operator. This function uses a `revert` - * opcode (which leaves remaining gas untouched) while Solidity uses an - * invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - require(b != 0, errorMessage); - return a % b; - } -} - - -// Dependency file: contracts/InterestRateModel.sol - -// pragma solidity 0.8.6; - -// import "contracts/Exponential.sol"; -// import "contracts/SafeMath.sol"; - -/** - * @title tropykus InterestRateModel Interface - * @author tropykus - */ -abstract contract InterestRateModel is Exponential { - using SafeMath for uint256; - - /// @notice Indicator that this is an InterestRateModel contract (for inspection) - bool public constant isInterestRateModel = true; - bool public isTropykusInterestRateModel; - - /** - * @notice The approximate number of blocks per year that is assumed by the interest rate model - */ - uint256 public constant blocksPerYear = 1051200; - - /** - * @notice Calculates the utilization rate of the market: `borrows / (cash + borrows - reserves)` - * @param cash The amount of cash in the market - * @param borrows The amount of borrows in the market - * @param reserves The amount of reserves in the market (currently unused) - * @return The utilization rate as a mantissa between [0, 1e18] - */ - function utilizationRate( - uint256 cash, - uint256 borrows, - uint256 reserves - ) public pure virtual returns (uint256) { - // Utilization rate is 0 when there are no borrows - if (borrows == 0) { - return 0; - } - - return borrows.mul(1e18).div(cash.add(borrows).sub(reserves)); - } - - /** - * @notice Calculates the current borrow interest rate per block - * @param cash The total amount of cash the market has - * @param borrows The total amount of borrows the market has outstanding - * @param reserves The total amnount of reserves the market has - * @return The borrow rate per block (as a percentage, and scaled by 1e18) - */ - function getBorrowRate( - uint256 cash, - uint256 borrows, - uint256 reserves - ) external view virtual returns (uint256); - - /** - * @notice Calculates the current supply interest rate per block - * @param cash The total amount of cash the market has - * @param borrows The total amount of borrows the market has outstanding - * @param reserves The total amnount of reserves the market has - * @param reserveFactorMantissa The current reserve factor the market has - * @return The supply rate per block (as a percentage, and scaled by 1e18) - */ - function getSupplyRate( - uint256 cash, - uint256 borrows, - uint256 reserves, - uint256 reserveFactorMantissa - ) external view virtual returns (uint256); - - function getExchangeRate( - uint256 _totalCash, - uint256 _totalBorrows, - uint256 _totalReserves, - uint256 _totalSupply - ) public pure returns (MathError, uint256) { - /* - * exchangeRate = (totalCash + totalBorrows - totalReserves) / totalSupply - */ - Exp memory exchangeRate; - MathError mathErr; - uint256 cashPlusBorrowsMinusReserves; - (mathErr, cashPlusBorrowsMinusReserves) = addThenSubUInt( - _totalCash, - _totalBorrows, - _totalReserves - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - (mathErr, exchangeRate) = getExp( - cashPlusBorrowsMinusReserves, - _totalSupply - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - - return (MathError.NO_ERROR, exchangeRate.mantissa); - } - - function isAboveOptimal( - uint256 cash, - uint256 borrows, - uint256 reserves - ) public view virtual returns (bool) { - cash; - borrows; - reserves; - return false; - } -} - - -// Dependency file: contracts/EIP20NonStandardInterface.sol - -// pragma solidity 0.8.6; - -/** - * @title EIP20NonStandardInterface - * @dev Version of ERC20 with no return values for `transfer` and `transferFrom` - * See https://medium.com/coinmonks/missing-return-value-bug-at-least-130-tokens-affected-d67bf08521ca - */ -interface EIP20NonStandardInterface { - /** - * @notice Get the total number of tokens in circulation - * @return The supply of tokens - */ - function totalSupply() external view returns (uint256); - - /** - * @notice Gets the balance of the specified address - * @param owner The address from which the balance will be retrieved - * @return balance The balance - */ - function balanceOf(address owner) external view returns (uint256 balance); - - /// - /// !!!!!!!!!!!!!! - /// !!! NOTICE !!! `transfer` does not return a value, in violation of the ERC-20 specification - /// !!!!!!!!!!!!!! - /// - - /** - * @notice Transfer `amount` tokens from `msg.sender` to `dst` - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - */ - function transfer(address dst, uint256 amount) external; - - /// - /// !!!!!!!!!!!!!! - /// !!! NOTICE !!! `transferFrom` does not return a value, in violation of the ERC-20 specification - /// !!!!!!!!!!!!!! - /// - - /** - * @notice Transfer `amount` tokens from `src` to `dst` - * @param src The address of the source account - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - */ - function transferFrom( - address src, - address dst, - uint256 amount - ) external; - - /** - * @notice Approve `spender` to transfer up to `amount` from `src` - * @dev This will overwrite the approval amount for `spender` - * and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve) - * @param spender The address of the account which may transfer tokens - * @param amount The number of tokens that are approved - * @return success Whether or not the approval succeeded - */ - function approve(address spender, uint256 amount) - external - returns (bool success); - - /** - * @notice Get the current allowance from `owner` for `spender` - * @param owner The address of the account which owns the tokens to be spent - * @param spender The address of the account which may transfer tokens - * @return remaining The number of tokens allowed to be spent - */ - function allowance(address owner, address spender) - external - view - returns (uint256 remaining); - - event Transfer(address indexed from, address indexed to, uint256 amount); - event Approval( - address indexed owner, - address indexed spender, - uint256 amount - ); -} - - -// Dependency file: contracts/CTokenInterfaces.sol - -// pragma solidity 0.8.6; - -// import "contracts/ComptrollerInterface.sol"; -// import "contracts/InterestRateModel.sol"; -// import "contracts/EIP20NonStandardInterface.sol"; - -contract CTokenStorage { - /** - * @dev Guard variable for re-entrancy checks - */ - bool internal _notEntered; - - /** - * @notice EIP-20 token name for this token - */ - string public name; - - /** - * @notice EIP-20 token symbol for this token - */ - string public symbol; - - /** - * @notice EIP-20 token decimals for this token - */ - uint8 public decimals; - - /** - * @notice Maximum borrow rate that can ever be applied (.0005% / block) - */ - - uint256 internal constant borrowRateMaxMantissa = 0.0005e16; - - /** - * @notice Maximum fraction of interest that can be set aside for reserves - */ - uint256 internal constant reserveFactorMaxMantissa = 1e18; - - /** - * @notice Administrator for this contract - */ - address payable public admin; - - /** - * @notice Pending administrator for this contract - */ - address payable public pendingAdmin; - - /** - * @notice Contract which oversees inter-cToken operations - */ - ComptrollerInterface public comptroller; - - /** - * @notice Model which tells what the current interest rate should be - */ - InterestRateModel public interestRateModel; - - /** - * @notice Initial exchange rate used when minting the first CTokens (used when totalSupply = 0) - */ - uint256 public initialExchangeRateMantissa; - - /** - * @notice Fraction of interest currently set aside for reserves - */ - uint256 public reserveFactorMantissa; - - /** - * @notice Block number that interest was last accrued at - */ - uint256 public accrualBlockNumber; - - /** - * @notice Accumulator of the total earned interest rate since the opening of the market - */ - uint256 public borrowIndex; - - /** - * @notice Total amount of outstanding borrows of the underlying in this market - */ - uint256 public totalBorrows; - - /** - * @notice Total amount of reserves of the underlying held in this market - */ - uint256 public totalReserves; - - /** - * @notice Total number of tokens in circulation - */ - uint256 public totalSupply; - - uint256 public subsidyFund; - - struct SupplySnapshot { - uint256 tokens; - uint256 underlyingAmount; - uint256 suppliedAt; - uint256 promisedSupplyRate; - } - - /** - * @notice Official record of token balances for each account - */ - mapping(address => SupplySnapshot) internal accountTokens; - - /** - * @notice Approved token transfer amounts on behalf of others - */ - mapping(address => mapping(address => uint256)) internal transferAllowances; - - /** - * @notice Container for borrow balance information - * @member principal Total balance (with accrued interest), after applying the most recent balance-changing action - * @member interestIndex Global borrowIndex as of the most recent balance-changing action - */ - struct BorrowSnapshot { - uint256 principal; - uint256 interestIndex; - } - - /** - * @notice Mapping of account addresses to outstanding borrow balances - */ - mapping(address => BorrowSnapshot) internal accountBorrows; -} - -abstract contract CTokenInterface is CTokenStorage { - /** - * @notice Indicator that this is a CToken contract (for inspection) - */ - bool public constant isCToken = true; - - /*** Market Events ***/ - - /** - * @notice Event emitted when interest is accrued - */ - event AccrueInterest( - uint256 cashPrior, - uint256 interestAccumulated, - uint256 borrowIndex, - uint256 totalBorrows - ); - - /** - * @notice Event emitted when tokens are minted - */ - event Mint(address indexed minter, uint256 mintAmount, uint256 mintTokens); - - /** - * @notice Event emitted when tokens are redeemed - */ - event Redeem( - address indexed redeemer, - uint256 redeemAmount, - uint256 redeemTokens - ); - - /** - * @notice Event emitted when underlying is borrowed - */ - event Borrow( - address indexed borrower, - uint256 borrowAmount, - uint256 accountBorrows, - uint256 totalBorrows - ); - - /** - * @notice Event emitted when a borrow is repaid - */ - event RepayBorrow( - address indexed payer, - address indexed borrower, - uint256 repayAmount, - uint256 accountBorrows, - uint256 totalBorrows - ); - - /** - * @notice Event emitted when a borrow is liquidated - */ - event LiquidateBorrow( - address indexed liquidator, - address indexed borrower, - uint256 repayAmount, - address indexed cTokenCollateral, - uint256 seizeTokens - ); - - /*** Admin Events ***/ - - /** - * @notice Event emitted when pendingAdmin is changed - */ - event NewPendingAdmin(address oldPendingAdmin, address newPendingAdmin); - - /** - * @notice Event emitted when pendingAdmin is accepted, which means admin is updated - */ - event NewAdmin(address oldAdmin, address newAdmin); - - /** - * @notice Event emitted when comptroller is changed - */ - event NewComptroller( - ComptrollerInterface oldComptroller, - ComptrollerInterface newComptroller - ); - - /** - * @notice Event emitted when interestRateModel is changed - */ - event NewMarketInterestRateModel( - InterestRateModel oldInterestRateModel, - InterestRateModel newInterestRateModel - ); - - /** - * @notice Event emitted when the reserve factor is changed - */ - event NewReserveFactor( - uint256 oldReserveFactorMantissa, - uint256 newReserveFactorMantissa - ); - - /** - * @notice Event emitted when the reserves are added - */ - event ReservesAdded( - address benefactor, - uint256 addAmount, - uint256 newTotalReserves - ); - - event SubsidyAdded( - address benefactor, - uint256 addAmount, - uint256 newSubsidyFund - ); - - /** - * @notice Event emitted when the reserves are reduced - */ - event ReservesReduced( - address admin, - uint256 reduceAmount, - uint256 newTotalReserves - ); - - /** - * @notice EIP20 Transfer event - */ - event Transfer(address indexed from, address indexed to, uint256 amount); - - /** - * @notice EIP20 Approval event - */ - event Approval( - address indexed owner, - address indexed spender, - uint256 amount - ); - - /** - * @notice Failure event - */ - event CTokenStorageFailure(uint256 error, uint256 info, uint256 detail); - - /*** User Interface ***/ - - function transfer(address dst, uint256 amount) - external - virtual - returns (bool); - - function transferFrom( - address src, - address dst, - uint256 amount - ) external virtual returns (bool); - - function approve(address spender, uint256 amount) - external - virtual - returns (bool); - - function allowance(address owner, address spender) - external - view - virtual - returns (uint256); - - function balanceOf(address owner) external view virtual returns (uint256); - - function balanceOfUnderlying(address owner) - external - virtual - returns (uint256); - - function getAccountSnapshot(address account) - external - view - virtual - returns ( - uint256, - uint256, - uint256, - uint256 - ); - - function borrowRatePerBlock() external view virtual returns (uint256); - - function supplyRatePerBlock() external view virtual returns (uint256); - - function totalBorrowsCurrent() external virtual returns (uint256); - - function borrowBalanceCurrent(address account) - external - virtual - returns (uint256); - - function borrowBalanceStored(address account) - public - view - virtual - returns (uint256); - - function exchangeRateCurrent() public virtual returns (uint256); - - function exchangeRateStored() public view virtual returns (uint256); - - function getCash() external view virtual returns (uint256); - - function accrueInterest() public virtual returns (uint256); - - function seize( - address liquidator, - address borrower, - uint256 seizeTokens - ) external virtual returns (uint256); - - /*** Admin Functions ***/ - - function _setPendingAdmin(address payable newPendingAdmin) - external - virtual - returns (uint256); - - function _acceptAdmin() external virtual returns (uint256); - - function _setComptroller(ComptrollerInterface newComptroller) - public - virtual - returns (uint256); - - function _setReserveFactor(uint256 newReserveFactorMantissa) - external - virtual - returns (uint256); - - function _reduceReserves(uint256 reduceAmount) - external - virtual - returns (uint256); - - function _setInterestRateModel(InterestRateModel newInterestRateModel) - public - virtual - returns (uint256); -} - -contract CErc20Storage { - /** - * @notice Underlying asset for this CToken - */ - address public underlying; -} - -abstract contract CErc20Interface is CErc20Storage { - /*** User Interface ***/ - - function mint(uint256 mintAmount) external virtual returns (uint256); - - function redeem(uint256 redeemAmount) - external - virtual - returns (uint256); - - function borrow(uint256 borrowAmount) external virtual returns (uint256); - - function repayBorrow(uint256 repayAmount) - external - virtual - returns (uint256); - - function liquidateBorrow( - address borrower, - uint256 repayAmount, - CTokenInterface cTokenCollateral - ) external virtual returns (uint256); - - function sweepToken(EIP20NonStandardInterface token) external virtual; - - /*** Admin Functions ***/ - - function _addReserves(uint256 addAmount) external virtual returns (uint256); -} - -contract CDelegationStorage { - /** - * @notice Implementation address for this contract - */ - address public implementation; -} - -abstract contract CDelegatorInterface is CDelegationStorage { - /** - * @notice Emitted when implementation is changed - */ - event NewImplementation( - address oldImplementation, - address newImplementation - ); - - /** - * @notice Called by the admin to update the implementation of the delegator - * @param implementation_ The address of the new implementation for delegation - * @param allowResign Flag to indicate whether to call _resignImplementation on the old implementation - * @param becomeImplementationData The encoded bytes data to be passed to _becomeImplementation - */ - function _setImplementation( - address implementation_, - bool allowResign, - bytes memory becomeImplementationData - ) public virtual; -} - -abstract contract CDelegateInterface is CDelegationStorage { - /** - * @notice Called by the delegator on a delegate to initialize it for duty - * @dev Should revert if any issues arise which make it unfit for delegation - * @param data The encoded bytes data for any initialization - */ - function _becomeImplementation(bytes memory data) public virtual; - - /** - * @notice Called by the delegator on a delegate to forfeit its responsibility - */ - function _resignImplementation() public virtual; -} - - -// Dependency file: contracts/ErrorReporter.sol - -// pragma solidity 0.8.6; - -contract ComptrollerErrorReporter { - enum Error { - NO_ERROR, - UNAUTHORIZED, - COMPTROLLER_MISMATCH, - INSUFFICIENT_SHORTFALL, - INSUFFICIENT_LIQUIDITY, - INVALID_CLOSE_FACTOR, - INVALID_COLLATERAL_FACTOR, - INVALID_LIQUIDATION_INCENTIVE, - MARKET_NOT_ENTERED, // no longer possible - MARKET_NOT_LISTED, - MARKET_ALREADY_LISTED, - MATH_ERROR, - NONZERO_BORROW_BALANCE, - PRICE_ERROR, - REJECTION, - SNAPSHOT_ERROR, - TOO_MANY_ASSETS, - TOO_MUCH_REPAY - } - - enum FailureInfo { - ACCEPT_ADMIN_PENDING_ADMIN_CHECK, - ACCEPT_PENDING_IMPLEMENTATION_ADDRESS_CHECK, - EXIT_MARKET_BALANCE_OWED, - EXIT_MARKET_REJECTION, - SET_CLOSE_FACTOR_OWNER_CHECK, - SET_CLOSE_FACTOR_VALIDATION, - SET_COLLATERAL_FACTOR_OWNER_CHECK, - SET_COLLATERAL_FACTOR_NO_EXISTS, - SET_COLLATERAL_FACTOR_VALIDATION, - SET_COLLATERAL_FACTOR_WITHOUT_PRICE, - SET_IMPLEMENTATION_OWNER_CHECK, - SET_LIQUIDATION_INCENTIVE_OWNER_CHECK, - SET_LIQUIDATION_INCENTIVE_VALIDATION, - SET_MAX_ASSETS_OWNER_CHECK, - SET_PENDING_ADMIN_OWNER_CHECK, - SET_PENDING_IMPLEMENTATION_OWNER_CHECK, - SET_PRICE_ORACLE_OWNER_CHECK, - SUPPORT_MARKET_EXISTS, - SUPPORT_MARKET_OWNER_CHECK, - SET_PAUSE_GUARDIAN_OWNER_CHECK - } - - /** - * @dev `error` corresponds to enum Error; `info` corresponds to enum FailureInfo, and `detail` is an arbitrary - * contract-specific code that enables us to report opaque error codes from upgradeable contracts. - **/ - event Failure(uint256 error, uint256 info, uint256 detail); - - /** - * @dev use this when reporting a known error from the money market or a non-upgradeable collaborator - */ - function fail(Error err, FailureInfo info) internal returns (uint256) { - emit Failure(uint256(err), uint256(info), 0); - - return uint256(err); - } - - /** - * @dev use this when reporting an opaque error from an upgradeable collaborator contract - */ - function failOpaque( - Error err, - FailureInfo info, - uint256 opaqueError - ) internal returns (uint256) { - emit Failure(uint256(err), uint256(info), opaqueError); - - return uint256(err); - } -} - -contract TokenErrorReporter { - enum Error { - NO_ERROR, - UNAUTHORIZED, - BAD_INPUT, - COMPTROLLER_REJECTION, - COMPTROLLER_CALCULATION_ERROR, - INTEREST_RATE_MODEL_ERROR, - INVALID_ACCOUNT_PAIR, - INVALID_CLOSE_AMOUNT_REQUESTED, - INVALID_COLLATERAL_FACTOR, - MATH_ERROR, - MARKET_NOT_FRESH, - MARKET_NOT_LISTED, - TOKEN_INSUFFICIENT_ALLOWANCE, - TOKEN_INSUFFICIENT_BALANCE, - TOKEN_INSUFFICIENT_CASH, - TOKEN_TRANSFER_IN_FAILED, - TOKEN_TRANSFER_OUT_FAILED - } - - /* - * Note: FailureInfo (but not Error) is kept in alphabetical order - * This is because FailureInfo grows significantly faster, and - * the order of Error has some meaning, while the order of FailureInfo - * is entirely arbitrary. - */ - enum FailureInfo { - ACCEPT_ADMIN_PENDING_ADMIN_CHECK, - ACCRUE_INTEREST_ACCUMULATED_INTEREST_CALCULATION_FAILED, - ACCRUE_INTEREST_BORROW_RATE_CALCULATION_FAILED, - ACCRUE_INTEREST_NEW_BORROW_INDEX_CALCULATION_FAILED, - ACCRUE_INTEREST_NEW_TOTAL_BORROWS_CALCULATION_FAILED, - ACCRUE_INTEREST_NEW_TOTAL_RESERVES_CALCULATION_FAILED, - ACCRUE_INTEREST_SIMPLE_INTEREST_FACTOR_CALCULATION_FAILED, - BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED, - BORROW_ACCRUE_INTEREST_FAILED, - BORROW_CASH_NOT_AVAILABLE, - BORROW_FRESHNESS_CHECK, - BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED, - BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED, - BORROW_MARKET_NOT_LISTED, - BORROW_COMPTROLLER_REJECTION, - LIQUIDATE_ACCRUE_BORROW_INTEREST_FAILED, - LIQUIDATE_ACCRUE_COLLATERAL_INTEREST_FAILED, - LIQUIDATE_COLLATERAL_FRESHNESS_CHECK, - LIQUIDATE_COMPTROLLER_REJECTION, - LIQUIDATE_COMPTROLLER_CALCULATE_AMOUNT_SEIZE_FAILED, - LIQUIDATE_CLOSE_AMOUNT_IS_UINT_MAX, - LIQUIDATE_CLOSE_AMOUNT_IS_ZERO, - LIQUIDATE_FRESHNESS_CHECK, - LIQUIDATE_LIQUIDATOR_IS_BORROWER, - LIQUIDATE_REPAY_BORROW_FRESH_FAILED, - LIQUIDATE_SEIZE_BALANCE_INCREMENT_FAILED, - LIQUIDATE_SEIZE_BALANCE_DECREMENT_FAILED, - LIQUIDATE_SEIZE_COMPTROLLER_REJECTION, - LIQUIDATE_SEIZE_LIQUIDATOR_IS_BORROWER, - LIQUIDATE_SEIZE_TOO_MUCH, - MINT_ACCRUE_INTEREST_FAILED, - MINT_COMPTROLLER_REJECTION, - MINT_EXCHANGE_CALCULATION_FAILED, - MINT_EXCHANGE_RATE_READ_FAILED, - MINT_FRESHNESS_CHECK, - MINT_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED, - MINT_NEW_TOTAL_SUPPLY_CALCULATION_FAILED, - MINT_TRANSFER_IN_FAILED, - MINT_TRANSFER_IN_NOT_POSSIBLE, - REDEEM_ACCRUE_INTEREST_FAILED, - REDEEM_COMPTROLLER_REJECTION, - REDEEM_EXCHANGE_TOKENS_CALCULATION_FAILED, - REDEEM_EXCHANGE_AMOUNT_CALCULATION_FAILED, - REDEEM_EXCHANGE_RATE_READ_FAILED, - REDEEM_FRESHNESS_CHECK, - REDEEM_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED, - REDEEM_NEW_TOTAL_SUPPLY_CALCULATION_FAILED, - REDEEM_TRANSFER_OUT_NOT_POSSIBLE, - REDUCE_RESERVES_ACCRUE_INTEREST_FAILED, - REDUCE_RESERVES_ADMIN_CHECK, - REDUCE_RESERVES_CASH_NOT_AVAILABLE, - REDUCE_RESERVES_FRESH_CHECK, - REDUCE_RESERVES_VALIDATION, - REPAY_BEHALF_ACCRUE_INTEREST_FAILED, - REPAY_BORROW_ACCRUE_INTEREST_FAILED, - REPAY_BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED, - REPAY_BORROW_COMPTROLLER_REJECTION, - REPAY_BORROW_FRESHNESS_CHECK, - REPAY_BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED, - REPAY_BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED, - REPAY_BORROW_TRANSFER_IN_NOT_POSSIBLE, - SET_COLLATERAL_FACTOR_OWNER_CHECK, - SET_COLLATERAL_FACTOR_VALIDATION, - SET_COMPTROLLER_OWNER_CHECK, - SET_INTEREST_RATE_MODEL_ACCRUE_INTEREST_FAILED, - SET_INTEREST_RATE_MODEL_FRESH_CHECK, - SET_INTEREST_RATE_MODEL_OWNER_CHECK, - SET_MAX_ASSETS_OWNER_CHECK, - SET_ORACLE_MARKET_NOT_LISTED, - SET_PENDING_ADMIN_OWNER_CHECK, - SET_RESERVE_FACTOR_ACCRUE_INTEREST_FAILED, - SET_RESERVE_FACTOR_ADMIN_CHECK, - SET_RESERVE_FACTOR_FRESH_CHECK, - SET_RESERVE_FACTOR_BOUNDS_CHECK, - TRANSFER_COMPTROLLER_REJECTION, - TRANSFER_NOT_ALLOWED, - TRANSFER_NOT_ENOUGH, - TRANSFER_TOO_MUCH, - ADD_RESERVES_ACCRUE_INTEREST_FAILED, - ADD_RESERVES_FRESH_CHECK, - ADD_RESERVES_TRANSFER_IN_NOT_POSSIBLE, - ADD_SUBSIDY_FUND_FAILED, - ADD_SUBSIDY_FUND_FRESH_CHECK - } - - /** - * @dev `error` corresponds to enum Error; `info` corresponds to enum FailureInfo, and `detail` is an arbitrary - * contract-specific code that enables us to report opaque error codes from upgradeable contracts. - **/ - event TokenFailure(uint256 error, uint256 info, uint256 detail); - - /** - * @dev use this when reporting a known error from the money market or a non-upgradeable collaborator - */ - function fail(Error err, FailureInfo info) internal returns (uint256) { - emit TokenFailure(uint256(err), uint256(info), 0); - - return uint256(err); - } - - /** - * @dev use this when reporting an opaque error from an upgradeable collaborator contract - */ - function failOpaque( - Error err, - FailureInfo info, - uint256 opaqueError - ) internal returns (uint256) { - emit TokenFailure(uint256(err), uint256(info), opaqueError); - - return uint256(err); - } -} - - -// Dependency file: contracts/EIP20Interface.sol - -// pragma solidity 0.8.6; - -/** - * @title ERC 20 Token Standard Interface - * https://eips.ethereum.org/EIPS/eip-20 - */ -interface EIP20Interface { - function name() external view returns (string memory); - - function symbol() external view returns (string memory); - - function decimals() external view returns (uint8); - - /** - * @notice Get the total number of tokens in circulation - * @return The supply of tokens - */ - function totalSupply() external view returns (uint256); - - /** - * @notice Gets the balance of the specified address - * @param owner The address from which the balance will be retrieved - * @return balance The balance - */ - function balanceOf(address owner) external view returns (uint256 balance); - - /** - * @notice Transfer `amount` tokens from `msg.sender` to `dst` - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - * @return success Whether or not the transfer succeeded - */ - function transfer(address dst, uint256 amount) - external - returns (bool success); - - /** - * @notice Transfer `amount` tokens from `src` to `dst` - * @param src The address of the source account - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - * @return success Whether or not the transfer succeeded - */ - function transferFrom( - address src, - address dst, - uint256 amount - ) external returns (bool success); - - /** - * @notice Approve `spender` to transfer up to `amount` from `src` - * @dev This will overwrite the approval amount for `spender` - * and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve) - * @param spender The address of the account which may transfer tokens - * @param amount The number of tokens that are approved (-1 means infinite) - * @return success Whether or not the approval succeeded - */ - function approve(address spender, uint256 amount) - external - returns (bool success); - - /** - * @notice Get the current allowance from `owner` for `spender` - * @param owner The address of the account which owns the tokens to be spent - * @param spender The address of the account which may transfer tokens - * @return remaining The number of tokens allowed to be spent (-1 means infinite) - */ - function allowance(address owner, address spender) - external - view - returns (uint256 remaining); - - event Transfer(address indexed from, address indexed to, uint256 amount); - event Approval( - address indexed owner, - address indexed spender, - uint256 amount - ); -} - - -// Dependency file: contracts/WhitelistInterface.sol - -// pragma solidity 0.8.6; - -interface WhitelistInterface { - function setStatus(bool _newStatus) external; - function enabled() external view returns(bool); - - function addUsers(address[] memory _users) external; - function exist(address _user) external view returns(bool); - function getUsers() external view returns(address[] memory currentUsers); - function removeUser(address _user) external; -} - -// Dependency file: contracts/CToken.sol - -// pragma solidity 0.8.6; - -// import "contracts/ComptrollerInterface.sol"; -// import "contracts/CTokenInterfaces.sol"; -// import "contracts/ErrorReporter.sol"; -// import "contracts/Exponential.sol"; -// import "contracts/EIP20Interface.sol"; -// import "contracts/InterestRateModel.sol"; -// import "contracts/WhitelistInterface.sol"; - -/** - * @title tropykus CToken Contract - * @notice Abstract base for CTokens - * @author tropykus - */ -abstract contract CToken is CTokenInterface, Exponential, TokenErrorReporter { - address whitelist; - - /** - * @notice Initialize the money market - * @param comptroller_ The address of the Comptroller - * @param interestRateModel_ The address of the interest rate model - * @param initialExchangeRateMantissa_ The initial exchange rate, scaled by 1e18 - * @param name_ EIP-20 name of this token - * @param symbol_ EIP-20 symbol of this token - * @param decimals_ EIP-20 decimal precision of this token - */ - function initialize( - ComptrollerInterface comptroller_, - InterestRateModel interestRateModel_, - uint256 initialExchangeRateMantissa_, - string memory name_, - string memory symbol_, - uint8 decimals_ - ) public { - require(msg.sender == admin, "CT01"); - require(accrualBlockNumber == 0 && borrowIndex == 0, "CT02"); - - initialExchangeRateMantissa = initialExchangeRateMantissa_; - require(initialExchangeRateMantissa > 0, "CT03"); - - uint256 err = _setComptroller(comptroller_); - require(err == uint256(Error.NO_ERROR), "CT04"); - - accrualBlockNumber = getBlockNumber(); - borrowIndex = mantissaOne; - - err = _setInterestRateModelFresh(interestRateModel_); - require(err == uint256(Error.NO_ERROR), "CT05"); - - name = name_; - symbol = symbol_; - decimals = decimals_; - - _notEntered = true; - } - - function addWhitelist(address _whitelist) external returns (uint256) { - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_INTEREST_RATE_MODEL_OWNER_CHECK - ); - } - whitelist = _whitelist; - } - - /** - * @notice Transfer `tokens` tokens from `src` to `dst` by `spender` - * @dev Called by both `transfer` and `transferFrom` internally - * @param spender The address of the account performing the transfer - * @param src The address of the source account - * @param dst The address of the destination account - * @param tokens The number of tokens to transfer - * @return Whether or not the transfer succeeded - */ - function transferTokens( - address spender, - address src, - address dst, - uint256 tokens - ) internal returns (uint256) { - uint256 allowed = comptroller.transferAllowed( - address(this), - src, - dst, - tokens - ); - if (allowed != 0) { - return - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.TRANSFER_COMPTROLLER_REJECTION, - allowed - ); - } - - if (src == dst) { - return fail(Error.BAD_INPUT, FailureInfo.TRANSFER_NOT_ALLOWED); - } - - uint256 startingAllowance = 0; - if (spender == src) { - startingAllowance = type(uint256).max; - } else { - startingAllowance = transferAllowances[src][spender]; - } - - MathError mathErr; - uint256 allowanceNew; - uint256 srcTokensNew; - uint256 dstTokensNew; - - (mathErr, allowanceNew) = subUInt(startingAllowance, tokens); - if (mathErr != MathError.NO_ERROR) { - return fail(Error.MATH_ERROR, FailureInfo.TRANSFER_NOT_ALLOWED); - } - - (mathErr, srcTokensNew) = subUInt(accountTokens[src].tokens, tokens); - if (mathErr != MathError.NO_ERROR) { - return fail(Error.MATH_ERROR, FailureInfo.TRANSFER_NOT_ENOUGH); - } - - (mathErr, dstTokensNew) = addUInt(accountTokens[dst].tokens, tokens); - if (mathErr != MathError.NO_ERROR) { - return fail(Error.MATH_ERROR, FailureInfo.TRANSFER_TOO_MUCH); - } - - accountTokens[src].tokens = srcTokensNew; - accountTokens[dst].tokens = dstTokensNew; - - if (startingAllowance != type(uint256).max) { - transferAllowances[src][spender] = allowanceNew; - } - - emit Transfer(src, dst, tokens); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Transfer `amount` tokens from `msg.sender` to `dst` - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - * @return Whether or not the transfer succeeded - */ - function transfer(address dst, uint256 amount) - external - override - nonReentrant - returns (bool) - { - return - transferTokens(msg.sender, msg.sender, dst, amount) == - uint256(Error.NO_ERROR); - } - - /** - * @notice Transfer `amount` tokens from `src` to `dst` - * @param src The address of the source account - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - * @return Whether or not the transfer succeeded - */ - function transferFrom( - address src, - address dst, - uint256 amount - ) external override nonReentrant returns (bool) { - return - transferTokens(msg.sender, src, dst, amount) == - uint256(Error.NO_ERROR); - } - - /** - * @notice Approve `spender` to transfer up to `amount` from `src` - * @dev This will overwrite the approval amount for `spender` - * and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve) - * @param spender The address of the account which may transfer tokens - * @param amount The number of tokens that are approved (-1 means infinite) - * @return Whether or not the approval succeeded - */ - function approve(address spender, uint256 amount) - external - override - returns (bool) - { - transferAllowances[msg.sender][spender] = amount; - emit Approval(msg.sender, spender, amount); - return true; - } - - /** - * @notice Get the current allowance from `owner` for `spender` - * @param owner The address of the account which owns the tokens to be spent - * @param spender The address of the account which may transfer tokens - * @return The number of tokens allowed to be spent (-1 means infinite) - */ - function allowance(address owner, address spender) - external - view - override - returns (uint256) - { - return transferAllowances[owner][spender]; - } - - /** - * @notice Get the token balance of the `owner` - * @param owner The address of the account to query - * @return The number of tokens owned by `owner` - */ - function balanceOf(address owner) external view override returns (uint256) { - return accountTokens[owner].tokens; - } - - /** - * @notice Get the underlying balance of the `owner` - * @dev This also accrues interest in a transaction - * @param owner The address of the account to query - * @return The amount of underlying owned by `owner` - */ - function balanceOfUnderlying(address owner) - external - override - returns (uint256) - { - (MathError mErr, uint256 balance) = mulScalarTruncate( - Exp({mantissa: exchangeRateCurrent()}), - accountTokens[owner].tokens - ); - require(mErr == MathError.NO_ERROR, "CT06"); - return balance; - } - - /** - * @notice Get a snapshot of the account's balances, and the cached exchange rate - * @dev This is used by comptroller to more efficiently perform liquidity checks. - * @param account Address of the account to snapshot - * @return (possible error, token balance, borrow balance, exchange rate mantissa) - */ - function getAccountSnapshot(address account) - external - view - override - returns ( - uint256, - uint256, - uint256, - uint256 - ) - { - uint256 cTokenBalance = accountTokens[account].tokens; - uint256 borrowBalance; - uint256 exchangeRateMantissa; - - MathError mErr; - - (mErr, borrowBalance) = borrowBalanceStoredInternal(account); - if (mErr != MathError.NO_ERROR) { - return (uint256(Error.MATH_ERROR), 0, 0, 0); - } - - (mErr, exchangeRateMantissa) = exchangeRateStoredInternal(); - if (mErr != MathError.NO_ERROR) { - return (uint256(Error.MATH_ERROR), 0, 0, 0); - } - - return ( - uint256(Error.NO_ERROR), - cTokenBalance, - borrowBalance, - exchangeRateMantissa - ); - } - - /** - * @dev Function to simply retrieve block number - * This exists mainly for inheriting test contracts to stub this result. - */ - function getBlockNumber() internal view virtual returns (uint256) { - return block.number; - } - - /** - * @notice Returns the current per-block borrow interest rate for this cToken - * @return The borrow interest rate per block, scaled by 1e18 - */ - function borrowRatePerBlock() external view override returns (uint256) { - return - interestRateModel.getBorrowRate( - getCashPrior(), - totalBorrows, - totalReserves - ); - } - - /** - * @notice Returns the current per-block supply interest rate for this cToken - * @return The supply interest rate per block, scaled by 1e18 - */ - function supplyRatePerBlock() external view override returns (uint256) { - return - interestRateModel.getSupplyRate( - getCashPrior(), - totalBorrows, - totalReserves, - reserveFactorMantissa - ); - } - - /** - * @notice Returns the current total borrows plus accrued interest - * @return The total borrows with interest - */ - function totalBorrowsCurrent() - external - override - nonReentrant - returns (uint256) - { - require(accrueInterest() == uint256(Error.NO_ERROR), "CT07"); - return totalBorrows; - } - - /** - * @notice Accrue interest to updated borrowIndex and then calculate account's borrow balance using the updated borrowIndex - * @param account The address whose balance should be calculated after updating borrowIndex - * @return The calculated balance - */ - function borrowBalanceCurrent(address account) - external - override - nonReentrant - returns (uint256) - { - require(accrueInterest() == uint256(Error.NO_ERROR), "CT07"); - return borrowBalanceStored(account); - } - - /** - * @notice Return the borrow balance of account based on stored data - * @param account The address whose balance should be calculated - * @return The calculated balance - */ - function borrowBalanceStored(address account) - public - view - override - returns (uint256) - { - (MathError err, uint256 result) = borrowBalanceStoredInternal(account); - require(err == MathError.NO_ERROR, "CT08"); - return result; - } - - /** - * @notice Return the borrow balance of account based on stored data - * @param account The address whose balance should be calculated - * @return (error code, the calculated balance or 0 if error code is non-zero) - */ - function borrowBalanceStoredInternal(address account) - internal - view - returns (MathError, uint256) - { - MathError mathErr; - uint256 principalTimesIndex; - uint256 result; - - BorrowSnapshot storage borrowSnapshot = accountBorrows[account]; - - if (borrowSnapshot.principal == 0) { - return (MathError.NO_ERROR, 0); - } - - (mathErr, principalTimesIndex) = mulUInt( - borrowSnapshot.principal, - borrowIndex - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - - (mathErr, result) = divUInt( - principalTimesIndex, - borrowSnapshot.interestIndex - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - - return (MathError.NO_ERROR, result); - } - - function getBorrowerPrincipalStored(address account) - public - view - returns (uint256 borrowed) - { - borrowed = accountBorrows[account].principal; - } - - function getSupplierSnapshotStored(address account) - public - view - returns ( - uint256 tokens, - uint256 underlyingAmount, - uint256 suppliedAt, - uint256 promisedSupplyRate - ) - { - tokens = accountTokens[account].tokens; - underlyingAmount = accountTokens[account].underlyingAmount; - suppliedAt = accountTokens[account].suppliedAt; - promisedSupplyRate = accountTokens[account].promisedSupplyRate; - } - - /** - * @notice Accrue interest then return the up-to-date exchange rate - * @return Calculated exchange rate scaled by 1e18 - */ - function exchangeRateCurrent() - public - override - nonReentrant - returns (uint256) - { - require(accrueInterest() == uint256(Error.NO_ERROR), "CT07"); - return exchangeRateStored(); - } - - /** - * @notice Calculates the exchange rate from the underlying to the CToken - * @dev This function does not accrue interest before calculating the exchange rate - * @return Calculated exchange rate scaled by 1e18 - */ - function exchangeRateStored() public view override returns (uint256) { - (MathError err, uint256 result) = exchangeRateStoredInternal(); - require(err == MathError.NO_ERROR, "CT09"); - return result; - } - - /** - * @notice Calculates the exchange rate from the underlying to the CToken - * @dev This function does not accrue interest before calculating the exchange rate - * @return (error code, calculated exchange rate scaled by 1e18) - */ - function exchangeRateStoredInternal() - internal - view - virtual - returns (MathError, uint256) - { - uint256 _totalSupply = totalSupply; - if (_totalSupply == 0) { - return (MathError.NO_ERROR, initialExchangeRateMantissa); - } else { - MathError error; - uint256 exchangeRate; - uint256 totalCash = getCashPrior(); - if (interestRateModel.isTropykusInterestRateModel()) { - (error, exchangeRate) = tropykusExchangeRateStoredInternal( - msg.sender - ); - if (error == MathError.NO_ERROR) { - return (MathError.NO_ERROR, exchangeRate); - } else { - return (MathError.NO_ERROR, initialExchangeRateMantissa); - } - } - return - interestRateModel.getExchangeRate( - totalCash, - totalBorrows, - totalReserves, - totalSupply - ); - } - } - - function tropykusExchangeRateStoredInternal(address redeemer) - internal - view - returns (MathError, uint256) - { - if (totalSupply == 0) { - return (MathError.NO_ERROR, initialExchangeRateMantissa); - } else { - SupplySnapshot storage supplySnapshot = accountTokens[redeemer]; - if (supplySnapshot.suppliedAt == 0) { - return (MathError.DIVISION_BY_ZERO, 0); - } - (, uint256 interestFactorMantissa, ) = tropykusInterestAccrued( - redeemer - ); - Exp memory interestFactor = Exp({mantissa: interestFactorMantissa}); - uint256 currentUnderlying = supplySnapshot.underlyingAmount; - Exp memory redeemerUnderlying = Exp({mantissa: currentUnderlying}); - (, Exp memory realAmount) = mulExp( - interestFactor, - redeemerUnderlying - ); - (, Exp memory exchangeRate) = getExp( - realAmount.mantissa, - supplySnapshot.tokens - ); - return (MathError.NO_ERROR, exchangeRate.mantissa); - } - } - - function tropykusInterestAccrued(address account) - internal - view - returns ( - MathError, - uint256, - uint256 - ) - { - SupplySnapshot storage supplySnapshot = accountTokens[account]; - uint256 promisedSupplyRate = supplySnapshot.promisedSupplyRate; - Exp memory expectedSupplyRatePerBlock = Exp({ - mantissa: promisedSupplyRate - }); - (, uint256 delta) = subUInt( - accrualBlockNumber, - supplySnapshot.suppliedAt - ); - (, Exp memory expectedSupplyRatePerBlockWithDelta) = mulScalar( - expectedSupplyRatePerBlock, - delta - ); - (, Exp memory interestFactor) = addExp( - Exp({mantissa: 1e18}), - expectedSupplyRatePerBlockWithDelta - ); - uint256 currentUnderlying = supplySnapshot.underlyingAmount; - Exp memory redeemerUnderlying = Exp({mantissa: currentUnderlying}); - (, Exp memory realAmount) = mulExp(interestFactor, redeemerUnderlying); - (, uint256 interestEarned) = subUInt( - realAmount.mantissa, - currentUnderlying - ); - return (MathError.NO_ERROR, interestFactor.mantissa, interestEarned); - } - - /** - * @notice Get cash balance of this cToken in the underlying asset - * @return The quantity of underlying asset owned by this contract - */ - function getCash() external view override returns (uint256) { - return getCashPrior(); - } - - /** - * @notice Applies accrued interest to total borrows and reserves - * @dev This calculates interest accrued from the last checkpointed block - * up to the current block and writes new checkpoint to storage. - */ - function accrueInterest() public override returns (uint256) { - uint256 currentBlockNumber = getBlockNumber(); - uint256 accrualBlockNumberPrior = accrualBlockNumber; - - if (accrualBlockNumberPrior == currentBlockNumber) { - return uint256(Error.NO_ERROR); - } - - uint256 cashPrior = getCashPrior(); - uint256 borrowsPrior = totalBorrows; - uint256 reservesPrior = totalReserves; - uint256 borrowIndexPrior = borrowIndex; - - uint256 borrowRateMantissa = interestRateModel.getBorrowRate( - cashPrior, - borrowsPrior, - reservesPrior - ); - require(borrowRateMantissa <= borrowRateMaxMantissa, "CT10"); - - (MathError mathErr, uint256 blockDelta) = subUInt( - currentBlockNumber, - accrualBlockNumberPrior - ); - require(mathErr == MathError.NO_ERROR, "CT11"); - - Exp memory simpleInterestFactor; - uint256 interestAccumulated; - uint256 totalBorrowsNew; - uint256 totalReservesNew; - uint256 borrowIndexNew; - - (mathErr, simpleInterestFactor) = mulScalar( - Exp({mantissa: borrowRateMantissa}), - blockDelta - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .ACCRUE_INTEREST_SIMPLE_INTEREST_FACTOR_CALCULATION_FAILED, - uint256(mathErr) - ); - } - - (mathErr, interestAccumulated) = mulScalarTruncate( - simpleInterestFactor, - borrowsPrior - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .ACCRUE_INTEREST_ACCUMULATED_INTEREST_CALCULATION_FAILED, - uint256(mathErr) - ); - } - - (mathErr, totalBorrowsNew) = addUInt(interestAccumulated, borrowsPrior); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .ACCRUE_INTEREST_NEW_TOTAL_BORROWS_CALCULATION_FAILED, - uint256(mathErr) - ); - } - - (mathErr, totalReservesNew) = mulScalarTruncateAddUInt( - Exp({mantissa: reserveFactorMantissa}), - interestAccumulated, - reservesPrior - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .ACCRUE_INTEREST_NEW_TOTAL_RESERVES_CALCULATION_FAILED, - uint256(mathErr) - ); - } - - if (interestRateModel.isTropykusInterestRateModel()) { - (mathErr, totalReservesNew) = newReserves( - borrowRateMantissa, - cashPrior, - borrowsPrior, - reservesPrior, - interestAccumulated - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .ACCRUE_INTEREST_NEW_TOTAL_RESERVES_CALCULATION_FAILED, - uint256(mathErr) - ); - } - } - - (mathErr, borrowIndexNew) = mulScalarTruncateAddUInt( - simpleInterestFactor, - borrowIndexPrior, - borrowIndexPrior - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .ACCRUE_INTEREST_NEW_BORROW_INDEX_CALCULATION_FAILED, - uint256(mathErr) - ); - } - - accrualBlockNumber = currentBlockNumber; - borrowIndex = borrowIndexNew; - totalBorrows = totalBorrowsNew; - totalReserves = totalReservesNew; - - emit AccrueInterest( - cashPrior, - interestAccumulated, - borrowIndexNew, - totalBorrowsNew - ); - - return uint256(Error.NO_ERROR); - } - - function newReserves( - uint256 borrowRateMantissa, - uint256 cashPrior, - uint256 borrowsPrior, - uint256 reservesPrior, - uint256 interestAccumulated - ) internal view returns (MathError mathErr, uint256 totalReservesNew) { - uint256 newReserveFactorMantissa; - uint256 utilizationRate = interestRateModel.utilizationRate( - cashPrior, - borrowsPrior, - reservesPrior - ); - uint256 expectedSupplyRate = interestRateModel.getSupplyRate( - cashPrior, - borrowsPrior, - reservesPrior, - reserveFactorMantissa - ); - if ( - interestRateModel.isAboveOptimal( - cashPrior, - borrowsPrior, - reservesPrior - ) - ) { - (mathErr, newReserveFactorMantissa) = mulScalarTruncate( - Exp({mantissa: utilizationRate}), - borrowRateMantissa - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - (mathErr, newReserveFactorMantissa) = subUInt( - newReserveFactorMantissa, - expectedSupplyRate - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - (mathErr, totalReservesNew) = mulScalarTruncateAddUInt( - Exp({mantissa: newReserveFactorMantissa}), - interestAccumulated, - reservesPrior - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - } else { - mathErr = MathError.NO_ERROR; - totalReservesNew = reservesPrior; - } - } - - /** - * @notice Sender supplies assets into the market and receives cTokens in exchange - * @dev Accrues interest whether or not the operation succeeds, unless reverted - * @param mintAmount The amount of the underlying asset to supply - * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual mint amount. - */ - function mintInternal(uint256 mintAmount) - internal - nonReentrant - returns (uint256, uint256) - { - if (WhitelistInterface(whitelist).enabled()) { - require(WhitelistInterface(whitelist).exist(msg.sender), "CT26"); - } - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return ( - fail(Error(error), FailureInfo.MINT_ACCRUE_INTEREST_FAILED), - 0 - ); - } - return mintFresh(msg.sender, mintAmount); - } - - struct MintLocalVars { - Error err; - MathError mathErr; - uint256 exchangeRateMantissa; - uint256 mintTokens; - uint256 totalSupplyNew; - uint256 accountTokensNew; - uint256 actualMintAmount; - } - - /** - * @notice User supplies assets into the market and receives cTokens in exchange - * @dev Assumes interest has already been accrued up to the current block - * @param minter The address of the account which is supplying the assets - * @param mintAmount The amount of the underlying asset to supply - * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual mint amount. - */ - function mintFresh(address minter, uint256 mintAmount) - internal - returns (uint256, uint256) - { - uint256 allowed = comptroller.mintAllowed( - address(this), - minter, - mintAmount - ); - if (allowed != 0) { - return ( - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.MINT_COMPTROLLER_REJECTION, - allowed - ), - 0 - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return ( - fail(Error.MARKET_NOT_FRESH, FailureInfo.MINT_FRESHNESS_CHECK), - 0 - ); - } - - MintLocalVars memory vars; - - ( - vars.mathErr, - vars.exchangeRateMantissa - ) = exchangeRateStoredInternal(); - if (vars.mathErr != MathError.NO_ERROR) { - return ( - failOpaque( - Error.MATH_ERROR, - FailureInfo.MINT_EXCHANGE_RATE_READ_FAILED, - uint256(vars.mathErr) - ), - 0 - ); - } - if (interestRateModel.isTropykusInterestRateModel()) { - SupplySnapshot storage supplySnapshot = accountTokens[minter]; - (, uint256 newTotalSupply) = addUInt( - supplySnapshot.underlyingAmount, - mintAmount - ); - require(newTotalSupply <= 0.1e18, "CT24"); - } - vars.actualMintAmount = doTransferIn(minter, mintAmount); - - (vars.mathErr, vars.mintTokens) = divScalarByExpTruncate( - vars.actualMintAmount, - Exp({mantissa: vars.exchangeRateMantissa}) - ); - require(vars.mathErr == MathError.NO_ERROR, "CT12"); - - (vars.mathErr, vars.totalSupplyNew) = addUInt( - totalSupply, - vars.mintTokens - ); - require(vars.mathErr == MathError.NO_ERROR, "CT13"); - - (vars.mathErr, vars.accountTokensNew) = addUInt( - accountTokens[minter].tokens, - vars.mintTokens - ); - require(vars.mathErr == MathError.NO_ERROR, "CT14"); - - uint256 currentSupplyRate = interestRateModel.getSupplyRate( - getCashPrior(), - totalBorrows, - totalReserves, - reserveFactorMantissa - ); - - bool isTropykusInterestRateModel = interestRateModel - .isTropykusInterestRateModel(); - - if (accountTokens[minter].tokens > 0) { - Exp memory updatedUnderlying; - if (isTropykusInterestRateModel) { - (, uint256 interestFactorMantissa, ) = tropykusInterestAccrued( - minter - ); - Exp memory interestFactor = Exp({ - mantissa: interestFactorMantissa - }); - uint256 currentUnderlyingAmount = accountTokens[minter] - .underlyingAmount; - MathError mErrorNewAmount; - (mErrorNewAmount, updatedUnderlying) = mulExp( - Exp({mantissa: currentUnderlyingAmount}), - interestFactor - ); - if (mErrorNewAmount != MathError.NO_ERROR) { - return ( - failOpaque( - Error.MATH_ERROR, - FailureInfo.MINT_EXCHANGE_CALCULATION_FAILED, - uint256(mErrorNewAmount) - ), - 0 - ); - } - } else { - uint256 currentTokens = accountTokens[minter].tokens; - MathError mErrorUpdatedUnderlying; - (mErrorUpdatedUnderlying, updatedUnderlying) = mulExp( - Exp({mantissa: currentTokens}), - Exp({mantissa: vars.exchangeRateMantissa}) - ); - if (mErrorUpdatedUnderlying != MathError.NO_ERROR) { - return ( - failOpaque( - Error.MATH_ERROR, - FailureInfo.MINT_EXCHANGE_CALCULATION_FAILED, - uint256(mErrorUpdatedUnderlying) - ), - 0 - ); - } - } - (, mintAmount) = addUInt(updatedUnderlying.mantissa, mintAmount); - } - - totalSupply = vars.totalSupplyNew; - accountTokens[minter] = SupplySnapshot({ - tokens: vars.accountTokensNew, - underlyingAmount: mintAmount, - suppliedAt: accrualBlockNumber, - promisedSupplyRate: currentSupplyRate - }); - - emit Mint(minter, vars.actualMintAmount, vars.mintTokens); - emit Transfer(address(this), minter, vars.mintTokens); - - return (uint256(Error.NO_ERROR), vars.actualMintAmount); - } - - /** - * @notice Sender redeems cTokens in exchange for a specified amount of underlying asset - * @dev Accrues interest whether or not the operation succeeds, unless reverted - * @param redeemAmount The amount of underlying to receive from redeeming cTokens - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function redeemUnderlyingInternal(uint256 redeemAmount) - internal - nonReentrant - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return - fail(Error(error), FailureInfo.REDEEM_ACCRUE_INTEREST_FAILED); - } - return redeemFresh(payable(msg.sender), redeemAmount); - } - - struct RedeemLocalVars { - Error err; - MathError mathErr; - uint256 exchangeRateMantissa; - uint256 redeemTokens; - uint256 redeemAmount; - uint256 totalSupplyNew; - uint256 accountTokensNew; - uint256 newSubsidyFund; - } - - /** - * @notice User redeems cTokens in exchange for the underlying asset - * @dev Assumes interest has already been accrued up to the current block - * @param redeemer The address of the account which is redeeming the tokens - * @param redeemAmountIn The number of underlying tokens to receive from redeeming cTokens - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function redeemFresh(address payable redeemer, uint256 redeemAmountIn) - internal - returns (uint256) - { - require(redeemAmountIn > 0, "CT15"); - - RedeemLocalVars memory vars; - - SupplySnapshot storage supplySnapshot = accountTokens[redeemer]; - - ( - vars.mathErr, - vars.exchangeRateMantissa - ) = exchangeRateStoredInternal(); - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.REDEEM_EXCHANGE_RATE_READ_FAILED, - uint256(vars.mathErr) - ); - } - - uint256 interestEarned; - uint256 subsidyFundPortion; - uint256 currentUnderlying; - - bool isTropykusInterestRateModel = interestRateModel - .isTropykusInterestRateModel(); - if (isTropykusInterestRateModel) { - currentUnderlying = supplySnapshot.underlyingAmount; - (, , interestEarned) = tropykusInterestAccrued(redeemer); - } - supplySnapshot.promisedSupplyRate = interestRateModel.getSupplyRate( - getCashPrior(), - totalBorrows, - totalReserves, - reserveFactorMantissa - ); - - if ( - isTropykusInterestRateModel && - !interestRateModel.isAboveOptimal( - getCashPrior(), - totalBorrows, - totalReserves - ) - ) { - uint256 borrowRate = interestRateModel.getBorrowRate( - getCashPrior(), - totalBorrows, - totalReserves - ); - - uint256 utilizationRate = interestRateModel.utilizationRate( - getCashPrior(), - totalBorrows, - totalReserves - ); - - (, uint256 estimatedEarning) = mulScalarTruncate( - Exp({mantissa: borrowRate}), - utilizationRate - ); - - (, subsidyFundPortion) = subUInt( - supplySnapshot.promisedSupplyRate, - estimatedEarning - ); - (, Exp memory subsidyFactor) = getExp( - subsidyFundPortion, - supplySnapshot.promisedSupplyRate - ); - (, subsidyFundPortion) = mulScalarTruncate( - subsidyFactor, - interestEarned - ); - } - - vars.redeemAmount = redeemAmountIn; - - if (isTropykusInterestRateModel) { - (, Exp memory num) = mulExp( - vars.redeemAmount, - supplySnapshot.tokens - ); - (, Exp memory realTokensWithdrawAmount) = getExp( - num.mantissa, - currentUnderlying - ); - vars.redeemTokens = realTokensWithdrawAmount.mantissa; - } else { - (vars.mathErr, vars.redeemTokens) = divScalarByExpTruncate( - redeemAmountIn, - Exp({mantissa: vars.exchangeRateMantissa}) - ); - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.REDEEM_EXCHANGE_AMOUNT_CALCULATION_FAILED, - uint256(vars.mathErr) - ); - } - } - // } - - uint256 allowed = comptroller.redeemAllowed( - address(this), - redeemer, - vars.redeemTokens - ); - if (allowed != 0) { - return - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.REDEEM_COMPTROLLER_REJECTION, - allowed - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.REDEEM_FRESHNESS_CHECK - ); - } - - (vars.mathErr, vars.totalSupplyNew) = subUInt( - totalSupply, - vars.redeemTokens - ); - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.REDEEM_NEW_TOTAL_SUPPLY_CALCULATION_FAILED, - uint256(vars.mathErr) - ); - } - - (, vars.newSubsidyFund) = subUInt(subsidyFund, subsidyFundPortion); - - (vars.mathErr, vars.accountTokensNew) = subUInt( - supplySnapshot.tokens, - vars.redeemTokens - ); - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.REDEEM_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED, - uint256(vars.mathErr) - ); - } - - uint256 cash = getCashPrior(); - if (isTropykusInterestRateModel) { - cash = address(this).balance; - } - - if (cash < vars.redeemAmount) { - return - fail( - Error.TOKEN_INSUFFICIENT_CASH, - FailureInfo.REDEEM_TRANSFER_OUT_NOT_POSSIBLE - ); - } - - doTransferOut(redeemer, vars.redeemAmount); - - totalSupply = vars.totalSupplyNew; - subsidyFund = vars.newSubsidyFund; - supplySnapshot.tokens = vars.accountTokensNew; - supplySnapshot.suppliedAt = accrualBlockNumber; - (, supplySnapshot.underlyingAmount) = subUInt( - supplySnapshot.underlyingAmount, - vars.redeemAmount - ); - - emit Transfer(redeemer, address(this), vars.redeemTokens); - emit Redeem(redeemer, vars.redeemAmount, vars.redeemTokens); - - comptroller.redeemVerify( - address(this), - redeemer, - vars.redeemAmount, - vars.redeemTokens - ); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Sender borrows assets from the protocol to their own address - * @param borrowAmount The amount of the underlying asset to borrow - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function borrowInternal(uint256 borrowAmount) - internal - nonReentrant - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return - fail(Error(error), FailureInfo.BORROW_ACCRUE_INTEREST_FAILED); - } - return borrowFresh(payable(msg.sender), borrowAmount); - } - - struct BorrowLocalVars { - MathError mathErr; - uint256 accountBorrows; - uint256 accountBorrowsNew; - uint256 totalBorrowsNew; - } - - /** - * @notice Users borrow assets from the protocol to their own address - * @param borrowAmount The amount of the underlying asset to borrow - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function borrowFresh(address payable borrower, uint256 borrowAmount) - internal - returns (uint256) - { - uint256 allowed = comptroller.borrowAllowed( - address(this), - borrower, - borrowAmount - ); - if (allowed != 0) { - return - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.BORROW_COMPTROLLER_REJECTION, - allowed - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.BORROW_FRESHNESS_CHECK - ); - } - - if (getCashPrior() < borrowAmount) { - return - fail( - Error.TOKEN_INSUFFICIENT_CASH, - FailureInfo.BORROW_CASH_NOT_AVAILABLE - ); - } - - BorrowLocalVars memory vars; - - (vars.mathErr, vars.accountBorrows) = borrowBalanceStoredInternal( - borrower - ); - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED, - uint256(vars.mathErr) - ); - } - - (vars.mathErr, vars.accountBorrowsNew) = addUInt( - vars.accountBorrows, - borrowAmount - ); - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED, - uint256(vars.mathErr) - ); - } - - (vars.mathErr, vars.totalBorrowsNew) = addUInt( - totalBorrows, - borrowAmount - ); - if (interestRateModel.isTropykusInterestRateModel()) { - require(vars.totalBorrowsNew <= 0.1e18, "CT25"); - } - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED, - uint256(vars.mathErr) - ); - } - - doTransferOut(borrower, borrowAmount); - - accountBorrows[borrower].principal = vars.accountBorrowsNew; - accountBorrows[borrower].interestIndex = borrowIndex; - totalBorrows = vars.totalBorrowsNew; - - emit Borrow( - borrower, - borrowAmount, - vars.accountBorrowsNew, - vars.totalBorrowsNew - ); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Sender repays their own borrow - * @param repayAmount The amount to repay - * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual repayment amount. - */ - function repayBorrowInternal(uint256 repayAmount) - internal - nonReentrant - returns (uint256, uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return ( - fail( - Error(error), - FailureInfo.REPAY_BORROW_ACCRUE_INTEREST_FAILED - ), - 0 - ); - } - return repayBorrowFresh(msg.sender, msg.sender, repayAmount); - } - - struct RepayBorrowLocalVars { - Error err; - MathError mathErr; - uint256 repayAmount; - uint256 borrowerIndex; - uint256 accountBorrows; - uint256 accountBorrowsNew; - uint256 totalBorrowsNew; - uint256 actualRepayAmount; - } - - /** - * @notice Borrows are repaid by another user (possibly the borrower). - * @param payer the account paying off the borrow - * @param borrower the account with the debt being payed off - * @param repayAmount the amount of undelrying tokens being returned - * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual repayment amount. - */ - function repayBorrowFresh( - address payer, - address borrower, - uint256 repayAmount - ) internal returns (uint256, uint256) { - uint256 allowed = comptroller.repayBorrowAllowed( - address(this), - payer, - borrower, - repayAmount - ); - if (allowed != 0) { - return ( - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.REPAY_BORROW_COMPTROLLER_REJECTION, - allowed - ), - 0 - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return ( - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.REPAY_BORROW_FRESHNESS_CHECK - ), - 0 - ); - } - - RepayBorrowLocalVars memory vars; - - vars.borrowerIndex = accountBorrows[borrower].interestIndex; - - (vars.mathErr, vars.accountBorrows) = borrowBalanceStoredInternal( - borrower - ); - if (vars.mathErr != MathError.NO_ERROR) { - return ( - failOpaque( - Error.MATH_ERROR, - FailureInfo - .REPAY_BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED, - uint256(vars.mathErr) - ), - 0 - ); - } - - if (repayAmount == type(uint256).max) { - vars.repayAmount = vars.accountBorrows; - } else { - vars.repayAmount = repayAmount; - } - - vars.actualRepayAmount = doTransferIn(payer, vars.repayAmount); - - (vars.mathErr, vars.accountBorrowsNew) = subUInt( - vars.accountBorrows, - vars.actualRepayAmount - ); - require(vars.mathErr == MathError.NO_ERROR, "CT16"); - - (vars.mathErr, vars.totalBorrowsNew) = subUInt( - totalBorrows, - vars.actualRepayAmount - ); - require(vars.mathErr == MathError.NO_ERROR, "CT17"); - - accountBorrows[borrower].principal = vars.accountBorrowsNew; - accountBorrows[borrower].interestIndex = borrowIndex; - totalBorrows = vars.totalBorrowsNew; - - emit RepayBorrow( - payer, - borrower, - vars.actualRepayAmount, - vars.accountBorrowsNew, - vars.totalBorrowsNew - ); - - return (uint256(Error.NO_ERROR), vars.actualRepayAmount); - } - - /** - * @notice The sender liquidates the borrowers collateral. - * The collateral seized is transferred to the liquidator. - * @param borrower The borrower of this cToken to be liquidated - * @param cTokenCollateral The market in which to seize collateral from the borrower - * @param repayAmount The amount of the underlying borrowed asset to repay - * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual repayment amount. - */ - function liquidateBorrowInternal( - address borrower, - uint256 repayAmount, - CTokenInterface cTokenCollateral - ) internal nonReentrant returns (uint256, uint256) { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return ( - fail( - Error(error), - FailureInfo.LIQUIDATE_ACCRUE_BORROW_INTEREST_FAILED - ), - 0 - ); - } - - error = cTokenCollateral.accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return ( - fail( - Error(error), - FailureInfo.LIQUIDATE_ACCRUE_COLLATERAL_INTEREST_FAILED - ), - 0 - ); - } - - // liquidateBorrowFresh emits borrow-specific logs on errors, so we don't need to - return - liquidateBorrowFresh( - msg.sender, - borrower, - repayAmount, - cTokenCollateral - ); - } - - /** - * @notice The liquidator liquidates the borrowers collateral. - * The collateral seized is transferred to the liquidator. - * @param borrower The borrower of this cToken to be liquidated - * @param liquidator The address repaying the borrow and seizing collateral - * @param cTokenCollateral The market in which to seize collateral from the borrower - * @param repayAmount The amount of the underlying borrowed asset to repay - * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual repayment amount. - */ - function liquidateBorrowFresh( - address liquidator, - address borrower, - uint256 repayAmount, - CTokenInterface cTokenCollateral - ) internal returns (uint256, uint256) { - uint256 allowed = comptroller.liquidateBorrowAllowed( - address(this), - address(cTokenCollateral), - liquidator, - borrower, - repayAmount - ); - if (allowed != 0) { - return ( - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.LIQUIDATE_COMPTROLLER_REJECTION, - allowed - ), - 0 - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return ( - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.LIQUIDATE_FRESHNESS_CHECK - ), - 0 - ); - } - - if (cTokenCollateral.accrualBlockNumber() != getBlockNumber()) { - return ( - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.LIQUIDATE_COLLATERAL_FRESHNESS_CHECK - ), - 0 - ); - } - - if (borrower == liquidator) { - return ( - fail( - Error.INVALID_ACCOUNT_PAIR, - FailureInfo.LIQUIDATE_LIQUIDATOR_IS_BORROWER - ), - 0 - ); - } - - if (repayAmount == 0) { - return ( - fail( - Error.INVALID_CLOSE_AMOUNT_REQUESTED, - FailureInfo.LIQUIDATE_CLOSE_AMOUNT_IS_ZERO - ), - 0 - ); - } - - if (repayAmount == type(uint256).max) { - return ( - fail( - Error.INVALID_CLOSE_AMOUNT_REQUESTED, - FailureInfo.LIQUIDATE_CLOSE_AMOUNT_IS_UINT_MAX - ), - 0 - ); - } - - ( - uint256 repayBorrowError, - uint256 actualRepayAmount - ) = repayBorrowFresh(liquidator, borrower, repayAmount); - if (repayBorrowError != uint256(Error.NO_ERROR)) { - return ( - fail( - Error(repayBorrowError), - FailureInfo.LIQUIDATE_REPAY_BORROW_FRESH_FAILED - ), - 0 - ); - } - - (uint256 amountSeizeError, uint256 seizeTokens) = comptroller - .liquidateCalculateSeizeTokens( - address(this), - address(cTokenCollateral), - actualRepayAmount - ); - require(amountSeizeError == uint256(Error.NO_ERROR), "CT18"); - - require(cTokenCollateral.balanceOf(borrower) >= seizeTokens, "CT19"); - - uint256 seizeError; - if (address(cTokenCollateral) == address(this)) { - seizeError = seizeInternal( - address(this), - liquidator, - borrower, - seizeTokens - ); - } else { - seizeError = cTokenCollateral.seize( - liquidator, - borrower, - seizeTokens - ); - } - - require(seizeError == uint256(Error.NO_ERROR), "CT20"); - - emit LiquidateBorrow( - liquidator, - borrower, - actualRepayAmount, - address(cTokenCollateral), - seizeTokens - ); - - return (uint256(Error.NO_ERROR), actualRepayAmount); - } - - /** - * @notice Transfers collateral tokens (this market) to the liquidator. - * @dev Will fail unless called by another cToken during the process of liquidation. - * Its absolutely critical to use msg.sender as the borrowed cToken and not a parameter. - * @param liquidator The account receiving seized collateral - * @param borrower The account having collateral seized - * @param seizeTokens The number of cTokens to seize - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function seize( - address liquidator, - address borrower, - uint256 seizeTokens - ) external override nonReentrant returns (uint256) { - return seizeInternal(msg.sender, liquidator, borrower, seizeTokens); - } - - struct SeizeVars { - uint256 seizeAmount; - uint256 exchangeRate; - uint256 borrowerTokensNew; - uint256 borrowerAmountNew; - uint256 liquidatorTokensNew; - uint256 liquidatorAmountNew; - uint256 totalCash; - uint256 supplyRate; - } - - /** - * @notice Transfers collateral tokens (this market) to the liquidator. - * @dev Called only during an in-kind liquidation, or by liquidateBorrow during the liquidation of another CToken. - * Its absolutely critical to use msg.sender as the seizer cToken and not a parameter. - * @param seizerToken The contract seizing the collateral (i.e. borrowed cToken) - * @param liquidator The account receiving seized collateral - * @param borrower The account having collateral seized - * @param seizeTokens The number of cTokens to seize - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function seizeInternal( - address seizerToken, - address liquidator, - address borrower, - uint256 seizeTokens - ) internal returns (uint256) { - uint256 allowed = comptroller.seizeAllowed( - address(this), - seizerToken, - liquidator, - borrower, - seizeTokens - ); - if (allowed != 0) { - return - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.LIQUIDATE_SEIZE_COMPTROLLER_REJECTION, - allowed - ); - } - - if (borrower == liquidator) { - return - fail( - Error.INVALID_ACCOUNT_PAIR, - FailureInfo.LIQUIDATE_SEIZE_LIQUIDATOR_IS_BORROWER - ); - } - - SeizeVars memory seizeVars; - - MathError mathErr; - - (mathErr, seizeVars.borrowerTokensNew) = subUInt( - accountTokens[borrower].tokens, - seizeTokens - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.LIQUIDATE_SEIZE_BALANCE_DECREMENT_FAILED, - uint256(mathErr) - ); - } - - seizeVars.totalCash = getCashPrior(); - seizeVars.supplyRate = interestRateModel.getSupplyRate( - seizeVars.totalCash, - totalBorrows, - totalReserves, - reserveFactorMantissa - ); - - (, seizeVars.exchangeRate) = interestRateModel.getExchangeRate( - seizeVars.totalCash, - totalBorrows, - totalReserves, - totalSupply - ); - - if (interestRateModel.isTropykusInterestRateModel()) { - (, seizeVars.exchangeRate) = tropykusExchangeRateStoredInternal( - borrower - ); - } - - (, seizeVars.seizeAmount) = mulUInt( - seizeTokens, - seizeVars.exchangeRate - ); - (, seizeVars.seizeAmount) = divUInt(seizeVars.seizeAmount, 1e18); - - (, seizeVars.borrowerAmountNew) = subUInt( - accountTokens[borrower].underlyingAmount, - seizeVars.seizeAmount - ); - - (mathErr, seizeVars.liquidatorTokensNew) = addUInt( - accountTokens[liquidator].tokens, - seizeTokens - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.LIQUIDATE_SEIZE_BALANCE_INCREMENT_FAILED, - uint256(mathErr) - ); - } - - (, seizeVars.liquidatorAmountNew) = addUInt( - accountTokens[liquidator].underlyingAmount, - seizeVars.seizeAmount - ); - - accountTokens[borrower].tokens = seizeVars.borrowerTokensNew; - accountTokens[borrower].underlyingAmount = seizeVars.borrowerAmountNew; - accountTokens[borrower].suppliedAt = getBlockNumber(); - accountTokens[borrower].promisedSupplyRate = seizeVars.supplyRate; - - accountTokens[liquidator].tokens = seizeVars.liquidatorTokensNew; - accountTokens[liquidator].underlyingAmount = seizeVars - .liquidatorAmountNew; - accountTokens[liquidator].suppliedAt = getBlockNumber(); - accountTokens[liquidator].promisedSupplyRate = seizeVars.supplyRate; - - emit Transfer(borrower, liquidator, seizeTokens); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Begins transfer of admin rights. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer. - * @dev Admin function to begin change of admin. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer. - * @param newPendingAdmin New pending admin. - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setPendingAdmin(address payable newPendingAdmin) - external - override - returns (uint256) - { - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_PENDING_ADMIN_OWNER_CHECK - ); - } - - address oldPendingAdmin = pendingAdmin; - - pendingAdmin = newPendingAdmin; - - emit NewPendingAdmin(oldPendingAdmin, newPendingAdmin); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Accepts transfer of admin rights. msg.sender must be pendingAdmin - * @dev Admin function for pending admin to accept role and update admin - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _acceptAdmin() external override returns (uint256) { - if (msg.sender != pendingAdmin || msg.sender == address(0)) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.ACCEPT_ADMIN_PENDING_ADMIN_CHECK - ); - } - - address oldAdmin = admin; - address oldPendingAdmin = pendingAdmin; - - admin = pendingAdmin; - - pendingAdmin = payable(address(0)); - - emit NewAdmin(oldAdmin, admin); - emit NewPendingAdmin(oldPendingAdmin, pendingAdmin); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Sets a new comptroller for the market - * @dev Admin function to set a new comptroller - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setComptroller(ComptrollerInterface newComptroller) - public - override - returns (uint256) - { - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_COMPTROLLER_OWNER_CHECK - ); - } - - ComptrollerInterface oldComptroller = comptroller; - require(newComptroller.isComptroller(), "CT21"); - - comptroller = newComptroller; - - emit NewComptroller(oldComptroller, newComptroller); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice accrues interest and sets a new reserve factor for the protocol using _setReserveFactorFresh - * @dev Admin function to accrue interest and set a new reserve factor - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setReserveFactor(uint256 newReserveFactorMantissa) - external - override - nonReentrant - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return - fail( - Error(error), - FailureInfo.SET_RESERVE_FACTOR_ACCRUE_INTEREST_FAILED - ); - } - return _setReserveFactorFresh(newReserveFactorMantissa); - } - - /** - * @notice Sets a new reserve factor for the protocol (*requires fresh interest accrual) - * @dev Admin function to set a new reserve factor - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setReserveFactorFresh(uint256 newReserveFactorMantissa) - internal - returns (uint256) - { - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_RESERVE_FACTOR_ADMIN_CHECK - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.SET_RESERVE_FACTOR_FRESH_CHECK - ); - } - - if (newReserveFactorMantissa > reserveFactorMaxMantissa) { - return - fail( - Error.BAD_INPUT, - FailureInfo.SET_RESERVE_FACTOR_BOUNDS_CHECK - ); - } - - uint256 oldReserveFactorMantissa = reserveFactorMantissa; - reserveFactorMantissa = newReserveFactorMantissa; - - emit NewReserveFactor( - oldReserveFactorMantissa, - newReserveFactorMantissa - ); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Accrues interest and reduces reserves by transferring from msg.sender - * @param addAmount Amount of addition to reserves - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _addReservesInternal(uint256 addAmount) - internal - nonReentrant - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return - fail( - Error(error), - FailureInfo.ADD_RESERVES_ACCRUE_INTEREST_FAILED - ); - } - - uint256 totalReservesNew; - uint256 actualAddAmount; - - if (accrualBlockNumber != getBlockNumber()) { - return ( - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.ADD_RESERVES_FRESH_CHECK - ) - ); - } - - actualAddAmount = doTransferIn(msg.sender, addAmount); - - totalReservesNew = totalReserves + actualAddAmount; - - require(totalReservesNew >= totalReserves, "CT22"); - - totalReserves = totalReservesNew; - - emit ReservesAdded(msg.sender, actualAddAmount, totalReservesNew); - - return (uint256(Error.NO_ERROR)); - } - - function _addSubsidyInternal(uint256 addAmount) - internal - nonReentrant - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - // accrueInterest emits logs on errors, but on top of that we want to log the fact that an attempted reduce reserves failed. - return fail(Error(error), FailureInfo.ADD_SUBSIDY_FUND_FAILED); - } - - uint256 subsidyFundNew; - uint256 actualAddAmount; - - if (accrualBlockNumber != getBlockNumber()) { - return ( - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.ADD_SUBSIDY_FUND_FRESH_CHECK - ) - ); - } - - actualAddAmount = doTransferIn(msg.sender, addAmount); - - subsidyFundNew = subsidyFund + actualAddAmount; - - require(subsidyFundNew >= subsidyFund, "CT22"); - - subsidyFund = subsidyFundNew; - - emit SubsidyAdded(msg.sender, actualAddAmount, subsidyFundNew); - - /* Return (NO_ERROR, actualAddAmount) */ - return (uint256(Error.NO_ERROR)); - } - - /** - * @notice Accrues interest and reduces reserves by transferring to admin - * @param reduceAmount Amount of reduction to reserves - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _reduceReserves(uint256 reduceAmount) - external - override - nonReentrant - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return - fail( - Error(error), - FailureInfo.REDUCE_RESERVES_ACCRUE_INTEREST_FAILED - ); - } - return _reduceReservesFresh(reduceAmount); - } - - /** - * @notice Reduces reserves by transferring to admin - * @dev Requires fresh interest accrual - * @param reduceAmount Amount of reduction to reserves - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _reduceReservesFresh(uint256 reduceAmount) - internal - returns (uint256) - { - uint256 totalReservesNew; - - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.REDUCE_RESERVES_ADMIN_CHECK - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.REDUCE_RESERVES_FRESH_CHECK - ); - } - - if (getCashPrior() < reduceAmount) { - return - fail( - Error.TOKEN_INSUFFICIENT_CASH, - FailureInfo.REDUCE_RESERVES_CASH_NOT_AVAILABLE - ); - } - - if (reduceAmount > totalReserves) { - return - fail(Error.BAD_INPUT, FailureInfo.REDUCE_RESERVES_VALIDATION); - } - - totalReservesNew = totalReserves - reduceAmount; - require(totalReservesNew <= totalReserves, "CT23"); - - totalReserves = totalReservesNew; - - doTransferOut(admin, reduceAmount); - - emit ReservesReduced(admin, reduceAmount, totalReservesNew); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice accrues interest and updates the interest rate model using _setInterestRateModelFresh - * @dev Admin function to accrue interest and update the interest rate model - * @param newInterestRateModel the new interest rate model to use - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setInterestRateModel(InterestRateModel newInterestRateModel) - public - override - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return - fail( - Error(error), - FailureInfo.SET_INTEREST_RATE_MODEL_ACCRUE_INTEREST_FAILED - ); - } - return _setInterestRateModelFresh(newInterestRateModel); - } - - /** - * @notice updates the interest rate model (*requires fresh interest accrual) - * @dev Admin function to update the interest rate model - * @param newInterestRateModel the new interest rate model to use - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setInterestRateModelFresh(InterestRateModel newInterestRateModel) - internal - returns (uint256) - { - InterestRateModel oldInterestRateModel; - - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_INTEREST_RATE_MODEL_OWNER_CHECK - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.SET_INTEREST_RATE_MODEL_FRESH_CHECK - ); - } - - oldInterestRateModel = interestRateModel; - - require(newInterestRateModel.isInterestRateModel(), "CT21"); - - interestRateModel = newInterestRateModel; - - emit NewMarketInterestRateModel( - oldInterestRateModel, - newInterestRateModel - ); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Gets balance of this contract in terms of the underlying - * @dev This excludes the value of the current message, if any - * @return The quantity of underlying owned by this contract - */ - function getCashPrior() internal view virtual returns (uint256); - - /** - * @dev Performs a transfer in, reverting upon failure. Returns the amount actually transferred to the protocol, in case of a fee. - * This may revert due to insufficient balance or insufficient allowance. - */ - function doTransferIn(address from, uint256 amount) - internal - virtual - returns (uint256); - - /** - * @dev Performs a transfer out, ideally returning an explanatory error code upon failure tather than reverting. - * If caller has not called checked protocol's balance, may revert due to insufficient cash held in the contract. - * If caller has checked protocol's balance, and verified it is >= amount, this should not revert in normal conditions. - */ - function doTransferOut(address payable to, uint256 amount) internal virtual; - - /** - * @dev Prevents a contract from calling itself, directly or indirectly. - */ - modifier nonReentrant() { - require(_notEntered, "re-entered"); - _notEntered = false; - _; - _notEntered = true; - } -} - - -// Dependency file: contracts/CErc20.sol - -// pragma solidity 0.8.6; - -// import "contracts/CToken.sol"; -// import "contracts/CTokenInterfaces.sol"; - -/** - * @title tropykus CErc20 Contract - * @notice CTokens which wrap an EIP-20 underlying - * @author tropykus - */ -contract CErc20 is CToken, CErc20Interface { - /** - * @notice Initialize the new money market - * @param underlying_ The address of the underlying asset - * @param comptroller_ The address of the Comptroller - * @param interestRateModel_ The address of the interest rate model - * @param initialExchangeRateMantissa_ The initial exchange rate, scaled by 1e18 - * @param name_ ERC-20 name of this token - * @param symbol_ ERC-20 symbol of this token - * @param decimals_ ERC-20 decimal precision of this token - */ - function initialize( - address underlying_, - ComptrollerInterface comptroller_, - InterestRateModel interestRateModel_, - uint256 initialExchangeRateMantissa_, - string memory name_, - string memory symbol_, - uint8 decimals_ - ) public { - // CToken initialize does the bulk of the work - super.initialize( - comptroller_, - interestRateModel_, - initialExchangeRateMantissa_, - name_, - symbol_, - decimals_ - ); - - // Set underlying and sanity check it - underlying = underlying_; - EIP20Interface(underlying).totalSupply(); - } - - /*** User Interface ***/ - - /** - * @notice Sender supplies assets into the market and receives cTokens in exchange - * @dev Accrues interest whether or not the operation succeeds, unless reverted - * @param mintAmount The amount of the underlying asset to supply - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function mint(uint256 mintAmount) external override returns (uint256) { - (uint256 err, ) = mintInternal(mintAmount); - return err; - } - - /** - * @notice Sender redeems cTokens in exchange for a specified amount of underlying asset - * @dev Accrues interest whether or not the operation succeeds, unless reverted - * @param redeemAmount The amount of underlying to redeem - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function redeem(uint256 redeemAmount) - external - override - returns (uint256) - { - return redeemUnderlyingInternal(redeemAmount); - } - - /** - * @notice Sender borrows assets from the protocol to their own address - * @param borrowAmount The amount of the underlying asset to borrow - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function borrow(uint256 borrowAmount) external override returns (uint256) { - return borrowInternal(borrowAmount); - } - - /** - * @notice Sender repays their own borrow - * @param repayAmount The amount to repay - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function repayBorrow(uint256 repayAmount) - external - override - returns (uint256) - { - (uint256 err, ) = repayBorrowInternal(repayAmount); - return err; - } - - /** - * @notice The sender liquidates the borrowers collateral. - * The collateral seized is transferred to the liquidator. - * @param borrower The borrower of this cToken to be liquidated - * @param repayAmount The amount of the underlying borrowed asset to repay - * @param cTokenCollateral The market in which to seize collateral from the borrower - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function liquidateBorrow( - address borrower, - uint256 repayAmount, - CTokenInterface cTokenCollateral - ) external override returns (uint256) { - (uint256 err, ) = liquidateBorrowInternal( - borrower, - repayAmount, - cTokenCollateral - ); - return err; - } - - /** - * @notice A public function to sweep accidental ERC-20 transfers to this contract. Tokens are sent to admin (timelock) - * @param token The address of the ERC-20 token to sweep - */ - function sweepToken(EIP20NonStandardInterface token) external override { - require(address(token) != underlying, "EC01"); - uint256 balance = token.balanceOf(address(this)); - token.transfer(admin, balance); - } - - /** - * @notice The sender adds to reserves. - * @param addAmount The amount fo underlying token to add as reserves - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _addReserves(uint256 addAmount) - external - override - returns (uint256) - { - return _addReservesInternal(addAmount); - } - - /*** Safe Token ***/ - - /** - * @notice Gets balance of this contract in terms of the underlying - * @dev This excludes the value of the current message, if any - * @return The quantity of underlying tokens owned by this contract - */ - function getCashPrior() internal view override returns (uint256) { - EIP20Interface token = EIP20Interface(underlying); - return token.balanceOf(address(this)); - } - - /** - * @dev Similar to EIP20 transfer, except it handles a False result from `transferFrom` and reverts in that case. - * This will revert due to insufficient balance or insufficient allowance. - * This function returns the actual amount received, - * which may be less than `amount` if there is a fee attached to the transfer. - * - * Note: This wrapper safely handles non-standard ERC-20 tokens that do not return a value. - * See here: https://medium.com/coinmonks/missing-return-value-bug-at-least-130-tokens-affected-d67bf08521ca - */ - function doTransferIn(address from, uint256 amount) - internal - override - returns (uint256) - { - EIP20NonStandardInterface token = EIP20NonStandardInterface(underlying); - uint256 balanceBefore = EIP20Interface(underlying).balanceOf( - address(this) - ); - token.transferFrom(from, address(this), amount); - - bool success; - assembly { - switch returndatasize() - case 0 { - // This is a non-standard ERC-20 - success := not(0) // set success to true - } - case 32 { - // This is a compliant ERC-20 - returndatacopy(0, 0, 32) - success := mload(0) // Set `success = returndata` of external call - } - default { - // This is an excessively non-compliant ERC-20, revert. - revert(0, 0) - } - } - require(success, "EC02"); - - // Calculate the amount that was *actually* transferred - uint256 balanceAfter = EIP20Interface(underlying).balanceOf( - address(this) - ); - require(balanceAfter >= balanceBefore, "EC03"); - return balanceAfter - balanceBefore; // underflow already checked above, just subtract - } - - /** - * @dev Similar to EIP20 transfer, except it handles a False success from `transfer` and returns an explanatory - * error code rather than reverting. If caller has not called checked protocol's balance, this may revert due to - * insufficient cash held in this contract. If caller has checked protocol's balance prior to this call, and verified - * it is >= amount, this should not revert in normal conditions. - * - * Note: This wrapper safely handles non-standard ERC-20 tokens that do not return a value. - * See here: https://medium.com/coinmonks/missing-return-value-bug-at-least-130-tokens-affected-d67bf08521ca - */ - function doTransferOut(address payable to, uint256 amount) - internal - virtual - override - { - EIP20NonStandardInterface token = EIP20NonStandardInterface(underlying); - token.transfer(to, amount); - - bool success; - assembly { - switch returndatasize() - case 0 { - // This is a non-standard ERC-20 - success := not(0) // set success to true - } - case 32 { - // This is a complaint ERC-20 - returndatacopy(0, 0, 32) - success := mload(0) // Set `success = returndata` of external call - } - default { - // This is an excessively non-compliant ERC-20, revert. - revert(0, 0) - } - } - require(success, "CE01"); - } -} - - -// Root file: contracts/mocks/MockPriceProviderMoC.sol - -pragma solidity 0.8.6; - -// import "contracts/CErc20.sol"; - -/** - * @title A mock price provider of Money on Chain (MoC) - * @notice You can use this contract for only simulation - */ -contract MockPriceProviderMoC { - /// @notice rbtcPrice of the interface provicer MoC - bytes32 rbtcPrice; - /// @notice has of the interface provicer MoC - bool has; - /// @notice Address of the guardian - address public guardian; - /// @notice Event rbtcPrice updated - event MockPriceProviderMoCUpdated(uint256 oldPrice, uint256 newPrice); - - constructor(address guardian_, uint256 price) { - require( - guardian_ != address(0), - "MockPriceProviderMoC: address could not be 0" - ); - require( - price != uint256(0), - "MockPriceProviderMoC: price could not be 0" - ); - guardian = guardian_; - rbtcPrice = bytes32(price); - has = true; - } - - function peek() public view returns (bytes32, bool) { - return (rbtcPrice, has); - } - - /** - * @notice Set the rbtcPrice price provider - * @param price uint of price provider - */ - function setPrice(uint256 price) public { - require( - msg.sender == guardian, - "MockPriceProviderMoC: only guardian may set the address" - ); - require( - price != uint256(0), - "MockPriceProviderMoC: price could not be 0" - ); - //set old price - bytes32 oldRbtcPrice = rbtcPrice; - //update rbtcPrice - rbtcPrice = bytes32(price); - //emit event - emit MockPriceProviderMoCUpdated( - uint256(oldRbtcPrice), - uint256(rbtcPrice) - ); - } -} diff --git a/flatten/MultiSigWallet.sol b/flatten/MultiSigWallet.sol deleted file mode 100644 index 0436f17..0000000 --- a/flatten/MultiSigWallet.sol +++ /dev/null @@ -1,417 +0,0 @@ -// Root file: contracts/MultiSigWallet.sol - -// SPDX-License-Identifier: UNLICENSED -pragma solidity 0.8.6; - -/// @title Multisignature wallet - Allows multiple parties to agree on transactions before execution. -/// @author Stefan George - -contract MultiSigWallet { - /* - * Events - */ - event Confirmation(address indexed sender, uint256 indexed transactionId); - event Revocation(address indexed sender, uint256 indexed transactionId); - event Submission(uint256 indexed transactionId); - event Execution(uint256 indexed transactionId); - event ExecutionFailure(uint256 indexed transactionId); - event Deposit(address indexed sender, uint256 value); - event OwnerAddition(address indexed owner); - event OwnerRemoval(address indexed owner); - event RequirementChange(uint256 required); - - /* - * views - */ - uint256 public constant MAX_OWNER_COUNT = 50; - - /* - * Storage - */ - mapping(uint256 => Transaction) public transactions; - mapping(uint256 => mapping(address => bool)) public confirmations; - mapping(address => bool) public isOwner; - address[] public owners; - uint256 public required; - uint256 public transactionCount; - - struct Transaction { - address destination; - uint256 value; - bytes data; - bool executed; - } - - /* - * Modifiers - */ - modifier onlyWallet() { - require(msg.sender == address(this), "Only wallet allowed"); - _; - } - - modifier ownerDoesNotExist(address owner) { - require(!isOwner[owner], "The owner already exists"); - _; - } - - modifier ownerExists(address owner) { - require(isOwner[owner], "The owner does not exist"); - _; - } - - modifier transactionExists(uint256 transactionId) { - require( - transactions[transactionId].destination != address(0), - "Transaction does not exist" - ); - _; - } - - modifier confirmed(uint256 transactionId, address owner) { - require( - confirmations[transactionId][owner], - "Transaction is not confirmed by owner" - ); - _; - } - - modifier notConfirmed(uint256 transactionId, address owner) { - require( - !confirmations[transactionId][owner], - "Transaction is already confirmed by owner" - ); - _; - } - - modifier notExecuted(uint256 transactionId) { - require( - !transactions[transactionId].executed, - "Transaction was already executed" - ); - _; - } - - modifier notNull(address _address) { - require(_address != address(0), "Address cannot be empty"); - _; - } - - modifier validRequirement(uint256 ownerCount, uint256 _required) { - // solium-disable-next-line max-len - require( - ownerCount <= MAX_OWNER_COUNT && - _required <= ownerCount && - _required != 0 && - ownerCount != 0, - "Required value is invalid for the current owners count" - ); - _; - } - - /// @dev Fallback function allows to deposit ether. - fallback() external payable { - if (msg.value > 0) emit Deposit(msg.sender, msg.value); - } - - receive() external payable { - if (msg.value > 0) emit Deposit(msg.sender, msg.value); - } - - /* - * Public functions - */ - /// @dev Contract constructor sets initial owners and required number of confirmations. - /// @param _owners List of initial owners. - /// @param _required Number of required confirmations. - constructor(address[] memory _owners, uint256 _required) - validRequirement(_owners.length, _required) - { - for (uint256 i = 0; i < _owners.length; i++) { - require( - !isOwner[_owners[i]] && _owners[i] != address(0), - "Owners addresses are invalid" - ); - isOwner[_owners[i]] = true; - } - owners = _owners; - required = _required; - } - - /// @dev Allows to add a new owner. Transaction has to be sent by wallet. - /// @param owner Address of new owner. - function addOwner(address owner) - public - onlyWallet - ownerDoesNotExist(owner) - notNull(owner) - validRequirement(owners.length + 1, required) - { - isOwner[owner] = true; - owners.push(owner); - emit OwnerAddition(owner); - } - - /// @dev Allows to remove an owner. Transaction has to be sent by wallet. - /// @param owner Address of owner. - function removeOwner(address owner) public onlyWallet ownerExists(owner) { - isOwner[owner] = false; - address[] memory oldOwners = owners; - owners = new address[](0); - for (uint256 i = 0; i < oldOwners.length; i++) { - if (oldOwners[i] == owner) continue; - owners.push(owners[i]); - } - if (required > owners.length) changeRequirement(owners.length); - emit OwnerRemoval(owner); - } - - /// @dev Allows to replace an owner with a new owner. Transaction has to be sent by wallet. - /// @param owner Address of owner to be replaced. - /// @param newOwner Address of new owner. - function replaceOwner(address owner, address newOwner) - public - onlyWallet - ownerExists(owner) - ownerDoesNotExist(newOwner) - { - for (uint256 i = 0; i < owners.length; i++) - if (owners[i] == owner) { - owners[i] = newOwner; - break; - } - isOwner[owner] = false; - isOwner[newOwner] = true; - emit OwnerRemoval(owner); - emit OwnerAddition(newOwner); - } - - /// @dev Allows to change the number of required confirmations. Transaction has to be sent by wallet. - /// @param _required Number of required confirmations. - function changeRequirement(uint256 _required) - public - onlyWallet - validRequirement(owners.length, _required) - { - required = _required; - emit RequirementChange(_required); - } - - /// @dev Allows an owner to submit and confirm a transaction. - /// @param destination Transaction target address. - /// @param value Transaction ether value. - /// @param data Transaction data payload. - /// @return transactionId Returns transaction ID. - function submitTransaction( - address destination, - uint256 value, - bytes memory data - ) public returns (uint256 transactionId) { - transactionId = addTransaction(destination, value, data); - confirmTransaction(transactionId); - } - - /// @dev Allows an owner to confirm a transaction. - /// @param transactionId Transaction ID. - function confirmTransaction(uint256 transactionId) - public - ownerExists(msg.sender) - transactionExists(transactionId) - notConfirmed(transactionId, msg.sender) - { - confirmations[transactionId][msg.sender] = true; - emit Confirmation(msg.sender, transactionId); - executeTransaction(transactionId); - } - - /// @dev Allows an owner to revoke a confirmation for a transaction. - /// @param transactionId Transaction ID. - function revokeConfirmation(uint256 transactionId) - public - ownerExists(msg.sender) - confirmed(transactionId, msg.sender) - notExecuted(transactionId) - { - confirmations[transactionId][msg.sender] = false; - emit Revocation(msg.sender, transactionId); - } - - /// @dev Allows anyone to execute a confirmed transaction. - /// @param transactionId Transaction ID. - function executeTransaction(uint256 transactionId) - public - ownerExists(msg.sender) - confirmed(transactionId, msg.sender) - notExecuted(transactionId) - { - if (isConfirmed(transactionId)) { - Transaction storage txn = transactions[transactionId]; - txn.executed = true; - if ( - external_call( - txn.destination, - txn.value, - txn.data.length, - txn.data - ) - ) emit Execution(transactionId); - else { - emit ExecutionFailure(transactionId); - txn.executed = false; - } - } - } - - // call has been separated into its own function in order to take advantage - // of the Solidity's code generator to produce a loop that copies tx.data into memory. - function external_call( - address destination, - uint256 value, - uint256 dataLength, - bytes memory data - ) internal returns (bool) { - bool result; - // solium-disable-next-line security/no-inline-assembly - assembly { - let x := mload(0x40) // "Allocate" memory for output (0x40 is where "free memory" pointer is stored by convention) - let d := add(data, 32) // First 32 bytes are the padded length of data, so exclude that - result := call( - sub(gas(), 34710), // 34710 is the value that solidity is currently emitting - // It includes callGas (700) + callVeryLow (3, to pay for SUB) + callValueTransferGas (9000) + - // callNewAccountGas (25000, in case the destination address does not exist and needs creating) - destination, - value, - d, - dataLength, // Size of the input (in bytes) - this is what fixes the padding problem - x, - 0 // Output is ignored, therefore the output size is zero - ) - } - return result; - } - - /// @dev Returns the confirmation status of a transaction. - /// @param transactionId Transaction ID. - /// @return result Confirmation status. - function isConfirmed(uint256 transactionId) public view returns (bool result) { - uint256 count = 0; - for (uint256 i = 0; i < owners.length; i++) { - if (confirmations[transactionId][owners[i]]) count += 1; - if (count == required) return true; - } - } - - /* - * Internal functions - */ - /// @dev Adds a new transaction to the transaction mapping, if transaction does not exist yet. - /// @param destination Transaction target address. - /// @param value Transaction ether value. - /// @param data Transaction data payload. - /// @return transactionId Returns transaction ID. - function addTransaction( - address destination, - uint256 value, - bytes memory data - ) internal notNull(destination) returns (uint256 transactionId) { - transactionId = transactionCount; - transactions[transactionId] = Transaction({ - destination: destination, - value: value, - data: data, - executed: false - }); - transactionCount += 1; - emit Submission(transactionId); - } - - /* - * Web3 call functions - */ - /// @dev Returns number of confirmations of a transaction. - /// @param transactionId Transaction ID. - /// @return count Number of confirmations. - function getConfirmationCount(uint256 transactionId) - public - view - returns (uint256 count) - { - for (uint256 i = 0; i < owners.length; i++) { - if (confirmations[transactionId][owners[i]]) { - count += 1; - } - } - } - - /// @dev Returns total number of transactions after filers are applied. - /// @param pending Include pending transactions. - /// @param executed Include executed transactions. - /// @return count Total number of transactions after filters are applied. - function getTransactionCount(bool pending, bool executed) - public - view - returns (uint256 count) - { - for (uint256 i = 0; i < transactionCount; i++) { - if ( - (pending && !transactions[i].executed) || - (executed && transactions[i].executed) - ) { - count += 1; - } - } - } - - /// @dev Returns list of owners. - /// @return List of owner addresses. - function getOwners() public view returns (address[] memory) { - return owners; - } - - /// @dev Returns array with owner addresses, which confirmed transaction. - /// @param transactionId Transaction ID. - /// @return _confirmations Returns array of owner addresses. - function getConfirmations(uint256 transactionId) - public - view - returns (address[] memory _confirmations) - { - address[] memory confirmationsTemp = new address[](owners.length); - uint256 count = 0; - uint256 i; - for (i = 0; i < owners.length; i++) - if (confirmations[transactionId][owners[i]]) { - confirmationsTemp[count] = owners[i]; - count += 1; - } - _confirmations = new address[](count); - for (i = 0; i < count; i++) _confirmations[i] = confirmationsTemp[i]; - } - - /// @dev Returns list of transaction IDs in defined range. - /// @param from Index start position of transaction array. - /// @param to Index end position of transaction array. - /// @param pending Include pending transactions. - /// @param executed Include executed transactions. - /// @return _transactionIds Returns array of transaction IDs. - function getTransactionIds( - uint256 from, - uint256 to, - bool pending, - bool executed - ) public view returns (uint256[] memory _transactionIds) { - uint256[] memory transactionIdsTemp = new uint256[](transactionCount); - uint256 count = 0; - uint256 i; - for (i = 0; i < transactionCount; i++) - if ( - (pending && !transactions[i].executed) || - (executed && transactions[i].executed) - ) { - transactionIdsTemp[count] = i; - count += 1; - } - _transactionIds = new uint256[](to - from); - for (i = from; i < to; i++) - _transactionIds[i - from] = transactionIdsTemp[i]; - } -} diff --git a/flatten/PriceOracle.sol b/flatten/PriceOracle.sol deleted file mode 100644 index f3e187e..0000000 --- a/flatten/PriceOracle.sol +++ /dev/null @@ -1,3947 +0,0 @@ -// Dependency file: contracts/ComptrollerInterface.sol - -// SPDX-License-Identifier: UNLICENSED -// pragma solidity 0.8.6; - -abstract contract ComptrollerInterface { - /// @notice Indicator that this is a Comptroller contract (for inspection) - bool public constant isComptroller = true; - - /*** Assets You Are In ***/ - - function enterMarkets(address[] calldata cTokens) - external - virtual - returns (uint256[] memory); - - function exitMarket(address cToken) external virtual returns (uint256); - - /*** Policy Hooks ***/ - - function mintAllowed( - address cToken, - address minter, - uint256 mintAmount - ) external virtual returns (uint256); - - function mintVerify( - address cToken, - address minter, - uint256 mintAmount, - uint256 mintTokens - ) external virtual; - - function redeemAllowed( - address cToken, - address redeemer, - uint256 redeemTokens - ) external virtual returns (uint256); - - function redeemVerify( - address cToken, - address redeemer, - uint256 redeemAmount, - uint256 redeemTokens - ) external virtual; - - function borrowAllowed( - address cToken, - address borrower, - uint256 borrowAmount - ) external virtual returns (uint256); - - function borrowVerify( - address cToken, - address borrower, - uint256 borrowAmount - ) external virtual; - - function repayBorrowAllowed( - address cToken, - address payer, - address borrower, - uint256 repayAmount - ) external virtual returns (uint256); - - function repayBorrowVerify( - address cToken, - address payer, - address borrower, - uint256 repayAmount, - uint256 borrowerIndex - ) external virtual; - - function liquidateBorrowAllowed( - address cTokenBorrowed, - address cTokenCollateral, - address liquidator, - address borrower, - uint256 repayAmount - ) external virtual returns (uint256); - - function liquidateBorrowVerify( - address cTokenBorrowed, - address cTokenCollateral, - address liquidator, - address borrower, - uint256 repayAmount, - uint256 seizeTokens - ) external virtual; - - function seizeAllowed( - address cTokenCollateral, - address cTokenBorrowed, - address liquidator, - address borrower, - uint256 seizeTokens - ) external virtual returns (uint256); - - function seizeVerify( - address cTokenCollateral, - address cTokenBorrowed, - address liquidator, - address borrower, - uint256 seizeTokens - ) external virtual; - - function transferAllowed( - address cToken, - address src, - address dst, - uint256 transferTokens - ) external virtual returns (uint256); - - function transferVerify( - address cToken, - address src, - address dst, - uint256 transferTokens - ) external virtual; - - /*** Liquidity/Liquidation Calculations ***/ - - function liquidateCalculateSeizeTokens( - address cTokenBorrowed, - address cTokenCollateral, - uint256 repayAmount - ) external view virtual returns (uint256, uint256); -} - - -// Dependency file: contracts/CarefulMath.sol - -// pragma solidity 0.8.6; - -/** - * @title Careful Math - * @author tropykus - * @notice Derived from OpenZeppelin's SafeMath library - * https://github.com/OpenZeppelin/openzeppelin-solidity/blob/master/contracts/math/SafeMath.sol - */ -contract CarefulMath { - - /** - * @dev Possible error codes that we can return - */ - enum MathError { - NO_ERROR, - DIVISION_BY_ZERO, - INTEGER_OVERFLOW, - INTEGER_UNDERFLOW - } - - /** - * @dev Multiplies two numbers, returns an error on overflow. - */ - function mulUInt(uint a, uint b) internal pure returns (MathError, uint) { - if (a == 0) { - return (MathError.NO_ERROR, 0); - } - - uint c = a * b; - - if (c / a != b) { - return (MathError.INTEGER_OVERFLOW, 0); - } else { - return (MathError.NO_ERROR, c); - } - } - - /** - * @dev Integer division of two numbers, truncating the quotient. - */ - function divUInt(uint a, uint b) internal pure returns (MathError, uint) { - if (b == 0) { - return (MathError.DIVISION_BY_ZERO, 0); - } - - return (MathError.NO_ERROR, a / b); - } - - /** - * @dev Subtracts two numbers, returns an error on overflow (i.e. if subtrahend is greater than minuend). - */ - function subUInt(uint a, uint b) internal pure returns (MathError, uint) { - if (b <= a) { - return (MathError.NO_ERROR, a - b); - } else { - return (MathError.INTEGER_UNDERFLOW, 0); - } - } - - /** - * @dev Adds two numbers, returns an error on overflow. - */ - function addUInt(uint a, uint b) internal pure returns (MathError, uint) { - uint c = a + b; - - if (c >= a) { - return (MathError.NO_ERROR, c); - } else { - return (MathError.INTEGER_OVERFLOW, 0); - } - } - - /** - * @dev add a and b and then subtract c - */ - function addThenSubUInt(uint a, uint b, uint c) internal pure returns (MathError, uint) { - (MathError err0, uint sum) = addUInt(a, b); - - if (err0 != MathError.NO_ERROR) { - return (err0, 0); - } - - return subUInt(sum, c); - } -} - - -// Dependency file: contracts/ExponentialNoError.sol - -// pragma solidity 0.8.6; - -/** - * @title Exponential module for storing fixed-precision decimals - * @author tropykus - * @notice Exp is a struct which stores decimals with a fixed precision of 18 decimal places. - * Thus, if we wanted to store the 5.1, mantissa would store 5.1e18. That is: - * `Exp({mantissa: 5100000000000000000})`. - */ -contract ExponentialNoError { - uint constant expScale = 1e18; - uint constant doubleScale = 1e36; - uint constant halfExpScale = expScale/2; - uint constant mantissaOne = expScale; - - struct Exp { - uint mantissa; - } - - struct Double { - uint mantissa; - } - - /** - * @dev Truncates the given exp to a whole number value. - * For example, truncate(Exp{mantissa: 15 * expScale}) = 15 - */ - function truncate(Exp memory exp) pure internal returns (uint) { - // Note: We are not using careful math here as we're performing a division that cannot fail - return exp.mantissa / expScale; - } - - /** - * @dev Multiply an Exp by a scalar, then truncate to return an unsigned integer. - */ - function mul_ScalarTruncate(Exp memory a, uint scalar) pure internal returns (uint) { - Exp memory product = mul_(a, scalar); - return truncate(product); - } - - /** - * @dev Multiply an Exp by a scalar, truncate, then add an to an unsigned integer, returning an unsigned integer. - */ - function mul_ScalarTruncateAddUInt(Exp memory a, uint scalar, uint addend) pure internal returns (uint) { - Exp memory product = mul_(a, scalar); - return add_(truncate(product), addend); - } - - /** - * @dev Checks if first Exp is less than second Exp. - */ - function lessThanExp(Exp memory left, Exp memory right) pure internal returns (bool) { - return left.mantissa < right.mantissa; - } - - /** - * @dev Checks if left Exp <= right Exp. - */ - function lessThanOrEqualExp(Exp memory left, Exp memory right) pure internal returns (bool) { - return left.mantissa <= right.mantissa; - } - - /** - * @dev Checks if left Exp > right Exp. - */ - function greaterThanExp(Exp memory left, Exp memory right) pure internal returns (bool) { - return left.mantissa > right.mantissa; - } - - /** - * @dev returns true if Exp is exactly zero - */ - function isZeroExp(Exp memory value) pure internal returns (bool) { - return value.mantissa == 0; - } - - function safe224(uint n, string memory errorMessage) pure internal returns (uint224) { - require(n < 2**224, errorMessage); - return uint224(n); - } - - function safe32(uint n, string memory errorMessage) pure internal returns (uint32) { - require(n < 2**32, errorMessage); - return uint32(n); - } - - function add_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { - return Exp({mantissa: add_(a.mantissa, b.mantissa)}); - } - - function add_(Double memory a, Double memory b) pure internal returns (Double memory) { - return Double({mantissa: add_(a.mantissa, b.mantissa)}); - } - - function add_(uint a, uint b) pure internal returns (uint) { - return add_(a, b, "addition overflow"); - } - - function add_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { - uint c = a + b; - require(c >= a, errorMessage); - return c; - } - - function sub_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { - return Exp({mantissa: sub_(a.mantissa, b.mantissa)}); - } - - function sub_(Double memory a, Double memory b) pure internal returns (Double memory) { - return Double({mantissa: sub_(a.mantissa, b.mantissa)}); - } - - function sub_(uint a, uint b) pure internal returns (uint) { - return sub_(a, b, "subtraction underflow"); - } - - function sub_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { - require(b <= a, errorMessage); - return a - b; - } - - function mul_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { - return Exp({mantissa: mul_(a.mantissa, b.mantissa) / expScale}); - } - - function mul_(Exp memory a, uint b) pure internal returns (Exp memory) { - return Exp({mantissa: mul_(a.mantissa, b)}); - } - - function mul_(uint a, Exp memory b) pure internal returns (uint) { - return mul_(a, b.mantissa) / expScale; - } - - function mul_(Double memory a, Double memory b) pure internal returns (Double memory) { - return Double({mantissa: mul_(a.mantissa, b.mantissa) / doubleScale}); - } - - function mul_(Double memory a, uint b) pure internal returns (Double memory) { - return Double({mantissa: mul_(a.mantissa, b)}); - } - - function mul_(uint a, Double memory b) pure internal returns (uint) { - return mul_(a, b.mantissa) / doubleScale; - } - - function mul_(uint a, uint b) pure internal returns (uint) { - return mul_(a, b, "multiplication overflow"); - } - - function mul_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { - if (a == 0 || b == 0) { - return 0; - } - uint c = a * b; - require(c / a == b, errorMessage); - return c; - } - - function div_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { - return Exp({mantissa: div_(mul_(a.mantissa, expScale), b.mantissa)}); - } - - function div_(Exp memory a, uint b) pure internal returns (Exp memory) { - return Exp({mantissa: div_(a.mantissa, b)}); - } - - function div_(uint a, Exp memory b) pure internal returns (uint) { - return div_(mul_(a, expScale), b.mantissa); - } - - function div_(Double memory a, Double memory b) pure internal returns (Double memory) { - return Double({mantissa: div_(mul_(a.mantissa, doubleScale), b.mantissa)}); - } - - function div_(Double memory a, uint b) pure internal returns (Double memory) { - return Double({mantissa: div_(a.mantissa, b)}); - } - - function div_(uint a, Double memory b) pure internal returns (uint) { - return div_(mul_(a, doubleScale), b.mantissa); - } - - function div_(uint a, uint b) pure internal returns (uint) { - return div_(a, b, "divide by zero"); - } - - function div_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { - require(b > 0, errorMessage); - return a / b; - } - - function fraction(uint a, uint b) pure internal returns (Double memory) { - return Double({mantissa: div_(mul_(a, doubleScale), b)}); - } -} - - -// Dependency file: contracts/Exponential.sol - -// pragma solidity 0.8.6; - -// import "contracts/CarefulMath.sol"; -// import "contracts/ExponentialNoError.sol"; - -/** - * @title Exponential module for storing fixed-precision decimals - * @author tropykus - * @dev Legacy contract for compatibility reasons with existing contracts that still use MathError - * @notice Exp is a struct which stores decimals with a fixed precision of 18 decimal places. - * Thus, if we wanted to store the 5.1, mantissa would store 5.1e18. That is: - * `Exp({mantissa: 5100000000000000000})`. - */ -contract Exponential is CarefulMath, ExponentialNoError { - /** - * @dev Creates an exponential from numerator and denominator values. - * Note: Returns an error if (`num` * 10e18) > MAX_INT, - * or if `denom` is zero. - */ - function getExp(uint num, uint denom) internal pure returns (MathError, Exp memory) { - (MathError err0, uint scaledNumerator) = mulUInt(num, expScale); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - - (MathError err1, uint rational) = divUInt(scaledNumerator, denom); - if (err1 != MathError.NO_ERROR) { - return (err1, Exp({mantissa: 0})); - } - - return (MathError.NO_ERROR, Exp({mantissa: rational})); - } - - /** - * @dev Adds two exponentials, returning a new exponential. - */ - function addExp(Exp memory a, Exp memory b) internal pure returns (MathError, Exp memory) { - (MathError error, uint result) = addUInt(a.mantissa, b.mantissa); - - return (error, Exp({mantissa: result})); - } - - /** - * @dev Subtracts two exponentials, returning a new exponential. - */ - function subExp(Exp memory a, Exp memory b) internal pure returns (MathError, Exp memory) { - (MathError error, uint result) = subUInt(a.mantissa, b.mantissa); - - return (error, Exp({mantissa: result})); - } - - /** - * @dev Multiply an Exp by a scalar, returning a new Exp. - */ - function mulScalar(Exp memory a, uint scalar) internal pure returns (MathError, Exp memory) { - (MathError err0, uint scaledMantissa) = mulUInt(a.mantissa, scalar); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - - return (MathError.NO_ERROR, Exp({mantissa: scaledMantissa})); - } - - /** - * @dev Multiply an Exp by a scalar, then truncate to return an unsigned integer. - */ - function mulScalarTruncate(Exp memory a, uint scalar) internal pure returns (MathError, uint) { - (MathError err, Exp memory product) = mulScalar(a, scalar); - if (err != MathError.NO_ERROR) { - return (err, 0); - } - - return (MathError.NO_ERROR, truncate(product)); - } - - /** - * @dev Multiply an Exp by a scalar, truncate, then add an to an unsigned integer, returning an unsigned integer. - */ - function mulScalarTruncateAddUInt(Exp memory a, uint scalar, uint addend) internal pure returns (MathError, uint) { - (MathError err, Exp memory product) = mulScalar(a, scalar); - if (err != MathError.NO_ERROR) { - return (err, 0); - } - - return addUInt(truncate(product), addend); - } - - /** - * @dev Divide an Exp by a scalar, returning a new Exp. - */ - function divScalar(Exp memory a, uint scalar) internal pure returns (MathError, Exp memory) { - (MathError err0, uint descaledMantissa) = divUInt(a.mantissa, scalar); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - - return (MathError.NO_ERROR, Exp({mantissa: descaledMantissa})); - } - - /** - * @dev Divide a scalar by an Exp, returning a new Exp. - */ - function divScalarByExp(uint scalar, Exp memory divisor) internal pure returns (MathError, Exp memory) { - /* - We are doing this as: - getExp(mulUInt(expScale, scalar), divisor.mantissa) - - How it works: - Exp = a / b; - Scalar = s; - `s / (a / b)` = `b * s / a` and since for an Exp `a = mantissa, b = expScale` - */ - (MathError err0, uint numerator) = mulUInt(expScale, scalar); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - return getExp(numerator, divisor.mantissa); - } - - /** - * @dev Divide a scalar by an Exp, then truncate to return an unsigned integer. - */ - function divScalarByExpTruncate(uint scalar, Exp memory divisor) internal pure returns (MathError, uint) { - (MathError err, Exp memory fraction) = divScalarByExp(scalar, divisor); - if (err != MathError.NO_ERROR) { - return (err, 0); - } - - return (MathError.NO_ERROR, truncate(fraction)); - } - - /** - * @dev Multiplies two exponentials, returning a new exponential. - */ - function mulExp(Exp memory a, Exp memory b) internal pure returns (MathError, Exp memory) { - - (MathError err0, uint doubleScaledProduct) = mulUInt(a.mantissa, b.mantissa); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - - // We add half the scale before dividing so that we get rounding instead of truncation. - // See "Listing 6" and text above it at https://accu.org/index.php/journals/1717 - // Without this change, a result like 6.6...e-19 will be truncated to 0 instead of being rounded to 1e-18. - (MathError err1, uint doubleScaledProductWithHalfScale) = addUInt(halfExpScale, doubleScaledProduct); - if (err1 != MathError.NO_ERROR) { - return (err1, Exp({mantissa: 0})); - } - - (MathError err2, uint product) = divUInt(doubleScaledProductWithHalfScale, expScale); - // The only error `div` can return is MathError.DIVISION_BY_ZERO but we control `expScale` and it is not zero. - assert(err2 == MathError.NO_ERROR); - - return (MathError.NO_ERROR, Exp({mantissa: product})); - } - - /** - * @dev Multiplies two exponentials given their mantissas, returning a new exponential. - */ - function mulExp(uint a, uint b) internal pure returns (MathError, Exp memory) { - return mulExp(Exp({mantissa: a}), Exp({mantissa: b})); - } - - /** - * @dev Multiplies three exponentials, returning a new exponential. - */ - function mulExp3(Exp memory a, Exp memory b, Exp memory c) internal pure returns (MathError, Exp memory) { - (MathError err, Exp memory ab) = mulExp(a, b); - if (err != MathError.NO_ERROR) { - return (err, ab); - } - return mulExp(ab, c); - } - - /** - * @dev Divides two exponentials, returning a new exponential. - * (a/scale) / (b/scale) = (a/scale) * (scale/b) = a/b, - * which we can scale as an Exp by calling getExp(a.mantissa, b.mantissa) - */ - function divExp(Exp memory a, Exp memory b) internal pure returns (MathError, Exp memory) { - return getExp(a.mantissa, b.mantissa); - } -} - - -// Dependency file: contracts/SafeMath.sol - -// pragma solidity 0.8.6; - -// From https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/math/Math.sol -// Subject to the MIT license. - -/** - * @dev Wrappers over Solidity's arithmetic operations with added overflow - * checks. - * - * Arithmetic operations in Solidity wrap on overflow. This can easily result - * in bugs, because programmers usually assume that an overflow raises an - * error, which is the standard behavior in high level programming languages. - * `SafeMath` restores this intuition by reverting the transaction when an - * operation overflows. - * - * Using this library instead of the unchecked operations eliminates an entire - * class of bugs, so it's recommended to use it always. - */ -library SafeMath { - /** - * @dev Returns the addition of two unsigned integers, reverting on overflow. - * - * Counterpart to Solidity's `+` operator. - * - * Requirements: - * - Addition cannot overflow. - */ - function add(uint256 a, uint256 b) internal pure returns (uint256) { - uint256 c = a + b; - require(c >= a, "SafeMath: addition overflow"); - - return c; - } - - /** - * @dev Returns the addition of two unsigned integers, reverting with custom message on overflow. - * - * Counterpart to Solidity's `+` operator. - * - * Requirements: - * - Addition cannot overflow. - */ - function add(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - uint256 c = a + b; - require(c >= a, errorMessage); - - return c; - } - - /** - * @dev Returns the subtraction of two unsigned integers, reverting on underflow (when the result is negative). - * - * Counterpart to Solidity's `-` operator. - * - * Requirements: - * - Subtraction cannot underflow. - */ - function sub(uint256 a, uint256 b) internal pure returns (uint256) { - return sub(a, b, "SafeMath: subtraction underflow"); - } - - /** - * @dev Returns the subtraction of two unsigned integers, reverting with custom message on underflow (when the result is negative). - * - * Counterpart to Solidity's `-` operator. - * - * Requirements: - * - Subtraction cannot underflow. - */ - function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - require(b <= a, errorMessage); - uint256 c = a - b; - - return c; - } - - /** - * @dev Returns the multiplication of two unsigned integers, reverting on overflow. - * - * Counterpart to Solidity's `*` operator. - * - * Requirements: - * - Multiplication cannot overflow. - */ - function mul(uint256 a, uint256 b) internal pure returns (uint256) { - // Gas optimization: this is cheaper than requiring 'a' not being zero, but the - // benefit is lost if 'b' is also tested. - // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 - if (a == 0) { - return 0; - } - - uint256 c = a * b; - require(c / a == b, "SafeMath: multiplication overflow"); - - return c; - } - - /** - * @dev Returns the multiplication of two unsigned integers, reverting on overflow. - * - * Counterpart to Solidity's `*` operator. - * - * Requirements: - * - Multiplication cannot overflow. - */ - function mul(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - // Gas optimization: this is cheaper than requiring 'a' not being zero, but the - // benefit is lost if 'b' is also tested. - // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 - if (a == 0) { - return 0; - } - - uint256 c = a * b; - require(c / a == b, errorMessage); - - return c; - } - - /** - * @dev Returns the integer division of two unsigned integers. - * Reverts on division by zero. The result is rounded towards zero. - * - * Counterpart to Solidity's `/` operator. Note: this function uses a - * `revert` opcode (which leaves remaining gas untouched) while Solidity - * uses an invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function div(uint256 a, uint256 b) internal pure returns (uint256) { - return div(a, b, "SafeMath: division by zero"); - } - - /** - * @dev Returns the integer division of two unsigned integers. - * Reverts with custom message on division by zero. The result is rounded towards zero. - * - * Counterpart to Solidity's `/` operator. Note: this function uses a - * `revert` opcode (which leaves remaining gas untouched) while Solidity - * uses an invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - // Solidity only automatically asserts when dividing by 0 - require(b > 0, errorMessage); - uint256 c = a / b; - // assert(a == b * c + a % b); // There is no case in which this doesn't hold - - return c; - } - - /** - * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), - * Reverts when dividing by zero. - * - * Counterpart to Solidity's `%` operator. This function uses a `revert` - * opcode (which leaves remaining gas untouched) while Solidity uses an - * invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function mod(uint256 a, uint256 b) internal pure returns (uint256) { - return mod(a, b, "SafeMath: modulo by zero"); - } - - /** - * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), - * Reverts with custom message when dividing by zero. - * - * Counterpart to Solidity's `%` operator. This function uses a `revert` - * opcode (which leaves remaining gas untouched) while Solidity uses an - * invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - require(b != 0, errorMessage); - return a % b; - } -} - - -// Dependency file: contracts/InterestRateModel.sol - -// pragma solidity 0.8.6; - -// import "contracts/Exponential.sol"; -// import "contracts/SafeMath.sol"; - -/** - * @title tropykus InterestRateModel Interface - * @author tropykus - */ -abstract contract InterestRateModel is Exponential { - using SafeMath for uint256; - - /// @notice Indicator that this is an InterestRateModel contract (for inspection) - bool public constant isInterestRateModel = true; - bool public isTropykusInterestRateModel; - - /** - * @notice The approximate number of blocks per year that is assumed by the interest rate model - */ - uint256 public constant blocksPerYear = 1051200; - - /** - * @notice Calculates the utilization rate of the market: `borrows / (cash + borrows - reserves)` - * @param cash The amount of cash in the market - * @param borrows The amount of borrows in the market - * @param reserves The amount of reserves in the market (currently unused) - * @return The utilization rate as a mantissa between [0, 1e18] - */ - function utilizationRate( - uint256 cash, - uint256 borrows, - uint256 reserves - ) public pure virtual returns (uint256) { - // Utilization rate is 0 when there are no borrows - if (borrows == 0) { - return 0; - } - - return borrows.mul(1e18).div(cash.add(borrows).sub(reserves)); - } - - /** - * @notice Calculates the current borrow interest rate per block - * @param cash The total amount of cash the market has - * @param borrows The total amount of borrows the market has outstanding - * @param reserves The total amnount of reserves the market has - * @return The borrow rate per block (as a percentage, and scaled by 1e18) - */ - function getBorrowRate( - uint256 cash, - uint256 borrows, - uint256 reserves - ) external view virtual returns (uint256); - - /** - * @notice Calculates the current supply interest rate per block - * @param cash The total amount of cash the market has - * @param borrows The total amount of borrows the market has outstanding - * @param reserves The total amnount of reserves the market has - * @param reserveFactorMantissa The current reserve factor the market has - * @return The supply rate per block (as a percentage, and scaled by 1e18) - */ - function getSupplyRate( - uint256 cash, - uint256 borrows, - uint256 reserves, - uint256 reserveFactorMantissa - ) external view virtual returns (uint256); - - function getExchangeRate( - uint256 _totalCash, - uint256 _totalBorrows, - uint256 _totalReserves, - uint256 _totalSupply - ) public pure returns (MathError, uint256) { - /* - * exchangeRate = (totalCash + totalBorrows - totalReserves) / totalSupply - */ - Exp memory exchangeRate; - MathError mathErr; - uint256 cashPlusBorrowsMinusReserves; - (mathErr, cashPlusBorrowsMinusReserves) = addThenSubUInt( - _totalCash, - _totalBorrows, - _totalReserves - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - (mathErr, exchangeRate) = getExp( - cashPlusBorrowsMinusReserves, - _totalSupply - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - - return (MathError.NO_ERROR, exchangeRate.mantissa); - } - - function isAboveOptimal( - uint256 cash, - uint256 borrows, - uint256 reserves - ) public view virtual returns (bool) { - cash; - borrows; - reserves; - return false; - } -} - - -// Dependency file: contracts/EIP20NonStandardInterface.sol - -// pragma solidity 0.8.6; - -/** - * @title EIP20NonStandardInterface - * @dev Version of ERC20 with no return values for `transfer` and `transferFrom` - * See https://medium.com/coinmonks/missing-return-value-bug-at-least-130-tokens-affected-d67bf08521ca - */ -interface EIP20NonStandardInterface { - /** - * @notice Get the total number of tokens in circulation - * @return The supply of tokens - */ - function totalSupply() external view returns (uint256); - - /** - * @notice Gets the balance of the specified address - * @param owner The address from which the balance will be retrieved - * @return balance The balance - */ - function balanceOf(address owner) external view returns (uint256 balance); - - /// - /// !!!!!!!!!!!!!! - /// !!! NOTICE !!! `transfer` does not return a value, in violation of the ERC-20 specification - /// !!!!!!!!!!!!!! - /// - - /** - * @notice Transfer `amount` tokens from `msg.sender` to `dst` - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - */ - function transfer(address dst, uint256 amount) external; - - /// - /// !!!!!!!!!!!!!! - /// !!! NOTICE !!! `transferFrom` does not return a value, in violation of the ERC-20 specification - /// !!!!!!!!!!!!!! - /// - - /** - * @notice Transfer `amount` tokens from `src` to `dst` - * @param src The address of the source account - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - */ - function transferFrom( - address src, - address dst, - uint256 amount - ) external; - - /** - * @notice Approve `spender` to transfer up to `amount` from `src` - * @dev This will overwrite the approval amount for `spender` - * and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve) - * @param spender The address of the account which may transfer tokens - * @param amount The number of tokens that are approved - * @return success Whether or not the approval succeeded - */ - function approve(address spender, uint256 amount) - external - returns (bool success); - - /** - * @notice Get the current allowance from `owner` for `spender` - * @param owner The address of the account which owns the tokens to be spent - * @param spender The address of the account which may transfer tokens - * @return remaining The number of tokens allowed to be spent - */ - function allowance(address owner, address spender) - external - view - returns (uint256 remaining); - - event Transfer(address indexed from, address indexed to, uint256 amount); - event Approval( - address indexed owner, - address indexed spender, - uint256 amount - ); -} - - -// Dependency file: contracts/CTokenInterfaces.sol - -// pragma solidity 0.8.6; - -// import "contracts/ComptrollerInterface.sol"; -// import "contracts/InterestRateModel.sol"; -// import "contracts/EIP20NonStandardInterface.sol"; - -contract CTokenStorage { - /** - * @dev Guard variable for re-entrancy checks - */ - bool internal _notEntered; - - /** - * @notice EIP-20 token name for this token - */ - string public name; - - /** - * @notice EIP-20 token symbol for this token - */ - string public symbol; - - /** - * @notice EIP-20 token decimals for this token - */ - uint8 public decimals; - - /** - * @notice Maximum borrow rate that can ever be applied (.0005% / block) - */ - - uint256 internal constant borrowRateMaxMantissa = 0.0005e16; - - /** - * @notice Maximum fraction of interest that can be set aside for reserves - */ - uint256 internal constant reserveFactorMaxMantissa = 1e18; - - /** - * @notice Administrator for this contract - */ - address payable public admin; - - /** - * @notice Pending administrator for this contract - */ - address payable public pendingAdmin; - - /** - * @notice Contract which oversees inter-cToken operations - */ - ComptrollerInterface public comptroller; - - /** - * @notice Model which tells what the current interest rate should be - */ - InterestRateModel public interestRateModel; - - /** - * @notice Initial exchange rate used when minting the first CTokens (used when totalSupply = 0) - */ - uint256 public initialExchangeRateMantissa; - - /** - * @notice Fraction of interest currently set aside for reserves - */ - uint256 public reserveFactorMantissa; - - /** - * @notice Block number that interest was last accrued at - */ - uint256 public accrualBlockNumber; - - /** - * @notice Accumulator of the total earned interest rate since the opening of the market - */ - uint256 public borrowIndex; - - /** - * @notice Total amount of outstanding borrows of the underlying in this market - */ - uint256 public totalBorrows; - - /** - * @notice Total amount of reserves of the underlying held in this market - */ - uint256 public totalReserves; - - /** - * @notice Total number of tokens in circulation - */ - uint256 public totalSupply; - - uint256 public subsidyFund; - - struct SupplySnapshot { - uint256 tokens; - uint256 underlyingAmount; - uint256 suppliedAt; - uint256 promisedSupplyRate; - } - - /** - * @notice Official record of token balances for each account - */ - mapping(address => SupplySnapshot) internal accountTokens; - - /** - * @notice Approved token transfer amounts on behalf of others - */ - mapping(address => mapping(address => uint256)) internal transferAllowances; - - /** - * @notice Container for borrow balance information - * @member principal Total balance (with accrued interest), after applying the most recent balance-changing action - * @member interestIndex Global borrowIndex as of the most recent balance-changing action - */ - struct BorrowSnapshot { - uint256 principal; - uint256 interestIndex; - } - - /** - * @notice Mapping of account addresses to outstanding borrow balances - */ - mapping(address => BorrowSnapshot) internal accountBorrows; -} - -abstract contract CTokenInterface is CTokenStorage { - /** - * @notice Indicator that this is a CToken contract (for inspection) - */ - bool public constant isCToken = true; - - /*** Market Events ***/ - - /** - * @notice Event emitted when interest is accrued - */ - event AccrueInterest( - uint256 cashPrior, - uint256 interestAccumulated, - uint256 borrowIndex, - uint256 totalBorrows - ); - - /** - * @notice Event emitted when tokens are minted - */ - event Mint(address indexed minter, uint256 mintAmount, uint256 mintTokens); - - /** - * @notice Event emitted when tokens are redeemed - */ - event Redeem( - address indexed redeemer, - uint256 redeemAmount, - uint256 redeemTokens - ); - - /** - * @notice Event emitted when underlying is borrowed - */ - event Borrow( - address indexed borrower, - uint256 borrowAmount, - uint256 accountBorrows, - uint256 totalBorrows - ); - - /** - * @notice Event emitted when a borrow is repaid - */ - event RepayBorrow( - address indexed payer, - address indexed borrower, - uint256 repayAmount, - uint256 accountBorrows, - uint256 totalBorrows - ); - - /** - * @notice Event emitted when a borrow is liquidated - */ - event LiquidateBorrow( - address indexed liquidator, - address indexed borrower, - uint256 repayAmount, - address indexed cTokenCollateral, - uint256 seizeTokens - ); - - /*** Admin Events ***/ - - /** - * @notice Event emitted when pendingAdmin is changed - */ - event NewPendingAdmin(address oldPendingAdmin, address newPendingAdmin); - - /** - * @notice Event emitted when pendingAdmin is accepted, which means admin is updated - */ - event NewAdmin(address oldAdmin, address newAdmin); - - /** - * @notice Event emitted when comptroller is changed - */ - event NewComptroller( - ComptrollerInterface oldComptroller, - ComptrollerInterface newComptroller - ); - - /** - * @notice Event emitted when interestRateModel is changed - */ - event NewMarketInterestRateModel( - InterestRateModel oldInterestRateModel, - InterestRateModel newInterestRateModel - ); - - /** - * @notice Event emitted when the reserve factor is changed - */ - event NewReserveFactor( - uint256 oldReserveFactorMantissa, - uint256 newReserveFactorMantissa - ); - - /** - * @notice Event emitted when the reserves are added - */ - event ReservesAdded( - address benefactor, - uint256 addAmount, - uint256 newTotalReserves - ); - - event SubsidyAdded( - address benefactor, - uint256 addAmount, - uint256 newSubsidyFund - ); - - /** - * @notice Event emitted when the reserves are reduced - */ - event ReservesReduced( - address admin, - uint256 reduceAmount, - uint256 newTotalReserves - ); - - /** - * @notice EIP20 Transfer event - */ - event Transfer(address indexed from, address indexed to, uint256 amount); - - /** - * @notice EIP20 Approval event - */ - event Approval( - address indexed owner, - address indexed spender, - uint256 amount - ); - - /** - * @notice Failure event - */ - event CTokenStorageFailure(uint256 error, uint256 info, uint256 detail); - - /*** User Interface ***/ - - function transfer(address dst, uint256 amount) - external - virtual - returns (bool); - - function transferFrom( - address src, - address dst, - uint256 amount - ) external virtual returns (bool); - - function approve(address spender, uint256 amount) - external - virtual - returns (bool); - - function allowance(address owner, address spender) - external - view - virtual - returns (uint256); - - function balanceOf(address owner) external view virtual returns (uint256); - - function balanceOfUnderlying(address owner) - external - virtual - returns (uint256); - - function getAccountSnapshot(address account) - external - view - virtual - returns ( - uint256, - uint256, - uint256, - uint256 - ); - - function borrowRatePerBlock() external view virtual returns (uint256); - - function supplyRatePerBlock() external view virtual returns (uint256); - - function totalBorrowsCurrent() external virtual returns (uint256); - - function borrowBalanceCurrent(address account) - external - virtual - returns (uint256); - - function borrowBalanceStored(address account) - public - view - virtual - returns (uint256); - - function exchangeRateCurrent() public virtual returns (uint256); - - function exchangeRateStored() public view virtual returns (uint256); - - function getCash() external view virtual returns (uint256); - - function accrueInterest() public virtual returns (uint256); - - function seize( - address liquidator, - address borrower, - uint256 seizeTokens - ) external virtual returns (uint256); - - /*** Admin Functions ***/ - - function _setPendingAdmin(address payable newPendingAdmin) - external - virtual - returns (uint256); - - function _acceptAdmin() external virtual returns (uint256); - - function _setComptroller(ComptrollerInterface newComptroller) - public - virtual - returns (uint256); - - function _setReserveFactor(uint256 newReserveFactorMantissa) - external - virtual - returns (uint256); - - function _reduceReserves(uint256 reduceAmount) - external - virtual - returns (uint256); - - function _setInterestRateModel(InterestRateModel newInterestRateModel) - public - virtual - returns (uint256); -} - -contract CErc20Storage { - /** - * @notice Underlying asset for this CToken - */ - address public underlying; -} - -abstract contract CErc20Interface is CErc20Storage { - /*** User Interface ***/ - - function mint(uint256 mintAmount) external virtual returns (uint256); - - function redeem(uint256 redeemAmount) - external - virtual - returns (uint256); - - function borrow(uint256 borrowAmount) external virtual returns (uint256); - - function repayBorrow(uint256 repayAmount) - external - virtual - returns (uint256); - - function liquidateBorrow( - address borrower, - uint256 repayAmount, - CTokenInterface cTokenCollateral - ) external virtual returns (uint256); - - function sweepToken(EIP20NonStandardInterface token) external virtual; - - /*** Admin Functions ***/ - - function _addReserves(uint256 addAmount) external virtual returns (uint256); -} - -contract CDelegationStorage { - /** - * @notice Implementation address for this contract - */ - address public implementation; -} - -abstract contract CDelegatorInterface is CDelegationStorage { - /** - * @notice Emitted when implementation is changed - */ - event NewImplementation( - address oldImplementation, - address newImplementation - ); - - /** - * @notice Called by the admin to update the implementation of the delegator - * @param implementation_ The address of the new implementation for delegation - * @param allowResign Flag to indicate whether to call _resignImplementation on the old implementation - * @param becomeImplementationData The encoded bytes data to be passed to _becomeImplementation - */ - function _setImplementation( - address implementation_, - bool allowResign, - bytes memory becomeImplementationData - ) public virtual; -} - -abstract contract CDelegateInterface is CDelegationStorage { - /** - * @notice Called by the delegator on a delegate to initialize it for duty - * @dev Should revert if any issues arise which make it unfit for delegation - * @param data The encoded bytes data for any initialization - */ - function _becomeImplementation(bytes memory data) public virtual; - - /** - * @notice Called by the delegator on a delegate to forfeit its responsibility - */ - function _resignImplementation() public virtual; -} - - -// Dependency file: contracts/ErrorReporter.sol - -// pragma solidity 0.8.6; - -contract ComptrollerErrorReporter { - enum Error { - NO_ERROR, - UNAUTHORIZED, - COMPTROLLER_MISMATCH, - INSUFFICIENT_SHORTFALL, - INSUFFICIENT_LIQUIDITY, - INVALID_CLOSE_FACTOR, - INVALID_COLLATERAL_FACTOR, - INVALID_LIQUIDATION_INCENTIVE, - MARKET_NOT_ENTERED, // no longer possible - MARKET_NOT_LISTED, - MARKET_ALREADY_LISTED, - MATH_ERROR, - NONZERO_BORROW_BALANCE, - PRICE_ERROR, - REJECTION, - SNAPSHOT_ERROR, - TOO_MANY_ASSETS, - TOO_MUCH_REPAY - } - - enum FailureInfo { - ACCEPT_ADMIN_PENDING_ADMIN_CHECK, - ACCEPT_PENDING_IMPLEMENTATION_ADDRESS_CHECK, - EXIT_MARKET_BALANCE_OWED, - EXIT_MARKET_REJECTION, - SET_CLOSE_FACTOR_OWNER_CHECK, - SET_CLOSE_FACTOR_VALIDATION, - SET_COLLATERAL_FACTOR_OWNER_CHECK, - SET_COLLATERAL_FACTOR_NO_EXISTS, - SET_COLLATERAL_FACTOR_VALIDATION, - SET_COLLATERAL_FACTOR_WITHOUT_PRICE, - SET_IMPLEMENTATION_OWNER_CHECK, - SET_LIQUIDATION_INCENTIVE_OWNER_CHECK, - SET_LIQUIDATION_INCENTIVE_VALIDATION, - SET_MAX_ASSETS_OWNER_CHECK, - SET_PENDING_ADMIN_OWNER_CHECK, - SET_PENDING_IMPLEMENTATION_OWNER_CHECK, - SET_PRICE_ORACLE_OWNER_CHECK, - SUPPORT_MARKET_EXISTS, - SUPPORT_MARKET_OWNER_CHECK, - SET_PAUSE_GUARDIAN_OWNER_CHECK - } - - /** - * @dev `error` corresponds to enum Error; `info` corresponds to enum FailureInfo, and `detail` is an arbitrary - * contract-specific code that enables us to report opaque error codes from upgradeable contracts. - **/ - event Failure(uint256 error, uint256 info, uint256 detail); - - /** - * @dev use this when reporting a known error from the money market or a non-upgradeable collaborator - */ - function fail(Error err, FailureInfo info) internal returns (uint256) { - emit Failure(uint256(err), uint256(info), 0); - - return uint256(err); - } - - /** - * @dev use this when reporting an opaque error from an upgradeable collaborator contract - */ - function failOpaque( - Error err, - FailureInfo info, - uint256 opaqueError - ) internal returns (uint256) { - emit Failure(uint256(err), uint256(info), opaqueError); - - return uint256(err); - } -} - -contract TokenErrorReporter { - enum Error { - NO_ERROR, - UNAUTHORIZED, - BAD_INPUT, - COMPTROLLER_REJECTION, - COMPTROLLER_CALCULATION_ERROR, - INTEREST_RATE_MODEL_ERROR, - INVALID_ACCOUNT_PAIR, - INVALID_CLOSE_AMOUNT_REQUESTED, - INVALID_COLLATERAL_FACTOR, - MATH_ERROR, - MARKET_NOT_FRESH, - MARKET_NOT_LISTED, - TOKEN_INSUFFICIENT_ALLOWANCE, - TOKEN_INSUFFICIENT_BALANCE, - TOKEN_INSUFFICIENT_CASH, - TOKEN_TRANSFER_IN_FAILED, - TOKEN_TRANSFER_OUT_FAILED - } - - /* - * Note: FailureInfo (but not Error) is kept in alphabetical order - * This is because FailureInfo grows significantly faster, and - * the order of Error has some meaning, while the order of FailureInfo - * is entirely arbitrary. - */ - enum FailureInfo { - ACCEPT_ADMIN_PENDING_ADMIN_CHECK, - ACCRUE_INTEREST_ACCUMULATED_INTEREST_CALCULATION_FAILED, - ACCRUE_INTEREST_BORROW_RATE_CALCULATION_FAILED, - ACCRUE_INTEREST_NEW_BORROW_INDEX_CALCULATION_FAILED, - ACCRUE_INTEREST_NEW_TOTAL_BORROWS_CALCULATION_FAILED, - ACCRUE_INTEREST_NEW_TOTAL_RESERVES_CALCULATION_FAILED, - ACCRUE_INTEREST_SIMPLE_INTEREST_FACTOR_CALCULATION_FAILED, - BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED, - BORROW_ACCRUE_INTEREST_FAILED, - BORROW_CASH_NOT_AVAILABLE, - BORROW_FRESHNESS_CHECK, - BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED, - BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED, - BORROW_MARKET_NOT_LISTED, - BORROW_COMPTROLLER_REJECTION, - LIQUIDATE_ACCRUE_BORROW_INTEREST_FAILED, - LIQUIDATE_ACCRUE_COLLATERAL_INTEREST_FAILED, - LIQUIDATE_COLLATERAL_FRESHNESS_CHECK, - LIQUIDATE_COMPTROLLER_REJECTION, - LIQUIDATE_COMPTROLLER_CALCULATE_AMOUNT_SEIZE_FAILED, - LIQUIDATE_CLOSE_AMOUNT_IS_UINT_MAX, - LIQUIDATE_CLOSE_AMOUNT_IS_ZERO, - LIQUIDATE_FRESHNESS_CHECK, - LIQUIDATE_LIQUIDATOR_IS_BORROWER, - LIQUIDATE_REPAY_BORROW_FRESH_FAILED, - LIQUIDATE_SEIZE_BALANCE_INCREMENT_FAILED, - LIQUIDATE_SEIZE_BALANCE_DECREMENT_FAILED, - LIQUIDATE_SEIZE_COMPTROLLER_REJECTION, - LIQUIDATE_SEIZE_LIQUIDATOR_IS_BORROWER, - LIQUIDATE_SEIZE_TOO_MUCH, - MINT_ACCRUE_INTEREST_FAILED, - MINT_COMPTROLLER_REJECTION, - MINT_EXCHANGE_CALCULATION_FAILED, - MINT_EXCHANGE_RATE_READ_FAILED, - MINT_FRESHNESS_CHECK, - MINT_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED, - MINT_NEW_TOTAL_SUPPLY_CALCULATION_FAILED, - MINT_TRANSFER_IN_FAILED, - MINT_TRANSFER_IN_NOT_POSSIBLE, - REDEEM_ACCRUE_INTEREST_FAILED, - REDEEM_COMPTROLLER_REJECTION, - REDEEM_EXCHANGE_TOKENS_CALCULATION_FAILED, - REDEEM_EXCHANGE_AMOUNT_CALCULATION_FAILED, - REDEEM_EXCHANGE_RATE_READ_FAILED, - REDEEM_FRESHNESS_CHECK, - REDEEM_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED, - REDEEM_NEW_TOTAL_SUPPLY_CALCULATION_FAILED, - REDEEM_TRANSFER_OUT_NOT_POSSIBLE, - REDUCE_RESERVES_ACCRUE_INTEREST_FAILED, - REDUCE_RESERVES_ADMIN_CHECK, - REDUCE_RESERVES_CASH_NOT_AVAILABLE, - REDUCE_RESERVES_FRESH_CHECK, - REDUCE_RESERVES_VALIDATION, - REPAY_BEHALF_ACCRUE_INTEREST_FAILED, - REPAY_BORROW_ACCRUE_INTEREST_FAILED, - REPAY_BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED, - REPAY_BORROW_COMPTROLLER_REJECTION, - REPAY_BORROW_FRESHNESS_CHECK, - REPAY_BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED, - REPAY_BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED, - REPAY_BORROW_TRANSFER_IN_NOT_POSSIBLE, - SET_COLLATERAL_FACTOR_OWNER_CHECK, - SET_COLLATERAL_FACTOR_VALIDATION, - SET_COMPTROLLER_OWNER_CHECK, - SET_INTEREST_RATE_MODEL_ACCRUE_INTEREST_FAILED, - SET_INTEREST_RATE_MODEL_FRESH_CHECK, - SET_INTEREST_RATE_MODEL_OWNER_CHECK, - SET_MAX_ASSETS_OWNER_CHECK, - SET_ORACLE_MARKET_NOT_LISTED, - SET_PENDING_ADMIN_OWNER_CHECK, - SET_RESERVE_FACTOR_ACCRUE_INTEREST_FAILED, - SET_RESERVE_FACTOR_ADMIN_CHECK, - SET_RESERVE_FACTOR_FRESH_CHECK, - SET_RESERVE_FACTOR_BOUNDS_CHECK, - TRANSFER_COMPTROLLER_REJECTION, - TRANSFER_NOT_ALLOWED, - TRANSFER_NOT_ENOUGH, - TRANSFER_TOO_MUCH, - ADD_RESERVES_ACCRUE_INTEREST_FAILED, - ADD_RESERVES_FRESH_CHECK, - ADD_RESERVES_TRANSFER_IN_NOT_POSSIBLE, - ADD_SUBSIDY_FUND_FAILED, - ADD_SUBSIDY_FUND_FRESH_CHECK - } - - /** - * @dev `error` corresponds to enum Error; `info` corresponds to enum FailureInfo, and `detail` is an arbitrary - * contract-specific code that enables us to report opaque error codes from upgradeable contracts. - **/ - event TokenFailure(uint256 error, uint256 info, uint256 detail); - - /** - * @dev use this when reporting a known error from the money market or a non-upgradeable collaborator - */ - function fail(Error err, FailureInfo info) internal returns (uint256) { - emit TokenFailure(uint256(err), uint256(info), 0); - - return uint256(err); - } - - /** - * @dev use this when reporting an opaque error from an upgradeable collaborator contract - */ - function failOpaque( - Error err, - FailureInfo info, - uint256 opaqueError - ) internal returns (uint256) { - emit TokenFailure(uint256(err), uint256(info), opaqueError); - - return uint256(err); - } -} - - -// Dependency file: contracts/EIP20Interface.sol - -// pragma solidity 0.8.6; - -/** - * @title ERC 20 Token Standard Interface - * https://eips.ethereum.org/EIPS/eip-20 - */ -interface EIP20Interface { - function name() external view returns (string memory); - - function symbol() external view returns (string memory); - - function decimals() external view returns (uint8); - - /** - * @notice Get the total number of tokens in circulation - * @return The supply of tokens - */ - function totalSupply() external view returns (uint256); - - /** - * @notice Gets the balance of the specified address - * @param owner The address from which the balance will be retrieved - * @return balance The balance - */ - function balanceOf(address owner) external view returns (uint256 balance); - - /** - * @notice Transfer `amount` tokens from `msg.sender` to `dst` - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - * @return success Whether or not the transfer succeeded - */ - function transfer(address dst, uint256 amount) - external - returns (bool success); - - /** - * @notice Transfer `amount` tokens from `src` to `dst` - * @param src The address of the source account - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - * @return success Whether or not the transfer succeeded - */ - function transferFrom( - address src, - address dst, - uint256 amount - ) external returns (bool success); - - /** - * @notice Approve `spender` to transfer up to `amount` from `src` - * @dev This will overwrite the approval amount for `spender` - * and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve) - * @param spender The address of the account which may transfer tokens - * @param amount The number of tokens that are approved (-1 means infinite) - * @return success Whether or not the approval succeeded - */ - function approve(address spender, uint256 amount) - external - returns (bool success); - - /** - * @notice Get the current allowance from `owner` for `spender` - * @param owner The address of the account which owns the tokens to be spent - * @param spender The address of the account which may transfer tokens - * @return remaining The number of tokens allowed to be spent (-1 means infinite) - */ - function allowance(address owner, address spender) - external - view - returns (uint256 remaining); - - event Transfer(address indexed from, address indexed to, uint256 amount); - event Approval( - address indexed owner, - address indexed spender, - uint256 amount - ); -} - - -// Dependency file: contracts/WhitelistInterface.sol - -// pragma solidity 0.8.6; - -interface WhitelistInterface { - function setStatus(bool _newStatus) external; - function enabled() external view returns(bool); - - function addUsers(address[] memory _users) external; - function exist(address _user) external view returns(bool); - function getUsers() external view returns(address[] memory currentUsers); - function removeUser(address _user) external; -} - -// Dependency file: contracts/CToken.sol - -// pragma solidity 0.8.6; - -// import "contracts/ComptrollerInterface.sol"; -// import "contracts/CTokenInterfaces.sol"; -// import "contracts/ErrorReporter.sol"; -// import "contracts/Exponential.sol"; -// import "contracts/EIP20Interface.sol"; -// import "contracts/InterestRateModel.sol"; -// import "contracts/WhitelistInterface.sol"; - -/** - * @title tropykus CToken Contract - * @notice Abstract base for CTokens - * @author tropykus - */ -abstract contract CToken is CTokenInterface, Exponential, TokenErrorReporter { - address whitelist; - - /** - * @notice Initialize the money market - * @param comptroller_ The address of the Comptroller - * @param interestRateModel_ The address of the interest rate model - * @param initialExchangeRateMantissa_ The initial exchange rate, scaled by 1e18 - * @param name_ EIP-20 name of this token - * @param symbol_ EIP-20 symbol of this token - * @param decimals_ EIP-20 decimal precision of this token - */ - function initialize( - ComptrollerInterface comptroller_, - InterestRateModel interestRateModel_, - uint256 initialExchangeRateMantissa_, - string memory name_, - string memory symbol_, - uint8 decimals_ - ) public { - require(msg.sender == admin, "CT01"); - require(accrualBlockNumber == 0 && borrowIndex == 0, "CT02"); - - initialExchangeRateMantissa = initialExchangeRateMantissa_; - require(initialExchangeRateMantissa > 0, "CT03"); - - uint256 err = _setComptroller(comptroller_); - require(err == uint256(Error.NO_ERROR), "CT04"); - - accrualBlockNumber = getBlockNumber(); - borrowIndex = mantissaOne; - - err = _setInterestRateModelFresh(interestRateModel_); - require(err == uint256(Error.NO_ERROR), "CT05"); - - name = name_; - symbol = symbol_; - decimals = decimals_; - - _notEntered = true; - } - - function addWhitelist(address _whitelist) external returns (uint256) { - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_INTEREST_RATE_MODEL_OWNER_CHECK - ); - } - whitelist = _whitelist; - } - - /** - * @notice Transfer `tokens` tokens from `src` to `dst` by `spender` - * @dev Called by both `transfer` and `transferFrom` internally - * @param spender The address of the account performing the transfer - * @param src The address of the source account - * @param dst The address of the destination account - * @param tokens The number of tokens to transfer - * @return Whether or not the transfer succeeded - */ - function transferTokens( - address spender, - address src, - address dst, - uint256 tokens - ) internal returns (uint256) { - uint256 allowed = comptroller.transferAllowed( - address(this), - src, - dst, - tokens - ); - if (allowed != 0) { - return - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.TRANSFER_COMPTROLLER_REJECTION, - allowed - ); - } - - if (src == dst) { - return fail(Error.BAD_INPUT, FailureInfo.TRANSFER_NOT_ALLOWED); - } - - uint256 startingAllowance = 0; - if (spender == src) { - startingAllowance = type(uint256).max; - } else { - startingAllowance = transferAllowances[src][spender]; - } - - MathError mathErr; - uint256 allowanceNew; - uint256 srcTokensNew; - uint256 dstTokensNew; - - (mathErr, allowanceNew) = subUInt(startingAllowance, tokens); - if (mathErr != MathError.NO_ERROR) { - return fail(Error.MATH_ERROR, FailureInfo.TRANSFER_NOT_ALLOWED); - } - - (mathErr, srcTokensNew) = subUInt(accountTokens[src].tokens, tokens); - if (mathErr != MathError.NO_ERROR) { - return fail(Error.MATH_ERROR, FailureInfo.TRANSFER_NOT_ENOUGH); - } - - (mathErr, dstTokensNew) = addUInt(accountTokens[dst].tokens, tokens); - if (mathErr != MathError.NO_ERROR) { - return fail(Error.MATH_ERROR, FailureInfo.TRANSFER_TOO_MUCH); - } - - accountTokens[src].tokens = srcTokensNew; - accountTokens[dst].tokens = dstTokensNew; - - if (startingAllowance != type(uint256).max) { - transferAllowances[src][spender] = allowanceNew; - } - - emit Transfer(src, dst, tokens); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Transfer `amount` tokens from `msg.sender` to `dst` - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - * @return Whether or not the transfer succeeded - */ - function transfer(address dst, uint256 amount) - external - override - nonReentrant - returns (bool) - { - return - transferTokens(msg.sender, msg.sender, dst, amount) == - uint256(Error.NO_ERROR); - } - - /** - * @notice Transfer `amount` tokens from `src` to `dst` - * @param src The address of the source account - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - * @return Whether or not the transfer succeeded - */ - function transferFrom( - address src, - address dst, - uint256 amount - ) external override nonReentrant returns (bool) { - return - transferTokens(msg.sender, src, dst, amount) == - uint256(Error.NO_ERROR); - } - - /** - * @notice Approve `spender` to transfer up to `amount` from `src` - * @dev This will overwrite the approval amount for `spender` - * and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve) - * @param spender The address of the account which may transfer tokens - * @param amount The number of tokens that are approved (-1 means infinite) - * @return Whether or not the approval succeeded - */ - function approve(address spender, uint256 amount) - external - override - returns (bool) - { - transferAllowances[msg.sender][spender] = amount; - emit Approval(msg.sender, spender, amount); - return true; - } - - /** - * @notice Get the current allowance from `owner` for `spender` - * @param owner The address of the account which owns the tokens to be spent - * @param spender The address of the account which may transfer tokens - * @return The number of tokens allowed to be spent (-1 means infinite) - */ - function allowance(address owner, address spender) - external - view - override - returns (uint256) - { - return transferAllowances[owner][spender]; - } - - /** - * @notice Get the token balance of the `owner` - * @param owner The address of the account to query - * @return The number of tokens owned by `owner` - */ - function balanceOf(address owner) external view override returns (uint256) { - return accountTokens[owner].tokens; - } - - /** - * @notice Get the underlying balance of the `owner` - * @dev This also accrues interest in a transaction - * @param owner The address of the account to query - * @return The amount of underlying owned by `owner` - */ - function balanceOfUnderlying(address owner) - external - override - returns (uint256) - { - (MathError mErr, uint256 balance) = mulScalarTruncate( - Exp({mantissa: exchangeRateCurrent()}), - accountTokens[owner].tokens - ); - require(mErr == MathError.NO_ERROR, "CT06"); - return balance; - } - - /** - * @notice Get a snapshot of the account's balances, and the cached exchange rate - * @dev This is used by comptroller to more efficiently perform liquidity checks. - * @param account Address of the account to snapshot - * @return (possible error, token balance, borrow balance, exchange rate mantissa) - */ - function getAccountSnapshot(address account) - external - view - override - returns ( - uint256, - uint256, - uint256, - uint256 - ) - { - uint256 cTokenBalance = accountTokens[account].tokens; - uint256 borrowBalance; - uint256 exchangeRateMantissa; - - MathError mErr; - - (mErr, borrowBalance) = borrowBalanceStoredInternal(account); - if (mErr != MathError.NO_ERROR) { - return (uint256(Error.MATH_ERROR), 0, 0, 0); - } - - (mErr, exchangeRateMantissa) = exchangeRateStoredInternal(); - if (mErr != MathError.NO_ERROR) { - return (uint256(Error.MATH_ERROR), 0, 0, 0); - } - - return ( - uint256(Error.NO_ERROR), - cTokenBalance, - borrowBalance, - exchangeRateMantissa - ); - } - - /** - * @dev Function to simply retrieve block number - * This exists mainly for inheriting test contracts to stub this result. - */ - function getBlockNumber() internal view virtual returns (uint256) { - return block.number; - } - - /** - * @notice Returns the current per-block borrow interest rate for this cToken - * @return The borrow interest rate per block, scaled by 1e18 - */ - function borrowRatePerBlock() external view override returns (uint256) { - return - interestRateModel.getBorrowRate( - getCashPrior(), - totalBorrows, - totalReserves - ); - } - - /** - * @notice Returns the current per-block supply interest rate for this cToken - * @return The supply interest rate per block, scaled by 1e18 - */ - function supplyRatePerBlock() external view override returns (uint256) { - return - interestRateModel.getSupplyRate( - getCashPrior(), - totalBorrows, - totalReserves, - reserveFactorMantissa - ); - } - - /** - * @notice Returns the current total borrows plus accrued interest - * @return The total borrows with interest - */ - function totalBorrowsCurrent() - external - override - nonReentrant - returns (uint256) - { - require(accrueInterest() == uint256(Error.NO_ERROR), "CT07"); - return totalBorrows; - } - - /** - * @notice Accrue interest to updated borrowIndex and then calculate account's borrow balance using the updated borrowIndex - * @param account The address whose balance should be calculated after updating borrowIndex - * @return The calculated balance - */ - function borrowBalanceCurrent(address account) - external - override - nonReentrant - returns (uint256) - { - require(accrueInterest() == uint256(Error.NO_ERROR), "CT07"); - return borrowBalanceStored(account); - } - - /** - * @notice Return the borrow balance of account based on stored data - * @param account The address whose balance should be calculated - * @return The calculated balance - */ - function borrowBalanceStored(address account) - public - view - override - returns (uint256) - { - (MathError err, uint256 result) = borrowBalanceStoredInternal(account); - require(err == MathError.NO_ERROR, "CT08"); - return result; - } - - /** - * @notice Return the borrow balance of account based on stored data - * @param account The address whose balance should be calculated - * @return (error code, the calculated balance or 0 if error code is non-zero) - */ - function borrowBalanceStoredInternal(address account) - internal - view - returns (MathError, uint256) - { - MathError mathErr; - uint256 principalTimesIndex; - uint256 result; - - BorrowSnapshot storage borrowSnapshot = accountBorrows[account]; - - if (borrowSnapshot.principal == 0) { - return (MathError.NO_ERROR, 0); - } - - (mathErr, principalTimesIndex) = mulUInt( - borrowSnapshot.principal, - borrowIndex - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - - (mathErr, result) = divUInt( - principalTimesIndex, - borrowSnapshot.interestIndex - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - - return (MathError.NO_ERROR, result); - } - - function getBorrowerPrincipalStored(address account) - public - view - returns (uint256 borrowed) - { - borrowed = accountBorrows[account].principal; - } - - function getSupplierSnapshotStored(address account) - public - view - returns ( - uint256 tokens, - uint256 underlyingAmount, - uint256 suppliedAt, - uint256 promisedSupplyRate - ) - { - tokens = accountTokens[account].tokens; - underlyingAmount = accountTokens[account].underlyingAmount; - suppliedAt = accountTokens[account].suppliedAt; - promisedSupplyRate = accountTokens[account].promisedSupplyRate; - } - - /** - * @notice Accrue interest then return the up-to-date exchange rate - * @return Calculated exchange rate scaled by 1e18 - */ - function exchangeRateCurrent() - public - override - nonReentrant - returns (uint256) - { - require(accrueInterest() == uint256(Error.NO_ERROR), "CT07"); - return exchangeRateStored(); - } - - /** - * @notice Calculates the exchange rate from the underlying to the CToken - * @dev This function does not accrue interest before calculating the exchange rate - * @return Calculated exchange rate scaled by 1e18 - */ - function exchangeRateStored() public view override returns (uint256) { - (MathError err, uint256 result) = exchangeRateStoredInternal(); - require(err == MathError.NO_ERROR, "CT09"); - return result; - } - - /** - * @notice Calculates the exchange rate from the underlying to the CToken - * @dev This function does not accrue interest before calculating the exchange rate - * @return (error code, calculated exchange rate scaled by 1e18) - */ - function exchangeRateStoredInternal() - internal - view - virtual - returns (MathError, uint256) - { - uint256 _totalSupply = totalSupply; - if (_totalSupply == 0) { - return (MathError.NO_ERROR, initialExchangeRateMantissa); - } else { - MathError error; - uint256 exchangeRate; - uint256 totalCash = getCashPrior(); - if (interestRateModel.isTropykusInterestRateModel()) { - (error, exchangeRate) = tropykusExchangeRateStoredInternal( - msg.sender - ); - if (error == MathError.NO_ERROR) { - return (MathError.NO_ERROR, exchangeRate); - } else { - return (MathError.NO_ERROR, initialExchangeRateMantissa); - } - } - return - interestRateModel.getExchangeRate( - totalCash, - totalBorrows, - totalReserves, - totalSupply - ); - } - } - - function tropykusExchangeRateStoredInternal(address redeemer) - internal - view - returns (MathError, uint256) - { - if (totalSupply == 0) { - return (MathError.NO_ERROR, initialExchangeRateMantissa); - } else { - SupplySnapshot storage supplySnapshot = accountTokens[redeemer]; - if (supplySnapshot.suppliedAt == 0) { - return (MathError.DIVISION_BY_ZERO, 0); - } - (, uint256 interestFactorMantissa, ) = tropykusInterestAccrued( - redeemer - ); - Exp memory interestFactor = Exp({mantissa: interestFactorMantissa}); - uint256 currentUnderlying = supplySnapshot.underlyingAmount; - Exp memory redeemerUnderlying = Exp({mantissa: currentUnderlying}); - (, Exp memory realAmount) = mulExp( - interestFactor, - redeemerUnderlying - ); - (, Exp memory exchangeRate) = getExp( - realAmount.mantissa, - supplySnapshot.tokens - ); - return (MathError.NO_ERROR, exchangeRate.mantissa); - } - } - - function tropykusInterestAccrued(address account) - internal - view - returns ( - MathError, - uint256, - uint256 - ) - { - SupplySnapshot storage supplySnapshot = accountTokens[account]; - uint256 promisedSupplyRate = supplySnapshot.promisedSupplyRate; - Exp memory expectedSupplyRatePerBlock = Exp({ - mantissa: promisedSupplyRate - }); - (, uint256 delta) = subUInt( - accrualBlockNumber, - supplySnapshot.suppliedAt - ); - (, Exp memory expectedSupplyRatePerBlockWithDelta) = mulScalar( - expectedSupplyRatePerBlock, - delta - ); - (, Exp memory interestFactor) = addExp( - Exp({mantissa: 1e18}), - expectedSupplyRatePerBlockWithDelta - ); - uint256 currentUnderlying = supplySnapshot.underlyingAmount; - Exp memory redeemerUnderlying = Exp({mantissa: currentUnderlying}); - (, Exp memory realAmount) = mulExp(interestFactor, redeemerUnderlying); - (, uint256 interestEarned) = subUInt( - realAmount.mantissa, - currentUnderlying - ); - return (MathError.NO_ERROR, interestFactor.mantissa, interestEarned); - } - - /** - * @notice Get cash balance of this cToken in the underlying asset - * @return The quantity of underlying asset owned by this contract - */ - function getCash() external view override returns (uint256) { - return getCashPrior(); - } - - /** - * @notice Applies accrued interest to total borrows and reserves - * @dev This calculates interest accrued from the last checkpointed block - * up to the current block and writes new checkpoint to storage. - */ - function accrueInterest() public override returns (uint256) { - uint256 currentBlockNumber = getBlockNumber(); - uint256 accrualBlockNumberPrior = accrualBlockNumber; - - if (accrualBlockNumberPrior == currentBlockNumber) { - return uint256(Error.NO_ERROR); - } - - uint256 cashPrior = getCashPrior(); - uint256 borrowsPrior = totalBorrows; - uint256 reservesPrior = totalReserves; - uint256 borrowIndexPrior = borrowIndex; - - uint256 borrowRateMantissa = interestRateModel.getBorrowRate( - cashPrior, - borrowsPrior, - reservesPrior - ); - require(borrowRateMantissa <= borrowRateMaxMantissa, "CT10"); - - (MathError mathErr, uint256 blockDelta) = subUInt( - currentBlockNumber, - accrualBlockNumberPrior - ); - require(mathErr == MathError.NO_ERROR, "CT11"); - - Exp memory simpleInterestFactor; - uint256 interestAccumulated; - uint256 totalBorrowsNew; - uint256 totalReservesNew; - uint256 borrowIndexNew; - - (mathErr, simpleInterestFactor) = mulScalar( - Exp({mantissa: borrowRateMantissa}), - blockDelta - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .ACCRUE_INTEREST_SIMPLE_INTEREST_FACTOR_CALCULATION_FAILED, - uint256(mathErr) - ); - } - - (mathErr, interestAccumulated) = mulScalarTruncate( - simpleInterestFactor, - borrowsPrior - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .ACCRUE_INTEREST_ACCUMULATED_INTEREST_CALCULATION_FAILED, - uint256(mathErr) - ); - } - - (mathErr, totalBorrowsNew) = addUInt(interestAccumulated, borrowsPrior); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .ACCRUE_INTEREST_NEW_TOTAL_BORROWS_CALCULATION_FAILED, - uint256(mathErr) - ); - } - - (mathErr, totalReservesNew) = mulScalarTruncateAddUInt( - Exp({mantissa: reserveFactorMantissa}), - interestAccumulated, - reservesPrior - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .ACCRUE_INTEREST_NEW_TOTAL_RESERVES_CALCULATION_FAILED, - uint256(mathErr) - ); - } - - if (interestRateModel.isTropykusInterestRateModel()) { - (mathErr, totalReservesNew) = newReserves( - borrowRateMantissa, - cashPrior, - borrowsPrior, - reservesPrior, - interestAccumulated - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .ACCRUE_INTEREST_NEW_TOTAL_RESERVES_CALCULATION_FAILED, - uint256(mathErr) - ); - } - } - - (mathErr, borrowIndexNew) = mulScalarTruncateAddUInt( - simpleInterestFactor, - borrowIndexPrior, - borrowIndexPrior - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .ACCRUE_INTEREST_NEW_BORROW_INDEX_CALCULATION_FAILED, - uint256(mathErr) - ); - } - - accrualBlockNumber = currentBlockNumber; - borrowIndex = borrowIndexNew; - totalBorrows = totalBorrowsNew; - totalReserves = totalReservesNew; - - emit AccrueInterest( - cashPrior, - interestAccumulated, - borrowIndexNew, - totalBorrowsNew - ); - - return uint256(Error.NO_ERROR); - } - - function newReserves( - uint256 borrowRateMantissa, - uint256 cashPrior, - uint256 borrowsPrior, - uint256 reservesPrior, - uint256 interestAccumulated - ) internal view returns (MathError mathErr, uint256 totalReservesNew) { - uint256 newReserveFactorMantissa; - uint256 utilizationRate = interestRateModel.utilizationRate( - cashPrior, - borrowsPrior, - reservesPrior - ); - uint256 expectedSupplyRate = interestRateModel.getSupplyRate( - cashPrior, - borrowsPrior, - reservesPrior, - reserveFactorMantissa - ); - if ( - interestRateModel.isAboveOptimal( - cashPrior, - borrowsPrior, - reservesPrior - ) - ) { - (mathErr, newReserveFactorMantissa) = mulScalarTruncate( - Exp({mantissa: utilizationRate}), - borrowRateMantissa - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - (mathErr, newReserveFactorMantissa) = subUInt( - newReserveFactorMantissa, - expectedSupplyRate - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - (mathErr, totalReservesNew) = mulScalarTruncateAddUInt( - Exp({mantissa: newReserveFactorMantissa}), - interestAccumulated, - reservesPrior - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - } else { - mathErr = MathError.NO_ERROR; - totalReservesNew = reservesPrior; - } - } - - /** - * @notice Sender supplies assets into the market and receives cTokens in exchange - * @dev Accrues interest whether or not the operation succeeds, unless reverted - * @param mintAmount The amount of the underlying asset to supply - * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual mint amount. - */ - function mintInternal(uint256 mintAmount) - internal - nonReentrant - returns (uint256, uint256) - { - if (WhitelistInterface(whitelist).enabled()) { - require(WhitelistInterface(whitelist).exist(msg.sender), "CT26"); - } - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return ( - fail(Error(error), FailureInfo.MINT_ACCRUE_INTEREST_FAILED), - 0 - ); - } - return mintFresh(msg.sender, mintAmount); - } - - struct MintLocalVars { - Error err; - MathError mathErr; - uint256 exchangeRateMantissa; - uint256 mintTokens; - uint256 totalSupplyNew; - uint256 accountTokensNew; - uint256 actualMintAmount; - } - - /** - * @notice User supplies assets into the market and receives cTokens in exchange - * @dev Assumes interest has already been accrued up to the current block - * @param minter The address of the account which is supplying the assets - * @param mintAmount The amount of the underlying asset to supply - * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual mint amount. - */ - function mintFresh(address minter, uint256 mintAmount) - internal - returns (uint256, uint256) - { - uint256 allowed = comptroller.mintAllowed( - address(this), - minter, - mintAmount - ); - if (allowed != 0) { - return ( - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.MINT_COMPTROLLER_REJECTION, - allowed - ), - 0 - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return ( - fail(Error.MARKET_NOT_FRESH, FailureInfo.MINT_FRESHNESS_CHECK), - 0 - ); - } - - MintLocalVars memory vars; - - ( - vars.mathErr, - vars.exchangeRateMantissa - ) = exchangeRateStoredInternal(); - if (vars.mathErr != MathError.NO_ERROR) { - return ( - failOpaque( - Error.MATH_ERROR, - FailureInfo.MINT_EXCHANGE_RATE_READ_FAILED, - uint256(vars.mathErr) - ), - 0 - ); - } - if (interestRateModel.isTropykusInterestRateModel()) { - SupplySnapshot storage supplySnapshot = accountTokens[minter]; - (, uint256 newTotalSupply) = addUInt( - supplySnapshot.underlyingAmount, - mintAmount - ); - require(newTotalSupply <= 0.1e18, "CT24"); - } - vars.actualMintAmount = doTransferIn(minter, mintAmount); - - (vars.mathErr, vars.mintTokens) = divScalarByExpTruncate( - vars.actualMintAmount, - Exp({mantissa: vars.exchangeRateMantissa}) - ); - require(vars.mathErr == MathError.NO_ERROR, "CT12"); - - (vars.mathErr, vars.totalSupplyNew) = addUInt( - totalSupply, - vars.mintTokens - ); - require(vars.mathErr == MathError.NO_ERROR, "CT13"); - - (vars.mathErr, vars.accountTokensNew) = addUInt( - accountTokens[minter].tokens, - vars.mintTokens - ); - require(vars.mathErr == MathError.NO_ERROR, "CT14"); - - uint256 currentSupplyRate = interestRateModel.getSupplyRate( - getCashPrior(), - totalBorrows, - totalReserves, - reserveFactorMantissa - ); - - bool isTropykusInterestRateModel = interestRateModel - .isTropykusInterestRateModel(); - - if (accountTokens[minter].tokens > 0) { - Exp memory updatedUnderlying; - if (isTropykusInterestRateModel) { - (, uint256 interestFactorMantissa, ) = tropykusInterestAccrued( - minter - ); - Exp memory interestFactor = Exp({ - mantissa: interestFactorMantissa - }); - uint256 currentUnderlyingAmount = accountTokens[minter] - .underlyingAmount; - MathError mErrorNewAmount; - (mErrorNewAmount, updatedUnderlying) = mulExp( - Exp({mantissa: currentUnderlyingAmount}), - interestFactor - ); - if (mErrorNewAmount != MathError.NO_ERROR) { - return ( - failOpaque( - Error.MATH_ERROR, - FailureInfo.MINT_EXCHANGE_CALCULATION_FAILED, - uint256(mErrorNewAmount) - ), - 0 - ); - } - } else { - uint256 currentTokens = accountTokens[minter].tokens; - MathError mErrorUpdatedUnderlying; - (mErrorUpdatedUnderlying, updatedUnderlying) = mulExp( - Exp({mantissa: currentTokens}), - Exp({mantissa: vars.exchangeRateMantissa}) - ); - if (mErrorUpdatedUnderlying != MathError.NO_ERROR) { - return ( - failOpaque( - Error.MATH_ERROR, - FailureInfo.MINT_EXCHANGE_CALCULATION_FAILED, - uint256(mErrorUpdatedUnderlying) - ), - 0 - ); - } - } - (, mintAmount) = addUInt(updatedUnderlying.mantissa, mintAmount); - } - - totalSupply = vars.totalSupplyNew; - accountTokens[minter] = SupplySnapshot({ - tokens: vars.accountTokensNew, - underlyingAmount: mintAmount, - suppliedAt: accrualBlockNumber, - promisedSupplyRate: currentSupplyRate - }); - - emit Mint(minter, vars.actualMintAmount, vars.mintTokens); - emit Transfer(address(this), minter, vars.mintTokens); - - return (uint256(Error.NO_ERROR), vars.actualMintAmount); - } - - /** - * @notice Sender redeems cTokens in exchange for a specified amount of underlying asset - * @dev Accrues interest whether or not the operation succeeds, unless reverted - * @param redeemAmount The amount of underlying to receive from redeeming cTokens - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function redeemUnderlyingInternal(uint256 redeemAmount) - internal - nonReentrant - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return - fail(Error(error), FailureInfo.REDEEM_ACCRUE_INTEREST_FAILED); - } - return redeemFresh(payable(msg.sender), redeemAmount); - } - - struct RedeemLocalVars { - Error err; - MathError mathErr; - uint256 exchangeRateMantissa; - uint256 redeemTokens; - uint256 redeemAmount; - uint256 totalSupplyNew; - uint256 accountTokensNew; - uint256 newSubsidyFund; - } - - /** - * @notice User redeems cTokens in exchange for the underlying asset - * @dev Assumes interest has already been accrued up to the current block - * @param redeemer The address of the account which is redeeming the tokens - * @param redeemAmountIn The number of underlying tokens to receive from redeeming cTokens - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function redeemFresh(address payable redeemer, uint256 redeemAmountIn) - internal - returns (uint256) - { - require(redeemAmountIn > 0, "CT15"); - - RedeemLocalVars memory vars; - - SupplySnapshot storage supplySnapshot = accountTokens[redeemer]; - - ( - vars.mathErr, - vars.exchangeRateMantissa - ) = exchangeRateStoredInternal(); - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.REDEEM_EXCHANGE_RATE_READ_FAILED, - uint256(vars.mathErr) - ); - } - - uint256 interestEarned; - uint256 subsidyFundPortion; - uint256 currentUnderlying; - - bool isTropykusInterestRateModel = interestRateModel - .isTropykusInterestRateModel(); - if (isTropykusInterestRateModel) { - currentUnderlying = supplySnapshot.underlyingAmount; - (, , interestEarned) = tropykusInterestAccrued(redeemer); - } - supplySnapshot.promisedSupplyRate = interestRateModel.getSupplyRate( - getCashPrior(), - totalBorrows, - totalReserves, - reserveFactorMantissa - ); - - if ( - isTropykusInterestRateModel && - !interestRateModel.isAboveOptimal( - getCashPrior(), - totalBorrows, - totalReserves - ) - ) { - uint256 borrowRate = interestRateModel.getBorrowRate( - getCashPrior(), - totalBorrows, - totalReserves - ); - - uint256 utilizationRate = interestRateModel.utilizationRate( - getCashPrior(), - totalBorrows, - totalReserves - ); - - (, uint256 estimatedEarning) = mulScalarTruncate( - Exp({mantissa: borrowRate}), - utilizationRate - ); - - (, subsidyFundPortion) = subUInt( - supplySnapshot.promisedSupplyRate, - estimatedEarning - ); - (, Exp memory subsidyFactor) = getExp( - subsidyFundPortion, - supplySnapshot.promisedSupplyRate - ); - (, subsidyFundPortion) = mulScalarTruncate( - subsidyFactor, - interestEarned - ); - } - - vars.redeemAmount = redeemAmountIn; - - if (isTropykusInterestRateModel) { - (, Exp memory num) = mulExp( - vars.redeemAmount, - supplySnapshot.tokens - ); - (, Exp memory realTokensWithdrawAmount) = getExp( - num.mantissa, - currentUnderlying - ); - vars.redeemTokens = realTokensWithdrawAmount.mantissa; - } else { - (vars.mathErr, vars.redeemTokens) = divScalarByExpTruncate( - redeemAmountIn, - Exp({mantissa: vars.exchangeRateMantissa}) - ); - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.REDEEM_EXCHANGE_AMOUNT_CALCULATION_FAILED, - uint256(vars.mathErr) - ); - } - } - // } - - uint256 allowed = comptroller.redeemAllowed( - address(this), - redeemer, - vars.redeemTokens - ); - if (allowed != 0) { - return - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.REDEEM_COMPTROLLER_REJECTION, - allowed - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.REDEEM_FRESHNESS_CHECK - ); - } - - (vars.mathErr, vars.totalSupplyNew) = subUInt( - totalSupply, - vars.redeemTokens - ); - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.REDEEM_NEW_TOTAL_SUPPLY_CALCULATION_FAILED, - uint256(vars.mathErr) - ); - } - - (, vars.newSubsidyFund) = subUInt(subsidyFund, subsidyFundPortion); - - (vars.mathErr, vars.accountTokensNew) = subUInt( - supplySnapshot.tokens, - vars.redeemTokens - ); - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.REDEEM_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED, - uint256(vars.mathErr) - ); - } - - uint256 cash = getCashPrior(); - if (isTropykusInterestRateModel) { - cash = address(this).balance; - } - - if (cash < vars.redeemAmount) { - return - fail( - Error.TOKEN_INSUFFICIENT_CASH, - FailureInfo.REDEEM_TRANSFER_OUT_NOT_POSSIBLE - ); - } - - doTransferOut(redeemer, vars.redeemAmount); - - totalSupply = vars.totalSupplyNew; - subsidyFund = vars.newSubsidyFund; - supplySnapshot.tokens = vars.accountTokensNew; - supplySnapshot.suppliedAt = accrualBlockNumber; - (, supplySnapshot.underlyingAmount) = subUInt( - supplySnapshot.underlyingAmount, - vars.redeemAmount - ); - - emit Transfer(redeemer, address(this), vars.redeemTokens); - emit Redeem(redeemer, vars.redeemAmount, vars.redeemTokens); - - comptroller.redeemVerify( - address(this), - redeemer, - vars.redeemAmount, - vars.redeemTokens - ); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Sender borrows assets from the protocol to their own address - * @param borrowAmount The amount of the underlying asset to borrow - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function borrowInternal(uint256 borrowAmount) - internal - nonReentrant - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return - fail(Error(error), FailureInfo.BORROW_ACCRUE_INTEREST_FAILED); - } - return borrowFresh(payable(msg.sender), borrowAmount); - } - - struct BorrowLocalVars { - MathError mathErr; - uint256 accountBorrows; - uint256 accountBorrowsNew; - uint256 totalBorrowsNew; - } - - /** - * @notice Users borrow assets from the protocol to their own address - * @param borrowAmount The amount of the underlying asset to borrow - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function borrowFresh(address payable borrower, uint256 borrowAmount) - internal - returns (uint256) - { - uint256 allowed = comptroller.borrowAllowed( - address(this), - borrower, - borrowAmount - ); - if (allowed != 0) { - return - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.BORROW_COMPTROLLER_REJECTION, - allowed - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.BORROW_FRESHNESS_CHECK - ); - } - - if (getCashPrior() < borrowAmount) { - return - fail( - Error.TOKEN_INSUFFICIENT_CASH, - FailureInfo.BORROW_CASH_NOT_AVAILABLE - ); - } - - BorrowLocalVars memory vars; - - (vars.mathErr, vars.accountBorrows) = borrowBalanceStoredInternal( - borrower - ); - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED, - uint256(vars.mathErr) - ); - } - - (vars.mathErr, vars.accountBorrowsNew) = addUInt( - vars.accountBorrows, - borrowAmount - ); - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED, - uint256(vars.mathErr) - ); - } - - (vars.mathErr, vars.totalBorrowsNew) = addUInt( - totalBorrows, - borrowAmount - ); - if (interestRateModel.isTropykusInterestRateModel()) { - require(vars.totalBorrowsNew <= 0.1e18, "CT25"); - } - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED, - uint256(vars.mathErr) - ); - } - - doTransferOut(borrower, borrowAmount); - - accountBorrows[borrower].principal = vars.accountBorrowsNew; - accountBorrows[borrower].interestIndex = borrowIndex; - totalBorrows = vars.totalBorrowsNew; - - emit Borrow( - borrower, - borrowAmount, - vars.accountBorrowsNew, - vars.totalBorrowsNew - ); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Sender repays their own borrow - * @param repayAmount The amount to repay - * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual repayment amount. - */ - function repayBorrowInternal(uint256 repayAmount) - internal - nonReentrant - returns (uint256, uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return ( - fail( - Error(error), - FailureInfo.REPAY_BORROW_ACCRUE_INTEREST_FAILED - ), - 0 - ); - } - return repayBorrowFresh(msg.sender, msg.sender, repayAmount); - } - - struct RepayBorrowLocalVars { - Error err; - MathError mathErr; - uint256 repayAmount; - uint256 borrowerIndex; - uint256 accountBorrows; - uint256 accountBorrowsNew; - uint256 totalBorrowsNew; - uint256 actualRepayAmount; - } - - /** - * @notice Borrows are repaid by another user (possibly the borrower). - * @param payer the account paying off the borrow - * @param borrower the account with the debt being payed off - * @param repayAmount the amount of undelrying tokens being returned - * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual repayment amount. - */ - function repayBorrowFresh( - address payer, - address borrower, - uint256 repayAmount - ) internal returns (uint256, uint256) { - uint256 allowed = comptroller.repayBorrowAllowed( - address(this), - payer, - borrower, - repayAmount - ); - if (allowed != 0) { - return ( - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.REPAY_BORROW_COMPTROLLER_REJECTION, - allowed - ), - 0 - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return ( - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.REPAY_BORROW_FRESHNESS_CHECK - ), - 0 - ); - } - - RepayBorrowLocalVars memory vars; - - vars.borrowerIndex = accountBorrows[borrower].interestIndex; - - (vars.mathErr, vars.accountBorrows) = borrowBalanceStoredInternal( - borrower - ); - if (vars.mathErr != MathError.NO_ERROR) { - return ( - failOpaque( - Error.MATH_ERROR, - FailureInfo - .REPAY_BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED, - uint256(vars.mathErr) - ), - 0 - ); - } - - if (repayAmount == type(uint256).max) { - vars.repayAmount = vars.accountBorrows; - } else { - vars.repayAmount = repayAmount; - } - - vars.actualRepayAmount = doTransferIn(payer, vars.repayAmount); - - (vars.mathErr, vars.accountBorrowsNew) = subUInt( - vars.accountBorrows, - vars.actualRepayAmount - ); - require(vars.mathErr == MathError.NO_ERROR, "CT16"); - - (vars.mathErr, vars.totalBorrowsNew) = subUInt( - totalBorrows, - vars.actualRepayAmount - ); - require(vars.mathErr == MathError.NO_ERROR, "CT17"); - - accountBorrows[borrower].principal = vars.accountBorrowsNew; - accountBorrows[borrower].interestIndex = borrowIndex; - totalBorrows = vars.totalBorrowsNew; - - emit RepayBorrow( - payer, - borrower, - vars.actualRepayAmount, - vars.accountBorrowsNew, - vars.totalBorrowsNew - ); - - return (uint256(Error.NO_ERROR), vars.actualRepayAmount); - } - - /** - * @notice The sender liquidates the borrowers collateral. - * The collateral seized is transferred to the liquidator. - * @param borrower The borrower of this cToken to be liquidated - * @param cTokenCollateral The market in which to seize collateral from the borrower - * @param repayAmount The amount of the underlying borrowed asset to repay - * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual repayment amount. - */ - function liquidateBorrowInternal( - address borrower, - uint256 repayAmount, - CTokenInterface cTokenCollateral - ) internal nonReentrant returns (uint256, uint256) { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return ( - fail( - Error(error), - FailureInfo.LIQUIDATE_ACCRUE_BORROW_INTEREST_FAILED - ), - 0 - ); - } - - error = cTokenCollateral.accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return ( - fail( - Error(error), - FailureInfo.LIQUIDATE_ACCRUE_COLLATERAL_INTEREST_FAILED - ), - 0 - ); - } - - // liquidateBorrowFresh emits borrow-specific logs on errors, so we don't need to - return - liquidateBorrowFresh( - msg.sender, - borrower, - repayAmount, - cTokenCollateral - ); - } - - /** - * @notice The liquidator liquidates the borrowers collateral. - * The collateral seized is transferred to the liquidator. - * @param borrower The borrower of this cToken to be liquidated - * @param liquidator The address repaying the borrow and seizing collateral - * @param cTokenCollateral The market in which to seize collateral from the borrower - * @param repayAmount The amount of the underlying borrowed asset to repay - * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual repayment amount. - */ - function liquidateBorrowFresh( - address liquidator, - address borrower, - uint256 repayAmount, - CTokenInterface cTokenCollateral - ) internal returns (uint256, uint256) { - uint256 allowed = comptroller.liquidateBorrowAllowed( - address(this), - address(cTokenCollateral), - liquidator, - borrower, - repayAmount - ); - if (allowed != 0) { - return ( - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.LIQUIDATE_COMPTROLLER_REJECTION, - allowed - ), - 0 - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return ( - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.LIQUIDATE_FRESHNESS_CHECK - ), - 0 - ); - } - - if (cTokenCollateral.accrualBlockNumber() != getBlockNumber()) { - return ( - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.LIQUIDATE_COLLATERAL_FRESHNESS_CHECK - ), - 0 - ); - } - - if (borrower == liquidator) { - return ( - fail( - Error.INVALID_ACCOUNT_PAIR, - FailureInfo.LIQUIDATE_LIQUIDATOR_IS_BORROWER - ), - 0 - ); - } - - if (repayAmount == 0) { - return ( - fail( - Error.INVALID_CLOSE_AMOUNT_REQUESTED, - FailureInfo.LIQUIDATE_CLOSE_AMOUNT_IS_ZERO - ), - 0 - ); - } - - if (repayAmount == type(uint256).max) { - return ( - fail( - Error.INVALID_CLOSE_AMOUNT_REQUESTED, - FailureInfo.LIQUIDATE_CLOSE_AMOUNT_IS_UINT_MAX - ), - 0 - ); - } - - ( - uint256 repayBorrowError, - uint256 actualRepayAmount - ) = repayBorrowFresh(liquidator, borrower, repayAmount); - if (repayBorrowError != uint256(Error.NO_ERROR)) { - return ( - fail( - Error(repayBorrowError), - FailureInfo.LIQUIDATE_REPAY_BORROW_FRESH_FAILED - ), - 0 - ); - } - - (uint256 amountSeizeError, uint256 seizeTokens) = comptroller - .liquidateCalculateSeizeTokens( - address(this), - address(cTokenCollateral), - actualRepayAmount - ); - require(amountSeizeError == uint256(Error.NO_ERROR), "CT18"); - - require(cTokenCollateral.balanceOf(borrower) >= seizeTokens, "CT19"); - - uint256 seizeError; - if (address(cTokenCollateral) == address(this)) { - seizeError = seizeInternal( - address(this), - liquidator, - borrower, - seizeTokens - ); - } else { - seizeError = cTokenCollateral.seize( - liquidator, - borrower, - seizeTokens - ); - } - - require(seizeError == uint256(Error.NO_ERROR), "CT20"); - - emit LiquidateBorrow( - liquidator, - borrower, - actualRepayAmount, - address(cTokenCollateral), - seizeTokens - ); - - return (uint256(Error.NO_ERROR), actualRepayAmount); - } - - /** - * @notice Transfers collateral tokens (this market) to the liquidator. - * @dev Will fail unless called by another cToken during the process of liquidation. - * Its absolutely critical to use msg.sender as the borrowed cToken and not a parameter. - * @param liquidator The account receiving seized collateral - * @param borrower The account having collateral seized - * @param seizeTokens The number of cTokens to seize - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function seize( - address liquidator, - address borrower, - uint256 seizeTokens - ) external override nonReentrant returns (uint256) { - return seizeInternal(msg.sender, liquidator, borrower, seizeTokens); - } - - struct SeizeVars { - uint256 seizeAmount; - uint256 exchangeRate; - uint256 borrowerTokensNew; - uint256 borrowerAmountNew; - uint256 liquidatorTokensNew; - uint256 liquidatorAmountNew; - uint256 totalCash; - uint256 supplyRate; - } - - /** - * @notice Transfers collateral tokens (this market) to the liquidator. - * @dev Called only during an in-kind liquidation, or by liquidateBorrow during the liquidation of another CToken. - * Its absolutely critical to use msg.sender as the seizer cToken and not a parameter. - * @param seizerToken The contract seizing the collateral (i.e. borrowed cToken) - * @param liquidator The account receiving seized collateral - * @param borrower The account having collateral seized - * @param seizeTokens The number of cTokens to seize - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function seizeInternal( - address seizerToken, - address liquidator, - address borrower, - uint256 seizeTokens - ) internal returns (uint256) { - uint256 allowed = comptroller.seizeAllowed( - address(this), - seizerToken, - liquidator, - borrower, - seizeTokens - ); - if (allowed != 0) { - return - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.LIQUIDATE_SEIZE_COMPTROLLER_REJECTION, - allowed - ); - } - - if (borrower == liquidator) { - return - fail( - Error.INVALID_ACCOUNT_PAIR, - FailureInfo.LIQUIDATE_SEIZE_LIQUIDATOR_IS_BORROWER - ); - } - - SeizeVars memory seizeVars; - - MathError mathErr; - - (mathErr, seizeVars.borrowerTokensNew) = subUInt( - accountTokens[borrower].tokens, - seizeTokens - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.LIQUIDATE_SEIZE_BALANCE_DECREMENT_FAILED, - uint256(mathErr) - ); - } - - seizeVars.totalCash = getCashPrior(); - seizeVars.supplyRate = interestRateModel.getSupplyRate( - seizeVars.totalCash, - totalBorrows, - totalReserves, - reserveFactorMantissa - ); - - (, seizeVars.exchangeRate) = interestRateModel.getExchangeRate( - seizeVars.totalCash, - totalBorrows, - totalReserves, - totalSupply - ); - - if (interestRateModel.isTropykusInterestRateModel()) { - (, seizeVars.exchangeRate) = tropykusExchangeRateStoredInternal( - borrower - ); - } - - (, seizeVars.seizeAmount) = mulUInt( - seizeTokens, - seizeVars.exchangeRate - ); - (, seizeVars.seizeAmount) = divUInt(seizeVars.seizeAmount, 1e18); - - (, seizeVars.borrowerAmountNew) = subUInt( - accountTokens[borrower].underlyingAmount, - seizeVars.seizeAmount - ); - - (mathErr, seizeVars.liquidatorTokensNew) = addUInt( - accountTokens[liquidator].tokens, - seizeTokens - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.LIQUIDATE_SEIZE_BALANCE_INCREMENT_FAILED, - uint256(mathErr) - ); - } - - (, seizeVars.liquidatorAmountNew) = addUInt( - accountTokens[liquidator].underlyingAmount, - seizeVars.seizeAmount - ); - - accountTokens[borrower].tokens = seizeVars.borrowerTokensNew; - accountTokens[borrower].underlyingAmount = seizeVars.borrowerAmountNew; - accountTokens[borrower].suppliedAt = getBlockNumber(); - accountTokens[borrower].promisedSupplyRate = seizeVars.supplyRate; - - accountTokens[liquidator].tokens = seizeVars.liquidatorTokensNew; - accountTokens[liquidator].underlyingAmount = seizeVars - .liquidatorAmountNew; - accountTokens[liquidator].suppliedAt = getBlockNumber(); - accountTokens[liquidator].promisedSupplyRate = seizeVars.supplyRate; - - emit Transfer(borrower, liquidator, seizeTokens); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Begins transfer of admin rights. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer. - * @dev Admin function to begin change of admin. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer. - * @param newPendingAdmin New pending admin. - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setPendingAdmin(address payable newPendingAdmin) - external - override - returns (uint256) - { - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_PENDING_ADMIN_OWNER_CHECK - ); - } - - address oldPendingAdmin = pendingAdmin; - - pendingAdmin = newPendingAdmin; - - emit NewPendingAdmin(oldPendingAdmin, newPendingAdmin); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Accepts transfer of admin rights. msg.sender must be pendingAdmin - * @dev Admin function for pending admin to accept role and update admin - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _acceptAdmin() external override returns (uint256) { - if (msg.sender != pendingAdmin || msg.sender == address(0)) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.ACCEPT_ADMIN_PENDING_ADMIN_CHECK - ); - } - - address oldAdmin = admin; - address oldPendingAdmin = pendingAdmin; - - admin = pendingAdmin; - - pendingAdmin = payable(address(0)); - - emit NewAdmin(oldAdmin, admin); - emit NewPendingAdmin(oldPendingAdmin, pendingAdmin); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Sets a new comptroller for the market - * @dev Admin function to set a new comptroller - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setComptroller(ComptrollerInterface newComptroller) - public - override - returns (uint256) - { - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_COMPTROLLER_OWNER_CHECK - ); - } - - ComptrollerInterface oldComptroller = comptroller; - require(newComptroller.isComptroller(), "CT21"); - - comptroller = newComptroller; - - emit NewComptroller(oldComptroller, newComptroller); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice accrues interest and sets a new reserve factor for the protocol using _setReserveFactorFresh - * @dev Admin function to accrue interest and set a new reserve factor - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setReserveFactor(uint256 newReserveFactorMantissa) - external - override - nonReentrant - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return - fail( - Error(error), - FailureInfo.SET_RESERVE_FACTOR_ACCRUE_INTEREST_FAILED - ); - } - return _setReserveFactorFresh(newReserveFactorMantissa); - } - - /** - * @notice Sets a new reserve factor for the protocol (*requires fresh interest accrual) - * @dev Admin function to set a new reserve factor - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setReserveFactorFresh(uint256 newReserveFactorMantissa) - internal - returns (uint256) - { - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_RESERVE_FACTOR_ADMIN_CHECK - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.SET_RESERVE_FACTOR_FRESH_CHECK - ); - } - - if (newReserveFactorMantissa > reserveFactorMaxMantissa) { - return - fail( - Error.BAD_INPUT, - FailureInfo.SET_RESERVE_FACTOR_BOUNDS_CHECK - ); - } - - uint256 oldReserveFactorMantissa = reserveFactorMantissa; - reserveFactorMantissa = newReserveFactorMantissa; - - emit NewReserveFactor( - oldReserveFactorMantissa, - newReserveFactorMantissa - ); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Accrues interest and reduces reserves by transferring from msg.sender - * @param addAmount Amount of addition to reserves - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _addReservesInternal(uint256 addAmount) - internal - nonReentrant - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return - fail( - Error(error), - FailureInfo.ADD_RESERVES_ACCRUE_INTEREST_FAILED - ); - } - - uint256 totalReservesNew; - uint256 actualAddAmount; - - if (accrualBlockNumber != getBlockNumber()) { - return ( - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.ADD_RESERVES_FRESH_CHECK - ) - ); - } - - actualAddAmount = doTransferIn(msg.sender, addAmount); - - totalReservesNew = totalReserves + actualAddAmount; - - require(totalReservesNew >= totalReserves, "CT22"); - - totalReserves = totalReservesNew; - - emit ReservesAdded(msg.sender, actualAddAmount, totalReservesNew); - - return (uint256(Error.NO_ERROR)); - } - - function _addSubsidyInternal(uint256 addAmount) - internal - nonReentrant - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - // accrueInterest emits logs on errors, but on top of that we want to log the fact that an attempted reduce reserves failed. - return fail(Error(error), FailureInfo.ADD_SUBSIDY_FUND_FAILED); - } - - uint256 subsidyFundNew; - uint256 actualAddAmount; - - if (accrualBlockNumber != getBlockNumber()) { - return ( - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.ADD_SUBSIDY_FUND_FRESH_CHECK - ) - ); - } - - actualAddAmount = doTransferIn(msg.sender, addAmount); - - subsidyFundNew = subsidyFund + actualAddAmount; - - require(subsidyFundNew >= subsidyFund, "CT22"); - - subsidyFund = subsidyFundNew; - - emit SubsidyAdded(msg.sender, actualAddAmount, subsidyFundNew); - - /* Return (NO_ERROR, actualAddAmount) */ - return (uint256(Error.NO_ERROR)); - } - - /** - * @notice Accrues interest and reduces reserves by transferring to admin - * @param reduceAmount Amount of reduction to reserves - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _reduceReserves(uint256 reduceAmount) - external - override - nonReentrant - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return - fail( - Error(error), - FailureInfo.REDUCE_RESERVES_ACCRUE_INTEREST_FAILED - ); - } - return _reduceReservesFresh(reduceAmount); - } - - /** - * @notice Reduces reserves by transferring to admin - * @dev Requires fresh interest accrual - * @param reduceAmount Amount of reduction to reserves - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _reduceReservesFresh(uint256 reduceAmount) - internal - returns (uint256) - { - uint256 totalReservesNew; - - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.REDUCE_RESERVES_ADMIN_CHECK - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.REDUCE_RESERVES_FRESH_CHECK - ); - } - - if (getCashPrior() < reduceAmount) { - return - fail( - Error.TOKEN_INSUFFICIENT_CASH, - FailureInfo.REDUCE_RESERVES_CASH_NOT_AVAILABLE - ); - } - - if (reduceAmount > totalReserves) { - return - fail(Error.BAD_INPUT, FailureInfo.REDUCE_RESERVES_VALIDATION); - } - - totalReservesNew = totalReserves - reduceAmount; - require(totalReservesNew <= totalReserves, "CT23"); - - totalReserves = totalReservesNew; - - doTransferOut(admin, reduceAmount); - - emit ReservesReduced(admin, reduceAmount, totalReservesNew); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice accrues interest and updates the interest rate model using _setInterestRateModelFresh - * @dev Admin function to accrue interest and update the interest rate model - * @param newInterestRateModel the new interest rate model to use - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setInterestRateModel(InterestRateModel newInterestRateModel) - public - override - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return - fail( - Error(error), - FailureInfo.SET_INTEREST_RATE_MODEL_ACCRUE_INTEREST_FAILED - ); - } - return _setInterestRateModelFresh(newInterestRateModel); - } - - /** - * @notice updates the interest rate model (*requires fresh interest accrual) - * @dev Admin function to update the interest rate model - * @param newInterestRateModel the new interest rate model to use - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setInterestRateModelFresh(InterestRateModel newInterestRateModel) - internal - returns (uint256) - { - InterestRateModel oldInterestRateModel; - - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_INTEREST_RATE_MODEL_OWNER_CHECK - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.SET_INTEREST_RATE_MODEL_FRESH_CHECK - ); - } - - oldInterestRateModel = interestRateModel; - - require(newInterestRateModel.isInterestRateModel(), "CT21"); - - interestRateModel = newInterestRateModel; - - emit NewMarketInterestRateModel( - oldInterestRateModel, - newInterestRateModel - ); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Gets balance of this contract in terms of the underlying - * @dev This excludes the value of the current message, if any - * @return The quantity of underlying owned by this contract - */ - function getCashPrior() internal view virtual returns (uint256); - - /** - * @dev Performs a transfer in, reverting upon failure. Returns the amount actually transferred to the protocol, in case of a fee. - * This may revert due to insufficient balance or insufficient allowance. - */ - function doTransferIn(address from, uint256 amount) - internal - virtual - returns (uint256); - - /** - * @dev Performs a transfer out, ideally returning an explanatory error code upon failure tather than reverting. - * If caller has not called checked protocol's balance, may revert due to insufficient cash held in the contract. - * If caller has checked protocol's balance, and verified it is >= amount, this should not revert in normal conditions. - */ - function doTransferOut(address payable to, uint256 amount) internal virtual; - - /** - * @dev Prevents a contract from calling itself, directly or indirectly. - */ - modifier nonReentrant() { - require(_notEntered, "re-entered"); - _notEntered = false; - _; - _notEntered = true; - } -} - - -// Root file: contracts/PriceOracle.sol - -pragma solidity 0.8.6; - -// import "contracts/CToken.sol"; - -abstract contract PriceOracle { - /// @notice Indicator that this is a PriceOracle contract (for inspection) - bool public constant isPriceOracle = true; - - /** - * @notice Get the underlying price of a cToken asset - * @param cToken The cToken to get the underlying price of - * @return The underlying asset price mantissa (scaled by 1e18). - * Zero means the price is unavailable. - */ - function getUnderlyingPrice(CToken cToken) - external - view - virtual - returns (uint256); -} diff --git a/flatten/PriceOracleAdapter.sol b/flatten/PriceOracleAdapter.sol deleted file mode 100644 index 68f684c..0000000 --- a/flatten/PriceOracleAdapter.sol +++ /dev/null @@ -1,20 +0,0 @@ -// Root file: contracts/PriceOracleAdapter.sol - -// SPDX-License-Identifier: UNLICENSED -pragma solidity 0.8.6; - -abstract contract PriceOracleAdapter { - /// @notice Event adapter interface updated - event PriceOracleAdapterUpdated(address oldAddress, address newAddress); - - /** - * @notice Get the price - * @return The underlying asset price mantissa (scaled by 1e18). - * Zero means the price is unavailable. - */ - function assetPrices(address cTokenAddress) - external - view - virtual - returns (uint256); -} diff --git a/flatten/PriceOracleAdapterCompound.sol b/flatten/PriceOracleAdapterCompound.sol deleted file mode 100644 index faebfb3..0000000 --- a/flatten/PriceOracleAdapterCompound.sol +++ /dev/null @@ -1,4303 +0,0 @@ -// Dependency file: contracts/PriceOracleAdapter.sol - -// SPDX-License-Identifier: UNLICENSED -// pragma solidity 0.8.6; - -abstract contract PriceOracleAdapter { - /// @notice Event adapter interface updated - event PriceOracleAdapterUpdated(address oldAddress, address newAddress); - - /** - * @notice Get the price - * @return The underlying asset price mantissa (scaled by 1e18). - * Zero means the price is unavailable. - */ - function assetPrices(address cTokenAddress) - external - view - virtual - returns (uint256); -} - - -// Dependency file: contracts/ComptrollerInterface.sol - -// pragma solidity 0.8.6; - -abstract contract ComptrollerInterface { - /// @notice Indicator that this is a Comptroller contract (for inspection) - bool public constant isComptroller = true; - - /*** Assets You Are In ***/ - - function enterMarkets(address[] calldata cTokens) - external - virtual - returns (uint256[] memory); - - function exitMarket(address cToken) external virtual returns (uint256); - - /*** Policy Hooks ***/ - - function mintAllowed( - address cToken, - address minter, - uint256 mintAmount - ) external virtual returns (uint256); - - function mintVerify( - address cToken, - address minter, - uint256 mintAmount, - uint256 mintTokens - ) external virtual; - - function redeemAllowed( - address cToken, - address redeemer, - uint256 redeemTokens - ) external virtual returns (uint256); - - function redeemVerify( - address cToken, - address redeemer, - uint256 redeemAmount, - uint256 redeemTokens - ) external virtual; - - function borrowAllowed( - address cToken, - address borrower, - uint256 borrowAmount - ) external virtual returns (uint256); - - function borrowVerify( - address cToken, - address borrower, - uint256 borrowAmount - ) external virtual; - - function repayBorrowAllowed( - address cToken, - address payer, - address borrower, - uint256 repayAmount - ) external virtual returns (uint256); - - function repayBorrowVerify( - address cToken, - address payer, - address borrower, - uint256 repayAmount, - uint256 borrowerIndex - ) external virtual; - - function liquidateBorrowAllowed( - address cTokenBorrowed, - address cTokenCollateral, - address liquidator, - address borrower, - uint256 repayAmount - ) external virtual returns (uint256); - - function liquidateBorrowVerify( - address cTokenBorrowed, - address cTokenCollateral, - address liquidator, - address borrower, - uint256 repayAmount, - uint256 seizeTokens - ) external virtual; - - function seizeAllowed( - address cTokenCollateral, - address cTokenBorrowed, - address liquidator, - address borrower, - uint256 seizeTokens - ) external virtual returns (uint256); - - function seizeVerify( - address cTokenCollateral, - address cTokenBorrowed, - address liquidator, - address borrower, - uint256 seizeTokens - ) external virtual; - - function transferAllowed( - address cToken, - address src, - address dst, - uint256 transferTokens - ) external virtual returns (uint256); - - function transferVerify( - address cToken, - address src, - address dst, - uint256 transferTokens - ) external virtual; - - /*** Liquidity/Liquidation Calculations ***/ - - function liquidateCalculateSeizeTokens( - address cTokenBorrowed, - address cTokenCollateral, - uint256 repayAmount - ) external view virtual returns (uint256, uint256); -} - - -// Dependency file: contracts/CarefulMath.sol - -// pragma solidity 0.8.6; - -/** - * @title Careful Math - * @author tropykus - * @notice Derived from OpenZeppelin's SafeMath library - * https://github.com/OpenZeppelin/openzeppelin-solidity/blob/master/contracts/math/SafeMath.sol - */ -contract CarefulMath { - - /** - * @dev Possible error codes that we can return - */ - enum MathError { - NO_ERROR, - DIVISION_BY_ZERO, - INTEGER_OVERFLOW, - INTEGER_UNDERFLOW - } - - /** - * @dev Multiplies two numbers, returns an error on overflow. - */ - function mulUInt(uint a, uint b) internal pure returns (MathError, uint) { - if (a == 0) { - return (MathError.NO_ERROR, 0); - } - - uint c = a * b; - - if (c / a != b) { - return (MathError.INTEGER_OVERFLOW, 0); - } else { - return (MathError.NO_ERROR, c); - } - } - - /** - * @dev Integer division of two numbers, truncating the quotient. - */ - function divUInt(uint a, uint b) internal pure returns (MathError, uint) { - if (b == 0) { - return (MathError.DIVISION_BY_ZERO, 0); - } - - return (MathError.NO_ERROR, a / b); - } - - /** - * @dev Subtracts two numbers, returns an error on overflow (i.e. if subtrahend is greater than minuend). - */ - function subUInt(uint a, uint b) internal pure returns (MathError, uint) { - if (b <= a) { - return (MathError.NO_ERROR, a - b); - } else { - return (MathError.INTEGER_UNDERFLOW, 0); - } - } - - /** - * @dev Adds two numbers, returns an error on overflow. - */ - function addUInt(uint a, uint b) internal pure returns (MathError, uint) { - uint c = a + b; - - if (c >= a) { - return (MathError.NO_ERROR, c); - } else { - return (MathError.INTEGER_OVERFLOW, 0); - } - } - - /** - * @dev add a and b and then subtract c - */ - function addThenSubUInt(uint a, uint b, uint c) internal pure returns (MathError, uint) { - (MathError err0, uint sum) = addUInt(a, b); - - if (err0 != MathError.NO_ERROR) { - return (err0, 0); - } - - return subUInt(sum, c); - } -} - - -// Dependency file: contracts/ExponentialNoError.sol - -// pragma solidity 0.8.6; - -/** - * @title Exponential module for storing fixed-precision decimals - * @author tropykus - * @notice Exp is a struct which stores decimals with a fixed precision of 18 decimal places. - * Thus, if we wanted to store the 5.1, mantissa would store 5.1e18. That is: - * `Exp({mantissa: 5100000000000000000})`. - */ -contract ExponentialNoError { - uint constant expScale = 1e18; - uint constant doubleScale = 1e36; - uint constant halfExpScale = expScale/2; - uint constant mantissaOne = expScale; - - struct Exp { - uint mantissa; - } - - struct Double { - uint mantissa; - } - - /** - * @dev Truncates the given exp to a whole number value. - * For example, truncate(Exp{mantissa: 15 * expScale}) = 15 - */ - function truncate(Exp memory exp) pure internal returns (uint) { - // Note: We are not using careful math here as we're performing a division that cannot fail - return exp.mantissa / expScale; - } - - /** - * @dev Multiply an Exp by a scalar, then truncate to return an unsigned integer. - */ - function mul_ScalarTruncate(Exp memory a, uint scalar) pure internal returns (uint) { - Exp memory product = mul_(a, scalar); - return truncate(product); - } - - /** - * @dev Multiply an Exp by a scalar, truncate, then add an to an unsigned integer, returning an unsigned integer. - */ - function mul_ScalarTruncateAddUInt(Exp memory a, uint scalar, uint addend) pure internal returns (uint) { - Exp memory product = mul_(a, scalar); - return add_(truncate(product), addend); - } - - /** - * @dev Checks if first Exp is less than second Exp. - */ - function lessThanExp(Exp memory left, Exp memory right) pure internal returns (bool) { - return left.mantissa < right.mantissa; - } - - /** - * @dev Checks if left Exp <= right Exp. - */ - function lessThanOrEqualExp(Exp memory left, Exp memory right) pure internal returns (bool) { - return left.mantissa <= right.mantissa; - } - - /** - * @dev Checks if left Exp > right Exp. - */ - function greaterThanExp(Exp memory left, Exp memory right) pure internal returns (bool) { - return left.mantissa > right.mantissa; - } - - /** - * @dev returns true if Exp is exactly zero - */ - function isZeroExp(Exp memory value) pure internal returns (bool) { - return value.mantissa == 0; - } - - function safe224(uint n, string memory errorMessage) pure internal returns (uint224) { - require(n < 2**224, errorMessage); - return uint224(n); - } - - function safe32(uint n, string memory errorMessage) pure internal returns (uint32) { - require(n < 2**32, errorMessage); - return uint32(n); - } - - function add_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { - return Exp({mantissa: add_(a.mantissa, b.mantissa)}); - } - - function add_(Double memory a, Double memory b) pure internal returns (Double memory) { - return Double({mantissa: add_(a.mantissa, b.mantissa)}); - } - - function add_(uint a, uint b) pure internal returns (uint) { - return add_(a, b, "addition overflow"); - } - - function add_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { - uint c = a + b; - require(c >= a, errorMessage); - return c; - } - - function sub_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { - return Exp({mantissa: sub_(a.mantissa, b.mantissa)}); - } - - function sub_(Double memory a, Double memory b) pure internal returns (Double memory) { - return Double({mantissa: sub_(a.mantissa, b.mantissa)}); - } - - function sub_(uint a, uint b) pure internal returns (uint) { - return sub_(a, b, "subtraction underflow"); - } - - function sub_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { - require(b <= a, errorMessage); - return a - b; - } - - function mul_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { - return Exp({mantissa: mul_(a.mantissa, b.mantissa) / expScale}); - } - - function mul_(Exp memory a, uint b) pure internal returns (Exp memory) { - return Exp({mantissa: mul_(a.mantissa, b)}); - } - - function mul_(uint a, Exp memory b) pure internal returns (uint) { - return mul_(a, b.mantissa) / expScale; - } - - function mul_(Double memory a, Double memory b) pure internal returns (Double memory) { - return Double({mantissa: mul_(a.mantissa, b.mantissa) / doubleScale}); - } - - function mul_(Double memory a, uint b) pure internal returns (Double memory) { - return Double({mantissa: mul_(a.mantissa, b)}); - } - - function mul_(uint a, Double memory b) pure internal returns (uint) { - return mul_(a, b.mantissa) / doubleScale; - } - - function mul_(uint a, uint b) pure internal returns (uint) { - return mul_(a, b, "multiplication overflow"); - } - - function mul_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { - if (a == 0 || b == 0) { - return 0; - } - uint c = a * b; - require(c / a == b, errorMessage); - return c; - } - - function div_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { - return Exp({mantissa: div_(mul_(a.mantissa, expScale), b.mantissa)}); - } - - function div_(Exp memory a, uint b) pure internal returns (Exp memory) { - return Exp({mantissa: div_(a.mantissa, b)}); - } - - function div_(uint a, Exp memory b) pure internal returns (uint) { - return div_(mul_(a, expScale), b.mantissa); - } - - function div_(Double memory a, Double memory b) pure internal returns (Double memory) { - return Double({mantissa: div_(mul_(a.mantissa, doubleScale), b.mantissa)}); - } - - function div_(Double memory a, uint b) pure internal returns (Double memory) { - return Double({mantissa: div_(a.mantissa, b)}); - } - - function div_(uint a, Double memory b) pure internal returns (uint) { - return div_(mul_(a, doubleScale), b.mantissa); - } - - function div_(uint a, uint b) pure internal returns (uint) { - return div_(a, b, "divide by zero"); - } - - function div_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { - require(b > 0, errorMessage); - return a / b; - } - - function fraction(uint a, uint b) pure internal returns (Double memory) { - return Double({mantissa: div_(mul_(a, doubleScale), b)}); - } -} - - -// Dependency file: contracts/Exponential.sol - -// pragma solidity 0.8.6; - -// import "contracts/CarefulMath.sol"; -// import "contracts/ExponentialNoError.sol"; - -/** - * @title Exponential module for storing fixed-precision decimals - * @author tropykus - * @dev Legacy contract for compatibility reasons with existing contracts that still use MathError - * @notice Exp is a struct which stores decimals with a fixed precision of 18 decimal places. - * Thus, if we wanted to store the 5.1, mantissa would store 5.1e18. That is: - * `Exp({mantissa: 5100000000000000000})`. - */ -contract Exponential is CarefulMath, ExponentialNoError { - /** - * @dev Creates an exponential from numerator and denominator values. - * Note: Returns an error if (`num` * 10e18) > MAX_INT, - * or if `denom` is zero. - */ - function getExp(uint num, uint denom) internal pure returns (MathError, Exp memory) { - (MathError err0, uint scaledNumerator) = mulUInt(num, expScale); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - - (MathError err1, uint rational) = divUInt(scaledNumerator, denom); - if (err1 != MathError.NO_ERROR) { - return (err1, Exp({mantissa: 0})); - } - - return (MathError.NO_ERROR, Exp({mantissa: rational})); - } - - /** - * @dev Adds two exponentials, returning a new exponential. - */ - function addExp(Exp memory a, Exp memory b) internal pure returns (MathError, Exp memory) { - (MathError error, uint result) = addUInt(a.mantissa, b.mantissa); - - return (error, Exp({mantissa: result})); - } - - /** - * @dev Subtracts two exponentials, returning a new exponential. - */ - function subExp(Exp memory a, Exp memory b) internal pure returns (MathError, Exp memory) { - (MathError error, uint result) = subUInt(a.mantissa, b.mantissa); - - return (error, Exp({mantissa: result})); - } - - /** - * @dev Multiply an Exp by a scalar, returning a new Exp. - */ - function mulScalar(Exp memory a, uint scalar) internal pure returns (MathError, Exp memory) { - (MathError err0, uint scaledMantissa) = mulUInt(a.mantissa, scalar); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - - return (MathError.NO_ERROR, Exp({mantissa: scaledMantissa})); - } - - /** - * @dev Multiply an Exp by a scalar, then truncate to return an unsigned integer. - */ - function mulScalarTruncate(Exp memory a, uint scalar) internal pure returns (MathError, uint) { - (MathError err, Exp memory product) = mulScalar(a, scalar); - if (err != MathError.NO_ERROR) { - return (err, 0); - } - - return (MathError.NO_ERROR, truncate(product)); - } - - /** - * @dev Multiply an Exp by a scalar, truncate, then add an to an unsigned integer, returning an unsigned integer. - */ - function mulScalarTruncateAddUInt(Exp memory a, uint scalar, uint addend) internal pure returns (MathError, uint) { - (MathError err, Exp memory product) = mulScalar(a, scalar); - if (err != MathError.NO_ERROR) { - return (err, 0); - } - - return addUInt(truncate(product), addend); - } - - /** - * @dev Divide an Exp by a scalar, returning a new Exp. - */ - function divScalar(Exp memory a, uint scalar) internal pure returns (MathError, Exp memory) { - (MathError err0, uint descaledMantissa) = divUInt(a.mantissa, scalar); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - - return (MathError.NO_ERROR, Exp({mantissa: descaledMantissa})); - } - - /** - * @dev Divide a scalar by an Exp, returning a new Exp. - */ - function divScalarByExp(uint scalar, Exp memory divisor) internal pure returns (MathError, Exp memory) { - /* - We are doing this as: - getExp(mulUInt(expScale, scalar), divisor.mantissa) - - How it works: - Exp = a / b; - Scalar = s; - `s / (a / b)` = `b * s / a` and since for an Exp `a = mantissa, b = expScale` - */ - (MathError err0, uint numerator) = mulUInt(expScale, scalar); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - return getExp(numerator, divisor.mantissa); - } - - /** - * @dev Divide a scalar by an Exp, then truncate to return an unsigned integer. - */ - function divScalarByExpTruncate(uint scalar, Exp memory divisor) internal pure returns (MathError, uint) { - (MathError err, Exp memory fraction) = divScalarByExp(scalar, divisor); - if (err != MathError.NO_ERROR) { - return (err, 0); - } - - return (MathError.NO_ERROR, truncate(fraction)); - } - - /** - * @dev Multiplies two exponentials, returning a new exponential. - */ - function mulExp(Exp memory a, Exp memory b) internal pure returns (MathError, Exp memory) { - - (MathError err0, uint doubleScaledProduct) = mulUInt(a.mantissa, b.mantissa); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - - // We add half the scale before dividing so that we get rounding instead of truncation. - // See "Listing 6" and text above it at https://accu.org/index.php/journals/1717 - // Without this change, a result like 6.6...e-19 will be truncated to 0 instead of being rounded to 1e-18. - (MathError err1, uint doubleScaledProductWithHalfScale) = addUInt(halfExpScale, doubleScaledProduct); - if (err1 != MathError.NO_ERROR) { - return (err1, Exp({mantissa: 0})); - } - - (MathError err2, uint product) = divUInt(doubleScaledProductWithHalfScale, expScale); - // The only error `div` can return is MathError.DIVISION_BY_ZERO but we control `expScale` and it is not zero. - assert(err2 == MathError.NO_ERROR); - - return (MathError.NO_ERROR, Exp({mantissa: product})); - } - - /** - * @dev Multiplies two exponentials given their mantissas, returning a new exponential. - */ - function mulExp(uint a, uint b) internal pure returns (MathError, Exp memory) { - return mulExp(Exp({mantissa: a}), Exp({mantissa: b})); - } - - /** - * @dev Multiplies three exponentials, returning a new exponential. - */ - function mulExp3(Exp memory a, Exp memory b, Exp memory c) internal pure returns (MathError, Exp memory) { - (MathError err, Exp memory ab) = mulExp(a, b); - if (err != MathError.NO_ERROR) { - return (err, ab); - } - return mulExp(ab, c); - } - - /** - * @dev Divides two exponentials, returning a new exponential. - * (a/scale) / (b/scale) = (a/scale) * (scale/b) = a/b, - * which we can scale as an Exp by calling getExp(a.mantissa, b.mantissa) - */ - function divExp(Exp memory a, Exp memory b) internal pure returns (MathError, Exp memory) { - return getExp(a.mantissa, b.mantissa); - } -} - - -// Dependency file: contracts/SafeMath.sol - -// pragma solidity 0.8.6; - -// From https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/math/Math.sol -// Subject to the MIT license. - -/** - * @dev Wrappers over Solidity's arithmetic operations with added overflow - * checks. - * - * Arithmetic operations in Solidity wrap on overflow. This can easily result - * in bugs, because programmers usually assume that an overflow raises an - * error, which is the standard behavior in high level programming languages. - * `SafeMath` restores this intuition by reverting the transaction when an - * operation overflows. - * - * Using this library instead of the unchecked operations eliminates an entire - * class of bugs, so it's recommended to use it always. - */ -library SafeMath { - /** - * @dev Returns the addition of two unsigned integers, reverting on overflow. - * - * Counterpart to Solidity's `+` operator. - * - * Requirements: - * - Addition cannot overflow. - */ - function add(uint256 a, uint256 b) internal pure returns (uint256) { - uint256 c = a + b; - require(c >= a, "SafeMath: addition overflow"); - - return c; - } - - /** - * @dev Returns the addition of two unsigned integers, reverting with custom message on overflow. - * - * Counterpart to Solidity's `+` operator. - * - * Requirements: - * - Addition cannot overflow. - */ - function add(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - uint256 c = a + b; - require(c >= a, errorMessage); - - return c; - } - - /** - * @dev Returns the subtraction of two unsigned integers, reverting on underflow (when the result is negative). - * - * Counterpart to Solidity's `-` operator. - * - * Requirements: - * - Subtraction cannot underflow. - */ - function sub(uint256 a, uint256 b) internal pure returns (uint256) { - return sub(a, b, "SafeMath: subtraction underflow"); - } - - /** - * @dev Returns the subtraction of two unsigned integers, reverting with custom message on underflow (when the result is negative). - * - * Counterpart to Solidity's `-` operator. - * - * Requirements: - * - Subtraction cannot underflow. - */ - function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - require(b <= a, errorMessage); - uint256 c = a - b; - - return c; - } - - /** - * @dev Returns the multiplication of two unsigned integers, reverting on overflow. - * - * Counterpart to Solidity's `*` operator. - * - * Requirements: - * - Multiplication cannot overflow. - */ - function mul(uint256 a, uint256 b) internal pure returns (uint256) { - // Gas optimization: this is cheaper than requiring 'a' not being zero, but the - // benefit is lost if 'b' is also tested. - // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 - if (a == 0) { - return 0; - } - - uint256 c = a * b; - require(c / a == b, "SafeMath: multiplication overflow"); - - return c; - } - - /** - * @dev Returns the multiplication of two unsigned integers, reverting on overflow. - * - * Counterpart to Solidity's `*` operator. - * - * Requirements: - * - Multiplication cannot overflow. - */ - function mul(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - // Gas optimization: this is cheaper than requiring 'a' not being zero, but the - // benefit is lost if 'b' is also tested. - // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 - if (a == 0) { - return 0; - } - - uint256 c = a * b; - require(c / a == b, errorMessage); - - return c; - } - - /** - * @dev Returns the integer division of two unsigned integers. - * Reverts on division by zero. The result is rounded towards zero. - * - * Counterpart to Solidity's `/` operator. Note: this function uses a - * `revert` opcode (which leaves remaining gas untouched) while Solidity - * uses an invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function div(uint256 a, uint256 b) internal pure returns (uint256) { - return div(a, b, "SafeMath: division by zero"); - } - - /** - * @dev Returns the integer division of two unsigned integers. - * Reverts with custom message on division by zero. The result is rounded towards zero. - * - * Counterpart to Solidity's `/` operator. Note: this function uses a - * `revert` opcode (which leaves remaining gas untouched) while Solidity - * uses an invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - // Solidity only automatically asserts when dividing by 0 - require(b > 0, errorMessage); - uint256 c = a / b; - // assert(a == b * c + a % b); // There is no case in which this doesn't hold - - return c; - } - - /** - * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), - * Reverts when dividing by zero. - * - * Counterpart to Solidity's `%` operator. This function uses a `revert` - * opcode (which leaves remaining gas untouched) while Solidity uses an - * invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function mod(uint256 a, uint256 b) internal pure returns (uint256) { - return mod(a, b, "SafeMath: modulo by zero"); - } - - /** - * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), - * Reverts with custom message when dividing by zero. - * - * Counterpart to Solidity's `%` operator. This function uses a `revert` - * opcode (which leaves remaining gas untouched) while Solidity uses an - * invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - require(b != 0, errorMessage); - return a % b; - } -} - - -// Dependency file: contracts/InterestRateModel.sol - -// pragma solidity 0.8.6; - -// import "contracts/Exponential.sol"; -// import "contracts/SafeMath.sol"; - -/** - * @title tropykus InterestRateModel Interface - * @author tropykus - */ -abstract contract InterestRateModel is Exponential { - using SafeMath for uint256; - - /// @notice Indicator that this is an InterestRateModel contract (for inspection) - bool public constant isInterestRateModel = true; - bool public isTropykusInterestRateModel; - - /** - * @notice The approximate number of blocks per year that is assumed by the interest rate model - */ - uint256 public constant blocksPerYear = 1051200; - - /** - * @notice Calculates the utilization rate of the market: `borrows / (cash + borrows - reserves)` - * @param cash The amount of cash in the market - * @param borrows The amount of borrows in the market - * @param reserves The amount of reserves in the market (currently unused) - * @return The utilization rate as a mantissa between [0, 1e18] - */ - function utilizationRate( - uint256 cash, - uint256 borrows, - uint256 reserves - ) public pure virtual returns (uint256) { - // Utilization rate is 0 when there are no borrows - if (borrows == 0) { - return 0; - } - - return borrows.mul(1e18).div(cash.add(borrows).sub(reserves)); - } - - /** - * @notice Calculates the current borrow interest rate per block - * @param cash The total amount of cash the market has - * @param borrows The total amount of borrows the market has outstanding - * @param reserves The total amnount of reserves the market has - * @return The borrow rate per block (as a percentage, and scaled by 1e18) - */ - function getBorrowRate( - uint256 cash, - uint256 borrows, - uint256 reserves - ) external view virtual returns (uint256); - - /** - * @notice Calculates the current supply interest rate per block - * @param cash The total amount of cash the market has - * @param borrows The total amount of borrows the market has outstanding - * @param reserves The total amnount of reserves the market has - * @param reserveFactorMantissa The current reserve factor the market has - * @return The supply rate per block (as a percentage, and scaled by 1e18) - */ - function getSupplyRate( - uint256 cash, - uint256 borrows, - uint256 reserves, - uint256 reserveFactorMantissa - ) external view virtual returns (uint256); - - function getExchangeRate( - uint256 _totalCash, - uint256 _totalBorrows, - uint256 _totalReserves, - uint256 _totalSupply - ) public pure returns (MathError, uint256) { - /* - * exchangeRate = (totalCash + totalBorrows - totalReserves) / totalSupply - */ - Exp memory exchangeRate; - MathError mathErr; - uint256 cashPlusBorrowsMinusReserves; - (mathErr, cashPlusBorrowsMinusReserves) = addThenSubUInt( - _totalCash, - _totalBorrows, - _totalReserves - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - (mathErr, exchangeRate) = getExp( - cashPlusBorrowsMinusReserves, - _totalSupply - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - - return (MathError.NO_ERROR, exchangeRate.mantissa); - } - - function isAboveOptimal( - uint256 cash, - uint256 borrows, - uint256 reserves - ) public view virtual returns (bool) { - cash; - borrows; - reserves; - return false; - } -} - - -// Dependency file: contracts/EIP20NonStandardInterface.sol - -// pragma solidity 0.8.6; - -/** - * @title EIP20NonStandardInterface - * @dev Version of ERC20 with no return values for `transfer` and `transferFrom` - * See https://medium.com/coinmonks/missing-return-value-bug-at-least-130-tokens-affected-d67bf08521ca - */ -interface EIP20NonStandardInterface { - /** - * @notice Get the total number of tokens in circulation - * @return The supply of tokens - */ - function totalSupply() external view returns (uint256); - - /** - * @notice Gets the balance of the specified address - * @param owner The address from which the balance will be retrieved - * @return balance The balance - */ - function balanceOf(address owner) external view returns (uint256 balance); - - /// - /// !!!!!!!!!!!!!! - /// !!! NOTICE !!! `transfer` does not return a value, in violation of the ERC-20 specification - /// !!!!!!!!!!!!!! - /// - - /** - * @notice Transfer `amount` tokens from `msg.sender` to `dst` - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - */ - function transfer(address dst, uint256 amount) external; - - /// - /// !!!!!!!!!!!!!! - /// !!! NOTICE !!! `transferFrom` does not return a value, in violation of the ERC-20 specification - /// !!!!!!!!!!!!!! - /// - - /** - * @notice Transfer `amount` tokens from `src` to `dst` - * @param src The address of the source account - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - */ - function transferFrom( - address src, - address dst, - uint256 amount - ) external; - - /** - * @notice Approve `spender` to transfer up to `amount` from `src` - * @dev This will overwrite the approval amount for `spender` - * and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve) - * @param spender The address of the account which may transfer tokens - * @param amount The number of tokens that are approved - * @return success Whether or not the approval succeeded - */ - function approve(address spender, uint256 amount) - external - returns (bool success); - - /** - * @notice Get the current allowance from `owner` for `spender` - * @param owner The address of the account which owns the tokens to be spent - * @param spender The address of the account which may transfer tokens - * @return remaining The number of tokens allowed to be spent - */ - function allowance(address owner, address spender) - external - view - returns (uint256 remaining); - - event Transfer(address indexed from, address indexed to, uint256 amount); - event Approval( - address indexed owner, - address indexed spender, - uint256 amount - ); -} - - -// Dependency file: contracts/CTokenInterfaces.sol - -// pragma solidity 0.8.6; - -// import "contracts/ComptrollerInterface.sol"; -// import "contracts/InterestRateModel.sol"; -// import "contracts/EIP20NonStandardInterface.sol"; - -contract CTokenStorage { - /** - * @dev Guard variable for re-entrancy checks - */ - bool internal _notEntered; - - /** - * @notice EIP-20 token name for this token - */ - string public name; - - /** - * @notice EIP-20 token symbol for this token - */ - string public symbol; - - /** - * @notice EIP-20 token decimals for this token - */ - uint8 public decimals; - - /** - * @notice Maximum borrow rate that can ever be applied (.0005% / block) - */ - - uint256 internal constant borrowRateMaxMantissa = 0.0005e16; - - /** - * @notice Maximum fraction of interest that can be set aside for reserves - */ - uint256 internal constant reserveFactorMaxMantissa = 1e18; - - /** - * @notice Administrator for this contract - */ - address payable public admin; - - /** - * @notice Pending administrator for this contract - */ - address payable public pendingAdmin; - - /** - * @notice Contract which oversees inter-cToken operations - */ - ComptrollerInterface public comptroller; - - /** - * @notice Model which tells what the current interest rate should be - */ - InterestRateModel public interestRateModel; - - /** - * @notice Initial exchange rate used when minting the first CTokens (used when totalSupply = 0) - */ - uint256 public initialExchangeRateMantissa; - - /** - * @notice Fraction of interest currently set aside for reserves - */ - uint256 public reserveFactorMantissa; - - /** - * @notice Block number that interest was last accrued at - */ - uint256 public accrualBlockNumber; - - /** - * @notice Accumulator of the total earned interest rate since the opening of the market - */ - uint256 public borrowIndex; - - /** - * @notice Total amount of outstanding borrows of the underlying in this market - */ - uint256 public totalBorrows; - - /** - * @notice Total amount of reserves of the underlying held in this market - */ - uint256 public totalReserves; - - /** - * @notice Total number of tokens in circulation - */ - uint256 public totalSupply; - - uint256 public subsidyFund; - - struct SupplySnapshot { - uint256 tokens; - uint256 underlyingAmount; - uint256 suppliedAt; - uint256 promisedSupplyRate; - } - - /** - * @notice Official record of token balances for each account - */ - mapping(address => SupplySnapshot) internal accountTokens; - - /** - * @notice Approved token transfer amounts on behalf of others - */ - mapping(address => mapping(address => uint256)) internal transferAllowances; - - /** - * @notice Container for borrow balance information - * @member principal Total balance (with accrued interest), after applying the most recent balance-changing action - * @member interestIndex Global borrowIndex as of the most recent balance-changing action - */ - struct BorrowSnapshot { - uint256 principal; - uint256 interestIndex; - } - - /** - * @notice Mapping of account addresses to outstanding borrow balances - */ - mapping(address => BorrowSnapshot) internal accountBorrows; -} - -abstract contract CTokenInterface is CTokenStorage { - /** - * @notice Indicator that this is a CToken contract (for inspection) - */ - bool public constant isCToken = true; - - /*** Market Events ***/ - - /** - * @notice Event emitted when interest is accrued - */ - event AccrueInterest( - uint256 cashPrior, - uint256 interestAccumulated, - uint256 borrowIndex, - uint256 totalBorrows - ); - - /** - * @notice Event emitted when tokens are minted - */ - event Mint(address indexed minter, uint256 mintAmount, uint256 mintTokens); - - /** - * @notice Event emitted when tokens are redeemed - */ - event Redeem( - address indexed redeemer, - uint256 redeemAmount, - uint256 redeemTokens - ); - - /** - * @notice Event emitted when underlying is borrowed - */ - event Borrow( - address indexed borrower, - uint256 borrowAmount, - uint256 accountBorrows, - uint256 totalBorrows - ); - - /** - * @notice Event emitted when a borrow is repaid - */ - event RepayBorrow( - address indexed payer, - address indexed borrower, - uint256 repayAmount, - uint256 accountBorrows, - uint256 totalBorrows - ); - - /** - * @notice Event emitted when a borrow is liquidated - */ - event LiquidateBorrow( - address indexed liquidator, - address indexed borrower, - uint256 repayAmount, - address indexed cTokenCollateral, - uint256 seizeTokens - ); - - /*** Admin Events ***/ - - /** - * @notice Event emitted when pendingAdmin is changed - */ - event NewPendingAdmin(address oldPendingAdmin, address newPendingAdmin); - - /** - * @notice Event emitted when pendingAdmin is accepted, which means admin is updated - */ - event NewAdmin(address oldAdmin, address newAdmin); - - /** - * @notice Event emitted when comptroller is changed - */ - event NewComptroller( - ComptrollerInterface oldComptroller, - ComptrollerInterface newComptroller - ); - - /** - * @notice Event emitted when interestRateModel is changed - */ - event NewMarketInterestRateModel( - InterestRateModel oldInterestRateModel, - InterestRateModel newInterestRateModel - ); - - /** - * @notice Event emitted when the reserve factor is changed - */ - event NewReserveFactor( - uint256 oldReserveFactorMantissa, - uint256 newReserveFactorMantissa - ); - - /** - * @notice Event emitted when the reserves are added - */ - event ReservesAdded( - address benefactor, - uint256 addAmount, - uint256 newTotalReserves - ); - - event SubsidyAdded( - address benefactor, - uint256 addAmount, - uint256 newSubsidyFund - ); - - /** - * @notice Event emitted when the reserves are reduced - */ - event ReservesReduced( - address admin, - uint256 reduceAmount, - uint256 newTotalReserves - ); - - /** - * @notice EIP20 Transfer event - */ - event Transfer(address indexed from, address indexed to, uint256 amount); - - /** - * @notice EIP20 Approval event - */ - event Approval( - address indexed owner, - address indexed spender, - uint256 amount - ); - - /** - * @notice Failure event - */ - event CTokenStorageFailure(uint256 error, uint256 info, uint256 detail); - - /*** User Interface ***/ - - function transfer(address dst, uint256 amount) - external - virtual - returns (bool); - - function transferFrom( - address src, - address dst, - uint256 amount - ) external virtual returns (bool); - - function approve(address spender, uint256 amount) - external - virtual - returns (bool); - - function allowance(address owner, address spender) - external - view - virtual - returns (uint256); - - function balanceOf(address owner) external view virtual returns (uint256); - - function balanceOfUnderlying(address owner) - external - virtual - returns (uint256); - - function getAccountSnapshot(address account) - external - view - virtual - returns ( - uint256, - uint256, - uint256, - uint256 - ); - - function borrowRatePerBlock() external view virtual returns (uint256); - - function supplyRatePerBlock() external view virtual returns (uint256); - - function totalBorrowsCurrent() external virtual returns (uint256); - - function borrowBalanceCurrent(address account) - external - virtual - returns (uint256); - - function borrowBalanceStored(address account) - public - view - virtual - returns (uint256); - - function exchangeRateCurrent() public virtual returns (uint256); - - function exchangeRateStored() public view virtual returns (uint256); - - function getCash() external view virtual returns (uint256); - - function accrueInterest() public virtual returns (uint256); - - function seize( - address liquidator, - address borrower, - uint256 seizeTokens - ) external virtual returns (uint256); - - /*** Admin Functions ***/ - - function _setPendingAdmin(address payable newPendingAdmin) - external - virtual - returns (uint256); - - function _acceptAdmin() external virtual returns (uint256); - - function _setComptroller(ComptrollerInterface newComptroller) - public - virtual - returns (uint256); - - function _setReserveFactor(uint256 newReserveFactorMantissa) - external - virtual - returns (uint256); - - function _reduceReserves(uint256 reduceAmount) - external - virtual - returns (uint256); - - function _setInterestRateModel(InterestRateModel newInterestRateModel) - public - virtual - returns (uint256); -} - -contract CErc20Storage { - /** - * @notice Underlying asset for this CToken - */ - address public underlying; -} - -abstract contract CErc20Interface is CErc20Storage { - /*** User Interface ***/ - - function mint(uint256 mintAmount) external virtual returns (uint256); - - function redeem(uint256 redeemAmount) - external - virtual - returns (uint256); - - function borrow(uint256 borrowAmount) external virtual returns (uint256); - - function repayBorrow(uint256 repayAmount) - external - virtual - returns (uint256); - - function liquidateBorrow( - address borrower, - uint256 repayAmount, - CTokenInterface cTokenCollateral - ) external virtual returns (uint256); - - function sweepToken(EIP20NonStandardInterface token) external virtual; - - /*** Admin Functions ***/ - - function _addReserves(uint256 addAmount) external virtual returns (uint256); -} - -contract CDelegationStorage { - /** - * @notice Implementation address for this contract - */ - address public implementation; -} - -abstract contract CDelegatorInterface is CDelegationStorage { - /** - * @notice Emitted when implementation is changed - */ - event NewImplementation( - address oldImplementation, - address newImplementation - ); - - /** - * @notice Called by the admin to update the implementation of the delegator - * @param implementation_ The address of the new implementation for delegation - * @param allowResign Flag to indicate whether to call _resignImplementation on the old implementation - * @param becomeImplementationData The encoded bytes data to be passed to _becomeImplementation - */ - function _setImplementation( - address implementation_, - bool allowResign, - bytes memory becomeImplementationData - ) public virtual; -} - -abstract contract CDelegateInterface is CDelegationStorage { - /** - * @notice Called by the delegator on a delegate to initialize it for duty - * @dev Should revert if any issues arise which make it unfit for delegation - * @param data The encoded bytes data for any initialization - */ - function _becomeImplementation(bytes memory data) public virtual; - - /** - * @notice Called by the delegator on a delegate to forfeit its responsibility - */ - function _resignImplementation() public virtual; -} - - -// Dependency file: contracts/ErrorReporter.sol - -// pragma solidity 0.8.6; - -contract ComptrollerErrorReporter { - enum Error { - NO_ERROR, - UNAUTHORIZED, - COMPTROLLER_MISMATCH, - INSUFFICIENT_SHORTFALL, - INSUFFICIENT_LIQUIDITY, - INVALID_CLOSE_FACTOR, - INVALID_COLLATERAL_FACTOR, - INVALID_LIQUIDATION_INCENTIVE, - MARKET_NOT_ENTERED, // no longer possible - MARKET_NOT_LISTED, - MARKET_ALREADY_LISTED, - MATH_ERROR, - NONZERO_BORROW_BALANCE, - PRICE_ERROR, - REJECTION, - SNAPSHOT_ERROR, - TOO_MANY_ASSETS, - TOO_MUCH_REPAY - } - - enum FailureInfo { - ACCEPT_ADMIN_PENDING_ADMIN_CHECK, - ACCEPT_PENDING_IMPLEMENTATION_ADDRESS_CHECK, - EXIT_MARKET_BALANCE_OWED, - EXIT_MARKET_REJECTION, - SET_CLOSE_FACTOR_OWNER_CHECK, - SET_CLOSE_FACTOR_VALIDATION, - SET_COLLATERAL_FACTOR_OWNER_CHECK, - SET_COLLATERAL_FACTOR_NO_EXISTS, - SET_COLLATERAL_FACTOR_VALIDATION, - SET_COLLATERAL_FACTOR_WITHOUT_PRICE, - SET_IMPLEMENTATION_OWNER_CHECK, - SET_LIQUIDATION_INCENTIVE_OWNER_CHECK, - SET_LIQUIDATION_INCENTIVE_VALIDATION, - SET_MAX_ASSETS_OWNER_CHECK, - SET_PENDING_ADMIN_OWNER_CHECK, - SET_PENDING_IMPLEMENTATION_OWNER_CHECK, - SET_PRICE_ORACLE_OWNER_CHECK, - SUPPORT_MARKET_EXISTS, - SUPPORT_MARKET_OWNER_CHECK, - SET_PAUSE_GUARDIAN_OWNER_CHECK - } - - /** - * @dev `error` corresponds to enum Error; `info` corresponds to enum FailureInfo, and `detail` is an arbitrary - * contract-specific code that enables us to report opaque error codes from upgradeable contracts. - **/ - event Failure(uint256 error, uint256 info, uint256 detail); - - /** - * @dev use this when reporting a known error from the money market or a non-upgradeable collaborator - */ - function fail(Error err, FailureInfo info) internal returns (uint256) { - emit Failure(uint256(err), uint256(info), 0); - - return uint256(err); - } - - /** - * @dev use this when reporting an opaque error from an upgradeable collaborator contract - */ - function failOpaque( - Error err, - FailureInfo info, - uint256 opaqueError - ) internal returns (uint256) { - emit Failure(uint256(err), uint256(info), opaqueError); - - return uint256(err); - } -} - -contract TokenErrorReporter { - enum Error { - NO_ERROR, - UNAUTHORIZED, - BAD_INPUT, - COMPTROLLER_REJECTION, - COMPTROLLER_CALCULATION_ERROR, - INTEREST_RATE_MODEL_ERROR, - INVALID_ACCOUNT_PAIR, - INVALID_CLOSE_AMOUNT_REQUESTED, - INVALID_COLLATERAL_FACTOR, - MATH_ERROR, - MARKET_NOT_FRESH, - MARKET_NOT_LISTED, - TOKEN_INSUFFICIENT_ALLOWANCE, - TOKEN_INSUFFICIENT_BALANCE, - TOKEN_INSUFFICIENT_CASH, - TOKEN_TRANSFER_IN_FAILED, - TOKEN_TRANSFER_OUT_FAILED - } - - /* - * Note: FailureInfo (but not Error) is kept in alphabetical order - * This is because FailureInfo grows significantly faster, and - * the order of Error has some meaning, while the order of FailureInfo - * is entirely arbitrary. - */ - enum FailureInfo { - ACCEPT_ADMIN_PENDING_ADMIN_CHECK, - ACCRUE_INTEREST_ACCUMULATED_INTEREST_CALCULATION_FAILED, - ACCRUE_INTEREST_BORROW_RATE_CALCULATION_FAILED, - ACCRUE_INTEREST_NEW_BORROW_INDEX_CALCULATION_FAILED, - ACCRUE_INTEREST_NEW_TOTAL_BORROWS_CALCULATION_FAILED, - ACCRUE_INTEREST_NEW_TOTAL_RESERVES_CALCULATION_FAILED, - ACCRUE_INTEREST_SIMPLE_INTEREST_FACTOR_CALCULATION_FAILED, - BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED, - BORROW_ACCRUE_INTEREST_FAILED, - BORROW_CASH_NOT_AVAILABLE, - BORROW_FRESHNESS_CHECK, - BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED, - BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED, - BORROW_MARKET_NOT_LISTED, - BORROW_COMPTROLLER_REJECTION, - LIQUIDATE_ACCRUE_BORROW_INTEREST_FAILED, - LIQUIDATE_ACCRUE_COLLATERAL_INTEREST_FAILED, - LIQUIDATE_COLLATERAL_FRESHNESS_CHECK, - LIQUIDATE_COMPTROLLER_REJECTION, - LIQUIDATE_COMPTROLLER_CALCULATE_AMOUNT_SEIZE_FAILED, - LIQUIDATE_CLOSE_AMOUNT_IS_UINT_MAX, - LIQUIDATE_CLOSE_AMOUNT_IS_ZERO, - LIQUIDATE_FRESHNESS_CHECK, - LIQUIDATE_LIQUIDATOR_IS_BORROWER, - LIQUIDATE_REPAY_BORROW_FRESH_FAILED, - LIQUIDATE_SEIZE_BALANCE_INCREMENT_FAILED, - LIQUIDATE_SEIZE_BALANCE_DECREMENT_FAILED, - LIQUIDATE_SEIZE_COMPTROLLER_REJECTION, - LIQUIDATE_SEIZE_LIQUIDATOR_IS_BORROWER, - LIQUIDATE_SEIZE_TOO_MUCH, - MINT_ACCRUE_INTEREST_FAILED, - MINT_COMPTROLLER_REJECTION, - MINT_EXCHANGE_CALCULATION_FAILED, - MINT_EXCHANGE_RATE_READ_FAILED, - MINT_FRESHNESS_CHECK, - MINT_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED, - MINT_NEW_TOTAL_SUPPLY_CALCULATION_FAILED, - MINT_TRANSFER_IN_FAILED, - MINT_TRANSFER_IN_NOT_POSSIBLE, - REDEEM_ACCRUE_INTEREST_FAILED, - REDEEM_COMPTROLLER_REJECTION, - REDEEM_EXCHANGE_TOKENS_CALCULATION_FAILED, - REDEEM_EXCHANGE_AMOUNT_CALCULATION_FAILED, - REDEEM_EXCHANGE_RATE_READ_FAILED, - REDEEM_FRESHNESS_CHECK, - REDEEM_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED, - REDEEM_NEW_TOTAL_SUPPLY_CALCULATION_FAILED, - REDEEM_TRANSFER_OUT_NOT_POSSIBLE, - REDUCE_RESERVES_ACCRUE_INTEREST_FAILED, - REDUCE_RESERVES_ADMIN_CHECK, - REDUCE_RESERVES_CASH_NOT_AVAILABLE, - REDUCE_RESERVES_FRESH_CHECK, - REDUCE_RESERVES_VALIDATION, - REPAY_BEHALF_ACCRUE_INTEREST_FAILED, - REPAY_BORROW_ACCRUE_INTEREST_FAILED, - REPAY_BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED, - REPAY_BORROW_COMPTROLLER_REJECTION, - REPAY_BORROW_FRESHNESS_CHECK, - REPAY_BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED, - REPAY_BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED, - REPAY_BORROW_TRANSFER_IN_NOT_POSSIBLE, - SET_COLLATERAL_FACTOR_OWNER_CHECK, - SET_COLLATERAL_FACTOR_VALIDATION, - SET_COMPTROLLER_OWNER_CHECK, - SET_INTEREST_RATE_MODEL_ACCRUE_INTEREST_FAILED, - SET_INTEREST_RATE_MODEL_FRESH_CHECK, - SET_INTEREST_RATE_MODEL_OWNER_CHECK, - SET_MAX_ASSETS_OWNER_CHECK, - SET_ORACLE_MARKET_NOT_LISTED, - SET_PENDING_ADMIN_OWNER_CHECK, - SET_RESERVE_FACTOR_ACCRUE_INTEREST_FAILED, - SET_RESERVE_FACTOR_ADMIN_CHECK, - SET_RESERVE_FACTOR_FRESH_CHECK, - SET_RESERVE_FACTOR_BOUNDS_CHECK, - TRANSFER_COMPTROLLER_REJECTION, - TRANSFER_NOT_ALLOWED, - TRANSFER_NOT_ENOUGH, - TRANSFER_TOO_MUCH, - ADD_RESERVES_ACCRUE_INTEREST_FAILED, - ADD_RESERVES_FRESH_CHECK, - ADD_RESERVES_TRANSFER_IN_NOT_POSSIBLE, - ADD_SUBSIDY_FUND_FAILED, - ADD_SUBSIDY_FUND_FRESH_CHECK - } - - /** - * @dev `error` corresponds to enum Error; `info` corresponds to enum FailureInfo, and `detail` is an arbitrary - * contract-specific code that enables us to report opaque error codes from upgradeable contracts. - **/ - event TokenFailure(uint256 error, uint256 info, uint256 detail); - - /** - * @dev use this when reporting a known error from the money market or a non-upgradeable collaborator - */ - function fail(Error err, FailureInfo info) internal returns (uint256) { - emit TokenFailure(uint256(err), uint256(info), 0); - - return uint256(err); - } - - /** - * @dev use this when reporting an opaque error from an upgradeable collaborator contract - */ - function failOpaque( - Error err, - FailureInfo info, - uint256 opaqueError - ) internal returns (uint256) { - emit TokenFailure(uint256(err), uint256(info), opaqueError); - - return uint256(err); - } -} - - -// Dependency file: contracts/EIP20Interface.sol - -// pragma solidity 0.8.6; - -/** - * @title ERC 20 Token Standard Interface - * https://eips.ethereum.org/EIPS/eip-20 - */ -interface EIP20Interface { - function name() external view returns (string memory); - - function symbol() external view returns (string memory); - - function decimals() external view returns (uint8); - - /** - * @notice Get the total number of tokens in circulation - * @return The supply of tokens - */ - function totalSupply() external view returns (uint256); - - /** - * @notice Gets the balance of the specified address - * @param owner The address from which the balance will be retrieved - * @return balance The balance - */ - function balanceOf(address owner) external view returns (uint256 balance); - - /** - * @notice Transfer `amount` tokens from `msg.sender` to `dst` - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - * @return success Whether or not the transfer succeeded - */ - function transfer(address dst, uint256 amount) - external - returns (bool success); - - /** - * @notice Transfer `amount` tokens from `src` to `dst` - * @param src The address of the source account - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - * @return success Whether or not the transfer succeeded - */ - function transferFrom( - address src, - address dst, - uint256 amount - ) external returns (bool success); - - /** - * @notice Approve `spender` to transfer up to `amount` from `src` - * @dev This will overwrite the approval amount for `spender` - * and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve) - * @param spender The address of the account which may transfer tokens - * @param amount The number of tokens that are approved (-1 means infinite) - * @return success Whether or not the approval succeeded - */ - function approve(address spender, uint256 amount) - external - returns (bool success); - - /** - * @notice Get the current allowance from `owner` for `spender` - * @param owner The address of the account which owns the tokens to be spent - * @param spender The address of the account which may transfer tokens - * @return remaining The number of tokens allowed to be spent (-1 means infinite) - */ - function allowance(address owner, address spender) - external - view - returns (uint256 remaining); - - event Transfer(address indexed from, address indexed to, uint256 amount); - event Approval( - address indexed owner, - address indexed spender, - uint256 amount - ); -} - - -// Dependency file: contracts/WhitelistInterface.sol - -// pragma solidity 0.8.6; - -interface WhitelistInterface { - function setStatus(bool _newStatus) external; - function enabled() external view returns(bool); - - function addUsers(address[] memory _users) external; - function exist(address _user) external view returns(bool); - function getUsers() external view returns(address[] memory currentUsers); - function removeUser(address _user) external; -} - -// Dependency file: contracts/CToken.sol - -// pragma solidity 0.8.6; - -// import "contracts/ComptrollerInterface.sol"; -// import "contracts/CTokenInterfaces.sol"; -// import "contracts/ErrorReporter.sol"; -// import "contracts/Exponential.sol"; -// import "contracts/EIP20Interface.sol"; -// import "contracts/InterestRateModel.sol"; -// import "contracts/WhitelistInterface.sol"; - -/** - * @title tropykus CToken Contract - * @notice Abstract base for CTokens - * @author tropykus - */ -abstract contract CToken is CTokenInterface, Exponential, TokenErrorReporter { - address whitelist; - - /** - * @notice Initialize the money market - * @param comptroller_ The address of the Comptroller - * @param interestRateModel_ The address of the interest rate model - * @param initialExchangeRateMantissa_ The initial exchange rate, scaled by 1e18 - * @param name_ EIP-20 name of this token - * @param symbol_ EIP-20 symbol of this token - * @param decimals_ EIP-20 decimal precision of this token - */ - function initialize( - ComptrollerInterface comptroller_, - InterestRateModel interestRateModel_, - uint256 initialExchangeRateMantissa_, - string memory name_, - string memory symbol_, - uint8 decimals_ - ) public { - require(msg.sender == admin, "CT01"); - require(accrualBlockNumber == 0 && borrowIndex == 0, "CT02"); - - initialExchangeRateMantissa = initialExchangeRateMantissa_; - require(initialExchangeRateMantissa > 0, "CT03"); - - uint256 err = _setComptroller(comptroller_); - require(err == uint256(Error.NO_ERROR), "CT04"); - - accrualBlockNumber = getBlockNumber(); - borrowIndex = mantissaOne; - - err = _setInterestRateModelFresh(interestRateModel_); - require(err == uint256(Error.NO_ERROR), "CT05"); - - name = name_; - symbol = symbol_; - decimals = decimals_; - - _notEntered = true; - } - - function addWhitelist(address _whitelist) external returns (uint256) { - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_INTEREST_RATE_MODEL_OWNER_CHECK - ); - } - whitelist = _whitelist; - } - - /** - * @notice Transfer `tokens` tokens from `src` to `dst` by `spender` - * @dev Called by both `transfer` and `transferFrom` internally - * @param spender The address of the account performing the transfer - * @param src The address of the source account - * @param dst The address of the destination account - * @param tokens The number of tokens to transfer - * @return Whether or not the transfer succeeded - */ - function transferTokens( - address spender, - address src, - address dst, - uint256 tokens - ) internal returns (uint256) { - uint256 allowed = comptroller.transferAllowed( - address(this), - src, - dst, - tokens - ); - if (allowed != 0) { - return - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.TRANSFER_COMPTROLLER_REJECTION, - allowed - ); - } - - if (src == dst) { - return fail(Error.BAD_INPUT, FailureInfo.TRANSFER_NOT_ALLOWED); - } - - uint256 startingAllowance = 0; - if (spender == src) { - startingAllowance = type(uint256).max; - } else { - startingAllowance = transferAllowances[src][spender]; - } - - MathError mathErr; - uint256 allowanceNew; - uint256 srcTokensNew; - uint256 dstTokensNew; - - (mathErr, allowanceNew) = subUInt(startingAllowance, tokens); - if (mathErr != MathError.NO_ERROR) { - return fail(Error.MATH_ERROR, FailureInfo.TRANSFER_NOT_ALLOWED); - } - - (mathErr, srcTokensNew) = subUInt(accountTokens[src].tokens, tokens); - if (mathErr != MathError.NO_ERROR) { - return fail(Error.MATH_ERROR, FailureInfo.TRANSFER_NOT_ENOUGH); - } - - (mathErr, dstTokensNew) = addUInt(accountTokens[dst].tokens, tokens); - if (mathErr != MathError.NO_ERROR) { - return fail(Error.MATH_ERROR, FailureInfo.TRANSFER_TOO_MUCH); - } - - accountTokens[src].tokens = srcTokensNew; - accountTokens[dst].tokens = dstTokensNew; - - if (startingAllowance != type(uint256).max) { - transferAllowances[src][spender] = allowanceNew; - } - - emit Transfer(src, dst, tokens); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Transfer `amount` tokens from `msg.sender` to `dst` - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - * @return Whether or not the transfer succeeded - */ - function transfer(address dst, uint256 amount) - external - override - nonReentrant - returns (bool) - { - return - transferTokens(msg.sender, msg.sender, dst, amount) == - uint256(Error.NO_ERROR); - } - - /** - * @notice Transfer `amount` tokens from `src` to `dst` - * @param src The address of the source account - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - * @return Whether or not the transfer succeeded - */ - function transferFrom( - address src, - address dst, - uint256 amount - ) external override nonReentrant returns (bool) { - return - transferTokens(msg.sender, src, dst, amount) == - uint256(Error.NO_ERROR); - } - - /** - * @notice Approve `spender` to transfer up to `amount` from `src` - * @dev This will overwrite the approval amount for `spender` - * and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve) - * @param spender The address of the account which may transfer tokens - * @param amount The number of tokens that are approved (-1 means infinite) - * @return Whether or not the approval succeeded - */ - function approve(address spender, uint256 amount) - external - override - returns (bool) - { - transferAllowances[msg.sender][spender] = amount; - emit Approval(msg.sender, spender, amount); - return true; - } - - /** - * @notice Get the current allowance from `owner` for `spender` - * @param owner The address of the account which owns the tokens to be spent - * @param spender The address of the account which may transfer tokens - * @return The number of tokens allowed to be spent (-1 means infinite) - */ - function allowance(address owner, address spender) - external - view - override - returns (uint256) - { - return transferAllowances[owner][spender]; - } - - /** - * @notice Get the token balance of the `owner` - * @param owner The address of the account to query - * @return The number of tokens owned by `owner` - */ - function balanceOf(address owner) external view override returns (uint256) { - return accountTokens[owner].tokens; - } - - /** - * @notice Get the underlying balance of the `owner` - * @dev This also accrues interest in a transaction - * @param owner The address of the account to query - * @return The amount of underlying owned by `owner` - */ - function balanceOfUnderlying(address owner) - external - override - returns (uint256) - { - (MathError mErr, uint256 balance) = mulScalarTruncate( - Exp({mantissa: exchangeRateCurrent()}), - accountTokens[owner].tokens - ); - require(mErr == MathError.NO_ERROR, "CT06"); - return balance; - } - - /** - * @notice Get a snapshot of the account's balances, and the cached exchange rate - * @dev This is used by comptroller to more efficiently perform liquidity checks. - * @param account Address of the account to snapshot - * @return (possible error, token balance, borrow balance, exchange rate mantissa) - */ - function getAccountSnapshot(address account) - external - view - override - returns ( - uint256, - uint256, - uint256, - uint256 - ) - { - uint256 cTokenBalance = accountTokens[account].tokens; - uint256 borrowBalance; - uint256 exchangeRateMantissa; - - MathError mErr; - - (mErr, borrowBalance) = borrowBalanceStoredInternal(account); - if (mErr != MathError.NO_ERROR) { - return (uint256(Error.MATH_ERROR), 0, 0, 0); - } - - (mErr, exchangeRateMantissa) = exchangeRateStoredInternal(); - if (mErr != MathError.NO_ERROR) { - return (uint256(Error.MATH_ERROR), 0, 0, 0); - } - - return ( - uint256(Error.NO_ERROR), - cTokenBalance, - borrowBalance, - exchangeRateMantissa - ); - } - - /** - * @dev Function to simply retrieve block number - * This exists mainly for inheriting test contracts to stub this result. - */ - function getBlockNumber() internal view virtual returns (uint256) { - return block.number; - } - - /** - * @notice Returns the current per-block borrow interest rate for this cToken - * @return The borrow interest rate per block, scaled by 1e18 - */ - function borrowRatePerBlock() external view override returns (uint256) { - return - interestRateModel.getBorrowRate( - getCashPrior(), - totalBorrows, - totalReserves - ); - } - - /** - * @notice Returns the current per-block supply interest rate for this cToken - * @return The supply interest rate per block, scaled by 1e18 - */ - function supplyRatePerBlock() external view override returns (uint256) { - return - interestRateModel.getSupplyRate( - getCashPrior(), - totalBorrows, - totalReserves, - reserveFactorMantissa - ); - } - - /** - * @notice Returns the current total borrows plus accrued interest - * @return The total borrows with interest - */ - function totalBorrowsCurrent() - external - override - nonReentrant - returns (uint256) - { - require(accrueInterest() == uint256(Error.NO_ERROR), "CT07"); - return totalBorrows; - } - - /** - * @notice Accrue interest to updated borrowIndex and then calculate account's borrow balance using the updated borrowIndex - * @param account The address whose balance should be calculated after updating borrowIndex - * @return The calculated balance - */ - function borrowBalanceCurrent(address account) - external - override - nonReentrant - returns (uint256) - { - require(accrueInterest() == uint256(Error.NO_ERROR), "CT07"); - return borrowBalanceStored(account); - } - - /** - * @notice Return the borrow balance of account based on stored data - * @param account The address whose balance should be calculated - * @return The calculated balance - */ - function borrowBalanceStored(address account) - public - view - override - returns (uint256) - { - (MathError err, uint256 result) = borrowBalanceStoredInternal(account); - require(err == MathError.NO_ERROR, "CT08"); - return result; - } - - /** - * @notice Return the borrow balance of account based on stored data - * @param account The address whose balance should be calculated - * @return (error code, the calculated balance or 0 if error code is non-zero) - */ - function borrowBalanceStoredInternal(address account) - internal - view - returns (MathError, uint256) - { - MathError mathErr; - uint256 principalTimesIndex; - uint256 result; - - BorrowSnapshot storage borrowSnapshot = accountBorrows[account]; - - if (borrowSnapshot.principal == 0) { - return (MathError.NO_ERROR, 0); - } - - (mathErr, principalTimesIndex) = mulUInt( - borrowSnapshot.principal, - borrowIndex - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - - (mathErr, result) = divUInt( - principalTimesIndex, - borrowSnapshot.interestIndex - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - - return (MathError.NO_ERROR, result); - } - - function getBorrowerPrincipalStored(address account) - public - view - returns (uint256 borrowed) - { - borrowed = accountBorrows[account].principal; - } - - function getSupplierSnapshotStored(address account) - public - view - returns ( - uint256 tokens, - uint256 underlyingAmount, - uint256 suppliedAt, - uint256 promisedSupplyRate - ) - { - tokens = accountTokens[account].tokens; - underlyingAmount = accountTokens[account].underlyingAmount; - suppliedAt = accountTokens[account].suppliedAt; - promisedSupplyRate = accountTokens[account].promisedSupplyRate; - } - - /** - * @notice Accrue interest then return the up-to-date exchange rate - * @return Calculated exchange rate scaled by 1e18 - */ - function exchangeRateCurrent() - public - override - nonReentrant - returns (uint256) - { - require(accrueInterest() == uint256(Error.NO_ERROR), "CT07"); - return exchangeRateStored(); - } - - /** - * @notice Calculates the exchange rate from the underlying to the CToken - * @dev This function does not accrue interest before calculating the exchange rate - * @return Calculated exchange rate scaled by 1e18 - */ - function exchangeRateStored() public view override returns (uint256) { - (MathError err, uint256 result) = exchangeRateStoredInternal(); - require(err == MathError.NO_ERROR, "CT09"); - return result; - } - - /** - * @notice Calculates the exchange rate from the underlying to the CToken - * @dev This function does not accrue interest before calculating the exchange rate - * @return (error code, calculated exchange rate scaled by 1e18) - */ - function exchangeRateStoredInternal() - internal - view - virtual - returns (MathError, uint256) - { - uint256 _totalSupply = totalSupply; - if (_totalSupply == 0) { - return (MathError.NO_ERROR, initialExchangeRateMantissa); - } else { - MathError error; - uint256 exchangeRate; - uint256 totalCash = getCashPrior(); - if (interestRateModel.isTropykusInterestRateModel()) { - (error, exchangeRate) = tropykusExchangeRateStoredInternal( - msg.sender - ); - if (error == MathError.NO_ERROR) { - return (MathError.NO_ERROR, exchangeRate); - } else { - return (MathError.NO_ERROR, initialExchangeRateMantissa); - } - } - return - interestRateModel.getExchangeRate( - totalCash, - totalBorrows, - totalReserves, - totalSupply - ); - } - } - - function tropykusExchangeRateStoredInternal(address redeemer) - internal - view - returns (MathError, uint256) - { - if (totalSupply == 0) { - return (MathError.NO_ERROR, initialExchangeRateMantissa); - } else { - SupplySnapshot storage supplySnapshot = accountTokens[redeemer]; - if (supplySnapshot.suppliedAt == 0) { - return (MathError.DIVISION_BY_ZERO, 0); - } - (, uint256 interestFactorMantissa, ) = tropykusInterestAccrued( - redeemer - ); - Exp memory interestFactor = Exp({mantissa: interestFactorMantissa}); - uint256 currentUnderlying = supplySnapshot.underlyingAmount; - Exp memory redeemerUnderlying = Exp({mantissa: currentUnderlying}); - (, Exp memory realAmount) = mulExp( - interestFactor, - redeemerUnderlying - ); - (, Exp memory exchangeRate) = getExp( - realAmount.mantissa, - supplySnapshot.tokens - ); - return (MathError.NO_ERROR, exchangeRate.mantissa); - } - } - - function tropykusInterestAccrued(address account) - internal - view - returns ( - MathError, - uint256, - uint256 - ) - { - SupplySnapshot storage supplySnapshot = accountTokens[account]; - uint256 promisedSupplyRate = supplySnapshot.promisedSupplyRate; - Exp memory expectedSupplyRatePerBlock = Exp({ - mantissa: promisedSupplyRate - }); - (, uint256 delta) = subUInt( - accrualBlockNumber, - supplySnapshot.suppliedAt - ); - (, Exp memory expectedSupplyRatePerBlockWithDelta) = mulScalar( - expectedSupplyRatePerBlock, - delta - ); - (, Exp memory interestFactor) = addExp( - Exp({mantissa: 1e18}), - expectedSupplyRatePerBlockWithDelta - ); - uint256 currentUnderlying = supplySnapshot.underlyingAmount; - Exp memory redeemerUnderlying = Exp({mantissa: currentUnderlying}); - (, Exp memory realAmount) = mulExp(interestFactor, redeemerUnderlying); - (, uint256 interestEarned) = subUInt( - realAmount.mantissa, - currentUnderlying - ); - return (MathError.NO_ERROR, interestFactor.mantissa, interestEarned); - } - - /** - * @notice Get cash balance of this cToken in the underlying asset - * @return The quantity of underlying asset owned by this contract - */ - function getCash() external view override returns (uint256) { - return getCashPrior(); - } - - /** - * @notice Applies accrued interest to total borrows and reserves - * @dev This calculates interest accrued from the last checkpointed block - * up to the current block and writes new checkpoint to storage. - */ - function accrueInterest() public override returns (uint256) { - uint256 currentBlockNumber = getBlockNumber(); - uint256 accrualBlockNumberPrior = accrualBlockNumber; - - if (accrualBlockNumberPrior == currentBlockNumber) { - return uint256(Error.NO_ERROR); - } - - uint256 cashPrior = getCashPrior(); - uint256 borrowsPrior = totalBorrows; - uint256 reservesPrior = totalReserves; - uint256 borrowIndexPrior = borrowIndex; - - uint256 borrowRateMantissa = interestRateModel.getBorrowRate( - cashPrior, - borrowsPrior, - reservesPrior - ); - require(borrowRateMantissa <= borrowRateMaxMantissa, "CT10"); - - (MathError mathErr, uint256 blockDelta) = subUInt( - currentBlockNumber, - accrualBlockNumberPrior - ); - require(mathErr == MathError.NO_ERROR, "CT11"); - - Exp memory simpleInterestFactor; - uint256 interestAccumulated; - uint256 totalBorrowsNew; - uint256 totalReservesNew; - uint256 borrowIndexNew; - - (mathErr, simpleInterestFactor) = mulScalar( - Exp({mantissa: borrowRateMantissa}), - blockDelta - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .ACCRUE_INTEREST_SIMPLE_INTEREST_FACTOR_CALCULATION_FAILED, - uint256(mathErr) - ); - } - - (mathErr, interestAccumulated) = mulScalarTruncate( - simpleInterestFactor, - borrowsPrior - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .ACCRUE_INTEREST_ACCUMULATED_INTEREST_CALCULATION_FAILED, - uint256(mathErr) - ); - } - - (mathErr, totalBorrowsNew) = addUInt(interestAccumulated, borrowsPrior); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .ACCRUE_INTEREST_NEW_TOTAL_BORROWS_CALCULATION_FAILED, - uint256(mathErr) - ); - } - - (mathErr, totalReservesNew) = mulScalarTruncateAddUInt( - Exp({mantissa: reserveFactorMantissa}), - interestAccumulated, - reservesPrior - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .ACCRUE_INTEREST_NEW_TOTAL_RESERVES_CALCULATION_FAILED, - uint256(mathErr) - ); - } - - if (interestRateModel.isTropykusInterestRateModel()) { - (mathErr, totalReservesNew) = newReserves( - borrowRateMantissa, - cashPrior, - borrowsPrior, - reservesPrior, - interestAccumulated - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .ACCRUE_INTEREST_NEW_TOTAL_RESERVES_CALCULATION_FAILED, - uint256(mathErr) - ); - } - } - - (mathErr, borrowIndexNew) = mulScalarTruncateAddUInt( - simpleInterestFactor, - borrowIndexPrior, - borrowIndexPrior - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .ACCRUE_INTEREST_NEW_BORROW_INDEX_CALCULATION_FAILED, - uint256(mathErr) - ); - } - - accrualBlockNumber = currentBlockNumber; - borrowIndex = borrowIndexNew; - totalBorrows = totalBorrowsNew; - totalReserves = totalReservesNew; - - emit AccrueInterest( - cashPrior, - interestAccumulated, - borrowIndexNew, - totalBorrowsNew - ); - - return uint256(Error.NO_ERROR); - } - - function newReserves( - uint256 borrowRateMantissa, - uint256 cashPrior, - uint256 borrowsPrior, - uint256 reservesPrior, - uint256 interestAccumulated - ) internal view returns (MathError mathErr, uint256 totalReservesNew) { - uint256 newReserveFactorMantissa; - uint256 utilizationRate = interestRateModel.utilizationRate( - cashPrior, - borrowsPrior, - reservesPrior - ); - uint256 expectedSupplyRate = interestRateModel.getSupplyRate( - cashPrior, - borrowsPrior, - reservesPrior, - reserveFactorMantissa - ); - if ( - interestRateModel.isAboveOptimal( - cashPrior, - borrowsPrior, - reservesPrior - ) - ) { - (mathErr, newReserveFactorMantissa) = mulScalarTruncate( - Exp({mantissa: utilizationRate}), - borrowRateMantissa - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - (mathErr, newReserveFactorMantissa) = subUInt( - newReserveFactorMantissa, - expectedSupplyRate - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - (mathErr, totalReservesNew) = mulScalarTruncateAddUInt( - Exp({mantissa: newReserveFactorMantissa}), - interestAccumulated, - reservesPrior - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - } else { - mathErr = MathError.NO_ERROR; - totalReservesNew = reservesPrior; - } - } - - /** - * @notice Sender supplies assets into the market and receives cTokens in exchange - * @dev Accrues interest whether or not the operation succeeds, unless reverted - * @param mintAmount The amount of the underlying asset to supply - * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual mint amount. - */ - function mintInternal(uint256 mintAmount) - internal - nonReentrant - returns (uint256, uint256) - { - if (WhitelistInterface(whitelist).enabled()) { - require(WhitelistInterface(whitelist).exist(msg.sender), "CT26"); - } - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return ( - fail(Error(error), FailureInfo.MINT_ACCRUE_INTEREST_FAILED), - 0 - ); - } - return mintFresh(msg.sender, mintAmount); - } - - struct MintLocalVars { - Error err; - MathError mathErr; - uint256 exchangeRateMantissa; - uint256 mintTokens; - uint256 totalSupplyNew; - uint256 accountTokensNew; - uint256 actualMintAmount; - } - - /** - * @notice User supplies assets into the market and receives cTokens in exchange - * @dev Assumes interest has already been accrued up to the current block - * @param minter The address of the account which is supplying the assets - * @param mintAmount The amount of the underlying asset to supply - * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual mint amount. - */ - function mintFresh(address minter, uint256 mintAmount) - internal - returns (uint256, uint256) - { - uint256 allowed = comptroller.mintAllowed( - address(this), - minter, - mintAmount - ); - if (allowed != 0) { - return ( - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.MINT_COMPTROLLER_REJECTION, - allowed - ), - 0 - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return ( - fail(Error.MARKET_NOT_FRESH, FailureInfo.MINT_FRESHNESS_CHECK), - 0 - ); - } - - MintLocalVars memory vars; - - ( - vars.mathErr, - vars.exchangeRateMantissa - ) = exchangeRateStoredInternal(); - if (vars.mathErr != MathError.NO_ERROR) { - return ( - failOpaque( - Error.MATH_ERROR, - FailureInfo.MINT_EXCHANGE_RATE_READ_FAILED, - uint256(vars.mathErr) - ), - 0 - ); - } - if (interestRateModel.isTropykusInterestRateModel()) { - SupplySnapshot storage supplySnapshot = accountTokens[minter]; - (, uint256 newTotalSupply) = addUInt( - supplySnapshot.underlyingAmount, - mintAmount - ); - require(newTotalSupply <= 0.1e18, "CT24"); - } - vars.actualMintAmount = doTransferIn(minter, mintAmount); - - (vars.mathErr, vars.mintTokens) = divScalarByExpTruncate( - vars.actualMintAmount, - Exp({mantissa: vars.exchangeRateMantissa}) - ); - require(vars.mathErr == MathError.NO_ERROR, "CT12"); - - (vars.mathErr, vars.totalSupplyNew) = addUInt( - totalSupply, - vars.mintTokens - ); - require(vars.mathErr == MathError.NO_ERROR, "CT13"); - - (vars.mathErr, vars.accountTokensNew) = addUInt( - accountTokens[minter].tokens, - vars.mintTokens - ); - require(vars.mathErr == MathError.NO_ERROR, "CT14"); - - uint256 currentSupplyRate = interestRateModel.getSupplyRate( - getCashPrior(), - totalBorrows, - totalReserves, - reserveFactorMantissa - ); - - bool isTropykusInterestRateModel = interestRateModel - .isTropykusInterestRateModel(); - - if (accountTokens[minter].tokens > 0) { - Exp memory updatedUnderlying; - if (isTropykusInterestRateModel) { - (, uint256 interestFactorMantissa, ) = tropykusInterestAccrued( - minter - ); - Exp memory interestFactor = Exp({ - mantissa: interestFactorMantissa - }); - uint256 currentUnderlyingAmount = accountTokens[minter] - .underlyingAmount; - MathError mErrorNewAmount; - (mErrorNewAmount, updatedUnderlying) = mulExp( - Exp({mantissa: currentUnderlyingAmount}), - interestFactor - ); - if (mErrorNewAmount != MathError.NO_ERROR) { - return ( - failOpaque( - Error.MATH_ERROR, - FailureInfo.MINT_EXCHANGE_CALCULATION_FAILED, - uint256(mErrorNewAmount) - ), - 0 - ); - } - } else { - uint256 currentTokens = accountTokens[minter].tokens; - MathError mErrorUpdatedUnderlying; - (mErrorUpdatedUnderlying, updatedUnderlying) = mulExp( - Exp({mantissa: currentTokens}), - Exp({mantissa: vars.exchangeRateMantissa}) - ); - if (mErrorUpdatedUnderlying != MathError.NO_ERROR) { - return ( - failOpaque( - Error.MATH_ERROR, - FailureInfo.MINT_EXCHANGE_CALCULATION_FAILED, - uint256(mErrorUpdatedUnderlying) - ), - 0 - ); - } - } - (, mintAmount) = addUInt(updatedUnderlying.mantissa, mintAmount); - } - - totalSupply = vars.totalSupplyNew; - accountTokens[minter] = SupplySnapshot({ - tokens: vars.accountTokensNew, - underlyingAmount: mintAmount, - suppliedAt: accrualBlockNumber, - promisedSupplyRate: currentSupplyRate - }); - - emit Mint(minter, vars.actualMintAmount, vars.mintTokens); - emit Transfer(address(this), minter, vars.mintTokens); - - return (uint256(Error.NO_ERROR), vars.actualMintAmount); - } - - /** - * @notice Sender redeems cTokens in exchange for a specified amount of underlying asset - * @dev Accrues interest whether or not the operation succeeds, unless reverted - * @param redeemAmount The amount of underlying to receive from redeeming cTokens - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function redeemUnderlyingInternal(uint256 redeemAmount) - internal - nonReentrant - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return - fail(Error(error), FailureInfo.REDEEM_ACCRUE_INTEREST_FAILED); - } - return redeemFresh(payable(msg.sender), redeemAmount); - } - - struct RedeemLocalVars { - Error err; - MathError mathErr; - uint256 exchangeRateMantissa; - uint256 redeemTokens; - uint256 redeemAmount; - uint256 totalSupplyNew; - uint256 accountTokensNew; - uint256 newSubsidyFund; - } - - /** - * @notice User redeems cTokens in exchange for the underlying asset - * @dev Assumes interest has already been accrued up to the current block - * @param redeemer The address of the account which is redeeming the tokens - * @param redeemAmountIn The number of underlying tokens to receive from redeeming cTokens - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function redeemFresh(address payable redeemer, uint256 redeemAmountIn) - internal - returns (uint256) - { - require(redeemAmountIn > 0, "CT15"); - - RedeemLocalVars memory vars; - - SupplySnapshot storage supplySnapshot = accountTokens[redeemer]; - - ( - vars.mathErr, - vars.exchangeRateMantissa - ) = exchangeRateStoredInternal(); - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.REDEEM_EXCHANGE_RATE_READ_FAILED, - uint256(vars.mathErr) - ); - } - - uint256 interestEarned; - uint256 subsidyFundPortion; - uint256 currentUnderlying; - - bool isTropykusInterestRateModel = interestRateModel - .isTropykusInterestRateModel(); - if (isTropykusInterestRateModel) { - currentUnderlying = supplySnapshot.underlyingAmount; - (, , interestEarned) = tropykusInterestAccrued(redeemer); - } - supplySnapshot.promisedSupplyRate = interestRateModel.getSupplyRate( - getCashPrior(), - totalBorrows, - totalReserves, - reserveFactorMantissa - ); - - if ( - isTropykusInterestRateModel && - !interestRateModel.isAboveOptimal( - getCashPrior(), - totalBorrows, - totalReserves - ) - ) { - uint256 borrowRate = interestRateModel.getBorrowRate( - getCashPrior(), - totalBorrows, - totalReserves - ); - - uint256 utilizationRate = interestRateModel.utilizationRate( - getCashPrior(), - totalBorrows, - totalReserves - ); - - (, uint256 estimatedEarning) = mulScalarTruncate( - Exp({mantissa: borrowRate}), - utilizationRate - ); - - (, subsidyFundPortion) = subUInt( - supplySnapshot.promisedSupplyRate, - estimatedEarning - ); - (, Exp memory subsidyFactor) = getExp( - subsidyFundPortion, - supplySnapshot.promisedSupplyRate - ); - (, subsidyFundPortion) = mulScalarTruncate( - subsidyFactor, - interestEarned - ); - } - - vars.redeemAmount = redeemAmountIn; - - if (isTropykusInterestRateModel) { - (, Exp memory num) = mulExp( - vars.redeemAmount, - supplySnapshot.tokens - ); - (, Exp memory realTokensWithdrawAmount) = getExp( - num.mantissa, - currentUnderlying - ); - vars.redeemTokens = realTokensWithdrawAmount.mantissa; - } else { - (vars.mathErr, vars.redeemTokens) = divScalarByExpTruncate( - redeemAmountIn, - Exp({mantissa: vars.exchangeRateMantissa}) - ); - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.REDEEM_EXCHANGE_AMOUNT_CALCULATION_FAILED, - uint256(vars.mathErr) - ); - } - } - // } - - uint256 allowed = comptroller.redeemAllowed( - address(this), - redeemer, - vars.redeemTokens - ); - if (allowed != 0) { - return - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.REDEEM_COMPTROLLER_REJECTION, - allowed - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.REDEEM_FRESHNESS_CHECK - ); - } - - (vars.mathErr, vars.totalSupplyNew) = subUInt( - totalSupply, - vars.redeemTokens - ); - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.REDEEM_NEW_TOTAL_SUPPLY_CALCULATION_FAILED, - uint256(vars.mathErr) - ); - } - - (, vars.newSubsidyFund) = subUInt(subsidyFund, subsidyFundPortion); - - (vars.mathErr, vars.accountTokensNew) = subUInt( - supplySnapshot.tokens, - vars.redeemTokens - ); - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.REDEEM_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED, - uint256(vars.mathErr) - ); - } - - uint256 cash = getCashPrior(); - if (isTropykusInterestRateModel) { - cash = address(this).balance; - } - - if (cash < vars.redeemAmount) { - return - fail( - Error.TOKEN_INSUFFICIENT_CASH, - FailureInfo.REDEEM_TRANSFER_OUT_NOT_POSSIBLE - ); - } - - doTransferOut(redeemer, vars.redeemAmount); - - totalSupply = vars.totalSupplyNew; - subsidyFund = vars.newSubsidyFund; - supplySnapshot.tokens = vars.accountTokensNew; - supplySnapshot.suppliedAt = accrualBlockNumber; - (, supplySnapshot.underlyingAmount) = subUInt( - supplySnapshot.underlyingAmount, - vars.redeemAmount - ); - - emit Transfer(redeemer, address(this), vars.redeemTokens); - emit Redeem(redeemer, vars.redeemAmount, vars.redeemTokens); - - comptroller.redeemVerify( - address(this), - redeemer, - vars.redeemAmount, - vars.redeemTokens - ); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Sender borrows assets from the protocol to their own address - * @param borrowAmount The amount of the underlying asset to borrow - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function borrowInternal(uint256 borrowAmount) - internal - nonReentrant - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return - fail(Error(error), FailureInfo.BORROW_ACCRUE_INTEREST_FAILED); - } - return borrowFresh(payable(msg.sender), borrowAmount); - } - - struct BorrowLocalVars { - MathError mathErr; - uint256 accountBorrows; - uint256 accountBorrowsNew; - uint256 totalBorrowsNew; - } - - /** - * @notice Users borrow assets from the protocol to their own address - * @param borrowAmount The amount of the underlying asset to borrow - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function borrowFresh(address payable borrower, uint256 borrowAmount) - internal - returns (uint256) - { - uint256 allowed = comptroller.borrowAllowed( - address(this), - borrower, - borrowAmount - ); - if (allowed != 0) { - return - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.BORROW_COMPTROLLER_REJECTION, - allowed - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.BORROW_FRESHNESS_CHECK - ); - } - - if (getCashPrior() < borrowAmount) { - return - fail( - Error.TOKEN_INSUFFICIENT_CASH, - FailureInfo.BORROW_CASH_NOT_AVAILABLE - ); - } - - BorrowLocalVars memory vars; - - (vars.mathErr, vars.accountBorrows) = borrowBalanceStoredInternal( - borrower - ); - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED, - uint256(vars.mathErr) - ); - } - - (vars.mathErr, vars.accountBorrowsNew) = addUInt( - vars.accountBorrows, - borrowAmount - ); - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED, - uint256(vars.mathErr) - ); - } - - (vars.mathErr, vars.totalBorrowsNew) = addUInt( - totalBorrows, - borrowAmount - ); - if (interestRateModel.isTropykusInterestRateModel()) { - require(vars.totalBorrowsNew <= 0.1e18, "CT25"); - } - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED, - uint256(vars.mathErr) - ); - } - - doTransferOut(borrower, borrowAmount); - - accountBorrows[borrower].principal = vars.accountBorrowsNew; - accountBorrows[borrower].interestIndex = borrowIndex; - totalBorrows = vars.totalBorrowsNew; - - emit Borrow( - borrower, - borrowAmount, - vars.accountBorrowsNew, - vars.totalBorrowsNew - ); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Sender repays their own borrow - * @param repayAmount The amount to repay - * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual repayment amount. - */ - function repayBorrowInternal(uint256 repayAmount) - internal - nonReentrant - returns (uint256, uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return ( - fail( - Error(error), - FailureInfo.REPAY_BORROW_ACCRUE_INTEREST_FAILED - ), - 0 - ); - } - return repayBorrowFresh(msg.sender, msg.sender, repayAmount); - } - - struct RepayBorrowLocalVars { - Error err; - MathError mathErr; - uint256 repayAmount; - uint256 borrowerIndex; - uint256 accountBorrows; - uint256 accountBorrowsNew; - uint256 totalBorrowsNew; - uint256 actualRepayAmount; - } - - /** - * @notice Borrows are repaid by another user (possibly the borrower). - * @param payer the account paying off the borrow - * @param borrower the account with the debt being payed off - * @param repayAmount the amount of undelrying tokens being returned - * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual repayment amount. - */ - function repayBorrowFresh( - address payer, - address borrower, - uint256 repayAmount - ) internal returns (uint256, uint256) { - uint256 allowed = comptroller.repayBorrowAllowed( - address(this), - payer, - borrower, - repayAmount - ); - if (allowed != 0) { - return ( - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.REPAY_BORROW_COMPTROLLER_REJECTION, - allowed - ), - 0 - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return ( - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.REPAY_BORROW_FRESHNESS_CHECK - ), - 0 - ); - } - - RepayBorrowLocalVars memory vars; - - vars.borrowerIndex = accountBorrows[borrower].interestIndex; - - (vars.mathErr, vars.accountBorrows) = borrowBalanceStoredInternal( - borrower - ); - if (vars.mathErr != MathError.NO_ERROR) { - return ( - failOpaque( - Error.MATH_ERROR, - FailureInfo - .REPAY_BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED, - uint256(vars.mathErr) - ), - 0 - ); - } - - if (repayAmount == type(uint256).max) { - vars.repayAmount = vars.accountBorrows; - } else { - vars.repayAmount = repayAmount; - } - - vars.actualRepayAmount = doTransferIn(payer, vars.repayAmount); - - (vars.mathErr, vars.accountBorrowsNew) = subUInt( - vars.accountBorrows, - vars.actualRepayAmount - ); - require(vars.mathErr == MathError.NO_ERROR, "CT16"); - - (vars.mathErr, vars.totalBorrowsNew) = subUInt( - totalBorrows, - vars.actualRepayAmount - ); - require(vars.mathErr == MathError.NO_ERROR, "CT17"); - - accountBorrows[borrower].principal = vars.accountBorrowsNew; - accountBorrows[borrower].interestIndex = borrowIndex; - totalBorrows = vars.totalBorrowsNew; - - emit RepayBorrow( - payer, - borrower, - vars.actualRepayAmount, - vars.accountBorrowsNew, - vars.totalBorrowsNew - ); - - return (uint256(Error.NO_ERROR), vars.actualRepayAmount); - } - - /** - * @notice The sender liquidates the borrowers collateral. - * The collateral seized is transferred to the liquidator. - * @param borrower The borrower of this cToken to be liquidated - * @param cTokenCollateral The market in which to seize collateral from the borrower - * @param repayAmount The amount of the underlying borrowed asset to repay - * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual repayment amount. - */ - function liquidateBorrowInternal( - address borrower, - uint256 repayAmount, - CTokenInterface cTokenCollateral - ) internal nonReentrant returns (uint256, uint256) { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return ( - fail( - Error(error), - FailureInfo.LIQUIDATE_ACCRUE_BORROW_INTEREST_FAILED - ), - 0 - ); - } - - error = cTokenCollateral.accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return ( - fail( - Error(error), - FailureInfo.LIQUIDATE_ACCRUE_COLLATERAL_INTEREST_FAILED - ), - 0 - ); - } - - // liquidateBorrowFresh emits borrow-specific logs on errors, so we don't need to - return - liquidateBorrowFresh( - msg.sender, - borrower, - repayAmount, - cTokenCollateral - ); - } - - /** - * @notice The liquidator liquidates the borrowers collateral. - * The collateral seized is transferred to the liquidator. - * @param borrower The borrower of this cToken to be liquidated - * @param liquidator The address repaying the borrow and seizing collateral - * @param cTokenCollateral The market in which to seize collateral from the borrower - * @param repayAmount The amount of the underlying borrowed asset to repay - * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual repayment amount. - */ - function liquidateBorrowFresh( - address liquidator, - address borrower, - uint256 repayAmount, - CTokenInterface cTokenCollateral - ) internal returns (uint256, uint256) { - uint256 allowed = comptroller.liquidateBorrowAllowed( - address(this), - address(cTokenCollateral), - liquidator, - borrower, - repayAmount - ); - if (allowed != 0) { - return ( - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.LIQUIDATE_COMPTROLLER_REJECTION, - allowed - ), - 0 - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return ( - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.LIQUIDATE_FRESHNESS_CHECK - ), - 0 - ); - } - - if (cTokenCollateral.accrualBlockNumber() != getBlockNumber()) { - return ( - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.LIQUIDATE_COLLATERAL_FRESHNESS_CHECK - ), - 0 - ); - } - - if (borrower == liquidator) { - return ( - fail( - Error.INVALID_ACCOUNT_PAIR, - FailureInfo.LIQUIDATE_LIQUIDATOR_IS_BORROWER - ), - 0 - ); - } - - if (repayAmount == 0) { - return ( - fail( - Error.INVALID_CLOSE_AMOUNT_REQUESTED, - FailureInfo.LIQUIDATE_CLOSE_AMOUNT_IS_ZERO - ), - 0 - ); - } - - if (repayAmount == type(uint256).max) { - return ( - fail( - Error.INVALID_CLOSE_AMOUNT_REQUESTED, - FailureInfo.LIQUIDATE_CLOSE_AMOUNT_IS_UINT_MAX - ), - 0 - ); - } - - ( - uint256 repayBorrowError, - uint256 actualRepayAmount - ) = repayBorrowFresh(liquidator, borrower, repayAmount); - if (repayBorrowError != uint256(Error.NO_ERROR)) { - return ( - fail( - Error(repayBorrowError), - FailureInfo.LIQUIDATE_REPAY_BORROW_FRESH_FAILED - ), - 0 - ); - } - - (uint256 amountSeizeError, uint256 seizeTokens) = comptroller - .liquidateCalculateSeizeTokens( - address(this), - address(cTokenCollateral), - actualRepayAmount - ); - require(amountSeizeError == uint256(Error.NO_ERROR), "CT18"); - - require(cTokenCollateral.balanceOf(borrower) >= seizeTokens, "CT19"); - - uint256 seizeError; - if (address(cTokenCollateral) == address(this)) { - seizeError = seizeInternal( - address(this), - liquidator, - borrower, - seizeTokens - ); - } else { - seizeError = cTokenCollateral.seize( - liquidator, - borrower, - seizeTokens - ); - } - - require(seizeError == uint256(Error.NO_ERROR), "CT20"); - - emit LiquidateBorrow( - liquidator, - borrower, - actualRepayAmount, - address(cTokenCollateral), - seizeTokens - ); - - return (uint256(Error.NO_ERROR), actualRepayAmount); - } - - /** - * @notice Transfers collateral tokens (this market) to the liquidator. - * @dev Will fail unless called by another cToken during the process of liquidation. - * Its absolutely critical to use msg.sender as the borrowed cToken and not a parameter. - * @param liquidator The account receiving seized collateral - * @param borrower The account having collateral seized - * @param seizeTokens The number of cTokens to seize - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function seize( - address liquidator, - address borrower, - uint256 seizeTokens - ) external override nonReentrant returns (uint256) { - return seizeInternal(msg.sender, liquidator, borrower, seizeTokens); - } - - struct SeizeVars { - uint256 seizeAmount; - uint256 exchangeRate; - uint256 borrowerTokensNew; - uint256 borrowerAmountNew; - uint256 liquidatorTokensNew; - uint256 liquidatorAmountNew; - uint256 totalCash; - uint256 supplyRate; - } - - /** - * @notice Transfers collateral tokens (this market) to the liquidator. - * @dev Called only during an in-kind liquidation, or by liquidateBorrow during the liquidation of another CToken. - * Its absolutely critical to use msg.sender as the seizer cToken and not a parameter. - * @param seizerToken The contract seizing the collateral (i.e. borrowed cToken) - * @param liquidator The account receiving seized collateral - * @param borrower The account having collateral seized - * @param seizeTokens The number of cTokens to seize - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function seizeInternal( - address seizerToken, - address liquidator, - address borrower, - uint256 seizeTokens - ) internal returns (uint256) { - uint256 allowed = comptroller.seizeAllowed( - address(this), - seizerToken, - liquidator, - borrower, - seizeTokens - ); - if (allowed != 0) { - return - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.LIQUIDATE_SEIZE_COMPTROLLER_REJECTION, - allowed - ); - } - - if (borrower == liquidator) { - return - fail( - Error.INVALID_ACCOUNT_PAIR, - FailureInfo.LIQUIDATE_SEIZE_LIQUIDATOR_IS_BORROWER - ); - } - - SeizeVars memory seizeVars; - - MathError mathErr; - - (mathErr, seizeVars.borrowerTokensNew) = subUInt( - accountTokens[borrower].tokens, - seizeTokens - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.LIQUIDATE_SEIZE_BALANCE_DECREMENT_FAILED, - uint256(mathErr) - ); - } - - seizeVars.totalCash = getCashPrior(); - seizeVars.supplyRate = interestRateModel.getSupplyRate( - seizeVars.totalCash, - totalBorrows, - totalReserves, - reserveFactorMantissa - ); - - (, seizeVars.exchangeRate) = interestRateModel.getExchangeRate( - seizeVars.totalCash, - totalBorrows, - totalReserves, - totalSupply - ); - - if (interestRateModel.isTropykusInterestRateModel()) { - (, seizeVars.exchangeRate) = tropykusExchangeRateStoredInternal( - borrower - ); - } - - (, seizeVars.seizeAmount) = mulUInt( - seizeTokens, - seizeVars.exchangeRate - ); - (, seizeVars.seizeAmount) = divUInt(seizeVars.seizeAmount, 1e18); - - (, seizeVars.borrowerAmountNew) = subUInt( - accountTokens[borrower].underlyingAmount, - seizeVars.seizeAmount - ); - - (mathErr, seizeVars.liquidatorTokensNew) = addUInt( - accountTokens[liquidator].tokens, - seizeTokens - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.LIQUIDATE_SEIZE_BALANCE_INCREMENT_FAILED, - uint256(mathErr) - ); - } - - (, seizeVars.liquidatorAmountNew) = addUInt( - accountTokens[liquidator].underlyingAmount, - seizeVars.seizeAmount - ); - - accountTokens[borrower].tokens = seizeVars.borrowerTokensNew; - accountTokens[borrower].underlyingAmount = seizeVars.borrowerAmountNew; - accountTokens[borrower].suppliedAt = getBlockNumber(); - accountTokens[borrower].promisedSupplyRate = seizeVars.supplyRate; - - accountTokens[liquidator].tokens = seizeVars.liquidatorTokensNew; - accountTokens[liquidator].underlyingAmount = seizeVars - .liquidatorAmountNew; - accountTokens[liquidator].suppliedAt = getBlockNumber(); - accountTokens[liquidator].promisedSupplyRate = seizeVars.supplyRate; - - emit Transfer(borrower, liquidator, seizeTokens); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Begins transfer of admin rights. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer. - * @dev Admin function to begin change of admin. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer. - * @param newPendingAdmin New pending admin. - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setPendingAdmin(address payable newPendingAdmin) - external - override - returns (uint256) - { - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_PENDING_ADMIN_OWNER_CHECK - ); - } - - address oldPendingAdmin = pendingAdmin; - - pendingAdmin = newPendingAdmin; - - emit NewPendingAdmin(oldPendingAdmin, newPendingAdmin); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Accepts transfer of admin rights. msg.sender must be pendingAdmin - * @dev Admin function for pending admin to accept role and update admin - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _acceptAdmin() external override returns (uint256) { - if (msg.sender != pendingAdmin || msg.sender == address(0)) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.ACCEPT_ADMIN_PENDING_ADMIN_CHECK - ); - } - - address oldAdmin = admin; - address oldPendingAdmin = pendingAdmin; - - admin = pendingAdmin; - - pendingAdmin = payable(address(0)); - - emit NewAdmin(oldAdmin, admin); - emit NewPendingAdmin(oldPendingAdmin, pendingAdmin); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Sets a new comptroller for the market - * @dev Admin function to set a new comptroller - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setComptroller(ComptrollerInterface newComptroller) - public - override - returns (uint256) - { - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_COMPTROLLER_OWNER_CHECK - ); - } - - ComptrollerInterface oldComptroller = comptroller; - require(newComptroller.isComptroller(), "CT21"); - - comptroller = newComptroller; - - emit NewComptroller(oldComptroller, newComptroller); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice accrues interest and sets a new reserve factor for the protocol using _setReserveFactorFresh - * @dev Admin function to accrue interest and set a new reserve factor - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setReserveFactor(uint256 newReserveFactorMantissa) - external - override - nonReentrant - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return - fail( - Error(error), - FailureInfo.SET_RESERVE_FACTOR_ACCRUE_INTEREST_FAILED - ); - } - return _setReserveFactorFresh(newReserveFactorMantissa); - } - - /** - * @notice Sets a new reserve factor for the protocol (*requires fresh interest accrual) - * @dev Admin function to set a new reserve factor - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setReserveFactorFresh(uint256 newReserveFactorMantissa) - internal - returns (uint256) - { - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_RESERVE_FACTOR_ADMIN_CHECK - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.SET_RESERVE_FACTOR_FRESH_CHECK - ); - } - - if (newReserveFactorMantissa > reserveFactorMaxMantissa) { - return - fail( - Error.BAD_INPUT, - FailureInfo.SET_RESERVE_FACTOR_BOUNDS_CHECK - ); - } - - uint256 oldReserveFactorMantissa = reserveFactorMantissa; - reserveFactorMantissa = newReserveFactorMantissa; - - emit NewReserveFactor( - oldReserveFactorMantissa, - newReserveFactorMantissa - ); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Accrues interest and reduces reserves by transferring from msg.sender - * @param addAmount Amount of addition to reserves - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _addReservesInternal(uint256 addAmount) - internal - nonReentrant - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return - fail( - Error(error), - FailureInfo.ADD_RESERVES_ACCRUE_INTEREST_FAILED - ); - } - - uint256 totalReservesNew; - uint256 actualAddAmount; - - if (accrualBlockNumber != getBlockNumber()) { - return ( - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.ADD_RESERVES_FRESH_CHECK - ) - ); - } - - actualAddAmount = doTransferIn(msg.sender, addAmount); - - totalReservesNew = totalReserves + actualAddAmount; - - require(totalReservesNew >= totalReserves, "CT22"); - - totalReserves = totalReservesNew; - - emit ReservesAdded(msg.sender, actualAddAmount, totalReservesNew); - - return (uint256(Error.NO_ERROR)); - } - - function _addSubsidyInternal(uint256 addAmount) - internal - nonReentrant - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - // accrueInterest emits logs on errors, but on top of that we want to log the fact that an attempted reduce reserves failed. - return fail(Error(error), FailureInfo.ADD_SUBSIDY_FUND_FAILED); - } - - uint256 subsidyFundNew; - uint256 actualAddAmount; - - if (accrualBlockNumber != getBlockNumber()) { - return ( - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.ADD_SUBSIDY_FUND_FRESH_CHECK - ) - ); - } - - actualAddAmount = doTransferIn(msg.sender, addAmount); - - subsidyFundNew = subsidyFund + actualAddAmount; - - require(subsidyFundNew >= subsidyFund, "CT22"); - - subsidyFund = subsidyFundNew; - - emit SubsidyAdded(msg.sender, actualAddAmount, subsidyFundNew); - - /* Return (NO_ERROR, actualAddAmount) */ - return (uint256(Error.NO_ERROR)); - } - - /** - * @notice Accrues interest and reduces reserves by transferring to admin - * @param reduceAmount Amount of reduction to reserves - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _reduceReserves(uint256 reduceAmount) - external - override - nonReentrant - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return - fail( - Error(error), - FailureInfo.REDUCE_RESERVES_ACCRUE_INTEREST_FAILED - ); - } - return _reduceReservesFresh(reduceAmount); - } - - /** - * @notice Reduces reserves by transferring to admin - * @dev Requires fresh interest accrual - * @param reduceAmount Amount of reduction to reserves - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _reduceReservesFresh(uint256 reduceAmount) - internal - returns (uint256) - { - uint256 totalReservesNew; - - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.REDUCE_RESERVES_ADMIN_CHECK - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.REDUCE_RESERVES_FRESH_CHECK - ); - } - - if (getCashPrior() < reduceAmount) { - return - fail( - Error.TOKEN_INSUFFICIENT_CASH, - FailureInfo.REDUCE_RESERVES_CASH_NOT_AVAILABLE - ); - } - - if (reduceAmount > totalReserves) { - return - fail(Error.BAD_INPUT, FailureInfo.REDUCE_RESERVES_VALIDATION); - } - - totalReservesNew = totalReserves - reduceAmount; - require(totalReservesNew <= totalReserves, "CT23"); - - totalReserves = totalReservesNew; - - doTransferOut(admin, reduceAmount); - - emit ReservesReduced(admin, reduceAmount, totalReservesNew); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice accrues interest and updates the interest rate model using _setInterestRateModelFresh - * @dev Admin function to accrue interest and update the interest rate model - * @param newInterestRateModel the new interest rate model to use - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setInterestRateModel(InterestRateModel newInterestRateModel) - public - override - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return - fail( - Error(error), - FailureInfo.SET_INTEREST_RATE_MODEL_ACCRUE_INTEREST_FAILED - ); - } - return _setInterestRateModelFresh(newInterestRateModel); - } - - /** - * @notice updates the interest rate model (*requires fresh interest accrual) - * @dev Admin function to update the interest rate model - * @param newInterestRateModel the new interest rate model to use - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setInterestRateModelFresh(InterestRateModel newInterestRateModel) - internal - returns (uint256) - { - InterestRateModel oldInterestRateModel; - - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_INTEREST_RATE_MODEL_OWNER_CHECK - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.SET_INTEREST_RATE_MODEL_FRESH_CHECK - ); - } - - oldInterestRateModel = interestRateModel; - - require(newInterestRateModel.isInterestRateModel(), "CT21"); - - interestRateModel = newInterestRateModel; - - emit NewMarketInterestRateModel( - oldInterestRateModel, - newInterestRateModel - ); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Gets balance of this contract in terms of the underlying - * @dev This excludes the value of the current message, if any - * @return The quantity of underlying owned by this contract - */ - function getCashPrior() internal view virtual returns (uint256); - - /** - * @dev Performs a transfer in, reverting upon failure. Returns the amount actually transferred to the protocol, in case of a fee. - * This may revert due to insufficient balance or insufficient allowance. - */ - function doTransferIn(address from, uint256 amount) - internal - virtual - returns (uint256); - - /** - * @dev Performs a transfer out, ideally returning an explanatory error code upon failure tather than reverting. - * If caller has not called checked protocol's balance, may revert due to insufficient cash held in the contract. - * If caller has checked protocol's balance, and verified it is >= amount, this should not revert in normal conditions. - */ - function doTransferOut(address payable to, uint256 amount) internal virtual; - - /** - * @dev Prevents a contract from calling itself, directly or indirectly. - */ - modifier nonReentrant() { - require(_notEntered, "re-entered"); - _notEntered = false; - _; - _notEntered = true; - } -} - - -// Dependency file: contracts/CErc20.sol - -// pragma solidity 0.8.6; - -// import "contracts/CToken.sol"; -// import "contracts/CTokenInterfaces.sol"; - -/** - * @title tropykus CErc20 Contract - * @notice CTokens which wrap an EIP-20 underlying - * @author tropykus - */ -contract CErc20 is CToken, CErc20Interface { - /** - * @notice Initialize the new money market - * @param underlying_ The address of the underlying asset - * @param comptroller_ The address of the Comptroller - * @param interestRateModel_ The address of the interest rate model - * @param initialExchangeRateMantissa_ The initial exchange rate, scaled by 1e18 - * @param name_ ERC-20 name of this token - * @param symbol_ ERC-20 symbol of this token - * @param decimals_ ERC-20 decimal precision of this token - */ - function initialize( - address underlying_, - ComptrollerInterface comptroller_, - InterestRateModel interestRateModel_, - uint256 initialExchangeRateMantissa_, - string memory name_, - string memory symbol_, - uint8 decimals_ - ) public { - // CToken initialize does the bulk of the work - super.initialize( - comptroller_, - interestRateModel_, - initialExchangeRateMantissa_, - name_, - symbol_, - decimals_ - ); - - // Set underlying and sanity check it - underlying = underlying_; - EIP20Interface(underlying).totalSupply(); - } - - /*** User Interface ***/ - - /** - * @notice Sender supplies assets into the market and receives cTokens in exchange - * @dev Accrues interest whether or not the operation succeeds, unless reverted - * @param mintAmount The amount of the underlying asset to supply - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function mint(uint256 mintAmount) external override returns (uint256) { - (uint256 err, ) = mintInternal(mintAmount); - return err; - } - - /** - * @notice Sender redeems cTokens in exchange for a specified amount of underlying asset - * @dev Accrues interest whether or not the operation succeeds, unless reverted - * @param redeemAmount The amount of underlying to redeem - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function redeem(uint256 redeemAmount) - external - override - returns (uint256) - { - return redeemUnderlyingInternal(redeemAmount); - } - - /** - * @notice Sender borrows assets from the protocol to their own address - * @param borrowAmount The amount of the underlying asset to borrow - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function borrow(uint256 borrowAmount) external override returns (uint256) { - return borrowInternal(borrowAmount); - } - - /** - * @notice Sender repays their own borrow - * @param repayAmount The amount to repay - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function repayBorrow(uint256 repayAmount) - external - override - returns (uint256) - { - (uint256 err, ) = repayBorrowInternal(repayAmount); - return err; - } - - /** - * @notice The sender liquidates the borrowers collateral. - * The collateral seized is transferred to the liquidator. - * @param borrower The borrower of this cToken to be liquidated - * @param repayAmount The amount of the underlying borrowed asset to repay - * @param cTokenCollateral The market in which to seize collateral from the borrower - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function liquidateBorrow( - address borrower, - uint256 repayAmount, - CTokenInterface cTokenCollateral - ) external override returns (uint256) { - (uint256 err, ) = liquidateBorrowInternal( - borrower, - repayAmount, - cTokenCollateral - ); - return err; - } - - /** - * @notice A public function to sweep accidental ERC-20 transfers to this contract. Tokens are sent to admin (timelock) - * @param token The address of the ERC-20 token to sweep - */ - function sweepToken(EIP20NonStandardInterface token) external override { - require(address(token) != underlying, "EC01"); - uint256 balance = token.balanceOf(address(this)); - token.transfer(admin, balance); - } - - /** - * @notice The sender adds to reserves. - * @param addAmount The amount fo underlying token to add as reserves - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _addReserves(uint256 addAmount) - external - override - returns (uint256) - { - return _addReservesInternal(addAmount); - } - - /*** Safe Token ***/ - - /** - * @notice Gets balance of this contract in terms of the underlying - * @dev This excludes the value of the current message, if any - * @return The quantity of underlying tokens owned by this contract - */ - function getCashPrior() internal view override returns (uint256) { - EIP20Interface token = EIP20Interface(underlying); - return token.balanceOf(address(this)); - } - - /** - * @dev Similar to EIP20 transfer, except it handles a False result from `transferFrom` and reverts in that case. - * This will revert due to insufficient balance or insufficient allowance. - * This function returns the actual amount received, - * which may be less than `amount` if there is a fee attached to the transfer. - * - * Note: This wrapper safely handles non-standard ERC-20 tokens that do not return a value. - * See here: https://medium.com/coinmonks/missing-return-value-bug-at-least-130-tokens-affected-d67bf08521ca - */ - function doTransferIn(address from, uint256 amount) - internal - override - returns (uint256) - { - EIP20NonStandardInterface token = EIP20NonStandardInterface(underlying); - uint256 balanceBefore = EIP20Interface(underlying).balanceOf( - address(this) - ); - token.transferFrom(from, address(this), amount); - - bool success; - assembly { - switch returndatasize() - case 0 { - // This is a non-standard ERC-20 - success := not(0) // set success to true - } - case 32 { - // This is a compliant ERC-20 - returndatacopy(0, 0, 32) - success := mload(0) // Set `success = returndata` of external call - } - default { - // This is an excessively non-compliant ERC-20, revert. - revert(0, 0) - } - } - require(success, "EC02"); - - // Calculate the amount that was *actually* transferred - uint256 balanceAfter = EIP20Interface(underlying).balanceOf( - address(this) - ); - require(balanceAfter >= balanceBefore, "EC03"); - return balanceAfter - balanceBefore; // underflow already checked above, just subtract - } - - /** - * @dev Similar to EIP20 transfer, except it handles a False success from `transfer` and returns an explanatory - * error code rather than reverting. If caller has not called checked protocol's balance, this may revert due to - * insufficient cash held in this contract. If caller has checked protocol's balance prior to this call, and verified - * it is >= amount, this should not revert in normal conditions. - * - * Note: This wrapper safely handles non-standard ERC-20 tokens that do not return a value. - * See here: https://medium.com/coinmonks/missing-return-value-bug-at-least-130-tokens-affected-d67bf08521ca - */ - function doTransferOut(address payable to, uint256 amount) - internal - virtual - override - { - EIP20NonStandardInterface token = EIP20NonStandardInterface(underlying); - token.transfer(to, amount); - - bool success; - assembly { - switch returndatasize() - case 0 { - // This is a non-standard ERC-20 - success := not(0) // set success to true - } - case 32 { - // This is a complaint ERC-20 - returndatacopy(0, 0, 32) - success := mload(0) // Set `success = returndata` of external call - } - default { - // This is an excessively non-compliant ERC-20, revert. - revert(0, 0) - } - } - require(success, "CE01"); - } -} - - -// Root file: contracts/mocks/PriceOracleAdapterCompound.sol - -pragma solidity 0.8.6; - -// import "contracts/PriceOracleAdapter.sol"; -// import "contracts/CErc20.sol"; - -interface V1PriceOracleInterface { - function assetPrices(address asset) external view returns (uint256); -} - -contract PriceOracleAdapterCompound is PriceOracleAdapter { - /// @notice Address of the guardian - address public guardian; - /// @notice Event oracle key updateed - event PriceOracleKeyUpdated( - address oldAddress, - address newAddress, - address cTokenAddress - ); - /// @notice The price oracle, which will continue to serve prices of compound - V1PriceOracleInterface public priceProviderInterface; - - // mapping(addressCtoken => addressKeyOracle); - mapping(address => address) public oracleKeyAddress; - - /// @notice Frozen SAI price (or 0 if not set yet) - uint256 public saiPrice; - - constructor(address guardian_) { - guardian = guardian_; - } - - /** - * @notice Get the price - * @param cTokenAddress address of cToken - * @return The price - */ - function assetPrices(address cTokenAddress) - public - view - override - returns (uint256) - { - //get keyAddress or undlerlyingAddress - address asset = (oracleKeyAddress[cTokenAddress] != address(0)) - ? address(oracleKeyAddress[cTokenAddress]) - : address(CErc20(cTokenAddress).underlying()); - return priceProviderInterface.assetPrices(asset); - } - - /** - * @notice Set the address of price provider - * @param priceProviderAddress address of price provider - */ - function setPriceProvider(address priceProviderAddress) public { - require( - msg.sender == guardian, - "PriceOracleAdapterCompound: only guardian may set the address" - ); - require( - priceProviderAddress != address(0), - "PriceOracleAdapterCompound: address could not be 0" - ); - //set old address - address oldBtcPriceProviderAddress = address(priceProviderInterface); - //update interface address - priceProviderInterface = V1PriceOracleInterface(priceProviderAddress); - //emit event - emit PriceOracleAdapterUpdated( - oldBtcPriceProviderAddress, - address(priceProviderInterface) - ); - } - - /** - * @notice Set the key oracle address of cToken address - * @param cTokenAddress address of key ctoken - * @param keyOracle address of key oracle - */ - function setKeyOracle(address cTokenAddress, address keyOracle) public { - require( - msg.sender == guardian, - "PriceOracleAdapterCompound: only guardian may set the address" - ); - require( - cTokenAddress != address(0), - "PriceOracleAdapterCompound: cTokenAddress could not be 0" - ); - require( - keyOracle != address(0), - "PriceOracleAdapterCompound: keyOracle could not be 0" - ); - //set old address - address oldBtcPriceProviderAddress = address( - oracleKeyAddress[cTokenAddress] - ); - //update key address - oracleKeyAddress[cTokenAddress] = keyOracle; - //emit event - emit PriceOracleKeyUpdated( - oldBtcPriceProviderAddress, - address(oracleKeyAddress[cTokenAddress]), - cTokenAddress - ); - } - - /** - * @notice Set the price of SAI, permanently - * @param price The price for SAI - */ - function setSaiPrice(uint256 price) public { - require(msg.sender == guardian, "only guardian may set the SAI price"); - require(saiPrice == 0, "SAI price may only be set once"); - require(price < 0.1e18, "SAI price must be < 0.1 ETH"); - saiPrice = price; - } -} diff --git a/flatten/PriceOracleAdapterMoc.sol b/flatten/PriceOracleAdapterMoc.sol deleted file mode 100644 index 9e2f783..0000000 --- a/flatten/PriceOracleAdapterMoc.sol +++ /dev/null @@ -1,111 +0,0 @@ -// Dependency file: contracts/PriceOracleAdapter.sol - -// SPDX-License-Identifier: UNLICENSED -// pragma solidity 0.8.6; - -abstract contract PriceOracleAdapter { - /// @notice Event adapter interface updated - event PriceOracleAdapterUpdated(address oldAddress, address newAddress); - - /** - * @notice Get the price - * @return The underlying asset price mantissa (scaled by 1e18). - * Zero means the price is unavailable. - */ - function assetPrices(address cTokenAddress) - external - view - virtual - returns (uint256); -} - - -// Root file: contracts/PriceOracleAdapterMoc.sol - -pragma solidity 0.8.6; - -// import "contracts/PriceOracleAdapter.sol"; - -interface PriceProviderMoC { - function peek() external view returns (bytes32, bool); -} - -contract PriceOracleAdapterMoc is PriceOracleAdapter { - /// @notice Address of the guardian - address public guardian; - /// @notice The MoC price oracle, which will continue to serve prices - PriceProviderMoC public priceProviderMoC; - - /// @notice Guardian updated - event NewGuardian(address oldGuardian, address newGuardian); - - /** - * @notice Construct a PriceOracleAdapter for a MoC oracle - * @param guardian_ address of guardian that is allowed to manage this contract - * @param priceProvider address of asset's MoC price provider - */ - constructor(address guardian_, address priceProvider) { - require( - guardian_ != address(0), - "PriceOracleAdapterMoc: guardian could not be 0" - ); - require( - priceProvider != address(0), - "PriceOracleAdapterMoc: priceProvider could not be 0" - ); - guardian = guardian_; - priceProviderMoC = PriceProviderMoC(priceProvider); - } - - /** - * @notice Get the price from MoC and divide it by the rBTC price - * @return The price - */ - function assetPrices(address) public view override returns (uint256) { - (bytes32 price, bool has) = priceProviderMoC.peek(); - require(has, "PriceOracleAdapterMoc: Oracle have no Price"); - return uint256(price); - } - - /** - * @notice Set the address of price provider - * @param priceProviderAddress address of price provider - */ - function setPriceProvider(address priceProviderAddress) public { - require( - msg.sender == guardian, - "PriceOracleAdapterMoc: only guardian may set the address" - ); - require( - priceProviderAddress != address(0), - "PriceOracleAdapterMoc: address could not be 0" - ); - //set old address - address oldPriceProviderAddress = address(priceProviderMoC); - //update interface address - priceProviderMoC = PriceProviderMoC(priceProviderAddress); - //emit event - emit PriceOracleAdapterUpdated( - oldPriceProviderAddress, - priceProviderAddress - ); - } - - /** - * @notice Set the address of the guardian - * @param newGuardian address of the guardian - */ - function setGuardian(address newGuardian) public { - require(msg.sender == guardian, "PriceOracleAdapterMoc: only guardian"); - require( - guardian != address(0), - "PriceOracleAdapterMoc: guardin address can not be 0" - ); - //set old address - address oldGuardian = guardian; - //update - guardian = newGuardian; - //emit event - emit NewGuardian(oldGuardian, newGuardian); - } -} diff --git a/flatten/PriceOracleProxy.sol b/flatten/PriceOracleProxy.sol deleted file mode 100644 index 2ef4539..0000000 --- a/flatten/PriceOracleProxy.sol +++ /dev/null @@ -1,4115 +0,0 @@ -// Dependency file: contracts/ComptrollerInterface.sol - -// SPDX-License-Identifier: UNLICENSED -// pragma solidity 0.8.6; - -abstract contract ComptrollerInterface { - /// @notice Indicator that this is a Comptroller contract (for inspection) - bool public constant isComptroller = true; - - /*** Assets You Are In ***/ - - function enterMarkets(address[] calldata cTokens) - external - virtual - returns (uint256[] memory); - - function exitMarket(address cToken) external virtual returns (uint256); - - /*** Policy Hooks ***/ - - function mintAllowed( - address cToken, - address minter, - uint256 mintAmount - ) external virtual returns (uint256); - - function mintVerify( - address cToken, - address minter, - uint256 mintAmount, - uint256 mintTokens - ) external virtual; - - function redeemAllowed( - address cToken, - address redeemer, - uint256 redeemTokens - ) external virtual returns (uint256); - - function redeemVerify( - address cToken, - address redeemer, - uint256 redeemAmount, - uint256 redeemTokens - ) external virtual; - - function borrowAllowed( - address cToken, - address borrower, - uint256 borrowAmount - ) external virtual returns (uint256); - - function borrowVerify( - address cToken, - address borrower, - uint256 borrowAmount - ) external virtual; - - function repayBorrowAllowed( - address cToken, - address payer, - address borrower, - uint256 repayAmount - ) external virtual returns (uint256); - - function repayBorrowVerify( - address cToken, - address payer, - address borrower, - uint256 repayAmount, - uint256 borrowerIndex - ) external virtual; - - function liquidateBorrowAllowed( - address cTokenBorrowed, - address cTokenCollateral, - address liquidator, - address borrower, - uint256 repayAmount - ) external virtual returns (uint256); - - function liquidateBorrowVerify( - address cTokenBorrowed, - address cTokenCollateral, - address liquidator, - address borrower, - uint256 repayAmount, - uint256 seizeTokens - ) external virtual; - - function seizeAllowed( - address cTokenCollateral, - address cTokenBorrowed, - address liquidator, - address borrower, - uint256 seizeTokens - ) external virtual returns (uint256); - - function seizeVerify( - address cTokenCollateral, - address cTokenBorrowed, - address liquidator, - address borrower, - uint256 seizeTokens - ) external virtual; - - function transferAllowed( - address cToken, - address src, - address dst, - uint256 transferTokens - ) external virtual returns (uint256); - - function transferVerify( - address cToken, - address src, - address dst, - uint256 transferTokens - ) external virtual; - - /*** Liquidity/Liquidation Calculations ***/ - - function liquidateCalculateSeizeTokens( - address cTokenBorrowed, - address cTokenCollateral, - uint256 repayAmount - ) external view virtual returns (uint256, uint256); -} - - -// Dependency file: contracts/CarefulMath.sol - -// pragma solidity 0.8.6; - -/** - * @title Careful Math - * @author tropykus - * @notice Derived from OpenZeppelin's SafeMath library - * https://github.com/OpenZeppelin/openzeppelin-solidity/blob/master/contracts/math/SafeMath.sol - */ -contract CarefulMath { - - /** - * @dev Possible error codes that we can return - */ - enum MathError { - NO_ERROR, - DIVISION_BY_ZERO, - INTEGER_OVERFLOW, - INTEGER_UNDERFLOW - } - - /** - * @dev Multiplies two numbers, returns an error on overflow. - */ - function mulUInt(uint a, uint b) internal pure returns (MathError, uint) { - if (a == 0) { - return (MathError.NO_ERROR, 0); - } - - uint c = a * b; - - if (c / a != b) { - return (MathError.INTEGER_OVERFLOW, 0); - } else { - return (MathError.NO_ERROR, c); - } - } - - /** - * @dev Integer division of two numbers, truncating the quotient. - */ - function divUInt(uint a, uint b) internal pure returns (MathError, uint) { - if (b == 0) { - return (MathError.DIVISION_BY_ZERO, 0); - } - - return (MathError.NO_ERROR, a / b); - } - - /** - * @dev Subtracts two numbers, returns an error on overflow (i.e. if subtrahend is greater than minuend). - */ - function subUInt(uint a, uint b) internal pure returns (MathError, uint) { - if (b <= a) { - return (MathError.NO_ERROR, a - b); - } else { - return (MathError.INTEGER_UNDERFLOW, 0); - } - } - - /** - * @dev Adds two numbers, returns an error on overflow. - */ - function addUInt(uint a, uint b) internal pure returns (MathError, uint) { - uint c = a + b; - - if (c >= a) { - return (MathError.NO_ERROR, c); - } else { - return (MathError.INTEGER_OVERFLOW, 0); - } - } - - /** - * @dev add a and b and then subtract c - */ - function addThenSubUInt(uint a, uint b, uint c) internal pure returns (MathError, uint) { - (MathError err0, uint sum) = addUInt(a, b); - - if (err0 != MathError.NO_ERROR) { - return (err0, 0); - } - - return subUInt(sum, c); - } -} - - -// Dependency file: contracts/ExponentialNoError.sol - -// pragma solidity 0.8.6; - -/** - * @title Exponential module for storing fixed-precision decimals - * @author tropykus - * @notice Exp is a struct which stores decimals with a fixed precision of 18 decimal places. - * Thus, if we wanted to store the 5.1, mantissa would store 5.1e18. That is: - * `Exp({mantissa: 5100000000000000000})`. - */ -contract ExponentialNoError { - uint constant expScale = 1e18; - uint constant doubleScale = 1e36; - uint constant halfExpScale = expScale/2; - uint constant mantissaOne = expScale; - - struct Exp { - uint mantissa; - } - - struct Double { - uint mantissa; - } - - /** - * @dev Truncates the given exp to a whole number value. - * For example, truncate(Exp{mantissa: 15 * expScale}) = 15 - */ - function truncate(Exp memory exp) pure internal returns (uint) { - // Note: We are not using careful math here as we're performing a division that cannot fail - return exp.mantissa / expScale; - } - - /** - * @dev Multiply an Exp by a scalar, then truncate to return an unsigned integer. - */ - function mul_ScalarTruncate(Exp memory a, uint scalar) pure internal returns (uint) { - Exp memory product = mul_(a, scalar); - return truncate(product); - } - - /** - * @dev Multiply an Exp by a scalar, truncate, then add an to an unsigned integer, returning an unsigned integer. - */ - function mul_ScalarTruncateAddUInt(Exp memory a, uint scalar, uint addend) pure internal returns (uint) { - Exp memory product = mul_(a, scalar); - return add_(truncate(product), addend); - } - - /** - * @dev Checks if first Exp is less than second Exp. - */ - function lessThanExp(Exp memory left, Exp memory right) pure internal returns (bool) { - return left.mantissa < right.mantissa; - } - - /** - * @dev Checks if left Exp <= right Exp. - */ - function lessThanOrEqualExp(Exp memory left, Exp memory right) pure internal returns (bool) { - return left.mantissa <= right.mantissa; - } - - /** - * @dev Checks if left Exp > right Exp. - */ - function greaterThanExp(Exp memory left, Exp memory right) pure internal returns (bool) { - return left.mantissa > right.mantissa; - } - - /** - * @dev returns true if Exp is exactly zero - */ - function isZeroExp(Exp memory value) pure internal returns (bool) { - return value.mantissa == 0; - } - - function safe224(uint n, string memory errorMessage) pure internal returns (uint224) { - require(n < 2**224, errorMessage); - return uint224(n); - } - - function safe32(uint n, string memory errorMessage) pure internal returns (uint32) { - require(n < 2**32, errorMessage); - return uint32(n); - } - - function add_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { - return Exp({mantissa: add_(a.mantissa, b.mantissa)}); - } - - function add_(Double memory a, Double memory b) pure internal returns (Double memory) { - return Double({mantissa: add_(a.mantissa, b.mantissa)}); - } - - function add_(uint a, uint b) pure internal returns (uint) { - return add_(a, b, "addition overflow"); - } - - function add_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { - uint c = a + b; - require(c >= a, errorMessage); - return c; - } - - function sub_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { - return Exp({mantissa: sub_(a.mantissa, b.mantissa)}); - } - - function sub_(Double memory a, Double memory b) pure internal returns (Double memory) { - return Double({mantissa: sub_(a.mantissa, b.mantissa)}); - } - - function sub_(uint a, uint b) pure internal returns (uint) { - return sub_(a, b, "subtraction underflow"); - } - - function sub_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { - require(b <= a, errorMessage); - return a - b; - } - - function mul_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { - return Exp({mantissa: mul_(a.mantissa, b.mantissa) / expScale}); - } - - function mul_(Exp memory a, uint b) pure internal returns (Exp memory) { - return Exp({mantissa: mul_(a.mantissa, b)}); - } - - function mul_(uint a, Exp memory b) pure internal returns (uint) { - return mul_(a, b.mantissa) / expScale; - } - - function mul_(Double memory a, Double memory b) pure internal returns (Double memory) { - return Double({mantissa: mul_(a.mantissa, b.mantissa) / doubleScale}); - } - - function mul_(Double memory a, uint b) pure internal returns (Double memory) { - return Double({mantissa: mul_(a.mantissa, b)}); - } - - function mul_(uint a, Double memory b) pure internal returns (uint) { - return mul_(a, b.mantissa) / doubleScale; - } - - function mul_(uint a, uint b) pure internal returns (uint) { - return mul_(a, b, "multiplication overflow"); - } - - function mul_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { - if (a == 0 || b == 0) { - return 0; - } - uint c = a * b; - require(c / a == b, errorMessage); - return c; - } - - function div_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { - return Exp({mantissa: div_(mul_(a.mantissa, expScale), b.mantissa)}); - } - - function div_(Exp memory a, uint b) pure internal returns (Exp memory) { - return Exp({mantissa: div_(a.mantissa, b)}); - } - - function div_(uint a, Exp memory b) pure internal returns (uint) { - return div_(mul_(a, expScale), b.mantissa); - } - - function div_(Double memory a, Double memory b) pure internal returns (Double memory) { - return Double({mantissa: div_(mul_(a.mantissa, doubleScale), b.mantissa)}); - } - - function div_(Double memory a, uint b) pure internal returns (Double memory) { - return Double({mantissa: div_(a.mantissa, b)}); - } - - function div_(uint a, Double memory b) pure internal returns (uint) { - return div_(mul_(a, doubleScale), b.mantissa); - } - - function div_(uint a, uint b) pure internal returns (uint) { - return div_(a, b, "divide by zero"); - } - - function div_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { - require(b > 0, errorMessage); - return a / b; - } - - function fraction(uint a, uint b) pure internal returns (Double memory) { - return Double({mantissa: div_(mul_(a, doubleScale), b)}); - } -} - - -// Dependency file: contracts/Exponential.sol - -// pragma solidity 0.8.6; - -// import "contracts/CarefulMath.sol"; -// import "contracts/ExponentialNoError.sol"; - -/** - * @title Exponential module for storing fixed-precision decimals - * @author tropykus - * @dev Legacy contract for compatibility reasons with existing contracts that still use MathError - * @notice Exp is a struct which stores decimals with a fixed precision of 18 decimal places. - * Thus, if we wanted to store the 5.1, mantissa would store 5.1e18. That is: - * `Exp({mantissa: 5100000000000000000})`. - */ -contract Exponential is CarefulMath, ExponentialNoError { - /** - * @dev Creates an exponential from numerator and denominator values. - * Note: Returns an error if (`num` * 10e18) > MAX_INT, - * or if `denom` is zero. - */ - function getExp(uint num, uint denom) internal pure returns (MathError, Exp memory) { - (MathError err0, uint scaledNumerator) = mulUInt(num, expScale); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - - (MathError err1, uint rational) = divUInt(scaledNumerator, denom); - if (err1 != MathError.NO_ERROR) { - return (err1, Exp({mantissa: 0})); - } - - return (MathError.NO_ERROR, Exp({mantissa: rational})); - } - - /** - * @dev Adds two exponentials, returning a new exponential. - */ - function addExp(Exp memory a, Exp memory b) internal pure returns (MathError, Exp memory) { - (MathError error, uint result) = addUInt(a.mantissa, b.mantissa); - - return (error, Exp({mantissa: result})); - } - - /** - * @dev Subtracts two exponentials, returning a new exponential. - */ - function subExp(Exp memory a, Exp memory b) internal pure returns (MathError, Exp memory) { - (MathError error, uint result) = subUInt(a.mantissa, b.mantissa); - - return (error, Exp({mantissa: result})); - } - - /** - * @dev Multiply an Exp by a scalar, returning a new Exp. - */ - function mulScalar(Exp memory a, uint scalar) internal pure returns (MathError, Exp memory) { - (MathError err0, uint scaledMantissa) = mulUInt(a.mantissa, scalar); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - - return (MathError.NO_ERROR, Exp({mantissa: scaledMantissa})); - } - - /** - * @dev Multiply an Exp by a scalar, then truncate to return an unsigned integer. - */ - function mulScalarTruncate(Exp memory a, uint scalar) internal pure returns (MathError, uint) { - (MathError err, Exp memory product) = mulScalar(a, scalar); - if (err != MathError.NO_ERROR) { - return (err, 0); - } - - return (MathError.NO_ERROR, truncate(product)); - } - - /** - * @dev Multiply an Exp by a scalar, truncate, then add an to an unsigned integer, returning an unsigned integer. - */ - function mulScalarTruncateAddUInt(Exp memory a, uint scalar, uint addend) internal pure returns (MathError, uint) { - (MathError err, Exp memory product) = mulScalar(a, scalar); - if (err != MathError.NO_ERROR) { - return (err, 0); - } - - return addUInt(truncate(product), addend); - } - - /** - * @dev Divide an Exp by a scalar, returning a new Exp. - */ - function divScalar(Exp memory a, uint scalar) internal pure returns (MathError, Exp memory) { - (MathError err0, uint descaledMantissa) = divUInt(a.mantissa, scalar); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - - return (MathError.NO_ERROR, Exp({mantissa: descaledMantissa})); - } - - /** - * @dev Divide a scalar by an Exp, returning a new Exp. - */ - function divScalarByExp(uint scalar, Exp memory divisor) internal pure returns (MathError, Exp memory) { - /* - We are doing this as: - getExp(mulUInt(expScale, scalar), divisor.mantissa) - - How it works: - Exp = a / b; - Scalar = s; - `s / (a / b)` = `b * s / a` and since for an Exp `a = mantissa, b = expScale` - */ - (MathError err0, uint numerator) = mulUInt(expScale, scalar); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - return getExp(numerator, divisor.mantissa); - } - - /** - * @dev Divide a scalar by an Exp, then truncate to return an unsigned integer. - */ - function divScalarByExpTruncate(uint scalar, Exp memory divisor) internal pure returns (MathError, uint) { - (MathError err, Exp memory fraction) = divScalarByExp(scalar, divisor); - if (err != MathError.NO_ERROR) { - return (err, 0); - } - - return (MathError.NO_ERROR, truncate(fraction)); - } - - /** - * @dev Multiplies two exponentials, returning a new exponential. - */ - function mulExp(Exp memory a, Exp memory b) internal pure returns (MathError, Exp memory) { - - (MathError err0, uint doubleScaledProduct) = mulUInt(a.mantissa, b.mantissa); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - - // We add half the scale before dividing so that we get rounding instead of truncation. - // See "Listing 6" and text above it at https://accu.org/index.php/journals/1717 - // Without this change, a result like 6.6...e-19 will be truncated to 0 instead of being rounded to 1e-18. - (MathError err1, uint doubleScaledProductWithHalfScale) = addUInt(halfExpScale, doubleScaledProduct); - if (err1 != MathError.NO_ERROR) { - return (err1, Exp({mantissa: 0})); - } - - (MathError err2, uint product) = divUInt(doubleScaledProductWithHalfScale, expScale); - // The only error `div` can return is MathError.DIVISION_BY_ZERO but we control `expScale` and it is not zero. - assert(err2 == MathError.NO_ERROR); - - return (MathError.NO_ERROR, Exp({mantissa: product})); - } - - /** - * @dev Multiplies two exponentials given their mantissas, returning a new exponential. - */ - function mulExp(uint a, uint b) internal pure returns (MathError, Exp memory) { - return mulExp(Exp({mantissa: a}), Exp({mantissa: b})); - } - - /** - * @dev Multiplies three exponentials, returning a new exponential. - */ - function mulExp3(Exp memory a, Exp memory b, Exp memory c) internal pure returns (MathError, Exp memory) { - (MathError err, Exp memory ab) = mulExp(a, b); - if (err != MathError.NO_ERROR) { - return (err, ab); - } - return mulExp(ab, c); - } - - /** - * @dev Divides two exponentials, returning a new exponential. - * (a/scale) / (b/scale) = (a/scale) * (scale/b) = a/b, - * which we can scale as an Exp by calling getExp(a.mantissa, b.mantissa) - */ - function divExp(Exp memory a, Exp memory b) internal pure returns (MathError, Exp memory) { - return getExp(a.mantissa, b.mantissa); - } -} - - -// Dependency file: contracts/SafeMath.sol - -// pragma solidity 0.8.6; - -// From https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/math/Math.sol -// Subject to the MIT license. - -/** - * @dev Wrappers over Solidity's arithmetic operations with added overflow - * checks. - * - * Arithmetic operations in Solidity wrap on overflow. This can easily result - * in bugs, because programmers usually assume that an overflow raises an - * error, which is the standard behavior in high level programming languages. - * `SafeMath` restores this intuition by reverting the transaction when an - * operation overflows. - * - * Using this library instead of the unchecked operations eliminates an entire - * class of bugs, so it's recommended to use it always. - */ -library SafeMath { - /** - * @dev Returns the addition of two unsigned integers, reverting on overflow. - * - * Counterpart to Solidity's `+` operator. - * - * Requirements: - * - Addition cannot overflow. - */ - function add(uint256 a, uint256 b) internal pure returns (uint256) { - uint256 c = a + b; - require(c >= a, "SafeMath: addition overflow"); - - return c; - } - - /** - * @dev Returns the addition of two unsigned integers, reverting with custom message on overflow. - * - * Counterpart to Solidity's `+` operator. - * - * Requirements: - * - Addition cannot overflow. - */ - function add(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - uint256 c = a + b; - require(c >= a, errorMessage); - - return c; - } - - /** - * @dev Returns the subtraction of two unsigned integers, reverting on underflow (when the result is negative). - * - * Counterpart to Solidity's `-` operator. - * - * Requirements: - * - Subtraction cannot underflow. - */ - function sub(uint256 a, uint256 b) internal pure returns (uint256) { - return sub(a, b, "SafeMath: subtraction underflow"); - } - - /** - * @dev Returns the subtraction of two unsigned integers, reverting with custom message on underflow (when the result is negative). - * - * Counterpart to Solidity's `-` operator. - * - * Requirements: - * - Subtraction cannot underflow. - */ - function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - require(b <= a, errorMessage); - uint256 c = a - b; - - return c; - } - - /** - * @dev Returns the multiplication of two unsigned integers, reverting on overflow. - * - * Counterpart to Solidity's `*` operator. - * - * Requirements: - * - Multiplication cannot overflow. - */ - function mul(uint256 a, uint256 b) internal pure returns (uint256) { - // Gas optimization: this is cheaper than requiring 'a' not being zero, but the - // benefit is lost if 'b' is also tested. - // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 - if (a == 0) { - return 0; - } - - uint256 c = a * b; - require(c / a == b, "SafeMath: multiplication overflow"); - - return c; - } - - /** - * @dev Returns the multiplication of two unsigned integers, reverting on overflow. - * - * Counterpart to Solidity's `*` operator. - * - * Requirements: - * - Multiplication cannot overflow. - */ - function mul(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - // Gas optimization: this is cheaper than requiring 'a' not being zero, but the - // benefit is lost if 'b' is also tested. - // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 - if (a == 0) { - return 0; - } - - uint256 c = a * b; - require(c / a == b, errorMessage); - - return c; - } - - /** - * @dev Returns the integer division of two unsigned integers. - * Reverts on division by zero. The result is rounded towards zero. - * - * Counterpart to Solidity's `/` operator. Note: this function uses a - * `revert` opcode (which leaves remaining gas untouched) while Solidity - * uses an invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function div(uint256 a, uint256 b) internal pure returns (uint256) { - return div(a, b, "SafeMath: division by zero"); - } - - /** - * @dev Returns the integer division of two unsigned integers. - * Reverts with custom message on division by zero. The result is rounded towards zero. - * - * Counterpart to Solidity's `/` operator. Note: this function uses a - * `revert` opcode (which leaves remaining gas untouched) while Solidity - * uses an invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - // Solidity only automatically asserts when dividing by 0 - require(b > 0, errorMessage); - uint256 c = a / b; - // assert(a == b * c + a % b); // There is no case in which this doesn't hold - - return c; - } - - /** - * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), - * Reverts when dividing by zero. - * - * Counterpart to Solidity's `%` operator. This function uses a `revert` - * opcode (which leaves remaining gas untouched) while Solidity uses an - * invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function mod(uint256 a, uint256 b) internal pure returns (uint256) { - return mod(a, b, "SafeMath: modulo by zero"); - } - - /** - * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), - * Reverts with custom message when dividing by zero. - * - * Counterpart to Solidity's `%` operator. This function uses a `revert` - * opcode (which leaves remaining gas untouched) while Solidity uses an - * invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - require(b != 0, errorMessage); - return a % b; - } -} - - -// Dependency file: contracts/InterestRateModel.sol - -// pragma solidity 0.8.6; - -// import "contracts/Exponential.sol"; -// import "contracts/SafeMath.sol"; - -/** - * @title tropykus InterestRateModel Interface - * @author tropykus - */ -abstract contract InterestRateModel is Exponential { - using SafeMath for uint256; - - /// @notice Indicator that this is an InterestRateModel contract (for inspection) - bool public constant isInterestRateModel = true; - bool public isTropykusInterestRateModel; - - /** - * @notice The approximate number of blocks per year that is assumed by the interest rate model - */ - uint256 public constant blocksPerYear = 1051200; - - /** - * @notice Calculates the utilization rate of the market: `borrows / (cash + borrows - reserves)` - * @param cash The amount of cash in the market - * @param borrows The amount of borrows in the market - * @param reserves The amount of reserves in the market (currently unused) - * @return The utilization rate as a mantissa between [0, 1e18] - */ - function utilizationRate( - uint256 cash, - uint256 borrows, - uint256 reserves - ) public pure virtual returns (uint256) { - // Utilization rate is 0 when there are no borrows - if (borrows == 0) { - return 0; - } - - return borrows.mul(1e18).div(cash.add(borrows).sub(reserves)); - } - - /** - * @notice Calculates the current borrow interest rate per block - * @param cash The total amount of cash the market has - * @param borrows The total amount of borrows the market has outstanding - * @param reserves The total amnount of reserves the market has - * @return The borrow rate per block (as a percentage, and scaled by 1e18) - */ - function getBorrowRate( - uint256 cash, - uint256 borrows, - uint256 reserves - ) external view virtual returns (uint256); - - /** - * @notice Calculates the current supply interest rate per block - * @param cash The total amount of cash the market has - * @param borrows The total amount of borrows the market has outstanding - * @param reserves The total amnount of reserves the market has - * @param reserveFactorMantissa The current reserve factor the market has - * @return The supply rate per block (as a percentage, and scaled by 1e18) - */ - function getSupplyRate( - uint256 cash, - uint256 borrows, - uint256 reserves, - uint256 reserveFactorMantissa - ) external view virtual returns (uint256); - - function getExchangeRate( - uint256 _totalCash, - uint256 _totalBorrows, - uint256 _totalReserves, - uint256 _totalSupply - ) public pure returns (MathError, uint256) { - /* - * exchangeRate = (totalCash + totalBorrows - totalReserves) / totalSupply - */ - Exp memory exchangeRate; - MathError mathErr; - uint256 cashPlusBorrowsMinusReserves; - (mathErr, cashPlusBorrowsMinusReserves) = addThenSubUInt( - _totalCash, - _totalBorrows, - _totalReserves - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - (mathErr, exchangeRate) = getExp( - cashPlusBorrowsMinusReserves, - _totalSupply - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - - return (MathError.NO_ERROR, exchangeRate.mantissa); - } - - function isAboveOptimal( - uint256 cash, - uint256 borrows, - uint256 reserves - ) public view virtual returns (bool) { - cash; - borrows; - reserves; - return false; - } -} - - -// Dependency file: contracts/EIP20NonStandardInterface.sol - -// pragma solidity 0.8.6; - -/** - * @title EIP20NonStandardInterface - * @dev Version of ERC20 with no return values for `transfer` and `transferFrom` - * See https://medium.com/coinmonks/missing-return-value-bug-at-least-130-tokens-affected-d67bf08521ca - */ -interface EIP20NonStandardInterface { - /** - * @notice Get the total number of tokens in circulation - * @return The supply of tokens - */ - function totalSupply() external view returns (uint256); - - /** - * @notice Gets the balance of the specified address - * @param owner The address from which the balance will be retrieved - * @return balance The balance - */ - function balanceOf(address owner) external view returns (uint256 balance); - - /// - /// !!!!!!!!!!!!!! - /// !!! NOTICE !!! `transfer` does not return a value, in violation of the ERC-20 specification - /// !!!!!!!!!!!!!! - /// - - /** - * @notice Transfer `amount` tokens from `msg.sender` to `dst` - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - */ - function transfer(address dst, uint256 amount) external; - - /// - /// !!!!!!!!!!!!!! - /// !!! NOTICE !!! `transferFrom` does not return a value, in violation of the ERC-20 specification - /// !!!!!!!!!!!!!! - /// - - /** - * @notice Transfer `amount` tokens from `src` to `dst` - * @param src The address of the source account - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - */ - function transferFrom( - address src, - address dst, - uint256 amount - ) external; - - /** - * @notice Approve `spender` to transfer up to `amount` from `src` - * @dev This will overwrite the approval amount for `spender` - * and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve) - * @param spender The address of the account which may transfer tokens - * @param amount The number of tokens that are approved - * @return success Whether or not the approval succeeded - */ - function approve(address spender, uint256 amount) - external - returns (bool success); - - /** - * @notice Get the current allowance from `owner` for `spender` - * @param owner The address of the account which owns the tokens to be spent - * @param spender The address of the account which may transfer tokens - * @return remaining The number of tokens allowed to be spent - */ - function allowance(address owner, address spender) - external - view - returns (uint256 remaining); - - event Transfer(address indexed from, address indexed to, uint256 amount); - event Approval( - address indexed owner, - address indexed spender, - uint256 amount - ); -} - - -// Dependency file: contracts/CTokenInterfaces.sol - -// pragma solidity 0.8.6; - -// import "contracts/ComptrollerInterface.sol"; -// import "contracts/InterestRateModel.sol"; -// import "contracts/EIP20NonStandardInterface.sol"; - -contract CTokenStorage { - /** - * @dev Guard variable for re-entrancy checks - */ - bool internal _notEntered; - - /** - * @notice EIP-20 token name for this token - */ - string public name; - - /** - * @notice EIP-20 token symbol for this token - */ - string public symbol; - - /** - * @notice EIP-20 token decimals for this token - */ - uint8 public decimals; - - /** - * @notice Maximum borrow rate that can ever be applied (.0005% / block) - */ - - uint256 internal constant borrowRateMaxMantissa = 0.0005e16; - - /** - * @notice Maximum fraction of interest that can be set aside for reserves - */ - uint256 internal constant reserveFactorMaxMantissa = 1e18; - - /** - * @notice Administrator for this contract - */ - address payable public admin; - - /** - * @notice Pending administrator for this contract - */ - address payable public pendingAdmin; - - /** - * @notice Contract which oversees inter-cToken operations - */ - ComptrollerInterface public comptroller; - - /** - * @notice Model which tells what the current interest rate should be - */ - InterestRateModel public interestRateModel; - - /** - * @notice Initial exchange rate used when minting the first CTokens (used when totalSupply = 0) - */ - uint256 public initialExchangeRateMantissa; - - /** - * @notice Fraction of interest currently set aside for reserves - */ - uint256 public reserveFactorMantissa; - - /** - * @notice Block number that interest was last accrued at - */ - uint256 public accrualBlockNumber; - - /** - * @notice Accumulator of the total earned interest rate since the opening of the market - */ - uint256 public borrowIndex; - - /** - * @notice Total amount of outstanding borrows of the underlying in this market - */ - uint256 public totalBorrows; - - /** - * @notice Total amount of reserves of the underlying held in this market - */ - uint256 public totalReserves; - - /** - * @notice Total number of tokens in circulation - */ - uint256 public totalSupply; - - uint256 public subsidyFund; - - struct SupplySnapshot { - uint256 tokens; - uint256 underlyingAmount; - uint256 suppliedAt; - uint256 promisedSupplyRate; - } - - /** - * @notice Official record of token balances for each account - */ - mapping(address => SupplySnapshot) internal accountTokens; - - /** - * @notice Approved token transfer amounts on behalf of others - */ - mapping(address => mapping(address => uint256)) internal transferAllowances; - - /** - * @notice Container for borrow balance information - * @member principal Total balance (with accrued interest), after applying the most recent balance-changing action - * @member interestIndex Global borrowIndex as of the most recent balance-changing action - */ - struct BorrowSnapshot { - uint256 principal; - uint256 interestIndex; - } - - /** - * @notice Mapping of account addresses to outstanding borrow balances - */ - mapping(address => BorrowSnapshot) internal accountBorrows; -} - -abstract contract CTokenInterface is CTokenStorage { - /** - * @notice Indicator that this is a CToken contract (for inspection) - */ - bool public constant isCToken = true; - - /*** Market Events ***/ - - /** - * @notice Event emitted when interest is accrued - */ - event AccrueInterest( - uint256 cashPrior, - uint256 interestAccumulated, - uint256 borrowIndex, - uint256 totalBorrows - ); - - /** - * @notice Event emitted when tokens are minted - */ - event Mint(address indexed minter, uint256 mintAmount, uint256 mintTokens); - - /** - * @notice Event emitted when tokens are redeemed - */ - event Redeem( - address indexed redeemer, - uint256 redeemAmount, - uint256 redeemTokens - ); - - /** - * @notice Event emitted when underlying is borrowed - */ - event Borrow( - address indexed borrower, - uint256 borrowAmount, - uint256 accountBorrows, - uint256 totalBorrows - ); - - /** - * @notice Event emitted when a borrow is repaid - */ - event RepayBorrow( - address indexed payer, - address indexed borrower, - uint256 repayAmount, - uint256 accountBorrows, - uint256 totalBorrows - ); - - /** - * @notice Event emitted when a borrow is liquidated - */ - event LiquidateBorrow( - address indexed liquidator, - address indexed borrower, - uint256 repayAmount, - address indexed cTokenCollateral, - uint256 seizeTokens - ); - - /*** Admin Events ***/ - - /** - * @notice Event emitted when pendingAdmin is changed - */ - event NewPendingAdmin(address oldPendingAdmin, address newPendingAdmin); - - /** - * @notice Event emitted when pendingAdmin is accepted, which means admin is updated - */ - event NewAdmin(address oldAdmin, address newAdmin); - - /** - * @notice Event emitted when comptroller is changed - */ - event NewComptroller( - ComptrollerInterface oldComptroller, - ComptrollerInterface newComptroller - ); - - /** - * @notice Event emitted when interestRateModel is changed - */ - event NewMarketInterestRateModel( - InterestRateModel oldInterestRateModel, - InterestRateModel newInterestRateModel - ); - - /** - * @notice Event emitted when the reserve factor is changed - */ - event NewReserveFactor( - uint256 oldReserveFactorMantissa, - uint256 newReserveFactorMantissa - ); - - /** - * @notice Event emitted when the reserves are added - */ - event ReservesAdded( - address benefactor, - uint256 addAmount, - uint256 newTotalReserves - ); - - event SubsidyAdded( - address benefactor, - uint256 addAmount, - uint256 newSubsidyFund - ); - - /** - * @notice Event emitted when the reserves are reduced - */ - event ReservesReduced( - address admin, - uint256 reduceAmount, - uint256 newTotalReserves - ); - - /** - * @notice EIP20 Transfer event - */ - event Transfer(address indexed from, address indexed to, uint256 amount); - - /** - * @notice EIP20 Approval event - */ - event Approval( - address indexed owner, - address indexed spender, - uint256 amount - ); - - /** - * @notice Failure event - */ - event CTokenStorageFailure(uint256 error, uint256 info, uint256 detail); - - /*** User Interface ***/ - - function transfer(address dst, uint256 amount) - external - virtual - returns (bool); - - function transferFrom( - address src, - address dst, - uint256 amount - ) external virtual returns (bool); - - function approve(address spender, uint256 amount) - external - virtual - returns (bool); - - function allowance(address owner, address spender) - external - view - virtual - returns (uint256); - - function balanceOf(address owner) external view virtual returns (uint256); - - function balanceOfUnderlying(address owner) - external - virtual - returns (uint256); - - function getAccountSnapshot(address account) - external - view - virtual - returns ( - uint256, - uint256, - uint256, - uint256 - ); - - function borrowRatePerBlock() external view virtual returns (uint256); - - function supplyRatePerBlock() external view virtual returns (uint256); - - function totalBorrowsCurrent() external virtual returns (uint256); - - function borrowBalanceCurrent(address account) - external - virtual - returns (uint256); - - function borrowBalanceStored(address account) - public - view - virtual - returns (uint256); - - function exchangeRateCurrent() public virtual returns (uint256); - - function exchangeRateStored() public view virtual returns (uint256); - - function getCash() external view virtual returns (uint256); - - function accrueInterest() public virtual returns (uint256); - - function seize( - address liquidator, - address borrower, - uint256 seizeTokens - ) external virtual returns (uint256); - - /*** Admin Functions ***/ - - function _setPendingAdmin(address payable newPendingAdmin) - external - virtual - returns (uint256); - - function _acceptAdmin() external virtual returns (uint256); - - function _setComptroller(ComptrollerInterface newComptroller) - public - virtual - returns (uint256); - - function _setReserveFactor(uint256 newReserveFactorMantissa) - external - virtual - returns (uint256); - - function _reduceReserves(uint256 reduceAmount) - external - virtual - returns (uint256); - - function _setInterestRateModel(InterestRateModel newInterestRateModel) - public - virtual - returns (uint256); -} - -contract CErc20Storage { - /** - * @notice Underlying asset for this CToken - */ - address public underlying; -} - -abstract contract CErc20Interface is CErc20Storage { - /*** User Interface ***/ - - function mint(uint256 mintAmount) external virtual returns (uint256); - - function redeem(uint256 redeemAmount) - external - virtual - returns (uint256); - - function borrow(uint256 borrowAmount) external virtual returns (uint256); - - function repayBorrow(uint256 repayAmount) - external - virtual - returns (uint256); - - function liquidateBorrow( - address borrower, - uint256 repayAmount, - CTokenInterface cTokenCollateral - ) external virtual returns (uint256); - - function sweepToken(EIP20NonStandardInterface token) external virtual; - - /*** Admin Functions ***/ - - function _addReserves(uint256 addAmount) external virtual returns (uint256); -} - -contract CDelegationStorage { - /** - * @notice Implementation address for this contract - */ - address public implementation; -} - -abstract contract CDelegatorInterface is CDelegationStorage { - /** - * @notice Emitted when implementation is changed - */ - event NewImplementation( - address oldImplementation, - address newImplementation - ); - - /** - * @notice Called by the admin to update the implementation of the delegator - * @param implementation_ The address of the new implementation for delegation - * @param allowResign Flag to indicate whether to call _resignImplementation on the old implementation - * @param becomeImplementationData The encoded bytes data to be passed to _becomeImplementation - */ - function _setImplementation( - address implementation_, - bool allowResign, - bytes memory becomeImplementationData - ) public virtual; -} - -abstract contract CDelegateInterface is CDelegationStorage { - /** - * @notice Called by the delegator on a delegate to initialize it for duty - * @dev Should revert if any issues arise which make it unfit for delegation - * @param data The encoded bytes data for any initialization - */ - function _becomeImplementation(bytes memory data) public virtual; - - /** - * @notice Called by the delegator on a delegate to forfeit its responsibility - */ - function _resignImplementation() public virtual; -} - - -// Dependency file: contracts/ErrorReporter.sol - -// pragma solidity 0.8.6; - -contract ComptrollerErrorReporter { - enum Error { - NO_ERROR, - UNAUTHORIZED, - COMPTROLLER_MISMATCH, - INSUFFICIENT_SHORTFALL, - INSUFFICIENT_LIQUIDITY, - INVALID_CLOSE_FACTOR, - INVALID_COLLATERAL_FACTOR, - INVALID_LIQUIDATION_INCENTIVE, - MARKET_NOT_ENTERED, // no longer possible - MARKET_NOT_LISTED, - MARKET_ALREADY_LISTED, - MATH_ERROR, - NONZERO_BORROW_BALANCE, - PRICE_ERROR, - REJECTION, - SNAPSHOT_ERROR, - TOO_MANY_ASSETS, - TOO_MUCH_REPAY - } - - enum FailureInfo { - ACCEPT_ADMIN_PENDING_ADMIN_CHECK, - ACCEPT_PENDING_IMPLEMENTATION_ADDRESS_CHECK, - EXIT_MARKET_BALANCE_OWED, - EXIT_MARKET_REJECTION, - SET_CLOSE_FACTOR_OWNER_CHECK, - SET_CLOSE_FACTOR_VALIDATION, - SET_COLLATERAL_FACTOR_OWNER_CHECK, - SET_COLLATERAL_FACTOR_NO_EXISTS, - SET_COLLATERAL_FACTOR_VALIDATION, - SET_COLLATERAL_FACTOR_WITHOUT_PRICE, - SET_IMPLEMENTATION_OWNER_CHECK, - SET_LIQUIDATION_INCENTIVE_OWNER_CHECK, - SET_LIQUIDATION_INCENTIVE_VALIDATION, - SET_MAX_ASSETS_OWNER_CHECK, - SET_PENDING_ADMIN_OWNER_CHECK, - SET_PENDING_IMPLEMENTATION_OWNER_CHECK, - SET_PRICE_ORACLE_OWNER_CHECK, - SUPPORT_MARKET_EXISTS, - SUPPORT_MARKET_OWNER_CHECK, - SET_PAUSE_GUARDIAN_OWNER_CHECK - } - - /** - * @dev `error` corresponds to enum Error; `info` corresponds to enum FailureInfo, and `detail` is an arbitrary - * contract-specific code that enables us to report opaque error codes from upgradeable contracts. - **/ - event Failure(uint256 error, uint256 info, uint256 detail); - - /** - * @dev use this when reporting a known error from the money market or a non-upgradeable collaborator - */ - function fail(Error err, FailureInfo info) internal returns (uint256) { - emit Failure(uint256(err), uint256(info), 0); - - return uint256(err); - } - - /** - * @dev use this when reporting an opaque error from an upgradeable collaborator contract - */ - function failOpaque( - Error err, - FailureInfo info, - uint256 opaqueError - ) internal returns (uint256) { - emit Failure(uint256(err), uint256(info), opaqueError); - - return uint256(err); - } -} - -contract TokenErrorReporter { - enum Error { - NO_ERROR, - UNAUTHORIZED, - BAD_INPUT, - COMPTROLLER_REJECTION, - COMPTROLLER_CALCULATION_ERROR, - INTEREST_RATE_MODEL_ERROR, - INVALID_ACCOUNT_PAIR, - INVALID_CLOSE_AMOUNT_REQUESTED, - INVALID_COLLATERAL_FACTOR, - MATH_ERROR, - MARKET_NOT_FRESH, - MARKET_NOT_LISTED, - TOKEN_INSUFFICIENT_ALLOWANCE, - TOKEN_INSUFFICIENT_BALANCE, - TOKEN_INSUFFICIENT_CASH, - TOKEN_TRANSFER_IN_FAILED, - TOKEN_TRANSFER_OUT_FAILED - } - - /* - * Note: FailureInfo (but not Error) is kept in alphabetical order - * This is because FailureInfo grows significantly faster, and - * the order of Error has some meaning, while the order of FailureInfo - * is entirely arbitrary. - */ - enum FailureInfo { - ACCEPT_ADMIN_PENDING_ADMIN_CHECK, - ACCRUE_INTEREST_ACCUMULATED_INTEREST_CALCULATION_FAILED, - ACCRUE_INTEREST_BORROW_RATE_CALCULATION_FAILED, - ACCRUE_INTEREST_NEW_BORROW_INDEX_CALCULATION_FAILED, - ACCRUE_INTEREST_NEW_TOTAL_BORROWS_CALCULATION_FAILED, - ACCRUE_INTEREST_NEW_TOTAL_RESERVES_CALCULATION_FAILED, - ACCRUE_INTEREST_SIMPLE_INTEREST_FACTOR_CALCULATION_FAILED, - BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED, - BORROW_ACCRUE_INTEREST_FAILED, - BORROW_CASH_NOT_AVAILABLE, - BORROW_FRESHNESS_CHECK, - BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED, - BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED, - BORROW_MARKET_NOT_LISTED, - BORROW_COMPTROLLER_REJECTION, - LIQUIDATE_ACCRUE_BORROW_INTEREST_FAILED, - LIQUIDATE_ACCRUE_COLLATERAL_INTEREST_FAILED, - LIQUIDATE_COLLATERAL_FRESHNESS_CHECK, - LIQUIDATE_COMPTROLLER_REJECTION, - LIQUIDATE_COMPTROLLER_CALCULATE_AMOUNT_SEIZE_FAILED, - LIQUIDATE_CLOSE_AMOUNT_IS_UINT_MAX, - LIQUIDATE_CLOSE_AMOUNT_IS_ZERO, - LIQUIDATE_FRESHNESS_CHECK, - LIQUIDATE_LIQUIDATOR_IS_BORROWER, - LIQUIDATE_REPAY_BORROW_FRESH_FAILED, - LIQUIDATE_SEIZE_BALANCE_INCREMENT_FAILED, - LIQUIDATE_SEIZE_BALANCE_DECREMENT_FAILED, - LIQUIDATE_SEIZE_COMPTROLLER_REJECTION, - LIQUIDATE_SEIZE_LIQUIDATOR_IS_BORROWER, - LIQUIDATE_SEIZE_TOO_MUCH, - MINT_ACCRUE_INTEREST_FAILED, - MINT_COMPTROLLER_REJECTION, - MINT_EXCHANGE_CALCULATION_FAILED, - MINT_EXCHANGE_RATE_READ_FAILED, - MINT_FRESHNESS_CHECK, - MINT_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED, - MINT_NEW_TOTAL_SUPPLY_CALCULATION_FAILED, - MINT_TRANSFER_IN_FAILED, - MINT_TRANSFER_IN_NOT_POSSIBLE, - REDEEM_ACCRUE_INTEREST_FAILED, - REDEEM_COMPTROLLER_REJECTION, - REDEEM_EXCHANGE_TOKENS_CALCULATION_FAILED, - REDEEM_EXCHANGE_AMOUNT_CALCULATION_FAILED, - REDEEM_EXCHANGE_RATE_READ_FAILED, - REDEEM_FRESHNESS_CHECK, - REDEEM_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED, - REDEEM_NEW_TOTAL_SUPPLY_CALCULATION_FAILED, - REDEEM_TRANSFER_OUT_NOT_POSSIBLE, - REDUCE_RESERVES_ACCRUE_INTEREST_FAILED, - REDUCE_RESERVES_ADMIN_CHECK, - REDUCE_RESERVES_CASH_NOT_AVAILABLE, - REDUCE_RESERVES_FRESH_CHECK, - REDUCE_RESERVES_VALIDATION, - REPAY_BEHALF_ACCRUE_INTEREST_FAILED, - REPAY_BORROW_ACCRUE_INTEREST_FAILED, - REPAY_BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED, - REPAY_BORROW_COMPTROLLER_REJECTION, - REPAY_BORROW_FRESHNESS_CHECK, - REPAY_BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED, - REPAY_BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED, - REPAY_BORROW_TRANSFER_IN_NOT_POSSIBLE, - SET_COLLATERAL_FACTOR_OWNER_CHECK, - SET_COLLATERAL_FACTOR_VALIDATION, - SET_COMPTROLLER_OWNER_CHECK, - SET_INTEREST_RATE_MODEL_ACCRUE_INTEREST_FAILED, - SET_INTEREST_RATE_MODEL_FRESH_CHECK, - SET_INTEREST_RATE_MODEL_OWNER_CHECK, - SET_MAX_ASSETS_OWNER_CHECK, - SET_ORACLE_MARKET_NOT_LISTED, - SET_PENDING_ADMIN_OWNER_CHECK, - SET_RESERVE_FACTOR_ACCRUE_INTEREST_FAILED, - SET_RESERVE_FACTOR_ADMIN_CHECK, - SET_RESERVE_FACTOR_FRESH_CHECK, - SET_RESERVE_FACTOR_BOUNDS_CHECK, - TRANSFER_COMPTROLLER_REJECTION, - TRANSFER_NOT_ALLOWED, - TRANSFER_NOT_ENOUGH, - TRANSFER_TOO_MUCH, - ADD_RESERVES_ACCRUE_INTEREST_FAILED, - ADD_RESERVES_FRESH_CHECK, - ADD_RESERVES_TRANSFER_IN_NOT_POSSIBLE, - ADD_SUBSIDY_FUND_FAILED, - ADD_SUBSIDY_FUND_FRESH_CHECK - } - - /** - * @dev `error` corresponds to enum Error; `info` corresponds to enum FailureInfo, and `detail` is an arbitrary - * contract-specific code that enables us to report opaque error codes from upgradeable contracts. - **/ - event TokenFailure(uint256 error, uint256 info, uint256 detail); - - /** - * @dev use this when reporting a known error from the money market or a non-upgradeable collaborator - */ - function fail(Error err, FailureInfo info) internal returns (uint256) { - emit TokenFailure(uint256(err), uint256(info), 0); - - return uint256(err); - } - - /** - * @dev use this when reporting an opaque error from an upgradeable collaborator contract - */ - function failOpaque( - Error err, - FailureInfo info, - uint256 opaqueError - ) internal returns (uint256) { - emit TokenFailure(uint256(err), uint256(info), opaqueError); - - return uint256(err); - } -} - - -// Dependency file: contracts/EIP20Interface.sol - -// pragma solidity 0.8.6; - -/** - * @title ERC 20 Token Standard Interface - * https://eips.ethereum.org/EIPS/eip-20 - */ -interface EIP20Interface { - function name() external view returns (string memory); - - function symbol() external view returns (string memory); - - function decimals() external view returns (uint8); - - /** - * @notice Get the total number of tokens in circulation - * @return The supply of tokens - */ - function totalSupply() external view returns (uint256); - - /** - * @notice Gets the balance of the specified address - * @param owner The address from which the balance will be retrieved - * @return balance The balance - */ - function balanceOf(address owner) external view returns (uint256 balance); - - /** - * @notice Transfer `amount` tokens from `msg.sender` to `dst` - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - * @return success Whether or not the transfer succeeded - */ - function transfer(address dst, uint256 amount) - external - returns (bool success); - - /** - * @notice Transfer `amount` tokens from `src` to `dst` - * @param src The address of the source account - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - * @return success Whether or not the transfer succeeded - */ - function transferFrom( - address src, - address dst, - uint256 amount - ) external returns (bool success); - - /** - * @notice Approve `spender` to transfer up to `amount` from `src` - * @dev This will overwrite the approval amount for `spender` - * and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve) - * @param spender The address of the account which may transfer tokens - * @param amount The number of tokens that are approved (-1 means infinite) - * @return success Whether or not the approval succeeded - */ - function approve(address spender, uint256 amount) - external - returns (bool success); - - /** - * @notice Get the current allowance from `owner` for `spender` - * @param owner The address of the account which owns the tokens to be spent - * @param spender The address of the account which may transfer tokens - * @return remaining The number of tokens allowed to be spent (-1 means infinite) - */ - function allowance(address owner, address spender) - external - view - returns (uint256 remaining); - - event Transfer(address indexed from, address indexed to, uint256 amount); - event Approval( - address indexed owner, - address indexed spender, - uint256 amount - ); -} - - -// Dependency file: contracts/WhitelistInterface.sol - -// pragma solidity 0.8.6; - -interface WhitelistInterface { - function setStatus(bool _newStatus) external; - function enabled() external view returns(bool); - - function addUsers(address[] memory _users) external; - function exist(address _user) external view returns(bool); - function getUsers() external view returns(address[] memory currentUsers); - function removeUser(address _user) external; -} - -// Dependency file: contracts/CToken.sol - -// pragma solidity 0.8.6; - -// import "contracts/ComptrollerInterface.sol"; -// import "contracts/CTokenInterfaces.sol"; -// import "contracts/ErrorReporter.sol"; -// import "contracts/Exponential.sol"; -// import "contracts/EIP20Interface.sol"; -// import "contracts/InterestRateModel.sol"; -// import "contracts/WhitelistInterface.sol"; - -/** - * @title tropykus CToken Contract - * @notice Abstract base for CTokens - * @author tropykus - */ -abstract contract CToken is CTokenInterface, Exponential, TokenErrorReporter { - address whitelist; - - /** - * @notice Initialize the money market - * @param comptroller_ The address of the Comptroller - * @param interestRateModel_ The address of the interest rate model - * @param initialExchangeRateMantissa_ The initial exchange rate, scaled by 1e18 - * @param name_ EIP-20 name of this token - * @param symbol_ EIP-20 symbol of this token - * @param decimals_ EIP-20 decimal precision of this token - */ - function initialize( - ComptrollerInterface comptroller_, - InterestRateModel interestRateModel_, - uint256 initialExchangeRateMantissa_, - string memory name_, - string memory symbol_, - uint8 decimals_ - ) public { - require(msg.sender == admin, "CT01"); - require(accrualBlockNumber == 0 && borrowIndex == 0, "CT02"); - - initialExchangeRateMantissa = initialExchangeRateMantissa_; - require(initialExchangeRateMantissa > 0, "CT03"); - - uint256 err = _setComptroller(comptroller_); - require(err == uint256(Error.NO_ERROR), "CT04"); - - accrualBlockNumber = getBlockNumber(); - borrowIndex = mantissaOne; - - err = _setInterestRateModelFresh(interestRateModel_); - require(err == uint256(Error.NO_ERROR), "CT05"); - - name = name_; - symbol = symbol_; - decimals = decimals_; - - _notEntered = true; - } - - function addWhitelist(address _whitelist) external returns (uint256) { - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_INTEREST_RATE_MODEL_OWNER_CHECK - ); - } - whitelist = _whitelist; - } - - /** - * @notice Transfer `tokens` tokens from `src` to `dst` by `spender` - * @dev Called by both `transfer` and `transferFrom` internally - * @param spender The address of the account performing the transfer - * @param src The address of the source account - * @param dst The address of the destination account - * @param tokens The number of tokens to transfer - * @return Whether or not the transfer succeeded - */ - function transferTokens( - address spender, - address src, - address dst, - uint256 tokens - ) internal returns (uint256) { - uint256 allowed = comptroller.transferAllowed( - address(this), - src, - dst, - tokens - ); - if (allowed != 0) { - return - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.TRANSFER_COMPTROLLER_REJECTION, - allowed - ); - } - - if (src == dst) { - return fail(Error.BAD_INPUT, FailureInfo.TRANSFER_NOT_ALLOWED); - } - - uint256 startingAllowance = 0; - if (spender == src) { - startingAllowance = type(uint256).max; - } else { - startingAllowance = transferAllowances[src][spender]; - } - - MathError mathErr; - uint256 allowanceNew; - uint256 srcTokensNew; - uint256 dstTokensNew; - - (mathErr, allowanceNew) = subUInt(startingAllowance, tokens); - if (mathErr != MathError.NO_ERROR) { - return fail(Error.MATH_ERROR, FailureInfo.TRANSFER_NOT_ALLOWED); - } - - (mathErr, srcTokensNew) = subUInt(accountTokens[src].tokens, tokens); - if (mathErr != MathError.NO_ERROR) { - return fail(Error.MATH_ERROR, FailureInfo.TRANSFER_NOT_ENOUGH); - } - - (mathErr, dstTokensNew) = addUInt(accountTokens[dst].tokens, tokens); - if (mathErr != MathError.NO_ERROR) { - return fail(Error.MATH_ERROR, FailureInfo.TRANSFER_TOO_MUCH); - } - - accountTokens[src].tokens = srcTokensNew; - accountTokens[dst].tokens = dstTokensNew; - - if (startingAllowance != type(uint256).max) { - transferAllowances[src][spender] = allowanceNew; - } - - emit Transfer(src, dst, tokens); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Transfer `amount` tokens from `msg.sender` to `dst` - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - * @return Whether or not the transfer succeeded - */ - function transfer(address dst, uint256 amount) - external - override - nonReentrant - returns (bool) - { - return - transferTokens(msg.sender, msg.sender, dst, amount) == - uint256(Error.NO_ERROR); - } - - /** - * @notice Transfer `amount` tokens from `src` to `dst` - * @param src The address of the source account - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - * @return Whether or not the transfer succeeded - */ - function transferFrom( - address src, - address dst, - uint256 amount - ) external override nonReentrant returns (bool) { - return - transferTokens(msg.sender, src, dst, amount) == - uint256(Error.NO_ERROR); - } - - /** - * @notice Approve `spender` to transfer up to `amount` from `src` - * @dev This will overwrite the approval amount for `spender` - * and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve) - * @param spender The address of the account which may transfer tokens - * @param amount The number of tokens that are approved (-1 means infinite) - * @return Whether or not the approval succeeded - */ - function approve(address spender, uint256 amount) - external - override - returns (bool) - { - transferAllowances[msg.sender][spender] = amount; - emit Approval(msg.sender, spender, amount); - return true; - } - - /** - * @notice Get the current allowance from `owner` for `spender` - * @param owner The address of the account which owns the tokens to be spent - * @param spender The address of the account which may transfer tokens - * @return The number of tokens allowed to be spent (-1 means infinite) - */ - function allowance(address owner, address spender) - external - view - override - returns (uint256) - { - return transferAllowances[owner][spender]; - } - - /** - * @notice Get the token balance of the `owner` - * @param owner The address of the account to query - * @return The number of tokens owned by `owner` - */ - function balanceOf(address owner) external view override returns (uint256) { - return accountTokens[owner].tokens; - } - - /** - * @notice Get the underlying balance of the `owner` - * @dev This also accrues interest in a transaction - * @param owner The address of the account to query - * @return The amount of underlying owned by `owner` - */ - function balanceOfUnderlying(address owner) - external - override - returns (uint256) - { - (MathError mErr, uint256 balance) = mulScalarTruncate( - Exp({mantissa: exchangeRateCurrent()}), - accountTokens[owner].tokens - ); - require(mErr == MathError.NO_ERROR, "CT06"); - return balance; - } - - /** - * @notice Get a snapshot of the account's balances, and the cached exchange rate - * @dev This is used by comptroller to more efficiently perform liquidity checks. - * @param account Address of the account to snapshot - * @return (possible error, token balance, borrow balance, exchange rate mantissa) - */ - function getAccountSnapshot(address account) - external - view - override - returns ( - uint256, - uint256, - uint256, - uint256 - ) - { - uint256 cTokenBalance = accountTokens[account].tokens; - uint256 borrowBalance; - uint256 exchangeRateMantissa; - - MathError mErr; - - (mErr, borrowBalance) = borrowBalanceStoredInternal(account); - if (mErr != MathError.NO_ERROR) { - return (uint256(Error.MATH_ERROR), 0, 0, 0); - } - - (mErr, exchangeRateMantissa) = exchangeRateStoredInternal(); - if (mErr != MathError.NO_ERROR) { - return (uint256(Error.MATH_ERROR), 0, 0, 0); - } - - return ( - uint256(Error.NO_ERROR), - cTokenBalance, - borrowBalance, - exchangeRateMantissa - ); - } - - /** - * @dev Function to simply retrieve block number - * This exists mainly for inheriting test contracts to stub this result. - */ - function getBlockNumber() internal view virtual returns (uint256) { - return block.number; - } - - /** - * @notice Returns the current per-block borrow interest rate for this cToken - * @return The borrow interest rate per block, scaled by 1e18 - */ - function borrowRatePerBlock() external view override returns (uint256) { - return - interestRateModel.getBorrowRate( - getCashPrior(), - totalBorrows, - totalReserves - ); - } - - /** - * @notice Returns the current per-block supply interest rate for this cToken - * @return The supply interest rate per block, scaled by 1e18 - */ - function supplyRatePerBlock() external view override returns (uint256) { - return - interestRateModel.getSupplyRate( - getCashPrior(), - totalBorrows, - totalReserves, - reserveFactorMantissa - ); - } - - /** - * @notice Returns the current total borrows plus accrued interest - * @return The total borrows with interest - */ - function totalBorrowsCurrent() - external - override - nonReentrant - returns (uint256) - { - require(accrueInterest() == uint256(Error.NO_ERROR), "CT07"); - return totalBorrows; - } - - /** - * @notice Accrue interest to updated borrowIndex and then calculate account's borrow balance using the updated borrowIndex - * @param account The address whose balance should be calculated after updating borrowIndex - * @return The calculated balance - */ - function borrowBalanceCurrent(address account) - external - override - nonReentrant - returns (uint256) - { - require(accrueInterest() == uint256(Error.NO_ERROR), "CT07"); - return borrowBalanceStored(account); - } - - /** - * @notice Return the borrow balance of account based on stored data - * @param account The address whose balance should be calculated - * @return The calculated balance - */ - function borrowBalanceStored(address account) - public - view - override - returns (uint256) - { - (MathError err, uint256 result) = borrowBalanceStoredInternal(account); - require(err == MathError.NO_ERROR, "CT08"); - return result; - } - - /** - * @notice Return the borrow balance of account based on stored data - * @param account The address whose balance should be calculated - * @return (error code, the calculated balance or 0 if error code is non-zero) - */ - function borrowBalanceStoredInternal(address account) - internal - view - returns (MathError, uint256) - { - MathError mathErr; - uint256 principalTimesIndex; - uint256 result; - - BorrowSnapshot storage borrowSnapshot = accountBorrows[account]; - - if (borrowSnapshot.principal == 0) { - return (MathError.NO_ERROR, 0); - } - - (mathErr, principalTimesIndex) = mulUInt( - borrowSnapshot.principal, - borrowIndex - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - - (mathErr, result) = divUInt( - principalTimesIndex, - borrowSnapshot.interestIndex - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - - return (MathError.NO_ERROR, result); - } - - function getBorrowerPrincipalStored(address account) - public - view - returns (uint256 borrowed) - { - borrowed = accountBorrows[account].principal; - } - - function getSupplierSnapshotStored(address account) - public - view - returns ( - uint256 tokens, - uint256 underlyingAmount, - uint256 suppliedAt, - uint256 promisedSupplyRate - ) - { - tokens = accountTokens[account].tokens; - underlyingAmount = accountTokens[account].underlyingAmount; - suppliedAt = accountTokens[account].suppliedAt; - promisedSupplyRate = accountTokens[account].promisedSupplyRate; - } - - /** - * @notice Accrue interest then return the up-to-date exchange rate - * @return Calculated exchange rate scaled by 1e18 - */ - function exchangeRateCurrent() - public - override - nonReentrant - returns (uint256) - { - require(accrueInterest() == uint256(Error.NO_ERROR), "CT07"); - return exchangeRateStored(); - } - - /** - * @notice Calculates the exchange rate from the underlying to the CToken - * @dev This function does not accrue interest before calculating the exchange rate - * @return Calculated exchange rate scaled by 1e18 - */ - function exchangeRateStored() public view override returns (uint256) { - (MathError err, uint256 result) = exchangeRateStoredInternal(); - require(err == MathError.NO_ERROR, "CT09"); - return result; - } - - /** - * @notice Calculates the exchange rate from the underlying to the CToken - * @dev This function does not accrue interest before calculating the exchange rate - * @return (error code, calculated exchange rate scaled by 1e18) - */ - function exchangeRateStoredInternal() - internal - view - virtual - returns (MathError, uint256) - { - uint256 _totalSupply = totalSupply; - if (_totalSupply == 0) { - return (MathError.NO_ERROR, initialExchangeRateMantissa); - } else { - MathError error; - uint256 exchangeRate; - uint256 totalCash = getCashPrior(); - if (interestRateModel.isTropykusInterestRateModel()) { - (error, exchangeRate) = tropykusExchangeRateStoredInternal( - msg.sender - ); - if (error == MathError.NO_ERROR) { - return (MathError.NO_ERROR, exchangeRate); - } else { - return (MathError.NO_ERROR, initialExchangeRateMantissa); - } - } - return - interestRateModel.getExchangeRate( - totalCash, - totalBorrows, - totalReserves, - totalSupply - ); - } - } - - function tropykusExchangeRateStoredInternal(address redeemer) - internal - view - returns (MathError, uint256) - { - if (totalSupply == 0) { - return (MathError.NO_ERROR, initialExchangeRateMantissa); - } else { - SupplySnapshot storage supplySnapshot = accountTokens[redeemer]; - if (supplySnapshot.suppliedAt == 0) { - return (MathError.DIVISION_BY_ZERO, 0); - } - (, uint256 interestFactorMantissa, ) = tropykusInterestAccrued( - redeemer - ); - Exp memory interestFactor = Exp({mantissa: interestFactorMantissa}); - uint256 currentUnderlying = supplySnapshot.underlyingAmount; - Exp memory redeemerUnderlying = Exp({mantissa: currentUnderlying}); - (, Exp memory realAmount) = mulExp( - interestFactor, - redeemerUnderlying - ); - (, Exp memory exchangeRate) = getExp( - realAmount.mantissa, - supplySnapshot.tokens - ); - return (MathError.NO_ERROR, exchangeRate.mantissa); - } - } - - function tropykusInterestAccrued(address account) - internal - view - returns ( - MathError, - uint256, - uint256 - ) - { - SupplySnapshot storage supplySnapshot = accountTokens[account]; - uint256 promisedSupplyRate = supplySnapshot.promisedSupplyRate; - Exp memory expectedSupplyRatePerBlock = Exp({ - mantissa: promisedSupplyRate - }); - (, uint256 delta) = subUInt( - accrualBlockNumber, - supplySnapshot.suppliedAt - ); - (, Exp memory expectedSupplyRatePerBlockWithDelta) = mulScalar( - expectedSupplyRatePerBlock, - delta - ); - (, Exp memory interestFactor) = addExp( - Exp({mantissa: 1e18}), - expectedSupplyRatePerBlockWithDelta - ); - uint256 currentUnderlying = supplySnapshot.underlyingAmount; - Exp memory redeemerUnderlying = Exp({mantissa: currentUnderlying}); - (, Exp memory realAmount) = mulExp(interestFactor, redeemerUnderlying); - (, uint256 interestEarned) = subUInt( - realAmount.mantissa, - currentUnderlying - ); - return (MathError.NO_ERROR, interestFactor.mantissa, interestEarned); - } - - /** - * @notice Get cash balance of this cToken in the underlying asset - * @return The quantity of underlying asset owned by this contract - */ - function getCash() external view override returns (uint256) { - return getCashPrior(); - } - - /** - * @notice Applies accrued interest to total borrows and reserves - * @dev This calculates interest accrued from the last checkpointed block - * up to the current block and writes new checkpoint to storage. - */ - function accrueInterest() public override returns (uint256) { - uint256 currentBlockNumber = getBlockNumber(); - uint256 accrualBlockNumberPrior = accrualBlockNumber; - - if (accrualBlockNumberPrior == currentBlockNumber) { - return uint256(Error.NO_ERROR); - } - - uint256 cashPrior = getCashPrior(); - uint256 borrowsPrior = totalBorrows; - uint256 reservesPrior = totalReserves; - uint256 borrowIndexPrior = borrowIndex; - - uint256 borrowRateMantissa = interestRateModel.getBorrowRate( - cashPrior, - borrowsPrior, - reservesPrior - ); - require(borrowRateMantissa <= borrowRateMaxMantissa, "CT10"); - - (MathError mathErr, uint256 blockDelta) = subUInt( - currentBlockNumber, - accrualBlockNumberPrior - ); - require(mathErr == MathError.NO_ERROR, "CT11"); - - Exp memory simpleInterestFactor; - uint256 interestAccumulated; - uint256 totalBorrowsNew; - uint256 totalReservesNew; - uint256 borrowIndexNew; - - (mathErr, simpleInterestFactor) = mulScalar( - Exp({mantissa: borrowRateMantissa}), - blockDelta - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .ACCRUE_INTEREST_SIMPLE_INTEREST_FACTOR_CALCULATION_FAILED, - uint256(mathErr) - ); - } - - (mathErr, interestAccumulated) = mulScalarTruncate( - simpleInterestFactor, - borrowsPrior - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .ACCRUE_INTEREST_ACCUMULATED_INTEREST_CALCULATION_FAILED, - uint256(mathErr) - ); - } - - (mathErr, totalBorrowsNew) = addUInt(interestAccumulated, borrowsPrior); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .ACCRUE_INTEREST_NEW_TOTAL_BORROWS_CALCULATION_FAILED, - uint256(mathErr) - ); - } - - (mathErr, totalReservesNew) = mulScalarTruncateAddUInt( - Exp({mantissa: reserveFactorMantissa}), - interestAccumulated, - reservesPrior - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .ACCRUE_INTEREST_NEW_TOTAL_RESERVES_CALCULATION_FAILED, - uint256(mathErr) - ); - } - - if (interestRateModel.isTropykusInterestRateModel()) { - (mathErr, totalReservesNew) = newReserves( - borrowRateMantissa, - cashPrior, - borrowsPrior, - reservesPrior, - interestAccumulated - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .ACCRUE_INTEREST_NEW_TOTAL_RESERVES_CALCULATION_FAILED, - uint256(mathErr) - ); - } - } - - (mathErr, borrowIndexNew) = mulScalarTruncateAddUInt( - simpleInterestFactor, - borrowIndexPrior, - borrowIndexPrior - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .ACCRUE_INTEREST_NEW_BORROW_INDEX_CALCULATION_FAILED, - uint256(mathErr) - ); - } - - accrualBlockNumber = currentBlockNumber; - borrowIndex = borrowIndexNew; - totalBorrows = totalBorrowsNew; - totalReserves = totalReservesNew; - - emit AccrueInterest( - cashPrior, - interestAccumulated, - borrowIndexNew, - totalBorrowsNew - ); - - return uint256(Error.NO_ERROR); - } - - function newReserves( - uint256 borrowRateMantissa, - uint256 cashPrior, - uint256 borrowsPrior, - uint256 reservesPrior, - uint256 interestAccumulated - ) internal view returns (MathError mathErr, uint256 totalReservesNew) { - uint256 newReserveFactorMantissa; - uint256 utilizationRate = interestRateModel.utilizationRate( - cashPrior, - borrowsPrior, - reservesPrior - ); - uint256 expectedSupplyRate = interestRateModel.getSupplyRate( - cashPrior, - borrowsPrior, - reservesPrior, - reserveFactorMantissa - ); - if ( - interestRateModel.isAboveOptimal( - cashPrior, - borrowsPrior, - reservesPrior - ) - ) { - (mathErr, newReserveFactorMantissa) = mulScalarTruncate( - Exp({mantissa: utilizationRate}), - borrowRateMantissa - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - (mathErr, newReserveFactorMantissa) = subUInt( - newReserveFactorMantissa, - expectedSupplyRate - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - (mathErr, totalReservesNew) = mulScalarTruncateAddUInt( - Exp({mantissa: newReserveFactorMantissa}), - interestAccumulated, - reservesPrior - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - } else { - mathErr = MathError.NO_ERROR; - totalReservesNew = reservesPrior; - } - } - - /** - * @notice Sender supplies assets into the market and receives cTokens in exchange - * @dev Accrues interest whether or not the operation succeeds, unless reverted - * @param mintAmount The amount of the underlying asset to supply - * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual mint amount. - */ - function mintInternal(uint256 mintAmount) - internal - nonReentrant - returns (uint256, uint256) - { - if (WhitelistInterface(whitelist).enabled()) { - require(WhitelistInterface(whitelist).exist(msg.sender), "CT26"); - } - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return ( - fail(Error(error), FailureInfo.MINT_ACCRUE_INTEREST_FAILED), - 0 - ); - } - return mintFresh(msg.sender, mintAmount); - } - - struct MintLocalVars { - Error err; - MathError mathErr; - uint256 exchangeRateMantissa; - uint256 mintTokens; - uint256 totalSupplyNew; - uint256 accountTokensNew; - uint256 actualMintAmount; - } - - /** - * @notice User supplies assets into the market and receives cTokens in exchange - * @dev Assumes interest has already been accrued up to the current block - * @param minter The address of the account which is supplying the assets - * @param mintAmount The amount of the underlying asset to supply - * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual mint amount. - */ - function mintFresh(address minter, uint256 mintAmount) - internal - returns (uint256, uint256) - { - uint256 allowed = comptroller.mintAllowed( - address(this), - minter, - mintAmount - ); - if (allowed != 0) { - return ( - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.MINT_COMPTROLLER_REJECTION, - allowed - ), - 0 - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return ( - fail(Error.MARKET_NOT_FRESH, FailureInfo.MINT_FRESHNESS_CHECK), - 0 - ); - } - - MintLocalVars memory vars; - - ( - vars.mathErr, - vars.exchangeRateMantissa - ) = exchangeRateStoredInternal(); - if (vars.mathErr != MathError.NO_ERROR) { - return ( - failOpaque( - Error.MATH_ERROR, - FailureInfo.MINT_EXCHANGE_RATE_READ_FAILED, - uint256(vars.mathErr) - ), - 0 - ); - } - if (interestRateModel.isTropykusInterestRateModel()) { - SupplySnapshot storage supplySnapshot = accountTokens[minter]; - (, uint256 newTotalSupply) = addUInt( - supplySnapshot.underlyingAmount, - mintAmount - ); - require(newTotalSupply <= 0.1e18, "CT24"); - } - vars.actualMintAmount = doTransferIn(minter, mintAmount); - - (vars.mathErr, vars.mintTokens) = divScalarByExpTruncate( - vars.actualMintAmount, - Exp({mantissa: vars.exchangeRateMantissa}) - ); - require(vars.mathErr == MathError.NO_ERROR, "CT12"); - - (vars.mathErr, vars.totalSupplyNew) = addUInt( - totalSupply, - vars.mintTokens - ); - require(vars.mathErr == MathError.NO_ERROR, "CT13"); - - (vars.mathErr, vars.accountTokensNew) = addUInt( - accountTokens[minter].tokens, - vars.mintTokens - ); - require(vars.mathErr == MathError.NO_ERROR, "CT14"); - - uint256 currentSupplyRate = interestRateModel.getSupplyRate( - getCashPrior(), - totalBorrows, - totalReserves, - reserveFactorMantissa - ); - - bool isTropykusInterestRateModel = interestRateModel - .isTropykusInterestRateModel(); - - if (accountTokens[minter].tokens > 0) { - Exp memory updatedUnderlying; - if (isTropykusInterestRateModel) { - (, uint256 interestFactorMantissa, ) = tropykusInterestAccrued( - minter - ); - Exp memory interestFactor = Exp({ - mantissa: interestFactorMantissa - }); - uint256 currentUnderlyingAmount = accountTokens[minter] - .underlyingAmount; - MathError mErrorNewAmount; - (mErrorNewAmount, updatedUnderlying) = mulExp( - Exp({mantissa: currentUnderlyingAmount}), - interestFactor - ); - if (mErrorNewAmount != MathError.NO_ERROR) { - return ( - failOpaque( - Error.MATH_ERROR, - FailureInfo.MINT_EXCHANGE_CALCULATION_FAILED, - uint256(mErrorNewAmount) - ), - 0 - ); - } - } else { - uint256 currentTokens = accountTokens[minter].tokens; - MathError mErrorUpdatedUnderlying; - (mErrorUpdatedUnderlying, updatedUnderlying) = mulExp( - Exp({mantissa: currentTokens}), - Exp({mantissa: vars.exchangeRateMantissa}) - ); - if (mErrorUpdatedUnderlying != MathError.NO_ERROR) { - return ( - failOpaque( - Error.MATH_ERROR, - FailureInfo.MINT_EXCHANGE_CALCULATION_FAILED, - uint256(mErrorUpdatedUnderlying) - ), - 0 - ); - } - } - (, mintAmount) = addUInt(updatedUnderlying.mantissa, mintAmount); - } - - totalSupply = vars.totalSupplyNew; - accountTokens[minter] = SupplySnapshot({ - tokens: vars.accountTokensNew, - underlyingAmount: mintAmount, - suppliedAt: accrualBlockNumber, - promisedSupplyRate: currentSupplyRate - }); - - emit Mint(minter, vars.actualMintAmount, vars.mintTokens); - emit Transfer(address(this), minter, vars.mintTokens); - - return (uint256(Error.NO_ERROR), vars.actualMintAmount); - } - - /** - * @notice Sender redeems cTokens in exchange for a specified amount of underlying asset - * @dev Accrues interest whether or not the operation succeeds, unless reverted - * @param redeemAmount The amount of underlying to receive from redeeming cTokens - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function redeemUnderlyingInternal(uint256 redeemAmount) - internal - nonReentrant - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return - fail(Error(error), FailureInfo.REDEEM_ACCRUE_INTEREST_FAILED); - } - return redeemFresh(payable(msg.sender), redeemAmount); - } - - struct RedeemLocalVars { - Error err; - MathError mathErr; - uint256 exchangeRateMantissa; - uint256 redeemTokens; - uint256 redeemAmount; - uint256 totalSupplyNew; - uint256 accountTokensNew; - uint256 newSubsidyFund; - } - - /** - * @notice User redeems cTokens in exchange for the underlying asset - * @dev Assumes interest has already been accrued up to the current block - * @param redeemer The address of the account which is redeeming the tokens - * @param redeemAmountIn The number of underlying tokens to receive from redeeming cTokens - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function redeemFresh(address payable redeemer, uint256 redeemAmountIn) - internal - returns (uint256) - { - require(redeemAmountIn > 0, "CT15"); - - RedeemLocalVars memory vars; - - SupplySnapshot storage supplySnapshot = accountTokens[redeemer]; - - ( - vars.mathErr, - vars.exchangeRateMantissa - ) = exchangeRateStoredInternal(); - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.REDEEM_EXCHANGE_RATE_READ_FAILED, - uint256(vars.mathErr) - ); - } - - uint256 interestEarned; - uint256 subsidyFundPortion; - uint256 currentUnderlying; - - bool isTropykusInterestRateModel = interestRateModel - .isTropykusInterestRateModel(); - if (isTropykusInterestRateModel) { - currentUnderlying = supplySnapshot.underlyingAmount; - (, , interestEarned) = tropykusInterestAccrued(redeemer); - } - supplySnapshot.promisedSupplyRate = interestRateModel.getSupplyRate( - getCashPrior(), - totalBorrows, - totalReserves, - reserveFactorMantissa - ); - - if ( - isTropykusInterestRateModel && - !interestRateModel.isAboveOptimal( - getCashPrior(), - totalBorrows, - totalReserves - ) - ) { - uint256 borrowRate = interestRateModel.getBorrowRate( - getCashPrior(), - totalBorrows, - totalReserves - ); - - uint256 utilizationRate = interestRateModel.utilizationRate( - getCashPrior(), - totalBorrows, - totalReserves - ); - - (, uint256 estimatedEarning) = mulScalarTruncate( - Exp({mantissa: borrowRate}), - utilizationRate - ); - - (, subsidyFundPortion) = subUInt( - supplySnapshot.promisedSupplyRate, - estimatedEarning - ); - (, Exp memory subsidyFactor) = getExp( - subsidyFundPortion, - supplySnapshot.promisedSupplyRate - ); - (, subsidyFundPortion) = mulScalarTruncate( - subsidyFactor, - interestEarned - ); - } - - vars.redeemAmount = redeemAmountIn; - - if (isTropykusInterestRateModel) { - (, Exp memory num) = mulExp( - vars.redeemAmount, - supplySnapshot.tokens - ); - (, Exp memory realTokensWithdrawAmount) = getExp( - num.mantissa, - currentUnderlying - ); - vars.redeemTokens = realTokensWithdrawAmount.mantissa; - } else { - (vars.mathErr, vars.redeemTokens) = divScalarByExpTruncate( - redeemAmountIn, - Exp({mantissa: vars.exchangeRateMantissa}) - ); - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.REDEEM_EXCHANGE_AMOUNT_CALCULATION_FAILED, - uint256(vars.mathErr) - ); - } - } - // } - - uint256 allowed = comptroller.redeemAllowed( - address(this), - redeemer, - vars.redeemTokens - ); - if (allowed != 0) { - return - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.REDEEM_COMPTROLLER_REJECTION, - allowed - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.REDEEM_FRESHNESS_CHECK - ); - } - - (vars.mathErr, vars.totalSupplyNew) = subUInt( - totalSupply, - vars.redeemTokens - ); - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.REDEEM_NEW_TOTAL_SUPPLY_CALCULATION_FAILED, - uint256(vars.mathErr) - ); - } - - (, vars.newSubsidyFund) = subUInt(subsidyFund, subsidyFundPortion); - - (vars.mathErr, vars.accountTokensNew) = subUInt( - supplySnapshot.tokens, - vars.redeemTokens - ); - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.REDEEM_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED, - uint256(vars.mathErr) - ); - } - - uint256 cash = getCashPrior(); - if (isTropykusInterestRateModel) { - cash = address(this).balance; - } - - if (cash < vars.redeemAmount) { - return - fail( - Error.TOKEN_INSUFFICIENT_CASH, - FailureInfo.REDEEM_TRANSFER_OUT_NOT_POSSIBLE - ); - } - - doTransferOut(redeemer, vars.redeemAmount); - - totalSupply = vars.totalSupplyNew; - subsidyFund = vars.newSubsidyFund; - supplySnapshot.tokens = vars.accountTokensNew; - supplySnapshot.suppliedAt = accrualBlockNumber; - (, supplySnapshot.underlyingAmount) = subUInt( - supplySnapshot.underlyingAmount, - vars.redeemAmount - ); - - emit Transfer(redeemer, address(this), vars.redeemTokens); - emit Redeem(redeemer, vars.redeemAmount, vars.redeemTokens); - - comptroller.redeemVerify( - address(this), - redeemer, - vars.redeemAmount, - vars.redeemTokens - ); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Sender borrows assets from the protocol to their own address - * @param borrowAmount The amount of the underlying asset to borrow - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function borrowInternal(uint256 borrowAmount) - internal - nonReentrant - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return - fail(Error(error), FailureInfo.BORROW_ACCRUE_INTEREST_FAILED); - } - return borrowFresh(payable(msg.sender), borrowAmount); - } - - struct BorrowLocalVars { - MathError mathErr; - uint256 accountBorrows; - uint256 accountBorrowsNew; - uint256 totalBorrowsNew; - } - - /** - * @notice Users borrow assets from the protocol to their own address - * @param borrowAmount The amount of the underlying asset to borrow - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function borrowFresh(address payable borrower, uint256 borrowAmount) - internal - returns (uint256) - { - uint256 allowed = comptroller.borrowAllowed( - address(this), - borrower, - borrowAmount - ); - if (allowed != 0) { - return - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.BORROW_COMPTROLLER_REJECTION, - allowed - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.BORROW_FRESHNESS_CHECK - ); - } - - if (getCashPrior() < borrowAmount) { - return - fail( - Error.TOKEN_INSUFFICIENT_CASH, - FailureInfo.BORROW_CASH_NOT_AVAILABLE - ); - } - - BorrowLocalVars memory vars; - - (vars.mathErr, vars.accountBorrows) = borrowBalanceStoredInternal( - borrower - ); - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED, - uint256(vars.mathErr) - ); - } - - (vars.mathErr, vars.accountBorrowsNew) = addUInt( - vars.accountBorrows, - borrowAmount - ); - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED, - uint256(vars.mathErr) - ); - } - - (vars.mathErr, vars.totalBorrowsNew) = addUInt( - totalBorrows, - borrowAmount - ); - if (interestRateModel.isTropykusInterestRateModel()) { - require(vars.totalBorrowsNew <= 0.1e18, "CT25"); - } - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED, - uint256(vars.mathErr) - ); - } - - doTransferOut(borrower, borrowAmount); - - accountBorrows[borrower].principal = vars.accountBorrowsNew; - accountBorrows[borrower].interestIndex = borrowIndex; - totalBorrows = vars.totalBorrowsNew; - - emit Borrow( - borrower, - borrowAmount, - vars.accountBorrowsNew, - vars.totalBorrowsNew - ); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Sender repays their own borrow - * @param repayAmount The amount to repay - * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual repayment amount. - */ - function repayBorrowInternal(uint256 repayAmount) - internal - nonReentrant - returns (uint256, uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return ( - fail( - Error(error), - FailureInfo.REPAY_BORROW_ACCRUE_INTEREST_FAILED - ), - 0 - ); - } - return repayBorrowFresh(msg.sender, msg.sender, repayAmount); - } - - struct RepayBorrowLocalVars { - Error err; - MathError mathErr; - uint256 repayAmount; - uint256 borrowerIndex; - uint256 accountBorrows; - uint256 accountBorrowsNew; - uint256 totalBorrowsNew; - uint256 actualRepayAmount; - } - - /** - * @notice Borrows are repaid by another user (possibly the borrower). - * @param payer the account paying off the borrow - * @param borrower the account with the debt being payed off - * @param repayAmount the amount of undelrying tokens being returned - * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual repayment amount. - */ - function repayBorrowFresh( - address payer, - address borrower, - uint256 repayAmount - ) internal returns (uint256, uint256) { - uint256 allowed = comptroller.repayBorrowAllowed( - address(this), - payer, - borrower, - repayAmount - ); - if (allowed != 0) { - return ( - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.REPAY_BORROW_COMPTROLLER_REJECTION, - allowed - ), - 0 - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return ( - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.REPAY_BORROW_FRESHNESS_CHECK - ), - 0 - ); - } - - RepayBorrowLocalVars memory vars; - - vars.borrowerIndex = accountBorrows[borrower].interestIndex; - - (vars.mathErr, vars.accountBorrows) = borrowBalanceStoredInternal( - borrower - ); - if (vars.mathErr != MathError.NO_ERROR) { - return ( - failOpaque( - Error.MATH_ERROR, - FailureInfo - .REPAY_BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED, - uint256(vars.mathErr) - ), - 0 - ); - } - - if (repayAmount == type(uint256).max) { - vars.repayAmount = vars.accountBorrows; - } else { - vars.repayAmount = repayAmount; - } - - vars.actualRepayAmount = doTransferIn(payer, vars.repayAmount); - - (vars.mathErr, vars.accountBorrowsNew) = subUInt( - vars.accountBorrows, - vars.actualRepayAmount - ); - require(vars.mathErr == MathError.NO_ERROR, "CT16"); - - (vars.mathErr, vars.totalBorrowsNew) = subUInt( - totalBorrows, - vars.actualRepayAmount - ); - require(vars.mathErr == MathError.NO_ERROR, "CT17"); - - accountBorrows[borrower].principal = vars.accountBorrowsNew; - accountBorrows[borrower].interestIndex = borrowIndex; - totalBorrows = vars.totalBorrowsNew; - - emit RepayBorrow( - payer, - borrower, - vars.actualRepayAmount, - vars.accountBorrowsNew, - vars.totalBorrowsNew - ); - - return (uint256(Error.NO_ERROR), vars.actualRepayAmount); - } - - /** - * @notice The sender liquidates the borrowers collateral. - * The collateral seized is transferred to the liquidator. - * @param borrower The borrower of this cToken to be liquidated - * @param cTokenCollateral The market in which to seize collateral from the borrower - * @param repayAmount The amount of the underlying borrowed asset to repay - * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual repayment amount. - */ - function liquidateBorrowInternal( - address borrower, - uint256 repayAmount, - CTokenInterface cTokenCollateral - ) internal nonReentrant returns (uint256, uint256) { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return ( - fail( - Error(error), - FailureInfo.LIQUIDATE_ACCRUE_BORROW_INTEREST_FAILED - ), - 0 - ); - } - - error = cTokenCollateral.accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return ( - fail( - Error(error), - FailureInfo.LIQUIDATE_ACCRUE_COLLATERAL_INTEREST_FAILED - ), - 0 - ); - } - - // liquidateBorrowFresh emits borrow-specific logs on errors, so we don't need to - return - liquidateBorrowFresh( - msg.sender, - borrower, - repayAmount, - cTokenCollateral - ); - } - - /** - * @notice The liquidator liquidates the borrowers collateral. - * The collateral seized is transferred to the liquidator. - * @param borrower The borrower of this cToken to be liquidated - * @param liquidator The address repaying the borrow and seizing collateral - * @param cTokenCollateral The market in which to seize collateral from the borrower - * @param repayAmount The amount of the underlying borrowed asset to repay - * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual repayment amount. - */ - function liquidateBorrowFresh( - address liquidator, - address borrower, - uint256 repayAmount, - CTokenInterface cTokenCollateral - ) internal returns (uint256, uint256) { - uint256 allowed = comptroller.liquidateBorrowAllowed( - address(this), - address(cTokenCollateral), - liquidator, - borrower, - repayAmount - ); - if (allowed != 0) { - return ( - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.LIQUIDATE_COMPTROLLER_REJECTION, - allowed - ), - 0 - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return ( - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.LIQUIDATE_FRESHNESS_CHECK - ), - 0 - ); - } - - if (cTokenCollateral.accrualBlockNumber() != getBlockNumber()) { - return ( - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.LIQUIDATE_COLLATERAL_FRESHNESS_CHECK - ), - 0 - ); - } - - if (borrower == liquidator) { - return ( - fail( - Error.INVALID_ACCOUNT_PAIR, - FailureInfo.LIQUIDATE_LIQUIDATOR_IS_BORROWER - ), - 0 - ); - } - - if (repayAmount == 0) { - return ( - fail( - Error.INVALID_CLOSE_AMOUNT_REQUESTED, - FailureInfo.LIQUIDATE_CLOSE_AMOUNT_IS_ZERO - ), - 0 - ); - } - - if (repayAmount == type(uint256).max) { - return ( - fail( - Error.INVALID_CLOSE_AMOUNT_REQUESTED, - FailureInfo.LIQUIDATE_CLOSE_AMOUNT_IS_UINT_MAX - ), - 0 - ); - } - - ( - uint256 repayBorrowError, - uint256 actualRepayAmount - ) = repayBorrowFresh(liquidator, borrower, repayAmount); - if (repayBorrowError != uint256(Error.NO_ERROR)) { - return ( - fail( - Error(repayBorrowError), - FailureInfo.LIQUIDATE_REPAY_BORROW_FRESH_FAILED - ), - 0 - ); - } - - (uint256 amountSeizeError, uint256 seizeTokens) = comptroller - .liquidateCalculateSeizeTokens( - address(this), - address(cTokenCollateral), - actualRepayAmount - ); - require(amountSeizeError == uint256(Error.NO_ERROR), "CT18"); - - require(cTokenCollateral.balanceOf(borrower) >= seizeTokens, "CT19"); - - uint256 seizeError; - if (address(cTokenCollateral) == address(this)) { - seizeError = seizeInternal( - address(this), - liquidator, - borrower, - seizeTokens - ); - } else { - seizeError = cTokenCollateral.seize( - liquidator, - borrower, - seizeTokens - ); - } - - require(seizeError == uint256(Error.NO_ERROR), "CT20"); - - emit LiquidateBorrow( - liquidator, - borrower, - actualRepayAmount, - address(cTokenCollateral), - seizeTokens - ); - - return (uint256(Error.NO_ERROR), actualRepayAmount); - } - - /** - * @notice Transfers collateral tokens (this market) to the liquidator. - * @dev Will fail unless called by another cToken during the process of liquidation. - * Its absolutely critical to use msg.sender as the borrowed cToken and not a parameter. - * @param liquidator The account receiving seized collateral - * @param borrower The account having collateral seized - * @param seizeTokens The number of cTokens to seize - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function seize( - address liquidator, - address borrower, - uint256 seizeTokens - ) external override nonReentrant returns (uint256) { - return seizeInternal(msg.sender, liquidator, borrower, seizeTokens); - } - - struct SeizeVars { - uint256 seizeAmount; - uint256 exchangeRate; - uint256 borrowerTokensNew; - uint256 borrowerAmountNew; - uint256 liquidatorTokensNew; - uint256 liquidatorAmountNew; - uint256 totalCash; - uint256 supplyRate; - } - - /** - * @notice Transfers collateral tokens (this market) to the liquidator. - * @dev Called only during an in-kind liquidation, or by liquidateBorrow during the liquidation of another CToken. - * Its absolutely critical to use msg.sender as the seizer cToken and not a parameter. - * @param seizerToken The contract seizing the collateral (i.e. borrowed cToken) - * @param liquidator The account receiving seized collateral - * @param borrower The account having collateral seized - * @param seizeTokens The number of cTokens to seize - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function seizeInternal( - address seizerToken, - address liquidator, - address borrower, - uint256 seizeTokens - ) internal returns (uint256) { - uint256 allowed = comptroller.seizeAllowed( - address(this), - seizerToken, - liquidator, - borrower, - seizeTokens - ); - if (allowed != 0) { - return - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.LIQUIDATE_SEIZE_COMPTROLLER_REJECTION, - allowed - ); - } - - if (borrower == liquidator) { - return - fail( - Error.INVALID_ACCOUNT_PAIR, - FailureInfo.LIQUIDATE_SEIZE_LIQUIDATOR_IS_BORROWER - ); - } - - SeizeVars memory seizeVars; - - MathError mathErr; - - (mathErr, seizeVars.borrowerTokensNew) = subUInt( - accountTokens[borrower].tokens, - seizeTokens - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.LIQUIDATE_SEIZE_BALANCE_DECREMENT_FAILED, - uint256(mathErr) - ); - } - - seizeVars.totalCash = getCashPrior(); - seizeVars.supplyRate = interestRateModel.getSupplyRate( - seizeVars.totalCash, - totalBorrows, - totalReserves, - reserveFactorMantissa - ); - - (, seizeVars.exchangeRate) = interestRateModel.getExchangeRate( - seizeVars.totalCash, - totalBorrows, - totalReserves, - totalSupply - ); - - if (interestRateModel.isTropykusInterestRateModel()) { - (, seizeVars.exchangeRate) = tropykusExchangeRateStoredInternal( - borrower - ); - } - - (, seizeVars.seizeAmount) = mulUInt( - seizeTokens, - seizeVars.exchangeRate - ); - (, seizeVars.seizeAmount) = divUInt(seizeVars.seizeAmount, 1e18); - - (, seizeVars.borrowerAmountNew) = subUInt( - accountTokens[borrower].underlyingAmount, - seizeVars.seizeAmount - ); - - (mathErr, seizeVars.liquidatorTokensNew) = addUInt( - accountTokens[liquidator].tokens, - seizeTokens - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.LIQUIDATE_SEIZE_BALANCE_INCREMENT_FAILED, - uint256(mathErr) - ); - } - - (, seizeVars.liquidatorAmountNew) = addUInt( - accountTokens[liquidator].underlyingAmount, - seizeVars.seizeAmount - ); - - accountTokens[borrower].tokens = seizeVars.borrowerTokensNew; - accountTokens[borrower].underlyingAmount = seizeVars.borrowerAmountNew; - accountTokens[borrower].suppliedAt = getBlockNumber(); - accountTokens[borrower].promisedSupplyRate = seizeVars.supplyRate; - - accountTokens[liquidator].tokens = seizeVars.liquidatorTokensNew; - accountTokens[liquidator].underlyingAmount = seizeVars - .liquidatorAmountNew; - accountTokens[liquidator].suppliedAt = getBlockNumber(); - accountTokens[liquidator].promisedSupplyRate = seizeVars.supplyRate; - - emit Transfer(borrower, liquidator, seizeTokens); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Begins transfer of admin rights. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer. - * @dev Admin function to begin change of admin. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer. - * @param newPendingAdmin New pending admin. - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setPendingAdmin(address payable newPendingAdmin) - external - override - returns (uint256) - { - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_PENDING_ADMIN_OWNER_CHECK - ); - } - - address oldPendingAdmin = pendingAdmin; - - pendingAdmin = newPendingAdmin; - - emit NewPendingAdmin(oldPendingAdmin, newPendingAdmin); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Accepts transfer of admin rights. msg.sender must be pendingAdmin - * @dev Admin function for pending admin to accept role and update admin - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _acceptAdmin() external override returns (uint256) { - if (msg.sender != pendingAdmin || msg.sender == address(0)) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.ACCEPT_ADMIN_PENDING_ADMIN_CHECK - ); - } - - address oldAdmin = admin; - address oldPendingAdmin = pendingAdmin; - - admin = pendingAdmin; - - pendingAdmin = payable(address(0)); - - emit NewAdmin(oldAdmin, admin); - emit NewPendingAdmin(oldPendingAdmin, pendingAdmin); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Sets a new comptroller for the market - * @dev Admin function to set a new comptroller - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setComptroller(ComptrollerInterface newComptroller) - public - override - returns (uint256) - { - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_COMPTROLLER_OWNER_CHECK - ); - } - - ComptrollerInterface oldComptroller = comptroller; - require(newComptroller.isComptroller(), "CT21"); - - comptroller = newComptroller; - - emit NewComptroller(oldComptroller, newComptroller); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice accrues interest and sets a new reserve factor for the protocol using _setReserveFactorFresh - * @dev Admin function to accrue interest and set a new reserve factor - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setReserveFactor(uint256 newReserveFactorMantissa) - external - override - nonReentrant - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return - fail( - Error(error), - FailureInfo.SET_RESERVE_FACTOR_ACCRUE_INTEREST_FAILED - ); - } - return _setReserveFactorFresh(newReserveFactorMantissa); - } - - /** - * @notice Sets a new reserve factor for the protocol (*requires fresh interest accrual) - * @dev Admin function to set a new reserve factor - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setReserveFactorFresh(uint256 newReserveFactorMantissa) - internal - returns (uint256) - { - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_RESERVE_FACTOR_ADMIN_CHECK - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.SET_RESERVE_FACTOR_FRESH_CHECK - ); - } - - if (newReserveFactorMantissa > reserveFactorMaxMantissa) { - return - fail( - Error.BAD_INPUT, - FailureInfo.SET_RESERVE_FACTOR_BOUNDS_CHECK - ); - } - - uint256 oldReserveFactorMantissa = reserveFactorMantissa; - reserveFactorMantissa = newReserveFactorMantissa; - - emit NewReserveFactor( - oldReserveFactorMantissa, - newReserveFactorMantissa - ); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Accrues interest and reduces reserves by transferring from msg.sender - * @param addAmount Amount of addition to reserves - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _addReservesInternal(uint256 addAmount) - internal - nonReentrant - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return - fail( - Error(error), - FailureInfo.ADD_RESERVES_ACCRUE_INTEREST_FAILED - ); - } - - uint256 totalReservesNew; - uint256 actualAddAmount; - - if (accrualBlockNumber != getBlockNumber()) { - return ( - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.ADD_RESERVES_FRESH_CHECK - ) - ); - } - - actualAddAmount = doTransferIn(msg.sender, addAmount); - - totalReservesNew = totalReserves + actualAddAmount; - - require(totalReservesNew >= totalReserves, "CT22"); - - totalReserves = totalReservesNew; - - emit ReservesAdded(msg.sender, actualAddAmount, totalReservesNew); - - return (uint256(Error.NO_ERROR)); - } - - function _addSubsidyInternal(uint256 addAmount) - internal - nonReentrant - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - // accrueInterest emits logs on errors, but on top of that we want to log the fact that an attempted reduce reserves failed. - return fail(Error(error), FailureInfo.ADD_SUBSIDY_FUND_FAILED); - } - - uint256 subsidyFundNew; - uint256 actualAddAmount; - - if (accrualBlockNumber != getBlockNumber()) { - return ( - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.ADD_SUBSIDY_FUND_FRESH_CHECK - ) - ); - } - - actualAddAmount = doTransferIn(msg.sender, addAmount); - - subsidyFundNew = subsidyFund + actualAddAmount; - - require(subsidyFundNew >= subsidyFund, "CT22"); - - subsidyFund = subsidyFundNew; - - emit SubsidyAdded(msg.sender, actualAddAmount, subsidyFundNew); - - /* Return (NO_ERROR, actualAddAmount) */ - return (uint256(Error.NO_ERROR)); - } - - /** - * @notice Accrues interest and reduces reserves by transferring to admin - * @param reduceAmount Amount of reduction to reserves - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _reduceReserves(uint256 reduceAmount) - external - override - nonReentrant - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return - fail( - Error(error), - FailureInfo.REDUCE_RESERVES_ACCRUE_INTEREST_FAILED - ); - } - return _reduceReservesFresh(reduceAmount); - } - - /** - * @notice Reduces reserves by transferring to admin - * @dev Requires fresh interest accrual - * @param reduceAmount Amount of reduction to reserves - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _reduceReservesFresh(uint256 reduceAmount) - internal - returns (uint256) - { - uint256 totalReservesNew; - - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.REDUCE_RESERVES_ADMIN_CHECK - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.REDUCE_RESERVES_FRESH_CHECK - ); - } - - if (getCashPrior() < reduceAmount) { - return - fail( - Error.TOKEN_INSUFFICIENT_CASH, - FailureInfo.REDUCE_RESERVES_CASH_NOT_AVAILABLE - ); - } - - if (reduceAmount > totalReserves) { - return - fail(Error.BAD_INPUT, FailureInfo.REDUCE_RESERVES_VALIDATION); - } - - totalReservesNew = totalReserves - reduceAmount; - require(totalReservesNew <= totalReserves, "CT23"); - - totalReserves = totalReservesNew; - - doTransferOut(admin, reduceAmount); - - emit ReservesReduced(admin, reduceAmount, totalReservesNew); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice accrues interest and updates the interest rate model using _setInterestRateModelFresh - * @dev Admin function to accrue interest and update the interest rate model - * @param newInterestRateModel the new interest rate model to use - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setInterestRateModel(InterestRateModel newInterestRateModel) - public - override - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return - fail( - Error(error), - FailureInfo.SET_INTEREST_RATE_MODEL_ACCRUE_INTEREST_FAILED - ); - } - return _setInterestRateModelFresh(newInterestRateModel); - } - - /** - * @notice updates the interest rate model (*requires fresh interest accrual) - * @dev Admin function to update the interest rate model - * @param newInterestRateModel the new interest rate model to use - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setInterestRateModelFresh(InterestRateModel newInterestRateModel) - internal - returns (uint256) - { - InterestRateModel oldInterestRateModel; - - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_INTEREST_RATE_MODEL_OWNER_CHECK - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.SET_INTEREST_RATE_MODEL_FRESH_CHECK - ); - } - - oldInterestRateModel = interestRateModel; - - require(newInterestRateModel.isInterestRateModel(), "CT21"); - - interestRateModel = newInterestRateModel; - - emit NewMarketInterestRateModel( - oldInterestRateModel, - newInterestRateModel - ); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Gets balance of this contract in terms of the underlying - * @dev This excludes the value of the current message, if any - * @return The quantity of underlying owned by this contract - */ - function getCashPrior() internal view virtual returns (uint256); - - /** - * @dev Performs a transfer in, reverting upon failure. Returns the amount actually transferred to the protocol, in case of a fee. - * This may revert due to insufficient balance or insufficient allowance. - */ - function doTransferIn(address from, uint256 amount) - internal - virtual - returns (uint256); - - /** - * @dev Performs a transfer out, ideally returning an explanatory error code upon failure tather than reverting. - * If caller has not called checked protocol's balance, may revert due to insufficient cash held in the contract. - * If caller has checked protocol's balance, and verified it is >= amount, this should not revert in normal conditions. - */ - function doTransferOut(address payable to, uint256 amount) internal virtual; - - /** - * @dev Prevents a contract from calling itself, directly or indirectly. - */ - modifier nonReentrant() { - require(_notEntered, "re-entered"); - _notEntered = false; - _; - _notEntered = true; - } -} - - -// Dependency file: contracts/PriceOracle.sol - -// pragma solidity 0.8.6; - -// import "contracts/CToken.sol"; - -abstract contract PriceOracle { - /// @notice Indicator that this is a PriceOracle contract (for inspection) - bool public constant isPriceOracle = true; - - /** - * @notice Get the underlying price of a cToken asset - * @param cToken The cToken to get the underlying price of - * @return The underlying asset price mantissa (scaled by 1e18). - * Zero means the price is unavailable. - */ - function getUnderlyingPrice(CToken cToken) - external - view - virtual - returns (uint256); -} - - -// Dependency file: contracts/PriceOracleAdapter.sol - -// pragma solidity 0.8.6; - -abstract contract PriceOracleAdapter { - /// @notice Event adapter interface updated - event PriceOracleAdapterUpdated(address oldAddress, address newAddress); - - /** - * @notice Get the price - * @return The underlying asset price mantissa (scaled by 1e18). - * Zero means the price is unavailable. - */ - function assetPrices(address cTokenAddress) - external - view - virtual - returns (uint256); -} - - -// Root file: contracts/PriceOracleProxy.sol - -pragma solidity 0.8.6; - -// import "contracts/PriceOracle.sol"; -// import "contracts/PriceOracleAdapter.sol"; - -contract PriceOracleProxy is PriceOracle { - /// @notice Address of the guardian - address public guardian; - /// @notice Address of the pending guardian - address public pendingGuardian; - /// @notice Mapping of the cTokenAddress => adapterAddress - mapping(address => address) public tokenAdapter; - ///@notice Emitted when pendingGuardian is changed - event NewPendingGuardian( - address oldPendingGuardian, - address newPendingGuardian - ); - ///@notice Emitted when pendingGuardian is accepted, which means gaurdian is updated - event NewGuardian(address oldGuardian, address newGuardian); - /// @notice Struct of the cTokensDetail - struct CtokenDetail { - address cToken; - string cTokenName; - } - - /// @notice Array of cTokensDetail - CtokenDetail[] public cTokensArray; - - /** - * @notice Get the length of cTokensArray - * @return The length of cTokensArray - */ - function cTokenArrayCount() public view returns (uint256) { - return cTokensArray.length; - } - - /// @param guardian_ The address of the guardian, which may set the - constructor(address guardian_) { - guardian = guardian_; - } - - /** - * @notice Get the underlying price of a listed cToken asset - * @param cToken The cToken to get the underlying price of - * @return The underlying asset price mantissa (scaled by 1e18) - */ - function getUnderlyingPrice(CToken cToken) - public - view - virtual - override - returns (uint256) - { - address oracleAdapter = tokenAdapter[address(cToken)]; - //validate mapping - if (oracleAdapter == address(0)) { - return 0; - } - return PriceOracleAdapter(oracleAdapter).assetPrices(address(cToken)); - } - - /** - * @notice Set the underlying price of a listed cToken asset - * @param addressToken Address of the cToken - * @param addressAdapter Address of the OracleAdapter - */ - function setAdapterToToken(address addressToken, address addressAdapter) - public - { - //validate only guardian can set - require( - msg.sender == guardian, - "PriceOracleProxy: only guardian may set the address" - ); - require( - addressToken != address(0), - "PriceOracleProxy: address token can not be 0" - ); - require( - addressAdapter != address(0), - "PriceOracleProxy: address adapter can not be 0" - ); - //validate and set new cToken in CtokenDetail - if (tokenAdapter[addressToken] == address(0)) { - CtokenDetail memory _cTokenD = CtokenDetail({ - cToken: addressToken, - cTokenName: CToken(addressToken).symbol() - }); - - cTokensArray.push(_cTokenD); - } - //set token => adapter - tokenAdapter[addressToken] = addressAdapter; - } - - /** - * @notice Begins transfer of gaurdian rights. The newPendingGaurdian must call `_acceptAdmin` to finalize the transfer. - * @param newPendingGuardian New pending gaurdian. - */ - function _setPendingAdmin(address newPendingGuardian) public { - // Check caller = gaurdian - require( - msg.sender == guardian, - "PriceOracleProxy: only guardian may set the address" - ); - require( - newPendingGuardian != address(0), - "PriceOracleProxy: address admin can not be 0" - ); - // Save current value, if any, for inclusion in log - address oldPendingGuardian = guardian; - // Store pendingGaurdian with value newPendingGaurdian - pendingGuardian = newPendingGuardian; - // Emit NewPendingGaurdian(oldPendingGaurdian, newPendingGaurdian) - emit NewPendingGuardian(oldPendingGuardian, newPendingGuardian); - } - - /// @notice Accepts transfer of gaurdian rights. msg.sender must be pendingGaurdian - function _acceptAdmin() public { - // Check caller is pendingGaurdian and pendingGaurdian ≠ address(0) - require( - msg.sender == pendingGuardian, - "PriceOracleProxy: only guardian may set the address" - ); - require( - msg.sender != address(0), - "PriceOracleProxy: sender can not be 0" - ); - - // Save current values for inclusion in log - address oldGuardian = guardian; - address oldPendingGaurdian = pendingGuardian; - - // Store gaurdian with value pendingGaurdian - guardian = pendingGuardian; - - // Clear the pending value - pendingGuardian = address(0); - - emit NewGuardian(oldGuardian, guardian); - emit NewPendingGuardian(oldPendingGaurdian, pendingGuardian); - } -} diff --git a/flatten/Reservoir.sol b/flatten/Reservoir.sol deleted file mode 100644 index 14453af..0000000 --- a/flatten/Reservoir.sol +++ /dev/null @@ -1,205 +0,0 @@ -// Dependency file: contracts/EIP20Interface.sol - -// SPDX-License-Identifier: UNLICENSED -// pragma solidity 0.8.6; - -/** - * @title ERC 20 Token Standard Interface - * https://eips.ethereum.org/EIPS/eip-20 - */ -interface EIP20Interface { - function name() external view returns (string memory); - - function symbol() external view returns (string memory); - - function decimals() external view returns (uint8); - - /** - * @notice Get the total number of tokens in circulation - * @return The supply of tokens - */ - function totalSupply() external view returns (uint256); - - /** - * @notice Gets the balance of the specified address - * @param owner The address from which the balance will be retrieved - * @return balance The balance - */ - function balanceOf(address owner) external view returns (uint256 balance); - - /** - * @notice Transfer `amount` tokens from `msg.sender` to `dst` - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - * @return success Whether or not the transfer succeeded - */ - function transfer(address dst, uint256 amount) - external - returns (bool success); - - /** - * @notice Transfer `amount` tokens from `src` to `dst` - * @param src The address of the source account - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - * @return success Whether or not the transfer succeeded - */ - function transferFrom( - address src, - address dst, - uint256 amount - ) external returns (bool success); - - /** - * @notice Approve `spender` to transfer up to `amount` from `src` - * @dev This will overwrite the approval amount for `spender` - * and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve) - * @param spender The address of the account which may transfer tokens - * @param amount The number of tokens that are approved (-1 means infinite) - * @return success Whether or not the approval succeeded - */ - function approve(address spender, uint256 amount) - external - returns (bool success); - - /** - * @notice Get the current allowance from `owner` for `spender` - * @param owner The address of the account which owns the tokens to be spent - * @param spender The address of the account which may transfer tokens - * @return remaining The number of tokens allowed to be spent (-1 means infinite) - */ - function allowance(address owner, address spender) - external - view - returns (uint256 remaining); - - event Transfer(address indexed from, address indexed to, uint256 amount); - event Approval( - address indexed owner, - address indexed spender, - uint256 amount - ); -} - - -// Root file: contracts/Reservoir.sol - -pragma solidity 0.8.6; - -/** - * @title Reservoir Contract - * @notice Distributes a token to a different contract at a fixed rate. - * @dev This contract must be poked via the `drip()` function every so often. - * @author tropykus - */ -contract Reservoir { - /// @notice The block number when the Reservoir started (immutable) - uint256 public dripStart; - - /// @notice Tokens per block that to drip to target (immutable) - uint256 public dripRate; - - /// @notice Reference to token to drip (immutable) - EIP20Interface public token; - - /// @notice Target to receive dripped tokens (immutable) - address public target; - - /// @notice Amount that has already been dripped - uint256 public dripped; - - /** - * @notice Constructs a Reservoir - * @param dripRate_ Numer of tokens per block to drip - * @param token_ The token to drip - * @param target_ The recipient of dripped tokens - */ - constructor( - uint256 dripRate_, - EIP20Interface token_, - address target_ - ) { - dripStart = block.number; - dripRate = dripRate_; - token = token_; - target = target_; - dripped = 0; - } - - /** - * @notice Drips the maximum amount of tokens to match the drip rate since inception - * @dev Note: this will only drip up to the amount of tokens available. - * @return The amount of tokens dripped in this call - */ - function drip() public returns (uint256) { - // First, read storage into memory - EIP20Interface token_ = token; - uint256 reservoirBalance_ = token_.balanceOf(address(this)); // TODO: Verify this is a static call - uint256 dripRate_ = dripRate; - uint256 dripStart_ = dripStart; - uint256 dripped_ = dripped; - address target_ = target; - uint256 blockNumber_ = block.number; - - // Next, calculate intermediate values - uint256 dripTotal_ = mul( - dripRate_, - blockNumber_ - dripStart_, - "dripTotal overflow" - ); - uint256 deltaDrip_ = sub(dripTotal_, dripped_, "deltaDrip underflow"); - uint256 toDrip_ = min(reservoirBalance_, deltaDrip_); - uint256 drippedNext_ = add(dripped_, toDrip_, "tautological"); - - // Finally, write new `dripped` value and transfer tokens to target - dripped = drippedNext_; - token_.transfer(target_, toDrip_); - - return toDrip_; - } - - /* Internal helper functions for safe math */ - - function add( - uint256 a, - uint256 b, - string memory errorMessage - ) internal pure returns (uint256) { - uint256 c = a + b; - require(c >= a, errorMessage); - return c; - } - - function sub( - uint256 a, - uint256 b, - string memory errorMessage - ) internal pure returns (uint256) { - require(b <= a, errorMessage); - uint256 c = a - b; - return c; - } - - function mul( - uint256 a, - uint256 b, - string memory errorMessage - ) internal pure returns (uint256) { - if (a == 0) { - return 0; - } - uint256 c = a * b; - require(c / a == b, errorMessage); - return c; - } - - function min(uint256 a, uint256 b) internal pure returns (uint256) { - if (a <= b) { - return a; - } else { - return b; - } - } -} - -// import "contracts/EIP20Interface.sol"; diff --git a/flatten/SafeMath.sol b/flatten/SafeMath.sol deleted file mode 100644 index f5fecb4..0000000 --- a/flatten/SafeMath.sol +++ /dev/null @@ -1,189 +0,0 @@ -// Root file: contracts/SafeMath.sol - -// SPDX-License-Identifier: UNLICENSED -pragma solidity 0.8.6; - -// From https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/math/Math.sol -// Subject to the MIT license. - -/** - * @dev Wrappers over Solidity's arithmetic operations with added overflow - * checks. - * - * Arithmetic operations in Solidity wrap on overflow. This can easily result - * in bugs, because programmers usually assume that an overflow raises an - * error, which is the standard behavior in high level programming languages. - * `SafeMath` restores this intuition by reverting the transaction when an - * operation overflows. - * - * Using this library instead of the unchecked operations eliminates an entire - * class of bugs, so it's recommended to use it always. - */ -library SafeMath { - /** - * @dev Returns the addition of two unsigned integers, reverting on overflow. - * - * Counterpart to Solidity's `+` operator. - * - * Requirements: - * - Addition cannot overflow. - */ - function add(uint256 a, uint256 b) internal pure returns (uint256) { - uint256 c = a + b; - require(c >= a, "SafeMath: addition overflow"); - - return c; - } - - /** - * @dev Returns the addition of two unsigned integers, reverting with custom message on overflow. - * - * Counterpart to Solidity's `+` operator. - * - * Requirements: - * - Addition cannot overflow. - */ - function add(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - uint256 c = a + b; - require(c >= a, errorMessage); - - return c; - } - - /** - * @dev Returns the subtraction of two unsigned integers, reverting on underflow (when the result is negative). - * - * Counterpart to Solidity's `-` operator. - * - * Requirements: - * - Subtraction cannot underflow. - */ - function sub(uint256 a, uint256 b) internal pure returns (uint256) { - return sub(a, b, "SafeMath: subtraction underflow"); - } - - /** - * @dev Returns the subtraction of two unsigned integers, reverting with custom message on underflow (when the result is negative). - * - * Counterpart to Solidity's `-` operator. - * - * Requirements: - * - Subtraction cannot underflow. - */ - function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - require(b <= a, errorMessage); - uint256 c = a - b; - - return c; - } - - /** - * @dev Returns the multiplication of two unsigned integers, reverting on overflow. - * - * Counterpart to Solidity's `*` operator. - * - * Requirements: - * - Multiplication cannot overflow. - */ - function mul(uint256 a, uint256 b) internal pure returns (uint256) { - // Gas optimization: this is cheaper than requiring 'a' not being zero, but the - // benefit is lost if 'b' is also tested. - // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 - if (a == 0) { - return 0; - } - - uint256 c = a * b; - require(c / a == b, "SafeMath: multiplication overflow"); - - return c; - } - - /** - * @dev Returns the multiplication of two unsigned integers, reverting on overflow. - * - * Counterpart to Solidity's `*` operator. - * - * Requirements: - * - Multiplication cannot overflow. - */ - function mul(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - // Gas optimization: this is cheaper than requiring 'a' not being zero, but the - // benefit is lost if 'b' is also tested. - // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 - if (a == 0) { - return 0; - } - - uint256 c = a * b; - require(c / a == b, errorMessage); - - return c; - } - - /** - * @dev Returns the integer division of two unsigned integers. - * Reverts on division by zero. The result is rounded towards zero. - * - * Counterpart to Solidity's `/` operator. Note: this function uses a - * `revert` opcode (which leaves remaining gas untouched) while Solidity - * uses an invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function div(uint256 a, uint256 b) internal pure returns (uint256) { - return div(a, b, "SafeMath: division by zero"); - } - - /** - * @dev Returns the integer division of two unsigned integers. - * Reverts with custom message on division by zero. The result is rounded towards zero. - * - * Counterpart to Solidity's `/` operator. Note: this function uses a - * `revert` opcode (which leaves remaining gas untouched) while Solidity - * uses an invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - // Solidity only automatically asserts when dividing by 0 - require(b > 0, errorMessage); - uint256 c = a / b; - // assert(a == b * c + a % b); // There is no case in which this doesn't hold - - return c; - } - - /** - * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), - * Reverts when dividing by zero. - * - * Counterpart to Solidity's `%` operator. This function uses a `revert` - * opcode (which leaves remaining gas untouched) while Solidity uses an - * invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function mod(uint256 a, uint256 b) internal pure returns (uint256) { - return mod(a, b, "SafeMath: modulo by zero"); - } - - /** - * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), - * Reverts with custom message when dividing by zero. - * - * Counterpart to Solidity's `%` operator. This function uses a `revert` - * opcode (which leaves remaining gas untouched) while Solidity uses an - * invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - require(b != 0, errorMessage); - return a % b; - } -} diff --git a/flatten/SignedSafeMath.sol b/flatten/SignedSafeMath.sol deleted file mode 100644 index 872be27..0000000 --- a/flatten/SignedSafeMath.sol +++ /dev/null @@ -1,68 +0,0 @@ -// Root file: contracts/SignedSafeMath.sol - -// SPDX-License-Identifier: MIT -pragma solidity 0.8.6; - -/** - * @dev Wrappers over Solidity's arithmetic operations. - * - * NOTE: `SignedSafeMath` is no longer needed starting with Solidity 0.8. The compiler - * now has built in overflow checking. - */ -library SignedSafeMath { - /** - * @dev Returns the multiplication of two signed integers, reverting on - * overflow. - * - * Counterpart to Solidity's `*` operator. - * - * Requirements: - * - * - Multiplication cannot overflow. - */ - function mul(int256 a, int256 b) internal pure returns (int256) { - return a * b; - } - - /** - * @dev Returns the integer division of two signed integers. Reverts on - * division by zero. The result is rounded towards zero. - * - * Counterpart to Solidity's `/` operator. - * - * Requirements: - * - * - The divisor cannot be zero. - */ - function div(int256 a, int256 b) internal pure returns (int256) { - return a / b; - } - - /** - * @dev Returns the subtraction of two signed integers, reverting on - * overflow. - * - * Counterpart to Solidity's `-` operator. - * - * Requirements: - * - * - Subtraction cannot overflow. - */ - function sub(int256 a, int256 b) internal pure returns (int256) { - return a - b; - } - - /** - * @dev Returns the addition of two signed integers, reverting on - * overflow. - * - * Counterpart to Solidity's `+` operator. - * - * Requirements: - * - * - Addition cannot overflow. - */ - function add(int256 a, int256 b) internal pure returns (int256) { - return a + b; - } -} diff --git a/flatten/SimplePriceOracle.sol b/flatten/SimplePriceOracle.sol deleted file mode 100644 index 82fd3b4..0000000 --- a/flatten/SimplePriceOracle.sol +++ /dev/null @@ -1,4254 +0,0 @@ -// Dependency file: contracts/ComptrollerInterface.sol - -// SPDX-License-Identifier: UNLICENSED -// pragma solidity 0.8.6; - -abstract contract ComptrollerInterface { - /// @notice Indicator that this is a Comptroller contract (for inspection) - bool public constant isComptroller = true; - - /*** Assets You Are In ***/ - - function enterMarkets(address[] calldata cTokens) - external - virtual - returns (uint256[] memory); - - function exitMarket(address cToken) external virtual returns (uint256); - - /*** Policy Hooks ***/ - - function mintAllowed( - address cToken, - address minter, - uint256 mintAmount - ) external virtual returns (uint256); - - function mintVerify( - address cToken, - address minter, - uint256 mintAmount, - uint256 mintTokens - ) external virtual; - - function redeemAllowed( - address cToken, - address redeemer, - uint256 redeemTokens - ) external virtual returns (uint256); - - function redeemVerify( - address cToken, - address redeemer, - uint256 redeemAmount, - uint256 redeemTokens - ) external virtual; - - function borrowAllowed( - address cToken, - address borrower, - uint256 borrowAmount - ) external virtual returns (uint256); - - function borrowVerify( - address cToken, - address borrower, - uint256 borrowAmount - ) external virtual; - - function repayBorrowAllowed( - address cToken, - address payer, - address borrower, - uint256 repayAmount - ) external virtual returns (uint256); - - function repayBorrowVerify( - address cToken, - address payer, - address borrower, - uint256 repayAmount, - uint256 borrowerIndex - ) external virtual; - - function liquidateBorrowAllowed( - address cTokenBorrowed, - address cTokenCollateral, - address liquidator, - address borrower, - uint256 repayAmount - ) external virtual returns (uint256); - - function liquidateBorrowVerify( - address cTokenBorrowed, - address cTokenCollateral, - address liquidator, - address borrower, - uint256 repayAmount, - uint256 seizeTokens - ) external virtual; - - function seizeAllowed( - address cTokenCollateral, - address cTokenBorrowed, - address liquidator, - address borrower, - uint256 seizeTokens - ) external virtual returns (uint256); - - function seizeVerify( - address cTokenCollateral, - address cTokenBorrowed, - address liquidator, - address borrower, - uint256 seizeTokens - ) external virtual; - - function transferAllowed( - address cToken, - address src, - address dst, - uint256 transferTokens - ) external virtual returns (uint256); - - function transferVerify( - address cToken, - address src, - address dst, - uint256 transferTokens - ) external virtual; - - /*** Liquidity/Liquidation Calculations ***/ - - function liquidateCalculateSeizeTokens( - address cTokenBorrowed, - address cTokenCollateral, - uint256 repayAmount - ) external view virtual returns (uint256, uint256); -} - - -// Dependency file: contracts/CarefulMath.sol - -// pragma solidity 0.8.6; - -/** - * @title Careful Math - * @author tropykus - * @notice Derived from OpenZeppelin's SafeMath library - * https://github.com/OpenZeppelin/openzeppelin-solidity/blob/master/contracts/math/SafeMath.sol - */ -contract CarefulMath { - - /** - * @dev Possible error codes that we can return - */ - enum MathError { - NO_ERROR, - DIVISION_BY_ZERO, - INTEGER_OVERFLOW, - INTEGER_UNDERFLOW - } - - /** - * @dev Multiplies two numbers, returns an error on overflow. - */ - function mulUInt(uint a, uint b) internal pure returns (MathError, uint) { - if (a == 0) { - return (MathError.NO_ERROR, 0); - } - - uint c = a * b; - - if (c / a != b) { - return (MathError.INTEGER_OVERFLOW, 0); - } else { - return (MathError.NO_ERROR, c); - } - } - - /** - * @dev Integer division of two numbers, truncating the quotient. - */ - function divUInt(uint a, uint b) internal pure returns (MathError, uint) { - if (b == 0) { - return (MathError.DIVISION_BY_ZERO, 0); - } - - return (MathError.NO_ERROR, a / b); - } - - /** - * @dev Subtracts two numbers, returns an error on overflow (i.e. if subtrahend is greater than minuend). - */ - function subUInt(uint a, uint b) internal pure returns (MathError, uint) { - if (b <= a) { - return (MathError.NO_ERROR, a - b); - } else { - return (MathError.INTEGER_UNDERFLOW, 0); - } - } - - /** - * @dev Adds two numbers, returns an error on overflow. - */ - function addUInt(uint a, uint b) internal pure returns (MathError, uint) { - uint c = a + b; - - if (c >= a) { - return (MathError.NO_ERROR, c); - } else { - return (MathError.INTEGER_OVERFLOW, 0); - } - } - - /** - * @dev add a and b and then subtract c - */ - function addThenSubUInt(uint a, uint b, uint c) internal pure returns (MathError, uint) { - (MathError err0, uint sum) = addUInt(a, b); - - if (err0 != MathError.NO_ERROR) { - return (err0, 0); - } - - return subUInt(sum, c); - } -} - - -// Dependency file: contracts/ExponentialNoError.sol - -// pragma solidity 0.8.6; - -/** - * @title Exponential module for storing fixed-precision decimals - * @author tropykus - * @notice Exp is a struct which stores decimals with a fixed precision of 18 decimal places. - * Thus, if we wanted to store the 5.1, mantissa would store 5.1e18. That is: - * `Exp({mantissa: 5100000000000000000})`. - */ -contract ExponentialNoError { - uint constant expScale = 1e18; - uint constant doubleScale = 1e36; - uint constant halfExpScale = expScale/2; - uint constant mantissaOne = expScale; - - struct Exp { - uint mantissa; - } - - struct Double { - uint mantissa; - } - - /** - * @dev Truncates the given exp to a whole number value. - * For example, truncate(Exp{mantissa: 15 * expScale}) = 15 - */ - function truncate(Exp memory exp) pure internal returns (uint) { - // Note: We are not using careful math here as we're performing a division that cannot fail - return exp.mantissa / expScale; - } - - /** - * @dev Multiply an Exp by a scalar, then truncate to return an unsigned integer. - */ - function mul_ScalarTruncate(Exp memory a, uint scalar) pure internal returns (uint) { - Exp memory product = mul_(a, scalar); - return truncate(product); - } - - /** - * @dev Multiply an Exp by a scalar, truncate, then add an to an unsigned integer, returning an unsigned integer. - */ - function mul_ScalarTruncateAddUInt(Exp memory a, uint scalar, uint addend) pure internal returns (uint) { - Exp memory product = mul_(a, scalar); - return add_(truncate(product), addend); - } - - /** - * @dev Checks if first Exp is less than second Exp. - */ - function lessThanExp(Exp memory left, Exp memory right) pure internal returns (bool) { - return left.mantissa < right.mantissa; - } - - /** - * @dev Checks if left Exp <= right Exp. - */ - function lessThanOrEqualExp(Exp memory left, Exp memory right) pure internal returns (bool) { - return left.mantissa <= right.mantissa; - } - - /** - * @dev Checks if left Exp > right Exp. - */ - function greaterThanExp(Exp memory left, Exp memory right) pure internal returns (bool) { - return left.mantissa > right.mantissa; - } - - /** - * @dev returns true if Exp is exactly zero - */ - function isZeroExp(Exp memory value) pure internal returns (bool) { - return value.mantissa == 0; - } - - function safe224(uint n, string memory errorMessage) pure internal returns (uint224) { - require(n < 2**224, errorMessage); - return uint224(n); - } - - function safe32(uint n, string memory errorMessage) pure internal returns (uint32) { - require(n < 2**32, errorMessage); - return uint32(n); - } - - function add_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { - return Exp({mantissa: add_(a.mantissa, b.mantissa)}); - } - - function add_(Double memory a, Double memory b) pure internal returns (Double memory) { - return Double({mantissa: add_(a.mantissa, b.mantissa)}); - } - - function add_(uint a, uint b) pure internal returns (uint) { - return add_(a, b, "addition overflow"); - } - - function add_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { - uint c = a + b; - require(c >= a, errorMessage); - return c; - } - - function sub_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { - return Exp({mantissa: sub_(a.mantissa, b.mantissa)}); - } - - function sub_(Double memory a, Double memory b) pure internal returns (Double memory) { - return Double({mantissa: sub_(a.mantissa, b.mantissa)}); - } - - function sub_(uint a, uint b) pure internal returns (uint) { - return sub_(a, b, "subtraction underflow"); - } - - function sub_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { - require(b <= a, errorMessage); - return a - b; - } - - function mul_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { - return Exp({mantissa: mul_(a.mantissa, b.mantissa) / expScale}); - } - - function mul_(Exp memory a, uint b) pure internal returns (Exp memory) { - return Exp({mantissa: mul_(a.mantissa, b)}); - } - - function mul_(uint a, Exp memory b) pure internal returns (uint) { - return mul_(a, b.mantissa) / expScale; - } - - function mul_(Double memory a, Double memory b) pure internal returns (Double memory) { - return Double({mantissa: mul_(a.mantissa, b.mantissa) / doubleScale}); - } - - function mul_(Double memory a, uint b) pure internal returns (Double memory) { - return Double({mantissa: mul_(a.mantissa, b)}); - } - - function mul_(uint a, Double memory b) pure internal returns (uint) { - return mul_(a, b.mantissa) / doubleScale; - } - - function mul_(uint a, uint b) pure internal returns (uint) { - return mul_(a, b, "multiplication overflow"); - } - - function mul_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { - if (a == 0 || b == 0) { - return 0; - } - uint c = a * b; - require(c / a == b, errorMessage); - return c; - } - - function div_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { - return Exp({mantissa: div_(mul_(a.mantissa, expScale), b.mantissa)}); - } - - function div_(Exp memory a, uint b) pure internal returns (Exp memory) { - return Exp({mantissa: div_(a.mantissa, b)}); - } - - function div_(uint a, Exp memory b) pure internal returns (uint) { - return div_(mul_(a, expScale), b.mantissa); - } - - function div_(Double memory a, Double memory b) pure internal returns (Double memory) { - return Double({mantissa: div_(mul_(a.mantissa, doubleScale), b.mantissa)}); - } - - function div_(Double memory a, uint b) pure internal returns (Double memory) { - return Double({mantissa: div_(a.mantissa, b)}); - } - - function div_(uint a, Double memory b) pure internal returns (uint) { - return div_(mul_(a, doubleScale), b.mantissa); - } - - function div_(uint a, uint b) pure internal returns (uint) { - return div_(a, b, "divide by zero"); - } - - function div_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { - require(b > 0, errorMessage); - return a / b; - } - - function fraction(uint a, uint b) pure internal returns (Double memory) { - return Double({mantissa: div_(mul_(a, doubleScale), b)}); - } -} - - -// Dependency file: contracts/Exponential.sol - -// pragma solidity 0.8.6; - -// import "contracts/CarefulMath.sol"; -// import "contracts/ExponentialNoError.sol"; - -/** - * @title Exponential module for storing fixed-precision decimals - * @author tropykus - * @dev Legacy contract for compatibility reasons with existing contracts that still use MathError - * @notice Exp is a struct which stores decimals with a fixed precision of 18 decimal places. - * Thus, if we wanted to store the 5.1, mantissa would store 5.1e18. That is: - * `Exp({mantissa: 5100000000000000000})`. - */ -contract Exponential is CarefulMath, ExponentialNoError { - /** - * @dev Creates an exponential from numerator and denominator values. - * Note: Returns an error if (`num` * 10e18) > MAX_INT, - * or if `denom` is zero. - */ - function getExp(uint num, uint denom) internal pure returns (MathError, Exp memory) { - (MathError err0, uint scaledNumerator) = mulUInt(num, expScale); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - - (MathError err1, uint rational) = divUInt(scaledNumerator, denom); - if (err1 != MathError.NO_ERROR) { - return (err1, Exp({mantissa: 0})); - } - - return (MathError.NO_ERROR, Exp({mantissa: rational})); - } - - /** - * @dev Adds two exponentials, returning a new exponential. - */ - function addExp(Exp memory a, Exp memory b) internal pure returns (MathError, Exp memory) { - (MathError error, uint result) = addUInt(a.mantissa, b.mantissa); - - return (error, Exp({mantissa: result})); - } - - /** - * @dev Subtracts two exponentials, returning a new exponential. - */ - function subExp(Exp memory a, Exp memory b) internal pure returns (MathError, Exp memory) { - (MathError error, uint result) = subUInt(a.mantissa, b.mantissa); - - return (error, Exp({mantissa: result})); - } - - /** - * @dev Multiply an Exp by a scalar, returning a new Exp. - */ - function mulScalar(Exp memory a, uint scalar) internal pure returns (MathError, Exp memory) { - (MathError err0, uint scaledMantissa) = mulUInt(a.mantissa, scalar); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - - return (MathError.NO_ERROR, Exp({mantissa: scaledMantissa})); - } - - /** - * @dev Multiply an Exp by a scalar, then truncate to return an unsigned integer. - */ - function mulScalarTruncate(Exp memory a, uint scalar) internal pure returns (MathError, uint) { - (MathError err, Exp memory product) = mulScalar(a, scalar); - if (err != MathError.NO_ERROR) { - return (err, 0); - } - - return (MathError.NO_ERROR, truncate(product)); - } - - /** - * @dev Multiply an Exp by a scalar, truncate, then add an to an unsigned integer, returning an unsigned integer. - */ - function mulScalarTruncateAddUInt(Exp memory a, uint scalar, uint addend) internal pure returns (MathError, uint) { - (MathError err, Exp memory product) = mulScalar(a, scalar); - if (err != MathError.NO_ERROR) { - return (err, 0); - } - - return addUInt(truncate(product), addend); - } - - /** - * @dev Divide an Exp by a scalar, returning a new Exp. - */ - function divScalar(Exp memory a, uint scalar) internal pure returns (MathError, Exp memory) { - (MathError err0, uint descaledMantissa) = divUInt(a.mantissa, scalar); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - - return (MathError.NO_ERROR, Exp({mantissa: descaledMantissa})); - } - - /** - * @dev Divide a scalar by an Exp, returning a new Exp. - */ - function divScalarByExp(uint scalar, Exp memory divisor) internal pure returns (MathError, Exp memory) { - /* - We are doing this as: - getExp(mulUInt(expScale, scalar), divisor.mantissa) - - How it works: - Exp = a / b; - Scalar = s; - `s / (a / b)` = `b * s / a` and since for an Exp `a = mantissa, b = expScale` - */ - (MathError err0, uint numerator) = mulUInt(expScale, scalar); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - return getExp(numerator, divisor.mantissa); - } - - /** - * @dev Divide a scalar by an Exp, then truncate to return an unsigned integer. - */ - function divScalarByExpTruncate(uint scalar, Exp memory divisor) internal pure returns (MathError, uint) { - (MathError err, Exp memory fraction) = divScalarByExp(scalar, divisor); - if (err != MathError.NO_ERROR) { - return (err, 0); - } - - return (MathError.NO_ERROR, truncate(fraction)); - } - - /** - * @dev Multiplies two exponentials, returning a new exponential. - */ - function mulExp(Exp memory a, Exp memory b) internal pure returns (MathError, Exp memory) { - - (MathError err0, uint doubleScaledProduct) = mulUInt(a.mantissa, b.mantissa); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - - // We add half the scale before dividing so that we get rounding instead of truncation. - // See "Listing 6" and text above it at https://accu.org/index.php/journals/1717 - // Without this change, a result like 6.6...e-19 will be truncated to 0 instead of being rounded to 1e-18. - (MathError err1, uint doubleScaledProductWithHalfScale) = addUInt(halfExpScale, doubleScaledProduct); - if (err1 != MathError.NO_ERROR) { - return (err1, Exp({mantissa: 0})); - } - - (MathError err2, uint product) = divUInt(doubleScaledProductWithHalfScale, expScale); - // The only error `div` can return is MathError.DIVISION_BY_ZERO but we control `expScale` and it is not zero. - assert(err2 == MathError.NO_ERROR); - - return (MathError.NO_ERROR, Exp({mantissa: product})); - } - - /** - * @dev Multiplies two exponentials given their mantissas, returning a new exponential. - */ - function mulExp(uint a, uint b) internal pure returns (MathError, Exp memory) { - return mulExp(Exp({mantissa: a}), Exp({mantissa: b})); - } - - /** - * @dev Multiplies three exponentials, returning a new exponential. - */ - function mulExp3(Exp memory a, Exp memory b, Exp memory c) internal pure returns (MathError, Exp memory) { - (MathError err, Exp memory ab) = mulExp(a, b); - if (err != MathError.NO_ERROR) { - return (err, ab); - } - return mulExp(ab, c); - } - - /** - * @dev Divides two exponentials, returning a new exponential. - * (a/scale) / (b/scale) = (a/scale) * (scale/b) = a/b, - * which we can scale as an Exp by calling getExp(a.mantissa, b.mantissa) - */ - function divExp(Exp memory a, Exp memory b) internal pure returns (MathError, Exp memory) { - return getExp(a.mantissa, b.mantissa); - } -} - - -// Dependency file: contracts/SafeMath.sol - -// pragma solidity 0.8.6; - -// From https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/math/Math.sol -// Subject to the MIT license. - -/** - * @dev Wrappers over Solidity's arithmetic operations with added overflow - * checks. - * - * Arithmetic operations in Solidity wrap on overflow. This can easily result - * in bugs, because programmers usually assume that an overflow raises an - * error, which is the standard behavior in high level programming languages. - * `SafeMath` restores this intuition by reverting the transaction when an - * operation overflows. - * - * Using this library instead of the unchecked operations eliminates an entire - * class of bugs, so it's recommended to use it always. - */ -library SafeMath { - /** - * @dev Returns the addition of two unsigned integers, reverting on overflow. - * - * Counterpart to Solidity's `+` operator. - * - * Requirements: - * - Addition cannot overflow. - */ - function add(uint256 a, uint256 b) internal pure returns (uint256) { - uint256 c = a + b; - require(c >= a, "SafeMath: addition overflow"); - - return c; - } - - /** - * @dev Returns the addition of two unsigned integers, reverting with custom message on overflow. - * - * Counterpart to Solidity's `+` operator. - * - * Requirements: - * - Addition cannot overflow. - */ - function add(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - uint256 c = a + b; - require(c >= a, errorMessage); - - return c; - } - - /** - * @dev Returns the subtraction of two unsigned integers, reverting on underflow (when the result is negative). - * - * Counterpart to Solidity's `-` operator. - * - * Requirements: - * - Subtraction cannot underflow. - */ - function sub(uint256 a, uint256 b) internal pure returns (uint256) { - return sub(a, b, "SafeMath: subtraction underflow"); - } - - /** - * @dev Returns the subtraction of two unsigned integers, reverting with custom message on underflow (when the result is negative). - * - * Counterpart to Solidity's `-` operator. - * - * Requirements: - * - Subtraction cannot underflow. - */ - function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - require(b <= a, errorMessage); - uint256 c = a - b; - - return c; - } - - /** - * @dev Returns the multiplication of two unsigned integers, reverting on overflow. - * - * Counterpart to Solidity's `*` operator. - * - * Requirements: - * - Multiplication cannot overflow. - */ - function mul(uint256 a, uint256 b) internal pure returns (uint256) { - // Gas optimization: this is cheaper than requiring 'a' not being zero, but the - // benefit is lost if 'b' is also tested. - // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 - if (a == 0) { - return 0; - } - - uint256 c = a * b; - require(c / a == b, "SafeMath: multiplication overflow"); - - return c; - } - - /** - * @dev Returns the multiplication of two unsigned integers, reverting on overflow. - * - * Counterpart to Solidity's `*` operator. - * - * Requirements: - * - Multiplication cannot overflow. - */ - function mul(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - // Gas optimization: this is cheaper than requiring 'a' not being zero, but the - // benefit is lost if 'b' is also tested. - // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 - if (a == 0) { - return 0; - } - - uint256 c = a * b; - require(c / a == b, errorMessage); - - return c; - } - - /** - * @dev Returns the integer division of two unsigned integers. - * Reverts on division by zero. The result is rounded towards zero. - * - * Counterpart to Solidity's `/` operator. Note: this function uses a - * `revert` opcode (which leaves remaining gas untouched) while Solidity - * uses an invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function div(uint256 a, uint256 b) internal pure returns (uint256) { - return div(a, b, "SafeMath: division by zero"); - } - - /** - * @dev Returns the integer division of two unsigned integers. - * Reverts with custom message on division by zero. The result is rounded towards zero. - * - * Counterpart to Solidity's `/` operator. Note: this function uses a - * `revert` opcode (which leaves remaining gas untouched) while Solidity - * uses an invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - // Solidity only automatically asserts when dividing by 0 - require(b > 0, errorMessage); - uint256 c = a / b; - // assert(a == b * c + a % b); // There is no case in which this doesn't hold - - return c; - } - - /** - * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), - * Reverts when dividing by zero. - * - * Counterpart to Solidity's `%` operator. This function uses a `revert` - * opcode (which leaves remaining gas untouched) while Solidity uses an - * invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function mod(uint256 a, uint256 b) internal pure returns (uint256) { - return mod(a, b, "SafeMath: modulo by zero"); - } - - /** - * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), - * Reverts with custom message when dividing by zero. - * - * Counterpart to Solidity's `%` operator. This function uses a `revert` - * opcode (which leaves remaining gas untouched) while Solidity uses an - * invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - require(b != 0, errorMessage); - return a % b; - } -} - - -// Dependency file: contracts/InterestRateModel.sol - -// pragma solidity 0.8.6; - -// import "contracts/Exponential.sol"; -// import "contracts/SafeMath.sol"; - -/** - * @title tropykus InterestRateModel Interface - * @author tropykus - */ -abstract contract InterestRateModel is Exponential { - using SafeMath for uint256; - - /// @notice Indicator that this is an InterestRateModel contract (for inspection) - bool public constant isInterestRateModel = true; - bool public isTropykusInterestRateModel; - - /** - * @notice The approximate number of blocks per year that is assumed by the interest rate model - */ - uint256 public constant blocksPerYear = 1051200; - - /** - * @notice Calculates the utilization rate of the market: `borrows / (cash + borrows - reserves)` - * @param cash The amount of cash in the market - * @param borrows The amount of borrows in the market - * @param reserves The amount of reserves in the market (currently unused) - * @return The utilization rate as a mantissa between [0, 1e18] - */ - function utilizationRate( - uint256 cash, - uint256 borrows, - uint256 reserves - ) public pure virtual returns (uint256) { - // Utilization rate is 0 when there are no borrows - if (borrows == 0) { - return 0; - } - - return borrows.mul(1e18).div(cash.add(borrows).sub(reserves)); - } - - /** - * @notice Calculates the current borrow interest rate per block - * @param cash The total amount of cash the market has - * @param borrows The total amount of borrows the market has outstanding - * @param reserves The total amnount of reserves the market has - * @return The borrow rate per block (as a percentage, and scaled by 1e18) - */ - function getBorrowRate( - uint256 cash, - uint256 borrows, - uint256 reserves - ) external view virtual returns (uint256); - - /** - * @notice Calculates the current supply interest rate per block - * @param cash The total amount of cash the market has - * @param borrows The total amount of borrows the market has outstanding - * @param reserves The total amnount of reserves the market has - * @param reserveFactorMantissa The current reserve factor the market has - * @return The supply rate per block (as a percentage, and scaled by 1e18) - */ - function getSupplyRate( - uint256 cash, - uint256 borrows, - uint256 reserves, - uint256 reserveFactorMantissa - ) external view virtual returns (uint256); - - function getExchangeRate( - uint256 _totalCash, - uint256 _totalBorrows, - uint256 _totalReserves, - uint256 _totalSupply - ) public pure returns (MathError, uint256) { - /* - * exchangeRate = (totalCash + totalBorrows - totalReserves) / totalSupply - */ - Exp memory exchangeRate; - MathError mathErr; - uint256 cashPlusBorrowsMinusReserves; - (mathErr, cashPlusBorrowsMinusReserves) = addThenSubUInt( - _totalCash, - _totalBorrows, - _totalReserves - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - (mathErr, exchangeRate) = getExp( - cashPlusBorrowsMinusReserves, - _totalSupply - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - - return (MathError.NO_ERROR, exchangeRate.mantissa); - } - - function isAboveOptimal( - uint256 cash, - uint256 borrows, - uint256 reserves - ) public view virtual returns (bool) { - cash; - borrows; - reserves; - return false; - } -} - - -// Dependency file: contracts/EIP20NonStandardInterface.sol - -// pragma solidity 0.8.6; - -/** - * @title EIP20NonStandardInterface - * @dev Version of ERC20 with no return values for `transfer` and `transferFrom` - * See https://medium.com/coinmonks/missing-return-value-bug-at-least-130-tokens-affected-d67bf08521ca - */ -interface EIP20NonStandardInterface { - /** - * @notice Get the total number of tokens in circulation - * @return The supply of tokens - */ - function totalSupply() external view returns (uint256); - - /** - * @notice Gets the balance of the specified address - * @param owner The address from which the balance will be retrieved - * @return balance The balance - */ - function balanceOf(address owner) external view returns (uint256 balance); - - /// - /// !!!!!!!!!!!!!! - /// !!! NOTICE !!! `transfer` does not return a value, in violation of the ERC-20 specification - /// !!!!!!!!!!!!!! - /// - - /** - * @notice Transfer `amount` tokens from `msg.sender` to `dst` - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - */ - function transfer(address dst, uint256 amount) external; - - /// - /// !!!!!!!!!!!!!! - /// !!! NOTICE !!! `transferFrom` does not return a value, in violation of the ERC-20 specification - /// !!!!!!!!!!!!!! - /// - - /** - * @notice Transfer `amount` tokens from `src` to `dst` - * @param src The address of the source account - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - */ - function transferFrom( - address src, - address dst, - uint256 amount - ) external; - - /** - * @notice Approve `spender` to transfer up to `amount` from `src` - * @dev This will overwrite the approval amount for `spender` - * and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve) - * @param spender The address of the account which may transfer tokens - * @param amount The number of tokens that are approved - * @return success Whether or not the approval succeeded - */ - function approve(address spender, uint256 amount) - external - returns (bool success); - - /** - * @notice Get the current allowance from `owner` for `spender` - * @param owner The address of the account which owns the tokens to be spent - * @param spender The address of the account which may transfer tokens - * @return remaining The number of tokens allowed to be spent - */ - function allowance(address owner, address spender) - external - view - returns (uint256 remaining); - - event Transfer(address indexed from, address indexed to, uint256 amount); - event Approval( - address indexed owner, - address indexed spender, - uint256 amount - ); -} - - -// Dependency file: contracts/CTokenInterfaces.sol - -// pragma solidity 0.8.6; - -// import "contracts/ComptrollerInterface.sol"; -// import "contracts/InterestRateModel.sol"; -// import "contracts/EIP20NonStandardInterface.sol"; - -contract CTokenStorage { - /** - * @dev Guard variable for re-entrancy checks - */ - bool internal _notEntered; - - /** - * @notice EIP-20 token name for this token - */ - string public name; - - /** - * @notice EIP-20 token symbol for this token - */ - string public symbol; - - /** - * @notice EIP-20 token decimals for this token - */ - uint8 public decimals; - - /** - * @notice Maximum borrow rate that can ever be applied (.0005% / block) - */ - - uint256 internal constant borrowRateMaxMantissa = 0.0005e16; - - /** - * @notice Maximum fraction of interest that can be set aside for reserves - */ - uint256 internal constant reserveFactorMaxMantissa = 1e18; - - /** - * @notice Administrator for this contract - */ - address payable public admin; - - /** - * @notice Pending administrator for this contract - */ - address payable public pendingAdmin; - - /** - * @notice Contract which oversees inter-cToken operations - */ - ComptrollerInterface public comptroller; - - /** - * @notice Model which tells what the current interest rate should be - */ - InterestRateModel public interestRateModel; - - /** - * @notice Initial exchange rate used when minting the first CTokens (used when totalSupply = 0) - */ - uint256 public initialExchangeRateMantissa; - - /** - * @notice Fraction of interest currently set aside for reserves - */ - uint256 public reserveFactorMantissa; - - /** - * @notice Block number that interest was last accrued at - */ - uint256 public accrualBlockNumber; - - /** - * @notice Accumulator of the total earned interest rate since the opening of the market - */ - uint256 public borrowIndex; - - /** - * @notice Total amount of outstanding borrows of the underlying in this market - */ - uint256 public totalBorrows; - - /** - * @notice Total amount of reserves of the underlying held in this market - */ - uint256 public totalReserves; - - /** - * @notice Total number of tokens in circulation - */ - uint256 public totalSupply; - - uint256 public subsidyFund; - - struct SupplySnapshot { - uint256 tokens; - uint256 underlyingAmount; - uint256 suppliedAt; - uint256 promisedSupplyRate; - } - - /** - * @notice Official record of token balances for each account - */ - mapping(address => SupplySnapshot) internal accountTokens; - - /** - * @notice Approved token transfer amounts on behalf of others - */ - mapping(address => mapping(address => uint256)) internal transferAllowances; - - /** - * @notice Container for borrow balance information - * @member principal Total balance (with accrued interest), after applying the most recent balance-changing action - * @member interestIndex Global borrowIndex as of the most recent balance-changing action - */ - struct BorrowSnapshot { - uint256 principal; - uint256 interestIndex; - } - - /** - * @notice Mapping of account addresses to outstanding borrow balances - */ - mapping(address => BorrowSnapshot) internal accountBorrows; -} - -abstract contract CTokenInterface is CTokenStorage { - /** - * @notice Indicator that this is a CToken contract (for inspection) - */ - bool public constant isCToken = true; - - /*** Market Events ***/ - - /** - * @notice Event emitted when interest is accrued - */ - event AccrueInterest( - uint256 cashPrior, - uint256 interestAccumulated, - uint256 borrowIndex, - uint256 totalBorrows - ); - - /** - * @notice Event emitted when tokens are minted - */ - event Mint(address indexed minter, uint256 mintAmount, uint256 mintTokens); - - /** - * @notice Event emitted when tokens are redeemed - */ - event Redeem( - address indexed redeemer, - uint256 redeemAmount, - uint256 redeemTokens - ); - - /** - * @notice Event emitted when underlying is borrowed - */ - event Borrow( - address indexed borrower, - uint256 borrowAmount, - uint256 accountBorrows, - uint256 totalBorrows - ); - - /** - * @notice Event emitted when a borrow is repaid - */ - event RepayBorrow( - address indexed payer, - address indexed borrower, - uint256 repayAmount, - uint256 accountBorrows, - uint256 totalBorrows - ); - - /** - * @notice Event emitted when a borrow is liquidated - */ - event LiquidateBorrow( - address indexed liquidator, - address indexed borrower, - uint256 repayAmount, - address indexed cTokenCollateral, - uint256 seizeTokens - ); - - /*** Admin Events ***/ - - /** - * @notice Event emitted when pendingAdmin is changed - */ - event NewPendingAdmin(address oldPendingAdmin, address newPendingAdmin); - - /** - * @notice Event emitted when pendingAdmin is accepted, which means admin is updated - */ - event NewAdmin(address oldAdmin, address newAdmin); - - /** - * @notice Event emitted when comptroller is changed - */ - event NewComptroller( - ComptrollerInterface oldComptroller, - ComptrollerInterface newComptroller - ); - - /** - * @notice Event emitted when interestRateModel is changed - */ - event NewMarketInterestRateModel( - InterestRateModel oldInterestRateModel, - InterestRateModel newInterestRateModel - ); - - /** - * @notice Event emitted when the reserve factor is changed - */ - event NewReserveFactor( - uint256 oldReserveFactorMantissa, - uint256 newReserveFactorMantissa - ); - - /** - * @notice Event emitted when the reserves are added - */ - event ReservesAdded( - address benefactor, - uint256 addAmount, - uint256 newTotalReserves - ); - - event SubsidyAdded( - address benefactor, - uint256 addAmount, - uint256 newSubsidyFund - ); - - /** - * @notice Event emitted when the reserves are reduced - */ - event ReservesReduced( - address admin, - uint256 reduceAmount, - uint256 newTotalReserves - ); - - /** - * @notice EIP20 Transfer event - */ - event Transfer(address indexed from, address indexed to, uint256 amount); - - /** - * @notice EIP20 Approval event - */ - event Approval( - address indexed owner, - address indexed spender, - uint256 amount - ); - - /** - * @notice Failure event - */ - event CTokenStorageFailure(uint256 error, uint256 info, uint256 detail); - - /*** User Interface ***/ - - function transfer(address dst, uint256 amount) - external - virtual - returns (bool); - - function transferFrom( - address src, - address dst, - uint256 amount - ) external virtual returns (bool); - - function approve(address spender, uint256 amount) - external - virtual - returns (bool); - - function allowance(address owner, address spender) - external - view - virtual - returns (uint256); - - function balanceOf(address owner) external view virtual returns (uint256); - - function balanceOfUnderlying(address owner) - external - virtual - returns (uint256); - - function getAccountSnapshot(address account) - external - view - virtual - returns ( - uint256, - uint256, - uint256, - uint256 - ); - - function borrowRatePerBlock() external view virtual returns (uint256); - - function supplyRatePerBlock() external view virtual returns (uint256); - - function totalBorrowsCurrent() external virtual returns (uint256); - - function borrowBalanceCurrent(address account) - external - virtual - returns (uint256); - - function borrowBalanceStored(address account) - public - view - virtual - returns (uint256); - - function exchangeRateCurrent() public virtual returns (uint256); - - function exchangeRateStored() public view virtual returns (uint256); - - function getCash() external view virtual returns (uint256); - - function accrueInterest() public virtual returns (uint256); - - function seize( - address liquidator, - address borrower, - uint256 seizeTokens - ) external virtual returns (uint256); - - /*** Admin Functions ***/ - - function _setPendingAdmin(address payable newPendingAdmin) - external - virtual - returns (uint256); - - function _acceptAdmin() external virtual returns (uint256); - - function _setComptroller(ComptrollerInterface newComptroller) - public - virtual - returns (uint256); - - function _setReserveFactor(uint256 newReserveFactorMantissa) - external - virtual - returns (uint256); - - function _reduceReserves(uint256 reduceAmount) - external - virtual - returns (uint256); - - function _setInterestRateModel(InterestRateModel newInterestRateModel) - public - virtual - returns (uint256); -} - -contract CErc20Storage { - /** - * @notice Underlying asset for this CToken - */ - address public underlying; -} - -abstract contract CErc20Interface is CErc20Storage { - /*** User Interface ***/ - - function mint(uint256 mintAmount) external virtual returns (uint256); - - function redeem(uint256 redeemAmount) - external - virtual - returns (uint256); - - function borrow(uint256 borrowAmount) external virtual returns (uint256); - - function repayBorrow(uint256 repayAmount) - external - virtual - returns (uint256); - - function liquidateBorrow( - address borrower, - uint256 repayAmount, - CTokenInterface cTokenCollateral - ) external virtual returns (uint256); - - function sweepToken(EIP20NonStandardInterface token) external virtual; - - /*** Admin Functions ***/ - - function _addReserves(uint256 addAmount) external virtual returns (uint256); -} - -contract CDelegationStorage { - /** - * @notice Implementation address for this contract - */ - address public implementation; -} - -abstract contract CDelegatorInterface is CDelegationStorage { - /** - * @notice Emitted when implementation is changed - */ - event NewImplementation( - address oldImplementation, - address newImplementation - ); - - /** - * @notice Called by the admin to update the implementation of the delegator - * @param implementation_ The address of the new implementation for delegation - * @param allowResign Flag to indicate whether to call _resignImplementation on the old implementation - * @param becomeImplementationData The encoded bytes data to be passed to _becomeImplementation - */ - function _setImplementation( - address implementation_, - bool allowResign, - bytes memory becomeImplementationData - ) public virtual; -} - -abstract contract CDelegateInterface is CDelegationStorage { - /** - * @notice Called by the delegator on a delegate to initialize it for duty - * @dev Should revert if any issues arise which make it unfit for delegation - * @param data The encoded bytes data for any initialization - */ - function _becomeImplementation(bytes memory data) public virtual; - - /** - * @notice Called by the delegator on a delegate to forfeit its responsibility - */ - function _resignImplementation() public virtual; -} - - -// Dependency file: contracts/ErrorReporter.sol - -// pragma solidity 0.8.6; - -contract ComptrollerErrorReporter { - enum Error { - NO_ERROR, - UNAUTHORIZED, - COMPTROLLER_MISMATCH, - INSUFFICIENT_SHORTFALL, - INSUFFICIENT_LIQUIDITY, - INVALID_CLOSE_FACTOR, - INVALID_COLLATERAL_FACTOR, - INVALID_LIQUIDATION_INCENTIVE, - MARKET_NOT_ENTERED, // no longer possible - MARKET_NOT_LISTED, - MARKET_ALREADY_LISTED, - MATH_ERROR, - NONZERO_BORROW_BALANCE, - PRICE_ERROR, - REJECTION, - SNAPSHOT_ERROR, - TOO_MANY_ASSETS, - TOO_MUCH_REPAY - } - - enum FailureInfo { - ACCEPT_ADMIN_PENDING_ADMIN_CHECK, - ACCEPT_PENDING_IMPLEMENTATION_ADDRESS_CHECK, - EXIT_MARKET_BALANCE_OWED, - EXIT_MARKET_REJECTION, - SET_CLOSE_FACTOR_OWNER_CHECK, - SET_CLOSE_FACTOR_VALIDATION, - SET_COLLATERAL_FACTOR_OWNER_CHECK, - SET_COLLATERAL_FACTOR_NO_EXISTS, - SET_COLLATERAL_FACTOR_VALIDATION, - SET_COLLATERAL_FACTOR_WITHOUT_PRICE, - SET_IMPLEMENTATION_OWNER_CHECK, - SET_LIQUIDATION_INCENTIVE_OWNER_CHECK, - SET_LIQUIDATION_INCENTIVE_VALIDATION, - SET_MAX_ASSETS_OWNER_CHECK, - SET_PENDING_ADMIN_OWNER_CHECK, - SET_PENDING_IMPLEMENTATION_OWNER_CHECK, - SET_PRICE_ORACLE_OWNER_CHECK, - SUPPORT_MARKET_EXISTS, - SUPPORT_MARKET_OWNER_CHECK, - SET_PAUSE_GUARDIAN_OWNER_CHECK - } - - /** - * @dev `error` corresponds to enum Error; `info` corresponds to enum FailureInfo, and `detail` is an arbitrary - * contract-specific code that enables us to report opaque error codes from upgradeable contracts. - **/ - event Failure(uint256 error, uint256 info, uint256 detail); - - /** - * @dev use this when reporting a known error from the money market or a non-upgradeable collaborator - */ - function fail(Error err, FailureInfo info) internal returns (uint256) { - emit Failure(uint256(err), uint256(info), 0); - - return uint256(err); - } - - /** - * @dev use this when reporting an opaque error from an upgradeable collaborator contract - */ - function failOpaque( - Error err, - FailureInfo info, - uint256 opaqueError - ) internal returns (uint256) { - emit Failure(uint256(err), uint256(info), opaqueError); - - return uint256(err); - } -} - -contract TokenErrorReporter { - enum Error { - NO_ERROR, - UNAUTHORIZED, - BAD_INPUT, - COMPTROLLER_REJECTION, - COMPTROLLER_CALCULATION_ERROR, - INTEREST_RATE_MODEL_ERROR, - INVALID_ACCOUNT_PAIR, - INVALID_CLOSE_AMOUNT_REQUESTED, - INVALID_COLLATERAL_FACTOR, - MATH_ERROR, - MARKET_NOT_FRESH, - MARKET_NOT_LISTED, - TOKEN_INSUFFICIENT_ALLOWANCE, - TOKEN_INSUFFICIENT_BALANCE, - TOKEN_INSUFFICIENT_CASH, - TOKEN_TRANSFER_IN_FAILED, - TOKEN_TRANSFER_OUT_FAILED - } - - /* - * Note: FailureInfo (but not Error) is kept in alphabetical order - * This is because FailureInfo grows significantly faster, and - * the order of Error has some meaning, while the order of FailureInfo - * is entirely arbitrary. - */ - enum FailureInfo { - ACCEPT_ADMIN_PENDING_ADMIN_CHECK, - ACCRUE_INTEREST_ACCUMULATED_INTEREST_CALCULATION_FAILED, - ACCRUE_INTEREST_BORROW_RATE_CALCULATION_FAILED, - ACCRUE_INTEREST_NEW_BORROW_INDEX_CALCULATION_FAILED, - ACCRUE_INTEREST_NEW_TOTAL_BORROWS_CALCULATION_FAILED, - ACCRUE_INTEREST_NEW_TOTAL_RESERVES_CALCULATION_FAILED, - ACCRUE_INTEREST_SIMPLE_INTEREST_FACTOR_CALCULATION_FAILED, - BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED, - BORROW_ACCRUE_INTEREST_FAILED, - BORROW_CASH_NOT_AVAILABLE, - BORROW_FRESHNESS_CHECK, - BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED, - BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED, - BORROW_MARKET_NOT_LISTED, - BORROW_COMPTROLLER_REJECTION, - LIQUIDATE_ACCRUE_BORROW_INTEREST_FAILED, - LIQUIDATE_ACCRUE_COLLATERAL_INTEREST_FAILED, - LIQUIDATE_COLLATERAL_FRESHNESS_CHECK, - LIQUIDATE_COMPTROLLER_REJECTION, - LIQUIDATE_COMPTROLLER_CALCULATE_AMOUNT_SEIZE_FAILED, - LIQUIDATE_CLOSE_AMOUNT_IS_UINT_MAX, - LIQUIDATE_CLOSE_AMOUNT_IS_ZERO, - LIQUIDATE_FRESHNESS_CHECK, - LIQUIDATE_LIQUIDATOR_IS_BORROWER, - LIQUIDATE_REPAY_BORROW_FRESH_FAILED, - LIQUIDATE_SEIZE_BALANCE_INCREMENT_FAILED, - LIQUIDATE_SEIZE_BALANCE_DECREMENT_FAILED, - LIQUIDATE_SEIZE_COMPTROLLER_REJECTION, - LIQUIDATE_SEIZE_LIQUIDATOR_IS_BORROWER, - LIQUIDATE_SEIZE_TOO_MUCH, - MINT_ACCRUE_INTEREST_FAILED, - MINT_COMPTROLLER_REJECTION, - MINT_EXCHANGE_CALCULATION_FAILED, - MINT_EXCHANGE_RATE_READ_FAILED, - MINT_FRESHNESS_CHECK, - MINT_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED, - MINT_NEW_TOTAL_SUPPLY_CALCULATION_FAILED, - MINT_TRANSFER_IN_FAILED, - MINT_TRANSFER_IN_NOT_POSSIBLE, - REDEEM_ACCRUE_INTEREST_FAILED, - REDEEM_COMPTROLLER_REJECTION, - REDEEM_EXCHANGE_TOKENS_CALCULATION_FAILED, - REDEEM_EXCHANGE_AMOUNT_CALCULATION_FAILED, - REDEEM_EXCHANGE_RATE_READ_FAILED, - REDEEM_FRESHNESS_CHECK, - REDEEM_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED, - REDEEM_NEW_TOTAL_SUPPLY_CALCULATION_FAILED, - REDEEM_TRANSFER_OUT_NOT_POSSIBLE, - REDUCE_RESERVES_ACCRUE_INTEREST_FAILED, - REDUCE_RESERVES_ADMIN_CHECK, - REDUCE_RESERVES_CASH_NOT_AVAILABLE, - REDUCE_RESERVES_FRESH_CHECK, - REDUCE_RESERVES_VALIDATION, - REPAY_BEHALF_ACCRUE_INTEREST_FAILED, - REPAY_BORROW_ACCRUE_INTEREST_FAILED, - REPAY_BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED, - REPAY_BORROW_COMPTROLLER_REJECTION, - REPAY_BORROW_FRESHNESS_CHECK, - REPAY_BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED, - REPAY_BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED, - REPAY_BORROW_TRANSFER_IN_NOT_POSSIBLE, - SET_COLLATERAL_FACTOR_OWNER_CHECK, - SET_COLLATERAL_FACTOR_VALIDATION, - SET_COMPTROLLER_OWNER_CHECK, - SET_INTEREST_RATE_MODEL_ACCRUE_INTEREST_FAILED, - SET_INTEREST_RATE_MODEL_FRESH_CHECK, - SET_INTEREST_RATE_MODEL_OWNER_CHECK, - SET_MAX_ASSETS_OWNER_CHECK, - SET_ORACLE_MARKET_NOT_LISTED, - SET_PENDING_ADMIN_OWNER_CHECK, - SET_RESERVE_FACTOR_ACCRUE_INTEREST_FAILED, - SET_RESERVE_FACTOR_ADMIN_CHECK, - SET_RESERVE_FACTOR_FRESH_CHECK, - SET_RESERVE_FACTOR_BOUNDS_CHECK, - TRANSFER_COMPTROLLER_REJECTION, - TRANSFER_NOT_ALLOWED, - TRANSFER_NOT_ENOUGH, - TRANSFER_TOO_MUCH, - ADD_RESERVES_ACCRUE_INTEREST_FAILED, - ADD_RESERVES_FRESH_CHECK, - ADD_RESERVES_TRANSFER_IN_NOT_POSSIBLE, - ADD_SUBSIDY_FUND_FAILED, - ADD_SUBSIDY_FUND_FRESH_CHECK - } - - /** - * @dev `error` corresponds to enum Error; `info` corresponds to enum FailureInfo, and `detail` is an arbitrary - * contract-specific code that enables us to report opaque error codes from upgradeable contracts. - **/ - event TokenFailure(uint256 error, uint256 info, uint256 detail); - - /** - * @dev use this when reporting a known error from the money market or a non-upgradeable collaborator - */ - function fail(Error err, FailureInfo info) internal returns (uint256) { - emit TokenFailure(uint256(err), uint256(info), 0); - - return uint256(err); - } - - /** - * @dev use this when reporting an opaque error from an upgradeable collaborator contract - */ - function failOpaque( - Error err, - FailureInfo info, - uint256 opaqueError - ) internal returns (uint256) { - emit TokenFailure(uint256(err), uint256(info), opaqueError); - - return uint256(err); - } -} - - -// Dependency file: contracts/EIP20Interface.sol - -// pragma solidity 0.8.6; - -/** - * @title ERC 20 Token Standard Interface - * https://eips.ethereum.org/EIPS/eip-20 - */ -interface EIP20Interface { - function name() external view returns (string memory); - - function symbol() external view returns (string memory); - - function decimals() external view returns (uint8); - - /** - * @notice Get the total number of tokens in circulation - * @return The supply of tokens - */ - function totalSupply() external view returns (uint256); - - /** - * @notice Gets the balance of the specified address - * @param owner The address from which the balance will be retrieved - * @return balance The balance - */ - function balanceOf(address owner) external view returns (uint256 balance); - - /** - * @notice Transfer `amount` tokens from `msg.sender` to `dst` - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - * @return success Whether or not the transfer succeeded - */ - function transfer(address dst, uint256 amount) - external - returns (bool success); - - /** - * @notice Transfer `amount` tokens from `src` to `dst` - * @param src The address of the source account - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - * @return success Whether or not the transfer succeeded - */ - function transferFrom( - address src, - address dst, - uint256 amount - ) external returns (bool success); - - /** - * @notice Approve `spender` to transfer up to `amount` from `src` - * @dev This will overwrite the approval amount for `spender` - * and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve) - * @param spender The address of the account which may transfer tokens - * @param amount The number of tokens that are approved (-1 means infinite) - * @return success Whether or not the approval succeeded - */ - function approve(address spender, uint256 amount) - external - returns (bool success); - - /** - * @notice Get the current allowance from `owner` for `spender` - * @param owner The address of the account which owns the tokens to be spent - * @param spender The address of the account which may transfer tokens - * @return remaining The number of tokens allowed to be spent (-1 means infinite) - */ - function allowance(address owner, address spender) - external - view - returns (uint256 remaining); - - event Transfer(address indexed from, address indexed to, uint256 amount); - event Approval( - address indexed owner, - address indexed spender, - uint256 amount - ); -} - - -// Dependency file: contracts/WhitelistInterface.sol - -// pragma solidity 0.8.6; - -interface WhitelistInterface { - function setStatus(bool _newStatus) external; - function enabled() external view returns(bool); - - function addUsers(address[] memory _users) external; - function exist(address _user) external view returns(bool); - function getUsers() external view returns(address[] memory currentUsers); - function removeUser(address _user) external; -} - -// Dependency file: contracts/CToken.sol - -// pragma solidity 0.8.6; - -// import "contracts/ComptrollerInterface.sol"; -// import "contracts/CTokenInterfaces.sol"; -// import "contracts/ErrorReporter.sol"; -// import "contracts/Exponential.sol"; -// import "contracts/EIP20Interface.sol"; -// import "contracts/InterestRateModel.sol"; -// import "contracts/WhitelistInterface.sol"; - -/** - * @title tropykus CToken Contract - * @notice Abstract base for CTokens - * @author tropykus - */ -abstract contract CToken is CTokenInterface, Exponential, TokenErrorReporter { - address whitelist; - - /** - * @notice Initialize the money market - * @param comptroller_ The address of the Comptroller - * @param interestRateModel_ The address of the interest rate model - * @param initialExchangeRateMantissa_ The initial exchange rate, scaled by 1e18 - * @param name_ EIP-20 name of this token - * @param symbol_ EIP-20 symbol of this token - * @param decimals_ EIP-20 decimal precision of this token - */ - function initialize( - ComptrollerInterface comptroller_, - InterestRateModel interestRateModel_, - uint256 initialExchangeRateMantissa_, - string memory name_, - string memory symbol_, - uint8 decimals_ - ) public { - require(msg.sender == admin, "CT01"); - require(accrualBlockNumber == 0 && borrowIndex == 0, "CT02"); - - initialExchangeRateMantissa = initialExchangeRateMantissa_; - require(initialExchangeRateMantissa > 0, "CT03"); - - uint256 err = _setComptroller(comptroller_); - require(err == uint256(Error.NO_ERROR), "CT04"); - - accrualBlockNumber = getBlockNumber(); - borrowIndex = mantissaOne; - - err = _setInterestRateModelFresh(interestRateModel_); - require(err == uint256(Error.NO_ERROR), "CT05"); - - name = name_; - symbol = symbol_; - decimals = decimals_; - - _notEntered = true; - } - - function addWhitelist(address _whitelist) external returns (uint256) { - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_INTEREST_RATE_MODEL_OWNER_CHECK - ); - } - whitelist = _whitelist; - } - - /** - * @notice Transfer `tokens` tokens from `src` to `dst` by `spender` - * @dev Called by both `transfer` and `transferFrom` internally - * @param spender The address of the account performing the transfer - * @param src The address of the source account - * @param dst The address of the destination account - * @param tokens The number of tokens to transfer - * @return Whether or not the transfer succeeded - */ - function transferTokens( - address spender, - address src, - address dst, - uint256 tokens - ) internal returns (uint256) { - uint256 allowed = comptroller.transferAllowed( - address(this), - src, - dst, - tokens - ); - if (allowed != 0) { - return - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.TRANSFER_COMPTROLLER_REJECTION, - allowed - ); - } - - if (src == dst) { - return fail(Error.BAD_INPUT, FailureInfo.TRANSFER_NOT_ALLOWED); - } - - uint256 startingAllowance = 0; - if (spender == src) { - startingAllowance = type(uint256).max; - } else { - startingAllowance = transferAllowances[src][spender]; - } - - MathError mathErr; - uint256 allowanceNew; - uint256 srcTokensNew; - uint256 dstTokensNew; - - (mathErr, allowanceNew) = subUInt(startingAllowance, tokens); - if (mathErr != MathError.NO_ERROR) { - return fail(Error.MATH_ERROR, FailureInfo.TRANSFER_NOT_ALLOWED); - } - - (mathErr, srcTokensNew) = subUInt(accountTokens[src].tokens, tokens); - if (mathErr != MathError.NO_ERROR) { - return fail(Error.MATH_ERROR, FailureInfo.TRANSFER_NOT_ENOUGH); - } - - (mathErr, dstTokensNew) = addUInt(accountTokens[dst].tokens, tokens); - if (mathErr != MathError.NO_ERROR) { - return fail(Error.MATH_ERROR, FailureInfo.TRANSFER_TOO_MUCH); - } - - accountTokens[src].tokens = srcTokensNew; - accountTokens[dst].tokens = dstTokensNew; - - if (startingAllowance != type(uint256).max) { - transferAllowances[src][spender] = allowanceNew; - } - - emit Transfer(src, dst, tokens); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Transfer `amount` tokens from `msg.sender` to `dst` - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - * @return Whether or not the transfer succeeded - */ - function transfer(address dst, uint256 amount) - external - override - nonReentrant - returns (bool) - { - return - transferTokens(msg.sender, msg.sender, dst, amount) == - uint256(Error.NO_ERROR); - } - - /** - * @notice Transfer `amount` tokens from `src` to `dst` - * @param src The address of the source account - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - * @return Whether or not the transfer succeeded - */ - function transferFrom( - address src, - address dst, - uint256 amount - ) external override nonReentrant returns (bool) { - return - transferTokens(msg.sender, src, dst, amount) == - uint256(Error.NO_ERROR); - } - - /** - * @notice Approve `spender` to transfer up to `amount` from `src` - * @dev This will overwrite the approval amount for `spender` - * and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve) - * @param spender The address of the account which may transfer tokens - * @param amount The number of tokens that are approved (-1 means infinite) - * @return Whether or not the approval succeeded - */ - function approve(address spender, uint256 amount) - external - override - returns (bool) - { - transferAllowances[msg.sender][spender] = amount; - emit Approval(msg.sender, spender, amount); - return true; - } - - /** - * @notice Get the current allowance from `owner` for `spender` - * @param owner The address of the account which owns the tokens to be spent - * @param spender The address of the account which may transfer tokens - * @return The number of tokens allowed to be spent (-1 means infinite) - */ - function allowance(address owner, address spender) - external - view - override - returns (uint256) - { - return transferAllowances[owner][spender]; - } - - /** - * @notice Get the token balance of the `owner` - * @param owner The address of the account to query - * @return The number of tokens owned by `owner` - */ - function balanceOf(address owner) external view override returns (uint256) { - return accountTokens[owner].tokens; - } - - /** - * @notice Get the underlying balance of the `owner` - * @dev This also accrues interest in a transaction - * @param owner The address of the account to query - * @return The amount of underlying owned by `owner` - */ - function balanceOfUnderlying(address owner) - external - override - returns (uint256) - { - (MathError mErr, uint256 balance) = mulScalarTruncate( - Exp({mantissa: exchangeRateCurrent()}), - accountTokens[owner].tokens - ); - require(mErr == MathError.NO_ERROR, "CT06"); - return balance; - } - - /** - * @notice Get a snapshot of the account's balances, and the cached exchange rate - * @dev This is used by comptroller to more efficiently perform liquidity checks. - * @param account Address of the account to snapshot - * @return (possible error, token balance, borrow balance, exchange rate mantissa) - */ - function getAccountSnapshot(address account) - external - view - override - returns ( - uint256, - uint256, - uint256, - uint256 - ) - { - uint256 cTokenBalance = accountTokens[account].tokens; - uint256 borrowBalance; - uint256 exchangeRateMantissa; - - MathError mErr; - - (mErr, borrowBalance) = borrowBalanceStoredInternal(account); - if (mErr != MathError.NO_ERROR) { - return (uint256(Error.MATH_ERROR), 0, 0, 0); - } - - (mErr, exchangeRateMantissa) = exchangeRateStoredInternal(); - if (mErr != MathError.NO_ERROR) { - return (uint256(Error.MATH_ERROR), 0, 0, 0); - } - - return ( - uint256(Error.NO_ERROR), - cTokenBalance, - borrowBalance, - exchangeRateMantissa - ); - } - - /** - * @dev Function to simply retrieve block number - * This exists mainly for inheriting test contracts to stub this result. - */ - function getBlockNumber() internal view virtual returns (uint256) { - return block.number; - } - - /** - * @notice Returns the current per-block borrow interest rate for this cToken - * @return The borrow interest rate per block, scaled by 1e18 - */ - function borrowRatePerBlock() external view override returns (uint256) { - return - interestRateModel.getBorrowRate( - getCashPrior(), - totalBorrows, - totalReserves - ); - } - - /** - * @notice Returns the current per-block supply interest rate for this cToken - * @return The supply interest rate per block, scaled by 1e18 - */ - function supplyRatePerBlock() external view override returns (uint256) { - return - interestRateModel.getSupplyRate( - getCashPrior(), - totalBorrows, - totalReserves, - reserveFactorMantissa - ); - } - - /** - * @notice Returns the current total borrows plus accrued interest - * @return The total borrows with interest - */ - function totalBorrowsCurrent() - external - override - nonReentrant - returns (uint256) - { - require(accrueInterest() == uint256(Error.NO_ERROR), "CT07"); - return totalBorrows; - } - - /** - * @notice Accrue interest to updated borrowIndex and then calculate account's borrow balance using the updated borrowIndex - * @param account The address whose balance should be calculated after updating borrowIndex - * @return The calculated balance - */ - function borrowBalanceCurrent(address account) - external - override - nonReentrant - returns (uint256) - { - require(accrueInterest() == uint256(Error.NO_ERROR), "CT07"); - return borrowBalanceStored(account); - } - - /** - * @notice Return the borrow balance of account based on stored data - * @param account The address whose balance should be calculated - * @return The calculated balance - */ - function borrowBalanceStored(address account) - public - view - override - returns (uint256) - { - (MathError err, uint256 result) = borrowBalanceStoredInternal(account); - require(err == MathError.NO_ERROR, "CT08"); - return result; - } - - /** - * @notice Return the borrow balance of account based on stored data - * @param account The address whose balance should be calculated - * @return (error code, the calculated balance or 0 if error code is non-zero) - */ - function borrowBalanceStoredInternal(address account) - internal - view - returns (MathError, uint256) - { - MathError mathErr; - uint256 principalTimesIndex; - uint256 result; - - BorrowSnapshot storage borrowSnapshot = accountBorrows[account]; - - if (borrowSnapshot.principal == 0) { - return (MathError.NO_ERROR, 0); - } - - (mathErr, principalTimesIndex) = mulUInt( - borrowSnapshot.principal, - borrowIndex - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - - (mathErr, result) = divUInt( - principalTimesIndex, - borrowSnapshot.interestIndex - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - - return (MathError.NO_ERROR, result); - } - - function getBorrowerPrincipalStored(address account) - public - view - returns (uint256 borrowed) - { - borrowed = accountBorrows[account].principal; - } - - function getSupplierSnapshotStored(address account) - public - view - returns ( - uint256 tokens, - uint256 underlyingAmount, - uint256 suppliedAt, - uint256 promisedSupplyRate - ) - { - tokens = accountTokens[account].tokens; - underlyingAmount = accountTokens[account].underlyingAmount; - suppliedAt = accountTokens[account].suppliedAt; - promisedSupplyRate = accountTokens[account].promisedSupplyRate; - } - - /** - * @notice Accrue interest then return the up-to-date exchange rate - * @return Calculated exchange rate scaled by 1e18 - */ - function exchangeRateCurrent() - public - override - nonReentrant - returns (uint256) - { - require(accrueInterest() == uint256(Error.NO_ERROR), "CT07"); - return exchangeRateStored(); - } - - /** - * @notice Calculates the exchange rate from the underlying to the CToken - * @dev This function does not accrue interest before calculating the exchange rate - * @return Calculated exchange rate scaled by 1e18 - */ - function exchangeRateStored() public view override returns (uint256) { - (MathError err, uint256 result) = exchangeRateStoredInternal(); - require(err == MathError.NO_ERROR, "CT09"); - return result; - } - - /** - * @notice Calculates the exchange rate from the underlying to the CToken - * @dev This function does not accrue interest before calculating the exchange rate - * @return (error code, calculated exchange rate scaled by 1e18) - */ - function exchangeRateStoredInternal() - internal - view - virtual - returns (MathError, uint256) - { - uint256 _totalSupply = totalSupply; - if (_totalSupply == 0) { - return (MathError.NO_ERROR, initialExchangeRateMantissa); - } else { - MathError error; - uint256 exchangeRate; - uint256 totalCash = getCashPrior(); - if (interestRateModel.isTropykusInterestRateModel()) { - (error, exchangeRate) = tropykusExchangeRateStoredInternal( - msg.sender - ); - if (error == MathError.NO_ERROR) { - return (MathError.NO_ERROR, exchangeRate); - } else { - return (MathError.NO_ERROR, initialExchangeRateMantissa); - } - } - return - interestRateModel.getExchangeRate( - totalCash, - totalBorrows, - totalReserves, - totalSupply - ); - } - } - - function tropykusExchangeRateStoredInternal(address redeemer) - internal - view - returns (MathError, uint256) - { - if (totalSupply == 0) { - return (MathError.NO_ERROR, initialExchangeRateMantissa); - } else { - SupplySnapshot storage supplySnapshot = accountTokens[redeemer]; - if (supplySnapshot.suppliedAt == 0) { - return (MathError.DIVISION_BY_ZERO, 0); - } - (, uint256 interestFactorMantissa, ) = tropykusInterestAccrued( - redeemer - ); - Exp memory interestFactor = Exp({mantissa: interestFactorMantissa}); - uint256 currentUnderlying = supplySnapshot.underlyingAmount; - Exp memory redeemerUnderlying = Exp({mantissa: currentUnderlying}); - (, Exp memory realAmount) = mulExp( - interestFactor, - redeemerUnderlying - ); - (, Exp memory exchangeRate) = getExp( - realAmount.mantissa, - supplySnapshot.tokens - ); - return (MathError.NO_ERROR, exchangeRate.mantissa); - } - } - - function tropykusInterestAccrued(address account) - internal - view - returns ( - MathError, - uint256, - uint256 - ) - { - SupplySnapshot storage supplySnapshot = accountTokens[account]; - uint256 promisedSupplyRate = supplySnapshot.promisedSupplyRate; - Exp memory expectedSupplyRatePerBlock = Exp({ - mantissa: promisedSupplyRate - }); - (, uint256 delta) = subUInt( - accrualBlockNumber, - supplySnapshot.suppliedAt - ); - (, Exp memory expectedSupplyRatePerBlockWithDelta) = mulScalar( - expectedSupplyRatePerBlock, - delta - ); - (, Exp memory interestFactor) = addExp( - Exp({mantissa: 1e18}), - expectedSupplyRatePerBlockWithDelta - ); - uint256 currentUnderlying = supplySnapshot.underlyingAmount; - Exp memory redeemerUnderlying = Exp({mantissa: currentUnderlying}); - (, Exp memory realAmount) = mulExp(interestFactor, redeemerUnderlying); - (, uint256 interestEarned) = subUInt( - realAmount.mantissa, - currentUnderlying - ); - return (MathError.NO_ERROR, interestFactor.mantissa, interestEarned); - } - - /** - * @notice Get cash balance of this cToken in the underlying asset - * @return The quantity of underlying asset owned by this contract - */ - function getCash() external view override returns (uint256) { - return getCashPrior(); - } - - /** - * @notice Applies accrued interest to total borrows and reserves - * @dev This calculates interest accrued from the last checkpointed block - * up to the current block and writes new checkpoint to storage. - */ - function accrueInterest() public override returns (uint256) { - uint256 currentBlockNumber = getBlockNumber(); - uint256 accrualBlockNumberPrior = accrualBlockNumber; - - if (accrualBlockNumberPrior == currentBlockNumber) { - return uint256(Error.NO_ERROR); - } - - uint256 cashPrior = getCashPrior(); - uint256 borrowsPrior = totalBorrows; - uint256 reservesPrior = totalReserves; - uint256 borrowIndexPrior = borrowIndex; - - uint256 borrowRateMantissa = interestRateModel.getBorrowRate( - cashPrior, - borrowsPrior, - reservesPrior - ); - require(borrowRateMantissa <= borrowRateMaxMantissa, "CT10"); - - (MathError mathErr, uint256 blockDelta) = subUInt( - currentBlockNumber, - accrualBlockNumberPrior - ); - require(mathErr == MathError.NO_ERROR, "CT11"); - - Exp memory simpleInterestFactor; - uint256 interestAccumulated; - uint256 totalBorrowsNew; - uint256 totalReservesNew; - uint256 borrowIndexNew; - - (mathErr, simpleInterestFactor) = mulScalar( - Exp({mantissa: borrowRateMantissa}), - blockDelta - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .ACCRUE_INTEREST_SIMPLE_INTEREST_FACTOR_CALCULATION_FAILED, - uint256(mathErr) - ); - } - - (mathErr, interestAccumulated) = mulScalarTruncate( - simpleInterestFactor, - borrowsPrior - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .ACCRUE_INTEREST_ACCUMULATED_INTEREST_CALCULATION_FAILED, - uint256(mathErr) - ); - } - - (mathErr, totalBorrowsNew) = addUInt(interestAccumulated, borrowsPrior); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .ACCRUE_INTEREST_NEW_TOTAL_BORROWS_CALCULATION_FAILED, - uint256(mathErr) - ); - } - - (mathErr, totalReservesNew) = mulScalarTruncateAddUInt( - Exp({mantissa: reserveFactorMantissa}), - interestAccumulated, - reservesPrior - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .ACCRUE_INTEREST_NEW_TOTAL_RESERVES_CALCULATION_FAILED, - uint256(mathErr) - ); - } - - if (interestRateModel.isTropykusInterestRateModel()) { - (mathErr, totalReservesNew) = newReserves( - borrowRateMantissa, - cashPrior, - borrowsPrior, - reservesPrior, - interestAccumulated - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .ACCRUE_INTEREST_NEW_TOTAL_RESERVES_CALCULATION_FAILED, - uint256(mathErr) - ); - } - } - - (mathErr, borrowIndexNew) = mulScalarTruncateAddUInt( - simpleInterestFactor, - borrowIndexPrior, - borrowIndexPrior - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .ACCRUE_INTEREST_NEW_BORROW_INDEX_CALCULATION_FAILED, - uint256(mathErr) - ); - } - - accrualBlockNumber = currentBlockNumber; - borrowIndex = borrowIndexNew; - totalBorrows = totalBorrowsNew; - totalReserves = totalReservesNew; - - emit AccrueInterest( - cashPrior, - interestAccumulated, - borrowIndexNew, - totalBorrowsNew - ); - - return uint256(Error.NO_ERROR); - } - - function newReserves( - uint256 borrowRateMantissa, - uint256 cashPrior, - uint256 borrowsPrior, - uint256 reservesPrior, - uint256 interestAccumulated - ) internal view returns (MathError mathErr, uint256 totalReservesNew) { - uint256 newReserveFactorMantissa; - uint256 utilizationRate = interestRateModel.utilizationRate( - cashPrior, - borrowsPrior, - reservesPrior - ); - uint256 expectedSupplyRate = interestRateModel.getSupplyRate( - cashPrior, - borrowsPrior, - reservesPrior, - reserveFactorMantissa - ); - if ( - interestRateModel.isAboveOptimal( - cashPrior, - borrowsPrior, - reservesPrior - ) - ) { - (mathErr, newReserveFactorMantissa) = mulScalarTruncate( - Exp({mantissa: utilizationRate}), - borrowRateMantissa - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - (mathErr, newReserveFactorMantissa) = subUInt( - newReserveFactorMantissa, - expectedSupplyRate - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - (mathErr, totalReservesNew) = mulScalarTruncateAddUInt( - Exp({mantissa: newReserveFactorMantissa}), - interestAccumulated, - reservesPrior - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - } else { - mathErr = MathError.NO_ERROR; - totalReservesNew = reservesPrior; - } - } - - /** - * @notice Sender supplies assets into the market and receives cTokens in exchange - * @dev Accrues interest whether or not the operation succeeds, unless reverted - * @param mintAmount The amount of the underlying asset to supply - * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual mint amount. - */ - function mintInternal(uint256 mintAmount) - internal - nonReentrant - returns (uint256, uint256) - { - if (WhitelistInterface(whitelist).enabled()) { - require(WhitelistInterface(whitelist).exist(msg.sender), "CT26"); - } - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return ( - fail(Error(error), FailureInfo.MINT_ACCRUE_INTEREST_FAILED), - 0 - ); - } - return mintFresh(msg.sender, mintAmount); - } - - struct MintLocalVars { - Error err; - MathError mathErr; - uint256 exchangeRateMantissa; - uint256 mintTokens; - uint256 totalSupplyNew; - uint256 accountTokensNew; - uint256 actualMintAmount; - } - - /** - * @notice User supplies assets into the market and receives cTokens in exchange - * @dev Assumes interest has already been accrued up to the current block - * @param minter The address of the account which is supplying the assets - * @param mintAmount The amount of the underlying asset to supply - * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual mint amount. - */ - function mintFresh(address minter, uint256 mintAmount) - internal - returns (uint256, uint256) - { - uint256 allowed = comptroller.mintAllowed( - address(this), - minter, - mintAmount - ); - if (allowed != 0) { - return ( - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.MINT_COMPTROLLER_REJECTION, - allowed - ), - 0 - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return ( - fail(Error.MARKET_NOT_FRESH, FailureInfo.MINT_FRESHNESS_CHECK), - 0 - ); - } - - MintLocalVars memory vars; - - ( - vars.mathErr, - vars.exchangeRateMantissa - ) = exchangeRateStoredInternal(); - if (vars.mathErr != MathError.NO_ERROR) { - return ( - failOpaque( - Error.MATH_ERROR, - FailureInfo.MINT_EXCHANGE_RATE_READ_FAILED, - uint256(vars.mathErr) - ), - 0 - ); - } - if (interestRateModel.isTropykusInterestRateModel()) { - SupplySnapshot storage supplySnapshot = accountTokens[minter]; - (, uint256 newTotalSupply) = addUInt( - supplySnapshot.underlyingAmount, - mintAmount - ); - require(newTotalSupply <= 0.1e18, "CT24"); - } - vars.actualMintAmount = doTransferIn(minter, mintAmount); - - (vars.mathErr, vars.mintTokens) = divScalarByExpTruncate( - vars.actualMintAmount, - Exp({mantissa: vars.exchangeRateMantissa}) - ); - require(vars.mathErr == MathError.NO_ERROR, "CT12"); - - (vars.mathErr, vars.totalSupplyNew) = addUInt( - totalSupply, - vars.mintTokens - ); - require(vars.mathErr == MathError.NO_ERROR, "CT13"); - - (vars.mathErr, vars.accountTokensNew) = addUInt( - accountTokens[minter].tokens, - vars.mintTokens - ); - require(vars.mathErr == MathError.NO_ERROR, "CT14"); - - uint256 currentSupplyRate = interestRateModel.getSupplyRate( - getCashPrior(), - totalBorrows, - totalReserves, - reserveFactorMantissa - ); - - bool isTropykusInterestRateModel = interestRateModel - .isTropykusInterestRateModel(); - - if (accountTokens[minter].tokens > 0) { - Exp memory updatedUnderlying; - if (isTropykusInterestRateModel) { - (, uint256 interestFactorMantissa, ) = tropykusInterestAccrued( - minter - ); - Exp memory interestFactor = Exp({ - mantissa: interestFactorMantissa - }); - uint256 currentUnderlyingAmount = accountTokens[minter] - .underlyingAmount; - MathError mErrorNewAmount; - (mErrorNewAmount, updatedUnderlying) = mulExp( - Exp({mantissa: currentUnderlyingAmount}), - interestFactor - ); - if (mErrorNewAmount != MathError.NO_ERROR) { - return ( - failOpaque( - Error.MATH_ERROR, - FailureInfo.MINT_EXCHANGE_CALCULATION_FAILED, - uint256(mErrorNewAmount) - ), - 0 - ); - } - } else { - uint256 currentTokens = accountTokens[minter].tokens; - MathError mErrorUpdatedUnderlying; - (mErrorUpdatedUnderlying, updatedUnderlying) = mulExp( - Exp({mantissa: currentTokens}), - Exp({mantissa: vars.exchangeRateMantissa}) - ); - if (mErrorUpdatedUnderlying != MathError.NO_ERROR) { - return ( - failOpaque( - Error.MATH_ERROR, - FailureInfo.MINT_EXCHANGE_CALCULATION_FAILED, - uint256(mErrorUpdatedUnderlying) - ), - 0 - ); - } - } - (, mintAmount) = addUInt(updatedUnderlying.mantissa, mintAmount); - } - - totalSupply = vars.totalSupplyNew; - accountTokens[minter] = SupplySnapshot({ - tokens: vars.accountTokensNew, - underlyingAmount: mintAmount, - suppliedAt: accrualBlockNumber, - promisedSupplyRate: currentSupplyRate - }); - - emit Mint(minter, vars.actualMintAmount, vars.mintTokens); - emit Transfer(address(this), minter, vars.mintTokens); - - return (uint256(Error.NO_ERROR), vars.actualMintAmount); - } - - /** - * @notice Sender redeems cTokens in exchange for a specified amount of underlying asset - * @dev Accrues interest whether or not the operation succeeds, unless reverted - * @param redeemAmount The amount of underlying to receive from redeeming cTokens - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function redeemUnderlyingInternal(uint256 redeemAmount) - internal - nonReentrant - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return - fail(Error(error), FailureInfo.REDEEM_ACCRUE_INTEREST_FAILED); - } - return redeemFresh(payable(msg.sender), redeemAmount); - } - - struct RedeemLocalVars { - Error err; - MathError mathErr; - uint256 exchangeRateMantissa; - uint256 redeemTokens; - uint256 redeemAmount; - uint256 totalSupplyNew; - uint256 accountTokensNew; - uint256 newSubsidyFund; - } - - /** - * @notice User redeems cTokens in exchange for the underlying asset - * @dev Assumes interest has already been accrued up to the current block - * @param redeemer The address of the account which is redeeming the tokens - * @param redeemAmountIn The number of underlying tokens to receive from redeeming cTokens - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function redeemFresh(address payable redeemer, uint256 redeemAmountIn) - internal - returns (uint256) - { - require(redeemAmountIn > 0, "CT15"); - - RedeemLocalVars memory vars; - - SupplySnapshot storage supplySnapshot = accountTokens[redeemer]; - - ( - vars.mathErr, - vars.exchangeRateMantissa - ) = exchangeRateStoredInternal(); - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.REDEEM_EXCHANGE_RATE_READ_FAILED, - uint256(vars.mathErr) - ); - } - - uint256 interestEarned; - uint256 subsidyFundPortion; - uint256 currentUnderlying; - - bool isTropykusInterestRateModel = interestRateModel - .isTropykusInterestRateModel(); - if (isTropykusInterestRateModel) { - currentUnderlying = supplySnapshot.underlyingAmount; - (, , interestEarned) = tropykusInterestAccrued(redeemer); - } - supplySnapshot.promisedSupplyRate = interestRateModel.getSupplyRate( - getCashPrior(), - totalBorrows, - totalReserves, - reserveFactorMantissa - ); - - if ( - isTropykusInterestRateModel && - !interestRateModel.isAboveOptimal( - getCashPrior(), - totalBorrows, - totalReserves - ) - ) { - uint256 borrowRate = interestRateModel.getBorrowRate( - getCashPrior(), - totalBorrows, - totalReserves - ); - - uint256 utilizationRate = interestRateModel.utilizationRate( - getCashPrior(), - totalBorrows, - totalReserves - ); - - (, uint256 estimatedEarning) = mulScalarTruncate( - Exp({mantissa: borrowRate}), - utilizationRate - ); - - (, subsidyFundPortion) = subUInt( - supplySnapshot.promisedSupplyRate, - estimatedEarning - ); - (, Exp memory subsidyFactor) = getExp( - subsidyFundPortion, - supplySnapshot.promisedSupplyRate - ); - (, subsidyFundPortion) = mulScalarTruncate( - subsidyFactor, - interestEarned - ); - } - - vars.redeemAmount = redeemAmountIn; - - if (isTropykusInterestRateModel) { - (, Exp memory num) = mulExp( - vars.redeemAmount, - supplySnapshot.tokens - ); - (, Exp memory realTokensWithdrawAmount) = getExp( - num.mantissa, - currentUnderlying - ); - vars.redeemTokens = realTokensWithdrawAmount.mantissa; - } else { - (vars.mathErr, vars.redeemTokens) = divScalarByExpTruncate( - redeemAmountIn, - Exp({mantissa: vars.exchangeRateMantissa}) - ); - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.REDEEM_EXCHANGE_AMOUNT_CALCULATION_FAILED, - uint256(vars.mathErr) - ); - } - } - // } - - uint256 allowed = comptroller.redeemAllowed( - address(this), - redeemer, - vars.redeemTokens - ); - if (allowed != 0) { - return - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.REDEEM_COMPTROLLER_REJECTION, - allowed - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.REDEEM_FRESHNESS_CHECK - ); - } - - (vars.mathErr, vars.totalSupplyNew) = subUInt( - totalSupply, - vars.redeemTokens - ); - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.REDEEM_NEW_TOTAL_SUPPLY_CALCULATION_FAILED, - uint256(vars.mathErr) - ); - } - - (, vars.newSubsidyFund) = subUInt(subsidyFund, subsidyFundPortion); - - (vars.mathErr, vars.accountTokensNew) = subUInt( - supplySnapshot.tokens, - vars.redeemTokens - ); - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.REDEEM_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED, - uint256(vars.mathErr) - ); - } - - uint256 cash = getCashPrior(); - if (isTropykusInterestRateModel) { - cash = address(this).balance; - } - - if (cash < vars.redeemAmount) { - return - fail( - Error.TOKEN_INSUFFICIENT_CASH, - FailureInfo.REDEEM_TRANSFER_OUT_NOT_POSSIBLE - ); - } - - doTransferOut(redeemer, vars.redeemAmount); - - totalSupply = vars.totalSupplyNew; - subsidyFund = vars.newSubsidyFund; - supplySnapshot.tokens = vars.accountTokensNew; - supplySnapshot.suppliedAt = accrualBlockNumber; - (, supplySnapshot.underlyingAmount) = subUInt( - supplySnapshot.underlyingAmount, - vars.redeemAmount - ); - - emit Transfer(redeemer, address(this), vars.redeemTokens); - emit Redeem(redeemer, vars.redeemAmount, vars.redeemTokens); - - comptroller.redeemVerify( - address(this), - redeemer, - vars.redeemAmount, - vars.redeemTokens - ); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Sender borrows assets from the protocol to their own address - * @param borrowAmount The amount of the underlying asset to borrow - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function borrowInternal(uint256 borrowAmount) - internal - nonReentrant - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return - fail(Error(error), FailureInfo.BORROW_ACCRUE_INTEREST_FAILED); - } - return borrowFresh(payable(msg.sender), borrowAmount); - } - - struct BorrowLocalVars { - MathError mathErr; - uint256 accountBorrows; - uint256 accountBorrowsNew; - uint256 totalBorrowsNew; - } - - /** - * @notice Users borrow assets from the protocol to their own address - * @param borrowAmount The amount of the underlying asset to borrow - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function borrowFresh(address payable borrower, uint256 borrowAmount) - internal - returns (uint256) - { - uint256 allowed = comptroller.borrowAllowed( - address(this), - borrower, - borrowAmount - ); - if (allowed != 0) { - return - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.BORROW_COMPTROLLER_REJECTION, - allowed - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.BORROW_FRESHNESS_CHECK - ); - } - - if (getCashPrior() < borrowAmount) { - return - fail( - Error.TOKEN_INSUFFICIENT_CASH, - FailureInfo.BORROW_CASH_NOT_AVAILABLE - ); - } - - BorrowLocalVars memory vars; - - (vars.mathErr, vars.accountBorrows) = borrowBalanceStoredInternal( - borrower - ); - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED, - uint256(vars.mathErr) - ); - } - - (vars.mathErr, vars.accountBorrowsNew) = addUInt( - vars.accountBorrows, - borrowAmount - ); - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED, - uint256(vars.mathErr) - ); - } - - (vars.mathErr, vars.totalBorrowsNew) = addUInt( - totalBorrows, - borrowAmount - ); - if (interestRateModel.isTropykusInterestRateModel()) { - require(vars.totalBorrowsNew <= 0.1e18, "CT25"); - } - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED, - uint256(vars.mathErr) - ); - } - - doTransferOut(borrower, borrowAmount); - - accountBorrows[borrower].principal = vars.accountBorrowsNew; - accountBorrows[borrower].interestIndex = borrowIndex; - totalBorrows = vars.totalBorrowsNew; - - emit Borrow( - borrower, - borrowAmount, - vars.accountBorrowsNew, - vars.totalBorrowsNew - ); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Sender repays their own borrow - * @param repayAmount The amount to repay - * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual repayment amount. - */ - function repayBorrowInternal(uint256 repayAmount) - internal - nonReentrant - returns (uint256, uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return ( - fail( - Error(error), - FailureInfo.REPAY_BORROW_ACCRUE_INTEREST_FAILED - ), - 0 - ); - } - return repayBorrowFresh(msg.sender, msg.sender, repayAmount); - } - - struct RepayBorrowLocalVars { - Error err; - MathError mathErr; - uint256 repayAmount; - uint256 borrowerIndex; - uint256 accountBorrows; - uint256 accountBorrowsNew; - uint256 totalBorrowsNew; - uint256 actualRepayAmount; - } - - /** - * @notice Borrows are repaid by another user (possibly the borrower). - * @param payer the account paying off the borrow - * @param borrower the account with the debt being payed off - * @param repayAmount the amount of undelrying tokens being returned - * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual repayment amount. - */ - function repayBorrowFresh( - address payer, - address borrower, - uint256 repayAmount - ) internal returns (uint256, uint256) { - uint256 allowed = comptroller.repayBorrowAllowed( - address(this), - payer, - borrower, - repayAmount - ); - if (allowed != 0) { - return ( - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.REPAY_BORROW_COMPTROLLER_REJECTION, - allowed - ), - 0 - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return ( - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.REPAY_BORROW_FRESHNESS_CHECK - ), - 0 - ); - } - - RepayBorrowLocalVars memory vars; - - vars.borrowerIndex = accountBorrows[borrower].interestIndex; - - (vars.mathErr, vars.accountBorrows) = borrowBalanceStoredInternal( - borrower - ); - if (vars.mathErr != MathError.NO_ERROR) { - return ( - failOpaque( - Error.MATH_ERROR, - FailureInfo - .REPAY_BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED, - uint256(vars.mathErr) - ), - 0 - ); - } - - if (repayAmount == type(uint256).max) { - vars.repayAmount = vars.accountBorrows; - } else { - vars.repayAmount = repayAmount; - } - - vars.actualRepayAmount = doTransferIn(payer, vars.repayAmount); - - (vars.mathErr, vars.accountBorrowsNew) = subUInt( - vars.accountBorrows, - vars.actualRepayAmount - ); - require(vars.mathErr == MathError.NO_ERROR, "CT16"); - - (vars.mathErr, vars.totalBorrowsNew) = subUInt( - totalBorrows, - vars.actualRepayAmount - ); - require(vars.mathErr == MathError.NO_ERROR, "CT17"); - - accountBorrows[borrower].principal = vars.accountBorrowsNew; - accountBorrows[borrower].interestIndex = borrowIndex; - totalBorrows = vars.totalBorrowsNew; - - emit RepayBorrow( - payer, - borrower, - vars.actualRepayAmount, - vars.accountBorrowsNew, - vars.totalBorrowsNew - ); - - return (uint256(Error.NO_ERROR), vars.actualRepayAmount); - } - - /** - * @notice The sender liquidates the borrowers collateral. - * The collateral seized is transferred to the liquidator. - * @param borrower The borrower of this cToken to be liquidated - * @param cTokenCollateral The market in which to seize collateral from the borrower - * @param repayAmount The amount of the underlying borrowed asset to repay - * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual repayment amount. - */ - function liquidateBorrowInternal( - address borrower, - uint256 repayAmount, - CTokenInterface cTokenCollateral - ) internal nonReentrant returns (uint256, uint256) { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return ( - fail( - Error(error), - FailureInfo.LIQUIDATE_ACCRUE_BORROW_INTEREST_FAILED - ), - 0 - ); - } - - error = cTokenCollateral.accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return ( - fail( - Error(error), - FailureInfo.LIQUIDATE_ACCRUE_COLLATERAL_INTEREST_FAILED - ), - 0 - ); - } - - // liquidateBorrowFresh emits borrow-specific logs on errors, so we don't need to - return - liquidateBorrowFresh( - msg.sender, - borrower, - repayAmount, - cTokenCollateral - ); - } - - /** - * @notice The liquidator liquidates the borrowers collateral. - * The collateral seized is transferred to the liquidator. - * @param borrower The borrower of this cToken to be liquidated - * @param liquidator The address repaying the borrow and seizing collateral - * @param cTokenCollateral The market in which to seize collateral from the borrower - * @param repayAmount The amount of the underlying borrowed asset to repay - * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual repayment amount. - */ - function liquidateBorrowFresh( - address liquidator, - address borrower, - uint256 repayAmount, - CTokenInterface cTokenCollateral - ) internal returns (uint256, uint256) { - uint256 allowed = comptroller.liquidateBorrowAllowed( - address(this), - address(cTokenCollateral), - liquidator, - borrower, - repayAmount - ); - if (allowed != 0) { - return ( - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.LIQUIDATE_COMPTROLLER_REJECTION, - allowed - ), - 0 - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return ( - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.LIQUIDATE_FRESHNESS_CHECK - ), - 0 - ); - } - - if (cTokenCollateral.accrualBlockNumber() != getBlockNumber()) { - return ( - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.LIQUIDATE_COLLATERAL_FRESHNESS_CHECK - ), - 0 - ); - } - - if (borrower == liquidator) { - return ( - fail( - Error.INVALID_ACCOUNT_PAIR, - FailureInfo.LIQUIDATE_LIQUIDATOR_IS_BORROWER - ), - 0 - ); - } - - if (repayAmount == 0) { - return ( - fail( - Error.INVALID_CLOSE_AMOUNT_REQUESTED, - FailureInfo.LIQUIDATE_CLOSE_AMOUNT_IS_ZERO - ), - 0 - ); - } - - if (repayAmount == type(uint256).max) { - return ( - fail( - Error.INVALID_CLOSE_AMOUNT_REQUESTED, - FailureInfo.LIQUIDATE_CLOSE_AMOUNT_IS_UINT_MAX - ), - 0 - ); - } - - ( - uint256 repayBorrowError, - uint256 actualRepayAmount - ) = repayBorrowFresh(liquidator, borrower, repayAmount); - if (repayBorrowError != uint256(Error.NO_ERROR)) { - return ( - fail( - Error(repayBorrowError), - FailureInfo.LIQUIDATE_REPAY_BORROW_FRESH_FAILED - ), - 0 - ); - } - - (uint256 amountSeizeError, uint256 seizeTokens) = comptroller - .liquidateCalculateSeizeTokens( - address(this), - address(cTokenCollateral), - actualRepayAmount - ); - require(amountSeizeError == uint256(Error.NO_ERROR), "CT18"); - - require(cTokenCollateral.balanceOf(borrower) >= seizeTokens, "CT19"); - - uint256 seizeError; - if (address(cTokenCollateral) == address(this)) { - seizeError = seizeInternal( - address(this), - liquidator, - borrower, - seizeTokens - ); - } else { - seizeError = cTokenCollateral.seize( - liquidator, - borrower, - seizeTokens - ); - } - - require(seizeError == uint256(Error.NO_ERROR), "CT20"); - - emit LiquidateBorrow( - liquidator, - borrower, - actualRepayAmount, - address(cTokenCollateral), - seizeTokens - ); - - return (uint256(Error.NO_ERROR), actualRepayAmount); - } - - /** - * @notice Transfers collateral tokens (this market) to the liquidator. - * @dev Will fail unless called by another cToken during the process of liquidation. - * Its absolutely critical to use msg.sender as the borrowed cToken and not a parameter. - * @param liquidator The account receiving seized collateral - * @param borrower The account having collateral seized - * @param seizeTokens The number of cTokens to seize - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function seize( - address liquidator, - address borrower, - uint256 seizeTokens - ) external override nonReentrant returns (uint256) { - return seizeInternal(msg.sender, liquidator, borrower, seizeTokens); - } - - struct SeizeVars { - uint256 seizeAmount; - uint256 exchangeRate; - uint256 borrowerTokensNew; - uint256 borrowerAmountNew; - uint256 liquidatorTokensNew; - uint256 liquidatorAmountNew; - uint256 totalCash; - uint256 supplyRate; - } - - /** - * @notice Transfers collateral tokens (this market) to the liquidator. - * @dev Called only during an in-kind liquidation, or by liquidateBorrow during the liquidation of another CToken. - * Its absolutely critical to use msg.sender as the seizer cToken and not a parameter. - * @param seizerToken The contract seizing the collateral (i.e. borrowed cToken) - * @param liquidator The account receiving seized collateral - * @param borrower The account having collateral seized - * @param seizeTokens The number of cTokens to seize - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function seizeInternal( - address seizerToken, - address liquidator, - address borrower, - uint256 seizeTokens - ) internal returns (uint256) { - uint256 allowed = comptroller.seizeAllowed( - address(this), - seizerToken, - liquidator, - borrower, - seizeTokens - ); - if (allowed != 0) { - return - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.LIQUIDATE_SEIZE_COMPTROLLER_REJECTION, - allowed - ); - } - - if (borrower == liquidator) { - return - fail( - Error.INVALID_ACCOUNT_PAIR, - FailureInfo.LIQUIDATE_SEIZE_LIQUIDATOR_IS_BORROWER - ); - } - - SeizeVars memory seizeVars; - - MathError mathErr; - - (mathErr, seizeVars.borrowerTokensNew) = subUInt( - accountTokens[borrower].tokens, - seizeTokens - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.LIQUIDATE_SEIZE_BALANCE_DECREMENT_FAILED, - uint256(mathErr) - ); - } - - seizeVars.totalCash = getCashPrior(); - seizeVars.supplyRate = interestRateModel.getSupplyRate( - seizeVars.totalCash, - totalBorrows, - totalReserves, - reserveFactorMantissa - ); - - (, seizeVars.exchangeRate) = interestRateModel.getExchangeRate( - seizeVars.totalCash, - totalBorrows, - totalReserves, - totalSupply - ); - - if (interestRateModel.isTropykusInterestRateModel()) { - (, seizeVars.exchangeRate) = tropykusExchangeRateStoredInternal( - borrower - ); - } - - (, seizeVars.seizeAmount) = mulUInt( - seizeTokens, - seizeVars.exchangeRate - ); - (, seizeVars.seizeAmount) = divUInt(seizeVars.seizeAmount, 1e18); - - (, seizeVars.borrowerAmountNew) = subUInt( - accountTokens[borrower].underlyingAmount, - seizeVars.seizeAmount - ); - - (mathErr, seizeVars.liquidatorTokensNew) = addUInt( - accountTokens[liquidator].tokens, - seizeTokens - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.LIQUIDATE_SEIZE_BALANCE_INCREMENT_FAILED, - uint256(mathErr) - ); - } - - (, seizeVars.liquidatorAmountNew) = addUInt( - accountTokens[liquidator].underlyingAmount, - seizeVars.seizeAmount - ); - - accountTokens[borrower].tokens = seizeVars.borrowerTokensNew; - accountTokens[borrower].underlyingAmount = seizeVars.borrowerAmountNew; - accountTokens[borrower].suppliedAt = getBlockNumber(); - accountTokens[borrower].promisedSupplyRate = seizeVars.supplyRate; - - accountTokens[liquidator].tokens = seizeVars.liquidatorTokensNew; - accountTokens[liquidator].underlyingAmount = seizeVars - .liquidatorAmountNew; - accountTokens[liquidator].suppliedAt = getBlockNumber(); - accountTokens[liquidator].promisedSupplyRate = seizeVars.supplyRate; - - emit Transfer(borrower, liquidator, seizeTokens); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Begins transfer of admin rights. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer. - * @dev Admin function to begin change of admin. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer. - * @param newPendingAdmin New pending admin. - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setPendingAdmin(address payable newPendingAdmin) - external - override - returns (uint256) - { - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_PENDING_ADMIN_OWNER_CHECK - ); - } - - address oldPendingAdmin = pendingAdmin; - - pendingAdmin = newPendingAdmin; - - emit NewPendingAdmin(oldPendingAdmin, newPendingAdmin); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Accepts transfer of admin rights. msg.sender must be pendingAdmin - * @dev Admin function for pending admin to accept role and update admin - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _acceptAdmin() external override returns (uint256) { - if (msg.sender != pendingAdmin || msg.sender == address(0)) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.ACCEPT_ADMIN_PENDING_ADMIN_CHECK - ); - } - - address oldAdmin = admin; - address oldPendingAdmin = pendingAdmin; - - admin = pendingAdmin; - - pendingAdmin = payable(address(0)); - - emit NewAdmin(oldAdmin, admin); - emit NewPendingAdmin(oldPendingAdmin, pendingAdmin); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Sets a new comptroller for the market - * @dev Admin function to set a new comptroller - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setComptroller(ComptrollerInterface newComptroller) - public - override - returns (uint256) - { - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_COMPTROLLER_OWNER_CHECK - ); - } - - ComptrollerInterface oldComptroller = comptroller; - require(newComptroller.isComptroller(), "CT21"); - - comptroller = newComptroller; - - emit NewComptroller(oldComptroller, newComptroller); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice accrues interest and sets a new reserve factor for the protocol using _setReserveFactorFresh - * @dev Admin function to accrue interest and set a new reserve factor - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setReserveFactor(uint256 newReserveFactorMantissa) - external - override - nonReentrant - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return - fail( - Error(error), - FailureInfo.SET_RESERVE_FACTOR_ACCRUE_INTEREST_FAILED - ); - } - return _setReserveFactorFresh(newReserveFactorMantissa); - } - - /** - * @notice Sets a new reserve factor for the protocol (*requires fresh interest accrual) - * @dev Admin function to set a new reserve factor - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setReserveFactorFresh(uint256 newReserveFactorMantissa) - internal - returns (uint256) - { - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_RESERVE_FACTOR_ADMIN_CHECK - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.SET_RESERVE_FACTOR_FRESH_CHECK - ); - } - - if (newReserveFactorMantissa > reserveFactorMaxMantissa) { - return - fail( - Error.BAD_INPUT, - FailureInfo.SET_RESERVE_FACTOR_BOUNDS_CHECK - ); - } - - uint256 oldReserveFactorMantissa = reserveFactorMantissa; - reserveFactorMantissa = newReserveFactorMantissa; - - emit NewReserveFactor( - oldReserveFactorMantissa, - newReserveFactorMantissa - ); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Accrues interest and reduces reserves by transferring from msg.sender - * @param addAmount Amount of addition to reserves - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _addReservesInternal(uint256 addAmount) - internal - nonReentrant - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return - fail( - Error(error), - FailureInfo.ADD_RESERVES_ACCRUE_INTEREST_FAILED - ); - } - - uint256 totalReservesNew; - uint256 actualAddAmount; - - if (accrualBlockNumber != getBlockNumber()) { - return ( - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.ADD_RESERVES_FRESH_CHECK - ) - ); - } - - actualAddAmount = doTransferIn(msg.sender, addAmount); - - totalReservesNew = totalReserves + actualAddAmount; - - require(totalReservesNew >= totalReserves, "CT22"); - - totalReserves = totalReservesNew; - - emit ReservesAdded(msg.sender, actualAddAmount, totalReservesNew); - - return (uint256(Error.NO_ERROR)); - } - - function _addSubsidyInternal(uint256 addAmount) - internal - nonReentrant - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - // accrueInterest emits logs on errors, but on top of that we want to log the fact that an attempted reduce reserves failed. - return fail(Error(error), FailureInfo.ADD_SUBSIDY_FUND_FAILED); - } - - uint256 subsidyFundNew; - uint256 actualAddAmount; - - if (accrualBlockNumber != getBlockNumber()) { - return ( - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.ADD_SUBSIDY_FUND_FRESH_CHECK - ) - ); - } - - actualAddAmount = doTransferIn(msg.sender, addAmount); - - subsidyFundNew = subsidyFund + actualAddAmount; - - require(subsidyFundNew >= subsidyFund, "CT22"); - - subsidyFund = subsidyFundNew; - - emit SubsidyAdded(msg.sender, actualAddAmount, subsidyFundNew); - - /* Return (NO_ERROR, actualAddAmount) */ - return (uint256(Error.NO_ERROR)); - } - - /** - * @notice Accrues interest and reduces reserves by transferring to admin - * @param reduceAmount Amount of reduction to reserves - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _reduceReserves(uint256 reduceAmount) - external - override - nonReentrant - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return - fail( - Error(error), - FailureInfo.REDUCE_RESERVES_ACCRUE_INTEREST_FAILED - ); - } - return _reduceReservesFresh(reduceAmount); - } - - /** - * @notice Reduces reserves by transferring to admin - * @dev Requires fresh interest accrual - * @param reduceAmount Amount of reduction to reserves - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _reduceReservesFresh(uint256 reduceAmount) - internal - returns (uint256) - { - uint256 totalReservesNew; - - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.REDUCE_RESERVES_ADMIN_CHECK - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.REDUCE_RESERVES_FRESH_CHECK - ); - } - - if (getCashPrior() < reduceAmount) { - return - fail( - Error.TOKEN_INSUFFICIENT_CASH, - FailureInfo.REDUCE_RESERVES_CASH_NOT_AVAILABLE - ); - } - - if (reduceAmount > totalReserves) { - return - fail(Error.BAD_INPUT, FailureInfo.REDUCE_RESERVES_VALIDATION); - } - - totalReservesNew = totalReserves - reduceAmount; - require(totalReservesNew <= totalReserves, "CT23"); - - totalReserves = totalReservesNew; - - doTransferOut(admin, reduceAmount); - - emit ReservesReduced(admin, reduceAmount, totalReservesNew); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice accrues interest and updates the interest rate model using _setInterestRateModelFresh - * @dev Admin function to accrue interest and update the interest rate model - * @param newInterestRateModel the new interest rate model to use - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setInterestRateModel(InterestRateModel newInterestRateModel) - public - override - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return - fail( - Error(error), - FailureInfo.SET_INTEREST_RATE_MODEL_ACCRUE_INTEREST_FAILED - ); - } - return _setInterestRateModelFresh(newInterestRateModel); - } - - /** - * @notice updates the interest rate model (*requires fresh interest accrual) - * @dev Admin function to update the interest rate model - * @param newInterestRateModel the new interest rate model to use - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setInterestRateModelFresh(InterestRateModel newInterestRateModel) - internal - returns (uint256) - { - InterestRateModel oldInterestRateModel; - - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_INTEREST_RATE_MODEL_OWNER_CHECK - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.SET_INTEREST_RATE_MODEL_FRESH_CHECK - ); - } - - oldInterestRateModel = interestRateModel; - - require(newInterestRateModel.isInterestRateModel(), "CT21"); - - interestRateModel = newInterestRateModel; - - emit NewMarketInterestRateModel( - oldInterestRateModel, - newInterestRateModel - ); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Gets balance of this contract in terms of the underlying - * @dev This excludes the value of the current message, if any - * @return The quantity of underlying owned by this contract - */ - function getCashPrior() internal view virtual returns (uint256); - - /** - * @dev Performs a transfer in, reverting upon failure. Returns the amount actually transferred to the protocol, in case of a fee. - * This may revert due to insufficient balance or insufficient allowance. - */ - function doTransferIn(address from, uint256 amount) - internal - virtual - returns (uint256); - - /** - * @dev Performs a transfer out, ideally returning an explanatory error code upon failure tather than reverting. - * If caller has not called checked protocol's balance, may revert due to insufficient cash held in the contract. - * If caller has checked protocol's balance, and verified it is >= amount, this should not revert in normal conditions. - */ - function doTransferOut(address payable to, uint256 amount) internal virtual; - - /** - * @dev Prevents a contract from calling itself, directly or indirectly. - */ - modifier nonReentrant() { - require(_notEntered, "re-entered"); - _notEntered = false; - _; - _notEntered = true; - } -} - - -// Dependency file: contracts/PriceOracle.sol - -// pragma solidity 0.8.6; - -// import "contracts/CToken.sol"; - -abstract contract PriceOracle { - /// @notice Indicator that this is a PriceOracle contract (for inspection) - bool public constant isPriceOracle = true; - - /** - * @notice Get the underlying price of a cToken asset - * @param cToken The cToken to get the underlying price of - * @return The underlying asset price mantissa (scaled by 1e18). - * Zero means the price is unavailable. - */ - function getUnderlyingPrice(CToken cToken) - external - view - virtual - returns (uint256); -} - - -// Dependency file: contracts/CErc20.sol - -// pragma solidity 0.8.6; - -// import "contracts/CToken.sol"; -// import "contracts/CTokenInterfaces.sol"; - -/** - * @title tropykus CErc20 Contract - * @notice CTokens which wrap an EIP-20 underlying - * @author tropykus - */ -contract CErc20 is CToken, CErc20Interface { - /** - * @notice Initialize the new money market - * @param underlying_ The address of the underlying asset - * @param comptroller_ The address of the Comptroller - * @param interestRateModel_ The address of the interest rate model - * @param initialExchangeRateMantissa_ The initial exchange rate, scaled by 1e18 - * @param name_ ERC-20 name of this token - * @param symbol_ ERC-20 symbol of this token - * @param decimals_ ERC-20 decimal precision of this token - */ - function initialize( - address underlying_, - ComptrollerInterface comptroller_, - InterestRateModel interestRateModel_, - uint256 initialExchangeRateMantissa_, - string memory name_, - string memory symbol_, - uint8 decimals_ - ) public { - // CToken initialize does the bulk of the work - super.initialize( - comptroller_, - interestRateModel_, - initialExchangeRateMantissa_, - name_, - symbol_, - decimals_ - ); - - // Set underlying and sanity check it - underlying = underlying_; - EIP20Interface(underlying).totalSupply(); - } - - /*** User Interface ***/ - - /** - * @notice Sender supplies assets into the market and receives cTokens in exchange - * @dev Accrues interest whether or not the operation succeeds, unless reverted - * @param mintAmount The amount of the underlying asset to supply - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function mint(uint256 mintAmount) external override returns (uint256) { - (uint256 err, ) = mintInternal(mintAmount); - return err; - } - - /** - * @notice Sender redeems cTokens in exchange for a specified amount of underlying asset - * @dev Accrues interest whether or not the operation succeeds, unless reverted - * @param redeemAmount The amount of underlying to redeem - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function redeem(uint256 redeemAmount) - external - override - returns (uint256) - { - return redeemUnderlyingInternal(redeemAmount); - } - - /** - * @notice Sender borrows assets from the protocol to their own address - * @param borrowAmount The amount of the underlying asset to borrow - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function borrow(uint256 borrowAmount) external override returns (uint256) { - return borrowInternal(borrowAmount); - } - - /** - * @notice Sender repays their own borrow - * @param repayAmount The amount to repay - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function repayBorrow(uint256 repayAmount) - external - override - returns (uint256) - { - (uint256 err, ) = repayBorrowInternal(repayAmount); - return err; - } - - /** - * @notice The sender liquidates the borrowers collateral. - * The collateral seized is transferred to the liquidator. - * @param borrower The borrower of this cToken to be liquidated - * @param repayAmount The amount of the underlying borrowed asset to repay - * @param cTokenCollateral The market in which to seize collateral from the borrower - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function liquidateBorrow( - address borrower, - uint256 repayAmount, - CTokenInterface cTokenCollateral - ) external override returns (uint256) { - (uint256 err, ) = liquidateBorrowInternal( - borrower, - repayAmount, - cTokenCollateral - ); - return err; - } - - /** - * @notice A public function to sweep accidental ERC-20 transfers to this contract. Tokens are sent to admin (timelock) - * @param token The address of the ERC-20 token to sweep - */ - function sweepToken(EIP20NonStandardInterface token) external override { - require(address(token) != underlying, "EC01"); - uint256 balance = token.balanceOf(address(this)); - token.transfer(admin, balance); - } - - /** - * @notice The sender adds to reserves. - * @param addAmount The amount fo underlying token to add as reserves - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _addReserves(uint256 addAmount) - external - override - returns (uint256) - { - return _addReservesInternal(addAmount); - } - - /*** Safe Token ***/ - - /** - * @notice Gets balance of this contract in terms of the underlying - * @dev This excludes the value of the current message, if any - * @return The quantity of underlying tokens owned by this contract - */ - function getCashPrior() internal view override returns (uint256) { - EIP20Interface token = EIP20Interface(underlying); - return token.balanceOf(address(this)); - } - - /** - * @dev Similar to EIP20 transfer, except it handles a False result from `transferFrom` and reverts in that case. - * This will revert due to insufficient balance or insufficient allowance. - * This function returns the actual amount received, - * which may be less than `amount` if there is a fee attached to the transfer. - * - * Note: This wrapper safely handles non-standard ERC-20 tokens that do not return a value. - * See here: https://medium.com/coinmonks/missing-return-value-bug-at-least-130-tokens-affected-d67bf08521ca - */ - function doTransferIn(address from, uint256 amount) - internal - override - returns (uint256) - { - EIP20NonStandardInterface token = EIP20NonStandardInterface(underlying); - uint256 balanceBefore = EIP20Interface(underlying).balanceOf( - address(this) - ); - token.transferFrom(from, address(this), amount); - - bool success; - assembly { - switch returndatasize() - case 0 { - // This is a non-standard ERC-20 - success := not(0) // set success to true - } - case 32 { - // This is a compliant ERC-20 - returndatacopy(0, 0, 32) - success := mload(0) // Set `success = returndata` of external call - } - default { - // This is an excessively non-compliant ERC-20, revert. - revert(0, 0) - } - } - require(success, "EC02"); - - // Calculate the amount that was *actually* transferred - uint256 balanceAfter = EIP20Interface(underlying).balanceOf( - address(this) - ); - require(balanceAfter >= balanceBefore, "EC03"); - return balanceAfter - balanceBefore; // underflow already checked above, just subtract - } - - /** - * @dev Similar to EIP20 transfer, except it handles a False success from `transfer` and returns an explanatory - * error code rather than reverting. If caller has not called checked protocol's balance, this may revert due to - * insufficient cash held in this contract. If caller has checked protocol's balance prior to this call, and verified - * it is >= amount, this should not revert in normal conditions. - * - * Note: This wrapper safely handles non-standard ERC-20 tokens that do not return a value. - * See here: https://medium.com/coinmonks/missing-return-value-bug-at-least-130-tokens-affected-d67bf08521ca - */ - function doTransferOut(address payable to, uint256 amount) - internal - virtual - override - { - EIP20NonStandardInterface token = EIP20NonStandardInterface(underlying); - token.transfer(to, amount); - - bool success; - assembly { - switch returndatasize() - case 0 { - // This is a non-standard ERC-20 - success := not(0) // set success to true - } - case 32 { - // This is a complaint ERC-20 - returndatacopy(0, 0, 32) - success := mload(0) // Set `success = returndata` of external call - } - default { - // This is an excessively non-compliant ERC-20, revert. - revert(0, 0) - } - } - require(success, "CE01"); - } -} - - -// Root file: contracts/mocks/SimplePriceOracle.sol - -pragma solidity 0.8.6; - -// import "contracts/PriceOracle.sol"; -// import "contracts/CErc20.sol"; - -/** - * @title Simplified Oracle for testing purposes. - * @author tropykus - * @notice This contract is meant for testing only. - */ -contract SimplePriceOracle is PriceOracle { - mapping(address => uint256) prices; - event PricePosted( - address asset, - uint256 previousPriceMantissa, - uint256 requestedPriceMantissa, - uint256 newPriceMantissa - ); - - function getUnderlyingPrice(CToken cToken) - public - view - override - returns (uint256) - { - if (compareStrings(cToken.symbol(), "cRBTC")) { - return prices[(address(cToken))]; - } else { - return prices[address(CErc20(address(cToken)).underlying())]; - } - } - - function setUnderlyingPrice(CToken cToken, uint256 underlyingPriceMantissa) - public - { - address asset = address(CErc20(address(cToken)).underlying()); - emit PricePosted( - asset, - prices[asset], - underlyingPriceMantissa, - underlyingPriceMantissa - ); - prices[asset] = underlyingPriceMantissa; - } - - function setDirectPrice(address asset, uint256 price) public { - emit PricePosted(asset, prices[asset], price, price); - prices[asset] = price; - } - - // v1 price oracle interface for use as backing of proxy - function assetPrices(address asset) external view returns (uint256) { - return prices[asset]; - } - - function compareStrings(string memory a, string memory b) - internal - pure - returns (bool) - { - return (keccak256(abi.encodePacked((a))) == - keccak256(abi.encodePacked((b)))); - } -} diff --git a/flatten/TROP.sol b/flatten/TROP.sol deleted file mode 100644 index b57f08d..0000000 --- a/flatten/TROP.sol +++ /dev/null @@ -1,448 +0,0 @@ -// Root file: contracts/Governance/TROP.sol - -// SPDX-License-Identifier: UNLICENSED -pragma solidity 0.8.6; -pragma experimental ABIEncoderV2; - -/** - * @title TROP ERC20 tokens. - * @author tropykus - * @notice Yield farming tokens that allow to propose and vote for protocol changes using the governance system. - */ -contract TROP { - /// @notice EIP-20 token name for this token - string public constant name = "tropykus"; - - /// @notice EIP-20 token symbol for this token - string public constant symbol = "TROP"; - - /// @notice EIP-20 token decimals for this token - uint8 public constant decimals = 18; - - /// @notice Total number of tokens in circulation - uint256 public constant totalSupply = 10000000e18; // 10 million TROP - - /// @notice Allowance amounts on behalf of others - mapping(address => mapping(address => uint96)) internal allowances; - - /// @notice Official record of token balances for each account - mapping(address => uint96) internal balances; - - /// @notice A record of each accounts delegate - mapping(address => address) public delegates; - - /// @notice A checkpoint for marking number of votes from a given block - struct Checkpoint { - uint32 fromBlock; - uint96 votes; - } - - /// @notice A record of votes checkpoints for each account, by index - mapping(address => mapping(uint32 => Checkpoint)) public checkpoints; - - /// @notice The number of checkpoints for each account - mapping(address => uint32) public numCheckpoints; - - /// @notice The EIP-712 typehash for the contract's domain - bytes32 public constant DOMAIN_TYPEHASH = - keccak256( - "EIP712Domain(string name,uint256 chainId,address verifyingContract)" - ); - - /// @notice The EIP-712 typehash for the delegation struct used by the contract - bytes32 public constant DELEGATION_TYPEHASH = - keccak256("Delegation(address delegatee,uint256 nonce,uint256 expiry)"); - - /// @notice A record of states for signing / validating signatures - mapping(address => uint256) public nonces; - - /// @notice An event thats emitted when an account changes its delegate - event DelegateChanged( - address indexed delegator, - address indexed fromDelegate, - address indexed toDelegate - ); - - /// @notice An event thats emitted when a delegate account's vote balance changes - event DelegateVotesChanged( - address indexed delegate, - uint256 previousBalance, - uint256 newBalance - ); - - /// @notice The standard EIP-20 transfer event - event Transfer(address indexed from, address indexed to, uint256 amount); - - /// @notice The standard EIP-20 approval event - event Approval( - address indexed owner, - address indexed spender, - uint256 amount - ); - - /** - * @notice Construct a new TROP token - * @param account The initial account to grant all the tokens - */ - constructor(address account) { - balances[account] = uint96(totalSupply); - emit Transfer(address(0), account, totalSupply); - } - - /** - * @notice Get the number of tokens `spender` is approved to spend on behalf of `account` - * @param account The address of the account holding the funds - * @param spender The address of the account spending the funds - * @return The number of tokens approved - */ - function allowance(address account, address spender) - external - view - returns (uint256) - { - return allowances[account][spender]; - } - - /** - * @notice Approve `spender` to transfer up to `amount` from `src` - * @dev This will overwrite the approval amount for `spender` - * and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve) - * @param spender The address of the account which may transfer tokens - * @param rawAmount The number of tokens that are approved (2^256-1 means infinite) - * @return Whether or not the approval succeeded - */ - function approve(address spender, uint256 rawAmount) - external - returns (bool) - { - uint96 amount; - if (rawAmount == type(uint256).max) { - amount = type(uint96).max; - } else { - amount = safe96(rawAmount, "TROP::approve: amount exceeds 96 bits"); - } - - allowances[msg.sender][spender] = amount; - - emit Approval(msg.sender, spender, amount); - return true; - } - - /** - * @notice Get the number of tokens held by the `account` - * @param account The address of the account to get the balance of - * @return The number of tokens held - */ - function balanceOf(address account) external view returns (uint256) { - return balances[account]; - } - - /** - * @notice Transfer `amount` tokens from `msg.sender` to `dst` - * @param dst The address of the destination account - * @param rawAmount The number of tokens to transfer - * @return Whether or not the transfer succeeded - */ - function transfer(address dst, uint256 rawAmount) external returns (bool) { - uint96 amount = safe96( - rawAmount, - "TROP::transfer: amount exceeds 96 bits" - ); - _transferTokens(msg.sender, dst, amount); - return true; - } - - /** - * @notice Transfer `amount` tokens from `src` to `dst` - * @param src The address of the source account - * @param dst The address of the destination account - * @param rawAmount The number of tokens to transfer - * @return Whether or not the transfer succeeded - */ - function transferFrom( - address src, - address dst, - uint256 rawAmount - ) external returns (bool) { - address spender = msg.sender; - uint96 spenderAllowance = allowances[src][spender]; - uint96 amount = safe96( - rawAmount, - "TROP::approve: amount exceeds 96 bits" - ); - - if (spender != src && spenderAllowance != type(uint96).max) { - uint96 newAllowance = sub96( - spenderAllowance, - amount, - "TROP::transferFrom: transfer amount exceeds spender allowance" - ); - allowances[src][spender] = newAllowance; - - emit Approval(src, spender, newAllowance); - } - - _transferTokens(src, dst, amount); - return true; - } - - /** - * @notice Delegate votes from `msg.sender` to `delegatee` - * @param delegatee The address to delegate votes to - */ - function delegate(address delegatee) public { - return _delegate(msg.sender, delegatee); - } - - /** - * @notice Delegates votes from signatory to `delegatee` - * @param delegatee The address to delegate votes to - * @param nonce The contract state required to match the signature - * @param expiry The time at which to expire the signature - * @param v The recovery byte of the signature - * @param r Half of the ECDSA signature pair - * @param s Half of the ECDSA signature pair - */ - function delegateBySig( - address delegatee, - uint256 nonce, - uint256 expiry, - uint8 v, - bytes32 r, - bytes32 s - ) public { - bytes32 domainSeparator = keccak256( - abi.encode( - DOMAIN_TYPEHASH, - keccak256(bytes(name)), - getChainId(), - address(this) - ) - ); - bytes32 structHash = keccak256( - abi.encode(DELEGATION_TYPEHASH, delegatee, nonce, expiry) - ); - bytes32 digest = keccak256( - abi.encodePacked("\x19\x01", domainSeparator, structHash) - ); - address signatory = ecrecover(digest, v, r, s); - require( - signatory != 0xdcc703c0E500B653Ca82273B7BFAd8045D85a470 && - signatory != address(0), - "TROP::delegateBySig: invalid signature" - ); - require( - nonce == nonces[signatory]++, - "TROP::delegateBySig: invalid nonce" - ); - require( - block.timestamp <= expiry, - "TROP::delegateBySig: signature expired" - ); - return _delegate(signatory, delegatee); - } - - /** - * @notice Gets the current votes balance for `account` - * @param account The address to get votes balance - * @return The number of current votes for `account` - */ - function getCurrentVotes(address account) external view returns (uint96) { - uint32 nCheckpoints = numCheckpoints[account]; - return - nCheckpoints > 0 ? checkpoints[account][nCheckpoints - 1].votes : 0; - } - - /** - * @notice Determine the prior number of votes for an account as of a block number - * @dev Block number must be a finalized block or else this function will revert to prevent misinformation. - * @param account The address of the account to check - * @param blockNumber The block number to get the vote balance at - * @return The number of votes the account had as of the given block - */ - function getPriorVotes(address account, uint256 blockNumber) - public - view - returns (uint96) - { - require( - blockNumber < block.number, - "TROP::getPriorVotes: not yet determined" - ); - - uint32 nCheckpoints = numCheckpoints[account]; - if (nCheckpoints == 0) { - return 0; - } - - // First check most recent balance - if (checkpoints[account][nCheckpoints - 1].fromBlock <= blockNumber) { - return checkpoints[account][nCheckpoints - 1].votes; - } - - // Next check implicit zero balance - if (checkpoints[account][0].fromBlock > blockNumber) { - return 0; - } - - uint32 lower = 0; - uint32 upper = nCheckpoints - 1; - while (upper > lower) { - uint32 center = upper - (upper - lower) / 2; // ceil, avoiding overflow - Checkpoint memory cp = checkpoints[account][center]; - if (cp.fromBlock == blockNumber) { - return cp.votes; - } else if (cp.fromBlock < blockNumber) { - lower = center; - } else { - upper = center - 1; - } - } - return checkpoints[account][lower].votes; - } - - function _delegate(address delegator, address delegatee) internal { - address currentDelegate = delegates[delegator]; - uint96 delegatorBalance = balances[delegator]; - delegates[delegator] = delegatee; - - emit DelegateChanged(delegator, currentDelegate, delegatee); - - _moveDelegates(currentDelegate, delegatee, delegatorBalance); - } - - function _transferTokens( - address src, - address dst, - uint96 amount - ) internal { - require( - src != address(0), - "TROP::_transferTokens: cannot transfer from the zero address" - ); - require( - dst != address(0), - "TROP::_transferTokens: cannot transfer to the zero address" - ); - - balances[src] = sub96( - balances[src], - amount, - "TROP::_transferTokens: transfer amount exceeds balance" - ); - balances[dst] = add96( - balances[dst], - amount, - "TROP::_transferTokens: transfer amount overflows" - ); - emit Transfer(src, dst, amount); - - _moveDelegates(delegates[src], delegates[dst], amount); - } - - function _moveDelegates( - address srcRep, - address dstRep, - uint96 amount - ) internal { - if (srcRep != dstRep && amount > 0) { - if (srcRep != address(0)) { - uint32 srcRepNum = numCheckpoints[srcRep]; - uint96 srcRepOld = srcRepNum > 0 - ? checkpoints[srcRep][srcRepNum - 1].votes - : 0; - uint96 srcRepNew = sub96( - srcRepOld, - amount, - "TROP::_moveVotes: vote amount underflows" - ); - _writeCheckpoint(srcRep, srcRepNum, srcRepOld, srcRepNew); - } - - if (dstRep != address(0)) { - uint32 dstRepNum = numCheckpoints[dstRep]; - uint96 dstRepOld = dstRepNum > 0 - ? checkpoints[dstRep][dstRepNum - 1].votes - : 0; - uint96 dstRepNew = add96( - dstRepOld, - amount, - "TROP::_moveVotes: vote amount overflows" - ); - _writeCheckpoint(dstRep, dstRepNum, dstRepOld, dstRepNew); - } - } - } - - function _writeCheckpoint( - address delegatee, - uint32 nCheckpoints, - uint96 oldVotes, - uint96 newVotes - ) internal { - uint32 blockNumber = safe32( - block.number, - "TROP::_writeCheckpoint: block number exceeds 32 bits" - ); - - if ( - nCheckpoints > 0 && - checkpoints[delegatee][nCheckpoints - 1].fromBlock == blockNumber - ) { - checkpoints[delegatee][nCheckpoints - 1].votes = newVotes; - } else { - checkpoints[delegatee][nCheckpoints] = Checkpoint( - blockNumber, - newVotes - ); - numCheckpoints[delegatee] = nCheckpoints + 1; - } - - emit DelegateVotesChanged(delegatee, oldVotes, newVotes); - } - - function safe32(uint256 n, string memory errorMessage) - internal - pure - returns (uint32) - { - require(n < 2**32, errorMessage); - return uint32(n); - } - - function safe96(uint256 n, string memory errorMessage) - internal - pure - returns (uint96) - { - require(n < 2**96, errorMessage); - return uint96(n); - } - - function add96( - uint96 a, - uint96 b, - string memory errorMessage - ) internal pure returns (uint96) { - uint96 c = a + b; - require(c >= a, errorMessage); - return c; - } - - function sub96( - uint96 a, - uint96 b, - string memory errorMessage - ) internal pure returns (uint96) { - require(b <= a, errorMessage); - return a - b; - } - - function getChainId() internal view returns (uint256) { - uint256 chainId; - assembly { - chainId := chainid() - } - return chainId; - } -} diff --git a/flatten/Timelock.sol b/flatten/Timelock.sol deleted file mode 100644 index aa7dd45..0000000 --- a/flatten/Timelock.sol +++ /dev/null @@ -1,400 +0,0 @@ -// Dependency file: contracts/SafeMath.sol - -// SPDX-License-Identifier: UNLICENSED -// pragma solidity 0.8.6; - -// From https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/math/Math.sol -// Subject to the MIT license. - -/** - * @dev Wrappers over Solidity's arithmetic operations with added overflow - * checks. - * - * Arithmetic operations in Solidity wrap on overflow. This can easily result - * in bugs, because programmers usually assume that an overflow raises an - * error, which is the standard behavior in high level programming languages. - * `SafeMath` restores this intuition by reverting the transaction when an - * operation overflows. - * - * Using this library instead of the unchecked operations eliminates an entire - * class of bugs, so it's recommended to use it always. - */ -library SafeMath { - /** - * @dev Returns the addition of two unsigned integers, reverting on overflow. - * - * Counterpart to Solidity's `+` operator. - * - * Requirements: - * - Addition cannot overflow. - */ - function add(uint256 a, uint256 b) internal pure returns (uint256) { - uint256 c = a + b; - require(c >= a, "SafeMath: addition overflow"); - - return c; - } - - /** - * @dev Returns the addition of two unsigned integers, reverting with custom message on overflow. - * - * Counterpart to Solidity's `+` operator. - * - * Requirements: - * - Addition cannot overflow. - */ - function add(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - uint256 c = a + b; - require(c >= a, errorMessage); - - return c; - } - - /** - * @dev Returns the subtraction of two unsigned integers, reverting on underflow (when the result is negative). - * - * Counterpart to Solidity's `-` operator. - * - * Requirements: - * - Subtraction cannot underflow. - */ - function sub(uint256 a, uint256 b) internal pure returns (uint256) { - return sub(a, b, "SafeMath: subtraction underflow"); - } - - /** - * @dev Returns the subtraction of two unsigned integers, reverting with custom message on underflow (when the result is negative). - * - * Counterpart to Solidity's `-` operator. - * - * Requirements: - * - Subtraction cannot underflow. - */ - function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - require(b <= a, errorMessage); - uint256 c = a - b; - - return c; - } - - /** - * @dev Returns the multiplication of two unsigned integers, reverting on overflow. - * - * Counterpart to Solidity's `*` operator. - * - * Requirements: - * - Multiplication cannot overflow. - */ - function mul(uint256 a, uint256 b) internal pure returns (uint256) { - // Gas optimization: this is cheaper than requiring 'a' not being zero, but the - // benefit is lost if 'b' is also tested. - // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 - if (a == 0) { - return 0; - } - - uint256 c = a * b; - require(c / a == b, "SafeMath: multiplication overflow"); - - return c; - } - - /** - * @dev Returns the multiplication of two unsigned integers, reverting on overflow. - * - * Counterpart to Solidity's `*` operator. - * - * Requirements: - * - Multiplication cannot overflow. - */ - function mul(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - // Gas optimization: this is cheaper than requiring 'a' not being zero, but the - // benefit is lost if 'b' is also tested. - // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 - if (a == 0) { - return 0; - } - - uint256 c = a * b; - require(c / a == b, errorMessage); - - return c; - } - - /** - * @dev Returns the integer division of two unsigned integers. - * Reverts on division by zero. The result is rounded towards zero. - * - * Counterpart to Solidity's `/` operator. Note: this function uses a - * `revert` opcode (which leaves remaining gas untouched) while Solidity - * uses an invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function div(uint256 a, uint256 b) internal pure returns (uint256) { - return div(a, b, "SafeMath: division by zero"); - } - - /** - * @dev Returns the integer division of two unsigned integers. - * Reverts with custom message on division by zero. The result is rounded towards zero. - * - * Counterpart to Solidity's `/` operator. Note: this function uses a - * `revert` opcode (which leaves remaining gas untouched) while Solidity - * uses an invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - // Solidity only automatically asserts when dividing by 0 - require(b > 0, errorMessage); - uint256 c = a / b; - // assert(a == b * c + a % b); // There is no case in which this doesn't hold - - return c; - } - - /** - * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), - * Reverts when dividing by zero. - * - * Counterpart to Solidity's `%` operator. This function uses a `revert` - * opcode (which leaves remaining gas untouched) while Solidity uses an - * invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function mod(uint256 a, uint256 b) internal pure returns (uint256) { - return mod(a, b, "SafeMath: modulo by zero"); - } - - /** - * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), - * Reverts with custom message when dividing by zero. - * - * Counterpart to Solidity's `%` operator. This function uses a `revert` - * opcode (which leaves remaining gas untouched) while Solidity uses an - * invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - require(b != 0, errorMessage); - return a % b; - } -} - - -// Root file: contracts/Timelock.sol - -pragma solidity 0.8.6; - -// import "contracts/SafeMath.sol"; - -contract Timelock { - using SafeMath for uint256; - - event NewAdmin(address indexed newAdmin); - event NewPendingAdmin(address indexed newPendingAdmin); - event NewDelay(uint256 indexed newDelay); - event CancelTransaction( - bytes32 indexed txHash, - address indexed target, - uint256 value, - string signature, - bytes data, - uint256 eta - ); - event ExecuteTransaction( - bytes32 indexed txHash, - address indexed target, - uint256 value, - string signature, - bytes data, - uint256 eta - ); - event QueueTransaction( - bytes32 indexed txHash, - address indexed target, - uint256 value, - string signature, - bytes data, - uint256 eta - ); - - uint256 public constant GRACE_PERIOD = 14 days; - uint256 public constant MINIMUM_DELAY = 2 days; - uint256 public constant MAXIMUM_DELAY = 30 days; - - address public admin; - address public pendingAdmin; - uint256 public delay; - - mapping(bytes32 => bool) public queuedTransactions; - - constructor(address admin_, uint256 delay_) { - require( - delay_ >= MINIMUM_DELAY, - "Timelock::constructor: Delay must exceed minimum delay." - ); - require( - delay_ <= MAXIMUM_DELAY, - "Timelock::setDelay: Delay must not exceed maximum delay." - ); - - admin = admin_; - delay = delay_; - } - - fallback() external payable {} - - receive() external payable {} - - function setDelay(uint256 delay_) public { - require( - msg.sender == address(this), - "Timelock::setDelay: Call must come from Timelock." - ); - require( - delay_ >= MINIMUM_DELAY, - "Timelock::setDelay: Delay must exceed minimum delay." - ); - require( - delay_ <= MAXIMUM_DELAY, - "Timelock::setDelay: Delay must not exceed maximum delay." - ); - delay = delay_; - - emit NewDelay(delay); - } - - function acceptAdmin() public { - require( - msg.sender == pendingAdmin, - "Timelock::acceptAdmin: Call must come from pendingAdmin." - ); - admin = msg.sender; - pendingAdmin = address(0); - - emit NewAdmin(admin); - } - - function setPendingAdmin(address pendingAdmin_) public { - require( - msg.sender == address(this), - "Timelock::setPendingAdmin: Call must come from Timelock." - ); - pendingAdmin = pendingAdmin_; - - emit NewPendingAdmin(pendingAdmin); - } - - function queueTransaction( - address target, - uint256 value, - string memory signature, - bytes memory data, - uint256 eta - ) public returns (bytes32) { - require( - msg.sender == admin, - "Timelock::queueTransaction: Call must come from admin." - ); - require( - eta >= getBlockTimestamp().add(delay), - "Timelock::queueTransaction: Estimated execution block must satisfy delay." - ); - - bytes32 txHash = keccak256( - abi.encode(target, value, signature, data, eta) - ); - queuedTransactions[txHash] = true; - - emit QueueTransaction(txHash, target, value, signature, data, eta); - return txHash; - } - - function cancelTransaction( - address target, - uint256 value, - string memory signature, - bytes memory data, - uint256 eta - ) public { - require( - msg.sender == admin, - "Timelock::cancelTransaction: Call must come from admin." - ); - - bytes32 txHash = keccak256( - abi.encode(target, value, signature, data, eta) - ); - queuedTransactions[txHash] = false; - - emit CancelTransaction(txHash, target, value, signature, data, eta); - } - - function executeTransaction( - address target, - uint256 value, - string memory signature, - bytes memory data, - uint256 eta - ) public payable returns (bytes memory) { - require( - msg.sender == admin, - "Timelock::executeTransaction: Call must come from admin." - ); - - bytes32 txHash = keccak256( - abi.encode(target, value, signature, data, eta) - ); - require( - queuedTransactions[txHash], - "Timelock::executeTransaction: Transaction hasn't been queued." - ); - require( - getBlockTimestamp() >= eta, - "Timelock::executeTransaction: Transaction hasn't surpassed time lock." - ); - require( - getBlockTimestamp() <= eta.add(GRACE_PERIOD), - "Timelock::executeTransaction: Transaction is stale." - ); - - queuedTransactions[txHash] = false; - - bytes memory callData; - - if (bytes(signature).length == 0) { - callData = data; - } else { - callData = abi.encodePacked( - bytes4(keccak256(bytes(signature))), - data - ); - } - - // solium-disable-next-line security/no-call-value - (bool success, bytes memory returnData) = target.call{value: value}( - callData - ); - require( - success, - "Timelock::executeTransaction: Transaction execution reverted." - ); - - emit ExecuteTransaction(txHash, target, value, signature, data, eta); - - return returnData; - } - - function getBlockTimestamp() internal view returns (uint256) { - // solium-disable-next-line security/no-block-members - return block.timestamp; - } -} diff --git a/flatten/TropykusLens.sol b/flatten/TropykusLens.sol deleted file mode 100644 index 0bd468c..0000000 --- a/flatten/TropykusLens.sol +++ /dev/null @@ -1,5518 +0,0 @@ -// Dependency file: contracts/ComptrollerInterface.sol - -// SPDX-License-Identifier: UNLICENSED -// pragma solidity 0.8.6; - -abstract contract ComptrollerInterface { - /// @notice Indicator that this is a Comptroller contract (for inspection) - bool public constant isComptroller = true; - - /*** Assets You Are In ***/ - - function enterMarkets(address[] calldata cTokens) - external - virtual - returns (uint256[] memory); - - function exitMarket(address cToken) external virtual returns (uint256); - - /*** Policy Hooks ***/ - - function mintAllowed( - address cToken, - address minter, - uint256 mintAmount - ) external virtual returns (uint256); - - function mintVerify( - address cToken, - address minter, - uint256 mintAmount, - uint256 mintTokens - ) external virtual; - - function redeemAllowed( - address cToken, - address redeemer, - uint256 redeemTokens - ) external virtual returns (uint256); - - function redeemVerify( - address cToken, - address redeemer, - uint256 redeemAmount, - uint256 redeemTokens - ) external virtual; - - function borrowAllowed( - address cToken, - address borrower, - uint256 borrowAmount - ) external virtual returns (uint256); - - function borrowVerify( - address cToken, - address borrower, - uint256 borrowAmount - ) external virtual; - - function repayBorrowAllowed( - address cToken, - address payer, - address borrower, - uint256 repayAmount - ) external virtual returns (uint256); - - function repayBorrowVerify( - address cToken, - address payer, - address borrower, - uint256 repayAmount, - uint256 borrowerIndex - ) external virtual; - - function liquidateBorrowAllowed( - address cTokenBorrowed, - address cTokenCollateral, - address liquidator, - address borrower, - uint256 repayAmount - ) external virtual returns (uint256); - - function liquidateBorrowVerify( - address cTokenBorrowed, - address cTokenCollateral, - address liquidator, - address borrower, - uint256 repayAmount, - uint256 seizeTokens - ) external virtual; - - function seizeAllowed( - address cTokenCollateral, - address cTokenBorrowed, - address liquidator, - address borrower, - uint256 seizeTokens - ) external virtual returns (uint256); - - function seizeVerify( - address cTokenCollateral, - address cTokenBorrowed, - address liquidator, - address borrower, - uint256 seizeTokens - ) external virtual; - - function transferAllowed( - address cToken, - address src, - address dst, - uint256 transferTokens - ) external virtual returns (uint256); - - function transferVerify( - address cToken, - address src, - address dst, - uint256 transferTokens - ) external virtual; - - /*** Liquidity/Liquidation Calculations ***/ - - function liquidateCalculateSeizeTokens( - address cTokenBorrowed, - address cTokenCollateral, - uint256 repayAmount - ) external view virtual returns (uint256, uint256); -} - - -// Dependency file: contracts/CarefulMath.sol - -// pragma solidity 0.8.6; - -/** - * @title Careful Math - * @author tropykus - * @notice Derived from OpenZeppelin's SafeMath library - * https://github.com/OpenZeppelin/openzeppelin-solidity/blob/master/contracts/math/SafeMath.sol - */ -contract CarefulMath { - - /** - * @dev Possible error codes that we can return - */ - enum MathError { - NO_ERROR, - DIVISION_BY_ZERO, - INTEGER_OVERFLOW, - INTEGER_UNDERFLOW - } - - /** - * @dev Multiplies two numbers, returns an error on overflow. - */ - function mulUInt(uint a, uint b) internal pure returns (MathError, uint) { - if (a == 0) { - return (MathError.NO_ERROR, 0); - } - - uint c = a * b; - - if (c / a != b) { - return (MathError.INTEGER_OVERFLOW, 0); - } else { - return (MathError.NO_ERROR, c); - } - } - - /** - * @dev Integer division of two numbers, truncating the quotient. - */ - function divUInt(uint a, uint b) internal pure returns (MathError, uint) { - if (b == 0) { - return (MathError.DIVISION_BY_ZERO, 0); - } - - return (MathError.NO_ERROR, a / b); - } - - /** - * @dev Subtracts two numbers, returns an error on overflow (i.e. if subtrahend is greater than minuend). - */ - function subUInt(uint a, uint b) internal pure returns (MathError, uint) { - if (b <= a) { - return (MathError.NO_ERROR, a - b); - } else { - return (MathError.INTEGER_UNDERFLOW, 0); - } - } - - /** - * @dev Adds two numbers, returns an error on overflow. - */ - function addUInt(uint a, uint b) internal pure returns (MathError, uint) { - uint c = a + b; - - if (c >= a) { - return (MathError.NO_ERROR, c); - } else { - return (MathError.INTEGER_OVERFLOW, 0); - } - } - - /** - * @dev add a and b and then subtract c - */ - function addThenSubUInt(uint a, uint b, uint c) internal pure returns (MathError, uint) { - (MathError err0, uint sum) = addUInt(a, b); - - if (err0 != MathError.NO_ERROR) { - return (err0, 0); - } - - return subUInt(sum, c); - } -} - - -// Dependency file: contracts/ExponentialNoError.sol - -// pragma solidity 0.8.6; - -/** - * @title Exponential module for storing fixed-precision decimals - * @author tropykus - * @notice Exp is a struct which stores decimals with a fixed precision of 18 decimal places. - * Thus, if we wanted to store the 5.1, mantissa would store 5.1e18. That is: - * `Exp({mantissa: 5100000000000000000})`. - */ -contract ExponentialNoError { - uint constant expScale = 1e18; - uint constant doubleScale = 1e36; - uint constant halfExpScale = expScale/2; - uint constant mantissaOne = expScale; - - struct Exp { - uint mantissa; - } - - struct Double { - uint mantissa; - } - - /** - * @dev Truncates the given exp to a whole number value. - * For example, truncate(Exp{mantissa: 15 * expScale}) = 15 - */ - function truncate(Exp memory exp) pure internal returns (uint) { - // Note: We are not using careful math here as we're performing a division that cannot fail - return exp.mantissa / expScale; - } - - /** - * @dev Multiply an Exp by a scalar, then truncate to return an unsigned integer. - */ - function mul_ScalarTruncate(Exp memory a, uint scalar) pure internal returns (uint) { - Exp memory product = mul_(a, scalar); - return truncate(product); - } - - /** - * @dev Multiply an Exp by a scalar, truncate, then add an to an unsigned integer, returning an unsigned integer. - */ - function mul_ScalarTruncateAddUInt(Exp memory a, uint scalar, uint addend) pure internal returns (uint) { - Exp memory product = mul_(a, scalar); - return add_(truncate(product), addend); - } - - /** - * @dev Checks if first Exp is less than second Exp. - */ - function lessThanExp(Exp memory left, Exp memory right) pure internal returns (bool) { - return left.mantissa < right.mantissa; - } - - /** - * @dev Checks if left Exp <= right Exp. - */ - function lessThanOrEqualExp(Exp memory left, Exp memory right) pure internal returns (bool) { - return left.mantissa <= right.mantissa; - } - - /** - * @dev Checks if left Exp > right Exp. - */ - function greaterThanExp(Exp memory left, Exp memory right) pure internal returns (bool) { - return left.mantissa > right.mantissa; - } - - /** - * @dev returns true if Exp is exactly zero - */ - function isZeroExp(Exp memory value) pure internal returns (bool) { - return value.mantissa == 0; - } - - function safe224(uint n, string memory errorMessage) pure internal returns (uint224) { - require(n < 2**224, errorMessage); - return uint224(n); - } - - function safe32(uint n, string memory errorMessage) pure internal returns (uint32) { - require(n < 2**32, errorMessage); - return uint32(n); - } - - function add_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { - return Exp({mantissa: add_(a.mantissa, b.mantissa)}); - } - - function add_(Double memory a, Double memory b) pure internal returns (Double memory) { - return Double({mantissa: add_(a.mantissa, b.mantissa)}); - } - - function add_(uint a, uint b) pure internal returns (uint) { - return add_(a, b, "addition overflow"); - } - - function add_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { - uint c = a + b; - require(c >= a, errorMessage); - return c; - } - - function sub_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { - return Exp({mantissa: sub_(a.mantissa, b.mantissa)}); - } - - function sub_(Double memory a, Double memory b) pure internal returns (Double memory) { - return Double({mantissa: sub_(a.mantissa, b.mantissa)}); - } - - function sub_(uint a, uint b) pure internal returns (uint) { - return sub_(a, b, "subtraction underflow"); - } - - function sub_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { - require(b <= a, errorMessage); - return a - b; - } - - function mul_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { - return Exp({mantissa: mul_(a.mantissa, b.mantissa) / expScale}); - } - - function mul_(Exp memory a, uint b) pure internal returns (Exp memory) { - return Exp({mantissa: mul_(a.mantissa, b)}); - } - - function mul_(uint a, Exp memory b) pure internal returns (uint) { - return mul_(a, b.mantissa) / expScale; - } - - function mul_(Double memory a, Double memory b) pure internal returns (Double memory) { - return Double({mantissa: mul_(a.mantissa, b.mantissa) / doubleScale}); - } - - function mul_(Double memory a, uint b) pure internal returns (Double memory) { - return Double({mantissa: mul_(a.mantissa, b)}); - } - - function mul_(uint a, Double memory b) pure internal returns (uint) { - return mul_(a, b.mantissa) / doubleScale; - } - - function mul_(uint a, uint b) pure internal returns (uint) { - return mul_(a, b, "multiplication overflow"); - } - - function mul_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { - if (a == 0 || b == 0) { - return 0; - } - uint c = a * b; - require(c / a == b, errorMessage); - return c; - } - - function div_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { - return Exp({mantissa: div_(mul_(a.mantissa, expScale), b.mantissa)}); - } - - function div_(Exp memory a, uint b) pure internal returns (Exp memory) { - return Exp({mantissa: div_(a.mantissa, b)}); - } - - function div_(uint a, Exp memory b) pure internal returns (uint) { - return div_(mul_(a, expScale), b.mantissa); - } - - function div_(Double memory a, Double memory b) pure internal returns (Double memory) { - return Double({mantissa: div_(mul_(a.mantissa, doubleScale), b.mantissa)}); - } - - function div_(Double memory a, uint b) pure internal returns (Double memory) { - return Double({mantissa: div_(a.mantissa, b)}); - } - - function div_(uint a, Double memory b) pure internal returns (uint) { - return div_(mul_(a, doubleScale), b.mantissa); - } - - function div_(uint a, uint b) pure internal returns (uint) { - return div_(a, b, "divide by zero"); - } - - function div_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { - require(b > 0, errorMessage); - return a / b; - } - - function fraction(uint a, uint b) pure internal returns (Double memory) { - return Double({mantissa: div_(mul_(a, doubleScale), b)}); - } -} - - -// Dependency file: contracts/Exponential.sol - -// pragma solidity 0.8.6; - -// import "contracts/CarefulMath.sol"; -// import "contracts/ExponentialNoError.sol"; - -/** - * @title Exponential module for storing fixed-precision decimals - * @author tropykus - * @dev Legacy contract for compatibility reasons with existing contracts that still use MathError - * @notice Exp is a struct which stores decimals with a fixed precision of 18 decimal places. - * Thus, if we wanted to store the 5.1, mantissa would store 5.1e18. That is: - * `Exp({mantissa: 5100000000000000000})`. - */ -contract Exponential is CarefulMath, ExponentialNoError { - /** - * @dev Creates an exponential from numerator and denominator values. - * Note: Returns an error if (`num` * 10e18) > MAX_INT, - * or if `denom` is zero. - */ - function getExp(uint num, uint denom) internal pure returns (MathError, Exp memory) { - (MathError err0, uint scaledNumerator) = mulUInt(num, expScale); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - - (MathError err1, uint rational) = divUInt(scaledNumerator, denom); - if (err1 != MathError.NO_ERROR) { - return (err1, Exp({mantissa: 0})); - } - - return (MathError.NO_ERROR, Exp({mantissa: rational})); - } - - /** - * @dev Adds two exponentials, returning a new exponential. - */ - function addExp(Exp memory a, Exp memory b) internal pure returns (MathError, Exp memory) { - (MathError error, uint result) = addUInt(a.mantissa, b.mantissa); - - return (error, Exp({mantissa: result})); - } - - /** - * @dev Subtracts two exponentials, returning a new exponential. - */ - function subExp(Exp memory a, Exp memory b) internal pure returns (MathError, Exp memory) { - (MathError error, uint result) = subUInt(a.mantissa, b.mantissa); - - return (error, Exp({mantissa: result})); - } - - /** - * @dev Multiply an Exp by a scalar, returning a new Exp. - */ - function mulScalar(Exp memory a, uint scalar) internal pure returns (MathError, Exp memory) { - (MathError err0, uint scaledMantissa) = mulUInt(a.mantissa, scalar); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - - return (MathError.NO_ERROR, Exp({mantissa: scaledMantissa})); - } - - /** - * @dev Multiply an Exp by a scalar, then truncate to return an unsigned integer. - */ - function mulScalarTruncate(Exp memory a, uint scalar) internal pure returns (MathError, uint) { - (MathError err, Exp memory product) = mulScalar(a, scalar); - if (err != MathError.NO_ERROR) { - return (err, 0); - } - - return (MathError.NO_ERROR, truncate(product)); - } - - /** - * @dev Multiply an Exp by a scalar, truncate, then add an to an unsigned integer, returning an unsigned integer. - */ - function mulScalarTruncateAddUInt(Exp memory a, uint scalar, uint addend) internal pure returns (MathError, uint) { - (MathError err, Exp memory product) = mulScalar(a, scalar); - if (err != MathError.NO_ERROR) { - return (err, 0); - } - - return addUInt(truncate(product), addend); - } - - /** - * @dev Divide an Exp by a scalar, returning a new Exp. - */ - function divScalar(Exp memory a, uint scalar) internal pure returns (MathError, Exp memory) { - (MathError err0, uint descaledMantissa) = divUInt(a.mantissa, scalar); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - - return (MathError.NO_ERROR, Exp({mantissa: descaledMantissa})); - } - - /** - * @dev Divide a scalar by an Exp, returning a new Exp. - */ - function divScalarByExp(uint scalar, Exp memory divisor) internal pure returns (MathError, Exp memory) { - /* - We are doing this as: - getExp(mulUInt(expScale, scalar), divisor.mantissa) - - How it works: - Exp = a / b; - Scalar = s; - `s / (a / b)` = `b * s / a` and since for an Exp `a = mantissa, b = expScale` - */ - (MathError err0, uint numerator) = mulUInt(expScale, scalar); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - return getExp(numerator, divisor.mantissa); - } - - /** - * @dev Divide a scalar by an Exp, then truncate to return an unsigned integer. - */ - function divScalarByExpTruncate(uint scalar, Exp memory divisor) internal pure returns (MathError, uint) { - (MathError err, Exp memory fraction) = divScalarByExp(scalar, divisor); - if (err != MathError.NO_ERROR) { - return (err, 0); - } - - return (MathError.NO_ERROR, truncate(fraction)); - } - - /** - * @dev Multiplies two exponentials, returning a new exponential. - */ - function mulExp(Exp memory a, Exp memory b) internal pure returns (MathError, Exp memory) { - - (MathError err0, uint doubleScaledProduct) = mulUInt(a.mantissa, b.mantissa); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - - // We add half the scale before dividing so that we get rounding instead of truncation. - // See "Listing 6" and text above it at https://accu.org/index.php/journals/1717 - // Without this change, a result like 6.6...e-19 will be truncated to 0 instead of being rounded to 1e-18. - (MathError err1, uint doubleScaledProductWithHalfScale) = addUInt(halfExpScale, doubleScaledProduct); - if (err1 != MathError.NO_ERROR) { - return (err1, Exp({mantissa: 0})); - } - - (MathError err2, uint product) = divUInt(doubleScaledProductWithHalfScale, expScale); - // The only error `div` can return is MathError.DIVISION_BY_ZERO but we control `expScale` and it is not zero. - assert(err2 == MathError.NO_ERROR); - - return (MathError.NO_ERROR, Exp({mantissa: product})); - } - - /** - * @dev Multiplies two exponentials given their mantissas, returning a new exponential. - */ - function mulExp(uint a, uint b) internal pure returns (MathError, Exp memory) { - return mulExp(Exp({mantissa: a}), Exp({mantissa: b})); - } - - /** - * @dev Multiplies three exponentials, returning a new exponential. - */ - function mulExp3(Exp memory a, Exp memory b, Exp memory c) internal pure returns (MathError, Exp memory) { - (MathError err, Exp memory ab) = mulExp(a, b); - if (err != MathError.NO_ERROR) { - return (err, ab); - } - return mulExp(ab, c); - } - - /** - * @dev Divides two exponentials, returning a new exponential. - * (a/scale) / (b/scale) = (a/scale) * (scale/b) = a/b, - * which we can scale as an Exp by calling getExp(a.mantissa, b.mantissa) - */ - function divExp(Exp memory a, Exp memory b) internal pure returns (MathError, Exp memory) { - return getExp(a.mantissa, b.mantissa); - } -} - - -// Dependency file: contracts/SafeMath.sol - -// pragma solidity 0.8.6; - -// From https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/math/Math.sol -// Subject to the MIT license. - -/** - * @dev Wrappers over Solidity's arithmetic operations with added overflow - * checks. - * - * Arithmetic operations in Solidity wrap on overflow. This can easily result - * in bugs, because programmers usually assume that an overflow raises an - * error, which is the standard behavior in high level programming languages. - * `SafeMath` restores this intuition by reverting the transaction when an - * operation overflows. - * - * Using this library instead of the unchecked operations eliminates an entire - * class of bugs, so it's recommended to use it always. - */ -library SafeMath { - /** - * @dev Returns the addition of two unsigned integers, reverting on overflow. - * - * Counterpart to Solidity's `+` operator. - * - * Requirements: - * - Addition cannot overflow. - */ - function add(uint256 a, uint256 b) internal pure returns (uint256) { - uint256 c = a + b; - require(c >= a, "SafeMath: addition overflow"); - - return c; - } - - /** - * @dev Returns the addition of two unsigned integers, reverting with custom message on overflow. - * - * Counterpart to Solidity's `+` operator. - * - * Requirements: - * - Addition cannot overflow. - */ - function add(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - uint256 c = a + b; - require(c >= a, errorMessage); - - return c; - } - - /** - * @dev Returns the subtraction of two unsigned integers, reverting on underflow (when the result is negative). - * - * Counterpart to Solidity's `-` operator. - * - * Requirements: - * - Subtraction cannot underflow. - */ - function sub(uint256 a, uint256 b) internal pure returns (uint256) { - return sub(a, b, "SafeMath: subtraction underflow"); - } - - /** - * @dev Returns the subtraction of two unsigned integers, reverting with custom message on underflow (when the result is negative). - * - * Counterpart to Solidity's `-` operator. - * - * Requirements: - * - Subtraction cannot underflow. - */ - function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - require(b <= a, errorMessage); - uint256 c = a - b; - - return c; - } - - /** - * @dev Returns the multiplication of two unsigned integers, reverting on overflow. - * - * Counterpart to Solidity's `*` operator. - * - * Requirements: - * - Multiplication cannot overflow. - */ - function mul(uint256 a, uint256 b) internal pure returns (uint256) { - // Gas optimization: this is cheaper than requiring 'a' not being zero, but the - // benefit is lost if 'b' is also tested. - // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 - if (a == 0) { - return 0; - } - - uint256 c = a * b; - require(c / a == b, "SafeMath: multiplication overflow"); - - return c; - } - - /** - * @dev Returns the multiplication of two unsigned integers, reverting on overflow. - * - * Counterpart to Solidity's `*` operator. - * - * Requirements: - * - Multiplication cannot overflow. - */ - function mul(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - // Gas optimization: this is cheaper than requiring 'a' not being zero, but the - // benefit is lost if 'b' is also tested. - // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 - if (a == 0) { - return 0; - } - - uint256 c = a * b; - require(c / a == b, errorMessage); - - return c; - } - - /** - * @dev Returns the integer division of two unsigned integers. - * Reverts on division by zero. The result is rounded towards zero. - * - * Counterpart to Solidity's `/` operator. Note: this function uses a - * `revert` opcode (which leaves remaining gas untouched) while Solidity - * uses an invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function div(uint256 a, uint256 b) internal pure returns (uint256) { - return div(a, b, "SafeMath: division by zero"); - } - - /** - * @dev Returns the integer division of two unsigned integers. - * Reverts with custom message on division by zero. The result is rounded towards zero. - * - * Counterpart to Solidity's `/` operator. Note: this function uses a - * `revert` opcode (which leaves remaining gas untouched) while Solidity - * uses an invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - // Solidity only automatically asserts when dividing by 0 - require(b > 0, errorMessage); - uint256 c = a / b; - // assert(a == b * c + a % b); // There is no case in which this doesn't hold - - return c; - } - - /** - * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), - * Reverts when dividing by zero. - * - * Counterpart to Solidity's `%` operator. This function uses a `revert` - * opcode (which leaves remaining gas untouched) while Solidity uses an - * invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function mod(uint256 a, uint256 b) internal pure returns (uint256) { - return mod(a, b, "SafeMath: modulo by zero"); - } - - /** - * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), - * Reverts with custom message when dividing by zero. - * - * Counterpart to Solidity's `%` operator. This function uses a `revert` - * opcode (which leaves remaining gas untouched) while Solidity uses an - * invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - require(b != 0, errorMessage); - return a % b; - } -} - - -// Dependency file: contracts/InterestRateModel.sol - -// pragma solidity 0.8.6; - -// import "contracts/Exponential.sol"; -// import "contracts/SafeMath.sol"; - -/** - * @title tropykus InterestRateModel Interface - * @author tropykus - */ -abstract contract InterestRateModel is Exponential { - using SafeMath for uint256; - - /// @notice Indicator that this is an InterestRateModel contract (for inspection) - bool public constant isInterestRateModel = true; - bool public isTropykusInterestRateModel; - - /** - * @notice The approximate number of blocks per year that is assumed by the interest rate model - */ - uint256 public constant blocksPerYear = 1051200; - - /** - * @notice Calculates the utilization rate of the market: `borrows / (cash + borrows - reserves)` - * @param cash The amount of cash in the market - * @param borrows The amount of borrows in the market - * @param reserves The amount of reserves in the market (currently unused) - * @return The utilization rate as a mantissa between [0, 1e18] - */ - function utilizationRate( - uint256 cash, - uint256 borrows, - uint256 reserves - ) public pure virtual returns (uint256) { - // Utilization rate is 0 when there are no borrows - if (borrows == 0) { - return 0; - } - - return borrows.mul(1e18).div(cash.add(borrows).sub(reserves)); - } - - /** - * @notice Calculates the current borrow interest rate per block - * @param cash The total amount of cash the market has - * @param borrows The total amount of borrows the market has outstanding - * @param reserves The total amnount of reserves the market has - * @return The borrow rate per block (as a percentage, and scaled by 1e18) - */ - function getBorrowRate( - uint256 cash, - uint256 borrows, - uint256 reserves - ) external view virtual returns (uint256); - - /** - * @notice Calculates the current supply interest rate per block - * @param cash The total amount of cash the market has - * @param borrows The total amount of borrows the market has outstanding - * @param reserves The total amnount of reserves the market has - * @param reserveFactorMantissa The current reserve factor the market has - * @return The supply rate per block (as a percentage, and scaled by 1e18) - */ - function getSupplyRate( - uint256 cash, - uint256 borrows, - uint256 reserves, - uint256 reserveFactorMantissa - ) external view virtual returns (uint256); - - function getExchangeRate( - uint256 _totalCash, - uint256 _totalBorrows, - uint256 _totalReserves, - uint256 _totalSupply - ) public pure returns (MathError, uint256) { - /* - * exchangeRate = (totalCash + totalBorrows - totalReserves) / totalSupply - */ - Exp memory exchangeRate; - MathError mathErr; - uint256 cashPlusBorrowsMinusReserves; - (mathErr, cashPlusBorrowsMinusReserves) = addThenSubUInt( - _totalCash, - _totalBorrows, - _totalReserves - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - (mathErr, exchangeRate) = getExp( - cashPlusBorrowsMinusReserves, - _totalSupply - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - - return (MathError.NO_ERROR, exchangeRate.mantissa); - } - - function isAboveOptimal( - uint256 cash, - uint256 borrows, - uint256 reserves - ) public view virtual returns (bool) { - cash; - borrows; - reserves; - return false; - } -} - - -// Dependency file: contracts/EIP20NonStandardInterface.sol - -// pragma solidity 0.8.6; - -/** - * @title EIP20NonStandardInterface - * @dev Version of ERC20 with no return values for `transfer` and `transferFrom` - * See https://medium.com/coinmonks/missing-return-value-bug-at-least-130-tokens-affected-d67bf08521ca - */ -interface EIP20NonStandardInterface { - /** - * @notice Get the total number of tokens in circulation - * @return The supply of tokens - */ - function totalSupply() external view returns (uint256); - - /** - * @notice Gets the balance of the specified address - * @param owner The address from which the balance will be retrieved - * @return balance The balance - */ - function balanceOf(address owner) external view returns (uint256 balance); - - /// - /// !!!!!!!!!!!!!! - /// !!! NOTICE !!! `transfer` does not return a value, in violation of the ERC-20 specification - /// !!!!!!!!!!!!!! - /// - - /** - * @notice Transfer `amount` tokens from `msg.sender` to `dst` - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - */ - function transfer(address dst, uint256 amount) external; - - /// - /// !!!!!!!!!!!!!! - /// !!! NOTICE !!! `transferFrom` does not return a value, in violation of the ERC-20 specification - /// !!!!!!!!!!!!!! - /// - - /** - * @notice Transfer `amount` tokens from `src` to `dst` - * @param src The address of the source account - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - */ - function transferFrom( - address src, - address dst, - uint256 amount - ) external; - - /** - * @notice Approve `spender` to transfer up to `amount` from `src` - * @dev This will overwrite the approval amount for `spender` - * and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve) - * @param spender The address of the account which may transfer tokens - * @param amount The number of tokens that are approved - * @return success Whether or not the approval succeeded - */ - function approve(address spender, uint256 amount) - external - returns (bool success); - - /** - * @notice Get the current allowance from `owner` for `spender` - * @param owner The address of the account which owns the tokens to be spent - * @param spender The address of the account which may transfer tokens - * @return remaining The number of tokens allowed to be spent - */ - function allowance(address owner, address spender) - external - view - returns (uint256 remaining); - - event Transfer(address indexed from, address indexed to, uint256 amount); - event Approval( - address indexed owner, - address indexed spender, - uint256 amount - ); -} - - -// Dependency file: contracts/CTokenInterfaces.sol - -// pragma solidity 0.8.6; - -// import "contracts/ComptrollerInterface.sol"; -// import "contracts/InterestRateModel.sol"; -// import "contracts/EIP20NonStandardInterface.sol"; - -contract CTokenStorage { - /** - * @dev Guard variable for re-entrancy checks - */ - bool internal _notEntered; - - /** - * @notice EIP-20 token name for this token - */ - string public name; - - /** - * @notice EIP-20 token symbol for this token - */ - string public symbol; - - /** - * @notice EIP-20 token decimals for this token - */ - uint8 public decimals; - - /** - * @notice Maximum borrow rate that can ever be applied (.0005% / block) - */ - - uint256 internal constant borrowRateMaxMantissa = 0.0005e16; - - /** - * @notice Maximum fraction of interest that can be set aside for reserves - */ - uint256 internal constant reserveFactorMaxMantissa = 1e18; - - /** - * @notice Administrator for this contract - */ - address payable public admin; - - /** - * @notice Pending administrator for this contract - */ - address payable public pendingAdmin; - - /** - * @notice Contract which oversees inter-cToken operations - */ - ComptrollerInterface public comptroller; - - /** - * @notice Model which tells what the current interest rate should be - */ - InterestRateModel public interestRateModel; - - /** - * @notice Initial exchange rate used when minting the first CTokens (used when totalSupply = 0) - */ - uint256 public initialExchangeRateMantissa; - - /** - * @notice Fraction of interest currently set aside for reserves - */ - uint256 public reserveFactorMantissa; - - /** - * @notice Block number that interest was last accrued at - */ - uint256 public accrualBlockNumber; - - /** - * @notice Accumulator of the total earned interest rate since the opening of the market - */ - uint256 public borrowIndex; - - /** - * @notice Total amount of outstanding borrows of the underlying in this market - */ - uint256 public totalBorrows; - - /** - * @notice Total amount of reserves of the underlying held in this market - */ - uint256 public totalReserves; - - /** - * @notice Total number of tokens in circulation - */ - uint256 public totalSupply; - - uint256 public subsidyFund; - - struct SupplySnapshot { - uint256 tokens; - uint256 underlyingAmount; - uint256 suppliedAt; - uint256 promisedSupplyRate; - } - - /** - * @notice Official record of token balances for each account - */ - mapping(address => SupplySnapshot) internal accountTokens; - - /** - * @notice Approved token transfer amounts on behalf of others - */ - mapping(address => mapping(address => uint256)) internal transferAllowances; - - /** - * @notice Container for borrow balance information - * @member principal Total balance (with accrued interest), after applying the most recent balance-changing action - * @member interestIndex Global borrowIndex as of the most recent balance-changing action - */ - struct BorrowSnapshot { - uint256 principal; - uint256 interestIndex; - } - - /** - * @notice Mapping of account addresses to outstanding borrow balances - */ - mapping(address => BorrowSnapshot) internal accountBorrows; -} - -abstract contract CTokenInterface is CTokenStorage { - /** - * @notice Indicator that this is a CToken contract (for inspection) - */ - bool public constant isCToken = true; - - /*** Market Events ***/ - - /** - * @notice Event emitted when interest is accrued - */ - event AccrueInterest( - uint256 cashPrior, - uint256 interestAccumulated, - uint256 borrowIndex, - uint256 totalBorrows - ); - - /** - * @notice Event emitted when tokens are minted - */ - event Mint(address indexed minter, uint256 mintAmount, uint256 mintTokens); - - /** - * @notice Event emitted when tokens are redeemed - */ - event Redeem( - address indexed redeemer, - uint256 redeemAmount, - uint256 redeemTokens - ); - - /** - * @notice Event emitted when underlying is borrowed - */ - event Borrow( - address indexed borrower, - uint256 borrowAmount, - uint256 accountBorrows, - uint256 totalBorrows - ); - - /** - * @notice Event emitted when a borrow is repaid - */ - event RepayBorrow( - address indexed payer, - address indexed borrower, - uint256 repayAmount, - uint256 accountBorrows, - uint256 totalBorrows - ); - - /** - * @notice Event emitted when a borrow is liquidated - */ - event LiquidateBorrow( - address indexed liquidator, - address indexed borrower, - uint256 repayAmount, - address indexed cTokenCollateral, - uint256 seizeTokens - ); - - /*** Admin Events ***/ - - /** - * @notice Event emitted when pendingAdmin is changed - */ - event NewPendingAdmin(address oldPendingAdmin, address newPendingAdmin); - - /** - * @notice Event emitted when pendingAdmin is accepted, which means admin is updated - */ - event NewAdmin(address oldAdmin, address newAdmin); - - /** - * @notice Event emitted when comptroller is changed - */ - event NewComptroller( - ComptrollerInterface oldComptroller, - ComptrollerInterface newComptroller - ); - - /** - * @notice Event emitted when interestRateModel is changed - */ - event NewMarketInterestRateModel( - InterestRateModel oldInterestRateModel, - InterestRateModel newInterestRateModel - ); - - /** - * @notice Event emitted when the reserve factor is changed - */ - event NewReserveFactor( - uint256 oldReserveFactorMantissa, - uint256 newReserveFactorMantissa - ); - - /** - * @notice Event emitted when the reserves are added - */ - event ReservesAdded( - address benefactor, - uint256 addAmount, - uint256 newTotalReserves - ); - - event SubsidyAdded( - address benefactor, - uint256 addAmount, - uint256 newSubsidyFund - ); - - /** - * @notice Event emitted when the reserves are reduced - */ - event ReservesReduced( - address admin, - uint256 reduceAmount, - uint256 newTotalReserves - ); - - /** - * @notice EIP20 Transfer event - */ - event Transfer(address indexed from, address indexed to, uint256 amount); - - /** - * @notice EIP20 Approval event - */ - event Approval( - address indexed owner, - address indexed spender, - uint256 amount - ); - - /** - * @notice Failure event - */ - event CTokenStorageFailure(uint256 error, uint256 info, uint256 detail); - - /*** User Interface ***/ - - function transfer(address dst, uint256 amount) - external - virtual - returns (bool); - - function transferFrom( - address src, - address dst, - uint256 amount - ) external virtual returns (bool); - - function approve(address spender, uint256 amount) - external - virtual - returns (bool); - - function allowance(address owner, address spender) - external - view - virtual - returns (uint256); - - function balanceOf(address owner) external view virtual returns (uint256); - - function balanceOfUnderlying(address owner) - external - virtual - returns (uint256); - - function getAccountSnapshot(address account) - external - view - virtual - returns ( - uint256, - uint256, - uint256, - uint256 - ); - - function borrowRatePerBlock() external view virtual returns (uint256); - - function supplyRatePerBlock() external view virtual returns (uint256); - - function totalBorrowsCurrent() external virtual returns (uint256); - - function borrowBalanceCurrent(address account) - external - virtual - returns (uint256); - - function borrowBalanceStored(address account) - public - view - virtual - returns (uint256); - - function exchangeRateCurrent() public virtual returns (uint256); - - function exchangeRateStored() public view virtual returns (uint256); - - function getCash() external view virtual returns (uint256); - - function accrueInterest() public virtual returns (uint256); - - function seize( - address liquidator, - address borrower, - uint256 seizeTokens - ) external virtual returns (uint256); - - /*** Admin Functions ***/ - - function _setPendingAdmin(address payable newPendingAdmin) - external - virtual - returns (uint256); - - function _acceptAdmin() external virtual returns (uint256); - - function _setComptroller(ComptrollerInterface newComptroller) - public - virtual - returns (uint256); - - function _setReserveFactor(uint256 newReserveFactorMantissa) - external - virtual - returns (uint256); - - function _reduceReserves(uint256 reduceAmount) - external - virtual - returns (uint256); - - function _setInterestRateModel(InterestRateModel newInterestRateModel) - public - virtual - returns (uint256); -} - -contract CErc20Storage { - /** - * @notice Underlying asset for this CToken - */ - address public underlying; -} - -abstract contract CErc20Interface is CErc20Storage { - /*** User Interface ***/ - - function mint(uint256 mintAmount) external virtual returns (uint256); - - function redeem(uint256 redeemAmount) - external - virtual - returns (uint256); - - function borrow(uint256 borrowAmount) external virtual returns (uint256); - - function repayBorrow(uint256 repayAmount) - external - virtual - returns (uint256); - - function liquidateBorrow( - address borrower, - uint256 repayAmount, - CTokenInterface cTokenCollateral - ) external virtual returns (uint256); - - function sweepToken(EIP20NonStandardInterface token) external virtual; - - /*** Admin Functions ***/ - - function _addReserves(uint256 addAmount) external virtual returns (uint256); -} - -contract CDelegationStorage { - /** - * @notice Implementation address for this contract - */ - address public implementation; -} - -abstract contract CDelegatorInterface is CDelegationStorage { - /** - * @notice Emitted when implementation is changed - */ - event NewImplementation( - address oldImplementation, - address newImplementation - ); - - /** - * @notice Called by the admin to update the implementation of the delegator - * @param implementation_ The address of the new implementation for delegation - * @param allowResign Flag to indicate whether to call _resignImplementation on the old implementation - * @param becomeImplementationData The encoded bytes data to be passed to _becomeImplementation - */ - function _setImplementation( - address implementation_, - bool allowResign, - bytes memory becomeImplementationData - ) public virtual; -} - -abstract contract CDelegateInterface is CDelegationStorage { - /** - * @notice Called by the delegator on a delegate to initialize it for duty - * @dev Should revert if any issues arise which make it unfit for delegation - * @param data The encoded bytes data for any initialization - */ - function _becomeImplementation(bytes memory data) public virtual; - - /** - * @notice Called by the delegator on a delegate to forfeit its responsibility - */ - function _resignImplementation() public virtual; -} - - -// Dependency file: contracts/ErrorReporter.sol - -// pragma solidity 0.8.6; - -contract ComptrollerErrorReporter { - enum Error { - NO_ERROR, - UNAUTHORIZED, - COMPTROLLER_MISMATCH, - INSUFFICIENT_SHORTFALL, - INSUFFICIENT_LIQUIDITY, - INVALID_CLOSE_FACTOR, - INVALID_COLLATERAL_FACTOR, - INVALID_LIQUIDATION_INCENTIVE, - MARKET_NOT_ENTERED, // no longer possible - MARKET_NOT_LISTED, - MARKET_ALREADY_LISTED, - MATH_ERROR, - NONZERO_BORROW_BALANCE, - PRICE_ERROR, - REJECTION, - SNAPSHOT_ERROR, - TOO_MANY_ASSETS, - TOO_MUCH_REPAY - } - - enum FailureInfo { - ACCEPT_ADMIN_PENDING_ADMIN_CHECK, - ACCEPT_PENDING_IMPLEMENTATION_ADDRESS_CHECK, - EXIT_MARKET_BALANCE_OWED, - EXIT_MARKET_REJECTION, - SET_CLOSE_FACTOR_OWNER_CHECK, - SET_CLOSE_FACTOR_VALIDATION, - SET_COLLATERAL_FACTOR_OWNER_CHECK, - SET_COLLATERAL_FACTOR_NO_EXISTS, - SET_COLLATERAL_FACTOR_VALIDATION, - SET_COLLATERAL_FACTOR_WITHOUT_PRICE, - SET_IMPLEMENTATION_OWNER_CHECK, - SET_LIQUIDATION_INCENTIVE_OWNER_CHECK, - SET_LIQUIDATION_INCENTIVE_VALIDATION, - SET_MAX_ASSETS_OWNER_CHECK, - SET_PENDING_ADMIN_OWNER_CHECK, - SET_PENDING_IMPLEMENTATION_OWNER_CHECK, - SET_PRICE_ORACLE_OWNER_CHECK, - SUPPORT_MARKET_EXISTS, - SUPPORT_MARKET_OWNER_CHECK, - SET_PAUSE_GUARDIAN_OWNER_CHECK - } - - /** - * @dev `error` corresponds to enum Error; `info` corresponds to enum FailureInfo, and `detail` is an arbitrary - * contract-specific code that enables us to report opaque error codes from upgradeable contracts. - **/ - event Failure(uint256 error, uint256 info, uint256 detail); - - /** - * @dev use this when reporting a known error from the money market or a non-upgradeable collaborator - */ - function fail(Error err, FailureInfo info) internal returns (uint256) { - emit Failure(uint256(err), uint256(info), 0); - - return uint256(err); - } - - /** - * @dev use this when reporting an opaque error from an upgradeable collaborator contract - */ - function failOpaque( - Error err, - FailureInfo info, - uint256 opaqueError - ) internal returns (uint256) { - emit Failure(uint256(err), uint256(info), opaqueError); - - return uint256(err); - } -} - -contract TokenErrorReporter { - enum Error { - NO_ERROR, - UNAUTHORIZED, - BAD_INPUT, - COMPTROLLER_REJECTION, - COMPTROLLER_CALCULATION_ERROR, - INTEREST_RATE_MODEL_ERROR, - INVALID_ACCOUNT_PAIR, - INVALID_CLOSE_AMOUNT_REQUESTED, - INVALID_COLLATERAL_FACTOR, - MATH_ERROR, - MARKET_NOT_FRESH, - MARKET_NOT_LISTED, - TOKEN_INSUFFICIENT_ALLOWANCE, - TOKEN_INSUFFICIENT_BALANCE, - TOKEN_INSUFFICIENT_CASH, - TOKEN_TRANSFER_IN_FAILED, - TOKEN_TRANSFER_OUT_FAILED - } - - /* - * Note: FailureInfo (but not Error) is kept in alphabetical order - * This is because FailureInfo grows significantly faster, and - * the order of Error has some meaning, while the order of FailureInfo - * is entirely arbitrary. - */ - enum FailureInfo { - ACCEPT_ADMIN_PENDING_ADMIN_CHECK, - ACCRUE_INTEREST_ACCUMULATED_INTEREST_CALCULATION_FAILED, - ACCRUE_INTEREST_BORROW_RATE_CALCULATION_FAILED, - ACCRUE_INTEREST_NEW_BORROW_INDEX_CALCULATION_FAILED, - ACCRUE_INTEREST_NEW_TOTAL_BORROWS_CALCULATION_FAILED, - ACCRUE_INTEREST_NEW_TOTAL_RESERVES_CALCULATION_FAILED, - ACCRUE_INTEREST_SIMPLE_INTEREST_FACTOR_CALCULATION_FAILED, - BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED, - BORROW_ACCRUE_INTEREST_FAILED, - BORROW_CASH_NOT_AVAILABLE, - BORROW_FRESHNESS_CHECK, - BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED, - BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED, - BORROW_MARKET_NOT_LISTED, - BORROW_COMPTROLLER_REJECTION, - LIQUIDATE_ACCRUE_BORROW_INTEREST_FAILED, - LIQUIDATE_ACCRUE_COLLATERAL_INTEREST_FAILED, - LIQUIDATE_COLLATERAL_FRESHNESS_CHECK, - LIQUIDATE_COMPTROLLER_REJECTION, - LIQUIDATE_COMPTROLLER_CALCULATE_AMOUNT_SEIZE_FAILED, - LIQUIDATE_CLOSE_AMOUNT_IS_UINT_MAX, - LIQUIDATE_CLOSE_AMOUNT_IS_ZERO, - LIQUIDATE_FRESHNESS_CHECK, - LIQUIDATE_LIQUIDATOR_IS_BORROWER, - LIQUIDATE_REPAY_BORROW_FRESH_FAILED, - LIQUIDATE_SEIZE_BALANCE_INCREMENT_FAILED, - LIQUIDATE_SEIZE_BALANCE_DECREMENT_FAILED, - LIQUIDATE_SEIZE_COMPTROLLER_REJECTION, - LIQUIDATE_SEIZE_LIQUIDATOR_IS_BORROWER, - LIQUIDATE_SEIZE_TOO_MUCH, - MINT_ACCRUE_INTEREST_FAILED, - MINT_COMPTROLLER_REJECTION, - MINT_EXCHANGE_CALCULATION_FAILED, - MINT_EXCHANGE_RATE_READ_FAILED, - MINT_FRESHNESS_CHECK, - MINT_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED, - MINT_NEW_TOTAL_SUPPLY_CALCULATION_FAILED, - MINT_TRANSFER_IN_FAILED, - MINT_TRANSFER_IN_NOT_POSSIBLE, - REDEEM_ACCRUE_INTEREST_FAILED, - REDEEM_COMPTROLLER_REJECTION, - REDEEM_EXCHANGE_TOKENS_CALCULATION_FAILED, - REDEEM_EXCHANGE_AMOUNT_CALCULATION_FAILED, - REDEEM_EXCHANGE_RATE_READ_FAILED, - REDEEM_FRESHNESS_CHECK, - REDEEM_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED, - REDEEM_NEW_TOTAL_SUPPLY_CALCULATION_FAILED, - REDEEM_TRANSFER_OUT_NOT_POSSIBLE, - REDUCE_RESERVES_ACCRUE_INTEREST_FAILED, - REDUCE_RESERVES_ADMIN_CHECK, - REDUCE_RESERVES_CASH_NOT_AVAILABLE, - REDUCE_RESERVES_FRESH_CHECK, - REDUCE_RESERVES_VALIDATION, - REPAY_BEHALF_ACCRUE_INTEREST_FAILED, - REPAY_BORROW_ACCRUE_INTEREST_FAILED, - REPAY_BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED, - REPAY_BORROW_COMPTROLLER_REJECTION, - REPAY_BORROW_FRESHNESS_CHECK, - REPAY_BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED, - REPAY_BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED, - REPAY_BORROW_TRANSFER_IN_NOT_POSSIBLE, - SET_COLLATERAL_FACTOR_OWNER_CHECK, - SET_COLLATERAL_FACTOR_VALIDATION, - SET_COMPTROLLER_OWNER_CHECK, - SET_INTEREST_RATE_MODEL_ACCRUE_INTEREST_FAILED, - SET_INTEREST_RATE_MODEL_FRESH_CHECK, - SET_INTEREST_RATE_MODEL_OWNER_CHECK, - SET_MAX_ASSETS_OWNER_CHECK, - SET_ORACLE_MARKET_NOT_LISTED, - SET_PENDING_ADMIN_OWNER_CHECK, - SET_RESERVE_FACTOR_ACCRUE_INTEREST_FAILED, - SET_RESERVE_FACTOR_ADMIN_CHECK, - SET_RESERVE_FACTOR_FRESH_CHECK, - SET_RESERVE_FACTOR_BOUNDS_CHECK, - TRANSFER_COMPTROLLER_REJECTION, - TRANSFER_NOT_ALLOWED, - TRANSFER_NOT_ENOUGH, - TRANSFER_TOO_MUCH, - ADD_RESERVES_ACCRUE_INTEREST_FAILED, - ADD_RESERVES_FRESH_CHECK, - ADD_RESERVES_TRANSFER_IN_NOT_POSSIBLE, - ADD_SUBSIDY_FUND_FAILED, - ADD_SUBSIDY_FUND_FRESH_CHECK - } - - /** - * @dev `error` corresponds to enum Error; `info` corresponds to enum FailureInfo, and `detail` is an arbitrary - * contract-specific code that enables us to report opaque error codes from upgradeable contracts. - **/ - event TokenFailure(uint256 error, uint256 info, uint256 detail); - - /** - * @dev use this when reporting a known error from the money market or a non-upgradeable collaborator - */ - function fail(Error err, FailureInfo info) internal returns (uint256) { - emit TokenFailure(uint256(err), uint256(info), 0); - - return uint256(err); - } - - /** - * @dev use this when reporting an opaque error from an upgradeable collaborator contract - */ - function failOpaque( - Error err, - FailureInfo info, - uint256 opaqueError - ) internal returns (uint256) { - emit TokenFailure(uint256(err), uint256(info), opaqueError); - - return uint256(err); - } -} - - -// Dependency file: contracts/EIP20Interface.sol - -// pragma solidity 0.8.6; - -/** - * @title ERC 20 Token Standard Interface - * https://eips.ethereum.org/EIPS/eip-20 - */ -interface EIP20Interface { - function name() external view returns (string memory); - - function symbol() external view returns (string memory); - - function decimals() external view returns (uint8); - - /** - * @notice Get the total number of tokens in circulation - * @return The supply of tokens - */ - function totalSupply() external view returns (uint256); - - /** - * @notice Gets the balance of the specified address - * @param owner The address from which the balance will be retrieved - * @return balance The balance - */ - function balanceOf(address owner) external view returns (uint256 balance); - - /** - * @notice Transfer `amount` tokens from `msg.sender` to `dst` - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - * @return success Whether or not the transfer succeeded - */ - function transfer(address dst, uint256 amount) - external - returns (bool success); - - /** - * @notice Transfer `amount` tokens from `src` to `dst` - * @param src The address of the source account - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - * @return success Whether or not the transfer succeeded - */ - function transferFrom( - address src, - address dst, - uint256 amount - ) external returns (bool success); - - /** - * @notice Approve `spender` to transfer up to `amount` from `src` - * @dev This will overwrite the approval amount for `spender` - * and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve) - * @param spender The address of the account which may transfer tokens - * @param amount The number of tokens that are approved (-1 means infinite) - * @return success Whether or not the approval succeeded - */ - function approve(address spender, uint256 amount) - external - returns (bool success); - - /** - * @notice Get the current allowance from `owner` for `spender` - * @param owner The address of the account which owns the tokens to be spent - * @param spender The address of the account which may transfer tokens - * @return remaining The number of tokens allowed to be spent (-1 means infinite) - */ - function allowance(address owner, address spender) - external - view - returns (uint256 remaining); - - event Transfer(address indexed from, address indexed to, uint256 amount); - event Approval( - address indexed owner, - address indexed spender, - uint256 amount - ); -} - - -// Dependency file: contracts/WhitelistInterface.sol - -// pragma solidity 0.8.6; - -interface WhitelistInterface { - function setStatus(bool _newStatus) external; - function enabled() external view returns(bool); - - function addUsers(address[] memory _users) external; - function exist(address _user) external view returns(bool); - function getUsers() external view returns(address[] memory currentUsers); - function removeUser(address _user) external; -} - -// Dependency file: contracts/CToken.sol - -// pragma solidity 0.8.6; - -// import "contracts/ComptrollerInterface.sol"; -// import "contracts/CTokenInterfaces.sol"; -// import "contracts/ErrorReporter.sol"; -// import "contracts/Exponential.sol"; -// import "contracts/EIP20Interface.sol"; -// import "contracts/InterestRateModel.sol"; -// import "contracts/WhitelistInterface.sol"; - -/** - * @title tropykus CToken Contract - * @notice Abstract base for CTokens - * @author tropykus - */ -abstract contract CToken is CTokenInterface, Exponential, TokenErrorReporter { - address whitelist; - - /** - * @notice Initialize the money market - * @param comptroller_ The address of the Comptroller - * @param interestRateModel_ The address of the interest rate model - * @param initialExchangeRateMantissa_ The initial exchange rate, scaled by 1e18 - * @param name_ EIP-20 name of this token - * @param symbol_ EIP-20 symbol of this token - * @param decimals_ EIP-20 decimal precision of this token - */ - function initialize( - ComptrollerInterface comptroller_, - InterestRateModel interestRateModel_, - uint256 initialExchangeRateMantissa_, - string memory name_, - string memory symbol_, - uint8 decimals_ - ) public { - require(msg.sender == admin, "CT01"); - require(accrualBlockNumber == 0 && borrowIndex == 0, "CT02"); - - initialExchangeRateMantissa = initialExchangeRateMantissa_; - require(initialExchangeRateMantissa > 0, "CT03"); - - uint256 err = _setComptroller(comptroller_); - require(err == uint256(Error.NO_ERROR), "CT04"); - - accrualBlockNumber = getBlockNumber(); - borrowIndex = mantissaOne; - - err = _setInterestRateModelFresh(interestRateModel_); - require(err == uint256(Error.NO_ERROR), "CT05"); - - name = name_; - symbol = symbol_; - decimals = decimals_; - - _notEntered = true; - } - - function addWhitelist(address _whitelist) external returns (uint256) { - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_INTEREST_RATE_MODEL_OWNER_CHECK - ); - } - whitelist = _whitelist; - } - - /** - * @notice Transfer `tokens` tokens from `src` to `dst` by `spender` - * @dev Called by both `transfer` and `transferFrom` internally - * @param spender The address of the account performing the transfer - * @param src The address of the source account - * @param dst The address of the destination account - * @param tokens The number of tokens to transfer - * @return Whether or not the transfer succeeded - */ - function transferTokens( - address spender, - address src, - address dst, - uint256 tokens - ) internal returns (uint256) { - uint256 allowed = comptroller.transferAllowed( - address(this), - src, - dst, - tokens - ); - if (allowed != 0) { - return - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.TRANSFER_COMPTROLLER_REJECTION, - allowed - ); - } - - if (src == dst) { - return fail(Error.BAD_INPUT, FailureInfo.TRANSFER_NOT_ALLOWED); - } - - uint256 startingAllowance = 0; - if (spender == src) { - startingAllowance = type(uint256).max; - } else { - startingAllowance = transferAllowances[src][spender]; - } - - MathError mathErr; - uint256 allowanceNew; - uint256 srcTokensNew; - uint256 dstTokensNew; - - (mathErr, allowanceNew) = subUInt(startingAllowance, tokens); - if (mathErr != MathError.NO_ERROR) { - return fail(Error.MATH_ERROR, FailureInfo.TRANSFER_NOT_ALLOWED); - } - - (mathErr, srcTokensNew) = subUInt(accountTokens[src].tokens, tokens); - if (mathErr != MathError.NO_ERROR) { - return fail(Error.MATH_ERROR, FailureInfo.TRANSFER_NOT_ENOUGH); - } - - (mathErr, dstTokensNew) = addUInt(accountTokens[dst].tokens, tokens); - if (mathErr != MathError.NO_ERROR) { - return fail(Error.MATH_ERROR, FailureInfo.TRANSFER_TOO_MUCH); - } - - accountTokens[src].tokens = srcTokensNew; - accountTokens[dst].tokens = dstTokensNew; - - if (startingAllowance != type(uint256).max) { - transferAllowances[src][spender] = allowanceNew; - } - - emit Transfer(src, dst, tokens); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Transfer `amount` tokens from `msg.sender` to `dst` - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - * @return Whether or not the transfer succeeded - */ - function transfer(address dst, uint256 amount) - external - override - nonReentrant - returns (bool) - { - return - transferTokens(msg.sender, msg.sender, dst, amount) == - uint256(Error.NO_ERROR); - } - - /** - * @notice Transfer `amount` tokens from `src` to `dst` - * @param src The address of the source account - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - * @return Whether or not the transfer succeeded - */ - function transferFrom( - address src, - address dst, - uint256 amount - ) external override nonReentrant returns (bool) { - return - transferTokens(msg.sender, src, dst, amount) == - uint256(Error.NO_ERROR); - } - - /** - * @notice Approve `spender` to transfer up to `amount` from `src` - * @dev This will overwrite the approval amount for `spender` - * and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve) - * @param spender The address of the account which may transfer tokens - * @param amount The number of tokens that are approved (-1 means infinite) - * @return Whether or not the approval succeeded - */ - function approve(address spender, uint256 amount) - external - override - returns (bool) - { - transferAllowances[msg.sender][spender] = amount; - emit Approval(msg.sender, spender, amount); - return true; - } - - /** - * @notice Get the current allowance from `owner` for `spender` - * @param owner The address of the account which owns the tokens to be spent - * @param spender The address of the account which may transfer tokens - * @return The number of tokens allowed to be spent (-1 means infinite) - */ - function allowance(address owner, address spender) - external - view - override - returns (uint256) - { - return transferAllowances[owner][spender]; - } - - /** - * @notice Get the token balance of the `owner` - * @param owner The address of the account to query - * @return The number of tokens owned by `owner` - */ - function balanceOf(address owner) external view override returns (uint256) { - return accountTokens[owner].tokens; - } - - /** - * @notice Get the underlying balance of the `owner` - * @dev This also accrues interest in a transaction - * @param owner The address of the account to query - * @return The amount of underlying owned by `owner` - */ - function balanceOfUnderlying(address owner) - external - override - returns (uint256) - { - (MathError mErr, uint256 balance) = mulScalarTruncate( - Exp({mantissa: exchangeRateCurrent()}), - accountTokens[owner].tokens - ); - require(mErr == MathError.NO_ERROR, "CT06"); - return balance; - } - - /** - * @notice Get a snapshot of the account's balances, and the cached exchange rate - * @dev This is used by comptroller to more efficiently perform liquidity checks. - * @param account Address of the account to snapshot - * @return (possible error, token balance, borrow balance, exchange rate mantissa) - */ - function getAccountSnapshot(address account) - external - view - override - returns ( - uint256, - uint256, - uint256, - uint256 - ) - { - uint256 cTokenBalance = accountTokens[account].tokens; - uint256 borrowBalance; - uint256 exchangeRateMantissa; - - MathError mErr; - - (mErr, borrowBalance) = borrowBalanceStoredInternal(account); - if (mErr != MathError.NO_ERROR) { - return (uint256(Error.MATH_ERROR), 0, 0, 0); - } - - (mErr, exchangeRateMantissa) = exchangeRateStoredInternal(); - if (mErr != MathError.NO_ERROR) { - return (uint256(Error.MATH_ERROR), 0, 0, 0); - } - - return ( - uint256(Error.NO_ERROR), - cTokenBalance, - borrowBalance, - exchangeRateMantissa - ); - } - - /** - * @dev Function to simply retrieve block number - * This exists mainly for inheriting test contracts to stub this result. - */ - function getBlockNumber() internal view virtual returns (uint256) { - return block.number; - } - - /** - * @notice Returns the current per-block borrow interest rate for this cToken - * @return The borrow interest rate per block, scaled by 1e18 - */ - function borrowRatePerBlock() external view override returns (uint256) { - return - interestRateModel.getBorrowRate( - getCashPrior(), - totalBorrows, - totalReserves - ); - } - - /** - * @notice Returns the current per-block supply interest rate for this cToken - * @return The supply interest rate per block, scaled by 1e18 - */ - function supplyRatePerBlock() external view override returns (uint256) { - return - interestRateModel.getSupplyRate( - getCashPrior(), - totalBorrows, - totalReserves, - reserveFactorMantissa - ); - } - - /** - * @notice Returns the current total borrows plus accrued interest - * @return The total borrows with interest - */ - function totalBorrowsCurrent() - external - override - nonReentrant - returns (uint256) - { - require(accrueInterest() == uint256(Error.NO_ERROR), "CT07"); - return totalBorrows; - } - - /** - * @notice Accrue interest to updated borrowIndex and then calculate account's borrow balance using the updated borrowIndex - * @param account The address whose balance should be calculated after updating borrowIndex - * @return The calculated balance - */ - function borrowBalanceCurrent(address account) - external - override - nonReentrant - returns (uint256) - { - require(accrueInterest() == uint256(Error.NO_ERROR), "CT07"); - return borrowBalanceStored(account); - } - - /** - * @notice Return the borrow balance of account based on stored data - * @param account The address whose balance should be calculated - * @return The calculated balance - */ - function borrowBalanceStored(address account) - public - view - override - returns (uint256) - { - (MathError err, uint256 result) = borrowBalanceStoredInternal(account); - require(err == MathError.NO_ERROR, "CT08"); - return result; - } - - /** - * @notice Return the borrow balance of account based on stored data - * @param account The address whose balance should be calculated - * @return (error code, the calculated balance or 0 if error code is non-zero) - */ - function borrowBalanceStoredInternal(address account) - internal - view - returns (MathError, uint256) - { - MathError mathErr; - uint256 principalTimesIndex; - uint256 result; - - BorrowSnapshot storage borrowSnapshot = accountBorrows[account]; - - if (borrowSnapshot.principal == 0) { - return (MathError.NO_ERROR, 0); - } - - (mathErr, principalTimesIndex) = mulUInt( - borrowSnapshot.principal, - borrowIndex - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - - (mathErr, result) = divUInt( - principalTimesIndex, - borrowSnapshot.interestIndex - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - - return (MathError.NO_ERROR, result); - } - - function getBorrowerPrincipalStored(address account) - public - view - returns (uint256 borrowed) - { - borrowed = accountBorrows[account].principal; - } - - function getSupplierSnapshotStored(address account) - public - view - returns ( - uint256 tokens, - uint256 underlyingAmount, - uint256 suppliedAt, - uint256 promisedSupplyRate - ) - { - tokens = accountTokens[account].tokens; - underlyingAmount = accountTokens[account].underlyingAmount; - suppliedAt = accountTokens[account].suppliedAt; - promisedSupplyRate = accountTokens[account].promisedSupplyRate; - } - - /** - * @notice Accrue interest then return the up-to-date exchange rate - * @return Calculated exchange rate scaled by 1e18 - */ - function exchangeRateCurrent() - public - override - nonReentrant - returns (uint256) - { - require(accrueInterest() == uint256(Error.NO_ERROR), "CT07"); - return exchangeRateStored(); - } - - /** - * @notice Calculates the exchange rate from the underlying to the CToken - * @dev This function does not accrue interest before calculating the exchange rate - * @return Calculated exchange rate scaled by 1e18 - */ - function exchangeRateStored() public view override returns (uint256) { - (MathError err, uint256 result) = exchangeRateStoredInternal(); - require(err == MathError.NO_ERROR, "CT09"); - return result; - } - - /** - * @notice Calculates the exchange rate from the underlying to the CToken - * @dev This function does not accrue interest before calculating the exchange rate - * @return (error code, calculated exchange rate scaled by 1e18) - */ - function exchangeRateStoredInternal() - internal - view - virtual - returns (MathError, uint256) - { - uint256 _totalSupply = totalSupply; - if (_totalSupply == 0) { - return (MathError.NO_ERROR, initialExchangeRateMantissa); - } else { - MathError error; - uint256 exchangeRate; - uint256 totalCash = getCashPrior(); - if (interestRateModel.isTropykusInterestRateModel()) { - (error, exchangeRate) = tropykusExchangeRateStoredInternal( - msg.sender - ); - if (error == MathError.NO_ERROR) { - return (MathError.NO_ERROR, exchangeRate); - } else { - return (MathError.NO_ERROR, initialExchangeRateMantissa); - } - } - return - interestRateModel.getExchangeRate( - totalCash, - totalBorrows, - totalReserves, - totalSupply - ); - } - } - - function tropykusExchangeRateStoredInternal(address redeemer) - internal - view - returns (MathError, uint256) - { - if (totalSupply == 0) { - return (MathError.NO_ERROR, initialExchangeRateMantissa); - } else { - SupplySnapshot storage supplySnapshot = accountTokens[redeemer]; - if (supplySnapshot.suppliedAt == 0) { - return (MathError.DIVISION_BY_ZERO, 0); - } - (, uint256 interestFactorMantissa, ) = tropykusInterestAccrued( - redeemer - ); - Exp memory interestFactor = Exp({mantissa: interestFactorMantissa}); - uint256 currentUnderlying = supplySnapshot.underlyingAmount; - Exp memory redeemerUnderlying = Exp({mantissa: currentUnderlying}); - (, Exp memory realAmount) = mulExp( - interestFactor, - redeemerUnderlying - ); - (, Exp memory exchangeRate) = getExp( - realAmount.mantissa, - supplySnapshot.tokens - ); - return (MathError.NO_ERROR, exchangeRate.mantissa); - } - } - - function tropykusInterestAccrued(address account) - internal - view - returns ( - MathError, - uint256, - uint256 - ) - { - SupplySnapshot storage supplySnapshot = accountTokens[account]; - uint256 promisedSupplyRate = supplySnapshot.promisedSupplyRate; - Exp memory expectedSupplyRatePerBlock = Exp({ - mantissa: promisedSupplyRate - }); - (, uint256 delta) = subUInt( - accrualBlockNumber, - supplySnapshot.suppliedAt - ); - (, Exp memory expectedSupplyRatePerBlockWithDelta) = mulScalar( - expectedSupplyRatePerBlock, - delta - ); - (, Exp memory interestFactor) = addExp( - Exp({mantissa: 1e18}), - expectedSupplyRatePerBlockWithDelta - ); - uint256 currentUnderlying = supplySnapshot.underlyingAmount; - Exp memory redeemerUnderlying = Exp({mantissa: currentUnderlying}); - (, Exp memory realAmount) = mulExp(interestFactor, redeemerUnderlying); - (, uint256 interestEarned) = subUInt( - realAmount.mantissa, - currentUnderlying - ); - return (MathError.NO_ERROR, interestFactor.mantissa, interestEarned); - } - - /** - * @notice Get cash balance of this cToken in the underlying asset - * @return The quantity of underlying asset owned by this contract - */ - function getCash() external view override returns (uint256) { - return getCashPrior(); - } - - /** - * @notice Applies accrued interest to total borrows and reserves - * @dev This calculates interest accrued from the last checkpointed block - * up to the current block and writes new checkpoint to storage. - */ - function accrueInterest() public override returns (uint256) { - uint256 currentBlockNumber = getBlockNumber(); - uint256 accrualBlockNumberPrior = accrualBlockNumber; - - if (accrualBlockNumberPrior == currentBlockNumber) { - return uint256(Error.NO_ERROR); - } - - uint256 cashPrior = getCashPrior(); - uint256 borrowsPrior = totalBorrows; - uint256 reservesPrior = totalReserves; - uint256 borrowIndexPrior = borrowIndex; - - uint256 borrowRateMantissa = interestRateModel.getBorrowRate( - cashPrior, - borrowsPrior, - reservesPrior - ); - require(borrowRateMantissa <= borrowRateMaxMantissa, "CT10"); - - (MathError mathErr, uint256 blockDelta) = subUInt( - currentBlockNumber, - accrualBlockNumberPrior - ); - require(mathErr == MathError.NO_ERROR, "CT11"); - - Exp memory simpleInterestFactor; - uint256 interestAccumulated; - uint256 totalBorrowsNew; - uint256 totalReservesNew; - uint256 borrowIndexNew; - - (mathErr, simpleInterestFactor) = mulScalar( - Exp({mantissa: borrowRateMantissa}), - blockDelta - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .ACCRUE_INTEREST_SIMPLE_INTEREST_FACTOR_CALCULATION_FAILED, - uint256(mathErr) - ); - } - - (mathErr, interestAccumulated) = mulScalarTruncate( - simpleInterestFactor, - borrowsPrior - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .ACCRUE_INTEREST_ACCUMULATED_INTEREST_CALCULATION_FAILED, - uint256(mathErr) - ); - } - - (mathErr, totalBorrowsNew) = addUInt(interestAccumulated, borrowsPrior); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .ACCRUE_INTEREST_NEW_TOTAL_BORROWS_CALCULATION_FAILED, - uint256(mathErr) - ); - } - - (mathErr, totalReservesNew) = mulScalarTruncateAddUInt( - Exp({mantissa: reserveFactorMantissa}), - interestAccumulated, - reservesPrior - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .ACCRUE_INTEREST_NEW_TOTAL_RESERVES_CALCULATION_FAILED, - uint256(mathErr) - ); - } - - if (interestRateModel.isTropykusInterestRateModel()) { - (mathErr, totalReservesNew) = newReserves( - borrowRateMantissa, - cashPrior, - borrowsPrior, - reservesPrior, - interestAccumulated - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .ACCRUE_INTEREST_NEW_TOTAL_RESERVES_CALCULATION_FAILED, - uint256(mathErr) - ); - } - } - - (mathErr, borrowIndexNew) = mulScalarTruncateAddUInt( - simpleInterestFactor, - borrowIndexPrior, - borrowIndexPrior - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .ACCRUE_INTEREST_NEW_BORROW_INDEX_CALCULATION_FAILED, - uint256(mathErr) - ); - } - - accrualBlockNumber = currentBlockNumber; - borrowIndex = borrowIndexNew; - totalBorrows = totalBorrowsNew; - totalReserves = totalReservesNew; - - emit AccrueInterest( - cashPrior, - interestAccumulated, - borrowIndexNew, - totalBorrowsNew - ); - - return uint256(Error.NO_ERROR); - } - - function newReserves( - uint256 borrowRateMantissa, - uint256 cashPrior, - uint256 borrowsPrior, - uint256 reservesPrior, - uint256 interestAccumulated - ) internal view returns (MathError mathErr, uint256 totalReservesNew) { - uint256 newReserveFactorMantissa; - uint256 utilizationRate = interestRateModel.utilizationRate( - cashPrior, - borrowsPrior, - reservesPrior - ); - uint256 expectedSupplyRate = interestRateModel.getSupplyRate( - cashPrior, - borrowsPrior, - reservesPrior, - reserveFactorMantissa - ); - if ( - interestRateModel.isAboveOptimal( - cashPrior, - borrowsPrior, - reservesPrior - ) - ) { - (mathErr, newReserveFactorMantissa) = mulScalarTruncate( - Exp({mantissa: utilizationRate}), - borrowRateMantissa - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - (mathErr, newReserveFactorMantissa) = subUInt( - newReserveFactorMantissa, - expectedSupplyRate - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - (mathErr, totalReservesNew) = mulScalarTruncateAddUInt( - Exp({mantissa: newReserveFactorMantissa}), - interestAccumulated, - reservesPrior - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - } else { - mathErr = MathError.NO_ERROR; - totalReservesNew = reservesPrior; - } - } - - /** - * @notice Sender supplies assets into the market and receives cTokens in exchange - * @dev Accrues interest whether or not the operation succeeds, unless reverted - * @param mintAmount The amount of the underlying asset to supply - * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual mint amount. - */ - function mintInternal(uint256 mintAmount) - internal - nonReentrant - returns (uint256, uint256) - { - if (WhitelistInterface(whitelist).enabled()) { - require(WhitelistInterface(whitelist).exist(msg.sender), "CT26"); - } - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return ( - fail(Error(error), FailureInfo.MINT_ACCRUE_INTEREST_FAILED), - 0 - ); - } - return mintFresh(msg.sender, mintAmount); - } - - struct MintLocalVars { - Error err; - MathError mathErr; - uint256 exchangeRateMantissa; - uint256 mintTokens; - uint256 totalSupplyNew; - uint256 accountTokensNew; - uint256 actualMintAmount; - } - - /** - * @notice User supplies assets into the market and receives cTokens in exchange - * @dev Assumes interest has already been accrued up to the current block - * @param minter The address of the account which is supplying the assets - * @param mintAmount The amount of the underlying asset to supply - * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual mint amount. - */ - function mintFresh(address minter, uint256 mintAmount) - internal - returns (uint256, uint256) - { - uint256 allowed = comptroller.mintAllowed( - address(this), - minter, - mintAmount - ); - if (allowed != 0) { - return ( - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.MINT_COMPTROLLER_REJECTION, - allowed - ), - 0 - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return ( - fail(Error.MARKET_NOT_FRESH, FailureInfo.MINT_FRESHNESS_CHECK), - 0 - ); - } - - MintLocalVars memory vars; - - ( - vars.mathErr, - vars.exchangeRateMantissa - ) = exchangeRateStoredInternal(); - if (vars.mathErr != MathError.NO_ERROR) { - return ( - failOpaque( - Error.MATH_ERROR, - FailureInfo.MINT_EXCHANGE_RATE_READ_FAILED, - uint256(vars.mathErr) - ), - 0 - ); - } - if (interestRateModel.isTropykusInterestRateModel()) { - SupplySnapshot storage supplySnapshot = accountTokens[minter]; - (, uint256 newTotalSupply) = addUInt( - supplySnapshot.underlyingAmount, - mintAmount - ); - require(newTotalSupply <= 0.1e18, "CT24"); - } - vars.actualMintAmount = doTransferIn(minter, mintAmount); - - (vars.mathErr, vars.mintTokens) = divScalarByExpTruncate( - vars.actualMintAmount, - Exp({mantissa: vars.exchangeRateMantissa}) - ); - require(vars.mathErr == MathError.NO_ERROR, "CT12"); - - (vars.mathErr, vars.totalSupplyNew) = addUInt( - totalSupply, - vars.mintTokens - ); - require(vars.mathErr == MathError.NO_ERROR, "CT13"); - - (vars.mathErr, vars.accountTokensNew) = addUInt( - accountTokens[minter].tokens, - vars.mintTokens - ); - require(vars.mathErr == MathError.NO_ERROR, "CT14"); - - uint256 currentSupplyRate = interestRateModel.getSupplyRate( - getCashPrior(), - totalBorrows, - totalReserves, - reserveFactorMantissa - ); - - bool isTropykusInterestRateModel = interestRateModel - .isTropykusInterestRateModel(); - - if (accountTokens[minter].tokens > 0) { - Exp memory updatedUnderlying; - if (isTropykusInterestRateModel) { - (, uint256 interestFactorMantissa, ) = tropykusInterestAccrued( - minter - ); - Exp memory interestFactor = Exp({ - mantissa: interestFactorMantissa - }); - uint256 currentUnderlyingAmount = accountTokens[minter] - .underlyingAmount; - MathError mErrorNewAmount; - (mErrorNewAmount, updatedUnderlying) = mulExp( - Exp({mantissa: currentUnderlyingAmount}), - interestFactor - ); - if (mErrorNewAmount != MathError.NO_ERROR) { - return ( - failOpaque( - Error.MATH_ERROR, - FailureInfo.MINT_EXCHANGE_CALCULATION_FAILED, - uint256(mErrorNewAmount) - ), - 0 - ); - } - } else { - uint256 currentTokens = accountTokens[minter].tokens; - MathError mErrorUpdatedUnderlying; - (mErrorUpdatedUnderlying, updatedUnderlying) = mulExp( - Exp({mantissa: currentTokens}), - Exp({mantissa: vars.exchangeRateMantissa}) - ); - if (mErrorUpdatedUnderlying != MathError.NO_ERROR) { - return ( - failOpaque( - Error.MATH_ERROR, - FailureInfo.MINT_EXCHANGE_CALCULATION_FAILED, - uint256(mErrorUpdatedUnderlying) - ), - 0 - ); - } - } - (, mintAmount) = addUInt(updatedUnderlying.mantissa, mintAmount); - } - - totalSupply = vars.totalSupplyNew; - accountTokens[minter] = SupplySnapshot({ - tokens: vars.accountTokensNew, - underlyingAmount: mintAmount, - suppliedAt: accrualBlockNumber, - promisedSupplyRate: currentSupplyRate - }); - - emit Mint(minter, vars.actualMintAmount, vars.mintTokens); - emit Transfer(address(this), minter, vars.mintTokens); - - return (uint256(Error.NO_ERROR), vars.actualMintAmount); - } - - /** - * @notice Sender redeems cTokens in exchange for a specified amount of underlying asset - * @dev Accrues interest whether or not the operation succeeds, unless reverted - * @param redeemAmount The amount of underlying to receive from redeeming cTokens - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function redeemUnderlyingInternal(uint256 redeemAmount) - internal - nonReentrant - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return - fail(Error(error), FailureInfo.REDEEM_ACCRUE_INTEREST_FAILED); - } - return redeemFresh(payable(msg.sender), redeemAmount); - } - - struct RedeemLocalVars { - Error err; - MathError mathErr; - uint256 exchangeRateMantissa; - uint256 redeemTokens; - uint256 redeemAmount; - uint256 totalSupplyNew; - uint256 accountTokensNew; - uint256 newSubsidyFund; - } - - /** - * @notice User redeems cTokens in exchange for the underlying asset - * @dev Assumes interest has already been accrued up to the current block - * @param redeemer The address of the account which is redeeming the tokens - * @param redeemAmountIn The number of underlying tokens to receive from redeeming cTokens - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function redeemFresh(address payable redeemer, uint256 redeemAmountIn) - internal - returns (uint256) - { - require(redeemAmountIn > 0, "CT15"); - - RedeemLocalVars memory vars; - - SupplySnapshot storage supplySnapshot = accountTokens[redeemer]; - - ( - vars.mathErr, - vars.exchangeRateMantissa - ) = exchangeRateStoredInternal(); - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.REDEEM_EXCHANGE_RATE_READ_FAILED, - uint256(vars.mathErr) - ); - } - - uint256 interestEarned; - uint256 subsidyFundPortion; - uint256 currentUnderlying; - - bool isTropykusInterestRateModel = interestRateModel - .isTropykusInterestRateModel(); - if (isTropykusInterestRateModel) { - currentUnderlying = supplySnapshot.underlyingAmount; - (, , interestEarned) = tropykusInterestAccrued(redeemer); - } - supplySnapshot.promisedSupplyRate = interestRateModel.getSupplyRate( - getCashPrior(), - totalBorrows, - totalReserves, - reserveFactorMantissa - ); - - if ( - isTropykusInterestRateModel && - !interestRateModel.isAboveOptimal( - getCashPrior(), - totalBorrows, - totalReserves - ) - ) { - uint256 borrowRate = interestRateModel.getBorrowRate( - getCashPrior(), - totalBorrows, - totalReserves - ); - - uint256 utilizationRate = interestRateModel.utilizationRate( - getCashPrior(), - totalBorrows, - totalReserves - ); - - (, uint256 estimatedEarning) = mulScalarTruncate( - Exp({mantissa: borrowRate}), - utilizationRate - ); - - (, subsidyFundPortion) = subUInt( - supplySnapshot.promisedSupplyRate, - estimatedEarning - ); - (, Exp memory subsidyFactor) = getExp( - subsidyFundPortion, - supplySnapshot.promisedSupplyRate - ); - (, subsidyFundPortion) = mulScalarTruncate( - subsidyFactor, - interestEarned - ); - } - - vars.redeemAmount = redeemAmountIn; - - if (isTropykusInterestRateModel) { - (, Exp memory num) = mulExp( - vars.redeemAmount, - supplySnapshot.tokens - ); - (, Exp memory realTokensWithdrawAmount) = getExp( - num.mantissa, - currentUnderlying - ); - vars.redeemTokens = realTokensWithdrawAmount.mantissa; - } else { - (vars.mathErr, vars.redeemTokens) = divScalarByExpTruncate( - redeemAmountIn, - Exp({mantissa: vars.exchangeRateMantissa}) - ); - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.REDEEM_EXCHANGE_AMOUNT_CALCULATION_FAILED, - uint256(vars.mathErr) - ); - } - } - // } - - uint256 allowed = comptroller.redeemAllowed( - address(this), - redeemer, - vars.redeemTokens - ); - if (allowed != 0) { - return - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.REDEEM_COMPTROLLER_REJECTION, - allowed - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.REDEEM_FRESHNESS_CHECK - ); - } - - (vars.mathErr, vars.totalSupplyNew) = subUInt( - totalSupply, - vars.redeemTokens - ); - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.REDEEM_NEW_TOTAL_SUPPLY_CALCULATION_FAILED, - uint256(vars.mathErr) - ); - } - - (, vars.newSubsidyFund) = subUInt(subsidyFund, subsidyFundPortion); - - (vars.mathErr, vars.accountTokensNew) = subUInt( - supplySnapshot.tokens, - vars.redeemTokens - ); - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.REDEEM_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED, - uint256(vars.mathErr) - ); - } - - uint256 cash = getCashPrior(); - if (isTropykusInterestRateModel) { - cash = address(this).balance; - } - - if (cash < vars.redeemAmount) { - return - fail( - Error.TOKEN_INSUFFICIENT_CASH, - FailureInfo.REDEEM_TRANSFER_OUT_NOT_POSSIBLE - ); - } - - doTransferOut(redeemer, vars.redeemAmount); - - totalSupply = vars.totalSupplyNew; - subsidyFund = vars.newSubsidyFund; - supplySnapshot.tokens = vars.accountTokensNew; - supplySnapshot.suppliedAt = accrualBlockNumber; - (, supplySnapshot.underlyingAmount) = subUInt( - supplySnapshot.underlyingAmount, - vars.redeemAmount - ); - - emit Transfer(redeemer, address(this), vars.redeemTokens); - emit Redeem(redeemer, vars.redeemAmount, vars.redeemTokens); - - comptroller.redeemVerify( - address(this), - redeemer, - vars.redeemAmount, - vars.redeemTokens - ); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Sender borrows assets from the protocol to their own address - * @param borrowAmount The amount of the underlying asset to borrow - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function borrowInternal(uint256 borrowAmount) - internal - nonReentrant - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return - fail(Error(error), FailureInfo.BORROW_ACCRUE_INTEREST_FAILED); - } - return borrowFresh(payable(msg.sender), borrowAmount); - } - - struct BorrowLocalVars { - MathError mathErr; - uint256 accountBorrows; - uint256 accountBorrowsNew; - uint256 totalBorrowsNew; - } - - /** - * @notice Users borrow assets from the protocol to their own address - * @param borrowAmount The amount of the underlying asset to borrow - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function borrowFresh(address payable borrower, uint256 borrowAmount) - internal - returns (uint256) - { - uint256 allowed = comptroller.borrowAllowed( - address(this), - borrower, - borrowAmount - ); - if (allowed != 0) { - return - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.BORROW_COMPTROLLER_REJECTION, - allowed - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.BORROW_FRESHNESS_CHECK - ); - } - - if (getCashPrior() < borrowAmount) { - return - fail( - Error.TOKEN_INSUFFICIENT_CASH, - FailureInfo.BORROW_CASH_NOT_AVAILABLE - ); - } - - BorrowLocalVars memory vars; - - (vars.mathErr, vars.accountBorrows) = borrowBalanceStoredInternal( - borrower - ); - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED, - uint256(vars.mathErr) - ); - } - - (vars.mathErr, vars.accountBorrowsNew) = addUInt( - vars.accountBorrows, - borrowAmount - ); - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED, - uint256(vars.mathErr) - ); - } - - (vars.mathErr, vars.totalBorrowsNew) = addUInt( - totalBorrows, - borrowAmount - ); - if (interestRateModel.isTropykusInterestRateModel()) { - require(vars.totalBorrowsNew <= 0.1e18, "CT25"); - } - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED, - uint256(vars.mathErr) - ); - } - - doTransferOut(borrower, borrowAmount); - - accountBorrows[borrower].principal = vars.accountBorrowsNew; - accountBorrows[borrower].interestIndex = borrowIndex; - totalBorrows = vars.totalBorrowsNew; - - emit Borrow( - borrower, - borrowAmount, - vars.accountBorrowsNew, - vars.totalBorrowsNew - ); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Sender repays their own borrow - * @param repayAmount The amount to repay - * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual repayment amount. - */ - function repayBorrowInternal(uint256 repayAmount) - internal - nonReentrant - returns (uint256, uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return ( - fail( - Error(error), - FailureInfo.REPAY_BORROW_ACCRUE_INTEREST_FAILED - ), - 0 - ); - } - return repayBorrowFresh(msg.sender, msg.sender, repayAmount); - } - - struct RepayBorrowLocalVars { - Error err; - MathError mathErr; - uint256 repayAmount; - uint256 borrowerIndex; - uint256 accountBorrows; - uint256 accountBorrowsNew; - uint256 totalBorrowsNew; - uint256 actualRepayAmount; - } - - /** - * @notice Borrows are repaid by another user (possibly the borrower). - * @param payer the account paying off the borrow - * @param borrower the account with the debt being payed off - * @param repayAmount the amount of undelrying tokens being returned - * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual repayment amount. - */ - function repayBorrowFresh( - address payer, - address borrower, - uint256 repayAmount - ) internal returns (uint256, uint256) { - uint256 allowed = comptroller.repayBorrowAllowed( - address(this), - payer, - borrower, - repayAmount - ); - if (allowed != 0) { - return ( - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.REPAY_BORROW_COMPTROLLER_REJECTION, - allowed - ), - 0 - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return ( - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.REPAY_BORROW_FRESHNESS_CHECK - ), - 0 - ); - } - - RepayBorrowLocalVars memory vars; - - vars.borrowerIndex = accountBorrows[borrower].interestIndex; - - (vars.mathErr, vars.accountBorrows) = borrowBalanceStoredInternal( - borrower - ); - if (vars.mathErr != MathError.NO_ERROR) { - return ( - failOpaque( - Error.MATH_ERROR, - FailureInfo - .REPAY_BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED, - uint256(vars.mathErr) - ), - 0 - ); - } - - if (repayAmount == type(uint256).max) { - vars.repayAmount = vars.accountBorrows; - } else { - vars.repayAmount = repayAmount; - } - - vars.actualRepayAmount = doTransferIn(payer, vars.repayAmount); - - (vars.mathErr, vars.accountBorrowsNew) = subUInt( - vars.accountBorrows, - vars.actualRepayAmount - ); - require(vars.mathErr == MathError.NO_ERROR, "CT16"); - - (vars.mathErr, vars.totalBorrowsNew) = subUInt( - totalBorrows, - vars.actualRepayAmount - ); - require(vars.mathErr == MathError.NO_ERROR, "CT17"); - - accountBorrows[borrower].principal = vars.accountBorrowsNew; - accountBorrows[borrower].interestIndex = borrowIndex; - totalBorrows = vars.totalBorrowsNew; - - emit RepayBorrow( - payer, - borrower, - vars.actualRepayAmount, - vars.accountBorrowsNew, - vars.totalBorrowsNew - ); - - return (uint256(Error.NO_ERROR), vars.actualRepayAmount); - } - - /** - * @notice The sender liquidates the borrowers collateral. - * The collateral seized is transferred to the liquidator. - * @param borrower The borrower of this cToken to be liquidated - * @param cTokenCollateral The market in which to seize collateral from the borrower - * @param repayAmount The amount of the underlying borrowed asset to repay - * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual repayment amount. - */ - function liquidateBorrowInternal( - address borrower, - uint256 repayAmount, - CTokenInterface cTokenCollateral - ) internal nonReentrant returns (uint256, uint256) { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return ( - fail( - Error(error), - FailureInfo.LIQUIDATE_ACCRUE_BORROW_INTEREST_FAILED - ), - 0 - ); - } - - error = cTokenCollateral.accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return ( - fail( - Error(error), - FailureInfo.LIQUIDATE_ACCRUE_COLLATERAL_INTEREST_FAILED - ), - 0 - ); - } - - // liquidateBorrowFresh emits borrow-specific logs on errors, so we don't need to - return - liquidateBorrowFresh( - msg.sender, - borrower, - repayAmount, - cTokenCollateral - ); - } - - /** - * @notice The liquidator liquidates the borrowers collateral. - * The collateral seized is transferred to the liquidator. - * @param borrower The borrower of this cToken to be liquidated - * @param liquidator The address repaying the borrow and seizing collateral - * @param cTokenCollateral The market in which to seize collateral from the borrower - * @param repayAmount The amount of the underlying borrowed asset to repay - * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual repayment amount. - */ - function liquidateBorrowFresh( - address liquidator, - address borrower, - uint256 repayAmount, - CTokenInterface cTokenCollateral - ) internal returns (uint256, uint256) { - uint256 allowed = comptroller.liquidateBorrowAllowed( - address(this), - address(cTokenCollateral), - liquidator, - borrower, - repayAmount - ); - if (allowed != 0) { - return ( - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.LIQUIDATE_COMPTROLLER_REJECTION, - allowed - ), - 0 - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return ( - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.LIQUIDATE_FRESHNESS_CHECK - ), - 0 - ); - } - - if (cTokenCollateral.accrualBlockNumber() != getBlockNumber()) { - return ( - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.LIQUIDATE_COLLATERAL_FRESHNESS_CHECK - ), - 0 - ); - } - - if (borrower == liquidator) { - return ( - fail( - Error.INVALID_ACCOUNT_PAIR, - FailureInfo.LIQUIDATE_LIQUIDATOR_IS_BORROWER - ), - 0 - ); - } - - if (repayAmount == 0) { - return ( - fail( - Error.INVALID_CLOSE_AMOUNT_REQUESTED, - FailureInfo.LIQUIDATE_CLOSE_AMOUNT_IS_ZERO - ), - 0 - ); - } - - if (repayAmount == type(uint256).max) { - return ( - fail( - Error.INVALID_CLOSE_AMOUNT_REQUESTED, - FailureInfo.LIQUIDATE_CLOSE_AMOUNT_IS_UINT_MAX - ), - 0 - ); - } - - ( - uint256 repayBorrowError, - uint256 actualRepayAmount - ) = repayBorrowFresh(liquidator, borrower, repayAmount); - if (repayBorrowError != uint256(Error.NO_ERROR)) { - return ( - fail( - Error(repayBorrowError), - FailureInfo.LIQUIDATE_REPAY_BORROW_FRESH_FAILED - ), - 0 - ); - } - - (uint256 amountSeizeError, uint256 seizeTokens) = comptroller - .liquidateCalculateSeizeTokens( - address(this), - address(cTokenCollateral), - actualRepayAmount - ); - require(amountSeizeError == uint256(Error.NO_ERROR), "CT18"); - - require(cTokenCollateral.balanceOf(borrower) >= seizeTokens, "CT19"); - - uint256 seizeError; - if (address(cTokenCollateral) == address(this)) { - seizeError = seizeInternal( - address(this), - liquidator, - borrower, - seizeTokens - ); - } else { - seizeError = cTokenCollateral.seize( - liquidator, - borrower, - seizeTokens - ); - } - - require(seizeError == uint256(Error.NO_ERROR), "CT20"); - - emit LiquidateBorrow( - liquidator, - borrower, - actualRepayAmount, - address(cTokenCollateral), - seizeTokens - ); - - return (uint256(Error.NO_ERROR), actualRepayAmount); - } - - /** - * @notice Transfers collateral tokens (this market) to the liquidator. - * @dev Will fail unless called by another cToken during the process of liquidation. - * Its absolutely critical to use msg.sender as the borrowed cToken and not a parameter. - * @param liquidator The account receiving seized collateral - * @param borrower The account having collateral seized - * @param seizeTokens The number of cTokens to seize - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function seize( - address liquidator, - address borrower, - uint256 seizeTokens - ) external override nonReentrant returns (uint256) { - return seizeInternal(msg.sender, liquidator, borrower, seizeTokens); - } - - struct SeizeVars { - uint256 seizeAmount; - uint256 exchangeRate; - uint256 borrowerTokensNew; - uint256 borrowerAmountNew; - uint256 liquidatorTokensNew; - uint256 liquidatorAmountNew; - uint256 totalCash; - uint256 supplyRate; - } - - /** - * @notice Transfers collateral tokens (this market) to the liquidator. - * @dev Called only during an in-kind liquidation, or by liquidateBorrow during the liquidation of another CToken. - * Its absolutely critical to use msg.sender as the seizer cToken and not a parameter. - * @param seizerToken The contract seizing the collateral (i.e. borrowed cToken) - * @param liquidator The account receiving seized collateral - * @param borrower The account having collateral seized - * @param seizeTokens The number of cTokens to seize - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function seizeInternal( - address seizerToken, - address liquidator, - address borrower, - uint256 seizeTokens - ) internal returns (uint256) { - uint256 allowed = comptroller.seizeAllowed( - address(this), - seizerToken, - liquidator, - borrower, - seizeTokens - ); - if (allowed != 0) { - return - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.LIQUIDATE_SEIZE_COMPTROLLER_REJECTION, - allowed - ); - } - - if (borrower == liquidator) { - return - fail( - Error.INVALID_ACCOUNT_PAIR, - FailureInfo.LIQUIDATE_SEIZE_LIQUIDATOR_IS_BORROWER - ); - } - - SeizeVars memory seizeVars; - - MathError mathErr; - - (mathErr, seizeVars.borrowerTokensNew) = subUInt( - accountTokens[borrower].tokens, - seizeTokens - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.LIQUIDATE_SEIZE_BALANCE_DECREMENT_FAILED, - uint256(mathErr) - ); - } - - seizeVars.totalCash = getCashPrior(); - seizeVars.supplyRate = interestRateModel.getSupplyRate( - seizeVars.totalCash, - totalBorrows, - totalReserves, - reserveFactorMantissa - ); - - (, seizeVars.exchangeRate) = interestRateModel.getExchangeRate( - seizeVars.totalCash, - totalBorrows, - totalReserves, - totalSupply - ); - - if (interestRateModel.isTropykusInterestRateModel()) { - (, seizeVars.exchangeRate) = tropykusExchangeRateStoredInternal( - borrower - ); - } - - (, seizeVars.seizeAmount) = mulUInt( - seizeTokens, - seizeVars.exchangeRate - ); - (, seizeVars.seizeAmount) = divUInt(seizeVars.seizeAmount, 1e18); - - (, seizeVars.borrowerAmountNew) = subUInt( - accountTokens[borrower].underlyingAmount, - seizeVars.seizeAmount - ); - - (mathErr, seizeVars.liquidatorTokensNew) = addUInt( - accountTokens[liquidator].tokens, - seizeTokens - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.LIQUIDATE_SEIZE_BALANCE_INCREMENT_FAILED, - uint256(mathErr) - ); - } - - (, seizeVars.liquidatorAmountNew) = addUInt( - accountTokens[liquidator].underlyingAmount, - seizeVars.seizeAmount - ); - - accountTokens[borrower].tokens = seizeVars.borrowerTokensNew; - accountTokens[borrower].underlyingAmount = seizeVars.borrowerAmountNew; - accountTokens[borrower].suppliedAt = getBlockNumber(); - accountTokens[borrower].promisedSupplyRate = seizeVars.supplyRate; - - accountTokens[liquidator].tokens = seizeVars.liquidatorTokensNew; - accountTokens[liquidator].underlyingAmount = seizeVars - .liquidatorAmountNew; - accountTokens[liquidator].suppliedAt = getBlockNumber(); - accountTokens[liquidator].promisedSupplyRate = seizeVars.supplyRate; - - emit Transfer(borrower, liquidator, seizeTokens); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Begins transfer of admin rights. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer. - * @dev Admin function to begin change of admin. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer. - * @param newPendingAdmin New pending admin. - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setPendingAdmin(address payable newPendingAdmin) - external - override - returns (uint256) - { - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_PENDING_ADMIN_OWNER_CHECK - ); - } - - address oldPendingAdmin = pendingAdmin; - - pendingAdmin = newPendingAdmin; - - emit NewPendingAdmin(oldPendingAdmin, newPendingAdmin); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Accepts transfer of admin rights. msg.sender must be pendingAdmin - * @dev Admin function for pending admin to accept role and update admin - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _acceptAdmin() external override returns (uint256) { - if (msg.sender != pendingAdmin || msg.sender == address(0)) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.ACCEPT_ADMIN_PENDING_ADMIN_CHECK - ); - } - - address oldAdmin = admin; - address oldPendingAdmin = pendingAdmin; - - admin = pendingAdmin; - - pendingAdmin = payable(address(0)); - - emit NewAdmin(oldAdmin, admin); - emit NewPendingAdmin(oldPendingAdmin, pendingAdmin); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Sets a new comptroller for the market - * @dev Admin function to set a new comptroller - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setComptroller(ComptrollerInterface newComptroller) - public - override - returns (uint256) - { - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_COMPTROLLER_OWNER_CHECK - ); - } - - ComptrollerInterface oldComptroller = comptroller; - require(newComptroller.isComptroller(), "CT21"); - - comptroller = newComptroller; - - emit NewComptroller(oldComptroller, newComptroller); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice accrues interest and sets a new reserve factor for the protocol using _setReserveFactorFresh - * @dev Admin function to accrue interest and set a new reserve factor - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setReserveFactor(uint256 newReserveFactorMantissa) - external - override - nonReentrant - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return - fail( - Error(error), - FailureInfo.SET_RESERVE_FACTOR_ACCRUE_INTEREST_FAILED - ); - } - return _setReserveFactorFresh(newReserveFactorMantissa); - } - - /** - * @notice Sets a new reserve factor for the protocol (*requires fresh interest accrual) - * @dev Admin function to set a new reserve factor - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setReserveFactorFresh(uint256 newReserveFactorMantissa) - internal - returns (uint256) - { - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_RESERVE_FACTOR_ADMIN_CHECK - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.SET_RESERVE_FACTOR_FRESH_CHECK - ); - } - - if (newReserveFactorMantissa > reserveFactorMaxMantissa) { - return - fail( - Error.BAD_INPUT, - FailureInfo.SET_RESERVE_FACTOR_BOUNDS_CHECK - ); - } - - uint256 oldReserveFactorMantissa = reserveFactorMantissa; - reserveFactorMantissa = newReserveFactorMantissa; - - emit NewReserveFactor( - oldReserveFactorMantissa, - newReserveFactorMantissa - ); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Accrues interest and reduces reserves by transferring from msg.sender - * @param addAmount Amount of addition to reserves - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _addReservesInternal(uint256 addAmount) - internal - nonReentrant - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return - fail( - Error(error), - FailureInfo.ADD_RESERVES_ACCRUE_INTEREST_FAILED - ); - } - - uint256 totalReservesNew; - uint256 actualAddAmount; - - if (accrualBlockNumber != getBlockNumber()) { - return ( - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.ADD_RESERVES_FRESH_CHECK - ) - ); - } - - actualAddAmount = doTransferIn(msg.sender, addAmount); - - totalReservesNew = totalReserves + actualAddAmount; - - require(totalReservesNew >= totalReserves, "CT22"); - - totalReserves = totalReservesNew; - - emit ReservesAdded(msg.sender, actualAddAmount, totalReservesNew); - - return (uint256(Error.NO_ERROR)); - } - - function _addSubsidyInternal(uint256 addAmount) - internal - nonReentrant - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - // accrueInterest emits logs on errors, but on top of that we want to log the fact that an attempted reduce reserves failed. - return fail(Error(error), FailureInfo.ADD_SUBSIDY_FUND_FAILED); - } - - uint256 subsidyFundNew; - uint256 actualAddAmount; - - if (accrualBlockNumber != getBlockNumber()) { - return ( - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.ADD_SUBSIDY_FUND_FRESH_CHECK - ) - ); - } - - actualAddAmount = doTransferIn(msg.sender, addAmount); - - subsidyFundNew = subsidyFund + actualAddAmount; - - require(subsidyFundNew >= subsidyFund, "CT22"); - - subsidyFund = subsidyFundNew; - - emit SubsidyAdded(msg.sender, actualAddAmount, subsidyFundNew); - - /* Return (NO_ERROR, actualAddAmount) */ - return (uint256(Error.NO_ERROR)); - } - - /** - * @notice Accrues interest and reduces reserves by transferring to admin - * @param reduceAmount Amount of reduction to reserves - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _reduceReserves(uint256 reduceAmount) - external - override - nonReentrant - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return - fail( - Error(error), - FailureInfo.REDUCE_RESERVES_ACCRUE_INTEREST_FAILED - ); - } - return _reduceReservesFresh(reduceAmount); - } - - /** - * @notice Reduces reserves by transferring to admin - * @dev Requires fresh interest accrual - * @param reduceAmount Amount of reduction to reserves - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _reduceReservesFresh(uint256 reduceAmount) - internal - returns (uint256) - { - uint256 totalReservesNew; - - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.REDUCE_RESERVES_ADMIN_CHECK - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.REDUCE_RESERVES_FRESH_CHECK - ); - } - - if (getCashPrior() < reduceAmount) { - return - fail( - Error.TOKEN_INSUFFICIENT_CASH, - FailureInfo.REDUCE_RESERVES_CASH_NOT_AVAILABLE - ); - } - - if (reduceAmount > totalReserves) { - return - fail(Error.BAD_INPUT, FailureInfo.REDUCE_RESERVES_VALIDATION); - } - - totalReservesNew = totalReserves - reduceAmount; - require(totalReservesNew <= totalReserves, "CT23"); - - totalReserves = totalReservesNew; - - doTransferOut(admin, reduceAmount); - - emit ReservesReduced(admin, reduceAmount, totalReservesNew); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice accrues interest and updates the interest rate model using _setInterestRateModelFresh - * @dev Admin function to accrue interest and update the interest rate model - * @param newInterestRateModel the new interest rate model to use - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setInterestRateModel(InterestRateModel newInterestRateModel) - public - override - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return - fail( - Error(error), - FailureInfo.SET_INTEREST_RATE_MODEL_ACCRUE_INTEREST_FAILED - ); - } - return _setInterestRateModelFresh(newInterestRateModel); - } - - /** - * @notice updates the interest rate model (*requires fresh interest accrual) - * @dev Admin function to update the interest rate model - * @param newInterestRateModel the new interest rate model to use - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setInterestRateModelFresh(InterestRateModel newInterestRateModel) - internal - returns (uint256) - { - InterestRateModel oldInterestRateModel; - - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_INTEREST_RATE_MODEL_OWNER_CHECK - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.SET_INTEREST_RATE_MODEL_FRESH_CHECK - ); - } - - oldInterestRateModel = interestRateModel; - - require(newInterestRateModel.isInterestRateModel(), "CT21"); - - interestRateModel = newInterestRateModel; - - emit NewMarketInterestRateModel( - oldInterestRateModel, - newInterestRateModel - ); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Gets balance of this contract in terms of the underlying - * @dev This excludes the value of the current message, if any - * @return The quantity of underlying owned by this contract - */ - function getCashPrior() internal view virtual returns (uint256); - - /** - * @dev Performs a transfer in, reverting upon failure. Returns the amount actually transferred to the protocol, in case of a fee. - * This may revert due to insufficient balance or insufficient allowance. - */ - function doTransferIn(address from, uint256 amount) - internal - virtual - returns (uint256); - - /** - * @dev Performs a transfer out, ideally returning an explanatory error code upon failure tather than reverting. - * If caller has not called checked protocol's balance, may revert due to insufficient cash held in the contract. - * If caller has checked protocol's balance, and verified it is >= amount, this should not revert in normal conditions. - */ - function doTransferOut(address payable to, uint256 amount) internal virtual; - - /** - * @dev Prevents a contract from calling itself, directly or indirectly. - */ - modifier nonReentrant() { - require(_notEntered, "re-entered"); - _notEntered = false; - _; - _notEntered = true; - } -} - - -// Dependency file: contracts/CErc20.sol - -// pragma solidity 0.8.6; - -// import "contracts/CToken.sol"; -// import "contracts/CTokenInterfaces.sol"; - -/** - * @title tropykus CErc20 Contract - * @notice CTokens which wrap an EIP-20 underlying - * @author tropykus - */ -contract CErc20 is CToken, CErc20Interface { - /** - * @notice Initialize the new money market - * @param underlying_ The address of the underlying asset - * @param comptroller_ The address of the Comptroller - * @param interestRateModel_ The address of the interest rate model - * @param initialExchangeRateMantissa_ The initial exchange rate, scaled by 1e18 - * @param name_ ERC-20 name of this token - * @param symbol_ ERC-20 symbol of this token - * @param decimals_ ERC-20 decimal precision of this token - */ - function initialize( - address underlying_, - ComptrollerInterface comptroller_, - InterestRateModel interestRateModel_, - uint256 initialExchangeRateMantissa_, - string memory name_, - string memory symbol_, - uint8 decimals_ - ) public { - // CToken initialize does the bulk of the work - super.initialize( - comptroller_, - interestRateModel_, - initialExchangeRateMantissa_, - name_, - symbol_, - decimals_ - ); - - // Set underlying and sanity check it - underlying = underlying_; - EIP20Interface(underlying).totalSupply(); - } - - /*** User Interface ***/ - - /** - * @notice Sender supplies assets into the market and receives cTokens in exchange - * @dev Accrues interest whether or not the operation succeeds, unless reverted - * @param mintAmount The amount of the underlying asset to supply - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function mint(uint256 mintAmount) external override returns (uint256) { - (uint256 err, ) = mintInternal(mintAmount); - return err; - } - - /** - * @notice Sender redeems cTokens in exchange for a specified amount of underlying asset - * @dev Accrues interest whether or not the operation succeeds, unless reverted - * @param redeemAmount The amount of underlying to redeem - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function redeem(uint256 redeemAmount) - external - override - returns (uint256) - { - return redeemUnderlyingInternal(redeemAmount); - } - - /** - * @notice Sender borrows assets from the protocol to their own address - * @param borrowAmount The amount of the underlying asset to borrow - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function borrow(uint256 borrowAmount) external override returns (uint256) { - return borrowInternal(borrowAmount); - } - - /** - * @notice Sender repays their own borrow - * @param repayAmount The amount to repay - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function repayBorrow(uint256 repayAmount) - external - override - returns (uint256) - { - (uint256 err, ) = repayBorrowInternal(repayAmount); - return err; - } - - /** - * @notice The sender liquidates the borrowers collateral. - * The collateral seized is transferred to the liquidator. - * @param borrower The borrower of this cToken to be liquidated - * @param repayAmount The amount of the underlying borrowed asset to repay - * @param cTokenCollateral The market in which to seize collateral from the borrower - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function liquidateBorrow( - address borrower, - uint256 repayAmount, - CTokenInterface cTokenCollateral - ) external override returns (uint256) { - (uint256 err, ) = liquidateBorrowInternal( - borrower, - repayAmount, - cTokenCollateral - ); - return err; - } - - /** - * @notice A public function to sweep accidental ERC-20 transfers to this contract. Tokens are sent to admin (timelock) - * @param token The address of the ERC-20 token to sweep - */ - function sweepToken(EIP20NonStandardInterface token) external override { - require(address(token) != underlying, "EC01"); - uint256 balance = token.balanceOf(address(this)); - token.transfer(admin, balance); - } - - /** - * @notice The sender adds to reserves. - * @param addAmount The amount fo underlying token to add as reserves - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _addReserves(uint256 addAmount) - external - override - returns (uint256) - { - return _addReservesInternal(addAmount); - } - - /*** Safe Token ***/ - - /** - * @notice Gets balance of this contract in terms of the underlying - * @dev This excludes the value of the current message, if any - * @return The quantity of underlying tokens owned by this contract - */ - function getCashPrior() internal view override returns (uint256) { - EIP20Interface token = EIP20Interface(underlying); - return token.balanceOf(address(this)); - } - - /** - * @dev Similar to EIP20 transfer, except it handles a False result from `transferFrom` and reverts in that case. - * This will revert due to insufficient balance or insufficient allowance. - * This function returns the actual amount received, - * which may be less than `amount` if there is a fee attached to the transfer. - * - * Note: This wrapper safely handles non-standard ERC-20 tokens that do not return a value. - * See here: https://medium.com/coinmonks/missing-return-value-bug-at-least-130-tokens-affected-d67bf08521ca - */ - function doTransferIn(address from, uint256 amount) - internal - override - returns (uint256) - { - EIP20NonStandardInterface token = EIP20NonStandardInterface(underlying); - uint256 balanceBefore = EIP20Interface(underlying).balanceOf( - address(this) - ); - token.transferFrom(from, address(this), amount); - - bool success; - assembly { - switch returndatasize() - case 0 { - // This is a non-standard ERC-20 - success := not(0) // set success to true - } - case 32 { - // This is a compliant ERC-20 - returndatacopy(0, 0, 32) - success := mload(0) // Set `success = returndata` of external call - } - default { - // This is an excessively non-compliant ERC-20, revert. - revert(0, 0) - } - } - require(success, "EC02"); - - // Calculate the amount that was *actually* transferred - uint256 balanceAfter = EIP20Interface(underlying).balanceOf( - address(this) - ); - require(balanceAfter >= balanceBefore, "EC03"); - return balanceAfter - balanceBefore; // underflow already checked above, just subtract - } - - /** - * @dev Similar to EIP20 transfer, except it handles a False success from `transfer` and returns an explanatory - * error code rather than reverting. If caller has not called checked protocol's balance, this may revert due to - * insufficient cash held in this contract. If caller has checked protocol's balance prior to this call, and verified - * it is >= amount, this should not revert in normal conditions. - * - * Note: This wrapper safely handles non-standard ERC-20 tokens that do not return a value. - * See here: https://medium.com/coinmonks/missing-return-value-bug-at-least-130-tokens-affected-d67bf08521ca - */ - function doTransferOut(address payable to, uint256 amount) - internal - virtual - override - { - EIP20NonStandardInterface token = EIP20NonStandardInterface(underlying); - token.transfer(to, amount); - - bool success; - assembly { - switch returndatasize() - case 0 { - // This is a non-standard ERC-20 - success := not(0) // set success to true - } - case 32 { - // This is a complaint ERC-20 - returndatacopy(0, 0, 32) - success := mload(0) // Set `success = returndata` of external call - } - default { - // This is an excessively non-compliant ERC-20, revert. - revert(0, 0) - } - } - require(success, "CE01"); - } -} - - -// Dependency file: contracts/PriceOracle.sol - -// pragma solidity 0.8.6; - -// import "contracts/CToken.sol"; - -abstract contract PriceOracle { - /// @notice Indicator that this is a PriceOracle contract (for inspection) - bool public constant isPriceOracle = true; - - /** - * @notice Get the underlying price of a cToken asset - * @param cToken The cToken to get the underlying price of - * @return The underlying asset price mantissa (scaled by 1e18). - * Zero means the price is unavailable. - */ - function getUnderlyingPrice(CToken cToken) - external - view - virtual - returns (uint256); -} - - -// Dependency file: contracts/Governance/GovernorAlpha.sol - -// pragma solidity 0.8.6; -pragma experimental ABIEncoderV2; - -/** - * @title Governor contract to vote on tropykus platform using TROP tokens. - * @author tropykus - * @notice This contract allows to propose and vote for protocol changes using the TROP tokens. - */ -contract GovernorAlpha { - /// @notice The name of this contract - string public constant name = "Compound Governor Alpha"; - - /// @notice The number of votes in support of a proposal required in order for a quorum to be reached and for a vote to succeed - function quorumVotes() public pure returns (uint256) { - return 400000e18; - } // 400,000 = 4% of Comp - - /// @notice The number of votes required in order for a voter to become a proposer - function proposalThreshold() public pure returns (uint256) { - return 100000e18; - } // 100,000 = 1% of Comp - - /// @notice The maximum number of actions that can be included in a proposal - function proposalMaxOperations() public pure returns (uint256) { - return 10; - } // 10 actions - - /// @notice The delay before voting on a proposal may take place, once proposed - function votingDelay() public pure returns (uint256) { - return 1; - } // 1 block - - /// @notice The duration of voting on a proposal, in blocks - function votingPeriod() public pure virtual returns (uint256) { - return 17280; - } // ~3 days in blocks (assuming 15s blocks) - - /// @notice The address of the Compound Protocol Timelock - TimelockInterface public timelock; - - /// @notice The address of the Compound governance token - CompInterface public comp; - - /// @notice The address of the Governor Guardian - address public guardian; - - /// @notice The total number of proposals - uint256 public proposalCount; - - struct Proposal { - /// @notice Unique id for looking up a proposal - uint256 id; - /// @notice Creator of the proposal - address proposer; - /// @notice The timestamp that the proposal will be available for execution, set once the vote succeeds - uint256 eta; - /// @notice the ordered list of target addresses for calls to be made - address[] targets; - /// @notice The ordered list of values (i.e. msg.value) to be passed to the calls to be made - uint256[] values; - /// @notice The ordered list of function signatures to be called - string[] signatures; - /// @notice The ordered list of calldata to be passed to each call - bytes[] calldatas; - /// @notice The block at which voting begins: holders must delegate their votes prior to this block - uint256 startBlock; - /// @notice The block at which voting ends: votes must be cast prior to this block - uint256 endBlock; - /// @notice Current number of votes in favor of this proposal - uint256 forVotes; - /// @notice Current number of votes in opposition to this proposal - uint256 againstVotes; - /// @notice Flag marking whether the proposal has been canceled - bool canceled; - /// @notice Flag marking whether the proposal has been executed - bool executed; - /// @notice Receipts of ballots for the entire set of voters - mapping(address => Receipt) receipts; - } - - /// @notice Ballot receipt record for a voter - struct Receipt { - /// @notice Whether or not a vote has been cast - bool hasVoted; - /// @notice Whether or not the voter supports the proposal - bool support; - /// @notice The number of votes the voter had, which were cast - uint96 votes; - } - - /// @notice Possible states that a proposal may be in - enum ProposalState { - Pending, - Active, - Canceled, - Defeated, - Succeeded, - Queued, - Expired, - Executed - } - - /// @notice The official record of all proposals ever proposed - mapping(uint256 => Proposal) public proposals; - - /// @notice The latest proposal for each proposer - mapping(address => uint256) public latestProposalIds; - - /// @notice The EIP-712 typehash for the contract's domain - bytes32 public constant DOMAIN_TYPEHASH = - keccak256( - "EIP712Domain(string name,uint256 chainId,address verifyingContract)" - ); - - /// @notice The EIP-712 typehash for the ballot struct used by the contract - bytes32 public constant BALLOT_TYPEHASH = - keccak256("Ballot(uint256 proposalId,bool support)"); - - /// @notice An event emitted when a new proposal is created - event ProposalCreated( - uint256 id, - address proposer, - address[] targets, - uint256[] values, - string[] signatures, - bytes[] calldatas, - uint256 startBlock, - uint256 endBlock, - string description - ); - - /// @notice An event emitted when a vote has been cast on a proposal - event VoteCast( - address voter, - uint256 proposalId, - bool support, - uint256 votes - ); - - /// @notice An event emitted when a proposal has been canceled - event ProposalCanceled(uint256 id); - - /// @notice An event emitted when a proposal has been queued in the Timelock - event ProposalQueued(uint256 id, uint256 eta); - - /// @notice An event emitted when a proposal has been executed in the Timelock - event ProposalExecuted(uint256 id); - - constructor( - address timelock_, - address comp_, - address guardian_ - ) { - timelock = TimelockInterface(timelock_); - comp = CompInterface(comp_); - guardian = guardian_; - } - - function propose( - address[] memory targets, - uint256[] memory values, - string[] memory signatures, - bytes[] memory calldatas, - string memory description - ) public returns (uint256) { - require( - comp.getPriorVotes(msg.sender, sub256(block.number, 1)) > - proposalThreshold(), - "GovernorAlpha::propose: proposer votes below proposal threshold" - ); - require( - targets.length == values.length && - targets.length == signatures.length && - targets.length == calldatas.length, - "GovernorAlpha::propose: proposal function information arity mismatch" - ); - require( - targets.length != 0, - "GovernorAlpha::propose: must provide actions" - ); - require( - targets.length <= proposalMaxOperations(), - "GovernorAlpha::propose: too many actions" - ); - - uint256 latestProposalId = latestProposalIds[msg.sender]; - if (latestProposalId != 0) { - ProposalState proposersLatestProposalState = state( - latestProposalId - ); - require( - proposersLatestProposalState != ProposalState.Active, - "GovernorAlpha::propose: one live proposal per proposer" - ); - require( - proposersLatestProposalState != ProposalState.Pending, - "GovernorAlpha::propose: one live proposal per proposer" - ); - } - - uint256 startBlock = add256(block.number, votingDelay()); - uint256 endBlock = add256(startBlock, votingPeriod()); - - proposalCount++; - Proposal storage newProposal = proposals[proposalCount]; - newProposal.id = proposalCount; - newProposal.proposer = msg.sender; - newProposal.eta = 0; - newProposal.targets = targets; - newProposal.values = values; - newProposal.signatures = signatures; - newProposal.calldatas = calldatas; - newProposal.startBlock = startBlock; - newProposal.endBlock = endBlock; - newProposal.forVotes = 0; - newProposal.againstVotes = 0; - newProposal.canceled = false; - newProposal.executed = false; - - latestProposalIds[newProposal.proposer] = newProposal.id; - - emit ProposalCreated( - newProposal.id, - msg.sender, - targets, - values, - signatures, - calldatas, - startBlock, - endBlock, - description - ); - return newProposal.id; - } - - function queue(uint256 proposalId) public { - require( - state(proposalId) == ProposalState.Succeeded, - "GovernorAlpha::queue: proposal can only be queued if it is succeeded" - ); - Proposal storage proposal = proposals[proposalId]; - uint256 eta = add256(block.timestamp, timelock.delay()); - for (uint256 i = 0; i < proposal.targets.length; i++) { - _queueOrRevert( - proposal.targets[i], - proposal.values[i], - proposal.signatures[i], - proposal.calldatas[i], - eta - ); - } - proposal.eta = eta; - emit ProposalQueued(proposalId, eta); - } - - function _queueOrRevert( - address target, - uint256 value, - string memory signature, - bytes memory data, - uint256 eta - ) internal { - require( - !timelock.queuedTransactions( - keccak256(abi.encode(target, value, signature, data, eta)) - ), - "GovernorAlpha::_queueOrRevert: proposal action already queued at eta" - ); - timelock.queueTransaction(target, value, signature, data, eta); - } - - function execute(uint256 proposalId) public payable { - require( - state(proposalId) == ProposalState.Queued, - "GovernorAlpha::execute: proposal can only be executed if it is queued" - ); - Proposal storage proposal = proposals[proposalId]; - proposal.executed = true; - for (uint256 i = 0; i < proposal.targets.length; i++) { - timelock.executeTransaction{value: proposal.values[i]}( - proposal.targets[i], - proposal.values[i], - proposal.signatures[i], - proposal.calldatas[i], - proposal.eta - ); - } - emit ProposalExecuted(proposalId); - } - - function cancel(uint256 proposalId) public { - ProposalState proposalState = state(proposalId); - require( - proposalState != ProposalState.Executed, - "GovernorAlpha::cancel: cannot cancel executed proposal" - ); - - Proposal storage proposal = proposals[proposalId]; - require( - msg.sender == guardian || - comp.getPriorVotes(proposal.proposer, sub256(block.number, 1)) < - proposalThreshold(), - "GovernorAlpha::cancel: proposer above threshold" - ); - - proposal.canceled = true; - for (uint256 i = 0; i < proposal.targets.length; i++) { - timelock.cancelTransaction( - proposal.targets[i], - proposal.values[i], - proposal.signatures[i], - proposal.calldatas[i], - proposal.eta - ); - } - - emit ProposalCanceled(proposalId); - } - - function getActions(uint256 proposalId) - public - view - returns ( - address[] memory targets, - uint256[] memory values, - string[] memory signatures, - bytes[] memory calldatas - ) - { - Proposal storage p = proposals[proposalId]; - return (p.targets, p.values, p.signatures, p.calldatas); - } - - function getReceipt(uint256 proposalId, address voter) - public - view - returns (Receipt memory) - { - return proposals[proposalId].receipts[voter]; - } - - function state(uint256 proposalId) public view returns (ProposalState) { - require( - proposalCount >= proposalId && proposalId > 0, - "GovernorAlpha::state: invalid proposal id" - ); - Proposal storage proposal = proposals[proposalId]; - if (proposal.canceled) { - return ProposalState.Canceled; - } else if (block.number <= proposal.startBlock) { - return ProposalState.Pending; - } else if (block.number <= proposal.endBlock) { - return ProposalState.Active; - } else if ( - proposal.forVotes <= proposal.againstVotes || - proposal.forVotes < quorumVotes() - ) { - return ProposalState.Defeated; - } else if (proposal.eta == 0) { - return ProposalState.Succeeded; - } else if (proposal.executed) { - return ProposalState.Executed; - } else if ( - block.timestamp >= add256(proposal.eta, timelock.GRACE_PERIOD()) - ) { - return ProposalState.Expired; - } else { - return ProposalState.Queued; - } - } - - function castVote(uint256 proposalId, bool support) public { - return _castVote(msg.sender, proposalId, support); - } - - function castVoteBySig( - uint256 proposalId, - bool support, - uint8 v, - bytes32 r, - bytes32 s - ) public { - bytes32 domainSeparator = keccak256( - abi.encode( - DOMAIN_TYPEHASH, - keccak256(bytes(name)), - getChainId(), - address(this) - ) - ); - bytes32 structHash = keccak256( - abi.encode(BALLOT_TYPEHASH, proposalId, support) - ); - bytes32 digest = keccak256( - abi.encodePacked("\x19\x01", domainSeparator, structHash) - ); - address signatory = ecrecover(digest, v, r, s); - require( - signatory != 0xdcc703c0E500B653Ca82273B7BFAd8045D85a470 && - signatory != address(0), - "GovernorAlpha::castVoteBySig: invalid signature" - ); - return _castVote(signatory, proposalId, support); - } - - function _castVote( - address voter, - uint256 proposalId, - bool support - ) internal { - require( - state(proposalId) == ProposalState.Active, - "GovernorAlpha::_castVote: voting is closed" - ); - Proposal storage proposal = proposals[proposalId]; - Receipt storage receipt = proposal.receipts[voter]; - require( - receipt.hasVoted == false, - "GovernorAlpha::_castVote: voter already voted" - ); - uint96 votes = comp.getPriorVotes(voter, proposal.startBlock); - - if (support) { - proposal.forVotes = add256(proposal.forVotes, votes); - } else { - proposal.againstVotes = add256(proposal.againstVotes, votes); - } - - receipt.hasVoted = true; - receipt.support = support; - receipt.votes = votes; - - emit VoteCast(voter, proposalId, support, votes); - } - - function __acceptAdmin() public { - require( - msg.sender == guardian, - "GovernorAlpha::__acceptAdmin: sender must be gov guardian" - ); - timelock.acceptAdmin(); - } - - function __abdicate() public { - require( - msg.sender == guardian, - "GovernorAlpha::__abdicate: sender must be gov guardian" - ); - guardian = address(0); - } - - function __queueSetTimelockPendingAdmin( - address newPendingAdmin, - uint256 eta - ) public { - require( - msg.sender == guardian, - "GovernorAlpha::__queueSetTimelockPendingAdmin: sender must be gov guardian" - ); - timelock.queueTransaction( - address(timelock), - 0, - "setPendingAdmin(address)", - abi.encode(newPendingAdmin), - eta - ); - } - - function __executeSetTimelockPendingAdmin( - address newPendingAdmin, - uint256 eta - ) public { - require( - msg.sender == guardian, - "GovernorAlpha::__executeSetTimelockPendingAdmin: sender must be gov guardian" - ); - timelock.executeTransaction( - address(timelock), - 0, - "setPendingAdmin(address)", - abi.encode(newPendingAdmin), - eta - ); - } - - function add256(uint256 a, uint256 b) internal pure returns (uint256) { - uint256 c = a + b; - require(c >= a, "addition overflow"); - return c; - } - - function sub256(uint256 a, uint256 b) internal pure returns (uint256) { - require(b <= a, "subtraction underflow"); - return a - b; - } - - function getChainId() internal view returns (uint256) { - uint256 chainId; - assembly { - chainId := chainid() - } - return chainId; - } -} - -interface TimelockInterface { - function delay() external view returns (uint256); - - function GRACE_PERIOD() external view returns (uint256); - - function acceptAdmin() external; - - function queuedTransactions(bytes32 hash) external view returns (bool); - - function queueTransaction( - address target, - uint256 value, - string calldata signature, - bytes calldata data, - uint256 eta - ) external returns (bytes32); - - function cancelTransaction( - address target, - uint256 value, - string calldata signature, - bytes calldata data, - uint256 eta - ) external; - - function executeTransaction( - address target, - uint256 value, - string calldata signature, - bytes calldata data, - uint256 eta - ) external payable returns (bytes memory); -} - -interface CompInterface { - function getPriorVotes(address account, uint256 blockNumber) - external - view - returns (uint96); -} - - -// Dependency file: contracts/Governance/TROP.sol - -// pragma solidity 0.8.6; -pragma experimental ABIEncoderV2; - -/** - * @title TROP ERC20 tokens. - * @author tropykus - * @notice Yield farming tokens that allow to propose and vote for protocol changes using the governance system. - */ -contract TROP { - /// @notice EIP-20 token name for this token - string public constant name = "tropykus"; - - /// @notice EIP-20 token symbol for this token - string public constant symbol = "TROP"; - - /// @notice EIP-20 token decimals for this token - uint8 public constant decimals = 18; - - /// @notice Total number of tokens in circulation - uint256 public constant totalSupply = 10000000e18; // 10 million TROP - - /// @notice Allowance amounts on behalf of others - mapping(address => mapping(address => uint96)) internal allowances; - - /// @notice Official record of token balances for each account - mapping(address => uint96) internal balances; - - /// @notice A record of each accounts delegate - mapping(address => address) public delegates; - - /// @notice A checkpoint for marking number of votes from a given block - struct Checkpoint { - uint32 fromBlock; - uint96 votes; - } - - /// @notice A record of votes checkpoints for each account, by index - mapping(address => mapping(uint32 => Checkpoint)) public checkpoints; - - /// @notice The number of checkpoints for each account - mapping(address => uint32) public numCheckpoints; - - /// @notice The EIP-712 typehash for the contract's domain - bytes32 public constant DOMAIN_TYPEHASH = - keccak256( - "EIP712Domain(string name,uint256 chainId,address verifyingContract)" - ); - - /// @notice The EIP-712 typehash for the delegation struct used by the contract - bytes32 public constant DELEGATION_TYPEHASH = - keccak256("Delegation(address delegatee,uint256 nonce,uint256 expiry)"); - - /// @notice A record of states for signing / validating signatures - mapping(address => uint256) public nonces; - - /// @notice An event thats emitted when an account changes its delegate - event DelegateChanged( - address indexed delegator, - address indexed fromDelegate, - address indexed toDelegate - ); - - /// @notice An event thats emitted when a delegate account's vote balance changes - event DelegateVotesChanged( - address indexed delegate, - uint256 previousBalance, - uint256 newBalance - ); - - /// @notice The standard EIP-20 transfer event - event Transfer(address indexed from, address indexed to, uint256 amount); - - /// @notice The standard EIP-20 approval event - event Approval( - address indexed owner, - address indexed spender, - uint256 amount - ); - - /** - * @notice Construct a new TROP token - * @param account The initial account to grant all the tokens - */ - constructor(address account) { - balances[account] = uint96(totalSupply); - emit Transfer(address(0), account, totalSupply); - } - - /** - * @notice Get the number of tokens `spender` is approved to spend on behalf of `account` - * @param account The address of the account holding the funds - * @param spender The address of the account spending the funds - * @return The number of tokens approved - */ - function allowance(address account, address spender) - external - view - returns (uint256) - { - return allowances[account][spender]; - } - - /** - * @notice Approve `spender` to transfer up to `amount` from `src` - * @dev This will overwrite the approval amount for `spender` - * and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve) - * @param spender The address of the account which may transfer tokens - * @param rawAmount The number of tokens that are approved (2^256-1 means infinite) - * @return Whether or not the approval succeeded - */ - function approve(address spender, uint256 rawAmount) - external - returns (bool) - { - uint96 amount; - if (rawAmount == type(uint256).max) { - amount = type(uint96).max; - } else { - amount = safe96(rawAmount, "TROP::approve: amount exceeds 96 bits"); - } - - allowances[msg.sender][spender] = amount; - - emit Approval(msg.sender, spender, amount); - return true; - } - - /** - * @notice Get the number of tokens held by the `account` - * @param account The address of the account to get the balance of - * @return The number of tokens held - */ - function balanceOf(address account) external view returns (uint256) { - return balances[account]; - } - - /** - * @notice Transfer `amount` tokens from `msg.sender` to `dst` - * @param dst The address of the destination account - * @param rawAmount The number of tokens to transfer - * @return Whether or not the transfer succeeded - */ - function transfer(address dst, uint256 rawAmount) external returns (bool) { - uint96 amount = safe96( - rawAmount, - "TROP::transfer: amount exceeds 96 bits" - ); - _transferTokens(msg.sender, dst, amount); - return true; - } - - /** - * @notice Transfer `amount` tokens from `src` to `dst` - * @param src The address of the source account - * @param dst The address of the destination account - * @param rawAmount The number of tokens to transfer - * @return Whether or not the transfer succeeded - */ - function transferFrom( - address src, - address dst, - uint256 rawAmount - ) external returns (bool) { - address spender = msg.sender; - uint96 spenderAllowance = allowances[src][spender]; - uint96 amount = safe96( - rawAmount, - "TROP::approve: amount exceeds 96 bits" - ); - - if (spender != src && spenderAllowance != type(uint96).max) { - uint96 newAllowance = sub96( - spenderAllowance, - amount, - "TROP::transferFrom: transfer amount exceeds spender allowance" - ); - allowances[src][spender] = newAllowance; - - emit Approval(src, spender, newAllowance); - } - - _transferTokens(src, dst, amount); - return true; - } - - /** - * @notice Delegate votes from `msg.sender` to `delegatee` - * @param delegatee The address to delegate votes to - */ - function delegate(address delegatee) public { - return _delegate(msg.sender, delegatee); - } - - /** - * @notice Delegates votes from signatory to `delegatee` - * @param delegatee The address to delegate votes to - * @param nonce The contract state required to match the signature - * @param expiry The time at which to expire the signature - * @param v The recovery byte of the signature - * @param r Half of the ECDSA signature pair - * @param s Half of the ECDSA signature pair - */ - function delegateBySig( - address delegatee, - uint256 nonce, - uint256 expiry, - uint8 v, - bytes32 r, - bytes32 s - ) public { - bytes32 domainSeparator = keccak256( - abi.encode( - DOMAIN_TYPEHASH, - keccak256(bytes(name)), - getChainId(), - address(this) - ) - ); - bytes32 structHash = keccak256( - abi.encode(DELEGATION_TYPEHASH, delegatee, nonce, expiry) - ); - bytes32 digest = keccak256( - abi.encodePacked("\x19\x01", domainSeparator, structHash) - ); - address signatory = ecrecover(digest, v, r, s); - require( - signatory != 0xdcc703c0E500B653Ca82273B7BFAd8045D85a470 && - signatory != address(0), - "TROP::delegateBySig: invalid signature" - ); - require( - nonce == nonces[signatory]++, - "TROP::delegateBySig: invalid nonce" - ); - require( - block.timestamp <= expiry, - "TROP::delegateBySig: signature expired" - ); - return _delegate(signatory, delegatee); - } - - /** - * @notice Gets the current votes balance for `account` - * @param account The address to get votes balance - * @return The number of current votes for `account` - */ - function getCurrentVotes(address account) external view returns (uint96) { - uint32 nCheckpoints = numCheckpoints[account]; - return - nCheckpoints > 0 ? checkpoints[account][nCheckpoints - 1].votes : 0; - } - - /** - * @notice Determine the prior number of votes for an account as of a block number - * @dev Block number must be a finalized block or else this function will revert to prevent misinformation. - * @param account The address of the account to check - * @param blockNumber The block number to get the vote balance at - * @return The number of votes the account had as of the given block - */ - function getPriorVotes(address account, uint256 blockNumber) - public - view - returns (uint96) - { - require( - blockNumber < block.number, - "TROP::getPriorVotes: not yet determined" - ); - - uint32 nCheckpoints = numCheckpoints[account]; - if (nCheckpoints == 0) { - return 0; - } - - // First check most recent balance - if (checkpoints[account][nCheckpoints - 1].fromBlock <= blockNumber) { - return checkpoints[account][nCheckpoints - 1].votes; - } - - // Next check implicit zero balance - if (checkpoints[account][0].fromBlock > blockNumber) { - return 0; - } - - uint32 lower = 0; - uint32 upper = nCheckpoints - 1; - while (upper > lower) { - uint32 center = upper - (upper - lower) / 2; // ceil, avoiding overflow - Checkpoint memory cp = checkpoints[account][center]; - if (cp.fromBlock == blockNumber) { - return cp.votes; - } else if (cp.fromBlock < blockNumber) { - lower = center; - } else { - upper = center - 1; - } - } - return checkpoints[account][lower].votes; - } - - function _delegate(address delegator, address delegatee) internal { - address currentDelegate = delegates[delegator]; - uint96 delegatorBalance = balances[delegator]; - delegates[delegator] = delegatee; - - emit DelegateChanged(delegator, currentDelegate, delegatee); - - _moveDelegates(currentDelegate, delegatee, delegatorBalance); - } - - function _transferTokens( - address src, - address dst, - uint96 amount - ) internal { - require( - src != address(0), - "TROP::_transferTokens: cannot transfer from the zero address" - ); - require( - dst != address(0), - "TROP::_transferTokens: cannot transfer to the zero address" - ); - - balances[src] = sub96( - balances[src], - amount, - "TROP::_transferTokens: transfer amount exceeds balance" - ); - balances[dst] = add96( - balances[dst], - amount, - "TROP::_transferTokens: transfer amount overflows" - ); - emit Transfer(src, dst, amount); - - _moveDelegates(delegates[src], delegates[dst], amount); - } - - function _moveDelegates( - address srcRep, - address dstRep, - uint96 amount - ) internal { - if (srcRep != dstRep && amount > 0) { - if (srcRep != address(0)) { - uint32 srcRepNum = numCheckpoints[srcRep]; - uint96 srcRepOld = srcRepNum > 0 - ? checkpoints[srcRep][srcRepNum - 1].votes - : 0; - uint96 srcRepNew = sub96( - srcRepOld, - amount, - "TROP::_moveVotes: vote amount underflows" - ); - _writeCheckpoint(srcRep, srcRepNum, srcRepOld, srcRepNew); - } - - if (dstRep != address(0)) { - uint32 dstRepNum = numCheckpoints[dstRep]; - uint96 dstRepOld = dstRepNum > 0 - ? checkpoints[dstRep][dstRepNum - 1].votes - : 0; - uint96 dstRepNew = add96( - dstRepOld, - amount, - "TROP::_moveVotes: vote amount overflows" - ); - _writeCheckpoint(dstRep, dstRepNum, dstRepOld, dstRepNew); - } - } - } - - function _writeCheckpoint( - address delegatee, - uint32 nCheckpoints, - uint96 oldVotes, - uint96 newVotes - ) internal { - uint32 blockNumber = safe32( - block.number, - "TROP::_writeCheckpoint: block number exceeds 32 bits" - ); - - if ( - nCheckpoints > 0 && - checkpoints[delegatee][nCheckpoints - 1].fromBlock == blockNumber - ) { - checkpoints[delegatee][nCheckpoints - 1].votes = newVotes; - } else { - checkpoints[delegatee][nCheckpoints] = Checkpoint( - blockNumber, - newVotes - ); - numCheckpoints[delegatee] = nCheckpoints + 1; - } - - emit DelegateVotesChanged(delegatee, oldVotes, newVotes); - } - - function safe32(uint256 n, string memory errorMessage) - internal - pure - returns (uint32) - { - require(n < 2**32, errorMessage); - return uint32(n); - } - - function safe96(uint256 n, string memory errorMessage) - internal - pure - returns (uint96) - { - require(n < 2**96, errorMessage); - return uint96(n); - } - - function add96( - uint96 a, - uint96 b, - string memory errorMessage - ) internal pure returns (uint96) { - uint96 c = a + b; - require(c >= a, errorMessage); - return c; - } - - function sub96( - uint96 a, - uint96 b, - string memory errorMessage - ) internal pure returns (uint96) { - require(b <= a, errorMessage); - return a - b; - } - - function getChainId() internal view returns (uint256) { - uint256 chainId; - assembly { - chainId := chainid() - } - return chainId; - } -} - - -// Root file: contracts/Lens/TropykusLens.sol - -pragma solidity 0.8.6; -pragma experimental ABIEncoderV2; - -// import "contracts/CErc20.sol"; -// import "contracts/CToken.sol"; -// import "contracts/PriceOracle.sol"; -// import "contracts/EIP20Interface.sol"; -// import "contracts/Governance/GovernorAlpha.sol"; -// import "contracts/Governance/TROP.sol"; - -interface ComptrollerLensInterface { - function markets(address) external view returns (bool, uint); - function oracle() external view returns (PriceOracle); - function getAccountLiquidity(address) external view returns (uint, uint, uint); - function getAssetsIn(address) external view returns (CToken[] memory); - function claimComp(address) external; - function compAccrued(address) external view returns (uint); -} - -/** - * @title Helper contract to get information of the protocol . - * @author tropykus - * @notice TropykusLens allows to make obtain global information with a single call. - */ -contract TropykusLens { - struct CTokenMetadata { - address cToken; - uint exchangeRateCurrent; - uint supplyRatePerBlock; - uint borrowRatePerBlock; - uint reserveFactorMantissa; - uint totalBorrows; - uint totalReserves; - uint totalSupply; - uint totalCash; - bool isListed; - uint collateralFactorMantissa; - address underlyingAssetAddress; - uint cTokenDecimals; - uint underlyingDecimals; - } - - function cTokenMetadata(CToken cToken) public returns (CTokenMetadata memory) { - uint exchangeRateCurrent = cToken.exchangeRateCurrent(); - ComptrollerLensInterface comptroller = ComptrollerLensInterface(address(cToken.comptroller())); - (bool isListed, uint collateralFactorMantissa) = comptroller.markets(address(cToken)); - address underlyingAssetAddress; - uint underlyingDecimals; - - if (compareStrings(cToken.symbol(), "cRBTC")) { - underlyingAssetAddress = address(0); - underlyingDecimals = 18; - } else { - CErc20 cErc20 = CErc20(address(cToken)); - underlyingAssetAddress = cErc20.underlying(); - underlyingDecimals = EIP20Interface(cErc20.underlying()).decimals(); - } - - return CTokenMetadata({ - cToken: address(cToken), - exchangeRateCurrent: exchangeRateCurrent, - supplyRatePerBlock: cToken.supplyRatePerBlock(), - borrowRatePerBlock: cToken.borrowRatePerBlock(), - reserveFactorMantissa: cToken.reserveFactorMantissa(), - totalBorrows: cToken.totalBorrows(), - totalReserves: cToken.totalReserves(), - totalSupply: cToken.totalSupply(), - totalCash: cToken.getCash(), - isListed: isListed, - collateralFactorMantissa: collateralFactorMantissa, - underlyingAssetAddress: underlyingAssetAddress, - cTokenDecimals: cToken.decimals(), - underlyingDecimals: underlyingDecimals - }); - } - - function cTokenMetadataAll(CToken[] calldata cTokens) external returns (CTokenMetadata[] memory) { - uint cTokenCount = cTokens.length; - CTokenMetadata[] memory res = new CTokenMetadata[](cTokenCount); - for (uint i = 0; i < cTokenCount; i++) { - res[i] = cTokenMetadata(cTokens[i]); - } - return res; - } - - struct CTokenBalances { - address cToken; - uint balanceOf; - uint borrowBalanceCurrent; - uint balanceOfUnderlying; - uint tokenBalance; - uint tokenAllowance; - } - - function cTokenBalances(CToken cToken, address payable account) public returns (CTokenBalances memory) { - uint balanceOf = cToken.balanceOf(account); - uint borrowBalanceCurrent = cToken.borrowBalanceCurrent(account); - uint balanceOfUnderlying = cToken.balanceOfUnderlying(account); - uint tokenBalance; - uint tokenAllowance; - - if (compareStrings(cToken.symbol(), "cRBTC")) { - tokenBalance = account.balance; - tokenAllowance = account.balance; - } else { - CErc20 cErc20 = CErc20(address(cToken)); - EIP20Interface underlying = EIP20Interface(cErc20.underlying()); - tokenBalance = underlying.balanceOf(account); - tokenAllowance = underlying.allowance(account, address(cToken)); - } - - return CTokenBalances({ - cToken: address(cToken), - balanceOf: balanceOf, - borrowBalanceCurrent: borrowBalanceCurrent, - balanceOfUnderlying: balanceOfUnderlying, - tokenBalance: tokenBalance, - tokenAllowance: tokenAllowance - }); - } - - function cTokenBalancesAll(CToken[] calldata cTokens, address payable account) external returns (CTokenBalances[] memory) { - uint cTokenCount = cTokens.length; - CTokenBalances[] memory res = new CTokenBalances[](cTokenCount); - for (uint i = 0; i < cTokenCount; i++) { - res[i] = cTokenBalances(cTokens[i], account); - } - return res; - } - - struct CTokenUnderlyingPrice { - address cToken; - uint underlyingPrice; - } - - function cTokenUnderlyingPrice(CToken cToken) public view returns (CTokenUnderlyingPrice memory) { - ComptrollerLensInterface comptroller = ComptrollerLensInterface(address(cToken.comptroller())); - PriceOracle priceOracle = comptroller.oracle(); - - return CTokenUnderlyingPrice({ - cToken: address(cToken), - underlyingPrice: priceOracle.getUnderlyingPrice(cToken) - }); - } - - function cTokenUnderlyingPriceAll(CToken[] calldata cTokens) external view returns (CTokenUnderlyingPrice[] memory) { - uint cTokenCount = cTokens.length; - CTokenUnderlyingPrice[] memory res = new CTokenUnderlyingPrice[](cTokenCount); - for (uint i = 0; i < cTokenCount; i++) { - res[i] = cTokenUnderlyingPrice(cTokens[i]); - } - return res; - } - - struct AccountLimits { - CToken[] markets; - uint liquidity; - uint shortfall; - } - - function getAccountLimits(ComptrollerLensInterface comptroller, address account) public view returns (AccountLimits memory) { - (uint errorCode, uint liquidity, uint shortfall) = comptroller.getAccountLiquidity(account); - require(errorCode == 0,"liquidity error"); - - return AccountLimits({ - markets: comptroller.getAssetsIn(account), - liquidity: liquidity, - shortfall: shortfall - }); - } - - struct GovReceipt { - uint proposalId; - bool hasVoted; - bool support; - uint96 votes; - } - - function getGovReceipts(GovernorAlpha governor, address voter, uint[] memory proposalIds) public view returns (GovReceipt[] memory) { - uint proposalCount = proposalIds.length; - GovReceipt[] memory res = new GovReceipt[](proposalCount); - for (uint i = 0; i < proposalCount; i++) { - GovernorAlpha.Receipt memory receipt = governor.getReceipt(proposalIds[i], voter); - res[i] = GovReceipt({ - proposalId: proposalIds[i], - hasVoted: receipt.hasVoted, - support: receipt.support, - votes: receipt.votes - }); - } - return res; - } - - struct GovProposal { - uint proposalId; - address proposer; - uint eta; - address[] targets; - uint[] values; - string[] signatures; - bytes[] calldatas; - uint startBlock; - uint endBlock; - uint forVotes; - uint againstVotes; - bool canceled; - bool executed; - } - - function setProposal(GovProposal memory res, GovernorAlpha governor, uint proposalId) internal view { - ( - , - address proposer, - uint eta, - uint startBlock, - uint endBlock, - uint forVotes, - uint againstVotes, - bool canceled, - bool executed - ) = governor.proposals(proposalId); - res.proposalId = proposalId; - res.proposer = proposer; - res.eta = eta; - res.startBlock = startBlock; - res.endBlock = endBlock; - res.forVotes = forVotes; - res.againstVotes = againstVotes; - res.canceled = canceled; - res.executed = executed; - } - - function getGovProposals(GovernorAlpha governor, uint[] calldata proposalIds) external view returns (GovProposal[] memory) { - GovProposal[] memory res = new GovProposal[](proposalIds.length); - for (uint i = 0; i < proposalIds.length; i++) { - ( - address[] memory targets, - uint[] memory values, - string[] memory signatures, - bytes[] memory calldatas - ) = governor.getActions(proposalIds[i]); - res[i] = GovProposal({ - proposalId: 0, - proposer: address(0), - eta: 0, - targets: targets, - values: values, - signatures: signatures, - calldatas: calldatas, - startBlock: 0, - endBlock: 0, - forVotes: 0, - againstVotes: 0, - canceled: false, - executed: false - }); - setProposal(res[i], governor, proposalIds[i]); - } - return res; - } - - struct CompBalanceMetadata { - uint balance; - uint votes; - address delegate; - } - - function getCompBalanceMetadata(TROP comp, address account) external view returns (CompBalanceMetadata memory) { - return CompBalanceMetadata({ - balance: comp.balanceOf(account), - votes: uint256(comp.getCurrentVotes(account)), - delegate: comp.delegates(account) - }); - } - - struct CompBalanceMetadataExt { - uint balance; - uint votes; - address delegate; - uint allocated; - } - - function getCompBalanceMetadataExt(TROP comp, ComptrollerLensInterface comptroller, address account) external returns (CompBalanceMetadataExt memory) { - uint balance = comp.balanceOf(account); - comptroller.claimComp(account); - uint newBalance = comp.balanceOf(account); - uint accrued = comptroller.compAccrued(account); - uint total = add(accrued, newBalance, "sum comp total"); - uint allocated = sub(total, balance, "sub allocated"); - - return CompBalanceMetadataExt({ - balance: balance, - votes: uint256(comp.getCurrentVotes(account)), - delegate: comp.delegates(account), - allocated: allocated - }); - } - - struct CompVotes { - uint blockNumber; - uint votes; - } - - function getCompVotes(TROP comp, address account, uint32[] calldata blockNumbers) external view returns (CompVotes[] memory) { - CompVotes[] memory res = new CompVotes[](blockNumbers.length); - for (uint i = 0; i < blockNumbers.length; i++) { - res[i] = CompVotes({ - blockNumber: uint256(blockNumbers[i]), - votes: uint256(comp.getPriorVotes(account, blockNumbers[i])) - }); - } - return res; - } - - function compareStrings(string memory a, string memory b) internal pure returns (bool) { - return (keccak256(abi.encodePacked((a))) == keccak256(abi.encodePacked((b)))); - } - - function add(uint a, uint b, string memory errorMessage) internal pure returns (uint) { - uint c = a + b; - require(c >= a, errorMessage); - return c; - } - - function sub(uint a, uint b, string memory errorMessage) internal pure returns (uint) { - require(b <= a, errorMessage); - uint c = a - b; - return c; - } -} diff --git a/flatten/Unitroller.sol b/flatten/Unitroller.sol deleted file mode 100644 index b26b275..0000000 --- a/flatten/Unitroller.sol +++ /dev/null @@ -1,4298 +0,0 @@ -// Dependency file: contracts/ErrorReporter.sol - -// SPDX-License-Identifier: UNLICENSED -// pragma solidity 0.8.6; - -contract ComptrollerErrorReporter { - enum Error { - NO_ERROR, - UNAUTHORIZED, - COMPTROLLER_MISMATCH, - INSUFFICIENT_SHORTFALL, - INSUFFICIENT_LIQUIDITY, - INVALID_CLOSE_FACTOR, - INVALID_COLLATERAL_FACTOR, - INVALID_LIQUIDATION_INCENTIVE, - MARKET_NOT_ENTERED, // no longer possible - MARKET_NOT_LISTED, - MARKET_ALREADY_LISTED, - MATH_ERROR, - NONZERO_BORROW_BALANCE, - PRICE_ERROR, - REJECTION, - SNAPSHOT_ERROR, - TOO_MANY_ASSETS, - TOO_MUCH_REPAY - } - - enum FailureInfo { - ACCEPT_ADMIN_PENDING_ADMIN_CHECK, - ACCEPT_PENDING_IMPLEMENTATION_ADDRESS_CHECK, - EXIT_MARKET_BALANCE_OWED, - EXIT_MARKET_REJECTION, - SET_CLOSE_FACTOR_OWNER_CHECK, - SET_CLOSE_FACTOR_VALIDATION, - SET_COLLATERAL_FACTOR_OWNER_CHECK, - SET_COLLATERAL_FACTOR_NO_EXISTS, - SET_COLLATERAL_FACTOR_VALIDATION, - SET_COLLATERAL_FACTOR_WITHOUT_PRICE, - SET_IMPLEMENTATION_OWNER_CHECK, - SET_LIQUIDATION_INCENTIVE_OWNER_CHECK, - SET_LIQUIDATION_INCENTIVE_VALIDATION, - SET_MAX_ASSETS_OWNER_CHECK, - SET_PENDING_ADMIN_OWNER_CHECK, - SET_PENDING_IMPLEMENTATION_OWNER_CHECK, - SET_PRICE_ORACLE_OWNER_CHECK, - SUPPORT_MARKET_EXISTS, - SUPPORT_MARKET_OWNER_CHECK, - SET_PAUSE_GUARDIAN_OWNER_CHECK - } - - /** - * @dev `error` corresponds to enum Error; `info` corresponds to enum FailureInfo, and `detail` is an arbitrary - * contract-specific code that enables us to report opaque error codes from upgradeable contracts. - **/ - event Failure(uint256 error, uint256 info, uint256 detail); - - /** - * @dev use this when reporting a known error from the money market or a non-upgradeable collaborator - */ - function fail(Error err, FailureInfo info) internal returns (uint256) { - emit Failure(uint256(err), uint256(info), 0); - - return uint256(err); - } - - /** - * @dev use this when reporting an opaque error from an upgradeable collaborator contract - */ - function failOpaque( - Error err, - FailureInfo info, - uint256 opaqueError - ) internal returns (uint256) { - emit Failure(uint256(err), uint256(info), opaqueError); - - return uint256(err); - } -} - -contract TokenErrorReporter { - enum Error { - NO_ERROR, - UNAUTHORIZED, - BAD_INPUT, - COMPTROLLER_REJECTION, - COMPTROLLER_CALCULATION_ERROR, - INTEREST_RATE_MODEL_ERROR, - INVALID_ACCOUNT_PAIR, - INVALID_CLOSE_AMOUNT_REQUESTED, - INVALID_COLLATERAL_FACTOR, - MATH_ERROR, - MARKET_NOT_FRESH, - MARKET_NOT_LISTED, - TOKEN_INSUFFICIENT_ALLOWANCE, - TOKEN_INSUFFICIENT_BALANCE, - TOKEN_INSUFFICIENT_CASH, - TOKEN_TRANSFER_IN_FAILED, - TOKEN_TRANSFER_OUT_FAILED - } - - /* - * Note: FailureInfo (but not Error) is kept in alphabetical order - * This is because FailureInfo grows significantly faster, and - * the order of Error has some meaning, while the order of FailureInfo - * is entirely arbitrary. - */ - enum FailureInfo { - ACCEPT_ADMIN_PENDING_ADMIN_CHECK, - ACCRUE_INTEREST_ACCUMULATED_INTEREST_CALCULATION_FAILED, - ACCRUE_INTEREST_BORROW_RATE_CALCULATION_FAILED, - ACCRUE_INTEREST_NEW_BORROW_INDEX_CALCULATION_FAILED, - ACCRUE_INTEREST_NEW_TOTAL_BORROWS_CALCULATION_FAILED, - ACCRUE_INTEREST_NEW_TOTAL_RESERVES_CALCULATION_FAILED, - ACCRUE_INTEREST_SIMPLE_INTEREST_FACTOR_CALCULATION_FAILED, - BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED, - BORROW_ACCRUE_INTEREST_FAILED, - BORROW_CASH_NOT_AVAILABLE, - BORROW_FRESHNESS_CHECK, - BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED, - BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED, - BORROW_MARKET_NOT_LISTED, - BORROW_COMPTROLLER_REJECTION, - LIQUIDATE_ACCRUE_BORROW_INTEREST_FAILED, - LIQUIDATE_ACCRUE_COLLATERAL_INTEREST_FAILED, - LIQUIDATE_COLLATERAL_FRESHNESS_CHECK, - LIQUIDATE_COMPTROLLER_REJECTION, - LIQUIDATE_COMPTROLLER_CALCULATE_AMOUNT_SEIZE_FAILED, - LIQUIDATE_CLOSE_AMOUNT_IS_UINT_MAX, - LIQUIDATE_CLOSE_AMOUNT_IS_ZERO, - LIQUIDATE_FRESHNESS_CHECK, - LIQUIDATE_LIQUIDATOR_IS_BORROWER, - LIQUIDATE_REPAY_BORROW_FRESH_FAILED, - LIQUIDATE_SEIZE_BALANCE_INCREMENT_FAILED, - LIQUIDATE_SEIZE_BALANCE_DECREMENT_FAILED, - LIQUIDATE_SEIZE_COMPTROLLER_REJECTION, - LIQUIDATE_SEIZE_LIQUIDATOR_IS_BORROWER, - LIQUIDATE_SEIZE_TOO_MUCH, - MINT_ACCRUE_INTEREST_FAILED, - MINT_COMPTROLLER_REJECTION, - MINT_EXCHANGE_CALCULATION_FAILED, - MINT_EXCHANGE_RATE_READ_FAILED, - MINT_FRESHNESS_CHECK, - MINT_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED, - MINT_NEW_TOTAL_SUPPLY_CALCULATION_FAILED, - MINT_TRANSFER_IN_FAILED, - MINT_TRANSFER_IN_NOT_POSSIBLE, - REDEEM_ACCRUE_INTEREST_FAILED, - REDEEM_COMPTROLLER_REJECTION, - REDEEM_EXCHANGE_TOKENS_CALCULATION_FAILED, - REDEEM_EXCHANGE_AMOUNT_CALCULATION_FAILED, - REDEEM_EXCHANGE_RATE_READ_FAILED, - REDEEM_FRESHNESS_CHECK, - REDEEM_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED, - REDEEM_NEW_TOTAL_SUPPLY_CALCULATION_FAILED, - REDEEM_TRANSFER_OUT_NOT_POSSIBLE, - REDUCE_RESERVES_ACCRUE_INTEREST_FAILED, - REDUCE_RESERVES_ADMIN_CHECK, - REDUCE_RESERVES_CASH_NOT_AVAILABLE, - REDUCE_RESERVES_FRESH_CHECK, - REDUCE_RESERVES_VALIDATION, - REPAY_BEHALF_ACCRUE_INTEREST_FAILED, - REPAY_BORROW_ACCRUE_INTEREST_FAILED, - REPAY_BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED, - REPAY_BORROW_COMPTROLLER_REJECTION, - REPAY_BORROW_FRESHNESS_CHECK, - REPAY_BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED, - REPAY_BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED, - REPAY_BORROW_TRANSFER_IN_NOT_POSSIBLE, - SET_COLLATERAL_FACTOR_OWNER_CHECK, - SET_COLLATERAL_FACTOR_VALIDATION, - SET_COMPTROLLER_OWNER_CHECK, - SET_INTEREST_RATE_MODEL_ACCRUE_INTEREST_FAILED, - SET_INTEREST_RATE_MODEL_FRESH_CHECK, - SET_INTEREST_RATE_MODEL_OWNER_CHECK, - SET_MAX_ASSETS_OWNER_CHECK, - SET_ORACLE_MARKET_NOT_LISTED, - SET_PENDING_ADMIN_OWNER_CHECK, - SET_RESERVE_FACTOR_ACCRUE_INTEREST_FAILED, - SET_RESERVE_FACTOR_ADMIN_CHECK, - SET_RESERVE_FACTOR_FRESH_CHECK, - SET_RESERVE_FACTOR_BOUNDS_CHECK, - TRANSFER_COMPTROLLER_REJECTION, - TRANSFER_NOT_ALLOWED, - TRANSFER_NOT_ENOUGH, - TRANSFER_TOO_MUCH, - ADD_RESERVES_ACCRUE_INTEREST_FAILED, - ADD_RESERVES_FRESH_CHECK, - ADD_RESERVES_TRANSFER_IN_NOT_POSSIBLE, - ADD_SUBSIDY_FUND_FAILED, - ADD_SUBSIDY_FUND_FRESH_CHECK - } - - /** - * @dev `error` corresponds to enum Error; `info` corresponds to enum FailureInfo, and `detail` is an arbitrary - * contract-specific code that enables us to report opaque error codes from upgradeable contracts. - **/ - event TokenFailure(uint256 error, uint256 info, uint256 detail); - - /** - * @dev use this when reporting a known error from the money market or a non-upgradeable collaborator - */ - function fail(Error err, FailureInfo info) internal returns (uint256) { - emit TokenFailure(uint256(err), uint256(info), 0); - - return uint256(err); - } - - /** - * @dev use this when reporting an opaque error from an upgradeable collaborator contract - */ - function failOpaque( - Error err, - FailureInfo info, - uint256 opaqueError - ) internal returns (uint256) { - emit TokenFailure(uint256(err), uint256(info), opaqueError); - - return uint256(err); - } -} - - -// Dependency file: contracts/ComptrollerInterface.sol - -// pragma solidity 0.8.6; - -abstract contract ComptrollerInterface { - /// @notice Indicator that this is a Comptroller contract (for inspection) - bool public constant isComptroller = true; - - /*** Assets You Are In ***/ - - function enterMarkets(address[] calldata cTokens) - external - virtual - returns (uint256[] memory); - - function exitMarket(address cToken) external virtual returns (uint256); - - /*** Policy Hooks ***/ - - function mintAllowed( - address cToken, - address minter, - uint256 mintAmount - ) external virtual returns (uint256); - - function mintVerify( - address cToken, - address minter, - uint256 mintAmount, - uint256 mintTokens - ) external virtual; - - function redeemAllowed( - address cToken, - address redeemer, - uint256 redeemTokens - ) external virtual returns (uint256); - - function redeemVerify( - address cToken, - address redeemer, - uint256 redeemAmount, - uint256 redeemTokens - ) external virtual; - - function borrowAllowed( - address cToken, - address borrower, - uint256 borrowAmount - ) external virtual returns (uint256); - - function borrowVerify( - address cToken, - address borrower, - uint256 borrowAmount - ) external virtual; - - function repayBorrowAllowed( - address cToken, - address payer, - address borrower, - uint256 repayAmount - ) external virtual returns (uint256); - - function repayBorrowVerify( - address cToken, - address payer, - address borrower, - uint256 repayAmount, - uint256 borrowerIndex - ) external virtual; - - function liquidateBorrowAllowed( - address cTokenBorrowed, - address cTokenCollateral, - address liquidator, - address borrower, - uint256 repayAmount - ) external virtual returns (uint256); - - function liquidateBorrowVerify( - address cTokenBorrowed, - address cTokenCollateral, - address liquidator, - address borrower, - uint256 repayAmount, - uint256 seizeTokens - ) external virtual; - - function seizeAllowed( - address cTokenCollateral, - address cTokenBorrowed, - address liquidator, - address borrower, - uint256 seizeTokens - ) external virtual returns (uint256); - - function seizeVerify( - address cTokenCollateral, - address cTokenBorrowed, - address liquidator, - address borrower, - uint256 seizeTokens - ) external virtual; - - function transferAllowed( - address cToken, - address src, - address dst, - uint256 transferTokens - ) external virtual returns (uint256); - - function transferVerify( - address cToken, - address src, - address dst, - uint256 transferTokens - ) external virtual; - - /*** Liquidity/Liquidation Calculations ***/ - - function liquidateCalculateSeizeTokens( - address cTokenBorrowed, - address cTokenCollateral, - uint256 repayAmount - ) external view virtual returns (uint256, uint256); -} - - -// Dependency file: contracts/CarefulMath.sol - -// pragma solidity 0.8.6; - -/** - * @title Careful Math - * @author tropykus - * @notice Derived from OpenZeppelin's SafeMath library - * https://github.com/OpenZeppelin/openzeppelin-solidity/blob/master/contracts/math/SafeMath.sol - */ -contract CarefulMath { - - /** - * @dev Possible error codes that we can return - */ - enum MathError { - NO_ERROR, - DIVISION_BY_ZERO, - INTEGER_OVERFLOW, - INTEGER_UNDERFLOW - } - - /** - * @dev Multiplies two numbers, returns an error on overflow. - */ - function mulUInt(uint a, uint b) internal pure returns (MathError, uint) { - if (a == 0) { - return (MathError.NO_ERROR, 0); - } - - uint c = a * b; - - if (c / a != b) { - return (MathError.INTEGER_OVERFLOW, 0); - } else { - return (MathError.NO_ERROR, c); - } - } - - /** - * @dev Integer division of two numbers, truncating the quotient. - */ - function divUInt(uint a, uint b) internal pure returns (MathError, uint) { - if (b == 0) { - return (MathError.DIVISION_BY_ZERO, 0); - } - - return (MathError.NO_ERROR, a / b); - } - - /** - * @dev Subtracts two numbers, returns an error on overflow (i.e. if subtrahend is greater than minuend). - */ - function subUInt(uint a, uint b) internal pure returns (MathError, uint) { - if (b <= a) { - return (MathError.NO_ERROR, a - b); - } else { - return (MathError.INTEGER_UNDERFLOW, 0); - } - } - - /** - * @dev Adds two numbers, returns an error on overflow. - */ - function addUInt(uint a, uint b) internal pure returns (MathError, uint) { - uint c = a + b; - - if (c >= a) { - return (MathError.NO_ERROR, c); - } else { - return (MathError.INTEGER_OVERFLOW, 0); - } - } - - /** - * @dev add a and b and then subtract c - */ - function addThenSubUInt(uint a, uint b, uint c) internal pure returns (MathError, uint) { - (MathError err0, uint sum) = addUInt(a, b); - - if (err0 != MathError.NO_ERROR) { - return (err0, 0); - } - - return subUInt(sum, c); - } -} - - -// Dependency file: contracts/ExponentialNoError.sol - -// pragma solidity 0.8.6; - -/** - * @title Exponential module for storing fixed-precision decimals - * @author tropykus - * @notice Exp is a struct which stores decimals with a fixed precision of 18 decimal places. - * Thus, if we wanted to store the 5.1, mantissa would store 5.1e18. That is: - * `Exp({mantissa: 5100000000000000000})`. - */ -contract ExponentialNoError { - uint constant expScale = 1e18; - uint constant doubleScale = 1e36; - uint constant halfExpScale = expScale/2; - uint constant mantissaOne = expScale; - - struct Exp { - uint mantissa; - } - - struct Double { - uint mantissa; - } - - /** - * @dev Truncates the given exp to a whole number value. - * For example, truncate(Exp{mantissa: 15 * expScale}) = 15 - */ - function truncate(Exp memory exp) pure internal returns (uint) { - // Note: We are not using careful math here as we're performing a division that cannot fail - return exp.mantissa / expScale; - } - - /** - * @dev Multiply an Exp by a scalar, then truncate to return an unsigned integer. - */ - function mul_ScalarTruncate(Exp memory a, uint scalar) pure internal returns (uint) { - Exp memory product = mul_(a, scalar); - return truncate(product); - } - - /** - * @dev Multiply an Exp by a scalar, truncate, then add an to an unsigned integer, returning an unsigned integer. - */ - function mul_ScalarTruncateAddUInt(Exp memory a, uint scalar, uint addend) pure internal returns (uint) { - Exp memory product = mul_(a, scalar); - return add_(truncate(product), addend); - } - - /** - * @dev Checks if first Exp is less than second Exp. - */ - function lessThanExp(Exp memory left, Exp memory right) pure internal returns (bool) { - return left.mantissa < right.mantissa; - } - - /** - * @dev Checks if left Exp <= right Exp. - */ - function lessThanOrEqualExp(Exp memory left, Exp memory right) pure internal returns (bool) { - return left.mantissa <= right.mantissa; - } - - /** - * @dev Checks if left Exp > right Exp. - */ - function greaterThanExp(Exp memory left, Exp memory right) pure internal returns (bool) { - return left.mantissa > right.mantissa; - } - - /** - * @dev returns true if Exp is exactly zero - */ - function isZeroExp(Exp memory value) pure internal returns (bool) { - return value.mantissa == 0; - } - - function safe224(uint n, string memory errorMessage) pure internal returns (uint224) { - require(n < 2**224, errorMessage); - return uint224(n); - } - - function safe32(uint n, string memory errorMessage) pure internal returns (uint32) { - require(n < 2**32, errorMessage); - return uint32(n); - } - - function add_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { - return Exp({mantissa: add_(a.mantissa, b.mantissa)}); - } - - function add_(Double memory a, Double memory b) pure internal returns (Double memory) { - return Double({mantissa: add_(a.mantissa, b.mantissa)}); - } - - function add_(uint a, uint b) pure internal returns (uint) { - return add_(a, b, "addition overflow"); - } - - function add_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { - uint c = a + b; - require(c >= a, errorMessage); - return c; - } - - function sub_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { - return Exp({mantissa: sub_(a.mantissa, b.mantissa)}); - } - - function sub_(Double memory a, Double memory b) pure internal returns (Double memory) { - return Double({mantissa: sub_(a.mantissa, b.mantissa)}); - } - - function sub_(uint a, uint b) pure internal returns (uint) { - return sub_(a, b, "subtraction underflow"); - } - - function sub_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { - require(b <= a, errorMessage); - return a - b; - } - - function mul_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { - return Exp({mantissa: mul_(a.mantissa, b.mantissa) / expScale}); - } - - function mul_(Exp memory a, uint b) pure internal returns (Exp memory) { - return Exp({mantissa: mul_(a.mantissa, b)}); - } - - function mul_(uint a, Exp memory b) pure internal returns (uint) { - return mul_(a, b.mantissa) / expScale; - } - - function mul_(Double memory a, Double memory b) pure internal returns (Double memory) { - return Double({mantissa: mul_(a.mantissa, b.mantissa) / doubleScale}); - } - - function mul_(Double memory a, uint b) pure internal returns (Double memory) { - return Double({mantissa: mul_(a.mantissa, b)}); - } - - function mul_(uint a, Double memory b) pure internal returns (uint) { - return mul_(a, b.mantissa) / doubleScale; - } - - function mul_(uint a, uint b) pure internal returns (uint) { - return mul_(a, b, "multiplication overflow"); - } - - function mul_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { - if (a == 0 || b == 0) { - return 0; - } - uint c = a * b; - require(c / a == b, errorMessage); - return c; - } - - function div_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { - return Exp({mantissa: div_(mul_(a.mantissa, expScale), b.mantissa)}); - } - - function div_(Exp memory a, uint b) pure internal returns (Exp memory) { - return Exp({mantissa: div_(a.mantissa, b)}); - } - - function div_(uint a, Exp memory b) pure internal returns (uint) { - return div_(mul_(a, expScale), b.mantissa); - } - - function div_(Double memory a, Double memory b) pure internal returns (Double memory) { - return Double({mantissa: div_(mul_(a.mantissa, doubleScale), b.mantissa)}); - } - - function div_(Double memory a, uint b) pure internal returns (Double memory) { - return Double({mantissa: div_(a.mantissa, b)}); - } - - function div_(uint a, Double memory b) pure internal returns (uint) { - return div_(mul_(a, doubleScale), b.mantissa); - } - - function div_(uint a, uint b) pure internal returns (uint) { - return div_(a, b, "divide by zero"); - } - - function div_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { - require(b > 0, errorMessage); - return a / b; - } - - function fraction(uint a, uint b) pure internal returns (Double memory) { - return Double({mantissa: div_(mul_(a, doubleScale), b)}); - } -} - - -// Dependency file: contracts/Exponential.sol - -// pragma solidity 0.8.6; - -// import "contracts/CarefulMath.sol"; -// import "contracts/ExponentialNoError.sol"; - -/** - * @title Exponential module for storing fixed-precision decimals - * @author tropykus - * @dev Legacy contract for compatibility reasons with existing contracts that still use MathError - * @notice Exp is a struct which stores decimals with a fixed precision of 18 decimal places. - * Thus, if we wanted to store the 5.1, mantissa would store 5.1e18. That is: - * `Exp({mantissa: 5100000000000000000})`. - */ -contract Exponential is CarefulMath, ExponentialNoError { - /** - * @dev Creates an exponential from numerator and denominator values. - * Note: Returns an error if (`num` * 10e18) > MAX_INT, - * or if `denom` is zero. - */ - function getExp(uint num, uint denom) internal pure returns (MathError, Exp memory) { - (MathError err0, uint scaledNumerator) = mulUInt(num, expScale); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - - (MathError err1, uint rational) = divUInt(scaledNumerator, denom); - if (err1 != MathError.NO_ERROR) { - return (err1, Exp({mantissa: 0})); - } - - return (MathError.NO_ERROR, Exp({mantissa: rational})); - } - - /** - * @dev Adds two exponentials, returning a new exponential. - */ - function addExp(Exp memory a, Exp memory b) internal pure returns (MathError, Exp memory) { - (MathError error, uint result) = addUInt(a.mantissa, b.mantissa); - - return (error, Exp({mantissa: result})); - } - - /** - * @dev Subtracts two exponentials, returning a new exponential. - */ - function subExp(Exp memory a, Exp memory b) internal pure returns (MathError, Exp memory) { - (MathError error, uint result) = subUInt(a.mantissa, b.mantissa); - - return (error, Exp({mantissa: result})); - } - - /** - * @dev Multiply an Exp by a scalar, returning a new Exp. - */ - function mulScalar(Exp memory a, uint scalar) internal pure returns (MathError, Exp memory) { - (MathError err0, uint scaledMantissa) = mulUInt(a.mantissa, scalar); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - - return (MathError.NO_ERROR, Exp({mantissa: scaledMantissa})); - } - - /** - * @dev Multiply an Exp by a scalar, then truncate to return an unsigned integer. - */ - function mulScalarTruncate(Exp memory a, uint scalar) internal pure returns (MathError, uint) { - (MathError err, Exp memory product) = mulScalar(a, scalar); - if (err != MathError.NO_ERROR) { - return (err, 0); - } - - return (MathError.NO_ERROR, truncate(product)); - } - - /** - * @dev Multiply an Exp by a scalar, truncate, then add an to an unsigned integer, returning an unsigned integer. - */ - function mulScalarTruncateAddUInt(Exp memory a, uint scalar, uint addend) internal pure returns (MathError, uint) { - (MathError err, Exp memory product) = mulScalar(a, scalar); - if (err != MathError.NO_ERROR) { - return (err, 0); - } - - return addUInt(truncate(product), addend); - } - - /** - * @dev Divide an Exp by a scalar, returning a new Exp. - */ - function divScalar(Exp memory a, uint scalar) internal pure returns (MathError, Exp memory) { - (MathError err0, uint descaledMantissa) = divUInt(a.mantissa, scalar); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - - return (MathError.NO_ERROR, Exp({mantissa: descaledMantissa})); - } - - /** - * @dev Divide a scalar by an Exp, returning a new Exp. - */ - function divScalarByExp(uint scalar, Exp memory divisor) internal pure returns (MathError, Exp memory) { - /* - We are doing this as: - getExp(mulUInt(expScale, scalar), divisor.mantissa) - - How it works: - Exp = a / b; - Scalar = s; - `s / (a / b)` = `b * s / a` and since for an Exp `a = mantissa, b = expScale` - */ - (MathError err0, uint numerator) = mulUInt(expScale, scalar); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - return getExp(numerator, divisor.mantissa); - } - - /** - * @dev Divide a scalar by an Exp, then truncate to return an unsigned integer. - */ - function divScalarByExpTruncate(uint scalar, Exp memory divisor) internal pure returns (MathError, uint) { - (MathError err, Exp memory fraction) = divScalarByExp(scalar, divisor); - if (err != MathError.NO_ERROR) { - return (err, 0); - } - - return (MathError.NO_ERROR, truncate(fraction)); - } - - /** - * @dev Multiplies two exponentials, returning a new exponential. - */ - function mulExp(Exp memory a, Exp memory b) internal pure returns (MathError, Exp memory) { - - (MathError err0, uint doubleScaledProduct) = mulUInt(a.mantissa, b.mantissa); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - - // We add half the scale before dividing so that we get rounding instead of truncation. - // See "Listing 6" and text above it at https://accu.org/index.php/journals/1717 - // Without this change, a result like 6.6...e-19 will be truncated to 0 instead of being rounded to 1e-18. - (MathError err1, uint doubleScaledProductWithHalfScale) = addUInt(halfExpScale, doubleScaledProduct); - if (err1 != MathError.NO_ERROR) { - return (err1, Exp({mantissa: 0})); - } - - (MathError err2, uint product) = divUInt(doubleScaledProductWithHalfScale, expScale); - // The only error `div` can return is MathError.DIVISION_BY_ZERO but we control `expScale` and it is not zero. - assert(err2 == MathError.NO_ERROR); - - return (MathError.NO_ERROR, Exp({mantissa: product})); - } - - /** - * @dev Multiplies two exponentials given their mantissas, returning a new exponential. - */ - function mulExp(uint a, uint b) internal pure returns (MathError, Exp memory) { - return mulExp(Exp({mantissa: a}), Exp({mantissa: b})); - } - - /** - * @dev Multiplies three exponentials, returning a new exponential. - */ - function mulExp3(Exp memory a, Exp memory b, Exp memory c) internal pure returns (MathError, Exp memory) { - (MathError err, Exp memory ab) = mulExp(a, b); - if (err != MathError.NO_ERROR) { - return (err, ab); - } - return mulExp(ab, c); - } - - /** - * @dev Divides two exponentials, returning a new exponential. - * (a/scale) / (b/scale) = (a/scale) * (scale/b) = a/b, - * which we can scale as an Exp by calling getExp(a.mantissa, b.mantissa) - */ - function divExp(Exp memory a, Exp memory b) internal pure returns (MathError, Exp memory) { - return getExp(a.mantissa, b.mantissa); - } -} - - -// Dependency file: contracts/SafeMath.sol - -// pragma solidity 0.8.6; - -// From https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/math/Math.sol -// Subject to the MIT license. - -/** - * @dev Wrappers over Solidity's arithmetic operations with added overflow - * checks. - * - * Arithmetic operations in Solidity wrap on overflow. This can easily result - * in bugs, because programmers usually assume that an overflow raises an - * error, which is the standard behavior in high level programming languages. - * `SafeMath` restores this intuition by reverting the transaction when an - * operation overflows. - * - * Using this library instead of the unchecked operations eliminates an entire - * class of bugs, so it's recommended to use it always. - */ -library SafeMath { - /** - * @dev Returns the addition of two unsigned integers, reverting on overflow. - * - * Counterpart to Solidity's `+` operator. - * - * Requirements: - * - Addition cannot overflow. - */ - function add(uint256 a, uint256 b) internal pure returns (uint256) { - uint256 c = a + b; - require(c >= a, "SafeMath: addition overflow"); - - return c; - } - - /** - * @dev Returns the addition of two unsigned integers, reverting with custom message on overflow. - * - * Counterpart to Solidity's `+` operator. - * - * Requirements: - * - Addition cannot overflow. - */ - function add(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - uint256 c = a + b; - require(c >= a, errorMessage); - - return c; - } - - /** - * @dev Returns the subtraction of two unsigned integers, reverting on underflow (when the result is negative). - * - * Counterpart to Solidity's `-` operator. - * - * Requirements: - * - Subtraction cannot underflow. - */ - function sub(uint256 a, uint256 b) internal pure returns (uint256) { - return sub(a, b, "SafeMath: subtraction underflow"); - } - - /** - * @dev Returns the subtraction of two unsigned integers, reverting with custom message on underflow (when the result is negative). - * - * Counterpart to Solidity's `-` operator. - * - * Requirements: - * - Subtraction cannot underflow. - */ - function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - require(b <= a, errorMessage); - uint256 c = a - b; - - return c; - } - - /** - * @dev Returns the multiplication of two unsigned integers, reverting on overflow. - * - * Counterpart to Solidity's `*` operator. - * - * Requirements: - * - Multiplication cannot overflow. - */ - function mul(uint256 a, uint256 b) internal pure returns (uint256) { - // Gas optimization: this is cheaper than requiring 'a' not being zero, but the - // benefit is lost if 'b' is also tested. - // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 - if (a == 0) { - return 0; - } - - uint256 c = a * b; - require(c / a == b, "SafeMath: multiplication overflow"); - - return c; - } - - /** - * @dev Returns the multiplication of two unsigned integers, reverting on overflow. - * - * Counterpart to Solidity's `*` operator. - * - * Requirements: - * - Multiplication cannot overflow. - */ - function mul(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - // Gas optimization: this is cheaper than requiring 'a' not being zero, but the - // benefit is lost if 'b' is also tested. - // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 - if (a == 0) { - return 0; - } - - uint256 c = a * b; - require(c / a == b, errorMessage); - - return c; - } - - /** - * @dev Returns the integer division of two unsigned integers. - * Reverts on division by zero. The result is rounded towards zero. - * - * Counterpart to Solidity's `/` operator. Note: this function uses a - * `revert` opcode (which leaves remaining gas untouched) while Solidity - * uses an invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function div(uint256 a, uint256 b) internal pure returns (uint256) { - return div(a, b, "SafeMath: division by zero"); - } - - /** - * @dev Returns the integer division of two unsigned integers. - * Reverts with custom message on division by zero. The result is rounded towards zero. - * - * Counterpart to Solidity's `/` operator. Note: this function uses a - * `revert` opcode (which leaves remaining gas untouched) while Solidity - * uses an invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - // Solidity only automatically asserts when dividing by 0 - require(b > 0, errorMessage); - uint256 c = a / b; - // assert(a == b * c + a % b); // There is no case in which this doesn't hold - - return c; - } - - /** - * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), - * Reverts when dividing by zero. - * - * Counterpart to Solidity's `%` operator. This function uses a `revert` - * opcode (which leaves remaining gas untouched) while Solidity uses an - * invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function mod(uint256 a, uint256 b) internal pure returns (uint256) { - return mod(a, b, "SafeMath: modulo by zero"); - } - - /** - * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), - * Reverts with custom message when dividing by zero. - * - * Counterpart to Solidity's `%` operator. This function uses a `revert` - * opcode (which leaves remaining gas untouched) while Solidity uses an - * invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - require(b != 0, errorMessage); - return a % b; - } -} - - -// Dependency file: contracts/InterestRateModel.sol - -// pragma solidity 0.8.6; - -// import "contracts/Exponential.sol"; -// import "contracts/SafeMath.sol"; - -/** - * @title tropykus InterestRateModel Interface - * @author tropykus - */ -abstract contract InterestRateModel is Exponential { - using SafeMath for uint256; - - /// @notice Indicator that this is an InterestRateModel contract (for inspection) - bool public constant isInterestRateModel = true; - bool public isTropykusInterestRateModel; - - /** - * @notice The approximate number of blocks per year that is assumed by the interest rate model - */ - uint256 public constant blocksPerYear = 1051200; - - /** - * @notice Calculates the utilization rate of the market: `borrows / (cash + borrows - reserves)` - * @param cash The amount of cash in the market - * @param borrows The amount of borrows in the market - * @param reserves The amount of reserves in the market (currently unused) - * @return The utilization rate as a mantissa between [0, 1e18] - */ - function utilizationRate( - uint256 cash, - uint256 borrows, - uint256 reserves - ) public pure virtual returns (uint256) { - // Utilization rate is 0 when there are no borrows - if (borrows == 0) { - return 0; - } - - return borrows.mul(1e18).div(cash.add(borrows).sub(reserves)); - } - - /** - * @notice Calculates the current borrow interest rate per block - * @param cash The total amount of cash the market has - * @param borrows The total amount of borrows the market has outstanding - * @param reserves The total amnount of reserves the market has - * @return The borrow rate per block (as a percentage, and scaled by 1e18) - */ - function getBorrowRate( - uint256 cash, - uint256 borrows, - uint256 reserves - ) external view virtual returns (uint256); - - /** - * @notice Calculates the current supply interest rate per block - * @param cash The total amount of cash the market has - * @param borrows The total amount of borrows the market has outstanding - * @param reserves The total amnount of reserves the market has - * @param reserveFactorMantissa The current reserve factor the market has - * @return The supply rate per block (as a percentage, and scaled by 1e18) - */ - function getSupplyRate( - uint256 cash, - uint256 borrows, - uint256 reserves, - uint256 reserveFactorMantissa - ) external view virtual returns (uint256); - - function getExchangeRate( - uint256 _totalCash, - uint256 _totalBorrows, - uint256 _totalReserves, - uint256 _totalSupply - ) public pure returns (MathError, uint256) { - /* - * exchangeRate = (totalCash + totalBorrows - totalReserves) / totalSupply - */ - Exp memory exchangeRate; - MathError mathErr; - uint256 cashPlusBorrowsMinusReserves; - (mathErr, cashPlusBorrowsMinusReserves) = addThenSubUInt( - _totalCash, - _totalBorrows, - _totalReserves - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - (mathErr, exchangeRate) = getExp( - cashPlusBorrowsMinusReserves, - _totalSupply - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - - return (MathError.NO_ERROR, exchangeRate.mantissa); - } - - function isAboveOptimal( - uint256 cash, - uint256 borrows, - uint256 reserves - ) public view virtual returns (bool) { - cash; - borrows; - reserves; - return false; - } -} - - -// Dependency file: contracts/EIP20NonStandardInterface.sol - -// pragma solidity 0.8.6; - -/** - * @title EIP20NonStandardInterface - * @dev Version of ERC20 with no return values for `transfer` and `transferFrom` - * See https://medium.com/coinmonks/missing-return-value-bug-at-least-130-tokens-affected-d67bf08521ca - */ -interface EIP20NonStandardInterface { - /** - * @notice Get the total number of tokens in circulation - * @return The supply of tokens - */ - function totalSupply() external view returns (uint256); - - /** - * @notice Gets the balance of the specified address - * @param owner The address from which the balance will be retrieved - * @return balance The balance - */ - function balanceOf(address owner) external view returns (uint256 balance); - - /// - /// !!!!!!!!!!!!!! - /// !!! NOTICE !!! `transfer` does not return a value, in violation of the ERC-20 specification - /// !!!!!!!!!!!!!! - /// - - /** - * @notice Transfer `amount` tokens from `msg.sender` to `dst` - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - */ - function transfer(address dst, uint256 amount) external; - - /// - /// !!!!!!!!!!!!!! - /// !!! NOTICE !!! `transferFrom` does not return a value, in violation of the ERC-20 specification - /// !!!!!!!!!!!!!! - /// - - /** - * @notice Transfer `amount` tokens from `src` to `dst` - * @param src The address of the source account - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - */ - function transferFrom( - address src, - address dst, - uint256 amount - ) external; - - /** - * @notice Approve `spender` to transfer up to `amount` from `src` - * @dev This will overwrite the approval amount for `spender` - * and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve) - * @param spender The address of the account which may transfer tokens - * @param amount The number of tokens that are approved - * @return success Whether or not the approval succeeded - */ - function approve(address spender, uint256 amount) - external - returns (bool success); - - /** - * @notice Get the current allowance from `owner` for `spender` - * @param owner The address of the account which owns the tokens to be spent - * @param spender The address of the account which may transfer tokens - * @return remaining The number of tokens allowed to be spent - */ - function allowance(address owner, address spender) - external - view - returns (uint256 remaining); - - event Transfer(address indexed from, address indexed to, uint256 amount); - event Approval( - address indexed owner, - address indexed spender, - uint256 amount - ); -} - - -// Dependency file: contracts/CTokenInterfaces.sol - -// pragma solidity 0.8.6; - -// import "contracts/ComptrollerInterface.sol"; -// import "contracts/InterestRateModel.sol"; -// import "contracts/EIP20NonStandardInterface.sol"; - -contract CTokenStorage { - /** - * @dev Guard variable for re-entrancy checks - */ - bool internal _notEntered; - - /** - * @notice EIP-20 token name for this token - */ - string public name; - - /** - * @notice EIP-20 token symbol for this token - */ - string public symbol; - - /** - * @notice EIP-20 token decimals for this token - */ - uint8 public decimals; - - /** - * @notice Maximum borrow rate that can ever be applied (.0005% / block) - */ - - uint256 internal constant borrowRateMaxMantissa = 0.0005e16; - - /** - * @notice Maximum fraction of interest that can be set aside for reserves - */ - uint256 internal constant reserveFactorMaxMantissa = 1e18; - - /** - * @notice Administrator for this contract - */ - address payable public admin; - - /** - * @notice Pending administrator for this contract - */ - address payable public pendingAdmin; - - /** - * @notice Contract which oversees inter-cToken operations - */ - ComptrollerInterface public comptroller; - - /** - * @notice Model which tells what the current interest rate should be - */ - InterestRateModel public interestRateModel; - - /** - * @notice Initial exchange rate used when minting the first CTokens (used when totalSupply = 0) - */ - uint256 public initialExchangeRateMantissa; - - /** - * @notice Fraction of interest currently set aside for reserves - */ - uint256 public reserveFactorMantissa; - - /** - * @notice Block number that interest was last accrued at - */ - uint256 public accrualBlockNumber; - - /** - * @notice Accumulator of the total earned interest rate since the opening of the market - */ - uint256 public borrowIndex; - - /** - * @notice Total amount of outstanding borrows of the underlying in this market - */ - uint256 public totalBorrows; - - /** - * @notice Total amount of reserves of the underlying held in this market - */ - uint256 public totalReserves; - - /** - * @notice Total number of tokens in circulation - */ - uint256 public totalSupply; - - uint256 public subsidyFund; - - struct SupplySnapshot { - uint256 tokens; - uint256 underlyingAmount; - uint256 suppliedAt; - uint256 promisedSupplyRate; - } - - /** - * @notice Official record of token balances for each account - */ - mapping(address => SupplySnapshot) internal accountTokens; - - /** - * @notice Approved token transfer amounts on behalf of others - */ - mapping(address => mapping(address => uint256)) internal transferAllowances; - - /** - * @notice Container for borrow balance information - * @member principal Total balance (with accrued interest), after applying the most recent balance-changing action - * @member interestIndex Global borrowIndex as of the most recent balance-changing action - */ - struct BorrowSnapshot { - uint256 principal; - uint256 interestIndex; - } - - /** - * @notice Mapping of account addresses to outstanding borrow balances - */ - mapping(address => BorrowSnapshot) internal accountBorrows; -} - -abstract contract CTokenInterface is CTokenStorage { - /** - * @notice Indicator that this is a CToken contract (for inspection) - */ - bool public constant isCToken = true; - - /*** Market Events ***/ - - /** - * @notice Event emitted when interest is accrued - */ - event AccrueInterest( - uint256 cashPrior, - uint256 interestAccumulated, - uint256 borrowIndex, - uint256 totalBorrows - ); - - /** - * @notice Event emitted when tokens are minted - */ - event Mint(address indexed minter, uint256 mintAmount, uint256 mintTokens); - - /** - * @notice Event emitted when tokens are redeemed - */ - event Redeem( - address indexed redeemer, - uint256 redeemAmount, - uint256 redeemTokens - ); - - /** - * @notice Event emitted when underlying is borrowed - */ - event Borrow( - address indexed borrower, - uint256 borrowAmount, - uint256 accountBorrows, - uint256 totalBorrows - ); - - /** - * @notice Event emitted when a borrow is repaid - */ - event RepayBorrow( - address indexed payer, - address indexed borrower, - uint256 repayAmount, - uint256 accountBorrows, - uint256 totalBorrows - ); - - /** - * @notice Event emitted when a borrow is liquidated - */ - event LiquidateBorrow( - address indexed liquidator, - address indexed borrower, - uint256 repayAmount, - address indexed cTokenCollateral, - uint256 seizeTokens - ); - - /*** Admin Events ***/ - - /** - * @notice Event emitted when pendingAdmin is changed - */ - event NewPendingAdmin(address oldPendingAdmin, address newPendingAdmin); - - /** - * @notice Event emitted when pendingAdmin is accepted, which means admin is updated - */ - event NewAdmin(address oldAdmin, address newAdmin); - - /** - * @notice Event emitted when comptroller is changed - */ - event NewComptroller( - ComptrollerInterface oldComptroller, - ComptrollerInterface newComptroller - ); - - /** - * @notice Event emitted when interestRateModel is changed - */ - event NewMarketInterestRateModel( - InterestRateModel oldInterestRateModel, - InterestRateModel newInterestRateModel - ); - - /** - * @notice Event emitted when the reserve factor is changed - */ - event NewReserveFactor( - uint256 oldReserveFactorMantissa, - uint256 newReserveFactorMantissa - ); - - /** - * @notice Event emitted when the reserves are added - */ - event ReservesAdded( - address benefactor, - uint256 addAmount, - uint256 newTotalReserves - ); - - event SubsidyAdded( - address benefactor, - uint256 addAmount, - uint256 newSubsidyFund - ); - - /** - * @notice Event emitted when the reserves are reduced - */ - event ReservesReduced( - address admin, - uint256 reduceAmount, - uint256 newTotalReserves - ); - - /** - * @notice EIP20 Transfer event - */ - event Transfer(address indexed from, address indexed to, uint256 amount); - - /** - * @notice EIP20 Approval event - */ - event Approval( - address indexed owner, - address indexed spender, - uint256 amount - ); - - /** - * @notice Failure event - */ - event CTokenStorageFailure(uint256 error, uint256 info, uint256 detail); - - /*** User Interface ***/ - - function transfer(address dst, uint256 amount) - external - virtual - returns (bool); - - function transferFrom( - address src, - address dst, - uint256 amount - ) external virtual returns (bool); - - function approve(address spender, uint256 amount) - external - virtual - returns (bool); - - function allowance(address owner, address spender) - external - view - virtual - returns (uint256); - - function balanceOf(address owner) external view virtual returns (uint256); - - function balanceOfUnderlying(address owner) - external - virtual - returns (uint256); - - function getAccountSnapshot(address account) - external - view - virtual - returns ( - uint256, - uint256, - uint256, - uint256 - ); - - function borrowRatePerBlock() external view virtual returns (uint256); - - function supplyRatePerBlock() external view virtual returns (uint256); - - function totalBorrowsCurrent() external virtual returns (uint256); - - function borrowBalanceCurrent(address account) - external - virtual - returns (uint256); - - function borrowBalanceStored(address account) - public - view - virtual - returns (uint256); - - function exchangeRateCurrent() public virtual returns (uint256); - - function exchangeRateStored() public view virtual returns (uint256); - - function getCash() external view virtual returns (uint256); - - function accrueInterest() public virtual returns (uint256); - - function seize( - address liquidator, - address borrower, - uint256 seizeTokens - ) external virtual returns (uint256); - - /*** Admin Functions ***/ - - function _setPendingAdmin(address payable newPendingAdmin) - external - virtual - returns (uint256); - - function _acceptAdmin() external virtual returns (uint256); - - function _setComptroller(ComptrollerInterface newComptroller) - public - virtual - returns (uint256); - - function _setReserveFactor(uint256 newReserveFactorMantissa) - external - virtual - returns (uint256); - - function _reduceReserves(uint256 reduceAmount) - external - virtual - returns (uint256); - - function _setInterestRateModel(InterestRateModel newInterestRateModel) - public - virtual - returns (uint256); -} - -contract CErc20Storage { - /** - * @notice Underlying asset for this CToken - */ - address public underlying; -} - -abstract contract CErc20Interface is CErc20Storage { - /*** User Interface ***/ - - function mint(uint256 mintAmount) external virtual returns (uint256); - - function redeem(uint256 redeemAmount) - external - virtual - returns (uint256); - - function borrow(uint256 borrowAmount) external virtual returns (uint256); - - function repayBorrow(uint256 repayAmount) - external - virtual - returns (uint256); - - function liquidateBorrow( - address borrower, - uint256 repayAmount, - CTokenInterface cTokenCollateral - ) external virtual returns (uint256); - - function sweepToken(EIP20NonStandardInterface token) external virtual; - - /*** Admin Functions ***/ - - function _addReserves(uint256 addAmount) external virtual returns (uint256); -} - -contract CDelegationStorage { - /** - * @notice Implementation address for this contract - */ - address public implementation; -} - -abstract contract CDelegatorInterface is CDelegationStorage { - /** - * @notice Emitted when implementation is changed - */ - event NewImplementation( - address oldImplementation, - address newImplementation - ); - - /** - * @notice Called by the admin to update the implementation of the delegator - * @param implementation_ The address of the new implementation for delegation - * @param allowResign Flag to indicate whether to call _resignImplementation on the old implementation - * @param becomeImplementationData The encoded bytes data to be passed to _becomeImplementation - */ - function _setImplementation( - address implementation_, - bool allowResign, - bytes memory becomeImplementationData - ) public virtual; -} - -abstract contract CDelegateInterface is CDelegationStorage { - /** - * @notice Called by the delegator on a delegate to initialize it for duty - * @dev Should revert if any issues arise which make it unfit for delegation - * @param data The encoded bytes data for any initialization - */ - function _becomeImplementation(bytes memory data) public virtual; - - /** - * @notice Called by the delegator on a delegate to forfeit its responsibility - */ - function _resignImplementation() public virtual; -} - - -// Dependency file: contracts/EIP20Interface.sol - -// pragma solidity 0.8.6; - -/** - * @title ERC 20 Token Standard Interface - * https://eips.ethereum.org/EIPS/eip-20 - */ -interface EIP20Interface { - function name() external view returns (string memory); - - function symbol() external view returns (string memory); - - function decimals() external view returns (uint8); - - /** - * @notice Get the total number of tokens in circulation - * @return The supply of tokens - */ - function totalSupply() external view returns (uint256); - - /** - * @notice Gets the balance of the specified address - * @param owner The address from which the balance will be retrieved - * @return balance The balance - */ - function balanceOf(address owner) external view returns (uint256 balance); - - /** - * @notice Transfer `amount` tokens from `msg.sender` to `dst` - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - * @return success Whether or not the transfer succeeded - */ - function transfer(address dst, uint256 amount) - external - returns (bool success); - - /** - * @notice Transfer `amount` tokens from `src` to `dst` - * @param src The address of the source account - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - * @return success Whether or not the transfer succeeded - */ - function transferFrom( - address src, - address dst, - uint256 amount - ) external returns (bool success); - - /** - * @notice Approve `spender` to transfer up to `amount` from `src` - * @dev This will overwrite the approval amount for `spender` - * and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve) - * @param spender The address of the account which may transfer tokens - * @param amount The number of tokens that are approved (-1 means infinite) - * @return success Whether or not the approval succeeded - */ - function approve(address spender, uint256 amount) - external - returns (bool success); - - /** - * @notice Get the current allowance from `owner` for `spender` - * @param owner The address of the account which owns the tokens to be spent - * @param spender The address of the account which may transfer tokens - * @return remaining The number of tokens allowed to be spent (-1 means infinite) - */ - function allowance(address owner, address spender) - external - view - returns (uint256 remaining); - - event Transfer(address indexed from, address indexed to, uint256 amount); - event Approval( - address indexed owner, - address indexed spender, - uint256 amount - ); -} - - -// Dependency file: contracts/WhitelistInterface.sol - -// pragma solidity 0.8.6; - -interface WhitelistInterface { - function setStatus(bool _newStatus) external; - function enabled() external view returns(bool); - - function addUsers(address[] memory _users) external; - function exist(address _user) external view returns(bool); - function getUsers() external view returns(address[] memory currentUsers); - function removeUser(address _user) external; -} - -// Dependency file: contracts/CToken.sol - -// pragma solidity 0.8.6; - -// import "contracts/ComptrollerInterface.sol"; -// import "contracts/CTokenInterfaces.sol"; -// import "contracts/ErrorReporter.sol"; -// import "contracts/Exponential.sol"; -// import "contracts/EIP20Interface.sol"; -// import "contracts/InterestRateModel.sol"; -// import "contracts/WhitelistInterface.sol"; - -/** - * @title tropykus CToken Contract - * @notice Abstract base for CTokens - * @author tropykus - */ -abstract contract CToken is CTokenInterface, Exponential, TokenErrorReporter { - address whitelist; - - /** - * @notice Initialize the money market - * @param comptroller_ The address of the Comptroller - * @param interestRateModel_ The address of the interest rate model - * @param initialExchangeRateMantissa_ The initial exchange rate, scaled by 1e18 - * @param name_ EIP-20 name of this token - * @param symbol_ EIP-20 symbol of this token - * @param decimals_ EIP-20 decimal precision of this token - */ - function initialize( - ComptrollerInterface comptroller_, - InterestRateModel interestRateModel_, - uint256 initialExchangeRateMantissa_, - string memory name_, - string memory symbol_, - uint8 decimals_ - ) public { - require(msg.sender == admin, "CT01"); - require(accrualBlockNumber == 0 && borrowIndex == 0, "CT02"); - - initialExchangeRateMantissa = initialExchangeRateMantissa_; - require(initialExchangeRateMantissa > 0, "CT03"); - - uint256 err = _setComptroller(comptroller_); - require(err == uint256(Error.NO_ERROR), "CT04"); - - accrualBlockNumber = getBlockNumber(); - borrowIndex = mantissaOne; - - err = _setInterestRateModelFresh(interestRateModel_); - require(err == uint256(Error.NO_ERROR), "CT05"); - - name = name_; - symbol = symbol_; - decimals = decimals_; - - _notEntered = true; - } - - function addWhitelist(address _whitelist) external returns (uint256) { - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_INTEREST_RATE_MODEL_OWNER_CHECK - ); - } - whitelist = _whitelist; - } - - /** - * @notice Transfer `tokens` tokens from `src` to `dst` by `spender` - * @dev Called by both `transfer` and `transferFrom` internally - * @param spender The address of the account performing the transfer - * @param src The address of the source account - * @param dst The address of the destination account - * @param tokens The number of tokens to transfer - * @return Whether or not the transfer succeeded - */ - function transferTokens( - address spender, - address src, - address dst, - uint256 tokens - ) internal returns (uint256) { - uint256 allowed = comptroller.transferAllowed( - address(this), - src, - dst, - tokens - ); - if (allowed != 0) { - return - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.TRANSFER_COMPTROLLER_REJECTION, - allowed - ); - } - - if (src == dst) { - return fail(Error.BAD_INPUT, FailureInfo.TRANSFER_NOT_ALLOWED); - } - - uint256 startingAllowance = 0; - if (spender == src) { - startingAllowance = type(uint256).max; - } else { - startingAllowance = transferAllowances[src][spender]; - } - - MathError mathErr; - uint256 allowanceNew; - uint256 srcTokensNew; - uint256 dstTokensNew; - - (mathErr, allowanceNew) = subUInt(startingAllowance, tokens); - if (mathErr != MathError.NO_ERROR) { - return fail(Error.MATH_ERROR, FailureInfo.TRANSFER_NOT_ALLOWED); - } - - (mathErr, srcTokensNew) = subUInt(accountTokens[src].tokens, tokens); - if (mathErr != MathError.NO_ERROR) { - return fail(Error.MATH_ERROR, FailureInfo.TRANSFER_NOT_ENOUGH); - } - - (mathErr, dstTokensNew) = addUInt(accountTokens[dst].tokens, tokens); - if (mathErr != MathError.NO_ERROR) { - return fail(Error.MATH_ERROR, FailureInfo.TRANSFER_TOO_MUCH); - } - - accountTokens[src].tokens = srcTokensNew; - accountTokens[dst].tokens = dstTokensNew; - - if (startingAllowance != type(uint256).max) { - transferAllowances[src][spender] = allowanceNew; - } - - emit Transfer(src, dst, tokens); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Transfer `amount` tokens from `msg.sender` to `dst` - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - * @return Whether or not the transfer succeeded - */ - function transfer(address dst, uint256 amount) - external - override - nonReentrant - returns (bool) - { - return - transferTokens(msg.sender, msg.sender, dst, amount) == - uint256(Error.NO_ERROR); - } - - /** - * @notice Transfer `amount` tokens from `src` to `dst` - * @param src The address of the source account - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - * @return Whether or not the transfer succeeded - */ - function transferFrom( - address src, - address dst, - uint256 amount - ) external override nonReentrant returns (bool) { - return - transferTokens(msg.sender, src, dst, amount) == - uint256(Error.NO_ERROR); - } - - /** - * @notice Approve `spender` to transfer up to `amount` from `src` - * @dev This will overwrite the approval amount for `spender` - * and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve) - * @param spender The address of the account which may transfer tokens - * @param amount The number of tokens that are approved (-1 means infinite) - * @return Whether or not the approval succeeded - */ - function approve(address spender, uint256 amount) - external - override - returns (bool) - { - transferAllowances[msg.sender][spender] = amount; - emit Approval(msg.sender, spender, amount); - return true; - } - - /** - * @notice Get the current allowance from `owner` for `spender` - * @param owner The address of the account which owns the tokens to be spent - * @param spender The address of the account which may transfer tokens - * @return The number of tokens allowed to be spent (-1 means infinite) - */ - function allowance(address owner, address spender) - external - view - override - returns (uint256) - { - return transferAllowances[owner][spender]; - } - - /** - * @notice Get the token balance of the `owner` - * @param owner The address of the account to query - * @return The number of tokens owned by `owner` - */ - function balanceOf(address owner) external view override returns (uint256) { - return accountTokens[owner].tokens; - } - - /** - * @notice Get the underlying balance of the `owner` - * @dev This also accrues interest in a transaction - * @param owner The address of the account to query - * @return The amount of underlying owned by `owner` - */ - function balanceOfUnderlying(address owner) - external - override - returns (uint256) - { - (MathError mErr, uint256 balance) = mulScalarTruncate( - Exp({mantissa: exchangeRateCurrent()}), - accountTokens[owner].tokens - ); - require(mErr == MathError.NO_ERROR, "CT06"); - return balance; - } - - /** - * @notice Get a snapshot of the account's balances, and the cached exchange rate - * @dev This is used by comptroller to more efficiently perform liquidity checks. - * @param account Address of the account to snapshot - * @return (possible error, token balance, borrow balance, exchange rate mantissa) - */ - function getAccountSnapshot(address account) - external - view - override - returns ( - uint256, - uint256, - uint256, - uint256 - ) - { - uint256 cTokenBalance = accountTokens[account].tokens; - uint256 borrowBalance; - uint256 exchangeRateMantissa; - - MathError mErr; - - (mErr, borrowBalance) = borrowBalanceStoredInternal(account); - if (mErr != MathError.NO_ERROR) { - return (uint256(Error.MATH_ERROR), 0, 0, 0); - } - - (mErr, exchangeRateMantissa) = exchangeRateStoredInternal(); - if (mErr != MathError.NO_ERROR) { - return (uint256(Error.MATH_ERROR), 0, 0, 0); - } - - return ( - uint256(Error.NO_ERROR), - cTokenBalance, - borrowBalance, - exchangeRateMantissa - ); - } - - /** - * @dev Function to simply retrieve block number - * This exists mainly for inheriting test contracts to stub this result. - */ - function getBlockNumber() internal view virtual returns (uint256) { - return block.number; - } - - /** - * @notice Returns the current per-block borrow interest rate for this cToken - * @return The borrow interest rate per block, scaled by 1e18 - */ - function borrowRatePerBlock() external view override returns (uint256) { - return - interestRateModel.getBorrowRate( - getCashPrior(), - totalBorrows, - totalReserves - ); - } - - /** - * @notice Returns the current per-block supply interest rate for this cToken - * @return The supply interest rate per block, scaled by 1e18 - */ - function supplyRatePerBlock() external view override returns (uint256) { - return - interestRateModel.getSupplyRate( - getCashPrior(), - totalBorrows, - totalReserves, - reserveFactorMantissa - ); - } - - /** - * @notice Returns the current total borrows plus accrued interest - * @return The total borrows with interest - */ - function totalBorrowsCurrent() - external - override - nonReentrant - returns (uint256) - { - require(accrueInterest() == uint256(Error.NO_ERROR), "CT07"); - return totalBorrows; - } - - /** - * @notice Accrue interest to updated borrowIndex and then calculate account's borrow balance using the updated borrowIndex - * @param account The address whose balance should be calculated after updating borrowIndex - * @return The calculated balance - */ - function borrowBalanceCurrent(address account) - external - override - nonReentrant - returns (uint256) - { - require(accrueInterest() == uint256(Error.NO_ERROR), "CT07"); - return borrowBalanceStored(account); - } - - /** - * @notice Return the borrow balance of account based on stored data - * @param account The address whose balance should be calculated - * @return The calculated balance - */ - function borrowBalanceStored(address account) - public - view - override - returns (uint256) - { - (MathError err, uint256 result) = borrowBalanceStoredInternal(account); - require(err == MathError.NO_ERROR, "CT08"); - return result; - } - - /** - * @notice Return the borrow balance of account based on stored data - * @param account The address whose balance should be calculated - * @return (error code, the calculated balance or 0 if error code is non-zero) - */ - function borrowBalanceStoredInternal(address account) - internal - view - returns (MathError, uint256) - { - MathError mathErr; - uint256 principalTimesIndex; - uint256 result; - - BorrowSnapshot storage borrowSnapshot = accountBorrows[account]; - - if (borrowSnapshot.principal == 0) { - return (MathError.NO_ERROR, 0); - } - - (mathErr, principalTimesIndex) = mulUInt( - borrowSnapshot.principal, - borrowIndex - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - - (mathErr, result) = divUInt( - principalTimesIndex, - borrowSnapshot.interestIndex - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - - return (MathError.NO_ERROR, result); - } - - function getBorrowerPrincipalStored(address account) - public - view - returns (uint256 borrowed) - { - borrowed = accountBorrows[account].principal; - } - - function getSupplierSnapshotStored(address account) - public - view - returns ( - uint256 tokens, - uint256 underlyingAmount, - uint256 suppliedAt, - uint256 promisedSupplyRate - ) - { - tokens = accountTokens[account].tokens; - underlyingAmount = accountTokens[account].underlyingAmount; - suppliedAt = accountTokens[account].suppliedAt; - promisedSupplyRate = accountTokens[account].promisedSupplyRate; - } - - /** - * @notice Accrue interest then return the up-to-date exchange rate - * @return Calculated exchange rate scaled by 1e18 - */ - function exchangeRateCurrent() - public - override - nonReentrant - returns (uint256) - { - require(accrueInterest() == uint256(Error.NO_ERROR), "CT07"); - return exchangeRateStored(); - } - - /** - * @notice Calculates the exchange rate from the underlying to the CToken - * @dev This function does not accrue interest before calculating the exchange rate - * @return Calculated exchange rate scaled by 1e18 - */ - function exchangeRateStored() public view override returns (uint256) { - (MathError err, uint256 result) = exchangeRateStoredInternal(); - require(err == MathError.NO_ERROR, "CT09"); - return result; - } - - /** - * @notice Calculates the exchange rate from the underlying to the CToken - * @dev This function does not accrue interest before calculating the exchange rate - * @return (error code, calculated exchange rate scaled by 1e18) - */ - function exchangeRateStoredInternal() - internal - view - virtual - returns (MathError, uint256) - { - uint256 _totalSupply = totalSupply; - if (_totalSupply == 0) { - return (MathError.NO_ERROR, initialExchangeRateMantissa); - } else { - MathError error; - uint256 exchangeRate; - uint256 totalCash = getCashPrior(); - if (interestRateModel.isTropykusInterestRateModel()) { - (error, exchangeRate) = tropykusExchangeRateStoredInternal( - msg.sender - ); - if (error == MathError.NO_ERROR) { - return (MathError.NO_ERROR, exchangeRate); - } else { - return (MathError.NO_ERROR, initialExchangeRateMantissa); - } - } - return - interestRateModel.getExchangeRate( - totalCash, - totalBorrows, - totalReserves, - totalSupply - ); - } - } - - function tropykusExchangeRateStoredInternal(address redeemer) - internal - view - returns (MathError, uint256) - { - if (totalSupply == 0) { - return (MathError.NO_ERROR, initialExchangeRateMantissa); - } else { - SupplySnapshot storage supplySnapshot = accountTokens[redeemer]; - if (supplySnapshot.suppliedAt == 0) { - return (MathError.DIVISION_BY_ZERO, 0); - } - (, uint256 interestFactorMantissa, ) = tropykusInterestAccrued( - redeemer - ); - Exp memory interestFactor = Exp({mantissa: interestFactorMantissa}); - uint256 currentUnderlying = supplySnapshot.underlyingAmount; - Exp memory redeemerUnderlying = Exp({mantissa: currentUnderlying}); - (, Exp memory realAmount) = mulExp( - interestFactor, - redeemerUnderlying - ); - (, Exp memory exchangeRate) = getExp( - realAmount.mantissa, - supplySnapshot.tokens - ); - return (MathError.NO_ERROR, exchangeRate.mantissa); - } - } - - function tropykusInterestAccrued(address account) - internal - view - returns ( - MathError, - uint256, - uint256 - ) - { - SupplySnapshot storage supplySnapshot = accountTokens[account]; - uint256 promisedSupplyRate = supplySnapshot.promisedSupplyRate; - Exp memory expectedSupplyRatePerBlock = Exp({ - mantissa: promisedSupplyRate - }); - (, uint256 delta) = subUInt( - accrualBlockNumber, - supplySnapshot.suppliedAt - ); - (, Exp memory expectedSupplyRatePerBlockWithDelta) = mulScalar( - expectedSupplyRatePerBlock, - delta - ); - (, Exp memory interestFactor) = addExp( - Exp({mantissa: 1e18}), - expectedSupplyRatePerBlockWithDelta - ); - uint256 currentUnderlying = supplySnapshot.underlyingAmount; - Exp memory redeemerUnderlying = Exp({mantissa: currentUnderlying}); - (, Exp memory realAmount) = mulExp(interestFactor, redeemerUnderlying); - (, uint256 interestEarned) = subUInt( - realAmount.mantissa, - currentUnderlying - ); - return (MathError.NO_ERROR, interestFactor.mantissa, interestEarned); - } - - /** - * @notice Get cash balance of this cToken in the underlying asset - * @return The quantity of underlying asset owned by this contract - */ - function getCash() external view override returns (uint256) { - return getCashPrior(); - } - - /** - * @notice Applies accrued interest to total borrows and reserves - * @dev This calculates interest accrued from the last checkpointed block - * up to the current block and writes new checkpoint to storage. - */ - function accrueInterest() public override returns (uint256) { - uint256 currentBlockNumber = getBlockNumber(); - uint256 accrualBlockNumberPrior = accrualBlockNumber; - - if (accrualBlockNumberPrior == currentBlockNumber) { - return uint256(Error.NO_ERROR); - } - - uint256 cashPrior = getCashPrior(); - uint256 borrowsPrior = totalBorrows; - uint256 reservesPrior = totalReserves; - uint256 borrowIndexPrior = borrowIndex; - - uint256 borrowRateMantissa = interestRateModel.getBorrowRate( - cashPrior, - borrowsPrior, - reservesPrior - ); - require(borrowRateMantissa <= borrowRateMaxMantissa, "CT10"); - - (MathError mathErr, uint256 blockDelta) = subUInt( - currentBlockNumber, - accrualBlockNumberPrior - ); - require(mathErr == MathError.NO_ERROR, "CT11"); - - Exp memory simpleInterestFactor; - uint256 interestAccumulated; - uint256 totalBorrowsNew; - uint256 totalReservesNew; - uint256 borrowIndexNew; - - (mathErr, simpleInterestFactor) = mulScalar( - Exp({mantissa: borrowRateMantissa}), - blockDelta - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .ACCRUE_INTEREST_SIMPLE_INTEREST_FACTOR_CALCULATION_FAILED, - uint256(mathErr) - ); - } - - (mathErr, interestAccumulated) = mulScalarTruncate( - simpleInterestFactor, - borrowsPrior - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .ACCRUE_INTEREST_ACCUMULATED_INTEREST_CALCULATION_FAILED, - uint256(mathErr) - ); - } - - (mathErr, totalBorrowsNew) = addUInt(interestAccumulated, borrowsPrior); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .ACCRUE_INTEREST_NEW_TOTAL_BORROWS_CALCULATION_FAILED, - uint256(mathErr) - ); - } - - (mathErr, totalReservesNew) = mulScalarTruncateAddUInt( - Exp({mantissa: reserveFactorMantissa}), - interestAccumulated, - reservesPrior - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .ACCRUE_INTEREST_NEW_TOTAL_RESERVES_CALCULATION_FAILED, - uint256(mathErr) - ); - } - - if (interestRateModel.isTropykusInterestRateModel()) { - (mathErr, totalReservesNew) = newReserves( - borrowRateMantissa, - cashPrior, - borrowsPrior, - reservesPrior, - interestAccumulated - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .ACCRUE_INTEREST_NEW_TOTAL_RESERVES_CALCULATION_FAILED, - uint256(mathErr) - ); - } - } - - (mathErr, borrowIndexNew) = mulScalarTruncateAddUInt( - simpleInterestFactor, - borrowIndexPrior, - borrowIndexPrior - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .ACCRUE_INTEREST_NEW_BORROW_INDEX_CALCULATION_FAILED, - uint256(mathErr) - ); - } - - accrualBlockNumber = currentBlockNumber; - borrowIndex = borrowIndexNew; - totalBorrows = totalBorrowsNew; - totalReserves = totalReservesNew; - - emit AccrueInterest( - cashPrior, - interestAccumulated, - borrowIndexNew, - totalBorrowsNew - ); - - return uint256(Error.NO_ERROR); - } - - function newReserves( - uint256 borrowRateMantissa, - uint256 cashPrior, - uint256 borrowsPrior, - uint256 reservesPrior, - uint256 interestAccumulated - ) internal view returns (MathError mathErr, uint256 totalReservesNew) { - uint256 newReserveFactorMantissa; - uint256 utilizationRate = interestRateModel.utilizationRate( - cashPrior, - borrowsPrior, - reservesPrior - ); - uint256 expectedSupplyRate = interestRateModel.getSupplyRate( - cashPrior, - borrowsPrior, - reservesPrior, - reserveFactorMantissa - ); - if ( - interestRateModel.isAboveOptimal( - cashPrior, - borrowsPrior, - reservesPrior - ) - ) { - (mathErr, newReserveFactorMantissa) = mulScalarTruncate( - Exp({mantissa: utilizationRate}), - borrowRateMantissa - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - (mathErr, newReserveFactorMantissa) = subUInt( - newReserveFactorMantissa, - expectedSupplyRate - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - (mathErr, totalReservesNew) = mulScalarTruncateAddUInt( - Exp({mantissa: newReserveFactorMantissa}), - interestAccumulated, - reservesPrior - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - } else { - mathErr = MathError.NO_ERROR; - totalReservesNew = reservesPrior; - } - } - - /** - * @notice Sender supplies assets into the market and receives cTokens in exchange - * @dev Accrues interest whether or not the operation succeeds, unless reverted - * @param mintAmount The amount of the underlying asset to supply - * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual mint amount. - */ - function mintInternal(uint256 mintAmount) - internal - nonReentrant - returns (uint256, uint256) - { - if (WhitelistInterface(whitelist).enabled()) { - require(WhitelistInterface(whitelist).exist(msg.sender), "CT26"); - } - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return ( - fail(Error(error), FailureInfo.MINT_ACCRUE_INTEREST_FAILED), - 0 - ); - } - return mintFresh(msg.sender, mintAmount); - } - - struct MintLocalVars { - Error err; - MathError mathErr; - uint256 exchangeRateMantissa; - uint256 mintTokens; - uint256 totalSupplyNew; - uint256 accountTokensNew; - uint256 actualMintAmount; - } - - /** - * @notice User supplies assets into the market and receives cTokens in exchange - * @dev Assumes interest has already been accrued up to the current block - * @param minter The address of the account which is supplying the assets - * @param mintAmount The amount of the underlying asset to supply - * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual mint amount. - */ - function mintFresh(address minter, uint256 mintAmount) - internal - returns (uint256, uint256) - { - uint256 allowed = comptroller.mintAllowed( - address(this), - minter, - mintAmount - ); - if (allowed != 0) { - return ( - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.MINT_COMPTROLLER_REJECTION, - allowed - ), - 0 - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return ( - fail(Error.MARKET_NOT_FRESH, FailureInfo.MINT_FRESHNESS_CHECK), - 0 - ); - } - - MintLocalVars memory vars; - - ( - vars.mathErr, - vars.exchangeRateMantissa - ) = exchangeRateStoredInternal(); - if (vars.mathErr != MathError.NO_ERROR) { - return ( - failOpaque( - Error.MATH_ERROR, - FailureInfo.MINT_EXCHANGE_RATE_READ_FAILED, - uint256(vars.mathErr) - ), - 0 - ); - } - if (interestRateModel.isTropykusInterestRateModel()) { - SupplySnapshot storage supplySnapshot = accountTokens[minter]; - (, uint256 newTotalSupply) = addUInt( - supplySnapshot.underlyingAmount, - mintAmount - ); - require(newTotalSupply <= 0.1e18, "CT24"); - } - vars.actualMintAmount = doTransferIn(minter, mintAmount); - - (vars.mathErr, vars.mintTokens) = divScalarByExpTruncate( - vars.actualMintAmount, - Exp({mantissa: vars.exchangeRateMantissa}) - ); - require(vars.mathErr == MathError.NO_ERROR, "CT12"); - - (vars.mathErr, vars.totalSupplyNew) = addUInt( - totalSupply, - vars.mintTokens - ); - require(vars.mathErr == MathError.NO_ERROR, "CT13"); - - (vars.mathErr, vars.accountTokensNew) = addUInt( - accountTokens[minter].tokens, - vars.mintTokens - ); - require(vars.mathErr == MathError.NO_ERROR, "CT14"); - - uint256 currentSupplyRate = interestRateModel.getSupplyRate( - getCashPrior(), - totalBorrows, - totalReserves, - reserveFactorMantissa - ); - - bool isTropykusInterestRateModel = interestRateModel - .isTropykusInterestRateModel(); - - if (accountTokens[minter].tokens > 0) { - Exp memory updatedUnderlying; - if (isTropykusInterestRateModel) { - (, uint256 interestFactorMantissa, ) = tropykusInterestAccrued( - minter - ); - Exp memory interestFactor = Exp({ - mantissa: interestFactorMantissa - }); - uint256 currentUnderlyingAmount = accountTokens[minter] - .underlyingAmount; - MathError mErrorNewAmount; - (mErrorNewAmount, updatedUnderlying) = mulExp( - Exp({mantissa: currentUnderlyingAmount}), - interestFactor - ); - if (mErrorNewAmount != MathError.NO_ERROR) { - return ( - failOpaque( - Error.MATH_ERROR, - FailureInfo.MINT_EXCHANGE_CALCULATION_FAILED, - uint256(mErrorNewAmount) - ), - 0 - ); - } - } else { - uint256 currentTokens = accountTokens[minter].tokens; - MathError mErrorUpdatedUnderlying; - (mErrorUpdatedUnderlying, updatedUnderlying) = mulExp( - Exp({mantissa: currentTokens}), - Exp({mantissa: vars.exchangeRateMantissa}) - ); - if (mErrorUpdatedUnderlying != MathError.NO_ERROR) { - return ( - failOpaque( - Error.MATH_ERROR, - FailureInfo.MINT_EXCHANGE_CALCULATION_FAILED, - uint256(mErrorUpdatedUnderlying) - ), - 0 - ); - } - } - (, mintAmount) = addUInt(updatedUnderlying.mantissa, mintAmount); - } - - totalSupply = vars.totalSupplyNew; - accountTokens[minter] = SupplySnapshot({ - tokens: vars.accountTokensNew, - underlyingAmount: mintAmount, - suppliedAt: accrualBlockNumber, - promisedSupplyRate: currentSupplyRate - }); - - emit Mint(minter, vars.actualMintAmount, vars.mintTokens); - emit Transfer(address(this), minter, vars.mintTokens); - - return (uint256(Error.NO_ERROR), vars.actualMintAmount); - } - - /** - * @notice Sender redeems cTokens in exchange for a specified amount of underlying asset - * @dev Accrues interest whether or not the operation succeeds, unless reverted - * @param redeemAmount The amount of underlying to receive from redeeming cTokens - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function redeemUnderlyingInternal(uint256 redeemAmount) - internal - nonReentrant - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return - fail(Error(error), FailureInfo.REDEEM_ACCRUE_INTEREST_FAILED); - } - return redeemFresh(payable(msg.sender), redeemAmount); - } - - struct RedeemLocalVars { - Error err; - MathError mathErr; - uint256 exchangeRateMantissa; - uint256 redeemTokens; - uint256 redeemAmount; - uint256 totalSupplyNew; - uint256 accountTokensNew; - uint256 newSubsidyFund; - } - - /** - * @notice User redeems cTokens in exchange for the underlying asset - * @dev Assumes interest has already been accrued up to the current block - * @param redeemer The address of the account which is redeeming the tokens - * @param redeemAmountIn The number of underlying tokens to receive from redeeming cTokens - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function redeemFresh(address payable redeemer, uint256 redeemAmountIn) - internal - returns (uint256) - { - require(redeemAmountIn > 0, "CT15"); - - RedeemLocalVars memory vars; - - SupplySnapshot storage supplySnapshot = accountTokens[redeemer]; - - ( - vars.mathErr, - vars.exchangeRateMantissa - ) = exchangeRateStoredInternal(); - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.REDEEM_EXCHANGE_RATE_READ_FAILED, - uint256(vars.mathErr) - ); - } - - uint256 interestEarned; - uint256 subsidyFundPortion; - uint256 currentUnderlying; - - bool isTropykusInterestRateModel = interestRateModel - .isTropykusInterestRateModel(); - if (isTropykusInterestRateModel) { - currentUnderlying = supplySnapshot.underlyingAmount; - (, , interestEarned) = tropykusInterestAccrued(redeemer); - } - supplySnapshot.promisedSupplyRate = interestRateModel.getSupplyRate( - getCashPrior(), - totalBorrows, - totalReserves, - reserveFactorMantissa - ); - - if ( - isTropykusInterestRateModel && - !interestRateModel.isAboveOptimal( - getCashPrior(), - totalBorrows, - totalReserves - ) - ) { - uint256 borrowRate = interestRateModel.getBorrowRate( - getCashPrior(), - totalBorrows, - totalReserves - ); - - uint256 utilizationRate = interestRateModel.utilizationRate( - getCashPrior(), - totalBorrows, - totalReserves - ); - - (, uint256 estimatedEarning) = mulScalarTruncate( - Exp({mantissa: borrowRate}), - utilizationRate - ); - - (, subsidyFundPortion) = subUInt( - supplySnapshot.promisedSupplyRate, - estimatedEarning - ); - (, Exp memory subsidyFactor) = getExp( - subsidyFundPortion, - supplySnapshot.promisedSupplyRate - ); - (, subsidyFundPortion) = mulScalarTruncate( - subsidyFactor, - interestEarned - ); - } - - vars.redeemAmount = redeemAmountIn; - - if (isTropykusInterestRateModel) { - (, Exp memory num) = mulExp( - vars.redeemAmount, - supplySnapshot.tokens - ); - (, Exp memory realTokensWithdrawAmount) = getExp( - num.mantissa, - currentUnderlying - ); - vars.redeemTokens = realTokensWithdrawAmount.mantissa; - } else { - (vars.mathErr, vars.redeemTokens) = divScalarByExpTruncate( - redeemAmountIn, - Exp({mantissa: vars.exchangeRateMantissa}) - ); - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.REDEEM_EXCHANGE_AMOUNT_CALCULATION_FAILED, - uint256(vars.mathErr) - ); - } - } - // } - - uint256 allowed = comptroller.redeemAllowed( - address(this), - redeemer, - vars.redeemTokens - ); - if (allowed != 0) { - return - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.REDEEM_COMPTROLLER_REJECTION, - allowed - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.REDEEM_FRESHNESS_CHECK - ); - } - - (vars.mathErr, vars.totalSupplyNew) = subUInt( - totalSupply, - vars.redeemTokens - ); - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.REDEEM_NEW_TOTAL_SUPPLY_CALCULATION_FAILED, - uint256(vars.mathErr) - ); - } - - (, vars.newSubsidyFund) = subUInt(subsidyFund, subsidyFundPortion); - - (vars.mathErr, vars.accountTokensNew) = subUInt( - supplySnapshot.tokens, - vars.redeemTokens - ); - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.REDEEM_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED, - uint256(vars.mathErr) - ); - } - - uint256 cash = getCashPrior(); - if (isTropykusInterestRateModel) { - cash = address(this).balance; - } - - if (cash < vars.redeemAmount) { - return - fail( - Error.TOKEN_INSUFFICIENT_CASH, - FailureInfo.REDEEM_TRANSFER_OUT_NOT_POSSIBLE - ); - } - - doTransferOut(redeemer, vars.redeemAmount); - - totalSupply = vars.totalSupplyNew; - subsidyFund = vars.newSubsidyFund; - supplySnapshot.tokens = vars.accountTokensNew; - supplySnapshot.suppliedAt = accrualBlockNumber; - (, supplySnapshot.underlyingAmount) = subUInt( - supplySnapshot.underlyingAmount, - vars.redeemAmount - ); - - emit Transfer(redeemer, address(this), vars.redeemTokens); - emit Redeem(redeemer, vars.redeemAmount, vars.redeemTokens); - - comptroller.redeemVerify( - address(this), - redeemer, - vars.redeemAmount, - vars.redeemTokens - ); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Sender borrows assets from the protocol to their own address - * @param borrowAmount The amount of the underlying asset to borrow - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function borrowInternal(uint256 borrowAmount) - internal - nonReentrant - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return - fail(Error(error), FailureInfo.BORROW_ACCRUE_INTEREST_FAILED); - } - return borrowFresh(payable(msg.sender), borrowAmount); - } - - struct BorrowLocalVars { - MathError mathErr; - uint256 accountBorrows; - uint256 accountBorrowsNew; - uint256 totalBorrowsNew; - } - - /** - * @notice Users borrow assets from the protocol to their own address - * @param borrowAmount The amount of the underlying asset to borrow - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function borrowFresh(address payable borrower, uint256 borrowAmount) - internal - returns (uint256) - { - uint256 allowed = comptroller.borrowAllowed( - address(this), - borrower, - borrowAmount - ); - if (allowed != 0) { - return - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.BORROW_COMPTROLLER_REJECTION, - allowed - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.BORROW_FRESHNESS_CHECK - ); - } - - if (getCashPrior() < borrowAmount) { - return - fail( - Error.TOKEN_INSUFFICIENT_CASH, - FailureInfo.BORROW_CASH_NOT_AVAILABLE - ); - } - - BorrowLocalVars memory vars; - - (vars.mathErr, vars.accountBorrows) = borrowBalanceStoredInternal( - borrower - ); - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED, - uint256(vars.mathErr) - ); - } - - (vars.mathErr, vars.accountBorrowsNew) = addUInt( - vars.accountBorrows, - borrowAmount - ); - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo - .BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED, - uint256(vars.mathErr) - ); - } - - (vars.mathErr, vars.totalBorrowsNew) = addUInt( - totalBorrows, - borrowAmount - ); - if (interestRateModel.isTropykusInterestRateModel()) { - require(vars.totalBorrowsNew <= 0.1e18, "CT25"); - } - if (vars.mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED, - uint256(vars.mathErr) - ); - } - - doTransferOut(borrower, borrowAmount); - - accountBorrows[borrower].principal = vars.accountBorrowsNew; - accountBorrows[borrower].interestIndex = borrowIndex; - totalBorrows = vars.totalBorrowsNew; - - emit Borrow( - borrower, - borrowAmount, - vars.accountBorrowsNew, - vars.totalBorrowsNew - ); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Sender repays their own borrow - * @param repayAmount The amount to repay - * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual repayment amount. - */ - function repayBorrowInternal(uint256 repayAmount) - internal - nonReentrant - returns (uint256, uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return ( - fail( - Error(error), - FailureInfo.REPAY_BORROW_ACCRUE_INTEREST_FAILED - ), - 0 - ); - } - return repayBorrowFresh(msg.sender, msg.sender, repayAmount); - } - - struct RepayBorrowLocalVars { - Error err; - MathError mathErr; - uint256 repayAmount; - uint256 borrowerIndex; - uint256 accountBorrows; - uint256 accountBorrowsNew; - uint256 totalBorrowsNew; - uint256 actualRepayAmount; - } - - /** - * @notice Borrows are repaid by another user (possibly the borrower). - * @param payer the account paying off the borrow - * @param borrower the account with the debt being payed off - * @param repayAmount the amount of undelrying tokens being returned - * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual repayment amount. - */ - function repayBorrowFresh( - address payer, - address borrower, - uint256 repayAmount - ) internal returns (uint256, uint256) { - uint256 allowed = comptroller.repayBorrowAllowed( - address(this), - payer, - borrower, - repayAmount - ); - if (allowed != 0) { - return ( - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.REPAY_BORROW_COMPTROLLER_REJECTION, - allowed - ), - 0 - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return ( - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.REPAY_BORROW_FRESHNESS_CHECK - ), - 0 - ); - } - - RepayBorrowLocalVars memory vars; - - vars.borrowerIndex = accountBorrows[borrower].interestIndex; - - (vars.mathErr, vars.accountBorrows) = borrowBalanceStoredInternal( - borrower - ); - if (vars.mathErr != MathError.NO_ERROR) { - return ( - failOpaque( - Error.MATH_ERROR, - FailureInfo - .REPAY_BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED, - uint256(vars.mathErr) - ), - 0 - ); - } - - if (repayAmount == type(uint256).max) { - vars.repayAmount = vars.accountBorrows; - } else { - vars.repayAmount = repayAmount; - } - - vars.actualRepayAmount = doTransferIn(payer, vars.repayAmount); - - (vars.mathErr, vars.accountBorrowsNew) = subUInt( - vars.accountBorrows, - vars.actualRepayAmount - ); - require(vars.mathErr == MathError.NO_ERROR, "CT16"); - - (vars.mathErr, vars.totalBorrowsNew) = subUInt( - totalBorrows, - vars.actualRepayAmount - ); - require(vars.mathErr == MathError.NO_ERROR, "CT17"); - - accountBorrows[borrower].principal = vars.accountBorrowsNew; - accountBorrows[borrower].interestIndex = borrowIndex; - totalBorrows = vars.totalBorrowsNew; - - emit RepayBorrow( - payer, - borrower, - vars.actualRepayAmount, - vars.accountBorrowsNew, - vars.totalBorrowsNew - ); - - return (uint256(Error.NO_ERROR), vars.actualRepayAmount); - } - - /** - * @notice The sender liquidates the borrowers collateral. - * The collateral seized is transferred to the liquidator. - * @param borrower The borrower of this cToken to be liquidated - * @param cTokenCollateral The market in which to seize collateral from the borrower - * @param repayAmount The amount of the underlying borrowed asset to repay - * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual repayment amount. - */ - function liquidateBorrowInternal( - address borrower, - uint256 repayAmount, - CTokenInterface cTokenCollateral - ) internal nonReentrant returns (uint256, uint256) { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return ( - fail( - Error(error), - FailureInfo.LIQUIDATE_ACCRUE_BORROW_INTEREST_FAILED - ), - 0 - ); - } - - error = cTokenCollateral.accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return ( - fail( - Error(error), - FailureInfo.LIQUIDATE_ACCRUE_COLLATERAL_INTEREST_FAILED - ), - 0 - ); - } - - // liquidateBorrowFresh emits borrow-specific logs on errors, so we don't need to - return - liquidateBorrowFresh( - msg.sender, - borrower, - repayAmount, - cTokenCollateral - ); - } - - /** - * @notice The liquidator liquidates the borrowers collateral. - * The collateral seized is transferred to the liquidator. - * @param borrower The borrower of this cToken to be liquidated - * @param liquidator The address repaying the borrow and seizing collateral - * @param cTokenCollateral The market in which to seize collateral from the borrower - * @param repayAmount The amount of the underlying borrowed asset to repay - * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual repayment amount. - */ - function liquidateBorrowFresh( - address liquidator, - address borrower, - uint256 repayAmount, - CTokenInterface cTokenCollateral - ) internal returns (uint256, uint256) { - uint256 allowed = comptroller.liquidateBorrowAllowed( - address(this), - address(cTokenCollateral), - liquidator, - borrower, - repayAmount - ); - if (allowed != 0) { - return ( - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.LIQUIDATE_COMPTROLLER_REJECTION, - allowed - ), - 0 - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return ( - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.LIQUIDATE_FRESHNESS_CHECK - ), - 0 - ); - } - - if (cTokenCollateral.accrualBlockNumber() != getBlockNumber()) { - return ( - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.LIQUIDATE_COLLATERAL_FRESHNESS_CHECK - ), - 0 - ); - } - - if (borrower == liquidator) { - return ( - fail( - Error.INVALID_ACCOUNT_PAIR, - FailureInfo.LIQUIDATE_LIQUIDATOR_IS_BORROWER - ), - 0 - ); - } - - if (repayAmount == 0) { - return ( - fail( - Error.INVALID_CLOSE_AMOUNT_REQUESTED, - FailureInfo.LIQUIDATE_CLOSE_AMOUNT_IS_ZERO - ), - 0 - ); - } - - if (repayAmount == type(uint256).max) { - return ( - fail( - Error.INVALID_CLOSE_AMOUNT_REQUESTED, - FailureInfo.LIQUIDATE_CLOSE_AMOUNT_IS_UINT_MAX - ), - 0 - ); - } - - ( - uint256 repayBorrowError, - uint256 actualRepayAmount - ) = repayBorrowFresh(liquidator, borrower, repayAmount); - if (repayBorrowError != uint256(Error.NO_ERROR)) { - return ( - fail( - Error(repayBorrowError), - FailureInfo.LIQUIDATE_REPAY_BORROW_FRESH_FAILED - ), - 0 - ); - } - - (uint256 amountSeizeError, uint256 seizeTokens) = comptroller - .liquidateCalculateSeizeTokens( - address(this), - address(cTokenCollateral), - actualRepayAmount - ); - require(amountSeizeError == uint256(Error.NO_ERROR), "CT18"); - - require(cTokenCollateral.balanceOf(borrower) >= seizeTokens, "CT19"); - - uint256 seizeError; - if (address(cTokenCollateral) == address(this)) { - seizeError = seizeInternal( - address(this), - liquidator, - borrower, - seizeTokens - ); - } else { - seizeError = cTokenCollateral.seize( - liquidator, - borrower, - seizeTokens - ); - } - - require(seizeError == uint256(Error.NO_ERROR), "CT20"); - - emit LiquidateBorrow( - liquidator, - borrower, - actualRepayAmount, - address(cTokenCollateral), - seizeTokens - ); - - return (uint256(Error.NO_ERROR), actualRepayAmount); - } - - /** - * @notice Transfers collateral tokens (this market) to the liquidator. - * @dev Will fail unless called by another cToken during the process of liquidation. - * Its absolutely critical to use msg.sender as the borrowed cToken and not a parameter. - * @param liquidator The account receiving seized collateral - * @param borrower The account having collateral seized - * @param seizeTokens The number of cTokens to seize - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function seize( - address liquidator, - address borrower, - uint256 seizeTokens - ) external override nonReentrant returns (uint256) { - return seizeInternal(msg.sender, liquidator, borrower, seizeTokens); - } - - struct SeizeVars { - uint256 seizeAmount; - uint256 exchangeRate; - uint256 borrowerTokensNew; - uint256 borrowerAmountNew; - uint256 liquidatorTokensNew; - uint256 liquidatorAmountNew; - uint256 totalCash; - uint256 supplyRate; - } - - /** - * @notice Transfers collateral tokens (this market) to the liquidator. - * @dev Called only during an in-kind liquidation, or by liquidateBorrow during the liquidation of another CToken. - * Its absolutely critical to use msg.sender as the seizer cToken and not a parameter. - * @param seizerToken The contract seizing the collateral (i.e. borrowed cToken) - * @param liquidator The account receiving seized collateral - * @param borrower The account having collateral seized - * @param seizeTokens The number of cTokens to seize - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function seizeInternal( - address seizerToken, - address liquidator, - address borrower, - uint256 seizeTokens - ) internal returns (uint256) { - uint256 allowed = comptroller.seizeAllowed( - address(this), - seizerToken, - liquidator, - borrower, - seizeTokens - ); - if (allowed != 0) { - return - failOpaque( - Error.COMPTROLLER_REJECTION, - FailureInfo.LIQUIDATE_SEIZE_COMPTROLLER_REJECTION, - allowed - ); - } - - if (borrower == liquidator) { - return - fail( - Error.INVALID_ACCOUNT_PAIR, - FailureInfo.LIQUIDATE_SEIZE_LIQUIDATOR_IS_BORROWER - ); - } - - SeizeVars memory seizeVars; - - MathError mathErr; - - (mathErr, seizeVars.borrowerTokensNew) = subUInt( - accountTokens[borrower].tokens, - seizeTokens - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.LIQUIDATE_SEIZE_BALANCE_DECREMENT_FAILED, - uint256(mathErr) - ); - } - - seizeVars.totalCash = getCashPrior(); - seizeVars.supplyRate = interestRateModel.getSupplyRate( - seizeVars.totalCash, - totalBorrows, - totalReserves, - reserveFactorMantissa - ); - - (, seizeVars.exchangeRate) = interestRateModel.getExchangeRate( - seizeVars.totalCash, - totalBorrows, - totalReserves, - totalSupply - ); - - if (interestRateModel.isTropykusInterestRateModel()) { - (, seizeVars.exchangeRate) = tropykusExchangeRateStoredInternal( - borrower - ); - } - - (, seizeVars.seizeAmount) = mulUInt( - seizeTokens, - seizeVars.exchangeRate - ); - (, seizeVars.seizeAmount) = divUInt(seizeVars.seizeAmount, 1e18); - - (, seizeVars.borrowerAmountNew) = subUInt( - accountTokens[borrower].underlyingAmount, - seizeVars.seizeAmount - ); - - (mathErr, seizeVars.liquidatorTokensNew) = addUInt( - accountTokens[liquidator].tokens, - seizeTokens - ); - if (mathErr != MathError.NO_ERROR) { - return - failOpaque( - Error.MATH_ERROR, - FailureInfo.LIQUIDATE_SEIZE_BALANCE_INCREMENT_FAILED, - uint256(mathErr) - ); - } - - (, seizeVars.liquidatorAmountNew) = addUInt( - accountTokens[liquidator].underlyingAmount, - seizeVars.seizeAmount - ); - - accountTokens[borrower].tokens = seizeVars.borrowerTokensNew; - accountTokens[borrower].underlyingAmount = seizeVars.borrowerAmountNew; - accountTokens[borrower].suppliedAt = getBlockNumber(); - accountTokens[borrower].promisedSupplyRate = seizeVars.supplyRate; - - accountTokens[liquidator].tokens = seizeVars.liquidatorTokensNew; - accountTokens[liquidator].underlyingAmount = seizeVars - .liquidatorAmountNew; - accountTokens[liquidator].suppliedAt = getBlockNumber(); - accountTokens[liquidator].promisedSupplyRate = seizeVars.supplyRate; - - emit Transfer(borrower, liquidator, seizeTokens); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Begins transfer of admin rights. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer. - * @dev Admin function to begin change of admin. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer. - * @param newPendingAdmin New pending admin. - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setPendingAdmin(address payable newPendingAdmin) - external - override - returns (uint256) - { - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_PENDING_ADMIN_OWNER_CHECK - ); - } - - address oldPendingAdmin = pendingAdmin; - - pendingAdmin = newPendingAdmin; - - emit NewPendingAdmin(oldPendingAdmin, newPendingAdmin); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Accepts transfer of admin rights. msg.sender must be pendingAdmin - * @dev Admin function for pending admin to accept role and update admin - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _acceptAdmin() external override returns (uint256) { - if (msg.sender != pendingAdmin || msg.sender == address(0)) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.ACCEPT_ADMIN_PENDING_ADMIN_CHECK - ); - } - - address oldAdmin = admin; - address oldPendingAdmin = pendingAdmin; - - admin = pendingAdmin; - - pendingAdmin = payable(address(0)); - - emit NewAdmin(oldAdmin, admin); - emit NewPendingAdmin(oldPendingAdmin, pendingAdmin); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Sets a new comptroller for the market - * @dev Admin function to set a new comptroller - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setComptroller(ComptrollerInterface newComptroller) - public - override - returns (uint256) - { - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_COMPTROLLER_OWNER_CHECK - ); - } - - ComptrollerInterface oldComptroller = comptroller; - require(newComptroller.isComptroller(), "CT21"); - - comptroller = newComptroller; - - emit NewComptroller(oldComptroller, newComptroller); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice accrues interest and sets a new reserve factor for the protocol using _setReserveFactorFresh - * @dev Admin function to accrue interest and set a new reserve factor - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setReserveFactor(uint256 newReserveFactorMantissa) - external - override - nonReentrant - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return - fail( - Error(error), - FailureInfo.SET_RESERVE_FACTOR_ACCRUE_INTEREST_FAILED - ); - } - return _setReserveFactorFresh(newReserveFactorMantissa); - } - - /** - * @notice Sets a new reserve factor for the protocol (*requires fresh interest accrual) - * @dev Admin function to set a new reserve factor - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setReserveFactorFresh(uint256 newReserveFactorMantissa) - internal - returns (uint256) - { - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_RESERVE_FACTOR_ADMIN_CHECK - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.SET_RESERVE_FACTOR_FRESH_CHECK - ); - } - - if (newReserveFactorMantissa > reserveFactorMaxMantissa) { - return - fail( - Error.BAD_INPUT, - FailureInfo.SET_RESERVE_FACTOR_BOUNDS_CHECK - ); - } - - uint256 oldReserveFactorMantissa = reserveFactorMantissa; - reserveFactorMantissa = newReserveFactorMantissa; - - emit NewReserveFactor( - oldReserveFactorMantissa, - newReserveFactorMantissa - ); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Accrues interest and reduces reserves by transferring from msg.sender - * @param addAmount Amount of addition to reserves - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _addReservesInternal(uint256 addAmount) - internal - nonReentrant - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return - fail( - Error(error), - FailureInfo.ADD_RESERVES_ACCRUE_INTEREST_FAILED - ); - } - - uint256 totalReservesNew; - uint256 actualAddAmount; - - if (accrualBlockNumber != getBlockNumber()) { - return ( - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.ADD_RESERVES_FRESH_CHECK - ) - ); - } - - actualAddAmount = doTransferIn(msg.sender, addAmount); - - totalReservesNew = totalReserves + actualAddAmount; - - require(totalReservesNew >= totalReserves, "CT22"); - - totalReserves = totalReservesNew; - - emit ReservesAdded(msg.sender, actualAddAmount, totalReservesNew); - - return (uint256(Error.NO_ERROR)); - } - - function _addSubsidyInternal(uint256 addAmount) - internal - nonReentrant - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - // accrueInterest emits logs on errors, but on top of that we want to log the fact that an attempted reduce reserves failed. - return fail(Error(error), FailureInfo.ADD_SUBSIDY_FUND_FAILED); - } - - uint256 subsidyFundNew; - uint256 actualAddAmount; - - if (accrualBlockNumber != getBlockNumber()) { - return ( - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.ADD_SUBSIDY_FUND_FRESH_CHECK - ) - ); - } - - actualAddAmount = doTransferIn(msg.sender, addAmount); - - subsidyFundNew = subsidyFund + actualAddAmount; - - require(subsidyFundNew >= subsidyFund, "CT22"); - - subsidyFund = subsidyFundNew; - - emit SubsidyAdded(msg.sender, actualAddAmount, subsidyFundNew); - - /* Return (NO_ERROR, actualAddAmount) */ - return (uint256(Error.NO_ERROR)); - } - - /** - * @notice Accrues interest and reduces reserves by transferring to admin - * @param reduceAmount Amount of reduction to reserves - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _reduceReserves(uint256 reduceAmount) - external - override - nonReentrant - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return - fail( - Error(error), - FailureInfo.REDUCE_RESERVES_ACCRUE_INTEREST_FAILED - ); - } - return _reduceReservesFresh(reduceAmount); - } - - /** - * @notice Reduces reserves by transferring to admin - * @dev Requires fresh interest accrual - * @param reduceAmount Amount of reduction to reserves - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _reduceReservesFresh(uint256 reduceAmount) - internal - returns (uint256) - { - uint256 totalReservesNew; - - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.REDUCE_RESERVES_ADMIN_CHECK - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.REDUCE_RESERVES_FRESH_CHECK - ); - } - - if (getCashPrior() < reduceAmount) { - return - fail( - Error.TOKEN_INSUFFICIENT_CASH, - FailureInfo.REDUCE_RESERVES_CASH_NOT_AVAILABLE - ); - } - - if (reduceAmount > totalReserves) { - return - fail(Error.BAD_INPUT, FailureInfo.REDUCE_RESERVES_VALIDATION); - } - - totalReservesNew = totalReserves - reduceAmount; - require(totalReservesNew <= totalReserves, "CT23"); - - totalReserves = totalReservesNew; - - doTransferOut(admin, reduceAmount); - - emit ReservesReduced(admin, reduceAmount, totalReservesNew); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice accrues interest and updates the interest rate model using _setInterestRateModelFresh - * @dev Admin function to accrue interest and update the interest rate model - * @param newInterestRateModel the new interest rate model to use - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setInterestRateModel(InterestRateModel newInterestRateModel) - public - override - returns (uint256) - { - uint256 error = accrueInterest(); - if (error != uint256(Error.NO_ERROR)) { - return - fail( - Error(error), - FailureInfo.SET_INTEREST_RATE_MODEL_ACCRUE_INTEREST_FAILED - ); - } - return _setInterestRateModelFresh(newInterestRateModel); - } - - /** - * @notice updates the interest rate model (*requires fresh interest accrual) - * @dev Admin function to update the interest rate model - * @param newInterestRateModel the new interest rate model to use - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setInterestRateModelFresh(InterestRateModel newInterestRateModel) - internal - returns (uint256) - { - InterestRateModel oldInterestRateModel; - - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_INTEREST_RATE_MODEL_OWNER_CHECK - ); - } - - if (accrualBlockNumber != getBlockNumber()) { - return - fail( - Error.MARKET_NOT_FRESH, - FailureInfo.SET_INTEREST_RATE_MODEL_FRESH_CHECK - ); - } - - oldInterestRateModel = interestRateModel; - - require(newInterestRateModel.isInterestRateModel(), "CT21"); - - interestRateModel = newInterestRateModel; - - emit NewMarketInterestRateModel( - oldInterestRateModel, - newInterestRateModel - ); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Gets balance of this contract in terms of the underlying - * @dev This excludes the value of the current message, if any - * @return The quantity of underlying owned by this contract - */ - function getCashPrior() internal view virtual returns (uint256); - - /** - * @dev Performs a transfer in, reverting upon failure. Returns the amount actually transferred to the protocol, in case of a fee. - * This may revert due to insufficient balance or insufficient allowance. - */ - function doTransferIn(address from, uint256 amount) - internal - virtual - returns (uint256); - - /** - * @dev Performs a transfer out, ideally returning an explanatory error code upon failure tather than reverting. - * If caller has not called checked protocol's balance, may revert due to insufficient cash held in the contract. - * If caller has checked protocol's balance, and verified it is >= amount, this should not revert in normal conditions. - */ - function doTransferOut(address payable to, uint256 amount) internal virtual; - - /** - * @dev Prevents a contract from calling itself, directly or indirectly. - */ - modifier nonReentrant() { - require(_notEntered, "re-entered"); - _notEntered = false; - _; - _notEntered = true; - } -} - - -// Dependency file: contracts/PriceOracle.sol - -// pragma solidity 0.8.6; - -// import "contracts/CToken.sol"; - -abstract contract PriceOracle { - /// @notice Indicator that this is a PriceOracle contract (for inspection) - bool public constant isPriceOracle = true; - - /** - * @notice Get the underlying price of a cToken asset - * @param cToken The cToken to get the underlying price of - * @return The underlying asset price mantissa (scaled by 1e18). - * Zero means the price is unavailable. - */ - function getUnderlyingPrice(CToken cToken) - external - view - virtual - returns (uint256); -} - - -// Dependency file: contracts/ComptrollerStorage.sol - -// pragma solidity 0.8.6; - -// import "contracts/CToken.sol"; -// import "contracts/PriceOracle.sol"; - -contract UnitrollerAdminStorage { - /** - * @notice Administrator for this contract - */ - address public admin; - - /** - * @notice Pending administrator for this contract - */ - address public pendingAdmin; - - /** - * @notice Active brains of Unitroller - */ - address public comptrollerImplementation; - - /** - * @notice Pending brains of Unitroller - */ - address public pendingComptrollerImplementation; -} - -contract ComptrollerV1Storage is UnitrollerAdminStorage { - - /** - * @notice Oracle which gives the price of any given asset - */ - PriceOracle public oracle; - - /** - * @notice Multiplier used to calculate the maximum repayAmount when liquidating a borrow - */ - uint public closeFactorMantissa; - - /** - * @notice Multiplier representing the discount on collateral that a liquidator receives - */ - uint public liquidationIncentiveMantissa; - - /** - * @notice Max number of assets a single account can participate in (borrow or use as collateral) - */ - uint public maxAssets; - - /** - * @notice Per-account mapping of "assets you are in", capped by maxAssets - */ - mapping(address => CToken[]) public accountAssets; - -} - -contract ComptrollerV2Storage is ComptrollerV1Storage { - struct Market { - /// @notice Whether or not this market is listed - bool isListed; - - /** - * @notice Multiplier representing the most one can borrow against their collateral in this market. - * For instance, 0.9 to allow borrowing 90% of collateral value. - * Must be between 0 and 1, and stored as a mantissa. - */ - uint collateralFactorMantissa; - - /// @notice Per-market mapping of "accounts in this asset" - mapping(address => bool) accountMembership; - - /// @notice Whether or not this market receives COMP - bool isComped; - } - - /** - * @notice Official mapping of cTokens -> Market metadata - * @dev Used e.g. to determine if a market is supported - */ - mapping(address => Market) public markets; - - - /** - * @notice The Pause Guardian can pause certain actions as a safety mechanism. - * Actions which allow users to remove their own assets cannot be paused. - * Liquidation / seizing / transfer can only be paused globally, not by market. - */ - address public pauseGuardian; - bool public _mintGuardianPaused; - bool public _borrowGuardianPaused; - bool public transferGuardianPaused; - bool public seizeGuardianPaused; - mapping(address => bool) public mintGuardianPaused; - mapping(address => bool) public borrowGuardianPaused; -} - -contract ComptrollerV3Storage is ComptrollerV2Storage { - struct CompMarketState { - /// @notice The market's last updated compBorrowIndex or compSupplyIndex - uint224 index; - - /// @notice The block number the index was last updated at - uint32 block; - } - - /// @notice A list of all markets - CToken[] public allMarkets; - - /// @notice The rate at which the flywheel distributes COMP, per block - uint public compRate; - - /// @notice The portion of compRate that each market currently receives - mapping(address => uint) public compSpeeds; - - /// @notice The COMP market supply state for each market - mapping(address => CompMarketState) public compSupplyState; - - /// @notice The COMP market borrow state for each market - mapping(address => CompMarketState) public compBorrowState; - - /// @notice The COMP borrow index for each market for each supplier as of the last time they accrued COMP - mapping(address => mapping(address => uint)) public compSupplierIndex; - - /// @notice The COMP borrow index for each market for each borrower as of the last time they accrued COMP - mapping(address => mapping(address => uint)) public compBorrowerIndex; - - /// @notice The COMP accrued but not yet transferred to each user - mapping(address => uint) public compAccrued; -} - -contract ComptrollerV4Storage is ComptrollerV3Storage { - // @notice The borrowCapGuardian can set borrowCaps to any number for any market. Lowering the borrow cap could disable borrowing on the given market. - address public borrowCapGuardian; - - // @notice Borrow caps enforced by borrowAllowed for each cToken address. Defaults to zero which corresponds to unlimited borrowing. - mapping(address => uint) public borrowCaps; - - // @notice address of the TROP token - address public tropAddress; -} - -contract ComptrollerV5Storage is ComptrollerV4Storage { - /// @notice The portion of COMP that each contributor receives per block - mapping(address => uint) public compContributorSpeeds; - - /// @notice Last block at which a contributor's COMP rewards have been allocated - mapping(address => uint) public lastContributorBlock; -} - - -// Root file: contracts/Unitroller.sol - -pragma solidity 0.8.6; - -// import "contracts/ErrorReporter.sol"; -// import "contracts/ComptrollerStorage.sol"; - -/** - * @title ComptrollerCore - * @dev Storage for the comptroller is at this address, while execution is delegated to the `comptrollerImplementation`. - * CTokens should reference this contract as their comptroller. - */ -contract Unitroller is UnitrollerAdminStorage, ComptrollerErrorReporter { - /** - * @notice Emitted when pendingComptrollerImplementation is changed - */ - event NewPendingImplementation( - address oldPendingImplementation, - address newPendingImplementation - ); - - /** - * @notice Emitted when pendingComptrollerImplementation is accepted, which means comptroller implementation is updated - */ - event NewImplementation( - address oldImplementation, - address newImplementation - ); - - /** - * @notice Emitted when pendingAdmin is changed - */ - event NewPendingAdmin(address oldPendingAdmin, address newPendingAdmin); - - /** - * @notice Emitted when pendingAdmin is accepted, which means admin is updated - */ - event NewAdmin(address oldAdmin, address newAdmin); - - constructor() { - // Set admin to caller - admin = msg.sender; - } - - /*** Admin Functions ***/ - function _setPendingImplementation(address newPendingImplementation) - public - returns (uint256) - { - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_PENDING_IMPLEMENTATION_OWNER_CHECK - ); - } - - address oldPendingImplementation = pendingComptrollerImplementation; - - pendingComptrollerImplementation = newPendingImplementation; - - emit NewPendingImplementation( - oldPendingImplementation, - pendingComptrollerImplementation - ); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Accepts new implementation of comptroller. msg.sender must be pendingImplementation - * @dev Admin function for new implementation to accept it's role as implementation - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _acceptImplementation() public returns (uint256) { - // Check caller is pendingImplementation and pendingImplementation ≠ address(0) - if ( - msg.sender != pendingComptrollerImplementation || - pendingComptrollerImplementation == address(0) - ) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.ACCEPT_PENDING_IMPLEMENTATION_ADDRESS_CHECK - ); - } - - // Save current values for inclusion in log - address oldImplementation = comptrollerImplementation; - address oldPendingImplementation = pendingComptrollerImplementation; - - comptrollerImplementation = pendingComptrollerImplementation; - - pendingComptrollerImplementation = address(0); - - emit NewImplementation(oldImplementation, comptrollerImplementation); - emit NewPendingImplementation( - oldPendingImplementation, - pendingComptrollerImplementation - ); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Begins transfer of admin rights. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer. - * @dev Admin function to begin change of admin. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer. - * @param newPendingAdmin New pending admin. - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _setPendingAdmin(address newPendingAdmin) - public - returns (uint256) - { - // Check caller = admin - if (msg.sender != admin) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.SET_PENDING_ADMIN_OWNER_CHECK - ); - } - - // Save current value, if any, for inclusion in log - address oldPendingAdmin = pendingAdmin; - - // Store pendingAdmin with value newPendingAdmin - pendingAdmin = newPendingAdmin; - - // Emit NewPendingAdmin(oldPendingAdmin, newPendingAdmin) - emit NewPendingAdmin(oldPendingAdmin, newPendingAdmin); - - return uint256(Error.NO_ERROR); - } - - /** - * @notice Accepts transfer of admin rights. msg.sender must be pendingAdmin - * @dev Admin function for pending admin to accept role and update admin - * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) - */ - function _acceptAdmin() public returns (uint256) { - // Check caller is pendingAdmin and pendingAdmin ≠ address(0) - if (msg.sender != pendingAdmin || msg.sender == address(0)) { - return - fail( - Error.UNAUTHORIZED, - FailureInfo.ACCEPT_ADMIN_PENDING_ADMIN_CHECK - ); - } - - // Save current values for inclusion in log - address oldAdmin = admin; - address oldPendingAdmin = pendingAdmin; - - // Store admin with value pendingAdmin - admin = pendingAdmin; - - // Clear the pending value - pendingAdmin = address(0); - - emit NewAdmin(oldAdmin, admin); - emit NewPendingAdmin(oldPendingAdmin, pendingAdmin); - - return uint256(Error.NO_ERROR); - } - - /** - * @dev Delegates execution to an implementation contract. - * It returns to the external caller whatever the implementation returns - * or forwards reverts. - */ - function internalFallback() public payable { - // delegate all other functions to current implementation - (bool success, ) = comptrollerImplementation.delegatecall(msg.data); - - assembly { - let free_mem_ptr := mload(0x40) - returndatacopy(free_mem_ptr, 0, returndatasize()) - - switch success - case 0 { - revert(free_mem_ptr, returndatasize()) - } - default { - return(free_mem_ptr, returndatasize()) - } - } - } - - fallback() external payable { - internalFallback(); - } - - receive() external payable { - internalFallback(); - } -} diff --git a/flatten/WhitePaperInterestRateModel.sol b/flatten/WhitePaperInterestRateModel.sol deleted file mode 100644 index 3246c49..0000000 --- a/flatten/WhitePaperInterestRateModel.sol +++ /dev/null @@ -1,863 +0,0 @@ -// Dependency file: contracts/CarefulMath.sol - -// SPDX-License-Identifier: UNLICENSED -// pragma solidity 0.8.6; - -/** - * @title Careful Math - * @author tropykus - * @notice Derived from OpenZeppelin's SafeMath library - * https://github.com/OpenZeppelin/openzeppelin-solidity/blob/master/contracts/math/SafeMath.sol - */ -contract CarefulMath { - - /** - * @dev Possible error codes that we can return - */ - enum MathError { - NO_ERROR, - DIVISION_BY_ZERO, - INTEGER_OVERFLOW, - INTEGER_UNDERFLOW - } - - /** - * @dev Multiplies two numbers, returns an error on overflow. - */ - function mulUInt(uint a, uint b) internal pure returns (MathError, uint) { - if (a == 0) { - return (MathError.NO_ERROR, 0); - } - - uint c = a * b; - - if (c / a != b) { - return (MathError.INTEGER_OVERFLOW, 0); - } else { - return (MathError.NO_ERROR, c); - } - } - - /** - * @dev Integer division of two numbers, truncating the quotient. - */ - function divUInt(uint a, uint b) internal pure returns (MathError, uint) { - if (b == 0) { - return (MathError.DIVISION_BY_ZERO, 0); - } - - return (MathError.NO_ERROR, a / b); - } - - /** - * @dev Subtracts two numbers, returns an error on overflow (i.e. if subtrahend is greater than minuend). - */ - function subUInt(uint a, uint b) internal pure returns (MathError, uint) { - if (b <= a) { - return (MathError.NO_ERROR, a - b); - } else { - return (MathError.INTEGER_UNDERFLOW, 0); - } - } - - /** - * @dev Adds two numbers, returns an error on overflow. - */ - function addUInt(uint a, uint b) internal pure returns (MathError, uint) { - uint c = a + b; - - if (c >= a) { - return (MathError.NO_ERROR, c); - } else { - return (MathError.INTEGER_OVERFLOW, 0); - } - } - - /** - * @dev add a and b and then subtract c - */ - function addThenSubUInt(uint a, uint b, uint c) internal pure returns (MathError, uint) { - (MathError err0, uint sum) = addUInt(a, b); - - if (err0 != MathError.NO_ERROR) { - return (err0, 0); - } - - return subUInt(sum, c); - } -} - - -// Dependency file: contracts/ExponentialNoError.sol - -// pragma solidity 0.8.6; - -/** - * @title Exponential module for storing fixed-precision decimals - * @author tropykus - * @notice Exp is a struct which stores decimals with a fixed precision of 18 decimal places. - * Thus, if we wanted to store the 5.1, mantissa would store 5.1e18. That is: - * `Exp({mantissa: 5100000000000000000})`. - */ -contract ExponentialNoError { - uint constant expScale = 1e18; - uint constant doubleScale = 1e36; - uint constant halfExpScale = expScale/2; - uint constant mantissaOne = expScale; - - struct Exp { - uint mantissa; - } - - struct Double { - uint mantissa; - } - - /** - * @dev Truncates the given exp to a whole number value. - * For example, truncate(Exp{mantissa: 15 * expScale}) = 15 - */ - function truncate(Exp memory exp) pure internal returns (uint) { - // Note: We are not using careful math here as we're performing a division that cannot fail - return exp.mantissa / expScale; - } - - /** - * @dev Multiply an Exp by a scalar, then truncate to return an unsigned integer. - */ - function mul_ScalarTruncate(Exp memory a, uint scalar) pure internal returns (uint) { - Exp memory product = mul_(a, scalar); - return truncate(product); - } - - /** - * @dev Multiply an Exp by a scalar, truncate, then add an to an unsigned integer, returning an unsigned integer. - */ - function mul_ScalarTruncateAddUInt(Exp memory a, uint scalar, uint addend) pure internal returns (uint) { - Exp memory product = mul_(a, scalar); - return add_(truncate(product), addend); - } - - /** - * @dev Checks if first Exp is less than second Exp. - */ - function lessThanExp(Exp memory left, Exp memory right) pure internal returns (bool) { - return left.mantissa < right.mantissa; - } - - /** - * @dev Checks if left Exp <= right Exp. - */ - function lessThanOrEqualExp(Exp memory left, Exp memory right) pure internal returns (bool) { - return left.mantissa <= right.mantissa; - } - - /** - * @dev Checks if left Exp > right Exp. - */ - function greaterThanExp(Exp memory left, Exp memory right) pure internal returns (bool) { - return left.mantissa > right.mantissa; - } - - /** - * @dev returns true if Exp is exactly zero - */ - function isZeroExp(Exp memory value) pure internal returns (bool) { - return value.mantissa == 0; - } - - function safe224(uint n, string memory errorMessage) pure internal returns (uint224) { - require(n < 2**224, errorMessage); - return uint224(n); - } - - function safe32(uint n, string memory errorMessage) pure internal returns (uint32) { - require(n < 2**32, errorMessage); - return uint32(n); - } - - function add_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { - return Exp({mantissa: add_(a.mantissa, b.mantissa)}); - } - - function add_(Double memory a, Double memory b) pure internal returns (Double memory) { - return Double({mantissa: add_(a.mantissa, b.mantissa)}); - } - - function add_(uint a, uint b) pure internal returns (uint) { - return add_(a, b, "addition overflow"); - } - - function add_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { - uint c = a + b; - require(c >= a, errorMessage); - return c; - } - - function sub_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { - return Exp({mantissa: sub_(a.mantissa, b.mantissa)}); - } - - function sub_(Double memory a, Double memory b) pure internal returns (Double memory) { - return Double({mantissa: sub_(a.mantissa, b.mantissa)}); - } - - function sub_(uint a, uint b) pure internal returns (uint) { - return sub_(a, b, "subtraction underflow"); - } - - function sub_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { - require(b <= a, errorMessage); - return a - b; - } - - function mul_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { - return Exp({mantissa: mul_(a.mantissa, b.mantissa) / expScale}); - } - - function mul_(Exp memory a, uint b) pure internal returns (Exp memory) { - return Exp({mantissa: mul_(a.mantissa, b)}); - } - - function mul_(uint a, Exp memory b) pure internal returns (uint) { - return mul_(a, b.mantissa) / expScale; - } - - function mul_(Double memory a, Double memory b) pure internal returns (Double memory) { - return Double({mantissa: mul_(a.mantissa, b.mantissa) / doubleScale}); - } - - function mul_(Double memory a, uint b) pure internal returns (Double memory) { - return Double({mantissa: mul_(a.mantissa, b)}); - } - - function mul_(uint a, Double memory b) pure internal returns (uint) { - return mul_(a, b.mantissa) / doubleScale; - } - - function mul_(uint a, uint b) pure internal returns (uint) { - return mul_(a, b, "multiplication overflow"); - } - - function mul_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { - if (a == 0 || b == 0) { - return 0; - } - uint c = a * b; - require(c / a == b, errorMessage); - return c; - } - - function div_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { - return Exp({mantissa: div_(mul_(a.mantissa, expScale), b.mantissa)}); - } - - function div_(Exp memory a, uint b) pure internal returns (Exp memory) { - return Exp({mantissa: div_(a.mantissa, b)}); - } - - function div_(uint a, Exp memory b) pure internal returns (uint) { - return div_(mul_(a, expScale), b.mantissa); - } - - function div_(Double memory a, Double memory b) pure internal returns (Double memory) { - return Double({mantissa: div_(mul_(a.mantissa, doubleScale), b.mantissa)}); - } - - function div_(Double memory a, uint b) pure internal returns (Double memory) { - return Double({mantissa: div_(a.mantissa, b)}); - } - - function div_(uint a, Double memory b) pure internal returns (uint) { - return div_(mul_(a, doubleScale), b.mantissa); - } - - function div_(uint a, uint b) pure internal returns (uint) { - return div_(a, b, "divide by zero"); - } - - function div_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { - require(b > 0, errorMessage); - return a / b; - } - - function fraction(uint a, uint b) pure internal returns (Double memory) { - return Double({mantissa: div_(mul_(a, doubleScale), b)}); - } -} - - -// Dependency file: contracts/Exponential.sol - -// pragma solidity 0.8.6; - -// import "contracts/CarefulMath.sol"; -// import "contracts/ExponentialNoError.sol"; - -/** - * @title Exponential module for storing fixed-precision decimals - * @author tropykus - * @dev Legacy contract for compatibility reasons with existing contracts that still use MathError - * @notice Exp is a struct which stores decimals with a fixed precision of 18 decimal places. - * Thus, if we wanted to store the 5.1, mantissa would store 5.1e18. That is: - * `Exp({mantissa: 5100000000000000000})`. - */ -contract Exponential is CarefulMath, ExponentialNoError { - /** - * @dev Creates an exponential from numerator and denominator values. - * Note: Returns an error if (`num` * 10e18) > MAX_INT, - * or if `denom` is zero. - */ - function getExp(uint num, uint denom) internal pure returns (MathError, Exp memory) { - (MathError err0, uint scaledNumerator) = mulUInt(num, expScale); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - - (MathError err1, uint rational) = divUInt(scaledNumerator, denom); - if (err1 != MathError.NO_ERROR) { - return (err1, Exp({mantissa: 0})); - } - - return (MathError.NO_ERROR, Exp({mantissa: rational})); - } - - /** - * @dev Adds two exponentials, returning a new exponential. - */ - function addExp(Exp memory a, Exp memory b) internal pure returns (MathError, Exp memory) { - (MathError error, uint result) = addUInt(a.mantissa, b.mantissa); - - return (error, Exp({mantissa: result})); - } - - /** - * @dev Subtracts two exponentials, returning a new exponential. - */ - function subExp(Exp memory a, Exp memory b) internal pure returns (MathError, Exp memory) { - (MathError error, uint result) = subUInt(a.mantissa, b.mantissa); - - return (error, Exp({mantissa: result})); - } - - /** - * @dev Multiply an Exp by a scalar, returning a new Exp. - */ - function mulScalar(Exp memory a, uint scalar) internal pure returns (MathError, Exp memory) { - (MathError err0, uint scaledMantissa) = mulUInt(a.mantissa, scalar); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - - return (MathError.NO_ERROR, Exp({mantissa: scaledMantissa})); - } - - /** - * @dev Multiply an Exp by a scalar, then truncate to return an unsigned integer. - */ - function mulScalarTruncate(Exp memory a, uint scalar) internal pure returns (MathError, uint) { - (MathError err, Exp memory product) = mulScalar(a, scalar); - if (err != MathError.NO_ERROR) { - return (err, 0); - } - - return (MathError.NO_ERROR, truncate(product)); - } - - /** - * @dev Multiply an Exp by a scalar, truncate, then add an to an unsigned integer, returning an unsigned integer. - */ - function mulScalarTruncateAddUInt(Exp memory a, uint scalar, uint addend) internal pure returns (MathError, uint) { - (MathError err, Exp memory product) = mulScalar(a, scalar); - if (err != MathError.NO_ERROR) { - return (err, 0); - } - - return addUInt(truncate(product), addend); - } - - /** - * @dev Divide an Exp by a scalar, returning a new Exp. - */ - function divScalar(Exp memory a, uint scalar) internal pure returns (MathError, Exp memory) { - (MathError err0, uint descaledMantissa) = divUInt(a.mantissa, scalar); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - - return (MathError.NO_ERROR, Exp({mantissa: descaledMantissa})); - } - - /** - * @dev Divide a scalar by an Exp, returning a new Exp. - */ - function divScalarByExp(uint scalar, Exp memory divisor) internal pure returns (MathError, Exp memory) { - /* - We are doing this as: - getExp(mulUInt(expScale, scalar), divisor.mantissa) - - How it works: - Exp = a / b; - Scalar = s; - `s / (a / b)` = `b * s / a` and since for an Exp `a = mantissa, b = expScale` - */ - (MathError err0, uint numerator) = mulUInt(expScale, scalar); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - return getExp(numerator, divisor.mantissa); - } - - /** - * @dev Divide a scalar by an Exp, then truncate to return an unsigned integer. - */ - function divScalarByExpTruncate(uint scalar, Exp memory divisor) internal pure returns (MathError, uint) { - (MathError err, Exp memory fraction) = divScalarByExp(scalar, divisor); - if (err != MathError.NO_ERROR) { - return (err, 0); - } - - return (MathError.NO_ERROR, truncate(fraction)); - } - - /** - * @dev Multiplies two exponentials, returning a new exponential. - */ - function mulExp(Exp memory a, Exp memory b) internal pure returns (MathError, Exp memory) { - - (MathError err0, uint doubleScaledProduct) = mulUInt(a.mantissa, b.mantissa); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - - // We add half the scale before dividing so that we get rounding instead of truncation. - // See "Listing 6" and text above it at https://accu.org/index.php/journals/1717 - // Without this change, a result like 6.6...e-19 will be truncated to 0 instead of being rounded to 1e-18. - (MathError err1, uint doubleScaledProductWithHalfScale) = addUInt(halfExpScale, doubleScaledProduct); - if (err1 != MathError.NO_ERROR) { - return (err1, Exp({mantissa: 0})); - } - - (MathError err2, uint product) = divUInt(doubleScaledProductWithHalfScale, expScale); - // The only error `div` can return is MathError.DIVISION_BY_ZERO but we control `expScale` and it is not zero. - assert(err2 == MathError.NO_ERROR); - - return (MathError.NO_ERROR, Exp({mantissa: product})); - } - - /** - * @dev Multiplies two exponentials given their mantissas, returning a new exponential. - */ - function mulExp(uint a, uint b) internal pure returns (MathError, Exp memory) { - return mulExp(Exp({mantissa: a}), Exp({mantissa: b})); - } - - /** - * @dev Multiplies three exponentials, returning a new exponential. - */ - function mulExp3(Exp memory a, Exp memory b, Exp memory c) internal pure returns (MathError, Exp memory) { - (MathError err, Exp memory ab) = mulExp(a, b); - if (err != MathError.NO_ERROR) { - return (err, ab); - } - return mulExp(ab, c); - } - - /** - * @dev Divides two exponentials, returning a new exponential. - * (a/scale) / (b/scale) = (a/scale) * (scale/b) = a/b, - * which we can scale as an Exp by calling getExp(a.mantissa, b.mantissa) - */ - function divExp(Exp memory a, Exp memory b) internal pure returns (MathError, Exp memory) { - return getExp(a.mantissa, b.mantissa); - } -} - - -// Dependency file: contracts/SafeMath.sol - -// pragma solidity 0.8.6; - -// From https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/math/Math.sol -// Subject to the MIT license. - -/** - * @dev Wrappers over Solidity's arithmetic operations with added overflow - * checks. - * - * Arithmetic operations in Solidity wrap on overflow. This can easily result - * in bugs, because programmers usually assume that an overflow raises an - * error, which is the standard behavior in high level programming languages. - * `SafeMath` restores this intuition by reverting the transaction when an - * operation overflows. - * - * Using this library instead of the unchecked operations eliminates an entire - * class of bugs, so it's recommended to use it always. - */ -library SafeMath { - /** - * @dev Returns the addition of two unsigned integers, reverting on overflow. - * - * Counterpart to Solidity's `+` operator. - * - * Requirements: - * - Addition cannot overflow. - */ - function add(uint256 a, uint256 b) internal pure returns (uint256) { - uint256 c = a + b; - require(c >= a, "SafeMath: addition overflow"); - - return c; - } - - /** - * @dev Returns the addition of two unsigned integers, reverting with custom message on overflow. - * - * Counterpart to Solidity's `+` operator. - * - * Requirements: - * - Addition cannot overflow. - */ - function add(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - uint256 c = a + b; - require(c >= a, errorMessage); - - return c; - } - - /** - * @dev Returns the subtraction of two unsigned integers, reverting on underflow (when the result is negative). - * - * Counterpart to Solidity's `-` operator. - * - * Requirements: - * - Subtraction cannot underflow. - */ - function sub(uint256 a, uint256 b) internal pure returns (uint256) { - return sub(a, b, "SafeMath: subtraction underflow"); - } - - /** - * @dev Returns the subtraction of two unsigned integers, reverting with custom message on underflow (when the result is negative). - * - * Counterpart to Solidity's `-` operator. - * - * Requirements: - * - Subtraction cannot underflow. - */ - function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - require(b <= a, errorMessage); - uint256 c = a - b; - - return c; - } - - /** - * @dev Returns the multiplication of two unsigned integers, reverting on overflow. - * - * Counterpart to Solidity's `*` operator. - * - * Requirements: - * - Multiplication cannot overflow. - */ - function mul(uint256 a, uint256 b) internal pure returns (uint256) { - // Gas optimization: this is cheaper than requiring 'a' not being zero, but the - // benefit is lost if 'b' is also tested. - // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 - if (a == 0) { - return 0; - } - - uint256 c = a * b; - require(c / a == b, "SafeMath: multiplication overflow"); - - return c; - } - - /** - * @dev Returns the multiplication of two unsigned integers, reverting on overflow. - * - * Counterpart to Solidity's `*` operator. - * - * Requirements: - * - Multiplication cannot overflow. - */ - function mul(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - // Gas optimization: this is cheaper than requiring 'a' not being zero, but the - // benefit is lost if 'b' is also tested. - // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 - if (a == 0) { - return 0; - } - - uint256 c = a * b; - require(c / a == b, errorMessage); - - return c; - } - - /** - * @dev Returns the integer division of two unsigned integers. - * Reverts on division by zero. The result is rounded towards zero. - * - * Counterpart to Solidity's `/` operator. Note: this function uses a - * `revert` opcode (which leaves remaining gas untouched) while Solidity - * uses an invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function div(uint256 a, uint256 b) internal pure returns (uint256) { - return div(a, b, "SafeMath: division by zero"); - } - - /** - * @dev Returns the integer division of two unsigned integers. - * Reverts with custom message on division by zero. The result is rounded towards zero. - * - * Counterpart to Solidity's `/` operator. Note: this function uses a - * `revert` opcode (which leaves remaining gas untouched) while Solidity - * uses an invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - // Solidity only automatically asserts when dividing by 0 - require(b > 0, errorMessage); - uint256 c = a / b; - // assert(a == b * c + a % b); // There is no case in which this doesn't hold - - return c; - } - - /** - * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), - * Reverts when dividing by zero. - * - * Counterpart to Solidity's `%` operator. This function uses a `revert` - * opcode (which leaves remaining gas untouched) while Solidity uses an - * invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function mod(uint256 a, uint256 b) internal pure returns (uint256) { - return mod(a, b, "SafeMath: modulo by zero"); - } - - /** - * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), - * Reverts with custom message when dividing by zero. - * - * Counterpart to Solidity's `%` operator. This function uses a `revert` - * opcode (which leaves remaining gas untouched) while Solidity uses an - * invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - require(b != 0, errorMessage); - return a % b; - } -} - - -// Dependency file: contracts/InterestRateModel.sol - -// pragma solidity 0.8.6; - -// import "contracts/Exponential.sol"; -// import "contracts/SafeMath.sol"; - -/** - * @title tropykus InterestRateModel Interface - * @author tropykus - */ -abstract contract InterestRateModel is Exponential { - using SafeMath for uint256; - - /// @notice Indicator that this is an InterestRateModel contract (for inspection) - bool public constant isInterestRateModel = true; - bool public isTropykusInterestRateModel; - - /** - * @notice The approximate number of blocks per year that is assumed by the interest rate model - */ - uint256 public constant blocksPerYear = 1051200; - - /** - * @notice Calculates the utilization rate of the market: `borrows / (cash + borrows - reserves)` - * @param cash The amount of cash in the market - * @param borrows The amount of borrows in the market - * @param reserves The amount of reserves in the market (currently unused) - * @return The utilization rate as a mantissa between [0, 1e18] - */ - function utilizationRate( - uint256 cash, - uint256 borrows, - uint256 reserves - ) public pure virtual returns (uint256) { - // Utilization rate is 0 when there are no borrows - if (borrows == 0) { - return 0; - } - - return borrows.mul(1e18).div(cash.add(borrows).sub(reserves)); - } - - /** - * @notice Calculates the current borrow interest rate per block - * @param cash The total amount of cash the market has - * @param borrows The total amount of borrows the market has outstanding - * @param reserves The total amnount of reserves the market has - * @return The borrow rate per block (as a percentage, and scaled by 1e18) - */ - function getBorrowRate( - uint256 cash, - uint256 borrows, - uint256 reserves - ) external view virtual returns (uint256); - - /** - * @notice Calculates the current supply interest rate per block - * @param cash The total amount of cash the market has - * @param borrows The total amount of borrows the market has outstanding - * @param reserves The total amnount of reserves the market has - * @param reserveFactorMantissa The current reserve factor the market has - * @return The supply rate per block (as a percentage, and scaled by 1e18) - */ - function getSupplyRate( - uint256 cash, - uint256 borrows, - uint256 reserves, - uint256 reserveFactorMantissa - ) external view virtual returns (uint256); - - function getExchangeRate( - uint256 _totalCash, - uint256 _totalBorrows, - uint256 _totalReserves, - uint256 _totalSupply - ) public pure returns (MathError, uint256) { - /* - * exchangeRate = (totalCash + totalBorrows - totalReserves) / totalSupply - */ - Exp memory exchangeRate; - MathError mathErr; - uint256 cashPlusBorrowsMinusReserves; - (mathErr, cashPlusBorrowsMinusReserves) = addThenSubUInt( - _totalCash, - _totalBorrows, - _totalReserves - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - (mathErr, exchangeRate) = getExp( - cashPlusBorrowsMinusReserves, - _totalSupply - ); - if (mathErr != MathError.NO_ERROR) { - return (mathErr, 0); - } - - return (MathError.NO_ERROR, exchangeRate.mantissa); - } - - function isAboveOptimal( - uint256 cash, - uint256 borrows, - uint256 reserves - ) public view virtual returns (bool) { - cash; - borrows; - reserves; - return false; - } -} - - -// Root file: contracts/WhitePaperInterestRateModel.sol - -pragma solidity 0.8.6; - -// import "contracts/InterestRateModel.sol"; -// import "contracts/SafeMath.sol"; - -/** - * @title tropykus WhitePaperInterestRateModel Contract - * @author tropykus - * @notice The parameterized model described in section 2.4 of the original tropykus Protocol whitepaper - */ -contract WhitePaperInterestRateModel is InterestRateModel { - using SafeMath for uint256; - - event NewInterestParams( - uint256 baseRatePerBlock, - uint256 multiplierPerBlock - ); - - /** - * @notice The multiplier of utilization rate that gives the slope of the interest rate - */ - uint256 public multiplierPerBlock; - - /** - * @notice The base interest rate which is the y-intercept when utilization rate is 0 - */ - uint256 public baseRatePerBlock; - - /** - * @notice Construct an interest rate model - * @param baseRatePerYear The approximate target base APR, as a mantissa (scaled by 1e18) - * @param multiplierPerYear The rate of increase in interest rate wrt utilization (scaled by 1e18) - */ - constructor(uint256 baseRatePerYear, uint256 multiplierPerYear) { - baseRatePerBlock = baseRatePerYear.div(blocksPerYear); - multiplierPerBlock = multiplierPerYear.div(blocksPerYear); - isTropykusInterestRateModel = false; - - emit NewInterestParams(baseRatePerBlock, multiplierPerBlock); - } - - /** - * @notice Calculates the current borrow rate per block, with the error code expected by the market - * @param cash The amount of cash in the market - * @param borrows The amount of borrows in the market - * @param reserves The amount of reserves in the market - * @return The borrow rate percentage per block as a mantissa (scaled by 1e18) - */ - function getBorrowRate( - uint256 cash, - uint256 borrows, - uint256 reserves - ) public view override returns (uint256) { - uint256 ur = utilizationRate(cash, borrows, reserves); - return ur.mul(multiplierPerBlock).div(1e18).add(baseRatePerBlock); - } - - /** - * @notice Calculates the current supply rate per block - * @param cash The amount of cash in the market - * @param borrows The amount of borrows in the market - * @param reserves The amount of reserves in the market - * @param reserveFactorMantissa The current reserve factor for the market - * @return The supply rate percentage per block as a mantissa (scaled by 1e18) - */ - function getSupplyRate( - uint256 cash, - uint256 borrows, - uint256 reserves, - uint256 reserveFactorMantissa - ) public view override returns (uint256) { - uint256 oneMinusReserveFactor = uint256(1e18).sub( - reserveFactorMantissa - ); - uint256 borrowRate = getBorrowRate(cash, borrows, reserves); - uint256 rateToPool = borrowRate.mul(oneMinusReserveFactor).div(1e18); - return - utilizationRate(cash, borrows, reserves).mul(rateToPool).div(1e18); - } -} diff --git a/flatten/Whitelist.sol b/flatten/Whitelist.sol deleted file mode 100644 index c37eeb6..0000000 --- a/flatten/Whitelist.sol +++ /dev/null @@ -1,70 +0,0 @@ -// Dependency file: contracts/WhitelistInterface.sol - -// SPDX-License-Identifier: UNLICENSED -// pragma solidity 0.8.6; - -interface WhitelistInterface { - function setStatus(bool _newStatus) external; - function enabled() external view returns(bool); - - function addUsers(address[] memory _users) external; - function exist(address _user) external view returns(bool); - function getUsers() external view returns(address[] memory currentUsers); - function removeUser(address _user) external; -} - -// Root file: contracts/Whitelist.sol - -pragma solidity 0.8.6; - -// import "contracts/WhitelistInterface.sol"; - -contract Whitelist is WhitelistInterface { - bool public override enabled; - address owner; - mapping(address => bool) public override exist; - address[] users; - - modifier onlyOwner() { - require(msg.sender == owner); - _; - } - - constructor() { - owner = msg.sender; - enabled = true; - } - - function setStatus(bool _newStatus) external override onlyOwner { - enabled = _newStatus; - } - - function addUsers(address[] memory _users) external override onlyOwner { - for (uint256 i = 0; i < _users.length; i++) { - if (exist[_users[i]]) continue; - users.push(_users[i]); - exist[_users[i]] = true; - } - } - - function getUsers() - external - view - override - returns (address[] memory currentUsers) - { - currentUsers = users; - } - - function removeUser(address _user) external override onlyOwner { - if (exist[_user]) { - exist[_user] = false; - address[] memory oldUsers = users; - users = new address[](0); - for (uint256 i = 0; i < oldUsers.length; i++) { - if (oldUsers[i] == _user) continue; - users.push(oldUsers[i]); - } - } - } -} diff --git a/flatten/WhitelistInterface.sol b/flatten/WhitelistInterface.sol deleted file mode 100644 index 43434b8..0000000 --- a/flatten/WhitelistInterface.sol +++ /dev/null @@ -1,14 +0,0 @@ -// Root file: contracts/WhitelistInterface.sol - -// SPDX-License-Identifier: UNLICENSED -pragma solidity 0.8.6; - -interface WhitelistInterface { - function setStatus(bool _newStatus) external; - function enabled() external view returns(bool); - - function addUsers(address[] memory _users) external; - function exist(address _user) external view returns(bool); - function getUsers() external view returns(address[] memory currentUsers); - function removeUser(address _user) external; -} \ No newline at end of file diff --git a/instructions b/instructions index 1d5ccec..9ccac5f 100644 --- a/instructions +++ b/instructions @@ -11,7 +11,6 @@ load = async() => { csat = await ethers.getContractAt('CRBTC', cSAT, dep); priceOracleProxy = await ethers.getContractAt('PriceOracleProxy', PriceOracleProxy, dep); rbtcOracle = await ethers.getContractAt('MockPriceProviderMoC', RBTCOracle, dep); - whitelist = await ethers.getContractAt('Whitelist', Whitelist, dep); } load() \ No newline at end of file diff --git a/tests/repayBorrow/repay.js b/tests/repayBorrow/repay.js index 102e458..70f41f2 100644 --- a/tests/repayBorrow/repay.js +++ b/tests/repayBorrow/repay.js @@ -87,10 +87,6 @@ describe('Repay Borrow Test', async () => { // const comptrollerDeployed = await comptrollerContract.deploy(); // // console.log(`Comptroller = ${comptrollerDeployed.address}`); - // const Whitelist = await ethers.getContractFactory('Whitelist'); - // const whitelistDeployed = await Whitelist.deploy(); - // console.log(`Whitelist = '${whitelistDeployed.address}';`); - // console.log('\n~~~~~~~~~~~~~~~~~~~~~~~~ TOKENS ~~~~~~~~~~~~~~~~~~~~~~~~'); // const standardTokenContract = await ethers.getContractFactory('StandardToken'); // let rifToken = { @@ -177,11 +173,6 @@ describe('Repay Borrow Test', async () => { // console.log(`cRBTC = '${cRBTCdeployed.address}';`); // console.log(`cSAT = '${cSATdeployed.address}';`); - // await cRIFdeployed.addWhitelist(whitelistDeployed.address); - // await cDOCdeployed.addWhitelist(whitelistDeployed.address); - // await cUSDTdeployed.addWhitelist(whitelistDeployed.address); - // await cRBTCdeployed.addWhitelist(whitelistDeployed.address); - // await cSATdeployed.addWhitelist(whitelistDeployed.address); // // console.log('~~~~~~~~~~~~~~~~~~~~ /MARKETS cTOKENS ~~~~~~~~~~~~~~~~~~~~\n'); // const tropykusLensContract = await ethers.getContractFactory('TropykusLens');