Address Contract Partially Verified
Address
0x4e59541306910aD6dC1daC0AC9dFB29bD9F15c67
Balance
0 ETH
Nonce
1
Code Size
23483 bytes
Creator
0xC9332fdC...38BC at tx 0x6a4491e8...c7b621
Indexed Transactions
0
Contract Bytecode
23483 bytes
0x6003361161000c576133f9565b60003560e01c6323cfed0381186100565760643610615a6957600054600214615a69576002600055346102c052606060046102e03760016103405261004f61455b565b6003600055005b63bc61ea2381186102575760c43610615a69576064358060a01c615a6957610640526084356004016005813511615a695780358061066052602082018160051b80826106803750505050600054600214615a695760026000556020615a9b60003960005163a9059cbb610720526106405161074052602435610760526020610720604461073c6000855af16100f0573d600060003e3d6000fd5b60203d10615a6957610720518060011c615a6957610780526107805050610640516040527fe62214fe0000000000000000000000000000000000000000000000000000000060605233608052600060a0526040600460c0376106605180610100528060051b806101208261068060045afa50505061016f610740614209565b61074060408101905051610720526004356040523460605261018f613f2e565b6020615abb6000396000516323b872dd6107405261064051610760526020615afb60003960005161078052610720516107a0526020610740606461075c6000855af16101e0573d600060003e3d6000fd5b3d6101f757803b15615a695760016107c052610210565b60203d10615a6957610740518060011c615a69576107c0525b6107c090505115615a695760006102c05260043561072051808201828110615a6957905090506102e052604060246103003760006103405261025061455b565b6003600055005b636f972f1281186102745760243610615a69573361052052610297565b6324049e5781186102ee5760443610615a69576024358060a01c615a6957610520525b600054600214615a695760026000556004356102b2576102e7565b6004356102c05260006102e05261052051610300526000610320526102d5614993565b600435604052346060526102e7613f2e565b6003600055005b63dd171e7c81186103db5760443610615a6957600054600214615a6957600260005560243561031c576103d4565b604060046102c0373361030052600061032052610337614993565b600435156103515760043560405234606052610351613f2e565b6020615a9b60003960005163a9059cbb610520523361054052602435610560526020610520604461053c6000855af161038f573d600060003e3d6000fd5b60203d10615a6957610520518060011c615a69576105805261058050506801000000000000000754602435808201828110615a69579050905068010000000000000007555b6003600055005b63c45a015581186104075760043610615a695734615a69576020615a7b60003960005160405260206040f35b632a94394581186104335760043610615a695734615a69576020615afb60003960005160405260206040f35b632621db2f811861045f5760043610615a695734615a69576020615abb60003960005160405260206040f35b639b6c56ec81186104a55760243610615a69576004358060a01c615a695760c05234615a6957600054600214615a6957602060c0516040526104a160e061369d565b60e0f35b63a21adb9e81186104f15760243610615a69576004358060a01c615a695760405234615a6957600054600214615a69576001604051602052600052604060002054151560605260206060f35b6331dc3ca881186105855760043610615a695734615a69576020615afb60003960005163095a0fc6606052602060606004607c845afa610536573d600060003e3d6000fd5b60203d10615a69576060905051604052600354606052600454608052606051604051808202811583838304141715615a6957905090506080518015615a69578082049050905060a052602060a0f35b639a49719681186105a35760443610615a695760006101e0526105be565b631cf1f94781186106ff5760643610615a69576044356101e0525b34615a6957600054600214615a69576004356020615adb600039600051808202811583838304141715615a6957905090506040526024356060526801000000000000000b5460805261061161022061373d565b61022051610200526001670de0b6b3a764000061020051610633610240613d23565b61024051808202811583838304141715615a69579050905004600181811860018311021890500361022052670de0b6b3a764000061022051670de05bc096e9c000810281670de05bc096e9c000820418615a695790500461022052610220516020615a9b6000396000516370a082316102405230610260526020610240602461025c845afa6106c7573d600060003e3d6000fd5b60203d10615a69576102409050516101e051808201828110615a69579050905080828118828410021890509050610280526020610280f35b63a7573206811861082d5760443610615a695734615a6957600054600214615a6957670de05bc096e9c0006020615adb600039600051600435670de0b6b3a7640000810281670de0b6b3a7640000820418615a695790506107616101e0613d23565b6101e0518015615a695780820490509050670de0b6b3a7640000810281670de0b6b3a7640000820418615a69579050670de0b6b3a76400006040526024356060526801000000000000000b546080526107bb61020061373d565b610200518015615a6957808204905090506024356024356107d08101818110615a69579050808202811583838304141715615a695790509050808201828110615a69579050905004670de0b6b3a7640000810281670de0b6b3a7640000820418615a6957905004610220526020610220f35b63720fb25481186108695760643610615a695734615a6957600054600214615a6957602060606004610120376108646102c0613864565b6102c0f35b63d14ff5b681186108875760243610615a69576001610520526108aa565b632e4af52a811861090a5760443610615a69576024358060011c615a6957610520525b34615a6957600054600214615a695760026000556004356108ca57610903565b6004356102c05260006102e05233610300526001610320526108ea614993565b336040526004356060526105205160805261090361408f565b6003600055005b63371fd8e681186109525760243610615a6957336102c0527f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6102e052600161030052610a11565b63acb7081581186109a45760443610615a69576024358060a01c615a69576102c0527f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6102e052600161030052610a11565b63b4440df481186109d85760643610615a69576024358060a01c615a69576102c0526044356102e052600161030052610a11565b6337671f9381186111165760843610615a69576024358060a01c615a69576102c0526044356102e0526064358060011c615a6957610300525b34615a6957600054600214615a69576002600055600435610a315761110f565b604036610320376102c05160a052610a4a610360613618565b6103608051610320526020810151610340525061032051610acb576012610360527f4c6f616e20646f65736e277420657869737400000000000000000000000000006103805261036050610360518061038001601f826000031636823750506308c379a061032052602061034052601f19601f61036051011660440161033cfd5b6103205160043580828118828410021890509050610360526103605161032051036103205261032051610c84576020615afb60003960005163f3fef3a36103c0526102c0516103e052670de0b6b3a76400006104005260406103c060446103dc6000855af1610b3f573d600060003e3d6000fd5b60403d10615a69576103c0905080516103805260208101516103a052506103805115610bde57336102c05118615a69576020615a9b6000396000516323b872dd6103c0526020615afb6000396000516103e0526102c05161040052610380516104205260206103c060646103dc6000855af1610bc0573d600060003e3d6000fd5b60203d10615a69576103c0518060011c615a69576104405261044050505b6103a05115610c04576102c0516040526103a05160605261030051608052610c0461408f565b6102c0517feec6b7095a637e006c79c1819d696e353a8f703db2c49fc0219e17a8fd04f7f260a0366103c03760a06103c0a26102c0517f77c6871227e5d2dec8dadd5354f78453203e22e669cd0ec4c19d9a8c5edb31d06103a0516103c052610360516103e05260406103c0a26102c051604052611011614de256611011565b6020615afb60003960005163c16ef2646103a05260206103a060046103bc845afa610cb4573d600060003e3d6000fd5b60203d10615a69576103a0905051610380526102e0516103805113615a69576020615afb60003960005163b461100d6103e0526102c0516104005260406103e060246103fc845afa610d0b573d600060003e3d6000fd5b60403d10615a69576103e0905080516103a05260208101516103c0525060016103a0516103c051030160008112615a69576103e052600061040052610380516103a05113610e175760026102c051602052600052604060002054610400526102c0517feec6b7095a637e006c79c1819d696e353a8f703db2c49fc0219e17a8fd04f7f27fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6104205261032051610440526103a051610460526103c05161048052610400516104a05260a0610420a26102c0517f77c6871227e5d2dec8dadd5354f78453203e22e669cd0ec4c19d9a8c5edb31d060006104205261036051610440526040610420a2610fd6565b6020615afb60003960005163f3fef3a3610460526102c05161048052670de0b6b3a76400006104a0526040610460604461047c6000855af1610e5e573d600060003e3d6000fd5b60403d10615a6957610460905080516104205260208101516104405250610440516101205261032051610140526103e05161016052610e9e610480613864565b6104805161046052610460516103a0516103c051038082018281126000831218615a695790509050610480526020615afb60003960005163ab047e006104a0526102c0516104c052610440516104e05261046051610500526104805161052052803b15615a695760006104a060846104bc6000855af1610f23573d600060003e3d6000fd5b506801000000000000000a54610400526104005160026102c0516020526000526040600020556102c0517feec6b7095a637e006c79c1819d696e353a8f703db2c49fc0219e17a8fd04f7f2610440516104a052610320516104c052610460516104e0526104805161050052610400516105205260a06104a0a26102c0517f77c6871227e5d2dec8dadd5354f78453203e22e669cd0ec4c19d9a8c5edb31d060006104a052610360516104c05260406104a0a25b336102c051146110115760016102c0516040526103205160605260006080526104005160a052611007610420614ebd565b6104205112615a69575b6020615a9b6000396000516323b872dd61038052336103a052306103c052610360516103e0526020610380606461039c6000855af1611055573d600060003e3d6000fd5b60203d10615a6957610380518060011c615a6957610400526104005050680100000000000000085461036051808201828110615a695790509050680100000000000000085560016102c05160205260005260406000206103205181556103405160018201555060035461034051808202811583838304141715615a6957905090506004548015615a695780820490509050610380526103605161038051610360518082811882841102189050905003600355610340516004555b6003600055005b63152f65cb81186118f75760643610615a69576004358060a01c615a6957610640526024356004016005813511615a695780358061066052602082018160051b8082610680375050505034615a6957600054600214615a695760026000556020615afb60003960005163b461100d6107605233610780526040610760602461077c845afa6111a9573d600060003e3d6000fd5b60403d10615a69576107609050805161072052602081015161074052506020615afb60003960005163f3fef3a36107a052336107c052670de0b6b3a76400006107e05260406107a060446107bc6000855af161120a573d600060003e3d6000fd5b60403d10615a69576107a09050805161076052602081015161078052506040366107a0373360a05261123d6107e0613618565b6107e080516107a05260208101516107c052506020615abb6000396000516323b872dd6107e0526020615afb600039600051610800526106405161082052610780516108405260206107e060646107fc6000855af16112a1573d600060003e3d6000fd5b3d6112b857803b15615a69576001610860526112d1565b60203d10615a69576107e0518060011c615a6957610860525b6108605050610640516040527fef67dc7400000000000000000000000000000000000000000000000000000000606052336080526107605160a0526107805160c0526107a05160e0526106605180610100528060051b806101208261068060045afa505050611341610840614209565b61084080516107e052602081015161080052604081015161082052506108005161076051808201828110615a695790509050610840526108405115615a69576000610860526107a0516108405110156115f65760016107205161074051030160008112615a6957610880526107e051610720511315615a69576108005161086052610800516107a051036107a05261082051610120526107a0516101405261088051610160526113f26108c0613864565b6108c0516108a0526108a0516107205161074051038082018281126000831218615a6957905090506108c0526020615afb60003960005163ab047e006108e052336109005261082051610920526108a051610940526108c05161096052803b15615a695760006108e060846108fc6000855af1611474573d600060003e3d6000fd5b506801000000000000000a546108e0526108e0516002336020526000526040600020556020615abb6000396000516323b872dd6109005261064051610920526020615afb6000396000516109405261082051610960526020610900606461091c6000855af16114e8573d600060003e3d6000fd5b3d6114ff57803b15615a6957600161098052611518565b60203d10615a6957610900518060011c615a6957610980525b61098090505115615a69576020615a9b6000396000516323b872dd610900526106405161092052306109405261080051610960526020610900606461091c6000855af161156a573d600060003e3d6000fd5b60203d10615a6957610900518060011c615a6957610980526109805050337feec6b7095a637e006c79c1819d696e353a8f703db2c49fc0219e17a8fd04f7f261082051610900526107a051610920526108a051610940526108c051610960526108e0516109805260a0610900a26107805161082051808203828111615a6957905090506107805261181f565b6107a0516108605260006107a05233604052611610614de2565b610800511561167e576020615a9b6000396000516323b872dd61088052610640516108a052306108c052610800516108e0526020610880606461089c6000855af1611660573d600060003e3d6000fd5b60203d10615a6957610880518060011c615a69576109005261090050505b61076051156116f3576020615a9b6000396000516323b872dd610880526020615afb6000396000516108a052306108c052610760516108e0526020610880606461089c6000855af16116d5573d600060003e3d6000fd5b60203d10615a6957610880518060011c615a69576109005261090050505b61086051610840511115611763576020615a9b60003960005163a9059cbb61088052336108a0526108605161084051036108c0526020610880604461089c6000855af1611745573d600060003e3d6000fd5b60203d10615a6957610880518060011c615a69576108e0526108e050505b61082051156117ef576020615abb6000396000516323b872dd61088052610640516108a052336108c052610820516108e0526020610880606461089c6000855af16117b3573d600060003e3d6000fd5b3d6117ca57803b15615a69576001610900526117e3565b60203d10615a6957610880518060011c615a6957610900525b61090090505115615a69575b337feec6b7095a637e006c79c1819d696e353a8f703db2c49fc0219e17a8fd04f7f260a0366108803760a0610880a25b337f77c6871227e5d2dec8dadd5354f78453203e22e669cd0ec4c19d9a8c5edb31d06107805161088052610860516108a0526040610880a2680100000000000000085461086051808201828110615a695790509050680100000000000000085560013360205260005260406000206107a05181556107c0516001820155506003546107c051808202811583838304141715615a6957905090506004548015615a6957808204905090506108805261086051610880516108605180828118828411021890509050036003556107c0516004556003600055005b630b8db68181186119155760843610615a6957600061030052611930565b6322c714538118611ec25760a43610615a6957608435610300525b6004358060a01c615a69576102c0526064358060011c615a69576102e05234615a6957600054600214615a69576020615afb60003960005163b461100d610360526102c051610380526040610360602461037c845afa611995573d600060003e3d6000fd5b60403d10615a69576103609050805161032052602081015161034052506102c0516040526119c461038061369d565b610380518060ff1c615a695761036052610300516103805260006103a0526103605115611a265760026102c0516020526000526040600020548060ff1c615a69576103a05260016103205161034051030160008112615a695761038052611a63565b6801000000000000000a548060ff1c615a69576103a0527f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff610320525b6060366103c037610360516044358082018281126000831218615a695790509050610360526001610360511215611afa576011610420527f4e6f6e2d706f73697469766520646562740000000000000000000000000000006104405261042050610420518061044001601f826000031636823750506308c379a06103e052602061040052601f19601f6104205101166044016103fcfd5b6020615afb60003960005163c16ef264610440526020610440600461045c845afa611b2a573d600060003e3d6000fd5b60203d10615a695761044090505161042052610420516103205113611b50576000611b65565b60243515611b5f576001611b65565b60443515155b611be657610320516103c0526020615afb6000396000516362ca4b18610440526102c051610460526020610440602461045c845afa611ba9573d600060003e3d6000fd5b60203d10615a6957610440905051670de0b6b3a7640000810281670de0b6b3a7640000820418615a695790508060ff1c615a695761040052611caf565b6020615afb60003960005163544fb5c1610440526102c051610460526040610440602461045c845afa611c1e573d600060003e3d6000fd5b60403d10615a69576104409050602081019050516020615adb600039600051808202811583838304141715615a6957905090508060ff1c615a69576024358082018281126000831218615a6957905090506103e0526103e05160008112615a6957610120526103605160008112615a6957610140526103805161016052611ca6610440613864565b610440516103c0525b6020615afb600039600051632eb858e7610460526103c051610480526020610460602461047c845afa611ce7573d600060003e3d6000fd5b60203d10615a69576104609050518060ff1c615a69576104405261042051610320511315611d6c576103e05160008112615a6957604052610380516060526000608052611d3561046061373d565b610460518060ff1c615a69576104405180820281191515600160ff1b8414151782158484840514171615615a695790509050610400525b6103605161040051056104605261046051670de0b6b3a7640000610460516103a05180820281191515600160ff1b8414151782158484840514171615615a695790509050058082038281136000831218615a695790509050670de0b6b3a76400008103818113615a69579050610460526102e05115611ebb57610420516103c0511315611ebb57610440516020615afb6000396000516386fc88d36104a05260206104a060046104bc845afa611e27573d600060003e3d6000fd5b60203d10615a69576104a09050518060ff1c615a695780828118828413021890509050610440518082038281136000831218615a6957905090506104805260016104805112611ebb576104605161036051610480516103e05180820281191515600160ff1b8414151782158484840514171615615a695790509050058082018281126000831218615a695790509050610460525b6020610460f35b63bcbaf4878118611ee05760443610615a695760016109c052611f03565b633ecdb8288118611f8f5760643610615a69576044358060011c615a69576109c0525b6004358060a01c615a69576109a05234615a6957600054600214615a6957600260005560006109e052336109a05114611f4d5760026109a0516020526000526040600020546109e0525b6109a05161064052602435610660526109e05161068052670de0b6b3a76400006106a0526109c0516106c0526040366106e037611f88615233565b6003600055005b63036aed8881186120a65760e43610615a69576004358060a01c615a69576109a0526064358060011c615a69576109c0526084358060a01c615a69576109e05260a4356004016005813511615a6957803580610a0052602082018160051b8082610a20375050505034615a6957600054600214615a695760026000556000610ac052336109a051146120325760026109a051602052600052604060002054610ac0525b6109a0516106405260243561066052610ac05161068052604435670de0b6b3a7640000818118670de0b6b3a76400008310021890506106a0526109c0516106c0526109e0516106e052610a005180610700528060051b8061072082610a2060045afa50505061209f615233565b6003600055005b631b25cdaf81186120ca5760243610615a6957670de0b6b3a764000060e0526120e4565b63546e040d81186122085760443610615a695760243560e0525b6004358060a01c615a695760c05234615a6957600054600214615a69576000610100523360c0511461212657600260c051602052600052604060002054610100525b670de0b6b3a76400006020615afb60003960005163544fb5c16101405260c051610160526040610140602461015c845afa612166573d600060003e3d6000fd5b60403d10615a695761014090505160e0516040526101005160605261218c6101a06151c6565b6101a051808202811583838304141715615a6957905090500461012052670de0b6b3a764000060c0516040526121c361016061369d565b6101605160e051808202811583838304141715615a69579050905004610140526101205161014051610120518082811882841102189050905003610160526020610160f35b63e2d8ebee81186122265760243610615a6957600061020052612249565b638908ea8281186122d55760443610615a69576024358060011c615a6957610200525b6004358060a01c615a69576101e05234615a6957600054600214615a695760206101e051610260526101e05160405261228361022061369d565b6102205161028052610200516102a05260026101e0516020526000526040600020546102c05261026051604052610280516060526102a0516080526102c05160a0526122d0610240614ebd565b610240f35b627c98ab81186122f35760043610615a69576040366101e037612334565b6380e8f6ec81186123185760243610615a69576004356101e052600061020052612334565b6390f8667d81186125b55760443610615a6957604060046101e0375b34615a6957600054600214615a695768010000000000000006546102205261020051610240526102005161236b5761022051610240525b6101e051610260526000610280526000620f4240905b80620273a052610220516102605110156123a55761024051620273a05118156123a8565b60015b156123b257612524565b6102605167fffffffffffffffe8111615a695760050154620273c052620273c0516040526123e26202740061369d565b6202740051620273e052620273c051604052620273e05160605260016080526002620273c05160205260005260406000205460a05261242362027420614ebd565b620274205162027400527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff620274005113612504576020615afb60003960005163544fb5c16202746052620273c051620274805260406202746060246202747c845afa612495573d600060003e3d6000fd5b60403d10615a6957620274609050805162027420526020810151620274405250610280516103e78111615a6957600181016102805260a081026102a001620273c05181526202742051602082015262027440516040820152620273e05160608201526202740051608082015250505b6102605160018101818110615a6957905061026052600101818118612381575b5050602080620273a05280620273a00160006102805180835260a081026000826103e88111615a6957801561259f57905b60a08102602087010160a082026102a00180518252602081015160208301526040810151604083015260608101516060830152608081015160808301525050600101818118612555575b50508201602001915050905081019050620273a0f35b63d9f11a64811861260a5760043610615a695734615a695760206020615afb60003960005163f2388acb604052602060406004605c845afa6125fc573d600060003e3d6000fd5b60203d10615a695760409050f35b632c5089c3811861276a5760243610615a69576004358060a01c615a695760405234615a6957600054600214615a69576020615afb60003960005163e8dd1ef1606052604051608052602060606024607c845afa61266d573d600060003e3d6000fd5b60203d10615a69576060518060011c615a695760a05260a090505115615a69576020615afb60003960005163b461100d60a05260405160c052604060a0602460bc845afa6126c0573d600060003e3d6000fd5b60403d10615a695760a0905080516060526020810151608052506020615afb600039600051632eb858e760a05260605160c052602060a0602460bc845afa61270d573d600060003e3d6000fd5b60203d10615a695760a0905051610120526020615afb6000396000516324299b7a60e05260805161010052602060e0602460fc845afa612752573d600060003e3d6000fd5b60203d10615a695760e0905051610140526040610120f35b63ec74d0a881186128885760243610615a69576004358060a01c615a695760c05234615a6957600054600214615a69576020615afb60003960005163544fb5c16101205260c051610140526040610120602461013c845afa6127d1573d600060003e3d6000fd5b60403d10615a69576101209050805160e052602081015161010052506020615afb60003960005163b461100d6101605260c051610180526040610160602461017c845afa612824573d600060003e3d6000fd5b60403d10615a6957610160905080516101205260208101516101405250610100516101805260e0516101a05260c05160405261286161016061369d565b610160516101c05260016101205161014051030160008112615a69576101e0526080610180f35b634189617d81186129b15760243610615a695734615a69576020615a7b60003960005163f851a440604052602060406004605c845afa6128cd573d600060003e3d6000fd5b60203d10615a69576040518060a01c615a695760805260809050513318615a695767016345785d8a00006004351115612907576000612911565b620f424060043510155b6129725760036040527f466565000000000000000000000000000000000000000000000000000000000060605260405060405180606001601f826000031636823750506308c379a06000526020602052601f19601f6040510116604401601cfd5b6020615afb600039600051631aa02d59604052600435606052803b15615a6957600060406024605c6000855af16129ae573d600060003e3d6000fd5b50005b63a5b4804a8118612ac55760243610615a695734615a69576020615a7b60003960005163f851a440604052602060406004605c845afa6129f6573d600060003e3d6000fd5b60203d10615a69576040518060a01c615a695760805260809050513318615a6957670de0b6b3a76400006004351115612a865760086040527f486967682066656500000000000000000000000000000000000000000000000060605260405060405180606001601f826000031636823750506308c379a06000526020602052601f19601f6040510116604401601cfd5b6020615afb600039600051633217902f604052600435606052803b15615a6957600060406024605c6000855af1612ac2573d600060003e3d6000fd5b50005b6381d2f1b78118612bbc5760243610615a69576004358060a01c615a695760405234615a6957600054600214615a695760026000556020615a7b60003960005163f851a440606052602060606004607c845afa612b27573d600060003e3d6000fd5b60203d10615a69576060518060a01c615a695760a05260a09050513318615a6957604051680100000000000000095560405163e91f2f4c606052602060606004607c6000855af1612b7d573d600060003e3d6000fd5b60203d10615a6957606050507f51fabb88f7860c9dbcc2a5a9b69a8b9476d63b87124591f97254e29f0e8daaeb60405160605260206060a16003600055005b632a0c35868118612cae5760443610615a695734615a6957600054600214615a695760026000556020615a7b60003960005163f851a440604052602060406004605c845afa612c10573d600060003e3d6000fd5b60203d10615a69576040518060a01c615a695760805260809050513318615a69576024356004351115615a6957662386f26fc1000060243510615a69576706f05b59d3b2000060043511615a69576024356801000000000000000a556004356801000000000000000b557fe2750bf9a7458977fcc01c1a0b615d12162f63b18cad78441bd64c590b337eca6040600460403760406040a16003600055005b63cc1891c78118612d755760243610615a69576004358060a01c615a695760405234615a6957600054600214615a695760026000556020615a7b60003960005163f851a440606052602060606004607c845afa612d10573d600060003e3d6000fd5b60203d10615a69576060518060a01c615a695760a05260a09050513318615a69576020615afb60003960005163cc1891c7606052604051608052803b15615a6957600060606024607c6000855af1612d6d573d600060003e3d6000fd5b506003600055005b631b1800e38118612e505760043610615a695734615a69576020615afb60003960005163095a0fc6606052602060606004607c845afa612dba573d600060003e3d6000fd5b60203d10615a69576060905051604052600354606052600454608052606051604051808202811583838304141715615a6957905090506080518015615a6957808204905090506060526060516801000000000000000854808201828110615a695790509050606052680100000000000000075460a05260a05160605160a051808281188284110218905090500360c052602060c0f35b631e0cfcef81186132305760043610615a695734615a6957600054600214615a695760026000556020615a7b60003960005163cab4d3db60c052602060c0600460dc845afa612ea4573d600060003e3d6000fd5b60203d10615a695760c0518060a01c615a69576101005261010090505160a0526020615afb60003960005163d1fea73360e052602060e0600460fc845afa612ef1573d600060003e3d6000fd5b60203d10615a695760e090505160c0526020615afb6000396000516389960ba7610100526020610100600461011c845afa612f31573d600060003e3d6000fd5b60203d10615a695761010090505160e05260c05115612fb7576020615a9b6000396000516323b872dd610100526020615afb6000396000516101205260a0516101405260c051610160526020610100606461011c6000855af1612f99573d600060003e3d6000fd5b60203d10615a6957610100518060011c615a69576101805261018050505b60e0511561304a576020615abb6000396000516323b872dd610100526020615afb6000396000516101205260a0516101405260e051610160526020610100606461011c6000855af161300e573d600060003e3d6000fd5b3d61302557803b15615a695760016101805261303e565b60203d10615a6957610100518060011c615a6957610180525b61018090505115615a69575b6020615afb60003960005163822fe50761010052803b15615a69576000610100600461011c6000855af1613083573d600060003e3d6000fd5b5061308f61012061357d565b610120516101005260035461012052600454610140526101205161010051808202811583838304141715615a695790509050610140518015615a6957808204905090506101205261010051610140526101205160035561014051600455610120516801000000000000000854808201828110615a69579050905061016052680100000000000000075461018052610180516101605111613172577f5393ab6ef9bb40d91d1b04bbbeb707fbf3d1eb73f46744e2d179e4996026283f60006101a052610120516101c05260406101a0a160006101a05260206101a061322956613229565b610160516801000000000000000755610180516101605103610160526020615a9b60003960005163a9059cbb6101a05260a0516101c052610160516101e05260206101a060446101bc6000855af16131cf573d600060003e3d6000fd5b60203d10615a69576101a0518060011c615a69576102005261020050507f5393ab6ef9bb40d91d1b04bbbeb707fbf3d1eb73f46744e2d179e4996026283f610160516101a052610120516101c05260406101a0a160206101605b6003600055f35b635457ff7b81186132705760243610615a69576004358060a01c615a695760405234615a6957600260405160205260005260406000205460605260206060f35b63e1ec3c6881186132a75760243610615a695734615a695760043567fffffffffffffffe8111615a69576005015460405260206040f35b637128f3b881186132ef5760243610615a69576004358060a01c615a695760405234615a69576801000000000000000560405160205260005260406000205460605260206060f35b636cce39be811861331b5760043610615a695734615a6957680100000000000000065460405260206040f35b634f02c42081186133475760043610615a695734615a6957680100000000000000075460405260206040f35b63e231bff081186133735760043610615a695734615a6957680100000000000000085460405260206040f35b63adfae4ce811861339f5760043610615a695734615a6957680100000000000000095460405260206040f35b63627d2b8381186133cb5760043610615a695734615a69576801000000000000000a5460405260206040f35b635449b9cb81186133f75760043610615a695734615a69576801000000000000000b5460405260206040f35b505b3415613410576020615b9b60003960005115615a69575b36615a6957005b670de0b6b3a764000060405110606052600060805260405160a0526060511561345b5760a0518015615a6957806ec097ce7bc90715b34b9f100000000004905060a0525b608060c05260006008905b8060e05260c05160020a61010052670de0b6b3a7640000610100510260a051106134aa576101005160a0510460a052608051670de0b6b3a764000060c05102016080525b60c05160011c60c052600101818118613466575050670de0b6b3a764000060e05260006022905b8061010052671bc16d674ec8000060a051106134fb5760e0516080510160805260a05160011c60a0525b670de0b6b3a764000060a05160a051020460a05260e05160011c60e0526001018181186134d1575050606051613542576080518060ff1c615a695781525061357b5661357b565b6080518060ff1c615a69577f80000000000000000000000000000000000000000000000000000000000000008114615a69576000038152505b565b680100000000000000095463e91f2f4c606052602060606004607c6000855af16135ac573d600060003e3d6000fd5b60203d10615a69576060905051640a3c2abcef818118640a3c2abcef8310021890506040526020615afb60003960005163d4387a99606052604051608052602060606024607c6000855af1613606573d600060003e3d6000fd5b60203d10615a69576060905051815250565b61362260e061357d565b60e05160c052600160a0516020526000526040600020805460e0526001810154610100525060e051613664576000815260c05160208201525061369b5661369b565b60e05160c051808202811583838304141715615a695790509050610100518015615a695780820490509050815260c0516020820152505b565b6020615afb60003960005163095a0fc6608052602060806004609c845afa6136ca573d600060003e3d6000fd5b60203d10615a69576080905051606052600160405160205260005260406000208054608052600181015460a0525060805161370d57600081525061373b5661373b565b608051606051808202811583838304141715615a69579050905060a0518015615a6957808204905090508152505b565b6040516080516040516060518015615a6957808204905090506103e88181186103e88311021890508015615a695780683635c9adc5dea00000049050808201828110615a695790509050670de0b6b3a7640000818118670de0b6b3a7640000831002189050670de0b6b3a764000003808202811583838304141715615a6957905090506020615b7b600039600051606051808202811583838304141715615a6957905090508015615a69578082049050905060a05260a05160c052600160318101905b8060e05260605160e051186138145761385a565b6020615b1b60003960005160a0516020615b3b600039600051808202811583838304141715615a6957905090500460a05260a05160c0510160c052600101818118613800575b505060c051815250565b610140516138d2576007610180527f4e6f206c6f616e000000000000000000000000000000000000000000000000006101a0526101805061018051806101a001601f826000031636823750506308c379a061014052602061016052601f19601f61018051011660440161015cfd5b6020615afb600039600051638f8654c56101a05260206101a060046101bc845afa613902573d600060003e3d6000fd5b60203d10615a69576101a0905051610180526020615afb600039600051632eb858e76101c052610180516101e05260206101c060246101dc845afa61394c573d600060003e3d6000fd5b60203d10615a69576101c09050516101a052610120516020615adb600039600051808202811583838304141715615a695790509050604052610160516060526801000000000000000b546080526139a46101e061373d565b6101e0516101c0526101c0516101a051808202811583838304141715615a6957905090506101405160018101818110615a695790508015615a6957808204905090506101c0526101c051613a5857600e6101e0527f416d6f756e7420746f6f206c6f77000000000000000000000000000000000000610200526101e0506101e0518061020001601f826000031636823750506308c379a06101a05260206101c052601f19601f6101e05101166044016101bcfd5b6101c051604052613a6a610200613417565b610200516101e0527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6101e05113613ad0576101e0516020615b5b60003960005160018103818113615a695790508082038281136000831218615a6957905090506101e0525b6101e0516020615b5b6000396000518015615a6957808205600160ff1b8314156000198314151715615a6957905090506101e0526101e051610160518060ff1c615a6957806104000361040081136000831218615a6957905080828118828412021890509050610180518082018281126000831218615a6957905090506101e052610180516101e05113613c2b576020615afb60003960005163ec654706610200526101e05160018103818113615a69579050610220526020610200602461021c845afa613ba3573d600060003e3d6000fd5b60203d10615a6957610200518060011c615a695761024052610240905051613c2b57600d610260527f4465627420746f6f2068696768000000000000000000000000000000000000006102805261026050610260518061028001601f826000031636823750506308c379a061022052602061024052601f19601f61026051011660440161023cfd5b6020615afb6000396000516386fc88d3610240526020610240600461025c845afa613c5b573d600060003e3d6000fd5b60203d10615a69576102409050516020615afb600039600051632eb858e7610200526101e051610220526020610200602461021c845afa613ca1573d600060003e3d6000fd5b60203d10615a695761020090505110613d1a57600d610280527f4465627420746f6f2068696768000000000000000000000000000000000000006102a0526102805061028051806102a001601f826000031636823750506308c379a061024052602061026052601f19601f61028051011660440161025cfd5b6101e051815250565b6020615afb6000396000516386fc88d3610140526020610140600461015c845afa613d53573d600060003e3d6000fd5b60203d10615a6957610140905051610120526020615b5b6000396000516020615afb60003960005163a7db79a5610160526020610160600461017c845afa613da0573d600060003e3d6000fd5b60203d10615a6957610160905051670de0b6b3a7640000810281670de0b6b3a7640000820418615a69579050610120518015615a695780820490509050604052613deb6101a0613417565b6101a0510560058101818112615a69579050610140526020615afb600039600051632eb858e761018052610140516101a0526020610180602461019c845afa613e39573d600060003e3d6000fd5b60203d10615a6957610180905051610160526020615afb60003960005163c16ef2646101a05260206101a060046101bc845afa613e7b573d600060003e3d6000fd5b60203d10615a69576101a0905051610180526000610401905b806101a0526101405160018103818113615a6957905061014052610180516101405113613ec057613f22565b610160516101c0526020615b3b600039600051610160516020615b1b600039600051808202811583838304141715615a695790509050046101605261012051610160511115613f17576101c0518352505050613f2c565b600101818118613e94575b5050610160518152505b565b6020615b9b600039600051613f4557606051615a69575b604051606051808203828111615a69579050905060805260605115614002576020615abb60003960005163d0e30db060a052803b15615a6957600060a0600460bc606051855af1613f9b573d600060003e3d6000fd5b506020615abb60003960005163a9059cbb60a0526020615afb60003960005160c05260605160e052602060a0604460bc6000855af1613fdf573d600060003e3d6000fd5b60203d10615a695760a0518060011c615a69576101005261010090505115615a69575b6080511561408d576020615abb6000396000516323b872dd60a0523360c0526020615afb60003960005160e05260805161010052602060a0606460bc6000855af1614052573d600060003e3d6000fd5b3d61406957803b15615a6957600161012052614081565b60203d10615a695760a0518060011c615a6957610120525b61012090505115615a69575b565b60805161409d5760006140a9565b6020615b9b6000396000515b614136576020615abb6000396000516323b872dd60a0526020615afb60003960005160c05260405160e05260605161010052602060a0606460bc6000855af16140f7573d600060003e3d6000fd5b3d61410e57803b15615a6957600161012052614126565b60203d10615a695760a0518060011c615a6957610120525b61012090505115615a6957614207565b6020615abb6000396000516323b872dd60a0526020615afb60003960005160c0523060e05260605161010052602060a0606460bc6000855af161417e573d600060003e3d6000fd5b60203d10615a695760a0518060011c615a69576101205261012090505115615a69576020615abb600039600051632e1a7d4d60a05260605160c052803b15615a6957600060a0602460bc6000855af16141dc573d600060003e3d6000fd5b50600060a05260a0506000600060a05160c0606051604051612710f1614207573d600060003e3d6000fd5b565b6020615abb60003960005160405114615a69576060366101c0376020615afb600039600051638f8654c5610220526020610220600461023c845afa614253573d600060003e3d6000fd5b60203d10615a69576102209050516101c0526020615afb60003960005163ebcb0067610240526101c051610260526020610240602461025c845afa61429d573d600060003e3d6000fd5b60203d10615a6957610240905051610220526020615afb6000396000516331f7e306610260526101c051610280526020610260602461027c845afa6142e7573d600060003e3d6000fd5b60203d10615a695761026090505161024052600060605181610460015260048101905060a06080516102e05260a0516103005260c0516103205260e051610340528061036052806102e0016000610100518083528060051b60008260058111615a6957801561437057905b8060051b61012001518160051b602088010152600101818118614352575b505082016020019150509050810190506102c0526102c080516020820183610460018281848460045afa505050808301925050508061044052610440505060406106006104405161046060006040515af16143d0573d600060003e3d6000fd5b3d604081183d60401002186105e0526105e0805180610260526020820181610280838360045afa5050505061026051602011615a6957610280516102e05260206102c0526102c06020810151815160200360031b1c90506101e05261026051604011615a69576102a0516102e05260206102c0526102c06020810151815160200360031b1c9050610200526020615afb600039600051638f8654c56102c05260206102c060046102dc845afa61448b573d600060003e3d6000fd5b60203d10615a69576102c09050516101c05118615a69576020615afb60003960005163ebcb00676102c0526101c0516102e05260206102c060246102dc845afa6144da573d600060003e3d6000fd5b60203d10615a69576102c09050516102205118615a69576020615afb6000396000516331f7e3066102c0526101c0516102e05260206102c060246102dc845afa614529573d600060003e3d6000fd5b60203d10615a69576102c09050516102405118615a69576101c05181526101e051602082015261020051604082015250565b600133602052600052604060002054156145d5576014610360527f4c6f616e20616c726561647920637265617465640000000000000000000000006103805261036050610360518061038001601f826000031636823750506308c379a061032052602061034052601f19601f61036051011660440161033cfd5b600461032051101561464757600f610360527f4e656564206d6f7265207469636b7300000000000000000000000000000000006103805261036050610360518061038001601f826000031636823750506308c379a061032052602061034052601f19601f61036051011660440161033cfd5b60326103205111156146b957600f610360527f4e656564206c657373207469636b7300000000000000000000000000000000006103805261036050610360518061038001601f826000031636823750506308c379a061032052602061034052601f19601f61036051011660440161033cfd5b6102e05161012052610300516101405261032051610160526146dc610380613864565b6103805161036052610360516103205160018103818111615a695790508060ff1c615a69578082018281126000831218615a695790509050610380526147236103c061357d565b6103c0516103a05260013360205260005260406000206103005181556103a0516001820155506801000000000000000a546103c0526103c05160023360205260005260406000205568010000000000000006546103e052336103e05167fffffffffffffffe8111615a6957600501556103e051680100000000000000053360205260005260406000205560016103e0510168010000000000000006556003546103a051808202811583838304141715615a6957905090506004548015615a69578082049050905061030051808201828110615a69579050905061040052610400516003556103a0516004556020615afb60003960005163ab047e006104205233610440526102e051610460526103605161048052610380516104a052803b15615a69576000610420608461043c6000855af1614864573d600060003e3d6000fd5b50680100000000000000075461030051808201828110615a69579050905068010000000000000007556103405115614909576102e0516040526102c0516060526148ac613f2e565b6020615a9b60003960005163a9059cbb61042052336104405261030051610460526020610420604461043c6000855af16148eb573d600060003e3d6000fd5b60203d10615a6957610420518060011c615a69576104805261048050505b337feec6b7095a637e006c79c1819d696e353a8f703db2c49fc0219e17a8fd04f7f26102e051610420526103005161044052610360516104605261038051610480526103c0516104a05260a0610420a2337fe1979fe4c35e0cef342fef5668e2c8e7a7e9f5d5d1ca8fee0ac6c427fa4153af6102e0516104205261030051610440526040610420a2565b604036610340376103005160a0526149ac610380613618565b6103808051610340526020810151610360525061034051614a2d576012610380527f4c6f616e20646f65736e277420657869737400000000000000000000000000006103a0526103805061038051806103a001601f826000031636823750506308c379a061034052602061036052601f19601f61038051011660440161035cfd5b610340516102e051808201828110615a695790509050610340526020615afb60003960005163b461100d6103c052610300516103e05260406103c060246103dc845afa614a7f573d600060003e3d6000fd5b60403d10615a69576103c0905080516103805260208101516103a052506001610380516103a051030160008112615a69576103c0526020615afb60003960005163f3fef3a3610420526103005161044052670de0b6b3a7640000610460526040610420604461043c6000855af1614afb573d600060003e3d6000fd5b60403d10615a6957610420905080516103e052602081015161040052506103e05115614b8757601a610420527f416c726561647920696e20756e6465727761746572206d6f64650000000000006104405261042050610420518061044001601f826000031636823750506308c379a06103e052602061040052601f19601f6104205101166044016103fcfd5b61032051614bae57610400516102c051808201828110615a69579050905061040052614bc9565b610400516102c051808203828111615a695790509050610400525b610400516101205261034051610140526103c05161016052614bec610440613864565b610440516104205261042051610380516103a051038082018281126000831218615a695790509050610440526020615afb60003960005163ab047e00610460526103005161048052610400516104a052610420516104c052610440516104e052803b15615a69576000610460608461047c6000855af1614c71573d600060003e3d6000fd5b506001610300516020526000526040600020610340518155610360516001820155506801000000000000000a5461046052610460516002610300516020526000526040600020556102e05115614d115760035461036051808202811583838304141715615a6957905090506004548015615a6957808204905090506102e051808201828110615a6957905090506104805261048051600355610360516004555b61032051614d5957610300517fe1979fe4c35e0cef342fef5668e2c8e7a7e9f5d5d1ca8fee0ac6c427fa4153af6102c051610480526102e0516104a0526040610480a2614d8d565b610300517fe25410a4059619c9594dc6f022fe231b02aaea733f689e7ab0cd21b3d4d0eb546102c051610480526020610480a25b610300517feec6b7095a637e006c79c1819d696e353a8f703db2c49fc0219e17a8fd04f7f26104005161048052610340516104a052610420516104c052610440516104e052610460516105005260a0610480a2565b680100000000000000065460018103818111615a695790506060526801000000000000000560405160205260005260406000205460805260405160805167fffffffffffffffe8111615a69576005015418615a69576000680100000000000000056040516020526000526040600020556060516080511015614ead5760605167fffffffffffffffe8111615a69576005015460a05260a05160805167fffffffffffffffe8111615a6957600501556080516801000000000000000560a0516020526000526040600020555b6060516801000000000000000655565b606051614f2157601260c0527f4c6f616e20646f65736e2774206578697374000000000000000000000000000060e05260c05060c0518060e001601f826000031636823750506308c379a0608052602060a052601f19601f60c0510116604401609cfd5b60a0518060ff1c615a695780670de0b6b3a764000003670de0b6b3a764000081136000831218615a6957905060c0526060518060ff1c615a69576020615afb6000396000516362ca4b1860e05260405161010052602060e0602460fc845afa614f8f573d600060003e3d6000fd5b60203d10615a695760e09050518060ff1c615a695760c05180820281191515600160ff1b8414151782158484840514171615615a69579050905005670de0b6b3a76400008103818113615a6957905060c052608051156151be576020615afb60003960005163b461100d61010052604051610120526040610100602461011c845afa615020573d600060003e3d6000fd5b60403d10615a695761010090505160e0526020615afb600039600051638f8654c5610100526020610100600461011c845afa615061573d600060003e3d6000fd5b60203d10615a695761010090505160e05113156151be576020615afb6000396000516386fc88d3610160526020610160600461017c845afa6150a8573d600060003e3d6000fd5b60203d10615a6957610160905051610140526020615afb600039600051632eb858e76101805260e0516101a0526020610180602461019c845afa6150f1573d600060003e3d6000fd5b60203d10615a695761018090505161016052610160516101405111156151be5760c0516060516101605161014051036020615afb60003960005163544fb5c1610180526040516101a0526040610180602461019c845afa615157573d600060003e3d6000fd5b60403d10615a6957610180905060208101905051808202811583838304141715615a6957905090506020615adb600039600051808202811583838304141715615a695790509050048060ff1c615a69578082018281126000831218615a69579050905060c0525b60c051815250565b670de0b6b3a7640000608052670de0b6b3a763ffff6040511161522b57606051670de0b6b3a764000001604051670de0b6b3a76400000360605160011c670de0b6b3a7640000010204608052670de0b6b3a76400006040516040516080510102046080525b608051815250565b6040366107c0376106405160a05261524c610800613618565b61080080516107c05260208101516107e05250610680511561531e577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff610640516040526107c05160605260016080526106805160a0526152ae610800614ebd565b61080051131561531e57600f610820527f4e6f7420656e6f7567682072656b7400000000000000000000000000000000006108405261082050610820518061084001601f826000031636823750506308c379a06107e052602061080052601f19601f6108205101166044016107fcfd5b6107c05161080052670de0b6b3a76400006107c0516106a051808202811583838304141715615a695790509050046107c0526107c05115615a69576107c0516108005103610800526020615afb60003960005163f3fef3a361088052610640516108a0526106a0516040526106805160605261539b6108606151c6565b610860516108c0526040610880604461089c6000855af16153c1573d600060003e3d6000fd5b60403d10615a695761088090508051610820526020810151610840525061066051610820511015615452576008610860527f536c6970706167650000000000000000000000000000000000000000000000006108805261086050610860518061088001601f826000031636823750506308c379a061082052602061084052601f19601f61086051011660440161083cfd5b610820516107c051808281188284100218905090506108605261086051156154e0576020615a9b6000396000516323b872dd610880526020615afb6000396000516108a052306108c052610860516108e0526020610880606461089c6000855af16154c2573d600060003e3d6000fd5b60203d10615a6957610880518060011c615a69576109005261090050505b610820516107c0511161558a5733604052610840516060526106c05160805261550761408f565b6107c051610820511115615903576020615a9b6000396000516323b872dd610880526020615afb6000396000516108a052336108c0526107c05161082051036108e0526020610880606461089c6000855af1615568573d600060003e3d6000fd5b60203d10615a6957610880518060011c615a6957610900526109005050615903565b610820516107c05103610880526106e05161561f5733604052610840516060526106c0516080526155b961408f565b6020615a9b6000396000516323b872dd6108a052336108c052306108e052610880516109005260206108a060646108bc6000855af16155fd573d600060003e3d6000fd5b60203d10615a69576108a0518060011c615a6957610920526109205050615903565b61084051156156b5576020615abb6000396000516323b872dd6108a0526020615afb6000396000516108c0526106e0516108e052610840516109005260206108a060646108bc6000855af1615679573d600060003e3d6000fd5b3d61569057803b15615a69576001610920526156a9565b60203d10615a69576108a0518060011c615a6957610920525b61092090505115615a69575b6106e0516040527f4ea696bb00000000000000000000000000000000000000000000000000000000606052610640516080526108205160a0526108405160c0526107c05160e0526107005180610100528060051b806101208261072060045afa505050615723610900614209565b61090080516108a05260208101516108c05260408101516108e05250610880516108c05110156157b3576013610900527f6e6f7420656e6f7567682070726f6365656473000000000000000000000000006109205261090050610900518061092001601f826000031636823750506308c379a06108c05260206108e052601f19601f6109005101166044016108dcfd5b610880516108c051111561582b576020615a9b6000396000516323b872dd610900526106e051610920523361094052610880516108c05103610960526020610900606461091c6000855af161580d573d600060003e3d6000fd5b60203d10615a6957610900518060011c615a69576109805261098050505b6020615a9b6000396000516323b872dd610900526106e05161092052306109405261088051610960526020610900606461091c6000855af1615872573d600060003e3d6000fd5b60203d10615a6957610900518060011c615a69576109805261098050506108e05115615903576020615abb6000396000516323b872dd610900526106e0516109205233610940526108e051610960526020610900606461091c6000855af16158df573d600060003e3d6000fd5b60203d10615a6957610900518060011c615a69576109805261098090505115615a69575b68010000000000000008546107c051808201828110615a695790509050680100000000000000085560016106405160205260005260406000206108005181556107e051600182015550610640517f77c6871227e5d2dec8dadd5354f78453203e22e669cd0ec4c19d9a8c5edb31d061084051610880526107c0516108a0526040610880a261064051337f642dd4d37ddd32036b9797cec464c0045dd2118c549066ae6b0f88e32240c2d06108405161088052610820516108a0526107c0516108c0526060610880a361080051615a1457610640517feec6b7095a637e006c79c1819d696e353a8f703db2c49fc0219e17a8fd04f7f260a0366108803760a0610880a261064051604052615a14614de2565b6003546107e051808202811583838304141715615a6957905090506004548015615a695780820490509050610880526107c051610880516107c05180828118828411021890509050036003556107e051600455565b600080fda165767970657283000307000b000000000000000000000000c9332fdcb1c491dcc683bae86fe3cb70360738bc000000000000000000000000f939e0a03fb07f59a73314e73794be0e57ac1b4e0000000000000000000000002260fac5e5542a773aa44fbcfedf7c193bc2c59900000000000000000000000000000000000000000000000000000002540be400000000000000000000000000e0438eb3703bf871e31ce639bd351109c88666ea00000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000063000000000000000000000000000000000000000000000000003383482309faa60000000000000000000000000000000000000000000000000df29c916c5c292b0000000000000000000000000000000000000000000000000000000000000000
Verified Source Code Partial Match
Compiler: v0.3.7+commit.6020b8bb
crvUSDController.vy 1329 lines
# @version 0.3.7
"""
@title crvUSD Controller
@author Curve.Fi
@license Copyright (c) Curve.Fi, 2020-2023 - all rights reserved
"""
interface LLAMMA:
def A() -> uint256: view
def get_p() -> uint256: view
def get_base_price() -> uint256: view
def active_band() -> int256: view
def active_band_with_skip() -> int256: view
def p_oracle_up(n: int256) -> uint256: view
def p_oracle_down(n: int256) -> uint256: view
def deposit_range(user: address, amount: uint256, n1: int256, n2: int256): nonpayable
def read_user_tick_numbers(_for: address) -> int256[2]: view
def get_sum_xy(user: address) -> uint256[2]: view
def withdraw(user: address, frac: uint256) -> uint256[2]: nonpayable
def get_x_down(user: address) -> uint256: view
def get_rate_mul() -> uint256: view
def set_rate(rate: uint256) -> uint256: nonpayable
def set_fee(fee: uint256): nonpayable
def set_admin_fee(fee: uint256): nonpayable
def price_oracle() -> uint256: view
def can_skip_bands(n_end: int256) -> bool: view
def set_price_oracle(price_oracle: PriceOracle): nonpayable
def admin_fees_x() -> uint256: view
def admin_fees_y() -> uint256: view
def reset_admin_fees(): nonpayable
def has_liquidity(user: address) -> bool: view
def bands_x(n: int256) -> uint256: view
def bands_y(n: int256) -> uint256: view
def set_callback(user: address): nonpayable
interface ERC20:
def transferFrom(_from: address, _to: address, _value: uint256) -> bool: nonpayable
def transfer(_to: address, _value: uint256) -> bool: nonpayable
def decimals() -> uint256: view
def approve(_spender: address, _value: uint256) -> bool: nonpayable
def balanceOf(_from: address) -> uint256: view
interface WETH:
def deposit(): payable
def withdraw(_amount: uint256): nonpayable
interface MonetaryPolicy:
def rate_write() -> uint256: nonpayable
interface Factory:
def stablecoin() -> address: view
def admin() -> address: view
def fee_receiver() -> address: view
def WETH() -> address: view
interface PriceOracle:
def price() -> uint256: view
def price_w() -> uint256: nonpayable
event UserState:
user: indexed(address)
collateral: uint256
debt: uint256
n1: int256
n2: int256
liquidation_discount: uint256
event Borrow:
user: indexed(address)
collateral_increase: uint256
loan_increase: uint256
event Repay:
user: indexed(address)
collateral_decrease: uint256
loan_decrease: uint256
event RemoveCollateral:
user: indexed(address)
collateral_decrease: uint256
event Liquidate:
liquidator: indexed(address)
user: indexed(address)
collateral_received: uint256
stablecoin_received: uint256
debt: uint256
event SetMonetaryPolicy:
monetary_policy: address
event SetBorrowingDiscounts:
loan_discount: uint256
liquidation_discount: uint256
event CollectFees:
amount: uint256
new_supply: uint256
struct Loan:
initial_debt: uint256
rate_mul: uint256
struct Position:
user: address
x: uint256
y: uint256
debt: uint256
health: int256
struct CallbackData:
active_band: int256
stablecoins: uint256
collateral: uint256
FACTORY: immutable(Factory)
STABLECOIN: immutable(ERC20)
MAX_LOAN_DISCOUNT: constant(uint256) = 5 * 10**17
MIN_LIQUIDATION_DISCOUNT: constant(uint256) = 10**16 # Start liquidating when threshold reached
MAX_TICKS: constant(int256) = 50
MAX_TICKS_UINT: constant(uint256) = 50
MIN_TICKS: constant(int256) = 4
MAX_SKIP_TICKS: constant(uint256) = 1024
MAX_P_BASE_BANDS: constant(int256) = 5
MAX_RATE: constant(uint256) = 43959106799 # 400% APY
loan: HashMap[address, Loan]
liquidation_discounts: public(HashMap[address, uint256])
_total_debt: Loan
loans: public(address[2**64 - 1]) # Enumerate existing loans
loan_ix: public(HashMap[address, uint256]) # Position of the loan in the list
n_loans: public(uint256) # Number of nonzero loans
minted: public(uint256)
redeemed: public(uint256)
monetary_policy: public(MonetaryPolicy)
liquidation_discount: public(uint256)
loan_discount: public(uint256)
COLLATERAL_TOKEN: immutable(ERC20)
COLLATERAL_PRECISION: immutable(uint256)
AMM: immutable(LLAMMA)
A: immutable(uint256)
Aminus1: immutable(uint256)
LOG2_A_RATIO: immutable(int256) # log(A / (A - 1))
SQRT_BAND_RATIO: immutable(uint256)
MAX_ADMIN_FEE: constant(uint256) = 10**18 # 100%
MIN_FEE: constant(uint256) = 10**6 # 1e-12, still needs to be above 0
MAX_FEE: constant(uint256) = 10**17 # 10%
USE_ETH: immutable(bool)
CALLBACK_DEPOSIT: constant(bytes4) = method_id("callback_deposit(address,uint256,uint256,uint256,uint256[])", output_type=bytes4)
CALLBACK_REPAY: constant(bytes4) = method_id("callback_repay(address,uint256,uint256,uint256,uint256[])", output_type=bytes4)
CALLBACK_LIQUIDATE: constant(bytes4) = method_id("callback_liquidate(address,uint256,uint256,uint256,uint256[])", output_type=bytes4)
DEAD_SHARES: constant(uint256) = 1000
MAX_ETH_GAS: constant(uint256) = 10000 # Forward this much gas to ETH transfers (2300 is what send() does)
@external
def __init__(
collateral_token: address,
monetary_policy: address,
loan_discount: uint256,
liquidation_discount: uint256,
amm: address):
"""
@notice Controller constructor deployed by the factory from blueprint
@param collateral_token Token to use for collateral
@param monetary_policy Address of monetary policy
@param loan_discount Discount of the maximum loan size compare to get_x_down() value
@param liquidation_discount Discount of the maximum loan size compare to
get_x_down() for "bad liquidation" purposes
@param amm AMM address (Already deployed from blueprint)
"""
FACTORY = Factory(msg.sender)
stablecoin: ERC20 = ERC20(Factory(msg.sender).stablecoin())
STABLECOIN = stablecoin
assert stablecoin.decimals() == 18
self.monetary_policy = MonetaryPolicy(monetary_policy)
self.liquidation_discount = liquidation_discount
self.loan_discount = loan_discount
self._total_debt.rate_mul = 10**18
AMM = LLAMMA(amm)
_A: uint256 = LLAMMA(amm).A()
A = _A
Aminus1 = _A - 1
LOG2_A_RATIO = self.log2(_A * 10**18 / unsafe_sub(_A, 1))
COLLATERAL_TOKEN = ERC20(collateral_token)
COLLATERAL_PRECISION = pow_mod256(10, 18 - ERC20(collateral_token).decimals())
SQRT_BAND_RATIO = isqrt(unsafe_div(10**36 * _A, unsafe_sub(_A, 1)))
stablecoin.approve(msg.sender, max_value(uint256))
if Factory(msg.sender).WETH() == collateral_token:
USE_ETH = True
@payable
@external
def __default__():
if msg.value > 0:
assert USE_ETH
assert len(msg.data) == 0
@internal
@pure
def log2(_x: uint256) -> int256:
"""
@notice int(1e18 * log2(_x / 1e18))
"""
# adapted from: https://medium.com/coinmonks/9aef8515136e
# and vyper log implementation
# Might use more optimal solmate's log
inverse: bool = _x < 10**18
res: uint256 = 0
x: uint256 = _x
if inverse:
x = 10**36 / x
t: uint256 = 2**7
for i in range(8):
p: uint256 = pow_mod256(2, t)
if x >= unsafe_mul(p, 10**18):
x = unsafe_div(x, p)
res = unsafe_add(unsafe_mul(t, 10**18), res)
t = unsafe_div(t, 2)
d: uint256 = 10**18
for i in range(34): # 10 decimals: math.log(10**10, 2) == 33.2. Need more?
if (x >= 2 * 10**18):
res = unsafe_add(res, d)
x = unsafe_div(x, 2)
x = unsafe_div(unsafe_mul(x, x), 10**18)
d = unsafe_div(d, 2)
if inverse:
return -convert(res, int256)
else:
return convert(res, int256)
@external
@view
def factory() -> Factory:
"""
@notice Address of the factory
"""
return FACTORY
@external
@view
def amm() -> LLAMMA:
"""
@notice Address of the AMM
"""
return AMM
@external
@view
def collateral_token() -> ERC20:
"""
@notice Address of the collateral token
"""
return COLLATERAL_TOKEN
@internal
def _rate_mul_w() -> uint256:
"""
@notice Getter for rate_mul (the one which is 1.0+) from the AMM
"""
rate: uint256 = min(self.monetary_policy.rate_write(), MAX_RATE)
return AMM.set_rate(rate)
@internal
def _debt(user: address) -> (uint256, uint256):
"""
@notice Get the value of debt and rate_mul and update the rate_mul counter
@param user User address
@return (debt, rate_mul)
"""
rate_mul: uint256 = self._rate_mul_w()
loan: Loan = self.loan[user]
if loan.initial_debt == 0:
return (0, rate_mul)
else:
return (loan.initial_debt * rate_mul / loan.rate_mul, rate_mul)
@internal
@view
def _debt_ro(user: address) -> uint256:
"""
@notice Get the value of debt without changing the state
@param user User address
@return Value of debt
"""
rate_mul: uint256 = AMM.get_rate_mul()
loan: Loan = self.loan[user]
if loan.initial_debt == 0:
return 0
else:
return loan.initial_debt * rate_mul / loan.rate_mul
@external
@view
@nonreentrant('lock')
def debt(user: address) -> uint256:
"""
@notice Get the value of debt without changing the state
@param user User address
@return Value of debt
"""
return self._debt_ro(user)
@external
@view
@nonreentrant('lock')
def loan_exists(user: address) -> bool:
"""
@notice Check whether there is a loan of `user` in existence
"""
return self.loan[user].initial_debt > 0
# No decorator because used in monetary policy
@external
@view
def total_debt() -> uint256:
"""
@notice Total debt of this controller
"""
rate_mul: uint256 = AMM.get_rate_mul()
loan: Loan = self._total_debt
return loan.initial_debt * rate_mul / loan.rate_mul
@internal
@view
def get_y_effective(collateral: uint256, N: uint256, discount: uint256) -> uint256:
"""
@notice Intermediary method which calculates y_effective defined as x_effective / p_base,
however discounted by loan_discount.
x_effective is an amount which can be obtained from collateral when liquidating
@param collateral Amount of collateral to get the value for
@param N Number of bands the deposit is made into
@param discount Loan discount at 1e18 base (e.g. 1e18 == 100%)
@return y_effective
"""
# x_effective = sum_{i=0..N-1}(y / N * p(n_{n1+i})) =
# = y / N * p_oracle_up(n1) * sqrt((A - 1) / A) * sum_{0..N-1}(((A-1) / A)**k)
# === d_y_effective * p_oracle_up(n1) * sum(...) === y_effective * p_oracle_up(n1)
# d_y_effective = y / N / sqrt(A / (A - 1))
# d_y_effective: uint256 = collateral * unsafe_sub(10**18, discount) / (SQRT_BAND_RATIO * N)
# Make some extra discount to always deposit lower when we have DEAD_SHARES rounding
d_y_effective: uint256 = collateral * unsafe_sub(
10**18, min(discount + (DEAD_SHARES * 10**18) / max(collateral / N, DEAD_SHARES), 10**18)
) / (SQRT_BAND_RATIO * N)
y_effective: uint256 = d_y_effective
for i in range(1, MAX_TICKS_UINT):
if i == N:
break
d_y_effective = unsafe_div(d_y_effective * Aminus1, A)
y_effective = unsafe_add(y_effective, d_y_effective)
return y_effective
@internal
@view
def _calculate_debt_n1(collateral: uint256, debt: uint256, N: uint256) -> int256:
"""
@notice Calculate the upper band number for the deposit to sit in to support
the given debt. Reverts if requested debt is too high.
@param collateral Amount of collateral (at its native precision)
@param debt Amount of requested debt
@param N Number of bands to deposit into
@return Upper band n1 (n1 <= n2) to deposit into. Signed integer
"""
assert debt > 0, "No loan"
n0: int256 = AMM.active_band()
p_base: uint256 = AMM.p_oracle_up(n0)
# x_effective = y / N * p_oracle_up(n1) * sqrt((A - 1) / A) * sum_{0..N-1}(((A-1) / A)**k)
# === d_y_effective * p_oracle_up(n1) * sum(...) === y_effective * p_oracle_up(n1)
# d_y_effective = y / N / sqrt(A / (A - 1))
y_effective: uint256 = self.get_y_effective(collateral * COLLATERAL_PRECISION, N, self.loan_discount)
# p_oracle_up(n1) = base_price * ((A - 1) / A)**n1
# We borrow up until min band touches p_oracle,
# or it touches non-empty bands which cannot be skipped.
# We calculate required n1 for given (collateral, debt),
# and if n1 corresponds to price_oracle being too high, or unreachable band
# - we revert.
# n1 is band number based on adiabatic trading, e.g. when p_oracle ~ p
y_effective = y_effective * p_base / (debt + 1) # Now it's a ratio
# n1 = floor(log2(y_effective) / self.logAratio)
# EVM semantics is not doing floor unlike Python, so we do this
assert y_effective > 0, "Amount too low"
n1: int256 = self.log2(y_effective) # <- switch to faster ln() XXX?
if n1 < 0:
n1 -= LOG2_A_RATIO - 1 # This is to deal with vyper's rounding of negative numbers
n1 /= LOG2_A_RATIO
n1 = min(n1, 1024 - convert(N, int256)) + n0
if n1 <= n0:
assert AMM.can_skip_bands(n1 - 1), "Debt too high"
# Let's not rely on active_band corresponding to price_oracle:
# this will be not correct if we are in the area of empty bands
assert AMM.p_oracle_up(n1) < AMM.price_oracle(), "Debt too high"
return n1
@internal
@view
def max_p_base() -> uint256:
"""
@notice Calculate max base price including skipping bands
"""
p_oracle: uint256 = AMM.price_oracle()
# Should be correct unless price changes suddenly by MAX_P_BASE_BANDS+ bands
n1: int256 = unsafe_div(self.log2(AMM.get_base_price() * 10**18 / p_oracle), LOG2_A_RATIO) + MAX_P_BASE_BANDS
p_base: uint256 = AMM.p_oracle_up(n1)
n_min: int256 = AMM.active_band_with_skip()
for i in range(MAX_SKIP_TICKS + 1):
n1 -= 1
if n1 <= n_min:
break
p_base_prev: uint256 = p_base
p_base = unsafe_div(p_base * A, Aminus1)
if p_base > p_oracle:
return p_base_prev
return p_base
@external
@view
@nonreentrant('lock')
def max_borrowable(collateral: uint256, N: uint256, current_debt: uint256 = 0) -> uint256:
"""
@notice Calculation of maximum which can be borrowed (details in comments)
@param collateral Collateral amount against which to borrow
@param N number of bands to have the deposit into
@param current_debt Current debt of the user (if any)
@return Maximum amount of stablecoin to borrow
"""
# Calculation of maximum which can be borrowed.
# It corresponds to a minimum between the amount corresponding to price_oracle
# and the one given by the min reachable band.
#
# Given by p_oracle (perhaps needs to be multiplied by (A - 1) / A to account for mid-band effects)
# x_max ~= y_effective * p_oracle
#
# Given by band number:
# if n1 is the lowest empty band in the AMM
# xmax ~= y_effective * amm.p_oracle_up(n1)
#
# When n1 -= 1:
# p_oracle_up *= A / (A - 1)
y_effective: uint256 = self.get_y_effective(collateral * COLLATERAL_PRECISION, N, self.loan_discount)
x: uint256 = unsafe_sub(max(unsafe_div(y_effective * self.max_p_base(), 10**18), 1), 1)
x = unsafe_div(x * (10**18 - 10**14), 10**18) # Make it a bit smaller
return min(x, STABLECOIN.balanceOf(self) + current_debt) # Cannot borrow beyond the amount of coins Controller has
@external
@view
@nonreentrant('lock')
def min_collateral(debt: uint256, N: uint256) -> uint256:
"""
@notice Minimal amount of collateral required to support debt
@param debt The debt to support
@param N Number of bands to deposit into
@return Minimal collateral required
"""
# Add N**2 to account for precision loss in multiple bands, e.g. N * 1 / (y/N) = N**2 / y
return unsafe_div(unsafe_div(debt * 10**18 / self.max_p_base() * 10**18 / self.get_y_effective(10**18, N, self.loan_discount) + N * (N + 2 * DEAD_SHARES), COLLATERAL_PRECISION) * 10**18, 10**18 - 10**14)
@external
@view
@nonreentrant('lock')
def calculate_debt_n1(collateral: uint256, debt: uint256, N: uint256) -> int256:
"""
@notice Calculate the upper band number for the deposit to sit in to support
the given debt. Reverts if requested debt is too high.
@param collateral Amount of collateral (at its native precision)
@param debt Amount of requested debt
@param N Number of bands to deposit into
@return Upper band n1 (n1 <= n2) to deposit into. Signed integer
"""
return self._calculate_debt_n1(collateral, debt, N)
@internal
def _deposit_collateral(amount: uint256, mvalue: uint256):
"""
Deposits raw ETH, WETH or both at the same time
"""
if not USE_ETH:
assert mvalue == 0 # dev: Not accepting ETH
diff: uint256 = amount - mvalue # dev: Incorrect ETH amount
if mvalue > 0:
WETH(COLLATERAL_TOKEN.address).deposit(value=mvalue)
assert COLLATERAL_TOKEN.transfer(AMM.address, mvalue)
if diff > 0:
assert COLLATERAL_TOKEN.transferFrom(msg.sender, AMM.address, diff, default_return_value=True)
@internal
def _withdraw_collateral(_for: address, amount: uint256, use_eth: bool):
if use_eth and USE_ETH:
assert COLLATERAL_TOKEN.transferFrom(AMM.address, self, amount)
WETH(COLLATERAL_TOKEN.address).withdraw(amount)
raw_call(_for, b"", value=amount, gas=MAX_ETH_GAS)
else:
assert COLLATERAL_TOKEN.transferFrom(AMM.address, _for, amount, default_return_value=True)
@internal
def execute_callback(callbacker: address, callback_sig: bytes4,
user: address, stablecoins: uint256, collateral: uint256, debt: uint256,
callback_args: DynArray[uint256, 5]) -> CallbackData:
assert callbacker != COLLATERAL_TOKEN.address
data: CallbackData = empty(CallbackData)
data.active_band = AMM.active_band()
band_x: uint256 = AMM.bands_x(data.active_band)
band_y: uint256 = AMM.bands_y(data.active_band)
# Callback
response: Bytes[64] = raw_call(
callbacker,
concat(callback_sig, _abi_encode(user, stablecoins, collateral, debt, callback_args)),
max_outsize=64
)
data.stablecoins = convert(slice(response, 0, 32), uint256)
data.collateral = convert(slice(response, 32, 32), uint256)
# Checks after callback
assert data.active_band == AMM.active_band()
assert band_x == AMM.bands_x(data.active_band)
assert band_y == AMM.bands_y(data.active_band)
return data
@internal
def _create_loan(mvalue: uint256, collateral: uint256, debt: uint256, N: uint256, transfer_coins: bool):
assert self.loan[msg.sender].initial_debt == 0, "Loan already created"
assert N > MIN_TICKS-1, "Need more ticks"
assert N < MAX_TICKS+1, "Need less ticks"
n1: int256 = self._calculate_debt_n1(collateral, debt, N)
n2: int256 = n1 + convert(N - 1, int256)
rate_mul: uint256 = self._rate_mul_w()
self.loan[msg.sender] = Loan({initial_debt: debt, rate_mul: rate_mul})
liquidation_discount: uint256 = self.liquidation_discount
self.liquidation_discounts[msg.sender] = liquidation_discount
n_loans: uint256 = self.n_loans
self.loans[n_loans] = msg.sender
self.loan_ix[msg.sender] = n_loans
self.n_loans = unsafe_add(n_loans, 1)
total_debt: uint256 = self._total_debt.initial_debt * rate_mul / self._total_debt.rate_mul + debt
self._total_debt.initial_debt = total_debt
self._total_debt.rate_mul = rate_mul
AMM.deposit_range(msg.sender, collateral, n1, n2)
self.minted += debt
if transfer_coins:
self._deposit_collateral(collateral, mvalue)
STABLECOIN.transfer(msg.sender, debt)
log UserState(msg.sender, collateral, debt, n1, n2, liquidation_discount)
log Borrow(msg.sender, collateral, debt)
@payable
@external
@nonreentrant('lock')
def create_loan(collateral: uint256, debt: uint256, N: uint256):
"""
@notice Create loan
@param collateral Amount of collateral to use
@param debt Stablecoin debt to take
@param N Number of bands to deposit into (to do autoliquidation-deliquidation),
can be from MIN_TICKS to MAX_TICKS
"""
self._create_loan(msg.value, collateral, debt, N, True)
@payable
@external
@nonreentrant('lock')
def create_loan_extended(collateral: uint256, debt: uint256, N: uint256, callbacker: address, callback_args: DynArray[uint256,5]):
"""
@notice Create loan but pass stablecoin to a callback first so that it can build leverage
@param collateral Amount of collateral to use
@param debt Stablecoin debt to take
@param N Number of bands to deposit into (to do autoliquidation-deliquidation),
can be from MIN_TICKS to MAX_TICKS
@param callbacker Address of the callback contract
@param callback_args Extra arguments for the callback (up to 5) such as min_amount etc
"""
# Before callback
STABLECOIN.transfer(callbacker, debt)
# Callback
# If there is any unused debt, callbacker can send it to the user
more_collateral: uint256 = self.execute_callback(
callbacker, CALLBACK_DEPOSIT, msg.sender, 0, collateral, debt, callback_args).collateral
# After callback
self._deposit_collateral(collateral, msg.value)
assert COLLATERAL_TOKEN.transferFrom(callbacker, AMM.address, more_collateral, default_return_value=True)
self._create_loan(0, collateral + more_collateral, debt, N, False)
@internal
def _add_collateral_borrow(d_collateral: uint256, d_debt: uint256, _for: address, remove_collateral: bool):
"""
@notice Internal method to borrow and add or remove collateral
@param d_collateral Amount of collateral to add
@param d_debt Amount of debt increase
@param _for Address to transfer tokens to
@param remove_collateral Remove collateral instead of adding
"""
debt: uint256 = 0
rate_mul: uint256 = 0
debt, rate_mul = self._debt(_for)
assert debt > 0, "Loan doesn't exist"
debt += d_debt
ns: int256[2] = AMM.read_user_tick_numbers(_for)
size: uint256 = convert(unsafe_add(unsafe_sub(ns[1], ns[0]), 1), uint256)
xy: uint256[2] = AMM.withdraw(_for, 10**18)
assert xy[0] == 0, "Already in underwater mode"
if remove_collateral:
xy[1] -= d_collateral
else:
xy[1] += d_collateral
n1: int256 = self._calculate_debt_n1(xy[1], debt, size)
n2: int256 = n1 + unsafe_sub(ns[1], ns[0])
AMM.deposit_range(_for, xy[1], n1, n2)
self.loan[_for] = Loan({initial_debt: debt, rate_mul: rate_mul})
liquidation_discount: uint256 = self.liquidation_discount
self.liquidation_discounts[_for] = liquidation_discount
if d_debt != 0:
total_debt: uint256 = self._total_debt.initial_debt * rate_mul / self._total_debt.rate_mul + d_debt
self._total_debt.initial_debt = total_debt
self._total_debt.rate_mul = rate_mul
if remove_collateral:
log RemoveCollateral(_for, d_collateral)
else:
log Borrow(_for, d_collateral, d_debt)
log UserState(_for, xy[1], debt, n1, n2, liquidation_discount)
@payable
@external
@nonreentrant('lock')
def add_collateral(collateral: uint256, _for: address = msg.sender):
"""
@notice Add extra collateral to avoid bad liqidations
@param collateral Amount of collateral to add
@param _for Address to add collateral for
"""
if collateral == 0:
return
self._add_collateral_borrow(collateral, 0, _for, False)
self._deposit_collateral(collateral, msg.value)
@external
@nonreentrant('lock')
def remove_collateral(collateral: uint256, use_eth: bool = True):
"""
@notice Remove some collateral without repaying the debt
@param collateral Amount of collateral to remove
@param use_eth Use wrapping/unwrapping if collateral is ETH
"""
if collateral == 0:
return
self._add_collateral_borrow(collateral, 0, msg.sender, True)
self._withdraw_collateral(msg.sender, collateral, use_eth)
@payable
@external
@nonreentrant('lock')
def borrow_more(collateral: uint256, debt: uint256):
"""
@notice Borrow more stablecoins while adding more collateral (not necessary)
@param collateral Amount of collateral to add
@param debt Amount of stablecoin debt to take
"""
if debt == 0:
return
self._add_collateral_borrow(collateral, debt, msg.sender, False)
if collateral != 0:
self._deposit_collateral(collateral, msg.value)
STABLECOIN.transfer(msg.sender, debt)
self.minted += debt
@internal
def _remove_from_list(_for: address):
last_loan_ix: uint256 = self.n_loans - 1
loan_ix: uint256 = self.loan_ix[_for]
assert self.loans[loan_ix] == _for # dev: should never fail but safety first
self.loan_ix[_for] = 0
if loan_ix < last_loan_ix: # Need to replace
last_loan: address = self.loans[last_loan_ix]
self.loans[loan_ix] = last_loan
self.loan_ix[last_loan] = loan_ix
self.n_loans = last_loan_ix
@external
@nonreentrant('lock')
def repay(_d_debt: uint256, _for: address = msg.sender, max_active_band: int256 = 2**255-1, use_eth: bool = True):
"""
@notice Repay debt (partially or fully)
@param _d_debt The amount of debt to repay. If higher than the current debt - will do full repayment
@param _for The user to repay the debt for
@param max_active_band Don't allow active band to be higher than this (to prevent front-running the repay)
@param use_eth Use wrapping/unwrapping if collateral is ETH
"""
if _d_debt == 0:
return
# Or repay all for MAX_UINT256
# Withdraw if debt become 0
debt: uint256 = 0
rate_mul: uint256 = 0
debt, rate_mul = self._debt(_for)
assert debt > 0, "Loan doesn't exist"
d_debt: uint256 = min(debt, _d_debt)
debt = unsafe_sub(debt, d_debt)
if debt == 0:
# Allow to withdraw all assets even when underwater
xy: uint256[2] = AMM.withdraw(_for, 10**18)
if xy[0] > 0:
# Only allow full repayment when underwater for the sender to do
assert _for == msg.sender
STABLECOIN.transferFrom(AMM.address, _for, xy[0])
if xy[1] > 0:
self._withdraw_collateral(_for, xy[1], use_eth)
log UserState(_for, 0, 0, 0, 0, 0)
log Repay(_for, xy[1], d_debt)
self._remove_from_list(_for)
else:
active_band: int256 = AMM.active_band_with_skip()
assert active_band <= max_active_band
ns: int256[2] = AMM.read_user_tick_numbers(_for)
size: uint256 = convert(unsafe_add(unsafe_sub(ns[1], ns[0]), 1), uint256)
liquidation_discount: uint256 = 0
if ns[0] > active_band:
# Not in liquidation - can move bands
xy: uint256[2] = AMM.withdraw(_for, 10**18)
n1: int256 = self._calculate_debt_n1(xy[1], debt, size)
n2: int256 = n1 + unsafe_sub(ns[1], ns[0])
AMM.deposit_range(_for, xy[1], n1, n2)
liquidation_discount = self.liquidation_discount
self.liquidation_discounts[_for] = liquidation_discount
log UserState(_for, xy[1], debt, n1, n2, liquidation_discount)
log Repay(_for, 0, d_debt)
else:
# Underwater - cannot move band but can avoid a bad liquidation
liquidation_discount = self.liquidation_discounts[_for]
log UserState(_for, max_value(uint256), debt, ns[0], ns[1], liquidation_discount)
log Repay(_for, 0, d_debt)
if _for != msg.sender:
# Doesn't allow non-sender to repay in a way which ends with unhealthy state
# full = False to make this condition non-manipulatable (and also cheaper on gas)
assert self._health(_for, debt, False, liquidation_discount) > 0
# If we withdrew already - will burn less!
STABLECOIN.transferFrom(msg.sender, self, d_debt) # fail: insufficient funds
self.redeemed += d_debt
self.loan[_for] = Loan({initial_debt: debt, rate_mul: rate_mul})
total_debt: uint256 = self._total_debt.initial_debt * rate_mul / self._total_debt.rate_mul
self._total_debt.initial_debt = unsafe_sub(max(total_debt, d_debt), d_debt)
self._total_debt.rate_mul = rate_mul
@external
@nonreentrant('lock')
def repay_extended(callbacker: address, callback_args: DynArray[uint256,5]):
"""
@notice Repay loan but get a stablecoin for that from callback (to deleverage)
@param callbacker Address of the callback contract
@param callback_args Extra arguments for the callback (up to 5) such as min_amount etc
"""
# Before callback
ns: int256[2] = AMM.read_user_tick_numbers(msg.sender)
xy: uint256[2] = AMM.withdraw(msg.sender, 10**18)
debt: uint256 = 0
rate_mul: uint256 = 0
debt, rate_mul = self._debt(msg.sender)
COLLATERAL_TOKEN.transferFrom(AMM.address, callbacker, xy[1], default_return_value=True)
cb: CallbackData = self.execute_callback(
callbacker, CALLBACK_REPAY, msg.sender, xy[0], xy[1], debt, callback_args)
# After callback
total_stablecoins: uint256 = cb.stablecoins + xy[0]
assert total_stablecoins > 0 # dev: no coins to repay
# d_debt: uint256 = min(debt, total_stablecoins)
d_debt: uint256 = 0
# If we have more stablecoins than the debt - full repayment and closing the position
if total_stablecoins >= debt:
d_debt = debt
debt = 0
self._remove_from_list(msg.sender)
# Transfer debt to self, everything else to sender
if cb.stablecoins > 0:
STABLECOIN.transferFrom(callbacker, self, cb.stablecoins)
if xy[0] > 0:
STABLECOIN.transferFrom(AMM.address, self, xy[0])
if total_stablecoins > d_debt:
STABLECOIN.transfer(msg.sender, unsafe_sub(total_stablecoins, d_debt))
if cb.collateral > 0:
assert COLLATERAL_TOKEN.transferFrom(callbacker, msg.sender, cb.collateral, default_return_value=True)
log UserState(msg.sender, 0, 0, 0, 0, 0)
# Else - partial repayment -> deleverage, but only if we are not underwater
else:
size: uint256 = convert(unsafe_add(unsafe_sub(ns[1], ns[0]), 1), uint256)
assert ns[0] > cb.active_band
d_debt = cb.stablecoins # cb.stablecoins <= total_stablecoins < debt
debt = unsafe_sub(debt, cb.stablecoins)
# Not in liquidation - can move bands
n1: int256 = self._calculate_debt_n1(cb.collateral, debt, size)
n2: int256 = n1 + unsafe_sub(ns[1], ns[0])
AMM.deposit_range(msg.sender, cb.collateral, n1, n2)
liquidation_discount: uint256 = self.liquidation_discount
self.liquidation_discounts[msg.sender] = liquidation_discount
assert COLLATERAL_TOKEN.transferFrom(callbacker, AMM.address, cb.collateral, default_return_value=True)
# Stablecoin is all spent to repay debt -> all goes to self
STABLECOIN.transferFrom(callbacker, self, cb.stablecoins)
# We are above active band, so xy[0] is 0 anyway
log UserState(msg.sender, cb.collateral, debt, n1, n2, liquidation_discount)
xy[1] -= cb.collateral
# No need to check _health() because it's the sender
# Common calls which we will do regardless of whether it's a full repay or not
log Repay(msg.sender, xy[1], d_debt)
self.redeemed += d_debt
self.loan[msg.sender] = Loan({initial_debt: debt, rate_mul: rate_mul})
total_debt: uint256 = self._total_debt.initial_debt * rate_mul / self._total_debt.rate_mul
self._total_debt.initial_debt = unsafe_sub(max(total_debt, d_debt), d_debt)
self._total_debt.rate_mul = rate_mul
@internal
@view
def _health(user: address, debt: uint256, full: bool, liquidation_discount: uint256) -> int256:
"""
@notice Returns position health normalized to 1e18 for the user.
Liquidation starts when < 0, however devaluation of collateral doesn't cause liquidation
@param user User address to calculate health for
@param debt The amount of debt to calculate health for
@param full Whether to take into account the price difference above the highest user's band
@param liquidation_discount Liquidation discount to use (can be 0)
@return Health: > 0 = good.
"""
assert debt > 0, "Loan doesn't exist"
health: int256 = 10**18 - convert(liquidation_discount, int256)
health = unsafe_div(convert(AMM.get_x_down(user), int256) * health, convert(debt, int256)) - 10**18
if full:
ns0: int256 = AMM.read_user_tick_numbers(user)[0] # ns[1] > ns[0]
if ns0 > AMM.active_band(): # We are not in liquidation mode
p: uint256 = AMM.price_oracle()
p_up: uint256 = AMM.p_oracle_up(ns0)
if p > p_up:
health += convert(unsafe_div(unsafe_sub(p, p_up) * AMM.get_sum_xy(user)[1] * COLLATERAL_PRECISION, debt), int256)
return health
@external
@view
@nonreentrant('lock')
def health_calculator(user: address, d_collateral: int256, d_debt: int256, full: bool, N: uint256 = 0) -> int256:
"""
@notice Health predictor in case user changes the debt or collateral
@param user Address of the user
@param d_collateral Change in collateral amount (signed)
@param d_debt Change in debt amount (signed)
@param full Whether it's a 'full' health or not
@param N Number of bands in case loan doesn't yet exist
@return Signed health value
"""
ns: int256[2] = AMM.read_user_tick_numbers(user)
debt: int256 = convert(self._debt_ro(user), int256)
n: uint256 = N
ld: int256 = 0
if debt != 0:
ld = convert(self.liquidation_discounts[user], int256)
n = convert(unsafe_add(unsafe_sub(ns[1], ns[0]), 1), uint256)
else:
ld = convert(self.liquidation_discount, int256)
ns[0] = max_value(int256) # This will trigger a "re-deposit"
n1: int256 = 0
collateral: int256 = 0
x_eff: int256 = 0
debt += d_debt
assert debt > 0, "Non-positive debt"
active_band: int256 = AMM.active_band_with_skip()
if ns[0] > active_band and (d_collateral != 0 or d_debt != 0): # re-deposit
collateral = convert(AMM.get_sum_xy(user)[1] * COLLATERAL_PRECISION, int256) + d_collateral
n1 = self._calculate_debt_n1(convert(collateral, uint256), convert(debt, uint256), n)
else:
n1 = ns[0]
x_eff = convert(AMM.get_x_down(user) * 10**18, int256)
p0: int256 = convert(AMM.p_oracle_up(n1), int256)
if ns[0] > active_band:
x_eff = convert(self.get_y_effective(convert(collateral, uint256), n, 0), int256) * p0
health: int256 = unsafe_div(x_eff, debt)
health = health - unsafe_div(health * ld, 10**18) - 10**18
if full:
if n1 > active_band: # We are not in liquidation mode
p_diff: int256 = max(p0, convert(AMM.price_oracle(), int256)) - p0
if p_diff > 0:
health += unsafe_div(p_diff * collateral, debt)
return health
@internal
@view
def _get_f_remove(frac: uint256, health_limit: uint256) -> uint256:
# f_remove = ((1 + h / 2) / (1 + h) * (1 - frac) + frac) * frac
f_remove: uint256 = 10 ** 18
if frac < 10 ** 18:
f_remove = unsafe_div(unsafe_mul(unsafe_add(10 ** 18, unsafe_div(health_limit, 2)), unsafe_sub(10 ** 18, frac)), unsafe_add(10 ** 18, health_limit))
f_remove = unsafe_div(unsafe_mul(unsafe_add(f_remove, frac), frac), 10 ** 18)
return f_remove
@internal
def _liquidate(user: address, min_x: uint256, health_limit: uint256, frac: uint256, use_eth: bool,
callbacker: address, callback_args: DynArray[uint256,5]):
"""
@notice Perform a bad liquidation of user if the health is too bad
@param user Address of the user
@param min_x Minimal amount of stablecoin withdrawn (to avoid liquidators being sandwiched)
@param health_limit Minimal health to liquidate at
@param frac Fraction to liquidate; 100% = 10**18
@param use_eth Use wrapping/unwrapping if collateral is ETH
@param callbacker Address of the callback contract
@param callback_args Extra arguments for the callback (up to 5) such as min_amount etc
"""
debt: uint256 = 0
rate_mul: uint256 = 0
debt, rate_mul = self._debt(user)
if health_limit != 0:
assert self._health(user, debt, True, health_limit) < 0, "Not enough rekt"
final_debt: uint256 = debt
debt = unsafe_div(debt * frac, 10**18)
assert debt > 0
final_debt = unsafe_sub(final_debt, debt)
# Withdraw sender's stablecoin and collateral to our contract
# When frac is set - we withdraw a bit less for the same debt fraction
# f_remove = ((1 + h/2) / (1 + h) * (1 - frac) + frac) * frac
# where h is health limit.
# This is less than full h discount but more than no discount
xy: uint256[2] = AMM.withdraw(user, self._get_f_remove(frac, health_limit)) # [stable, collateral]
# x increase in same block -> price up -> good
# x decrease in same block -> price down -> bad
assert xy[0] >= min_x, "Slippage"
min_amm_burn: uint256 = min(xy[0], debt)
if min_amm_burn != 0:
STABLECOIN.transferFrom(AMM.address, self, min_amm_burn)
if debt > xy[0]:
to_repay: uint256 = unsafe_sub(debt, xy[0])
if callbacker == empty(address):
# Withdraw collateral if no callback is present
self._withdraw_collateral(msg.sender, xy[1], use_eth)
# Request what's left from user
STABLECOIN.transferFrom(msg.sender, self, to_repay)
else:
# Move collateral to callbacker, call it and remove everything from it back in
if xy[1] > 0:
assert COLLATERAL_TOKEN.transferFrom(AMM.address, callbacker, xy[1], default_return_value=True)
# Callback
cb: CallbackData = self.execute_callback(
callbacker, CALLBACK_LIQUIDATE, user, xy[0], xy[1], debt, callback_args)
assert cb.stablecoins >= to_repay, "not enough proceeds"
if cb.stablecoins > to_repay:
STABLECOIN.transferFrom(callbacker, msg.sender, unsafe_sub(cb.stablecoins, to_repay))
STABLECOIN.transferFrom(callbacker, self, to_repay)
if cb.collateral > 0:
assert COLLATERAL_TOKEN.transferFrom(callbacker, msg.sender, cb.collateral)
else:
# Withdraw collateral
self._withdraw_collateral(msg.sender, xy[1], use_eth)
# Return what's left to user
if xy[0] > debt:
STABLECOIN.transferFrom(AMM.address, msg.sender, unsafe_sub(xy[0], debt))
self.redeemed += debt
self.loan[user] = Loan({initial_debt: final_debt, rate_mul: rate_mul})
log Repay(user, xy[1], debt)
log Liquidate(msg.sender, user, xy[1], xy[0], debt)
if final_debt == 0:
log UserState(user, 0, 0, 0, 0, 0) # Not logging partial removeal b/c we have not enough info
self._remove_from_list(user)
d: uint256 = self._total_debt.initial_debt * rate_mul / self._total_debt.rate_mul
self._total_debt.initial_debt = unsafe_sub(max(d, debt), debt)
self._total_debt.rate_mul = rate_mul
@external
@nonreentrant('lock')
def liquidate(user: address, min_x: uint256, use_eth: bool = True):
"""
@notice Peform a bad liquidation (or self-liquidation) of user if health is not good
@param min_x Minimal amount of stablecoin to receive (to avoid liquidators being sandwiched)
@param use_eth Use wrapping/unwrapping if collateral is ETH
"""
discount: uint256 = 0
if user != msg.sender:
discount = self.liquidation_discounts[user]
self._liquidate(user, min_x, discount, 10**18, use_eth, empty(address), [])
@external
@nonreentrant('lock')
def liquidate_extended(user: address, min_x: uint256, frac: uint256, use_eth: bool,
callbacker: address, callback_args: DynArray[uint256,5]):
"""
@notice Peform a bad liquidation (or self-liquidation) of user if health is not good
@param min_x Minimal amount of stablecoin to receive (to avoid liquidators being sandwiched)
@param frac Fraction to liquidate; 100% = 10**18
@param use_eth Use wrapping/unwrapping if collateral is ETH
@param callbacker Address of the callback contract
@param callback_args Extra arguments for the callback (up to 5) such as min_amount etc
"""
discount: uint256 = 0
if user != msg.sender:
discount = self.liquidation_discounts[user]
self._liquidate(user, min_x, discount, min(frac, 10**18), use_eth, callbacker, callback_args)
@view
@external
@nonreentrant('lock')
def tokens_to_liquidate(user: address, frac: uint256 = 10 ** 18) -> uint256:
"""
@notice Calculate the amount of stablecoins to have in liquidator's wallet to liquidate a user
@param user Address of the user to liquidate
@param frac Fraction to liquidate; 100% = 10**18
@return The amount of stablecoins needed
"""
health_limit: uint256 = 0
if user != msg.sender:
health_limit = self.liquidation_discounts[user]
stablecoins: uint256 = unsafe_div(AMM.get_sum_xy(user)[0] * self._get_f_remove(frac, health_limit), 10 ** 18)
debt: uint256 = unsafe_div(self._debt_ro(user) * frac, 10 ** 18)
return unsafe_sub(max(debt, stablecoins), stablecoins)
@view
@external
@nonreentrant('lock')
def health(user: address, full: bool = False) -> int256:
"""
@notice Returns position health normalized to 1e18 for the user.
Liquidation starts when < 0, however devaluation of collateral doesn't cause liquidation
"""
return self._health(user, self._debt_ro(user), full, self.liquidation_discounts[user])
@view
@external
@nonreentrant('lock')
def users_to_liquidate(_from: uint256=0, _limit: uint256=0) -> DynArray[Position, 1000]:
"""
@notice Returns a dynamic array of users who can be "hard-liquidated".
This method is designed for convenience of liquidation bots.
@param _from Loan index to start iteration from
@param _limit Number of loans to look over
@return Dynamic array with detailed info about positions of users
"""
n_loans: uint256 = self.n_loans
limit: uint256 = _limit
if _limit == 0:
limit = n_loans
ix: uint256 = _from
out: DynArray[Position, 1000] = []
for i in range(10**6):
if ix >= n_loans or i == limit:
break
user: address = self.loans[ix]
debt: uint256 = self._debt_ro(user)
health: int256 = self._health(user, debt, True, self.liquidation_discounts[user])
if health < 0:
xy: uint256[2] = AMM.get_sum_xy(user)
out.append(Position({
user: user,
x: xy[0],
y: xy[1],
debt: debt,
health: health
}))
ix += 1
return out
# AMM has a nonreentrant decorator
@view
@external
def amm_price() -> uint256:
"""
@notice Current price from the AMM
"""
return AMM.get_p()
@view
@external
@nonreentrant('lock')
def user_prices(user: address) -> uint256[2]: # Upper, lower
"""
@notice Lowest price of the lower band and highest price of the upper band the user has deposit in the AMM
@param user User address
@return (upper_price, lower_price)
"""
assert AMM.has_liquidity(user)
ns: int256[2] = AMM.read_user_tick_numbers(user) # ns[1] > ns[0]
return [AMM.p_oracle_up(ns[0]), AMM.p_oracle_down(ns[1])]
@view
@external
@nonreentrant('lock')
def user_state(user: address) -> uint256[4]:
"""
@notice Return the user state in one call
@param user User to return the state for
@return (collateral, stablecoin, debt, N)
"""
xy: uint256[2] = AMM.get_sum_xy(user)
ns: int256[2] = AMM.read_user_tick_numbers(user) # ns[1] > ns[0]
return [xy[1], xy[0], self._debt_ro(user), convert(unsafe_add(unsafe_sub(ns[1], ns[0]), 1), uint256)]
# AMM has nonreentrant decorator
@external
def set_amm_fee(fee: uint256):
"""
@notice Set the AMM fee (factory admin only)
@param fee The fee which should be no higher than MAX_FEE
"""
assert msg.sender == FACTORY.admin()
assert fee <= MAX_FEE and fee >= MIN_FEE, "Fee"
AMM.set_fee(fee)
# AMM has nonreentrant decorator
@external
def set_amm_admin_fee(fee: uint256):
"""
@notice Set AMM's admin fee
@param fee New admin fee (not higher than MAX_ADMIN_FEE)
"""
assert msg.sender == FACTORY.admin()
assert fee <= MAX_ADMIN_FEE, "High fee"
AMM.set_admin_fee(fee)
@nonreentrant('lock')
@external
def set_monetary_policy(monetary_policy: address):
"""
@notice Set monetary policy contract
@param monetary_policy Address of the monetary policy contract
"""
assert msg.sender == FACTORY.admin()
self.monetary_policy = MonetaryPolicy(monetary_policy)
MonetaryPolicy(monetary_policy).rate_write()
log SetMonetaryPolicy(monetary_policy)
@nonreentrant('lock')
@external
def set_borrowing_discounts(loan_discount: uint256, liquidation_discount: uint256):
"""
@notice Set discounts at which we can borrow (defines max LTV) and where bad liquidation starts
@param loan_discount Discount which defines LTV
@param liquidation_discount Discount where bad liquidation starts
"""
assert msg.sender == FACTORY.admin()
assert loan_discount > liquidation_discount
assert liquidation_discount >= MIN_LIQUIDATION_DISCOUNT
assert loan_discount <= MAX_LOAN_DISCOUNT
self.liquidation_discount = liquidation_discount
self.loan_discount = loan_discount
log SetBorrowingDiscounts(loan_discount, liquidation_discount)
@external
@nonreentrant('lock')
def set_callback(cb: address):
"""
@notice Set liquidity mining callback
"""
assert msg.sender == FACTORY.admin()
AMM.set_callback(cb)
@external
@view
def admin_fees() -> uint256:
"""
@notice Calculate the amount of fees obtained from the interest
"""
rate_mul: uint256 = AMM.get_rate_mul()
loan: Loan = self._total_debt
loan.initial_debt = loan.initial_debt * rate_mul / loan.rate_mul
loan.initial_debt += self.redeemed
minted: uint256 = self.minted
return unsafe_sub(max(loan.initial_debt, minted), minted)
@external
@nonreentrant('lock')
def collect_fees() -> uint256:
"""
@notice Collect the fees charged as interest
"""
_to: address = FACTORY.fee_receiver()
# AMM-based fees
borrowed_fees: uint256 = AMM.admin_fees_x()
collateral_fees: uint256 = AMM.admin_fees_y()
if borrowed_fees > 0:
STABLECOIN.transferFrom(AMM.address, _to, borrowed_fees)
if collateral_fees > 0:
assert COLLATERAL_TOKEN.transferFrom(AMM.address, _to, collateral_fees, default_return_value=True)
AMM.reset_admin_fees()
# Borrowing-based fees
rate_mul: uint256 = self._rate_mul_w()
loan: Loan = self._total_debt
loan.initial_debt = loan.initial_debt * rate_mul / loan.rate_mul
loan.rate_mul = rate_mul
self._total_debt = loan
# Amount which would have been redeemed if all the debt was repaid now
to_be_redeemed: uint256 = loan.initial_debt + self.redeemed
# Amount which was minted when borrowing + all previously claimed admin fees
minted: uint256 = self.minted
# Difference between to_be_redeemed and minted amount is exactly due to interest charged
if to_be_redeemed > minted:
self.minted = to_be_redeemed
to_be_redeemed = unsafe_sub(to_be_redeemed, minted) # Now this is the fees to charge
STABLECOIN.transfer(_to, to_be_redeemed)
log CollectFees(to_be_redeemed, loan.initial_debt)
return to_be_redeemed
else:
log CollectFees(0, loan.initial_debt)
return 0
Read Contract
admin_fees 0x1b1800e3 → uint256
amm 0x2a943945 → address
amm_price 0xd9f11a64 → uint256
calculate_debt_n1 0x720fb254 → int256
collateral_token 0x2621db2f → address
debt 0x9b6c56ec → uint256
factory 0xc45a0155 → address
health 0xe2d8ebee → int256
health 0x8908ea82 → int256
health_calculator 0x0b8db681 → int256
health_calculator 0x22c71453 → int256
liquidation_discount 0x627d2b83 → uint256
liquidation_discounts 0x5457ff7b → uint256
loan_discount 0x5449b9cb → uint256
loan_exists 0xa21adb9e → bool
loan_ix 0x7128f3b8 → uint256
loans 0xe1ec3c68 → address
max_borrowable 0x9a497196 → uint256
max_borrowable 0x1cf1f947 → uint256
min_collateral 0xa7573206 → uint256
minted 0x4f02c420 → uint256
monetary_policy 0xadfae4ce → address
n_loans 0x6cce39be → uint256
redeemed 0xe231bff0 → uint256
tokens_to_liquidate 0x1b25cdaf → uint256
tokens_to_liquidate 0x546e040d → uint256
total_debt 0x31dc3ca8 → uint256
user_prices 0x2c5089c3 → uint256[2]
user_state 0xec74d0a8 → uint256[4]
users_to_liquidate 0x007c98ab → tuple[]
users_to_liquidate 0x80e8f6ec → tuple[]
users_to_liquidate 0x90f8667d → tuple[]
Write Contract 21 functions
These functions modify contract state and require a wallet transaction to execute.
add_collateral 0x6f972f12
uint256 collateral
add_collateral 0x24049e57
uint256 collateral
address _for
borrow_more 0xdd171e7c
uint256 collateral
uint256 debt
collect_fees 0x1e0cfcef
No parameters
returns: uint256
create_loan 0x23cfed03
uint256 collateral
uint256 debt
uint256 N
create_loan_extended 0xbc61ea23
uint256 collateral
uint256 debt
uint256 N
address callbacker
uint256[] callback_args
liquidate 0xbcbaf487
address user
uint256 min_x
liquidate 0x3ecdb828
address user
uint256 min_x
bool use_eth
liquidate_extended 0x036aed88
address user
uint256 min_x
uint256 frac
bool use_eth
address callbacker
uint256[] callback_args
remove_collateral 0xd14ff5b6
uint256 collateral
remove_collateral 0x2e4af52a
uint256 collateral
bool use_eth
repay 0x371fd8e6
uint256 _d_debt
repay 0xacb70815
uint256 _d_debt
address _for
repay 0xb4440df4
uint256 _d_debt
address _for
int256 max_active_band
repay 0x37671f93
uint256 _d_debt
address _for
int256 max_active_band
bool use_eth
repay_extended 0x152f65cb
address callbacker
uint256[] callback_args
set_amm_admin_fee 0xa5b4804a
uint256 fee
set_amm_fee 0x4189617d
uint256 fee
set_borrowing_discounts 0x2a0c3586
uint256 loan_discount
uint256 liquidation_discount
set_callback 0xcc1891c7
address cb
set_monetary_policy 0x81d2f1b7
address monetary_policy
Recent Transactions
No transactions found for this address