Address Contract Partially Verified
Address
0x1Cf3DAB407aa14389f9C79b80B16E48cbc7246EE
Balance
0 ETH
Nonce
1
Code Size
16159 bytes
Creator
0x5723759D...5190 at tx 0xec0ce9a5...9f2e84
Indexed Transactions
0
Contract Bytecode
16159 bytes
0x6003361161000c57612d42565b5f3560e01c63c290d6918118610ada5760243610613f0e573461010052600c5461009c57610100511561009c57601c610120527f6e6f2045544820616c6c6f77656420666f722074686973206c6f616e000000006101405261012050610120518061014001601f825f031636823750506308c379a060e052602061010052601f19601f61012051011660440160fcfd5b60065463c2224e0b610120523361014052600435610160526020610120604461013c845afa6100cd573d5f5f3e3d5ffd5b60203d10613f0e57610120518060011c613f0e576101805261018090505161015457600e6101a0527f6c6f616e206e6f7420666f756e640000000000000000000000000000000000006101c0526101a0506101a051806101c001601f825f031636823750506308c379a061016052602061018052601f19601f6101a051011660440161017cfd5b60065463a1c5158661284052336128605260043561288052612760612840604461285c845afa610186573d5f5f3e3d5ffd5b6101e03d10613f0e5761284051612840018051614fc0526020810151614fe05260408101516150005260608101516150205260808101516150405260a081015181016064815111613f0e5780515f8160648111613f0e57801561022357905b606081026150800160608202602086010180518060a01c613f0e578252602081015160208301526040810151604083015250506001018181186101e5575b50508061506052505060c08101516176005260e0810151617620526101008101518060011c613f0e57617640526101208101518060011c613f0e57617660526101408101518060011c613f0e57617680526101608101518060011c613f0e576176a0526101808101518060011c613f0e576176c05250614fc0905080516101205260208101516101405260408101516101605260608101516101805260808101516101a05260a0810180516020820160608202806101e0828460045afa505050806101c052505061264081015161276052612660810151612780526126808101516127a0526126a08101516127c0526126c08101516127e0526126e0810151612800526127008101516128205250610180514211156103a1576015612840527f6c6f616e206d61747572697479207265616368656400000000000000000000006128605261284050612840518061286001601f825f031636823750506308c379a061280052602061282052601f19601f61284051011660440161281cfd5b6127e0511561040f576011612840527f6c6f616e20616c726561647920706169640000000000000000000000000000006128605261284050612840518061286001601f825f031636823750506308c379a061280052602061282052601f19601f61284051011660440161281cfd5b426040526101a05160605260035460805261042b612860613048565b6128605161284052610140516040526127605160605261016051608052610180516101a051808203828111613f0e579050905060a0526128405160c05260035460e052610479612880612f9a565b612880516128605260075463856e84886128a05260206128a060046128bc845afa6104a6573d5f5f3e3d5ffd5b60203d10613f0e576128a0518060a01c613f0e576128e0526128e0905051612880525f6128a052610100511561059d576128605161010051101561054957601b6128c0527f696e73756666696369656e742076616c756520726563656976656400000000006128e0526128c0506128c051806128e001601f825f031636823750506308c379a06128805260206128a052601f19601f6128c051011660440161289cfd5b6101005161286051808203828111613f0e57905090506128a052337f45fdc265dc29885b9a485766b03e70978440d38c7c328ee0a14fa40c76c6af54336128c052610100516128e05260406128c0a2610734565b61286051612880516370a082316128c052336128e05260206128c060246128dc845afa6105cc573d5f5f3e3d5ffd5b60203d10613f0e576128c09050511015610645576014612900527f696e73756666696369656e742062616c616e63650000000000000000000000006129205261290050612900518061292001601f825f031636823750506308c379a06128c05260206128e052601f19601f6129005101166044016128dcfd5b612860516128805163dd62ed3e61292052336129405260075463a6def0a06128c05260206128c060046128dc845afa610680573d5f5f3e3d5ffd5b60203d10613f0e576128c0518060a01c613f0e5761290052612900905051612960526020612920604461293c845afa6106bb573d5f5f3e3d5ffd5b60203d10613f0e576129209050511015610734576016612980527f696e73756666696369656e7420616c6c6f77616e6365000000000000000000006129a0526129805061298051806129a001601f825f031636823750506308c379a061294052602061296052601f19601f61298051011660440161295cfd5b6128605161014051808203828111613f0e57905090506128c05260065463291a7e4c6128e05233612900526004356129205261014051612940526128c05161296052803b15613f0e575f6128e060846128fc5f855af1610796573d5f5f3e3d5ffd5b5060065463a07bda7f6128e052336129005260043561292052803b15613f0e575f6128e060446128fc5f855af16107cf573d5f5f3e3d5ffd5b506006546361e8726d6128e052336129005260043561292052803b15613f0e575f6128e060446128fc5f855af1610808573d5f5f3e3d5ffd5b506101005115610895576007546312d8f9166128e052336129005261014051612920526128c05161294052803b15613f0e575f6128e060646128fc61286051855af1610856573d5f5f3e3d5ffd5b506007547fd52bd61f7c422d441e024604f4517878fd3305d6acf0fe37baef23ed21af6bc96007546128e052612860516129005260406128e0a26108d8565b6007546315e7c65a6128e052336129005261014051612920526128c05161294052803b15613f0e575f6128e060646128fc5f855af16108d6573d5f5f3e3d5ffd5b505b5f6101c05160648111613f0e5780156109ff57905b606081026101e00180516128e05260208101516129005260408101516129205250600654631af860556129405233612960526128e05161298052612900516129a052612920516129c0526004356129e052803b15613f0e575f61294060a461295c5f855af161095e573d5f5f3e3d5ffd5b5060065463f7230a75612940526128e051612960526129005161298052612920516129a05260016129c052803b15613f0e575f612940608461295c5f855af16109a9573d5f5f3e3d5ffd5b5060085463b4ece41b6129405233612960526128e05161298052612900516129a052612880516129c052803b15613f0e575f612940608461295c5f855af16109f3573d5f5f3e3d5ffd5b506001018181186108ed575b50506128a05115610a50575f5f5f5f6128a051335ff115613f0e57337fd52bd61f7c422d441e024604f4517878fd3305d6acf0fe37baef23ed21af6bc9336128e0526128a0516129005260406128e0a25b337f31c401ba8a3eb75cf55e1d9f4971e726115e8448c80446935cffbea991ca2473336128e0526004356129005261014051612920526128c05161294052612880516129605260a06128e0a2337f42d434e1d98bb8cb642015660476f098bbb0f00b64ddb556e149e17de4dd3645336128e05260043561290052612880516129205260606128e0a2005b34613f0e57638da5cb5b8118610af5575f5460405260206040f35b63f851a4408118610b0c5760015460405260206040f35b63d153b60c8118610b235760025460405260206040f35b63f511b6f78118610b3a5760035460405260206040f35b6320cc187d8118610b515760045460405260206040f35b63c71782308118610b685760055460405260206040f35b632bf65d9d8118610b7f5760065460405260206040f35b63bbb6bbc68118610b965760075460405260206040f35b63d38835db8118610bad5760085460405260206040f35b638f0099068118610bc45760095460405260206040f35b63bfe767ea8118610bdb57600a5460405260206040f35b63d8e99f928118610bf257600b5460405260206040f35b63ce46e0468118610c0957600c5460405260206040f35b63b5ed298a8118610e3e5760243610613f0e576004358060a01c613f0e576040525f54331815610c8f57601b6060527f6d73672e73656e646572206973206e6f7420746865206f776e6572000000000060805260605060605180608001601f825f031636823750506308c379a06020526020604052601f19601f6060510116604401603cfd5b604051610cf257601c6060527f5f6164647265737320697420746865207a65726f20616464726573730000000060805260605060605180608001601f825f031636823750506308c379a06020526020604052601f19601f6060510116604401603cfd5b6040515f5418610d585760206060527f70726f706f736564206f776e6572206164647220697320746865206f776e657260805260605060605180608001601f825f031636823750506308c379a06020526020604052601f19601f6060510116604401603cfd5b60405160025418610dbf57601f6060527f70726f706f736564206f776e65722061646472206973207468652073616d650060805260605060605180608001601f825f031636823750506308c379a06020526020604052601f19601f6060510116604401603cfd5b6040516002556040515f547fb4c8aadbed5e1d6c2b41b85b2a233853a33c3f9284159abad98bf7d24d5a6f745f5460c05260405160e05260075463856e8488606052602060606004607c845afa610e18573d5f5f3e3d5ffd5b60203d10613f0e576060518060a01c613f0e5760a05260a090505161010052606060c0a3005b634e71e0c88118610f2f57600254331815610eae57601e6040527f6d73672e73656e646572206973206e6f74207468652070726f706f736564000060605260405060405180606001601f825f031636823750506308c379a05f526020602052601f19601f6040510116604401601cfd5b6002545f547fd5b903f8ba0e47f8a7bfe27b5098230bd3900b46d8b430e37480be7096ca7f6d5f5460a05260025460c05260075463856e8488604052602060406004605c845afa610f01573d5f5f3e3d5ffd5b60203d10613f0e576040518060a01c613f0e57608052608090505160e052606060a0a36002545f555f600255005b636f25721381186110c75760243610613f0e575f54331815610fa657601b6040527f6d73672e73656e646572206973206e6f7420746865206f776e6572000000000060605260405060405180606001601f825f031636823750506308c379a05f526020602052601f19601f6040510116604401601cfd5b6003546004351861100c5760126040527f5f76616c7565206973207468652073616d65000000000000000000000000000060605260405060405180606001601f825f031636823750506308c379a05f526020602052601f19601f6040510116604401601cfd5b60075463856e8488604052602060406004605c845afa61102e573d5f5f3e3d5ffd5b60203d10613f0e576040518060a01c613f0e5760805260809050517f3bf96a23eccc8bbd7d753be214e0d205e1ab1633ef155ea4ebc9cf0cdaf1ed62600354610100526004356101205260075463856e848860a052602060a0600460bc845afa61109a573d5f5f3e3d5ffd5b60203d10613f0e5760a0518060a01c613f0e5760e05260e0905051610140526060610100a2600435600355005b6354858bf381186112d45760243610613f0e576004358060a01c613f0e576040525f5433181561114d57601b6060527f6d73672e73656e646572206973206e6f7420746865206f776e6572000000000060805260605060605180608001601f825f031636823750506308c379a06020526020604052601f19601f6060510116604401603cfd5b6040516111b057601c6060527f5f6164647265737320697320746865207a65726f20616464726573730000000060805260605060605180608001601f825f031636823750506308c379a06020526020604052601f19601f6060510116604401603cfd5b6040516007541861121757601d6060527f6e6577204c505065726970682061646472206973207468652073616d6500000060805260605060605180608001601f825f031636823750506308c379a06020526020604052601f19601f6060510116604401603cfd5b60075463856e8488606052602060606004607c845afa611239573d5f5f3e3d5ffd5b60203d10613f0e576060518060a01c613f0e5760a05260a09050517f9ff7d50605c1c682dbf5814a8b8e219e93415e94914ac5caea5447f84a233c74600754610120526040516101405260075463856e848860c052602060c0600460dc845afa6112a5573d5f5f3e3d5ffd5b60203d10613f0e5760c0518060a01c613f0e5761010052610100905051610160526060610120a2604051600755005b634f401e2981186114e15760243610613f0e576004358060a01c613f0e576040525f5433181561135a57601b6060527f6d73672e73656e646572206973206e6f7420746865206f776e6572000000000060805260605060605180608001601f825f031636823750506308c379a06020526020604052601f19601f6060510116604401603cfd5b6040516113bd57601c6060527f5f6164647265737320697320746865207a65726f20616464726573730000000060805260605060605180608001601f825f031636823750506308c379a06020526020604052601f19601f6060510116604401603cfd5b6040516008541861142457601b6060527f6e6577204c50436f72652061646472206973207468652073616d65000000000060805260605060605180608001601f825f031636823750506308c379a06020526020604052601f19601f6060510116604401603cfd5b60075463856e8488606052602060606004607c845afa611446573d5f5f3e3d5ffd5b60203d10613f0e576060518060a01c613f0e5760a05260a09050517ff60eafa74e7cd89f0b37050eeb419aeba0a9dcf0b54e7bb3d8544253127d6466600854610120526040516101405260075463856e848860c052602060c0600460dc845afa6114b2573d5f5f3e3d5ffd5b60203d10613f0e5760c0518060a01c613f0e5761010052610100905051610160526060610120a2604051600855005b63dfe5cf4e81186116ee5760243610613f0e576004358060a01c613f0e576040525f5433181561156757601b6060527f6d73672e73656e646572206973206e6f7420746865206f776e6572000000000060805260605060605180608001601f825f031636823750506308c379a06020526020604052601f19601f6060510116604401603cfd5b6040516115ca57601c6060527f5f6164647265737320697320746865207a65726f20616464726573730000000060805260605060605180608001601f825f031636823750506308c379a06020526020604052601f19601f6060510116604401603cfd5b6040516009541861163157601b6060527f6e6577204c50436f72652061646472206973207468652073616d65000000000060805260605060605180608001601f825f031636823750506308c379a06020526020604052601f19601f6060510116604401603cfd5b60075463856e8488606052602060606004607c845afa611653573d5f5f3e3d5ffd5b60203d10613f0e576060518060a01c613f0e5760a05260a09050517fd5cf3817f09a159f02f30e9ca8842239c472b01ce4ee28c5bd3dae53f1ed71b9600954610120526040516101405260075463856e848860c052602060c0600460dc845afa6116bf573d5f5f3e3d5ffd5b60203d10613f0e5760c0518060a01c613f0e5761010052610100905051610160526060610120a2604051600955005b637eefa48781186118fb5760243610613f0e576004358060a01c613f0e576040525f5433181561177457601b6060527f6d73672e73656e646572206973206e6f7420746865206f776e6572000000000060805260605060605180608001601f825f031636823750506308c379a06020526020604052601f19601f6060510116604401603cfd5b6040516117d757601c6060527f5f6164647265737320697320746865207a65726f20616464726573730000000060805260605060605180608001601f825f031636823750506308c379a06020526020604052601f19601f6060510116604401603cfd5b600a546040511861183e5760156060527f6e65772076616c7565206973207468652073616d65000000000000000000000060805260605060605180608001601f825f031636823750506308c379a06020526020604052601f19601f6060510116604401603cfd5b60075463856e8488606052602060606004607c845afa611860573d5f5f3e3d5ffd5b60203d10613f0e576060518060a01c613f0e5760a05260a09050517fc9dff19604a1a239924a95245890bf12b12dec6ce9529c14a187ffae033d63b0600a54610120526040516101405260075463856e848860c052602060c0600460dc845afa6118cc573d5f5f3e3d5ffd5b60203d10613f0e5760c0518060a01c613f0e5761010052610100905051610160526060610120a2604051600a55005b634b6c36b58118611a9e5760243610613f0e576004358060011c613f0e576040525f5433181561198157601b6060527f6d73672e73656e646572206973206e6f7420746865206f776e6572000000000060805260605060605180608001601f825f031636823750506308c379a06020526020604052601f19601f6060510116604401603cfd5b604051600454186119e857601f6060527f6e657720636f6e747261637420737461747573206973207468652073616d650060805260605060605180608001601f825f031636823750506308c379a06020526020604052601f19601f6060510116604401603cfd5b60405160045560075463856e8488606052602060606004607c845afa611a10573d5f5f3e3d5ffd5b60203d10613f0e576060518060a01c613f0e5760a05260a09050517ff1f3fb69901207764e1ded1276f81ef0e7d27d4c937f4290a397554a78b942f26040516101205260075463856e848860c052602060c0600460dc845afa611a75573d5f5f3e3d5ffd5b60203d10613f0e5760c0518060a01c613f0e5761010052610100905051610140526040610120a2005b630fcc0c288118611c20575f54331815611b0d57601b6040527f6d73672e73656e646572206973206e6f7420746865206f776e6572000000000060605260405060405180606001601f825f031636823750506308c379a05f526020602052601f19601f6040510116604401601cfd5b60055415611b7057601e6040527f636f6e747261637420697320616c72656164792064657072656361746564000060605260405060405180606001601f825f031636823750506308c379a05f526020602052601f19601f6040510116604401601cfd5b60016005555f60045560075463856e8488604052602060406004605c845afa611b9b573d5f5f3e3d5ffd5b60203d10613f0e576040518060a01c613f0e5760805260809050517fdd10c817d080a89ad8dd5d6c365f18b6eed6b4c4c66bd37933429277d3ae3da760075463856e848860a052602060a0600460bc845afa611bf9573d5f5f3e3d5ffd5b60203d10613f0e5760a0518060a01c613f0e5760e05260e0905051610100526020610100a2005b63490718208118611d0d576020806102205260075463856e8488604052602060406004605c845afa611c54573d5f5f3e3d5ffd5b60203d10613f0e576040518060a01c613f0e5760805260809050516395d89b4160a05260c060a0600460bc845afa611c8e573d5f5f3e3d5ffd5b60403d10613f0e5760a05160a0016064815111613f0e57805160208201816101a0838360045afa50508061018052505061018090508161022001815160208301602083018281848460045afa505050808252508051806020830101601f825f03163682375050601f19601f825160200101169050905081019050610220f35b63e535754e811861200f5760643610613f0e576004358060a01c613f0e576101005260065463a1c5158661284052610100516128605260243561288052612760612840604461285c845afa611d64573d5f5f3e3d5ffd5b6101e03d10613f0e5761284051612840018051614fc0526020810151614fe05260408101516150005260608101516150205260808101516150405260a081015181016064815111613f0e5780515f8160648111613f0e578015611e0157905b606081026150800160608202602086010180518060a01c613f0e57825260208101516020830152604081015160408301525050600101818118611dc3575b50508061506052505060c08101516176005260e0810151617620526101008101518060011c613f0e57617640526101208101518060011c613f0e57617660526101408101518060011c613f0e57617680526101608101518060011c613f0e576176a0526101808101518060011c613f0e576176c05250614fc0905080516101205260208101516101405260408101516101605260608101516101805260808101516101a05260a0810180516020820160608202806101e0828460045afa505050806101c052505061264081015161276052612660810151612780526126808101516127a0526126a08101516127c0526126c08101516127e0526126e08101516128005261270081015161282052506127e05115611f27575f61284052602061284061200d565b6044356101a0511115611f63577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff61284052602061284061200d565b6127a05115611fe2576044356040526101a051606052600354608052611f8a612860613048565b61286051612840526020610140516040526127605160605261016051608052610180516101a051808203828111613f0e579050905060a0526128405160c05260035460e052611fda612860612f9a565b61286061200d565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6128405260206128405bf35b63018b92ba811861212a576101843610613f0e576064356004016064813511613f0e5780355f8160648111613f0e57801561208457905b60608102619d600160608202602086010180358060a01c613f0e57825260208101356020830152604081013560408301525050600101818118612046575b505080619d405250506084358060011c613f0e5761c2e05260606004614f2037619d40516060810280614fa082619d6060045afa505080614f80525061c2e0516175205260a4356175405260a060c4617560376120e261c320613336565b61c3205161c30052600754636f64234e61c320523361c3405260043561c36052803b15613f0e575f61c320604461c33c5f855af1612122573d5f5f3e3d5ffd5b50602061c300f35b635a5cd02e8118612245576101843610613f0e576064356004016064813511613f0e5780355f8160648111613f0e57801561219f57905b60608102619d600160608202602086010180358060a01c613f0e57825260208101356020830152604081013560408301525050600101818118612161575b505080619d405250506084358060011c613f0e5761c2e05260606004614f2037619d40516060810280614fa082619d6060045afa505080614f80525061c2e0516175205260a4356175405260a060c4617560376121fd61c320613336565b61c3205161c30052600754638396b88a61c320523361c3405260043561c36052803b15613f0e575f61c320604461c33c5f855af161223d573d5f5f3e3d5ffd5b50602061c300f35b637a964a3281186128fa5760443610613f0e576004358060a01c613f0e576040526001543318156122cc57601b6060527f6d73672e73656e646572206973206e6f74207468652061646d696e000000000060805260605060605180608001601f825f031636823750506308c379a06020526020604052601f19601f6060510116604401603cfd5b60065463c2224e0b60605260405160805260243560a052602060606044607c845afa6122fa573d5f5f3e3d5ffd5b60203d10613f0e576060518060011c613f0e5760c05260c090505161237757600e60e0527f6c6f616e206e6f7420666f756e640000000000000000000000000000000000006101005260e05060e0518061010001601f825f031636823750506308c379a060a052602060c052601f19601f60e051011660440160bcfd5b60065463a1c51586612780526040516127a0526024356127c052612760612780604461279c845afa6123ab573d5f5f3e3d5ffd5b6101e03d10613f0e5761278051612780018051614f00526020810151614f20526040810151614f40526060810151614f60526080810151614f805260a081015181016064815111613f0e5780515f8160648111613f0e57801561244857905b60608102614fc00160608202602086010180518060a01c613f0e5782526020810151602083015260408101516040830152505060010181811861240a575b505080614fa052505060c08101516175405260e0810151617560526101008101518060011c613f0e57617580526101208101518060011c613f0e576175a0526101408101518060011c613f0e576175c0526101608101518060011c613f0e576175e0526101808101518060011c613f0e576176005250614f00905080516060526020810151608052604081015160a052606081015160c052608081015160e05260a081018051602082016060820280610120828460045afa505050806101005250506126408101516126a0526126608101516126c0526126808101516126e0526126a0810151612700526126c0810151612720526126e081015161274052612700810151612760525061272051156125bf576011612780527f6c6f616e20616c726561647920706169640000000000000000000000000000006127a0526127805061278051806127a001601f825f031636823750506308c379a061274052602061276052601f19601f61278051011660440161275cfd5b60c051421161262d57601e612780527f6c6f616e2069732077697468696e206d6174757269747920706572696f6400006127a0526127805061278051806127a001601f825f031636823750506308c379a061274052602061276052601f19601f61278051011660440161275cfd5b60095461269957601c612780527f424e50657269706820697320746865207a65726f2061646472657373000000006127a0526127805061278051806127a001601f825f031636823750506308c379a061274052602061276052601f19601f61278051011660440161275cfd5b60065463cf2e4f76612780526040516127a0526024356127c052803b15613f0e575f612780604461279c5f855af16126d3573d5f5f3e3d5ffd5b5060065463b50c85ca612780526040516127a0526024356127c052803b15613f0e575f612780604461279c5f855af161270e573d5f5f3e3d5ffd5b505f6101005160648111613f0e5780156127ee57905b606081026101200180516127805260208101516127a05260408101516127c05250600654631af860556127e0526040516128005261278051612820526127a051612840526127c0516128605260243561288052803b15613f0e575f6127e060a46127fc5f855af1612797573d5f5f3e3d5ffd5b5060065463f7230a756127e05261278051612800526127a051612820526127c05161284052600161286052803b15613f0e575f6127e060846127fc5f855af16127e2573d5f5f3e3d5ffd5b50600101818118612724575b505060095463e196ce426127e052604051612800526024356128205260075463856e8488612780526020612780600461279c845afa61282f573d5f5f3e3d5ffd5b60203d10613f0e57612780518060a01c613f0e576127c0526127c090505161284052803b15613f0e575f6127e060646127fc5f855af1612871573d5f5f3e3d5ffd5b506040517f098169d32c0f83653c192e3fe5e7da2ae5d6e98615fd0f767785098bea1f51b76040516127e052602435612800526080516128205260075463856e8488612780526020612780600461279c845afa6128d0573d5f5f3e3d5ffd5b60203d10613f0e57612780518060a01c613f0e576127c0526127c09050516128405260806127e0a2005b63e3f1a9828118612d405760843610613f0e576024358060a01c613f0e576040526064358060011c613f0e5760605260065463a1c515866127a052336127c0526004356127e0526127606127a060446127bc845afa61295b573d5f5f3e3d5ffd5b6101e03d10613f0e576127a0516127a0018051614f20526020810151614f40526040810151614f60526060810151614f80526080810151614fa05260a081015181016064815111613f0e5780515f8160648111613f0e5780156129f857905b60608102614fe00160608202602086010180518060a01c613f0e578252602081015160208301526040810151604083015250506001018181186129ba575b505080614fc052505060c08101516175605260e0810151617580526101008101518060011c613f0e576175a0526101208101518060011c613f0e576175c0526101408101518060011c613f0e576175e0526101608101518060011c613f0e57617600526101808101518060011c613f0e576176205250614f2090508051608052602081015160a052604081015160c052606081015160e05260808101516101005260a081018051602082016060820280610140828460045afa505050806101205250506126408101516126c0526126608101516126e052612680810151612700526126a0810151612720526126c0810151612740526126e081015161276052612700810151612780525060a051612b6e57600f6127a0527f696e76616c6964206c6f616e20696400000000000000000000000000000000006127c0526127a0506127a051806127c001601f825f031636823750506308c379a061276052602061278052601f19601f6127a051011660440161277cfd5b60e051421115612bdd5760156127a0527f6c6f616e206d61747572697479207265616368656400000000000000000000006127c0526127a0506127a051806127c001601f825f031636823750506308c379a061276052602061278052601f19601f6127a051011660440161277cfd5b6127405115612c4b5760116127a0527f6c6f616e20616c726561647920706169640000000000000000000000000000006127c0526127a0506127a051806127c001601f825f031636823750506308c379a061276052602061278052601f19601f6127a051011660440161277cfd5b5f6101205160648111613f0e578015612d3c57905b606081026101400180516127a05260208101516127c05260408101516127e052506040516127a05118612c9b576044356127c0511815612c9d565b5f5b15612d315760085463dc75c0c56128605233612880526040516128a0526044356128c05260075463856e8488612800526020612800600461281c845afa612ce6573d5f5f3e3d5ffd5b60203d10613f0e57612800518060a01c613f0e57612840526128409050516128e05260605161290052803b15613f0e575f61286060a461287c5f855af1612d2f573d5f5f3e3d5ffd5b505b600101818118612c60575b5050005b505b5f5ffd5b5f6125e0525f60405160648111613f0e578015612da457905b60608102606001805161260052602081015161262052604081015161264052506125e05161264051808201828110613f0e57905090506125e052600101818118612d5f575b50506125e051815250565b5f6125e0525f60405160648111613f0e578015612e9d57905b6060810260600180516132805260208101516132a05260408101516132c052506132805160016132e0525f6125e05160648111613f0e578015612e2b57905b8060051b61260001518318612e20575f6132e052612e2b565b600101818118612e07575b50506132e051905015612e6c576125e05160638111613f0e57613280518160051b6126000152600181016125e052505f600d613280516020525f5260405f20555b600d613280516020525f5260405f2080546132c051808201828110613f0e5790509050815550600101818118612dc8575b50505f6125e05160648111613f0e578015612f9057905b8060051b612600015161328052600a5463f8ba072b61332052600d613280516020525f5260405f20546133405261328051613360526006546133805260075463a6def0a06132c05260206132c060046132dc845afa612f15573d5f5f3e3d5ffd5b60203d10613f0e576132c0518060a01c613f0e57613300526133009050516133a0526020613320608461333c845afa612f50573d5f5f3e3d5ffd5b60203d10613f0e57613320518060011c613f0e576133c0526133c09050516132a0526132a051612f85575f8352505050612f98565b600101818118612eb4575b505060018152505b565b604051606051808203828111613f0e579050905060a051612710810281612710820418613f0e57905060805160c05160e051808201828110613f0e579050905062093a8081811862093a80831102189050808202811583838304141715613f0e5790509050808201828110613f0e5790509050808202811583838304141715613f0e579050905060a051612710810281612710820418613f0e5790508015613f0e5780820490509050815250565b604051606051808203828111613f0e5790509050604051606051808203828111613f0e57905090506080518015613f0e5780820690509050808203828111613f0e5790509050815250565b5f612740525f60c05160648111613f0e57801561314457905b6060810260e00180516133e052602081015161340052604081015161342052506127405160638111613f0e577fff8e2078b59bfb7feec7622e414c417495d08ff9057c3dbf9d26636d7a16019f613460526133e05161348052613400516134a052613420516134c0526080613440526134408051602082012090508160051b61276001526001810161274052506001018181186130ac575b50507f27c10cc7ba799b99d7c1a1eedc44a5087817851cb95e5c4c3fdd98186fb40bb8614de052604051614e0052606051614e2052608051614e405260a051614e60526020806134205280613420015f612740518083528060051b5f8260648111613f0e5780156131cf57905b8060051b61276001518160051b6020880101526001018181186131b1575b505082016020019150509050810190506134005261340060c0518060051b818160051c18613f0e57905081518160400111613f0e576040602083010181614100838360045afa5050806140e0526140e090509050805160208201209050614e805261266051614ea05261268051614ec0526126a051614ee0526126c051614f0052610140614dc052614dc08051602082012090506133e0525f6002613420527f190100000000000000000000000000000000000000000000000000000000000061344052613420805160208201836134e00181518152505080830192505050600f54613480526133e0516134a052604061346052613460805160208201836134e0018281848460045afa50505080830192505050806134c0526134c090508051602082012090506134005261340051613440526126e051613460526127005161348052612720516134a05260205f608061344060015afa505f516134205261342051815250565b600554156133a3576016617600527f636f6e74726163742069732064657072656361746564000000000000000000006176205261760050617600518061762001601f825f031636823750506308c379a06175c05260206175e052601f19601f6176005101166044016175dcfd5b60045461340f57601f617600527f636f6e7472616374206973206e6f7420616363657074696e67206c6f616e73006176205261760050617600518061762001601f825f031636823750506308c379a06175c05260206175e052601f19601f6176005101166044016175dcfd5b614f6051421061347e576017617600527f6d6174757269747920697320696e2074686520706173740000000000000000006176205261760050617600518061762001601f825f031636823750506308c379a06175c05260206175e052601f19601f6176005101166044016175dcfd5b617540514211156134ee576013617600527f646561646c696e652068617320706173736564000000000000000000000000006176205261760050617600518061762001601f825f031636823750506308c379a06175c05260206175e052601f19601f6176005101166044016175dcfd5b614f2051614f80516060810280606082614fa060045afa50508060405250613517617600612d46565b617600511815613586576020617620527f616d6f756e7420696e20636f6c6c61747320213d207468616e20616d6f756e746176405261762050617620518061764001601f825f031636823750506308c379a06175e052602061760052601f19601f6176205101166044016175fcfd5b614f205160075463172b8500617600526020617600600461761c845afa6135af573d5f5f3e3d5ffd5b60203d10613f0e576176009050511015613628576016617640527f696e73756666696369656e74206c6971756964697479000000000000000000006176605261764050617640518061766001601f825f031636823750506308c379a061760052602061762052601f19601f61764051011660440161761cfd5b600a5463985b50b0617600523361762052614f20516176405260065461766052600754617680526020617600608461761c845afa613668573d5f5f3e3d5ffd5b60203d10613f0e57617600518060011c613f0e576176a0526176a09050516136ef57601e6176c0527f6d6178206c6f616e7320706f6f6c2073686172652073757270617373656400006176e0526176c0506176c051806176e001601f825f031636823750506308c379a06176805260206176a052601f19601f6176c051011660440161769cfd5b614f80516060810280606082614fa060045afa50508060405250613714617600612daf565b6176005161378157601e617620527f6d617820636f6c6c656374696f6e2073686172652073757270617373656400006176405261762050617620518061764001601f825f031636823750506308c379a06175e052602061760052601f19601f6176205101166044016175fcfd5b60065463fdfda91261760052336176205261756051617640526020617600604461761c845afa6137b3573d5f5f3e3d5ffd5b60203d10613f0e57617600518060011c613f0e57617660526176609050511561383b576014617680527f6c6f616e20616c726561647920637265617465640000000000000000000000006176a0526176805061768051806176a001601f825f031636823750506308c379a061764052602061766052601f19601f61768051011660440161765cfd5b617560511561390a5760065463fdfda9126176005233617620526175605160018103818111613f0e579050617640526020617600604461761c845afa613883573d5f5f3e3d5ffd5b60203d10613f0e57617600518060011c613f0e576176605261766090505161390a576016617680527f6c6f616e206973206e6f742073657175656e7469616c000000000000000000006176a0526176805061768051806176a001601f825f031636823750506308c379a061764052602061766052601f19601f61768051011660440161765cfd5b33604052614f2051606052614f4051608052614f605160a052614f8051606081028060e082614fa060045afa50508060c0525061752051612660526175405161268052617560516126a052617580516126c0526175a0516126e0526175c051612700526175e05161272052613980617620613093565b61762051617600526001546176005118156139fa576019617620527f696e76616c6964206d657373616765207369676e6174757265000000000000006176405261762050617620518061764001601f825f031636823750506308c379a06175e052602061760052601f19601f6176205101166044016175fcfd5b61758051613a09576001613a58565b33600b54636352211e6176205261758051617640526020617620602461763c845afa613a37573d5f5f3e3d5ffd5b60203d10613f0e57617620518060a01c613f0e576176605261766090505118155b613ac1576016617680527f67656e65736973546f6b656e206e6f74206f776e6564000000000000000000006176a0526176805061768051806176a001601f825f031636823750506308c379a061764052602061766052601f19601f61768051011660440161765cfd5b6006546326b7f5966176405260a03361766052614f205161768052614f40516176a052614f60516176c052806176e05280617660015f614f8051808352606081025f8260648111613f0e578015613b4a57905b60608102602087010160608202614fa0018051825260208101516020830152604081015160408301525050600101818118613b14575b50508201602001915050905081015050602061764061264461765c5f855af1613b75573d5f5f3e3d5ffd5b60203d10613f0e57617640905051617620525f614f805160648111613f0e578015613cf557905b60608102614fa0018051617640526020810151617660526040810151617680525060065463c4836b976176a052336176c052617640516176e052617660516177005261768051617720526176205161774052803b15613f0e575f6176a060a46176bc5f855af1613c0e573d5f5f3e3d5ffd5b5060065463f7230a756176a052617640516176c052617660516176e05261768051617700525f61772052803b15613f0e575f6176a060846176bc5f855af1613c58573d5f5f3e3d5ffd5b506008546311e459606177005233617720526176405161774052617660516177605260075463856e84886176a05260206176a060046176bc845afa613c9f573d5f5f3e3d5ffd5b60203d10613f0e576176a0518060a01c613f0e576176e0526176e090505161778052617520516177a052803b15613f0e575f61770060a461771c5f855af1613ce9573d5f5f3e3d5ffd5b50600101818118613b9c575b5050337f4a558778654b4d21f09ae7e2aa4eebc0de757d1233dc825b43183a1276a7b2a1610100336176a052617620516176c05260075463856e8488617640526020617640600461765c845afa613d4e573d5f5f3e3d5ffd5b60203d10613f0e57617640518060a01c613f0e57617680526176809050516176e052614f405161016d81028161016d820418613f0e5790506201518081028162015180820418613f0e579050614f605142808203828111613f0e57905090508015613f0e578082049050905061770052614f205161772052614f605142808203828111613f0e5790509050617740528061776052806176a0015f614f8051808352606081025f8260648111613f0e578015613e3b57905b60608102602087010160608202614fa0018051825260208101516020830152604081015160408301525050600101818118613e05575b5050820160200191505090508101905061758051617780526176a0a2600654634700e8bd6176405233617660526176205161768052803b15613f0e575f617640604461765c5f855af1613e90573d5f5f3e3d5ffd5b5060065463e10cc41a6176405233617660526176205161768052803b15613f0e575f617640604461765c5f855af1613eca573d5f5f3e3d5ffd5b5060065463c9876fbb6176405233617660526176205161768052803b15613f0e575f617640604461765c5f855af1613f04573d5f5f3e3d5ffd5b5061762051815250565b5f80fda165767970657283000309000b
Verified Source Code Partial Match
Compiler: v0.3.9+commit.66b96705
EVM: cancun
Loans.vy 855 lines
# @version 0.3.9
"""
@title Loans
@author [Zharta](https://zharta.io/)
@notice The loans contract exists as the main interface to create peer-to-pool NFT-backed loans
@dev Uses a `LoansCore` contract to store state
"""
# Interfaces
from vyper.interfaces import ERC165 as IERC165
from vyper.interfaces import ERC721 as IERC721
from vyper.interfaces import ERC20 as IERC20
interface ILoansCore:
def isLoanCreated(_borrower: address, _loanId: uint256) -> bool: view
def isLoanStarted(_borrower: address, _loanId: uint256) -> bool: view
def getLoan(_borrower: address, _loanId: uint256) -> Loan: view
def addCollateralToLoan(_borrower: address, _collateral: Collateral, _loanId: uint256): nonpayable
def removeCollateralFromLoan(_borrower: address, _collateral: Collateral, _loanId: uint256): nonpayable
def updateCollaterals(_collateral: Collateral, _toRemove: bool): nonpayable
def addLoan(_borrower: address, _amount: uint256, _interest: uint256, _maturity: uint256, _collaterals: DynArray[Collateral, 100]) -> uint256: nonpayable
def updateLoanStarted(_borrower: address, _loanId: uint256): nonpayable
def updateLoanPaidAmount(_borrower: address, _loanId: uint256, _paidPrincipal: uint256, _paidInterestAmount: uint256): nonpayable
def updatePaidLoan(_borrower: address, _loanId: uint256): nonpayable
def updateDefaultedLoan(_borrower: address, _loanId: uint256): nonpayable
def updateHighestSingleCollateralLoan(_borrower: address, _loanId: uint256): nonpayable
def updateHighestCollateralBundleLoan(_borrower: address, _loanId: uint256): nonpayable
def updateHighestRepayment(_borrower: address, _loanId: uint256): nonpayable
def updateHighestDefaultedLoan(_borrower: address, _loanId: uint256): nonpayable
interface ICollateralVaultPeripheral:
def storeCollateral(_wallet: address, _collateralAddress: address, _tokenId: uint256, _erc20TokenContract: address, _createDelegation: bool): nonpayable
def transferCollateralFromLoan(_wallet: address, _collateralAddress: address, _tokenId: uint256, _erc20TokenContract: address): nonpayable
def isCollateralApprovedForVault(_borrower: address, _collateralAddress: address, _tokenId: uint256) -> bool: view
def setCollateralDelegation(_wallet: address, _collateralAddress: address, _tokenId: uint256, _erc20TokenContract: address, _value: bool): nonpayable
interface ILiquidityControls:
def withinLoansPoolShareLimit(_borrower: address, _amount: uint256, _loansCoreContractAddress: address, _lpPeripheralContractAddress: address) -> bool: view
def withinCollectionShareLimit(_amount: uint256, _collectionAddress: address, _loansCoreContractAddress: address, _lpCoreContractAddress: address) -> bool: view
interface IERC20Symbol:
def symbol() -> String[100]: view
interface ILendingPoolPeripheral:
def maxFundsInvestable() -> uint256: view
def erc20TokenContract() -> address: view
def sendFundsEth(_to: address, _amount: uint256): nonpayable
def sendFunds(_to: address, _amount: uint256): nonpayable
def receiveFundsEth(_borrower: address, _amount: uint256, _rewardsAmount: uint256): payable
def receiveFunds(_borrower: address, _amount: uint256, _rewardsAmount: uint256): payable
def lendingPoolCoreContract() -> address: view
interface ILiquidationsPeripheral:
def addLiquidation(_borrower: address, _loanId: uint256, _erc20TokenContract: address): nonpayable
# Structs
struct Collateral:
contractAddress: address
tokenId: uint256
amount: uint256
struct Loan:
id: uint256
amount: uint256
interest: uint256 # parts per 10000, e.g. 2.5% is represented by 250 parts per 10000
maturity: uint256
startTime: uint256
collaterals: DynArray[Collateral, 100]
paidPrincipal: uint256
paidInterestAmount: uint256
started: bool
invalidated: bool
paid: bool
defaulted: bool
canceled: bool
struct EIP712Domain:
name: String[100]
version: String[10]
chain_id: uint256
verifying_contract: address
struct ReserveMessageContent:
amount: uint256
interest: uint256
maturity: uint256
collaterals: DynArray[Collateral, 100]
delegations: DynArray[bool, 100]
deadline: uint256
# Events
event OwnershipTransferred:
ownerIndexed: indexed(address)
proposedOwnerIndexed: indexed(address)
owner: address
proposedOwner: address
erc20TokenContract: address
event OwnerProposed:
ownerIndexed: indexed(address)
proposedOwnerIndexed: indexed(address)
owner: address
proposedOwner: address
erc20TokenContract: address
event InterestAccrualPeriodChanged:
erc20TokenContractIndexed: indexed(address)
currentValue: uint256
newValue: uint256
erc20TokenContract: address
event LendingPoolPeripheralAddressSet:
erc20TokenContractIndexed: indexed(address)
currentValue: address
newValue: address
erc20TokenContract: address
event CollateralVaultPeripheralAddressSet:
erc20TokenContractIndexed: indexed(address)
currentValue: address
newValue: address
erc20TokenContract: address
event LiquidationsPeripheralAddressSet:
erc20TokenContractIndexed: indexed(address)
currentValue: address
newValue: address
erc20TokenContract: address
event LiquidityControlsAddressSet:
erc20TokenContractIndexed: indexed(address)
currentValue: address
newValue: address
erc20TokenContract: address
event ContractStatusChanged:
erc20TokenContractIndexed: indexed(address)
value: bool
erc20TokenContract: address
event ContractDeprecated:
erc20TokenContractIndexed: indexed(address)
erc20TokenContract: address
event LoanCreated:
walletIndexed: indexed(address)
wallet: address
loanId: uint256
erc20TokenContract: address
apr: uint256 # calculated from the interest to 365 days, in bps
amount: uint256
duration: uint256
collaterals: DynArray[Collateral, 100]
genesisToken: uint256
event LoanPayment:
walletIndexed: indexed(address)
wallet: address
loanId: uint256
principal: uint256
interestAmount: uint256
erc20TokenContract: address
event LoanPaid:
walletIndexed: indexed(address)
wallet: address
loanId: uint256
erc20TokenContract: address
event LoanDefaulted:
walletIndexed: indexed(address)
wallet: address
loanId: uint256
amount: uint256
erc20TokenContract: address
event PaymentSent:
walletIndexed: indexed(address)
wallet: address
amount: uint256
event PaymentReceived:
walletIndexed: indexed(address)
wallet: address
amount: uint256
# Global variables
owner: public(address)
admin: public(address)
proposedOwner: public(address)
interestAccrualPeriod: public(uint256)
isAcceptingLoans: public(bool)
isDeprecated: public(bool)
loansCoreContract: public(address)
lendingPoolPeripheralContract: public(address)
collateralVaultPeripheralContract: public(address)
liquidationsPeripheralContract: public(address)
liquidityControlsContract: public(address)
genesisContract: public(address)
isPayable: public(bool)
collectionsAmount: HashMap[address, uint256] # aux variable
ZHARTA_DOMAIN_NAME: constant(String[6]) = "Zharta"
ZHARTA_DOMAIN_VERSION: constant(String[1]) = "1"
COLLATERAL_TYPE_DEF: constant(String[66]) = "Collateral(address contractAddress,uint256 tokenId,uint256 amount)"
RESERVE_TYPE_DEF: constant(String[269]) = "ReserveMessageContent(address borrower,uint256 amount,uint256 interest,uint256 maturity,Collateral[] collaterals," \
"bool delegations,uint256 deadline,uint256 nonce,uint256 genesisToken)" \
"Collateral(address contractAddress,uint256 tokenId,uint256 amount)"
DOMAIN_TYPE_HASH: constant(bytes32) = keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)")
COLLATERAL_TYPE_HASH: constant(bytes32) = keccak256(COLLATERAL_TYPE_DEF)
RESERVE_TYPE_HASH: constant(bytes32) = keccak256(RESERVE_TYPE_DEF)
reserve_message_typehash: bytes32
reserve_sig_domain_separator: bytes32
MINIMUM_INTEREST_PERIOD: constant(uint256) = 604800 # 7 days
@external
def __init__(
_interestAccrualPeriod: uint256,
_loansCoreContract: address,
_lendingPoolPeripheralContract: address,
_collateralVaultPeripheralContract: address,
_genesisContract: address,
_isPayable: bool
):
assert _loansCoreContract != empty(address), "address is the zero address"
assert _lendingPoolPeripheralContract != empty(address), "address is the zero address"
assert _collateralVaultPeripheralContract != empty(address), "address is the zero address"
assert _genesisContract != empty(address), "address is the zero address"
self.owner = msg.sender
self.admin = msg.sender
self.interestAccrualPeriod = _interestAccrualPeriod
self.loansCoreContract = _loansCoreContract
self.lendingPoolPeripheralContract = _lendingPoolPeripheralContract
self.collateralVaultPeripheralContract = _collateralVaultPeripheralContract
self.genesisContract = _genesisContract
self.isAcceptingLoans = True
self.isPayable = _isPayable
self.reserve_sig_domain_separator = keccak256(
_abi_encode(
DOMAIN_TYPE_HASH,
keccak256(ZHARTA_DOMAIN_NAME),
keccak256(ZHARTA_DOMAIN_VERSION),
chain.id,
self
)
)
@pure
@internal
def _collateralsAmounts(_collaterals: DynArray[Collateral, 100]) -> uint256:
sumAmount: uint256 = 0
for collateral in _collaterals:
sumAmount += collateral.amount
return sumAmount
@internal
def _withinCollectionShareLimit(_collaterals: DynArray[Collateral, 100]) -> bool:
collections: DynArray[address, 100] = empty(DynArray[address, 100])
for collateral in _collaterals:
if collateral.contractAddress not in collections:
collections.append(collateral.contractAddress)
self.collectionsAmount[collateral.contractAddress] = 0
self.collectionsAmount[collateral.contractAddress] += collateral.amount
for collection in collections:
result: bool = ILiquidityControls(self.liquidityControlsContract).withinCollectionShareLimit(
self.collectionsAmount[collection],
collection,
self.loansCoreContract,
ILendingPoolPeripheral(self.lendingPoolPeripheralContract).lendingPoolCoreContract()
)
if not result:
return False
return True
@pure
@internal
def _loanPayableAmount(
_amount: uint256,
_paidAmount: uint256,
_interest: uint256,
_maxLoanDuration: uint256,
_timePassed: uint256,
_interestAccrualPeriod: uint256
) -> uint256:
return (_amount - _paidAmount) * (10000 * _maxLoanDuration + _interest * (max(_timePassed + _interestAccrualPeriod, MINIMUM_INTEREST_PERIOD))) / (10000 * _maxLoanDuration)
@pure
@internal
def _computePeriodPassedInSeconds(_recentTimestamp: uint256, _olderTimestamp: uint256, _period: uint256) -> uint256:
return (_recentTimestamp - _olderTimestamp) - ((_recentTimestamp - _olderTimestamp) % _period)
@internal
def _recoverReserveSigner(
_borrower: address,
_amount: uint256,
_interest: uint256,
_maturity: uint256,
_collaterals: DynArray[Collateral, 100],
_delegations: bool,
_deadline: uint256,
_nonce: uint256,
_genesisToken: uint256,
_v: uint256,
_r: uint256,
_s: uint256
) -> address:
"""
@notice recovers the sender address of the signed reserve function call
"""
collaterals_data_hash: DynArray[bytes32, 100] = []
for c in _collaterals:
collaterals_data_hash.append(keccak256(_abi_encode(COLLATERAL_TYPE_HASH, c.contractAddress, c.tokenId, c.amount)))
data_hash: bytes32 = keccak256(_abi_encode(
RESERVE_TYPE_HASH,
_borrower,
_amount,
_interest,
_maturity,
keccak256(slice(_abi_encode(collaterals_data_hash), 32*2, 32*len(_collaterals))),
_delegations,
_deadline,
_nonce,
_genesisToken
))
sig_hash: bytes32 = keccak256(concat(convert("\x19\x01", Bytes[2]), _abi_encode(self.reserve_sig_domain_separator, data_hash)))
signer: address = ecrecover(sig_hash, _v, _r, _s)
return signer
@internal
def _reserve(
_amount: uint256,
_interest: uint256,
_maturity: uint256,
_collaterals: DynArray[Collateral, 100],
_delegations: bool,
_deadline: uint256,
_nonce: uint256,
_genesisToken: uint256,
_v: uint256,
_r: uint256,
_s: uint256
) -> uint256:
assert not self.isDeprecated, "contract is deprecated"
assert self.isAcceptingLoans, "contract is not accepting loans"
assert block.timestamp < _maturity, "maturity is in the past"
assert block.timestamp <= _deadline, "deadline has passed"
assert self._collateralsAmounts(_collaterals) == _amount, "amount in collats != than amount"
assert ILendingPoolPeripheral(self.lendingPoolPeripheralContract).maxFundsInvestable() >= _amount, "insufficient liquidity"
assert ILiquidityControls(self.liquidityControlsContract).withinLoansPoolShareLimit(
msg.sender,
_amount,
self.loansCoreContract,
self.lendingPoolPeripheralContract
), "max loans pool share surpassed"
assert self._withinCollectionShareLimit(_collaterals), "max collection share surpassed"
assert not ILoansCore(self.loansCoreContract).isLoanCreated(msg.sender, _nonce), "loan already created"
if _nonce > 0:
assert ILoansCore(self.loansCoreContract).isLoanCreated(msg.sender, _nonce - 1), "loan is not sequential"
signer: address = self._recoverReserveSigner(msg.sender, _amount, _interest, _maturity, _collaterals, _delegations, _deadline, _nonce, _genesisToken, _v, _r, _s)
assert signer == self.admin, "invalid message signature"
assert _genesisToken == 0 or IERC721(self.genesisContract).ownerOf(_genesisToken) == msg.sender, "genesisToken not owned"
newLoanId: uint256 = ILoansCore(self.loansCoreContract).addLoan(
msg.sender,
_amount,
_interest,
_maturity,
_collaterals
)
for collateral in _collaterals:
ILoansCore(self.loansCoreContract).addCollateralToLoan(msg.sender, collateral, newLoanId)
ILoansCore(self.loansCoreContract).updateCollaterals(collateral, False)
ICollateralVaultPeripheral(self.collateralVaultPeripheralContract).storeCollateral(
msg.sender,
collateral.contractAddress,
collateral.tokenId,
ILendingPoolPeripheral(self.lendingPoolPeripheralContract).erc20TokenContract(),
_delegations
)
log LoanCreated(
msg.sender,
msg.sender,
newLoanId,
ILendingPoolPeripheral(self.lendingPoolPeripheralContract).erc20TokenContract(),
_interest * 365 * 86400 / (_maturity - block.timestamp),
_amount,
_maturity - block.timestamp,
_collaterals,
_genesisToken
)
ILoansCore(self.loansCoreContract).updateLoanStarted(msg.sender, newLoanId)
ILoansCore(self.loansCoreContract).updateHighestSingleCollateralLoan(msg.sender, newLoanId)
ILoansCore(self.loansCoreContract).updateHighestCollateralBundleLoan(msg.sender, newLoanId)
return newLoanId
@external
def proposeOwner(_address: address):
assert msg.sender == self.owner, "msg.sender is not the owner"
assert _address != empty(address), "_address it the zero address"
assert self.owner != _address, "proposed owner addr is the owner"
assert self.proposedOwner != _address, "proposed owner addr is the same"
self.proposedOwner = _address
log OwnerProposed(
self.owner,
_address,
self.owner,
_address,
ILendingPoolPeripheral(self.lendingPoolPeripheralContract).erc20TokenContract()
)
@external
def claimOwnership():
assert msg.sender == self.proposedOwner, "msg.sender is not the proposed"
log OwnershipTransferred(
self.owner,
self.proposedOwner,
self.owner,
self.proposedOwner,
ILendingPoolPeripheral(self.lendingPoolPeripheralContract).erc20TokenContract()
)
self.owner = self.proposedOwner
self.proposedOwner = empty(address)
@external
def changeInterestAccrualPeriod(_value: uint256):
"""
@notice Sets the interest accrual period, considered on loan payment calculations
@dev Logs `InterestAccrualPeriodChanged` event
@param _value The interest accrual period in seconds
"""
assert msg.sender == self.owner, "msg.sender is not the owner"
assert _value != self.interestAccrualPeriod, "_value is the same"
log InterestAccrualPeriodChanged(
ILendingPoolPeripheral(self.lendingPoolPeripheralContract).erc20TokenContract(),
self.interestAccrualPeriod,
_value,
ILendingPoolPeripheral(self.lendingPoolPeripheralContract).erc20TokenContract()
)
self.interestAccrualPeriod = _value
@external
def setLendingPoolPeripheralAddress(_address: address):
assert msg.sender == self.owner, "msg.sender is not the owner"
assert _address != empty(address), "_address is the zero address"
assert self.lendingPoolPeripheralContract != _address, "new LPPeriph addr is the same"
log LendingPoolPeripheralAddressSet(
ILendingPoolPeripheral(self.lendingPoolPeripheralContract).erc20TokenContract(),
self.lendingPoolPeripheralContract,
_address,
ILendingPoolPeripheral(self.lendingPoolPeripheralContract).erc20TokenContract()
)
self.lendingPoolPeripheralContract = _address
@external
def setCollateralVaultPeripheralAddress(_address: address):
assert msg.sender == self.owner, "msg.sender is not the owner"
assert _address != empty(address), "_address is the zero address"
assert self.collateralVaultPeripheralContract != _address, "new LPCore addr is the same"
log CollateralVaultPeripheralAddressSet(
ILendingPoolPeripheral(self.lendingPoolPeripheralContract).erc20TokenContract(),
self.collateralVaultPeripheralContract,
_address,
ILendingPoolPeripheral(self.lendingPoolPeripheralContract).erc20TokenContract()
)
self.collateralVaultPeripheralContract = _address
@external
def setLiquidationsPeripheralAddress(_address: address):
assert msg.sender == self.owner, "msg.sender is not the owner"
assert _address != empty(address), "_address is the zero address"
assert self.liquidationsPeripheralContract != _address, "new LPCore addr is the same"
log LiquidationsPeripheralAddressSet(
ILendingPoolPeripheral(self.lendingPoolPeripheralContract).erc20TokenContract(),
self.liquidationsPeripheralContract,
_address,
ILendingPoolPeripheral(self.lendingPoolPeripheralContract).erc20TokenContract()
)
self.liquidationsPeripheralContract = _address
@external
def setLiquidityControlsAddress(_address: address):
assert msg.sender == self.owner, "msg.sender is not the owner"
assert _address != empty(address), "_address is the zero address"
assert _address != self.liquidityControlsContract, "new value is the same"
log LiquidityControlsAddressSet(
ILendingPoolPeripheral(self.lendingPoolPeripheralContract).erc20TokenContract(),
self.liquidityControlsContract,
_address,
ILendingPoolPeripheral(self.lendingPoolPeripheralContract).erc20TokenContract()
)
self.liquidityControlsContract = _address
@external
def changeContractStatus(_flag: bool):
assert msg.sender == self.owner, "msg.sender is not the owner"
assert self.isAcceptingLoans != _flag, "new contract status is the same"
self.isAcceptingLoans = _flag
log ContractStatusChanged(
ILendingPoolPeripheral(self.lendingPoolPeripheralContract).erc20TokenContract(),
_flag,
ILendingPoolPeripheral(self.lendingPoolPeripheralContract).erc20TokenContract()
)
@external
def deprecate():
assert msg.sender == self.owner, "msg.sender is not the owner"
assert not self.isDeprecated, "contract is already deprecated"
self.isDeprecated = True
self.isAcceptingLoans = False
log ContractDeprecated(
ILendingPoolPeripheral(self.lendingPoolPeripheralContract).erc20TokenContract(),
ILendingPoolPeripheral(self.lendingPoolPeripheralContract).erc20TokenContract()
)
@view
@external
def erc20TokenSymbol() -> String[100]:
return IERC20Symbol(ILendingPoolPeripheral(self.lendingPoolPeripheralContract).erc20TokenContract()).symbol()
@view
@external
def getLoanPayableAmount(_borrower: address, _loanId: uint256, _timestamp: uint256) -> uint256:
loan: Loan = ILoansCore(self.loansCoreContract).getLoan(_borrower, _loanId)
if loan.paid:
return 0
if loan.startTime > _timestamp:
return max_value(uint256)
if loan.started:
timePassed: uint256 = self._computePeriodPassedInSeconds(
_timestamp,
loan.startTime,
self.interestAccrualPeriod
)
return self._loanPayableAmount(
loan.amount,
loan.paidPrincipal,
loan.interest,
loan.maturity - loan.startTime,
timePassed,
self.interestAccrualPeriod
)
return max_value(uint256)
@external
def reserve(
_amount: uint256,
_interest: uint256,
_maturity: uint256,
_collaterals: DynArray[Collateral, 100],
_delegations: bool,
_deadline: uint256,
_nonce: uint256,
_genesisToken: uint256,
_v: uint256,
_r: uint256,
_s: uint256
) -> uint256:
"""
@notice Creates a new loan with the defined amount, interest rate and collateral. The message must be signed by the contract admin.
@dev Logs `LoanCreated` event. The last 3 parameters must match a signature by the contract admin of the implicit message consisting of the remaining parameters, in order for the loan to be created
@param _amount The loan amount in wei
@param _interest The interest rate in bps (1/1000) for the loan duration
@param _maturity The loan maturity in unix epoch format
@param _collaterals The list of collaterals supporting the loan
@param _delegations Wether to set the requesting wallet as a delegate for all collaterals
@param _deadline The deadline of validity for the signed message in unix epoch format
@param _genesisToken The optional Genesis Pass token used to determine the loan conditions, must be > 0
@param _v recovery id for public key recover
@param _r r value in ECDSA signature
@param _s s value in ECDSA signature
@return The loan id
"""
newLoanId: uint256 = self._reserve(_amount, _interest, _maturity, _collaterals, _delegations, _deadline, _nonce, _genesisToken, _v, _r, _s)
ILendingPoolPeripheral(self.lendingPoolPeripheralContract).sendFunds(
msg.sender,
_amount
)
return newLoanId
@external
def reserveEth(
_amount: uint256,
_interest: uint256,
_maturity: uint256,
_collaterals: DynArray[Collateral, 100],
_delegations: bool,
_deadline: uint256,
_nonce: uint256,
_genesisToken: uint256,
_v: uint256,
_r: uint256,
_s: uint256
) -> uint256:
"""
@notice Creates a new loan with the defined amount, interest rate and collateral. The message must be signed by the contract admin.
@dev Logs `LoanCreated` event. The last 3 parameters must match a signature by the contract admin of the implicit message consisting of the remaining parameters, in order for the loan to be created
@param _amount The loan amount in wei
@param _interest The interest rate in bps (1/1000) for the loan duration
@param _maturity The loan maturity in unix epoch format
@param _collaterals The list of collaterals supporting the loan
@param _delegations Wether to set the requesting wallet as a delegate for all collaterals
@param _deadline The deadline of validity for the signed message in unix epoch format
@param _genesisToken The optional Genesis Pass token used to determine the loan conditions, must be > 0
@param _v recovery id for public key recover
@param _r r value in ECDSA signature
@param _s s value in ECDSA signature
@return The loan id
"""
newLoanId: uint256 = self._reserve(_amount, _interest, _maturity, _collaterals, _delegations, _deadline, _nonce, _genesisToken, _v, _r, _s)
ILendingPoolPeripheral(self.lendingPoolPeripheralContract).sendFundsEth(
msg.sender,
_amount
)
return newLoanId
@payable
@external
def pay(_loanId: uint256):
"""
@notice Closes an active loan by paying the full amount
@dev Logs the `LoanPayment` and `LoanPaid` events. The associated `LendingPoolCore` contract must be approved for the payment amount
@param _loanId The id of the loan to settle
"""
receivedAmount: uint256 = msg.value
if not self.isPayable:
assert receivedAmount == 0, "no ETH allowed for this loan"
assert ILoansCore(self.loansCoreContract).isLoanStarted(msg.sender, _loanId), "loan not found"
loan: Loan = ILoansCore(self.loansCoreContract).getLoan(msg.sender, _loanId)
assert block.timestamp <= loan.maturity, "loan maturity reached"
assert not loan.paid, "loan already paid"
# compute days passed in seconds
timePassed: uint256 = self._computePeriodPassedInSeconds(
block.timestamp,
loan.startTime,
self.interestAccrualPeriod
)
# pro-rata computation of max amount payable based on actual loan duration in days
paymentAmount: uint256 = self._loanPayableAmount(
loan.amount,
loan.paidPrincipal,
loan.interest,
loan.maturity - loan.startTime,
timePassed,
self.interestAccrualPeriod
)
erc20TokenContract: address = ILendingPoolPeripheral(self.lendingPoolPeripheralContract).erc20TokenContract()
excessAmount: uint256 = 0
if receivedAmount > 0:
assert receivedAmount >= paymentAmount, "insufficient value received"
excessAmount = receivedAmount - paymentAmount
log PaymentReceived(msg.sender, msg.sender, receivedAmount)
else:
assert IERC20(erc20TokenContract).balanceOf(msg.sender) >= paymentAmount, "insufficient balance"
assert IERC20(erc20TokenContract).allowance(
msg.sender,
ILendingPoolPeripheral(self.lendingPoolPeripheralContract).lendingPoolCoreContract()
) >= paymentAmount, "insufficient allowance"
paidInterestAmount: uint256 = paymentAmount - loan.amount
ILoansCore(self.loansCoreContract).updateLoanPaidAmount(msg.sender, _loanId, loan.amount, paidInterestAmount)
ILoansCore(self.loansCoreContract).updatePaidLoan(msg.sender, _loanId)
ILoansCore(self.loansCoreContract).updateHighestRepayment(msg.sender, _loanId)
if receivedAmount > 0:
ILendingPoolPeripheral(self.lendingPoolPeripheralContract).receiveFundsEth(msg.sender, loan.amount, paidInterestAmount, value=paymentAmount)
log PaymentSent(self.lendingPoolPeripheralContract, self.lendingPoolPeripheralContract, paymentAmount)
else:
ILendingPoolPeripheral(self.lendingPoolPeripheralContract).receiveFunds(msg.sender, loan.amount, paidInterestAmount)
for collateral in loan.collaterals:
ILoansCore(self.loansCoreContract).removeCollateralFromLoan(msg.sender, collateral, _loanId)
ILoansCore(self.loansCoreContract).updateCollaterals(collateral, True)
ICollateralVaultPeripheral(self.collateralVaultPeripheralContract).transferCollateralFromLoan(
msg.sender,
collateral.contractAddress,
collateral.tokenId,
erc20TokenContract
)
if excessAmount > 0:
send(msg.sender, excessAmount)
log PaymentSent(msg.sender, msg.sender,excessAmount)
log LoanPayment(
msg.sender,
msg.sender,
_loanId,
loan.amount,
paidInterestAmount,
erc20TokenContract
)
log LoanPaid(
msg.sender,
msg.sender,
_loanId,
erc20TokenContract
)
@external
def settleDefault(_borrower: address, _loanId: uint256):
"""
@notice Settles an active loan as defaulted
@dev Logs the `LoanDefaulted` event, removes the collaterals from the loan and creates a liquidation
@param _borrower The wallet address of the borrower
@param _loanId The id of the loan to settle
"""
assert msg.sender == self.admin, "msg.sender is not the admin"
assert ILoansCore(self.loansCoreContract).isLoanStarted(_borrower, _loanId), "loan not found"
loan: Loan = ILoansCore(self.loansCoreContract).getLoan(_borrower, _loanId)
assert not loan.paid, "loan already paid"
assert block.timestamp > loan.maturity, "loan is within maturity period"
assert self.liquidationsPeripheralContract != empty(address), "BNPeriph is the zero address"
ILoansCore(self.loansCoreContract).updateDefaultedLoan(_borrower, _loanId)
ILoansCore(self.loansCoreContract).updateHighestDefaultedLoan(_borrower, _loanId)
for collateral in loan.collaterals:
ILoansCore(self.loansCoreContract).removeCollateralFromLoan(_borrower, collateral, _loanId)
ILoansCore(self.loansCoreContract).updateCollaterals(collateral, True)
ILiquidationsPeripheral(self.liquidationsPeripheralContract).addLiquidation(
_borrower,
_loanId,
ILendingPoolPeripheral(self.lendingPoolPeripheralContract).erc20TokenContract()
)
log LoanDefaulted(
_borrower,
_borrower,
_loanId,
loan.amount,
ILendingPoolPeripheral(self.lendingPoolPeripheralContract).erc20TokenContract()
)
@external
def setDelegation(_loanId: uint256, _collateralAddress: address, _tokenId: uint256, _value: bool):
"""
@notice Sets / unsets a delegation for some collateral of a given loan. Only available to unpaid loans until maturity is reached
@param _loanId The id of the loan to settle
@param _collateralAddress The contract address of the collateral
@param _tokenId The token id of the collateral
@param _value Wether to set or unset the token delegation
"""
loan: Loan = ILoansCore(self.loansCoreContract).getLoan(msg.sender, _loanId)
assert loan.amount > 0, "invalid loan id"
assert block.timestamp <= loan.maturity, "loan maturity reached"
assert not loan.paid, "loan already paid"
for collateral in loan.collaterals:
if collateral.contractAddress ==_collateralAddress and collateral.tokenId == _tokenId:
ICollateralVaultPeripheral(self.collateralVaultPeripheralContract).setCollateralDelegation(
msg.sender,
_collateralAddress,
_tokenId,
ILendingPoolPeripheral(self.lendingPoolPeripheralContract).erc20TokenContract(),
_value
)
Read Contract
admin 0xf851a440 → address
collateralVaultPeripheralContract 0xd38835db → address
erc20TokenSymbol 0x49071820 → string
genesisContract 0xd8e99f92 → address
getLoanPayableAmount 0xe535754e → uint256
interestAccrualPeriod 0xf511b6f7 → uint256
isAcceptingLoans 0x20cc187d → bool
isDeprecated 0xc7178230 → bool
isPayable 0xce46e046 → bool
lendingPoolPeripheralContract 0xbbb6bbc6 → address
liquidationsPeripheralContract 0x8f009906 → address
liquidityControlsContract 0xbfe767ea → address
loansCoreContract 0x2bf65d9d → address
owner 0x8da5cb5b → address
proposedOwner 0xd153b60c → address
Write Contract 14 functions
These functions modify contract state and require a wallet transaction to execute.
changeContractStatus 0x4b6c36b5
bool _flag
changeInterestAccrualPeriod 0x6f257213
uint256 _value
claimOwnership 0x4e71e0c8
No parameters
deprecate 0x0fcc0c28
No parameters
pay 0xc290d691
uint256 _loanId
proposeOwner 0xb5ed298a
address _address
reserve 0x2482e86d
uint256 _amount
uint256 _interest
uint256 _maturity
tuple[] _collaterals
bool _delegations
uint256 _deadline
uint256 _nonce
uint256 _genesisToken
uint256 _v
uint256 _r
uint256 _s
returns: uint256
reserveEth 0x1a79890a
uint256 _amount
uint256 _interest
uint256 _maturity
tuple[] _collaterals
bool _delegations
uint256 _deadline
uint256 _nonce
uint256 _genesisToken
uint256 _v
uint256 _r
uint256 _s
returns: uint256
setCollateralVaultPeripheralAddress 0x4f401e29
address _address
setDelegation 0xe3f1a982
uint256 _loanId
address _collateralAddress
uint256 _tokenId
bool _value
setLendingPoolPeripheralAddress 0x54858bf3
address _address
setLiquidationsPeripheralAddress 0xdfe5cf4e
address _address
setLiquidityControlsAddress 0x7eefa487
address _address
settleDefault 0x7a964a32
address _borrower
uint256 _loanId
Recent Transactions
No transactions found for this address