├── .gitattributes ├── .gitignore ├── README.md ├── assets ├── CHAI │ ├── DAI │ │ ├── daiJoin.sol │ │ ├── daiToken.sol │ │ ├── pot.sol │ │ └── vat.sol │ └── chai.sol ├── HUSDFaucet.sol ├── PAX │ ├── AdminUpgradeabilityProxy.sol │ └── PAXImplementationV2.sol ├── TUSD │ ├── OwnedUpgradeabilityProxy.sol │ ├── TokenController.sol │ ├── TrueUSD.sol │ └── TrueUSDOriginal.sol ├── USDC │ ├── FiatTokenProxy.sol │ └── FiatTokenV1.sol ├── USDTFaucet.sol ├── USDxFaucet.sol ├── WBTCFaucet.sol ├── imBTCFaucet.sol └── wethFaucet.sol ├── contracts ├── CarefulMath.sol ├── EIP20Interface.sol ├── EIP20NonStandardInterface.sol ├── ErrorReporter.sol ├── ExchangeRate.sol ├── Exponential.sol ├── InterestRateModel.sol ├── LiquidationChecker.sol ├── Liquidator.sol ├── MoneyMarket.sol ├── PriceOracle.sol ├── PriceOracleInterface.sol ├── PriceOracleProxy.sol ├── SafeToken.sol ├── StableCoinInterestRateModel.sol ├── StandardInterestRateModel.sol ├── USDTRateModel.sol ├── USDxInterestRateModel.sol └── imBTCRateModel.sol └── test └── InterestModel ├── abi └── testInterestModel.json ├── contract └── testInterestModel.sol └── testInterestModel.js /.gitattributes: -------------------------------------------------------------------------------- 1 | *.sol linguist-language=Solidity 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Coverage directory 3 | coverage 4 | coverage.json 5 | coverageEnv 6 | 7 | # Dependency directory 8 | node_modules 9 | 10 | # Debug log from npm 11 | npm-debug.log 12 | 13 | # Local env variables 14 | .env 15 | 16 | # Truffle build directory 17 | build/ 18 | 19 | # misc 20 | .DS_Store 21 | */.DS_Store 22 | .env 23 | .idea/ 24 | .vscode/ 25 | 26 | # Logs 27 | logs 28 | *.log 29 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Mainnet Contract Address(2020-03-14) 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 |
Contract NameContract Address
MoneyMarket 0x0eEe3E3828A45f7601D5F54bF49bB01d1A9dF5ea
Liquidator 0x9893292300c4e530a14FB2526271732a2a9b3f05
DSRToken 0x06AF07097C9Eeb7fD685c692751D5C66dB49c215
DSRTokenRateModel 0x79BE3Be94b8D25F6628c616a99fA09094bcF3712
HBTC 0x0316EB71485b0Ab14103307bf65a021042c6d380
HBTCRateModel 0x5Dc95A046020880b93F15902540Dbfe86489FddA
HUSD 0xdF574c24545E5FfEcb9a659c229253D4111d87e1
HUSDRateModel 0x79BE3Be94b8D25F6628c616a99fA09094bcF3712
imBTC 0x3212b29E33587A00FB1C83346f5dBFA69A458923
imBTCRateModel 0x9a18c4D9587344f2B15686Aa67EE7e5C4B00D549
PAX 0x8E870D67F660D95d5be530380D0eC0bd388289E1
PAXRateModel 0x79BE3Be94b8D25F6628c616a99fA09094bcF3712
TUSD 0x0000000000085d4780B73119b644AE5ecd22b376
TUSDRateModel 0x79BE3Be94b8D25F6628c616a99fA09094bcF3712
USDC 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48
USDCRateModel 0x79BE3Be94b8D25F6628c616a99fA09094bcF3712
USDT 0xdAC17F958D2ee523a2206206994597C13D831ec7
USDTRateModel 0x79BE3Be94b8D25F6628c616a99fA09094bcF3712
USDx 0xeb269732ab75A6fD61Ea60b06fE994cD32a83549
USDxRateModel 0x83D5f6dc9d9750A137a744333C55b4Adf5F9A234
WBTC 0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599
WBTCRateModel 0x5Dc95A046020880b93F15902540Dbfe86489FddA
WETH 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2
WETHRateModel 0x5Dc95A046020880b93F15902540Dbfe86489FddA
PriceOracle 0xE171D8c7e9EE0DDAe1A9bec0c7f35294e48c28d4
PriceOracleProxy 0xB620707637C5b2cc49843A03d90E28D9abbDa149
DAI 0x6B175474E89094C44Da98b954EedeAC495271d0F
ExchangeRate 0x3eE954244629c9Bc6e53A50baCCC9A7B472f7D42
121 | 122 | 123 | ## Mainnet Test Contract Address(2020-03-14) 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 |
Contract NameContract Address
MoneyMarket 0xEDA3849869FD560B49daB8C110bE3a020F46c79E
Liquidator 0xa116F88A1FF715206923f909585FEa35F52d540a
DSRToken 0xfab8E55ae02826BF6e849E8eaE78c5b8FA4182F3
DSRTokenRateModel 0x1016B2c721A260E9908Ece0EE694F9fD10896C8D
HBTC 0xa2C7088b08833a00dB49A0d564b5e1463A4B49cB
HBTCRateModel 0xA4e7D12909FaD9cFc620c34cFA1b9DCC31f3BF43
HUSD 0x91Ca723288ecd5772e263e25F52D4014C493f5D0
HUSDRateModel 0x1016B2c721A260E9908Ece0EE694F9fD10896C8D
imBTC 0x1141687E2a906722254e77241019c57496c0e83e
imBTCRateModel 0x0ae2612845C3dDcc49f6d4F4F728f9de503AAbBf
PAX 0x6CDd244AFFf8902cE285F02C39A2623Ecb461454
PAXRateModel 0x1016B2c721A260E9908Ece0EE694F9fD10896C8D
TUSD 0xfd062D0EBC900EF504435DCe9347797d3b5e12Aa
TUSDRateModel 0x1016B2c721A260E9908Ece0EE694F9fD10896C8D
USDC 0x2cd68eCF48B0687c95EE6C06D33389688C3cbb8e
USDCRateModel 0x1016B2c721A260E9908Ece0EE694F9fD10896C8D
USDT 0x622B859cf4f1013642F6c177bA713d482fF5b483
USDTRateModel 0x1016B2c721A260E9908Ece0EE694F9fD10896C8D
USDx 0x3A9E75AFcFFcD89613037989EA0ED6cEc44a4353
USDxRateModel 0xa79B3ea1729Bf43Be12A7C89BDffd1306dBFe647
WBTC 0xb699238e9Fc2724CBc7ca28AEF68b546Cd773612
WBTCRateModel 0xA4e7D12909FaD9cFc620c34cFA1b9DCC31f3BF43
WETH 0x06A1cd567e61b7Edda49c30D3D32e60F607fD646
WETHRateModel 0xA4e7D12909FaD9cFc620c34cFA1b9DCC31f3BF43
PriceOracle 0x54934a16e77445F45A37C52B70a43c3b4D011aD4
PriceOracleProxy 0x0388617179F1fabcBCf975507Ab424D8179cfF75
DAI 0x4Eab78e4C2acf2Ed41d56ce71b51c9D717782124
ExchangeRate 0xBe87C16290e554229E2364DeB46b78a4BFcae74a
243 | 244 | 245 | 246 | ## Rinkeby Contract Address(2020-03-14) 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | 360 | 361 | 362 | 363 | 364 | 365 |
Contract NameContract Address
MoneyMarket 0xDCfD113789Ef683f676435fFf90B953A0Cc76044
Liquidator 0x84E81B87D1736D2E2Be5dB591326E29F8458c63C
DSRToken 0x8a5C1BD4D75e168a4f65eB902c289400B90FD980
DSRTokenRateModel 0x63b920386b3b4021d36EcFaB90F3F5b74Bc8b902
HBTC 0xcf07906CbCF9824D0caE475E8F958d48AcF1014C
HBTCRateModel 0x0Ecc207Eb5E1d9476543D7e32D61A75e6bf767d3
HUSD 0x0D518472330FF1D943881BBBDda03b221A7F9F74
HUSDRateModel 0x63b920386b3b4021d36EcFaB90F3F5b74Bc8b902
imBTC 0x5Dc95A046020880b93F15902540Dbfe86489FddA
imBTCRateModel 0xe7cF47e58829Dc4eD4FDB9638eC309A00a96D13a
PAX 0x722E6238335d89393A42e2cA316A5fb1b8B2EB55
PAXRateModel 0x63b920386b3b4021d36EcFaB90F3F5b74Bc8b902
TUSD 0xe72a3181f69Eb21A19bd4Ce19Eb68FDb333d74c6
TUSDRateModel 0x63b920386b3b4021d36EcFaB90F3F5b74Bc8b902
USDC 0x4DBCdF9B62e891a7cec5A2568C3F4FAF9E8Abe2b
USDCRateModel 0x63b920386b3b4021d36EcFaB90F3F5b74Bc8b902
USDT 0xaa74B62f737bbA1D2E520F9ec38Fc23b6E6817df
USDTRateModel 0x63b920386b3b4021d36EcFaB90F3F5b74Bc8b902
USDx 0xD96cC7f80C1cb595eBcdC072531e1799B3a2436E
USDxRateModel 0xe302E676E1Add419cc87e75fb5B73DAB24Ad1534
WBTC 0x7B65B937A0f3764a7a5e29fD696C391233218E91
WBTCRateModel 0x0Ecc207Eb5E1d9476543D7e32D61A75e6bf767d3
WETH 0x7A967421410019044aA829746D65575325082e99
WETHRateModel 0x0Ecc207Eb5E1d9476543D7e32D61A75e6bf767d3
PriceOracle 0xd75AF5Bc8e1f022002c47508C27455A20738b1F5
PriceOracleProxy 0x1ca246F23cb90c75B879fd58Cc02C64B52B01e99
DAI 0xA3A59273494BB5B8F0a8FAcf21B3f666A47d6140
ExchangeRate 0x0226953975D4948b417571Fb73A02358d25aFF1A
366 | -------------------------------------------------------------------------------- /assets/CHAI/DAI/daiJoin.sol: -------------------------------------------------------------------------------- 1 | /* 2 | ======================================================================== 3 | !!!!!!!!!!!!!! 4 | !!! NOTICE !!! 5 | !!!!!!!!!!!!!! 6 | This is a test contract very similar to the formal contract. 7 | The actual code on the mainnet is at here: 8 | https://etherscan.io/address/0x9759a6ac90977b93b58547b4a71c78317f391a28#code 9 | ======================================================================== 10 | */ 11 | 12 | // hevm: flattened sources of /nix/store/8xb41r4qd0cjb63wcrxf1qmfg88p0961-dss-6fd7de0/src/join.sol 13 | pragma solidity =0.5.12; 14 | 15 | ////// /nix/store/8xb41r4qd0cjb63wcrxf1qmfg88p0961-dss-6fd7de0/src/lib.sol 16 | // This program is free software: you can redistribute it and/or modify 17 | // it under the terms of the GNU General Public License as published by 18 | // the Free Software Foundation, either version 3 of the License, or 19 | // (at your option) any later version. 20 | 21 | // This program is distributed in the hope that it will be useful, 22 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 23 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 24 | // GNU General Public License for more details. 25 | 26 | // You should have received a copy of the GNU General Public License 27 | // along with this program. If not, see . 28 | 29 | /* pragma solidity 0.5.12; */ 30 | 31 | contract LibNote { 32 | event LogNote( 33 | bytes4 indexed sig, 34 | address indexed usr, 35 | bytes32 indexed arg1, 36 | bytes32 indexed arg2, 37 | bytes data 38 | ) anonymous; 39 | 40 | modifier note { 41 | _; 42 | assembly { 43 | // log an 'anonymous' event with a constant 6 words of calldata 44 | // and four indexed topics: selector, caller, arg1 and arg2 45 | let mark := msize // end of memory ensures zero 46 | mstore(0x40, add(mark, 288)) // update free memory pointer 47 | mstore(mark, 0x20) // bytes type data offset 48 | mstore(add(mark, 0x20), 224) // bytes size (padded) 49 | calldatacopy(add(mark, 0x40), 0, 224) // bytes payload 50 | log4(mark, 288, // calldata 51 | shl(224, shr(224, calldataload(0))), // msg.sig 52 | caller, // msg.sender 53 | calldataload(4), // arg1 54 | calldataload(36) // arg2 55 | ) 56 | } 57 | } 58 | } 59 | 60 | ////// /nix/store/8xb41r4qd0cjb63wcrxf1qmfg88p0961-dss-6fd7de0/src/join.sol 61 | /// join.sol -- Basic token adapters 62 | 63 | // Copyright (C) 2018 Rain 64 | // 65 | // This program is free software: you can redistribute it and/or modify 66 | // it under the terms of the GNU Affero General Public License as published by 67 | // the Free Software Foundation, either version 3 of the License, or 68 | // (at your option) any later version. 69 | // 70 | // This program is distributed in the hope that it will be useful, 71 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 72 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 73 | // GNU Affero General Public License for more details. 74 | // 75 | // You should have received a copy of the GNU Affero General Public License 76 | // along with this program. If not, see . 77 | 78 | /* pragma solidity 0.5.12; */ 79 | 80 | /* import "./lib.sol"; */ 81 | 82 | contract GemLike { 83 | function decimals() public view returns (uint); 84 | function transfer(address,uint) external returns (bool); 85 | function transferFrom(address,address,uint) external returns (bool); 86 | } 87 | 88 | contract DSTokenLike { 89 | function mint(address,uint) external; 90 | function burn(address,uint) external; 91 | } 92 | 93 | contract VatLike { 94 | function slip(bytes32,address,int) external; 95 | function move(address,address,uint) external; 96 | } 97 | 98 | /* 99 | Here we provide *adapters* to connect the Vat to arbitrary external 100 | token implementations, creating a bounded context for the Vat. The 101 | adapters here are provided as working examples: 102 | 103 | - `GemJoin`: For well behaved ERC20 tokens, with simple transfer 104 | semantics. 105 | 106 | - `ETHJoin`: For native Ether. 107 | 108 | - `DaiJoin`: For connecting internal Dai balances to an external 109 | `DSToken` implementation. 110 | 111 | In practice, adapter implementations will be varied and specific to 112 | individual collateral types, accounting for different transfer 113 | semantics and token standards. 114 | 115 | Adapters need to implement two basic methods: 116 | 117 | - `join`: enter collateral into the system 118 | - `exit`: remove collateral from the system 119 | 120 | */ 121 | 122 | contract GemJoin is LibNote { 123 | // --- Auth --- 124 | mapping (address => uint) public wards; 125 | function rely(address usr) external note auth { wards[usr] = 1; } 126 | function deny(address usr) external note auth { wards[usr] = 0; } 127 | modifier auth { 128 | require(wards[msg.sender] == 1, "GemJoin/not-authorized"); 129 | _; 130 | } 131 | 132 | VatLike public vat; 133 | bytes32 public ilk; 134 | GemLike public gem; 135 | uint public dec; 136 | uint public live; // Access Flag 137 | 138 | constructor(address vat_, bytes32 ilk_, address gem_) public { 139 | wards[msg.sender] = 1; 140 | live = 1; 141 | vat = VatLike(vat_); 142 | ilk = ilk_; 143 | gem = GemLike(gem_); 144 | dec = gem.decimals(); 145 | } 146 | function cage() external note auth { 147 | live = 0; 148 | } 149 | function join(address usr, uint wad) external note { 150 | require(live == 1, "GemJoin/not-live"); 151 | require(int(wad) >= 0, "GemJoin/overflow"); 152 | vat.slip(ilk, usr, int(wad)); 153 | require(gem.transferFrom(msg.sender, address(this), wad), "GemJoin/failed-transfer"); 154 | } 155 | function exit(address usr, uint wad) external note { 156 | require(wad <= 2 ** 255, "GemJoin/overflow"); 157 | vat.slip(ilk, msg.sender, -int(wad)); 158 | require(gem.transfer(usr, wad), "GemJoin/failed-transfer"); 159 | } 160 | } 161 | 162 | contract ETHJoin is LibNote { 163 | // --- Auth --- 164 | mapping (address => uint) public wards; 165 | function rely(address usr) external note auth { wards[usr] = 1; } 166 | function deny(address usr) external note auth { wards[usr] = 0; } 167 | modifier auth { 168 | require(wards[msg.sender] == 1, "ETHJoin/not-authorized"); 169 | _; 170 | } 171 | 172 | VatLike public vat; 173 | bytes32 public ilk; 174 | uint public live; // Access Flag 175 | 176 | constructor(address vat_, bytes32 ilk_) public { 177 | wards[msg.sender] = 1; 178 | live = 1; 179 | vat = VatLike(vat_); 180 | ilk = ilk_; 181 | } 182 | function cage() external note auth { 183 | live = 0; 184 | } 185 | function join(address usr) external payable note { 186 | require(live == 1, "ETHJoin/not-live"); 187 | require(int(msg.value) >= 0, "ETHJoin/overflow"); 188 | vat.slip(ilk, usr, int(msg.value)); 189 | } 190 | function exit(address payable usr, uint wad) external note { 191 | require(int(wad) >= 0, "ETHJoin/overflow"); 192 | vat.slip(ilk, msg.sender, -int(wad)); 193 | usr.transfer(wad); 194 | } 195 | } 196 | 197 | contract DaiJoin is LibNote { 198 | // --- Auth --- 199 | mapping (address => uint) public wards; 200 | function rely(address usr) external note auth { wards[usr] = 1; } 201 | function deny(address usr) external note auth { wards[usr] = 0; } 202 | modifier auth { 203 | require(wards[msg.sender] == 1, "DaiJoin/not-authorized"); 204 | _; 205 | } 206 | 207 | VatLike public vat; 208 | DSTokenLike public dai; 209 | uint public live; // Access Flag 210 | 211 | constructor(address vat_, address dai_) public { 212 | wards[msg.sender] = 1; 213 | live = 1; 214 | vat = VatLike(vat_); 215 | dai = DSTokenLike(dai_); 216 | } 217 | function cage() external note auth { 218 | live = 0; 219 | } 220 | uint constant ONE = 10 ** 27; 221 | function mul(uint x, uint y) internal pure returns (uint z) { 222 | require(y == 0 || (z = x * y) / y == x); 223 | } 224 | function join(address usr, uint wad) external note { 225 | vat.move(address(this), usr, mul(ONE, wad)); 226 | dai.burn(msg.sender, wad); 227 | } 228 | function exit(address usr, uint wad) external note { 229 | require(live == 1, "DaiJoin/not-live"); 230 | vat.move(msg.sender, address(this), mul(ONE, wad)); 231 | dai.mint(usr, wad); 232 | } 233 | } 234 | -------------------------------------------------------------------------------- /assets/CHAI/DAI/daiToken.sol: -------------------------------------------------------------------------------- 1 | /* 2 | ======================================================================== 3 | !!!!!!!!!!!!!! 4 | !!! NOTICE !!! 5 | !!!!!!!!!!!!!! 6 | This is a test contract very similar to the formal contract. 7 | The only difference between this contract and the formal contract is 8 | that there is an additional function named allocateTo() to get token free. 9 | The actual code on the mainnet is at here: 10 | https://etherscan.io/address/0x6b175474e89094c44da98b954eedeac495271d0f#code 11 | ======================================================================== 12 | */ 13 | 14 | // hevm: flattened sources of /nix/store/8xb41r4qd0cjb63wcrxf1qmfg88p0961-dss-6fd7de0/src/dai.sol 15 | pragma solidity =0.5.12; 16 | 17 | ////// /nix/store/8xb41r4qd0cjb63wcrxf1qmfg88p0961-dss-6fd7de0/src/lib.sol 18 | // This program is free software: you can redistribute it and/or modify 19 | // it under the terms of the GNU General Public License as published by 20 | // the Free Software Foundation, either version 3 of the License, or 21 | // (at your option) any later version. 22 | 23 | // This program is distributed in the hope that it will be useful, 24 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 25 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 26 | // GNU General Public License for more details. 27 | 28 | // You should have received a copy of the GNU General Public License 29 | // along with this program. If not, see . 30 | 31 | /* pragma solidity 0.5.12; */ 32 | 33 | contract LibNote { 34 | event LogNote( 35 | bytes4 indexed sig, 36 | address indexed usr, 37 | bytes32 indexed arg1, 38 | bytes32 indexed arg2, 39 | bytes data 40 | ) anonymous; 41 | 42 | modifier note { 43 | _; 44 | assembly { 45 | // log an 'anonymous' event with a constant 6 words of calldata 46 | // and four indexed topics: selector, caller, arg1 and arg2 47 | let mark := msize // end of memory ensures zero 48 | mstore(0x40, add(mark, 288)) // update free memory pointer 49 | mstore(mark, 0x20) // bytes type data offset 50 | mstore(add(mark, 0x20), 224) // bytes size (padded) 51 | calldatacopy(add(mark, 0x40), 0, 224) // bytes payload 52 | log4(mark, 288, // calldata 53 | shl(224, shr(224, calldataload(0))), // msg.sig 54 | caller, // msg.sender 55 | calldataload(4), // arg1 56 | calldataload(36) // arg2 57 | ) 58 | } 59 | } 60 | } 61 | 62 | ////// /nix/store/8xb41r4qd0cjb63wcrxf1qmfg88p0961-dss-6fd7de0/src/dai.sol 63 | // Copyright (C) 2017, 2018, 2019 dbrock, rain, mrchico 64 | 65 | // This program is free software: you can redistribute it and/or modify 66 | // it under the terms of the GNU Affero General Public License as published by 67 | // the Free Software Foundation, either version 3 of the License, or 68 | // (at your option) any later version. 69 | // 70 | // This program is distributed in the hope that it will be useful, 71 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 72 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 73 | // GNU Affero General Public License for more details. 74 | // 75 | // You should have received a copy of the GNU Affero General Public License 76 | // along with this program. If not, see . 77 | 78 | /* pragma solidity 0.5.12; */ 79 | 80 | /* import "./lib.sol"; */ 81 | 82 | contract Dai is LibNote { 83 | // --- Auth --- 84 | mapping (address => uint) public wards; 85 | function rely(address guy) external note auth { wards[guy] = 1; } 86 | function deny(address guy) external note auth { wards[guy] = 0; } 87 | modifier auth { 88 | require(wards[msg.sender] == 1, "Dai/not-authorized"); 89 | _; 90 | } 91 | 92 | // --- ERC20 Data --- 93 | string public constant name = "Dai Stablecoin"; 94 | string public constant symbol = "DAI"; 95 | string public constant version = "1"; 96 | uint8 public constant decimals = 18; 97 | uint256 public totalSupply; 98 | 99 | mapping (address => uint) public balanceOf; 100 | mapping (address => mapping (address => uint)) public allowance; 101 | mapping (address => uint) public nonces; 102 | 103 | event Approval(address indexed src, address indexed guy, uint wad); 104 | event Transfer(address indexed src, address indexed dst, uint wad); 105 | 106 | // --- Math --- 107 | function add(uint x, uint y) internal pure returns (uint z) { 108 | require((z = x + y) >= x); 109 | } 110 | function sub(uint x, uint y) internal pure returns (uint z) { 111 | require((z = x - y) <= x); 112 | } 113 | 114 | // --- EIP712 niceties --- 115 | bytes32 public DOMAIN_SEPARATOR; 116 | // bytes32 public constant PERMIT_TYPEHASH = keccak256("Permit(address holder,address spender,uint256 nonce,uint256 expiry,bool allowed)"); 117 | bytes32 public constant PERMIT_TYPEHASH = 0xea2aa0a1be11a07ed86d755c93467f4f82362b452371d1ba94d1715123511acb; 118 | 119 | constructor(uint256 chainId_) public { 120 | wards[msg.sender] = 1; 121 | DOMAIN_SEPARATOR = keccak256(abi.encode( 122 | keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"), 123 | keccak256(bytes(name)), 124 | keccak256(bytes(version)), 125 | chainId_, 126 | address(this) 127 | )); 128 | } 129 | 130 | // --- Token --- 131 | function transfer(address dst, uint wad) external returns (bool) { 132 | return transferFrom(msg.sender, dst, wad); 133 | } 134 | function transferFrom(address src, address dst, uint wad) 135 | public returns (bool) 136 | { 137 | require(balanceOf[src] >= wad, "Dai/insufficient-balance"); 138 | if (src != msg.sender && allowance[src][msg.sender] != uint(-1)) { 139 | require(allowance[src][msg.sender] >= wad, "Dai/insufficient-allowance"); 140 | allowance[src][msg.sender] = sub(allowance[src][msg.sender], wad); 141 | } 142 | balanceOf[src] = sub(balanceOf[src], wad); 143 | balanceOf[dst] = add(balanceOf[dst], wad); 144 | emit Transfer(src, dst, wad); 145 | return true; 146 | } 147 | function mint(address usr, uint wad) external auth { 148 | balanceOf[usr] = add(balanceOf[usr], wad); 149 | totalSupply = add(totalSupply, wad); 150 | emit Transfer(address(0), usr, wad); 151 | } 152 | function burn(address usr, uint wad) external { 153 | require(balanceOf[usr] >= wad, "Dai/insufficient-balance"); 154 | if (usr != msg.sender && allowance[usr][msg.sender] != uint(-1)) { 155 | require(allowance[usr][msg.sender] >= wad, "Dai/insufficient-allowance"); 156 | allowance[usr][msg.sender] = sub(allowance[usr][msg.sender], wad); 157 | } 158 | balanceOf[usr] = sub(balanceOf[usr], wad); 159 | totalSupply = sub(totalSupply, wad); 160 | emit Transfer(usr, address(0), wad); 161 | } 162 | function approve(address usr, uint wad) external returns (bool) { 163 | allowance[msg.sender][usr] = wad; 164 | emit Approval(msg.sender, usr, wad); 165 | return true; 166 | } 167 | 168 | // --- Alias --- 169 | function push(address usr, uint wad) external { 170 | transferFrom(msg.sender, usr, wad); 171 | } 172 | function pull(address usr, uint wad) external { 173 | transferFrom(usr, msg.sender, wad); 174 | } 175 | function move(address src, address dst, uint wad) external { 176 | transferFrom(src, dst, wad); 177 | } 178 | 179 | // --- Approve by signature --- 180 | function permit(address holder, address spender, uint256 nonce, uint256 expiry, 181 | bool allowed, uint8 v, bytes32 r, bytes32 s) external 182 | { 183 | bytes32 digest = 184 | keccak256(abi.encodePacked( 185 | "\x19\x01", 186 | DOMAIN_SEPARATOR, 187 | keccak256(abi.encode(PERMIT_TYPEHASH, 188 | holder, 189 | spender, 190 | nonce, 191 | expiry, 192 | allowed)) 193 | )); 194 | 195 | require(holder != address(0), "Dai/invalid-address-0"); 196 | require(holder == ecrecover(digest, v, r, s), "Dai/invalid-permit"); 197 | require(expiry == 0 || now <= expiry, "Dai/permit-expired"); 198 | require(nonce == nonces[holder]++, "Dai/invalid-nonce"); 199 | uint wad = allowed ? uint(-1) : 0; 200 | allowance[holder][spender] = wad; 201 | emit Approval(holder, spender, wad); 202 | } 203 | 204 | // This is not a function used in actual production 205 | // Only for getting free token to test 206 | function allocateTo(address usr, uint wad) public { 207 | balanceOf[usr] = add(balanceOf[usr], wad); 208 | totalSupply = add(totalSupply, wad); 209 | emit Transfer(address(0), usr, wad); 210 | } 211 | } 212 | -------------------------------------------------------------------------------- /assets/CHAI/DAI/pot.sol: -------------------------------------------------------------------------------- 1 | /* 2 | ======================================================================== 3 | !!!!!!!!!!!!!! 4 | !!! NOTICE !!! 5 | !!!!!!!!!!!!!! 6 | This is a test contract very similar to the formal contract. 7 | The actual code on the mainnet is at here: 8 | https://etherscan.io/address/0x197e90f9fad81970ba7976f33cbd77088e5d7cf7#code 9 | ======================================================================== 10 | */ 11 | 12 | // hevm: flattened sources of /nix/store/8xb41r4qd0cjb63wcrxf1qmfg88p0961-dss-6fd7de0/src/pot.sol 13 | pragma solidity =0.5.12; 14 | 15 | ////// /nix/store/8xb41r4qd0cjb63wcrxf1qmfg88p0961-dss-6fd7de0/src/lib.sol 16 | // This program is free software: you can redistribute it and/or modify 17 | // it under the terms of the GNU General Public License as published by 18 | // the Free Software Foundation, either version 3 of the License, or 19 | // (at your option) any later version. 20 | 21 | // This program is distributed in the hope that it will be useful, 22 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 23 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 24 | // GNU General Public License for more details. 25 | 26 | // You should have received a copy of the GNU General Public License 27 | // along with this program. If not, see . 28 | 29 | /* pragma solidity 0.5.12; */ 30 | 31 | contract LibNote { 32 | event LogNote( 33 | bytes4 indexed sig, 34 | address indexed usr, 35 | bytes32 indexed arg1, 36 | bytes32 indexed arg2, 37 | bytes data 38 | ) anonymous; 39 | 40 | modifier note { 41 | _; 42 | assembly { 43 | // log an 'anonymous' event with a constant 6 words of calldata 44 | // and four indexed topics: selector, caller, arg1 and arg2 45 | let mark := msize // end of memory ensures zero 46 | mstore(0x40, add(mark, 288)) // update free memory pointer 47 | mstore(mark, 0x20) // bytes type data offset 48 | mstore(add(mark, 0x20), 224) // bytes size (padded) 49 | calldatacopy(add(mark, 0x40), 0, 224) // bytes payload 50 | log4(mark, 288, // calldata 51 | shl(224, shr(224, calldataload(0))), // msg.sig 52 | caller, // msg.sender 53 | calldataload(4), // arg1 54 | calldataload(36) // arg2 55 | ) 56 | } 57 | } 58 | } 59 | 60 | ////// /nix/store/8xb41r4qd0cjb63wcrxf1qmfg88p0961-dss-6fd7de0/src/pot.sol 61 | /// pot.sol -- Dai Savings Rate 62 | 63 | // Copyright (C) 2018 Rain 64 | // 65 | // This program is free software: you can redistribute it and/or modify 66 | // it under the terms of the GNU Affero General Public License as published by 67 | // the Free Software Foundation, either version 3 of the License, or 68 | // (at your option) any later version. 69 | // 70 | // This program is distributed in the hope that it will be useful, 71 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 72 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 73 | // GNU Affero General Public License for more details. 74 | // 75 | // You should have received a copy of the GNU Affero General Public License 76 | // along with this program. If not, see . 77 | 78 | /* pragma solidity 0.5.12; */ 79 | 80 | /* import "./lib.sol"; */ 81 | 82 | /* 83 | "Savings Dai" is obtained when Dai is deposited into 84 | this contract. Each "Savings Dai" accrues Dai interest 85 | at the "Dai Savings Rate". 86 | 87 | This contract does not implement a user tradeable token 88 | and is intended to be used with adapters. 89 | 90 | --- `save` your `dai` in the `pot` --- 91 | 92 | - `dsr`: the Dai Savings Rate 93 | - `pie`: user balance of Savings Dai 94 | 95 | - `join`: start saving some dai 96 | - `exit`: remove some dai 97 | - `drip`: perform rate collection 98 | 99 | */ 100 | 101 | contract VatLike { 102 | function move(address,address,uint256) external; 103 | function suck(address,address,uint256) external; 104 | } 105 | 106 | contract Pot is LibNote { 107 | // --- Auth --- 108 | mapping (address => uint) public wards; 109 | function rely(address guy) external note auth { wards[guy] = 1; } 110 | function deny(address guy) external note auth { wards[guy] = 0; } 111 | modifier auth { 112 | require(wards[msg.sender] == 1, "Pot/not-authorized"); 113 | _; 114 | } 115 | 116 | // --- Data --- 117 | mapping (address => uint256) public pie; // user Savings Dai 118 | 119 | uint256 public Pie; // total Savings Dai 120 | uint256 public dsr; // the Dai Savings Rate 121 | uint256 public chi; // the Rate Accumulator 122 | 123 | VatLike public vat; // CDP engine 124 | address public vow; // debt engine 125 | uint256 public rho; // time of last drip 126 | 127 | uint256 public live; // Access Flag 128 | 129 | // --- Init --- 130 | constructor(address vat_) public { 131 | wards[msg.sender] = 1; 132 | vat = VatLike(vat_); 133 | dsr = ONE; 134 | chi = ONE; 135 | rho = now; 136 | live = 1; 137 | } 138 | 139 | // --- Math --- 140 | uint256 constant ONE = 10 ** 27; 141 | function rpow(uint x, uint n, uint base) internal pure returns (uint z) { 142 | assembly { 143 | switch x case 0 {switch n case 0 {z := base} default {z := 0}} 144 | default { 145 | switch mod(n, 2) case 0 { z := base } default { z := x } 146 | let half := div(base, 2) // for rounding. 147 | for { n := div(n, 2) } n { n := div(n,2) } { 148 | let xx := mul(x, x) 149 | if iszero(eq(div(xx, x), x)) { revert(0,0) } 150 | let xxRound := add(xx, half) 151 | if lt(xxRound, xx) { revert(0,0) } 152 | x := div(xxRound, base) 153 | if mod(n,2) { 154 | let zx := mul(z, x) 155 | if and(iszero(iszero(x)), iszero(eq(div(zx, x), z))) { revert(0,0) } 156 | let zxRound := add(zx, half) 157 | if lt(zxRound, zx) { revert(0,0) } 158 | z := div(zxRound, base) 159 | } 160 | } 161 | } 162 | } 163 | } 164 | 165 | function rmul(uint x, uint y) internal pure returns (uint z) { 166 | z = mul(x, y) / ONE; 167 | } 168 | 169 | function add(uint x, uint y) internal pure returns (uint z) { 170 | require((z = x + y) >= x); 171 | } 172 | 173 | function sub(uint x, uint y) internal pure returns (uint z) { 174 | require((z = x - y) <= x); 175 | } 176 | 177 | function mul(uint x, uint y) internal pure returns (uint z) { 178 | require(y == 0 || (z = x * y) / y == x); 179 | } 180 | 181 | // --- Administration --- 182 | function file(bytes32 what, uint256 data) external note auth { 183 | require(live == 1, "Pot/not-live"); 184 | require(now == rho, "Pot/rho-not-updated"); 185 | if (what == "dsr") dsr = data; 186 | else revert("Pot/file-unrecognized-param"); 187 | } 188 | 189 | function file(bytes32 what, address addr) external note auth { 190 | if (what == "vow") vow = addr; 191 | else revert("Pot/file-unrecognized-param"); 192 | } 193 | 194 | function cage() external note auth { 195 | live = 0; 196 | dsr = ONE; 197 | } 198 | 199 | // --- Savings Rate Accumulation --- 200 | function drip() external note returns (uint tmp) { 201 | require(now >= rho, "Pot/invalid-now"); 202 | tmp = rmul(rpow(dsr, now - rho, ONE), chi); 203 | uint chi_ = sub(tmp, chi); 204 | chi = tmp; 205 | rho = now; 206 | vat.suck(address(vow), address(this), mul(Pie, chi_)); 207 | } 208 | 209 | // --- Savings Dai Management --- 210 | function join(uint wad) external note { 211 | require(now == rho, "Pot/rho-not-updated"); 212 | pie[msg.sender] = add(pie[msg.sender], wad); 213 | Pie = add(Pie, wad); 214 | vat.move(msg.sender, address(this), mul(chi, wad)); 215 | } 216 | 217 | function exit(uint wad) external note { 218 | pie[msg.sender] = sub(pie[msg.sender], wad); 219 | Pie = sub(Pie, wad); 220 | vat.move(address(this), msg.sender, mul(chi, wad)); 221 | } 222 | } 223 | -------------------------------------------------------------------------------- /assets/CHAI/DAI/vat.sol: -------------------------------------------------------------------------------- 1 | /* 2 | ======================================================================== 3 | !!!!!!!!!!!!!! 4 | !!! NOTICE !!! 5 | !!!!!!!!!!!!!! 6 | This is a test contract very similar to the formal contract. 7 | The actual code on the mainnet is at here: 8 | https://etherscan.io/address/0x35d1b3f3d7966a1dfe207aa4514c12a259a0492b#code 9 | ======================================================================== 10 | */ 11 | 12 | /// vat.sol -- Dai CDP database 13 | 14 | // Copyright (C) 2018 Rain 15 | // 16 | // This program is free software: you can redistribute it and/or modify 17 | // it under the terms of the GNU Affero General Public License as published by 18 | // the Free Software Foundation, either version 3 of the License, or 19 | // (at your option) any later version. 20 | // 21 | // This program is distributed in the hope that it will be useful, 22 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 23 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 24 | // GNU Affero General Public License for more details. 25 | // 26 | // You should have received a copy of the GNU Affero General Public License 27 | // along with this program. If not, see . 28 | 29 | pragma solidity =0.5.12; 30 | 31 | contract Vat { 32 | // --- Auth --- 33 | mapping (address => uint) public wards; 34 | function rely(address usr) external note auth { require(live == 1, "Vat/not-live"); wards[usr] = 1; } 35 | function deny(address usr) external note auth { require(live == 1, "Vat/not-live"); wards[usr] = 0; } 36 | modifier auth { 37 | require(wards[msg.sender] == 1, "Vat/not-authorized"); 38 | _; 39 | } 40 | 41 | mapping(address => mapping (address => uint)) public can; 42 | function hope(address usr) external note { can[msg.sender][usr] = 1; } 43 | function nope(address usr) external note { can[msg.sender][usr] = 0; } 44 | function wish(address bit, address usr) internal view returns (bool) { 45 | return either(bit == usr, can[bit][usr] == 1); 46 | } 47 | 48 | // --- Data --- 49 | struct Ilk { 50 | uint256 Art; // Total Normalised Debt [wad] 51 | uint256 rate; // Accumulated Rates [ray] 52 | uint256 spot; // Price with Safety Margin [ray] 53 | uint256 line; // Debt Ceiling [rad] 54 | uint256 dust; // Urn Debt Floor [rad] 55 | } 56 | struct Urn { 57 | uint256 ink; // Locked Collateral [wad] 58 | uint256 art; // Normalised Debt [wad] 59 | } 60 | 61 | mapping (bytes32 => Ilk) public ilks; 62 | mapping (bytes32 => mapping (address => Urn )) public urns; 63 | mapping (bytes32 => mapping (address => uint)) public gem; // [wad] 64 | mapping (address => uint256) public dai; // [rad] 65 | mapping (address => uint256) public sin; // [rad] 66 | 67 | uint256 public debt; // Total Dai Issued [rad] 68 | uint256 public vice; // Total Unbacked Dai [rad] 69 | uint256 public Line; // Total Debt Ceiling [rad] 70 | uint256 public live; // Access Flag 71 | 72 | // --- Logs --- 73 | event LogNote( 74 | bytes4 indexed sig, 75 | bytes32 indexed arg1, 76 | bytes32 indexed arg2, 77 | bytes32 indexed arg3, 78 | bytes data 79 | ) anonymous; 80 | 81 | modifier note { 82 | _; 83 | assembly { 84 | // log an 'anonymous' event with a constant 6 words of calldata 85 | // and four indexed topics: the selector and the first three args 86 | let mark := msize // end of memory ensures zero 87 | mstore(0x40, add(mark, 288)) // update free memory pointer 88 | mstore(mark, 0x20) // bytes type data offset 89 | mstore(add(mark, 0x20), 224) // bytes size (padded) 90 | calldatacopy(add(mark, 0x40), 0, 224) // bytes payload 91 | log4(mark, 288, // calldata 92 | shl(224, shr(224, calldataload(0))), // msg.sig 93 | calldataload(4), // arg1 94 | calldataload(36), // arg2 95 | calldataload(68) // arg3 96 | ) 97 | } 98 | } 99 | 100 | // --- Init --- 101 | constructor() public { 102 | wards[msg.sender] = 1; 103 | live = 1; 104 | } 105 | 106 | // --- Math --- 107 | function add(uint x, int y) internal pure returns (uint z) { 108 | z = x + uint(y); 109 | require(y >= 0 || z <= x); 110 | require(y <= 0 || z >= x); 111 | } 112 | function sub(uint x, int y) internal pure returns (uint z) { 113 | z = x - uint(y); 114 | require(y <= 0 || z <= x); 115 | require(y >= 0 || z >= x); 116 | } 117 | function mul(uint x, int y) internal pure returns (int z) { 118 | z = int(x) * y; 119 | require(int(x) >= 0); 120 | require(y == 0 || z / y == int(x)); 121 | } 122 | function add(uint x, uint y) internal pure returns (uint z) { 123 | require((z = x + y) >= x); 124 | } 125 | function sub(uint x, uint y) internal pure returns (uint z) { 126 | require((z = x - y) <= x); 127 | } 128 | function mul(uint x, uint y) internal pure returns (uint z) { 129 | require(y == 0 || (z = x * y) / y == x); 130 | } 131 | 132 | // --- Administration --- 133 | function init(bytes32 ilk) external note auth { 134 | require(ilks[ilk].rate == 0, "Vat/ilk-already-init"); 135 | ilks[ilk].rate = 10 ** 27; 136 | } 137 | function file(bytes32 what, uint data) external note auth { 138 | require(live == 1, "Vat/not-live"); 139 | if (what == "Line") Line = data; 140 | else revert("Vat/file-unrecognized-param"); 141 | } 142 | function file(bytes32 ilk, bytes32 what, uint data) external note auth { 143 | require(live == 1, "Vat/not-live"); 144 | if (what == "spot") ilks[ilk].spot = data; 145 | else if (what == "line") ilks[ilk].line = data; 146 | else if (what == "dust") ilks[ilk].dust = data; 147 | else revert("Vat/file-unrecognized-param"); 148 | } 149 | function cage() external note auth { 150 | live = 0; 151 | } 152 | 153 | // --- Fungibility --- 154 | function slip(bytes32 ilk, address usr, int256 wad) external note auth { 155 | gem[ilk][usr] = add(gem[ilk][usr], wad); 156 | } 157 | function flux(bytes32 ilk, address src, address dst, uint256 wad) external note { 158 | require(wish(src, msg.sender), "Vat/not-allowed"); 159 | gem[ilk][src] = sub(gem[ilk][src], wad); 160 | gem[ilk][dst] = add(gem[ilk][dst], wad); 161 | } 162 | function move(address src, address dst, uint256 rad) external note { 163 | require(wish(src, msg.sender), "Vat/not-allowed"); 164 | dai[src] = sub(dai[src], rad); 165 | dai[dst] = add(dai[dst], rad); 166 | } 167 | 168 | function either(bool x, bool y) internal pure returns (bool z) { 169 | assembly{ z := or(x, y)} 170 | } 171 | function both(bool x, bool y) internal pure returns (bool z) { 172 | assembly{ z := and(x, y)} 173 | } 174 | 175 | // --- CDP Manipulation --- 176 | function frob(bytes32 i, address u, address v, address w, int dink, int dart) external note { 177 | // system is live 178 | require(live == 1, "Vat/not-live"); 179 | 180 | Urn memory urn = urns[i][u]; 181 | Ilk memory ilk = ilks[i]; 182 | // ilk has been initialised 183 | require(ilk.rate != 0, "Vat/ilk-not-init"); 184 | 185 | urn.ink = add(urn.ink, dink); 186 | urn.art = add(urn.art, dart); 187 | ilk.Art = add(ilk.Art, dart); 188 | 189 | int dtab = mul(ilk.rate, dart); 190 | uint tab = mul(ilk.rate, urn.art); 191 | debt = add(debt, dtab); 192 | 193 | // either debt has decreased, or debt ceilings are not exceeded 194 | require(either(dart <= 0, both(mul(ilk.Art, ilk.rate) <= ilk.line, debt <= Line)), "Vat/ceiling-exceeded"); 195 | // urn is either less risky than before, or it is safe 196 | require(either(both(dart <= 0, dink >= 0), tab <= mul(urn.ink, ilk.spot)), "Vat/not-safe"); 197 | 198 | // urn is either more safe, or the owner consents 199 | require(either(both(dart <= 0, dink >= 0), wish(u, msg.sender)), "Vat/not-allowed-u"); 200 | // collateral src consents 201 | require(either(dink <= 0, wish(v, msg.sender)), "Vat/not-allowed-v"); 202 | // debt dst consents 203 | require(either(dart >= 0, wish(w, msg.sender)), "Vat/not-allowed-w"); 204 | 205 | // urn has no debt, or a non-dusty amount 206 | require(either(urn.art == 0, tab >= ilk.dust), "Vat/dust"); 207 | 208 | gem[i][v] = sub(gem[i][v], dink); 209 | dai[w] = add(dai[w], dtab); 210 | 211 | urns[i][u] = urn; 212 | ilks[i] = ilk; 213 | } 214 | // --- CDP Fungibility --- 215 | function fork(bytes32 ilk, address src, address dst, int dink, int dart) external note { 216 | Urn storage u = urns[ilk][src]; 217 | Urn storage v = urns[ilk][dst]; 218 | Ilk storage i = ilks[ilk]; 219 | 220 | u.ink = sub(u.ink, dink); 221 | u.art = sub(u.art, dart); 222 | v.ink = add(v.ink, dink); 223 | v.art = add(v.art, dart); 224 | 225 | uint utab = mul(u.art, i.rate); 226 | uint vtab = mul(v.art, i.rate); 227 | 228 | // both sides consent 229 | require(both(wish(src, msg.sender), wish(dst, msg.sender)), "Vat/not-allowed"); 230 | 231 | // both sides safe 232 | require(utab <= mul(u.ink, i.spot), "Vat/not-safe-src"); 233 | require(vtab <= mul(v.ink, i.spot), "Vat/not-safe-dst"); 234 | 235 | // both sides non-dusty 236 | require(either(utab >= i.dust, u.art == 0), "Vat/dust-src"); 237 | require(either(vtab >= i.dust, v.art == 0), "Vat/dust-dst"); 238 | } 239 | // --- CDP Confiscation --- 240 | function grab(bytes32 i, address u, address v, address w, int dink, int dart) external note auth { 241 | Urn storage urn = urns[i][u]; 242 | Ilk storage ilk = ilks[i]; 243 | 244 | urn.ink = add(urn.ink, dink); 245 | urn.art = add(urn.art, dart); 246 | ilk.Art = add(ilk.Art, dart); 247 | 248 | int dtab = mul(ilk.rate, dart); 249 | 250 | gem[i][v] = sub(gem[i][v], dink); 251 | sin[w] = sub(sin[w], dtab); 252 | vice = sub(vice, dtab); 253 | } 254 | 255 | // --- Settlement --- 256 | function heal(uint rad) external note { 257 | address u = msg.sender; 258 | sin[u] = sub(sin[u], rad); 259 | dai[u] = sub(dai[u], rad); 260 | vice = sub(vice, rad); 261 | debt = sub(debt, rad); 262 | } 263 | function suck(address u, address v, uint rad) external note auth { 264 | sin[u] = add(sin[u], rad); 265 | dai[v] = add(dai[v], rad); 266 | vice = add(vice, rad); 267 | debt = add(debt, rad); 268 | } 269 | 270 | // --- Rates --- 271 | function fold(bytes32 i, address u, int rate) external note auth { 272 | require(live == 1, "Vat/not-live"); 273 | Ilk storage ilk = ilks[i]; 274 | ilk.rate = add(ilk.rate, rate); 275 | int rad = mul(ilk.Art, rate); 276 | dai[u] = add(dai[u], rad); 277 | debt = add(debt, rad); 278 | } 279 | } 280 | -------------------------------------------------------------------------------- /assets/CHAI/chai.sol: -------------------------------------------------------------------------------- 1 | /* 2 | ======================================================================== 3 | !!!!!!!!!!!!!! 4 | !!! NOTICE !!! 5 | !!!!!!!!!!!!!! 6 | This is a test contract very similar to the formal contract. 7 | The actual code on the mainnet is at here: 8 | https://etherscan.io/address/0x06AF07097C9Eeb7fD685c692751D5C66dB49c215#code 9 | ======================================================================== 10 | */ 11 | 12 | pragma solidity 0.5.12; 13 | 14 | contract VatLike { 15 | function hope(address) external; 16 | } 17 | 18 | contract PotLike { 19 | function chi() external returns (uint256); 20 | function rho() external returns (uint256); 21 | function drip() external returns (uint256); 22 | function join(uint256) external; 23 | function exit(uint256) external; 24 | } 25 | 26 | contract JoinLike { 27 | function join(address, uint) external; 28 | function exit(address, uint) external; 29 | } 30 | 31 | contract GemLike { 32 | function transferFrom(address,address,uint) external returns (bool); 33 | function approve(address,uint) external returns (bool); 34 | } 35 | 36 | contract Chai { 37 | // --- Data --- 38 | VatLike public vat = VatLike(0x5822B8f58ec21058E89A2998ae15faf25ba67587); 39 | PotLike public pot = PotLike(0xC5881103670131228E8FA62F756202f7D0f79872); 40 | JoinLike public daiJoin = JoinLike(0x8128f605EeD1519F5C9396acC9cd10D3aeFCeC5e); 41 | GemLike public daiToken = GemLike(0xA3A59273494BB5B8F0a8FAcf21B3f666A47d6140); 42 | 43 | // --- ERC20 Data --- 44 | string public constant name = "Chai"; 45 | string public constant symbol = "CHAI"; 46 | string public constant version = "1"; 47 | uint8 public constant decimals = 18; 48 | uint256 public totalSupply; 49 | 50 | mapping (address => uint) public balanceOf; 51 | mapping (address => mapping (address => uint)) public allowance; 52 | mapping (address => uint) public nonces; 53 | 54 | event Approval(address indexed src, address indexed guy, uint wad); 55 | event Transfer(address indexed src, address indexed dst, uint wad); 56 | 57 | // --- Math --- 58 | uint constant RAY = 10 ** 27; 59 | function add(uint x, uint y) internal pure returns (uint z) { 60 | require((z = x + y) >= x); 61 | } 62 | function sub(uint x, uint y) internal pure returns (uint z) { 63 | require((z = x - y) <= x); 64 | } 65 | function mul(uint x, uint y) internal pure returns (uint z) { 66 | require(y == 0 || (z = x * y) / y == x); 67 | } 68 | function rmul(uint x, uint y) internal pure returns (uint z) { 69 | // always rounds down 70 | z = mul(x, y) / RAY; 71 | } 72 | function rdiv(uint x, uint y) internal pure returns (uint z) { 73 | // always rounds down 74 | z = mul(x, RAY) / y; 75 | } 76 | function rdivup(uint x, uint y) internal pure returns (uint z) { 77 | // always rounds up 78 | z = add(mul(x, RAY), sub(y, 1)) / y; 79 | } 80 | 81 | // --- EIP712 niceties --- 82 | bytes32 public constant DOMAIN_SEPARATOR = 0xd1c0483db5f229996071fb2c9ed5f49369d03fed3bf37446892b6976d6433275; 83 | // keccak256("Permit(address holder,address spender,uint256 nonce,uint256 expiry,bool allowed)")); 84 | bytes32 public constant PERMIT_TYPEHASH = 0xea2aa0a1be11a07ed86d755c93467f4f82362b452371d1ba94d1715123511acb; 85 | 86 | 87 | constructor() public { 88 | assert (DOMAIN_SEPARATOR == 89 | keccak256(abi.encode( 90 | keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"), 91 | keccak256(bytes(name)), keccak256(bytes(version)), 1, address(this))) 92 | ); 93 | 94 | vat.hope(address(daiJoin)); 95 | vat.hope(address(pot)); 96 | 97 | daiToken.approve(address(daiJoin), uint(-1)); 98 | } 99 | 100 | // --- Token --- 101 | function transfer(address dst, uint wad) external returns (bool) { 102 | return transferFrom(msg.sender, dst, wad); 103 | } 104 | // like transferFrom but dai-denominated 105 | function move(address src, address dst, uint wad) external returns (bool) { 106 | uint chi = (now > pot.rho()) ? pot.drip() : pot.chi(); 107 | // rounding up ensures dst gets at least wad dai 108 | return transferFrom(src, dst, rdivup(wad, chi)); 109 | } 110 | function transferFrom(address src, address dst, uint wad) 111 | public returns (bool) 112 | { 113 | require(balanceOf[src] >= wad, "chai/insufficient-balance"); 114 | if (src != msg.sender && allowance[src][msg.sender] != uint(-1)) { 115 | require(allowance[src][msg.sender] >= wad, "chai/insufficient-allowance"); 116 | allowance[src][msg.sender] = sub(allowance[src][msg.sender], wad); 117 | } 118 | balanceOf[src] = sub(balanceOf[src], wad); 119 | balanceOf[dst] = add(balanceOf[dst], wad); 120 | emit Transfer(src, dst, wad); 121 | return true; 122 | } 123 | function approve(address usr, uint wad) external returns (bool) { 124 | allowance[msg.sender][usr] = wad; 125 | emit Approval(msg.sender, usr, wad); 126 | return true; 127 | } 128 | 129 | // --- Approve by signature --- 130 | function permit(address holder, address spender, uint256 nonce, uint256 expiry, bool allowed, uint8 v, bytes32 r, bytes32 s) external 131 | { 132 | bytes32 digest = keccak256(abi.encodePacked( 133 | "\x19\x01", 134 | DOMAIN_SEPARATOR, 135 | keccak256(abi.encode(PERMIT_TYPEHASH, 136 | holder, 137 | spender, 138 | nonce, 139 | expiry, 140 | allowed)))); 141 | require(holder != address(0), "chai/invalid holder"); 142 | require(holder == ecrecover(digest, v, r, s), "chai/invalid-permit"); 143 | require(expiry == 0 || now <= expiry, "chai/permit-expired"); 144 | require(nonce == nonces[holder]++, "chai/invalid-nonce"); 145 | 146 | uint can = allowed ? uint(-1) : 0; 147 | allowance[holder][spender] = can; 148 | emit Approval(holder, spender, can); 149 | } 150 | 151 | function dai(address usr) external returns (uint wad) { 152 | uint chi = (now > pot.rho()) ? pot.drip() : pot.chi(); 153 | wad = rmul(chi, balanceOf[usr]); 154 | } 155 | // wad is denominated in dai 156 | function join(address dst, uint wad) external { 157 | uint chi = (now > pot.rho()) ? pot.drip() : pot.chi(); 158 | uint pie = rdiv(wad, chi); 159 | balanceOf[dst] = add(balanceOf[dst], pie); 160 | totalSupply = add(totalSupply, pie); 161 | 162 | daiToken.transferFrom(msg.sender, address(this), wad); 163 | daiJoin.join(address(this), wad); 164 | pot.join(pie); 165 | emit Transfer(address(0), dst, pie); 166 | } 167 | 168 | // wad is denominated in (1/chi) * dai 169 | function exit(address src, uint wad) public { 170 | require(balanceOf[src] >= wad, "chai/insufficient-balance"); 171 | if (src != msg.sender && allowance[src][msg.sender] != uint(-1)) { 172 | require(allowance[src][msg.sender] >= wad, "chai/insufficient-allowance"); 173 | allowance[src][msg.sender] = sub(allowance[src][msg.sender], wad); 174 | } 175 | balanceOf[src] = sub(balanceOf[src], wad); 176 | totalSupply = sub(totalSupply, wad); 177 | 178 | uint chi = (now > pot.rho()) ? pot.drip() : pot.chi(); 179 | pot.exit(wad); 180 | daiJoin.exit(msg.sender, rmul(chi, wad)); 181 | emit Transfer(src, address(0), wad); 182 | } 183 | 184 | // wad is denominated in dai 185 | function draw(address src, uint wad) external { 186 | uint chi = (now > pot.rho()) ? pot.drip() : pot.chi(); 187 | // rounding up ensures usr gets at least wad dai 188 | exit(src, rdivup(wad, chi)); 189 | } 190 | } 191 | -------------------------------------------------------------------------------- /assets/PAX/AdminUpgradeabilityProxy.sol: -------------------------------------------------------------------------------- 1 | /* 2 | ======================================================================== 3 | !!!!!!!!!!!!!! 4 | !!! NOTICE !!! 5 | !!!!!!!!!!!!!! 6 | This is a test contract very similar to the formal contract. 7 | The only difference between this contract and the formal contract is 8 | that there is an additional function named allocateTo() to get token free. 9 | The actual code on the mainnet is at here: 10 | https://etherscan.io/address/0x8E870D67F660D95d5be530380D0eC0bd388289E1#code 11 | ======================================================================== 12 | */ 13 | 14 | pragma solidity ^0.4.24; 15 | 16 | // File: contracts/zeppelin/Proxy.sol 17 | 18 | /** 19 | * @title Proxy 20 | * @dev Implements delegation of calls to other contracts, with proper 21 | * forwarding of return values and bubbling of failures. 22 | * It defines a fallback function that delegates all calls to the address 23 | * returned by the abstract _implementation() internal function. 24 | */ 25 | contract Proxy { 26 | /** 27 | * @dev Fallback function. 28 | * Implemented entirely in `_fallback`. 29 | */ 30 | function () payable external { 31 | _fallback(); 32 | } 33 | 34 | /** 35 | * @return The Address of the implementation. 36 | */ 37 | function _implementation() internal view returns (address); 38 | 39 | /** 40 | * @dev Delegates execution to an implementation contract. 41 | * This is a low level function that doesn't return to its internal call site. 42 | * It will return to the external caller whatever the implementation returns. 43 | * @param implementation Address to delegate. 44 | */ 45 | function _delegate(address implementation) internal { 46 | assembly { 47 | // Copy msg.data. We take full control of memory in this inline assembly 48 | // block because it will not return to Solidity code. We overwrite the 49 | // Solidity scratch pad at memory position 0. 50 | calldatacopy(0, 0, calldatasize) 51 | 52 | // Call the implementation. 53 | // out and outsize are 0 because we don't know the size yet. 54 | let result := delegatecall(gas, implementation, 0, calldatasize, 0, 0) 55 | 56 | // Copy the returned data. 57 | returndatacopy(0, 0, returndatasize) 58 | 59 | switch result 60 | // delegatecall returns 0 on error. 61 | case 0 { revert(0, returndatasize) } 62 | default { return(0, returndatasize) } 63 | } 64 | } 65 | 66 | /** 67 | * @dev Function that is run as the first thing in the fallback function. 68 | * Can be redefined in derived contracts to add functionality. 69 | * Redefinitions must call super._willFallback(). 70 | */ 71 | function _willFallback() internal { 72 | } 73 | 74 | /** 75 | * @dev fallback implementation. 76 | * Extracted to enable manual triggering. 77 | */ 78 | function _fallback() internal { 79 | _willFallback(); 80 | _delegate(_implementation()); 81 | } 82 | } 83 | 84 | // File: contracts/zeppelin/AddressUtils.sol 85 | 86 | /** 87 | * Utility library of inline functions on addresses 88 | */ 89 | library AddressUtils { 90 | 91 | /** 92 | * Returns whether the target address is a contract 93 | * @dev This function will return false if invoked during the constructor of a contract, 94 | * as the code is not actually created until after the constructor finishes. 95 | * @param addr address to check 96 | * @return whether the target address is a contract 97 | */ 98 | function isContract(address addr) internal view returns (bool) { 99 | uint256 size; 100 | // XXX Currently there is no better way to check if there is a contract in an address 101 | // than to check the size of the code at that address. 102 | // See https://ethereum.stackexchange.com/a/14016/36603 103 | // for more details about how this works. 104 | // TODO Check this again before the Serenity release, because all addresses will be 105 | // contracts then. 106 | // solium-disable-next-line security/no-inline-assembly 107 | assembly { size := extcodesize(addr) } 108 | return size > 0; 109 | } 110 | 111 | } 112 | 113 | // File: contracts/zeppelin/UpgradeabilityProxy.sol 114 | 115 | /** 116 | * @title UpgradeabilityProxy 117 | * @dev This contract implements a proxy that allows to change the 118 | * implementation address to which it will delegate. 119 | * Such a change is called an implementation upgrade. 120 | */ 121 | contract UpgradeabilityProxy is Proxy { 122 | /** 123 | * @dev Emitted when the implementation is upgraded. 124 | * @param implementation Address of the new implementation. 125 | */ 126 | event Upgraded(address implementation); 127 | 128 | /** 129 | * @dev Storage slot with the address of the current implementation. 130 | * This is the keccak-256 hash of "org.zeppelinos.proxy.implementation", and is 131 | * validated in the constructor. 132 | */ 133 | bytes32 private constant IMPLEMENTATION_SLOT = 0x7050c9e0f4ca769c69bd3a8ef740bc37934f8e2c036e5a723fd8ee048ed3f8c3; 134 | 135 | /** 136 | * @dev Contract constructor. 137 | * @param _implementation Address of the initial implementation. 138 | */ 139 | constructor(address _implementation) public { 140 | assert(IMPLEMENTATION_SLOT == keccak256("org.zeppelinos.proxy.implementation")); 141 | 142 | _setImplementation(_implementation); 143 | } 144 | 145 | /** 146 | * @dev Returns the current implementation. 147 | * @return Address of the current implementation 148 | */ 149 | function _implementation() internal view returns (address impl) { 150 | bytes32 slot = IMPLEMENTATION_SLOT; 151 | assembly { 152 | impl := sload(slot) 153 | } 154 | } 155 | 156 | /** 157 | * @dev Upgrades the proxy to a new implementation. 158 | * @param newImplementation Address of the new implementation. 159 | */ 160 | function _upgradeTo(address newImplementation) internal { 161 | _setImplementation(newImplementation); 162 | emit Upgraded(newImplementation); 163 | } 164 | 165 | /** 166 | * @dev Sets the implementation address of the proxy. 167 | * @param newImplementation Address of the new implementation. 168 | */ 169 | function _setImplementation(address newImplementation) private { 170 | require(AddressUtils.isContract(newImplementation), "Cannot set a proxy implementation to a non-contract address"); 171 | 172 | bytes32 slot = IMPLEMENTATION_SLOT; 173 | 174 | assembly { 175 | sstore(slot, newImplementation) 176 | } 177 | } 178 | } 179 | 180 | // File: contracts/zeppelin/AdminUpgradeabilityProxy.sol 181 | 182 | /** 183 | * @title AdminUpgradeabilityProxy 184 | * @dev This contract combines an upgradeability proxy with an authorization 185 | * mechanism for administrative tasks. 186 | * All external functions in this contract must be guarded by the 187 | * `ifAdmin` modifier. See ethereum/solidity#3864 for a Solidity 188 | * feature proposal that would enable this to be done automatically. 189 | */ 190 | contract AdminUpgradeabilityProxy is UpgradeabilityProxy { 191 | /** 192 | * @dev Emitted when the administration has been transferred. 193 | * @param previousAdmin Address of the previous admin. 194 | * @param newAdmin Address of the new admin. 195 | */ 196 | event AdminChanged(address previousAdmin, address newAdmin); 197 | 198 | /** 199 | * @dev Storage slot with the admin of the contract. 200 | * This is the keccak-256 hash of "org.zeppelinos.proxy.admin", and is 201 | * validated in the constructor. 202 | */ 203 | bytes32 private constant ADMIN_SLOT = 0x10d6a54a4754c8869d6886b5f5d7fbfa5b4522237ea5c60d11bc4e7a1ff9390b; 204 | 205 | /** 206 | * @dev Modifier to check whether the `msg.sender` is the admin. 207 | * If it is, it will run the function. Otherwise, it will delegate the call 208 | * to the implementation. 209 | */ 210 | modifier ifAdmin() { 211 | if (msg.sender == _admin()) { 212 | _; 213 | } else { 214 | _fallback(); 215 | } 216 | } 217 | 218 | /** 219 | * Contract constructor. 220 | * It sets the `msg.sender` as the proxy administrator. 221 | * @param _implementation address of the initial implementation. 222 | */ 223 | constructor(address _implementation) UpgradeabilityProxy(_implementation) public { 224 | assert(ADMIN_SLOT == keccak256("org.zeppelinos.proxy.admin")); 225 | 226 | _setAdmin(msg.sender); 227 | } 228 | 229 | /** 230 | * @return The address of the proxy admin. 231 | */ 232 | function admin() external view ifAdmin returns (address) { 233 | return _admin(); 234 | } 235 | 236 | /** 237 | * @return The address of the implementation. 238 | */ 239 | function implementation() external view ifAdmin returns (address) { 240 | return _implementation(); 241 | } 242 | 243 | /** 244 | * @dev Changes the admin of the proxy. 245 | * Only the current admin can call this function. 246 | * @param newAdmin Address to transfer proxy administration to. 247 | */ 248 | function changeAdmin(address newAdmin) external ifAdmin { 249 | require(newAdmin != address(0), "Cannot change the admin of a proxy to the zero address"); 250 | emit AdminChanged(_admin(), newAdmin); 251 | _setAdmin(newAdmin); 252 | } 253 | 254 | /** 255 | * @dev Upgrade the backing implementation of the proxy. 256 | * Only the admin can call this function. 257 | * @param newImplementation Address of the new implementation. 258 | */ 259 | function upgradeTo(address newImplementation) external ifAdmin { 260 | _upgradeTo(newImplementation); 261 | } 262 | 263 | /** 264 | * @dev Upgrade the backing implementation of the proxy and call a function 265 | * on the new implementation. 266 | * This is useful to initialize the proxied contract. 267 | * @param newImplementation Address of the new implementation. 268 | * @param data Data to send as msg.data in the low level call. 269 | * It should include the signature and the parameters of the function to be 270 | * called, as described in 271 | * https://solidity.readthedocs.io/en/develop/abi-spec.html#function-selector-and-argument-encoding. 272 | */ 273 | function upgradeToAndCall(address newImplementation, bytes data) payable external ifAdmin { 274 | _upgradeTo(newImplementation); 275 | require(address(this).call.value(msg.value)(data)); 276 | } 277 | 278 | /** 279 | * @return The admin slot. 280 | */ 281 | function _admin() internal view returns (address adm) { 282 | bytes32 slot = ADMIN_SLOT; 283 | assembly { 284 | adm := sload(slot) 285 | } 286 | } 287 | 288 | /** 289 | * @dev Sets the address of the proxy admin. 290 | * @param newAdmin Address of the new proxy admin. 291 | */ 292 | function _setAdmin(address newAdmin) internal { 293 | bytes32 slot = ADMIN_SLOT; 294 | 295 | assembly { 296 | sstore(slot, newAdmin) 297 | } 298 | } 299 | 300 | /** 301 | * @dev Only fall back when the sender is not the admin. 302 | */ 303 | function _willFallback() internal { 304 | require(msg.sender != _admin(), "Cannot call fallback function from the proxy admin"); 305 | super._willFallback(); 306 | } 307 | } 308 | -------------------------------------------------------------------------------- /assets/TUSD/OwnedUpgradeabilityProxy.sol: -------------------------------------------------------------------------------- 1 | /* 2 | ======================================================================== 3 | !!!!!!!!!!!!!! 4 | !!! NOTICE !!! 5 | !!!!!!!!!!!!!! 6 | This is a test contract very similar to the formal contract. 7 | The only difference between this contract and the formal contract is 8 | that there is an additional function named allocateTo() to get token free. 9 | The actual code on the mainnet is at here: 10 | https://etherscan.io/address/0x0000000000085d4780B73119b644AE5ecd22b376#code 11 | ======================================================================== 12 | */ 13 | 14 | pragma solidity ^0.4.23; 15 | 16 | // This is the proxy contract for the TrustToken Registry 17 | 18 | // File: contracts/Proxy/Proxy.sol 19 | 20 | /** 21 | * @title Proxy 22 | * @dev Gives the possibility to delegate any call to a foreign implementation. 23 | */ 24 | contract Proxy { 25 | 26 | /** 27 | * @dev Tells the address of the implementation where every call will be delegated. 28 | * @return address of the implementation to which it will be delegated 29 | */ 30 | function implementation() public view returns (address); 31 | 32 | /** 33 | * @dev Fallback function allowing to perform a delegatecall to the given implementation. 34 | * This function will return whatever the implementation call returns 35 | */ 36 | function() external payable { 37 | address _impl = implementation(); 38 | require(_impl != address(0), "implementation contract not set"); 39 | 40 | assembly { 41 | let ptr := mload(0x40) 42 | calldatacopy(ptr, 0, calldatasize) 43 | let result := delegatecall(gas, _impl, ptr, calldatasize, 0, 0) 44 | let size := returndatasize 45 | returndatacopy(ptr, 0, size) 46 | 47 | switch result 48 | case 0 { revert(ptr, size) } 49 | default { return(ptr, size) } 50 | } 51 | } 52 | } 53 | 54 | // File: contracts/Proxy/UpgradeabilityProxy.sol 55 | 56 | /** 57 | * @title UpgradeabilityProxy 58 | * @dev This contract represents a proxy where the implementation address to which it will delegate can be upgraded 59 | */ 60 | contract UpgradeabilityProxy is Proxy { 61 | /** 62 | * @dev This event will be emitted every time the implementation gets upgraded 63 | * @param implementation representing the address of the upgraded implementation 64 | */ 65 | event Upgraded(address indexed implementation); 66 | 67 | // Storage position of the address of the current implementation 68 | bytes32 private constant implementationPosition = keccak256("trueUSD.proxy.implementation"); 69 | 70 | /** 71 | * @dev Tells the address of the current implementation 72 | * @return address of the current implementation 73 | */ 74 | function implementation() public view returns (address impl) { 75 | bytes32 position = implementationPosition; 76 | assembly { 77 | impl := sload(position) 78 | } 79 | } 80 | 81 | /** 82 | * @dev Sets the address of the current implementation 83 | * @param newImplementation address representing the new implementation to be set 84 | */ 85 | function _setImplementation(address newImplementation) internal { 86 | bytes32 position = implementationPosition; 87 | assembly { 88 | sstore(position, newImplementation) 89 | } 90 | } 91 | 92 | /** 93 | * @dev Upgrades the implementation address 94 | * @param newImplementation representing the address of the new implementation to be set 95 | */ 96 | function _upgradeTo(address newImplementation) internal { 97 | address currentImplementation = implementation(); 98 | require(currentImplementation != newImplementation); 99 | _setImplementation(newImplementation); 100 | emit Upgraded(newImplementation); 101 | } 102 | } 103 | 104 | // File: contracts/Proxy/OwnedUpgradeabilityProxy.sol 105 | 106 | /** 107 | * @title OwnedUpgradeabilityProxy 108 | * @dev This contract combines an upgradeability proxy with basic authorization control functionalities 109 | */ 110 | contract OwnedUpgradeabilityProxy is UpgradeabilityProxy { 111 | /** 112 | * @dev Event to show ownership has been transferred 113 | * @param previousOwner representing the address of the previous owner 114 | * @param newOwner representing the address of the new owner 115 | */ 116 | event ProxyOwnershipTransferred(address indexed previousOwner, address indexed newOwner); 117 | 118 | /** 119 | * @dev Event to show ownership transfer is pending 120 | * @param currentOwner representing the address of the current owner 121 | * @param pendingOwner representing the address of the pending owner 122 | */ 123 | event NewPendingOwner(address currentOwner, address pendingOwner); 124 | 125 | // Storage position of the owner and pendingOwner of the contract 126 | bytes32 private constant proxyOwnerPosition = keccak256("trueUSD.proxy.owner"); 127 | bytes32 private constant pendingProxyOwnerPosition = keccak256("trueUSD.pending.proxy.owner"); 128 | 129 | /** 130 | * @dev the constructor sets the original owner of the contract to the sender account. 131 | */ 132 | constructor() public { 133 | _setUpgradeabilityOwner(msg.sender); 134 | } 135 | 136 | /** 137 | * @dev Throws if called by any account other than the owner. 138 | */ 139 | modifier onlyProxyOwner() { 140 | require(msg.sender == proxyOwner(), "only Proxy Owner"); 141 | _; 142 | } 143 | 144 | /** 145 | * @dev Throws if called by any account other than the pending owner. 146 | */ 147 | modifier onlyPendingProxyOwner() { 148 | require(msg.sender == pendingProxyOwner(), "only pending Proxy Owner"); 149 | _; 150 | } 151 | 152 | /** 153 | * @dev Tells the address of the owner 154 | * @return the address of the owner 155 | */ 156 | function proxyOwner() public view returns (address owner) { 157 | bytes32 position = proxyOwnerPosition; 158 | assembly { 159 | owner := sload(position) 160 | } 161 | } 162 | 163 | /** 164 | * @dev Tells the address of the owner 165 | * @return the address of the owner 166 | */ 167 | function pendingProxyOwner() public view returns (address pendingOwner) { 168 | bytes32 position = pendingProxyOwnerPosition; 169 | assembly { 170 | pendingOwner := sload(position) 171 | } 172 | } 173 | 174 | /** 175 | * @dev Sets the address of the owner 176 | */ 177 | function _setUpgradeabilityOwner(address newProxyOwner) internal { 178 | bytes32 position = proxyOwnerPosition; 179 | assembly { 180 | sstore(position, newProxyOwner) 181 | } 182 | } 183 | 184 | /** 185 | * @dev Sets the address of the owner 186 | */ 187 | function _setPendingUpgradeabilityOwner(address newPendingProxyOwner) internal { 188 | bytes32 position = pendingProxyOwnerPosition; 189 | assembly { 190 | sstore(position, newPendingProxyOwner) 191 | } 192 | } 193 | 194 | /** 195 | * @dev Allows the current owner to transfer control of the contract to a newOwner. 196 | *changes the pending owner to newOwner. But doesn't actually transfer 197 | * @param newOwner The address to transfer ownership to. 198 | */ 199 | function transferProxyOwnership(address newOwner) external onlyProxyOwner { 200 | require(newOwner != address(0)); 201 | _setPendingUpgradeabilityOwner(newOwner); 202 | emit NewPendingOwner(proxyOwner(), newOwner); 203 | } 204 | 205 | /** 206 | * @dev Allows the pendingOwner to claim ownership of the proxy 207 | */ 208 | function claimProxyOwnership() external onlyPendingProxyOwner { 209 | emit ProxyOwnershipTransferred(proxyOwner(), pendingProxyOwner()); 210 | _setUpgradeabilityOwner(pendingProxyOwner()); 211 | _setPendingUpgradeabilityOwner(address(0)); 212 | } 213 | 214 | /** 215 | * @dev Allows the proxy owner to upgrade the current version of the proxy. 216 | * @param implementation representing the address of the new implementation to be set. 217 | */ 218 | function upgradeTo(address implementation) external onlyProxyOwner { 219 | _upgradeTo(implementation); 220 | } 221 | } 222 | -------------------------------------------------------------------------------- /assets/TUSD/TokenController.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.23; 2 | 3 | // This is the proxy contract for the TrustToken Registry 4 | 5 | // File: contracts/Proxy/Proxy.sol 6 | 7 | /** 8 | * @title Proxy 9 | * @dev Gives the possibility to delegate any call to a foreign implementation. 10 | */ 11 | contract Proxy { 12 | 13 | /** 14 | * @dev Tells the address of the implementation where every call will be delegated. 15 | * @return address of the implementation to which it will be delegated 16 | */ 17 | function implementation() public view returns (address); 18 | 19 | /** 20 | * @dev Fallback function allowing to perform a delegatecall to the given implementation. 21 | * This function will return whatever the implementation call returns 22 | */ 23 | function() external payable { 24 | address _impl = implementation(); 25 | require(_impl != address(0), "implementation contract not set"); 26 | 27 | assembly { 28 | let ptr := mload(0x40) 29 | calldatacopy(ptr, 0, calldatasize) 30 | let result := delegatecall(gas, _impl, ptr, calldatasize, 0, 0) 31 | let size := returndatasize 32 | returndatacopy(ptr, 0, size) 33 | 34 | switch result 35 | case 0 { revert(ptr, size) } 36 | default { return(ptr, size) } 37 | } 38 | } 39 | } 40 | 41 | // File: contracts/Proxy/UpgradeabilityProxy.sol 42 | 43 | /** 44 | * @title UpgradeabilityProxy 45 | * @dev This contract represents a proxy where the implementation address to which it will delegate can be upgraded 46 | */ 47 | contract UpgradeabilityProxy is Proxy { 48 | /** 49 | * @dev This event will be emitted every time the implementation gets upgraded 50 | * @param implementation representing the address of the upgraded implementation 51 | */ 52 | event Upgraded(address indexed implementation); 53 | 54 | // Storage position of the address of the current implementation 55 | bytes32 private constant implementationPosition = keccak256("trueUSD.proxy.implementation"); 56 | 57 | /** 58 | * @dev Tells the address of the current implementation 59 | * @return address of the current implementation 60 | */ 61 | function implementation() public view returns (address impl) { 62 | bytes32 position = implementationPosition; 63 | assembly { 64 | impl := sload(position) 65 | } 66 | } 67 | 68 | /** 69 | * @dev Sets the address of the current implementation 70 | * @param newImplementation address representing the new implementation to be set 71 | */ 72 | function _setImplementation(address newImplementation) internal { 73 | bytes32 position = implementationPosition; 74 | assembly { 75 | sstore(position, newImplementation) 76 | } 77 | } 78 | 79 | /** 80 | * @dev Upgrades the implementation address 81 | * @param newImplementation representing the address of the new implementation to be set 82 | */ 83 | function _upgradeTo(address newImplementation) internal { 84 | address currentImplementation = implementation(); 85 | require(currentImplementation != newImplementation); 86 | _setImplementation(newImplementation); 87 | emit Upgraded(newImplementation); 88 | } 89 | } 90 | 91 | // File: contracts/Proxy/OwnedUpgradeabilityProxy.sol 92 | 93 | /** 94 | * @title OwnedUpgradeabilityProxy 95 | * @dev This contract combines an upgradeability proxy with basic authorization control functionalities 96 | */ 97 | contract OwnedUpgradeabilityProxy is UpgradeabilityProxy { 98 | /** 99 | * @dev Event to show ownership has been transferred 100 | * @param previousOwner representing the address of the previous owner 101 | * @param newOwner representing the address of the new owner 102 | */ 103 | event ProxyOwnershipTransferred(address indexed previousOwner, address indexed newOwner); 104 | 105 | /** 106 | * @dev Event to show ownership transfer is pending 107 | * @param currentOwner representing the address of the current owner 108 | * @param pendingOwner representing the address of the pending owner 109 | */ 110 | event NewPendingOwner(address currentOwner, address pendingOwner); 111 | 112 | // Storage position of the owner and pendingOwner of the contract 113 | bytes32 private constant proxyOwnerPosition = keccak256("trueUSD.proxy.owner"); 114 | bytes32 private constant pendingProxyOwnerPosition = keccak256("trueUSD.pending.proxy.owner"); 115 | 116 | /** 117 | * @dev the constructor sets the original owner of the contract to the sender account. 118 | */ 119 | constructor() public { 120 | _setUpgradeabilityOwner(msg.sender); 121 | } 122 | 123 | /** 124 | * @dev Throws if called by any account other than the owner. 125 | */ 126 | modifier onlyProxyOwner() { 127 | require(msg.sender == proxyOwner(), "only Proxy Owner"); 128 | _; 129 | } 130 | 131 | /** 132 | * @dev Throws if called by any account other than the pending owner. 133 | */ 134 | modifier onlyPendingProxyOwner() { 135 | require(msg.sender == pendingProxyOwner(), "only pending Proxy Owner"); 136 | _; 137 | } 138 | 139 | /** 140 | * @dev Tells the address of the owner 141 | * @return the address of the owner 142 | */ 143 | function proxyOwner() public view returns (address owner) { 144 | bytes32 position = proxyOwnerPosition; 145 | assembly { 146 | owner := sload(position) 147 | } 148 | } 149 | 150 | /** 151 | * @dev Tells the address of the owner 152 | * @return the address of the owner 153 | */ 154 | function pendingProxyOwner() public view returns (address pendingOwner) { 155 | bytes32 position = pendingProxyOwnerPosition; 156 | assembly { 157 | pendingOwner := sload(position) 158 | } 159 | } 160 | 161 | /** 162 | * @dev Sets the address of the owner 163 | */ 164 | function _setUpgradeabilityOwner(address newProxyOwner) internal { 165 | bytes32 position = proxyOwnerPosition; 166 | assembly { 167 | sstore(position, newProxyOwner) 168 | } 169 | } 170 | 171 | /** 172 | * @dev Sets the address of the owner 173 | */ 174 | function _setPendingUpgradeabilityOwner(address newPendingProxyOwner) internal { 175 | bytes32 position = pendingProxyOwnerPosition; 176 | assembly { 177 | sstore(position, newPendingProxyOwner) 178 | } 179 | } 180 | 181 | /** 182 | * @dev Allows the current owner to transfer control of the contract to a newOwner. 183 | *changes the pending owner to newOwner. But doesn't actually transfer 184 | * @param newOwner The address to transfer ownership to. 185 | */ 186 | function transferProxyOwnership(address newOwner) external onlyProxyOwner { 187 | require(newOwner != address(0)); 188 | _setPendingUpgradeabilityOwner(newOwner); 189 | emit NewPendingOwner(proxyOwner(), newOwner); 190 | } 191 | 192 | /** 193 | * @dev Allows the pendingOwner to claim ownership of the proxy 194 | */ 195 | function claimProxyOwnership() external onlyPendingProxyOwner { 196 | emit ProxyOwnershipTransferred(proxyOwner(), pendingProxyOwner()); 197 | _setUpgradeabilityOwner(pendingProxyOwner()); 198 | _setPendingUpgradeabilityOwner(address(0)); 199 | } 200 | 201 | /** 202 | * @dev Allows the proxy owner to upgrade the current version of the proxy. 203 | * @param implementation representing the address of the new implementation to be set. 204 | */ 205 | function upgradeTo(address implementation) external onlyProxyOwner { 206 | _upgradeTo(implementation); 207 | } 208 | } 209 | -------------------------------------------------------------------------------- /assets/USDC/FiatTokenProxy.sol: -------------------------------------------------------------------------------- 1 | /** 2 | ======================================================================== 3 | Notice!!! : 4 | this is a test contract with function allocateTo() to get token free 5 | the actual code on the mainnet is at here: 6 | https://etherscan.io/address/0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48#code 7 | ======================================================================== 8 | */ 9 | 10 | pragma solidity ^0.4.24; 11 | 12 | // File: zos-lib/contracts/upgradeability/Proxy.sol 13 | 14 | /** 15 | * @title Proxy 16 | * @dev Implements delegation of calls to other contracts, with proper 17 | * forwarding of return values and bubbling of failures. 18 | * It defines a fallback function that delegates all calls to the address 19 | * returned by the abstract _implementation() internal function. 20 | */ 21 | contract Proxy { 22 | /** 23 | * @dev Fallback function. 24 | * Implemented entirely in `_fallback`. 25 | */ 26 | function () payable external { 27 | _fallback(); 28 | } 29 | 30 | /** 31 | * @return The Address of the implementation. 32 | */ 33 | function _implementation() internal view returns (address); 34 | 35 | /** 36 | * @dev Delegates execution to an implementation contract. 37 | * This is a low level function that doesn't return to its internal call site. 38 | * It will return to the external caller whatever the implementation returns. 39 | * @param implementation Address to delegate. 40 | */ 41 | function _delegate(address implementation) internal { 42 | assembly { 43 | // Copy msg.data. We take full control of memory in this inline assembly 44 | // block because it will not return to Solidity code. We overwrite the 45 | // Solidity scratch pad at memory position 0. 46 | calldatacopy(0, 0, calldatasize) 47 | 48 | // Call the implementation. 49 | // out and outsize are 0 because we don't know the size yet. 50 | let result := delegatecall(gas, implementation, 0, calldatasize, 0, 0) 51 | 52 | // Copy the returned data. 53 | returndatacopy(0, 0, returndatasize) 54 | 55 | switch result 56 | // delegatecall returns 0 on error. 57 | case 0 { revert(0, returndatasize) } 58 | default { return(0, returndatasize) } 59 | } 60 | } 61 | 62 | /** 63 | * @dev Function that is run as the first thing in the fallback function. 64 | * Can be redefined in derived contracts to add functionality. 65 | * Redefinitions must call super._willFallback(). 66 | */ 67 | function _willFallback() internal { 68 | } 69 | 70 | /** 71 | * @dev fallback implementation. 72 | * Extracted to enable manual triggering. 73 | */ 74 | function _fallback() internal { 75 | _willFallback(); 76 | _delegate(_implementation()); 77 | } 78 | } 79 | 80 | // File: openzeppelin-solidity/contracts/AddressUtils.sol 81 | 82 | /** 83 | * Utility library of inline functions on addresses 84 | */ 85 | library AddressUtils { 86 | 87 | /** 88 | * Returns whether the target address is a contract 89 | * @dev This function will return false if invoked during the constructor of a contract, 90 | * as the code is not actually created until after the constructor finishes. 91 | * @param addr address to check 92 | * @return whether the target address is a contract 93 | */ 94 | function isContract(address addr) internal view returns (bool) { 95 | uint256 size; 96 | // XXX Currently there is no better way to check if there is a contract in an address 97 | // than to check the size of the code at that address. 98 | // See https://ethereum.stackexchange.com/a/14016/36603 99 | // for more details about how this works. 100 | // TODO Check this again before the Serenity release, because all addresses will be 101 | // contracts then. 102 | // solium-disable-next-line security/no-inline-assembly 103 | assembly { size := extcodesize(addr) } 104 | return size > 0; 105 | } 106 | 107 | } 108 | 109 | // File: zos-lib/contracts/upgradeability/UpgradeabilityProxy.sol 110 | 111 | /** 112 | * @title UpgradeabilityProxy 113 | * @dev This contract implements a proxy that allows to change the 114 | * implementation address to which it will delegate. 115 | * Such a change is called an implementation upgrade. 116 | */ 117 | contract UpgradeabilityProxy is Proxy { 118 | /** 119 | * @dev Emitted when the implementation is upgraded. 120 | * @param implementation Address of the new implementation. 121 | */ 122 | event Upgraded(address implementation); 123 | 124 | /** 125 | * @dev Storage slot with the address of the current implementation. 126 | * This is the keccak-256 hash of "org.zeppelinos.proxy.implementation", and is 127 | * validated in the constructor. 128 | */ 129 | bytes32 private constant IMPLEMENTATION_SLOT = 0x7050c9e0f4ca769c69bd3a8ef740bc37934f8e2c036e5a723fd8ee048ed3f8c3; 130 | 131 | /** 132 | * @dev Contract constructor. 133 | * @param _implementation Address of the initial implementation. 134 | */ 135 | constructor(address _implementation) public { 136 | assert(IMPLEMENTATION_SLOT == keccak256("org.zeppelinos.proxy.implementation")); 137 | 138 | _setImplementation(_implementation); 139 | } 140 | 141 | /** 142 | * @dev Returns the current implementation. 143 | * @return Address of the current implementation 144 | */ 145 | function _implementation() internal view returns (address impl) { 146 | bytes32 slot = IMPLEMENTATION_SLOT; 147 | assembly { 148 | impl := sload(slot) 149 | } 150 | } 151 | 152 | /** 153 | * @dev Upgrades the proxy to a new implementation. 154 | * @param newImplementation Address of the new implementation. 155 | */ 156 | function _upgradeTo(address newImplementation) internal { 157 | _setImplementation(newImplementation); 158 | emit Upgraded(newImplementation); 159 | } 160 | 161 | /** 162 | * @dev Sets the implementation address of the proxy. 163 | * @param newImplementation Address of the new implementation. 164 | */ 165 | function _setImplementation(address newImplementation) private { 166 | require(AddressUtils.isContract(newImplementation), "Cannot set a proxy implementation to a non-contract address"); 167 | 168 | bytes32 slot = IMPLEMENTATION_SLOT; 169 | 170 | assembly { 171 | sstore(slot, newImplementation) 172 | } 173 | } 174 | } 175 | 176 | // File: zos-lib/contracts/upgradeability/AdminUpgradeabilityProxy.sol 177 | 178 | /** 179 | * @title AdminUpgradeabilityProxy 180 | * @dev This contract combines an upgradeability proxy with an authorization 181 | * mechanism for administrative tasks. 182 | * All external functions in this contract must be guarded by the 183 | * `ifAdmin` modifier. See ethereum/solidity#3864 for a Solidity 184 | * feature proposal that would enable this to be done automatically. 185 | */ 186 | contract AdminUpgradeabilityProxy is UpgradeabilityProxy { 187 | /** 188 | * @dev Emitted when the administration has been transferred. 189 | * @param previousAdmin Address of the previous admin. 190 | * @param newAdmin Address of the new admin. 191 | */ 192 | event AdminChanged(address previousAdmin, address newAdmin); 193 | 194 | /** 195 | * @dev Storage slot with the admin of the contract. 196 | * This is the keccak-256 hash of "org.zeppelinos.proxy.admin", and is 197 | * validated in the constructor. 198 | */ 199 | bytes32 private constant ADMIN_SLOT = 0x10d6a54a4754c8869d6886b5f5d7fbfa5b4522237ea5c60d11bc4e7a1ff9390b; 200 | 201 | /** 202 | * @dev Modifier to check whether the `msg.sender` is the admin. 203 | * If it is, it will run the function. Otherwise, it will delegate the call 204 | * to the implementation. 205 | */ 206 | modifier ifAdmin() { 207 | if (msg.sender == _admin()) { 208 | _; 209 | } else { 210 | _fallback(); 211 | } 212 | } 213 | 214 | /** 215 | * Contract constructor. 216 | * It sets the `msg.sender` as the proxy administrator. 217 | * @param _implementation address of the initial implementation. 218 | */ 219 | constructor(address _implementation) UpgradeabilityProxy(_implementation) public { 220 | assert(ADMIN_SLOT == keccak256("org.zeppelinos.proxy.admin")); 221 | 222 | _setAdmin(msg.sender); 223 | } 224 | 225 | /** 226 | * @return The address of the proxy admin. 227 | */ 228 | function admin() external view ifAdmin returns (address) { 229 | return _admin(); 230 | } 231 | 232 | /** 233 | * @return The address of the implementation. 234 | */ 235 | function implementation() external view ifAdmin returns (address) { 236 | return _implementation(); 237 | } 238 | 239 | /** 240 | * @dev Changes the admin of the proxy. 241 | * Only the current admin can call this function. 242 | * @param newAdmin Address to transfer proxy administration to. 243 | */ 244 | function changeAdmin(address newAdmin) external ifAdmin { 245 | require(newAdmin != address(0), "Cannot change the admin of a proxy to the zero address"); 246 | emit AdminChanged(_admin(), newAdmin); 247 | _setAdmin(newAdmin); 248 | } 249 | 250 | /** 251 | * @dev Upgrade the backing implementation of the proxy. 252 | * Only the admin can call this function. 253 | * @param newImplementation Address of the new implementation. 254 | */ 255 | function upgradeTo(address newImplementation) external ifAdmin { 256 | _upgradeTo(newImplementation); 257 | } 258 | 259 | /** 260 | * @dev Upgrade the backing implementation of the proxy and call a function 261 | * on the new implementation. 262 | * This is useful to initialize the proxied contract. 263 | * @param newImplementation Address of the new implementation. 264 | * @param data Data to send as msg.data in the low level call. 265 | * It should include the signature and the parameters of the function to be 266 | * called, as described in 267 | * https://solidity.readthedocs.io/en/develop/abi-spec.html#function-selector-and-argument-encoding. 268 | */ 269 | function upgradeToAndCall(address newImplementation, bytes data) payable external ifAdmin { 270 | _upgradeTo(newImplementation); 271 | require(address(this).call.value(msg.value)(data)); 272 | } 273 | 274 | /** 275 | * @return The admin slot. 276 | */ 277 | function _admin() internal view returns (address adm) { 278 | bytes32 slot = ADMIN_SLOT; 279 | assembly { 280 | adm := sload(slot) 281 | } 282 | } 283 | 284 | /** 285 | * @dev Sets the address of the proxy admin. 286 | * @param newAdmin Address of the new proxy admin. 287 | */ 288 | function _setAdmin(address newAdmin) internal { 289 | bytes32 slot = ADMIN_SLOT; 290 | 291 | assembly { 292 | sstore(slot, newAdmin) 293 | } 294 | } 295 | 296 | /** 297 | * @dev Only fall back when the sender is not the admin. 298 | */ 299 | function _willFallback() internal { 300 | require(msg.sender != _admin(), "Cannot call fallback function from the proxy admin"); 301 | super._willFallback(); 302 | } 303 | } 304 | 305 | // File: contracts/FiatTokenProxy.sol 306 | 307 | /** 308 | * Copyright CENTRE SECZ 2018 309 | * 310 | * Permission is hereby granted, free of charge, to any person obtaining a copy 311 | * of this software and associated documentation files (the "Software"), to deal 312 | * in the Software without restriction, including without limitation the rights 313 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 314 | * copies of the Software, and to permit persons to whom the Software is furnished to 315 | * do so, subject to the following conditions: 316 | * 317 | * The above copyright notice and this permission notice shall be included in all 318 | * copies or substantial portions of the Software. 319 | * 320 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 321 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 322 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 323 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 324 | * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 325 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 326 | */ 327 | 328 | pragma solidity ^0.4.24; 329 | 330 | 331 | /** 332 | * @title FiatTokenProxy 333 | * @dev This contract proxies FiatToken calls and enables FiatToken upgrades 334 | */ 335 | contract FiatTokenProxy is AdminUpgradeabilityProxy { 336 | constructor(address _implementation) public AdminUpgradeabilityProxy(_implementation) { 337 | } 338 | } 339 | -------------------------------------------------------------------------------- /assets/USDxFaucet.sol: -------------------------------------------------------------------------------- 1 | /* 2 | ======================================================================== 3 | !!!!!!!!!!!!!! 4 | !!! NOTICE !!! 5 | !!!!!!!!!!!!!! 6 | This is a test contract very similar to the formal contract. 7 | The only difference between this contract and the formal contract is 8 | that there is an additional function named allocateTo() to get token free. 9 | The actual code on the mainnet is at here: 10 | https://etherscan.io/address/0xeb269732ab75a6fd61ea60b06fe994cd32a83549#code 11 | ======================================================================== 12 | */ 13 | 14 | pragma solidity ^0.5.2; 15 | 16 | contract DSMath { 17 | function add(uint x, uint y) internal pure returns (uint z) { 18 | require((z = x + y) >= x, "ds-math-add-overflow"); 19 | } 20 | function sub(uint x, uint y) internal pure returns (uint z) { 21 | require((z = x - y) <= x, "ds-math-sub-underflow"); 22 | } 23 | function mul(uint x, uint y) internal pure returns (uint z) { 24 | require(y == 0 || (z = x * y) / y == x, "ds-math-mul-overflow"); 25 | } 26 | 27 | function div(uint x, uint y) internal pure returns (uint z) { 28 | require(y > 0, "ds-math-div-overflow"); 29 | z = x / y; 30 | } 31 | 32 | function min(uint x, uint y) internal pure returns (uint z) { 33 | return x <= y ? x : y; 34 | } 35 | function max(uint x, uint y) internal pure returns (uint z) { 36 | return x >= y ? x : y; 37 | } 38 | // function imin(int x, int y) internal pure returns (int z) { 39 | // return x <= y ? x : y; 40 | // } 41 | // function imax(int x, int y) internal pure returns (int z) { 42 | // return x >= y ? x : y; 43 | // } 44 | 45 | uint constant WAD = 10 ** 18; 46 | // uint constant RAY = 10 ** 27; 47 | 48 | // function wmul(uint x, uint y) internal pure returns (uint z) { 49 | // z = add(mul(x, y), WAD / 2) / WAD; 50 | // } 51 | // function rmul(uint x, uint y) internal pure returns (uint z) { 52 | // z = add(mul(x, y), RAY / 2) / RAY; 53 | // } 54 | function wdiv(uint x, uint y) internal pure returns (uint z) { 55 | z = add(mul(x, WAD), y / 2) / y; 56 | } 57 | // function rdiv(uint x, uint y) internal pure returns (uint z) { 58 | // z = add(mul(x, RAY), y / 2) / y; 59 | // } 60 | 61 | // This famous algorithm is called "exponentiation by squaring" 62 | // and calculates x^n with x as fixed-point and n as regular unsigned. 63 | // 64 | // It's O(log n), instead of O(n) for naive repeated multiplication. 65 | // 66 | // These facts are why it works: 67 | // 68 | // If n is even, then x^n = (x^2)^(n/2). 69 | // If n is odd, then x^n = x * x^(n-1), 70 | // and applying the equation for even x gives 71 | // x^n = x * (x^2)^((n-1) / 2). 72 | // 73 | // Also, EVM division is flooring and 74 | // floor[(n-1) / 2] = floor[n / 2]. 75 | // 76 | // function rpow(uint _x, uint n) internal pure returns (uint z) { 77 | // uint x = _x; 78 | // z = n % 2 != 0 ? x : RAY; 79 | 80 | // for (n /= 2; n != 0; n /= 2) { 81 | // x = rmul(x, x); 82 | 83 | // if (n % 2 != 0) { 84 | // z = rmul(z, x); 85 | // } 86 | // } 87 | // } 88 | 89 | /** 90 | * @dev x to the power of y power(base, exponent) 91 | */ 92 | function pow(uint256 base, uint256 exponent) public pure returns (uint256) { 93 | if (exponent == 0) { 94 | return 1; 95 | } 96 | else if (exponent == 1) { 97 | return base; 98 | } 99 | else if (base == 0 && exponent != 0) { 100 | return 0; 101 | } 102 | else { 103 | uint256 z = base; 104 | for (uint256 i = 1; i < exponent; i++) 105 | z = mul(z, base); 106 | return z; 107 | } 108 | } 109 | } 110 | 111 | contract DSAuthEvents { 112 | event LogSetAuthority (address indexed authority); 113 | event LogSetOwner (address indexed owner); 114 | } 115 | 116 | contract DSAuth is DSAuthEvents { 117 | address public authority; 118 | address public owner; 119 | 120 | constructor() public { 121 | owner = msg.sender; 122 | emit LogSetOwner(msg.sender); 123 | } 124 | 125 | function setOwner(address owner_) 126 | public 127 | onlyOwner 128 | { 129 | require(owner_ != address(0), "invalid owner address"); 130 | owner = owner_; 131 | emit LogSetOwner(owner); 132 | } 133 | 134 | function setAuthority(address authority_) 135 | public 136 | onlyOwner 137 | { 138 | authority = authority_; 139 | emit LogSetAuthority(address(authority)); 140 | } 141 | 142 | modifier auth { 143 | require(isAuthorized(msg.sender), "ds-auth-unauthorized"); 144 | _; 145 | } 146 | 147 | modifier onlyOwner { 148 | require(isOwner(msg.sender), "ds-auth-non-owner"); 149 | _; 150 | } 151 | 152 | function isOwner(address src) public view returns (bool) { 153 | return bool(src == owner); 154 | } 155 | 156 | function isAuthorized(address src) internal view returns (bool) { 157 | if (src == address(this)) { 158 | return true; 159 | } else if (src == owner) { 160 | return true; 161 | } else if (authority == address(0)) { 162 | return false; 163 | } else if (src == authority) { 164 | return true; 165 | } else { 166 | return false; 167 | } 168 | } 169 | } 170 | 171 | contract DSNote { 172 | event LogNote( 173 | bytes4 indexed sig, 174 | address indexed guy, 175 | bytes32 indexed foo, 176 | bytes32 indexed bar, 177 | uint256 wad, 178 | bytes fax 179 | ) anonymous; 180 | 181 | modifier note { 182 | bytes32 foo; 183 | bytes32 bar; 184 | uint256 wad; 185 | 186 | assembly { 187 | foo := calldataload(4) 188 | bar := calldataload(36) 189 | wad := callvalue 190 | } 191 | 192 | emit LogNote(msg.sig, msg.sender, foo, bar, wad, msg.data); 193 | 194 | _; 195 | } 196 | } 197 | 198 | contract DSStop is DSNote, DSAuth, DSMath { 199 | bool public stopped; 200 | 201 | modifier stoppable { 202 | require(!stopped, "ds-stop-is-stopped"); 203 | _; 204 | } 205 | function stop() public onlyOwner note { 206 | stopped = true; 207 | } 208 | function start() public onlyOwner note { 209 | stopped = false; 210 | } 211 | } 212 | 213 | contract ERC20Events { 214 | event Approval(address indexed src, address indexed guy, uint wad); 215 | event Transfer(address indexed src, address indexed dst, uint wad); 216 | } 217 | 218 | contract ERC20 is ERC20Events { 219 | function totalSupply() public view returns (uint); 220 | function balanceOf(address guy) public view returns (uint); 221 | function allowance(address src, address guy) public view returns (uint); 222 | 223 | function approve(address guy, uint wad) public returns (bool); 224 | function transfer(address dst, uint wad) public returns (bool); 225 | function transferFrom(address src, address dst, uint wad) public returns (bool); 226 | } 227 | 228 | contract DSTokenBase is ERC20, DSMath { 229 | uint256 _supply; 230 | mapping (address => uint256) _balances; 231 | mapping (address => mapping (address => uint256)) _approvals; 232 | 233 | constructor(uint supply) public { 234 | _supply = supply; 235 | } 236 | 237 | function totalSupply() public view returns (uint) { 238 | return _supply; 239 | } 240 | function balanceOf(address src) public view returns (uint) { 241 | return _balances[src]; 242 | } 243 | function allowance(address src, address guy) public view returns (uint) { 244 | return _approvals[src][guy]; 245 | } 246 | 247 | function transfer(address dst, uint wad) public returns (bool) { 248 | return transferFrom(msg.sender, dst, wad); 249 | } 250 | 251 | function transferFrom(address src, address dst, uint wad) 252 | public 253 | returns (bool) 254 | { 255 | if (src != msg.sender) { 256 | require(_approvals[src][msg.sender] >= wad, "ds-token-insufficient-approval"); 257 | _approvals[src][msg.sender] = sub(_approvals[src][msg.sender], wad); 258 | } 259 | 260 | require(_balances[src] >= wad, "ds-token-insufficient-balance"); 261 | _balances[src] = sub(_balances[src], wad); 262 | _balances[dst] = add(_balances[dst], wad); 263 | 264 | emit Transfer(src, dst, wad); 265 | 266 | return true; 267 | } 268 | 269 | function approve(address guy, uint wad) public returns (bool) { 270 | _approvals[msg.sender][guy] = wad; 271 | 272 | emit Approval(msg.sender, guy, wad); 273 | 274 | return true; 275 | } 276 | } 277 | 278 | contract DSToken is DSTokenBase(0), DSStop { 279 | 280 | bytes32 public name = ""; 281 | bytes32 public symbol; 282 | uint256 public decimals = 18; 283 | 284 | constructor(bytes32 symbol_) public { 285 | symbol = symbol_; 286 | } 287 | 288 | function setName(bytes32 name_) public onlyOwner { 289 | name = name_; 290 | } 291 | 292 | function approvex(address guy) public stoppable returns (bool) { 293 | return super.approve(guy, uint(-1)); 294 | } 295 | 296 | function approve(address guy, uint wad) public stoppable returns (bool) { 297 | require(_approvals[msg.sender][guy] == 0 || wad == 0); //take care of re-approve. 298 | return super.approve(guy, wad); 299 | } 300 | 301 | function transferFrom(address src, address dst, uint wad) 302 | public 303 | stoppable 304 | returns (bool) 305 | { 306 | if (src != msg.sender && _approvals[src][msg.sender] != uint(-1)) { 307 | require(_approvals[src][msg.sender] >= wad, "ds-token-insufficient-approval"); 308 | _approvals[src][msg.sender] = sub(_approvals[src][msg.sender], wad); 309 | } 310 | 311 | require(_balances[src] >= wad, "ds-token-insufficient-balance"); 312 | _balances[src] = sub(_balances[src], wad); 313 | _balances[dst] = add(_balances[dst], wad); 314 | 315 | emit Transfer(src, dst, wad); 316 | 317 | return true; 318 | } 319 | 320 | function mint(address guy, uint wad) public auth stoppable { 321 | _mint(guy, wad); 322 | } 323 | 324 | function burn(address guy, uint wad) public auth stoppable { 325 | _burn(guy, wad); 326 | } 327 | 328 | function _mint(address guy, uint wad) internal { 329 | require(guy != address(0), "ds-token-mint: mint to the zero address"); 330 | 331 | _balances[guy] = add(_balances[guy], wad); 332 | _supply = add(_supply, wad); 333 | emit Transfer(address(0), guy, wad); 334 | } 335 | 336 | function _burn(address guy, uint wad) internal { 337 | require(guy != address(0), "ds-token-burn: burn from the zero address"); 338 | require(_balances[guy] >= wad, "ds-token-insufficient-balance"); 339 | 340 | if (guy != msg.sender && _approvals[guy][msg.sender] != uint(-1)) { 341 | require(_approvals[guy][msg.sender] >= wad, "ds-token-insufficient-approval"); 342 | _approvals[guy][msg.sender] = sub(_approvals[guy][msg.sender], wad); 343 | } 344 | 345 | _balances[guy] = sub(_balances[guy], wad); 346 | _supply = sub(_supply, wad); 347 | emit Transfer(guy, address(0), wad); 348 | } 349 | 350 | // This is not a function used in actual production 351 | // Only for getting free token to test 352 | function allocateTo(address owner, uint256 value) public { 353 | _balances[owner] += value; 354 | emit Transfer(address(this), owner, value); 355 | } 356 | } 357 | -------------------------------------------------------------------------------- /contracts/CarefulMath.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.24; 2 | 3 | import "./ErrorReporter.sol"; 4 | 5 | /** 6 | * @title Careful Math 7 | * @notice Derived from OpenZeppelin's SafeMath library 8 | * https://github.com/OpenZeppelin/openzeppelin-solidity/blob/master/contracts/math/SafeMath.sol 9 | */ 10 | contract CarefulMath is ErrorReporter { 11 | /** 12 | * @dev Multiplies two numbers, returns an error on overflow. 13 | */ 14 | function mul(uint a, uint b) internal pure returns (Error, uint) { 15 | if (a == 0) { 16 | return (Error.NO_ERROR, 0); 17 | } 18 | 19 | uint c = a * b; 20 | 21 | if (c / a != b) { 22 | return (Error.INTEGER_OVERFLOW, 0); 23 | } else { 24 | return (Error.NO_ERROR, c); 25 | } 26 | } 27 | 28 | /** 29 | * @dev Integer division of two numbers, truncating the quotient. 30 | */ 31 | function div(uint a, uint b) internal pure returns (Error, uint) { 32 | if (b == 0) { 33 | return (Error.DIVISION_BY_ZERO, 0); 34 | } 35 | 36 | return (Error.NO_ERROR, a / b); 37 | } 38 | 39 | /** 40 | * @dev Subtracts two numbers, returns an error on overflow (i.e. if subtrahend is greater than minuend). 41 | */ 42 | function sub(uint a, uint b) internal pure returns (Error, uint) { 43 | if (b <= a) { 44 | return (Error.NO_ERROR, a - b); 45 | } else { 46 | return (Error.INTEGER_UNDERFLOW, 0); 47 | } 48 | } 49 | 50 | /** 51 | * @dev Adds two numbers, returns an error on overflow. 52 | */ 53 | function add(uint a, uint b) internal pure returns (Error, uint) { 54 | uint c = a + b; 55 | 56 | if (c >= a) { 57 | return (Error.NO_ERROR, c); 58 | } else { 59 | return (Error.INTEGER_OVERFLOW, 0); 60 | } 61 | } 62 | 63 | /** 64 | * @dev add a and b and then subtract c 65 | */ 66 | function addThenSub(uint a, uint b, uint c) internal pure returns (Error, uint) { 67 | (Error err0, uint sum) = add(a, b); 68 | 69 | if (err0 != Error.NO_ERROR) { 70 | return (err0, 0); 71 | } 72 | 73 | return sub(sum, c); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /contracts/EIP20Interface.sol: -------------------------------------------------------------------------------- 1 | // Abstract contract for the full ERC 20 Token standard 2 | // https://github.com/ethereum/EIPs/issues/20 3 | pragma solidity ^0.4.24; 4 | 5 | 6 | contract EIP20Interface { 7 | /* This is a slight change to the ERC20 base standard. 8 | function totalSupply() constant returns (uint256 supply); 9 | is replaced with: 10 | uint256 public totalSupply; 11 | This automatically creates a getter function for the totalSupply. 12 | This is moved to the base contract since public getter functions are not 13 | currently recognised as an implementation of the matching abstract 14 | function by the compiler. 15 | */ 16 | // total amount of tokens 17 | uint256 public totalSupply; 18 | /** 19 | * @param _owner The address from which the balance will be retrieved 20 | * @return The balance 21 | */ 22 | function balanceOf(address _owner) public view returns (uint256 balance); 23 | 24 | /** 25 | * @notice send `_value` token to `_to` from `msg.sender` 26 | * @param _to The address of the recipient 27 | * @param _value The amount of token to be transferred 28 | * @return Whether the transfer was successful or not 29 | */ 30 | function transfer(address _to, uint256 _value) public returns (bool success); 31 | 32 | /** 33 | * @notice send `_value` token to `_to` from `_from` on the condition it is approved by `_from` 34 | * @param _from The address of the sender 35 | * @param _to The address of the recipient 36 | * @param _value The amount of token to be transferred 37 | * @return Whether the transfer was successful or not 38 | */ 39 | function transferFrom(address _from, address _to, uint256 _value) public returns (bool success); 40 | 41 | /** 42 | * @notice `msg.sender` approves `_spender` to spend `_value` tokens 43 | * @param _spender The address of the account able to transfer the tokens 44 | * @param _value The amount of tokens to be approved for transfer 45 | * @return Whether the approval was successful or not 46 | */ 47 | function approve(address _spender, uint256 _value) public returns (bool success); 48 | 49 | /** 50 | * @param _owner The address of the account owning tokens 51 | * @param _spender The address of the account able to transfer the tokens 52 | * @return Amount of remaining tokens allowed to spent 53 | */ 54 | function allowance(address _owner, address _spender) public view returns (uint256 remaining); 55 | 56 | // solhint-disable-next-line no-simple-event-func-name 57 | event Transfer(address indexed _from, address indexed _to, uint256 _value); 58 | event Approval(address indexed _owner, address indexed _spender, uint256 _value); 59 | } 60 | -------------------------------------------------------------------------------- /contracts/EIP20NonStandardInterface.sol: -------------------------------------------------------------------------------- 1 | // Abstract contract for the full ERC 20 Token standard 2 | // https://github.com/ethereum/EIPs/issues/20 3 | pragma solidity ^0.4.24; 4 | 5 | /** 6 | * @title EIP20NonStandardInterface 7 | * @dev Version of ERC20 with no return values for `transfer` and `transferFrom` 8 | * See https://medium.com/coinmonks/missing-return-value-bug-at-least-130-tokens-affected-d67bf08521ca 9 | */ 10 | contract EIP20NonStandardInterface { 11 | /* This is a slight change to the ERC20 base standard. 12 | function totalSupply() constant returns (uint256 supply); 13 | is replaced with: 14 | uint256 public totalSupply; 15 | This automatically creates a getter function for the totalSupply. 16 | This is moved to the base contract since public getter functions are not 17 | currently recognised as an implementation of the matching abstract 18 | function by the compiler. 19 | */ 20 | // total amount of tokens 21 | uint256 public totalSupply; 22 | 23 | /** 24 | * @param _owner The address from which the balance will be retrieved 25 | * @return The balance 26 | */ 27 | function balanceOf(address _owner) public view returns (uint256 balance); 28 | 29 | /** 30 | * !!!!!!!!!!!!!! 31 | * !!! NOTICE !!! `transfer` does not return a value, in violation of the ERC-20 specification 32 | * !!!!!!!!!!!!!! 33 | * 34 | * @notice send `_value` token to `_to` from `msg.sender` 35 | * @param _to The address of the recipient 36 | * @param _value The amount of token to be transferred 37 | * @return Whether the transfer was successful or not 38 | */ 39 | function transfer(address _to, uint256 _value) public; 40 | 41 | /** 42 | * 43 | * !!!!!!!!!!!!!! 44 | * !!! NOTICE !!! `transferFrom` does not return a value, in violation of the ERC-20 specification 45 | * !!!!!!!!!!!!!! 46 | * 47 | * @notice send `_value` token to `_to` from `_from` on the condition it is approved by `_from` 48 | * @param _from The address of the sender 49 | * @param _to The address of the recipient 50 | * @param _value The amount of token to be transferred 51 | * @return Whether the transfer was successful or not 52 | */ 53 | function transferFrom(address _from, address _to, uint256 _value) public; 54 | 55 | /** 56 | * @notice `msg.sender` approves `_spender` to spend `_value` tokens 57 | * @param _spender The address of the account able to transfer the tokens 58 | * @param _value The amount of tokens to be approved for transfer 59 | * @return Whether the approval was successful or not 60 | */ 61 | function approve(address _spender, uint256 _value) public; 62 | 63 | /** 64 | * @param _owner The address of the account owning tokens 65 | * @param _spender The address of the account able to transfer the tokens 66 | * @return Amount of remaining tokens allowed to spent 67 | */ 68 | function allowance(address _owner, address _spender) public view returns (uint256 remaining); 69 | 70 | // solhint-disable-next-line no-simple-event-func-name 71 | event Transfer(address indexed _from, address indexed _to, uint256 _value); 72 | event Approval(address indexed _owner, address indexed _spender, uint256 _value); 73 | } 74 | -------------------------------------------------------------------------------- /contracts/ErrorReporter.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.24; 2 | 3 | contract ErrorReporter { 4 | /** 5 | * @dev `error` corresponds to enum Error; `info` corresponds to enum FailureInfo, and `detail` is an arbitrary 6 | * contract-specific code that enables us to report opaque error codes from upgradeable contracts. 7 | */ 8 | event Failure(uint error, uint info, uint detail); 9 | 10 | enum Error { 11 | NO_ERROR, 12 | OPAQUE_ERROR, // To be used when reporting errors from upgradeable contracts; the opaque code should be given as `detail` in the `Failure` event 13 | UNAUTHORIZED, 14 | INTEGER_OVERFLOW, 15 | INTEGER_UNDERFLOW, 16 | DIVISION_BY_ZERO, 17 | BAD_INPUT, 18 | TOKEN_INSUFFICIENT_ALLOWANCE, 19 | TOKEN_INSUFFICIENT_BALANCE, 20 | TOKEN_TRANSFER_FAILED, 21 | MARKET_NOT_SUPPORTED, 22 | SUPPLY_RATE_CALCULATION_FAILED, 23 | BORROW_RATE_CALCULATION_FAILED, 24 | TOKEN_INSUFFICIENT_CASH, 25 | TOKEN_TRANSFER_OUT_FAILED, 26 | INSUFFICIENT_LIQUIDITY, 27 | INSUFFICIENT_BALANCE, 28 | INVALID_COLLATERAL_RATIO, 29 | MISSING_ASSET_PRICE, 30 | EQUITY_INSUFFICIENT_BALANCE, 31 | INVALID_CLOSE_AMOUNT_REQUESTED, 32 | ASSET_NOT_PRICED, 33 | INVALID_LIQUIDATION_DISCOUNT, 34 | INVALID_COMBINED_RISK_PARAMETERS, 35 | ZERO_ORACLE_ADDRESS, 36 | CONTRACT_PAUSED 37 | } 38 | 39 | /** 40 | * Note: FailureInfo (but not Error) is kept in alphabetical order 41 | * This is because FailureInfo grows significantly faster, and 42 | * the order of Error has some meaning, while the order of FailureInfo 43 | * is entirely arbitrary. 44 | */ 45 | enum FailureInfo { 46 | ACCEPT_ADMIN_PENDING_ADMIN_CHECK, 47 | BORROW_ACCOUNT_LIQUIDITY_CALCULATION_FAILED, 48 | BORROW_ACCOUNT_SHORTFALL_PRESENT, 49 | BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED, 50 | BORROW_AMOUNT_LIQUIDITY_SHORTFALL, 51 | BORROW_AMOUNT_VALUE_CALCULATION_FAILED, 52 | BORROW_CONTRACT_PAUSED, 53 | BORROW_MARKET_NOT_SUPPORTED, 54 | BORROW_NEW_BORROW_INDEX_CALCULATION_FAILED, 55 | BORROW_NEW_BORROW_RATE_CALCULATION_FAILED, 56 | BORROW_NEW_SUPPLY_INDEX_CALCULATION_FAILED, 57 | BORROW_NEW_SUPPLY_RATE_CALCULATION_FAILED, 58 | BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED, 59 | BORROW_NEW_TOTAL_BORROW_CALCULATION_FAILED, 60 | BORROW_NEW_TOTAL_CASH_CALCULATION_FAILED, 61 | BORROW_ORIGINATION_FEE_CALCULATION_FAILED, 62 | BORROW_TRANSFER_OUT_FAILED, 63 | EQUITY_WITHDRAWAL_AMOUNT_VALIDATION, 64 | EQUITY_WITHDRAWAL_CALCULATE_EQUITY, 65 | EQUITY_WITHDRAWAL_MODEL_OWNER_CHECK, 66 | EQUITY_WITHDRAWAL_TRANSFER_OUT_FAILED, 67 | LIQUIDATE_ACCUMULATED_BORROW_BALANCE_CALCULATION_FAILED, 68 | LIQUIDATE_ACCUMULATED_SUPPLY_BALANCE_CALCULATION_FAILED_BORROWER_COLLATERAL_ASSET, 69 | LIQUIDATE_ACCUMULATED_SUPPLY_BALANCE_CALCULATION_FAILED_LIQUIDATOR_COLLATERAL_ASSET, 70 | LIQUIDATE_AMOUNT_SEIZE_CALCULATION_FAILED, 71 | LIQUIDATE_BORROW_DENOMINATED_COLLATERAL_CALCULATION_FAILED, 72 | LIQUIDATE_CLOSE_AMOUNT_TOO_HIGH, 73 | LIQUIDATE_CONTRACT_PAUSED, 74 | LIQUIDATE_DISCOUNTED_REPAY_TO_EVEN_AMOUNT_CALCULATION_FAILED, 75 | LIQUIDATE_NEW_BORROW_INDEX_CALCULATION_FAILED_BORROWED_ASSET, 76 | LIQUIDATE_NEW_BORROW_INDEX_CALCULATION_FAILED_COLLATERAL_ASSET, 77 | LIQUIDATE_NEW_BORROW_RATE_CALCULATION_FAILED_BORROWED_ASSET, 78 | LIQUIDATE_NEW_SUPPLY_INDEX_CALCULATION_FAILED_BORROWED_ASSET, 79 | LIQUIDATE_NEW_SUPPLY_INDEX_CALCULATION_FAILED_COLLATERAL_ASSET, 80 | LIQUIDATE_NEW_SUPPLY_RATE_CALCULATION_FAILED_BORROWED_ASSET, 81 | LIQUIDATE_NEW_TOTAL_BORROW_CALCULATION_FAILED_BORROWED_ASSET, 82 | LIQUIDATE_NEW_TOTAL_CASH_CALCULATION_FAILED_BORROWED_ASSET, 83 | LIQUIDATE_NEW_TOTAL_SUPPLY_BALANCE_CALCULATION_FAILED_BORROWER_COLLATERAL_ASSET, 84 | LIQUIDATE_NEW_TOTAL_SUPPLY_BALANCE_CALCULATION_FAILED_LIQUIDATOR_COLLATERAL_ASSET, 85 | LIQUIDATE_FETCH_ASSET_PRICE_FAILED, 86 | LIQUIDATE_TRANSFER_IN_FAILED, 87 | LIQUIDATE_TRANSFER_IN_NOT_POSSIBLE, 88 | REPAY_BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED, 89 | REPAY_BORROW_CONTRACT_PAUSED, 90 | REPAY_BORROW_NEW_BORROW_INDEX_CALCULATION_FAILED, 91 | REPAY_BORROW_NEW_BORROW_RATE_CALCULATION_FAILED, 92 | REPAY_BORROW_NEW_SUPPLY_INDEX_CALCULATION_FAILED, 93 | REPAY_BORROW_NEW_SUPPLY_RATE_CALCULATION_FAILED, 94 | REPAY_BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED, 95 | REPAY_BORROW_NEW_TOTAL_BORROW_CALCULATION_FAILED, 96 | REPAY_BORROW_NEW_TOTAL_CASH_CALCULATION_FAILED, 97 | REPAY_BORROW_TRANSFER_IN_FAILED, 98 | REPAY_BORROW_TRANSFER_IN_NOT_POSSIBLE, 99 | SET_ASSET_PRICE_CHECK_ORACLE, 100 | SET_MARKET_INTEREST_RATE_MODEL_OWNER_CHECK, 101 | SET_ORACLE_OWNER_CHECK, 102 | SET_ORIGINATION_FEE_OWNER_CHECK, 103 | SET_PAUSED_OWNER_CHECK, 104 | SET_PENDING_ADMIN_OWNER_CHECK, 105 | SET_RISK_PARAMETERS_OWNER_CHECK, 106 | SET_RISK_PARAMETERS_VALIDATION, 107 | SUPPLY_ACCUMULATED_BALANCE_CALCULATION_FAILED, 108 | SUPPLY_CONTRACT_PAUSED, 109 | SUPPLY_MARKET_NOT_SUPPORTED, 110 | SUPPLY_NEW_BORROW_INDEX_CALCULATION_FAILED, 111 | SUPPLY_NEW_BORROW_RATE_CALCULATION_FAILED, 112 | SUPPLY_NEW_SUPPLY_INDEX_CALCULATION_FAILED, 113 | SUPPLY_NEW_SUPPLY_RATE_CALCULATION_FAILED, 114 | SUPPLY_NEW_TOTAL_BALANCE_CALCULATION_FAILED, 115 | SUPPLY_NEW_TOTAL_CASH_CALCULATION_FAILED, 116 | SUPPLY_NEW_TOTAL_SUPPLY_CALCULATION_FAILED, 117 | SUPPLY_TRANSFER_IN_FAILED, 118 | SUPPLY_TRANSFER_IN_NOT_POSSIBLE, 119 | SUPPORT_MARKET_FETCH_PRICE_FAILED, 120 | SUPPORT_MARKET_OWNER_CHECK, 121 | SUPPORT_MARKET_PRICE_CHECK, 122 | SUSPEND_MARKET_OWNER_CHECK, 123 | WITHDRAW_ACCOUNT_LIQUIDITY_CALCULATION_FAILED, 124 | WITHDRAW_ACCOUNT_SHORTFALL_PRESENT, 125 | WITHDRAW_ACCUMULATED_BALANCE_CALCULATION_FAILED, 126 | WITHDRAW_AMOUNT_LIQUIDITY_SHORTFALL, 127 | WITHDRAW_AMOUNT_VALUE_CALCULATION_FAILED, 128 | WITHDRAW_CAPACITY_CALCULATION_FAILED, 129 | WITHDRAW_CONTRACT_PAUSED, 130 | WITHDRAW_NEW_BORROW_INDEX_CALCULATION_FAILED, 131 | WITHDRAW_NEW_BORROW_RATE_CALCULATION_FAILED, 132 | WITHDRAW_NEW_SUPPLY_INDEX_CALCULATION_FAILED, 133 | WITHDRAW_NEW_SUPPLY_RATE_CALCULATION_FAILED, 134 | WITHDRAW_NEW_TOTAL_BALANCE_CALCULATION_FAILED, 135 | WITHDRAW_NEW_TOTAL_SUPPLY_CALCULATION_FAILED, 136 | WITHDRAW_TRANSFER_OUT_FAILED, 137 | WITHDRAW_TRANSFER_OUT_NOT_POSSIBLE 138 | } 139 | 140 | /** 141 | * @dev use this when reporting a known error from the money market or a non-upgradeable collaborator 142 | */ 143 | function fail(Error err, FailureInfo info) internal returns (uint) { 144 | emit Failure(uint(err), uint(info), 0); 145 | 146 | return uint(err); 147 | } 148 | 149 | /** 150 | * @dev use this when reporting an opaque error from an upgradeable collaborator contract 151 | */ 152 | function failOpaque(FailureInfo info, uint opaqueError) internal returns (uint) { 153 | emit Failure(uint(Error.OPAQUE_ERROR), uint(info), opaqueError); 154 | 155 | return uint(Error.OPAQUE_ERROR); 156 | } 157 | } 158 | -------------------------------------------------------------------------------- /contracts/ExchangeRate.sol: -------------------------------------------------------------------------------- 1 | pragma solidity =0.5.12; 2 | 3 | contract PotLike { 4 | function chi() external view returns (uint256); 5 | function rho() external view returns (uint256); 6 | function dsr() external view returns (uint256); 7 | } 8 | 9 | contract ExchangeRateModel { 10 | 11 | address public owner; 12 | address public newOwner; 13 | PotLike public pot; 14 | 15 | address public token; 16 | 17 | uint constant public scale = 10 ** 27; 18 | 19 | event OwnerUpdate(address indexed owner, address indexed newOwner); 20 | event SetPot(address indexed owner, address indexed newPot, address indexed oldPot); 21 | 22 | modifier onlyOwner() { 23 | require(msg.sender == owner, "non-owner"); 24 | _; 25 | } 26 | 27 | constructor(address _pot, address _token) public { 28 | owner = msg.sender; 29 | pot = PotLike(_pot); 30 | token = _token; 31 | } 32 | 33 | function transferOwnership(address newOwner_) external onlyOwner { 34 | require(newOwner_ != owner, "TransferOwnership: the same owner."); 35 | newOwner = newOwner_; 36 | } 37 | 38 | function acceptOwnership() external { 39 | require(msg.sender == newOwner, "AcceptOwnership: only new owner do this."); 40 | emit OwnerUpdate(owner, newOwner); 41 | owner = newOwner; 42 | newOwner = address(0x0); 43 | } 44 | 45 | function setPot(address _pot) external onlyOwner { 46 | require(_pot != address(0), "setPot: pot cannot be a zero address."); 47 | require(address(pot) != _pot, "setPot: The old and new addresses cannot be the same."); 48 | address _oldpot = address(pot); 49 | pot = PotLike(_pot); 50 | emit SetPot(owner, _pot, _oldpot); 51 | } 52 | 53 | // --- Math --- 54 | function rpow(uint x, uint n, uint base) internal pure returns (uint z) { 55 | assembly { 56 | switch x case 0 {switch n case 0 {z := base} default {z := 0}} 57 | default { 58 | switch mod(n, 2) case 0 { z := base } default { z := x } 59 | let half := div(base, 2) // for rounding. 60 | for { n := div(n, 2) } n { n := div(n,2) } { 61 | let xx := mul(x, x) 62 | if iszero(eq(div(xx, x), x)) { revert(0,0) } 63 | let xxRound := add(xx, half) 64 | if lt(xxRound, xx) { revert(0,0) } 65 | x := div(xxRound, base) 66 | if mod(n,2) { 67 | let zx := mul(z, x) 68 | if and(iszero(iszero(x)), iszero(eq(div(zx, x), z))) { revert(0,0) } 69 | let zxRound := add(zx, half) 70 | if lt(zxRound, zx) { revert(0,0) } 71 | z := div(zxRound, base) 72 | } 73 | } 74 | } 75 | } 76 | } 77 | 78 | function safeMul(uint x, uint y) internal pure returns (uint z) { 79 | require(y == 0 || (z = x * y) / y == x); 80 | } 81 | 82 | function getExchangeRate() external view returns (uint) { 83 | return getFixedExchangeRate(now - pot.rho()); 84 | } 85 | 86 | function getFixedExchangeRate(uint interval) public view returns (uint) { 87 | uint _scale = scale; 88 | return safeMul(rpow(pot.dsr(), interval, _scale), pot.chi()) / _scale; 89 | } 90 | 91 | function getFixedInterestRate(uint interval) external view returns (uint) { 92 | return rpow(pot.dsr(), interval, scale); 93 | } 94 | 95 | function getMaxSwingRate(uint interval) external view returns (uint) { 96 | return safeMul(getFixedExchangeRate(interval), scale) / pot.chi(); 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /contracts/Exponential.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.24; 2 | 3 | import "./ErrorReporter.sol"; 4 | import "./CarefulMath.sol"; 5 | 6 | contract Exponential is ErrorReporter, CarefulMath { 7 | // TODO: We may wish to put the result of 10**18 here instead of the expression. 8 | // Per https://solidity.readthedocs.io/en/latest/contracts.html#constant-state-variables 9 | // the optimizer MAY replace the expression 10**18 with its calculated value. 10 | uint constant expScale = 10**18; 11 | 12 | // See TODO on expScale 13 | uint constant halfExpScale = expScale/2; 14 | 15 | struct Exp { 16 | uint mantissa; 17 | } 18 | 19 | uint constant mantissaOne = 10**18; 20 | uint constant mantissaOneTenth = 10**17; 21 | 22 | /** 23 | * @dev Creates an exponential from numerator and denominator values. 24 | * Note: Returns an error if (`num` * 10e18) > MAX_INT, 25 | * or if `denom` is zero. 26 | */ 27 | function getExp(uint num, uint denom) pure internal returns (Error, Exp memory) { 28 | (Error err0, uint scaledNumerator) = mul(num, expScale); 29 | if (err0 != Error.NO_ERROR) { 30 | return (err0, Exp({mantissa: 0})); 31 | } 32 | 33 | (Error err1, uint rational) = div(scaledNumerator, denom); 34 | if (err1 != Error.NO_ERROR) { 35 | return (err1, Exp({mantissa: 0})); 36 | } 37 | 38 | return (Error.NO_ERROR, Exp({mantissa: rational})); 39 | } 40 | 41 | /** 42 | * @dev Adds two exponentials, returning a new exponential. 43 | */ 44 | function addExp(Exp memory a, Exp memory b) pure internal returns (Error, Exp memory) { 45 | (Error error, uint result) = add(a.mantissa, b.mantissa); 46 | 47 | return (error, Exp({mantissa: result})); 48 | } 49 | 50 | /** 51 | * @dev Subtracts two exponentials, returning a new exponential. 52 | */ 53 | function subExp(Exp memory a, Exp memory b) pure internal returns (Error, Exp memory) { 54 | (Error error, uint result) = sub(a.mantissa, b.mantissa); 55 | 56 | return (error, Exp({mantissa: result})); 57 | } 58 | 59 | /** 60 | * @dev Multiply an Exp by a scalar, returning a new Exp. 61 | */ 62 | function mulScalar(Exp memory a, uint scalar) pure internal returns (Error, Exp memory) { 63 | (Error err0, uint scaledMantissa) = mul(a.mantissa, scalar); 64 | if (err0 != Error.NO_ERROR) { 65 | return (err0, Exp({mantissa: 0})); 66 | } 67 | 68 | return (Error.NO_ERROR, Exp({mantissa: scaledMantissa})); 69 | } 70 | 71 | /** 72 | * @dev Divide an Exp by a scalar, returning a new Exp. 73 | */ 74 | function divScalar(Exp memory a, uint scalar) pure internal returns (Error, Exp memory) { 75 | (Error err0, uint descaledMantissa) = div(a.mantissa, scalar); 76 | if (err0 != Error.NO_ERROR) { 77 | return (err0, Exp({mantissa: 0})); 78 | } 79 | 80 | return (Error.NO_ERROR, Exp({mantissa: descaledMantissa})); 81 | } 82 | 83 | /** 84 | * @dev Divide a scalar by an Exp, returning a new Exp. 85 | */ 86 | function divScalarByExp(uint scalar, Exp divisor) pure internal returns (Error, Exp memory) { 87 | /* 88 | We are doing this as: 89 | getExp(mul(expScale, scalar), divisor.mantissa) 90 | 91 | How it works: 92 | Exp = a / b; 93 | Scalar = s; 94 | `s / (a / b)` = `b * s / a` and since for an Exp `a = mantissa, b = expScale` 95 | */ 96 | (Error err0, uint numerator) = mul(expScale, scalar); 97 | if (err0 != Error.NO_ERROR) { 98 | return (err0, Exp({mantissa: 0})); 99 | } 100 | return getExp(numerator, divisor.mantissa); 101 | } 102 | 103 | /** 104 | * @dev Multiplies two exponentials, returning a new exponential. 105 | */ 106 | function mulExp(Exp memory a, Exp memory b) pure internal returns (Error, Exp memory) { 107 | 108 | (Error err0, uint doubleScaledProduct) = mul(a.mantissa, b.mantissa); 109 | if (err0 != Error.NO_ERROR) { 110 | return (err0, Exp({mantissa: 0})); 111 | } 112 | 113 | // We add half the scale before dividing so that we get rounding instead of truncation. 114 | // See "Listing 6" and text above it at https://accu.org/index.php/journals/1717 115 | // Without this change, a result like 6.6...e-19 will be truncated to 0 instead of being rounded to 1e-18. 116 | (Error err1, uint doubleScaledProductWithHalfScale) = add(halfExpScale, doubleScaledProduct); 117 | if (err1 != Error.NO_ERROR) { 118 | return (err1, Exp({mantissa: 0})); 119 | } 120 | 121 | (Error err2, uint product) = div(doubleScaledProductWithHalfScale, expScale); 122 | // The only error `div` can return is Error.DIVISION_BY_ZERO but we control `expScale` and it is not zero. 123 | assert(err2 == Error.NO_ERROR); 124 | 125 | return (Error.NO_ERROR, Exp({mantissa: product})); 126 | } 127 | 128 | /** 129 | * @dev Divides two exponentials, returning a new exponential. 130 | * (a/scale) / (b/scale) = (a/scale) * (scale/b) = a/b, 131 | * which we can scale as an Exp by calling getExp(a.mantissa, b.mantissa) 132 | */ 133 | function divExp(Exp memory a, Exp memory b) pure internal returns (Error, Exp memory) { 134 | return getExp(a.mantissa, b.mantissa); 135 | } 136 | 137 | /** 138 | * @dev Truncates the given exp to a whole number value. 139 | * For example, truncate(Exp{mantissa: 15 * (10**18)}) = 15 140 | */ 141 | function truncate(Exp memory exp) pure internal returns (uint) { 142 | // Note: We are not using careful math here as we're performing a division that cannot fail 143 | return exp.mantissa / 10**18; 144 | } 145 | 146 | /** 147 | * @dev Checks if first Exp is less than second Exp. 148 | */ 149 | function lessThanExp(Exp memory left, Exp memory right) pure internal returns (bool) { 150 | return left.mantissa < right.mantissa; //TODO: Add some simple tests and this in another PR yo. 151 | } 152 | 153 | /** 154 | * @dev Checks if left Exp <= right Exp. 155 | */ 156 | function lessThanOrEqualExp(Exp memory left, Exp memory right) pure internal returns (bool) { 157 | return left.mantissa <= right.mantissa; 158 | } 159 | 160 | /** 161 | * @dev Checks if first Exp is greater than second Exp. 162 | */ 163 | function greaterThanExp(Exp memory left, Exp memory right) pure internal returns (bool) { 164 | return left.mantissa > right.mantissa; 165 | } 166 | 167 | /** 168 | * @dev returns true if Exp is exactly zero 169 | */ 170 | function isZeroExp(Exp memory value) pure internal returns (bool) { 171 | return value.mantissa == 0; 172 | } 173 | } 174 | 175 | -------------------------------------------------------------------------------- /contracts/InterestRateModel.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.24; 2 | 3 | /** 4 | * @title The Lendf.Me InterestRateModel Interface 5 | * @notice Any interest rate model should derive from this contract. 6 | * @dev These functions are specifically not marked `pure` as implementations of this 7 | * contract may read from storage variables. 8 | */ 9 | contract InterestRateModel { 10 | /** 11 | * @notice Gets the current supply interest rate based on the given asset, total cash and total borrows 12 | * @dev The return value should be scaled by 1e18, thus a return value of 13 | * `(true, 1000000000000)` implies an interest rate of 0.000001 or 0.0001% *per block*. 14 | * @param asset The asset to get the interest rate of 15 | * @param cash The total cash of the asset in the market 16 | * @param borrows The total borrows of the asset in the market 17 | * @return Success or failure and the supply interest rate per block scaled by 10e18 18 | */ 19 | function getSupplyRate(address asset, uint cash, uint borrows) public view returns (uint, uint); 20 | 21 | /** 22 | * @notice Gets the current borrow interest rate based on the given asset, total cash and total borrows 23 | * @dev The return value should be scaled by 1e18, thus a return value of 24 | * `(true, 1000000000000)` implies an interest rate of 0.000001 or 0.0001% *per block*. 25 | * @param asset The asset to get the interest rate of 26 | * @param cash The total cash of the asset in the market 27 | * @param borrows The total borrows of the asset in the market 28 | * @return Success or failure and the borrow interest rate per block scaled by 10e18 29 | */ 30 | function getBorrowRate(address asset, uint cash, uint borrows) public view returns (uint, uint); 31 | } 32 | -------------------------------------------------------------------------------- /contracts/LiquidationChecker.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.24; 2 | 3 | 4 | contract EIP20Interface { 5 | function balanceOf(address _owner) public view returns (uint256 balance); 6 | } 7 | 8 | contract PriceOracleProxy { 9 | address public mostRecentCaller; 10 | uint public mostRecentBlock; 11 | 12 | /** 13 | * @notice Gets the price of a given asset 14 | * @dev fetches the price of a given asset 15 | * @param asset Asset to get the price of 16 | * @return the price scaled by 10**18, or zero if the price is not available 17 | */ 18 | function assetPrices(address asset) public returns (uint); 19 | } 20 | 21 | contract MoneyMarket { 22 | /** 23 | * @dev Account allowed to set oracle prices for this contract. Initially set 24 | * in constructor, but can be changed by the admin. 25 | */ 26 | address public oracle; 27 | } 28 | 29 | contract LiquidationChecker { 30 | MoneyMarket public moneyMarket; 31 | address public liquidator; 32 | bool public allowLiquidation; 33 | 34 | constructor(address moneyMarket_, address liquidator_) public { 35 | moneyMarket = MoneyMarket(moneyMarket_); 36 | liquidator = liquidator_; 37 | allowLiquidation = false; 38 | } 39 | 40 | function isAllowed(address asset, uint newCash) internal returns(bool) { 41 | return allowLiquidation || !isLiquidate(asset, newCash); 42 | } 43 | 44 | function isLiquidate(address asset, uint newCash) internal returns(bool) { 45 | return cashIsUp(asset, newCash) && oracleTouched(); 46 | } 47 | 48 | function cashIsUp(address asset, uint newCash) internal view returns(bool) { 49 | uint oldCash = EIP20Interface(asset).balanceOf(moneyMarket); 50 | 51 | return newCash >= oldCash; 52 | } 53 | 54 | function oracleTouched() internal returns(bool) { 55 | PriceOracleProxy oracle = PriceOracleProxy(moneyMarket.oracle()); 56 | 57 | bool sameOrigin = oracle.mostRecentCaller() == tx.origin; 58 | bool sameBlock = oracle.mostRecentBlock() == block.number; 59 | 60 | return sameOrigin && sameBlock; 61 | } 62 | 63 | function setAllowLiquidation(bool allowLiquidation_) public { 64 | require(msg.sender == liquidator, "LIQUIDATION_CHECKER_INVALID_LIQUIDATOR"); 65 | 66 | allowLiquidation = allowLiquidation_; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /contracts/Liquidator.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.24; 2 | 3 | import "./EIP20Interface.sol"; 4 | import "./EIP20NonStandardInterface.sol"; 5 | import "./ErrorReporter.sol"; 6 | import "./InterestRateModel.sol"; 7 | import "./SafeToken.sol"; 8 | 9 | contract LiquidationChecker { 10 | function setAllowLiquidation(bool allowLiquidation_) public; 11 | } 12 | 13 | contract MoneyMarket{ 14 | /** 15 | * @dev Container for per-asset balance sheet and interest rate information written to storage, intended to be stored in a map where the asset address is the key 16 | * 17 | * struct Market { 18 | * isSupported = Whether this market is supported or not (not to be confused with the list of collateral assets) 19 | * blockNumber = when the other values in this struct were calculated 20 | * totalSupply = total amount of this asset supplied (in asset wei) 21 | * supplyRateMantissa = the per-block interest rate for supplies of asset as of blockNumber, scaled by 10e18 22 | * supplyIndex = the interest index for supplies of asset as of blockNumber; initialized in _supportMarket 23 | * totalBorrows = total amount of this asset borrowed (in asset wei) 24 | * borrowRateMantissa = the per-block interest rate for borrows of asset as of blockNumber, scaled by 10e18 25 | * borrowIndex = the interest index for borrows of asset as of blockNumber; initialized in _supportMarket 26 | * } 27 | */ 28 | struct Market { 29 | bool isSupported; 30 | uint blockNumber; 31 | InterestRateModel interestRateModel; 32 | 33 | uint totalSupply; 34 | uint supplyRateMantissa; 35 | uint supplyIndex; 36 | 37 | uint totalBorrows; 38 | uint borrowRateMantissa; 39 | uint borrowIndex; 40 | } 41 | 42 | /** 43 | * @dev map: assetAddress -> Market 44 | */ 45 | mapping(address => Market) public markets; 46 | 47 | /** 48 | * @notice users repay all or some of an underwater borrow and receive collateral 49 | * @param targetAccount The account whose borrow should be liquidated 50 | * @param assetBorrow The market asset to repay 51 | * @param assetCollateral The borrower's market asset to receive in exchange 52 | * @param requestedAmountClose The amount to repay (or -1 for max) 53 | * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) 54 | */ 55 | function liquidateBorrow(address targetAccount, address assetBorrow, address assetCollateral, uint requestedAmountClose) public returns (uint); 56 | 57 | /** 58 | * @notice withdraw `amount` of `asset` from sender's account to sender's address 59 | * @dev withdraw `amount` of `asset` from msg.sender's account to msg.sender 60 | * @param asset The market asset to withdraw 61 | * @param requestedAmount The amount to withdraw (or -1 for max) 62 | * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) 63 | */ 64 | function withdraw(address asset, uint requestedAmount) public returns (uint); 65 | 66 | /** 67 | * @notice return supply balance with any accumulated interest for `asset` belonging to `account` 68 | * @dev returns supply balance with any accumulated interest for `asset` belonging to `account` 69 | * @param account the account to examine 70 | * @param asset the market asset whose supply balance belonging to `account` should be checked 71 | * @return uint supply balance on success, throws on failed assertion otherwise 72 | */ 73 | function getSupplyBalance(address account, address asset) view public returns (uint); 74 | 75 | /** 76 | * @notice return borrow balance with any accumulated interest for `asset` belonging to `account` 77 | * @dev returns borrow balance with any accumulated interest for `asset` belonging to `account` 78 | * @param account the account to examine 79 | * @param asset the market asset whose borrow balance belonging to `account` should be checked 80 | * @return uint borrow balance on success, throws on failed assertion otherwise 81 | */ 82 | function getBorrowBalance(address account, address asset) view public returns (uint); 83 | } 84 | 85 | contract Liquidator is ErrorReporter, SafeToken { 86 | MoneyMarket public moneyMarket; 87 | 88 | constructor(address moneyMarket_) public { 89 | moneyMarket = MoneyMarket(moneyMarket_); 90 | } 91 | 92 | event BorrowLiquidated(address targetAccount, 93 | address assetBorrow, 94 | uint borrowBalanceBefore, 95 | uint borrowBalanceAccumulated, 96 | uint amountRepaid, 97 | uint borrowBalanceAfter, 98 | address liquidator, 99 | address assetCollateral, 100 | uint collateralBalanceBefore, 101 | uint collateralBalanceAccumulated, 102 | uint amountSeized, 103 | uint collateralBalanceAfter); 104 | 105 | function liquidateBorrow(address targetAccount, address assetBorrow, address assetCollateral, uint requestedAmountClose) public returns (uint) { 106 | require(targetAccount != address(this), "FAILED_LIQUIDATE_LIQUIDATOR"); 107 | require(targetAccount != msg.sender, "FAILED_LIQUIDATE_SELF"); 108 | require(msg.sender != address(this), "FAILED_LIQUIDATE_RECURSIVE"); 109 | require(assetBorrow != assetCollateral, "FAILED_LIQUIDATE_IN_KIND"); 110 | 111 | InterestRateModel interestRateModel; 112 | (,,interestRateModel,,,,,,) = moneyMarket.markets(assetBorrow); 113 | 114 | require(interestRateModel != address(0), "FAILED_LIQUIDATE_NO_INTEREST_RATE_MODEL"); 115 | require(checkTransferIn(assetBorrow, msg.sender, requestedAmountClose) == Error.NO_ERROR, "FAILED_LIQUIDATE_TRANSFER_IN_INVALID"); 116 | 117 | require(doTransferIn(assetBorrow, msg.sender, requestedAmountClose) == Error.NO_ERROR, "FAILED_LIQUIDATE_TRANSFER_IN_FAILED"); 118 | 119 | tokenAllowAll(assetBorrow, moneyMarket); 120 | 121 | LiquidationChecker(interestRateModel).setAllowLiquidation(true); 122 | 123 | uint result = moneyMarket.liquidateBorrow(targetAccount, assetBorrow, assetCollateral, requestedAmountClose); 124 | 125 | require(moneyMarket.withdraw(assetCollateral, uint(-1)) == uint(Error.NO_ERROR), "FAILED_LIQUIDATE_WITHDRAW_FAILED"); 126 | 127 | LiquidationChecker(interestRateModel).setAllowLiquidation(false); 128 | 129 | // Ensure there's no remaining balances here 130 | require(moneyMarket.getSupplyBalance(address(this), assetCollateral) == 0, "FAILED_LIQUIDATE_REMAINING_SUPPLY_COLLATERAL"); // just to be sure 131 | require(moneyMarket.getSupplyBalance(address(this), assetBorrow) == 0, "FAILED_LIQUIDATE_REMAINING_SUPPLY_BORROW"); // just to be sure 132 | require(moneyMarket.getBorrowBalance(address(this), assetCollateral) == 0, "FAILED_LIQUIDATE_REMAINING_BORROW_COLLATERAL"); // just to be sure 133 | require(moneyMarket.getBorrowBalance(address(this), assetBorrow) == 0, "FAILED_LIQUIDATE_REMAINING_BORROW_BORROW"); // just to be sure 134 | 135 | // Transfer out everything remaining 136 | tokenTransferAll(assetCollateral, msg.sender); 137 | tokenTransferAll(assetBorrow, msg.sender); 138 | 139 | return uint(result); 140 | } 141 | 142 | function tokenAllowAll(address asset, address allowee) internal { 143 | EIP20Interface token = EIP20Interface(asset); 144 | 145 | if (token.allowance(address(this), allowee) != uint(-1)) 146 | // require(token.approve(allowee, uint(-1)), "FAILED_LIQUIDATE_ASSET_ALLOWANCE_FAILED"); 147 | require(doApprove(asset, allowee, uint(-1)) == Error.NO_ERROR, "FAILED_LIQUIDATE_ASSET_ALLOWANCE_FAILED"); 148 | } 149 | 150 | function tokenTransferAll(address asset, address recipient) internal { 151 | uint balance = getBalanceOf(asset, address(this)); 152 | 153 | if (balance > 0){ 154 | require(doTransferOut(asset, recipient, balance) == Error.NO_ERROR, "FAILED_LIQUIDATE_TRANSFER_OUT_FAILED"); 155 | } 156 | } 157 | } 158 | -------------------------------------------------------------------------------- /contracts/PriceOracleInterface.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.24; 2 | 3 | contract PriceOracleInterface { 4 | /** 5 | * @notice Gets the price of a given asset 6 | * @dev fetches the price of a given asset 7 | * @param asset Asset to get the price of 8 | * @return the price scaled by 10**18, or zero if the price is not available 9 | */ 10 | function assetPrices(address asset) public view returns (uint); 11 | } 12 | -------------------------------------------------------------------------------- /contracts/PriceOracleProxy.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.24; 2 | 3 | import "./PriceOracleInterface.sol"; 4 | 5 | 6 | contract PriceOracleProxy { 7 | address public mostRecentCaller; 8 | uint public mostRecentBlock; 9 | PriceOracleInterface public realPriceOracle; 10 | 11 | constructor(address realPriceOracle_) public { 12 | realPriceOracle = PriceOracleInterface(realPriceOracle_); 13 | } 14 | 15 | /** 16 | * @notice Gets the price of a given asset 17 | * @dev fetches the price of a given asset 18 | * @param asset Asset to get the price of 19 | * @return the price scaled by 10**18, or zero if the price is not available 20 | */ 21 | function assetPrices(address asset) public returns (uint) { 22 | mostRecentCaller = tx.origin; 23 | mostRecentBlock = block.number; 24 | 25 | return realPriceOracle.assetPrices(asset); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /contracts/SafeToken.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.24; 2 | 3 | import "./EIP20Interface.sol"; 4 | import "./EIP20NonStandardInterface.sol"; 5 | import "./ErrorReporter.sol"; 6 | 7 | contract SafeToken is ErrorReporter { 8 | 9 | /** 10 | * @dev Checks whether or not there is sufficient allowance for this contract to move amount from `from` and 11 | * whether or not `from` has a balance of at least `amount`. Does NOT do a transfer. 12 | */ 13 | function checkTransferIn(address asset, address from, uint amount) internal view returns (Error) { 14 | EIP20Interface token = EIP20Interface(asset); 15 | 16 | if (token.allowance(from, address(this)) < amount) { 17 | return Error.TOKEN_INSUFFICIENT_ALLOWANCE; 18 | } 19 | 20 | if (token.balanceOf(from) < amount) { 21 | return Error.TOKEN_INSUFFICIENT_BALANCE; 22 | } 23 | 24 | return Error.NO_ERROR; 25 | } 26 | 27 | /** 28 | * @dev Similar to EIP20 transfer, except it handles a False result from `transferFrom` and returns an explanatory 29 | * error code rather than reverting. If caller has not called `checkTransferIn`, this may revert due to 30 | * insufficient balance or insufficient allowance. If caller has called `checkTransferIn` prior to this call, 31 | * and it returned Error.NO_ERROR, this should not revert in normal conditions. 32 | * 33 | * Note: This wrapper safely handles non-standard ERC-20 tokens that do not return a value. 34 | * See here: https://medium.com/coinmonks/missing-return-value-bug-at-least-130-tokens-affected-d67bf08521ca 35 | */ 36 | function doTransferIn(address asset, address from, uint amount) internal returns (Error) { 37 | EIP20NonStandardInterface token = EIP20NonStandardInterface(asset); 38 | 39 | bool result; 40 | 41 | token.transferFrom(from, address(this), amount); 42 | 43 | assembly { 44 | switch returndatasize() 45 | case 0 { // This is a non-standard ERC-20 46 | result := not(0) // set result to true 47 | } 48 | case 32 { // This is a complaint ERC-20 49 | returndatacopy(0, 0, 32) 50 | result := mload(0) // Set `result = returndata` of external call 51 | } 52 | default { // This is an excessively non-compliant ERC-20, revert. 53 | revert(0, 0) 54 | } 55 | } 56 | 57 | if (!result) { 58 | return Error.TOKEN_TRANSFER_FAILED; 59 | } 60 | 61 | return Error.NO_ERROR; 62 | } 63 | 64 | /** 65 | * @dev Checks balance of this contract in asset 66 | */ 67 | function getCash(address asset) internal view returns (uint) { 68 | EIP20Interface token = EIP20Interface(asset); 69 | 70 | return token.balanceOf(address(this)); 71 | } 72 | 73 | /** 74 | * @dev Checks balance of `from` in `asset` 75 | */ 76 | function getBalanceOf(address asset, address from) internal view returns (uint) { 77 | EIP20Interface token = EIP20Interface(asset); 78 | 79 | return token.balanceOf(from); 80 | } 81 | 82 | /** 83 | * @dev Similar to EIP20 transfer, except it handles a False result from `transfer` and returns an explanatory 84 | * error code rather than reverting. If caller has not called checked protocol's balance, this may revert due to 85 | * insufficient cash held in this contract. If caller has checked protocol's balance prior to this call, and verified 86 | * it is >= amount, this should not revert in normal conditions. 87 | * 88 | * Note: This wrapper safely handles non-standard ERC-20 tokens that do not return a value. 89 | * See here: https://medium.com/coinmonks/missing-return-value-bug-at-least-130-tokens-affected-d67bf08521ca 90 | */ 91 | function doTransferOut(address asset, address to, uint amount) internal returns (Error) { 92 | EIP20NonStandardInterface token = EIP20NonStandardInterface(asset); 93 | 94 | bool result; 95 | 96 | token.transfer(to, amount); 97 | 98 | assembly { 99 | switch returndatasize() 100 | case 0 { // This is a non-standard ERC-20 101 | result := not(0) // set result to true 102 | } 103 | case 32 { // This is a complaint ERC-20 104 | returndatacopy(0, 0, 32) 105 | result := mload(0) // Set `result = returndata` of external call 106 | } 107 | default { // This is an excessively non-compliant ERC-20, revert. 108 | revert(0, 0) 109 | } 110 | } 111 | 112 | if (!result) { 113 | return Error.TOKEN_TRANSFER_OUT_FAILED; 114 | } 115 | 116 | return Error.NO_ERROR; 117 | } 118 | 119 | function doApprove(address asset, address to, uint amount) internal returns (Error) { 120 | EIP20NonStandardInterface token = EIP20NonStandardInterface(asset); 121 | bool result; 122 | token.approve(to, amount); 123 | assembly { 124 | switch returndatasize() 125 | case 0 { // This is a non-standard ERC-20 126 | result := not(0) // set result to true 127 | } 128 | case 32 { // This is a complaint ERC-20 129 | returndatacopy(0, 0, 32) 130 | result := mload(0) // Set `result = returndata` of external call 131 | } 132 | default { // This is an excessively non-compliant ERC-20, revert. 133 | revert(0, 0) 134 | } 135 | } 136 | if (!result) { 137 | return Error.TOKEN_TRANSFER_OUT_FAILED; 138 | } 139 | return Error.NO_ERROR; 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /contracts/StableCoinInterestRateModel.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.24; 2 | 3 | import "./Exponential.sol"; 4 | import "./InterestRateModel.sol"; 5 | import "./LiquidationChecker.sol"; 6 | 7 | 8 | contract MoneyMarket { 9 | function markets(address asset) public view returns (bool, uint, InterestRateModel, uint, uint, uint, uint, uint, uint); 10 | function oracle() public view returns (address); 11 | } 12 | 13 | contract PriceOracleProxy { 14 | address public mostRecentCaller; 15 | uint public mostRecentBlock; 16 | 17 | /** 18 | * @notice Gets the price of a given asset 19 | * @dev fetches the price of a given asset 20 | * @param asset Asset to get the price of 21 | * @return the price scaled by 10**18, or zero if the price is not available 22 | */ 23 | function assetPrices(address asset) public returns (uint); 24 | } 25 | 26 | contract StableCoinRateModel is Exponential, LiquidationChecker { 27 | uint constant oneMinusSpreadBasisPoints = 9000; 28 | uint constant blocksPerYear = 2102400; 29 | 30 | address public owner; 31 | address public newOwner; 32 | 33 | modifier onlyOwner() { 34 | require(msg.sender == owner, "non-owner"); 35 | _; 36 | } 37 | 38 | enum IRError { 39 | NO_ERROR, 40 | FAILED_TO_ADD_CASH_PLUS_BORROWS, 41 | FAILED_TO_GET_EXP, 42 | FAILED_TO_MUL_PRODUCT_TIMES_BORROW_RATE 43 | } 44 | 45 | event OwnerUpdate(address indexed owner, address indexed newOwner); 46 | event LiquidatorUpdate(address indexed owner, address indexed newLiquidator, address indexed oldLiquidator); 47 | 48 | constructor(address moneyMarket, address liquidator) LiquidationChecker(moneyMarket, liquidator) { 49 | owner = msg.sender; 50 | } 51 | 52 | function transferOwnership(address newOwner_) external onlyOwner { 53 | require(newOwner_ != owner, "TransferOwnership: the same owner."); 54 | newOwner = newOwner_; 55 | } 56 | 57 | function acceptOwnership() external { 58 | require(msg.sender == newOwner, "AcceptOwnership: only new owner do this."); 59 | emit OwnerUpdate(owner, newOwner); 60 | owner = newOwner; 61 | newOwner = address(0x0); 62 | } 63 | 64 | function setLiquidator(address _liquidator) external onlyOwner { 65 | require(_liquidator != address(0), "setLiquidator: liquidator cannot be a zero address"); 66 | require(liquidator != _liquidator, "setLiquidator: The old and new addresses cannot be the same"); 67 | address oldLiquidator = liquidator; 68 | liquidator = _liquidator; 69 | emit LiquidatorUpdate(msg.sender, _liquidator, oldLiquidator); 70 | } 71 | 72 | /* 73 | * @dev Calculates the utilization rate (borrows / (cash + borrows)) as an Exp 74 | */ 75 | function getUtilizationRate(uint cash, uint borrows) pure internal returns (IRError, Exp memory) { 76 | if (borrows == 0) { 77 | // Utilization rate is zero when there's no borrows 78 | return (IRError.NO_ERROR, Exp({mantissa: 0})); 79 | } 80 | 81 | (Error err0, uint cashPlusBorrows) = add(cash, borrows); 82 | if (err0 != Error.NO_ERROR) { 83 | return (IRError.FAILED_TO_ADD_CASH_PLUS_BORROWS, Exp({mantissa: 0})); 84 | } 85 | 86 | (Error err1, Exp memory utilizationRate) = getExp(borrows, cashPlusBorrows); 87 | if (err1 != Error.NO_ERROR) { 88 | return (IRError.FAILED_TO_GET_EXP, Exp({mantissa: 0})); 89 | } 90 | 91 | return (IRError.NO_ERROR, utilizationRate); 92 | } 93 | 94 | function powDecimal(uint utilizationRate, uint power) pure internal returns (Error, uint){ 95 | 96 | uint result = utilizationRate; 97 | Error err0; 98 | uint decimal = 10**18; 99 | uint i = 1; 100 | while(i < power){ 101 | 102 | if(power - i > 2){ 103 | 104 | (err0, result) = mul(result, utilizationRate ** 3); 105 | if (err0 != Error.NO_ERROR) 106 | return (err0, 0); 107 | 108 | result = result / decimal ** 3; 109 | i += 3; 110 | }else if(power - i > 1){ 111 | 112 | (err0, result) = mul(result, utilizationRate ** 2); 113 | if (err0 != Error.NO_ERROR) 114 | return (err0, 0); 115 | 116 | result = result / decimal ** 2; 117 | i += 2; 118 | }else { 119 | 120 | (err0, result) = mul(result, utilizationRate); 121 | if (err0 != Error.NO_ERROR) 122 | return (err0, 0); 123 | 124 | result = result / decimal; 125 | i++; 126 | } 127 | } 128 | 129 | return (err0, result); 130 | } 131 | 132 | /* 133 | * @dev Calculates the utilization and borrow rates for use by get{Supply,Borrow}Rate functions 134 | */ 135 | function getUtilizationAndAnnualBorrowRate(uint cash, uint borrows) pure internal returns (IRError, Exp memory, Exp memory) { 136 | (IRError err0, Exp memory utilizationRate) = getUtilizationRate(cash, borrows); 137 | if (err0 != IRError.NO_ERROR) { 138 | return (err0, Exp({mantissa: 0}), Exp({mantissa: 0})); 139 | } 140 | 141 | Error err; 142 | uint temp; 143 | uint annualBorrowRate; 144 | 145 | temp = utilizationRate.mantissa**2 / 10**18; 146 | (err, annualBorrowRate) = add(utilizationRate.mantissa, temp); 147 | assert(err == Error.NO_ERROR); 148 | 149 | temp = temp**2 / 10**18; 150 | (err, annualBorrowRate) = add(annualBorrowRate, temp); 151 | assert(err == Error.NO_ERROR); 152 | 153 | (err, temp) = powDecimal(temp, 8); 154 | assert(err == Error.NO_ERROR); 155 | (err, annualBorrowRate) = add(annualBorrowRate, temp); 156 | assert(err == Error.NO_ERROR); 157 | 158 | (err, annualBorrowRate) = add(annualBorrowRate, temp); 159 | assert(err == Error.NO_ERROR); 160 | 161 | // Borrow Rate is (UtilizationRate + UtilizationRate^2 + UtilizationRate^4 + 2 * UtilizationRate^32) * 5% 162 | Exp memory annualBorrowRateMuled; 163 | (err, annualBorrowRateMuled) = mulScalar(Exp({mantissa: annualBorrowRate}), 5); 164 | // `mulScalar` only overflows when the product is >= 2^256. 165 | // utilizationRate is a real number on the interval [0,1], which means that 166 | // utilizationRate.mantissa is in the interval [0e18,1e18], which means that 2 times 167 | // that is in the interval [0e18,2e18]. That interval has no intersection with 2^256, and therefore 168 | // this can never overflow. As such, we assert. 169 | assert(err == Error.NO_ERROR); 170 | 171 | Exp memory annualBorrowRateScaled; 172 | (err, annualBorrowRateScaled) = divScalar(annualBorrowRateMuled, 100); 173 | // 100 is a constant, and therefore cannot be zero, which is the only error case of divScalar. 174 | assert(err == Error.NO_ERROR); 175 | 176 | return (IRError.NO_ERROR, utilizationRate, annualBorrowRateScaled); 177 | } 178 | 179 | /** 180 | * @notice Gets the current supply interest rate based on the given asset, total cash and total borrows 181 | * @dev The return value should be scaled by 1e18, thus a return value of 182 | * `(true, 1000000000000)` implies an interest rate of 0.000001 or 0.0001% *per block*. 183 | * @param _asset The asset to get the interest rate of 184 | * @param cash The total cash of the asset in the market 185 | * @param borrows The total borrows of the asset in the market 186 | * @return Success or failure and the supply interest rate per block scaled by 10e18 187 | */ 188 | function getSupplyRate(address _asset, uint cash, uint borrows) public view returns (uint, uint) { 189 | _asset; // pragma ignore unused argument 190 | 191 | (IRError err0, Exp memory utilizationRate0, Exp memory annualBorrowRate) = getUtilizationAndAnnualBorrowRate(cash, borrows); 192 | if (err0 != IRError.NO_ERROR) { 193 | return (uint(err0), 0); 194 | } 195 | 196 | // We're going to multiply the utilization rate by the spread's numerator 197 | (Error err1, Exp memory utilizationRate1) = mulScalar(utilizationRate0, oneMinusSpreadBasisPoints); 198 | // mulScalar only overflows when product is greater than or equal to 2^256. 199 | // utilization rate's mantissa is a number between [0e18,1e18]. That means that 200 | // utilizationRate1 is a value between [0e18,8.5e21]. This is strictly less than 2^256. 201 | assert(err1 == Error.NO_ERROR); 202 | 203 | // Next multiply this product times the borrow rate 204 | (Error err2, Exp memory supplyRate0) = mulExp(utilizationRate1, annualBorrowRate); 205 | // If the product of the mantissas for mulExp are both less than 2^256, 206 | // then this operation will never fail. TODO: Verify. 207 | // We know that borrow rate is in the interval [0, 2.25e17] from above. 208 | // We know that utilizationRate1 is in the interval [0, 9e21] from directly above. 209 | // As such, the multiplication is in the interval of [0, 2.025e39]. This is strictly 210 | // less than 2^256 (which is about 10e77). 211 | assert(err2 == Error.NO_ERROR); 212 | 213 | // And then divide down by the spread's denominator (basis points divisor) 214 | // as well as by blocks per year. 215 | (Error err3, Exp memory supplyRate1) = divScalar(supplyRate0, 10000 * blocksPerYear); // basis points * blocks per year 216 | // divScalar only fails when divisor is zero. This is clearly not the case. 217 | assert(err3 == Error.NO_ERROR); 218 | 219 | return (uint(IRError.NO_ERROR), supplyRate1.mantissa); 220 | } 221 | 222 | /** 223 | * @notice Gets the current borrow interest rate based on the given asset, total cash and total borrows 224 | * @dev The return value should be scaled by 1e18, thus a return value of 225 | * `(true, 1000000000000)` implies an interest rate of 0.000001 or 0.0001% *per block*. 226 | * @param asset The asset to get the interest rate of 227 | * @param cash The total cash of the asset in the market 228 | * @param borrows The total borrows of the asset in the market 229 | * @return Success or failure and the borrow interest rate per block scaled by 10e18 230 | */ 231 | function getBorrowRate(address asset, uint cash, uint borrows) public returns (uint, uint) { 232 | require(isAllowed(asset, cash)); 233 | 234 | (IRError err0, Exp memory _utilizationRate, Exp memory annualBorrowRate) = getUtilizationAndAnnualBorrowRate(cash, borrows); 235 | if (err0 != IRError.NO_ERROR) { 236 | return (uint(err0), 0); 237 | } 238 | 239 | // And then divide down by blocks per year. 240 | (Error err1, Exp memory borrowRate) = divScalar(annualBorrowRate, blocksPerYear); // basis points * blocks per year 241 | // divScalar only fails when divisor is zero. This is clearly not the case. 242 | assert(err1 == Error.NO_ERROR); 243 | 244 | _utilizationRate; // pragma ignore unused variable 245 | 246 | // Note: mantissa is the rate scaled 1e18, which matches the expected result 247 | return (uint(IRError.NO_ERROR), borrowRate.mantissa); 248 | } 249 | } 250 | -------------------------------------------------------------------------------- /contracts/StandardInterestRateModel.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.24; 2 | 3 | import "./Exponential.sol"; 4 | import "./InterestRateModel.sol"; 5 | import "./LiquidationChecker.sol"; 6 | 7 | 8 | contract MoneyMarket { 9 | function markets(address asset) public view returns (bool, uint, InterestRateModel, uint, uint, uint, uint, uint, uint); 10 | function oracle() public view returns (address); 11 | } 12 | 13 | contract PriceOracleProxy { 14 | address public mostRecentCaller; 15 | uint public mostRecentBlock; 16 | 17 | /** 18 | * @notice Gets the price of a given asset 19 | * @dev fetches the price of a given asset 20 | * @param asset Asset to get the price of 21 | * @return the price scaled by 10**18, or zero if the price is not available 22 | */ 23 | function assetPrices(address asset) public returns (uint); 24 | } 25 | 26 | /** 27 | * @title The Lendf.Me Standard Interest Rate Model with LiquidationChecker 28 | * @author Lendf.Me 29 | */ 30 | contract StandardInterestRateModel is Exponential, LiquidationChecker { 31 | uint constant oneMinusSpreadBasisPoints = 9800; 32 | uint constant blocksPerYear = 2102400; 33 | // uint constant mantissaFivePercent = 5 * 10**16; 34 | 35 | address public owner; 36 | address public newOwner; 37 | 38 | modifier onlyOwner() { 39 | require(msg.sender == owner, "non-owner"); 40 | _; 41 | } 42 | 43 | enum IRError { 44 | NO_ERROR, 45 | FAILED_TO_ADD_CASH_PLUS_BORROWS, 46 | FAILED_TO_GET_EXP, 47 | FAILED_TO_MUL_PRODUCT_TIMES_BORROW_RATE 48 | } 49 | 50 | event OwnerUpdate(address indexed owner, address indexed newOwner); 51 | event LiquidatorUpdate(address indexed owner, address indexed newLiquidator, address indexed oldLiquidator); 52 | 53 | constructor(address moneyMarket, address liquidator) LiquidationChecker(moneyMarket, liquidator) { 54 | owner = msg.sender; 55 | } 56 | 57 | function transferOwnership(address newOwner_) external onlyOwner { 58 | require(newOwner_ != owner, "TransferOwnership: the same owner."); 59 | newOwner = newOwner_; 60 | } 61 | 62 | function acceptOwnership() external { 63 | require(msg.sender == newOwner, "AcceptOwnership: only new owner do this."); 64 | emit OwnerUpdate(owner, newOwner); 65 | owner = newOwner; 66 | newOwner = address(0x0); 67 | } 68 | 69 | function setLiquidator(address _liquidator) external onlyOwner { 70 | require(_liquidator != address(0), "SetLiquidator: liquidator cannot be a zero address"); 71 | require(liquidator != _liquidator, "SetLiquidator: The old and new addresses cannot be the same"); 72 | address oldLiquidator = liquidator; 73 | liquidator = _liquidator; 74 | emit LiquidatorUpdate(msg.sender, _liquidator, oldLiquidator); 75 | } 76 | 77 | /** 78 | * @dev Calculates the utilization rate (borrows / (cash + borrows)) as an Exp 79 | */ 80 | function getUtilizationRate(uint cash, uint borrows) pure internal returns (IRError, Exp memory) { 81 | if (borrows == 0) { 82 | // Utilization rate is zero when there's no borrows 83 | return (IRError.NO_ERROR, Exp({mantissa: 0})); 84 | } 85 | 86 | (Error err0, uint cashPlusBorrows) = add(cash, borrows); 87 | if (err0 != Error.NO_ERROR) { 88 | return (IRError.FAILED_TO_ADD_CASH_PLUS_BORROWS, Exp({mantissa: 0})); 89 | } 90 | 91 | (Error err1, Exp memory utilizationRate) = getExp(borrows, cashPlusBorrows); 92 | if (err1 != Error.NO_ERROR) { 93 | return (IRError.FAILED_TO_GET_EXP, Exp({mantissa: 0})); 94 | } 95 | 96 | return (IRError.NO_ERROR, utilizationRate); 97 | } 98 | 99 | /** 100 | * @dev Calculates the utilization and borrow rates for use by get{Supply,Borrow}Rate functions 101 | */ 102 | function getUtilizationAndAnnualBorrowRate(uint cash, uint borrows) pure internal returns (IRError, Exp memory, Exp memory) { 103 | (IRError err0, Exp memory utilizationRate) = getUtilizationRate(cash, borrows); 104 | if (err0 != IRError.NO_ERROR) { 105 | return (err0, Exp({mantissa: 0}), Exp({mantissa: 0})); 106 | } 107 | 108 | // Borrow Rate is UtilizationRate * 20% 109 | // 20% of utilizationRate, is `rate * 20 / 100` 110 | (Error err1, Exp memory utilizationRateMuled) = mulScalar(utilizationRate, 20); 111 | // `mulScalar` only overflows when the product is >= 2^256. 112 | // utilizationRate is a real number on the interval [0,1], which means that 113 | // utilizationRate.mantissa is in the interval [0e18,1e18], which means that 45 times 114 | // that is in the interval [0e18,45e18]. That interval has no intersection with 2^256, and therefore 115 | // this can never overflow. As such, we assert. 116 | assert(err1 == Error.NO_ERROR); 117 | 118 | (Error err2, Exp memory utilizationRateScaled) = divScalar(utilizationRateMuled, 100); 119 | // 100 is a constant, and therefore cannot be zero, which is the only error case of divScalar. 120 | assert(err2 == Error.NO_ERROR); 121 | 122 | // Add the 5% for (5% + 20% * Ua) 123 | // (Error err3, Exp memory annualBorrowRate) = addExp(utilizationRateScaled, Exp({mantissa: mantissaFivePercent})); 124 | // `addExp` only fails when the addition of mantissas overflow. 125 | // As per above, utilizationRateMuled is capped at 45e18, 126 | // and utilizationRateScaled is capped at 4.5e17. mantissaFivePercent = 0.5e17, and thus the addition 127 | // is capped at 5e17, which is less than 2^256. 128 | // assert(err3 == Error.NO_ERROR); 129 | 130 | return (IRError.NO_ERROR, utilizationRate, utilizationRateScaled); 131 | } 132 | 133 | /** 134 | * @notice Gets the current supply interest rate based on the given asset, total cash and total borrows 135 | * @dev The return value should be scaled by 1e18, thus a return value of 136 | * `(true, 1000000000000)` implies an interest rate of 0.000001 or 0.0001% *per block*. 137 | * @param _asset The asset to get the interest rate of 138 | * @param cash The total cash of the asset in the market 139 | * @param borrows The total borrows of the asset in the market 140 | * @return Success or failure and the supply interest rate per block scaled by 10e18 141 | */ 142 | function getSupplyRate(address _asset, uint cash, uint borrows) public view returns (uint, uint) { 143 | _asset; // pragma ignore unused argument 144 | 145 | (IRError err0, Exp memory utilizationRate0, Exp memory annualBorrowRate) = getUtilizationAndAnnualBorrowRate(cash, borrows); 146 | if (err0 != IRError.NO_ERROR) { 147 | return (uint(err0), 0); 148 | } 149 | 150 | // We're going to multiply the utilization rate by the spread's numerator 151 | (Error err1, Exp memory utilizationRate1) = mulScalar(utilizationRate0, oneMinusSpreadBasisPoints); 152 | // mulScalar only overflows when product is greater than or equal to 2^256. 153 | // utilization rate's mantissa is a number between [0e18,1e18]. That means that 154 | // utilizationRate1 is a value between [0e18,9e21]. This is strictly less than 2^256. 155 | assert(err1 == Error.NO_ERROR); 156 | 157 | // Next multiply this product times the borrow rate 158 | (Error err2, Exp memory supplyRate0) = mulExp(utilizationRate1, annualBorrowRate); 159 | // If the product of the mantissas for mulExp are both less than 2^256, 160 | // then this operation will never fail. TODO: Verify. 161 | // We know that borrow rate is in the interval [0, 4e17] from above. 162 | // We know that utilizationRate1 is in the interval [0, 9e21] from directly above. 163 | // As such, the multiplication is in the interval of [0, 3.6e39]. This is strictly 164 | // less than 2^256 (which is about 10e77). 165 | assert(err2 == Error.NO_ERROR); 166 | 167 | // And then divide down by the spread's denominator (basis points divisor) 168 | // as well as by blocks per year. 169 | (Error err3, Exp memory supplyRate1) = divScalar(supplyRate0, 10000 * blocksPerYear); // basis points * blocks per year 170 | // divScalar only fails when divisor is zero. This is clearly not the case. 171 | assert(err3 == Error.NO_ERROR); 172 | 173 | // Note: mantissa is the rate scaled 1e18, which matches the expected result 174 | return (uint(IRError.NO_ERROR), supplyRate1.mantissa); 175 | } 176 | 177 | /** 178 | * @notice Gets the current borrow interest rate based on the given asset, total cash and total borrows 179 | * @dev The return value should be scaled by 1e18, thus a return value of 180 | * `(true, 1000000000000)` implies an interest rate of 0.000001 or 0.0001% *per block*. 181 | * @param asset The asset to get the interest rate of 182 | * @param cash The total cash of the asset in the market 183 | * @param borrows The total borrows of the asset in the market 184 | * @return Success or failure and the borrow interest rate per block scaled by 10e18 185 | */ 186 | function getBorrowRate(address asset, uint cash, uint borrows) public returns (uint, uint) { 187 | require(isAllowed(asset, cash)); 188 | 189 | (IRError err0, Exp memory _utilizationRate, Exp memory annualBorrowRate) = getUtilizationAndAnnualBorrowRate(cash, borrows); 190 | if (err0 != IRError.NO_ERROR) { 191 | return (uint(err0), 0); 192 | } 193 | 194 | // And then divide down by blocks per year. 195 | (Error err1, Exp memory borrowRate) = divScalar(annualBorrowRate, blocksPerYear); // basis points * blocks per year 196 | // divScalar only fails when divisor is zero. This is clearly not the case. 197 | assert(err1 == Error.NO_ERROR); 198 | 199 | _utilizationRate; // pragma ignore unused variable 200 | 201 | // Note: mantissa is the rate scaled 1e18, which matches the expected result 202 | return (uint(IRError.NO_ERROR), borrowRate.mantissa); 203 | } 204 | } 205 | -------------------------------------------------------------------------------- /contracts/USDTRateModel.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.24; 2 | 3 | import "./Exponential.sol"; 4 | import "./InterestRateModel.sol"; 5 | import "./LiquidationChecker.sol"; 6 | 7 | 8 | contract MoneyMarket { 9 | function markets(address asset) public view returns (bool, uint, InterestRateModel, uint, uint, uint, uint, uint, uint); 10 | function oracle() public view returns (address); 11 | } 12 | 13 | contract PriceOracleProxy { 14 | address public mostRecentCaller; 15 | uint public mostRecentBlock; 16 | 17 | /** 18 | * @notice Gets the price of a given asset 19 | * @dev fetches the price of a given asset 20 | * @param asset Asset to get the price of 21 | * @return the price scaled by 10**18, or zero if the price is not available 22 | */ 23 | function assetPrices(address asset) public returns (uint); 24 | } 25 | 26 | contract USDTRateModel is Exponential, LiquidationChecker { 27 | 28 | uint constant blocksPerYear = 2102400; 29 | 30 | address public owner; 31 | address public newOwner; 32 | 33 | modifier onlyOwner() { 34 | require(msg.sender == owner, "non-owner"); 35 | _; 36 | } 37 | 38 | enum IRError { 39 | NO_ERROR, 40 | FAILED_TO_ADD_CASH_PLUS_BORROWS, 41 | FAILED_TO_GET_EXP, 42 | FAILED_TO_MUL_PRODUCT_TIMES_BORROW_RATE 43 | } 44 | 45 | event OwnerUpdate(address indexed owner, address indexed newOwner); 46 | event LiquidatorUpdate(address indexed owner, address indexed newLiquidator, address indexed oldLiquidator); 47 | 48 | constructor(address moneyMarket, address liquidator) LiquidationChecker(moneyMarket, liquidator) { 49 | owner = msg.sender; 50 | } 51 | 52 | function transferOwnership(address newOwner_) external onlyOwner { 53 | require(newOwner_ != owner, "TransferOwnership: the same owner."); 54 | newOwner = newOwner_; 55 | } 56 | 57 | function acceptOwnership() external { 58 | require(msg.sender == newOwner, "AcceptOwnership: only new owner do this."); 59 | emit OwnerUpdate(owner, newOwner); 60 | owner = newOwner; 61 | newOwner = address(0x0); 62 | } 63 | 64 | function setLiquidator(address _liquidator) external onlyOwner { 65 | require(_liquidator != address(0), "setLiquidator: liquidator cannot be a zero address"); 66 | require(liquidator != _liquidator, "setLiquidator: The old and new addresses cannot be the same"); 67 | address oldLiquidator = liquidator; 68 | liquidator = _liquidator; 69 | emit LiquidatorUpdate(msg.sender, _liquidator, oldLiquidator); 70 | } 71 | 72 | /* 73 | * @dev Calculates the utilization rate (borrows / (cash + borrows)) as an Exp 74 | */ 75 | function getUtilizationRate(uint cash, uint borrows) pure internal returns (IRError, Exp memory) { 76 | if (borrows == 0) { 77 | // Utilization rate is zero when there's no borrows 78 | return (IRError.NO_ERROR, Exp({mantissa: 0})); 79 | } 80 | 81 | (Error err0, uint cashPlusBorrows) = add(cash, borrows); 82 | if (err0 != Error.NO_ERROR) { 83 | return (IRError.FAILED_TO_ADD_CASH_PLUS_BORROWS, Exp({mantissa: 0})); 84 | } 85 | 86 | (Error err1, Exp memory utilizationRate) = getExp(borrows, cashPlusBorrows); 87 | if (err1 != Error.NO_ERROR) { 88 | return (IRError.FAILED_TO_GET_EXP, Exp({mantissa: 0})); 89 | } 90 | 91 | return (IRError.NO_ERROR, utilizationRate); 92 | } 93 | 94 | function powDecimal(uint utilizationRate, uint power) pure internal returns (Error, uint){ 95 | 96 | uint result = utilizationRate; 97 | Error err0; 98 | uint decimal = 10**18; 99 | uint i = 1; 100 | while(i < power){ 101 | 102 | if(power - i > 2){ 103 | 104 | (err0, result) = mul(result, utilizationRate ** 3); 105 | if (err0 != Error.NO_ERROR) 106 | return (err0, 0); 107 | 108 | result = result / decimal ** 3; 109 | i += 3; 110 | }else if(power - i > 1){ 111 | 112 | (err0, result) = mul(result, utilizationRate ** 2); 113 | if (err0 != Error.NO_ERROR) 114 | return (err0, 0); 115 | 116 | result = result / decimal ** 2; 117 | i += 2; 118 | }else { 119 | 120 | (err0, result) = mul(result, utilizationRate); 121 | if (err0 != Error.NO_ERROR) 122 | return (err0, 0); 123 | 124 | result = result / decimal; 125 | i++; 126 | } 127 | } 128 | 129 | return (err0, result); 130 | } 131 | 132 | /* 133 | * @dev Calculates the utilization and borrow rates for use by get{Supply,Borrow}Rate functions 134 | */ 135 | function getUtilizationAndAnnualBorrowRate(uint cash, uint borrows) pure internal returns (IRError, Exp memory, Exp memory) { 136 | (IRError err0, Exp memory utilizationRate) = getUtilizationRate(cash, borrows); 137 | if (err0 != IRError.NO_ERROR) { 138 | return (err0, Exp({mantissa: 0}), Exp({mantissa: 0})); 139 | } 140 | 141 | if (utilizationRate.mantissa >= 75e16 && utilizationRate.mantissa <= 85e16) 142 | return (IRError.NO_ERROR, utilizationRate, Exp({mantissa: 63835754242258350})); 143 | 144 | /** 145 | * Borrow Rate 146 | * 0 < UR < 75% : 0.06 * UR + 0.05 * UR^4 + 0.03 * UR^8 + 0.12 * UR^32 147 | * 75% <= UR <= 85% : 0.06 * 0.75 + 0.05 * 0.75^4 + 0.03 * 0.75^8 + 0.12 * 0.75^32 148 | * 85% < UR : 0.06 * UR + 0.05 * UR^12 + 0.03 * UR^8 + 0.12 * UR^32 149 | */ 150 | Error err; 151 | uint annualBorrowRateScaled; 152 | (err, annualBorrowRateScaled) = mul(utilizationRate.mantissa, 6); 153 | assert(err == Error.NO_ERROR); 154 | 155 | uint temp; 156 | uint base; 157 | 158 | (err, base) = powDecimal(utilizationRate.mantissa, 4); 159 | assert(err == Error.NO_ERROR); 160 | 161 | (err, temp) = mul(utilizationRate.mantissa > 85e16 ? base**3 / 10**36 : base, 5); 162 | assert(err == Error.NO_ERROR); 163 | 164 | (err, annualBorrowRateScaled) = add(annualBorrowRateScaled, temp); 165 | assert(err == Error.NO_ERROR); 166 | 167 | (err, temp) = mul(base**2 / 10**18, 3); 168 | assert(err == Error.NO_ERROR); 169 | 170 | (err, annualBorrowRateScaled) = add(annualBorrowRateScaled, temp); 171 | assert(err == Error.NO_ERROR); 172 | 173 | (err, base) = powDecimal(base**2 / 10**18, 4); 174 | assert(err == Error.NO_ERROR); 175 | 176 | (err, temp) = mul(base, 12); 177 | assert(err == Error.NO_ERROR); 178 | 179 | (err, annualBorrowRateScaled) = add(annualBorrowRateScaled, temp); 180 | assert(err == Error.NO_ERROR); 181 | 182 | return (IRError.NO_ERROR, utilizationRate, Exp({mantissa: annualBorrowRateScaled / 100})); 183 | } 184 | 185 | /** 186 | * @notice Gets the current supply interest rate based on the given asset, total cash and total borrows 187 | * @dev The return value should be scaled by 1e18, thus a return value of 188 | * `(true, 1000000000000)` implies an interest rate of 0.000001 or 0.0001% *per block*. 189 | * @param _asset The asset to get the interest rate of 190 | * @param cash The total cash of the asset in the market 191 | * @param borrows The total borrows of the asset in the market 192 | * @return Success or failure and the supply interest rate per block scaled by 10e18 193 | */ 194 | function getSupplyRate(address _asset, uint cash, uint borrows) public view returns (uint, uint) { 195 | _asset; // pragma ignore unused argument 196 | 197 | (IRError err0, Exp memory utilizationRate0, Exp memory annualBorrowRate) = getUtilizationAndAnnualBorrowRate(cash, borrows); 198 | if (err0 != IRError.NO_ERROR) { 199 | return (uint(err0), 0); 200 | } 201 | 202 | /** 203 | * Supply Rate 204 | * 0 < UR < 75% : 0.98 * BorrowRate 205 | * 75% <= UR : 0.99 * BorrowRate 206 | */ 207 | uint oneMinusSpreadBasisPoints = utilizationRate0.mantissa >= 75e16 ? 9900 : 9800; 208 | 209 | // We're going to multiply the utilization rate by the spread's numerator 210 | (Error err1, Exp memory utilizationRate1) = mulScalar(utilizationRate0, oneMinusSpreadBasisPoints); 211 | // mulScalar only overflows when product is greater than or equal to 2^256. 212 | // utilization rate's mantissa is a number between [0e18,1e18]. That means that 213 | // utilizationRate1 is a value between [0e18,8.5e21]. This is strictly less than 2^256. 214 | assert(err1 == Error.NO_ERROR); 215 | 216 | // Next multiply this product times the borrow rate 217 | (Error err2, Exp memory supplyRate0) = mulExp(utilizationRate1, annualBorrowRate); 218 | // If the product of the mantissas for mulExp are both less than 2^256, 219 | // then this operation will never fail. TODO: Verify. 220 | // We know that borrow rate is in the interval [0, 2.25e17] from above. 221 | // We know that utilizationRate1 is in the interval [0, 9e21] from directly above. 222 | // As such, the multiplication is in the interval of [0, 2.025e39]. This is strictly 223 | // less than 2^256 (which is about 10e77). 224 | assert(err2 == Error.NO_ERROR); 225 | 226 | // And then divide down by the spread's denominator (basis points divisor) 227 | // as well as by blocks per year. 228 | (Error err3, Exp memory supplyRate1) = divScalar(supplyRate0, 10000 * blocksPerYear); // basis points * blocks per year 229 | // divScalar only fails when divisor is zero. This is clearly not the case. 230 | assert(err3 == Error.NO_ERROR); 231 | 232 | return (uint(IRError.NO_ERROR), supplyRate1.mantissa); 233 | } 234 | 235 | /** 236 | * @notice Gets the current borrow interest rate based on the given asset, total cash and total borrows 237 | * @dev The return value should be scaled by 1e18, thus a return value of 238 | * `(true, 1000000000000)` implies an interest rate of 0.000001 or 0.0001% *per block*. 239 | * @param asset The asset to get the interest rate of 240 | * @param cash The total cash of the asset in the market 241 | * @param borrows The total borrows of the asset in the market 242 | * @return Success or failure and the borrow interest rate per block scaled by 10e18 243 | */ 244 | function getBorrowRate(address asset, uint cash, uint borrows) public returns (uint, uint) { 245 | require(isAllowed(asset, cash)); 246 | 247 | (IRError err0, , Exp memory annualBorrowRate) = getUtilizationAndAnnualBorrowRate(cash, borrows); 248 | if (err0 != IRError.NO_ERROR) { 249 | return (uint(err0), 0); 250 | } 251 | 252 | // And then divide down by blocks per year. 253 | (Error err1, Exp memory borrowRate) = divScalar(annualBorrowRate, blocksPerYear); // basis points * blocks per year 254 | // divScalar only fails when divisor is zero. This is clearly not the case. 255 | assert(err1 == Error.NO_ERROR); 256 | 257 | // Note: mantissa is the rate scaled 1e18, which matches the expected result 258 | return (uint(IRError.NO_ERROR), borrowRate.mantissa); 259 | } 260 | } 261 | -------------------------------------------------------------------------------- /contracts/USDxInterestRateModel.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.24; 2 | 3 | import "./Exponential.sol"; 4 | import "./InterestRateModel.sol"; 5 | import "./LiquidationChecker.sol"; 6 | 7 | 8 | contract MoneyMarket { 9 | function markets(address asset) public view returns (bool, uint, InterestRateModel, uint, uint, uint, uint, uint, uint); 10 | function oracle() public view returns (address); 11 | } 12 | 13 | contract PriceOracleProxy { 14 | address public mostRecentCaller; 15 | uint public mostRecentBlock; 16 | 17 | /** 18 | * @notice Gets the price of a given asset 19 | * @dev fetches the price of a given asset 20 | * @param asset Asset to get the price of 21 | * @return the price scaled by 10**18, or zero if the price is not available 22 | */ 23 | function assetPrices(address asset) public returns (uint); 24 | } 25 | 26 | contract USDxRateModel is Exponential, LiquidationChecker { 27 | 28 | uint constant oneMinusSpreadBasisPoints = 9800; 29 | uint constant blocksPerYear = 2102400; 30 | 31 | address public owner; 32 | address public newOwner; 33 | 34 | modifier onlyOwner() { 35 | require(msg.sender == owner, "non-owner"); 36 | _; 37 | } 38 | 39 | enum IRError { 40 | NO_ERROR, 41 | FAILED_TO_ADD_CASH_PLUS_BORROWS, 42 | FAILED_TO_GET_EXP, 43 | FAILED_TO_MUL_PRODUCT_TIMES_BORROW_RATE 44 | } 45 | 46 | event OwnerUpdate(address indexed owner, address indexed newOwner); 47 | event LiquidatorUpdate(address indexed owner, address indexed newLiquidator, address indexed oldLiquidator); 48 | 49 | constructor(address moneyMarket, address liquidator) LiquidationChecker(moneyMarket, liquidator) { 50 | owner = msg.sender; 51 | } 52 | 53 | function transferOwnership(address newOwner_) external onlyOwner { 54 | require(newOwner_ != owner, "TransferOwnership: the same owner."); 55 | newOwner = newOwner_; 56 | } 57 | 58 | function acceptOwnership() external { 59 | require(msg.sender == newOwner, "AcceptOwnership: only new owner do this."); 60 | emit OwnerUpdate(owner, newOwner); 61 | owner = newOwner; 62 | newOwner = address(0x0); 63 | } 64 | 65 | function setLiquidator(address _liquidator) external onlyOwner { 66 | require(_liquidator != address(0), "setLiquidator: liquidator cannot be a zero address"); 67 | require(liquidator != _liquidator, "setLiquidator: The old and new addresses cannot be the same"); 68 | address oldLiquidator = liquidator; 69 | liquidator = _liquidator; 70 | emit LiquidatorUpdate(msg.sender, _liquidator, oldLiquidator); 71 | } 72 | 73 | /* 74 | * @dev Calculates the utilization rate (borrows / (cash + borrows)) as an Exp 75 | */ 76 | function getUtilizationRate(uint cash, uint borrows) pure internal returns (IRError, Exp memory) { 77 | if (borrows == 0) { 78 | // Utilization rate is zero when there's no borrows 79 | return (IRError.NO_ERROR, Exp({mantissa: 0})); 80 | } 81 | 82 | (Error err0, uint cashPlusBorrows) = add(cash, borrows); 83 | if (err0 != Error.NO_ERROR) { 84 | return (IRError.FAILED_TO_ADD_CASH_PLUS_BORROWS, Exp({mantissa: 0})); 85 | } 86 | 87 | (Error err1, Exp memory utilizationRate) = getExp(borrows, cashPlusBorrows); 88 | if (err1 != Error.NO_ERROR) { 89 | return (IRError.FAILED_TO_GET_EXP, Exp({mantissa: 0})); 90 | } 91 | 92 | return (IRError.NO_ERROR, utilizationRate); 93 | } 94 | 95 | function powDecimal(uint utilizationRate, uint power) pure internal returns (Error, uint){ 96 | 97 | uint result = utilizationRate; 98 | Error err0; 99 | uint decimal = 10**18; 100 | uint i = 1; 101 | while(i < power){ 102 | 103 | if(power - i > 2){ 104 | 105 | (err0, result) = mul(result, utilizationRate ** 3); 106 | if (err0 != Error.NO_ERROR) 107 | return (err0, 0); 108 | 109 | result = result / decimal ** 3; 110 | i += 3; 111 | }else if(power - i > 1){ 112 | 113 | (err0, result) = mul(result, utilizationRate ** 2); 114 | if (err0 != Error.NO_ERROR) 115 | return (err0, 0); 116 | 117 | result = result / decimal ** 2; 118 | i += 2; 119 | }else { 120 | 121 | (err0, result) = mul(result, utilizationRate); 122 | if (err0 != Error.NO_ERROR) 123 | return (err0, 0); 124 | 125 | result = result / decimal; 126 | i++; 127 | } 128 | } 129 | 130 | return (err0, result); 131 | } 132 | 133 | /* 134 | * @dev Calculates the utilization and borrow rates for use by get{Supply,Borrow}Rate functions 135 | */ 136 | function getUtilizationAndAnnualBorrowRate(uint cash, uint borrows) pure internal returns (IRError, Exp memory, Exp memory) { 137 | (IRError err0, Exp memory utilizationRate) = getUtilizationRate(cash, borrows); 138 | if (err0 != IRError.NO_ERROR) { 139 | return (err0, Exp({mantissa: 0}), Exp({mantissa: 0})); 140 | } 141 | 142 | Error err; 143 | uint temp; 144 | uint annualBorrowRate; 145 | 146 | temp = utilizationRate.mantissa**2 / 10**18; 147 | (err, annualBorrowRate) = add(utilizationRate.mantissa, temp); 148 | assert(err == Error.NO_ERROR); 149 | 150 | temp = temp**2 / 10**18; 151 | (err, annualBorrowRate) = add(annualBorrowRate, temp); 152 | assert(err == Error.NO_ERROR); 153 | 154 | (err, temp) = powDecimal(temp, 8); 155 | assert(err == Error.NO_ERROR); 156 | (err, annualBorrowRate) = add(annualBorrowRate, temp); 157 | assert(err == Error.NO_ERROR); 158 | 159 | (err, annualBorrowRate) = add(annualBorrowRate, temp); 160 | assert(err == Error.NO_ERROR); 161 | 162 | // Borrow Rate is (UtilizationRate + UtilizationRate^2 + UtilizationRate^4 + 2 * UtilizationRate^32) * 5% 163 | Exp memory annualBorrowRateMuled; 164 | (err, annualBorrowRateMuled) = mulScalar(Exp({mantissa: annualBorrowRate}), 5); 165 | // `mulScalar` only overflows when the product is >= 2^256. 166 | // utilizationRate is a real number on the interval [0,1], which means that 167 | // utilizationRate.mantissa is in the interval [0e18,1e18], which means that 2 times 168 | // that is in the interval [0e18,2e18]. That interval has no intersection with 2^256, and therefore 169 | // this can never overflow. As such, we assert. 170 | assert(err == Error.NO_ERROR); 171 | 172 | Exp memory annualBorrowRateScaled; 173 | (err, annualBorrowRateScaled) = divScalar(annualBorrowRateMuled, 100); 174 | // 100 is a constant, and therefore cannot be zero, which is the only error case of divScalar. 175 | assert(err == Error.NO_ERROR); 176 | 177 | return (IRError.NO_ERROR, utilizationRate, annualBorrowRateScaled); 178 | } 179 | 180 | /** 181 | * @notice Gets the current supply interest rate based on the given asset, total cash and total borrows 182 | * @dev The return value should be scaled by 1e18, thus a return value of 183 | * `(true, 1000000000000)` implies an interest rate of 0.000001 or 0.0001% *per block*. 184 | * @param _asset The asset to get the interest rate of 185 | * @param cash The total cash of the asset in the market 186 | * @param borrows The total borrows of the asset in the market 187 | * @return Success or failure and the supply interest rate per block scaled by 10e18 188 | */ 189 | function getSupplyRate(address _asset, uint cash, uint borrows) public view returns (uint, uint) { 190 | _asset; // pragma ignore unused argument 191 | 192 | (IRError err0, Exp memory utilizationRate0, Exp memory annualBorrowRate) = getUtilizationAndAnnualBorrowRate(cash, borrows); 193 | if (err0 != IRError.NO_ERROR) { 194 | return (uint(err0), 0); 195 | } 196 | 197 | // We're going to multiply the utilization rate by the spread's numerator 198 | (Error err1, Exp memory utilizationRate1) = mulScalar(utilizationRate0, oneMinusSpreadBasisPoints); 199 | // mulScalar only overflows when product is greater than or equal to 2^256. 200 | // utilization rate's mantissa is a number between [0e18,1e18]. That means that 201 | // utilizationRate1 is a value between [0e18,8.5e21]. This is strictly less than 2^256. 202 | assert(err1 == Error.NO_ERROR); 203 | 204 | // Next multiply this product times the borrow rate 205 | (Error err2, Exp memory supplyRate0) = mulExp(utilizationRate1, annualBorrowRate); 206 | // If the product of the mantissas for mulExp are both less than 2^256, 207 | // then this operation will never fail. TODO: Verify. 208 | // We know that borrow rate is in the interval [0, 2.25e17] from above. 209 | // We know that utilizationRate1 is in the interval [0, 9e21] from directly above. 210 | // As such, the multiplication is in the interval of [0, 2.025e39]. This is strictly 211 | // less than 2^256 (which is about 10e77). 212 | assert(err2 == Error.NO_ERROR); 213 | 214 | // And then divide down by the spread's denominator (basis points divisor) 215 | // as well as by blocks per year. 216 | (Error err3, Exp memory supplyRate1) = divScalar(supplyRate0, 10000 * blocksPerYear); // basis points * blocks per year 217 | // divScalar only fails when divisor is zero. This is clearly not the case. 218 | assert(err3 == Error.NO_ERROR); 219 | 220 | return (uint(IRError.NO_ERROR), supplyRate1.mantissa); 221 | } 222 | 223 | /** 224 | * @notice Gets the current borrow interest rate based on the given asset, total cash and total borrows 225 | * @dev The return value should be scaled by 1e18, thus a return value of 226 | * `(true, 1000000000000)` implies an interest rate of 0.000001 or 0.0001% *per block*. 227 | * @param asset The asset to get the interest rate of 228 | * @param cash The total cash of the asset in the market 229 | * @param borrows The total borrows of the asset in the market 230 | * @return Success or failure and the borrow interest rate per block scaled by 10e18 231 | */ 232 | function getBorrowRate(address asset, uint cash, uint borrows) public returns (uint, uint) { 233 | require(isAllowed(asset, cash)); 234 | 235 | (IRError err0, Exp memory _utilizationRate, Exp memory annualBorrowRate) = getUtilizationAndAnnualBorrowRate(cash, borrows); 236 | if (err0 != IRError.NO_ERROR) { 237 | return (uint(err0), 0); 238 | } 239 | 240 | // And then divide down by blocks per year. 241 | (Error err1, Exp memory borrowRate) = divScalar(annualBorrowRate, blocksPerYear); // basis points * blocks per year 242 | // divScalar only fails when divisor is zero. This is clearly not the case. 243 | assert(err1 == Error.NO_ERROR); 244 | 245 | _utilizationRate; // pragma ignore unused variable 246 | 247 | // Note: mantissa is the rate scaled 1e18, which matches the expected result 248 | return (uint(IRError.NO_ERROR), borrowRate.mantissa); 249 | } 250 | } 251 | -------------------------------------------------------------------------------- /contracts/imBTCRateModel.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.24; 2 | 3 | import "./Exponential.sol"; 4 | import "./InterestRateModel.sol"; 5 | import "./LiquidationChecker.sol"; 6 | 7 | 8 | contract MoneyMarket { 9 | function markets(address asset) public view returns (bool, uint, InterestRateModel, uint, uint, uint, uint, uint, uint); 10 | function oracle() public view returns (address); 11 | } 12 | 13 | contract PriceOracleProxy { 14 | address public mostRecentCaller; 15 | uint public mostRecentBlock; 16 | 17 | /** 18 | * @notice Gets the price of a given asset 19 | * @dev fetches the price of a given asset 20 | * @param asset Asset to get the price of 21 | * @return the price scaled by 10**18, or zero if the price is not available 22 | */ 23 | function assetPrices(address asset) public returns (uint); 24 | } 25 | 26 | /** 27 | * @title The Lendf.Me Standard Interest Rate Model with LiquidationChecker 28 | * @author Lendf.Me 29 | */ 30 | contract ImBTCInterestRateModel is Exponential, LiquidationChecker { 31 | 32 | uint constant oneMinusSpreadBasisPoints = 9800; 33 | uint constant blocksPerYear = 2102400; 34 | // uint constant mantissaFivePercent = 5 * 10**16; 35 | uint public baseRate = 11200000000000000; 36 | uint public maxBaseRate = 60000000000000000; 37 | 38 | address public owner; 39 | address public newOwner; 40 | 41 | modifier onlyOwner() { 42 | require(msg.sender == owner, "non-owner"); 43 | _; 44 | } 45 | 46 | enum IRError { 47 | NO_ERROR, 48 | FAILED_TO_ADD_CASH_PLUS_BORROWS, 49 | FAILED_TO_GET_EXP, 50 | FAILED_TO_MUL_PRODUCT_TIMES_BORROW_RATE 51 | } 52 | 53 | event OwnerUpdate(address indexed owner, address indexed newOwner); 54 | event LiquidatorUpdate(address indexed owner, address indexed newLiquidator, address indexed oldLiquidator); 55 | event BaseRateUpdate(address indexed owner, uint indexed newBaseRate, uint indexed oldBaseRate); 56 | event MaxBaseRateUpdate(address indexed owner, uint indexed newMaxBaseRate, uint indexed oldMaxBaseRate); 57 | 58 | constructor(address moneyMarket, address liquidator) LiquidationChecker(moneyMarket, liquidator) { 59 | owner = msg.sender; 60 | } 61 | 62 | function transferOwnership(address newOwner_) external onlyOwner { 63 | require(newOwner_ != owner, "TransferOwnership: the same owner."); 64 | newOwner = newOwner_; 65 | } 66 | 67 | function acceptOwnership() external { 68 | require(msg.sender == newOwner, "AcceptOwnership: only new owner do this."); 69 | emit OwnerUpdate(owner, newOwner); 70 | owner = newOwner; 71 | newOwner = address(0x0); 72 | } 73 | 74 | function setLiquidator(address _liquidator) external onlyOwner { 75 | require(_liquidator != address(0), "setLiquidator: liquidator cannot be a zero address"); 76 | require(liquidator != _liquidator, "setLiquidator: The old and new addresses cannot be the same"); 77 | address oldLiquidator = liquidator; 78 | liquidator = _liquidator; 79 | emit LiquidatorUpdate(msg.sender, _liquidator, oldLiquidator); 80 | } 81 | 82 | function setMaxBaseRate(uint _maxBaseRate) external onlyOwner { 83 | require(_maxBaseRate != maxBaseRate, "setMaxBaseRate: the same maxBaseRate"); 84 | require(_maxBaseRate <= 10**18, "setMaxBaseRate: maxBaseRate must be less than or equal to the 100%"); 85 | uint oldMaxBaseRate = maxBaseRate; 86 | maxBaseRate = _maxBaseRate; 87 | emit MaxBaseRateUpdate(msg.sender, _maxBaseRate, oldMaxBaseRate); 88 | } 89 | 90 | function setBaseRate(uint _baseRate) external onlyOwner { 91 | require(_baseRate != baseRate, "setBaseRate: the same baseRate"); 92 | require(_baseRate <= maxBaseRate, "setBaseRate: baseRate must be less than or equal to the maxBaseRate"); 93 | uint oldBaseRate = baseRate; 94 | baseRate = _baseRate; 95 | emit BaseRateUpdate(msg.sender, _baseRate, oldBaseRate); 96 | } 97 | 98 | /** 99 | * @dev Calculates the utilization rate (borrows / (cash + borrows)) as an Exp 100 | */ 101 | function getUtilizationRate(uint cash, uint borrows) pure internal returns (IRError, Exp memory) { 102 | if (borrows == 0) { 103 | // Utilization rate is zero when there's no borrows 104 | return (IRError.NO_ERROR, Exp({mantissa: 0})); 105 | } 106 | 107 | (Error err0, uint cashPlusBorrows) = add(cash, borrows); 108 | if (err0 != Error.NO_ERROR) { 109 | return (IRError.FAILED_TO_ADD_CASH_PLUS_BORROWS, Exp({mantissa: 0})); 110 | } 111 | 112 | (Error err1, Exp memory utilizationRate) = getExp(borrows, cashPlusBorrows); 113 | if (err1 != Error.NO_ERROR) { 114 | return (IRError.FAILED_TO_GET_EXP, Exp({mantissa: 0})); 115 | } 116 | 117 | return (IRError.NO_ERROR, utilizationRate); 118 | } 119 | 120 | /** 121 | * @dev Calculates the utilization and borrow rates for use by get{Supply,Borrow}Rate functions 122 | */ 123 | function getUtilizationAndAnnualBorrowRate(uint cash, uint borrows) pure internal returns (IRError, Exp memory, Exp memory) { 124 | (IRError err0, Exp memory utilizationRate) = getUtilizationRate(cash, borrows); 125 | if (err0 != IRError.NO_ERROR) { 126 | return (err0, Exp({mantissa: 0}), Exp({mantissa: 0})); 127 | } 128 | 129 | // Borrow Rate is UtilizationRate * 20% 130 | // 20% of utilizationRate, is `rate * 20 / 100` 131 | (Error err1, Exp memory utilizationRateMuled) = mulScalar(utilizationRate, 20); 132 | // `mulScalar` only overflows when the product is >= 2^256. 133 | // utilizationRate is a real number on the interval [0,1], which means that 134 | // utilizationRate.mantissa is in the interval [0e18,1e18], which means that 45 times 135 | // that is in the interval [0e18,45e18]. That interval has no intersection with 2^256, and therefore 136 | // this can never overflow. As such, we assert. 137 | assert(err1 == Error.NO_ERROR); 138 | 139 | (Error err2, Exp memory utilizationRateScaled) = divScalar(utilizationRateMuled, 100); 140 | // 100 is a constant, and therefore cannot be zero, which is the only error case of divScalar. 141 | assert(err2 == Error.NO_ERROR); 142 | 143 | // Add the 5% for (5% + 20% * Ua) 144 | // (Error err3, Exp memory annualBorrowRate) = addExp(utilizationRateScaled, Exp({mantissa: mantissaFivePercent})); 145 | // `addExp` only fails when the addition of mantissas overflow. 146 | // As per above, utilizationRateMuled is capped at 45e18, 147 | // and utilizationRateScaled is capped at 4.5e17. mantissaFivePercent = 0.5e17, and thus the addition 148 | // is capped at 5e17, which is less than 2^256. 149 | // assert(err3 == Error.NO_ERROR); 150 | 151 | return (IRError.NO_ERROR, utilizationRate, utilizationRateScaled); 152 | } 153 | 154 | /** 155 | * @notice Gets the current supply interest rate based on the given asset, total cash and total borrows 156 | * @dev The return value should be scaled by 1e18, thus a return value of 157 | * `(true, 1000000000000)` implies an interest rate of 0.000001 or 0.0001% *per block*. 158 | * @param _asset The asset to get the interest rate of 159 | * @param cash The total cash of the asset in the market 160 | * @param borrows The total borrows of the asset in the market 161 | * @return Success or failure and the supply interest rate per block scaled by 10e18 162 | */ 163 | function getSupplyRate(address _asset, uint cash, uint borrows) public view returns (uint, uint) { 164 | _asset; // pragma ignore unused argument 165 | 166 | (IRError err0, Exp memory utilizationRate0, Exp memory annualBorrowRate) = getUtilizationAndAnnualBorrowRate(cash, borrows); 167 | if (err0 != IRError.NO_ERROR) { 168 | return (uint(err0), 0); 169 | } 170 | 171 | // We're going to multiply the utilization rate by the spread's numerator 172 | (Error err1, Exp memory utilizationRate1) = mulScalar(utilizationRate0, oneMinusSpreadBasisPoints); 173 | // mulScalar only overflows when product is greater than or equal to 2^256. 174 | // utilization rate's mantissa is a number between [0e18,1e18]. That means that 175 | // utilizationRate1 is a value between [0e18,9e21]. This is strictly less than 2^256. 176 | assert(err1 == Error.NO_ERROR); 177 | 178 | // Next multiply this product times the borrow rate 179 | (Error err2, Exp memory supplyRate0) = mulExp(utilizationRate1, annualBorrowRate); 180 | // If the product of the mantissas for mulExp are both less than 2^256, 181 | // then this operation will never fail. TODO: Verify. 182 | // We know that borrow rate is in the interval [0, 4e17] from above. 183 | // We know that utilizationRate1 is in the interval [0, 9e21] from directly above. 184 | // As such, the multiplication is in the interval of [0, 3.6e39]. This is strictly 185 | // less than 2^256 (which is about 10e77). 186 | assert(err2 == Error.NO_ERROR); 187 | 188 | // And then divide down by the spread's denominator (basis points divisor) 189 | // as well as by blocks per year. 190 | (Error err3, Exp memory supplyRate1) = divScalar(supplyRate0, 10000 * blocksPerYear); // basis points * blocks per year 191 | // divScalar only fails when divisor is zero. This is clearly not the case. 192 | assert(err3 == Error.NO_ERROR); 193 | 194 | // Note: mantissa is the rate scaled 1e18, which matches the expected result 195 | return (uint(IRError.NO_ERROR), supplyRate1.mantissa + baseRate / blocksPerYear); 196 | } 197 | 198 | /** 199 | * @notice Gets the current borrow interest rate based on the given asset, total cash and total borrows 200 | * @dev The return value should be scaled by 1e18, thus a return value of 201 | * `(true, 1000000000000)` implies an interest rate of 0.000001 or 0.0001% *per block*. 202 | * @param asset The asset to get the interest rate of 203 | * @param cash The total cash of the asset in the market 204 | * @param borrows The total borrows of the asset in the market 205 | * @return Success or failure and the borrow interest rate per block scaled by 10e18 206 | */ 207 | function getBorrowRate(address asset, uint cash, uint borrows) public returns (uint, uint) { 208 | require(isAllowed(asset, cash)); 209 | 210 | (IRError err0, Exp memory _utilizationRate, Exp memory annualBorrowRate) = getUtilizationAndAnnualBorrowRate(cash, borrows); 211 | if (err0 != IRError.NO_ERROR) { 212 | return (uint(err0), 0); 213 | } 214 | 215 | // And then divide down by blocks per year. 216 | (Error err1, Exp memory borrowRate) = divScalar(annualBorrowRate, blocksPerYear); // basis points * blocks per year 217 | // divScalar only fails when divisor is zero. This is clearly not the case. 218 | assert(err1 == Error.NO_ERROR); 219 | 220 | _utilizationRate; // pragma ignore unused variable 221 | 222 | // Note: mantissa is the rate scaled 1e18, which matches the expected result 223 | return (uint(IRError.NO_ERROR), borrowRate.mantissa + baseRate / blocksPerYear); 224 | } 225 | } 226 | -------------------------------------------------------------------------------- /test/InterestModel/abi/testInterestModel.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "constant": false, 4 | "inputs": [ 5 | { 6 | "name": "allowLiquidation_", 7 | "type": "bool" 8 | } 9 | ], 10 | "name": "setAllowLiquidation", 11 | "outputs": [], 12 | "payable": false, 13 | "stateMutability": "nonpayable", 14 | "type": "function" 15 | }, 16 | { 17 | "inputs": [ 18 | { 19 | "name": "moneyMarket", 20 | "type": "address" 21 | }, 22 | { 23 | "name": "liquidator", 24 | "type": "address" 25 | } 26 | ], 27 | "payable": false, 28 | "stateMutability": "nonpayable", 29 | "type": "constructor" 30 | }, 31 | { 32 | "anonymous": false, 33 | "inputs": [ 34 | { 35 | "indexed": false, 36 | "name": "error", 37 | "type": "uint256" 38 | }, 39 | { 40 | "indexed": false, 41 | "name": "info", 42 | "type": "uint256" 43 | }, 44 | { 45 | "indexed": false, 46 | "name": "detail", 47 | "type": "uint256" 48 | } 49 | ], 50 | "name": "Failure", 51 | "type": "event" 52 | }, 53 | { 54 | "constant": true, 55 | "inputs": [], 56 | "name": "allowLiquidation", 57 | "outputs": [ 58 | { 59 | "name": "", 60 | "type": "bool" 61 | } 62 | ], 63 | "payable": false, 64 | "stateMutability": "view", 65 | "type": "function" 66 | }, 67 | { 68 | "constant": true, 69 | "inputs": [ 70 | { 71 | "name": "ur", 72 | "type": "uint256" 73 | } 74 | ], 75 | "name": "getBorrowRate", 76 | "outputs": [ 77 | { 78 | "name": "", 79 | "type": "uint256" 80 | }, 81 | { 82 | "name": "", 83 | "type": "uint256" 84 | } 85 | ], 86 | "payable": false, 87 | "stateMutability": "view", 88 | "type": "function" 89 | }, 90 | { 91 | "constant": true, 92 | "inputs": [ 93 | { 94 | "name": "ur", 95 | "type": "uint256" 96 | } 97 | ], 98 | "name": "getSupplyRate", 99 | "outputs": [ 100 | { 101 | "name": "", 102 | "type": "uint256" 103 | }, 104 | { 105 | "name": "", 106 | "type": "uint256" 107 | } 108 | ], 109 | "payable": false, 110 | "stateMutability": "view", 111 | "type": "function" 112 | }, 113 | { 114 | "constant": true, 115 | "inputs": [], 116 | "name": "liquidator", 117 | "outputs": [ 118 | { 119 | "name": "", 120 | "type": "address" 121 | } 122 | ], 123 | "payable": false, 124 | "stateMutability": "view", 125 | "type": "function" 126 | }, 127 | { 128 | "constant": true, 129 | "inputs": [], 130 | "name": "moneyMarket", 131 | "outputs": [ 132 | { 133 | "name": "", 134 | "type": "address" 135 | } 136 | ], 137 | "payable": false, 138 | "stateMutability": "view", 139 | "type": "function" 140 | }, 141 | { 142 | "constant": true, 143 | "inputs": [], 144 | "name": "owner", 145 | "outputs": [ 146 | { 147 | "name": "", 148 | "type": "address" 149 | } 150 | ], 151 | "payable": false, 152 | "stateMutability": "view", 153 | "type": "function" 154 | } 155 | ] 156 | -------------------------------------------------------------------------------- /test/InterestModel/contract/testInterestModel.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.24; 2 | 3 | import "../../../contracts/Exponential.sol"; 4 | 5 | contract testRateModel is Exponential { 6 | uint constant blocksPerYear = 2102400; 7 | 8 | enum IRError { 9 | NO_ERROR, 10 | FAILED_TO_ADD_CASH_PLUS_BORROWS, 11 | FAILED_TO_GET_EXP, 12 | FAILED_TO_MUL_PRODUCT_TIMES_BORROW_RATE 13 | } 14 | 15 | function powDecimal(uint utilizationRate, uint power) pure internal returns (Error, uint) { 16 | 17 | uint result = utilizationRate; 18 | Error err0; 19 | uint decimal = 10**18; 20 | uint i = 1; 21 | while(i < power){ 22 | 23 | if(power - i > 2){ 24 | 25 | (err0, result) = mul(result, utilizationRate ** 3); 26 | if (err0 != Error.NO_ERROR) 27 | return (err0, 0); 28 | 29 | result = result / decimal ** 3; 30 | i += 3; 31 | }else if(power - i > 1){ 32 | 33 | (err0, result) = mul(result, utilizationRate ** 2); 34 | if (err0 != Error.NO_ERROR) 35 | return (err0, 0); 36 | 37 | result = result / decimal ** 2; 38 | i += 2; 39 | }else { 40 | 41 | (err0, result) = mul(result, utilizationRate); 42 | if (err0 != Error.NO_ERROR) 43 | return (err0, 0); 44 | 45 | result = result / decimal; 46 | i++; 47 | } 48 | } 49 | 50 | return (err0, result); 51 | } 52 | 53 | /* 54 | * @dev Calculates the utilization and borrow rates for use by get{Supply,Borrow}Rate functions 55 | */ 56 | function getUtilizationAndAnnualBorrowRate(uint ur) pure internal returns (IRError, Exp memory, Exp memory) { 57 | // (IRError err0, Exp memory utilizationRate) = getUtilizationRate(cash, borrows); 58 | // if (err0 != IRError.NO_ERROR) { 59 | // return (err0, Exp({mantissa: 0}), Exp({mantissa: 0})); 60 | // } 61 | Exp memory utilizationRate = Exp({mantissa: ur}); 62 | 63 | if (utilizationRate.mantissa >= 75e16 && utilizationRate.mantissa <= 85e16) 64 | return (IRError.NO_ERROR, utilizationRate, Exp({mantissa: 63835754242258350})); 65 | 66 | /** 67 | * Borrow Rate 68 | * 0 < UR < 75% : 0.06 * UR + 0.05 * UR^4 + 0.03 * UR^8 + 0.12 * UR^32 69 | * 75% <= UR <= 85% : 0.06 * 0.75 + 0.05 * 0.75^4 + 0.03 * 0.75^8 + 0.12 * 0.75^32 70 | * 85% < UR : 0.06 * UR + 0.05 * UR^12 + 0.03 * UR^8 + 0.12 * UR^32 71 | */ 72 | Error err; 73 | uint annualBorrowRateScaled; 74 | (err, annualBorrowRateScaled) = mul(utilizationRate.mantissa, 6); 75 | assert(err == Error.NO_ERROR); 76 | 77 | uint temp; 78 | uint base; 79 | 80 | (err, base) = powDecimal(utilizationRate.mantissa, 4); 81 | assert(err == Error.NO_ERROR); 82 | 83 | (err, temp) = mul(utilizationRate.mantissa > 85e16 ? base**3 / 10**36 : base, 5); 84 | assert(err == Error.NO_ERROR); 85 | 86 | (err, annualBorrowRateScaled) = add(annualBorrowRateScaled, temp); 87 | assert(err == Error.NO_ERROR); 88 | 89 | (err, temp) = mul(base**2 / 10**18, 3); 90 | assert(err == Error.NO_ERROR); 91 | 92 | (err, annualBorrowRateScaled) = add(annualBorrowRateScaled, temp); 93 | assert(err == Error.NO_ERROR); 94 | 95 | (err, base) = powDecimal(base**2 / 10**18, 4); 96 | assert(err == Error.NO_ERROR); 97 | 98 | (err, temp) = mul(base, 12); 99 | assert(err == Error.NO_ERROR); 100 | 101 | (err, annualBorrowRateScaled) = add(annualBorrowRateScaled, temp); 102 | assert(err == Error.NO_ERROR); 103 | 104 | return (IRError.NO_ERROR, utilizationRate, Exp({mantissa: annualBorrowRateScaled / 100})); 105 | } 106 | 107 | 108 | function getSupplyRate(uint ur) public view returns (uint, uint) { 109 | // _asset; // pragma ignore unused argument 110 | 111 | (IRError err0, Exp memory utilizationRate0, Exp memory annualBorrowRate) = getUtilizationAndAnnualBorrowRate(ur); 112 | if (err0 != IRError.NO_ERROR) { 113 | return (uint(err0), 0); 114 | } 115 | 116 | /** 117 | * Supply Rate 118 | * 0 < UR < 75% : 0.98 * BorrowRate 119 | * 75% <= UR : 0.99 * BorrowRate 120 | */ 121 | uint oneMinusSpreadBasisPoints = utilizationRate0.mantissa >= 75e16 ? 9900 : 9800; 122 | 123 | // We're going to multiply the utilization rate by the spread's numerator 124 | (Error err1, Exp memory utilizationRate1) = mulScalar(utilizationRate0, oneMinusSpreadBasisPoints); 125 | // mulScalar only overflows when product is greater than or equal to 2^256. 126 | // utilization rate's mantissa is a number between [0e18,1e18]. That means that 127 | // utilizationRate1 is a value between [0e18,8.5e21]. This is strictly less than 2^256. 128 | assert(err1 == Error.NO_ERROR); 129 | 130 | // Next multiply this product times the borrow rate 131 | (Error err2, Exp memory supplyRate0) = mulExp(utilizationRate1, annualBorrowRate); 132 | // If the product of the mantissas for mulExp are both less than 2^256, 133 | // then this operation will never fail. TODO: Verify. 134 | // We know that borrow rate is in the interval [0, 2.25e17] from above. 135 | // We know that utilizationRate1 is in the interval [0, 9e21] from directly above. 136 | // As such, the multiplication is in the interval of [0, 2.025e39]. This is strictly 137 | // less than 2^256 (which is about 10e77). 138 | assert(err2 == Error.NO_ERROR); 139 | 140 | // And then divide down by the spread's denominator (basis points divisor) 141 | // as well as by blocks per year. 142 | (Error err3, Exp memory supplyRate1) = divScalar(supplyRate0, 10000 * blocksPerYear); // basis points * blocks per year 143 | // divScalar only fails when divisor is zero. This is clearly not the case. 144 | assert(err3 == Error.NO_ERROR); 145 | 146 | return (uint(IRError.NO_ERROR), supplyRate1.mantissa); 147 | 148 | } 149 | 150 | function getBorrowRate(uint ur) public view returns (uint, uint) { 151 | 152 | (IRError err0, Exp memory _utilizationRate, Exp memory annualBorrowRate) = getUtilizationAndAnnualBorrowRate(ur); 153 | if (err0 != IRError.NO_ERROR) { 154 | return (uint(err0), 0); 155 | } 156 | 157 | // And then divide down by blocks per year. 158 | (Error err1, Exp memory borrowRate) = divScalar(annualBorrowRate, blocksPerYear); // basis points * blocks per year 159 | // divScalar only fails when divisor is zero. This is clearly not the case. 160 | assert(err1 == Error.NO_ERROR); 161 | 162 | // Note: mantissa is the rate scaled 1e18, which matches the expected result 163 | return (uint(IRError.NO_ERROR), borrowRate.mantissa); 164 | } 165 | } 166 | 167 | 168 | -------------------------------------------------------------------------------- /test/InterestModel/testInterestModel.js: -------------------------------------------------------------------------------- 1 | const Web3 = require('web3'); 2 | const BN = require('bn.js'); 3 | 4 | const USDTRateModelNewABI = require("./abi/testInterestModel.json"); 5 | 6 | // Add your own infura key at here! 7 | const web3 = new Web3(new Web3.providers.HttpProvider("https://rinkeby.infura.io/v3/" + INFURA_KEY)); 8 | 9 | const mantissOne = (new BN(10)).pow(new BN(12)) 10 | 11 | // If you want to test for the specific number, add to following array list, 12 | // !!!!!!!!!! 13 | // !! Note !!: the number has four decimal places, so if we want to test UR=5.67%, we should input 56700. 14 | // !!!!!!!!!! 15 | // default is 0% ~ 100%, that is there are 100 sets of data. 16 | // const configList = [56700, 100000]; 17 | let configList = []; 18 | 19 | const NewAddress = '0x1993Ef555636C0591b3fCA51a5301dA91a35ee87'; 20 | const contract = new web3.eth.Contract(USDTRateModelNewABI, NewAddress); 21 | 22 | async function main() { 23 | console.log('Borrow APR') 24 | 25 | let len = configList.length === 0 ? 102 : configList.length 26 | if (configList.length === 0) { 27 | for (let i = 0; i < 101; i++) { 28 | configList.push(i*10**4) 29 | } 30 | } 31 | 32 | for (let i = 0; i < len; i++) { 33 | let data = ((new BN(configList[i])).mul(mantissOne)).toString() 34 | let result = await contract.methods.getBorrowRate(data).call() 35 | console.log("result is: ", configList[i]/10**4, "%", result[1].toString() * 2102400 / 10 ** 18) 36 | } 37 | 38 | console.log('\n\n') 39 | console.log('Supply APR') 40 | 41 | for (let i = 0; i < len; i++) { 42 | let data = ((new BN(configList[i])).mul(mantissOne)).toString() 43 | let result = await contract.methods.getSupplyRate(data).call() 44 | console.log("result is: ", configList[i]/10**4, "%", result[1].toString() * 2102400 / 10 ** 18) 45 | } 46 | } 47 | 48 | 49 | main() 50 | --------------------------------------------------------------------------------