Address Contract Partially Verified
Address
0xCF346a4F898e9FdacD3a130fFe00F1f2dA56C90a
Balance
0 ETH
Nonce
1
Code Size
14815 bytes
Creator
0xa90c33E8...92D0 at tx 0xcd082458...c8f341
Indexed Transactions
0 (1 on-chain, 0.8% indexed)
Contract Bytecode
14815 bytes
0x60406080815260048036101561001f575b5050361561001d57600080fd5b005b600091823560e01c91826306f2850114612032578263077d97d714611ebe57826313f14fee14611e955782631f5a0bbe14611e2857826320118aad14611d835782632478842914611d1a5782633186a8f814611cfd5782633419ba2314611c335783836334b10a6d14611b8d575082633540302314611b18578263371fd8e614611aa3578263380ede2d14611a0e5782633c965dbb146119be57826343b8f0e41461196f57826352fd5ab81461162e5782635f9a21921461160b5783836369276319146110d357508263715018a61461106d57826379ba5097146110265782638da5cb5b14610ffe578383639169d83314610f52575082639504ad6d14610f025782639ac2a01114610ec4578263a791d6ea14610e5f578263b381cf4014610e1b578263b3ccbcfe14610df257838363b61d27f614610d7257508263b64906d414610d55578263b6703fcd14610d19578263b82ceb4514610cfc578263c3f909d414610ca1578263c4e2c1e614610c5f578263c5ebeaec14610be2578263d0d4332714610b75578263d65ba6f314610b5857838363d7d0309c14610a5e57508263d897fe3a14610a2f578263da3e339714610813578263debf5ecc1461071c578263e019cbe914610657578263e042386c146105dc578263e1b971391461055b578263e30c397814610532578263e68b7757146104ba578263ee9af25d14610429578263f28121351461036e57508163f2fde38b14610301578163f3fef3a3146102d2578163f7888aec14610299575063fa09e6301461025f5780610010565b346102965760203660031901126102965761029361027b61233c565b610283612890565b61028c816131dc565b33916131f8565b80f35b80fd5b9050346102ce57806003193601126102ce576020906102c76102b961233c565b6102c1612352565b90612824565b9051908152f35b5080fd5b9050346102ce57366003190112610296576102936102ee61233c565b6102f6612890565b3390602435906131f8565b82346102965760203660031901126102965761031b61233c565b610323612890565b600180546001600160a01b0319166001600160a01b0392831690811790915582549091167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e227008380a380f35b9150346104255782600319360112610425578281805161038d816121d8565b82815260208101839052015260035481516330fe427560e21b81526001600160a01b039390916060918391829087165afa90811561041b57908291606095916103ee575b508151938082511685526020820151166020850152015190820152f35b61040e9150853d8711610414575b610406818361220e565b8101906123d7565b386103d1565b503d6103fc565b82513d86823e3d90fd5b8280fd5b8382346102ce57816003193601126102ce57600354815163ee9af25d60e01b81529360209185919082906001600160a01b03165afa9182156104af5791610475575b6020925051908152f35b90506020823d6020116104a7575b816104906020938361220e565b810103126104a257602091519061046b565b600080fd5b3d9150610483565b9051903d90823e3d90fd5b915034610425576020366003190112610425576001600160a01b038235818116929083900361052e577fbb8ae84f77396c61f3771bf6ff158e748b500aa24f69c0ab9cf6730c5a7312739061050d612890565b84549281519084168152846020820152a16001600160a01b03191617905580f35b8480fd5b8382346102ce57816003193601126102ce5760015490516001600160a01b039091168152602090f35b909150346104255760203660031901126104255761057761233c565b91610580612890565b6001600160a01b03831615610599578361029384612e45565b906020606492519162461bcd60e51b8352820152601860248201527f4954424f776e61626c653a207a65726f206164647265737300000000000000006044820152fd5b90915034610425576020366003190112610425576001600160a01b0390358181169290839003610653577ff6de81a7def6ff2d3b03e6036f52c547b9073772cfbcab0b96ef94580b6f73b690610630612890565b6003549281519084168152846020820152a16001600160a01b0319161760035580f35b8380fd5b90915034610425576060366003190112610425576044356001600160401b03811161065357916106e3610703926106b37fe8787cca738efc7ab80ec15b44031f5f90e9e089d0fc90c1bdf553a60dce5509969536908301612246565b9060018060a01b0386541633148015610707575b6106d090612368565b8584516106dc816121f3565b5235613443565b906106ef602435612e9b565b5193838594a16020835260208301906122d8565b0390f35b5033865260026020528386205460ff166106c7565b91503461042557806003193601126104255761073661233c565b8354602435926001600160a01b03918691908316331480156107fe575b61075c90612368565b60ff60065416806107d1575b61077f575b50508061029394541690309216612dd9565b8286541690813b15610425578280926024835180958193639169d83360e01b83528b8d8401525af19081156107c857501561076d576107bd906121c5565b61052e57843861076d565b513d84823e3d90fd5b50827f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc21683851614610768565b5033825260026020528082205460ff16610753565b909150346104255760603660031901126104255761082f61233c565b610837612352565b9260443592610844612890565b8484156109865750815163095ea7b360e01b60208083018281526001600160a01b03898116602486015260448086018a905285529394878516949092909160009061089060648961220e565b87519082885af16000513d8261096a575b5050156108ec575b5050505050906108e660008051602061398a83398151915293925b516001600160a01b039586168152602081019390935293169281906040820190565b0390a280f35b855192602084015288166024830152600060448301526044825260808201908282106001600160401b03831117610955575092849261094561094a936108e69660008051602061398a8339815191529a99985282613769565b613769565b9192933880806108a9565b604190634e487b7160e01b6000525260246000fd5b90915061097e5750833b15155b38806108a1565b600114610977565b825163095ea7b360e01b81526001600160a01b03909116918101918252602082810186905292949392909182908190604001038160006001600160a01b0387165af18015610a24576109ec575b506108e660008051602061398a833981519152936108c4565b6020813d602011610a1c575b81610a056020938361220e565b810103126104a25751801515036104a257386109d3565b3d91506109f8565b84513d6000823e3d90fd5b50823461029657806003193601126102965750610a4a612505565b610a526126d0565b82519182526020820152f35b92509034610b545780600319360112610b5457610a7961233c565b835460243593916001600160a01b0391829190821633148015610b3f575b610aa090612368565b16610aaf858385541683612f9b565b60ff600654169081610b13575b50610ac5578480f35b81541692833b1561052e576024859283855196879485936334b10a6d60e01b85528401525af19081156107c85750610aff575b8080808480f35b610b08906121c5565b610296578038610af8565b9050817f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2161438610abc565b5033875260026020528487205460ff16610a97565b5050fd5b8382346102ce57816003193601126102ce576020906102c761277b565b8382346102ce57610bba61070392610b8c366122a6565b9160018060a01b0381541633148015610bcd575b610ba990612368565b8451610bb4816121f3565b52613443565b90519182916020835260208301906122d8565b5033815260026020528481205460ff16610ba0565b909150346104255760203660031901126104255782547fb848ae6b1253b6cb77e81464128ce8bd94d3d524fea54e801e0da869784dca339260209235916001600160a01b031633148015610c4b575b610c3a90612368565b610c4382613351565b51908152a180f35b50338552600283528085205460ff16610c31565b833461029657606036600319011261029657610c7961233c565b6044356001600160a01b03811681036104a25761029391610c98612890565b602435906131f8565b50823461029657806003193601126102965760208251610cc081612194565b82815201528051610cd081612194565b600554815260ff6006541615156020820152610cfa82518092602080918051845201511515910152565bf35b8382346102ce57816003193601126102ce576020906102c76126d0565b8382346102ce5736600319011261029657610293610d3561233c565b610d3d612352565b90610d46612890565b610d4f816131dc565b906131f8565b8382346102ce57816003193601126102ce576020906102c76125f5565b91925060603660031901126102ce57610d8961233c565b604435936001600160401b039283861161052e573660238701121561052e578501359283116106535736602484870101116106535761029394838594602493610dd0612890565b5193849301833781018481520391602435905af1610dec61243c565b9061247b565b8382346102ce57816003193601126102ce5760035490516001600160a01b039091168152602090f35b8382346102ce57816003193601126102ce57517f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b03168152602090f35b8382346102ce57806003193601126102ce5761029390610e7d61233c565b83546001600160a01b0392610e9e9184163314908115610eae575b50612368565b6024359180600354169116612f9b565b60ff915033875260026020528620541686610e98565b8382346102ce5760203660031901126102ce5760209160ff9082906001600160a01b03610eef61233c565b1681526002855220541690519015158152f35b9091503461042557602036600319011261042557610f366102939260018060a01b038554163314908115610f3c5750612368565b35612e9b565b60ff915033865260026020528520541638610e98565b92509034610b54576020366003190112610b545782546001600160a01b0390811633148015610fe9575b610f8590612368565b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc216803b15610fe4578390825193848092630d0e30db60e41b82528235905af19081156107c85750610fd45750f35b610fdd906121c5565b6102965780f35b505050fd5b5033845260026020528184205460ff16610f7c565b8382346102ce57816003193601126102ce57905490516001600160a01b039091168152602090f35b915034610425578260031936011261042557600154336001600160a01b0390911603611056578261029333612e45565b60249250519063118cdaa760e01b82523390820152fd5b8334610296578060031936011261029657611086612890565b600180546001600160a01b0319908116909155600080549182168155906001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a380f35b92509034610b545760209182600319360112610fe45780356001600160401b03811161052e576111069036908301612246565b908461116960018060a01b039384835416331480156115f7575b61112990612368565b828651611135816121f3565b52848454169086519889809481936207a9a360ea1b8352670de0b6b3a7640000898401528a602484015260448301906122d8565b03925af19485156115ed5786956115c9575b50600380548451636c9c2faf60e01b808252929391851687828481845afa9182156115bf578a92611590575b50865163ee9af25d60e01b815288818581855afa9081156115195784929189918d9161155a575b5090606093947f5640f49f00c8bd81403744e20c54a689d610cce204d6f415546a4e7a73f715e79282519182528c820152a187516330fe427560e21b815293849182905afa918215611403578992611539575b5061122a61363c565b868201926112658a8786511661125b8b8b61124484613588565b94338d82541614928315611523575b505050612368565b8888541690612f9b565b8960c087875416848a5180948193632bc5c95360e11b83525af18015611519578b8c916114db575b61129792506124e2565b908686541690885190815289818581855afa9081156114d1578c916114a4575b5082101561142b5750899086865416803b1561042557828091858b5180948193633e8eb9b760e21b83525af180156114215790839161140d575b50508686541692833b1561042557602490838a519586948593639504ad6d60e01b85528401525af18015611403576113eb575b5091849391611368610703979899945b8481511685611347818754168093612824565b9251169033878954161480156113d7575b61136190612368565b3091612dd9565b61137a83808351169354168093612824565b9384611396575b505050505050519282849384528301906122d8565b6113b79584611361935116943390835416149182156113c2575b5050612368565b803880808080611381565b60ff925033815260028b5220541686386113b0565b5033885260028c528888205460ff16611358565b6113f589916121c5565b6113ff5738611324565b8780fd5b86513d8b823e3d90fd5b611416906121c5565b6102ce5781386112f1565b89513d85823e3d90fd5b88999a969594989150869288518094819363254b344d60e11b83525af1801561149a57908891611469575b5050906107039561136886959493611334565b8195949392953d8311611493575b611481818361220e565b810103126104a2579091928638611456565b503d611477565b86513d87823e3d90fd5b90508981813d83116114ca575b6114bb818361220e565b810103126104a25751386112b7565b503d6114b1565b89513d8e823e3d90fd5b505060c0813d60c011611511575b816114f660c0938361220e565b8101031261150d578051908901516112979161128d565b8a80fd5b3d91506114e9565b88513d8d823e3d90fd5b60ff9350600290338352522054168b8f8e611253565b61155391925060603d60601161041457610406818361220e565b9038611221565b935050508882813d8311611589575b611573818361220e565b810103126104a2579051839190889060606111ce565b503d611569565b9091508781813d83116115b8575b6115a8818361220e565b810103126104a2575190386111a7565b503d61159e565b87513d8c823e3d90fd5b6115e69195503d8088833e6115de818361220e565b8101906135c3565b933861117b565b83513d88823e3d90fd5b50338352600287528583205460ff16611120565b508234610296578060031936011261029657506116266125f5565b610a5261277b565b91503461042557606036600319011261042557813591602491816024359360018060a01b03808854163314801561195a575b61166990612368565b878451611675816121f3565b528661194c575b8561193e575b606081600354168551948580926330fe427560e21b82525afa928315611934578893611913575b508060208094015116966116bb6137c5565b9789988a5b81518110156119045782856116d58385612e31565b5116146116e4576001016116c0565b505050909192939495965060015b156118a8576116ff6137c5565b90885b82518110156118045789846117178386612e31565b511661172e866117278588612e31565b5116613588565b9033878454161480156117f0575b61174590612368565b61175382888d541683612f9b565b60ff6006541690816117c4575b50611770575b5050600101611702565b858a541690813b15610425578290888c838d5195869485936334b10a6d60e01b85528401525af180156117ba5715611766576117ab906121c5565b6117b6578938611766565b8980fd5b89513d84823e3d90fd5b9050867f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2161438611760565b50338352600289528983205460ff1661173c565b858a8881838c60248f7f928e86394a65ffcbb1a1f7330d2968e88d0ba215f3dfc5ea62125552067657d5868b8e93825191825287820152a1825416918551948593849263735373d160e11b8452604435908401525af192831561189d579261186e575b5051908152f35b9091508281813d8311611896575b611886818361220e565b810103126104a257519083611867565b503d61187c565b8251903d90823e3d90fd5b845162461bcd60e51b8152808701859052603060248201527f436f6e6669677572656420626f72726f7720746f6b656e206d7573742062652060448201526f7573656420696e20737472617465677960801b6064820152608490fd5b505050909192939495966116f2565b61192d91935060603d60601161041457610406818361220e565b91386116a9565b84513d8a823e3d90fd5b61194786613351565b611682565b61195587612b99565b61167c565b5033885260026020528388205460ff16611660565b8382346102ce57806003193601126102ce576102939061198d61233c565b83546001600160a01b03926119ad9184163314908115610eae5750612368565b816003541660243592309216612dd9565b8382346102ce57816003193601126102ce576119f16020928260018060a01b0382541633149182156119f9575050612368565b6102c7612dbc565b60ff92503381526002865220541682856113b0565b8382346102ce57906107037fe8787cca738efc7ab80ec15b44031f5f90e9e089d0fc90c1bdf553a60dce550992611a70611a47366122a6565b9060018060a01b0386541633148015611a8e575b611a6490612368565b858451610bb4816121f3565b90611a79612dbc565b505193838594a16020835260208301906122d8565b5033865260026020528386205460ff16611a5b565b909150346104255760203660031901126104255782547fa6ffc78a660e4971a47a0f916a0abae483804e6f42c9292ed06aa64f8fe462309260209235916001600160a01b031633148015611b04575b611afb90612368565b610c4382612c6e565b50338552600283528085205460ff16611af2565b909150346104255760203660031901126104255782547f1862f918d5600ec0980589e8cc806b3c79b1e762fcbf44cc2947ba12499207eb9260209235916001600160a01b031633148015611b79575b611b7090612368565b610c4382612b99565b50338552600283528085205460ff16611b67565b925034610b54576020366003190112610b545782546001600160a01b0390811633148015611c1e575b611bbf90612368565b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc216803b15610fe4576024849284519586938492632e1a7d4d60e01b84528035908401525af19081156107c85750611c15575080f35b610293906121c5565b5033845260026020528284205460ff16611bb6565b90915034610425578160031936011261042557611c4e61233c565b91611c57612352565b611c5f612890565b815163095ea7b360e01b81526001600160a01b039182169381018490526024810186905293169260208160448188885af18015611cf357611cbb575b5060008051602061398a833981519152918151908152846020820152a280f35b6020813d602011611ceb575b81611cd46020938361220e565b8101031261052e5751801515036106535738611c9b565b3d9150611cc7565b82513d87823e3d90fd5b8382346102ce57816003193601126102ce576020906102c7612505565b8382346102ce5760203660031901126102ce57611d3561233c565b611d3d612890565b60018060a01b0316807f9fdbc2d48b8a0db2f62663bf9312ad02f5b1f6414ad600b55a247d09aeec3ea260208451868152a2825260026020528120805460ff1916905580f35b909150346104255781600319360112610425576024358015158091036106535760ff91611dae612890565b835190611dba82612194565b358152602081019182527f601bd64f1b6034521a7ad828eb0da8578cd3bbe802a4594825a03ba55b98d82b608085516005548152611e136006549787891615156020840152820185602080918051845201511515910152565ba151600555511515169060ff19161760065580f35b8382346102ce5760203660031901126102ce57611e4361233c565b611e4b612890565b60018060a01b0316807f9fdbc2d48b8a0db2f62663bf9312ad02f5b1f6414ad600b55a247d09aeec3ea26020845160018152a2825260026020528120805460ff1916600117905580f35b909150346104255782600319360112610425575490516001600160a01b03909116815260209150f35b9091506060366003190112610425576001600160401b03813581811161052e57611eeb903690840161230c565b90936024916024358481116113ff57611f07903690870161230c565b9390956044358681116117b657611f21903690830161230c565b959093611f2c612890565b81811480612029575b15611fe6578a5b818110611f47578b80f35b611f5281838d612416565b35906001600160a01b0382168203611fe257611f6f81858d612416565b3589821015611fd0578d8260051b890135601e198a3603018112156102ce578901938435948d8611610425576020019085360382136104255785611fca9484936001988f519384928337810185815203925af1610dec61243c565b01611f3c565b634e487b7160e01b8e5260328652868efd5b8c80fd5b855162461bcd60e51b8152602081850152601960248201527f417267756d656e7473206c656e677468206d69736d61746368000000000000006044820152606490fd5b50868114611f35565b9091503461042557612043366122a6565b84546001600160a01b039391869185163314801561217f575b61206590612368565b82606086600354168851958680926330fe427560e21b82525afa801561217557602087916120da968691612156575b50015116948388516120a5816121f3565b52836120b087613588565b97835416928951968795869485936207a9a360ea1b85528401528b602484015260448301906122d8565b03925af194851561214b578095612125575b505090612103612108926120fe61363c565b613588565b6124e2565b61211b82519383859485528401906122d8565b9060208301520390f35b6121089392955061210391612143913d8091833e6115de818361220e565b9491926120ec565b8451903d90823e3d90fd5b61216f915060603d60601161041457610406818361220e565b38612094565b87513d85823e3d90fd5b5033825260026020528582205460ff1661205c565b604081019081106001600160401b038211176121af57604052565b634e487b7160e01b600052604160045260246000fd5b6001600160401b0381116121af57604052565b606081019081106001600160401b038211176121af57604052565b602081019081106001600160401b038211176121af57604052565b90601f801991011681019081106001600160401b038211176121af57604052565b6001600160401b0381116121af5760051b60200190565b9080601f830112156104a25760209082356122608161222f565b9361226e604051958661220e565b81855260208086019260051b8201019283116104a257602001905b828210612297575050505090565b81358152908301908301612289565b9060406003198301126104a25760043591602435906001600160401b0382116104a2576122d591600401612246565b90565b90815180825260208080930193019160005b8281106122f8575050505090565b8351855293810193928101926001016122ea565b9181601f840112156104a2578235916001600160401b0383116104a2576020808501948460051b0101116104a257565b600435906001600160a01b03821682036104a257565b602435906001600160a01b03821682036104a257565b1561236f57565b60405162461bcd60e51b815260206004820152602660248201527f45786563757461626c653a2063616c6c6572206973206e6f742074686520657860448201526532b1baba37b960d11b6064820152608490fd5b51906001600160a01b03821682036104a257565b908160609103126104a25760408051916123f0836121d8565b6123f9816123c3565b8352612407602082016123c3565b60208401520151604082015290565b91908110156124265760051b0190565b634e487b7160e01b600052603260045260246000fd5b3d15612476573d906001600160401b0382116121af576040519161246a601f8201601f19166020018461220e565b82523d6000602084013e565b606090565b156124835750565b6040519062461bcd60e51b82528160208060048301528251908160248401526000935b8285106124c9575050604492506000838284010152601f80199101168101030190fd5b84810182015186860160440152938101938593506124a6565b919082039182116124ef57565b634e487b7160e01b600052601160045260246000fd5b60055460035460405163a5f352b760e01b81526020916001600160a01b0316908281600481855afa80156125b05784916000916125c4575b5011156125bc578161255060049461292f565b916040519485809263ee9af25d60e01b82525afa9182156125b05760009261257e575b506122d592506124e2565b90915082813d83116125a9575b612595818361220e565b810103126104a2576122d591519038612573565b503d61258b565b6040513d6000823e3d90fd5b505050600090565b809250848092503d83116125ee575b6125dd818361220e565b810103126104a2578390513861253d565b503d6125d3565b60055460035460405163a5f352b760e01b81526001600160a01b03909116906020908181600481865afa80156125b057849160009161269f575b5011156125bc5780612642600494612fd7565b9260405194858092636c9c2faf60e01b82525afa9081156125b05760009161266f57506122d592506124e2565b905082813d8311612698575b612685818361220e565b810103126104a2576122d5915138612573565b503d61267b565b809250838092503d83116126c9575b6126b8818361220e565b810103126104a2578390513861262f565b503d6126ae565b60055460035460405163a5f352b760e01b81526001600160a01b03909116906020908181600481865afa80156125b057849160009161274a575b5010156125bc578061271d60049461292f565b926040519485809263ee9af25d60e01b82525afa9081156125b05760009161266f57506122d592506124e2565b809250838092503d8311612774575b612763818361220e565b810103126104a2578390513861270a565b503d612759565b60055460035460405163a5f352b760e01b81526020916001600160a01b0316908281600481855afa80156125b05784916000916127f3575b5010156125bc57816127c6600494612fd7565b9160405194858092636c9c2faf60e01b82525afa9182156125b05760009261257e57506122d592506124e2565b809250848092503d831161281d575b61280c818361220e565b810103126104a257839051386127b3565b503d612802565b6040516370a0823160e01b81526001600160a01b0392831660048201529160209183916024918391165afa9081156125b057600091612861575090565b90506020813d602011612888575b8161287c6020938361220e565b810103126104a2575190565b3d915061286f565b6000546001600160a01b031633036128a457565b60405163118cdaa760e01b8152336004820152602490fd5b908160209103126104a2575160ff811681036104a25790565b60ff16604d81116124ef57600a0a90565b91908260409103126104a2576020825192015190565b818102929181159184041417156124ef57565b8115612919570490565b634e487b7160e01b600052601260045260246000fd5b60035460408051636c9c2faf60e01b81529093926001600160a01b03929091906004908416602080848481855afa938415612abc57600094612b6a575b508315612b5e5787516330fe427560e21b81529188906060848681845afa938415612b5357600094612b32575b50878451169782518481888163313ce56760e01b9d8e82525afa8015610a24576129cb91600091612b05575b506128d5565b9884828188015116918886518094819382525afa8015610a24576129f691600091612b0557506128d5565b94518351631ee1b90b60e21b81529116868201528381602481855afa938415612afa57600094612ac7575b5050815163bd9a548b60e01b815294859182905afa928315612abc5791612a6d93916122d59899612a78979694600091600095612a7e575b505090612a6d612a6d92612a7295966128fc565b6128fc565b946128fc565b9061290f565b612a729550612a6d939250612a6d9181612aac92903d10612ab5575b612aa4818361220e565b8101906128e6565b95509192612a59565b503d612a9a565b88513d6000823e3d90fd5b809294508193503d8311612af3575b612ae0818361220e565b810103126104a257889051913880612a21565b503d612ad6565b83513d6000823e3d90fd5b612b259150863d8811612b2b575b612b1d818361220e565b8101906128bc565b386129c5565b503d612b13565b612b4c91945060603d60601161041457610406818361220e565b9238612999565b82513d6000823e3d90fd5b50600096505050505050565b9080945081813d8311612b92575b612b82818361220e565b810103126104a25751923861296c565b503d612b78565b6003546040516330fe427560e21b81526001600160a01b03918216606082600481845afa9081156125b057838592612bf294600091612c4f575b505116846000541633148015612c36575b612bed90612368565b612f9b565b6003541690813b156104a257600091602483926040519485938492633540302360e01b845260048401525af180156125b057612c2b5750565b612c34906121c5565b565b503360009081526002602052604090205460ff16612be4565b612c68915060603d60601161041457610406818361220e565b38612bd3565b600354604080516330fe427560e21b815290916001600160a01b039190821690606081600481855afa908115610a2457600091612d9d575b50826020809201511690845163ee9af25d60e01b81528181600481875afa908115612d9257600091612d65575b50808711612d5b575b50918591612cfd9385600054163314908115612d41575b50612bed90612368565b6003541691823b156104a2576000926024849284519586938492631b8fec7360e11b845260048401525af1908115612d375750612c2b5750565b513d6000823e3d90fd5b600291503360005252612bed60ff87600020541690612cf3565b9550612cfd612cdc565b90508181813d8311612d8b575b612d7c818361220e565b810103126104a2575138612cd3565b503d612d72565b86513d6000823e3d90fd5b612db6915060603d60601161041457610406818361220e565b38612ca6565b612dc46125f5565b8015612dd3576122d581612e9b565b50600090565b6040516323b872dd60e01b60208201526001600160a01b03928316602482015292909116604483015260648083019390935291815260a08101918183106001600160401b038411176121af57612c3492604052613769565b80518210156124265760209160051b010190565b6bffffffffffffffffffffffff60a01b90816001541660015560005460018060a01b038092168093821617600055167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a3565b6003546001600160a01b03908116906000823b156102965780806040946024865180948193639504ad6d60e01b83528a60048401525af18015612f9157612f82575b5081600354169083516330fe427560e21b8152606081600481865afa908115612f785793859361136184602098848b99967f28f1c27f506f0a8d8cf21ad670fb93d0a296e8f069f12f0a2a6331ed81039f869c97612f529991612f59575b5051169482541633149182156113c2575050612368565b51908152a1565b612f72915060603d60601161041457610406818361220e565b38612f3b565b85513d84823e3d90fd5b612f8b906121c5565b38612edd565b84513d84823e3d90fd5b60405163a9059cbb60e01b60208201526001600160a01b03929092166024830152604480830193909352918152612c349161094560648361220e565b6003546040805163ee9af25d60e01b81529093926001600160a01b039283169260209291600484848281895afa938415612abc576000946131ad575b508315612b5e5787516330fe427560e21b81529588906060888481845afa978815612b535760009861318c575b50848851169482518881868163313ce56760e01b9a8b82525afa8015610a24576130719160009161317557506128d5565b958882818c015116918686518094819382525afa8015610a245761309c9160009161317557506128d5565b98518351631ee1b90b60e21b81529116848201528781602481855afa978815612afa57600098613142575b5050815163bd9a548b60e01b815292839182905afa908115612abc5792612a789594926122d5989992612a6d9560009460009261311257505090612a6d612a6d92612a7295966128fc565b612a729550612a6d939250612a6d918161313792903d10612ab557612aa4818361220e565b909592935091612a59565b809298508193503d831161316e575b61315b818361220e565b810103126104a2578890519538806130c7565b503d613151565b612b2591508a3d8c11612b2b57612b1d818361220e565b6131a691985060603d60601161041457610406818361220e565b9638613040565b9093508481813d83116131d5575b6131c5818361220e565b810103126104a257519238613013565b503d6131bb565b6001600160a01b0381166131ef57504790565b6122d590613588565b90916001600160a01b0390811691821561331a5783613216826131dc565b106132e0571691826132ac57600080808084865af161323361243c565b50156132675760207f9207361cc2a04b9c7a06691df1eb87c6a63957ae88bf01d0d18c81e3d1272099915b604051908152a3565b60405162461bcd60e51b815260206004820152601760248201527f4e6174697665207472616e73666572206661696c65642e0000000000000000006044820152606490fd5b6020816132db7f9207361cc2a04b9c7a06691df1eb87c6a63957ae88bf01d0d18c81e3d1272099938587612f9b565b61325e565b60405162461bcd60e51b8152602060048201526012602482015271496e73756666696369656e742066756e647360701b6044820152606490fd5b60405162461bcd60e51b815260206004820152600f60248201526e496e76616c6964206164647265737360881b6044820152606490fd5b60035460009291906001600160a01b039084908216803b156102ce57819060246040518094819363317afabb60e21b83528860048401525af1801561343857613425575b5080600354166040516330fe427560e21b8152606081600481855afa90811561341a579583602061136193612c34989984916133fb575b500151169381541633149081156133e35750612368565b60ff9150604090338152600260205220541638610e98565b613414915060603d60601161041457610406818361220e565b386133cc565b6040513d88823e3d90fd5b613431909491946121c5565b9238613395565b6040513d87823e3d90fd5b91909160018060a01b03806003541691600460606040948551928380926330fe427560e21b82525afa908115610a2457958360206000936134c198998591613569575b500151169261349484613588565b9460045416908387518099819582946207a9a360ea1b845260048401528a602484015260448301906122d8565b03925af1938415612afa5760009461351b575b50916135096020926121037f0bb6e019230e47211b08e219cc7dcfec394e152ecfd86b07dc0b0d4683b44912956120fe61363c565b9061351382612c6e565b51908152a190565b7f0bb6e019230e47211b08e219cc7dcfec394e152ecfd86b07dc0b0d4683b449129391945060209261210361355d613509933d806000833e6115de818361220e565b969395505092506134d4565b613582915060603d60601161041457610406818361220e565b38613486565b6040516370a0823160e01b815230600482015290602090829060249082906001600160a01b03165afa9081156125b057600091612861575090565b60209081818403126104a2578051906001600160401b0382116104a257019180601f840112156104a25782516135f88161222f565b93613606604051958661220e565b818552838086019260051b8201019283116104a2578301905b82821061362d575050505090565b8151815290830190830161361f565b6136446137c5565b9060005b8251811015613764576001600160a01b03806136648386612e31565b51169061367c816136758588612e31565b511661391a565b9133826000541614801561374b575b61369490612368565b60ff6006541680613720575b6136c0575b916136ba916001949330916004541690612dd9565b01613648565b60048281541690813b156104a25760008560246040938385519687948593639169d83360e01b85528401525af1908115612d375750916136ba93916001969593613711575b509193945091506136a5565b61371a906121c5565b38613705565b50817f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc21681146136a0565b503360009081526002602052604090205460ff1661368b565b509050565b906000602091828151910182855af1156125b0576000513d6137bc57506001600160a01b0381163b155b61379a5750565b604051635274afe760e01b81526001600160a01b039091166004820152602490fd5b60011415613793565b6004805460405163087ed83760e01b81526000939290916001600160a01b03918591849190829085165afa91821561390f57849261386d575b50819360ff6006541661381057505050565b825181101561386857808261382760019386612e31565b511615613835575b01613810565b827f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2166138628286612e31565b5261382f565b505050565b9091503d8085833e61387f818361220e565b8101906020908181840312613907578051906001600160401b03821161390b57019180601f840112156139075782516138b78161222f565b936138c5604051958661220e565b818552838086019260051b8201019283116113ff578301905b8282106138f0575050505090386137fe565b8380916138fc846123c3565b8152019101906138de565b8580fd5b8680fd5b6040513d86823e3d90fd5b60ff6006541680613953575b613942576004546122d5916001600160a01b0390911690612824565b506004546001600160a01b03163190565b506001600160a01b038181167f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc29091161461392656feeded619173dbb378903f97d44ecec898a1c4876f445ae551e063113aef58b471a2646970667358221220c63770146efd3ca171ac19765b6ebb076e5690c3d452ff27e1c7f1733d1ffa4d64736f6c63430008160033
Verified Source Code Partial Match
Compiler: v0.8.22+commit.4fc1097e
EVM: paris
Optimization: Yes (200 runs)
ILoanManager.sol 52 lines
/* SPDX-License-Identifier: UNLICENSED */
pragma solidity ^0.8.20;
import './ITBContract.sol';
interface ILoanManager {
struct LoanConfig {
address supplyAddress;
address borrowAddress;
uint minHealthFactor;
}
function getConfig() external view returns (LoanConfig memory);
function setConfig(address supplyAddress, address borrowAddress, uint minHealthFactor) external;
function supply(uint amount) external;
function borrow(uint amount) external;
function repay(uint256 _amount) external;
function repayAll() external;
function withdrawSupply(uint256 _amount) external;
function withdrawSupplyAll() external;
function repayAllAndWithdrawSupplyAll() external returns (uint256);
function getPrices() external view returns (uint256, uint256);
function getHealthFactor() external view returns (uint256);
function getLiquidityAndShortFall() external view returns (uint256, uint256);
function getSupply() external view returns (uint256);
function getBorrow() external view returns (uint256);
function getSupplyRate() external view returns (uint256);
function getBorrowRate() external view returns (uint256);
function getPositionDataSnapshot() external view returns (uint256, uint256, uint256, uint256, uint256, uint256, uint256);
function claimRewards() external returns (address[] memory, uint256[] memory);
function getMarketsData() external returns (uint256, uint256, uint256, uint256, uint256, uint256);
function getLiquidationThreshold(address _collateral) external view returns (uint256);
}
ITBContract.sol 100 lines
/* SPDX-License-Identifier: UNLICENSED */
pragma solidity ^0.8.20;
import './utils/Withdrawable.sol';
import './utils/IWETH.sol';
/// @title ITBContract contract that implements common owner only functions accros all strategies
/// @author IntoTheBlock Corp
/// @dev Abstract
abstract contract ITBContract is Withdrawable {
using SafeERC20 for IERC20;
event ApproveToken(address indexed token, address guy, uint256 wad);
address payable immutable public WNATIVE;
uint constant ONE = 1e18;
/// @param _executors Executor addresses
constructor(address[] memory _executors, address payable _wnative) Executable(_executors) {
WNATIVE = _wnative;
}
function _percentageAmount(uint _amount, uint _percentage) internal pure returns (uint) {
return _amount * _percentage / ONE;
}
/// @notice Set allowance for a given token, amount and spender
/// @param _token Token to spend
/// @param _guy Spender
/// @param _wad Max amount to spend
function _approveToken(address _token, address _guy, uint256 _wad) internal {
if (_wad != 0)
IERC20(_token).forceApprove(_guy, _wad);
else
IERC20(_token).approve(_guy, _wad);
emit ApproveToken(_token, _guy, _wad);
}
/// @notice For a given token, amount and spender, check if contract can spend amount and, if necessary, set the allowance to amount
/// @param _token Token to spend
/// @param _guy Spender
/// @param _amount Amount to spend
function _checkAllowanceAndApprove(address _token, address _guy, uint256 _amount) internal {
_checkAllowanceAndApprove(_token, _guy, _amount, _amount);
}
/// @notice For a given token, amount and spender, check if contract can spend amount and, if necessary, set the allowance to approval amount
/// @param _token Token to spend
/// @param _guy Spender
/// @param _amount Amount to spend
/// @param _approval_amount Amount to approve
function _checkAllowanceAndApprove(address _token, address _guy, uint256 _amount, uint256 _approval_amount) internal {
if (IERC20(_token).allowance(address(this), _guy) < _amount)
_approveToken(_token, _guy, _approval_amount);
}
/// @notice Only owner. Set allowance for a given token, amount and spender
/// @param _token Token to spend
/// @param _guy Spender
/// @param _wad Max amount to spend
function approveToken(address _token, address _guy, uint256 _wad) external onlyOwner {
_approveToken(_token, _guy, _wad);
}
/// @notice Only owner. Revoke allowance for a given token and spender
/// @param _token Token to spend
/// @param _guy Spender
function revokeToken(address _token, address _guy) external onlyOwner {
_approveToken(_token, _guy, 0);
}
/// @notice Only owner. Execute an arbitrary call
/// @param _to Target address
/// @param _value Value (i. e. msg.value)
/// @param _data Invocation data
function execute(address _to, uint256 _value, bytes calldata _data) external payable onlyOwner {
(bool success, bytes memory returnData) = _to.call{ value: _value }(_data);
require(success, string(returnData));
}
/// @notice Only owner. Execute multiple arbitrary calls in order
/// @param _tos Target address for each call
/// @param _values Value for each call (i. e. msg.value)
/// @param _datas Invocation data for each call
function batchExecute(address[] calldata _tos, uint256[] calldata _values, bytes[] calldata _datas) external payable onlyOwner {
require(_tos.length == _values.length && _tos.length == _datas.length, "Arguments length mismatch");
for (uint256 i = 0; i < _tos.length; i++) {
(bool success, bytes memory returnData) = _tos[i].call{ value: _values[i] }(_datas[i]);
require(success, string(returnData));
}
}
function wrapNative(uint256 _amount) public onlyExecutor {
IWETH(WNATIVE).deposit{ value: _amount }();
}
function unwrapNative(uint256 _amount) public onlyExecutor {
IWETH(WNATIVE).withdraw(_amount);
}
}
IYieldStrategy.sol 26 lines
/* SPDX-License-Identifier: UNLICENSED */
pragma solidity ^0.8.20;
import './ITBContract.sol';
interface IYieldStrategy {
function assemble() external;
function assemble(uint256 _min_lpts_out) external returns (uint256);
function disassemble(uint _percent) external;
function disassemble(uint _percent, uint256[] memory _min_coins_out) external returns (uint256[] memory);
function fullDisassemble() external;
function fullDisassemble(uint256[] memory min_coins_out) external returns (uint256[] memory);
function getPositionAssets() external view returns (address [] memory);
function getUnderlyings() external view returns (address[] memory, uint256[] memory);
function claimRewards() external returns (address[] memory, uint256[] memory);
function VERSION() external view returns (string memory);
}
Executable.sol 40 lines
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.20;
import "@openzeppelin/contracts/access/Ownable2Step.sol";
/// @title Base contract that implements executor related functions
/// @author IntoTheBlock Corp
/// @dev Abstract
abstract contract Executable is Ownable2Step {
mapping(address => bool) public executors;
event ExecutorUpdated(address indexed executor, bool enabled);
/// @param _executors Initial whitelisted executor addresses
constructor(address[] memory _executors) Ownable(msg.sender) {
for (uint256 i = 0; i < _executors.length; i++) {
addExecutor(_executors[i]);
}
}
/// @notice Revert if call is not being made from the owner or an executor
modifier onlyExecutor() {
require(owner() == msg.sender || executors[msg.sender], "Executable: caller is not the executor");
_;
}
/// @notice Only owner. Add an executor
/// @param _executor New executor address
function addExecutor(address _executor) public onlyOwner {
emit ExecutorUpdated(_executor, true);
executors[_executor] = true;
}
/// @notice Only owner. Remove an executor
/// @param _executor Executor address to remove
function removeExecutor(address _executor) external onlyOwner {
emit ExecutorUpdated(_executor, false);
executors[_executor] = false;
}
}
IWETH.sol 25 lines
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.20;
interface IWETH {
function name() external view returns (string memory);
function symbol() external view returns (string memory);
function decimals() external view returns (uint8);
event Approval(address indexed src, address indexed guy, uint256 wad);
event Transfer(address indexed src, address indexed dst, uint256 wad);
event Deposit(address indexed dst, uint256 wad);
event Withdrawal(address indexed src, uint256 wad);
function balanceOf(address) external view returns (uint256);
function allowance(address, address) external view returns (uint256);
fallback() external payable;
receive() external payable;
function deposit() external payable;
function withdraw(uint256 wad) external;
function totalSupply() external view returns (uint256);
function approve(address guy, uint256 wad) external returns (bool);
function transfer(address dst, uint256 wad) external returns (bool);
function transferFrom(address src, address dst, uint256 wad) external returns (bool);
}
Ownable2StepWithShortcut.sol 11 lines
/* SPDX-License-Identifier: UNLICENSED */
pragma solidity ^0.8.20;
import "@openzeppelin/contracts/access/Ownable2Step.sol";
abstract contract Ownable2StepWithShortcut is Ownable2Step {
function transferOwnership1Step(address newOwner) public onlyOwner {
require(newOwner != address(0), "ITBOwnable: zero address");
_transferOwnership(newOwner);
}
}
Withdrawable.sol 97 lines
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.20;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import './Executable.sol';
/**
Ensures that any contract that inherits from this contract is able to
withdraw funds that are accidentally received or stuck.
*/
/// @title Base contract that implements withdrawal related functions
/// @author IntoTheBlock Corp
/// @dev Abstract
abstract contract Withdrawable is Executable {
using SafeERC20 for IERC20;
address constant ETHER = address(0);
event LogWithdraw(
address indexed _to,
address indexed _asset_address,
uint256 amount
);
receive() external payable {}
/// @notice ERC20 or ETH balance of this contract given a token address
/// @param _asset_address Token address or address(0) for ETH
/// @return Balance
function _erc20OrNativeBalance(address _asset_address) internal view returns (uint256) {
return _asset_address == ETHER ? _nativeBalance() : _erc20Balance(_asset_address);
}
function _erc20Balance(address _asset_address) internal view returns (uint256) {
return IERC20(_asset_address).balanceOf(address(this));
}
function _nativeBalance() internal view returns (uint256) {
return address(this).balance;
}
/// @notice ERC20 balance of given account
/// @param _asset_address Token address
/// @param _account Account address
/// @return Balance
function balanceOf(address _asset_address, address _account) public view returns (uint256) {
return IERC20(_asset_address).balanceOf(_account);
}
/// @notice Send the given amount of the given token or ETH to the given receiver
/// @param _asset_address Token address or address(0) for ETH
/// @param _amount Amount to send
/// @param _to Receiver address
function _withdraw_to(address _asset_address, uint256 _amount, address payable _to) internal {
require(_to != address(0), 'Invalid address');
uint256 balance = _erc20OrNativeBalance(_asset_address);
require(balance >= _amount, 'Insufficient funds');
if (_asset_address == ETHER) {
(bool success, ) = _to.call{value: _amount}(''); /* carry gas over so it works with contracts with custom fallback, we dont care about reentrancy on onlyOwner */
require(success, 'Native transfer failed.');
} else
IERC20(_asset_address).safeTransfer(_to, _amount);
emit LogWithdraw(_to, _asset_address, _amount);
}
/// @notice Only owner. Send the given amount of the given token or ETH to the caller
/// @param _asset_address Token address or address(0) for ETH
/// @param _amount Amount to send
function withdraw(address _asset_address, uint256 _amount) external onlyOwner {
_withdraw_to(_asset_address, _amount, payable(msg.sender));
}
/// @notice Only owner. Send the given amount of the given token or ETH to the given receiver
/// @param _asset_address Token address or address(0) for ETH
/// @param _amount Amount to send
/// @param _to Receiver address
function withdrawTo(address _asset_address, uint256 _amount, address payable _to) external onlyOwner {
_withdraw_to(_asset_address, _amount, _to);
}
/// @notice Only owner. Send its entire balance of the given token or ETH to the caller
/// @param _asset_address Token address or address(0) for ETH
function withdrawAll(address _asset_address) external onlyOwner {
uint256 balance = _erc20OrNativeBalance(_asset_address);
_withdraw_to(_asset_address, balance, payable(msg.sender));
}
/// @notice Only owner. Send its entire balance of the given token or ETH to the given receiver
/// @param _asset_address Token address or address(0) for ETH
/// @param _to Receiver address
function withdrawAllTo(address _asset_address, address payable _to) external onlyOwner {
uint256 balance = _erc20OrNativeBalance(_asset_address);
_withdraw_to(_asset_address, balance, _to);
}
}
Ownable.sol 100 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)
pragma solidity ^0.8.20;
import {Context} from "../utils/Context.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* The initial owner is set to the address provided by the deployer. This can
* later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract Ownable is Context {
address private _owner;
/**
* @dev The caller account is not authorized to perform an operation.
*/
error OwnableUnauthorizedAccount(address account);
/**
* @dev The owner is not a valid owner account. (eg. `address(0)`)
*/
error OwnableInvalidOwner(address owner);
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the address provided by the deployer as the initial owner.
*/
constructor(address initialOwner) {
if (initialOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(initialOwner);
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if the sender is not the owner.
*/
function _checkOwner() internal view virtual {
if (owner() != _msgSender()) {
revert OwnableUnauthorizedAccount(_msgSender());
}
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby disabling any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
if (newOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}
Ownable2Step.sol 67 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (access/Ownable2Step.sol)
pragma solidity ^0.8.20;
import {Ownable} from "./Ownable.sol";
/**
* @dev Contract module which provides access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* This extension of the {Ownable} contract includes a two-step mechanism to transfer
* ownership, where the new owner must call {acceptOwnership} in order to replace the
* old one. This can help prevent common mistakes, such as transfers of ownership to
* incorrect accounts, or to contracts that are unable to interact with the
* permission system.
*
* The initial owner is specified at deployment time in the constructor for `Ownable`. This
* can later be changed with {transferOwnership} and {acceptOwnership}.
*
* This module is used through inheritance. It will make available all functions
* from parent (Ownable).
*/
abstract contract Ownable2Step is Ownable {
address private _pendingOwner;
event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner);
/**
* @dev Returns the address of the pending owner.
*/
function pendingOwner() public view virtual returns (address) {
return _pendingOwner;
}
/**
* @dev Starts the ownership transfer of the contract to a new account. Replaces the pending transfer if there is one.
* Can only be called by the current owner.
*
* Setting `newOwner` to the zero address is allowed; this can be used to cancel an initiated ownership transfer.
*/
function transferOwnership(address newOwner) public virtual override onlyOwner {
_pendingOwner = newOwner;
emit OwnershipTransferStarted(owner(), newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`) and deletes any pending owner.
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual override {
delete _pendingOwner;
super._transferOwnership(newOwner);
}
/**
* @dev The new owner accepts the ownership transfer.
*/
function acceptOwnership() public virtual {
address sender = _msgSender();
if (pendingOwner() != sender) {
revert OwnableUnauthorizedAccount(sender);
}
_transferOwnership(sender);
}
}
draft-IERC6093.sol 161 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/draft-IERC6093.sol)
pragma solidity >=0.8.4;
/**
* @dev Standard ERC-20 Errors
* Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC-20 tokens.
*/
interface IERC20Errors {
/**
* @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
* @param balance Current balance for the interacting account.
* @param needed Minimum amount required to perform a transfer.
*/
error ERC20InsufficientBalance(address sender, uint256 balance, uint256 needed);
/**
* @dev Indicates a failure with the token `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
*/
error ERC20InvalidSender(address sender);
/**
* @dev Indicates a failure with the token `receiver`. Used in transfers.
* @param receiver Address to which tokens are being transferred.
*/
error ERC20InvalidReceiver(address receiver);
/**
* @dev Indicates a failure with the `spender`’s `allowance`. Used in transfers.
* @param spender Address that may be allowed to operate on tokens without being their owner.
* @param allowance Amount of tokens a `spender` is allowed to operate with.
* @param needed Minimum amount required to perform a transfer.
*/
error ERC20InsufficientAllowance(address spender, uint256 allowance, uint256 needed);
/**
* @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
* @param approver Address initiating an approval operation.
*/
error ERC20InvalidApprover(address approver);
/**
* @dev Indicates a failure with the `spender` to be approved. Used in approvals.
* @param spender Address that may be allowed to operate on tokens without being their owner.
*/
error ERC20InvalidSpender(address spender);
}
/**
* @dev Standard ERC-721 Errors
* Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC-721 tokens.
*/
interface IERC721Errors {
/**
* @dev Indicates that an address can't be an owner. For example, `address(0)` is a forbidden owner in ERC-20.
* Used in balance queries.
* @param owner Address of the current owner of a token.
*/
error ERC721InvalidOwner(address owner);
/**
* @dev Indicates a `tokenId` whose `owner` is the zero address.
* @param tokenId Identifier number of a token.
*/
error ERC721NonexistentToken(uint256 tokenId);
/**
* @dev Indicates an error related to the ownership over a particular token. Used in transfers.
* @param sender Address whose tokens are being transferred.
* @param tokenId Identifier number of a token.
* @param owner Address of the current owner of a token.
*/
error ERC721IncorrectOwner(address sender, uint256 tokenId, address owner);
/**
* @dev Indicates a failure with the token `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
*/
error ERC721InvalidSender(address sender);
/**
* @dev Indicates a failure with the token `receiver`. Used in transfers.
* @param receiver Address to which tokens are being transferred.
*/
error ERC721InvalidReceiver(address receiver);
/**
* @dev Indicates a failure with the `operator`’s approval. Used in transfers.
* @param operator Address that may be allowed to operate on tokens without being their owner.
* @param tokenId Identifier number of a token.
*/
error ERC721InsufficientApproval(address operator, uint256 tokenId);
/**
* @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
* @param approver Address initiating an approval operation.
*/
error ERC721InvalidApprover(address approver);
/**
* @dev Indicates a failure with the `operator` to be approved. Used in approvals.
* @param operator Address that may be allowed to operate on tokens without being their owner.
*/
error ERC721InvalidOperator(address operator);
}
/**
* @dev Standard ERC-1155 Errors
* Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC-1155 tokens.
*/
interface IERC1155Errors {
/**
* @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
* @param balance Current balance for the interacting account.
* @param needed Minimum amount required to perform a transfer.
* @param tokenId Identifier number of a token.
*/
error ERC1155InsufficientBalance(address sender, uint256 balance, uint256 needed, uint256 tokenId);
/**
* @dev Indicates a failure with the token `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
*/
error ERC1155InvalidSender(address sender);
/**
* @dev Indicates a failure with the token `receiver`. Used in transfers.
* @param receiver Address to which tokens are being transferred.
*/
error ERC1155InvalidReceiver(address receiver);
/**
* @dev Indicates a failure with the `operator`’s approval. Used in transfers.
* @param operator Address that may be allowed to operate on tokens without being their owner.
* @param owner Address of the current owner of a token.
*/
error ERC1155MissingApprovalForAll(address operator, address owner);
/**
* @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
* @param approver Address initiating an approval operation.
*/
error ERC1155InvalidApprover(address approver);
/**
* @dev Indicates a failure with the `operator` to be approved. Used in approvals.
* @param operator Address that may be allowed to operate on tokens without being their owner.
*/
error ERC1155InvalidOperator(address operator);
/**
* @dev Indicates an array length mismatch between ids and values in a safeBatchTransferFrom operation.
* Used in batch transfers.
* @param idsLength Length of the array of token identifiers
* @param valuesLength Length of the array of token amounts
*/
error ERC1155InvalidArrayLength(uint256 idsLength, uint256 valuesLength);
}
IERC1363.sol 86 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC1363.sol)
pragma solidity >=0.6.2;
import {IERC20} from "./IERC20.sol";
import {IERC165} from "./IERC165.sol";
/**
* @title IERC1363
* @dev Interface of the ERC-1363 standard as defined in the https://eips.ethereum.org/EIPS/eip-1363[ERC-1363].
*
* Defines an extension interface for ERC-20 tokens that supports executing code on a recipient contract
* after `transfer` or `transferFrom`, or code on a spender contract after `approve`, in a single transaction.
*/
interface IERC1363 is IERC20, IERC165 {
/*
* Note: the ERC-165 identifier for this interface is 0xb0202a11.
* 0xb0202a11 ===
* bytes4(keccak256('transferAndCall(address,uint256)')) ^
* bytes4(keccak256('transferAndCall(address,uint256,bytes)')) ^
* bytes4(keccak256('transferFromAndCall(address,address,uint256)')) ^
* bytes4(keccak256('transferFromAndCall(address,address,uint256,bytes)')) ^
* bytes4(keccak256('approveAndCall(address,uint256)')) ^
* bytes4(keccak256('approveAndCall(address,uint256,bytes)'))
*/
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferAndCall(address to, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @param data Additional data with no specified format, sent in call to `to`.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferAndCall(address to, uint256 value, bytes calldata data) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param from The address which you want to send tokens from.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferFromAndCall(address from, address to, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param from The address which you want to send tokens from.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @param data Additional data with no specified format, sent in call to `to`.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferFromAndCall(address from, address to, uint256 value, bytes calldata data) external returns (bool);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.
* @param spender The address which will spend the funds.
* @param value The amount of tokens to be spent.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function approveAndCall(address spender, uint256 value) external returns (bool);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.
* @param spender The address which will spend the funds.
* @param value The amount of tokens to be spent.
* @param data Additional data with no specified format, sent in call to `spender`.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function approveAndCall(address spender, uint256 value, bytes calldata data) external returns (bool);
}
IERC165.sol 6 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC165.sol)
pragma solidity >=0.4.16;
import {IERC165} from "../utils/introspection/IERC165.sol";
IERC20.sol 6 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC20.sol)
pragma solidity >=0.4.16;
import {IERC20} from "../token/ERC20/IERC20.sol";
ERC20.sol 305 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (token/ERC20/ERC20.sol)
pragma solidity ^0.8.20;
import {IERC20} from "./IERC20.sol";
import {IERC20Metadata} from "./extensions/IERC20Metadata.sol";
import {Context} from "../../utils/Context.sol";
import {IERC20Errors} from "../../interfaces/draft-IERC6093.sol";
/**
* @dev Implementation of the {IERC20} interface.
*
* This implementation is agnostic to the way tokens are created. This means
* that a supply mechanism has to be added in a derived contract using {_mint}.
*
* TIP: For a detailed writeup see our guide
* https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How
* to implement supply mechanisms].
*
* The default value of {decimals} is 18. To change this, you should override
* this function so it returns a different value.
*
* We have followed general OpenZeppelin Contracts guidelines: functions revert
* instead returning `false` on failure. This behavior is nonetheless
* conventional and does not conflict with the expectations of ERC-20
* applications.
*/
abstract contract ERC20 is Context, IERC20, IERC20Metadata, IERC20Errors {
mapping(address account => uint256) private _balances;
mapping(address account => mapping(address spender => uint256)) private _allowances;
uint256 private _totalSupply;
string private _name;
string private _symbol;
/**
* @dev Sets the values for {name} and {symbol}.
*
* Both values are immutable: they can only be set once during construction.
*/
constructor(string memory name_, string memory symbol_) {
_name = name_;
_symbol = symbol_;
}
/**
* @dev Returns the name of the token.
*/
function name() public view virtual returns (string memory) {
return _name;
}
/**
* @dev Returns the symbol of the token, usually a shorter version of the
* name.
*/
function symbol() public view virtual returns (string memory) {
return _symbol;
}
/**
* @dev Returns the number of decimals used to get its user representation.
* For example, if `decimals` equals `2`, a balance of `505` tokens should
* be displayed to a user as `5.05` (`505 / 10 ** 2`).
*
* Tokens usually opt for a value of 18, imitating the relationship between
* Ether and Wei. This is the default value returned by this function, unless
* it's overridden.
*
* NOTE: This information is only used for _display_ purposes: it in
* no way affects any of the arithmetic of the contract, including
* {IERC20-balanceOf} and {IERC20-transfer}.
*/
function decimals() public view virtual returns (uint8) {
return 18;
}
/// @inheritdoc IERC20
function totalSupply() public view virtual returns (uint256) {
return _totalSupply;
}
/// @inheritdoc IERC20
function balanceOf(address account) public view virtual returns (uint256) {
return _balances[account];
}
/**
* @dev See {IERC20-transfer}.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - the caller must have a balance of at least `value`.
*/
function transfer(address to, uint256 value) public virtual returns (bool) {
address owner = _msgSender();
_transfer(owner, to, value);
return true;
}
/// @inheritdoc IERC20
function allowance(address owner, address spender) public view virtual returns (uint256) {
return _allowances[owner][spender];
}
/**
* @dev See {IERC20-approve}.
*
* NOTE: If `value` is the maximum `uint256`, the allowance is not updated on
* `transferFrom`. This is semantically equivalent to an infinite approval.
*
* Requirements:
*
* - `spender` cannot be the zero address.
*/
function approve(address spender, uint256 value) public virtual returns (bool) {
address owner = _msgSender();
_approve(owner, spender, value);
return true;
}
/**
* @dev See {IERC20-transferFrom}.
*
* Skips emitting an {Approval} event indicating an allowance update. This is not
* required by the ERC. See {xref-ERC20-_approve-address-address-uint256-bool-}[_approve].
*
* NOTE: Does not update the allowance if the current allowance
* is the maximum `uint256`.
*
* Requirements:
*
* - `from` and `to` cannot be the zero address.
* - `from` must have a balance of at least `value`.
* - the caller must have allowance for ``from``'s tokens of at least
* `value`.
*/
function transferFrom(address from, address to, uint256 value) public virtual returns (bool) {
address spender = _msgSender();
_spendAllowance(from, spender, value);
_transfer(from, to, value);
return true;
}
/**
* @dev Moves a `value` amount of tokens from `from` to `to`.
*
* This internal function is equivalent to {transfer}, and can be used to
* e.g. implement automatic token fees, slashing mechanisms, etc.
*
* Emits a {Transfer} event.
*
* NOTE: This function is not virtual, {_update} should be overridden instead.
*/
function _transfer(address from, address to, uint256 value) internal {
if (from == address(0)) {
revert ERC20InvalidSender(address(0));
}
if (to == address(0)) {
revert ERC20InvalidReceiver(address(0));
}
_update(from, to, value);
}
/**
* @dev Transfers a `value` amount of tokens from `from` to `to`, or alternatively mints (or burns) if `from`
* (or `to`) is the zero address. All customizations to transfers, mints, and burns should be done by overriding
* this function.
*
* Emits a {Transfer} event.
*/
function _update(address from, address to, uint256 value) internal virtual {
if (from == address(0)) {
// Overflow check required: The rest of the code assumes that totalSupply never overflows
_totalSupply += value;
} else {
uint256 fromBalance = _balances[from];
if (fromBalance < value) {
revert ERC20InsufficientBalance(from, fromBalance, value);
}
unchecked {
// Overflow not possible: value <= fromBalance <= totalSupply.
_balances[from] = fromBalance - value;
}
}
if (to == address(0)) {
unchecked {
// Overflow not possible: value <= totalSupply or value <= fromBalance <= totalSupply.
_totalSupply -= value;
}
} else {
unchecked {
// Overflow not possible: balance + value is at most totalSupply, which we know fits into a uint256.
_balances[to] += value;
}
}
emit Transfer(from, to, value);
}
/**
* @dev Creates a `value` amount of tokens and assigns them to `account`, by transferring it from address(0).
* Relies on the `_update` mechanism
*
* Emits a {Transfer} event with `from` set to the zero address.
*
* NOTE: This function is not virtual, {_update} should be overridden instead.
*/
function _mint(address account, uint256 value) internal {
if (account == address(0)) {
revert ERC20InvalidReceiver(address(0));
}
_update(address(0), account, value);
}
/**
* @dev Destroys a `value` amount of tokens from `account`, lowering the total supply.
* Relies on the `_update` mechanism.
*
* Emits a {Transfer} event with `to` set to the zero address.
*
* NOTE: This function is not virtual, {_update} should be overridden instead
*/
function _burn(address account, uint256 value) internal {
if (account == address(0)) {
revert ERC20InvalidSender(address(0));
}
_update(account, address(0), value);
}
/**
* @dev Sets `value` as the allowance of `spender` over the `owner`'s tokens.
*
* This internal function is equivalent to `approve`, and can be used to
* e.g. set automatic allowances for certain subsystems, etc.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `owner` cannot be the zero address.
* - `spender` cannot be the zero address.
*
* Overrides to this logic should be done to the variant with an additional `bool emitEvent` argument.
*/
function _approve(address owner, address spender, uint256 value) internal {
_approve(owner, spender, value, true);
}
/**
* @dev Variant of {_approve} with an optional flag to enable or disable the {Approval} event.
*
* By default (when calling {_approve}) the flag is set to true. On the other hand, approval changes made by
* `_spendAllowance` during the `transferFrom` operation set the flag to false. This saves gas by not emitting any
* `Approval` event during `transferFrom` operations.
*
* Anyone who wishes to continue emitting `Approval` events on the`transferFrom` operation can force the flag to
* true using the following override:
*
* ```solidity
* function _approve(address owner, address spender, uint256 value, bool) internal virtual override {
* super._approve(owner, spender, value, true);
* }
* ```
*
* Requirements are the same as {_approve}.
*/
function _approve(address owner, address spender, uint256 value, bool emitEvent) internal virtual {
if (owner == address(0)) {
revert ERC20InvalidApprover(address(0));
}
if (spender == address(0)) {
revert ERC20InvalidSpender(address(0));
}
_allowances[owner][spender] = value;
if (emitEvent) {
emit Approval(owner, spender, value);
}
}
/**
* @dev Updates `owner`'s allowance for `spender` based on spent `value`.
*
* Does not update the allowance value in case of infinite allowance.
* Revert if not enough allowance is available.
*
* Does not emit an {Approval} event.
*/
function _spendAllowance(address owner, address spender, uint256 value) internal virtual {
uint256 currentAllowance = allowance(owner, spender);
if (currentAllowance < type(uint256).max) {
if (currentAllowance < value) {
revert ERC20InsufficientAllowance(spender, currentAllowance, value);
}
unchecked {
_approve(owner, spender, currentAllowance - value, false);
}
}
}
}
IERC20Metadata.sol 26 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (token/ERC20/extensions/IERC20Metadata.sol)
pragma solidity >=0.6.2;
import {IERC20} from "../IERC20.sol";
/**
* @dev Interface for the optional metadata functions from the ERC-20 standard.
*/
interface IERC20Metadata is IERC20 {
/**
* @dev Returns the name of the token.
*/
function name() external view returns (string memory);
/**
* @dev Returns the symbol of the token.
*/
function symbol() external view returns (string memory);
/**
* @dev Returns the decimals places of the token.
*/
function decimals() external view returns (uint8);
}
IERC20.sol 79 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (token/ERC20/IERC20.sol)
pragma solidity >=0.4.16;
/**
* @dev Interface of the ERC-20 standard as defined in the ERC.
*/
interface IERC20 {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the value of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the value of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 value) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the
* allowance mechanism. `value` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 value) external returns (bool);
}
SafeERC20.sol 212 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.3.0) (token/ERC20/utils/SafeERC20.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../IERC20.sol";
import {IERC1363} from "../../../interfaces/IERC1363.sol";
/**
* @title SafeERC20
* @dev Wrappers around ERC-20 operations that throw on failure (when the token
* contract returns false). Tokens that return no value (and instead revert or
* throw on failure) are also supported, non-reverting calls are assumed to be
* successful.
* To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/
library SafeERC20 {
/**
* @dev An operation with an ERC-20 token failed.
*/
error SafeERC20FailedOperation(address token);
/**
* @dev Indicates a failed `decreaseAllowance` request.
*/
error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);
/**
* @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeTransfer(IERC20 token, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));
}
/**
* @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
* calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
*/
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));
}
/**
* @dev Variant of {safeTransfer} that returns a bool instead of reverting if the operation is not successful.
*/
function trySafeTransfer(IERC20 token, address to, uint256 value) internal returns (bool) {
return _callOptionalReturnBool(token, abi.encodeCall(token.transfer, (to, value)));
}
/**
* @dev Variant of {safeTransferFrom} that returns a bool instead of reverting if the operation is not successful.
*/
function trySafeTransferFrom(IERC20 token, address from, address to, uint256 value) internal returns (bool) {
return _callOptionalReturnBool(token, abi.encodeCall(token.transferFrom, (from, to, value)));
}
/**
* @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*
* IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client"
* smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using
* this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract
* that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.
*/
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 oldAllowance = token.allowance(address(this), spender);
forceApprove(token, spender, oldAllowance + value);
}
/**
* @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no
* value, non-reverting calls are assumed to be successful.
*
* IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client"
* smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using
* this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract
* that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.
*/
function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {
unchecked {
uint256 currentAllowance = token.allowance(address(this), spender);
if (currentAllowance < requestedDecrease) {
revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);
}
forceApprove(token, spender, currentAllowance - requestedDecrease);
}
}
/**
* @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
* to be set to zero before setting it to a non-zero value, such as USDT.
*
* NOTE: If the token implements ERC-7674, this function will not modify any temporary allowance. This function
* only sets the "standard" allowance. Any temporary allowance will remain active, in addition to the value being
* set here.
*/
function forceApprove(IERC20 token, address spender, uint256 value) internal {
bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));
if (!_callOptionalReturnBool(token, approvalCall)) {
_callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));
_callOptionalReturn(token, approvalCall);
}
}
/**
* @dev Performs an {ERC1363} transferAndCall, with a fallback to the simple {ERC20} transfer if the target has no
* code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
* targeting contracts.
*
* Reverts if the returned value is other than `true`.
*/
function transferAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {
if (to.code.length == 0) {
safeTransfer(token, to, value);
} else if (!token.transferAndCall(to, value, data)) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Performs an {ERC1363} transferFromAndCall, with a fallback to the simple {ERC20} transferFrom if the target
* has no code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
* targeting contracts.
*
* Reverts if the returned value is other than `true`.
*/
function transferFromAndCallRelaxed(
IERC1363 token,
address from,
address to,
uint256 value,
bytes memory data
) internal {
if (to.code.length == 0) {
safeTransferFrom(token, from, to, value);
} else if (!token.transferFromAndCall(from, to, value, data)) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Performs an {ERC1363} approveAndCall, with a fallback to the simple {ERC20} approve if the target has no
* code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
* targeting contracts.
*
* NOTE: When the recipient address (`to`) has no code (i.e. is an EOA), this function behaves as {forceApprove}.
* Opposedly, when the recipient address (`to`) has code, this function only attempts to call {ERC1363-approveAndCall}
* once without retrying, and relies on the returned value to be true.
*
* Reverts if the returned value is other than `true`.
*/
function approveAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {
if (to.code.length == 0) {
forceApprove(token, to, value);
} else if (!token.approveAndCall(to, value, data)) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*
* This is a variant of {_callOptionalReturnBool} that reverts if call fails to meet the requirements.
*/
function _callOptionalReturn(IERC20 token, bytes memory data) private {
uint256 returnSize;
uint256 returnValue;
assembly ("memory-safe") {
let success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)
// bubble errors
if iszero(success) {
let ptr := mload(0x40)
returndatacopy(ptr, 0, returndatasize())
revert(ptr, returndatasize())
}
returnSize := returndatasize()
returnValue := mload(0)
}
if (returnSize == 0 ? address(token).code.length == 0 : returnValue != 1) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*
* This is a variant of {_callOptionalReturn} that silently catches all reverts and returns a bool instead.
*/
function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
bool success;
uint256 returnSize;
uint256 returnValue;
assembly ("memory-safe") {
success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)
returnSize := returndatasize()
returnValue := mload(0)
}
return success && (returnSize == 0 ? address(token).code.length > 0 : returnValue == 1);
}
}
Context.sol 28 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)
pragma solidity ^0.8.20;
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
function _contextSuffixLength() internal view virtual returns (uint256) {
return 0;
}
}
IERC165.sol 25 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (utils/introspection/IERC165.sol)
pragma solidity >=0.4.16;
/**
* @dev Interface of the ERC-165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[ERC].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface IERC165 {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[ERC section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}
SupervisedLoanPositionManager.sol 461 lines
/* SPDX-License-Identifier: UNLICENSED */
pragma solidity ^0.8.0;
import '@itb/quant-common/contracts/solidity8/ITBContract.sol';
import '@itb/quant-common/contracts/solidity8/ILoanManager.sol';
import '@itb/quant-common/contracts/solidity8/IYieldStrategy.sol';
import '@openzeppelin/contracts/token/ERC20/ERC20.sol';
/// @title SupervisedLoanPositionManager
/// @author IntoTheBlock Corp
contract SupervisedLoanPositionManager is ITBContract {
using SafeERC20 for IERC20;
struct SupervisedConfig {
uint256 targetHealthFactor;
bool yieldStrategyUseNativeAssets;
}
event FullDisassemble(uint supply_amount, uint borrow_amount);
event Assemble(uint supply_amount, uint borrow_amount);
event WithdrawSupplyAndAssemble(uint supply_amount);
event UnwindAndSupply(uint supply_amount);
event UnwindAndRepay(uint borrow_amount);
event UnwindRepayAndWithdraw();
event Supply(uint supply_amount);
event WithdrawSupply(uint supply_amount);
event Borrow(uint borrow_amount);
event Repay(uint borrow_amount);
event UpdateSupervisedConfig(SupervisedConfig old_config, SupervisedConfig new_config);
event UpdateLoanManager(ILoanManager old_loan_manager, ILoanManager new_loan_manager);
event UpdateYieldStrategy(IYieldStrategy old_yield_strategy, IYieldStrategy new_yield_strategy);
ILoanManager public loanManager;
IYieldStrategy public yieldStrategy;
SupervisedConfig supervisedConfig;
/// @param _executors Array of executors addresses.
/// @param _wnative Native token address.
/// @param _loanManager Loan Manager address.
/// @param _yieldStrategy Yield Strategy Position Manager address.
/// @param _targetHealthFactor Target health factor.
constructor(address[] memory _executors, address payable _wnative, ILoanManager _loanManager, IYieldStrategy _yieldStrategy, uint256 _targetHealthFactor, bool _yieldStrategyUseNativeAssets) ITBContract(_executors, _wnative) {
setConfig(_targetHealthFactor, _yieldStrategyUseNativeAssets);
updateLoanManager(_loanManager);
updateYieldStrategy(_yieldStrategy);
}
function setConfig(uint256 _targetHealthFactor, bool _yieldStrategyUseNativeAssets) public onlyOwner {
SupervisedConfig memory new_config = SupervisedConfig(_targetHealthFactor, _yieldStrategyUseNativeAssets);
emit UpdateSupervisedConfig(supervisedConfig, new_config);
supervisedConfig = new_config;
}
function getConfig() public view returns (SupervisedConfig memory) {
return supervisedConfig;
}
function getLoanManagerConfig() external view returns (ILoanManager.LoanConfig memory) {
return loanManager.getConfig();
}
/// @notice Only owner. Updates LoanManager address.
/// @param _address New Loan Manager address.
function updateLoanManager(ILoanManager _address) public onlyOwner {
emit UpdateLoanManager(loanManager, _address);
loanManager = _address;
}
/// @notice Only owner. Updates Yield Strategy Position Manager address.
/// @param _address New Yield Strategy Position Manager address.
function updateYieldStrategy(IYieldStrategy _address) public onlyOwner {
emit UpdateYieldStrategy(yieldStrategy, _address);
yieldStrategy = _address;
}
function _balanceOfLoan(address _asset) internal view returns (uint) {
return balanceOf(_asset, address(loanManager));
}
function _balanceOfYield(address _asset) internal view returns (uint) {
if (supervisedConfig.yieldStrategyUseNativeAssets && _asset == WNATIVE)
return address(yieldStrategy).balance;
return balanceOf(_asset, address(yieldStrategy));
}
function _getYieldAssets() internal view returns (address[] memory positionAssets) {
positionAssets = yieldStrategy.getPositionAssets();
if (supervisedConfig.yieldStrategyUseNativeAssets)
for (uint i = 0; i < positionAssets.length; i++)
if (positionAssets[i] == address(0))
positionAssets[i] = WNATIVE;
}
function _transferAllAssetsFromYield() internal {
address[] memory positionAssets = _getYieldAssets();
for (uint i = 0; i < positionAssets.length; i++)
transferAssetsFromYieldStrategy(positionAssets[i], _balanceOfYield(positionAssets[i]));
}
/// @notice Supplies collateral to the loan.
/// @param _amount Amount to supply.
function _supply(uint256 _amount) internal {
transferAssetsToLoanManager(loanManager.getConfig().supplyAddress, _amount);
loanManager.supply(_amount);
}
/// @notice Withdraw supply from the loan.
/// @param _amount Amount to withdraw.
function _withdrawSupply(uint256 _amount) internal {
loanManager.withdrawSupply(_amount);
transferAssetsFromLoanManager(loanManager.getConfig().supplyAddress, _amount);
emit WithdrawSupply(_amount);
}
/// @notice Borrows from the loan.
/// @param _amount Amount to borrow.
function _borrow(uint256 _amount) internal {
loanManager.borrow(_amount);
transferAssetsFromLoanManager(loanManager.getConfig().borrowAddress, _amount);
}
/// @notice Repays part of the loan.
/// @param _amount Amount to repay.
function _repay(uint256 _amount) internal {
address borrowedAsset = loanManager.getConfig().borrowAddress;
uint256 borrowed = loanManager.getBorrow();
if (_amount > borrowed)
_amount = borrowed;
transferAssetsToLoanManager(borrowedAsset, _amount);
loanManager.repay(_amount);
}
/// @notice Withdraw all available supply to reach the desired HF.
function _withdrawSupplyAvailable() internal returns (uint256) {
uint256 withdrawAmount = getAvailableWithdraw();
if (withdrawAmount == 0)
return 0;
_withdrawSupply(withdrawAmount);
return withdrawAmount;
}
/// @notice Assembles a supervised loan position.
/// @param _supplyAmount Amount of token to deposit and use as collateral.
/// @param _borrowAmount Amount of token to borrow from the lending protocol.
/// @param _min_lpt_out Min lpts out.
/// @param _before_assemble_data Data to be used with custom logic before assembling the yield strategy.
/// @return lpt_amount Amount out of LPT token from yield_strategy.
function _assemble(uint256 _supplyAmount, uint256 _borrowAmount, uint256 _min_lpt_out, bytes memory _before_assemble_data) internal virtual returns (uint256) {
if (_supplyAmount != 0)
_supply(_supplyAmount);
if (_borrowAmount != 0)
_borrow(_borrowAmount);
_beforeYieldStrategyAssemble(_before_assemble_data);
address[] memory positionAssets = _getYieldAssets();
for (uint i = 0; i < positionAssets.length; i++)
transferAssetsToYieldStrategy(positionAssets[i], _erc20Balance(positionAssets[i]));
emit Assemble(_supplyAmount, _borrowAmount);
return _yieldStrategyAssemble(_min_lpt_out);
}
function _unwind(address _asset, uint _percentage, uint256[] memory _min_yield_outs, bytes memory _after_disassemble_data) internal virtual returns (uint256[] memory yield_outs, uint256 amount_out) {
uint256 previousBalance = _erc20Balance(_asset);
yield_outs = _yieldStrategyDisassemble(_percentage, _min_yield_outs);
_afterYieldStrategyDisassemble(_after_disassemble_data);
_transferAllAssetsFromYield();
uint256 newBalance = _erc20Balance(_asset);
amount_out = newBalance - previousBalance;
}
/// @notice Unwinds a percentage of the yield position and uses it to repay part of the loan.
/// @param _percentage Amount to unwind expressed as percentage. 1e18 is equivalent to 100%.
/// @param _min_yield_outs Min coin amounts out of yield_strategy.
/// @param _after_disassemble_data Data to be used with custom logic after disassembling the yield strategy.
/// @return yield_outs Coin amounts out of yield_strategy.
function _unwindAndRepay(uint _percentage, uint256[] memory _min_yield_outs, bytes memory _after_disassemble_data) internal virtual returns (uint256[] memory) {
(uint256[] memory yield_outs, uint256 repay_amount) = _unwind(loanManager.getConfig().borrowAddress, _percentage, _min_yield_outs, _after_disassemble_data);
_repay(repay_amount);
emit UnwindAndRepay(repay_amount);
return yield_outs;
}
function _unwindRepayAndWithdraw(uint _percentage, uint _withdraw_supply_amount, uint256[] memory _min_yield_outs, bytes memory _after_disassemble_data) internal virtual returns (uint256[] memory) {
uint256[] memory yield_outs = _unwindAndRepay(_percentage, _min_yield_outs, _after_disassemble_data);
_withdrawSupply(_withdraw_supply_amount);
emit UnwindRepayAndWithdraw();
return yield_outs;
}
function _unwindRepayAndWithdrawAvailable(uint _percentage, uint256[] memory _min_yield_outs, bytes memory _after_disassemble_data) internal virtual returns (uint256[] memory) {
uint256[] memory yield_outs = _unwindAndRepay(_percentage, _min_yield_outs, _after_disassemble_data);
_withdrawSupplyAvailable();
emit UnwindRepayAndWithdraw();
return yield_outs;
}
/// @notice Completely disassembles a supervised loan position.
/// @param _min_yield_outs Min coin amounts out of yield_strategy.
/// @param _after_disassemble_data Data to be used with custom logic after disassembling the yield strategy.
/// @return yields_out Coin amounts out of yield_strategy.
function _fullDisassemble(uint256[] memory _min_yield_outs, bytes memory _after_disassemble_data) internal virtual returns (uint256[] memory yields_out) {
yields_out = _yieldStrategyFullDisassemble(_min_yield_outs);
emit FullDisassemble(loanManager.getSupply(), loanManager.getBorrow());
_afterYieldStrategyDisassemble(_after_disassemble_data);
_finishFullDisassemble();
}
function _finishFullDisassemble() internal {
ILoanManager.LoanConfig memory loanConfig = loanManager.getConfig();
_transferAllAssetsFromYield();
transferAssetsToLoanManager(loanConfig.borrowAddress, _erc20Balance(loanConfig.borrowAddress));
(uint256 supplyMarketDeposits, uint256 supplyMarketDebt, , , , ) = loanManager.getMarketsData();
uint256 liquidity = supplyMarketDeposits - supplyMarketDebt;
if (liquidity < loanManager.getSupply()) {
loanManager.repayAll();
loanManager.withdrawSupply(liquidity);
}
else
loanManager.repayAllAndWithdrawSupplyAll();
uint256 withdrawAmount = _balanceOfLoan(loanConfig.supplyAddress);
transferAssetsFromLoanManager(loanConfig.supplyAddress, withdrawAmount);
uint256 remainingBorrowAsset = _balanceOfLoan(loanConfig.borrowAddress);
if (remainingBorrowAsset > 0)
transferAssetsFromLoanManager(loanConfig.borrowAddress, remainingBorrowAsset);
}
function _maxBorrow(uint256 targetHealthFactor) internal view returns (uint256) {
uint256 supplied = loanManager.getSupply();
if (supplied == 0)
return 0;
ILoanManager.LoanConfig memory loanConfig = loanManager.getConfig();
uint256 supplyExp = 10 ** ERC20(loanConfig.supplyAddress).decimals();
uint256 borrowExp = 10 ** ERC20(loanConfig.borrowAddress).decimals();
uint256 collateralFactor = loanManager.getLiquidationThreshold(loanConfig.supplyAddress);
(uint256 supplyTokenPrice, uint256 borrowTokenPrice) = loanManager.getPrices();
uint256 supplyAsBase = supplied * supplyTokenPrice;
uint256 supplyPowerAsBase = supplyAsBase * collateralFactor;
return supplyPowerAsBase * borrowExp / (supplyExp * borrowTokenPrice * targetHealthFactor);
}
function _minSupply(uint256 targetHealthFactor) internal view returns (uint256) {
uint256 borrowed = loanManager.getBorrow();
if (borrowed == 0)
return 0;
ILoanManager.LoanConfig memory loanConfig = loanManager.getConfig();
uint256 supplyExp = 10 ** ERC20(loanConfig.supplyAddress).decimals();
uint256 borrowExp = 10 ** ERC20(loanConfig.borrowAddress).decimals();
uint256 collateralFactor = loanManager.getLiquidationThreshold(loanConfig.supplyAddress);
(uint256 supplyTokenPrice, uint256 borrowTokenPrice) = loanManager.getPrices();
uint256 borrowAsBase = borrowed * borrowTokenPrice;
uint256 minSupplyPowerAsBase = borrowAsBase * targetHealthFactor;
return minSupplyPowerAsBase * supplyExp / (borrowExp * supplyTokenPrice * collateralFactor);
}
function _beforeTransferFromYieldStrategy(address asset, uint amount) internal {
if (supervisedConfig.yieldStrategyUseNativeAssets && asset == WNATIVE)
ITBContract(payable(address(yieldStrategy))).wrapNative(amount);
}
function _afterTransferToYieldStrategy(address asset, uint amount) internal {
if (supervisedConfig.yieldStrategyUseNativeAssets && asset == WNATIVE)
ITBContract(payable(address(yieldStrategy))).unwrapNative(amount);
}
function _beforeYieldStrategyAssemble(bytes memory) internal virtual {
address borrowAddress = loanManager.getConfig().borrowAddress;
address[] memory positionAssets = _getYieldAssets();
bool borrowNeeded;
for (uint i = 0; i < positionAssets.length; i++)
if (positionAssets[i] == borrowAddress) {
borrowNeeded = true;
break;
}
require(borrowNeeded, "Configured borrow token must be used in strategy");
}
function _afterYieldStrategyDisassemble(bytes memory) internal virtual {}
/// @notice Assembles the yield position.
/// @param _min_lpt_out Min LPT amount increase from assembling the yield position.
/// @return lpt_out LPT amount obtained from assembling the yield position.
function _yieldStrategyAssemble(uint256 _min_lpt_out) internal virtual returns (uint256) {
return yieldStrategy.assemble(_min_lpt_out);
}
/// @notice Unwinds a percentage of the yield position.
/// @param _percentage Amount to unwind expressed as percentage. 1e18 is equivalent to 100%.
/// @param _min_yield_outs Min coin amounts out of yield_strategy.
/// @return yield_outs Coin amounts out of yield_strategy.
function _yieldStrategyDisassemble(uint256 _percentage, uint256[] memory _min_yield_outs) internal virtual returns (uint256[] memory) {
return yieldStrategy.disassemble(_percentage, _min_yield_outs);
}
/// @notice Unwinds the yield position.
/// @param _min_yield_outs Min coin amounts out of yield_strategy.
/// @return yield_outs Coin amounts out of yield_strategy.
function _yieldStrategyFullDisassemble(uint256[] memory _min_yield_outs) internal virtual returns (uint256[] memory) {
return yieldStrategy.disassemble(1e18, _min_yield_outs);
}
function getBorrow() external view returns (uint256) {
return loanManager.getBorrow();
}
function getAvailableBorrow() public view returns (uint256) {
uint256 targetHealthFactor = supervisedConfig.targetHealthFactor;
uint256 healthFactor = loanManager.getHealthFactor();
if (healthFactor <= targetHealthFactor)
return 0;
uint256 maxBorrow = _maxBorrow(targetHealthFactor);
uint256 borrowed = loanManager.getBorrow();
return maxBorrow - borrowed;
}
function getRequiredRepay() public view returns (uint256) {
uint256 targetHealthFactor = supervisedConfig.targetHealthFactor;
uint256 healthFactor = loanManager.getHealthFactor();
if (healthFactor >= targetHealthFactor)
return 0;
uint256 maxBorrow = _maxBorrow(targetHealthFactor);
uint256 borrowed = loanManager.getBorrow();
return borrowed - maxBorrow;
}
function getAvailableBorrowOrRequiredRepay() external view returns (uint256 availableBorrow, uint256 requiredRepay) {
return (getAvailableBorrow(), getRequiredRepay());
}
function getAvailableWithdraw() public view returns (uint256) {
uint256 targetHealthFactor = supervisedConfig.targetHealthFactor;
uint256 healthFactor = loanManager.getHealthFactor();
if (healthFactor <= targetHealthFactor)
return 0;
uint256 minSupply = _minSupply(targetHealthFactor);
uint256 supplied = loanManager.getSupply();
return supplied - minSupply;
}
function getRequiredSupply() public view returns (uint256) {
uint256 targetHealthFactor = supervisedConfig.targetHealthFactor;
uint256 healthFactor = loanManager.getHealthFactor();
if (healthFactor >= targetHealthFactor)
return 0;
uint256 minSupply = _minSupply(targetHealthFactor);
uint256 supplied = loanManager.getSupply();
return minSupply - supplied;
}
function getAvailableWithdrawOrRequiredSupply() external view returns (uint256 availableWithdraw, uint256 requiredSupply) {
return (getAvailableWithdraw(), getRequiredSupply());
}
/// @notice Only executor. Receives the specified amount of asset from the loan manager.
/// @param _assetAddress Address of the asset being received.
/// @param _amount Amount of asset to be received.
function transferAssetsFromLoanManager(address _assetAddress, uint256 _amount) public onlyExecutor {
IERC20(_assetAddress).safeTransferFrom(address(loanManager), address(this), _amount);
}
/// @notice Only executor. Sends the specified amount of asset to the loan manager.
/// @param _assetAddress Address of the asset being sent.
/// @param _amount Amount of asset to be sent.
function transferAssetsToLoanManager(address _assetAddress, uint256 _amount) public onlyExecutor {
IERC20(_assetAddress).safeTransfer(address(loanManager), _amount);
}
/// @notice Only executor. Receives the specified amount of asset from the yield strategy.
/// @param _assetAddress Address of the asset being received.
/// @param _amount Amount of asset to be received.
function transferAssetsFromYieldStrategy(address _assetAddress, uint256 _amount) public onlyExecutor {
_beforeTransferFromYieldStrategy(_assetAddress, _amount);
IERC20(_assetAddress).safeTransferFrom(address(yieldStrategy), address(this), _amount);
}
/// @notice Only executor. Sends the specified amount of asset to the yield strategy.
/// @param _assetAddress Address of the asset being sent.
/// @param _amount Amount of asset to be sent.
function transferAssetsToYieldStrategy(address _assetAddress, uint256 _amount) public onlyExecutor {
IERC20(_assetAddress).safeTransfer(address(yieldStrategy), _amount);
_afterTransferToYieldStrategy(_assetAddress, _amount);
}
/// @notice Only executor. Supplies collateral to the loan.
/// @param _amount Amount to supply.
function supply(uint256 _amount) external onlyExecutor {
_supply(_amount);
emit Supply(_amount);
}
/// @notice Only executor. Withdraw supply from the loan.
/// @param _amount Amount to withdraw.
function withdrawSupply(uint256 _amount) external onlyExecutor {
_withdrawSupply(_amount);
}
/// @notice Only executor. Borrows from the loan.
/// @param _amount Amount to borrow.
function borrow(uint256 _amount) external onlyExecutor {
_borrow(_amount);
emit Borrow(_amount);
}
/// @notice Only executor. Repays part of the loan.
/// @param _amount Amount to repay.
function repay(uint256 _amount) external onlyExecutor {
_repay(_amount);
emit Repay(_amount);
}
/// @notice Only executor. Withdraw all available supply to reach the desired HF.
function withdrawSupplyAvailable() external onlyExecutor returns (uint256) {
return _withdrawSupplyAvailable();
}
/// @notice Only executor. Assembles a supervised loan position.
/// @param _supplyAmount Amount of token to deposit and use as collateral.
/// @param _borrowAmount Amount of token to borrow from the lending protocol.
/// @param _min_lpt_out Min lpts out.
/// @return lpt_amount Amount out of LPT token from yield_strategy.
function assemble(uint256 _supplyAmount, uint256 _borrowAmount, uint256 _min_lpt_out) external virtual onlyExecutor returns (uint256) {
return _assemble(_supplyAmount, _borrowAmount, _min_lpt_out, new bytes(0));
}
function unwind(uint _percentage, uint256[] memory _min_yield_outs) external virtual onlyExecutor returns (uint256[] memory yield_outs, uint256 amount_out) {
return _unwind(loanManager.getConfig().borrowAddress, _percentage, _min_yield_outs, new bytes(0));
}
/// @notice Only executor. Unwinds a percentage of the yield position and uses it to repay part of the loan.
/// @param _percentage Amount to unwind expressed as percentage. 1e18 is equivalent to 100%.
/// @param _min_yield_outs Min coin amounts out of yield_strategy.
/// @return yield_outs Coin amounts out of yield_strategy.
function unwindAndRepay(uint _percentage, uint256[] memory _min_yield_outs) external virtual onlyExecutor returns (uint256[] memory) {
return _unwindAndRepay(_percentage, _min_yield_outs, new bytes(0));
}
function unwindRepayAndWithdraw(uint _percentage, uint _withdraw_supply_amount, uint256[] memory _min_yield_outs) external virtual onlyExecutor returns (uint256[] memory) {
return _unwindRepayAndWithdraw(_percentage, _withdraw_supply_amount, _min_yield_outs, new bytes(0));
}
function unwindRepayAndWithdrawAvailable(uint _percentage, uint256[] memory _min_yield_outs) external virtual onlyExecutor returns (uint256[] memory) {
return _unwindRepayAndWithdrawAvailable(_percentage, _min_yield_outs, new bytes(0));
}
/// @notice Completely disassembles a supervised loan position.
/// @param _min_yield_outs Min coin amounts out of yield_strategy.
/// @return yields_out Coin amounts out of yield_strategy.
function fullDisassemble(uint256[] memory _min_yield_outs) external virtual onlyExecutor returns (uint256[] memory yields_out) {
return _fullDisassemble(_min_yield_outs, new bytes(0));
}
}
SupervisedLoanPositionManagerOwnable2StepWithShortcut.sol 9 lines
/* SPDX-License-Identifier: UNLICENSED */
pragma solidity ^0.8.0;
import './SupervisedLoanPositionManager.sol';
import '@itb/quant-common/contracts/solidity8/utils/Ownable2StepWithShortcut.sol';
contract SupervisedLoanPositionManagerOwnable2StepWithShortcut is SupervisedLoanPositionManager, Ownable2StepWithShortcut {
constructor(address[] memory _executors, address payable _wnative, ILoanManager _loanManager, IYieldStrategy _yieldStrategy, uint256 _targetHealthFactor, bool _yieldStrategyUseNativeAssets) SupervisedLoanPositionManager(_executors, _wnative, _loanManager, _yieldStrategy, _targetHealthFactor, _yieldStrategyUseNativeAssets) {}
}
Read Contract
WNATIVE 0xb381cf40 → address
balanceOf 0xf7888aec → uint256
executors 0x9ac2a011 → bool
getAvailableBorrow 0x3186a8f8 → uint256
getAvailableBorrowOrRequiredRepay 0xd897fe3a → uint256, uint256
getAvailableWithdraw 0xb64906d4 → uint256
getAvailableWithdrawOrRequiredSupply 0x5f9a2192 → uint256, uint256
getBorrow 0xee9af25d → uint256
getConfig 0xc3f909d4 → tuple
getLoanManagerConfig 0xf2812135 → tuple
getRequiredRepay 0xb82ceb45 → uint256
getRequiredSupply 0xd65ba6f3 → uint256
loanManager 0xb3ccbcfe → address
owner 0x8da5cb5b → address
pendingOwner 0xe30c3978 → address
yieldStrategy 0x13f14fee → address
Write Contract 34 functions
These functions modify contract state and require a wallet transaction to execute.
acceptOwnership 0x79ba5097
No parameters
addExecutor 0x1f5a0bbe
address _executor
approveToken 0xda3e3397
address _token
address _guy
uint256 _wad
assemble 0x52fd5ab8
uint256 _supplyAmount
uint256 _borrowAmount
uint256 _min_lpt_out
returns: uint256
batchExecute 0x077d97d7
address[] _tos
uint256[] _values
bytes[] _datas
borrow 0xc5ebeaec
uint256 _amount
execute 0xb61d27f6
address _to
uint256 _value
bytes _data
fullDisassemble 0x69276319
uint256[] _min_yield_outs
returns: uint256[]
removeExecutor 0x24788429
address _executor
renounceOwnership 0x715018a6
No parameters
repay 0x371fd8e6
uint256 _amount
revokeToken 0x3419ba23
address _token
address _guy
setConfig 0x20118aad
uint256 _targetHealthFactor
bool _yieldStrategyUseNativeAssets
supply 0x35403023
uint256 _amount
transferAssetsFromLoanManager 0x43b8f0e4
address _assetAddress
uint256 _amount
transferAssetsFromYieldStrategy 0xdebf5ecc
address _assetAddress
uint256 _amount
transferAssetsToLoanManager 0xa791d6ea
address _assetAddress
uint256 _amount
transferAssetsToYieldStrategy 0xd7d0309c
address _assetAddress
uint256 _amount
transferOwnership 0xf2fde38b
address newOwner
transferOwnership1Step 0xe1b97139
address newOwner
unwind 0x06f28501
uint256 _percentage
uint256[] _min_yield_outs
returns: uint256[], uint256
unwindAndRepay 0xd0d43327
uint256 _percentage
uint256[] _min_yield_outs
returns: uint256[]
unwindRepayAndWithdraw 0xe019cbe9
uint256 _percentage
uint256 _withdraw_supply_amount
uint256[] _min_yield_outs
returns: uint256[]
unwindRepayAndWithdrawAvailable 0x380ede2d
uint256 _percentage
uint256[] _min_yield_outs
returns: uint256[]
unwrapNative 0x34b10a6d
uint256 _amount
updateLoanManager 0xe042386c
address _address
updateYieldStrategy 0xe68b7757
address _address
withdraw 0xf3fef3a3
address _asset_address
uint256 _amount
withdrawAll 0xfa09e630
address _asset_address
withdrawAllTo 0xb6703fcd
address _asset_address
address _to
withdrawSupply 0x9504ad6d
uint256 _amount
withdrawSupplyAvailable 0x3c965dbb
No parameters
returns: uint256
withdrawTo 0xc4e2c1e6
address _asset_address
uint256 _amount
address _to
wrapNative 0x9169d833
uint256 _amount
Recent Transactions
This address has 1 on-chain transactions, but only 0.8% of the chain is indexed. Transactions will appear as indexing progresses. View on Etherscan →