Cryo Explorer Ethereum Mainnet

Address Contract Verified

Address 0x58EbB8Db8b4FdF2dCbbB16E04c2F5b952963B514
Balance 0 ETH
Nonce 1
Code Size 19278 bytes
Indexed Transactions Index loading...
External Etherscan · Sourcify

Contract Bytecode

19278 bytes
0x60806040526004361015610018575b6100166147bd565b005b60003560e01c8063042e02cf146105545780630902f1ac1461054b5780630bc47ad1146105425780630c340a241461053957806318160ddd14610530578063189bb2f1146105275780631c9f7fb91461051e5780631f5954bd1461051557806323b872dd1461050c57806324a3d6221461050357806326441318146104fa5780632a48cf12146104f15780632b92a07d146104e85780632d05670b146104df5780632e04b8e7146104d6578063300e6beb146104cd578063313ce567146104c457806332176c49146104bb578063374c49b4146104b257806338aa813f146104a95780633b3bec2e146104a057806341976e09146104975780634232cd631461048e578063439e2e451461048557806344c1e5eb1461047c57806344c35d071461047357806344ff241d1461046a57806359e017bd146104615780635a94b8d11461045857806367800b5f1461044f57806370a08231146104465780637914acc71461043d5780637ac88ed1146104345780637eb711311461042b578063804de71f146104225780638285ef40146104195780638d5d814c1461041057806390323177146104075780639241a561146103fe5780639364e18a146103f557806394920cca146103ec5780639ea99a5a146103e35780639fa83b5a146103da5780639ff567f8146103d1578063a1654379146103c8578063a1a1ef43146103bf578063a46fe83b146103b6578063a5b4ff79146103ad578063a9059cbb146103a4578063aba7f15e1461039b578063ad14777c14610392578063bfe69c8d14610389578063c1ee2c1814610380578063c3b35a7e14610377578063c3cecfd21461036e578063c55dae6314610365578063c5fa15cf1461035c578063c8c7fe6b14610353578063cde680411461034a578063d8e5f61114610341578063d955759d14610338578063dc4abafd1461032f578063e478795d14610326578063e4e6e7791461031d578063e7dad6bd14610314578063f2b9fdb81461030b5763f3fef3a30361000e57610306611a71565b61000e565b50610306611a3c565b506103066119f6565b5061030661186d565b50610306611782565b5061030661170f565b506103066116f0565b506103066116c9565b506103066116ad565b50610306611682565b50610306611614565b506103066115ce565b50610306611569565b50610306611545565b5061030661151f565b50610306611484565b506103066113df565b506103066113a3565b5061030661134d565b50610306611311565b506103066112d2565b506103066112ab565b5061030661126a565b50610306611242565b50610306611211565b506103066111d5565b50610306611199565b5061030661115d565b50610306611121565b506103066110fb565b506103066110d4565b50610306611073565b50610306611037565b5061030661101b565b50610306610fef565b50610306610fb3565b50610306610f8b565b50610306610f64565b50610306610f28565b50610306610ed2565b50610306610e8c565b50610306610d0d565b50610306610cc4565b50610306610ca0565b50610306610c7c565b50610306610c54565b50610306610c1f565b50610306610b53565b50610306610b2b565b50610306610aef565b50610306610ab0565b50610306610a74565b50610306610a36565b506103066109fa565b506103066109a5565b50610306610904565b506103066108ca565b5061030661084d565b506103066107ea565b50610306610781565b506103066106fb565b506103066106bf565b50610306610653565b5061030661060d565b506103066105d4565b506103066105b0565b50610306610573565b6001600160a01b0381160361056e57565b600080fd5b503461056e57602036600319011261056e57602061059b6004356105968161055d565b612c8b565b6040519015158152f35b600091031261056e57565b503461056e57600036600319011261056e5760206105cc612992565b604051908152f35b503461056e57600036600319011261056e5760206001805460f81c161515604051908152f35b6001600160a01b03909116815260200190565b503461056e57600036600319011261056e576040517f0000000000000000000000006d903f6003cca6255d85cca4d3b5e5146dc339256001600160a01b03168152602090f35b503461056e57600036600319011261056e57602066038d7ea4c680006106b661067a61217a565b61069d6001549161069764ffffffffff91828560d01c16906121ee565b1661245d565b506001600160401b0316906001600160681b0316611b81565b04604051908152f35b503461056e57600036600319011261056e5760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b503461056e5760008060031936011261077e5760015464ffffffffff8160d01c1661076d5764ffffffffff60d01b61073161217a565b64ffffffffff60d01b1990921660d09290921b161760015580546001600160801b0319166e038d7ea4c6800000038d7ea4c68000178155604051f35b60405162dc149f60e41b8152600490fd5b80fd5b503461056e57600036600319011261056e5760206040517f0000000000000000000000000000000000000000000000000853a0d2313c00008152f35b9081606091031261056e5780356107d38161055d565b91604060208301356107e48161055d565b92013590565b503461056e576108306107fe3660046107bd565b91906108086131b8565b7f000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec7913361388f565b6000600080516020614af983398151915255602060405160018152f35b503461056e57600036600319011261056e576040517f000000000000000000000000bbf3f1421d886e9b2c5d716b5192ac998af2012c6001600160a01b03168152602090f35b919082608091031261056e5781356108aa8161055d565b9160208101356108b98161055d565b91606060408301356107e48161055d565b503461056e576108f06108de366004610893565b926108ea9291926131b8565b33613ced565b6000600080516020614af983398151915255005b503461056e57600036600319011261056e5760206040517f00000000000000000000000000000000000000000000000000000017a029afcc8152f35b919082604091031261056e57602082356109598161055d565b9201356109658161055d565b90565b9060018060a01b0316600052602052604060002090565b6001600160801b031690565b6001600160801b0391821681529116602082015260400190565b503461056e576109f66109da6109bc366004610940565b6001600160a01b039091166000908152600660205260409020610968565b54604051918291608081901c906001600160801b03168361098b565b0390f35b503461056e57600036600319011261056e5760206040517f00000000000000000000000000000000000000000000000000000000734b08df8152f35b503461056e57602036600319011261056e57600435610a548161055d565b60018060a01b031660005260046020526020604060002054604051908152f35b503461056e57600036600319011261056e5760206040517f0000000000000000000000000000000000000000000000000000000005f5e1008152f35b503461056e57600036600319011261056e57602060405160ff7f0000000000000000000000000000000000000000000000000000000000000006168152f35b503461056e57600036600319011261056e5760206040517f000000000000000000000000000000000000000000000000000012309ce540008152f35b503461056e57602036600319011261056e5760206105cc600435610b4e8161055d565b614775565b503461056e57602036600319011261056e57602061059b600435610b768161055d565b612ac2565b6001600160401b031690565b610c1d9092919260e08061010083019560ff815116845260018060a01b03806020830151166020860152604082015116604085015260018060401b036060820151166060850152610be76080820151608086019060018060401b03169052565b60a0818101516001600160401b03169085015260c0818101516001600160401b03169085015201516001600160801b0316910152565b565b503461056e57602036600319011261056e576109f6610c48600435610c438161055d565b6120f6565b60405191829182610b87565b503461056e57602036600319011261056e5760206105cc600435610c778161055d565b6127d0565b503461056e576108f0610c903660046107bd565b91610c996131b8565b333361312c565b503461056e576108f0610cb43660046107bd565b91610cbd6131b8565b333361388f565b503461056e57600036600319011261056e5760206040517f00000000000000000000000000000000000000000000000000000000000f42408152f35b3590811515820361056e57565b503461056e5760a036600319011261056e57610d296004610d00565b610d336024610d00565b610d3d6044610d00565b91610d486064610d00565b92610d536084610d00565b60018060a01b03807f0000000000000000000000006d903f6003cca6255d85cca4d3b5e5146dc33925163314159081610e5f575b50610e4e577f3be39979091ae7ca962aa1c44e645f2df3c221b79f324afa5f44aedc8d2f690d94610e4992610e14610dd16000610dc388614aca565b9060ff8080931691161b1690565b610ddf6001610dc38a614aca565b17610dee6002610dc385614aca565b17610dfd6003610dc386614aca565b17610e0c6004610dc387614aca565b176001612d9f565b6040519586958693909594919260809360a0860197151586521515602086015215156040850152151560608401521515910152565b0390a1005b6040516282b42960e81b8152600490fd5b90507f000000000000000000000000bbf3f1421d886e9b2c5d716b5192ac998af2012c1633141538610d87565b503461056e57600036600319011261056e576040517f0000000000000000000000005c58d4479a1e9b2d19ee052143fa73f0ee79a36e6001600160a01b03168152602090f35b503461056e57602036600319011261056e57600435610ef08161055d565b6001600160a01b0316600090815260026020526040908190205490519081906109f690608081901c906001600160801b03168361098b565b503461056e57600036600319011261056e5760206040517f000000000000000000000000000000000000000000000000000000006f83541f8152f35b503461056e57600036600319011261056e576020600460015460f81c161515604051908152f35b503461056e57602036600319011261056e5760206105cc600435610fae8161055d565b614717565b503461056e57600036600319011261056e5760206040517f000000000000000000000000000000000000000000000000000000001c59cb9f8152f35b503461056e57604036600319011261056e5760206105cc6004356110128161055d565b602435906145f8565b503461056e57600036600319011261056e5760206105cc612735565b503461056e57600036600319011261056e5760206040517f000000000000000000000000000000000000000000000000000000156925c7508152f35b503461056e57600036600319011261056e57602066038d7ea4c680006106b661109a61217a565b6110b76001549161069764ffffffffff91828560d01c16906121ee565b6001600160401b03169160681c6001600160681b03169050611b81565b503461056e57600036600319011261056e576020600860015460f81c161515604051908152f35b503461056e576108f061110f366004610893565b9261111b9291926131b8565b3361312c565b503461056e57600036600319011261056e5760206040517f0000000000000000000000000000000000000000000000000c7d713b49da00008152f35b503461056e57600036600319011261056e5760206040517f000000000000000000000000000000000000000000000000000000e8d4a510008152f35b503461056e57600036600319011261056e5760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b503461056e57600036600319011261056e5760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b503461056e57602036600319011261056e576020611230600435612616565b6040516001600160401b039091168152f35b503461056e57602036600319011261056e5760206105cc6004356112658161055d565b61288a565b503461056e57602060ff61129f611282366004610940565b6001600160a01b0390911660009081526003855260409020610968565b54166040519015158152f35b503461056e57600036600319011261056e576020600260015460f81c161515604051908152f35b503461056e57600036600319011261056e57602060405160ff7f0000000000000000000000000000000000000000000000000000000000000006168152f35b503461056e57600036600319011261056e5760206040517f0000000000000000000000000000000000000000000000000c7d713b49da00008152f35b503461056e57604036600319011261056e5761083060043561136e8161055d565b6113766131b8565b602435907f000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec790333361388f565b503461056e57600036600319011261056e5760206040517f00000000000000000000000000000000000000000000000000038d7ea4c680008152f35b503461056e576113f03660046107bd565b91906001600160a01b03907f0000000000000000000000006d903f6003cca6255d85cca4d3b5e5146dc3392582163303610e4e571691823b1561056e57611451926000928360405180968195829463095ea7b360e01b845260048401613ed6565b03925af18015611477575b61146257005b80611471600061001693611aa6565b806105a5565b61147f6127c3565b61145c565b503461056e57602036600319011261056e576100166004356114a58161055d565b6114ad612254565b60018060a01b03811660005260056020526040600020611514604051916114d560a084611aa6565b54600c81900b83526001600160401b03606882901c8116602085015260a882901c16604084015261ffff60e882901c16606084015260f81c6080830152565b8051600c0b91612fcc565b503461056e576108f0611533366004610893565b9261153f9291926131b8565b3361388f565b503461056e576108f06115593660046107bd565b916115626131b8565b3333613ced565b503461056e57604036600319011261056e576004356115878161055d565b602435906001600160401b039081831161056e573660238401121561056e57826004013591821161056e573660248360051b8501011161056e576024610016930190614118565b503461056e57600036600319011261056e576040517f000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec76001600160a01b03168152602090f35b503461056e57602036600319011261056e576004356116328161055d565b60018060a01b0316600052600760205260806040600020546040519063ffffffff8116825260018060401b038160201c166020830152600180841b038160601c16604083015260e01c6060820152f35b503461056e57602036600319011261056e5760043560ff8116810361056e57610c486109f691611bce565b503461056e57602061059b6116c3366004610940565b906147fc565b503461056e57600036600319011261056e576020601060015460f81c161515604051908152f35b503461056e57602036600319011261056e576020611230600435612506565b503461056e57602036600319011261056e5760043561172d8161055d565b60018060a01b0316600052600560205260a06040600020546040519080600c0b825260018060401b03808260681c1660208401528160a81c16604083015261ffff8160e81c16606083015260f81c6080820152f35b503461056e57604036600319011261056e576004356117a08161055d565b602435906001600160a01b037f0000000000000000000000006d903f6003cca6255d85cca4d3b5e5146dc3392581163303610e4e576117dd612992565b6000811290811561185b575b50611849578161183b847fec4431f2ba1a9382f6b0c4352b888cba6f7db91667d9f776abe5ad8ddc5401b6947f000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec7613ef1565b6040519384521691602090a2005b60405163128bd24d60e31b8152600490fd5b6118659150614abf565b8311386117e9565b503461056e57608036600319011261056e5760043561188b8161055d565b606435906118988261055d565b6118a06131b8565b601060015460f81c166119e4576118b5612992565b600081121590816119b9575b506119a7576118f3604435337f000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec7613467565b906118fe82826145f8565b926024358410611995576119118261288a565b8411611849577ff891b2a411b0e66a5f0a6ff1368670fefa287a13f541eb633a386a1a9cc7046b9161195861197b9261195161194c88614a1e565b61097f565b9083613ef1565b6040805194855260208501959095526001600160a01b0316933393918291820190565b0390a36100166000600080516020614af983398151915255565b60405163fa6ad35560e01b8152600490fd5b604051631d99ddbf60e01b8152600490fd5b90507f000000000000000000000000000000000000000000000000000012309ce540001115386118c1565b6040516313d0ff5960e31b8152600490fd5b503461056e57600036600319011261056e576040517f0000000000000000000000003e7d1eab13ad0104d2750b8863b489d65364e32d6001600160a01b03168152602090f35b503461056e57604036600319011261056e576108f0600435611a5d8161055d565b611a656131b8565b6024359033333361312c565b503461056e57604036600319011261056e576108f0600435611a928161055d565b611a9a6131b8565b60243590333333613ced565b601f909101601f19168101906001600160401b03821190821017611ac957604052565b634e487b7160e01b600052604160045260246000fd5b90610c1d6040519283611aa6565b60405190611afd61010083611aa6565b8160e06000918281528260208201528260408201528260608201528260808201528260a08201528260c08201520152565b50634e487b7160e01b600052601260045260246000fd5b50634e487b7160e01b600052601160045260246000fd5b6001600160401b0391821691908215611b7457160490565b611b7c611b2e565b160490565b8060001904821181151516611b94570290565b611b9c611b45565b0290565b60ff16604d8111611bb2575b600a0a90565b611bba611b45565b611bac565b6001600160401b039091169052565b611bd6611aed565b5060ff811660ff7f0000000000000000000000000000000000000000000000000000000000000006168110156120e45780611d6457507f000000000000000000000012dbd020caef83efd542f4de03e3cf0c28a4428bd57f0000000000001d4c1b581964c00e94cb662c3520282e6f5717214004a7f268885b6001600160401b0380611c6c612710670de0b6b3a7640000611b5c565b1661ffff9181838560a01c1690611c8291611b81565b611c8b90610b7b565b91611c9c8160b087901c8616611b81565b611ca590610b7b565b938560c01c1690611cb591611b81565b611cbe90610b7b565b938560a01c60ff16611ccf90611ba0565b611cd890610b7b565b91808316908760a81c1690611cec91611b81565b611cf59061097f565b95611d01610100611adf565b60ff9890981688526001600160a01b039182166020890152166040870152611d2c9060608701611bbf565b611d399060808601611bbf565b611d469060a08501611bbf565b611d539060c08401611bbf565b6001600160801b031660e082015290565b60018103611db457507f0000000000000000000000125f4ec3df9cbd43714fe2740f5e3616155c5b84197f000000000000251c2328206cc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2611c4f565b60028103611e0457507f0000000000000000000000084e64e54c9f0313852a230782b3ba4b3b0952b4997f000000000000251c21341f402260fac5e5542a773aa44fbcfedf7c193bc2c599611c4f565b60038103611e5457507f000000000000000000000012553303d460ee0afb37edff9be42922d8ff63220e7f00000000000021341fa41d4c1f9840a85d5af5bf1d1762f925bdaddc4201f984611c4f565b60048103611ea457507f0000000000000000000000122c1d072e956affc0d435cb7ac38ef18d24d9127c7f000000000000245421341edc514910771af9ca656af840dff83e8264ecf986ca611c4f565b60058103611ef457507f000000000000000000000012023ee795361b28cdbb94e302983578486a0a5f1b7f000000000000251c21341f407f39c581f595b53c5cb19bd0b3f8da6c935e2ca0611c4f565b60068103611f4457507f00000000000000000000000000000000000000000000000000000000000000007f0000000000000000000000000000000000000000000000000000000000000000611c4f565b60078103611f9457507f00000000000000000000000000000000000000000000000000000000000000007f0000000000000000000000000000000000000000000000000000000000000000611c4f565b60088103611fe457507f00000000000000000000000000000000000000000000000000000000000000007f0000000000000000000000000000000000000000000000000000000000000000611c4f565b6009810361203457507f00000000000000000000000000000000000000000000000000000000000000007f0000000000000000000000000000000000000000000000000000000000000000611c4f565b600a810361208457507f00000000000000000000000000000000000000000000000000000000000000007f0000000000000000000000000000000000000000000000000000000000000000611c4f565b600b036120d2577f00000000000000000000000000000000000000000000000000000000000000007f0000000000000000000000000000000000000000000000000000000000000000611c4f565b60405163971241a160e01b8152600490fd5b604051633640530560e01b8152600490fd5b906120ff611aed565b5060009060ff92837f000000000000000000000000000000000000000000000000000000000000000616925b838582161061214657604051633640530560e01b8152600490fd5b61214f81611bce565b60208101516001600160a01b038481169116146121715750600101841661212b565b93505050915090565b600160281b4210156121915764ffffffffff421690565b604051633d32ffdb60e01b8152600490fd5b906040516121b260a082611aa6565b608081935480600c0b835260018060401b03808260681c1660208501528160a81c16604084015261ffff8160e81c16606084015260f81c910152565b64ffffffffff9182169116818110612204570390565b61220c611b45565b0390565b6001600160681b031690565b6001600160401b0391821691908116908290038111612239570190565b612241611b45565b0190565b60681c6001600160681b031690565b61225c61217a565b61228661227c61227660015464ffffffffff9060d01c1690565b836121ee565b64ffffffffff1690565b9081612290575050565b816122e76122a0610c1d9461245d565b60008054600160401b600160801b03191660409290921b600160401b600160801b0316919091178155919082546001600160401b0319166001600160401b03909116178255565b6122f2600154612210565b7f000000000000000000000000000000000000000000000000000000e8d4a5100092906001600160681b0316838110156123e7575b5061233b612336600154612245565b612210565b9283101561236f575b50506001805464ffffffffff60d01b191660d09390931b64ffffffffff60d01b169290921790915550565b6123b06123ab6123df946123a66123bf947f0000000000000000000000000000000000000000000000000000000000000000611b81565b612dd5565b6149d2565b825460c01c61221c565b61221c565b81546001600160c01b031660c09190911b6001600160c01b031916179055565b388080612344565b61243161241e6123ab612457936123a6867f0000000000000000000000000000000000000000000000000000000000000000611b81565b845460801c6001600160401b031661221c565b8354600160801b600160c01b03191660809190911b600160801b600160c01b0316178355565b38612327565b6000546001600160401b03604082901c81169392918116919081612482575b50509190565b816124d56124cf6124af97946124e16124e7976124db876124b66124db996124a8612735565b9e8f612506565b169d612616565b169b6124d56124cf670de0b6b3a7640000998a93611b81565b84611b81565b046149d2565b9061221c565b98611b81565b91388061247c565b81198111612239570190565b818110612204570390565b7f0000000000000000000000000000000000000000000000000c7d713b49da000080821161258f57506123ab670de0b6b3a7640000612568610965937f000000000000000000000000000000000000000000000000000000006f83541f611b81565b047f00000000000000000000000000000000000000000000000000000000000000006124ef565b610965916123ab91612602670de0b6b3a7640000916125d283612568837f000000000000000000000000000000000000000000000000000000006f83541f611b81565b93818110612609575b037f000000000000000000000000000000000000000000000000000000156925c750611b81565b04906124ef565b612611611b45565b6125db565b7f0000000000000000000000000000000000000000000000000c7d713b49da000080821161269f57506123ab670de0b6b3a7640000612678610965937f00000000000000000000000000000000000000000000000000000000734b08df611b81565b047f000000000000000000000000000000000000000000000000000000001c59cb9f6124ef565b610965916123ab91612602670de0b6b3a7640000916126e283612678837f00000000000000000000000000000000000000000000000000000000734b08df611b81565b93818110612712575b037f00000000000000000000000000000000000000000000000000000017a029afcc611b81565b61271a611b45565b6126eb565b8115612729570490565b612731611b2e565b0490565b60005460015466038d7ea4c6800090612777906001600160681b036001600160401b0384612767828816848616611b81565b049560401c169160681c16611b81565b0481612784575050600090565b670de0b6b3a76400009080600019048211811515166127a257020490565b6127aa611b45565b020490565b51906001600160501b038216820361056e57565b506040513d6000823e3d90fd5b604051633fabe5a360e21b81529060a090829060049082906001600160a01b03165afa90811561286e575b600091612822575b5060008113156128105790565b60405163fd1ee34960e01b8152600490fd5b9060a0823d8211612866575b8161283b60a09383611aa6565b8101031261077e575061284d816127af565b5061285f6080602083015192016127af565b5038612803565b3d915061282e565b6128766127c3565b6127fb565b9081602091031261056e575190565b6040516370a0823160e01b8152306004820152906001600160a01b0316602082602481845afa918215612915575b6000926128e5575b506000908152600260205260409020546001600160801b031690818110612204570390565b61290791925060203d811161290e575b6128ff8183611aa6565b81019061287b565b90386128c0565b503d6128f5565b61291d6127c3565b6128b8565b600082128015600160ff1b840183121661294c575b6001600160ff1b038301821316612204570390565b612954611b45565b612937565b6000811280156001600160ff1b03839003841316612985575b600160ff1b829003831216612239570190565b61298d611b45565b612972565b61096561299d61217a565b6129c06129bb61227c6001549364ffffffffff8560d01c16906121ee565b61245d565b90604051926370a0823160e01b8452602084806129e030600483016105fa565b03817f000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec76001600160a01b03165afa938415612ab5575b600094612a7d575b5091612a71612a6b612a6b93612a64612a779666038d7ea4c680009260018060401b0384612a578260018060681b039416848616611b81565b0497169160681c16611b81565b0495614a73565b91614a73565b90612922565b90612959565b612a7793919450612a6b612a6b93612a64612aa8612a719460203d811161290e576128ff8183611aa6565b9794965050935050612a1e565b612abd6127c3565b612a16565b90612ad8612ad1836005610968565b54600c0b90565b906000928383600c0b1215612c8257612b68612b0f612b09612afe846005979697610968565b5460e81c61ffff1690565b93614839565b612b387f0000000000000000000000003e7d1eab13ad0104d2750b8863b489d65364e32d6127d0565b7f00000000000000000000000000000000000000000000000000000000000f42406001600160401b031691612e20565b90849360ff95867f000000000000000000000000000000000000000000000000000000000000000616955b8781169087821015612c745790889161ffff600180931b891616612bb9575b0116612b93565b9590915082811215612c685790612c628992612a77612c5d88612c57612c526080612c4a612c198f612bf8612bf0612c0c92611bce565b976006610968565b60208801516001600160a01b031690610968565b546001600160801b031690565b6040860151612c30906001600160a01b03166127d0565b612c3d6060880151610b7b565b91600180861b0316612e00565b930151610b7b565b610b7b565b90612dc2565b614a73565b95612bb2565b50955050945050505090565b505094509450509050121590565b50915050600190565b90612c9a612ad1836005610968565b906000928383600c0b1215612d9a57612cc0612b0f612b09612afe846005979697610968565b90849360ff95867f000000000000000000000000000000000000000000000000000000000000000616955b8781169087821015612d8d5790889161ffff600180931b891616612d11575b0116612ceb565b9590915082811215612d815790612d7b8992612a77612c5d88612c57612c5260a0612c4a612d488f612bf8612bf0612c0c92611bce565b6040860151612d5f906001600160a01b03166127d0565b612d6c6060880151610b7b565b916001600160801b0316612e00565b95612d0a565b50509450945050505090565b5050945094505090501290565b509050565b80546001600160f81b031660f89290921b6001600160f81b031916919091179055565b670de0b6b3a76400009161273191611b81565b61271f907f00000000000000000000000000000000000000000000000000000000000f424090611b81565b90612e0a91611b81565b6001600160401b03909116908115612729570490565b9190612e2b90614a73565b6000808413939082136001600160ff1b03858216848204841116612ee7575b600160ff1b95600085129185918316858905831216612eda575b60008512938416828905861216612ecd575b058312911616612ec0575b6001600160401b03909216929102908215612eb3575b8114600019831416612ea7570590565b612eaf611b45565b0590565b612ebb611b2e565b612e97565b612ec8611b45565b612e81565b612ed5611b45565b612e76565b612ee2611b45565b612e64565b612eef611b45565b612e4a565b6001600160401b039182169116818110612204570390565b600c0b6001600160671b03198114612f25575b60000390565b612f2d611b45565b612f1f565b805461ffff60e81b191660e89290921b61ffff60e81b16919091179055565b81518154602084015160408501516001600160e81b03199092166001600160681b039093169290921760689290921b600160681b600160a81b03169190911760a89190911b600160a81b600160e81b03161781556060820151610c1d9260ff9160809190612fc39061ffff1685612f32565b01511690612d9f565b6130d590610c1d93612fdf8451600c0b90565b600c82900b855260009182918683600c83900b81136130ec5761306c6130456130ab94613036612c526130939661303060206130286123ab995460018060401b039060801c1690565b920151610b7b565b90612ef4565b906001600160681b0316611b81565b7f00000000000000000000000000000000000000000000000000038d7ea4c680009061271f565b7f00000000000000000000000000000000000000000000000000000000000000019061271f565b6130a560408901916123ba8351610b7b565b90611bbf565b600c0b126130da57546130ce9060801c6001600160401b03165b60208501611bbf565b6005610968565b612f51565b546130e79060c01c6130c5565b6130ce565b61306c6130456131279461312261233661221061311c612c526130939961303060206130286123ab9c5460c01c90565b93612f0c565b611b81565b6130ab565b939290936001805460f81c166119e45761314961314d91866147fc565b1590565b610e4e576001600160a01b038181167f000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec7909116036131a45750610c1d92600019830361326557915061319e81614775565b91613265565b906131b2610c1d9493614a1e565b9261368b565b600080516020614af983398151915260018154146131d65760019055565b60405163139b643560e21b8152600490fd5b6001600160681b0391821691908116908290038111612239570190565b80546001600160681b0319166001600160681b03909216919091179055565b6001600160681b039182169116818110612204570390565b8054600160681b600160d01b03191660689290921b600160681b600160d01b0316919091179055565b6132946133129293827f000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec7613467565b61329c612254565b61331f6132b26132ad866005610968565b6121a3565b8051600c0b906133196132e26132db6132d66132cd86614839565b612a7789614a73565b6148d3565b80946133eb565b97906133026132fb8a6132f6600154612210565b6131e8565b6001613205565b61330d600154612245565b613224565b600161323c565b86612fcc565b6040519081526001600160a01b0393841693849216907fd1cf3d156d5f8f0d50f6c122ed609cec09d35c9b9fb3fff6ea0959134dae424e90602090a36001600160681b03811661336d575050565b600080516020614ad98339815191526133a461339460009361338f8554610b7b565b6148ae565b6040519081529081906020820190565b0390a3565b600c91820b910b6000821280156001600160671b031984018312166133de575b6001600160671b038301821316612204570390565b6133e6611b45565b6133c9565b91909180600c0b83600c0b81811261345a5760001261341e575061340f91926133a9565b6001600160681b031690600090565b6000136134415761342f91926133a9565b6000916001600160681b039190911690565b61344a90612f0c565b6001600160681b03908116921690565b5050509050600090600090565b6040516370a0823160e01b8082529390926020926001600160a01b0316919083858061349630600483016105fa565b0381865afa9485156135d4575b6000956135b5575b50823b1561056e576040516323b872dd60e01b81526001600160a01b03919091166004820152306024820152604481019190915260008160648183865af180156135a8575b613593575b503d801561358a5760201461350957600080fd5b816000803e6000515b156135785781610965946040519283918252818061353330600483016105fa565b03915afa91821561356b575b60009261354e575b50506124fb565b6135649250803d1061290e576128ff8183611aa6565b3880613547565b6135736127c3565b61353f565b60405163073d1efd60e51b8152600490fd5b50600019613512565b8061147160006135a293611aa6565b386134f5565b6135b06127c3565b6134f0565b6135cd919550843d861161290e576128ff8183611aa6565b93386134ab565b6135dc6127c3565b6134a3565b906040516135f0604082611aa6565b91546001600160801b038116835260801c6020830152565b6001600160801b0391821691908116908290038111612239570190565b80546001600160801b0319166001600160801b03909216919091179055565b90602060018060801b039161365c8382511685613625565b0151825490911660809190911b6001600160801b031916179055565b6001600160801b03909116815260200190565b9190926136aa6136a560018060801b038093168585613467565b614a1e565b916136b4816120f6565b906136c86136c3826002610968565b6135e1565b926136ec6136df866136da875161097f565b613608565b6001600160801b03168552565b6136f6845161097f565b9061370761194c60e086015161097f565b9116116137b15761378c61377a856137ac946137867ffa56f7b24f17183d81894d3ac2ee654e3c26388d17a28dbd9549b8114304e1f4976137818761375b8e613767613760612c0c8561375b856006610968565b610968565b9889613608565b988995613775856002610968565b613644565b6006610968565b613625565b896137c3565b6040516001600160a01b0391821696821695909116939091829182613678565b0390a4565b604051637ac7b99d60e11b8152600490fd5b909290916001600160801b03908116158080613884575b156138255750505061380d6138056137f6610c1d945160ff1690565b600160ff9091161b61ffff1690565b916005610968565b9061381e825461ffff9060e81c1690565b1790612f32565b159182613879575b5050613837575050565b60ff610c1d92600161ffff92839251161b16199160018060a01b03166000526005602052604060002091613871835461ffff9060e81c1690565b161690612f32565b16159050388061382d565b5081831615156137da565b93929093600260015460f81c166119e4576131496138ad91866147fc565b610e4e576001600160a01b038481168382161461392557807f000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec716908216146000146139115750610c1d92600019830361394857915061390b82614717565b91613948565b9061391f610c1d9493614a1e565b92613be1565b60405163e397a99b60e01b8152600490fd5b600160ff1b8114612f255760000390565b919091613953612254565b61395e816005610968565b613967906121a3565b613972846005610968565b61397b906121a3565b92815161398890600c0b90565b93805161399590600c0b90565b9261399f86614839565b6139a884614a73565b6139b191612922565b926139bb85614839565b906139c590614a73565b6139ce91612959565b906139d8846148d3565b6139e281936148d3565b9788936139ee91613b7c565b986139f991976133eb565b98878a600154613a0890612210565b90613a12916131e8565b90613a1c91613224565b613a27906001613205565b600154613a3390612245565b90613a3d916131e8565b90613a4791613224565b613a5290600161323c565b613a5c9187612fcc565b613a669187612fcc565b60008112613b13575b506001600160681b0391818316613acb575b50508116613a8d575050565b600080516020614ad98339815191526133a4613aaf60009361338f8554610b7b565b6040519081526001600160a01b03909416939081906020820190565b600080516020614ad9833981519152613b09613aed60009461338f8654610b7b565b6040519081526001600160a01b03909316929081906020820190565b0390a33880613a81565b613b1c90613937565b7f0000000000000000000000000000000000000000000000000000000005f5e10011613b6a57613b4e61314983612ac2565b613b585738613a6f565b604051630a62fbdb60e11b8152600490fd5b604051637139da2360e11b8152600490fd5b919082600c0b81600c0b81811361345a57600013613b9f575061340f91926133a9565b600012613bb05761342f91926133a9565b613bb990612f0c565b6001600160681b03928316921690565b6001600160801b039182169116818110612204570390565b6001600160a01b0380821660008181526006602052604090206001600160801b03959194919391908690613c16908690610968565b54168382169687600052600660205285604060002090613c3591610968565b5416613c418983613bc9565b613c4b8a83613608565b928188613c59886006610968565b90613c6391610968565b90613c6d91613625565b8388613c7a876006610968565b90613c8491610968565b90613c8e91613625565b613c97886120f6565b91613ca39183886137c3565b613cac936137c3565b613cb590612ac2565b15613b58577f29db89d45e1a802b4d55e202984fce9faf1d30aedf86503ff1ea0ed9ebb64201916137ac604051928392169682613678565b93929093600460015460f81c166119e457613149613d0b91866147fc565b610e4e576001600160a01b038181167f000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec790911603613d625750610c1d926000198303613d76579150613d5c82614717565b91613d76565b90613d70610c1d9493614a1e565b92613f99565b909161331292613d84612254565b613d926132ad846005610968565b613dec613da08251600c0b90565b613db5613dac82614839565b612a7187614a73565b92613319613dcc613dc5866148d3565b8094613b7c565b613de16132fb8361330d60019e959e54612210565b6132f6600154612245565b60008112613e91575b50613e2182827f000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec7613ef1565b6040519182526001600160a01b0392831692169082907f9b1bfa7fa9ee420a16e124f794c35ac9f90472acc99140eb2f6447c714cad8eb90602090a36001600160681b038216613e6f575050565b600080516020614ad98339815191526133a461339460009461338f8654610b7b565b613e9a90613937565b7f0000000000000000000000000000000000000000000000000000000005f5e10011613b6a57613ecc61314984612ac2565b613b585738613df5565b6001600160a01b039091168152602081019190915260400190565b6001600160a01b03169291833b1561056e57613f2b90604051809581809563a9059cbb60e01b825260009889968796879360048401613ed6565b03925af18015613f8c575b613f7c575b503d90508015613f7157602014613f50575080fd5b90602081803e515b15613f5f57565b60405163cefaffeb60e01b8152600490fd5b509050600019613f58565b613f8591611aa6565b3882613f3b565b613f946127c3565b613f36565b6001600160a01b038082166000818152600660205260408120909695919491936001600160801b03918290613fcf908790610968565b5416613fdb8882613bc9565b80878781169b8c81526002602052604081208c8882541690613ffc91613bc9565b61400591613625565b8a81526006602052604090209061401b91610968565b9061402591613625565b61402e876120f6565b9161403992846137c3565b61404290612ac2565b15613b58577fd6d480d5b3068db003533b170d67561494d72e3bf9fa40a266471351ebba9e16938261407692881691613ef1565b6137ac604051928392169582613678565b91908110156140975760051b0190565b634e487b7160e01b600052603260045260246000fd5b356109658161055d565b906040516140c6608082611aa6565b915463ffffffff81168352602081811c6001600160401b031690840152606081811c6001600160801b0316604085015260e09190911c90830152565b60019063ffffffff809116908114612239570190565b9291909260016008815460f81c166119e4575a94614134612254565b60005b84811061422e575050506141d9906141d26141b36136a561415d610c1d97985a906124fb565b6141ac61419a614176614171886007610968565b6140b7565b986123ab61419061418b8c5163ffffffff1690565b614102565b63ffffffff168b52565b6130a560208a01916123ba8351610b7b565b4890611b81565b6141c560408601916136da835161097f565b6001600160801b03169052565b6007610968565b815160208084015160408501516060958601516001600160e01b031960e09190911b16600160601b600160e01b039190961b1663ffffffff909316600160201b600160601b039190921b161717919091179055565b8061424c61424661424186948987614087565b6140ad565b86614252565b01614137565b9161425f61314983612c8b565b6145e657906142726132ad826005610968565b9061427e8251600c0b90565b9361428885614839565b9260609061429a8282015161ffff1690565b6142c37f0000000000000000000000003e7d1eab13ad0104d2750b8863b489d65364e32d6127d0565b96600092839860ff9a8b7f0000000000000000000000000000000000000000000000000000000000000006169a5b8c8116908c82101561446557908d91898c8c61ffff600180961b8c161661431d575b50505001166142f1565b90919a8261432a85611bce565b60208101519092906001600160a01b0316908160068161434a8683610968565b9061435491610968565b546001600160801b03169461436891610968565b9061437291610968565b600061437d91613625565b614388826002610968565b8381546143949061097f565b9061439e91613bc9565b6143a791613625565b604084810151909f906001600160a01b03166143c2906127d0565b908501516143cf90610b7b565b6143e2916001600160801b038616612e00565b9360c001516143f090610b7b565b6143f990610b7b565b6144039085612dc2565b61440c916124ef565b9d516001600160801b0392909216825260208201929092526001600160a01b0391821693821692909116907f9850ab1af75177e4a9201c65a2cf7976d5d28e40ef63494b44366f86b2f9412e90604090a4898c8c614313565b50509497969950945096915097506144bb6144b5612c5d856144b060018060401b037f00000000000000000000000000000000000000000000000000000000000f424016809a611b81565b61271f565b82612959565b91600083126145dd575b6144ce836148d3565b96876144da9187612fcc565b866144e6866005610968565b60006144f191612f32565b6144fa916133eb565b60015461450690612210565b90614510916131e8565b61451b906001613205565b60015461452790612245565b9061453191613224565b61453c90600161323c565b61454591612922565b61454e90614abf565b926145599184612e00565b6040805193845260208401919091526001600160a01b039182169485939216917f1547a878dc89ad3c367b6338b4be6a65a5dd74fb77ae044da1e8747ef1f4f62f9190a380600c0b6000126145ac575050565b600080516020614ad98339815191526133a46133946000936145d76145d18654610b7b565b91614a96565b906148ae565b600092506144c5565b604051636ef5bcdd60e11b8152600490fd5b906146c0614608610965936120f6565b61468b60606146b661462560018060a01b036040860151166127d0565b60c08501516001600160401b0394670de0b6b3a7640000929091839061467a908890811680841061470a575b8303167f0000000000000000000000000000000000000000000000000853a0d2313c0000611b81565b048084106146fd575b830390611b81565b04956131227f0000000000000000000000003e7d1eab13ad0104d2750b8863b489d65364e32d6127d0565b9201511690611b81565b9080156146f0575b7f00000000000000000000000000000000000000000000000000000000000f4240910461271f565b6146f8611b2e565b6146c8565b614705611b45565b614683565b614712611b45565b614651565b61473a61472261217a565b61069764ffffffffff918260015460d01c16906121ee565b506001600160a01b03909116600090815260056020526040812054600c0b91908083131561476f57506145d761096592614a96565b91505090565b61478061472261217a565b6001600160a01b03909216600090815260056020526040812054600c0b9291508083121561476f57506145d76147b861096593612f0c565b614a96565b50600036818037808036817f0000000000000000000000005c58d4479a1e9b2d19ee052143fa73f0ee79a36e5af43d82803e156147f8573d90f35b3d90fd5b6001600160a01b0380831691169081149190821561481957505090565b60ff9250906148349160005260036020526040600020610968565b541690565b6000600c82900b12614879576000546109659166038d7ea4c6800091614873916001600160401b03909116906001600160681b0316611b81565b04614a73565b6148a9612c5d6109659261489a60018060401b0360005460401c1691612f0c565b6001600160681b0316906148ae565b613937565b66038d7ea4c6800091612731916001600160401b0316906001600160681b0316611b81565b600081126148f957600054610965916148f4916001600160401b0316614982565b614a44565b6149566148f46109659261491a60018060401b0360005460401c1691613937565b61493f826000199266038d7ea4c6800090808504821181151516614975575b026124ef565b60018110614968575b821561495b575b01046149f8565b612f0c565b614963611b2e565b61494f565b614970611b45565b614948565b61497d611b45565b614939565b906109659166038d7ea4c680009082600019048211831515166149c5575b6001600160401b03169182156149b8575b02046149f8565b6149c0611b2e565b6149b1565b6149cd611b45565b6149a0565b6001600160401b03908181116149e6571690565b6040516372a1cb5160e11b8152600490fd5b6001600160681b0390818111614a0c571690565b604051630dc7925560e11b8152600490fd5b6001600160801b0390818111614a32571690565b60405163762ea71160e11b8152600490fd5b6001600160681b03166001600160671b038111614a6157600c0b90565b604051639369ae3560e01b8152600490fd5b6001600160ff1b038111614a845790565b60405163e7e828ad60e01b8152600490fd5b600081600c0b12614aad576001600160681b031690565b60405163363b64b760e11b8152600490fd5b60008112614aad5790565b60009015610965575060019056feddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efc98c7730ba19013824f711a9ab74801459b27e6ff7685cb924587c89aeda53aca2646970667358221220e903a46a611c4328a7fd6e38661c216cfea42f72d5b44f8f5e267f7d01691b3a64736f6c634300080f0033

Verified Source Code Full Match

Compiler: v0.8.15+commit.e14f2714 EVM: london
Comet.sol 1378 lines
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.15;

import "./CometMainInterface.sol";
import "./IERC20NonStandard.sol";
import "./IPriceFeed.sol";

/**
 * @title Compound's Comet Contract
 * @notice An efficient monolithic money market protocol
 * @author Compound
 */
contract Comet is CometMainInterface {
    /** General configuration constants **/

    /// @notice The admin of the protocol
    address public override immutable governor;

    /// @notice The account which may trigger pauses
    address public override immutable pauseGuardian;

    /// @notice The address of the base token contract
    address public override immutable baseToken;

    /// @notice The address of the price feed for the base token
    address public override immutable baseTokenPriceFeed;

    /// @notice The address of the extension contract delegate
    address public override immutable extensionDelegate;

    /// @notice The point in the supply rates separating the low interest rate slope and the high interest rate slope (factor)
    /// @dev uint64
    uint public override immutable supplyKink;

    /// @notice Per second supply interest rate slope applied when utilization is below kink (factor)
    /// @dev uint64
    uint public override immutable supplyPerSecondInterestRateSlopeLow;

    /// @notice Per second supply interest rate slope applied when utilization is above kink (factor)
    /// @dev uint64
    uint public override immutable supplyPerSecondInterestRateSlopeHigh;

    /// @notice Per second supply base interest rate (factor)
    /// @dev uint64
    uint public override immutable supplyPerSecondInterestRateBase;

    /// @notice The point in the borrow rate separating the low interest rate slope and the high interest rate slope (factor)
    /// @dev uint64
    uint public override immutable borrowKink;

    /// @notice Per second borrow interest rate slope applied when utilization is below kink (factor)
    /// @dev uint64
    uint public override immutable borrowPerSecondInterestRateSlopeLow;

    /// @notice Per second borrow interest rate slope applied when utilization is above kink (factor)
    /// @dev uint64
    uint public override immutable borrowPerSecondInterestRateSlopeHigh;

    /// @notice Per second borrow base interest rate (factor)
    /// @dev uint64
    uint public override immutable borrowPerSecondInterestRateBase;

    /// @notice The fraction of the liquidation penalty that goes to buyers of collateral instead of the protocol
    /// @dev uint64
    uint public override immutable storeFrontPriceFactor;

    /// @notice The scale for base token (must be less than 18 decimals)
    /// @dev uint64
    uint public override immutable baseScale;

    /// @notice The scale for reward tracking
    /// @dev uint64
    uint public override immutable trackingIndexScale;

    /// @notice The speed at which supply rewards are tracked (in trackingIndexScale)
    /// @dev uint64
    uint public override immutable baseTrackingSupplySpeed;

    /// @notice The speed at which borrow rewards are tracked (in trackingIndexScale)
    /// @dev uint64
    uint public override immutable baseTrackingBorrowSpeed;

    /// @notice The minimum amount of base principal wei for rewards to accrue
    /// @dev This must be large enough so as to prevent division by base wei from overflowing the 64 bit indices
    /// @dev uint104
    uint public override immutable baseMinForRewards;

    /// @notice The minimum base amount required to initiate a borrow
    uint public override immutable baseBorrowMin;

    /// @notice The minimum base token reserves which must be held before collateral is hodled
    uint public override immutable targetReserves;

    /// @notice The number of decimals for wrapped base token
    uint8 public override immutable decimals;

    /// @notice The number of assets this contract actually supports
    uint8 public override immutable numAssets;

    /// @notice Factor to divide by when accruing rewards in order to preserve 6 decimals (i.e. baseScale / 1e6)
    uint internal immutable accrualDescaleFactor;

    /** Collateral asset configuration (packed) **/

    uint256 internal immutable asset00_a;
    uint256 internal immutable asset00_b;
    uint256 internal immutable asset01_a;
    uint256 internal immutable asset01_b;
    uint256 internal immutable asset02_a;
    uint256 internal immutable asset02_b;
    uint256 internal immutable asset03_a;
    uint256 internal immutable asset03_b;
    uint256 internal immutable asset04_a;
    uint256 internal immutable asset04_b;
    uint256 internal immutable asset05_a;
    uint256 internal immutable asset05_b;
    uint256 internal immutable asset06_a;
    uint256 internal immutable asset06_b;
    uint256 internal immutable asset07_a;
    uint256 internal immutable asset07_b;
    uint256 internal immutable asset08_a;
    uint256 internal immutable asset08_b;
    uint256 internal immutable asset09_a;
    uint256 internal immutable asset09_b;
    uint256 internal immutable asset10_a;
    uint256 internal immutable asset10_b;
    uint256 internal immutable asset11_a;
    uint256 internal immutable asset11_b;

    /**
     * @notice Construct a new protocol instance
     * @param config The mapping of initial/constant parameters
     **/
    constructor(Configuration memory config) {
        // Sanity checks
        uint8 decimals_ = IERC20NonStandard(config.baseToken).decimals();
        if (decimals_ > MAX_BASE_DECIMALS) revert BadDecimals();
        if (config.storeFrontPriceFactor > FACTOR_SCALE) revert BadDiscount();
        if (config.assetConfigs.length > MAX_ASSETS) revert TooManyAssets();
        if (config.baseMinForRewards == 0) revert BadMinimum();
        if (IPriceFeed(config.baseTokenPriceFeed).decimals() != PRICE_FEED_DECIMALS) revert BadDecimals();

        // Copy configuration
        unchecked {
            governor = config.governor;
            pauseGuardian = config.pauseGuardian;
            baseToken = config.baseToken;
            baseTokenPriceFeed = config.baseTokenPriceFeed;
            extensionDelegate = config.extensionDelegate;
            storeFrontPriceFactor = config.storeFrontPriceFactor;

            decimals = decimals_;
            baseScale = uint64(10 ** decimals_);
            trackingIndexScale = config.trackingIndexScale;
            if (baseScale < BASE_ACCRUAL_SCALE) revert BadDecimals();
            accrualDescaleFactor = baseScale / BASE_ACCRUAL_SCALE;

            baseMinForRewards = config.baseMinForRewards;
            baseTrackingSupplySpeed = config.baseTrackingSupplySpeed;
            baseTrackingBorrowSpeed = config.baseTrackingBorrowSpeed;

            baseBorrowMin = config.baseBorrowMin;
            targetReserves = config.targetReserves;
        }

        // Set interest rate model configs
        unchecked {
            supplyKink = config.supplyKink;
            supplyPerSecondInterestRateSlopeLow = config.supplyPerYearInterestRateSlopeLow / SECONDS_PER_YEAR;
            supplyPerSecondInterestRateSlopeHigh = config.supplyPerYearInterestRateSlopeHigh / SECONDS_PER_YEAR;
            supplyPerSecondInterestRateBase = config.supplyPerYearInterestRateBase / SECONDS_PER_YEAR;
            borrowKink = config.borrowKink;
            borrowPerSecondInterestRateSlopeLow = config.borrowPerYearInterestRateSlopeLow / SECONDS_PER_YEAR;
            borrowPerSecondInterestRateSlopeHigh = config.borrowPerYearInterestRateSlopeHigh / SECONDS_PER_YEAR;
            borrowPerSecondInterestRateBase = config.borrowPerYearInterestRateBase / SECONDS_PER_YEAR;
        }

        // Set asset info
        numAssets = uint8(config.assetConfigs.length);

        (asset00_a, asset00_b) = getPackedAssetInternal(config.assetConfigs, 0);
        (asset01_a, asset01_b) = getPackedAssetInternal(config.assetConfigs, 1);
        (asset02_a, asset02_b) = getPackedAssetInternal(config.assetConfigs, 2);
        (asset03_a, asset03_b) = getPackedAssetInternal(config.assetConfigs, 3);
        (asset04_a, asset04_b) = getPackedAssetInternal(config.assetConfigs, 4);
        (asset05_a, asset05_b) = getPackedAssetInternal(config.assetConfigs, 5);
        (asset06_a, asset06_b) = getPackedAssetInternal(config.assetConfigs, 6);
        (asset07_a, asset07_b) = getPackedAssetInternal(config.assetConfigs, 7);
        (asset08_a, asset08_b) = getPackedAssetInternal(config.assetConfigs, 8);
        (asset09_a, asset09_b) = getPackedAssetInternal(config.assetConfigs, 9);
        (asset10_a, asset10_b) = getPackedAssetInternal(config.assetConfigs, 10);
        (asset11_a, asset11_b) = getPackedAssetInternal(config.assetConfigs, 11);
    }

    /**
     * @dev Prevents marked functions from being reentered 
     * Note: this restrict contracts from calling comet functions in their hooks.
     * Doing so will cause the transaction to revert.
     */
    modifier nonReentrant() {
        nonReentrantBefore();
        _;
        nonReentrantAfter();
    }

    /**
     * @dev Checks that the reentrancy flag is not set and then sets the flag
     */
    function nonReentrantBefore() internal {
        bytes32 slot = REENTRANCY_GUARD_FLAG_SLOT;
        uint256 status;
        assembly ("memory-safe") {
            status := sload(slot)
        }

        if (status == REENTRANCY_GUARD_ENTERED) revert ReentrantCallBlocked();
        assembly ("memory-safe") {
            sstore(slot, REENTRANCY_GUARD_ENTERED)
        }
    }

    /**
     * @dev Unsets the reentrancy flag
     */
    function nonReentrantAfter() internal {
        bytes32 slot = REENTRANCY_GUARD_FLAG_SLOT;
        uint256 status;
        assembly ("memory-safe") {
            sstore(slot, REENTRANCY_GUARD_NOT_ENTERED)
        }
    }

    /**
     * @notice Initialize storage for the contract
     * @dev Can be used from constructor or proxy
     */
    function initializeStorage() override external {
        if (lastAccrualTime != 0) revert AlreadyInitialized();

        // Initialize aggregates
        lastAccrualTime = getNowInternal();
        baseSupplyIndex = BASE_INDEX_SCALE;
        baseBorrowIndex = BASE_INDEX_SCALE;

        // Implicit initialization (not worth increasing contract size)
        // trackingSupplyIndex = 0;
        // trackingBorrowIndex = 0;
    }

    /**
     * @dev Checks and gets the packed asset info for storage
     */
    function getPackedAssetInternal(AssetConfig[] memory assetConfigs, uint i) internal view returns (uint256, uint256) {
        AssetConfig memory assetConfig;
        if (i < assetConfigs.length) {
            assembly {
                assetConfig := mload(add(add(assetConfigs, 0x20), mul(i, 0x20)))
            }
        } else {
            return (0, 0);
        }
        address asset = assetConfig.asset;
        address priceFeed = assetConfig.priceFeed;
        uint8 decimals_ = assetConfig.decimals;

        // Short-circuit if asset is nil
        if (asset == address(0)) {
            return (0, 0);
        }

        // Sanity check price feed and asset decimals
        if (IPriceFeed(priceFeed).decimals() != PRICE_FEED_DECIMALS) revert BadDecimals();
        if (IERC20NonStandard(asset).decimals() != decimals_) revert BadDecimals();

        // Ensure collateral factors are within range
        if (assetConfig.borrowCollateralFactor >= assetConfig.liquidateCollateralFactor) revert BorrowCFTooLarge();
        if (assetConfig.liquidateCollateralFactor > MAX_COLLATERAL_FACTOR) revert LiquidateCFTooLarge();

        unchecked {
            // Keep 4 decimals for each factor
            uint64 descale = FACTOR_SCALE / 1e4;
            uint16 borrowCollateralFactor = uint16(assetConfig.borrowCollateralFactor / descale);
            uint16 liquidateCollateralFactor = uint16(assetConfig.liquidateCollateralFactor / descale);
            uint16 liquidationFactor = uint16(assetConfig.liquidationFactor / descale);

            // Be nice and check descaled values are still within range
            if (borrowCollateralFactor >= liquidateCollateralFactor) revert BorrowCFTooLarge();

            // Keep whole units of asset for supply cap
            uint64 supplyCap = uint64(assetConfig.supplyCap / (10 ** decimals_));

            uint256 word_a = (uint160(asset) << 0 |
                              uint256(borrowCollateralFactor) << 160 |
                              uint256(liquidateCollateralFactor) << 176 |
                              uint256(liquidationFactor) << 192);
            uint256 word_b = (uint160(priceFeed) << 0 |
                              uint256(decimals_) << 160 |
                              uint256(supplyCap) << 168);

            return (word_a, word_b);
        }
    }

    /**
     * @notice Get the i-th asset info, according to the order they were passed in originally
     * @param i The index of the asset info to get
     * @return The asset info object
     */
    function getAssetInfo(uint8 i) override public view returns (AssetInfo memory) {
        if (i >= numAssets) revert BadAsset();

        uint256 word_a;
        uint256 word_b;

        if (i == 0) {
            word_a = asset00_a;
            word_b = asset00_b;
        } else if (i == 1) {
            word_a = asset01_a;
            word_b = asset01_b;
        } else if (i == 2) {
            word_a = asset02_a;
            word_b = asset02_b;
        } else if (i == 3) {
            word_a = asset03_a;
            word_b = asset03_b;
        } else if (i == 4) {
            word_a = asset04_a;
            word_b = asset04_b;
        } else if (i == 5) {
            word_a = asset05_a;
            word_b = asset05_b;
        } else if (i == 6) {
            word_a = asset06_a;
            word_b = asset06_b;
        } else if (i == 7) {
            word_a = asset07_a;
            word_b = asset07_b;
        } else if (i == 8) {
            word_a = asset08_a;
            word_b = asset08_b;
        } else if (i == 9) {
            word_a = asset09_a;
            word_b = asset09_b;
        } else if (i == 10) {
            word_a = asset10_a;
            word_b = asset10_b;
        } else if (i == 11) {
            word_a = asset11_a;
            word_b = asset11_b;
        } else {
            revert Absurd();
        }

        address asset = address(uint160(word_a & type(uint160).max));
        uint64 rescale = FACTOR_SCALE / 1e4;
        uint64 borrowCollateralFactor = uint64(((word_a >> 160) & type(uint16).max) * rescale);
        uint64 liquidateCollateralFactor = uint64(((word_a >> 176) & type(uint16).max) * rescale);
        uint64 liquidationFactor = uint64(((word_a >> 192) & type(uint16).max) * rescale);

        address priceFeed = address(uint160(word_b & type(uint160).max));
        uint8 decimals_ = uint8(((word_b >> 160) & type(uint8).max));
        uint64 scale = uint64(10 ** decimals_);
        uint128 supplyCap = uint128(((word_b >> 168) & type(uint64).max) * scale);

        return AssetInfo({
            offset: i,
            asset: asset,
            priceFeed: priceFeed,
            scale: scale,
            borrowCollateralFactor: borrowCollateralFactor,
            liquidateCollateralFactor: liquidateCollateralFactor,
            liquidationFactor: liquidationFactor,
            supplyCap: supplyCap
         });
    }

    /**
     * @dev Determine index of asset that matches given address
     */
    function getAssetInfoByAddress(address asset) override public view returns (AssetInfo memory) {
        for (uint8 i = 0; i < numAssets; ) {
            AssetInfo memory assetInfo = getAssetInfo(i);
            if (assetInfo.asset == asset) {
                return assetInfo;
            }
            unchecked { i++; }
        }
        revert BadAsset();
    }

    /**
     * @return The current timestamp
     **/
    function getNowInternal() virtual internal view returns (uint40) {
        if (block.timestamp >= 2**40) revert TimestampTooLarge();
        return uint40(block.timestamp);
    }

    /**
     * @dev Calculate accrued interest indices for base token supply and borrows
     **/
    function accruedInterestIndices(uint timeElapsed) internal view returns (uint64, uint64) {
        uint64 baseSupplyIndex_ = baseSupplyIndex;
        uint64 baseBorrowIndex_ = baseBorrowIndex;
        if (timeElapsed > 0) {
            uint utilization = getUtilization();
            uint supplyRate = getSupplyRate(utilization);
            uint borrowRate = getBorrowRate(utilization);
            baseSupplyIndex_ += safe64(mulFactor(baseSupplyIndex_, supplyRate * timeElapsed));
            baseBorrowIndex_ += safe64(mulFactor(baseBorrowIndex_, borrowRate * timeElapsed));
        }
        return (baseSupplyIndex_, baseBorrowIndex_);
    }

    /**
     * @dev Accrue interest (and rewards) in base token supply and borrows
     **/
    function accrueInternal() internal {
        uint40 now_ = getNowInternal();
        uint timeElapsed = uint256(now_ - lastAccrualTime);
        if (timeElapsed > 0) {
            (baseSupplyIndex, baseBorrowIndex) = accruedInterestIndices(timeElapsed);
            if (totalSupplyBase >= baseMinForRewards) {
                trackingSupplyIndex += safe64(divBaseWei(baseTrackingSupplySpeed * timeElapsed, totalSupplyBase));
            }
            if (totalBorrowBase >= baseMinForRewards) {
                trackingBorrowIndex += safe64(divBaseWei(baseTrackingBorrowSpeed * timeElapsed, totalBorrowBase));
            }
            lastAccrualTime = now_;
        }
    }

    /**
     * @notice Accrue interest and rewards for an account
     **/
    function accrueAccount(address account) override external {
        accrueInternal();

        UserBasic memory basic = userBasic[account];
        updateBasePrincipal(account, basic, basic.principal);
    }

    /**
     * @dev Note: Does not accrue interest first
     * @param utilization The utilization to check the supply rate for
     * @return The per second supply rate at `utilization`
     */
    function getSupplyRate(uint utilization) override public view returns (uint64) {
        if (utilization <= supplyKink) {
            // interestRateBase + interestRateSlopeLow * utilization
            return safe64(supplyPerSecondInterestRateBase + mulFactor(supplyPerSecondInterestRateSlopeLow, utilization));
        } else {
            // interestRateBase + interestRateSlopeLow * kink + interestRateSlopeHigh * (utilization - kink)
            return safe64(supplyPerSecondInterestRateBase + mulFactor(supplyPerSecondInterestRateSlopeLow, supplyKink) + mulFactor(supplyPerSecondInterestRateSlopeHigh, (utilization - supplyKink)));
        }
    }

    /**
     * @dev Note: Does not accrue interest first
     * @param utilization The utilization to check the borrow rate for
     * @return The per second borrow rate at `utilization`
     */
    function getBorrowRate(uint utilization) override public view returns (uint64) {
        if (utilization <= borrowKink) {
            // interestRateBase + interestRateSlopeLow * utilization
            return safe64(borrowPerSecondInterestRateBase + mulFactor(borrowPerSecondInterestRateSlopeLow, utilization));
        } else {
            // interestRateBase + interestRateSlopeLow * kink + interestRateSlopeHigh * (utilization - kink)
            return safe64(borrowPerSecondInterestRateBase + mulFactor(borrowPerSecondInterestRateSlopeLow, borrowKink) + mulFactor(borrowPerSecondInterestRateSlopeHigh, (utilization - borrowKink)));
        }
    }

    /**
     * @dev Note: Does not accrue interest first
     * @return The utilization rate of the base asset
     */
    function getUtilization() override public view returns (uint) {
        uint totalSupply_ = presentValueSupply(baseSupplyIndex, totalSupplyBase);
        uint totalBorrow_ = presentValueBorrow(baseBorrowIndex, totalBorrowBase);
        if (totalSupply_ == 0) {
            return 0;
        } else {
            return totalBorrow_ * FACTOR_SCALE / totalSupply_;
        }
    }

    /**
     * @notice Get the current price from a feed
     * @param priceFeed The address of a price feed
     * @return The price, scaled by `PRICE_SCALE`
     */
    function getPrice(address priceFeed) override public view returns (uint256) {
        (, int price, , , ) = IPriceFeed(priceFeed).latestRoundData();
        if (price <= 0) revert BadPrice();
        return uint256(price);
    }

    /**
     * @notice Gets the total balance of protocol collateral reserves for an asset
     * @dev Note: Reverts if collateral reserves are somehow negative, which should not be possible
     * @param asset The collateral asset
     */
    function getCollateralReserves(address asset) override public view returns (uint) {
        return IERC20NonStandard(asset).balanceOf(address(this)) - totalsCollateral[asset].totalSupplyAsset;
    }

    /**
     * @notice Gets the total amount of protocol reserves of the base asset
     */
    function getReserves() override public view returns (int) {
        (uint64 baseSupplyIndex_, uint64 baseBorrowIndex_) = accruedInterestIndices(getNowInternal() - lastAccrualTime);
        uint balance = IERC20NonStandard(baseToken).balanceOf(address(this));
        uint totalSupply_ = presentValueSupply(baseSupplyIndex_, totalSupplyBase);
        uint totalBorrow_ = presentValueBorrow(baseBorrowIndex_, totalBorrowBase);
        return signed256(balance) - signed256(totalSupply_) + signed256(totalBorrow_);
    }

    /**
     * @notice Check whether an account has enough collateral to borrow
     * @param account The address to check
     * @return Whether the account is minimally collateralized enough to borrow
     */
    function isBorrowCollateralized(address account) override public view returns (bool) {
        int104 principal = userBasic[account].principal;

        if (principal >= 0) {
            return true;
        }

        uint16 assetsIn = userBasic[account].assetsIn;
        int liquidity = signedMulPrice(
            presentValue(principal),
            getPrice(baseTokenPriceFeed),
            uint64(baseScale)
        );

        for (uint8 i = 0; i < numAssets; ) {
            if (isInAsset(assetsIn, i)) {
                if (liquidity >= 0) {
                    return true;
                }

                AssetInfo memory asset = getAssetInfo(i);
                uint newAmount = mulPrice(
                    userCollateral[account][asset.asset].balance,
                    getPrice(asset.priceFeed),
                    asset.scale
                );
                liquidity += signed256(mulFactor(
                    newAmount,
                    asset.borrowCollateralFactor
                ));
            }
            unchecked { i++; }
        }

        return liquidity >= 0;
    }

    /**
     * @notice Check whether an account has enough collateral to not be liquidated
     * @param account The address to check
     * @return Whether the account is minimally collateralized enough to not be liquidated
     */
    function isLiquidatable(address account) override public view returns (bool) {
        int104 principal = userBasic[account].principal;

        if (principal >= 0) {
            return false;
        }

        uint16 assetsIn = userBasic[account].assetsIn;
        int liquidity = signedMulPrice(
            presentValue(principal),
            getPrice(baseTokenPriceFeed),
            uint64(baseScale)
        );

        for (uint8 i = 0; i < numAssets; ) {
            if (isInAsset(assetsIn, i)) {
                if (liquidity >= 0) {
                    return false;
                }

                AssetInfo memory asset = getAssetInfo(i);
                uint newAmount = mulPrice(
                    userCollateral[account][asset.asset].balance,
                    getPrice(asset.priceFeed),
                    asset.scale
                );
                liquidity += signed256(mulFactor(
                    newAmount,
                    asset.liquidateCollateralFactor
                ));
            }
            unchecked { i++; }
        }

        return liquidity < 0;
    }

    /**
     * @dev The change in principal broken into repay and supply amounts
     */
    function repayAndSupplyAmount(int104 oldPrincipal, int104 newPrincipal) internal pure returns (uint104, uint104) {
        // If the new principal is less than the old principal, then no amount has been repaid or supplied
        if (newPrincipal < oldPrincipal) return (0, 0);

        if (newPrincipal <= 0) {
            return (uint104(newPrincipal - oldPrincipal), 0);
        } else if (oldPrincipal >= 0) {
            return (0, uint104(newPrincipal - oldPrincipal));
        } else {
            return (uint104(-oldPrincipal), uint104(newPrincipal));
        }
    }

    /**
     * @dev The change in principal broken into withdraw and borrow amounts
     */
    function withdrawAndBorrowAmount(int104 oldPrincipal, int104 newPrincipal) internal pure returns (uint104, uint104) {
        // If the new principal is greater than the old principal, then no amount has been withdrawn or borrowed
        if (newPrincipal > oldPrincipal) return (0, 0);

        if (newPrincipal >= 0) {
            return (uint104(oldPrincipal - newPrincipal), 0);
        } else if (oldPrincipal <= 0) {
            return (0, uint104(oldPrincipal - newPrincipal));
        } else {
            return (uint104(oldPrincipal), uint104(-newPrincipal));
        }
    }

    /**
     * @notice Pauses different actions within Comet
     * @param supplyPaused Boolean for pausing supply actions
     * @param transferPaused Boolean for pausing transfer actions
     * @param withdrawPaused Boolean for pausing withdraw actions
     * @param absorbPaused Boolean for pausing absorb actions
     * @param buyPaused Boolean for pausing buy actions
     */
    function pause(
        bool supplyPaused,
        bool transferPaused,
        bool withdrawPaused,
        bool absorbPaused,
        bool buyPaused
    ) override external {
        if (msg.sender != governor && msg.sender != pauseGuardian) revert Unauthorized();

        pauseFlags =
            uint8(0) |
            (toUInt8(supplyPaused) << PAUSE_SUPPLY_OFFSET) |
            (toUInt8(transferPaused) << PAUSE_TRANSFER_OFFSET) |
            (toUInt8(withdrawPaused) << PAUSE_WITHDRAW_OFFSET) |
            (toUInt8(absorbPaused) << PAUSE_ABSORB_OFFSET) |
            (toUInt8(buyPaused) << PAUSE_BUY_OFFSET);

        emit PauseAction(supplyPaused, transferPaused, withdrawPaused, absorbPaused, buyPaused);
    }

    /**
     * @return Whether or not supply actions are paused
     */
    function isSupplyPaused() override public view returns (bool) {
        return toBool(pauseFlags & (uint8(1) << PAUSE_SUPPLY_OFFSET));
    }

    /**
     * @return Whether or not transfer actions are paused
     */
    function isTransferPaused() override public view returns (bool) {
        return toBool(pauseFlags & (uint8(1) << PAUSE_TRANSFER_OFFSET));
    }

    /**
     * @return Whether or not withdraw actions are paused
     */
    function isWithdrawPaused() override public view returns (bool) {
        return toBool(pauseFlags & (uint8(1) << PAUSE_WITHDRAW_OFFSET));
    }

    /**
     * @return Whether or not absorb actions are paused
     */
    function isAbsorbPaused() override public view returns (bool) {
        return toBool(pauseFlags & (uint8(1) << PAUSE_ABSORB_OFFSET));
    }

    /**
     * @return Whether or not buy actions are paused
     */
    function isBuyPaused() override public view returns (bool) {
        return toBool(pauseFlags & (uint8(1) << PAUSE_BUY_OFFSET));
    }

    /**
     * @dev Multiply a number by a factor
     */
    function mulFactor(uint n, uint factor) internal pure returns (uint) {
        return n * factor / FACTOR_SCALE;
    }

    /**
     * @dev Divide a number by an amount of base
     */
    function divBaseWei(uint n, uint baseWei) internal view returns (uint) {
        return n * baseScale / baseWei;
    }

    /**
     * @dev Multiply a `fromScale` quantity by a price, returning a common price quantity
     */
    function mulPrice(uint n, uint price, uint64 fromScale) internal pure returns (uint) {
        return n * price / fromScale;
    }

    /**
     * @dev Multiply a signed `fromScale` quantity by a price, returning a common price quantity
     */
    function signedMulPrice(int n, uint price, uint64 fromScale) internal pure returns (int) {
        return n * signed256(price) / int256(uint256(fromScale));
    }

    /**
     * @dev Divide a common price quantity by a price, returning a `toScale` quantity
     */
    function divPrice(uint n, uint price, uint64 toScale) internal pure returns (uint) {
        return n * toScale / price;
    }

    /**
     * @dev Whether user has a non-zero balance of an asset, given assetsIn flags
     */
    function isInAsset(uint16 assetsIn, uint8 assetOffset) internal pure returns (bool) {
        return (assetsIn & (uint16(1) << assetOffset) != 0);
    }

    /**
     * @dev Update assetsIn bit vector if user has entered or exited an asset
     */
    function updateAssetsIn(
        address account,
        AssetInfo memory assetInfo,
        uint128 initialUserBalance,
        uint128 finalUserBalance
    ) internal {
        if (initialUserBalance == 0 && finalUserBalance != 0) {
            // set bit for asset
            userBasic[account].assetsIn |= (uint16(1) << assetInfo.offset);
        } else if (initialUserBalance != 0 && finalUserBalance == 0) {
            // clear bit for asset
            userBasic[account].assetsIn &= ~(uint16(1) << assetInfo.offset);
        }
    }

    /**
     * @dev Write updated principal to store and tracking participation
     */
    function updateBasePrincipal(address account, UserBasic memory basic, int104 principalNew) internal {
        int104 principal = basic.principal;
        basic.principal = principalNew;

        if (principal >= 0) {
            uint indexDelta = uint256(trackingSupplyIndex - basic.baseTrackingIndex);
            basic.baseTrackingAccrued += safe64(uint104(principal) * indexDelta / trackingIndexScale / accrualDescaleFactor);
        } else {
            uint indexDelta = uint256(trackingBorrowIndex - basic.baseTrackingIndex);
            basic.baseTrackingAccrued += safe64(uint104(-principal) * indexDelta / trackingIndexScale / accrualDescaleFactor);
        }

        if (principalNew >= 0) {
            basic.baseTrackingIndex = trackingSupplyIndex;
        } else {
            basic.baseTrackingIndex = trackingBorrowIndex;
        }

        userBasic[account] = basic;
    }

    /**
     * @dev Safe ERC20 transfer in and returns the final amount transferred (taking into account any fees)
     * @dev Note: Safely handles non-standard ERC-20 tokens that do not return a value. See here: https://medium.com/coinmonks/missing-return-value-bug-at-least-130-tokens-affected-d67bf08521ca
     */
    function doTransferIn(address asset, address from, uint amount) internal returns (uint) {
        uint256 preTransferBalance = IERC20NonStandard(asset).balanceOf(address(this));
        IERC20NonStandard(asset).transferFrom(from, address(this), amount);
        bool success;
        assembly ("memory-safe") {
            switch returndatasize()
                case 0 {                       // This is a non-standard ERC-20
                    success := not(0)          // set success to true
                }
                case 32 {                      // This is a compliant ERC-20
                    returndatacopy(0, 0, 32)
                    success := mload(0)        // Set `success = returndata` of override external call
                }
                default {                      // This is an excessively non-compliant ERC-20, revert.
                    revert(0, 0)
                }
        }
        if (!success) revert TransferInFailed();
        return IERC20NonStandard(asset).balanceOf(address(this)) - preTransferBalance;
    }

    /**
     * @dev Safe ERC20 transfer out
     * @dev Note: Safely handles non-standard ERC-20 tokens that do not return a value. See here: https://medium.com/coinmonks/missing-return-value-bug-at-least-130-tokens-affected-d67bf08521ca
     */
    function doTransferOut(address asset, address to, uint amount) internal {
        IERC20NonStandard(asset).transfer(to, amount);
        bool success;
        assembly ("memory-safe") {
            switch returndatasize()
                case 0 {                       // This is a non-standard ERC-20
                    success := not(0)          // set success to true
                }
                case 32 {                      // This is a compliant ERC-20
                    returndatacopy(0, 0, 32)
                    success := mload(0)        // Set `success = returndata` of override external call
                }
                default {                      // This is an excessively non-compliant ERC-20, revert.
                    revert(0, 0)
                }
        }
        if (!success) revert TransferOutFailed();
    }

    /**
     * @notice Supply an amount of asset to the protocol
     * @param asset The asset to supply
     * @param amount The quantity to supply
     */
    function supply(address asset, uint amount) override external {
        return supplyInternal(msg.sender, msg.sender, msg.sender, asset, amount);
    }

    /**
     * @notice Supply an amount of asset to dst
     * @param dst The address which will hold the balance
     * @param asset The asset to supply
     * @param amount The quantity to supply
     */
    function supplyTo(address dst, address asset, uint amount) override external {
        return supplyInternal(msg.sender, msg.sender, dst, asset, amount);
    }

    /**
     * @notice Supply an amount of asset from `from` to dst, if allowed
     * @param from The supplier address
     * @param dst The address which will hold the balance
     * @param asset The asset to supply
     * @param amount The quantity to supply
     */
    function supplyFrom(address from, address dst, address asset, uint amount) override external {
        return supplyInternal(msg.sender, from, dst, asset, amount);
    }

    /**
     * @dev Supply either collateral or base asset, depending on the asset, if operator is allowed
     * @dev Note: Specifying an `amount` of uint256.max will repay all of `dst`'s accrued base borrow balance
     */
    function supplyInternal(address operator, address from, address dst, address asset, uint amount) internal nonReentrant {
        if (isSupplyPaused()) revert Paused();
        if (!hasPermission(from, operator)) revert Unauthorized();

        if (asset == baseToken) {
            if (amount == type(uint256).max) {
                amount = borrowBalanceOf(dst);
            }
            return supplyBase(from, dst, amount);
        } else {
            return supplyCollateral(from, dst, asset, safe128(amount));
        }
    }

    /**
     * @dev Supply an amount of base asset from `from` to dst
     */
    function supplyBase(address from, address dst, uint256 amount) internal {
        amount = doTransferIn(baseToken, from, amount);

        accrueInternal();

        UserBasic memory dstUser = userBasic[dst];
        int104 dstPrincipal = dstUser.principal;
        int256 dstBalance = presentValue(dstPrincipal) + signed256(amount);
        int104 dstPrincipalNew = principalValue(dstBalance);

        (uint104 repayAmount, uint104 supplyAmount) = repayAndSupplyAmount(dstPrincipal, dstPrincipalNew);

        totalSupplyBase += supplyAmount;
        totalBorrowBase -= repayAmount;

        updateBasePrincipal(dst, dstUser, dstPrincipalNew);

        emit Supply(from, dst, amount);

        if (supplyAmount > 0) {
            emit Transfer(address(0), dst, presentValueSupply(baseSupplyIndex, supplyAmount));
        }
    }

    /**
     * @dev Supply an amount of collateral asset from `from` to dst
     */
    function supplyCollateral(address from, address dst, address asset, uint128 amount) internal {
        amount = safe128(doTransferIn(asset, from, amount));

        AssetInfo memory assetInfo = getAssetInfoByAddress(asset);
        TotalsCollateral memory totals = totalsCollateral[asset];
        totals.totalSupplyAsset += amount;
        if (totals.totalSupplyAsset > assetInfo.supplyCap) revert SupplyCapExceeded();

        uint128 dstCollateral = userCollateral[dst][asset].balance;
        uint128 dstCollateralNew = dstCollateral + amount;

        totalsCollateral[asset] = totals;
        userCollateral[dst][asset].balance = dstCollateralNew;

        updateAssetsIn(dst, assetInfo, dstCollateral, dstCollateralNew);

        emit SupplyCollateral(from, dst, asset, amount);
    }

    /**
     * @notice ERC20 transfer an amount of base token to dst
     * @param dst The recipient address
     * @param amount The quantity to transfer
     * @return true
     */
    function transfer(address dst, uint amount) override external returns (bool) {
        transferInternal(msg.sender, msg.sender, dst, baseToken, amount);
        return true;
    }

    /**
     * @notice ERC20 transfer an amount of base token from src to dst, if allowed
     * @param src The sender address
     * @param dst The recipient address
     * @param amount The quantity to transfer
     * @return true
     */
    function transferFrom(address src, address dst, uint amount) override external returns (bool) {
        transferInternal(msg.sender, src, dst, baseToken, amount);
        return true;
    }

    /**
     * @notice Transfer an amount of asset to dst
     * @param dst The recipient address
     * @param asset The asset to transfer
     * @param amount The quantity to transfer
     */
    function transferAsset(address dst, address asset, uint amount) override external {
        return transferInternal(msg.sender, msg.sender, dst, asset, amount);
    }

    /**
     * @notice Transfer an amount of asset from src to dst, if allowed
     * @param src The sender address
     * @param dst The recipient address
     * @param asset The asset to transfer
     * @param amount The quantity to transfer
     */
    function transferAssetFrom(address src, address dst, address asset, uint amount) override external {
        return transferInternal(msg.sender, src, dst, asset, amount);
    }

    /**
     * @dev Transfer either collateral or base asset, depending on the asset, if operator is allowed
     * @dev Note: Specifying an `amount` of uint256.max will transfer all of `src`'s accrued base balance
     */
    function transferInternal(address operator, address src, address dst, address asset, uint amount) internal nonReentrant {
        if (isTransferPaused()) revert Paused();
        if (!hasPermission(src, operator)) revert Unauthorized();
        if (src == dst) revert NoSelfTransfer();

        if (asset == baseToken) {
            if (amount == type(uint256).max) {
                amount = balanceOf(src);
            }
            return transferBase(src, dst, amount);
        } else {
            return transferCollateral(src, dst, asset, safe128(amount));
        }
    }

    /**
     * @dev Transfer an amount of base asset from src to dst, borrowing if possible/necessary
     */
    function transferBase(address src, address dst, uint256 amount) internal {
        accrueInternal();

        UserBasic memory srcUser = userBasic[src];
        UserBasic memory dstUser = userBasic[dst];

        int104 srcPrincipal = srcUser.principal;
        int104 dstPrincipal = dstUser.principal;
        int256 srcBalance = presentValue(srcPrincipal) - signed256(amount);
        int256 dstBalance = presentValue(dstPrincipal) + signed256(amount);
        int104 srcPrincipalNew = principalValue(srcBalance);
        int104 dstPrincipalNew = principalValue(dstBalance);

        (uint104 withdrawAmount, uint104 borrowAmount) = withdrawAndBorrowAmount(srcPrincipal, srcPrincipalNew);
        (uint104 repayAmount, uint104 supplyAmount) = repayAndSupplyAmount(dstPrincipal, dstPrincipalNew);

        // Note: Instead of `total += addAmount - subAmount` to avoid underflow errors.
        totalSupplyBase = totalSupplyBase + supplyAmount - withdrawAmount;
        totalBorrowBase = totalBorrowBase + borrowAmount - repayAmount;

        updateBasePrincipal(src, srcUser, srcPrincipalNew);
        updateBasePrincipal(dst, dstUser, dstPrincipalNew);

        if (srcBalance < 0) {
            if (uint256(-srcBalance) < baseBorrowMin) revert BorrowTooSmall();
            if (!isBorrowCollateralized(src)) revert NotCollateralized();
        }

        if (withdrawAmount > 0) {
            emit Transfer(src, address(0), presentValueSupply(baseSupplyIndex, withdrawAmount));
        }

        if (supplyAmount > 0) {
            emit Transfer(address(0), dst, presentValueSupply(baseSupplyIndex, supplyAmount));
        }
    }

    /**
     * @dev Transfer an amount of collateral asset from src to dst
     */
    function transferCollateral(address src, address dst, address asset, uint128 amount) internal {
        uint128 srcCollateral = userCollateral[src][asset].balance;
        uint128 dstCollateral = userCollateral[dst][asset].balance;
        uint128 srcCollateralNew = srcCollateral - amount;
        uint128 dstCollateralNew = dstCollateral + amount;

        userCollateral[src][asset].balance = srcCollateralNew;
        userCollateral[dst][asset].balance = dstCollateralNew;

        AssetInfo memory assetInfo = getAssetInfoByAddress(asset);
        updateAssetsIn(src, assetInfo, srcCollateral, srcCollateralNew);
        updateAssetsIn(dst, assetInfo, dstCollateral, dstCollateralNew);

        // Note: no accrue interest, BorrowCF < LiquidationCF covers small changes
        if (!isBorrowCollateralized(src)) revert NotCollateralized();

        emit TransferCollateral(src, dst, asset, amount);
    }

    /**
     * @notice Withdraw an amount of asset from the protocol
     * @param asset The asset to withdraw
     * @param amount The quantity to withdraw
     */
    function withdraw(address asset, uint amount) override external {
        return withdrawInternal(msg.sender, msg.sender, msg.sender, asset, amount);
    }

    /**
     * @notice Withdraw an amount of asset to `to`
     * @param to The recipient address
     * @param asset The asset to withdraw
     * @param amount The quantity to withdraw
     */
    function withdrawTo(address to, address asset, uint amount) override external {
        return withdrawInternal(msg.sender, msg.sender, to, asset, amount);
    }

    /**
     * @notice Withdraw an amount of asset from src to `to`, if allowed
     * @param src The sender address
     * @param to The recipient address
     * @param asset The asset to withdraw
     * @param amount The quantity to withdraw
     */
    function withdrawFrom(address src, address to, address asset, uint amount) override external {
        return withdrawInternal(msg.sender, src, to, asset, amount);
    }

    /**
     * @dev Withdraw either collateral or base asset, depending on the asset, if operator is allowed
     * @dev Note: Specifying an `amount` of uint256.max will withdraw all of `src`'s accrued base balance
     */
    function withdrawInternal(address operator, address src, address to, address asset, uint amount) internal nonReentrant {
        if (isWithdrawPaused()) revert Paused();
        if (!hasPermission(src, operator)) revert Unauthorized();

        if (asset == baseToken) {
            if (amount == type(uint256).max) {
                amount = balanceOf(src);
            }
            return withdrawBase(src, to, amount);
        } else {
            return withdrawCollateral(src, to, asset, safe128(amount));
        }
    }

    /**
     * @dev Withdraw an amount of base asset from src to `to`, borrowing if possible/necessary
     */
    function withdrawBase(address src, address to, uint256 amount) internal {
        accrueInternal();

        UserBasic memory srcUser = userBasic[src];
        int104 srcPrincipal = srcUser.principal;
        int256 srcBalance = presentValue(srcPrincipal) - signed256(amount);
        int104 srcPrincipalNew = principalValue(srcBalance);

        (uint104 withdrawAmount, uint104 borrowAmount) = withdrawAndBorrowAmount(srcPrincipal, srcPrincipalNew);

        totalSupplyBase -= withdrawAmount;
        totalBorrowBase += borrowAmount;

        updateBasePrincipal(src, srcUser, srcPrincipalNew);

        if (srcBalance < 0) {
            if (uint256(-srcBalance) < baseBorrowMin) revert BorrowTooSmall();
            if (!isBorrowCollateralized(src)) revert NotCollateralized();
        }

        doTransferOut(baseToken, to, amount);

        emit Withdraw(src, to, amount);

        if (withdrawAmount > 0) {
            emit Transfer(src, address(0), presentValueSupply(baseSupplyIndex, withdrawAmount));
        }
    }

    /**
     * @dev Withdraw an amount of collateral asset from src to `to`
     */
    function withdrawCollateral(address src, address to, address asset, uint128 amount) internal {
        uint128 srcCollateral = userCollateral[src][asset].balance;
        uint128 srcCollateralNew = srcCollateral - amount;

        totalsCollateral[asset].totalSupplyAsset -= amount;
        userCollateral[src][asset].balance = srcCollateralNew;

        AssetInfo memory assetInfo = getAssetInfoByAddress(asset);
        updateAssetsIn(src, assetInfo, srcCollateral, srcCollateralNew);

        // Note: no accrue interest, BorrowCF < LiquidationCF covers small changes
        if (!isBorrowCollateralized(src)) revert NotCollateralized();

        doTransferOut(asset, to, amount);

        emit WithdrawCollateral(src, to, asset, amount);
    }

    /**
     * @notice Absorb a list of underwater accounts onto the protocol balance sheet
     * @param absorber The recipient of the incentive paid to the caller of absorb
     * @param accounts The list of underwater accounts to absorb
     */
    function absorb(address absorber, address[] calldata accounts) override external {
        if (isAbsorbPaused()) revert Paused();

        uint startGas = gasleft();
        accrueInternal();
        for (uint i = 0; i < accounts.length; ) {
            absorbInternal(absorber, accounts[i]);
            unchecked { i++; }
        }
        uint gasUsed = startGas - gasleft();

        // Note: liquidator points are an imperfect tool for governance,
        //  to be used while evaluating strategies for incentivizing absorption.
        // Using gas price instead of base fee would more accurately reflect spend,
        //  but is also subject to abuse if refunds were to be given automatically.
        LiquidatorPoints memory points = liquidatorPoints[absorber];
        points.numAbsorbs++;
        points.numAbsorbed += safe64(accounts.length);
        points.approxSpend += safe128(gasUsed * block.basefee);
        liquidatorPoints[absorber] = points;
    }

    /**
     * @dev Transfer user's collateral and debt to the protocol itself.
     */
    function absorbInternal(address absorber, address account) internal {
        if (!isLiquidatable(account)) revert NotLiquidatable();

        UserBasic memory accountUser = userBasic[account];
        int104 oldPrincipal = accountUser.principal;
        int256 oldBalance = presentValue(oldPrincipal);
        uint16 assetsIn = accountUser.assetsIn;

        uint256 basePrice = getPrice(baseTokenPriceFeed);
        uint256 deltaValue = 0;

        for (uint8 i = 0; i < numAssets; ) {
            if (isInAsset(assetsIn, i)) {
                AssetInfo memory assetInfo = getAssetInfo(i);
                address asset = assetInfo.asset;
                uint128 seizeAmount = userCollateral[account][asset].balance;
                userCollateral[account][asset].balance = 0;
                totalsCollateral[asset].totalSupplyAsset -= seizeAmount;

                uint256 value = mulPrice(seizeAmount, getPrice(assetInfo.priceFeed), assetInfo.scale);
                deltaValue += mulFactor(value, assetInfo.liquidationFactor);

                emit AbsorbCollateral(absorber, account, asset, seizeAmount, value);
            }
            unchecked { i++; }
        }

        uint256 deltaBalance = divPrice(deltaValue, basePrice, uint64(baseScale));
        int256 newBalance = oldBalance + signed256(deltaBalance);
        // New balance will not be negative, all excess debt absorbed by reserves
        if (newBalance < 0) {
            newBalance = 0;
        }

        int104 newPrincipal = principalValue(newBalance);
        updateBasePrincipal(account, accountUser, newPrincipal);

        // reset assetsIn
        userBasic[account].assetsIn = 0;

        (uint104 repayAmount, uint104 supplyAmount) = repayAndSupplyAmount(oldPrincipal, newPrincipal);

        // Reserves are decreased by increasing total supply and decreasing borrows
        //  the amount of debt repaid by reserves is `newBalance - oldBalance`
        totalSupplyBase += supplyAmount;
        totalBorrowBase -= repayAmount;

        uint256 basePaidOut = unsigned256(newBalance - oldBalance);
        uint256 valueOfBasePaidOut = mulPrice(basePaidOut, basePrice, uint64(baseScale));
        emit AbsorbDebt(absorber, account, basePaidOut, valueOfBasePaidOut);

        if (newPrincipal > 0) {
            emit Transfer(address(0), account, presentValueSupply(baseSupplyIndex, unsigned104(newPrincipal)));
        }
    }

    /**
     * @notice Buy collateral from the protocol using base tokens, increasing protocol reserves
       A minimum collateral amount should be specified to indicate the maximum slippage acceptable for the buyer.
     * @param asset The asset to buy
     * @param minAmount The minimum amount of collateral tokens that should be received by the buyer
     * @...

// [truncated — 56587 bytes total]
CometCore.sol 127 lines
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.15;

import "./CometConfiguration.sol";
import "./CometStorage.sol";
import "./CometMath.sol";

abstract contract CometCore is CometConfiguration, CometStorage, CometMath {
    struct AssetInfo {
        uint8 offset;
        address asset;
        address priceFeed;
        uint64 scale;
        uint64 borrowCollateralFactor;
        uint64 liquidateCollateralFactor;
        uint64 liquidationFactor;
        uint128 supplyCap;
    }

    /** Internal constants **/

    /// @dev The max number of assets this contract is hardcoded to support
    ///  Do not change this variable without updating all the fields throughout the contract,
    //    including the size of UserBasic.assetsIn and corresponding integer conversions.
    uint8 internal constant MAX_ASSETS = 15;

    /// @dev The max number of decimals base token can have
    ///  Note this cannot just be increased arbitrarily.
    uint8 internal constant MAX_BASE_DECIMALS = 18;

    /// @dev The max value for a collateral factor (1)
    uint64 internal constant MAX_COLLATERAL_FACTOR = FACTOR_SCALE;

    /// @dev Offsets for specific actions in the pause flag bit array
    uint8 internal constant PAUSE_SUPPLY_OFFSET = 0;
    uint8 internal constant PAUSE_TRANSFER_OFFSET = 1;
    uint8 internal constant PAUSE_WITHDRAW_OFFSET = 2;
    uint8 internal constant PAUSE_ABSORB_OFFSET = 3;
    uint8 internal constant PAUSE_BUY_OFFSET = 4;

    /// @dev The decimals required for a price feed
    uint8 internal constant PRICE_FEED_DECIMALS = 8;

    /// @dev 365 days * 24 hours * 60 minutes * 60 seconds
    uint64 internal constant SECONDS_PER_YEAR = 31_536_000;

    /// @dev The scale for base tracking accrual
    uint64 internal constant BASE_ACCRUAL_SCALE = 1e6;

    /// @dev The scale for base index (depends on time/rate scales, not base token)
    uint64 internal constant BASE_INDEX_SCALE = 1e15;

    /// @dev The scale for prices (in USD)
    uint64 internal constant PRICE_SCALE = uint64(10 ** PRICE_FEED_DECIMALS);

    /// @dev The scale for factors
    uint64 internal constant FACTOR_SCALE = 1e18;

    /// @dev The storage slot for reentrancy guard flags
    bytes32 internal constant REENTRANCY_GUARD_FLAG_SLOT = bytes32(keccak256("comet.reentrancy.guard"));

    /// @dev The reentrancy guard statuses
    uint256 internal constant REENTRANCY_GUARD_NOT_ENTERED = 0;
    uint256 internal constant REENTRANCY_GUARD_ENTERED = 1;

    /**
     * @notice Determine if the manager has permission to act on behalf of the owner
     * @param owner The owner account
     * @param manager The manager account
     * @return Whether or not the manager has permission
     */
    function hasPermission(address owner, address manager) public view returns (bool) {
        return owner == manager || isAllowed[owner][manager];
    }

    /**
     * @dev The positive present supply balance if positive or the negative borrow balance if negative
     */
    function presentValue(int104 principalValue_) internal view returns (int256) {
        if (principalValue_ >= 0) {
            return signed256(presentValueSupply(baseSupplyIndex, uint104(principalValue_)));
        } else {
            return -signed256(presentValueBorrow(baseBorrowIndex, uint104(-principalValue_)));
        }
    }

    /**
     * @dev The principal amount projected forward by the supply index
     */
    function presentValueSupply(uint64 baseSupplyIndex_, uint104 principalValue_) internal pure returns (uint256) {
        return uint256(principalValue_) * baseSupplyIndex_ / BASE_INDEX_SCALE;
    }

    /**
     * @dev The principal amount projected forward by the borrow index
     */
    function presentValueBorrow(uint64 baseBorrowIndex_, uint104 principalValue_) internal pure returns (uint256) {
        return uint256(principalValue_) * baseBorrowIndex_ / BASE_INDEX_SCALE;
    }

    /**
     * @dev The positive principal if positive or the negative principal if negative
     */
    function principalValue(int256 presentValue_) internal view returns (int104) {
        if (presentValue_ >= 0) {
            return signed104(principalValueSupply(baseSupplyIndex, uint256(presentValue_)));
        } else {
            return -signed104(principalValueBorrow(baseBorrowIndex, uint256(-presentValue_)));
        }
    }

    /**
     * @dev The present value projected backward by the supply index (rounded down)
     *  Note: This will overflow (revert) at 2^104/1e18=~20 trillion principal for assets with 18 decimals.
     */
    function principalValueSupply(uint64 baseSupplyIndex_, uint256 presentValue_) internal pure returns (uint104) {
        return safe104((presentValue_ * BASE_INDEX_SCALE) / baseSupplyIndex_);
    }

    /**
     * @dev The present value projected backward by the borrow index (rounded up)
     *  Note: This will overflow (revert) at 2^104/1e18=~20 trillion principal for assets with 18 decimals.
     */
    function principalValueBorrow(uint64 baseBorrowIndex_, uint256 presentValue_) internal pure returns (uint104) {
        return safe104((presentValue_ * BASE_INDEX_SCALE + baseBorrowIndex_ - 1) / baseBorrowIndex_);
    }
}
CometMath.sol 61 lines
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.15;

/**
 * @title Compound's Comet Math Contract
 * @dev Pure math functions
 * @author Compound
 */
contract CometMath {
    /** Custom errors **/

    error InvalidUInt64();
    error InvalidUInt104();
    error InvalidUInt128();
    error InvalidInt104();
    error InvalidInt256();
    error NegativeNumber();

    function safe64(uint n) internal pure returns (uint64) {
        if (n > type(uint64).max) revert InvalidUInt64();
        return uint64(n);
    }

    function safe104(uint n) internal pure returns (uint104) {
        if (n > type(uint104).max) revert InvalidUInt104();
        return uint104(n);
    }

    function safe128(uint n) internal pure returns (uint128) {
        if (n > type(uint128).max) revert InvalidUInt128();
        return uint128(n);
    }

    function signed104(uint104 n) internal pure returns (int104) {
        if (n > uint104(type(int104).max)) revert InvalidInt104();
        return int104(n);
    }

    function signed256(uint256 n) internal pure returns (int256) {
        if (n > uint256(type(int256).max)) revert InvalidInt256();
        return int256(n);
    }

    function unsigned104(int104 n) internal pure returns (uint104) {
        if (n < 0) revert NegativeNumber();
        return uint104(n);
    }

    function unsigned256(int256 n) internal pure returns (uint256) {
        if (n < 0) revert NegativeNumber();
        return uint256(n);
    }

    function toUInt8(bool x) internal pure returns (uint8) {
        return x ? 1 : 0;
    }

    function toBool(uint8 x) internal pure returns (bool) {
        return x != 0;
    }
}
IPriceFeed.sol 25 lines
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.15;

/**
 * @dev Interface for price feeds used by Comet
 * Note This is Chainlink's AggregatorV3Interface, but without the `getRoundData` function.
 */
interface IPriceFeed {
  function decimals() external view returns (uint8);

  function description() external view returns (string memory);

  function version() external view returns (uint256);

  function latestRoundData()
    external
    view
    returns (
      uint80 roundId,
      int256 answer,
      uint256 startedAt,
      uint256 updatedAt,
      uint80 answeredInRound
    );
}
CometStorage.sol 76 lines
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.15;

/**
 * @title Compound's Comet Storage Interface
 * @dev Versions can enforce append-only storage slots via inheritance.
 * @author Compound
 */
contract CometStorage {
    // 512 bits total = 2 slots
    struct TotalsBasic {
        // 1st slot
        uint64 baseSupplyIndex;
        uint64 baseBorrowIndex;
        uint64 trackingSupplyIndex;
        uint64 trackingBorrowIndex;
        // 2nd slot
        uint104 totalSupplyBase;
        uint104 totalBorrowBase;
        uint40 lastAccrualTime;
        uint8 pauseFlags;
    }

    struct TotalsCollateral {
        uint128 totalSupplyAsset;
        uint128 _reserved;
    }

    struct UserBasic {
        int104 principal;
        uint64 baseTrackingIndex;
        uint64 baseTrackingAccrued;
        uint16 assetsIn;
        uint8 _reserved;
    }

    struct UserCollateral {
        uint128 balance;
        uint128 _reserved;
    }

    struct LiquidatorPoints {
        uint32 numAbsorbs;
        uint64 numAbsorbed;
        uint128 approxSpend;
        uint32 _reserved;
    }

    /// @dev Aggregate variables tracked for the entire market
    uint64 internal baseSupplyIndex;
    uint64 internal baseBorrowIndex;
    uint64 internal trackingSupplyIndex;
    uint64 internal trackingBorrowIndex;
    uint104 internal totalSupplyBase;
    uint104 internal totalBorrowBase;
    uint40 internal lastAccrualTime;
    uint8 internal pauseFlags;

    /// @notice Aggregate variables tracked for each collateral asset
    mapping(address => TotalsCollateral) public totalsCollateral;

    /// @notice Mapping of users to accounts which may be permitted to manage the user account
    mapping(address => mapping(address => bool)) public isAllowed;

    /// @notice The next expected nonce for an address, for validating authorizations via signature
    mapping(address => uint) public userNonce;

    /// @notice Mapping of users to base principal and other basic data
    mapping(address => UserBasic) public userBasic;

    /// @notice Mapping of users to collateral data per collateral asset
    mapping(address => mapping(address => UserCollateral)) public userCollateral;

    /// @notice Mapping of magic liquidator points
    mapping(address => LiquidatorPoints) public liquidatorPoints;
}
IERC20NonStandard.sol 43 lines
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.15;

/**
 * @title IERC20NonStandard
 * @dev Version of ERC20 with no return values for `approve`, `transfer`, and `transferFrom`
 *  See https://medium.com/coinmonks/missing-return-value-bug-at-least-130-tokens-affected-d67bf08521ca
 */
interface IERC20NonStandard {
    function name() external view returns (string memory);
    function symbol() external view returns (string memory);
    function decimals() external view returns (uint8);

    /**
     * @notice Approve `spender` to transfer up to `amount` from `src`
     * @dev This will overwrite the approval amount for `spender`
     *  and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve)
     * @param spender The address of the account which may transfer tokens
     * @param amount The number of tokens that are approved (-1 means infinite)
     */
    function approve(address spender, uint256 amount) external;

    /**
     * @notice Transfer `value` tokens from `msg.sender` to `to`
     * @param to The address of the destination account
     * @param value The number of tokens to transfer
     */
    function transfer(address to, uint256 value) external;

    /**
     * @notice Transfer `value` tokens from `from` to `to`
     * @param from The address of the source account
     * @param to The address of the destination account
     * @param value The number of tokens to transfer
     */
    function transferFrom(address from, address to, uint256 value) external;

    /**
     * @notice Gets the balance of the specified address
     * @param account The address from which the balance will be retrieved
     */
    function balanceOf(address account) external view returns (uint256);
}
CometConfiguration.sol 49 lines
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.15;

/**
 * @title Compound's Comet Configuration Interface
 * @author Compound
 */
contract CometConfiguration {
    struct ExtConfiguration {
        bytes32 name32;
        bytes32 symbol32;
    }

    struct Configuration {
        address governor;
        address pauseGuardian;
        address baseToken;
        address baseTokenPriceFeed;
        address extensionDelegate;

        uint64 supplyKink;
        uint64 supplyPerYearInterestRateSlopeLow;
        uint64 supplyPerYearInterestRateSlopeHigh;
        uint64 supplyPerYearInterestRateBase;
        uint64 borrowKink;
        uint64 borrowPerYearInterestRateSlopeLow;
        uint64 borrowPerYearInterestRateSlopeHigh;
        uint64 borrowPerYearInterestRateBase;
        uint64 storeFrontPriceFactor;
        uint64 trackingIndexScale;
        uint64 baseTrackingSupplySpeed;
        uint64 baseTrackingBorrowSpeed;
        uint104 baseMinForRewards;
        uint104 baseBorrowMin;
        uint104 targetReserves;

        AssetConfig[] assetConfigs;
    }

    struct AssetConfig {
        address asset;
        address priceFeed;
        uint8 decimals;
        uint64 borrowCollateralFactor;
        uint64 liquidateCollateralFactor;
        uint64 liquidationFactor;
        uint128 supplyCap;
    }
}
CometMainInterface.sol 152 lines
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.15;

import "./CometCore.sol";

/**
 * @title Compound's Comet Main Interface (without Ext)
 * @notice An efficient monolithic money market protocol
 * @author Compound
 */
abstract contract CometMainInterface is CometCore {
    error Absurd();
    error AlreadyInitialized();
    error BadAsset();
    error BadDecimals();
    error BadDiscount();
    error BadMinimum();
    error BadPrice();
    error BorrowTooSmall();
    error BorrowCFTooLarge();
    error InsufficientReserves();
    error LiquidateCFTooLarge();
    error NoSelfTransfer();
    error NotCollateralized();
    error NotForSale();
    error NotLiquidatable();
    error Paused();
    error ReentrantCallBlocked();
    error SupplyCapExceeded();
    error TimestampTooLarge();
    error TooManyAssets();
    error TooMuchSlippage();
    error TransferInFailed();
    error TransferOutFailed();
    error Unauthorized();

    event Supply(address indexed from, address indexed dst, uint amount);
    event Transfer(address indexed from, address indexed to, uint amount);
    event Withdraw(address indexed src, address indexed to, uint amount);

    event SupplyCollateral(address indexed from, address indexed dst, address indexed asset, uint amount);
    event TransferCollateral(address indexed from, address indexed to, address indexed asset, uint amount);
    event WithdrawCollateral(address indexed src, address indexed to, address indexed asset, uint amount);

    /// @notice Event emitted when a borrow position is absorbed by the protocol
    event AbsorbDebt(address indexed absorber, address indexed borrower, uint basePaidOut, uint usdValue);

    /// @notice Event emitted when a user's collateral is absorbed by the protocol
    event AbsorbCollateral(address indexed absorber, address indexed borrower, address indexed asset, uint collateralAbsorbed, uint usdValue);

    /// @notice Event emitted when a collateral asset is purchased from the protocol
    event BuyCollateral(address indexed buyer, address indexed asset, uint baseAmount, uint collateralAmount);

    /// @notice Event emitted when an action is paused/unpaused
    event PauseAction(bool supplyPaused, bool transferPaused, bool withdrawPaused, bool absorbPaused, bool buyPaused);

    /// @notice Event emitted when reserves are withdrawn by the governor
    event WithdrawReserves(address indexed to, uint amount);

    function supply(address asset, uint amount) virtual external;
    function supplyTo(address dst, address asset, uint amount) virtual external;
    function supplyFrom(address from, address dst, address asset, uint amount) virtual external;

    function transfer(address dst, uint amount) virtual external returns (bool);
    function transferFrom(address src, address dst, uint amount) virtual external returns (bool);

    function transferAsset(address dst, address asset, uint amount) virtual external;
    function transferAssetFrom(address src, address dst, address asset, uint amount) virtual external;

    function withdraw(address asset, uint amount) virtual external;
    function withdrawTo(address to, address asset, uint amount) virtual external;
    function withdrawFrom(address src, address to, address asset, uint amount) virtual external;

    function approveThis(address manager, address asset, uint amount) virtual external;
    function withdrawReserves(address to, uint amount) virtual external;

    function absorb(address absorber, address[] calldata accounts) virtual external;
    function buyCollateral(address asset, uint minAmount, uint baseAmount, address recipient) virtual external;
    function quoteCollateral(address asset, uint baseAmount) virtual public view returns (uint);

    function getAssetInfo(uint8 i) virtual public view returns (AssetInfo memory);
    function getAssetInfoByAddress(address asset) virtual public view returns (AssetInfo memory);
    function getCollateralReserves(address asset) virtual public view returns (uint);
    function getReserves() virtual public view returns (int);
    function getPrice(address priceFeed) virtual public view returns (uint);

    function isBorrowCollateralized(address account) virtual public view returns (bool);
    function isLiquidatable(address account) virtual public view returns (bool);

    function totalSupply() virtual external view returns (uint256);
    function totalBorrow() virtual external view returns (uint256);
    function balanceOf(address owner) virtual public view returns (uint256);
    function borrowBalanceOf(address account) virtual public view returns (uint256);

    function pause(bool supplyPaused, bool transferPaused, bool withdrawPaused, bool absorbPaused, bool buyPaused) virtual external;
    function isSupplyPaused() virtual public view returns (bool);
    function isTransferPaused() virtual public view returns (bool);
    function isWithdrawPaused() virtual public view returns (bool);
    function isAbsorbPaused() virtual public view returns (bool);
    function isBuyPaused() virtual public view returns (bool);

    function accrueAccount(address account) virtual external;
    function getSupplyRate(uint utilization) virtual public view returns (uint64);
    function getBorrowRate(uint utilization) virtual public view returns (uint64);
    function getUtilization() virtual public view returns (uint);

    function governor() virtual external view returns (address);
    function pauseGuardian() virtual external view returns (address);
    function baseToken() virtual external view returns (address);
    function baseTokenPriceFeed() virtual external view returns (address);
    function extensionDelegate() virtual external view returns (address);

    /// @dev uint64
    function supplyKink() virtual external view returns (uint);
    /// @dev uint64
    function supplyPerSecondInterestRateSlopeLow() virtual external view returns (uint);
    /// @dev uint64
    function supplyPerSecondInterestRateSlopeHigh() virtual external view returns (uint);
    /// @dev uint64
    function supplyPerSecondInterestRateBase() virtual external view returns (uint);
    /// @dev uint64
    function borrowKink() virtual external view returns (uint);
    /// @dev uint64
    function borrowPerSecondInterestRateSlopeLow() virtual external view returns (uint);
    /// @dev uint64
    function borrowPerSecondInterestRateSlopeHigh() virtual external view returns (uint);
    /// @dev uint64
    function borrowPerSecondInterestRateBase() virtual external view returns (uint);
    /// @dev uint64
    function storeFrontPriceFactor() virtual external view returns (uint);

    /// @dev uint64
    function baseScale() virtual external view returns (uint);
    /// @dev uint64
    function trackingIndexScale() virtual external view returns (uint);

    /// @dev uint64
    function baseTrackingSupplySpeed() virtual external view returns (uint);
    /// @dev uint64
    function baseTrackingBorrowSpeed() virtual external view returns (uint);
    /// @dev uint104
    function baseMinForRewards() virtual external view returns (uint);
    /// @dev uint104
    function baseBorrowMin() virtual external view returns (uint);
    /// @dev uint104
    function targetReserves() virtual external view returns (uint);

    function numAssets() virtual external view returns (uint8);
    function decimals() virtual external view returns (uint8);

    function initializeStorage() virtual external;
}

Read Contract

balanceOf 0x70a08231 → uint256
baseBorrowMin 0x300e6beb → uint256
baseMinForRewards 0x9364e18a → uint256
baseScale 0x44c1e5eb → uint256
baseToken 0xc55dae63 → address
baseTokenPriceFeed 0xe7dad6bd → address
baseTrackingBorrowSpeed 0x9ea99a5a → uint256
baseTrackingSupplySpeed 0x189bb2f1 → uint256
borrowBalanceOf 0x374c49b4 → uint256
borrowKink 0x9241a561 → uint256
borrowPerSecondInterestRateBase 0x7914acc7 → uint256
borrowPerSecondInterestRateSlopeHigh 0x2a48cf12 → uint256
borrowPerSecondInterestRateSlopeLow 0x2d05670b → uint256
decimals 0x313ce567 → uint8
extensionDelegate 0x44ff241d → address
getAssetInfo 0xc8c7fe6b → tuple
getAssetInfoByAddress 0x3b3bec2e → tuple
getBorrowRate 0x9fa83b5a → uint64
getCollateralReserves 0x9ff567f8 → uint256
getPrice 0x41976e09 → uint256
getReserves 0x0902f1ac → int256
getSupplyRate 0xd955759d → uint64
getUtilization 0x7eb71131 → uint256
governor 0x0c340a24 → address
hasPermission 0xcde68041 → bool
isAbsorbPaused 0x8d5d814c → bool
isAllowed 0xa1654379 → bool
isBorrowCollateralized 0x38aa813f → bool
isBuyPaused 0xd8e5f611 → bool
isLiquidatable 0x042e02cf → bool
isSupplyPaused 0x0bc47ad1 → bool
isTransferPaused 0xa1a1ef43 → bool
isWithdrawPaused 0x67800b5f → bool
liquidatorPoints 0xc5fa15cf → uint32, uint64, uint128, uint32
numAssets 0xa46fe83b → uint8
pauseGuardian 0x24a3d622 → address
quoteCollateral 0x7ac88ed1 → uint256
storeFrontPriceFactor 0x1f5954bd → uint256
supplyKink 0xa5b4ff79 → uint256
supplyPerSecondInterestRateBase 0x94920cca → uint256
supplyPerSecondInterestRateSlopeHigh 0x804de71f → uint256
supplyPerSecondInterestRateSlopeLow 0x5a94b8d1 → uint256
targetReserves 0x32176c49 → uint256
totalBorrow 0x8285ef40 → uint256
totalSupply 0x18160ddd → uint256
totalsCollateral 0x59e017bd → uint128, uint128
trackingIndexScale 0xaba7f15e → uint256
userBasic 0xdc4abafd → int104, uint64, uint64, uint16, uint8
userCollateral 0x2b92a07d → uint128, uint128
userNonce 0x2e04b8e7 → uint256

Write Contract 17 functions

These functions modify contract state and require a wallet transaction to execute.

absorb 0xc3cecfd2
address absorber
address[] accounts
accrueAccount 0xbfe69c8d
address account
approveThis 0xad14777c
address manager
address asset
uint256 amount
buyCollateral 0xe4e6e779
address asset
uint256 minAmount
uint256 baseAmount
address recipient
initializeStorage 0x1c9f7fb9
No parameters
pause 0x44c35d07
bool supplyPaused
bool transferPaused
bool withdrawPaused
bool absorbPaused
bool buyPaused
supply 0xf2b9fdb8
address asset
uint256 amount
supplyFrom 0x90323177
address from
address dst
address asset
uint256 amount
supplyTo 0x4232cd63
address dst
address asset
uint256 amount
transfer 0xa9059cbb
address dst
uint256 amount
returns: bool
transferAsset 0x439e2e45
address dst
address asset
uint256 amount
transferAssetFrom 0xc1ee2c18
address src
address dst
address asset
uint256 amount
transferFrom 0x23b872dd
address src
address dst
uint256 amount
returns: bool
withdraw 0xf3fef3a3
address asset
uint256 amount
withdrawFrom 0x26441318
address src
address to
address asset
uint256 amount
withdrawReserves 0xe478795d
address to
uint256 amount
withdrawTo 0xc3b35a7e
address to
address asset
uint256 amount

Recent Transactions

Transaction index is loading. Only unfinalized transactions are shown while the index starts up.