Address Contract Verified
Address
0x27D7D02AED6C4F95Ada2faf02DcCB9666D3abB8C
Balance
0 ETH
Nonce
1
Code Size
21601 bytes
Creator
0x49E3C589...4d2B at tx 0x5e1214fc...ad8817
Indexed Transactions
0
Contract Bytecode
21601 bytes
0x608060405234801561001057600080fd5b50600436106104145760003560e01c8063795d26c311610221578063bcd375261161012b578063d5b35635116100c3578063ee266b8711610087578063ee266b87146109c5578063f2fde38b146109ce578063f36b2425146109e1578063f92d343314610562578063fe2ba848146109e957600080fd5b8063d5b356351461095a578063d66a25531461096d578063d9a7244414610996578063e2ac77b0146109a9578063e6a91f16146109bc57600080fd5b8063bcd37526146108dc578063bf9befb1146108ef578063c52861f2146108f8578063c7b5548114610900578063cbd138ae1461090f578063d293c71014610922578063d380a37c14610935578063d38b05581461093e578063d3d6f8431461094757600080fd5b80639976cf45116101b9578063ae9187541161017d578063ae9187541461085d578063b0d8e18114610870578063b7f8cf9b14610883578063b82f263d14610896578063b91af97c146108a957600080fd5b80639976cf45146107f65780639ba7a40814610809578063a20baee614610720578063a3f4df7e1461081c578063a68b663e1461085457600080fd5b8063795d26c3146107775780637f7dde4a1461077f578063807d138d1461079257806382fe3eb91461079b578063887105d3146107ae5780638da5cb5b146107b65780638f32d59b146107c7578063953f0bb1146107da57806396d711ff146107ed57600080fd5b8063480cd57811610322578063653d46e7116102ba57806372fe25aa1161027e57806372fe25aa14610720578063741bef1a1461072f578063756b253e1461074257806377e16f1e14610755578063794e57241461076857600080fd5b8063653d46e71461068657806366ca4a21146106995780636c37a4af146106a15780636ef64338146106b457806372423c171461070d57600080fd5b8063480cd578146105be5780634870dd9a146105ea57806349eefeee146105f25780634a3c95c4146105fa5780634e443d9e1461060d5780635733d58f146106305780635dba4c4a1461063f578063631203b01461064757806364cee2601461065a57600080fd5b80631f68f20a116103b05780632b11551a116103745780632b11551a1461056a5780632f865568146105725780633cc74225146105855780634597f6ed14610598578063477d66cf146105ab57600080fd5b80631f68f20a146105055780631fd6a4341461050e57806321e378011461051e578063240926691461055a57806328d28b5b1461056257600080fd5b8063048c661d14610419578063071a7541146104425780630b0765571461045857806312610e921461046d57806315d549f1146104805780631673c79a1461049357806318f2817a146104cf5780631bf43555146104e25780631e8b1c2b146104f2575b600080fd5b60055461042c906001600160a01b031681565b6040516104399190614e03565b60405180910390f35b61044a600281565b604051908152602001610439565b61046b610466366004614e3c565b6109fc565b005b61044a61047b366004614e59565b610a24565b61044a61048e366004614e3c565b610a77565b6104ba6104a1366004614e3c565b6013602052600090815260409020805460019091015482565b60408051928352602083019190915201610439565b61044a6104dd366004614e3c565b610a99565b61044a686194049f30f720000081565b61046b610500366004614e9b565b610aac565b61044a600b5481565b61044a680ad78ebc5ac620000081565b61054d61052c366004614e3c565b6001600160a01b03166000908152600d602052604090206003015460ff1690565b6040516104399190614f8a565b61044a610e4d565b61044a610e6e565b61044a610e82565b61046b610580366004614e3c565b610e94565b60015461042c906001600160a01b031681565b60095461042c906001600160a01b031681565b61044a6105b9366004614f98565b610f00565b61044a6105cc366004614e3c565b6001600160a01b03166000908152600d602052604090206001015490565b61044a60c881565b60145461044a565b61044a610608366004614e3c565b610f13565b61062061061b366004614f98565b610fce565b6040519015158152602001610439565b61044a6714d1120d7b16000081565b61046b610fd9565b61044a610655366004614f98565b611045565b61044a610668366004614e3c565b6001600160a01b03166000908152600d602052604090206002015490565b61046b610694366004614f98565b611052565b61044a6113c8565b61046b6106af366004614fb1565b6113da565b6106fc6106c2366004614e3c565b600d6020526000908152604090208054600182015460028301546003909301549192909160ff81169061010090046001600160801b031685565b60405161043995949392919061507d565b61044a61071b366004614e59565b61172b565b61044a670de0b6b3a764000081565b60025461042c906001600160a01b031681565b61042c610750366004614f98565b611783565b60085461042c906001600160a01b031681565b61044a670f43fc2c04ee000081565b61044a6117ad565b60005461042c906001600160a01b031681565b61044a600f5481565b61046b6107a9366004614e3c565b6118a9565b61044a6118ba565b6003546001600160a01b031661042c565b6003546001600160a01b03163314610620565b61046b6107e83660046150ba565b61197f565b61044a60105481565b61044a610804366004614e59565b6119c8565b61044a610817366004614e3c565b6119f6565b6108476040518060400160405280600c81526020016b2a3937bb32a6b0b730b3b2b960a11b81525081565b60405161043991906150f7565b61044a60125481565b600a5461042c906001600160a01b031681565b61044a61087e366004614e3c565b611a22565b60045461042c906001600160a01b031681565b61044a6108a4366004614f98565b611a49565b6108bc6108b7366004614e3c565b611a54565b604080519485526020850193909352918301526060820152608001610439565b61046b6108ea366004615145565b611aac565b61044a600e5481565b61044a612148565b61044a670ddd4b8c6c7d70d881565b61046b61091d366004614e3c565b61215a565b61044a610930366004614e59565b61216d565b61044a600c5481565b61044a60155481565b61044a610955366004614e59565b61218c565b61044a610968366004614f98565b6121bd565b61044a61097b366004614e3c565b6001600160a01b03166000908152600d602052604090205490565b61042c6109a4366004614f98565b6121d0565b6106206109b7366004614e3c565b612200565b61044a60165481565b61044a60115481565b61046b6109dc366004614e3c565b612263565b61044a6122fb565b61046b6109f7366004614e3c565b612308565b610a04612319565b600054600154610a21916001600160a01b0390811691168361239b565b50565b6000610a2e612319565b6001600160a01b0383166000908152600d6020526040812054610a529084906151c9565b6001600160a01b0385166000908152600d602052604090208190559150505b92915050565b6000610a81612319565b610a8a82612497565b6001600160801b031692915050565b6000610aa3612319565b610a7182612530565b8051600003610b215760405162461bcd60e51b815260206004820152603660248201527f54726f76654d616e616765723a2043616c6c646174612061646472657373206160448201527572726179206d757374206e6f7420626520656d70747960501b60648201526084015b60405180910390fd5b6000546001546005546001600160a01b03928316929182169116610b43614d3e565b610b4b614d6f565b600260009054906101000a90046001600160a01b03166001600160a01b0316630fdb11cf6040518163ffffffff1660e01b81526004016020604051808303816000875af1158015610ba0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bc491906151dc565b826000018181525050826001600160a01b03166301081fda6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610c0b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c2f91906151dc565b60208301528151610c3f906125d5565b1580156040840152610c6757610c608585846000015185602001518a6125f2565b9050610c7f565b610c7c8585846000015185602001518a612827565b90505b6000816020015111610ca35760405162461bcd60e51b8152600401610b18906151f5565b608081015160a082015160405163335525ad60e01b81526001600160a01b0386169263335525ad92610ce092600401918252602082015260400190565b600060405180830381600087803b158015610cfa57600080fd5b505af1158015610d0e573d6000803e3d6000fd5b50505050610d2685858360c001518460e001516128fc565b61010081015115610d9d57600754610100820151604051636250216960e01b81526001600160a01b0388811693636250216993610d6a939290911691600401615237565b600060405180830381600087803b158015610d8457600080fd5b505af1158015610d98573d6000803e3d6000fd5b505050505b610dab858260400151612b3b565b6020810151606083015261010081015160408201518251610dcc91906151c9565b610dd691906151c9565b6080838101829052606080850151604085810151868401518251938452602084019690965290820152908101929092527f4152c73dd2614c4f9fc35e8c9cf16013cd588c75b49a4c1673ecffdcbcda9403910160405180910390a1610e45853383606001518460400151612c86565b505050505050565b610e606064670de0b6b3a7640000615266565b610e6b90600561527a565b81565b610e606103e8670de0b6b3a7640000615266565b6000610e8f600b54612d5d565b905090565b610e9d81612d9a565b604080516001808252818301909252600091602080830190803683370190505090508181600081518110610ed357610ed3615291565b60200260200101906001600160a01b031690816001600160a01b031681525050610efc81610aac565b5050565b6000610a71610f0d6113c8565b83612e31565b6001600160a01b0381166000908152601360205260408120546011548290610f3c9083906151c9565b9050801580610f7b575060016001600160a01b0385166000908152600d602052604090206003015460ff166004811115610f7857610f78614f60565b14155b15610f8a575060009392505050565b6001600160a01b0384166000908152600d602052604081206002015490670de0b6b3a7640000610fba848461527a565b610fc49190615266565b9695505050505050565b6000610a71826125d5565b610fe1612319565b6000610feb612e57565b9050670de0b6b3a7640000811115611005576110056152a7565b600b8190556040518181527fc454ee9b76c52f782a256af821b857ca6e125d1e3333bcede402fec2bed9600c9060200160405180910390a1610a21612e9b565b6000610a71610f0d6122fb565b6040805160e081018252600080546001600160a01b0390811683526001548116602084015292820181905260608201819052600a548316608083015260a0820181905260c08201526005549091166110a8614d3e565b6110b0614d6f565b600260009054906101000a90046001600160a01b03166001600160a01b0316630fdb11cf6040518163ffffffff1660e01b81526004016020604051808303816000875af1158015611105573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061112991906151dc565b826000018181525050826001600160a01b03166301081fda6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611170573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061119491906151dc565b602083015281516111a4906125d5565b15801560408401526111cb576111c4848360000151846020015188612ef2565b90506111eb565b6111e884600001518560200151846000015185602001518961327e565b90505b600081602001511161120f5760405162461bcd60e51b8152600401610b18906151f5565b608081015160a082015160405163335525ad60e01b81526001600160a01b0386169263335525ad9261124c92600401918252602082015260400190565b600060405180830381600087803b15801561126657600080fd5b505af115801561127a573d6000803e3d6000fd5b5050505061129a846000015185602001518360c001518460e001516128fc565b61010081015115611311578351600754610100830151604051636250216960e01b81526001600160a01b03938416936362502169936112de93911691600401615237565b600060405180830381600087803b1580156112f857600080fd5b505af115801561130c573d6000803e3d6000fd5b505050505b61132384600001518260400151612b3b565b602081015160608301526101008101516040820151825161134491906151c9565b61134e91906151c9565b6080838101829052606080850151604085810151868401518251938452602084019690965290820152908101929092527f4152c73dd2614c4f9fc35e8c9cf16013cd588c75b49a4c1673ecffdcbcda9403910160405180910390a16113c184600001513383606001518460400151612c86565b5050505050565b6000610e8f6113d5612e57565b6133b4565b6003546001600160a01b031633146114045760405162461bcd60e51b8152600401610b18906152bd565b61140d8a613406565b61141689613406565b61141f88613406565b61142887613406565b61143186613406565b61143a85613406565b61144384613406565b61144c83613406565b61145582613406565b61145e81613406565b600480546001600160a01b03199081166001600160a01b038d8116919091179092556000805482168c84161790556001805482168b84161790556005805482168a8416179055600680548216898416179055600780548216888416179055600280548216878416179055600880548216868416179055600a80548216858416179055600980549091169183169190911790556040517f3ca631ffcd2a9b5d9ae18543fc82f58eb4ca33af9e6ab01b7a8e95331e6ed98590611520908c90614e03565b60405180910390a17f78f058b189175430c48dc02699e3a0031ea4ff781536dc2fab847de4babdd882896040516115579190614e03565b60405180910390a17f5ee0cae2f063ed938bb55046f6a932fb6ae792bf43624806bb90abe68a50be9b8860405161158e9190614e03565b60405180910390a17f82966d27eea39b038ee0fa30cd16532bb24f6e65d31cb58fb227aa5766cdcc7f876040516115c59190614e03565b60405180910390a17fcfb07d791fcafc032b35837b50eb84b74df518cf4cc287e8084f47630fa70fa0866040516115fc9190614e03565b60405180910390a17fe67f36a6e961157d6eff83b91f3af5a62131ceb6f04954ef74f51c1c05e7f88d856040516116339190614e03565b60405180910390a17f8c537274438aa850a330284665d81a85dd38267d09e4050d416bfc94142db2648460405161166a9190614e03565b60405180910390a17fe1e858a66c0bbbcdfa22d58dde1e5d42370be20cdb176e560287f85412e546e0836040516116a19190614e03565b60405180910390a17f65f4cf077bc01e4742eb5ad98326f6e95b63548ea24b17f8d5e823111fe78800826040516116d89190614e03565b60405180910390a17f38335c64466e2376ab931166337e19127650d842036ebe01da1ba3e5c1255ebb8160405161170f9190614e03565b60405180910390a161171f6134ab565b50505050505050505050565b6000611735612319565b6001600160a01b0383166000908152600d602052604081206001015461175c9084906152f2565b6001600160a01b0385166000908152600d6020526040902060010181905591505092915050565b6014818154811061179357600080fd5b6000918252602090912001546001600160a01b0316905081565b600080546040805163f07424e960e01b8152905183926001600160a01b03169163f07424e99160048083019260209291908290030181865afa1580156117f7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061181b91906151dc565b90506000600160009054906101000a90046001600160a01b03166001600160a01b031663f07424e96040518163ffffffff1660e01b8152600401602060405180830381865afa158015611872573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061189691906151dc565b90506118a281836152f2565b9250505090565b6118b1612319565b610a21816134f5565b6000805460408051631529a63960e01b8152905183926001600160a01b031691631529a6399160048083019260209291908290030181865afa158015611904573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061192891906151dc565b90506000600160009054906101000a90046001600160a01b03166001600160a01b0316631529a6396040518163ffffffff1660e01b8152600401602060405180830381865afa158015611872573d6000803e3d6000fd5b611987612319565b6001600160a01b0382166000908152600d60205260409020600301805482919060ff191660018360048111156119bf576119bf614f60565b02179055505050565b60006119d2612319565b6001600160a01b0383166000908152600d6020526040812054610a529084906152f2565b6001600160a01b0381166000908152601360205260408120600101546012548290610f3c9083906151c9565b6000806000611a3084613559565b915091506000611a4083836135d5565b95945050505050565b6000610a718261360b565b6001600160a01b0381166000908152600d602052604081208054600190910154909180611a80856119f6565b9150611a8b85610f13565b9050611a9782856152f2565b9350611aa381846152f2565b92509193509193565b6040805160e08082018352600080546001600160a01b03908116845260015481166020808601919091526008548216858701526009548216606080870191909152600a548316608080880191909152600754841660a08089019190915260065490941660c080890191909152885161010081018a5286815293840186905297830185905290820184905281018390529081018290529384018190529083015290611b5583613637565b600260009054906101000a90046001600160a01b03166001600160a01b0316630fdb11cf6040518163ffffffff1660e01b81526004016020604051808303816000875af1158015611baa573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bce91906151dc565b60c08201819052611bde906136d2565b611be789613745565b611bf68260400151338b6137ac565b611bfe6117ad565b60e0820152888152608082015160c0820151600091611c1e918b906138a7565b15611c2a575087611d3c565b82608001516001600160a01b0316634d6228316040518163ffffffff1660e01b8152600401602060405180830381865afa158015611c6c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c909190615305565b90505b6001600160a01b03811615801590611cbf5750670f43fc2c04ee0000611cbd828460c0015161216d565b105b15611d3c5782608001516001600160a01b031663b72703ac826040518263ffffffff1660e01b8152600401611cf49190614e03565b602060405180830381865afa158015611d11573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d359190615305565b9050611c93565b84600003611d4a5760001994505b6001600160a01b03811615801590611d625750815115155b8015611d6e5750600085115b15611e815784611d7d81615322565b955050600083608001516001600160a01b031663b72703ac836040518263ffffffff1660e01b8152600401611db29190614e03565b602060405180830381865afa158015611dcf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611df39190615305565b9050611e08846000015185602001518461239b565b6000611e21858486600001518760c001518e8e8e6139f1565b9050806040015115611e34575050611e81565b8051602085018051611e479083906152f2565b9052506020810151604085018051611e609083906152f2565b905250805184518590611e749083906151c9565b905250909150611d4a9050565b6000826040015111611ee75760405162461bcd60e51b815260206004820152602960248201527f54726f76654d616e616765723a20556e61626c6520746f2072656465656d20616044820152681b9e48185b5bdd5b9d60ba1b6064820152608401610b18565b611efe82604001518360c001518460e00151613c7f565b50611f0c8260400151613d22565b606083018190526040830151611f23919086613d2f565b825160608085015190840151604051636250216960e01b81526001600160a01b0390931692636250216992611f5c929091600401615237565b600060405180830381600087803b158015611f7657600080fd5b505af1158015611f8a573d6000803e3d6000fd5b50505060608301516040840151611fa192506151c9565b60808301526020820151604080840151606085015191517f43a3f4082a4dbc33d78e317d2497d3a730bc7fc3574159dcea1056e62e5d9ad893611ffd938f93919293845260208401929092526040830152606082015260800190565b60405180910390a182604001516001600160a01b0316639dc29fac3384602001516040518363ffffffff1660e01b815260040161203b929190615237565b600060405180830381600087803b15801561205557600080fd5b505af1158015612069573d6000803e3d6000fd5b505084516020850151604051637b7fc9eb60e11b81526001600160a01b03909216935063f6ff93d692506120a39160040190815260200190565b600060405180830381600087803b1580156120bd57600080fd5b505af11580156120d1573d6000803e3d6000fd5b505084516080850151604051636250216960e01b81526001600160a01b0390921693506362502169925061210a91339190600401615237565b600060405180830381600087803b15801561212457600080fd5b505af1158015612138573d6000803e3d6000fd5b5050505050505050505050505050565b6000610e8f612155612e57565b612d5d565b612162612319565b610a21816002613da0565b600080600061217b85613559565b915091506000610fc4838387613f47565b6000612196612319565b6001600160a01b0383166000908152600d602052604081206001015461175c9084906151c9565b6000610a716121ca612148565b83613f78565b6000601482815481106121e5576121e5615291565b6000918252602090912001546001600160a01b031692915050565b600060016001600160a01b0383166000908152600d602052604090206003015460ff16600481111561223457612234614f60565b1461224157506000919050565b506011546001600160a01b039091166000908152601360205260409020541090565b6003546001600160a01b0316331461228d5760405162461bcd60e51b8152600401610b18906152bd565b6001600160a01b0381166122f25760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610b18565b610a2181614008565b6000610e8f600b546133b4565b612310612319565b610a218161405a565b6004546001600160a01b031633146123995760405162461bcd60e51b815260206004820152603b60248201527f54726f76654d616e616765723a2043616c6c6572206973206e6f74207468652060448201527f426f72726f7765724f7065726174696f6e7320636f6e747261637400000000006064820152608401610b18565b565b6123a481612200565b15612492576123b281612d9a565b60006123bd82610f13565b905060006123ca836119f6565b6001600160a01b0384166000908152600d60205260408120600101805492935084929091906123fa9084906152f2565b90915550506001600160a01b0383166000908152600d6020526040812080548392906124279084906152f2565b909155506124369050836134f5565b612442858583856140ac565b6001600160a01b0383166000818152600d602052604080822080546001820154600290920154925160008051602061540c833981519152946124879492939291615349565b60405180910390a250505b505050565b601480546001808201835560008381527fce6d7b5282bd9a3661ae061feed1dbda4e52ab073b1f9285be6e155d9c38d4ec90920180546001600160a01b0319166001600160a01b038616179055915490916124f1916151c9565b6001600160a01b03929092166000908152600d602052604090206003018054610100600160881b0319166101006001600160801b038516021790555090565b6001600160a01b0381166000908152600d602052604081206001015481906125579061418d565b6001600160a01b0384166000908152600d60205260409020600201805490829055600e5491925090829061258c9083906151c9565b61259691906152f2565b600e8190556040519081527f6bac5e0eb3c44eb03a60ab11ec3a2c051771616aecadbcfff2630aabae5203829060200160405180910390a15092915050565b6000806125e18361360b565b6714d1120d7b160000119392505050565b6125fa614d6f565b612602614dbb565b61260a614d6f565b8482526000608083015261261c6117ad565b60a08301526126296118ba565b60c0830152600060208301525b83518260200151101561281c578382602001518151811061265957612659615291565b6020908102919091018101516001600160a01b0316606084018190526000908152600d909152604090206003015460019060ff16600481111561269e5761269e614f60565b03612804576126b182606001518761216d565b604083015260808201516127a757670f43fc2c04ee00008260400151101580156126da57508151155b6128045760006126f38360c001518460a0015189613f47565b90506127108989856060015186604001518760000151868d6141c3565b915081608001518360000181815161272891906151c9565b905250608082015160a0840180516127419083906151c9565b905250610100820151604083015160a084015161275e91906152f2565b61276891906152f2565b8360c00181815161277991906151c9565b90525061278684836144be565b935061279b8360c001518460a00151896145a8565b15608084015250612804565b816080015180156127c35750670f43fc2c04ee00008260400151105b15612804576127dc8888846060015185600001516145c9565b90508060800151826000018181516127f491906151c9565b90525061280183826144be565b92505b602082018051906128148261536b565b905250612636565b505095945050505050565b61282f614d6f565b612837614dbb565b61283f614d6f565b848252600060208301525b83518260200151101561281c578382602001518151811061286d5761286d615291565b60209081029190910101516001600160a01b031660608301819052612892908761216d565b60408301819052670f43fc2c04ee000011156128e4576128bc8888846060015185600001516145c9565b90508060800151826000018181516128d491906151c9565b9052506128e183826144be565b92505b602082018051906128f48261536b565b90525061284a565b8115612b355760155460009061291a670de0b6b3a76400008461527a565b61292491906152f2565b90506000601654670de0b6b3a76400008561293f919061527a565b61294991906152f2565b90506000600e548361295b9190615266565b90506000600e548361296d9190615266565b9050600e548261297d919061527a565b61298790856151c9565b601555600e54612997908261527a565b6129a190846151c9565b60168190555081601160008282546129b991906152f2565b9250508190555080601260008282546129d291906152f2565b90915550506011546012546040517f9f8bc8ab0daf5bceef75ecfd2085d1fcc6548c657ea970d9a23a60610d0737e392612a1492908252602082015260400190565b60405180910390a1604051637b7fc9eb60e11b8152600481018790526001600160a01b0389169063f6ff93d690602401600060405180830381600087803b158015612a5e57600080fd5b505af1158015612a72573d6000803e3d6000fd5b50506040516342c31a2360e01b8152600481018990526001600160a01b038a1692506342c31a239150602401600060405180830381600087803b158015612ab857600080fd5b505af1158015612acc573d6000803e3d6000fd5b5050604051636250216960e01b81526001600160a01b038b16925063625021699150612afe908a908990600401615237565b600060405180830381600087803b158015612b1857600080fd5b505af1158015612b2c573d6000803e3d6000fd5b50505050505050505b50505050565b600e54600f819055506000826001600160a01b0316631529a6396040518163ffffffff1660e01b8152600401602060405180830381865afa158015612b84573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ba891906151dc565b90506000600160009054906101000a90046001600160a01b03166001600160a01b0316631529a6396040518163ffffffff1660e01b8152600401602060405180830381865afa158015612bff573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c2391906151dc565b905080612c3084846151c9565b612c3a91906152f2565b6010819055600f546040517f51bf4c63ec3cba9d03d43238abbdd979dd91bd16d9895c74ceea9118c7baaf6092612c78928252602082015260400190565b60405180910390a150505050565b8115612cf1576006546040516316268b0d60e21b81526001600160a01b039091169063589a2c3490612cbe9086908690600401615237565b600060405180830381600087803b158015612cd857600080fd5b505af1158015612cec573d6000803e3d6000fd5b505050505b8015612b3557604051636250216960e01b81526001600160a01b03851690636250216990612d259086908590600401615237565b600060405180830381600087803b158015612d3f57600080fd5b505af1158015612d53573d6000803e3d6000fd5b5050505050505050565b6000610a7182612d776103e8670de0b6b3a7640000615266565b612d8290600561527a565b612d8c91906152f2565b670de0b6b3a7640000614710565b60016001600160a01b0382166000908152600d602052604090206003015460ff166004811115612dcc57612dcc614f60565b14610a215760405162461bcd60e51b815260206004820152602f60248201527f54726f76654d616e616765723a2054726f766520646f6573206e6f742065786960448201526e1cdd081bdc881a5cc818db1bdcd959608a1b6064820152608401610b18565b6000670de0b6b3a7640000612e46838561527a565b612e509190615266565b9392505050565b600080612e62614726565b90506000612e78670ddd4b8c6c7d70d883614742565b9050670de0b6b3a764000081600b54612e91919061527a565b6118a29190615266565b6000600c5442612eab91906151c9565b9050603c8110610a215742600c8190556040519081527f860f8d2f0c74dd487e89e2883e3b25b8159ce1e1b3433a291cba7b82c508f3bc906020015b60405180910390a150565b612efa614d6f565b612f02614dbb565b612f0a614d6f565b84825260006080830152612f1c6117ad565b60a0830152612f296118ba565b8260c001818152505086608001516001600160a01b0316634d6228316040518163ffffffff1660e01b8152600401602060405180830381865afa158015612f74573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f989190615305565b82606001906001600160a01b031690816001600160a01b031681525050600087608001516001600160a01b0316631e2231436040518163ffffffff1660e01b8152600401602060405180830381865afa158015612ff9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061301d9190615305565b6000602085015290505b8483602001511080156130505750806001600160a01b031683606001516001600160a01b031614155b156132735760808801516060840151604051632dc9c0eb60e21b81526000926001600160a01b03169163b72703ac9161308c9190600401614e03565b602060405180830381865afa1580156130a9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130cd9190615305565b90506130dd84606001518961216d565b604085015260808401516131de57670f43fc2c04ee000084604001511015801561310657508351155b156131115750613273565b60006131268560c001518660a001518b613f47565b8a5160208c015160608801516040890151895194955061314794868f6141c3565b935083608001518560000181815161315f91906151c9565b905250608084015160a0860180516131789083906151c9565b905250610100840151604085015160a086015161319591906152f2565b61319f91906152f2565b8560c0018181516131b091906151c9565b9052506131bd86856144be565b95506131d28560c001518660a001518b6145a8565b1560808601525061324d565b836080015180156131fa5750670f43fc2c04ee00008460400151105b156132475761321b89600001518a60200151866060015187600001516145c9565b925082608001518460000181815161323391906151c9565b90525061324085846144be565b945061324d565b50613273565b6001600160a01b031660608401526020830180519061326b8261536b565b905250613027565b505050949350505050565b613286614d6f565b61328e614dbb565b613296614d6f565b600a54858352600060208401526001600160a01b03165b84836020015110156133a857806001600160a01b0316634d6228316040518163ffffffff1660e01b8152600401602060405180830381865afa1580156132f7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061331b9190615305565b6001600160a01b031660608401819052613335908861216d565b60408401819052670f43fc2c04ee0000111561338b5761335f8989856060015186600001516145c9565b915081608001518360000181815161337791906151c9565b90525061338484836144be565b9350613390565b6133a8565b602083018051906133a08261536b565b9052506132ad565b50505095945050505050565b6000610a71826133ce6103e8670de0b6b3a7640000615266565b6133d990600561527a565b6133e391906152f2565b6133f66064670de0b6b3a7640000615266565b61340190600561527a565b614710565b6001600160a01b03811661345c5760405162461bcd60e51b815260206004820152601e60248201527f4163636f756e742063616e6e6f74206265207a65726f206164647265737300006044820152606401610b18565b803b80610efc5760405162461bcd60e51b815260206004820181905260248201527f4163636f756e7420636f64652073697a652063616e6e6f74206265207a65726f6044820152606401610b18565b6003546040516000916001600160a01b0316907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a3600380546001600160a01b0319169055565b601180546001600160a01b038316600090815260136020526040908190209182556012546001909201829055915491517fc437f324d85e369394148dd9d62f98f534b382e01ed3dd2eb98138fb6d3ab49a92612ee792908252602082015260400190565b600080600061356784610f13565b90506000613574856119f6565b6001600160a01b0386166000908152600d60205260408120600101549192509061359f9084906152f2565b6001600160a01b0387166000908152600d6020526040812054919250906135c79084906152f2565b919791965090945050505050565b6000811561360257816135f168056bc75e2d631000008561527a565b6135fb9190615266565b9050610a71565b50600019610a71565b6000806136166118ba565b905060006136226117ad565b905061362f828286613f47565b949350505050565b61364b6103e8670de0b6b3a7640000615266565b61365690600561527a565b811015801561366d5750670de0b6b3a76400008111155b610a215760405162461bcd60e51b815260206004820152603060248201527f4d6178206665652070657263656e74616765206d75737420626520626574776560448201526f656e20302e352520616e64203130302560801b6064820152608401610b18565b670f43fc2c04ee00006136e48261360b565b1015610a215760405162461bcd60e51b815260206004820152602a60248201527f54726f76654d616e616765723a2043616e6e6f742072656465656d207768656e604482015269102a21a9101e1026a1a960b11b6064820152608401610b18565b60008111610a215760405162461bcd60e51b815260206004820152602e60248201527f54726f76654d616e616765723a20416d6f756e74206d7573742062652067726560448201526d61746572207468616e207a65726f60901b6064820152608401610b18565b6040516370a0823160e01b815281906001600160a01b038516906370a08231906137da908690600401614e03565b602060405180830381865afa1580156137f7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061381b91906151dc565b10156124925760405162461bcd60e51b815260206004820152604f60248201527f54726f76654d616e616765723a2052657175657374656420726564656d70746960448201527f6f6e20616d6f756e74206d757374206265203c3d20757365722773205448555360648201526e4420746f6b656e2062616c616e636560881b608482015260a401610b18565b60006001600160a01b03831615806139295750604051630bb7c8fd60e31b81526001600160a01b03851690635dbe47e8906138e6908690600401614e03565b602060405180830381865afa158015613903573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906139279190615384565b155b806139445750670f43fc2c04ee0000613942848461216d565b105b1561395157506000612e50565b60405163765e015960e01b81526000906001600160a01b0386169063765e015990613980908790600401614e03565b602060405180830381865afa15801561399d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906139c19190615305565b90506001600160a01b0381161580611a405750670f43fc2c04ee00006139e7828561216d565b1095945050505050565b613a17604051806060016040528060008152602001600081526020016000151581525090565b6001600160a01b0387166000908152600d6020526040902054613a4a90879061340190680ad78ebc5ac6200000906151c9565b8082528590613a6290670de0b6b3a76400009061527a565b613a6c9190615266565b60208083019190915281516001600160a01b0389166000908152600d9092526040822054613a9a91906151c9565b6020808401516001600160a01b038b166000908152600d90925260408220600101549293509091613acb91906151c9565b9050680ad78ebc5ac62000008203613b4357613ae68961405a565b613af1896004613da0565b613b068a8a680ad78ebc5ac6200000846147ed565b886001600160a01b031660008051602061540c83398151915260008060006003604051613b369493929190615349565b60405180910390a2613c71565b6000613b4f82846135d5565b90508481141580613b705750686194049f30f7200000613b6e8461494c565b105b15613b845750506001604083015250613c74565b60808b015160405163015f109360e51b81526001600160a01b038c81166004830152602482018490528981166044830152888116606483015290911690632be2126090608401600060405180830381600087803b158015613be457600080fd5b505af1158015613bf8573d6000803e3d6000fd5b5050506001600160a01b038b166000908152600d6020526040902084815560010183905550613c268a612530565b506001600160a01b038a166000818152600d60205260409081902060020154905160008051602061540c83398151915291613c679187918791600390615349565b60405180910390a2505b50505b979650505050505050565b600080613c8a612e57565b9050600083613c99868861527a565b613ca39190615266565b90506000613cb2600283615266565b613cbc90846152f2565b9050613cd081670de0b6b3a7640000614710565b905060008111613ce257613ce26152a7565b600b8190556040518181527fc454ee9b76c52f782a256af821b857ca6e125d1e3333bcede402fec2bed9600c9060200160405180910390a1610fc4612e9b565b6000610a716121ca610e82565b600082613d44670de0b6b3a76400008661527a565b613d4e9190615266565b905081811115612b355760405162461bcd60e51b815260206004820152601d60248201527f4665652065786365656465642070726f7669646564206d6178696d756d0000006044820152606401610b18565b6000816004811115613db457613db4614f60565b14158015613dd457506001816004811115613dd157613dd1614f60565b14155b613de057613de06152a7565b60145460085460048054604051635f7a196360e11b81526001600160a01b039384169363bef432c693613e17939091169101614e03565b602060405180830381865afa158015613e34573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613e589190615384565b15613e6657613e6681614961565b6001600160a01b0383166000908152600d60205260409020600301805483919060ff19166001836004811115613e9e57613e9e614f60565b02179055506001600160a01b0383166000908152600d60209081526040808320600180820185905590849055601390925282208281550155613ee08382614a3b565b600a54604051631484968760e11b81526001600160a01b03909116906329092d0e90613f10908690600401614e03565b600060405180830381600087803b158015613f2a57600080fd5b505af1158015613f3e573d6000803e3d6000fd5b50505050505050565b60008215613f6f57600083613f5c848761527a565b613f669190615266565b9150612e509050565b50600019612e50565b600080670de0b6b3a7640000613f8e848661527a565b613f989190615266565b9050828110612e505760405162461bcd60e51b815260206004820152603660248201527f54726f76654d616e616765723a2046656520776f756c642065617420757020616044820152751b1b081c995d1d5c9b99590818dbdb1b185d195c985b60521b6064820152608401610b18565b600380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6001600160a01b0381166000908152600d6020526040812060020154600e8054919283926140899084906151c9565b9091555050506001600160a01b03166000908152600d6020526040812060020155565b604051637b7fc9eb60e11b8152600481018390526001600160a01b0384169063f6ff93d690602401600060405180830381600087803b1580156140ee57600080fd5b505af1158015614102573d6000803e3d6000fd5b50506040516342c31a2360e01b8152600481018590526001600160a01b03871692506342c31a239150602401600060405180830381600087803b15801561414857600080fd5b505af115801561415c573d6000803e3d6000fd5b5050604051633ef8ba8160e11b8152600481018490526001600160a01b0386169250637df175029150602401612d25565b6000806010546000036141a1575081610a71565b6000600f54116141b3576141b36152a7565b601054600f54612e46908561527a565b6141cb614d6f565b6141ef60405180606001604052806000815260200160008152602001600081525090565b6014546001106141ff5750613c74565b61420887611a54565b6040850152602084810191909152840181905290835261422790614c0b565b60408301819052680ad78ebc5ac62000006060840152602083015161424c91906151c9565b8152670de0b6b3a76400008611614317576142718989836020015184604001516140ac565b61427a8761405a565b60006080830181905260a0830152815160c0830152805160e08301526142a1876003613da0565b815160208301516040516001600160a01b038a16926000805160206153ec833981519152926142d2926002906153a6565b60405180910390a2866001600160a01b031660008051602061540c8339815191526000806000600260405161430a9493929190615349565b60405180910390a26144b2565b670de0b6b3a7640000861180156143355750670f43fc2c04ee000086105b156143855761434e8989836020015184604001516140ac565b6143578761405a565b81518151614366919087614c18565b60e086015260c085015260a084015260808301526142a1876003613da0565b670f43fc2c04ee0000861015801561439c57508386105b80156143a9575081518510155b156144a1576143c28989836020015184604001516140ac565b846000036143d2576143d26152a7565b6143db8761405a565b6143ee8260000151836020015185614c79565b91506143fb876003613da0565b6101008201511561447057600754610100830151604051633f10abab60e01b81526001600160a01b0390921691633f10abab9161443d918b9190600401615237565b600060405180830381600087803b15801561445757600080fd5b505af115801561446b573d6000803e3d6000fd5b505050505b815160a08301516040516001600160a01b038a16926000805160206153ec833981519152926142d2926002906153a6565b6144a9614d6f565b9150613c749050565b50979650505050505050565b6144c6614d6f565b816040015183604001516144da91906152f2565b6040820152606080830151908401516144f391906152f2565b60608201528151602084015161450991906152f2565b602080830191909152820151835161452191906152f2565b81526080808301519084015161453791906152f2565b608082015260a0808301519084015161455091906152f2565b60a082015260c0808301519084015161456991906152f2565b60c082015260e0808301519084015161458291906152f2565b60e0820152610100808301519084015161459c91906152f2565b61010082015292915050565b6000806145b6858585613f47565b6714d1120d7b1600001195945050505050565b6145d1614d6f565b6145f560405180606001604052806000815260200160008152602001600081525090565b6145fe84611a54565b604085019081526020858101928352860192909252918452905190516146289188918891906140ac565b6146318461405a565b61463e8260200151614c0b565b60408301819052680ad78ebc5ac620000060608401526020830151600091614665916151c9565b905061467683600001518286614c18565b60e087015260c086015260a08501526080840152614695856003613da0565b825160208401516040516001600160a01b038816926000805160206153ec833981519152926146c6926001906153a6565b60405180910390a2846001600160a01b031660008051602061540c833981519152600080600060016040516146fe9493929190615349565b60405180910390a25050949350505050565b600081831061471f5781612e50565b5090919050565b6000603c600c544261473891906151c9565b610e8f9190615266565b6000631f54050082111561475857631f54050091505b8160000361476f5750670de0b6b3a7640000610a71565b670de0b6b3a764000083835b60018111156147e35761478f6002826153c1565b6000036147b4576147a08283614d07565b91506147ad600282615266565b905061477b565b6147be8284614d07565b92506147ca8283614d07565b915060026147d96001836151c9565b6147ad9190615266565b610fc48284614d07565b6040808501516006549151632770a7eb60e21b81526001600160a01b0391821692639dc29fac92614825929116908690600401615237565b600060405180830381600087803b15801561483f57600080fd5b505af1158015614853573d6000803e3d6000fd5b50508551604051637b7fc9eb60e11b8152600481018690526001600160a01b03909116925063f6ff93d69150602401600060405180830381600087803b15801561489c57600080fd5b505af11580156148b0573d6000803e3d6000fd5b505050508360a001516001600160a01b0316633f10abab84836040518363ffffffff1660e01b81526004016148e6929190615237565b600060405180830381600087803b15801561490057600080fd5b505af1158015614914573d6000803e3d6000fd5b5050855160a0870151604051636250216960e01b81526001600160a01b03909216935063625021699250612d25918590600401615237565b6000610a71680ad78ebc5ac6200000836151c9565b6001811180156149dc5750600a546040805163de8fa43160e01b815290516001926001600160a01b03169163de8fa4319160048083019260209291908290030181865afa1580156149b6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906149da91906151dc565b115b610a215760405162461bcd60e51b815260206004820152602a60248201527f54726f76654d616e616765723a204f6e6c79206f6e652074726f766520696e206044820152697468652073797374656d60b01b6064820152608401610b18565b6001600160a01b0382166000908152600d602052604081206003015460ff1690816004811115614a6d57614a6d614f60565b14158015614a8d57506001816004811115614a8a57614a8a614f60565b14155b614a9957614a996152a7565b6001600160a01b0383166000908152600d602052604081206003015461010090046001600160801b0316908390614ad16001836151c9565b905080836001600160801b03161115614aec57614aec6152a7565b600060148281548110614b0157614b01615291565b600091825260209091200154601480546001600160a01b03909216925082916001600160801b038716908110614b3957614b39615291565b600091825260208083209190910180546001600160a01b0319166001600160a01b03948516179055918316808252600d83526040918290206003018054610100600160881b0319166101006001600160801b038a16908102919091179091558251918252928101929092527f02b04ae5f7be9ca7c103293a2aa15f3c339d15d6eda53b721fef7b0e609c831a910160405180910390a16014805480614be057614be06153d5565b600082815260209020810160001990810180546001600160a01b031916905501905550505050505050565b6000610a7160c883615266565b60008080808415614c6357614c2d8786614710565b935086614c3a858861527a565b614c449190615266565b9250614c5084886151c9565b9150614c5c83876151c9565b9050614c70565b5060009250829150859050845b93509350935093565b614c81614d6f565b83815260208101839052600082614ca0670f43fc2c04ee00008761527a565b614caa9190615266565b9050614cb581614c0b565b60408301819052680ad78ebc5ac6200000606084015260808301869052614cdc90826151c9565b60a0830152614ceb81856151c9565b61010083015250600060c0820181905260e08201529392505050565b600080614d14838561527a565b9050670de0b6b3a7640000614d2a600282615266565b614d3490836152f2565b61362f9190615266565b6040518060a00160405280600081526020016000815260200160001515815260200160008152602001600081525090565b6040518061012001604052806000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b6040518060e0016040528060008152602001600081526020016000815260200160006001600160a01b0316815260200160001515815260200160008152602001600081525090565b6001600160a01b0391909116815260200190565b6001600160a01b0381168114610a2157600080fd5b8035614e3781614e17565b919050565b600060208284031215614e4e57600080fd5b8135612e5081614e17565b60008060408385031215614e6c57600080fd5b8235614e7781614e17565b946020939093013593505050565b634e487b7160e01b600052604160045260246000fd5b60006020808385031215614eae57600080fd5b823567ffffffffffffffff80821115614ec657600080fd5b818501915085601f830112614eda57600080fd5b813581811115614eec57614eec614e85565b8060051b604051601f19603f83011681018181108582111715614f1157614f11614e85565b604052918252848201925083810185019188831115614f2f57600080fd5b938501935b82851015614f5457614f4585614e2c565b84529385019392850192614f34565b98975050505050505050565b634e487b7160e01b600052602160045260246000fd5b60058110614f8657614f86614f60565b9052565b60208101610a718284614f76565b600060208284031215614faa57600080fd5b5035919050565b6000806000806000806000806000806101408b8d031215614fd157600080fd5b8a35614fdc81614e17565b995060208b0135614fec81614e17565b985060408b0135614ffc81614e17565b975060608b013561500c81614e17565b965060808b013561501c81614e17565b955060a08b013561502c81614e17565b945060c08b013561503c81614e17565b935060e08b013561504c81614e17565b92506101008b013561505d81614e17565b915061506c6101208c01614e2c565b90509295989b9194979a5092959850565b858152602081018590526040810184905260a0810161509f6060830185614f76565b6001600160801b039290921660809190910152949350505050565b600080604083850312156150cd57600080fd5b82356150d881614e17565b91506020830135600581106150ec57600080fd5b809150509250929050565b600060208083528351808285015260005b8181101561512457858101830151858201604001528201615108565b506000604082860101526040601f19601f8301168501019250505092915050565b600080600080600080600060e0888a03121561516057600080fd5b87359650602088013561517281614e17565b9550604088013561518281614e17565b9450606088013561519281614e17565b9699959850939660808101359560a0820135955060c0909101359350915050565b634e487b7160e01b600052601160045260246000fd5b81810381811115610a7157610a716151b3565b6000602082840312156151ee57600080fd5b5051919050565b60208082526022908201527f54726f76654d616e616765723a206e6f7468696e6720746f206c697175696461604082015261746560f01b606082015260800190565b6001600160a01b03929092168252602082015260400190565b634e487b7160e01b600052601260045260246000fd5b60008261527557615275615250565b500490565b8082028115828204841417610a7157610a716151b3565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052600160045260246000fd5b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b80820180821115610a7157610a716151b3565b60006020828403121561531757600080fd5b8151612e5081614e17565b600081615331576153316151b3565b506000190190565b60048110614f8657614f86614f60565b848152602081018490526040810183905260808101611a406060830184615339565b60006001820161537d5761537d6151b3565b5060010190565b60006020828403121561539657600080fd5b81518015158114612e5057600080fd5b838152602081018390526060810161362f6040830184615339565b6000826153d0576153d0615250565b500690565b634e487b7160e01b600052603160045260246000fdfeea67486ed7ebe3eea8ab3390efd4a3c8aae48be5bea27df104a8af786c408434c3770d654ed33aeea6bf11ac8ef05d02a6a04ed4686dd2f624d853bbec43cc8ba26469706673582212202d04ada939169bc7aa7216586e65c2ce4e3fc480b31b737556f319a5eca7f7f364736f6c63430008110033
Verified Source Code Full Match
Compiler: v0.8.17+commit.8df45f5f
EVM: london
Optimization: Yes (100 runs)
TroveManager.sol 1512 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
import "./Interfaces/ITroveManager.sol";
import "./Interfaces/IStabilityPool.sol";
import "./Interfaces/ICollSurplusPool.sol";
import "./Interfaces/IGasPool.sol";
import "./Interfaces/ITHUSDToken.sol";
import "./Interfaces/ISortedTroves.sol";
import "./Interfaces/IPCV.sol";
import "./Dependencies/LiquityBase.sol";
import "./Dependencies/Ownable.sol";
import "./Dependencies/CheckContract.sol";
contract TroveManager is LiquityBase, Ownable, CheckContract, ITroveManager {
string constant public NAME = "TroveManager";
// --- Connected contract declarations ---
address public borrowerOperationsAddress;
IStabilityPool public override stabilityPool;
address gasPoolAddress;
ICollSurplusPool collSurplusPool;
ITHUSDToken public override thusdToken;
IPCV public override pcv;
// A doubly linked list of Troves, sorted by their sorted by their collateral ratios
ISortedTroves public sortedTroves;
// --- Data structures ---
/*
* Half-life of 12h. 12h = 720 min
* (1/2) = d^720 => d = (1/2)^(1/720)
*/
uint256 constant public MINUTE_DECAY_FACTOR = 999037758833783000;
uint256 constant public REDEMPTION_FEE_FLOOR = DECIMAL_PRECISION / 1000 * 5; // 0.5%
uint256 constant public MAX_BORROWING_FEE = DECIMAL_PRECISION / 100 * 5; // 5%
/*
* BETA: 18 digit decimal. Parameter by which to divide the redeemed fraction, in order to calc the new base rate from a redemption.
* Corresponds to (1 / ALPHA) in the white paper.
*/
uint256 constant public BETA = 2;
uint256 public baseRate;
// The timestamp of the latest fee operation (redemption or new THUSD issuance)
uint256 public lastFeeOperationTime;
// Store the necessary data for a trove
struct Trove {
uint256 debt;
uint256 coll;
uint256 stake;
Status status;
uint128 arrayIndex;
}
mapping (address => Trove) public Troves;
uint256 public totalStakes;
// Snapshot of the value of totalStakes, taken immediately after the latest liquidation
uint256 public totalStakesSnapshot;
// Snapshot of the total collateral across the ActivePool and DefaultPool, immediately after the latest liquidation.
uint256 public totalCollateralSnapshot;
/*
* L_Collateral and L_THUSDDebt track the sums of accumulated liquidation rewards per unit staked. During its lifetime, each stake earns:
*
* An collateral gain of ( stake * [L_Collateral - L_Collateral(0)] )
* A THUSDDebt increase of ( stake * [L_THUSDDebt - L_THUSDDebt(0)] )
*
* Where L_Collateral(0) and L_THUSDDebt(0) are snapshots of L_Collateral and L_THUSDDebt for the active Trove taken at the instant the stake was made
*/
uint256 public L_Collateral;
uint256 public L_THUSDDebt;
// Map addresses with active troves to their RewardSnapshot
mapping (address => RewardSnapshot) public rewardSnapshots;
// Object containing the collateral and THUSD snapshots for a given active trove
struct RewardSnapshot { uint256 collateral; uint256 THUSDDebt;}
// Array of all active trove addresses - used to to compute an approximate hint off-chain, for the sorted list insertion
address[] public TroveOwners;
// Error trackers for the trove redistribution calculation
uint256 public lastCollateralError_Redistribution;
uint256 public lastTHUSDDebtError_Redistribution;
/*
* --- Variable container structs for liquidations ---
*
* These structs are used to hold, return and assign variables inside the liquidation functions,
* in order to avoid the error: "CompilerError: Stack too deep".
**/
struct LocalVariables_OuterLiquidationFunction {
uint256 price;
uint256 THUSDInStabPool;
bool recoveryModeAtStart;
uint256 liquidatedDebt;
uint256 liquidatedColl;
}
struct LocalVariables_InnerSingleLiquidateFunction {
uint256 collToLiquidate;
uint256 pendingDebtReward;
uint256 pendingCollReward;
}
struct LocalVariables_LiquidationSequence {
uint256 remainingTHUSDInStabPool;
uint256 i;
uint256 ICR;
address user;
bool backToNormalMode;
uint256 entireSystemDebt;
uint256 entireSystemColl;
}
struct LiquidationValues {
uint256 entireTroveDebt;
uint256 entireTroveColl;
uint256 collGasCompensation;
uint256 THUSDGasCompensation;
uint256 debtToOffset;
uint256 collToSendToSP;
uint256 debtToRedistribute;
uint256 collToRedistribute;
uint256 collSurplus;
}
struct LiquidationTotals {
uint256 totalCollInSequence;
uint256 totalDebtInSequence;
uint256 totalCollGasCompensation;
uint256 totalTHUSDGasCompensation;
uint256 totalDebtToOffset;
uint256 totalCollToSendToSP;
uint256 totalDebtToRedistribute;
uint256 totalCollToRedistribute;
uint256 totalCollSurplus;
}
struct ContractsCache {
IActivePool activePool;
IDefaultPool defaultPool;
ITHUSDToken thusdToken;
IPCV pcv;
ISortedTroves sortedTroves;
ICollSurplusPool collSurplusPool;
address gasPoolAddress;
}
// --- Variable container structs for redemptions ---
struct RedemptionTotals {
uint256 remainingTHUSD;
uint256 totalTHUSDToRedeem;
uint256 totalCollateralDrawn;
uint256 collateralFee;
uint256 collateralToSendToRedeemer;
uint256 decayedBaseRate;
uint256 price;
uint256 totalTHUSDDebtAtStart;
}
struct SingleRedemptionValues {
uint256 THUSDLot;
uint256 collateralLot;
bool cancelledPartial;
}
// --- Events ---
event TroveUpdated(address indexed _borrower, uint256 _debt, uint256 _coll, uint256 _stake, TroveManagerOperation _operation);
event TroveLiquidated(address indexed _borrower, uint256 _debt, uint256 _coll, TroveManagerOperation _operation);
enum TroveManagerOperation {
applyPendingRewards,
liquidateInNormalMode,
liquidateInRecoveryMode,
redeemCollateral
}
// --- Dependency setter ---
function setAddresses(
address _borrowerOperationsAddress,
address _activePoolAddress,
address _defaultPoolAddress,
address _stabilityPoolAddress,
address _gasPoolAddress,
address _collSurplusPoolAddress,
address _priceFeedAddress,
address _thusdTokenAddress,
address _sortedTrovesAddress,
address _pcvAddress
)
external
override
onlyOwner
{
checkContract(_borrowerOperationsAddress);
checkContract(_activePoolAddress);
checkContract(_defaultPoolAddress);
checkContract(_stabilityPoolAddress);
checkContract(_gasPoolAddress);
checkContract(_collSurplusPoolAddress);
checkContract(_priceFeedAddress);
checkContract(_thusdTokenAddress);
checkContract(_sortedTrovesAddress);
checkContract(_pcvAddress);
borrowerOperationsAddress = _borrowerOperationsAddress;
activePool = IActivePool(_activePoolAddress);
defaultPool = IDefaultPool(_defaultPoolAddress);
stabilityPool = IStabilityPool(_stabilityPoolAddress);
gasPoolAddress = _gasPoolAddress;
collSurplusPool = ICollSurplusPool(_collSurplusPoolAddress);
priceFeed = IPriceFeed(_priceFeedAddress);
thusdToken = ITHUSDToken(_thusdTokenAddress);
sortedTroves = ISortedTroves(_sortedTrovesAddress);
pcv = IPCV(_pcvAddress);
emit BorrowerOperationsAddressChanged(_borrowerOperationsAddress);
emit ActivePoolAddressChanged(_activePoolAddress);
emit DefaultPoolAddressChanged(_defaultPoolAddress);
emit StabilityPoolAddressChanged(_stabilityPoolAddress);
emit GasPoolAddressChanged(_gasPoolAddress);
emit CollSurplusPoolAddressChanged(_collSurplusPoolAddress);
emit PriceFeedAddressChanged(_priceFeedAddress);
emit THUSDTokenAddressChanged(_thusdTokenAddress);
emit SortedTrovesAddressChanged(_sortedTrovesAddress);
emit PCVAddressChanged(_pcvAddress);
_renounceOwnership();
}
// --- Getters ---
function getTroveOwnersCount() external view override returns (uint) {
return TroveOwners.length;
}
function getTroveFromTroveOwnersArray(uint256 _index) external view override returns (address) {
return TroveOwners[_index];
}
// --- Trove Liquidation functions ---
// Single liquidation function. Closes the trove if its ICR is lower than the minimum collateral ratio.
function liquidate(address _borrower) external override {
_requireTroveIsActive(_borrower);
address[] memory borrowers = new address[](1);
borrowers[0] = _borrower;
batchLiquidateTroves(borrowers);
}
// --- Inner single liquidation functions ---
// Liquidate one trove, in Normal Mode.
function _liquidateNormalMode(
IActivePool _activePool,
IDefaultPool _defaultPool,
address _borrower,
uint256 _THUSDInStabPool
)
internal
returns (LiquidationValues memory singleLiquidation)
{
LocalVariables_InnerSingleLiquidateFunction memory vars;
(singleLiquidation.entireTroveDebt,
singleLiquidation.entireTroveColl,
vars.pendingDebtReward,
vars.pendingCollReward) = getEntireDebtAndColl(_borrower);
_movePendingTroveRewardsToActivePool(_activePool, _defaultPool, vars.pendingDebtReward, vars.pendingCollReward);
_removeStake(_borrower);
singleLiquidation.collGasCompensation = _getCollGasCompensation(singleLiquidation.entireTroveColl);
singleLiquidation.THUSDGasCompensation = THUSD_GAS_COMPENSATION;
uint256 collToLiquidate = singleLiquidation.entireTroveColl - singleLiquidation.collGasCompensation;
(singleLiquidation.debtToOffset,
singleLiquidation.collToSendToSP,
singleLiquidation.debtToRedistribute,
singleLiquidation.collToRedistribute) = _getOffsetAndRedistributionVals(singleLiquidation.entireTroveDebt, collToLiquidate, _THUSDInStabPool);
_closeTrove(_borrower, Status.closedByLiquidation);
emit TroveLiquidated(_borrower, singleLiquidation.entireTroveDebt, singleLiquidation.entireTroveColl, TroveManagerOperation.liquidateInNormalMode);
emit TroveUpdated(_borrower, 0, 0, 0, TroveManagerOperation.liquidateInNormalMode);
return singleLiquidation;
}
// Liquidate one trove, in Recovery Mode.
function _liquidateRecoveryMode(
IActivePool _activePool,
IDefaultPool _defaultPool,
address _borrower,
uint256 _ICR,
uint256 _THUSDInStabPool,
uint256 _TCR,
uint256 _price
)
internal
returns (LiquidationValues memory singleLiquidation)
{
LocalVariables_InnerSingleLiquidateFunction memory vars;
if (TroveOwners.length <= 1) {return singleLiquidation;} // don't liquidate if last trove
(singleLiquidation.entireTroveDebt,
singleLiquidation.entireTroveColl,
vars.pendingDebtReward,
vars.pendingCollReward) = getEntireDebtAndColl(_borrower);
singleLiquidation.collGasCompensation = _getCollGasCompensation(singleLiquidation.entireTroveColl);
singleLiquidation.THUSDGasCompensation = THUSD_GAS_COMPENSATION;
vars.collToLiquidate = singleLiquidation.entireTroveColl - singleLiquidation.collGasCompensation;
// If ICR <= 100%, purely redistribute the Trove across all active Troves
if (_ICR <= _100pct) {
_movePendingTroveRewardsToActivePool(_activePool, _defaultPool, vars.pendingDebtReward, vars.pendingCollReward);
_removeStake(_borrower);
singleLiquidation.debtToOffset = 0;
singleLiquidation.collToSendToSP = 0;
singleLiquidation.debtToRedistribute = singleLiquidation.entireTroveDebt;
singleLiquidation.collToRedistribute = vars.collToLiquidate;
_closeTrove(_borrower, Status.closedByLiquidation);
emit TroveLiquidated(_borrower, singleLiquidation.entireTroveDebt, singleLiquidation.entireTroveColl, TroveManagerOperation.liquidateInRecoveryMode);
emit TroveUpdated(_borrower, 0, 0, 0, TroveManagerOperation.liquidateInRecoveryMode);
// If 100% < ICR < MCR, offset as much as possible, and redistribute the remainder
} else if ((_ICR > _100pct) && (_ICR < MCR)) {
_movePendingTroveRewardsToActivePool(_activePool, _defaultPool, vars.pendingDebtReward, vars.pendingCollReward);
_removeStake(_borrower);
(singleLiquidation.debtToOffset,
singleLiquidation.collToSendToSP,
singleLiquidation.debtToRedistribute,
singleLiquidation.collToRedistribute) = _getOffsetAndRedistributionVals(singleLiquidation.entireTroveDebt, vars.collToLiquidate, _THUSDInStabPool);
_closeTrove(_borrower, Status.closedByLiquidation);
emit TroveLiquidated(_borrower, singleLiquidation.entireTroveDebt, singleLiquidation.entireTroveColl, TroveManagerOperation.liquidateInRecoveryMode);
emit TroveUpdated(_borrower, 0, 0, 0, TroveManagerOperation.liquidateInRecoveryMode);
/*
* If 110% <= ICR < current TCR (accounting for the preceding liquidations in the current sequence)
* and there is THUSD in the Stability Pool, only offset, with no redistribution,
* but at a capped rate of 1.1 and only if the whole debt can be liquidated.
* The remainder due to the capped rate will be claimable as collateral surplus.
*/
} else if ((_ICR >= MCR) && (_ICR < _TCR) && (singleLiquidation.entireTroveDebt <= _THUSDInStabPool)) {
_movePendingTroveRewardsToActivePool(_activePool, _defaultPool, vars.pendingDebtReward, vars.pendingCollReward);
assert(_THUSDInStabPool != 0);
_removeStake(_borrower);
singleLiquidation = _getCappedOffsetVals(singleLiquidation.entireTroveDebt, singleLiquidation.entireTroveColl, _price);
_closeTrove(_borrower, Status.closedByLiquidation);
if (singleLiquidation.collSurplus > 0) {
collSurplusPool.accountSurplus(_borrower, singleLiquidation.collSurplus);
}
emit TroveLiquidated(_borrower, singleLiquidation.entireTroveDebt, singleLiquidation.collToSendToSP, TroveManagerOperation.liquidateInRecoveryMode);
emit TroveUpdated(_borrower, 0, 0, 0, TroveManagerOperation.liquidateInRecoveryMode);
} else { // if (_ICR >= MCR && ( _ICR >= _TCR || singleLiquidation.entireTroveDebt > _THUSDInStabPool))
LiquidationValues memory zeroVals;
return zeroVals;
}
return singleLiquidation;
}
/* In a full liquidation, returns the values for a trove's coll and debt to be offset, and coll and debt to be
* redistributed to active troves.
*/
function _getOffsetAndRedistributionVals
(
uint256 _debt,
uint256 _coll,
uint256 _THUSDInStabPool
)
internal
pure
returns (uint256 debtToOffset, uint256 collToSendToSP, uint256 debtToRedistribute, uint256 collToRedistribute)
{
if (_THUSDInStabPool > 0) {
/*
* Offset as much debt & collateral as possible against the Stability Pool, and redistribute the remainder
* between all active troves.
*
* If the trove's debt is larger than the deposited THUSD in the Stability Pool:
*
* - Offset an amount of the trove's debt equal to the THUSD in the Stability Pool
* - Send a fraction of the trove's collateral to the Stability Pool, equal to the fraction of its offset debt
*
*/
debtToOffset = LiquityMath._min(_debt, _THUSDInStabPool);
collToSendToSP = _coll * debtToOffset / _debt;
debtToRedistribute = _debt - debtToOffset;
collToRedistribute = _coll - collToSendToSP;
} else {
debtToOffset = 0;
collToSendToSP = 0;
debtToRedistribute = _debt;
collToRedistribute = _coll;
}
}
/*
* Get its offset coll/debt and collateral gas comp, and close the trove.
*/
function _getCappedOffsetVals
(
uint256 _entireTroveDebt,
uint256 _entireTroveColl,
uint256 _price
)
internal
pure
returns (LiquidationValues memory singleLiquidation)
{
singleLiquidation.entireTroveDebt = _entireTroveDebt;
singleLiquidation.entireTroveColl = _entireTroveColl;
uint256 cappedCollPortion = _entireTroveDebt * MCR / _price;
singleLiquidation.collGasCompensation = _getCollGasCompensation(cappedCollPortion);
singleLiquidation.THUSDGasCompensation = THUSD_GAS_COMPENSATION;
singleLiquidation.debtToOffset = _entireTroveDebt;
singleLiquidation.collToSendToSP = cappedCollPortion - singleLiquidation.collGasCompensation;
singleLiquidation.collSurplus = _entireTroveColl - cappedCollPortion;
singleLiquidation.debtToRedistribute = 0;
singleLiquidation.collToRedistribute = 0;
}
/*
* Liquidate a sequence of troves. Closes a maximum number of n under-collateralized Troves,
* starting from the one with the lowest collateral ratio in the system, and moving upwards
*/
function liquidateTroves(uint256 _n) external override {
ContractsCache memory contractsCache = ContractsCache(
activePool,
defaultPool,
ITHUSDToken(address(0)),
IPCV(address(0)),
sortedTroves,
ICollSurplusPool(address(0)),
address(0)
);
IStabilityPool stabilityPoolCached = stabilityPool;
LocalVariables_OuterLiquidationFunction memory vars;
LiquidationTotals memory totals;
vars.price = priceFeed.fetchPrice();
vars.THUSDInStabPool = stabilityPoolCached.getTotalTHUSDDeposits();
vars.recoveryModeAtStart = _checkRecoveryMode(vars.price);
// Perform the appropriate liquidation sequence - tally the values, and obtain their totals
if (vars.recoveryModeAtStart) {
totals = _getTotalsFromLiquidateTrovesSequence_RecoveryMode(contractsCache, vars.price, vars.THUSDInStabPool, _n);
} else { // if !vars.recoveryModeAtStart
totals = _getTotalsFromLiquidateTrovesSequence_NormalMode(contractsCache.activePool, contractsCache.defaultPool, vars.price, vars.THUSDInStabPool, _n);
}
require(totals.totalDebtInSequence > 0, "TroveManager: nothing to liquidate");
// Move liquidated collateral and THUSD to the appropriate pools
stabilityPoolCached.offset(totals.totalDebtToOffset, totals.totalCollToSendToSP);
_redistributeDebtAndColl(contractsCache.activePool, contractsCache.defaultPool, totals.totalDebtToRedistribute, totals.totalCollToRedistribute);
if (totals.totalCollSurplus > 0) {
contractsCache.activePool.sendCollateral(address(collSurplusPool), totals.totalCollSurplus);
}
// Update system snapshots
_updateSystemSnapshots_excludeCollRemainder(contractsCache.activePool, totals.totalCollGasCompensation);
vars.liquidatedDebt = totals.totalDebtInSequence;
vars.liquidatedColl = totals.totalCollInSequence - totals.totalCollGasCompensation - totals.totalCollSurplus;
emit Liquidation(vars.liquidatedDebt, vars.liquidatedColl, totals.totalCollGasCompensation, totals.totalTHUSDGasCompensation);
// Send gas compensation to caller
_sendGasCompensation(contractsCache.activePool, msg.sender, totals.totalTHUSDGasCompensation, totals.totalCollGasCompensation);
}
/*
* This function is used when the liquidateTroves sequence starts during Recovery Mode. However, it
* handle the case where the system *leaves* Recovery Mode, part way through the liquidation sequence
*/
function _getTotalsFromLiquidateTrovesSequence_RecoveryMode
(
ContractsCache memory _contractsCache,
uint256 _price,
uint256 _THUSDInStabPool,
uint256 _n
)
internal
returns(LiquidationTotals memory totals)
{
LocalVariables_LiquidationSequence memory vars;
LiquidationValues memory singleLiquidation;
vars.remainingTHUSDInStabPool = _THUSDInStabPool;
vars.backToNormalMode = false;
vars.entireSystemDebt = getEntireSystemDebt();
vars.entireSystemColl = getEntireSystemColl();
vars.user = _contractsCache.sortedTroves.getLast();
address firstUser = _contractsCache.sortedTroves.getFirst();
for (vars.i = 0; vars.i < _n && vars.user != firstUser; vars.i++) {
// we need to cache it, because current user is likely going to be deleted
address nextUser = _contractsCache.sortedTroves.getPrev(vars.user);
vars.ICR = getCurrentICR(vars.user, _price);
if (!vars.backToNormalMode) {
// Break the loop if ICR is greater than MCR and Stability Pool is empty
if (vars.ICR >= MCR && vars.remainingTHUSDInStabPool == 0) { break; }
uint256 TCR = LiquityMath._computeCR(vars.entireSystemColl, vars.entireSystemDebt, _price);
singleLiquidation = _liquidateRecoveryMode(_contractsCache.activePool, _contractsCache.defaultPool, vars.user, vars.ICR, vars.remainingTHUSDInStabPool, TCR, _price);
// Update aggregate trackers
vars.remainingTHUSDInStabPool -= singleLiquidation.debtToOffset;
vars.entireSystemDebt -= singleLiquidation.debtToOffset;
vars.entireSystemColl -= singleLiquidation.collToSendToSP
+ singleLiquidation.collGasCompensation
+ singleLiquidation.collSurplus;
// Add liquidation values to their respective running totals
totals = _addLiquidationValuesToTotals(totals, singleLiquidation);
vars.backToNormalMode = !_checkPotentialRecoveryMode(vars.entireSystemColl, vars.entireSystemDebt, _price);
}
else if (vars.backToNormalMode && vars.ICR < MCR) {
singleLiquidation = _liquidateNormalMode(_contractsCache.activePool, _contractsCache.defaultPool, vars.user, vars.remainingTHUSDInStabPool);
vars.remainingTHUSDInStabPool -= singleLiquidation.debtToOffset;
// Add liquidation values to their respective running totals
totals = _addLiquidationValuesToTotals(totals, singleLiquidation);
} else break; // break if the loop reaches a Trove with ICR >= MCR
vars.user = nextUser;
}
}
function _getTotalsFromLiquidateTrovesSequence_NormalMode
(
IActivePool _activePool,
IDefaultPool _defaultPool,
uint256 _price,
uint256 _THUSDInStabPool,
uint256 _n
)
internal
returns(LiquidationTotals memory totals)
{
LocalVariables_LiquidationSequence memory vars;
LiquidationValues memory singleLiquidation;
ISortedTroves sortedTrovesCached = sortedTroves;
vars.remainingTHUSDInStabPool = _THUSDInStabPool;
for (vars.i = 0; vars.i < _n; vars.i++) {
vars.user = sortedTrovesCached.getLast();
vars.ICR = getCurrentICR(vars.user, _price);
if (vars.ICR < MCR) {
singleLiquidation = _liquidateNormalMode(_activePool, _defaultPool, vars.user, vars.remainingTHUSDInStabPool);
vars.remainingTHUSDInStabPool -= singleLiquidation.debtToOffset;
// Add liquidation values to their respective running totals
totals = _addLiquidationValuesToTotals(totals, singleLiquidation);
} else break; // break if the loop reaches a Trove with ICR >= MCR
}
}
/*
* Attempt to liquidate a custom list of troves provided by the caller.
*/
function batchLiquidateTroves(address[] memory _troveArray) public override {
require(_troveArray.length != 0, "TroveManager: Calldata address array must not be empty");
IActivePool activePoolCached = activePool;
IDefaultPool defaultPoolCached = defaultPool;
IStabilityPool stabilityPoolCached = stabilityPool;
LocalVariables_OuterLiquidationFunction memory vars;
LiquidationTotals memory totals;
vars.price = priceFeed.fetchPrice();
vars.THUSDInStabPool = stabilityPoolCached.getTotalTHUSDDeposits();
vars.recoveryModeAtStart = _checkRecoveryMode(vars.price);
// Perform the appropriate liquidation sequence - tally values and obtain their totals.
if (vars.recoveryModeAtStart) {
totals = _getTotalFromBatchLiquidate_RecoveryMode(activePoolCached, defaultPoolCached, vars.price, vars.THUSDInStabPool, _troveArray);
} else { // if !vars.recoveryModeAtStart
totals = _getTotalsFromBatchLiquidate_NormalMode(activePoolCached, defaultPoolCached, vars.price, vars.THUSDInStabPool, _troveArray);
}
require(totals.totalDebtInSequence > 0, "TroveManager: nothing to liquidate");
// Move liquidated collateral and THUSD to the appropriate pools
stabilityPoolCached.offset(totals.totalDebtToOffset, totals.totalCollToSendToSP);
_redistributeDebtAndColl(activePoolCached, defaultPoolCached, totals.totalDebtToRedistribute, totals.totalCollToRedistribute);
if (totals.totalCollSurplus > 0) {
activePoolCached.sendCollateral(address(collSurplusPool), totals.totalCollSurplus);
}
// Update system snapshots
_updateSystemSnapshots_excludeCollRemainder(activePoolCached, totals.totalCollGasCompensation);
vars.liquidatedDebt = totals.totalDebtInSequence;
vars.liquidatedColl = totals.totalCollInSequence - totals.totalCollGasCompensation - totals.totalCollSurplus;
emit Liquidation(vars.liquidatedDebt, vars.liquidatedColl, totals.totalCollGasCompensation, totals.totalTHUSDGasCompensation);
// Send gas compensation to caller
_sendGasCompensation(activePoolCached, msg.sender, totals.totalTHUSDGasCompensation, totals.totalCollGasCompensation);
}
/*
* This function is used when the batch liquidation sequence starts during Recovery Mode. However, it
* handle the case where the system *leaves* Recovery Mode, part way through the liquidation sequence
*/
function _getTotalFromBatchLiquidate_RecoveryMode
(
IActivePool _activePool,
IDefaultPool _defaultPool,
uint256 _price,
uint256 _THUSDInStabPool,
address[] memory _troveArray
)
internal
returns(LiquidationTotals memory totals)
{
LocalVariables_LiquidationSequence memory vars;
LiquidationValues memory singleLiquidation;
vars.remainingTHUSDInStabPool = _THUSDInStabPool;
vars.backToNormalMode = false;
vars.entireSystemDebt = getEntireSystemDebt();
vars.entireSystemColl = getEntireSystemColl();
for (vars.i = 0; vars.i < _troveArray.length; vars.i++) {
vars.user = _troveArray[vars.i];
// Skip non-active troves
if (Troves[vars.user].status != Status.active) { continue; }
vars.ICR = getCurrentICR(vars.user, _price);
if (!vars.backToNormalMode) {
// Skip this trove if ICR is greater than MCR and Stability Pool is empty
if (vars.ICR >= MCR && vars.remainingTHUSDInStabPool == 0) { continue; }
uint256 TCR = LiquityMath._computeCR(vars.entireSystemColl, vars.entireSystemDebt, _price);
singleLiquidation = _liquidateRecoveryMode(_activePool, _defaultPool, vars.user, vars.ICR, vars.remainingTHUSDInStabPool, TCR, _price);
// Update aggregate trackers
vars.remainingTHUSDInStabPool -= singleLiquidation.debtToOffset;
vars.entireSystemDebt -= singleLiquidation.debtToOffset;
vars.entireSystemColl -= singleLiquidation.collToSendToSP
+ singleLiquidation.collGasCompensation
+ singleLiquidation.collSurplus;
// Add liquidation values to their respective running totals
totals = _addLiquidationValuesToTotals(totals, singleLiquidation);
vars.backToNormalMode = !_checkPotentialRecoveryMode(vars.entireSystemColl, vars.entireSystemDebt, _price);
}
else if (vars.backToNormalMode && vars.ICR < MCR) {
singleLiquidation = _liquidateNormalMode(_activePool, _defaultPool, vars.user, vars.remainingTHUSDInStabPool);
vars.remainingTHUSDInStabPool -= singleLiquidation.debtToOffset;
// Add liquidation values to their respective running totals
totals = _addLiquidationValuesToTotals(totals, singleLiquidation);
} else continue; // In Normal Mode skip troves with ICR >= MCR
}
}
function _getTotalsFromBatchLiquidate_NormalMode
(
IActivePool _activePool,
IDefaultPool _defaultPool,
uint256 _price,
uint256 _THUSDInStabPool,
address[] memory _troveArray
)
internal
returns(LiquidationTotals memory totals)
{
LocalVariables_LiquidationSequence memory vars;
LiquidationValues memory singleLiquidation;
vars.remainingTHUSDInStabPool = _THUSDInStabPool;
for (vars.i = 0; vars.i < _troveArray.length; vars.i++) {
vars.user = _troveArray[vars.i];
vars.ICR = getCurrentICR(vars.user, _price);
if (vars.ICR < MCR) {
singleLiquidation = _liquidateNormalMode(_activePool, _defaultPool, vars.user, vars.remainingTHUSDInStabPool);
vars.remainingTHUSDInStabPool -= singleLiquidation.debtToOffset;
// Add liquidation values to their respective running totals
totals = _addLiquidationValuesToTotals(totals, singleLiquidation);
}
}
}
// --- Liquidation helper functions ---
function _addLiquidationValuesToTotals(LiquidationTotals memory oldTotals, LiquidationValues memory singleLiquidation)
internal pure returns(LiquidationTotals memory newTotals) {
// Tally all the values with their respective running totals
newTotals.totalCollGasCompensation = oldTotals.totalCollGasCompensation + singleLiquidation.collGasCompensation;
newTotals.totalTHUSDGasCompensation = oldTotals.totalTHUSDGasCompensation + singleLiquidation.THUSDGasCompensation;
newTotals.totalDebtInSequence = oldTotals.totalDebtInSequence + singleLiquidation.entireTroveDebt;
newTotals.totalCollInSequence = oldTotals.totalCollInSequence + singleLiquidation.entireTroveColl;
newTotals.totalDebtToOffset = oldTotals.totalDebtToOffset + singleLiquidation.debtToOffset;
newTotals.totalCollToSendToSP = oldTotals.totalCollToSendToSP + singleLiquidation.collToSendToSP;
newTotals.totalDebtToRedistribute = oldTotals.totalDebtToRedistribute + singleLiquidation.debtToRedistribute;
newTotals.totalCollToRedistribute = oldTotals.totalCollToRedistribute + singleLiquidation.collToRedistribute;
newTotals.totalCollSurplus = oldTotals.totalCollSurplus + singleLiquidation.collSurplus;
return newTotals;
}
function _sendGasCompensation(IActivePool _activePool, address _liquidator, uint256 _THUSD, uint256 _collateral) internal {
if (_THUSD > 0) {
IGasPool(gasPoolAddress).sendTHUSD(_liquidator, _THUSD);
}
if (_collateral > 0) {
_activePool.sendCollateral(_liquidator, _collateral);
}
}
// Move a Trove's pending debt and collateral rewards from distributions, from the Default Pool to the Active Pool
function _movePendingTroveRewardsToActivePool(IActivePool _activePool, IDefaultPool _defaultPool, uint256 _THUSD, uint256 _collateral) internal {
_defaultPool.decreaseTHUSDDebt(_THUSD);
_activePool.increaseTHUSDDebt(_THUSD);
_defaultPool.sendCollateralToActivePool(_collateral);
}
// --- Redemption functions ---
// Redeem as much collateral as possible from _borrower's Trove in exchange for THUSD up to _maxTHUSDamount
function _redeemCollateralFromTrove(
ContractsCache memory _contractsCache,
address _borrower,
uint256 _maxTHUSDamount,
uint256 _price,
address _upperPartialRedemptionHint,
address _lowerPartialRedemptionHint,
uint256 _partialRedemptionHintNICR
)
internal returns (SingleRedemptionValues memory singleRedemption)
{
// Determine the remaining amount (lot) to be redeemed, capped by the entire debt of the Trove minus the liquidation reserve
singleRedemption.THUSDLot = LiquityMath._min(_maxTHUSDamount, Troves[_borrower].debt - THUSD_GAS_COMPENSATION);
// Get the collateralLot of equivalent value in USD
singleRedemption.collateralLot = singleRedemption.THUSDLot * DECIMAL_PRECISION / _price;
// Decrease the debt and collateral of the current Trove according to the THUSD lot and corresponding collateral to send
uint256 newDebt = Troves[_borrower].debt - singleRedemption.THUSDLot;
uint256 newColl = Troves[_borrower].coll - singleRedemption.collateralLot;
if (newDebt == THUSD_GAS_COMPENSATION) {
// No debt left in the Trove (except for the liquidation reserve), therefore the trove gets closed
_removeStake(_borrower);
_closeTrove(_borrower, Status.closedByRedemption);
_redeemCloseTrove(_contractsCache, _borrower, THUSD_GAS_COMPENSATION, newColl);
emit TroveUpdated(_borrower, 0, 0, 0, TroveManagerOperation.redeemCollateral);
} else {
uint256 newNICR = LiquityMath._computeNominalCR(newColl, newDebt);
/*
* If the provided hint is out of date, we bail since trying to reinsert without a good hint will almost
* certainly result in running out of gas.
*
* If the resultant net debt of the partial is less than the minimum, net debt we bail.
*/
if (newNICR != _partialRedemptionHintNICR || _getNetDebt(newDebt) < MIN_NET_DEBT) {
singleRedemption.cancelledPartial = true;
return singleRedemption;
}
_contractsCache.sortedTroves.reInsert(_borrower, newNICR, _upperPartialRedemptionHint, _lowerPartialRedemptionHint);
Troves[_borrower].debt = newDebt;
Troves[_borrower].coll = newColl;
_updateStakeAndTotalStakes(_borrower);
emit TroveUpdated(
_borrower,
newDebt, newColl,
Troves[_borrower].stake,
TroveManagerOperation.redeemCollateral
);
}
return singleRedemption;
}
/*
* Called when a full redemption occurs, and closes the trove.
* The redeemer swaps (debt - liquidation reserve) THUSD for (debt - liquidation reserve) worth of collateral, so the THUSD liquidation reserve left corresponds to the remaining debt.
* In order to close the trove, the THUSD liquidation reserve is burned, and the corresponding debt is removed from the active pool.
* The debt recorded on the trove's struct is zero'd elswhere, in _closeTrove.
* Any surplus collateral left in the trove, is sent to the Coll surplus pool, and can be later claimed by the borrower.
*/
function _redeemCloseTrove(ContractsCache memory _contractsCache, address _borrower, uint256 _THUSD, uint256 _collateral) internal {
_contractsCache.thusdToken.burn(gasPoolAddress, _THUSD);
// Update Active Pool THUSD, and send collateral to account
_contractsCache.activePool.decreaseTHUSDDebt(_THUSD);
// send collateral from Active Pool to CollSurplus Pool
_contractsCache.collSurplusPool.accountSurplus(_borrower, _collateral);
_contractsCache.activePool.sendCollateral(address(_contractsCache.collSurplusPool), _collateral);
}
function _isValidFirstRedemptionHint(ISortedTroves _sortedTroves, address _firstRedemptionHint, uint256 _price) internal view returns (bool) {
if (_firstRedemptionHint == address(0) ||
!_sortedTroves.contains(_firstRedemptionHint) ||
getCurrentICR(_firstRedemptionHint, _price) < MCR
) {
return false;
}
address nextTrove = _sortedTroves.getNext(_firstRedemptionHint);
return nextTrove == address(0) || getCurrentICR(nextTrove, _price) < MCR;
}
/* Send _THUSDamount THUSD to the system and redeem the corresponding amount of collateral from as many Troves as are needed to fill the redemption
* request. Applies pending rewards to a Trove before reducing its debt and coll.
*
* Note that if _amount is very large, this function can run out of gas, specially if traversed troves are small. This can be easily avoided by
* splitting the total _amount in appropriate chunks and calling the function multiple times.
*
* Param `_maxIterations` can also be provided, so the loop through Troves is capped (if it’s zero, it will be ignored).This makes it easier to
* avoid OOG for the frontend, as only knowing approximately the average cost of an iteration is enough, without needing to know the “topology”
* of the trove list. It also avoids the need to set the cap in stone in the contract, nor doing gas calculations, as both gas price and opcode
* costs can vary.
*
* All Troves that are redeemed from -- with the likely exception of the last one -- will end up with no debt left, therefore they will be closed.
* If the last Trove does have some remaining debt, it has a finite ICR, and the reinsertion could be anywhere in the list, therefore it requires a hint.
* A frontend should use getRedemptionHints() to calculate what the ICR of this Trove will be after redemption, and pass a hint for its position
* in the sortedTroves list along with the ICR value that the hint was found for.
*
* If another transaction modifies the list between calling getRedemptionHints() and passing the hints to redeemCollateral(), it
* is very likely that the last (partially) redeemed Trove would end up with a different ICR than what the hint is for. In this case the
* redemption will stop after the last completely redeemed Trove and the sender will keep the remaining THUSD amount, which they can attempt
* to redeem later.
*/
function redeemCollateral(
uint256 _THUSDamount,
address _firstRedemptionHint,
address _upperPartialRedemptionHint,
address _lowerPartialRedemptionHint,
uint256 _partialRedemptionHintNICR,
uint256 _maxIterations,
uint256 _maxFeePercentage
)
external
override
{
ContractsCache memory contractsCache = ContractsCache(
activePool,
defaultPool,
thusdToken,
pcv,
sortedTroves,
collSurplusPool,
gasPoolAddress
);
RedemptionTotals memory totals;
_requireValidMaxFeePercentage(_maxFeePercentage);
totals.price = priceFeed.fetchPrice();
_requireTCRoverMCR(totals.price);
_requireAmountGreaterThanZero(_THUSDamount);
_requireTHUSDBalanceCoversRedemption(contractsCache.thusdToken, msg.sender, _THUSDamount);
totals.totalTHUSDDebtAtStart = getEntireSystemDebt();
totals.remainingTHUSD = _THUSDamount;
address currentBorrower;
if (_isValidFirstRedemptionHint(contractsCache.sortedTroves, _firstRedemptionHint, totals.price)) {
currentBorrower = _firstRedemptionHint;
} else {
currentBorrower = contractsCache.sortedTroves.getLast();
// Find the first trove with ICR >= MCR
while (currentBorrower != address(0) && getCurrentICR(currentBorrower, totals.price) < MCR) {
currentBorrower = contractsCache.sortedTroves.getPrev(currentBorrower);
}
}
// Loop through the Troves starting from the one with lowest collateral ratio until _amount of THUSD is exchanged for collateral
if (_maxIterations == 0) { _maxIterations = type(uint256).max; }
while (currentBorrower != address(0) && totals.remainingTHUSD > 0 && _maxIterations > 0) {
_maxIterations--;
// Save the address of the Trove preceding the current one, before potentially modifying the list
address nextUserToCheck = contractsCache.sortedTroves.getPrev(currentBorrower);
_applyPendingRewards(contractsCache.activePool, contractsCache.defaultPool, currentBorrower);
SingleRedemptionValues memory singleRedemption = _redeemCollateralFromTrove(
contractsCache,
currentBorrower,
totals.remainingTHUSD,
totals.price,
_upperPartialRedemptionHint,
_lowerPartialRedemptionHint,
_partialRedemptionHintNICR
);
if (singleRedemption.cancelledPartial) break; // Partial redemption was cancelled (out-of-date hint, or new net debt < minimum), therefore we could not redeem from the last Trove
totals.totalTHUSDToRedeem += singleRedemption.THUSDLot;
totals.totalCollateralDrawn += singleRedemption.collateralLot;
totals.remainingTHUSD -= singleRedemption.THUSDLot;
currentBorrower = nextUserToCheck;
}
require(totals.totalCollateralDrawn > 0, "TroveManager: Unable to redeem any amount");
// Decay the baseRate due to time passed, and then increase it according to the size of this redemption.
// Use the saved total THUSD supply value, from before it was reduced by the redemption.
_updateBaseRateFromRedemption(totals.totalCollateralDrawn, totals.price, totals.totalTHUSDDebtAtStart);
// Calculate the collateral fee
totals.collateralFee = _getRedemptionFee(totals.totalCollateralDrawn);
_requireUserAcceptsFee(totals.collateralFee, totals.totalCollateralDrawn, _maxFeePercentage);
// Send the collateral fee to the PCV contract
contractsCache.activePool.sendCollateral(address(contractsCache.pcv), totals.collateralFee);
totals.collateralToSendToRedeemer = totals.totalCollateralDrawn - totals.collateralFee;
emit Redemption(_THUSDamount, totals.totalTHUSDToRedeem, totals.totalCollateralDrawn, totals.collateralFee);
// Burn the total THUSD that is cancelled with debt, and send the redeemed collateral to msg.sender
contractsCache.thusdToken.burn(msg.sender, totals.totalTHUSDToRedeem);
// Update Active Pool THUSD, and send collateral to account
contractsCache.activePool.decreaseTHUSDDebt(totals.totalTHUSDToRedeem);
contractsCache.activePool.sendCollateral(msg.sender, totals.collateralToSendToRedeemer);
}
// --- Helper functions ---
// Return the nominal collateral ratio (ICR) of a given Trove, without the price. Takes a trove's pending coll and debt rewards from redistributions into account.
function getNominalICR(address _borrower) public view override returns (uint) {
(uint256 currentCollateral, uint256 currentTHUSDDebt) = _getCurrentTroveAmounts(_borrower);
uint256 NICR = LiquityMath._computeNominalCR(currentCollateral, currentTHUSDDebt);
return NICR;
}
// Return the current collateral ratio (ICR) of a given Trove. Takes a trove's pending coll and debt rewards from redistributions into account.
function getCurrentICR(address _borrower, uint256 _price) public view override returns (uint) {
(uint256 currentCollateral, uint256 currentTHUSDDebt) = _getCurrentTroveAmounts(_borrower);
uint256 ICR = LiquityMath._computeCR(currentCollateral, currentTHUSDDebt, _price);
return ICR;
}
function _getCurrentTroveAmounts(address _borrower) internal view returns (uint, uint) {
uint256 pendingCollateralReward = getPendingCollateralReward(_borrower);
uint256 pendingTHUSDDebtReward = getPendingTHUSDDebtReward(_borrower);
uint256 currentCollateral = Troves[_borrower].coll + pendingCollateralReward;
uint256 currentTHUSDDebt = Troves[_borrower].debt + pendingTHUSDDebtReward;
return (currentCollateral, currentTHUSDDebt);
}
function applyPendingRewards(address _borrower) external override {
_requireCallerIsBorrowerOperations();
return _applyPendingRewards(activePool, defaultPool, _borrower);
}
// Add the borrowers's coll and debt rewards earned from redistributions, to their Trove
function _applyPendingRewards(IActivePool _activePool, IDefaultPool _defaultPool, address _borrower) internal {
if (hasPendingRewards(_borrower)) {
_requireTroveIsActive(_borrower);
// Compute pending rewards
uint256 pendingCollateralReward = getPendingCollateralReward(_borrower);
uint256 pendingTHUSDDebtReward = getPendingTHUSDDebtReward(_borrower);
// Apply pending rewards to trove's state
Troves[_borrower].coll += pendingCollateralReward;
Troves[_borrower].debt += pendingTHUSDDebtReward;
_updateTroveRewardSnapshots(_borrower);
// Transfer from DefaultPool to ActivePool
_movePendingTroveRewardsToActivePool(_activePool, _defaultPool, pendingTHUSDDebtReward, pendingCollateralReward);
emit TroveUpdated(
_borrower,
Troves[_borrower].debt,
Troves[_borrower].coll,
Troves[_borrower].stake,
TroveManagerOperation.applyPendingRewards
);
}
}
// Update borrower's snapshots of L_Collateral and L_THUSDDebt to reflect the current values
function updateTroveRewardSnapshots(address _borrower) external override {
_requireCallerIsBorrowerOperations();
return _updateTroveRewardSnapshots(_borrower);
}
function _updateTroveRewardSnapshots(address _borrower) internal {
rewardSnapshots[_borrower].collateral = L_Collateral;
rewardSnapshots[_borrower].THUSDDebt = L_THUSDDebt;
emit TroveSnapshotsUpdated(L_Collateral, L_THUSDDebt);
}
// Get the borrower's pending accumulated collateral reward, earned by their stake
function getPendingCollateralReward(address _borrower) public view override returns (uint) {
uint256 snapshotCollateral = rewardSnapshots[_borrower].collateral;
uint256 rewardPerUnitStaked = L_Collateral - snapshotCollateral;
if ( rewardPerUnitStaked == 0 || Troves[_borrower].status != Status.active) { return 0; }
uint256 stake = Troves[_borrower].stake;
uint256 pendingCollateralReward = stake * rewardPerUnitStaked / DECIMAL_PRECISION;
return pendingCollateralReward;
}
// Get the borrower's pending accumulated THUSD reward, earned by their stake
function getPendingTHUSDDebtReward(address _borrower) public view override returns (uint) {
uint256 snapshotTHUSDDebt = rewardSnapshots[_borrower].THUSDDebt;
uint256 rewardPerUnitStaked = L_THUSDDebt - snapshotTHUSDDebt;
if ( rewardPerUnitStaked == 0 || Troves[_borrower].status != Status.active) { return 0; }
uint256 stake = Troves[_borrower].stake;
uint256 pendingTHUSDDebtReward = stake * rewardPerUnitStaked / DECIMAL_PRECISION;
return pendingTHUSDDebtReward;
}
function hasPendingRewards(address _borrower) public view override returns (bool) {
/*
* A Trove has pending rewards if its snapshot is less than the current rewards per-unit-staked sum:
* this indicates that rewards have occured since the snapshot was made, and the user therefore has
* pending rewards
*/
if (Troves[_borrower].status != Status.active) {return false;}
return (rewardSna...
// [truncated — 67966 bytes total]
IPCV.sol 57 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "./ITHUSDToken.sol";
interface IPCV {
// --- Events --
event THUSDTokenAddressSet(address _thusdTokenAddress);
event BorrowerOperationsAddressSet(address _borrowerOperationsAddress);
event CollateralAddressSet(address _collateralAddress);
event BAMMAddressSet(address _bammAddress);
event RolesSet(address _council, address _treasury);
event BAMMDeposit(uint256 _thusdAmount);
event BAMMWithdraw(uint256 _numShares);
event THUSDWithdraw(address _recipient, uint256 _thusdAmount);
event CollateralWithdraw(address _recipient, uint256 _collateralAmount);
event PCVDebtPaid(uint256 _paidDebt);
event RecipientAdded(address _recipient);
event RecipientRemoved(address _recipient);
// --- Functions ---
function debtToPay() external returns(uint256);
function payDebt(uint256 _thusdToBurn) external;
function setAddresses(
address _thusdTokenAddress,
address _borrowerOperations,
address payable _bammAddress,
address _collateralERC20
) external;
function initialize() external;
function depositToBAMM(uint256 _thusdAmount) external;
function withdrawFromBAMM(uint256 _numShares) external;
function withdrawTHUSD(address _recipient, uint256 _thusdAmount) external;
function withdrawCollateral(address _recipient, uint256 _collateralAmount) external;
function addRecipientToWhitelist(address _recipient) external;
function addRecipientsToWhitelist(address[] calldata _recipients) external;
function removeRecipientFromWhitelist(address _recipient) external;
function removeRecipientsFromWhitelist(address[] calldata _recipients) external;
function startChangingRoles(address _council, address _treasury) external;
function cancelChangingRoles() external;
function finalizeChangingRoles() external;
function collateralERC20() external view returns(IERC20);
function thusdToken() external view returns(ITHUSDToken);
}
IPool.sol 26 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
// Common interface for the Pools.
interface IPool {
// --- Events ---
event CollateralBalanceUpdated(uint256 _newBalance);
event THUSDBalanceUpdated(uint256 _newBalance);
event ActivePoolAddressChanged(address _newActivePoolAddress);
event DefaultPoolAddressChanged(address _newDefaultPoolAddress);
event StabilityPoolAddressChanged(address _newStabilityPoolAddress);
event CollateralSent(address _to, uint256 _amount);
// --- Functions ---
function getCollateralBalance() external view returns (uint);
function getTHUSDDebt() external view returns (uint);
function increaseTHUSDDebt(uint256 _amount) external;
function decreaseTHUSDDebt(uint256 _amount) external;
}
IGasPool.sol 13 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
interface IGasPool {
// --- Events ---
event TroveManagerAddressChanged(address _newTroveManagerAddress);
event THUSDTokenAddressChanged(address _thusdTokenAddress);
// --- Functions ---
function sendTHUSD(address _account, uint256 _amount) external;
}
Ownable.sol 85 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
/**
* Based on OpenZeppelin's Ownable contract:
* https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/access/Ownable.sol
*
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
contract Ownable {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/
constructor () {
_owner = msg.sender;
emit OwnershipTransferred(address(0), msg.sender);
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view returns (address) {
return _owner;
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
require(isOwner(), "Ownable: caller is not the owner");
_;
}
/**
* @dev Returns true if the caller is the current owner.
*/
function isOwner() public view returns (bool) {
return msg.sender == _owner;
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions anymore.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby removing any functionality that is only available to the owner.
*
* NOTE: This function is not safe, as it doesn’t check owner is calling it.
* Make sure you check it before calling it.
*/
function _renounceOwnership() internal {
emit OwnershipTransferred(_owner, address(0));
_owner = address(0);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}
BaseMath.sol 7 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
contract BaseMath {
uint256 constant public DECIMAL_PRECISION = 1e18;
}
IERC2612.sol 58 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
/**
* @dev Interface of the ERC2612 standard as defined in the EIP.
*
* Adds the {permit} method, which can be used to change one's
* {IERC20-allowance} without having to send a transaction, by signing a
* message. This allows users to spend tokens without having to hold Ether.
*
* See https://eips.ethereum.org/EIPS/eip-2612.
*
* Code adapted from https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2237/
*/
interface IERC2612 {
/**
* @dev Sets `amount` as the allowance of `spender` over `owner`'s tokens,
* given `owner`'s signed approval.
*
* IMPORTANT: The same issues {IERC20-approve} has related to transaction
* ordering also apply here.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `owner` cannot be the zero address.
* - `spender` cannot be the zero address.
* - `deadline` must be a timestamp in the future.
* - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
* over the EIP712-formatted function arguments.
* - the signature must use ``owner``'s current nonce (see {nonces}).
*
* For more information on the signature format, see the
* https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
* section].
*/
function permit(address owner, address spender, uint256 amount,
uint256 deadline, uint8 v, bytes32 r, bytes32 s) external;
/**
* @dev Returns the current ERC2612 nonce for `owner`. This value must be
* included whenever a signature is generated for {permit}.
*
* Every successful call to {permit} increases `owner`'s nonce by one. This
* prevents a signature from being used multiple times.
*
* `owner` can limit the time a Permit is valid for by setting `deadline` to
* a value in the near future. The deadline argument can be set to uint(-1) to
* create Permits that effectively never expire.
*/
function nonces(address owner) external view returns (uint256);
function version() external view returns (string memory);
function permitTypeHash() external view returns (bytes32);
function domainSeparator() external view returns (bytes32);
}
IPriceFeed.sol 12 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
interface IPriceFeed {
// --- Events ---
event LastGoodPriceUpdated(uint256 _lastGoodPrice);
// --- Function ---
function fetchPrice() external returns (uint);
}
IActivePool.sol 21 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
import "./IPool.sol";
interface IActivePool is IPool {
// --- Events ---
event BorrowerOperationsAddressChanged(address _newBorrowerOperationsAddress);
event TroveManagerAddressChanged(address _newTroveManagerAddress);
event ActivePoolTHUSDDebtUpdated(uint256 _THUSDDebt);
event ActivePoolCollateralBalanceUpdated(uint256 _collateral);
event CollateralAddressChanged(address _newCollateralAddress);
event CollSurplusPoolAddressChanged(address _newCollSurplusPoolAddress);
// --- Functions ---
function sendCollateral(address _account, uint256 _amount) external;
function updateCollateralBalance(uint256 _amount) external;
function collateralAddress() external view returns(address);
}
ITHUSDToken.sol 29 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import "../Dependencies/IERC2612.sol";
interface ITHUSDToken is IERC20Metadata, IERC2612 {
// --- Events ---
event TroveManagerAddressAdded(address _troveManagerAddress);
event StabilityPoolAddressAdded(address _newStabilityPoolAddress);
event BorrowerOperationsAddressAdded(address _newBorrowerOperationsAddress);
event THUSDTokenBalanceUpdated(address _user, uint256 _amount);
// --- Functions ---
function mintList(address contractAddress) external view returns (bool);
function burnList(address contractAddress) external view returns (bool);
function mint(address _account, uint256 _amount) external;
function burn(address _account, uint256 _amount) external;
function increaseAllowance(address spender, uint256 addedValue) external returns (bool);
function decreaseAllowance(address spender, uint256 subtractedValue) external returns (bool);
}
IDefaultPool.sol 19 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
import "./IPool.sol";
interface IDefaultPool is IPool {
// --- Events ---
event TroveManagerAddressChanged(address _newTroveManagerAddress);
event DefaultPoolTHUSDDebtUpdated(uint256 _THUSDDebt);
event DefaultPoolCollateralBalanceUpdated(uint256 _collateral);
event CollateralAddressChanged(address _newCollateralAddress);
// --- Functions ---
function sendCollateralToActivePool(uint256 _amount) external;
function updateCollateralBalance(uint256 _amount) external;
function collateralAddress() external view returns(address);
}
ILiquityBase.sol 10 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
import "./IPriceFeed.sol";
interface ILiquityBase {
function priceFeed() external view returns (IPriceFeed);
}
LiquityBase.sol 90 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
import "./BaseMath.sol";
import "./LiquityMath.sol";
import "../Interfaces/IActivePool.sol";
import "../Interfaces/IDefaultPool.sol";
import "../Interfaces/IPriceFeed.sol";
import "../Interfaces/ILiquityBase.sol";
/*
* Base contract for TroveManager, BorrowerOperations and StabilityPool. Contains global system constants and
* common functions.
*/
contract LiquityBase is BaseMath, ILiquityBase {
uint256 constant public _100pct = 1e18; // 1e18 == 100%
// Minimum collateral ratio for individual troves
uint256 constant public MCR = 1.1e18; // 110%
// Critical system collateral ratio. If the system's total collateral ratio (TCR) falls below the CCR, Recovery Mode is triggered.
uint256 constant public CCR = 1.5e18; // 150%
// Amount of THUSD to be locked in gas pool on opening troves
uint256 constant public THUSD_GAS_COMPENSATION = 200e18;
// Minimum amount of net THUSD debt a trove must have
uint256 constant public MIN_NET_DEBT = 1800e18;
// uint256 constant public MIN_NET_DEBT = 0;
uint256 constant public PERCENT_DIVISOR = 200; // dividing by 200 yields 0.5%
uint256 constant public BORROWING_FEE_FLOOR = DECIMAL_PRECISION / 1000 * 5; // 0.5%
IActivePool public activePool;
IDefaultPool public defaultPool;
IPriceFeed public override priceFeed;
// --- Gas compensation functions ---
// Returns the composite debt (drawn debt + gas compensation) of a trove, for the purpose of ICR calculation
function _getCompositeDebt(uint256 _debt) internal pure returns (uint) {
return _debt + THUSD_GAS_COMPENSATION;
}
function _getNetDebt(uint256 _debt) internal pure returns (uint) {
return _debt - THUSD_GAS_COMPENSATION;
}
// Return the amount of collateral to be drawn from a trove's collateral and sent as gas compensation.
function _getCollGasCompensation(uint256 _entireColl) internal pure returns (uint) {
return _entireColl / PERCENT_DIVISOR;
}
function getEntireSystemColl() public view returns (uint256 entireSystemColl) {
uint256 activeColl = activePool.getCollateralBalance();
uint256 liquidatedColl = defaultPool.getCollateralBalance();
return activeColl + liquidatedColl;
}
function getEntireSystemDebt() public view returns (uint256 entireSystemDebt) {
uint256 activeDebt = activePool.getTHUSDDebt();
uint256 closedDebt = defaultPool.getTHUSDDebt();
return activeDebt + closedDebt;
}
function _getTCR(uint256 _price) internal view returns (uint256 TCR) {
uint256 entireSystemColl = getEntireSystemColl();
uint256 entireSystemDebt = getEntireSystemDebt();
TCR = LiquityMath._computeCR(entireSystemColl, entireSystemDebt, _price);
return TCR;
}
function _checkRecoveryMode(uint256 _price) internal view returns (bool) {
uint256 TCR = _getTCR(_price);
return TCR < CCR;
}
function _requireUserAcceptsFee(uint256 _fee, uint256 _amount, uint256 _maxFeePercentage) internal pure {
uint256 feePercentage = _fee * DECIMAL_PRECISION / _amount;
require(feePercentage <= _maxFeePercentage, "Fee exceeded provided maximum");
}
}
LiquityMath.sol 108 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
library LiquityMath {
uint256 internal constant DECIMAL_PRECISION = 1e18;
/* Precision for Nominal ICR (independent of price). Rationale for the value:
*
* - Making it “too high” could lead to overflows.
* - Making it “too low” could lead to an ICR equal to zero, due to truncation from Solidity floor division.
*
* This value of 1e20 is chosen for safety: the NICR will only overflow for numerator > ~1e39 ETH,
* and will only truncate to 0 if the denominator is at least 1e20 times greater than the numerator.
*
*/
uint256 internal constant NICR_PRECISION = 1e20;
function _min(uint256 _a, uint256 _b) internal pure returns (uint) {
return (_a < _b) ? _a : _b;
}
function _max(uint256 _a, uint256 _b) internal pure returns (uint) {
return (_a >= _b) ? _a : _b;
}
/*
* Multiply two decimal numbers and use normal rounding rules:
* -round product up if 19'th mantissa digit >= 5
* -round product down if 19'th mantissa digit < 5
*
* Used only inside the exponentiation, _decPow().
*/
function decMul(uint256 x, uint256 y) internal pure returns (uint256 decProd) {
uint256 prod_xy = x * y;
decProd = (prod_xy + (DECIMAL_PRECISION / 2)) / DECIMAL_PRECISION;
}
/*
* _decPow: Exponentiation function for 18-digit decimal base, and integer exponent n.
*
* Uses the efficient "exponentiation by squaring" algorithm. O(log(n)) complexity.
*
* Called by one function that represent time in units of minutes:
* 1) TroveManager._calcDecayedBaseRate
*
* The exponent is capped to avoid reverting due to overflow. The cap 525600000 equals
* "minutes in 1000 years": 60 * 24 * 365 * 1000
*
* If a period of > 1000 years is ever used as an exponent in either of the above functions, the result will be
* negligibly different from just passing the cap, since:
*
* In function 1), the decayed base rate will be 0 for 1000 years or > 1000 years
* In function 2), the difference in tokens issued at 1000 years and any time > 1000 years, will be negligible
*/
function _decPow(uint256 _base, uint256 _minutes) internal pure returns (uint) {
if (_minutes > 525600000) {_minutes = 525600000;} // cap to avoid overflow
if (_minutes == 0) {return DECIMAL_PRECISION;}
uint256 y = DECIMAL_PRECISION;
uint256 x = _base;
uint256 n = _minutes;
// Exponentiation-by-squaring
while (n > 1) {
if (n % 2 == 0) {
x = decMul(x, x);
n = n / 2;
} else { // if (n % 2 != 0)
y = decMul(x, y);
x = decMul(x, x);
n = (n - 1) / 2;
}
}
return decMul(x, y);
}
function _getAbsoluteDifference(uint256 _a, uint256 _b) internal pure returns (uint) {
return (_a >= _b) ? _a - _b : _b - _a;
}
function _computeNominalCR(uint256 _coll, uint256 _debt) internal pure returns (uint) {
if (_debt > 0) {
return _coll * NICR_PRECISION / _debt;
}
// Return the maximal value for uint256 if the Trove has a debt of 0. Represents "infinite" CR.
else { // if (_debt == 0)
return type(uint256).max;
}
}
function _computeCR(uint256 _coll, uint256 _debt, uint256 _price) internal pure returns (uint) {
if (_debt > 0) {
uint256 newCollRatio = _coll * _price / _debt;
return newCollRatio;
}
// Return the maximal value for uint256 if the Trove has a debt of 0. Represents "infinite" CR.
else { // if (_debt == 0)
return type(uint256).max;
}
}
}
ISortedTroves.sol 46 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
// Common interface for the SortedTroves Doubly Linked List.
interface ISortedTroves {
// --- Events ---
event SortedTrovesAddressChanged(address _sortedDoublyLLAddress);
event BorrowerOperationsAddressChanged(address _borrowerOperationsAddress);
event NodeAdded(address _id, uint256 _NICR);
event NodeRemoved(address _id);
// --- Functions ---
function setParams(uint256 _size, address _TroveManagerAddress, address _borrowerOperationsAddress) external;
function insert(address _id, uint256 _ICR, address _prevId, address _nextId) external;
function remove(address _id) external;
function reInsert(address _id, uint256 _newICR, address _prevId, address _nextId) external;
function contains(address _id) external view returns (bool);
function isFull() external view returns (bool);
function isEmpty() external view returns (bool);
function getSize() external view returns (uint256);
function getMaxSize() external view returns (uint256);
function getFirst() external view returns (address);
function getLast() external view returns (address);
function getNext(address _id) external view returns (address);
function getPrev(address _id) external view returns (address);
function validInsertPosition(uint256 _ICR, address _prevId, address _nextId) external view returns (bool);
function findInsertPosition(uint256 _ICR, address _prevId, address _nextId) external view returns (address, address);
}
ITroveManager.sol 148 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
import "./ILiquityBase.sol";
import "./IStabilityPool.sol";
import "./ITHUSDToken.sol";
import "./IPCV.sol";
// Common interface for the Trove Manager.
interface ITroveManager is ILiquityBase {
enum Status {
nonExistent,
active,
closedByOwner,
closedByLiquidation,
closedByRedemption
}
// --- Events ---
event BorrowerOperationsAddressChanged(address _newBorrowerOperationsAddress);
event PriceFeedAddressChanged(address _newPriceFeedAddress);
event THUSDTokenAddressChanged(address _newTHUSDTokenAddress);
event ActivePoolAddressChanged(address _activePoolAddress);
event DefaultPoolAddressChanged(address _defaultPoolAddress);
event StabilityPoolAddressChanged(address _stabilityPoolAddress);
event GasPoolAddressChanged(address _gasPoolAddress);
event CollSurplusPoolAddressChanged(address _collSurplusPoolAddress);
event SortedTrovesAddressChanged(address _sortedTrovesAddress);
event PCVAddressChanged(address _pcvAddress);
event Liquidation(uint256 _liquidatedDebt, uint256 _liquidatedColl, uint256 _collGasCompensation, uint256 _THUSDGasCompensation);
event Redemption(uint256 _attemptedTHUSDAmount, uint256 _actualTHUSDAmount, uint256 _collateralSent, uint256 _collateralFee);
event TroveUpdated(address indexed _borrower, uint256 _debt, uint256 _coll, uint256 stake, uint8 operation);
event TroveLiquidated(address indexed _borrower, uint256 _debt, uint256 _coll, uint8 operation);
event BaseRateUpdated(uint256 _baseRate);
event LastFeeOpTimeUpdated(uint256 _lastFeeOpTime);
event TotalStakesUpdated(uint256 _newTotalStakes);
event SystemSnapshotsUpdated(uint256 _totalStakesSnapshot, uint256 _totalCollateralSnapshot);
event LTermsUpdated(uint256 _L_Collateral, uint256 _L_THUSDDebt);
event TroveSnapshotsUpdated(uint256 _L_Collateral, uint256 _L_THUSDDebt);
event TroveIndexUpdated(address _borrower, uint256 _newIndex);
// --- Functions ---
function setAddresses(
address _borrowerOperationsAddress,
address _activePoolAddress,
address _defaultPoolAddress,
address _stabilityPoolAddress,
address _gasPoolAddress,
address _collSurplusPoolAddress,
address _priceFeedAddress,
address _thusdTokenAddress,
address _sortedTrovesAddress,
address _pcvAddress
) external;
function stabilityPool() external view returns (IStabilityPool);
function thusdToken() external view returns (ITHUSDToken);
function pcv() external view returns (IPCV);
function getTroveOwnersCount() external view returns (uint);
function getTroveFromTroveOwnersArray(uint256 _index) external view returns (address);
function getNominalICR(address _borrower) external view returns (uint);
function getCurrentICR(address _borrower, uint256 _price) external view returns (uint);
function liquidate(address _borrower) external;
function liquidateTroves(uint256 _n) external;
function batchLiquidateTroves(address[] calldata _troveArray) external;
function redeemCollateral(
uint256 _THUSDAmount,
address _firstRedemptionHint,
address _upperPartialRedemptionHint,
address _lowerPartialRedemptionHint,
uint256 _partialRedemptionHintNICR,
uint256 _maxIterations,
uint256 _maxFee
) external;
function updateStakeAndTotalStakes(address _borrower) external returns (uint);
function updateTroveRewardSnapshots(address _borrower) external;
function addTroveOwnerToArray(address _borrower) external returns (uint256 index);
function applyPendingRewards(address _borrower) external;
function getPendingCollateralReward(address _borrower) external view returns (uint);
function getPendingTHUSDDebtReward(address _borrower) external view returns (uint);
function hasPendingRewards(address _borrower) external view returns (bool);
function getEntireDebtAndColl(address _borrower) external view returns (
uint256 debt,
uint256 coll,
uint256 pendingTHUSDDebtReward,
uint256 pendingCollateralReward
);
function closeTrove(address _borrower) external;
function removeStake(address _borrower) external;
function getRedemptionRate() external view returns (uint);
function getRedemptionRateWithDecay() external view returns (uint);
function getRedemptionFeeWithDecay(uint256 _collateralDrawn) external view returns (uint);
function getBorrowingRate() external view returns (uint);
function getBorrowingRateWithDecay() external view returns (uint);
function getBorrowingFee(uint256 THUSDDebt) external view returns (uint);
function getBorrowingFeeWithDecay(uint256 _THUSDDebt) external view returns (uint);
function decayBaseRateFromBorrowing() external;
function getTroveStatus(address _borrower) external view returns (Status);
function getTroveStake(address _borrower) external view returns (uint);
function getTroveDebt(address _borrower) external view returns (uint);
function getTroveColl(address _borrower) external view returns (uint);
function setTroveStatus(address _borrower, Status _status) external;
function increaseTroveColl(address _borrower, uint256 _collIncrease) external returns (uint);
function decreaseTroveColl(address _borrower, uint256 _collDecrease) external returns (uint);
function increaseTroveDebt(address _borrower, uint256 _debtIncrease) external returns (uint);
function decreaseTroveDebt(address _borrower, uint256 _collDecrease) external returns (uint);
function getTCR(uint256 _price) external view returns (uint);
function checkRecoveryMode(uint256 _price) external view returns (bool);
}
IStabilityPool.sol 142 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
/*
* The Stability Pool holds THUSD tokens deposited by Stability Pool depositors.
*
* When a trove is liquidated, then depending on system conditions, some of its THUSD debt gets offset with
* THUSD in the Stability Pool: that is, the offset debt evaporates, and an equal amount of THUSD tokens in the Stability Pool is burned.
*
* Thus, a liquidation causes each depositor to receive a THUSD loss, in proportion to their deposit as a share of total deposits.
* They also receive an collateral gain, as the collateral of the liquidated trove is distributed among Stability depositors,
* in the same proportion.
*
* When a liquidation occurs, it depletes every deposit by the same fraction: for example, a liquidation that depletes 40%
* of the total THUSD in the Stability Pool, depletes 40% of each deposit.
*
* A deposit that has experienced a series of liquidations is termed a "compounded deposit": each liquidation depletes the deposit,
* multiplying it by some factor in range ]0,1[
*
* Please see the implementation spec in the proof document, which closely follows on from the compounded deposit / collateral gain derivations:
* https://github.com/liquity/liquity/blob/master/papers/Scalable_Reward_Distribution_with_Compounding_Stakes.pdf
*
*/
interface IStabilityPool {
// --- Events ---
event StabilityPoolCollateralBalanceUpdated(uint256 _newBalance);
event StabilityPoolTHUSDBalanceUpdated(uint256 _newBalance);
event BorrowerOperationsAddressChanged(address _newBorrowerOperationsAddress);
event TroveManagerAddressChanged(address _newTroveManagerAddress);
event ActivePoolAddressChanged(address _newActivePoolAddress);
event DefaultPoolAddressChanged(address _newDefaultPoolAddress);
event THUSDTokenAddressChanged(address _newTHUSDTokenAddress);
event SortedTrovesAddressChanged(address _newSortedTrovesAddress);
event PriceFeedAddressChanged(address _newPriceFeedAddress);
event CollateralAddressChanged(address _newCollateralAddress);
event P_Updated(uint256 _P);
event S_Updated(uint256 _S, uint128 _epoch, uint128 _scale);
event EpochUpdated(uint128 _currentEpoch);
event ScaleUpdated(uint128 _currentScale);
event DepositSnapshotUpdated(address indexed _depositor, uint256 _P, uint256 _S);
event UserDepositChanged(address indexed _depositor, uint256 _newDeposit);
event CollateralGainWithdrawn(address indexed _depositor, uint256 _collateral, uint256 _THUSDLoss);
event CollateralSent(address _to, uint256 _amount);
// --- Functions ---
/*
* Called only once on init, to set addresses of other Liquity contracts
* Callable only by owner, renounces ownership at the end
*/
function setAddresses(
address _borrowerOperationsAddress,
address _troveManagerAddress,
address _activePoolAddress,
address _thusdTokenAddress,
address _sortedTrovesAddress,
address _priceFeedAddress,
address _collateralAddress
) external;
/*
* Initial checks:
* - _amount is not zero
* ---
* - Sends depositor's accumulated gains (collateral) to depositor
*/
function provideToSP(uint256 _amount) external;
/*
* Initial checks:
* - _amount is zero or there are no under collateralized troves left in the system
* - User has a non zero deposit
* ---
* - Sends all depositor's accumulated gains (collateral) to depositor
* - Decreases deposit stake, and takes new snapshot.
*
* If _amount > userDeposit, the user withdraws all of their compounded deposit.
*/
function withdrawFromSP(uint256 _amount) external;
/*
* Initial checks:
* - User has a non zero deposit
* - User has an open trove
* - User has some collateral gain
* ---
* - Transfers the depositor's entire collateral gain from the Stability Pool to the caller's trove
* - Leaves their compounded deposit in the Stability Pool
* - Updates snapshots for deposit
*/
function withdrawCollateralGainToTrove(address _upperHint, address _lowerHint) external;
/*
* Initial checks:
* - Caller is TroveManager
* ---
* Cancels out the specified debt against the THUSD contained in the Stability Pool (as far as possible)
* and transfers the Trove's collateral from ActivePool to StabilityPool.
* Only called by liquidation functions in the TroveManager.
*/
function offset(uint256 _debt, uint256 _coll) external;
/*
* Returns the total amount of collateral held by the pool, accounted in an internal variable instead of `balance`,
* to exclude edge cases like collateral received from a self-destruct.
*/
function getCollateralBalance() external view returns (uint);
/*
* Returns THUSD held in the pool. Changes when users deposit/withdraw, and when Trove debt is offset.
*/
function getTotalTHUSDDeposits() external view returns (uint);
/*
* Calculates the collateral gain earned by the deposit since its last snapshots were taken.
*/
function getDepositorCollateralGain(address _depositor) external view returns (uint);
/*
* Return the user's compounded deposit.
*/
function getCompoundedTHUSDDeposit(address _depositor) external view returns (uint);
/*
* Only callable by Active Pool, updates ERC20 tokens recieved
*/
function updateCollateralBalance(uint256 _amount) external;
/*
* Fallback function
* Only callable by Active Pool, it just accounts for ETH received
* receive() external payable;
*/
function collateralAddress() external view returns(address);
}
CheckContract.sol 19 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
contract CheckContract {
/**
* Check that the account is an already deployed non-destroyed contract.
* See: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/Address.sol#L12
*/
function checkContract(address _account) internal view {
require(_account != address(0), "Account cannot be zero address");
uint256 size;
// solhint-disable-next-line no-inline-assembly
assembly { size := extcodesize(_account) }
require(size > 0, "Account code size cannot be zero");
}
}
ICollSurplusPool.sol 38 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
interface ICollSurplusPool {
// --- Events ---
event BorrowerOperationsAddressChanged(address _newBorrowerOperationsAddress);
event TroveManagerAddressChanged(address _newTroveManagerAddress);
event ActivePoolAddressChanged(address _newActivePoolAddress);
event CollateralAddressChanged(address _newCollateralAddress);
event CollBalanceUpdated(address indexed _account, uint256 _newBalance);
event CollateralSent(address _to, uint256 _amount);
// --- Contract setters ---
function setAddresses(
address _borrowerOperationsAddress,
address _troveManagerAddress,
address _activePoolAddress,
address _collateralAddress
) external;
function getCollateralBalance() external view returns (uint);
function getCollateral(address _account) external view returns (uint);
function accountSurplus(address _account, uint256 _amount) external;
function claimColl(address _account) external;
function updateCollateralBalance(uint256 _amount) external;
function collateralAddress() external view returns(address);
}
IERC20.sol 78 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves `amount` tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 amount) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 amount) external returns (bool);
/**
* @dev Moves `amount` tokens from `from` to `to` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 amount) external returns (bool);
}
IERC20Metadata.sol 28 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)
pragma solidity ^0.8.0;
import "../IERC20.sol";
/**
* @dev Interface for the optional metadata functions from the ERC20 standard.
*
* _Available since v4.1._
*/
interface IERC20Metadata is IERC20 {
/**
* @dev Returns the name of the token.
*/
function name() external view returns (string memory);
/**
* @dev Returns the symbol of the token.
*/
function symbol() external view returns (string memory);
/**
* @dev Returns the decimals places of the token.
*/
function decimals() external view returns (uint8);
}
Read Contract
BETA 0x071a7541 → uint256
BORROWING_FEE_FLOOR 0xf92d3433 → uint256
CCR 0x5733d58f → uint256
DECIMAL_PRECISION 0xa20baee6 → uint256
L_Collateral 0xee266b87 → uint256
L_THUSDDebt 0xa68b663e → uint256
MAX_BORROWING_FEE 0x24092669 → uint256
MCR 0x794e5724 → uint256
MINUTE_DECAY_FACTOR 0xc7b55481 → uint256
MIN_NET_DEBT 0x1bf43555 → uint256
NAME 0xa3f4df7e → string
PERCENT_DIVISOR 0x4870dd9a → uint256
REDEMPTION_FEE_FLOOR 0x28d28b5b → uint256
THUSD_GAS_COMPENSATION 0x1fd6a434 → uint256
TroveOwners 0x756b253e → address
Troves 0x6ef64338 → uint256, uint256, uint256, uint8, uint128
_100pct 0x72fe25aa → uint256
activePool 0x7f7dde4a → address
baseRate 0x1f68f20a → uint256
borrowerOperationsAddress 0xb7f8cf9b → address
checkRecoveryMode 0x4e443d9e → bool
defaultPool 0x3cc74225 → address
getBorrowingFee 0x631203b0 → uint256
getBorrowingFeeWithDecay 0x477d66cf → uint256
getBorrowingRate 0xf36b2425 → uint256
getBorrowingRateWithDecay 0x66ca4a21 → uint256
getCurrentICR 0xd293c710 → uint256
getEntireDebtAndColl 0xb91af97c → uint256, uint256, uint256, uint256
getEntireSystemColl 0x887105d3 → uint256
getEntireSystemDebt 0x795d26c3 → uint256
getNominalICR 0xb0d8e181 → uint256
getPendingCollateralReward 0x4a3c95c4 → uint256
getPendingTHUSDDebtReward 0x9ba7a408 → uint256
getRedemptionFeeWithDecay 0xd5b35635 → uint256
getRedemptionRate 0x2b11551a → uint256
getRedemptionRateWithDecay 0xc52861f2 → uint256
getTCR 0xb82f263d → uint256
getTroveColl 0x480cd578 → uint256
getTroveDebt 0xd66a2553 → uint256
getTroveFromTroveOwnersArray 0xd9a72444 → address
getTroveOwnersCount 0x49eefeee → uint256
getTroveStake 0x64cee260 → uint256
getTroveStatus 0x21e37801 → uint8
hasPendingRewards 0xe2ac77b0 → bool
isOwner 0x8f32d59b → bool
lastCollateralError_Redistribution 0xd38b0558 → uint256
lastFeeOperationTime 0xd380a37c → uint256
lastTHUSDDebtError_Redistribution 0xe6a91f16 → uint256
owner 0x8da5cb5b → address
pcv 0x4597f6ed → address
priceFeed 0x741bef1a → address
rewardSnapshots 0x1673c79a → uint256, uint256
sortedTroves 0xae918754 → address
stabilityPool 0x048c661d → address
thusdToken 0x77e16f1e → address
totalCollateralSnapshot 0x96d711ff → uint256
totalStakes 0xbf9befb1 → uint256
totalStakesSnapshot 0x807d138d → uint256
Write Contract 18 functions
These functions modify contract state and require a wallet transaction to execute.
addTroveOwnerToArray 0x15d549f1
address _borrower
returns: uint256
applyPendingRewards 0x0b076557
address _borrower
batchLiquidateTroves 0x1e8b1c2b
address[] _troveArray
closeTrove 0xcbd138ae
address _borrower
decayBaseRateFromBorrowing 0x5dba4c4a
No parameters
decreaseTroveColl 0xd3d6f843
address _borrower
uint256 _collDecrease
returns: uint256
decreaseTroveDebt 0x12610e92
address _borrower
uint256 _debtDecrease
returns: uint256
increaseTroveColl 0x72423c17
address _borrower
uint256 _collIncrease
returns: uint256
increaseTroveDebt 0x9976cf45
address _borrower
uint256 _debtIncrease
returns: uint256
liquidate 0x2f865568
address _borrower
liquidateTroves 0x653d46e7
uint256 _n
redeemCollateral 0xbcd37526
uint256 _THUSDamount
address _firstRedemptionHint
address _upperPartialRedemptionHint
address _lowerPartialRedemptionHint
uint256 _partialRedemptionHintNICR
uint256 _maxIterations
uint256 _maxFeePercentage
removeStake 0xfe2ba848
address _borrower
setAddresses 0x6c37a4af
address _borrowerOperationsAddress
address _activePoolAddress
address _defaultPoolAddress
address _stabilityPoolAddress
address _gasPoolAddress
address _collSurplusPoolAddress
address _priceFeedAddress
address _thusdTokenAddress
address _sortedTrovesAddress
address _pcvAddress
setTroveStatus 0x953f0bb1
address _borrower
uint8 _status
transferOwnership 0xf2fde38b
address newOwner
updateStakeAndTotalStakes 0x18f2817a
address _borrower
returns: uint256
updateTroveRewardSnapshots 0x82fe3eb9
address _borrower
Recent Transactions
No transactions found for this address