Forkchoice Ethereum Mainnet

Address Contract Partially Verified

Address 0x3FaC534213b205A6F2789Dc29e15e9C024DDBB0D
Balance 0 ETH
Nonce 1
Code Size 14660 bytes
Indexed Transactions 0 (1 on-chain, 1.0% indexed)
External Etherscan · Sourcify

Contract Bytecode

14660 bytes
0x60406080815260048036101561001f575b5050361561001d57600080fd5b005b600091823560e01c91826306f2850114611fed578263077d97d714611e7957826313f14fee14611e505782631f5a0bbe14611de357826320118aad14611d3e5782632478842914611cd55782633186a8f814611cb85782633419ba2314611bee5783836334b10a6d14611b48575082633540302314611ad3578263371fd8e614611a5e578263380ede2d146119c95782633c965dbb1461197957826343b8f0e41461192a57826352fd5ab8146115e95782635f9a2192146115c657838363692763191461108e57508263715018a61461102857826379ba509714610f9a5782638da5cb5b14610f72578383639169d83314610ec6575082639504ad6d14610e765782639ac2a01114610e38578263a791d6ea14610dd3578263b381cf4014610d8f578263b3ccbcfe14610d6657838363b61d27f614610ce657508263b64906d414610cc9578263b6703fcd14610c8d578263b82ceb4514610c70578263c3f909d414610c15578263c4e2c1e614610bd3578263c5ebeaec14610b56578263d0d4332714610ae9578263d65ba6f314610acc57838363d7d0309c146109d257508263d897fe3a146109a3578263da3e339714610787578263debf5ecc14610690578263e019cbe9146105cb578263e042386c14610550578263e30c397814610527578263e68b7757146104af578263ee9af25d1461041e578263f28121351461036357508163f2fde38b146102f6578163f3fef3a3146102c7578163f7888aec1461028e575063fa09e630146102545780610010565b3461028b57602036600319011261028b576102886102706122f7565b61027861284b565b61028181613141565b339161315d565b80f35b80fd5b9050346102c357806003193601126102c3576020906102bc6102ae6122f7565b6102b661230d565b906127df565b9051908152f35b5080fd5b9050346102c35736600319011261028b576102886102e36122f7565b6102eb61284b565b33906024359061315d565b823461028b57602036600319011261028b576103106122f7565b61031861284b565b600180546001600160a01b0319166001600160a01b0392831690811790915582549091167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e227008380a380f35b91503461041a578260031936011261041a578281805161038281612193565b82815260208101839052015260035481516330fe427560e21b81526001600160a01b039390916060918391829087165afa90811561041057908291606095916103e3575b508151938082511685526020820151166020850152015190820152f35b6104039150853d8711610409575b6103fb81836121c9565b810190612392565b386103c6565b503d6103f1565b82513d86823e3d90fd5b8280fd5b8382346102c357816003193601126102c357600354815163ee9af25d60e01b81529360209185919082906001600160a01b03165afa9182156104a4579161046a575b6020925051908152f35b90506020823d60201161049c575b81610485602093836121c9565b81010312610497576020915190610460565b600080fd5b3d9150610478565b9051903d90823e3d90fd5b91503461041a57602036600319011261041a576001600160a01b0382358181169290839003610523577fbb8ae84f77396c61f3771bf6ff158e748b500aa24f69c0ab9cf6730c5a7312739061050261284b565b84549281519084168152846020820152a16001600160a01b03191617905580f35b8480fd5b8382346102c357816003193601126102c35760015490516001600160a01b039091168152602090f35b9091503461041a57602036600319011261041a576001600160a01b03903581811692908390036105c7577ff6de81a7def6ff2d3b03e6036f52c547b9073772cfbcab0b96ef94580b6f73b6906105a461284b565b6003549281519084168152846020820152a16001600160a01b0319161760035580f35b8380fd5b9091503461041a57606036600319011261041a576044356001600160401b0381116105c75791610657610677926106277fe8787cca738efc7ab80ec15b44031f5f90e9e089d0fc90c1bdf553a60dce5509969536908301612201565b9060018060a01b038654163314801561067b575b61064490612323565b858451610650816121ae565b52356133a8565b90610663602435612e00565b5193838594a1602083526020830190612293565b0390f35b5033865260026020528386205460ff1661063b565b91503461041a578060031936011261041a576106aa6122f7565b8354602435926001600160a01b0391869190831633148015610772575b6106d090612323565b60ff6006541680610745575b6106f3575b50508061028894541690309216612d94565b8286541690813b1561041a578280926024835180958193639169d83360e01b83528b8d8401525af190811561073c5750156106e15761073190612180565b6105235784386106e1565b513d84823e3d90fd5b50827f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc216838516146106dc565b5033825260026020528082205460ff166106c7565b9091503461041a57606036600319011261041a576107a36122f7565b6107ab61230d565b92604435926107b861284b565b8484156108fa5750815163095ea7b360e01b60208083018281526001600160a01b03898116602486015260448086018a90528552939487851694909290916000906108046064896121c9565b87519082885af16000513d826108de575b505015610860575b50505050509061085a6000805160206138ef83398151915293925b516001600160a01b039586168152602081019390935293169281906040820190565b0390a280f35b855192602084015288166024830152600060448301526044825260808201908282106001600160401b038311176108c957509284926108b96108be9361085a966000805160206138ef8339815191529a999852826136ce565b6136ce565b91929338808061081d565b604190634e487b7160e01b6000525260246000fd5b9091506108f25750833b15155b3880610815565b6001146108eb565b825163095ea7b360e01b81526001600160a01b03909116918101918252602082810186905292949392909182908190604001038160006001600160a01b0387165af1801561099857610960575b5061085a6000805160206138ef83398151915293610838565b6020813d602011610990575b81610979602093836121c9565b810103126104975751801515036104975738610947565b3d915061096c565b84513d6000823e3d90fd5b50823461028b578060031936011261028b57506109be6124c0565b6109c661268b565b82519182526020820152f35b92509034610ac85780600319360112610ac8576109ed6122f7565b835460243593916001600160a01b0391829190821633148015610ab3575b610a1490612323565b16610a23858385541683612f00565b60ff600654169081610a87575b50610a39578480f35b81541692833b15610523576024859283855196879485936334b10a6d60e01b85528401525af190811561073c5750610a73575b8080808480f35b610a7c90612180565b61028b578038610a6c565b9050817f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2161438610a30565b5033875260026020528487205460ff16610a0b565b5050fd5b8382346102c357816003193601126102c3576020906102bc612736565b8382346102c357610b2e61067792610b0036612261565b9160018060a01b0381541633148015610b41575b610b1d90612323565b8451610b28816121ae565b526133a8565b9051918291602083526020830190612293565b5033815260026020528481205460ff16610b14565b9091503461041a57602036600319011261041a5782547fb848ae6b1253b6cb77e81464128ce8bd94d3d524fea54e801e0da869784dca339260209235916001600160a01b031633148015610bbf575b610bae90612323565b610bb7826132b6565b51908152a180f35b50338552600283528085205460ff16610ba5565b833461028b57606036600319011261028b57610bed6122f7565b6044356001600160a01b03811681036104975761028891610c0c61284b565b6024359061315d565b50823461028b578060031936011261028b5760208251610c348161214f565b82815201528051610c448161214f565b600554815260ff6006541615156020820152610c6e82518092602080918051845201511515910152565bf35b8382346102c357816003193601126102c3576020906102bc61268b565b8382346102c35736600319011261028b57610288610ca96122f7565b610cb161230d565b90610cba61284b565b610cc381613141565b9061315d565b8382346102c357816003193601126102c3576020906102bc6125b0565b91925060603660031901126102c357610cfd6122f7565b604435936001600160401b03928386116105235736602387011215610523578501359283116105c75736602484870101116105c75761028894838594602493610d4461284b565b5193849301833781018481520391602435905af1610d606123f7565b90612436565b8382346102c357816003193601126102c35760035490516001600160a01b039091168152602090f35b8382346102c357816003193601126102c357517f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b03168152602090f35b8382346102c357806003193601126102c35761028890610df16122f7565b83546001600160a01b0392610e129184163314908115610e22575b50612323565b6024359180600354169116612f00565b60ff915033875260026020528620541686610e0c565b8382346102c35760203660031901126102c35760209160ff9082906001600160a01b03610e636122f7565b1681526002855220541690519015158152f35b9091503461041a57602036600319011261041a57610eaa6102889260018060a01b038554163314908115610eb05750612323565b35612e00565b60ff915033865260026020528520541638610e0c565b92509034610ac8576020366003190112610ac85782546001600160a01b0390811633148015610f5d575b610ef990612323565b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc216803b15610f58578390825193848092630d0e30db60e41b82528235905af190811561073c5750610f485750f35b610f5190612180565b61028b5780f35b505050fd5b5033845260026020528184205460ff16610ef0565b8382346102c357816003193601126102c357905490516001600160a01b039091168152602090f35b91503461041a578260031936011261041a57600154916001600160a01b039133838516036110115750506bffffffffffffffffffffffff60a01b8092166001556000549133908316176000553391167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a380f35b60249250519063118cdaa760e01b82523390820152fd5b833461028b578060031936011261028b5761104161284b565b600180546001600160a01b0319908116909155600080549182168155906001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a380f35b92509034610ac85760209182600319360112610f585780356001600160401b038111610523576110c19036908301612201565b908461112460018060a01b039384835416331480156115b2575b6110e490612323565b8286516110f0816121ae565b52848454169086519889809481936207a9a360ea1b8352670de0b6b3a7640000898401528a60248401526044830190612293565b03925af19485156115a8578695611584575b50600380548451636c9c2faf60e01b808252929391851687828481845afa91821561157a578a9261154b575b50865163ee9af25d60e01b815288818581855afa9081156114d45784929189918d91611515575b5090606093947f5640f49f00c8bd81403744e20c54a689d610cce204d6f415546a4e7a73f715e79282519182528c820152a187516330fe427560e21b815293849182905afa9182156113be5789926114f4575b506111e56135a1565b868201926112208a878651166112168b8b6111ff846134ed565b94338d825416149283156114de575b505050612323565b8888541690612f00565b8960c087875416848a5180948193632bc5c95360e11b83525af180156114d4578b8c91611496575b611252925061249d565b908686541690885190815289818581855afa90811561148c578c9161145f575b508210156113e65750899086865416803b1561041a57828091858b5180948193633e8eb9b760e21b83525af180156113dc579083916113c8575b50508686541692833b1561041a57602490838a519586948593639504ad6d60e01b85528401525af180156113be576113a6575b5091849391611323610677979899945b84815116856113028187541680936127df565b925116903387895416148015611392575b61131c90612323565b3091612d94565b611335838083511693541680936127df565b9384611351575b50505050505051928284938452830190612293565b611372958461131c9351169433908354161491821561137d575b5050612323565b80388080808061133c565b60ff925033815260028b52205416863861136b565b5033885260028c528888205460ff16611313565b6113b08991612180565b6113ba57386112df565b8780fd5b86513d8b823e3d90fd5b6113d190612180565b6102c35781386112ac565b89513d85823e3d90fd5b88999a969594989150869288518094819363254b344d60e11b83525af1801561145557908891611424575b50509061067795611323869594936112ef565b8195949392953d831161144e575b61143c81836121c9565b81010312610497579091928638611411565b503d611432565b86513d87823e3d90fd5b90508981813d8311611485575b61147681836121c9565b81010312610497575138611272565b503d61146c565b89513d8e823e3d90fd5b505060c0813d60c0116114cc575b816114b160c093836121c9565b810103126114c85780519089015161125291611248565b8a80fd5b3d91506114a4565b88513d8d823e3d90fd5b60ff9350600290338352522054168b8f8e61120e565b61150e91925060603d606011610409576103fb81836121c9565b90386111dc565b935050508882813d8311611544575b61152e81836121c9565b8101031261049757905183919088906060611189565b503d611524565b9091508781813d8311611573575b61156381836121c9565b8101031261049757519038611162565b503d611559565b87513d8c823e3d90fd5b6115a19195503d8088833e61159981836121c9565b810190613528565b9338611136565b83513d88823e3d90fd5b50338352600287528583205460ff166110db565b50823461028b578060031936011261028b57506115e16125b0565b6109c6612736565b91503461041a57606036600319011261041a57813591602491816024359360018060a01b038088541633148015611915575b61162490612323565b878451611630816121ae565b5286611907575b856118f9575b606081600354168551948580926330fe427560e21b82525afa9283156118ef5788936118ce575b5080602080940151169661167661372a565b9789988a5b81518110156118bf5782856116908385612dec565b51161461169f5760010161167b565b505050909192939495965060015b15611863576116ba61372a565b90885b82518110156117bf5789846116d28386612dec565b51166116e9866116e28588612dec565b51166134ed565b9033878454161480156117ab575b61170090612323565b61170e82888d541683612f00565b60ff60065416908161177f575b5061172b575b50506001016116bd565b858a541690813b1561041a578290888c838d5195869485936334b10a6d60e01b85528401525af1801561177557156117215761176690612180565b611771578938611721565b8980fd5b89513d84823e3d90fd5b9050867f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc216143861171b565b50338352600289528983205460ff166116f7565b858a8881838c60248f7f928e86394a65ffcbb1a1f7330d2968e88d0ba215f3dfc5ea62125552067657d5868b8e93825191825287820152a1825416918551948593849263735373d160e11b8452604435908401525af19283156118585792611829575b5051908152f35b9091508281813d8311611851575b61184181836121c9565b8101031261049757519083611822565b503d611837565b8251903d90823e3d90fd5b845162461bcd60e51b8152808701859052603060248201527f436f6e6669677572656420626f72726f7720746f6b656e206d7573742062652060448201526f7573656420696e20737472617465677960801b6064820152608490fd5b505050909192939495966116ad565b6118e891935060603d606011610409576103fb81836121c9565b9138611664565b84513d8a823e3d90fd5b611902866132b6565b61163d565b61191087612b54565b611637565b5033885260026020528388205460ff1661161b565b8382346102c357806003193601126102c357610288906119486122f7565b83546001600160a01b03926119689184163314908115610e225750612323565b816003541660243592309216612d94565b8382346102c357816003193601126102c3576119ac6020928260018060a01b0382541633149182156119b4575050612323565b6102bc612d77565b60ff925033815260028652205416828561136b565b8382346102c357906106777fe8787cca738efc7ab80ec15b44031f5f90e9e089d0fc90c1bdf553a60dce550992611a2b611a0236612261565b9060018060a01b0386541633148015611a49575b611a1f90612323565b858451610b28816121ae565b90611a34612d77565b505193838594a1602083526020830190612293565b5033865260026020528386205460ff16611a16565b9091503461041a57602036600319011261041a5782547fa6ffc78a660e4971a47a0f916a0abae483804e6f42c9292ed06aa64f8fe462309260209235916001600160a01b031633148015611abf575b611ab690612323565b610bb782612c29565b50338552600283528085205460ff16611aad565b9091503461041a57602036600319011261041a5782547f1862f918d5600ec0980589e8cc806b3c79b1e762fcbf44cc2947ba12499207eb9260209235916001600160a01b031633148015611b34575b611b2b90612323565b610bb782612b54565b50338552600283528085205460ff16611b22565b925034610ac8576020366003190112610ac85782546001600160a01b0390811633148015611bd9575b611b7a90612323565b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc216803b15610f58576024849284519586938492632e1a7d4d60e01b84528035908401525af190811561073c5750611bd0575080f35b61028890612180565b5033845260026020528284205460ff16611b71565b9091503461041a578160031936011261041a57611c096122f7565b91611c1261230d565b611c1a61284b565b815163095ea7b360e01b81526001600160a01b039182169381018490526024810186905293169260208160448188885af18015611cae57611c76575b506000805160206138ef833981519152918151908152846020820152a280f35b6020813d602011611ca6575b81611c8f602093836121c9565b810103126105235751801515036105c75738611c56565b3d9150611c82565b82513d87823e3d90fd5b8382346102c357816003193601126102c3576020906102bc6124c0565b8382346102c35760203660031901126102c357611cf06122f7565b611cf861284b565b60018060a01b0316807f9fdbc2d48b8a0db2f62663bf9312ad02f5b1f6414ad600b55a247d09aeec3ea260208451868152a2825260026020528120805460ff1916905580f35b9091503461041a578160031936011261041a576024358015158091036105c75760ff91611d6961284b565b835190611d758261214f565b358152602081019182527f601bd64f1b6034521a7ad828eb0da8578cd3bbe802a4594825a03ba55b98d82b608085516005548152611dce6006549787891615156020840152820185602080918051845201511515910152565ba151600555511515169060ff19161760065580f35b8382346102c35760203660031901126102c357611dfe6122f7565b611e0661284b565b60018060a01b0316807f9fdbc2d48b8a0db2f62663bf9312ad02f5b1f6414ad600b55a247d09aeec3ea26020845160018152a2825260026020528120805460ff1916600117905580f35b9091503461041a578260031936011261041a575490516001600160a01b03909116815260209150f35b909150606036600319011261041a576001600160401b03813581811161052357611ea690369084016122c7565b90936024916024358481116113ba57611ec290369087016122c7565b93909560443586811161177157611edc90369083016122c7565b959093611ee761284b565b81811480611fe4575b15611fa1578a5b818110611f02578b80f35b611f0d81838d6123d1565b35906001600160a01b0382168203611f9d57611f2a81858d6123d1565b3589821015611f8b578d8260051b890135601e198a3603018112156102c3578901938435948d861161041a5760200190853603821361041a5785611f859484936001988f519384928337810185815203925af1610d606123f7565b01611ef7565b634e487b7160e01b8e5260328652868efd5b8c80fd5b855162461bcd60e51b8152602081850152601960248201527f417267756d656e7473206c656e677468206d69736d61746368000000000000006044820152606490fd5b50868114611ef0565b9091503461041a57611ffe36612261565b84546001600160a01b039391869185163314801561213a575b61202090612323565b82606086600354168851958680926330fe427560e21b82525afa80156121305760208791612095968691612111575b5001511694838851612060816121ae565b528361206b876134ed565b97835416928951968795869485936207a9a360ea1b85528401528b60248401526044830190612293565b03925af19485156121065780956120e0575b5050906120be6120c3926120b96135a1565b6134ed565b61249d565b6120d68251938385948552840190612293565b9060208301520390f35b6120c3939295506120be916120fe913d8091833e61159981836121c9565b9491926120a7565b8451903d90823e3d90fd5b61212a915060603d606011610409576103fb81836121c9565b3861204f565b87513d85823e3d90fd5b5033825260026020528582205460ff16612017565b604081019081106001600160401b0382111761216a57604052565b634e487b7160e01b600052604160045260246000fd5b6001600160401b03811161216a57604052565b606081019081106001600160401b0382111761216a57604052565b602081019081106001600160401b0382111761216a57604052565b90601f801991011681019081106001600160401b0382111761216a57604052565b6001600160401b03811161216a5760051b60200190565b9080601f8301121561049757602090823561221b816121ea565b9361222960405195866121c9565b81855260208086019260051b82010192831161049757602001905b828210612252575050505090565b81358152908301908301612244565b9060406003198301126104975760043591602435906001600160401b0382116104975761229091600401612201565b90565b90815180825260208080930193019160005b8281106122b3575050505090565b8351855293810193928101926001016122a5565b9181601f84011215610497578235916001600160401b038311610497576020808501948460051b01011161049757565b600435906001600160a01b038216820361049757565b602435906001600160a01b038216820361049757565b1561232a57565b60405162461bcd60e51b815260206004820152602660248201527f45786563757461626c653a2063616c6c6572206973206e6f742074686520657860448201526532b1baba37b960d11b6064820152608490fd5b51906001600160a01b038216820361049757565b908160609103126104975760408051916123ab83612193565b6123b48161237e565b83526123c26020820161237e565b60208401520151604082015290565b91908110156123e15760051b0190565b634e487b7160e01b600052603260045260246000fd5b3d15612431573d906001600160401b03821161216a5760405191612425601f8201601f1916602001846121c9565b82523d6000602084013e565b606090565b1561243e5750565b6040519062461bcd60e51b82528160208060048301528251908160248401526000935b828510612484575050604492506000838284010152601f80199101168101030190fd5b8481018201518686016044015293810193859350612461565b919082039182116124aa57565b634e487b7160e01b600052601160045260246000fd5b60055460035460405163a5f352b760e01b81526020916001600160a01b0316908281600481855afa801561256b57849160009161257f575b501115612577578161250b6004946128ea565b916040519485809263ee9af25d60e01b82525afa91821561256b57600092612539575b50612290925061249d565b90915082813d8311612564575b61255081836121c9565b81010312610497576122909151903861252e565b503d612546565b6040513d6000823e3d90fd5b505050600090565b809250848092503d83116125a9575b61259881836121c9565b8101031261049757839051386124f8565b503d61258e565b60055460035460405163a5f352b760e01b81526001600160a01b03909116906020908181600481865afa801561256b57849160009161265a575b50111561257757806125fd600494612f3c565b9260405194858092636c9c2faf60e01b82525afa90811561256b5760009161262a5750612290925061249d565b905082813d8311612653575b61264081836121c9565b810103126104975761229091513861252e565b503d612636565b809250838092503d8311612684575b61267381836121c9565b8101031261049757839051386125ea565b503d612669565b60055460035460405163a5f352b760e01b81526001600160a01b03909116906020908181600481865afa801561256b578491600091612705575b50101561257757806126d86004946128ea565b926040519485809263ee9af25d60e01b82525afa90811561256b5760009161262a5750612290925061249d565b809250838092503d831161272f575b61271e81836121c9565b8101031261049757839051386126c5565b503d612714565b60055460035460405163a5f352b760e01b81526020916001600160a01b0316908281600481855afa801561256b5784916000916127ae575b5010156125775781612781600494612f3c565b9160405194858092636c9c2faf60e01b82525afa91821561256b576000926125395750612290925061249d565b809250848092503d83116127d8575b6127c781836121c9565b81010312610497578390513861276e565b503d6127bd565b6040516370a0823160e01b81526001600160a01b0392831660048201529160209183916024918391165afa90811561256b5760009161281c575090565b90506020813d602011612843575b81612837602093836121c9565b81010312610497575190565b3d915061282a565b6000546001600160a01b0316330361285f57565b60405163118cdaa760e01b8152336004820152602490fd5b90816020910312610497575160ff811681036104975790565b60ff16604d81116124aa57600a0a90565b9190826040910312610497576020825192015190565b818102929181159184041417156124aa57565b81156128d4570490565b634e487b7160e01b600052601260045260246000fd5b60035460408051636c9c2faf60e01b81529093926001600160a01b03929091906004908416602080848481855afa938415612a7757600094612b25575b508315612b195787516330fe427560e21b81529188906060848681845afa938415612b0e57600094612aed575b50878451169782518481888163313ce56760e01b9d8e82525afa80156109985761298691600091612ac0575b50612890565b9884828188015116918886518094819382525afa8015610998576129b191600091612ac05750612890565b94518351631ee1b90b60e21b81529116868201528381602481855afa938415612ab557600094612a82575b5050815163bd9a548b60e01b815294859182905afa928315612a775791612a2893916122909899612a33979694600091600095612a39575b505090612a28612a2892612a2d95966128b7565b6128b7565b946128b7565b906128ca565b612a2d9550612a28939250612a289181612a6792903d10612a70575b612a5f81836121c9565b8101906128a1565b95509192612a14565b503d612a55565b88513d6000823e3d90fd5b809294508193503d8311612aae575b612a9b81836121c9565b81010312610497578890519138806129dc565b503d612a91565b83513d6000823e3d90fd5b612ae09150863d8811612ae6575b612ad881836121c9565b810190612877565b38612980565b503d612ace565b612b0791945060603d606011610409576103fb81836121c9565b9238612954565b82513d6000823e3d90fd5b50600096505050505050565b9080945081813d8311612b4d575b612b3d81836121c9565b8101031261049757519238612927565b503d612b33565b6003546040516330fe427560e21b81526001600160a01b03918216606082600481845afa90811561256b57838592612bad94600091612c0a575b505116846000541633148015612bf1575b612ba890612323565b612f00565b6003541690813b1561049757600091602483926040519485938492633540302360e01b845260048401525af1801561256b57612be65750565b612bef90612180565b565b503360009081526002602052604090205460ff16612b9f565b612c23915060603d606011610409576103fb81836121c9565b38612b8e565b600354604080516330fe427560e21b815290916001600160a01b039190821690606081600481855afa90811561099857600091612d58575b50826020809201511690845163ee9af25d60e01b81528181600481875afa908115612d4d57600091612d20575b50808711612d16575b50918591612cb89385600054163314908115612cfc575b50612ba890612323565b6003541691823b15610497576000926024849284519586938492631b8fec7360e11b845260048401525af1908115612cf25750612be65750565b513d6000823e3d90fd5b600291503360005252612ba860ff87600020541690612cae565b9550612cb8612c97565b90508181813d8311612d46575b612d3781836121c9565b81010312610497575138612c8e565b503d612d2d565b86513d6000823e3d90fd5b612d71915060603d606011610409576103fb81836121c9565b38612c61565b612d7f6125b0565b8015612d8e5761229081612e00565b50600090565b6040516323b872dd60e01b60208201526001600160a01b03928316602482015292909116604483015260648083019390935291815260a08101918183106001600160401b0384111761216a57612bef926040526136ce565b80518210156123e15760209160051b010190565b6003546001600160a01b03908116906000823b1561028b5780806040946024865180948193639504ad6d60e01b83528a60048401525af18015612ef657612ee7575b5081600354169083516330fe427560e21b8152606081600481865afa908115612edd5793859361131c84602098848b99967f28f1c27f506f0a8d8cf21ad670fb93d0a296e8f069f12f0a2a6331ed81039f869c97612eb79991612ebe575b50511694825416331491821561137d575050612323565b51908152a1565b612ed7915060603d606011610409576103fb81836121c9565b38612ea0565b85513d84823e3d90fd5b612ef090612180565b38612e42565b84513d84823e3d90fd5b60405163a9059cbb60e01b60208201526001600160a01b03929092166024830152604480830193909352918152612bef916108b96064836121c9565b6003546040805163ee9af25d60e01b81529093926001600160a01b039283169260209291600484848281895afa938415612a7757600094613112575b508315612b195787516330fe427560e21b81529588906060888481845afa978815612b0e576000986130f1575b50848851169482518881868163313ce56760e01b9a8b82525afa801561099857612fd6916000916130da5750612890565b958882818c015116918686518094819382525afa801561099857613001916000916130da5750612890565b98518351631ee1b90b60e21b81529116848201528781602481855afa978815612ab5576000986130a7575b5050815163bd9a548b60e01b815292839182905afa908115612a775792612a33959492612290989992612a289560009460009261307757505090612a28612a2892612a2d95966128b7565b612a2d9550612a28939250612a28918161309c92903d10612a7057612a5f81836121c9565b909592935091612a14565b809298508193503d83116130d3575b6130c081836121c9565b810103126104975788905195388061302c565b503d6130b6565b612ae091508a3d8c11612ae657612ad881836121c9565b61310b91985060603d606011610409576103fb81836121c9565b9638612fa5565b9093508481813d831161313a575b61312a81836121c9565b8101031261049757519238612f78565b503d613120565b6001600160a01b03811661315457504790565b612290906134ed565b90916001600160a01b0390811691821561327f578361317b82613141565b106132455716918261321157600080808084865af16131986123f7565b50156131cc5760207f9207361cc2a04b9c7a06691df1eb87c6a63957ae88bf01d0d18c81e3d1272099915b604051908152a3565b60405162461bcd60e51b815260206004820152601760248201527f4e6174697665207472616e73666572206661696c65642e0000000000000000006044820152606490fd5b6020816132407f9207361cc2a04b9c7a06691df1eb87c6a63957ae88bf01d0d18c81e3d1272099938587612f00565b6131c3565b60405162461bcd60e51b8152602060048201526012602482015271496e73756666696369656e742066756e647360701b6044820152606490fd5b60405162461bcd60e51b815260206004820152600f60248201526e496e76616c6964206164647265737360881b6044820152606490fd5b60035460009291906001600160a01b039084908216803b156102c357819060246040518094819363317afabb60e21b83528860048401525af1801561339d5761338a575b5080600354166040516330fe427560e21b8152606081600481855afa90811561337f579583602061131c93612bef98998491613360575b500151169381541633149081156133485750612323565b60ff9150604090338152600260205220541638610e0c565b613379915060603d606011610409576103fb81836121c9565b38613331565b6040513d88823e3d90fd5b61339690949194612180565b92386132fa565b6040513d87823e3d90fd5b91909160018060a01b03806003541691600460606040948551928380926330fe427560e21b82525afa9081156109985795836020600093613426989985916134ce575b50015116926133f9846134ed565b9460045416908387518099819582946207a9a360ea1b845260048401528a60248401526044830190612293565b03925af1938415612ab557600094613480575b509161346e6020926120be7f0bb6e019230e47211b08e219cc7dcfec394e152ecfd86b07dc0b0d4683b44912956120b96135a1565b9061347882612c29565b51908152a190565b7f0bb6e019230e47211b08e219cc7dcfec394e152ecfd86b07dc0b0d4683b44912939194506020926120be6134c261346e933d806000833e61159981836121c9565b96939550509250613439565b6134e7915060603d606011610409576103fb81836121c9565b386133eb565b6040516370a0823160e01b815230600482015290602090829060249082906001600160a01b03165afa90811561256b5760009161281c575090565b6020908181840312610497578051906001600160401b03821161049757019180601f8401121561049757825161355d816121ea565b9361356b60405195866121c9565b818552838086019260051b820101928311610497578301905b828210613592575050505090565b81518152908301908301613584565b6135a961372a565b9060005b82518110156136c9576001600160a01b03806135c98386612dec565b5116906135e1816135da8588612dec565b511661387f565b913382600054161480156136b0575b6135f990612323565b60ff6006541680613685575b613625575b9161361f916001949330916004541690612d94565b016135ad565b60048281541690813b156104975760008560246040938385519687948593639169d83360e01b85528401525af1908115612cf257509161361f93916001969593613676575b5091939450915061360a565b61367f90612180565b3861366a565b50817f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2168114613605565b503360009081526002602052604090205460ff166135f0565b509050565b906000602091828151910182855af11561256b576000513d61372157506001600160a01b0381163b155b6136ff5750565b604051635274afe760e01b81526001600160a01b039091166004820152602490fd5b600114156136f8565b6004805460405163087ed83760e01b81526000939290916001600160a01b03918591849190829085165afa9182156138745784926137d2575b50819360ff6006541661377557505050565b82518110156137cd57808261378c60019386612dec565b51161561379a575b01613775565b827f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2166137c78286612dec565b52613794565b505050565b9091503d8085833e6137e481836121c9565b810190602090818184031261386c578051906001600160401b03821161387057019180601f8401121561386c57825161381c816121ea565b9361382a60405195866121c9565b818552838086019260051b8201019283116113ba578301905b82821061385557505050509038613763565b8380916138618461237e565b815201910190613843565b8580fd5b8680fd5b6040513d86823e3d90fd5b60ff60065416806138b8575b6138a757600454612290916001600160a01b03909116906127df565b506004546001600160a01b03163190565b506001600160a01b038181167f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc29091161461388b56feeded619173dbb378903f97d44ecec898a1c4876f445ae551e063113aef58b471a2646970667358221220d07574cbf60e4143913fd35971e91e8503f26e9dbad65bafd69de39217d556f464736f6c63430008160033

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 accross 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);
}
Withdrawable.sol 96 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));
    }
}

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 33 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
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 1.0% of the chain is indexed. Transactions will appear as indexing progresses. View on Etherscan →