Address Contract Partially Verified
Address
0x5F19431BC8A3eb21222771c6C867a63a119DeDA7
Balance
0 ETH
Nonce
1
Code Size
23541 bytes
Creator
0x5723759D...5190 at tx 0x9bcc9439...199eb5
Indexed Transactions
0
Contract Bytecode
23541 bytes
0x5f3560e01c6002601f820660011b615a9701601e395f51565b638da5cb5b81186100335734615a93575f5460405260206040f35b6361acb5598118613d0857602436103417615a935760076004356020525f5260405f205460405260206040f3613d08565b63885753de81186100805734615a935760015460405260206040f35b63ffa1ad748118613d085734615a935760208060805260176040527f5032504c656e64696e674e6674732e323032343130303200000000000000000060605260408160800181518152602082015160208201528051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506080f3613d08565b63331c658781186101205734615a93576020615ad560403960206040f35b6305107f058118613d085761022436103417615a93576004356004018035610c60526020810135610c80526040810135610ca0526060810135610cc0526080810135610ce05260a08101358060a01c615a9357610d005260c0810135610d205260e0810135610d40526101008101358060a01c615a9357610d60526101208101358060a01c615a9357610d80526101408101358060a01c615a9357610da052610160810135610dc05261018081013581016004813511615a935780355f8160048111615a9357801561023e57905b8060071b610e00018160071b602086010180358060041c615a93578252602081013560208301526040810135604083015260608101358060a01c615a9357606083015250506001018181186101ee575b505080610de05250506101a08101358060011c615a9357611000526101c08101358060a01c615a935761102052506103e06108606103e0610c6060045afa50610288611040615308565b611040516102f557600c611060527f696e76616c6964206c6f616e00000000000000000000000000000000000000006110805261106050611060518061108001601f825f031636823750506308c379a061102052602061104052601f19601f61106051011660440161103cfd5b610d20514211610364576012611040527f6c6f616e206e6f742064656661756c74656400000000000000000000000000006110605261104050611040518061106001601f825f031636823750506308c379a061100052602061102052601f19601f61104051011660440161101cfd5b610d805160405261037661104061533d565b611040516103e357600a611060527f6e6f74206c656e646572000000000000000000000000000000000000000000006110805261106050611060518061108001601f825f031636823750506308c379a061102052602061104052601f19601f61106051011660440161103cfd5b5f6002610c60516020525f5260405f2055610d805161022052610da05161024052610dc0516102605261041461588c565b611020511561043e5761102051604052610da051606052610dc0516080525f60a05261043e6152b1565b7f4a55c2facef4f87dd498aace39997457e1fc66968956bfe3ac7f20f736e77e74610c605161104052610d605161106052610d805161108052610da0516110a052610dc0516110c05260a0611040a100613d08565b63c4a9081581186104c057602436103417615a935760026004356020525f5260405f205460405260206040f35b639544fa7c8118613d0857604436103417615a93576004358060a01c615a93576040526024358060011c615a93576060525f543318156105565760096080527f6e6f74206f776e6572000000000000000000000000000000000000000000000060a0526080506080518060a001601f825f031636823750506308c379a06040526020606052601f19601f6080510116604401605cfd5b60605160086040516020525f5260405f20557f5e09e79221e29a6d762b708b6fa399e730dfc027f946b2e81a31d849b2fb1fa960405160805260605160a05260406080a100613d08565b63e5107ed781186105be5734615a93576020615af560403960206040f35b63c2a5022b8118613d0857604436103417615a93575f543318156106375760096040527f6e6f74206f776e6572000000000000000000000000000000000000000000000060605260405060405180606001601f825f031636823750506308c379a05f526020602052601f19601f6040510116604401601cfd5b6020615b555f395f5160043511156106a45760176040527f757066726f6e74206665652065786365656473206d617800000000000000000060605260405060405180606001601f825f031636823750506308c379a05f526020602052601f19601f6040510116604401601cfd5b6020615b755f395f51602435111561071157601a6040527f736574746c656d656e74206665652065786365656473206d617800000000000060605260405060405180606001601f825f031636823750506308c379a05f526020602052601f19601f6040510116604401601cfd5b7f4bfb2e8697c06dccd3777bdd9b4dab854905ca53b2a56bb47882c744729729d46004546040526005546060526040600460803760806040a160043560045560243560055500613d08565b635556eda98118613d085734615a93576020615b1560403960206040f3613d08565b637719e9ea811861079c5734615a93576020615b3560403960206040f35b639274bbcd8118613d0857602436103417615a93576004358060a01c615a935760405260096040516020525f5260405f205460605260206060f3613d08565b6367db749981186107f75734615a935760035460405260206040f35b63f8c266298118613d085734615a93576020615b9560403960206040f3613d08565b6358e7783781186108355734615a935760045460405260206040f35b63f7a79a028118613d085734615a93576001543318156108aa5760166040527f6e6f74207468652070726f706f736564206f776e65720000000000000000000060605260405060405180606001601f825f031636823750506308c379a05f526020602052601f19601f6040510116604401601cfd5b7f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f5460405260015460605260406040a1335f555f60015500613d08565b6361dd0b8b8118613d085734615a935760055460405260206040f3613d08565b6350d0d5ad8118613d085734615a93576020615b5560403960206040f3613d08565b6387c8f69481186109485734615a93576020615b7560403960206040f35b63a1c7a5678118613d08576103a436103417615a935760406004610860376044358060a01c615a93576108a0526064356108c052606060846108e03760e4358060a01c615a935761094052610104358060031c615a935761096052610124356109805260a06101446109a0376101e4358060a01c615a9357610a4052610204358060011c615a9357610a60526040610224610a80376060610264610ac0376102e4356004016020813511615a9357803560208160051b018083610b2037505050610304358060a01c615a9357610f4052610364358060a01c615a9357610f60526102c060406102c061086060045afa50610a405161030052610a4b610f80613d0c565b610f8051610ab857601a610fa0527f6f66666572206e6f74207369676e6564206279206c656e646572000000000000610fc052610fa050610fa05180610fc001601f825f031636823750506308c379a0610f60526020610f8052601f19601f610fa0510116604401610f7cfd5b42610a205111610b2757600d610f80527f6f66666572206578706972656400000000000000000000000000000000000000610fa052610f8050610f805180610fa001601f825f031636823750506308c379a0610f40526020610f6052601f19601f610f80510116604401610f5cfd5b6020615ad55f395f516108a0511815610b9f576015610f80527f696e76616c6964207061796d656e7420746f6b656e0000000000000000000000610fa052610f8050610f805180610fa001601f825f031636823750506308c379a0610f40526020610f6052601f19601f610f80510116604401610f5cfd5b610860516108e0511115610c1257601c610f80527f6f726967696e6174696f6e20666565206774207072696e636970616c00000000610fa052610f8050610f805180610fa001601f825f031636823750506308c379a0610f40526020610f6052601f19601f610f80510116604401610f5cfd5b6020615b355f395f516356108f8a610fc0526109e051610fe0526040610fc06024610fdc5f855af1610c46573d5f5f3e3d5ffd5b60403d10615a9357610fc0518060a01c615a935761102052610fe0516110405261102090508051610f80526020810151610fa05250610260604061026061086060045afa506102c4356102a052610f80516102c052610fa0516102e052610b205160208160051b018061030082610b2060045afa505050610cc5613e1f565b610260604061026061086060045afa5060406103246102a037610f60516102e052610cf16111e0614104565b6111e0805160208160071b0180610fc0828560045afa505050505f6111e0525f610fc05160048111615a93578015610d7457905b8060071b610fe001805161120052602081015161122052604081015161124052606081015161126052506111e05161122051808201828110615a9357905090506111e052600101818118610d25575b50506102c060406102c061086060045afa50610d9161122061452b565b61122051611200525f611220526112005161124052610aa051611260526108605161128052610880516112a0526108a0516112c052426108c051808201828110615a9357905090506112e05242611300526008336020525f5260405f2054610df95733610dfb565b325b61132052610a405161134052610f8051611360526102c43561138052610fc05160208160071b01806113a082610fc060045afa505050610a60516115c052610f40516115e0526103e060406103e061122060045afa50610e5c611600614574565b61160051611220526002611220516020525f5260405f205415610ede576013611600527f6c6f616e20616c726561647920657869737473000000000000000000000000006116205261160050611600518061162001601f825f031636823750506308c379a06115c05260206115e052601f19601f6116005101166044016115dcfd5b6102c06103a06102c061086060045afa50610ef7614636565b6103e060406103e061122060045afa50610f126116006147a6565b611600516002611220516020525f5260405f2055611320516102a052611360516102c052611380516102e052610f46614e87565b6113405160405261132051606052611280516111e051808203828111615a93579050905061090051808201828110615a935790509050608052610f876151ed565b5f610fc05160048111615a9357801561100b57905b8060071b610fe0018051611600526020810151611620526040810151611640526060810151611660525060026116005114610fdc57611620511515610fde565b5f5b15611000576113405160405261166051606052611620516080526110006151ed565b600101818118610f9c575b5050610f40511561103857610f40516040526113605160605261138051608052600160a0526110386152b1565b7f6827a33d0a24e36314681156d8d9a7d20d6a0548c169735fe25e00c9d38ac5a96101e0611220516116005261128051611620526112a051611640526112c051611660526112e05161168052611300516116a052611320516116c052611340516116e05261136051611700526113805161172052806117405280611600015f6113a0518083528060071b5f8260048111615a9357801561111457905b8060071b60208701018160071b6113c0018051825260208101516020830152604081015160408301526060810151606083015250506001018181186110d4575b505082016020019150509050810190506115c051611760526112005161178052610aa0516117a052610f40516117c052611600a16020611220f3613d08565b631b0b0c638118613d085734615a93576020615bb560403960206040f3613d08565b63225daa0f8118613d0857602436103417615a935760066004356020525f5260405f205460405260206040f3613d08565b6396069a5f8118613d0857602436103417615a93576004358060a01c615a935760405260086040516020525f5260405f205460605260206060f3613d08565b6372e76f13811861130a57602436103417615a93576004358060a01c615a93576040525f5433181561126d5760096060527f6e6f74206f776e6572000000000000000000000000000000000000000000000060805260605060605180608001601f825f031636823750506308c379a06020526020604052601f19601f6060510116604401603cfd5b6040516112d057601a6060527f77616c6c657420697320746865207a65726f206164647265737300000000000060805260605060605180608001601f825f031636823750506308c379a06020526020604052601f19601f6060510116604401603cfd5b7f6defa6e1a7dcc97f459fb552cf25427ab19cd60692b94e4f38660850a6e917e860035460605260405160805260406060a1604051600355005b63c75b6e5e8118613d08576102c436103417615a935760406004610780376044358060a01c615a93576107c0526064356107e052606060846108003760e4358060a01c615a935761086052610104358060031c615a935761088052610124356108a05260a06101446108c0376101e4358060a01c615a935761096052610204358060011c615a93576109805260406102246109a03760606102646109e037610960516040526113ba610a4061533d565b610a405161142757600a610a60527f6e6f74206c656e64657200000000000000000000000000000000000000000000610a8052610a6050610a605180610a8001601f825f031636823750506308c379a0610a20526020610a4052601f19601f610a60510116604401610a3cfd5b42610940511161149657600d610a40527f6f66666572206578706972656400000000000000000000000000000000000000610a6052610a4050610a405180610a6001601f825f031636823750506308c379a0610a00526020610a2052601f19601f610a40510116604401610a1cfd5b6102c060406102c061078060045afa5061096051610300526114b9610a40613d0c565b610a405161152657601a610a60527f6f66666572206e6f74207369676e6564206279206c656e646572000000000000610a8052610a6050610a605180610a8001601f825f031636823750506308c379a0610a20526020610a4052601f19601f610a60510116604401610a3cfd5b6102c060406102c061078060045afa50611541610a6061452b565b610a6051610a40526007610a40516020525f5260405f2054156115c3576015610a60527f6f6666657220616c7265616479207265766f6b65640000000000000000000000610a8052610a6050610a605180610a8001601f825f031636823750506308c379a0610a20526020610a4052601f19601f610a60510116604401610a3cfd5b610a40516040526102c060606102c061078060045afa506115e26145dd565b00613d08565b63bc71771d8118613d0857602436103417615a93576004358060a01c615a93576040525f543318156116705760096060527f6e6f74206f776e6572000000000000000000000000000000000000000000000060805260605060605180608001601f825f031636823750506308c379a06020526020604052601f19601f6060510116604401603cfd5b6040516116d35760106060527f5f61646472657373206973207a65726f0000000000000000000000000000000060805260605060605180608001601f825f031636823750506308c379a06020526020604052601f19601f6060510116604401603cfd5b7f722cace8a9cbcb7713f3f71015c8c6b59ed317672489140eb6b3fa7f4a139d845f5460605260405160805260406060a160405160015500613d08565b63802d67998118613d085761022436103417615a93576004356004018035610c60526020810135610c80526040810135610ca0526060810135610cc0526080810135610ce05260a08101358060a01c615a9357610d005260c0810135610d205260e0810135610d40526101008101358060a01c615a9357610d60526101208101358060a01c615a9357610d80526101408101358060a01c615a9357610da052610160810135610dc05261018081013581016004813511615a935780355f8160048111615a9357801561182e57905b8060071b610e00018160071b602086010180358060041c615a93578252602081013560208301526040810135604083015260608101358060a01c615a9357606083015250506001018181186117de575b505080610de05250506101a08101358060011c615a9357611000526101c08101358060a01c615a935761102052506103e06108606103e0610c6060045afa50611878611040615308565b611040516118e557600c611060527f696e76616c6964206c6f616e00000000000000000000000000000000000000006110805261106050611060518061108001601f825f031636823750506308c379a061102052602061104052601f19601f61106051011660440161103cfd5b610d205142111561195557600e611040527f6c6f616e2064656661756c7465640000000000000000000000000000000000006110605261104050611040518061106001601f825f031636823750506308c379a061100052602061102052601f19601f61104051011660440161101cfd5b610d605160405261196761104061533d565b611040516119d457600c611060527f6e6f7420626f72726f77657200000000000000000000000000000000000000006110805261106050611060518061108001601f825f031636823750506308c379a061102052602061104052601f19601f61106051011660440161103cfd5b6103e060406103e0610c6060045afa506119ef611060615370565b6110605161104052604036611060375f611220526103e060406103e0610c6060045afa506110405161042052611a266112406153da565b61124080516020606082020180611080828560045afa5050506101a0810151611060526101c081015161122052505f6002610c60516020525f5260405f2055610ca051604052611a746154f5565b610d6051604052610cc05161104051808201828110615a93579050905061122051808201828110615a935790509050606052611aae615517565b610d8051604052610cc05161104051808201828110615a93579050905061106051808203828111615a93579050905061122051808201828110615a935790509050606052611afa6155d6565b5f6110805160048111615a93578015611b5157905b606081026110a001805161124052602081015161126052604081015161128052506112805160405261126051606052611b466155d6565b600101818118611b0f575b5050610d605161022052610da05161024052610dc05161026052611b7361588c565b6110205115611b9d5761102051604052610da051606052610dc0516080525f60a052611b9d6152b1565b7f2aa6f229bb00348f1aa98ab5ab1636a2618696536f698200d76b66a87906eafa60e0610c605161124052610d605161126052610d805161128052610d00516112a052610cc0516112c052611040516112e052806113005280611240015f61108051808352606081025f8260048111615a93578015611c4e57905b606081026020870101606082026110a0018051825260208101516020830152604081015160408301525050600101818118611c18575b50508201602001915050905081019050611240a100613d08565b6313c072ee8118613d085761058436103417615a93576004356004018035610c60526020810135610c80526040810135610ca0526060810135610cc0526080810135610ce05260a08101358060a01c615a9357610d005260c0810135610d205260e0810135610d40526101008101358060a01c615a9357610d60526101208101358060a01c615a9357610d80526101408101358060a01c615a9357610da052610160810135610dc05261018081013581016004813511615a935780355f8160048111615a93578015611d8657905b8060071b610e00018160071b602086010180358060041c615a93578252602081013560208301526040810135604083015260608101358060a01c615a935760608301525050600101818118611d36575b505080610de05250506101a08101358060011c615a9357611000526101c08101358060a01c615a9357611020525060406024611040376064358060a01c615a9357611080526084356110a052606060a46110c037610104358060a01c615a935761112052610124358060031c615a935761114052610144356111605260a061016461118037610204358060a01c615a935761122052610224358060011c615a93576112405260406102446112603760606102846112a0376102e4356004016020813511615a9357803560208160051b01808361130037505050610344358060a01c615a9357611720526103e06108606103e0610c6060045afa50611e8b611740615308565b61174051611ef857600c611760527f696e76616c6964206c6f616e00000000000000000000000000000000000000006117805261176050611760518061178001601f825f031636823750506308c379a061172052602061174052601f19601f61176051011660440161173cfd5b610d6051604052611f0a61174061533d565b61174051611f7757600c611760527f6e6f7420626f72726f77657200000000000000000000000000000000000000006117805261176050611760518061178001601f825f031636823750506308c379a061172052602061174052601f19601f61176051011660440161173cfd5b610d2051421115611fe757600e611740527f6c6f616e2064656661756c7465640000000000000000000000000000000000006117605261174050611740518061176001601f825f031636823750506308c379a061170052602061172052601f19601f61174051011660440161171cfd5b6102c060406102c061104060045afa50611220516103005261200a611740613d0c565b6117405161207757601a611760527f6f66666572206e6f74207369676e6564206279206c656e6465720000000000006117805261176050611760518061178001601f825f031636823750506308c379a061172052602061174052601f19601f61176051011660440161173cfd5b4261120051116120e657600d611740527f6f666665722065787069726564000000000000000000000000000000000000006117605261174050611740518061176001601f825f031636823750506308c379a061170052602061172052601f19601f61174051011660440161171cfd5b6020615ad55f395f5161108051181561215e576015611740527f696e76616c6964207061796d656e7420746f6b656e00000000000000000000006117605261174050611740518061176001601f825f031636823750506308c379a061170052602061172052601f19601f61174051011660440161171cfd5b611040516110c05111156121d157601c611740527f6f726967696e6174696f6e20666565206774207072696e636970616c000000006117605261174050611740518061176001601f825f031636823750506308c379a061170052602061172052601f19601f61174051011660440161171cfd5b6020615b355f395f516356108f8a611780526111c0516117a0526040611780602461179c5f855af1612205573d5f5f3e3d5ffd5b60403d10615a9357611780518060a01c615a93576117e0526117a051611800526117e0905080516117405260208101516117605250610260604061026061104060045afa50610dc0516102a052611740516102c052611760516102e0526113005160208160051b01806103008261130060045afa505050612284613e1f565b610da0516117405118156122f757601c611780527f636f6c6c61746572616c20636f6e7472616374206d69736d61746368000000006117a0526117805061178051806117a001601f825f031636823750506308c379a061174052602061176052601f19601f61178051011660440161175cfd5b6102c06103a06102c061104060045afa50612310614636565b610ca05160405261231f6154f5565b611040518060ff1c615a9357610cc0518060ff1c615a93578082038281135f831218615a935790509050611780526103e060406103e0610c6060045afa506123686117c0615370565b6117c0516117a0526040366117c0375f611980526103e060406103e0610c6060045afa506117a0516104205261239f6119a06153da565b6119a0805160206060820201806117e0828560045afa5050506101a08101516117c0526101c08101516119805250610260604061026061104060045afa5060406103046102a037611720516102e0526123f9611bc0614104565b611bc0805160208160071b01806119a0828560045afa505050505f611bc0525f6119a05160048111615a9357801561247c57905b8060071b6119c0018051611be0526020810151611c00526040810151611c20526060810151611c405250611bc051611c0051808201828110615a935790509050611bc05260010181811861242d575b50505f6002610c60516020525f5260405f205561178051611bc0516117a051808201828110615a93579050905061198051808201828110615a9357905090508060ff1c615a93578082038281135f831218615a9357905090506110e0518060ff1c615a93578082018281125f831218615a935790509050611be052610cc0516117a051808201828110615a9357905090506117c051808203828111615a93579050905061198051808201828110615a935790509050611c0052611040516110c051808203828111615a9357905090506110e051808201828110615a935790509050611c20527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff611be051136125c057610d6051604052611be051805f03600160ff1b82141582825f03141615615a935790505f8112615a93576060526125c0615517565b61122051610d8051146125fd5761122051604052611c20516060526125e3615517565b610d8051604052611c005160605261266c6155d65661266c565b611c2051611c00511161264457611c2051611c0051101561266c57610d8051604052611c2051611c0051808203828111615a93579050905060605261266c6155175661266c565b610d8051604052611c0051611c2051808203828111615a93579050905060605261266c6155d6565b6001611be0511261269457610d6051604052611be0515f8112615a93576060526126946155d6565b5f6117e05160048111615a935780156126eb57905b60608102611800018051611c40526020810151611c60526040810151611c805250611c8051604052611c60516060526126e06155d6565b6001018181186126a9575b50505f6119a05160048111615a9357801561276a57905b8060071b6119c0018051611c40526020810151611c60526040810151611c80526060810151611ca052506002611c40511461274257611c60511515612744565b5f5b1561275f57611ca051604052611c605160605261275f6155d6565b600101818118612702575b50506102c060406102c061104060045afa50612787611c6061452b565b611c6051611c40525f611c6052611c4051611c805261128051611ca05261104051611cc05261106051611ce05261108051611d0052426110a051808201828110615a935790509050611d205242611d4052610d6051611d605261122051611d805261174051611da052610dc051611dc0526119a05160208160071b0180611de0826119a060045afa505050611240516120005261102051612020526103e060406103e0611c6060045afa5061283d612040614574565b61204051611c60526002611c60516020525f5260405f2054156128bf576013612040527f6c6f616e20616c726561647920657869737473000000000000000000000000006120605261204050612040518061206001601f825f031636823750506308c379a061200052602061202052601f19601f61204051011660440161201cfd5b6103e060406103e0611c6060045afa506128da6120406147a6565b612040516002611c60516020525f5260405f20557fadf0e5d2eb7098352961e41ff94c8d5bd1e0d24910d7c8e7ae147610146fef21610240611c605161204052611cc05161206052611ce05161208052611d00516120a052611d20516120c052611d40516120e052611da05161210052611dc05161212052611d605161214052611d805161216052806121805280612040015f611de0518083528060071b5f8260048111615a935780156129ca57905b8060071b60208701018160071b611e000180518252602081015160208301526040810151604083015260608101516060830152505060010181811861298a575b50508201602001915050905081019050612000516121a052610c60516121c052610cc0516121e0526117a05161220052806122205280612040015f6117e051808352606081025f8260048111615a93578015612a5857905b60608102602087010160608202611800018051825260208101516020830152604081015160408301525050600101818118612a22575b50508201602001915050905081019050611c4051612240526112805161226052612040a16020611c60f3613d08565b63304b74ed8118613d085761052436103417615a93576004356004018035610c60526020810135610c80526040810135610ca0526060810135610cc0526080810135610ce05260a08101358060a01c615a9357610d005260c0810135610d205260e0810135610d40526101008101358060a01c615a9357610d60526101208101358060a01c615a9357610d80526101408101358060a01c615a9357610da052610160810135610dc05261018081013581016004813511615a935780355f8160048111615a93578015612ba557905b8060071b610e00018160071b602086010180358060041c615a93578252602081013560208301526040810135604083015260608101358060a01c615a935760608301525050600101818118612b55575b505080610de05250506101a08101358060011c615a9357611000526101c08101358060a01c615a9357611020525060406024611040376064358060a01c615a9357611080526084356110a052606060a46110c037610104358060a01c615a935761112052610124358060031c615a935761114052610144356111605260a061016461118037610204358060a01c615a935761122052610224358060011c615a93576112405260406102446112603760606102846112a0376102e4356004016020813511615a9357803560208160051b018083611300375050506103e06108606103e0610c6060045afa50612c9a611720615308565b61172051612d0757600c611740527f696e76616c6964206c6f616e00000000000000000000000000000000000000006117605261174050611740518061176001601f825f031636823750506308c379a061170052602061172052601f19601f61174051011660440161171cfd5b610d8051604052612d1961172061533d565b61172051612d8657600a611740527f6e6f74206c656e646572000000000000000000000000000000000000000000006117605261174050611740518061176001601f825f031636823750506308c379a061170052602061172052601f19601f61174051011660440161171cfd5b610d2051421115612df657600e611720527f6c6f616e2064656661756c7465640000000000000000000000000000000000006117405261172050611720518061174001601f825f031636823750506308c379a06116e052602061170052601f19601f6117205101166044016116fcfd5b6102c060406102c061104060045afa506112205161030052612e19611720613d0c565b61172051612e8657601a611740527f6f66666572206e6f74207369676e6564206279206c656e6465720000000000006117605261174050611740518061176001601f825f031636823750506308c379a061170052602061172052601f19601f61174051011660440161171cfd5b426112005111612ef557600d611720527f6f666665722065787069726564000000000000000000000000000000000000006117405261172050611720518061174001601f825f031636823750506308c379a06116e052602061170052601f19601f6117205101166044016116fcfd5b6020615ad55f395f51611080511815612f6d576015611720527f696e76616c6964207061796d656e7420746f6b656e00000000000000000000006117405261172050611720518061174001601f825f031636823750506308c379a06116e052602061170052601f19601f6117205101166044016116fcfd5b611040516110c0511115612fe057601c611720527f6f726967696e6174696f6e20666565206774207072696e636970616c000000006117405261172050611720518061174001601f825f031636823750506308c379a06116e052602061170052601f19601f6117205101166044016116fcfd5b610d2051426110a051808201828110615a935790509050101561306257601d611720527f6d61747572697479206265666f7265206c6f616e206d617475726974790000006117405261172050611720518061174001601f825f031636823750506308c379a06116e052602061170052601f19601f6117205101166044016116fcfd5b6020615b355f395f516356108f8a611760526111c051611780526040611760602461177c5f855af1613096573d5f5f3e3d5ffd5b60403d10615a9357611760518060a01c615a93576117c052611780516117e0526117c0905080516117205260208101516117405250610260604061026061104060045afa50610dc0516102a052611720516102c052611740516102e0526113005160208160051b01806103008261130060045afa505050613115613e1f565b610da05161172051181561318857601c611760527f636f6c6c61746572616c20636f6e7472616374206d69736d61746368000000006117805261176050611760518061178001601f825f031636823750506308c379a061172052602061174052601f19601f61176051011660440161173cfd5b6102c06103a06102c061104060045afa506131a1614636565b610ca0516040526131b06154f5565b611040518060ff1c615a9357610cc0518060ff1c615a93578082038281135f831218615a935790509050611760526103e060406103e0610c6060045afa506131f96117a0615370565b6117a051611780526040366117a0375f611960526103e060406103e0610c6060045afa5061178051610420526132306119806153da565b611980805160206060820201806117c0828560045afa5050506101a08101516117a0526101c08101516119605250610260604061026061104060045afa506060366102a037613280611ba0614104565b611ba0805160208160071b0180611980828560045afa505050505f611ba0525f6119805160048111615a9357801561330357905b8060071b6119a0018051611bc0526020810151611be0526040810151611c00526060810151611c205250611ba051611be051808201828110615a935790509050611ba0526001018181186132b4575b50505f6002610c60516020525f5260405f20556103e060406103e0610c6060045afa5061026061042061026061104060045afa506117805161068052611960516106a052613352611be06158ea565b611be051611bc052611bc0518060ff1c615a93576117805161196051808201828110615a9357905090508060ff1c615a9357611760518082038281135f831218615a935790509050808281188284130218905090505f8112615a9357611be05261176051611780518060ff1c615a93578082038281135f831218615a935790509050611960518060ff1c615a93578082038281135f831218615a935790509050611be0518060ff1c615a93578082018281125f831218615a935790509050611c0052610cc05161178051808201828110615a93579050905061196051808201828110615a9357905090506110e051808201828110615a9357905090508060ff1c615a9357611ba0516117a051808201828110615a935790509050611be051808201828110615a9357905090508060ff1c615a93578082038281135f831218615a935790509050611c2052611040516110c051808203828111615a9357905090506110e051808201828110615a935790509050611c40525f611c00511215613538576012611c60527f626f72726f7765722064656c7461203c20300000000000000000000000000000611c8052611c6050611c605180611c8001601f825f031636823750506308c379a0611c20526020611c4052601f19601f611c60510116604401611c3cfd5b61122051610d8051146135f7575f611c205112156135b5576010611c60527f6c656e6465722064656c7461203c203000000000000000000000000000000000611c8052611c6050611c605180611c8001601f825f031636823750506308c379a0611c20526020611c4052601f19601f611c60510116604401611c3cfd5b61122051604052611c40516060526135cb615517565b6001611c2051126136ec57610d8051604052611c20515f8112615a93576060526136ec6155d6566136ec565b611c2051611c40518060ff1c615a93578082038281135f831218615a935790509050611c60525f611c6051131561368d576010611c80527f6c656e6465722064656c7461203e203000000000000000000000000000000000611ca052611c8050611c805180611ca001601f825f031636823750506308c379a0611c40526020611c6052601f19601f611c80510116604401611c5cfd5b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff611c6051136136ec57610d8051604052611c6051805f03600160ff1b82141582825f03141615615a935790505f8112615a93576060526136ec615517565b6001611c00511261371457610d6051604052611c00515f8112615a93576060526137146155d6565b5f6117c05160048111615a9357801561376b57905b606081026117e0018051611c60526020810151611c80526040810151611ca05250611ca051604052611c80516060526137606155d6565b600101818118613729575b50505f6119805160048111615a935780156137ea57905b8060071b6119a0018051611c60526020810151611c80526040810151611ca0526060810151611cc052506002611c6051146137c257611c805115156137c4565b5f5b156137df57611cc051604052611c80516060526137df6155d6565b600101818118613782575b50506102c060406102c061104060045afa50613807611c8061452b565b611c8051611c60525f611c8052611c6051611ca05261128051611cc05261104051611ce05261106051611d005261108051611d2052426110a051808201828110615a935790509050611d405242611d6052610d6051611d805261122051611da05261172051611dc052610dc051611de0526119805160208160071b0180611e008261198060045afa505050611240516120205261102051612040526103e060406103e0611c8060045afa506138bd612060614574565b61206051611c80526002611c80516020525f5260405f20541561393f576013612060527f6c6f616e20616c726561647920657869737473000000000000000000000000006120805261206050612060518061208001601f825f031636823750506308c379a061202052602061204052601f19601f61206051011660440161203cfd5b6103e060406103e0611c8060045afa5061395a6120606147a6565b612060516002611c80516020525f5260405f20557f3104dd99ab576a709e2bea4bedb076e17210d16fdbc54a86b7db45e9f3be8284610260611c805161206052611ce05161208052611d00516120a052611d20516120c052611d40516120e052611d605161210052611dc05161212052611de05161214052611d805161216052611da05161218052806121a05280612060015f611e00518083528060071b5f8260048111615a93578015613a4a57905b8060071b60208701018160071b611e2001805182526020810151602083015260408101516040830152606081015160608301525050600101818118613a0a575b50508201602001915050905081019050612020516121c052610c60516121e052610cc051612200526117805161222052806122405280612060015f6117c051808352606081025f8260048111615a93578015613ad857905b606081026020870101606082026117e0018051825260208101516020830152604081015160408301525050600101818118613aa2575b50508201602001915050905081019050611be05161226052611c605161228052611280516122a052612060a16020611c80f3613d08565b638199abaf8118613d085734615a93576009336020525f5260405f2054613b8b5760146040527f6e6f2070656e64696e67207472616e736665727300000000000000000000000060605260405060405180606001601f825f031636823750506308c379a05f526020602052601f19601f6040510116604401601cfd5b6009336020525f5260405f20546040525f6009336020525f5260405f20556020615ad55f395f5163a9059cbb6060523360805260405160a052602060606044607c5f855af1613bdc573d5f5f3e3d5ffd5b60203d10615a93576060518060011c615a935760c05260c0905051613c5957601360e0527f6572726f722073656e64696e672066756e6473000000000000000000000000006101005260e05060e0518061010001601f825f031636823750506308c379a060a052602060c052601f19601f60e051011660440160bcfd5b7fb533bf65f7139533fed34316e420b8cefd0c9fb1730ceaf49fa4d0cd42341dd93360605260405160805260406060a100613d08565b63150b7a028118613d085760a436103417615a93576004358060a01c615a93576040526024358060a01c615a9357606052606435600401610400813511615a93576020813501808260803750507f150b7a02000000000000000000000000000000000000000000000000000000006104a05260206104a0f35b5f5ffd5b610300515f610760525f6002610320527f1901000000000000000000000000000000000000000000000000000000000000610340526103208051602082018361068001815181525050808301925050506020615bd5610620397fb54af15efd4078a08fa64b2ca6923174f13b55e91014d675bcae943a355f4335610380526102606103a0610260604060045afa50610280610360526103608051602082012090506106405260406106005261060080516020820183610680018281848460045afa50505080830192505050806106605261066090508051602082012090506106e0526102a051610700526102c051610720526102e05161074052602061076060806106e060015afa506107605114815250565b6102c051613e8c57601a610720527f636f6c6c61746572616c206e6f742077686974656c69737465640000000000006107405261072050610720518061074001601f825f031636823750506308c379a06106e052602061070052601f19601f6107205101166044016106fcfd5b60016101405118613f0e576102a051610160511815614102576015610720527f746f6b656e206964206e6f7420696e206f6666657200000000000000000000006107405261072050610720518061074001601f825f031636823750506308c379a06106e052602061070052601f19601f6107205101166044016106fcfd614102565b6002610140511861400357610180516102a0511015613f8c576019610720527f746f6b656e69642062656c6f77206f666665722072616e6765000000000000006107405261072050610720518061074001601f825f031636823750506308c379a06106e052602061070052601f19601f6107205101166044016106fcfd5b6101a0516102a0511115614102576019610720527f746f6b656e69642061626f7665206f666665722072616e6765000000000000006107405261072050610720518061074001601f825f031636823750506308c379a06106e052602061070052601f19601f6107205101166044016106fcfd614102565b6102c051610760526101e051610780526102a0516107a052606061074052610740805160208201209050610720525f6103005160208111615a9357801561408d57905b8060051b610320015161074052610740515f5260205f20610720515f5260205f20186107805260206107605261076080516020820120905061072052600101818118614046575b5050610720516102e051181561410257600d610740527f70726f6f6620696e76616c6964000000000000000000000000000000000000006107605261074050610740518061076001601f825f031636823750506308c379a061070052602061072052601f19601f61074051011660440161071cfd5b565b5f6103005260c051156141825760405160c051111561418257601c610520527f6f726967696e6174696f6e20666565206774207072696e636970616c000000006105405261052050610520518061054001601f825f031636823750506308c379a06104e052602061050052601f19601f6105205101166044016104fcfd5b6101005115614192576001614198565b60e05115155b1561420a576101205161420a57601a610520527f62726f6b65722066656520776974686f757420616464726573730000000000006105405261052050610520518061054001601f825f031636823750506308c379a06104e052602061050052601f19601f6105205101166044016104fcfd5b6102a0511561421a576001614221565b6102c05115155b15614293576102e05161429357601a610520527f62726f6b65722066656520776974686f757420616464726573730000000000006105405261052050610520518061054001601f825f031636823750506308c379a06104e052602061050052601f19601f6105205101166044016104fcfd5b6020615b955f395f5161010051111561430b57601d610520527f6c656e6465722062726f6b6572206665652065786365656473206d61780000006105405261052050610520518061054001601f825f031636823750506308c379a06104e052602061050052601f19601f6105205101166044016104fcfd5b6020615bb55f395f516102c051111561438357601f610520527f626f72726f7765722062726f6b6572206665652065786365656473206d6178006105405261052050610520518061054001601f825f031636823750506308c379a06104e052602061050052601f19601f6105205101166044016104fcfd5b61271060055461010051808201828110615a935790509050111561440657601c610520527f736574746c656d656e742066656573206774207072696e636970616c000000006105405261052050610520518061054001601f825f031636823750506308c379a06104e052602061050052601f19601f6105205101166044016104fcfd5b6103005160038111615a93578060071b6103200160018152600454604051808202811583838304141715615a93579050905061271081049050602082015260055460408201526003546060820152506001810161030052506103005160038111615a93578060071b610320016002815260c05160208201525f6040820152610220516060820152506001810161030052506103005160038111615a93578060071b610320016004815260e0516020820152610100516040820152610120516060820152506001810161030052506103005160038111615a93578060071b61032001600881526102a05160208201526102c05160408201526102e0516060820152506001810161030052506103005160208160071b0180838261030060045afa50505050565b5f6102a0518161032001526020810190506102c0518161032001526020810190506102e05181610320015260208101905080610300526103009050805160208201209050815250565b5f610140518161044001526020810190506101605181610440015260208101905061012051816104400152602081019050610180518161044001526020810190506101a05181610440015260208101905080610420526104209050805160208201209050815250565b600160076040516020525f5260405f20557f08f7f4fedc8c9bd3165579676da5b715f2babe388ed555519fcae0e56c2e507d6040516103205261024051610340526101e0516103605261016051610380526080610320a1565b6102c060406102c06103a060045afa5061465161068061452b565b61068051610660526007610660516020525f5260405f2054156146d357600d610680527f6f66666572207265766f6b6564000000000000000000000000000000000000006106a0526106805061068051806106a001601f825f031636823750506308c379a061064052602061066052601f19601f61068051011660440161065cfd5b60066105e0516020525f5260405f2054610680526105c05161068051106147595760146106a0527f6f666665722066756c6c79207574696c697a65640000000000000000000000006106c0526106a0506106a051806106c001601f825f031636823750506308c379a061066052602061068052601f19601f6106a051011660440161067cfd5b6106805160018101818110615a9357905060066105e0516020525f5260405f205560016104a051186147a457610660516040526102c060606102c06103a060045afa506147a46145dd565b565b6020806104405280610440016101e060405182526060516020830152608051604083015260a051606083015260c051608083015260e05160a08301526101005160c08301526101205160e08301526101405161010083015261016051610120830152610180516101408301526101a051610160830152806101808301528082015f6101c0518083528060071b5f8260048111615a9357801561488457905b8060071b60208701018160071b6101e001805182526020810151602083015260408101516040830152606081015160608301525050600101818118614844575b505082016020019150509050810190506103e0516101a0830152610400516101c083015290508101905061042052610420805160208201209050815250565b604051635817816860805260605160a052602060806024609c845afa6148eb573d5f5f3e3d5ffd5b60203d10615a93576080518060a01c615a935760c05260c0905051815250565b6020615b155f395f5163088f11f3610140526080516101605260a0610140602461015c845afa61493d573d5f5f3e3d5ffd5b60a03d10615a9357610140518060011c615a9357610200526101605161022052610180518060a01c615a9357610240526101a051610260526101c0518060a01c615a9357610280526102009050805160a052602081015160c052604081015160e0526060810151610100526080810151610120525060a0516149bf575f6149f5565b60805160c051186149f357610100516149ed57610120516149e15760016149f5565b306101205118156149f5565b5f6149f5565b5f5b815250565b60605163088f11f3610140526080516101605260a0610140602461015c845afa614a26573d5f5f3e3d5ffd5b60a03d10615a9357610140518060011c615a9357610200526101605161022052610180518060a01c615a9357610240526101a051610260526101c0518060a01c615a9357610280526102009050805160a052602081015160c052604081015160e0526060810151610100526080810151610120525060a051614b07576017610140527f636f6c6c61746572616c206e6f7420666f722073616c650000000000000000006101605261014050610140518061016001601f825f031636823750506308c379a061010052602061012052601f19601f61014051011660440161011cfd5b60805160c0511815614b7857601f610140527f636f6c6c61746572616c20776974682077726f6e672070756e6b496e646578006101605261014050610140518061016001601f825f031636823750506308c379a061010052602061012052601f19601f61014051011660440161011cfd5b60405160e0511815614be957601e610140527f636f6c6c61746572616c206e6f77206f776e65642062792077616c6c657400006101605261014050610140518061016001601f825f031636823750506308c379a061010052602061012052601f19601f61014051011660440161011cfd5b6101005115614c5757601c610140527f636f6c6c61746572616c206f66666572206973206e6f74207a65726f000000006101605261014050610140518061016001601f825f031636823750506308c379a061010052602061012052601f19601f61014051011660440161011cfd5b61012051614c66576001614c6e565b306101205118155b614cd7576020610140527f636f6c6c61746572616c20627579696e67206e6f7420617574686f72697a65646101605261014050610140518061016001601f825f031636823750506308c379a061010052602061012052601f19601f61014051011660440161011cfd5b606051638264fe986101405260805161016052803b15615a93575f610140602461015c5f855af1614d0a573d5f5f3e3d5ffd5b50565b604051636352211e60805260605160a052602060806024609c845afa614d35573d5f5f3e3d5ffd5b60203d10615a93576080518060a01c615a935760c05260c0905051815250565b60605163e985e9c560a05260405160c0523060e052602060a0604460bc845afa614d81573d5f5f3e3d5ffd5b60203d10615a935760a0518060011c615a935761010052610100905051614df4573060605163081812fc61012052608051610140526020610120602461013c845afa614dcf573d5f5f3e3d5ffd5b60203d10615a9357610120518060a01c615a9357610160526101609050511815614df7565b60015b815250565b60605163b88d4fde60c052608060405160e05230610100526080516101205280610140525f60a05260a08160e0015f81528051806020830101601f825f03163682375050601f19601f825160200101169050905081015050803b15615a93575f60c060a460dc5f855af1614e72573d5f5f3e3d5ffd5b50565b6020615b155f395f5160405114815250565b6102a051614ef4576015610300527f6164647220697320746865207a65726f206164647200000000000000000000006103205261030050610300518061032001601f825f031636823750506308c379a06102c05260206102e052601f19601f6103005101166044016102dcfd5b6102c051614f6157601c610300527f636f6c6c6174206164647220697320746865207a65726f2061646472000000006103205261030050610300518061032001601f825f031636823750506308c379a06102c05260206102e052601f19601f6103005101166044016102dcfd5b6102c051604052614f73610300614e75565b610300516150b5576102a0516102c0516040526102e051606052614f98610300614d0d565b61030051181561500757601e610320527f636f6c6c61746572616c206e6f74206f776e65642062792077616c6c657400006103405261032050610320518061034001601f825f031636823750506308c379a06102e052602061030052601f19601f6103205101166044016102fcfd5b6102a0516040526102c0516060526102e051608052615027610300614d55565b61030051615094576018610320527f7472616e73666572206973206e6f7420617070726f76656400000000000000006103405261032050610320518061034001601f825f031636823750506308c379a06102e052602061030052601f19601f6103205101166044016102fcfd5b6102a0516040526102c0516060526102e0516080526151eb614dfc566151eb565b6102a0516102c0516040526102e0516060526150d26103206148c3565b61032051181561514157601e610340527f636f6c6c61746572616c206e6f74206f776e65642062792077616c6c657400006103605261034050610340518061036001601f825f031636823750506308c379a061030052602061032052601f19601f61034051011660440161031cfd5b6102a0516040526102c0516060526102e05160805261516161032061490b565b610320516151ce576018610340527f7472616e73666572206973206e6f7420617070726f76656400000000000000006103605261034050610340518061036001601f825f031636823750506308c379a061030052602061032052601f19601f61034051011660440161031cfd5b6102a0516040526102c0516060526102e0516080526151eb6149fa565b565b6020615ad55f395f516323b872dd60a05260405160c05260605160e05260805161010052602060a0606460bc5f855af1615229573d5f5f3e3d5ffd5b60203d10615a935760a0518060011c615a9357610120526101209050516152af576013610140527f7472616e7366657246726f6d206661696c6564000000000000000000000000006101605261014050610140518061016001601f825f031636823750506308c379a061010052602061012052601f19601f61014051011660440161011cfd5b565b6020615af55f395f5163b18e2bbb60c05260405160e05260605161010052608051610120525f6101405260a05161016052602060c060a460dc5f855af16152fa573d5f5f3e3d5ffd5b60203d10615a935760c05050565b6103e060406103e061086060045afa50615323610c406147a6565b610c40516002610860516020525f5260405f205414815250565b604051331861534d57600161536b565b6008336020525f5260405f2054615364575f61536b565b3260405118155b815250565b6103e0516153875760c0518152506153d8566153d8565b60c0514261012051808203828111615a935790509050808202811583838304141715615a9357905090506101005161012051808203828111615a9357905090508015615a9357808204905090508152505b565b604036610440375f610600525f6101c05160048111615a935780156154c457905b8060071b6101e0018051610620526020810151610640526040810151610660526060810151610680525061066051156154b9576104205161066051808202811583838304141715615a935790509050612710810490506106a0526104605160038111615a935760608102610480016106205181526106a051602082015261068051604082015250600181016104605250610440516106a051808201828110615a93579050905061044052600861062051186154b9576106a051610600525b6001018181186153fb575b5050610460516020606082020180838261046060045afa505050610440516101a0820152610600516101c082015250565b60066040516020525f5260405f20805460018103818111615a93579050815550565b6020615ad55f395f516323b872dd60805260405160a0523060c05260605160e052602060806064609c5f855af1615550573d5f5f3e3d5ffd5b60203d10615a93576080518060011c615a9357610100526101009050516155d4576013610120527f7472616e7366657246726f6d206661696c6564000000000000000000000000006101405261012050610120518061014001601f825f031636823750506308c379a060e052602061010052601f19601f61012051011660440160fcfd5b565b6040366080376020615ad55f395f515a63a9059cbb60e4526004604051610104526060516101245260400160e05260e050602061018060e0516101005f8686f1905090506080523d602081183d602010021861016052610160805160a052602081015160c0525060805161564b57600161565a565b60c05160a05160200360031b1c155b156156b7577f1c43b9761b3fba5321ca8212bfc231945f668ccc0c446f333999eea9ce8fda8160405160e05260605161010052604060e0a160096040516020525f5260405f208054606051808201828110615a9357905090508155505b565b3061010051604052610120516060526156d36101406148c3565b61014051181561574257601d610160527f636f6c6c61746572616c206e6f74206f776e6564206279207661756c740000006101805261016050610160518061018001601f825f031636823750506308c379a061012052602061014052601f19601f61016051011660440161013cfd5b61010051638b72a2ec6101405260e051610160526101205161018052803b15615a93575f610140604461015c5f855af161577e573d5f5f3e3d5ffd5b50565b30610100516040526101205160605261579b610140614d0d565b61014051181561580a57601d610160527f636f6c6c61746572616c206e6f74206f776e6564206279207661756c740000006101805261016050610160518061018001601f825f031636823750506308c379a061012052602061014052601f19601f61016051011660440161013cfd5b6101005163b88d4fde610160526080306101805260e0516101a052610120516101c052806101e0525f6101405261014081610180015f81528051806020830101601f825f03163682375050601f19601f825160200101169050905081015050803b15615a93575f61016060a461017c5f855af1615889573d5f5f3e3d5ffd5b50565b6102405160405261589e610280614e75565b610280516158c9576102205160e052610240516101005261026051610120526158e8615781566158e8565b6102205160e052610240516101005261026051610120526158e86156b9565b565b5f6106c0525f6101c05160048111615a9357801561594d57905b8060071b6101e00180516106e0526020810151610700526040810151610720526060810151610740525060086106e0511861594257610720516106c0525b600101818118615904575b50506106205161595f57610440615968565b5f610700526107005b516106e0526106205161597b575f6159b0565b60c05161068051808203828111615a9357905090506106c051808202811583838304141715615a935790509050612710810490505b6107005260c05161068051808203828111615a93579050905061072052610620516159dd57610440615a21565b610440516101005142808203828111615a935790509050808202811583838304141715615a935790509050610480518015615a935780820490509050610760526107605b51610740526106e0518060ff1c615a9357610740518060ff1c615a9357610720518060ff1c615a93578082038281135f831218615a935790509050610700518060ff1c615a93578082038281135f831218615a935790509050808281188284130218905090505f8112615a9357815250565b5f80fd11e5075c08193c8f3d0807db2a873b0f09081c683d083d0800643d083d0817103d0801023d0811a608e805a0077e00183d080493092a3d081175115315e8000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000447e69651d841bd8d104bed493000000000000000000000000b47e3cd837ddf8e4c57f05d70ab865de6e193bbb000000000000000000000000a11704b3dd545dc0771d9a9c5572064db2a5c06200000000000000000000000000000000000000000000000000000000000013880000000000000000000000000000000000000000000000000000000000001388000000000000000000000000000000000000000000000000000000000000138800000000000000000000000000000000000000000000000000000000000013886d1b99f1a5c06364c839c0ed8aed09de5cb05b31a10190bbb613cede614558e4
Verified Source Code Partial Match
Compiler: v0.3.10+commit.91361694
P2PLendingNfts.vy 1195 lines
# @version 0.3.10
"""
@title P2PLendingNfts
@author [Zharta](https://zharta.io/)
@notice This contract facilitates peer-to-peer lending using NFTs as collateral.
@dev It facilitates peer-to-peer lending using NFTs as collateral.
The contract allows lenders to offer loans and borrowers to accept them by providing NFTs as collateral.
Key functionalities include:
- Creating and managing loan offers
- Accepting loan offers and locking NFTs as collateral
- Accepts ERC721 and CryptoPunks NFTs as collateral
- Delegating the collateral using [Delegate](https://delegate.xyz/) DelegateRegistry v2
- Settling loans by repaying the principal and interest
- Claiming collateral in case of loan default
- Replacing existing loans with new terms
- Four types of fees are supported: protocol fee, origination fee, lender broker fee, and borrower broker fee
- Managing protocol fees and authorized proxies
- Handling ownership transfer of the contract
- Loan state is kept hashed in the contract to save gas
The contract ensures secure and transparent lending operations within the Zharta ecosystem.
"""
# Interfaces
from vyper.interfaces import ERC165 as IERC165
from vyper.interfaces import ERC721 as IERC721
from vyper.interfaces import ERC20 as IERC20
interface CryptoPunksMarket:
def transferPunk(to: address, punkIndex: uint256): nonpayable
def buyPunk(punkIndex: uint256): payable
def punksOfferedForSale(punkIndex: uint256) -> PunkOffer: view
def punkIndexToAddress(punkIndex: uint256) -> address: view
def offerPunkForSaleToAddress(punkIndex: uint256, minSalePriceInWei: uint256, toAddress: address): nonpayable
interface DelegationRegistry:
def delegateERC721(delegate: address, contract: address, token_id: uint256, rights: bytes32, _value: bool) -> bytes32: nonpayable
interface P2PLendingControl:
def get_collection_status(collection_key_hash: bytes32) -> CollectionStatus: nonpayable
# Structs
PROOF_MAX_SIZE: constant(uint256) = 32
MAX_FEES: constant(uint256) = 4
BPS: constant(uint256) = 10000
enum FeeType:
PROTOCOL_FEE
ORIGINATION_FEE
LENDER_BROKER_FEE
BORROWER_BROKER_FEE
enum OfferType:
TOKEN
COLLECTION
TRAIT
struct Fee:
type: FeeType
upfront_amount: uint256
interest_bps: uint256
wallet: address
struct FeeAmount:
type: FeeType
amount: uint256
wallet: address
struct Offer:
principal: uint256
interest: uint256
payment_token: address
duration: uint256
origination_fee_amount: uint256
broker_upfront_fee_amount: uint256
broker_settlement_fee_bps: uint256
broker_address: address
offer_type: OfferType
token_id: uint256
token_range_min: uint256
token_range_max: uint256
collection_key_hash: bytes32
trait_hash: bytes32
expiration: uint256
lender: address
pro_rata: bool
size: uint256
tracing_id: bytes32
struct Signature:
v: uint256
r: uint256
s: uint256
struct SignedOffer:
offer: Offer
signature: Signature
struct Loan:
id: bytes32
offer_id: bytes32
offer_tracing_id: bytes32
amount: uint256 # principal - origination_fee_amount
interest: uint256
payment_token: address
maturity: uint256
start_time: uint256
borrower: address
lender: address
collateral_contract: address
collateral_token_id: uint256
fees: DynArray[Fee, MAX_FEES]
pro_rata: bool
delegate: address
struct CollectionStatus:
contract: address
trait_root: bytes32
struct PunkOffer:
isForSale: bool
punkIndex: uint256
seller: address
minValue: uint256
onlySellTo: address
event LoanCreated:
id: bytes32
amount: uint256
interest: uint256
payment_token: address
maturity: uint256
start_time: uint256
borrower: address
lender: address
collateral_contract: address
collateral_token_id: uint256
fees: DynArray[Fee, MAX_FEES]
pro_rata: bool
offer_id: bytes32
offer_tracing_id: bytes32
delegate: address
event LoanReplaced:
id: bytes32
amount: uint256
interest: uint256
payment_token: address
maturity: uint256
start_time: uint256
collateral_contract: address
collateral_token_id: uint256
borrower: address
lender: address
fees: DynArray[Fee, MAX_FEES]
pro_rata: bool
original_loan_id: bytes32
paid_principal: uint256
paid_interest: uint256
paid_settlement_fees: DynArray[FeeAmount, MAX_FEES]
offer_id: bytes32
offer_tracing_id: bytes32
event LoanReplacedByLender:
id: bytes32
amount: uint256
interest: uint256
payment_token: address
maturity: uint256
start_time: uint256
collateral_contract: address
collateral_token_id: uint256
borrower: address
lender: address
fees: DynArray[Fee, MAX_FEES]
pro_rata: bool
original_loan_id: bytes32
paid_principal: uint256
paid_interest: uint256
paid_settlement_fees: DynArray[FeeAmount, MAX_FEES]
borrower_compensation: uint256
offer_id: bytes32
offer_tracing_id: bytes32
event LoanPaid:
id: bytes32
borrower: address
lender: address
payment_token: address
paid_principal: uint256
paid_interest: uint256
paid_settlement_fees: DynArray[FeeAmount, MAX_FEES]
event LoanCollateralClaimed:
id: bytes32
borrower: address
lender: address
collateral_contract: address
collateral_token_id: uint256
event OfferRevoked:
offer_id: bytes32
lender: address
collection_key_hash: bytes32
offer_type: OfferType
event OwnerProposed:
owner: address
proposed_owner: address
event OwnershipTransferred:
old_owner: address
new_owner: address
event ProtocolFeeSet:
old_upfront_fee: uint256
old_settlement_fee: uint256
new_upfront_fee: uint256
new_settlement_fee: uint256
event ProtocolWalletChanged:
old_wallet: address
new_wallet: address
event ProxyAuthorizationChanged:
proxy: address
value: bool
event TransferFailed:
_to: address
amount: uint256
event PendingTransfersClaimed:
_to: address
amount: uint256
# Global variables
owner: public(address)
proposed_owner: public(address)
payment_token: public(immutable(address))
loans: public(HashMap[bytes32, bytes32])
delegation_registry: public(immutable(DelegationRegistry))
cryptopunks: public(immutable(CryptoPunksMarket))
p2p_control: public(immutable(P2PLendingControl))
protocol_wallet: public(address)
protocol_upfront_fee: public(uint256)
protocol_settlement_fee: public(uint256)
max_protocol_upfront_fee: public(immutable(uint256))
max_protocol_settlement_fee: public(immutable(uint256))
max_lender_broker_settlement_fee: public(immutable(uint256))
max_borrower_broker_settlement_fee: public(immutable(uint256))
offer_count: public(HashMap[bytes32, uint256])
revoked_offers: public(HashMap[bytes32, bool])
authorized_proxies: public(HashMap[address, bool])
pending_transfers: public(HashMap[address, uint256])
VERSION: public(constant(String[30])) = "P2PLendingNfts.20241002"
ZHARTA_DOMAIN_NAME: constant(String[6]) = "Zharta"
ZHARTA_DOMAIN_VERSION: constant(String[1]) = "1"
DOMAIN_TYPE_HASH: constant(bytes32) = keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)")
OFFER_TYPE_DEF: constant(String[413]) = "Offer(uint256 principal,uint256 interest,address payment_token,uint256 duration,uint256 origination_fee_amount," \
"uint256 broker_upfront_fee_amount,uint256 broker_settlement_fee_bps,address broker_address," \
"uint256 offer_type,uint256 token_id,uint256 token_range_min,uint256 token_range_max,bytes32 collection_key_hash," \
"bytes32 trait_hash,uint256 expiration,address lender,bool pro_rata,uint256 size,bytes32 tracing_id)"
OFFER_TYPE_HASH: constant(bytes32) = keccak256(OFFER_TYPE_DEF)
offer_sig_domain_separator: immutable(bytes32)
@external
def __init__(
_payment_token: address,
_p2p_control: address,
_delegation_registry: address,
_cryptopunks: address,
_protocol_upfront_fee: uint256,
_protocol_settlement_fee: uint256,
_protocol_wallet: address,
_max_protocol_upfront_fee: uint256,
_max_protocol_settlement_fee: uint256,
_max_lender_broker_settlement_fee: uint256,
_max_borrower_broker_settlement_fee: uint256,
):
"""
@notice Initialize the contract with the given parameters.
@param _payment_token The address of the payment token.
@param _delegation_registry The address of the delegation registry.
@param _cryptopunks The address of the CryptoPunksMarket contract.
@param _protocol_upfront_fee The percentage (bps) of the principal paid to the protocol at origination.
@param _protocol_settlement_fee The percentage (bps) of the interest paid to the protocol at settlement.
@param _protocol_wallet The address where the protocol fees are accrued.
"""
assert _protocol_wallet != empty(address), "wallet is the zero address"
assert _payment_token != empty(address), "payment token is zero"
assert _p2p_control != empty(address), "p2p control is zero"
assert _delegation_registry != empty(address), "delegation registry is zero"
assert _protocol_upfront_fee <= _max_protocol_upfront_fee, "upfront fee exceeds max"
assert _protocol_settlement_fee <= _max_protocol_settlement_fee, "settlement fee exceeds max"
self.owner = msg.sender
payment_token = _payment_token
p2p_control = P2PLendingControl(_p2p_control)
delegation_registry = DelegationRegistry(_delegation_registry)
cryptopunks = CryptoPunksMarket(_cryptopunks)
max_protocol_upfront_fee = _max_protocol_upfront_fee
max_protocol_settlement_fee = _max_protocol_settlement_fee
max_lender_broker_settlement_fee = _max_lender_broker_settlement_fee
max_borrower_broker_settlement_fee = _max_borrower_broker_settlement_fee
self.protocol_upfront_fee = _protocol_upfront_fee
self.protocol_settlement_fee = _protocol_settlement_fee
self.protocol_wallet = _protocol_wallet
offer_sig_domain_separator = keccak256(
_abi_encode(
DOMAIN_TYPE_HASH,
keccak256(ZHARTA_DOMAIN_NAME),
keccak256(ZHARTA_DOMAIN_VERSION),
chain.id,
self
)
)
# Config functions
@external
def set_protocol_fee(protocol_upfront_fee: uint256, protocol_settlement_fee: uint256):
"""
@notice Set the protocol fee
@dev Sets the protocol fee to the given value and logs the event. Admin function.
@param protocol_upfront_fee The new protocol upfront fee.
@param protocol_settlement_fee The new protocol settlement fee.
"""
assert msg.sender == self.owner, "not owner"
assert protocol_upfront_fee <= max_protocol_upfront_fee, "upfront fee exceeds max"
assert protocol_settlement_fee <= max_protocol_settlement_fee, "settlement fee exceeds max"
log ProtocolFeeSet(self.protocol_upfront_fee, self.protocol_settlement_fee, protocol_upfront_fee, protocol_settlement_fee)
self.protocol_upfront_fee = protocol_upfront_fee
self.protocol_settlement_fee = protocol_settlement_fee
@external
def change_protocol_wallet(new_protocol_wallet: address):
"""
@notice Change the protocol wallet
@dev Changes the protocol wallet to the given address and logs the event. Admin function.
@param new_protocol_wallet The new protocol wallet.
"""
assert msg.sender == self.owner, "not owner"
assert new_protocol_wallet != empty(address), "wallet is the zero address"
log ProtocolWalletChanged(self.protocol_wallet, new_protocol_wallet)
self.protocol_wallet = new_protocol_wallet
@external
def set_proxy_authorization(_proxy: address, _value: bool):
"""
@notice Set authorization
@dev Sets the authorization for the given proxy and logs the event. Admin function.
@param _proxy The address of the proxy.
@param _value The value of the authorization.
"""
assert msg.sender == self.owner, "not owner"
self.authorized_proxies[_proxy] = _value
log ProxyAuthorizationChanged(_proxy, _value)
@external
def propose_owner(_address: address):
"""
@notice Propose a new owner
@dev Proposes a new owner and logs the event. Admin function.
@param _address The address of the proposed owner.
"""
assert msg.sender == self.owner, "not owner"
assert _address != empty(address), "_address is zero"
log OwnerProposed(self.owner, _address)
self.proposed_owner = _address
@external
def claim_ownership():
"""
@notice Claim the ownership of the contract
@dev Claims the ownership of the contract and logs the event. Requires the caller to be the proposed owner.
"""
assert msg.sender == self.proposed_owner, "not the proposed owner"
log OwnershipTransferred(self.owner, self.proposed_owner)
self.owner = msg.sender
self.proposed_owner = empty(address)
# Core functions
@external
def create_loan(
offer: SignedOffer,
collateral_token_id: uint256,
collateral_proof: DynArray[bytes32, PROOF_MAX_SIZE],
delegate: address,
borrower_broker_upfront_fee_amount: uint256,
borrower_broker_settlement_fee_bps: uint256,
borrower_broker: address
) -> bytes32:
"""
@notice Create a loan.
@param offer The signed offer.
@param collateral_token_id The ID of the collateral token.
@param delegate The address of the delegate. If empty, no delegation is set.
@param borrower_broker_upfront_fee_amount The upfront fee amount for the borrower broker.
@param borrower_broker_settlement_fee_bps The settlement fee basis points relative to the interest for the borrower broker.
@param borrower_broker The address of the borrower broker.
@return The ID of the created loan.
"""
assert self._is_offer_signed_by_lender(offer, offer.offer.lender), "offer not signed by lender"
assert offer.offer.expiration > block.timestamp, "offer expired"
assert offer.offer.payment_token == payment_token, "invalid payment token"
assert offer.offer.origination_fee_amount <= offer.offer.principal, "origination fee gt principal"
collection_status: CollectionStatus = p2p_control.get_collection_status(offer.offer.collection_key_hash)
self._validate_token_ids(offer.offer, collateral_token_id, collection_status, collateral_proof)
fees: DynArray[Fee, MAX_FEES] = self._get_loan_fees(offer.offer, borrower_broker_upfront_fee_amount, borrower_broker_settlement_fee_bps, borrower_broker)
total_upfront_fees: uint256 = 0
for fee in fees:
total_upfront_fees += fee.upfront_amount
offer_id: bytes32 = self._compute_signed_offer_id(offer)
loan: Loan = Loan({
id: empty(bytes32),
offer_id: offer_id,
offer_tracing_id: offer.offer.tracing_id,
amount: offer.offer.principal,
interest: offer.offer.interest,
payment_token: offer.offer.payment_token,
maturity: block.timestamp + offer.offer.duration,
start_time: block.timestamp,
borrower: msg.sender if not self.authorized_proxies[msg.sender] else tx.origin,
lender: offer.offer.lender,
collateral_contract: collection_status.contract,
collateral_token_id: collateral_token_id,
fees: fees,
pro_rata: offer.offer.pro_rata,
delegate: delegate
})
loan.id = self._compute_loan_id(loan)
assert self.loans[loan.id] == empty(bytes32), "loan already exists"
self._check_and_update_offer_state(offer)
self.loans[loan.id] = self._loan_state_hash(loan)
self._store_collateral(loan.borrower, loan.collateral_contract, loan.collateral_token_id)
self._transfer_funds(loan.lender, loan.borrower, loan.amount - total_upfront_fees + offer.offer.broker_upfront_fee_amount)
for fee in fees:
if fee.type != FeeType.ORIGINATION_FEE and fee.upfront_amount > 0:
self._transfer_funds(loan.lender, fee.wallet, fee.upfront_amount)
if delegate != empty(address):
self._set_delegation(delegate, loan.collateral_contract, loan.collateral_token_id, True)
log LoanCreated(
loan.id,
loan.amount,
loan.interest,
loan.payment_token,
loan.maturity,
loan.start_time,
loan.borrower,
loan.lender,
loan.collateral_contract,
loan.collateral_token_id,
loan.fees,
loan.pro_rata,
offer_id,
offer.offer.tracing_id,
delegate
)
return loan.id
@external
def settle_loan(loan: Loan):
"""
@notice Settle a loan.
@param loan The loan to be settled.
"""
assert self._is_loan_valid(loan), "invalid loan"
assert block.timestamp <= loan.maturity, "loan defaulted"
assert self._check_user(loan.borrower), "not borrower"
interest: uint256 = self._compute_settlement_interest(loan)
settlement_fees_total: uint256 = 0
settlement_fees: DynArray[FeeAmount, MAX_FEES] = []
borrower_broker_fee_amount: uint256 = 0
settlement_fees, settlement_fees_total, borrower_broker_fee_amount = self._get_settlement_fees(loan, interest)
self.loans[loan.id] = empty(bytes32)
self._reduce_offer_count(loan.offer_tracing_id)
self._receive_funds(loan.borrower, loan.amount + interest + borrower_broker_fee_amount)
self._send_funds(loan.lender, loan.amount + interest - settlement_fees_total + borrower_broker_fee_amount)
for fee in settlement_fees:
self._send_funds(fee.wallet, fee.amount)
self._transfer_collateral(loan.borrower, loan.collateral_contract, loan.collateral_token_id)
if loan.delegate != empty(address):
self._set_delegation(loan.delegate, loan.collateral_contract, loan.collateral_token_id, False)
log LoanPaid(
loan.id,
loan.borrower,
loan.lender,
loan.payment_token,
loan.amount,
interest,
settlement_fees
)
@external
def claim_defaulted_loan_collateral(loan: Loan):
"""
@notice Claim defaulted loan collateral.
@param loan The loan whose collateral is to be claimed. The loan maturity must have been passed.
"""
assert self._is_loan_valid(loan), "invalid loan"
assert block.timestamp > loan.maturity, "loan not defaulted"
assert self._check_user(loan.lender), "not lender"
self.loans[loan.id] = empty(bytes32)
self._transfer_collateral(loan.lender, loan.collateral_contract, loan.collateral_token_id)
if loan.delegate != empty(address):
self._set_delegation(loan.delegate, loan.collateral_contract, loan.collateral_token_id, False)
log LoanCollateralClaimed(
loan.id,
loan.borrower,
loan.lender,
loan.collateral_contract,
loan.collateral_token_id
)
@external
def replace_loan(
loan: Loan,
offer: SignedOffer,
collateral_proof: DynArray[bytes32, PROOF_MAX_SIZE],
borrower_broker_upfront_fee_amount: uint256,
borrower_broker_settlement_fee_bps: uint256,
borrower_broker: address
) -> bytes32:
"""
@notice Replace an existing loan by accepting a new offer over the same collateral. The current loan is settled and the new loan is created. Must be called by the borrower.
@dev No collateral transfer is required and the delegation is not changed. The borrower must be the same as the borrower of the current loan.
@param loan The loan to be replaced.
@param offer The new signed offer.
@param borrower_broker_upfront_fee_amount The upfront fee amount for the borrower broker.
@param borrower_broker_settlement_fee_bps The settlement fee basis points relative to the interest for the borrower broker.
@param borrower_broker The address of the borrower broker, if any.
@return The ID of the new loan.
"""
assert self._is_loan_valid(loan), "invalid loan"
assert self._check_user(loan.borrower), "not borrower"
assert block.timestamp <= loan.maturity, "loan defaulted"
assert self._is_offer_signed_by_lender(offer, offer.offer.lender), "offer not signed by lender"
assert offer.offer.expiration > block.timestamp, "offer expired"
assert offer.offer.payment_token == payment_token, "invalid payment token"
assert offer.offer.origination_fee_amount <= offer.offer.principal, "origination fee gt principal"
collection_status: CollectionStatus = p2p_control.get_collection_status(offer.offer.collection_key_hash)
self._validate_token_ids(offer.offer, loan.collateral_token_id, collection_status, collateral_proof)
assert collection_status.contract == loan.collateral_contract, "collateral contract mismatch"
self._check_and_update_offer_state(offer)
self._reduce_offer_count(loan.offer_tracing_id)
principal_delta: int256 = convert(offer.offer.principal, int256) - convert(loan.amount, int256)
interest: uint256 = self._compute_settlement_interest(loan)
settlement_fees_total: uint256 = 0
settlement_fees: DynArray[FeeAmount, MAX_FEES] = []
borrower_broker_fee_amount: uint256 = 0
settlement_fees, settlement_fees_total, borrower_broker_fee_amount = self._get_settlement_fees(loan, interest)
new_loan_fees: DynArray[Fee, MAX_FEES] = self._get_loan_fees(offer.offer, borrower_broker_upfront_fee_amount, borrower_broker_settlement_fee_bps, borrower_broker)
total_upfront_fees: uint256 = 0
for fee in new_loan_fees:
total_upfront_fees += fee.upfront_amount
self.loans[loan.id] = empty(bytes32)
borrower_delta: int256 = principal_delta - convert(total_upfront_fees + interest + borrower_broker_fee_amount, int256) + convert(offer.offer.broker_upfront_fee_amount, int256)
current_lender_delta: uint256 = loan.amount + interest - settlement_fees_total + borrower_broker_fee_amount
new_lender_delta_abs: uint256 = offer.offer.principal - offer.offer.origination_fee_amount + offer.offer.broker_upfront_fee_amount
if borrower_delta < 0:
self._receive_funds(loan.borrower, convert(-1 * borrower_delta, uint256))
if loan.lender != offer.offer.lender:
self._receive_funds(offer.offer.lender, new_lender_delta_abs)
self._send_funds(loan.lender, current_lender_delta)
elif current_lender_delta > new_lender_delta_abs:
self._send_funds(loan.lender, current_lender_delta - new_lender_delta_abs)
elif current_lender_delta < new_lender_delta_abs:
self._receive_funds(loan.lender, new_lender_delta_abs - current_lender_delta)
if borrower_delta > 0:
self._send_funds(loan.borrower, convert(borrower_delta, uint256))
for fee in settlement_fees:
self._send_funds(fee.wallet, fee.amount)
for fee in new_loan_fees:
if fee.type != FeeType.ORIGINATION_FEE and fee.upfront_amount > 0:
self._send_funds(fee.wallet, fee.upfront_amount)
offer_id: bytes32 = self._compute_signed_offer_id(offer)
new_loan: Loan = Loan({
id: empty(bytes32),
offer_id: offer_id,
offer_tracing_id: offer.offer.tracing_id,
amount: offer.offer.principal,
interest: offer.offer.interest,
payment_token: offer.offer.payment_token,
maturity: block.timestamp + offer.offer.duration,
start_time: block.timestamp,
borrower: loan.borrower,
lender: offer.offer.lender,
collateral_contract: collection_status.contract,
collateral_token_id: loan.collateral_token_id,
fees: new_loan_fees,
pro_rata: offer.offer.pro_rata,
delegate: loan.delegate
})
new_loan.id = self._compute_loan_id(new_loan)
assert self.loans[new_loan.id] == empty(bytes32), "loan already exists"
self.loans[new_loan.id] = self._loan_state_hash(new_loan)
log LoanReplaced(
new_loan.id,
new_loan.amount,
new_loan.interest,
new_loan.payment_token,
new_loan.maturity,
new_loan.start_time,
new_loan.collateral_contract,
new_loan.collateral_token_id,
new_loan.borrower,
new_loan.lender,
new_loan.fees,
new_loan.pro_rata,
loan.id,
loan.amount,
interest,
settlement_fees,
offer_id,
offer.offer.tracing_id
)
return new_loan.id
@external
def replace_loan_lender(loan: Loan, offer: SignedOffer, collateral_proof: DynArray[bytes32, PROOF_MAX_SIZE]) -> bytes32:
"""
@notice Replace a loan by the lender. The current loan is settled and the new loan is created. Must be called by the lender.
@dev No collateral transfer is required and the delegation is not changed. The borrower must be the same as the borrower of the current loan. No funds are required from the borrower. Also no funds are required from the lender, except when the current and new lender are the same.
@param loan The loan to be replaced.
@param offer The new signed offer.
@return The ID of the new loan.
"""
assert self._is_loan_valid(loan), "invalid loan"
assert self._check_user(loan.lender), "not lender"
assert block.timestamp <= loan.maturity, "loan defaulted"
assert self._is_offer_signed_by_lender(offer, offer.offer.lender), "offer not signed by lender"
assert offer.offer.expiration > block.timestamp, "offer expired"
assert offer.offer.payment_token == payment_token, "invalid payment token"
assert offer.offer.origination_fee_amount <= offer.offer.principal, "origination fee gt principal"
assert block.timestamp + offer.offer.duration >= loan.maturity, "maturity before loan maturity"
collection_status: CollectionStatus = p2p_control.get_collection_status(offer.offer.collection_key_hash)
self._validate_token_ids(offer.offer, loan.collateral_token_id, collection_status, collateral_proof)
assert collection_status.contract == loan.collateral_contract, "collateral contract mismatch"
self._check_and_update_offer_state(offer)
self._reduce_offer_count(loan.offer_tracing_id)
principal_delta: int256 = convert(offer.offer.principal, int256) - convert(loan.amount, int256)
interest: uint256 = self._compute_settlement_interest(loan)
settlement_fees_total: uint256 = 0
settlement_fees: DynArray[FeeAmount, MAX_FEES] = []
borrower_broker_fee_amount: uint256 = 0
settlement_fees, settlement_fees_total, borrower_broker_fee_amount = self._get_settlement_fees(loan, interest)
new_loan_fees: DynArray[Fee, MAX_FEES] = self._get_loan_fees(offer.offer, 0, 0, empty(address))
total_upfront_fees: uint256 = 0
for fee in new_loan_fees:
total_upfront_fees += fee.upfront_amount
self.loans[loan.id] = empty(bytes32)
max_interest_delta: uint256 = self._compute_max_interest_delta(loan, offer.offer, interest, borrower_broker_fee_amount)
borrower_compensation: uint256 = convert(max(convert(max_interest_delta, int256), convert(interest + borrower_broker_fee_amount, int256) - principal_delta), uint256)
borrower_delta: int256 = principal_delta - convert(interest, int256) - convert(borrower_broker_fee_amount, int256) + convert(borrower_compensation, int256)
current_lender_delta: int256 = convert(loan.amount + interest + borrower_broker_fee_amount + offer.offer.broker_upfront_fee_amount, int256) - convert(total_upfront_fees + settlement_fees_total + borrower_compensation, int256)
new_lender_delta_abs: uint256 = offer.offer.principal - offer.offer.origination_fee_amount + offer.offer.broker_upfront_fee_amount
assert borrower_delta >= 0, "borrower delta < 0"
if loan.lender != offer.offer.lender:
assert current_lender_delta >= 0, "lender delta < 0"
self._receive_funds(offer.offer.lender, new_lender_delta_abs)
if current_lender_delta > 0:
self._send_funds(loan.lender, convert(current_lender_delta, uint256))
else:
lender_delta: int256 = current_lender_delta - convert(new_lender_delta_abs, int256)
# cant have lender delta > 0 and borrower delta >= 0
assert lender_delta <= 0, "lender delta > 0"
if lender_delta < 0:
self._receive_funds(loan.lender, convert(-1 * lender_delta, uint256))
if borrower_delta > 0:
self._send_funds(loan.borrower, convert(borrower_delta, uint256))
for fee in settlement_fees:
self._send_funds(fee.wallet, fee.amount)
for fee in new_loan_fees:
if fee.type != FeeType.ORIGINATION_FEE and fee.upfront_amount > 0:
self._send_funds(fee.wallet, fee.upfront_amount)
offer_id: bytes32 = self._compute_signed_offer_id(offer)
new_loan: Loan = Loan({
id: empty(bytes32),
offer_id: offer_id,
offer_tracing_id: offer.offer.tracing_id,
amount: offer.offer.principal,
interest: offer.offer.interest,
payment_token: offer.offer.payment_token,
maturity: block.timestamp + offer.offer.duration,
start_time: block.timestamp,
borrower: loan.borrower,
lender: offer.offer.lender,
collateral_contract: collection_status.contract,
collateral_token_id: loan.collateral_token_id,
fees: new_loan_fees,
pro_rata: offer.offer.pro_rata,
delegate: loan.delegate
})
new_loan.id = self._compute_loan_id(new_loan)
assert self.loans[new_loan.id] == empty(bytes32), "loan already exists"
self.loans[new_loan.id] = self._loan_state_hash(new_loan)
log LoanReplacedByLender(
new_loan.id,
new_loan.amount,
new_loan.interest,
new_loan.payment_token,
new_loan.maturity,
new_loan.start_time,
new_loan.collateral_contract,
new_loan.collateral_token_id,
new_loan.borrower,
new_loan.lender,
new_loan.fees,
new_loan.pro_rata,
loan.id,
loan.amount,
interest,
settlement_fees,
borrower_compensation,
offer_id,
offer.offer.tracing_id
)
return new_loan.id
@external
def revoke_offer(offer: SignedOffer):
"""
@notice Revoke an offer.
@param offer The signed offer to be revoked.
"""
assert self._check_user(offer.offer.lender), "not lender"
assert offer.offer.expiration > block.timestamp, "offer expired"
assert self._is_offer_signed_by_lender(offer, offer.offer.lender), "offer not signed by lender"
offer_id: bytes32 = self._compute_signed_offer_id(offer)
assert not self.revoked_offers[offer_id], "offer already revoked"
self._revoke_offer(offer_id, offer)
@external
def claim_pending_transfers():
assert self.pending_transfers[msg.sender] > 0, "no pending transfers"
_amount: uint256 = self.pending_transfers[msg.sender]
self.pending_transfers[msg.sender] = 0
assert IERC20(payment_token).transfer(msg.sender, _amount), "error sending funds"
log PendingTransfersClaimed(msg.sender, _amount)
@view
@external
def onERC721Received(_operator: address, _from: address, _tokenId: uint256, _data: Bytes[1024]) -> bytes4:
"""
@notice ERC721 token receiver callback.
@dev Returns the ERC721 receiver callback selector.
@param _operator The address which called `safeTransferFrom` function.
@param _from The address which previously owned the token.
@param _tokenId The NFT identifier which is being transferred.
@param _data Additional data with no specified format.
@return The ERC721 receiver callback selector.
"""
return method_id("onERC721Received(address,address,uint256,bytes)", output_type=bytes4)
# Internal functions
@pure
@internal
def _compute_loan_id(loan: Loan) -> bytes32:
return keccak256(concat(
convert(loan.borrower, bytes32),
convert(loan.lender, bytes32),
convert(loan.start_time, bytes32),
convert(loan.collateral_contract, bytes32),
convert(loan.collateral_token_id, bytes32),
))
@pure
@internal
def _compute_signed_offer_id(offer: SignedOffer) -> bytes32:
return keccak256(concat(
convert(offer.signature.v, bytes32),
convert(offer.signature.r, bytes32),
convert(offer.signature.s, bytes32),
))
@internal
def _check_and_update_offer_state(offer: SignedOffer):
offer_id: bytes32 = self._compute_signed_offer_id(offer)
assert not self.revoked_offers[offer_id], "offer revoked"
count: uint256 = self.offer_count[offer.offer.tracing_id]
assert count < offer.offer.size, "offer fully utilized"
self.offer_count[offer.offer.tracing_id] = count + 1
if offer.offer.offer_type == OfferType.TOKEN:
self._revoke_offer(offer_id, offer)
@internal
def _revoke_offer(offer_id: bytes32, offer: SignedOffer):
self.revoked_offers[offer_id] = True
log OfferRevoked(
offer_id,
offer.offer.lender,
offer.offer.collection_key_hash,
offer.offer.offer_type,
)
@internal
def _reduce_offer_count(tracing_id: bytes32):
self.offer_count[tracing_id] -= 1
@view
@internal
def _is_loan_valid(loan: Loan) -> bool:
return self.loans[loan.id] == self._loan_state_hash(loan)
@pure
@internal
def _loan_state_hash(loan: Loan) -> bytes32:
return keccak256(_abi_encode(loan))
@internal
def _is_offer_signed_by_lender(signed_offer: SignedOffer, lender: address) -> bool:
return ecrecover(
keccak256(
concat(
convert("\x19\x01", Bytes[2]),
_abi_encode(
offer_sig_domain_separator,
keccak256(_abi_encode(OFFER_TYPE_HASH, signed_offer.offer))
)
)
),
signed_offer.signature.v,
signed_offer.signature.r,
signed_offer.signature.s
) == lender
@internal
def _get_loan_fees(offer: Offer, borrower_broker_upfront_fee_amount: uint256, borrower_broker_settlement_fee_bps: uint256, borrower_broker: address) -> DynArray[Fee, MAX_FEES]:
fees: DynArray[Fee, MAX_FEES] = []
if offer.origination_fee_amount > 0:
assert offer.origination_fee_amount <= offer.principal, "origination fee gt principal"
if offer.broker_settlement_fee_bps > 0 or offer.broker_upfront_fee_amount > 0:
assert offer.broker_address != empty(address), "broker fee without address"
if borrower_broker_upfront_fee_amount > 0 or borrower_broker_settlement_fee_bps > 0:
assert borrower_broker != empty(address), "broker fee without address"
assert offer.broker_settlement_fee_bps <= max_lender_broker_settlement_fee, "lender broker fee exceeds max"
assert borrower_broker_settlement_fee_bps <= max_borrower_broker_settlement_fee, "borrower broker fee exceeds max"
assert self.protocol_settlement_fee + offer.broker_settlement_fee_bps <= BPS, "settlement fees gt principal"
fees.append(Fee({
type: FeeType.PROTOCOL_FEE,
upfront_amount: self.protocol_upfront_fee * offer.principal / BPS,
interest_bps: self.protocol_settlement_fee,
wallet: self.protocol_wallet
}))
fees.append(Fee({
type: FeeType.ORIGINATION_FEE,
upfront_amount: offer.origination_fee_amount,
interest_bps: 0,
wallet: offer.lender
}))
fees.append(Fee({
type: FeeType.LENDER_BROKER_FEE,
upfront_amount: offer.broker_upfront_fee_amount,
interest_bps: offer.broker_settlement_fee_bps,
wallet: offer.broker_address
}))
fees.append(Fee({
type: FeeType.BORROWER_BROKER_FEE,
upfront_amount: borrower_broker_upfront_fee_amount,
interest_bps: borrower_broker_settlement_fee_bps,
wallet: borrower_broker
}))
return fees
@internal
def _get_settlement_fees(loan: Loan, settlement_interest: uint256) -> (DynArray[FeeAmount, MAX_FEES], uint256, uint256):
total: uint256 = 0
settlement_fees: DynArray[FeeAmount, MAX_FEES] = []
borrower_broker_fee_amount: uint256 = 0
for fee in loan.fees:
if fee.interest_bps > 0:
fee_amount: uint256 = settlement_interest * fee.interest_bps / BPS
settlement_fees.append(FeeAmount({type: fee.type, amount: fee_amount, wallet: fee.wallet}))
total += fee_amount
if fee.type == FeeType.BORROWER_BROKER_FEE:
borrower_broker_fee_amount = fee_amount
return (settlement_fees, total, borrower_broker_fee_amount)
@internal
def _compute_settlement_interest(loan: Loan) -> uint256:
if loan.pro_rata:
return loan.interest * (block.timestamp - loan.start_time) / (loan.maturity - loan.start_time)
else:
return loan.interest
@internal
def _compute_max_interest_delta(loan: Loan, offer: Offer, interest: uint256, borrower_broker_fee_amount: uint256) -> uint256:
"""
Computes the maximum interest difference between the new offer and the current loan.
That max difference can be reached either at the refinance timestamp or at the original loan maturity.
The difference can never be negative because at the refinance timestamp the delta is just the offer interest.
"""
borrower_broker_fee_bps: uint256 = 0
for fee in loan.fees:
if fee.type == FeeType.BORROWER_BROKER_FEE:
borrower_broker_fee_bps = fee.interest_bps
delta_at_refinance: uint256 = 0 if offer.pro_rata else offer.interest
borrower_broker_fee_delta_at_maturity: uint256 = (loan.interest - interest) * borrower_broker_fee_bps / BPS if offer.pro_rata else 0
loan_interest_delta_at_maturity: uint256 = loan.interest - interest
offer_interest_at_loan_maturity: uint256 = offer.interest * (loan.maturity - block.timestamp) / offer.duration if offer.pro_rata else offer.interest
return convert(max(
convert(delta_at_refinance, int256),
convert(offer_interest_at_loan_maturity, int256) - convert(loan_interest_delta_at_maturity, int256) - convert(borrower_broker_fee_delta_at_maturity, int256)
), uint256)
@internal
def _set_delegation(_wallet: address, _collateral_address: address, _token_id: uint256, _value: bool):
delegation_registry.delegateERC721(_wallet, _collateral_address, _token_id, empty(bytes32), _value)
@internal
def _store_punk(_wallet: address, _collateralAddress: address, _tokenId: uint256):
offer: PunkOffer = CryptoPunksMarket(_collateralAddress).punksOfferedForSale(_tokenId)
assert offer.isForSale, "collateral not for sale"
assert offer.punkIndex == _tokenId, "collateral with wrong punkIndex"
assert offer.seller == _wallet, "collateral now owned by wallet"
assert offer.minValue == 0, "collateral offer is not zero"
assert offer.onlySellTo == empty(address) or offer.onlySellTo == self, "collateral buying not authorized"
CryptoPunksMarket(_collateralAddress).buyPunk(_tokenId)
@internal
def _store_erc721(_wallet: address, _collateralAddress: address, _tokenId: uint256):
IERC721(_collateralAddress).safeTransferFrom(_wallet, self, _tokenId, b"")
@internal
def _transfer_punk(_wallet: address, _collateralAddress: address, _tokenId: uint256):
assert self._punk_owner(_collateralAddress, _tokenId) == self, "collateral not owned by vault"
CryptoPunksMarket(_collateralAddress).transferPunk(_wallet, _tokenId)
@internal
def _transfer_erc721(_wallet: address, _collateralAddress: address, _tokenId: uint256):
assert self._erc721_owner(_collateralAddress, _tokenId) == self, "collateral not owned by vault"
IERC721(_collateralAddress).safeTransferFrom(self, _wallet, _tokenId, b"")
@internal
def _transfer_collateral(wallet: address, collateral_contract: address, token_id: uint256):
if self._is_punk(collateral_contract):
self._transfer_punk(wallet, collateral_contract, token_id)
else:
self._transfer_erc721(wallet, collateral_contract, token_id)
@internal
def _send_funds(_to: address, _amount: uint256):
success: bool = False
response: Bytes[32] = b""
success, response = raw_call(
payment_token,
_abi_encode(_to, _amount, method_id=method_id("transfer(address,uint256)")),
max_outsize=32,
revert_on_failure=False
)
if not success or not convert(response, bool):
log TransferFailed(_to, _amount)
self.pending_transfers[_to] += _amount
@internal
def _receive_funds(_from: address, _amount: uint256):
assert IERC20(payment_token).transferFrom(_from, self, _amount), "transferFrom failed"
@internal
def _transfer_funds(_from: address, _to: address, _amount: uint256):
assert IERC20(payment_token).transferFrom(_from, _to, _amount), "transferFrom failed"
@pure
@internal
def _is_punk(_collateralAddress: address) -> bool:
return _collateralAddress == cryptopunks.address
@view
@internal
def _punk_owner(_collateralAddress: address, _tokenId: uint256) -> address:
return CryptoPunksMarket(_collateralAddress).punkIndexToAddress(_tokenId)
@view
@internal
def _erc721_owner(_collateralAddress: address, _tokenId: uint256) -> address:
return IERC721(_collateralAddress).ownerOf(_tokenId)
@view
@internal
def _is_punk_approved_for_vault(_borrower: address, _collateralAddress: address, _tokenId: uint256) -> bool:
offer: PunkOffer = cryptopunks.punksOfferedForSale(_tokenId)
return (
offer.isForSale and
offer.punkIndex == _tokenId and
offer.minValue == 0 and
(offer.onlySellTo == empty(address) or offer.onlySellTo == self)
)
@view
@internal
def _is_erc721_approved_for_vault(_borrower: address, _collateralAddress: address, _tokenId: uint256) -> bool:
return IERC721(_collateralAddress).isApprovedForAll(_borrower, self) or IERC721(_collateralAddress).getApproved(_tokenId) == self
@internal
def _store_collateral(wallet: address, collateral_contract: address, token_id: uint256):
assert wallet != empty(address), "addr is the zero addr"
assert collateral_contract != empty(address), "collat addr is the zero addr"
if self._is_punk(collateral_contract):
assert self._punk_owner(collateral_contract, token_id) == wallet, "collateral not owned by wallet"
assert self._is_punk_approved_for_vault(wallet, collateral_contract, token_id), "transfer is not approved"
self._store_punk(wallet, collateral_contract, token_id)
else:
assert self._erc721_owner(collateral_contract, token_id) == wallet, "collateral not owned by wallet"
assert self._is_erc721_approved_for_vault(wallet, collateral_contract, token_id), "transfer is not approved"
self._store_erc721(wallet, collateral_contract, token_id)
@internal
def _check_user(user: address) -> bool:
return msg.sender == user or (self.authorized_proxies[msg.sender] and user == tx.origin)
@internal
def _validate_token_ids(
offer: Offer,
collateral_token_id: uint256,
collection_status: CollectionStatus,
collateral_proof: DynArray[bytes32, PROOF_MAX_SIZE]
):
assert collection_status.contract != empty(address), "collateral not whitelisted"
if offer.offer_type == OfferType.TOKEN:
assert offer.token_id == collateral_token_id, "token id not in offer"
elif offer.offer_type == OfferType.COLLECTION:
assert collateral_token_id >= offer.token_range_min, "tokenid below offer range"
assert collateral_token_id <= offer.token_range_max, "tokenid above offer range"
else:
_hash: bytes32 = keccak256(_abi_encode(collection_status.contract, offer.trait_hash, collateral_token_id))
for p in collateral_proof:
_hash = keccak256(_abi_encode(convert(keccak256(_hash), uint256) ^ convert(keccak256(p), uint256)))
assert collection_status.trait_root == _hash, "proof invalid"
Read Contract
VERSION 0xffa1ad74 → string
authorized_proxies 0x96069a5f → bool
cryptopunks 0x5556eda9 → address
delegation_registry 0xe5107ed7 → address
loans 0xc4a90815 → bytes32
max_borrower_broker_settlement_fee 0x1b0b0c63 → uint256
max_lender_broker_settlement_fee 0xf8c26629 → uint256
max_protocol_settlement_fee 0x87c8f694 → uint256
max_protocol_upfront_fee 0x50d0d5ad → uint256
offer_count 0x225daa0f → uint256
onERC721Received 0x150b7a02 → bytes4
owner 0x8da5cb5b → address
p2p_control 0x7719e9ea → address
payment_token 0x331c6587 → address
pending_transfers 0x9274bbcd → uint256
proposed_owner 0x885753de → address
protocol_settlement_fee 0x61dd0b8b → uint256
protocol_upfront_fee 0x58e77837 → uint256
protocol_wallet 0x67db7499 → address
revoked_offers 0x61acb559 → bool
Write Contract 12 functions
These functions modify contract state and require a wallet transaction to execute.
change_protocol_wallet 0x72e76f13
address new_protocol_wallet
claim_defaulted_loan_collateral 0xdf19cbdb
tuple loan
claim_ownership 0xf7a79a02
No parameters
claim_pending_transfers 0x8199abaf
No parameters
create_loan 0xc48ac26e
tuple offer
uint256 collateral_token_id
bytes32[] collateral_proof
address delegate
uint256 borrower_broker_upfront_fee_amount
uint256 borrower_broker_settlement_fee_bps
address borrower_broker
returns: bytes32
propose_owner 0xbc71771d
address _address
replace_loan 0x7a7ab06f
tuple loan
tuple offer
bytes32[] collateral_proof
uint256 borrower_broker_upfront_fee_amount
uint256 borrower_broker_settlement_fee_bps
address borrower_broker
returns: bytes32
replace_loan_lender 0xaab4ffb9
tuple loan
tuple offer
bytes32[] collateral_proof
returns: bytes32
revoke_offer 0x5449d1d5
tuple offer
set_protocol_fee 0xc2a5022b
uint256 protocol_upfront_fee
uint256 protocol_settlement_fee
set_proxy_authorization 0x9544fa7c
address _proxy
bool _value
settle_loan 0x546dd516
tuple loan
Token Balances (1)
View Transfers →Recent Transactions
No transactions found for this address