Cryo Explorer Ethereum Mainnet

Address Contract Verified

Address 0x267dF6b637DdCaa7763d94b64eBe09F01b07cB36
Balance 0 ETH
Nonce 1
Code Size 21233 bytes
Indexed Transactions 0
External Etherscan · Sourcify

Contract Bytecode

21233 bytes
0x60806040526004361015610011575f80fd5b5f5f3560e01c8062f714ce1461425757806306fdde031461410e5780630956e5a6146140d3578063095ea7b3146140265780630e84563414613fd557806316efd94114613f8457806318160ddd14613f495780631c30e68214613d4657806323b872dd14613bb25780632859398414613b5a5780632e8ebaae14613b145780632ed6b75d14613ac35780632f278fe81461389b5780633066bb271461384a578063313ce5671461375f57806333a100ca1461353957806339b70e38146134e7578063465fc5d2146134955780634956eaf0146130c15780634f5e80851461306f5780634f908e7f14612e7457806357c44f8e14612c5357806358e7544014612b6057806359746aab146128eb5780635c966646146127ca5780635d83f0931461278e5780635e1816551461264f57806361d027b3146125fd57806370a082311461259b57806375efcf77146124a257806378e808d5146124505780637a801f53146123fe5780637b9282b01461231857806382beee891461225a57806389fe02cb146122215780638c05b4721461202a578063958da91814611fc757806395d89b4114611e65578063999927df14611c5557806399f428cf146116ec5780639aefaff8146113fa578063a25db8ce146113b8578063a9059cbb14611368578063aec48f5014611251578063afa92945146111f8578063b6b55f2514610e83578063c0cbbca614610bfc578063c7c4ff4614610baa578063d211fd1814610b6e578063d574ea3d14610b00578063d8b5138a146109df578063dd62ed3e14610966578063e322ad2b14610925578063e357e92e14610740578063edf1d2b3146105d9578063f0f442601461048e578063f2c098b7146103a1578063f905c15a14610365578063fbe85f061461031e5763fc0c546a146102ad575f80fd5b3461031b57807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261031b57602060405173ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec7168152f35b80fd5b503461031b5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261031b57602060043561035b614d99565b1015604051908152f35b503461031b57807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261031b576020600554604051908152f35b503461031b5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261031b576103d9614890565b73ffffffffffffffffffffffffffffffffffffffff60085416330361046657602073ffffffffffffffffffffffffffffffffffffffff7ff112f2fd3f9db4cbbd348d7d8948ad19988985c74b787d6f0fb8f62ba25f9e0e9216807fffffffffffffffffffffffff0000000000000000000000000000000000000000600e541617600e55604051908152a180f35b6004827f980bf844000000000000000000000000000000000000000000000000000000008152fd5b503461031b5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261031b576104c6614890565b73ffffffffffffffffffffffffffffffffffffffff600a5416908133036105b15773ffffffffffffffffffffffffffffffffffffffff1690811561058957600b80547fffffffffffffffffffffffff0000000000000000000000000000000000000000811684179091556040805173ffffffffffffffffffffffffffffffffffffffff938416815291851690931790911660208201527f74826a97c225ebfc6ae4d01aa55f9846d00bb141717acca3947f3778534be5a191819081015b0390a180f35b6004837fed2a1062000000000000000000000000000000000000000000000000000000008152fd5b6004837f6b7bc451000000000000000000000000000000000000000000000000000000008152fd5b503461031b57807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261031b5773ffffffffffffffffffffffffffffffffffffffff600854163314158061071e575b6106f657600b5473ffffffffffffffffffffffffffffffffffffffff8116801561058957600a54918173ffffffffffffffffffffffffffffffffffffffff8416146106ce577fffffffffffffffffffffffff00000000000000000000000000000000000000008084168317600a5516600b556040519183161781527f1f54d231bb9d500b1923e4a1cb25e600f366a8368873d9af7c1c623814df19fc90602090a180f35b6004847f281a0b0a000000000000000000000000000000000000000000000000000000008152fd5b807f7fa76e940000000000000000000000000000000000000000000000000000000060049252fd5b5073ffffffffffffffffffffffffffffffffffffffff6006541633141561062a565b503461031b5760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261031b57610778614890565b60243591610784614fba565b73ffffffffffffffffffffffffffffffffffffffff6006541633036108fd576107ac82614a3a565b156108d557604051917fcb27acfd0000000000000000000000000000000000000000000000000000000083528360048401526020836024818573ffffffffffffffffffffffffffffffffffffffff86165af19283156108ca578293610891575b506040805133815273ffffffffffffffffffffffffffffffffffffffff909216602083810191909152908201949094527fb093bd21cacddf175c466449524962624f8edabfc8497212c45b6ce70c90bfe29080606081015b0390a17f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f005d604051908152f35b9092506020813d6020116108c2575b816108ad6020938361493b565b810103126108be575191602061080c565b5f80fd5b3d91506108a0565b6040513d84823e3d90fd5b807fe83f2cde0000000000000000000000000000000000000000000000000000000060049252fd5b807fbbab12130000000000000000000000000000000000000000000000000000000060049252fd5b503461031b57807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261031b57602061095e614d99565b604051908152f35b503461031b5760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261031b5773ffffffffffffffffffffffffffffffffffffffff60406109b5614890565b92826109bf61486d565b9416815260016020522091165f52602052602060405f2054604051908152f35b503461031b5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261031b57610a17614890565b73ffffffffffffffffffffffffffffffffffffffff6006541690813303610ad85773ffffffffffffffffffffffffffffffffffffffff1690811561058957600780547fffffffffffffffffffffffff0000000000000000000000000000000000000000811684179091556040805173ffffffffffffffffffffffffffffffffffffffff938416815291851690931790911660208201527f9199036abbe383a5a535e02e8f65421079bb3fa71d03495a107b8b0231b616f29181908101610583565b6004837fbbab1213000000000000000000000000000000000000000000000000000000008152fd5b503461031b5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261031b576004359060105482101561031b57602073ffffffffffffffffffffffffffffffffffffffff610b5e846148f6565b90549060031b1c16604051908152f35b503461031b57807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261031b576020600254604051908152f35b503461031b57807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261031b57602073ffffffffffffffffffffffffffffffffffffffff600e5416604051908152f35b503461031b5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261031b5760043573ffffffffffffffffffffffffffffffffffffffff6008541633036104665760105480821015610e5b5773ffffffffffffffffffffffffffffffffffffffff610c77836148f6565b90549060031b1c169182845260116020526040842054610e33577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8201918211610e0657818103610da1575b50506010548015610d74577f206dcdb9e6d573bb19797ecdc31f426bc49808caf16879b86cee1ba682e3881f917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6105839201610d1f816148f6565b73ffffffffffffffffffffffffffffffffffffffff82549160031b1b19169055601055604051918291338390929173ffffffffffffffffffffffffffffffffffffffff60209181604085019616845216910152565b6024837f4e487b710000000000000000000000000000000000000000000000000000000081526031600452fd5b610dd373ffffffffffffffffffffffffffffffffffffffff610dc5610dff946148f6565b90549060031b1c16916148f6565b90919073ffffffffffffffffffffffffffffffffffffffff8084549260031b9316831b921b1916179055565b5f80610cc3565b6024847f4e487b710000000000000000000000000000000000000000000000000000000081526011600452fd5b6004847fe83f2cde000000000000000000000000000000000000000000000000000000008152fd5b6004837f5979b5d3000000000000000000000000000000000000000000000000000000008152fd5b503461031b5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261031b57600435610ebe614fba565b73ffffffffffffffffffffffffffffffffffffffff600d5416331415806111d6575b6111ae578015611186578173ffffffffffffffffffffffffffffffffffffffff600f5416806110cb575b505073ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec7166040517f23b872dd00000000000000000000000000000000000000000000000000000000845233600452306024528260445260208460648180865af19060018551148216156110aa575b604052836060521561107f575033156110535761102a81610fd17fe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c93600254614aa0565b600255335f525f60205260405f208181540190556040518181525f7fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60203393a360408051338152602081019290925290918291820190565b0390a1807f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f005d80f35b6024827fec442f0500000000000000000000000000000000000000000000000000000000815280600452fd5b7f5274afe7000000000000000000000000000000000000000000000000000000008352600452602482fd5b9060018115166110c257823b15153d15161690610f8d565b503d84823e3d90fd5b6110d3614b0a565b90803b15611182576040517fa69fe8630000000000000000000000000000000000000000000000000000000081527f000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec773ffffffffffffffffffffffffffffffffffffffff16600482015260248101859052604481019290925290919081908390606490829084905af1611167575b90610f0a565b6111709161493b565b815f1261117e575f82611161565b5080fd5b8280fd5b6004827f8dc3160f000000000000000000000000000000000000000000000000000000008152fd5b6004827f52644c18000000000000000000000000000000000000000000000000000000008152fd5b5073ffffffffffffffffffffffffffffffffffffffff600e5416331415610ee0565b503461031b5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261031b5760209060043590611237614d99565b90508181111561124a5750604051908152f35b905061095e565b503461031b57807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261031b5773ffffffffffffffffffffffffffffffffffffffff600a541633141580611346575b6106f65760095473ffffffffffffffffffffffffffffffffffffffff8116801561058957600854918173ffffffffffffffffffffffffffffffffffffffff8416146106ce577fffffffffffffffffffffffff00000000000000000000000000000000000000008084168317600855166009556040519183161781527f1d71beb956329ce4bda4b6a3cf409eae37dca995fe985253f39c49f5dd3bf3c790602090a180f35b5073ffffffffffffffffffffffffffffffffffffffff600654163314156112a2565b503461031b5760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261031b576113ad6113a3614890565b60243590336151c5565b602060405160018152f35b503461031b5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261031b57602061095e6113f5614890565b614c75565b503461031b5760807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261031b57611432614890565b61143a61486d565b906064359167ffffffffffffffff83116116e857366023840112156116e857826004013567ffffffffffffffff81116116e45736602482860101116116e45773ffffffffffffffffffffffffffffffffffffffff60065416331415806116c2575b61169a576114a883614a3a565b15611672579173ffffffffffffffffffffffffffffffffffffffff85816084602497957fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f89869a6040519c8d9b8c9a8b977fb61d27f6000000000000000000000000000000000000000000000000000000008952166004880152604435828801526060604488015282606488015201868601378685828601015201168101030193165af19182156116665780918193611582575b505061157e604051928392151583526040602084015260408301906148b3565b0390f35b915091503d8083833e611595818361493b565b81019160408284031261031b576115ab826149a9565b9160208101519067ffffffffffffffff8211611182570183601f8201121561117e5780519067ffffffffffffffff8211611639576040519461161560207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f860116018761493b565b8286526020838301011161118257908060208093018387015e840101525f8061155e565b6024837f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b604051903d90823e3d90fd5b6004857fe83f2cde000000000000000000000000000000000000000000000000000000008152fd5b6004857f7158b7f3000000000000000000000000000000000000000000000000000000008152fd5b5073ffffffffffffffffffffffffffffffffffffffff600c541633141561149b565b8480fd5b8380fd5b503461031b5760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261031b5760043561172761486d565b90611730614fba565b73ffffffffffffffffffffffffffffffffffffffff600d541633141580611c33575b611c0b578273ffffffffffffffffffffffffffffffffffffffff600f541680611af5575b5050809160105490826117e7575b505081611790916149d3565b906111865761102a817fe66f2a5f859e75187ec8381862cf2edc4124d6ea89f5fa1a7b66035121bd4461926117d8575b60408051338152602081019290925290918291820190565b6117e2813361502e565b6117c0565b91849391935b84811080611aec575b15611add57856024602073ffffffffffffffffffffffffffffffffffffffff61181e856148f6565b90549060031b1c16604051928380927f70a082310000000000000000000000000000000000000000000000000000000082523060048301525afa9081156108ca578291611aa9575b5080156118e25784811115611aa45750835b602073ffffffffffffffffffffffffffffffffffffffff611898856148f6565b90549060031b1c166024604051809581937f1071a2900000000000000000000000000000000000000000000000000000000083528660048401525af1889281611a71575b506118f2575b50506118ed90614a0d565b6117ed565b81156118e257829473ffffffffffffffffffffffffffffffffffffffff61191c61198f94956148f6565b90549060031b1c168952601160205260408920548083115f14611a6a575b73ffffffffffffffffffffffffffffffffffffffff611958886148f6565b90549060031b1c168a52601160205260408a206119768282546149d3565b90556005549081811115611a59575050886005556149d3565b926004602073ffffffffffffffffffffffffffffffffffffffff6119b2846148f6565b90549060031b1c16604051928380927f5037b7e90000000000000000000000000000000000000000000000000000000082525afa928315611a4e578673ffffffffffffffffffffffffffffffffffffffff6118ed95611a19948c91611a20575b5016615104565b905f6118e2565b611a41915060203d8111611a47575b611a39818361493b565b810190614aad565b5f611a12565b503d611a2f565b6040513d8a823e3d90fd5b611a62916149d3565b6005556149d3565b508161193a565b9092506020813d8211611a9c575b81611a8c6020938361493b565b810103126108be5751915f6118dc565b3d9150611a7f565b611878565b9150506020813d8211611ad5575b81611ac46020938361493b565b810103126108be578690515f611866565b3d9150611ab7565b50819350611790925091611784565b508215156117f6565b611b80604091611b03614b0a565b83519485809481937f0f3482f4000000000000000000000000000000000000000000000000000000008352897f000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec76004850160409194939273ffffffffffffffffffffffffffffffffffffffff606083019616825260208201520152565b03925af1908185918693611bd8575b50611b9d575b849150611776565b15611ba85780611b95565b83906044927f1bbc0205000000000000000000000000000000000000000000000000000000008352600452602452fd5b909250611bfd915060403d604011611c04575b611bf5818361493b565b8101906149b6565b915f611b8f565b503d611beb565b6004837f52644c18000000000000000000000000000000000000000000000000000000008152fd5b5073ffffffffffffffffffffffffffffffffffffffff600e5416331415611752565b503461031b5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261031b57611c8d614890565b9073ffffffffffffffffffffffffffffffffffffffff6006541633141580611e43575b611e1b57611cbd82614a3a565b156108d557602073ffffffffffffffffffffffffffffffffffffffff92602484600a54168460405196879485937f999927df0000000000000000000000000000000000000000000000000000000085526004850152165af1918215611e0e578192611dda575b508115611db2576020827ff3055bc8d92d9c8d2f12b45d112dd345cd2cfd17292b8d65c5642ac6f912dfd760405180611da7847f000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec7338473ffffffffffffffffffffffffffffffffffffffff6040929594938160608401971683521660208201520152565b0390a1604051908152f35b807f524b3c6c0000000000000000000000000000000000000000000000000000000060049252fd5b9091506020813d602011611e06575b81611df66020938361493b565b810103126108be5751905f611d23565b3d9150611de9565b50604051903d90823e3d90fd5b807f7158b7f30000000000000000000000000000000000000000000000000000000060049252fd5b5073ffffffffffffffffffffffffffffffffffffffff600c5416331415611cb0565b503461031b57807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261031b576040519080600454908160011c91600181168015611fbd575b602084108114611f9057838652908115611f4b5750600114611eee575b61157e84611eda8186038261493b565b6040519182916020835260208301906148b3565b600481527f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b939250905b808210611f3157509091508101602001611eda82611eca565b919260018160209254838588010152019101909291611f18565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660208087019190915292151560051b85019092019250611eda9150839050611eca565b6024837f4e487b710000000000000000000000000000000000000000000000000000000081526022600452fd5b92607f1692611ead565b503461031b5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261031b57604060209173ffffffffffffffffffffffffffffffffffffffff612019614890565b168152601183522054604051908152f35b503461031b57807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261031b57612061614fba565b73ffffffffffffffffffffffffffffffffffffffff60065416331415806121ff575b611e1b577f000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec773ffffffffffffffffffffffffffffffffffffffff8116906040517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152602081602481865afa9081156121f45784916121c2575b50600254908181111561219a5792602094926121437fe33b3f29026207fc167007711d41e9edd78750b0051defa03f1e4ea002accd6a93612166966149d3565b9485809373ffffffffffffffffffffffffffffffffffffffff600a541690615104565b6040805133815273ffffffffffffffffffffffffffffffffffffffff90921660208301528101919091528060608101610864565b6004857f524b3c6c000000000000000000000000000000000000000000000000000000008152fd5b90506020813d6020116121ec575b816121dd6020938361493b565b810103126108be57515f612103565b3d91506121d0565b6040513d86823e3d90fd5b5073ffffffffffffffffffffffffffffffffffffffff600c5416331415612083565b503461031b57807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261031b57602061095e614b0a565b503461031b5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261031b57612292614890565b73ffffffffffffffffffffffffffffffffffffffff6008541633036104665773ffffffffffffffffffffffffffffffffffffffff16807fffffffffffffffffffffffff0000000000000000000000000000000000000000600f541617600f557f576d39e65c913b7fedc16b28e8563e891fb6d44bcf0c1c29495375595cd79b658280a280f35b503461031b57807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261031b57604051907f70a0823100000000000000000000000000000000000000000000000000000000825230600483015260208260248173ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec7165afa90811561166657906123cb575b602090604051908152f35b506020813d6020116123f6575b816123e56020938361493b565b810103126108be57602090516123c0565b3d91506123d8565b503461031b57807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261031b57602073ffffffffffffffffffffffffffffffffffffffff60075416604051908152f35b503461031b57807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261031b57602073ffffffffffffffffffffffffffffffffffffffff60065416604051908152f35b503461031b5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261031b576124da614890565b73ffffffffffffffffffffffffffffffffffffffff6006541690813303610ad85773ffffffffffffffffffffffffffffffffffffffff1690811561058957600c80547fffffffffffffffffffffffff0000000000000000000000000000000000000000811684179091556040805173ffffffffffffffffffffffffffffffffffffffff938416815291851690931790911660208201527f68d1aa5e9bdbf0db52fe140cc136ad3a30d9010e7d2f048eaf1ab0dad87c59759181908101610583565b503461031b5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261031b57604060209173ffffffffffffffffffffffffffffffffffffffff6125ed614890565b1681528083522054604051908152f35b503461031b57807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261031b57602073ffffffffffffffffffffffffffffffffffffffff600a5416604051908152f35b503461031b57807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261031b5773ffffffffffffffffffffffffffffffffffffffff600a54163314158061276c575b6127445760075473ffffffffffffffffffffffffffffffffffffffff8116801561058957600654918173ffffffffffffffffffffffffffffffffffffffff8416146106ce577fffffffffffffffffffffffff00000000000000000000000000000000000000008084168317600655166007556040519183161781527f6c6266c4ca096dc11256cb3c5a2f481d4ebfc848b647e04ba395e5e02cde9a1d90602090a180f35b807f7acfd5970000000000000000000000000000000000000000000000000000000060049252fd5b5073ffffffffffffffffffffffffffffffffffffffff600854163314156126a0565b503461031b57807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261031b576020601354604051908152f35b503461031b5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261031b57612802614890565b73ffffffffffffffffffffffffffffffffffffffff60085416908133036128c35773ffffffffffffffffffffffffffffffffffffffff1690811561058957600980547fffffffffffffffffffffffff0000000000000000000000000000000000000000811684179091556040805173ffffffffffffffffffffffffffffffffffffffff938416815291851690931790911660208201527f229906f503462bb4f822a3a5c8a143331ba9ca0b25dd7de323cf57b842eb0c849181908101610583565b6004837f980bf844000000000000000000000000000000000000000000000000000000008152fd5b503461031b5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261031b5760043567ffffffffffffffff811161117e573660238201121561117e5780600401359067ffffffffffffffff8211611182576024810190602436918460051b0101116111825773ffffffffffffffffffffffffffffffffffffffff6008541633036128c357601054808303612ae357835b818110612a5d5750835b818110612a1f575050604051918060208401602085525260408301919084905b8082106129e757857faaeeacfd3dbf7ee886e6df5ff129be2537f1886a93f3a104d6bba8b305fc52b186860387a180f35b90919283359073ffffffffffffffffffffffffffffffffffffffff82168092036108be576020816001938293520194019201906129b6565b80612a5773ffffffffffffffffffffffffffffffffffffffff612a4d612a486001958989614ad9565b614ae9565b16610dd3836148f6565b01612996565b612a73612a6e612a48838787614ad9565b614a3a565b15612b385760018101808211612b0b575b828110612a94575060010161298c565b612aa8612a48838787969997989598614ad9565b73ffffffffffffffffffffffffffffffffffffffff80612acc612a48858789614ad9565b16911614612ae35760010194919294939093612a84565b6004847f7804bc35000000000000000000000000000000000000000000000000000000008152fd5b6024867f4e487b710000000000000000000000000000000000000000000000000000000081526011600452fd5b6004857f7804bc35000000000000000000000000000000000000000000000000000000008152fd5b503461031b5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261031b57612b98614890565b73ffffffffffffffffffffffffffffffffffffffff6008541633036104665773ffffffffffffffffffffffffffffffffffffffff168015612c2b576020817fcac43e3f2c27e1b165ed9d6100079705fcc1d17d86c9588a65b3b21af19efb55927fffffffffffffffffffffffff0000000000000000000000000000000000000000600d541617600d55604051908152a180f35b6004827fed2a1062000000000000000000000000000000000000000000000000000000008152fd5b503461031b5760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261031b57612c8b614890565b612c93614fba565b73ffffffffffffffffffffffffffffffffffffffff600654163303612e4c57612cbb81614a3a565b15612e245773ffffffffffffffffffffffffffffffffffffffff8116604051917f2e1a7d4d000000000000000000000000000000000000000000000000000000008352602435600484015260208360248187865af19182156121f4578492612dd0575b808552601160205260408520547f77a629eef1a2b0e39a9b09a71ddafbded84fb873712d56f5b2f6b1e1706e266b945080841115612dc857905b8552601160205260408520612d6e8282546149d3565b90556005549081811115612db7575050836005555b6040805133815273ffffffffffffffffffffffffffffffffffffffff9092166020830152810191909152806060810161102a565b612dc0916149d3565b600555612d83565b508290612d58565b91506020833d602011612e1c575b81612deb6020938361493b565b810103126108be577f77a629eef1a2b0e39a9b09a71ddafbded84fb873712d56f5b2f6b1e1706e266b925191612d1e565b3d9150612dde565b6004827fe83f2cde000000000000000000000000000000000000000000000000000000008152fd5b6004827fbbab1213000000000000000000000000000000000000000000000000000000008152fd5b503461031b57807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261031b5773ffffffffffffffffffffffffffffffffffffffff600a541633036106f65773ffffffffffffffffffffffffffffffffffffffff601254168015612c2b57601354421061304757601054680100000000000000008110156116395790610dd3826001612f1294016010556148f6565b6008546012546040805173ffffffffffffffffffffffffffffffffffffffff93841681529290911660208301819052839290917f5196e6e427329801067f2d2174593bfbda5a246c506762f55fc401ee6084845e91a1803b15613044578180916024604051809581937f422570800000000000000000000000000000000000000000000000000000000083523060048401525af161302d575b601280547fffffffffffffffffffffffff000000000000000000000000000000000000000016905560138190556008546040805173ffffffffffffffffffffffffffffffffffffffff928316815291831660208301527ffdcf3907978ffc608fc7f27e245c3d5d995700556bdc27685b2182a48b9b7e72919081908101610583565b6130369161493b565b805f1261031b575f81612fab565b50fd5b6004827fc2c1a34c000000000000000000000000000000000000000000000000000000008152fd5b503461031b57807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261031b57602073ffffffffffffffffffffffffffffffffffffffff600d5416604051908152f35b503461031b5760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261031b576130f9614890565b602435613104614fba565b73ffffffffffffffffffffffffffffffffffffffff600654163303610ad85761312c82614a3a565b1561346d5773ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec716916040517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152602081602481875afa8015613462578391869161342d575b501061340557604051927f095ea7b3000000000000000000000000000000000000000000000000000000005f5273ffffffffffffffffffffffffffffffffffffffff821693846004528360245260205f60448180865af19060015f51148216156133f6575b604052156132f6575b50823b156116e857836040517fb6b55f25000000000000000000000000000000000000000000000000000000008152836004820152818160248183895af180156108ca576132de575b50927fb03c53b28e78a88e31607a27e1fa48234dce28d5d9d9ec7b295aeb02e674a1e1935260116020526040842061329d838254614aa0565b90556132ab82600554614aa0565b6005556040805173ffffffffffffffffffffffffffffffffffffffff90921682526020820192909252908190810161102a565b906132e89161493b565b835f126116e857835f613264565b6040517f095ea7b3000000000000000000000000000000000000000000000000000000005f52846004525f60245260205f60448180865af19060015f51148216156133de575b60405215613392576040517f095ea7b3000000000000000000000000000000000000000000000000000000005f52846004528360245260205f60448180865af19060015f51148216156133bd575b60405261321b575b7f5274afe7000000000000000000000000000000000000000000000000000000008552600452602484fd5b9060018115166133d557823b15153d1516169061338a565b503d5f823e3d90fd5b9060018115166133d557823b15153d1516169061333c565b90823b15153d15161690613212565b6004847f8dc3160f000000000000000000000000000000000000000000000000000000008152fd5b9150506020813d60201161345a575b816134496020938361493b565b810103126108be578290515f6131ad565b3d915061343c565b6040513d87823e3d90fd5b6004837fe83f2cde000000000000000000000000000000000000000000000000000000008152fd5b503461031b57807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261031b57602073ffffffffffffffffffffffffffffffffffffffff60125416604051908152f35b503461031b57807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261031b57602073ffffffffffffffffffffffffffffffffffffffff60085416604051908152f35b346108be5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126108be57613570614890565b73ffffffffffffffffffffffffffffffffffffffff60085416908133036137375773ffffffffffffffffffffffffffffffffffffffff811690811561370f576135b890614a3a565b8015613665575b61363d57601280547fffffffffffffffffffffffff00000000000000000000000000000000000000001682179055426013556040805173ffffffffffffffffffffffffffffffffffffffff93841681529290911660208301527ffdcf3907978ffc608fc7f27e245c3d5d995700556bdc27685b2182a48b9b7e7291a1005b7fe83f2cde000000000000000000000000000000000000000000000000000000005f5260045ffd5b506040517ffc0c546a000000000000000000000000000000000000000000000000000000008152602081600481855afa908115613704575f916136e5575b5073ffffffffffffffffffffffffffffffffffffffff807f000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec716911614156135bf565b6136fe915060203d602011611a4757611a39818361493b565b836136a3565b6040513d5f823e3d90fd5b7fed2a1062000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f980bf844000000000000000000000000000000000000000000000000000000005f5260045ffd5b346108be575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126108be576040517f313ce56700000000000000000000000000000000000000000000000000000000815260208160048173ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec7165afa8015613704575f9061380d575b60209060ff60405191168152f35b506020813d602011613842575b816138276020938361493b565b810103126108be575160ff811681036108be576020906137ff565b3d915061381a565b346108be575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126108be57602073ffffffffffffffffffffffffffffffffffffffff600c5416604051908152f35b346108be575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126108be5773ffffffffffffffffffffffffffffffffffffffff6006541633141580613aa1575b613a79575f60105473ffffffffffffffffffffffffffffffffffffffff600a5416905f915b8183106139c35783801561399b576020907ff3055bc8d92d9c8d2f12b45d112dd345cd2cfd17292b8d65c5642ac6f912dfd760405180611da7847f000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec7338473ffffffffffffffffffffffffffffffffffffffff6040929594938160608401971683521660208201520152565b7f524b3c6c000000000000000000000000000000000000000000000000000000005f5260045ffd5b9091925f602073ffffffffffffffffffffffffffffffffffffffff6139e7876148f6565b90549060031b1c166024604051809481937f999927df0000000000000000000000000000000000000000000000000000000083528860048401525af1908115613704575f91613a47575b50613a3e90600192614aa0565b93019190613910565b90506020813d8211613a71575b81613a616020938361493b565b810103126108be57516001613a31565b3d9150613a54565b7f7158b7f3000000000000000000000000000000000000000000000000000000005f5260045ffd5b5073ffffffffffffffffffffffffffffffffffffffff600c54163314156138eb565b346108be575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126108be57602073ffffffffffffffffffffffffffffffffffffffff600b5416604051908152f35b346108be5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126108be576020613b50612a6e614890565b6040519015158152f35b346108be575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126108be57613b90614b0a565b6002549081811115613ba85760209161095e916149d3565b505060205f61095e565b346108be5760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126108be57613be9614890565b613bf161486d565b6044359073ffffffffffffffffffffffffffffffffffffffff831692835f52600160205260405f2073ffffffffffffffffffffffffffffffffffffffff33165f5260205260405f20547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8110613c6d575b506113ad93506151c5565b838110613d12578415613ce6573315613cba576113ad945f52600160205260405f2073ffffffffffffffffffffffffffffffffffffffff33165f526020528360405f209103905584613c62565b7f94280d62000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b7fe602df05000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b83907ffb8f41b2000000000000000000000000000000000000000000000000000000005f523360045260245260445260645ffd5b346108be5760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126108be57613d7d614890565b613d85614fba565b73ffffffffffffffffffffffffffffffffffffffff600654163303613f2157613dad81614a3a565b1561363d5773ffffffffffffffffffffffffffffffffffffffff811690604051907fcdbb2fb400000000000000000000000000000000000000000000000000000000825260243560048301526020826024815f875af1918215613704575f92613eec575b50817f77a629eef1a2b0e39a9b09a71ddafbded84fb873712d56f5b2f6b1e1706e266b91846020955f526011865260405f20548084115f14613ee457905b5f526011865260405f20613e648282546149d3565b90556005549081811115613ed35750505f6005555b6040805133815273ffffffffffffffffffffffffffffffffffffffff929092166020830152810191909152606090a15f7f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f005d604051908152f35b613edc916149d3565b600555613e79565b508290613e4f565b9091506020813d602011613f19575b81613f086020938361493b565b810103126108be5751906020613e11565b3d9150613efb565b7fbbab1213000000000000000000000000000000000000000000000000000000005f5260045ffd5b346108be575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126108be576020600254604051908152f35b346108be575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126108be57602073ffffffffffffffffffffffffffffffffffffffff600f5416604051908152f35b346108be575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126108be57602073ffffffffffffffffffffffffffffffffffffffff60095416604051908152f35b346108be5760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126108be5761405d614890565b602435903315613ce65773ffffffffffffffffffffffffffffffffffffffff16908115613cba57335f52600160205260405f20825f526020528060405f20556040519081527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560203392a3602060405160018152f35b346108be575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126108be576020601054604051908152f35b346108be575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126108be576040515f6003548060011c9060018116801561424d575b602083108114614220578285529081156141de5750600114614180575b61157e83611eda8185038261493b565b91905060035f527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b915f905b8082106141c457509091508101602001611eda614170565b9192600181602092548385880101520191019092916141ac565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660208086019190915291151560051b84019091019150611eda9050614170565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b91607f1691614153565b346108be5760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126108be5760043561429161486d565b9061429a614fba565b73ffffffffffffffffffffffffffffffffffffffff600d54163314158061484b575b6148235773ffffffffffffffffffffffffffffffffffffffff600f54168061479c575b50809173ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec716906040517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152602081602481865afa908115613704575f9161476a575b5080614743575b50601054925f5b8481108061473a575b15614669576024602073ffffffffffffffffffffffffffffffffffffffff61439b846148f6565b90549060031b1c16604051928380927f70a082310000000000000000000000000000000000000000000000000000000082523060048301525afa5f9181614636575b506143f157506143ec90614a0d565b61436b565b80156144e757602073ffffffffffffffffffffffffffffffffffffffff614417846148f6565b90549060031b1c16916024604051809481937fafa9294500000000000000000000000000000000000000000000000000000000835260048301525afa5f9181614603575b5061446a57506143ec90614a0d565b80156144e757868111156145fa57505f6020875b602473ffffffffffffffffffffffffffffffffffffffff61449e866148f6565b90549060031b1c169160405194859384927f2e1a7d4d00000000000000000000000000000000000000000000000000000000845260048401525af15f91816145c7575b506144f1575b506143ec90614a0d565b80156144e757909573ffffffffffffffffffffffffffffffffffffffff614517886148f6565b90549060031b1c165f52601160205260405f20548083115f146145c0575b73ffffffffffffffffffffffffffffffffffffffff614553896148f6565b90549060031b1c165f52601160205260405f206145718282546149d3565b905560055490818111156145af5750505f6005555b8082111561459c5750506143ec5f955b906144e7565b6143ec916145a9916149d3565b95614596565b6145b8916149d3565b600555614586565b5081614535565b9091506020813d82116145f2575b816145e26020938361493b565b810103126108be575190886144e1565b3d91506145d5565b60205f9161447e565b9091506020813d821161462e575b8161461e6020938361493b565b810103126108be5751908861445b565b3d9150614611565b9091506020813d8211614661575b816146516020938361493b565b810103126108be575190886143dd565b3d9150614644565b506146758580926149d3565b90614712577f884edad9ce6fa2440d8a54cc123490eb96d2768479d49ff9c7366125a942436492816146ca9381151580614703575b6146f2575b50506040805133815260208101939093529192839283019150565b0390a15f7f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f005d005b6146fb92615104565b8381816146af565b61470d833361502e565b6146aa565b7f8dc3160f000000000000000000000000000000000000000000000000000000005f5260045ffd5b50851515614374565b90935082811115614761575061475a825b836149d3565b9284614364565b61475a90614754565b90506020813d602011614794575b816147856020938361493b565b810103126108be57518561435d565b3d9150614778565b60406147ab5f92611b03614b0a565b03925af190815f915f93614800575b506147c6575b506142df565b156147d157806147c0565b907f1bbc0205000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b90925061481c915060403d604011611c0457611bf5818361493b565b91856147ba565b7f52644c18000000000000000000000000000000000000000000000000000000005f5260045ffd5b5073ffffffffffffffffffffffffffffffffffffffff600e54163314156142bc565b6024359073ffffffffffffffffffffffffffffffffffffffff821682036108be57565b6004359073ffffffffffffffffffffffffffffffffffffffff821682036108be57565b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f602080948051918291828752018686015e5f8582860101520116010190565b60105481101561490e5760105f5260205f2001905f90565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff82111761497c57604052565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b519081151582036108be57565b91908260409103126108be5760206149cd836149a9565b92015190565b919082039182116149e057565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81146149e05760010190565b601054905f5b828110614a4e575050505f90565b73ffffffffffffffffffffffffffffffffffffffff614a6c826148f6565b90549060031b1c1673ffffffffffffffffffffffffffffffffffffffff831614614a9857600101614a40565b505050600190565b919082018092116149e057565b908160209103126108be575173ffffffffffffffffffffffffffffffffffffffff811681036108be5790565b919081101561490e5760051b0190565b3573ffffffffffffffffffffffffffffffffffffffff811681036108be5790565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015260208160248173ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec7165afa908115613704575f91614c43575b50906010545f905b808210614b96575050565b90926004602073ffffffffffffffffffffffffffffffffffffffff614bba876148f6565b90549060031b1c16604051928380927f89fe02cb0000000000000000000000000000000000000000000000000000000082525afa908115613704575f91614c11575b50614c0990600192614aa0565b930190614b8b565b90506020813d8211614c3b575b81614c2b6020938361493b565b810103126108be57516001614bfc565b3d9150614c1e565b90506020813d602011614c6d575b81614c5e6020938361493b565b810103126108be57515f614b83565b3d9150614c51565b614c7e81614a3a565b15614d945773ffffffffffffffffffffffffffffffffffffffff166040517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152602081602481855afa5f9181614d60575b50614ce15750505f90565b6020906024604051809481937fafa9294500000000000000000000000000000000000000000000000000000000835260048301525afa5f9181614d2c575b50614d2957505f90565b90565b9091506020813d602011614d58575b81614d486020938361493b565b810103126108be5751905f614d1f565b3d9150614d3b565b9091506020813d602011614d8c575b81614d7c6020938361493b565b810103126108be5751905f614cd6565b3d9150614d6f565b505f90565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015260208160248173ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec7165afa908115613704575f91614f88575b50906010545f5b818110614e24575050565b6024602073ffffffffffffffffffffffffffffffffffffffff614e46846148f6565b90549060031b1c16604051928380927f70a082310000000000000000000000000000000000000000000000000000000082523060048301525afa5f9181614f55575b50614f5057505f5b80614e9f575b50600101614e19565b602073ffffffffffffffffffffffffffffffffffffffff614ebf846148f6565b90549060031b1c16916024604051809481937fafa9294500000000000000000000000000000000000000000000000000000000835260048301525afa5f9181614f1d575b5015614e9657614f169060019295614aa0565b9390614e96565b9091506020813d8211614f48575b81614f386020938361493b565b810103126108be5751905f614f03565b3d9150614f2b565b614e90565b9091506020813d8211614f80575b81614f706020938361493b565b810103126108be5751905f614e88565b3d9150614f63565b90506020813d602011614fb2575b81614fa36020938361493b565b810103126108be57515f614e12565b3d9150614f96565b7f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f005c6150065760017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f005d565b7f3ee5aeb5000000000000000000000000000000000000000000000000000000005f5260045ffd5b90919073ffffffffffffffffffffffffffffffffffffffff1680156150d857805f525f60205260405f20548381106150a5576020845f94957fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef938587528684520360408620558060025403600255604051908152a3565b91507fe450d38c000000000000000000000000000000000000000000000000000000005f5260045260245260445260645ffd5b7f96c6fd1e000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b9173ffffffffffffffffffffffffffffffffffffffff604051927fa9059cbb000000000000000000000000000000000000000000000000000000005f521660045260245260205f60448180865af19060015f51148216156151ad575b6040521561516b5750565b73ffffffffffffffffffffffffffffffffffffffff907f5274afe7000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b9060018115166133d557823b15153d15161690615160565b73ffffffffffffffffffffffffffffffffffffffff169081156150d85773ffffffffffffffffffffffffffffffffffffffff1691821561528f57815f525f60205260405f205481811061525d57817fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef92602092855f525f84520360405f2055845f525f825260405f20818154019055604051908152a3565b827fe450d38c000000000000000000000000000000000000000000000000000000005f5260045260245260445260645ffd5b7fec442f05000000000000000000000000000000000000000000000000000000005f525f60045260245ffdfea26469706673582212202b2f502bd8af25582f02c831c71eeffe0cd4319de27ac1eaf3ca6c7d2bf3857b64736f6c634300081e0033

Verified Source Code Full Match

Compiler: v0.8.30+commit.73712a01 EVM: cancun Optimization: Yes (999999 runs)
ftYieldWrapper.sol 745 lines
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.30;

import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import {
    IERC20Metadata,
    IERC20
} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {ReentrancyGuardTransient} from "@openzeppelin/contracts/utils/ReentrancyGuardTransient.sol";
import {IStrategy, IStrategyWithQueue} from "./interfaces/IStrategy.sol";
import {IftYieldWrapper} from "./interfaces/IftYieldWrapper.sol";
import {ICircuitBreaker} from "./interfaces/ICircuitBreaker.sol";

// Single asset per chain wrapper
contract ftYieldWrapper is IftYieldWrapper, ERC20, ReentrancyGuardTransient {
    using SafeERC20 for IERC20;
    using SafeERC20 for IERC20Metadata;

    uint256 public deployed; // default to 0

    address public immutable token;

    address public yieldClaimer;
    address public pendingYieldClaimer;
    address public strategyManager;
    address public pendingStrategyManager;
    address public treasury;
    address public pendingTreasury;
    address public subYieldClaimer;
    address public putManager;
    address public depositor;
    address public circuitBreaker;

    IStrategy[] public strategies;
    mapping(address strategy => uint256 deployed) public deployedToStrategy;

    // must be submitted by strategyManager
    address public pendingStrategy;
    uint256 public delayStrategy;
    uint256 internal constant DELAY = 0; // 1 days in production

    event Deployed(address strategy, uint256 allocation);
    event YieldClaimed(address yieldClaimer, address token, uint256 amount);
    event Deposit(address owner, uint256 amount);
    event Withdraw(address owner, uint256 amount);
    event WithdrawUnderlying(address owner, uint256 amount);
    event QueuedToWrapper(address strategyManager, address strategy, uint256 amount);
    event WithdrawToWrapper(address strategyManager, address strategy, uint256 amount);

    event PendingYieldClaimer(address yieldClaimer, address pendingYieldClaimer);
    event PendingStrategyManager(address strategyManager, address pendingStrategyManager);
    event PendingTreasury(address treasury, address pendingTreasuy);
    event PendingStrategy(address strategyManager, address pendingStrategy);

    event UpdateYieldClaimer(address newYieldClaimer);
    event UpdateStrategyManager(address newStrategyManager);
    event UpdateTreasury(address newTreasury);
    event UpdateSubYieldClaimer(address yieldClaimer, address subYieldClaimer);
    event UpdatePutManager(address newPutManager);
    event UpdateDepositor(address newDepositor);

    event AddedStrategy(address strategyManager, address strategy);
    event RemovedStrategy(address strategyManager, address strategy);
    event StrategiesReordered(address[] newOrder);
    event YieldSwept(address caller, address token, uint256 amount);
    event CircuitBreakerUpdated(address indexed newCircuitBreaker);

    error ftYieldWrapperInsufficientLiquidity();
    error ftYieldWrapperNotYieldClaimer();
    error ftYieldWrapperNotYieldClaimers();
    error ftYieldWrapperDelayNotExpired();
    error ftYieldWrapperNotStrategyManager();
    error ftYieldWrapperZeroAddress();
    error ftYieldWrapperNotSetter();
    error ftYieldWrapperNotConfirmer();
    error ftYieldWrapperNotYieldClaimConfirmer();
    error ftYieldWrapperSettingUnchanged();
    error ftYieldWrapperNotStrategy();
    error ftYieldWrapperNoYield();
    error ftYieldWrapperInvalidStrategyIndex();
    error ftYieldWrapperInvalidStrategiesOrder();
    error ftYieldWrapperNotPutManagerOrDepositor();
    error ftYieldWrapperRateLimitExceeded(uint256 requested, uint256 available);

    modifier onlyYieldClaimer() {
        if (msg.sender != yieldClaimer) revert ftYieldWrapperNotYieldClaimer();
        _;
    }

    modifier onlyStrategyManager() {
        if (msg.sender != strategyManager) {
            revert ftYieldWrapperNotStrategyManager();
        }
        _;
    }

    modifier onlyYieldClaimers() {
        if (msg.sender != yieldClaimer && msg.sender != subYieldClaimer) {
            revert ftYieldWrapperNotYieldClaimers();
        }
        _;
    }

    modifier onlyPutManagerOrDepositor() {
        if (msg.sender != putManager && msg.sender != depositor) {
            revert ftYieldWrapperNotPutManagerOrDepositor();
        }
        _;
    }

    constructor(
        address _token,
        address _yieldClaimer,
        address _strategyManager,
        address _treasury
    )
        ERC20(
            string.concat("Flying Tulip ", IERC20Metadata(_token).name()),
            string.concat("ft", IERC20Metadata(_token).symbol())
        )
    {
        if (_token == address(0x0)) revert ftYieldWrapperZeroAddress();
        if (_yieldClaimer == address(0x0)) revert ftYieldWrapperZeroAddress();
        if (_strategyManager == address(0x0)) {
            revert ftYieldWrapperZeroAddress();
        }
        if (_treasury == address(0x0)) revert ftYieldWrapperZeroAddress();

        token = _token;
        yieldClaimer = _yieldClaimer;
        strategyManager = _strategyManager;
        treasury = _treasury;
        // putManager defaults to 0x0
        // depositor defaults to 0x0

        emit Transfer(address(0x0), address(this), 0);
    }

    function setYieldClaimer(address _yieldClaimer) external onlyYieldClaimer {
        if (_yieldClaimer == address(0x0)) revert ftYieldWrapperZeroAddress();
        pendingYieldClaimer = _yieldClaimer;
        emit PendingYieldClaimer(yieldClaimer, pendingYieldClaimer);
    }

    function setSubYieldClaimer(address _subYieldClaimer) external onlyYieldClaimer {
        if (_subYieldClaimer == address(0x0)) {
            revert ftYieldWrapperZeroAddress();
        }
        subYieldClaimer = _subYieldClaimer;
        emit UpdateSubYieldClaimer(yieldClaimer, subYieldClaimer);
    }

    function confirmYieldClaimer() external {
        if (msg.sender != treasury && msg.sender != strategyManager) {
            revert ftYieldWrapperNotYieldClaimConfirmer();
        }
        if (pendingYieldClaimer == address(0x0)) {
            revert ftYieldWrapperZeroAddress();
        }
        if (yieldClaimer == pendingYieldClaimer) {
            revert ftYieldWrapperSettingUnchanged();
        }
        yieldClaimer = pendingYieldClaimer;
        pendingYieldClaimer = address(0x0);
        emit UpdateYieldClaimer(yieldClaimer);
    }

    function setStrategyManager(address _strategyManager) external onlyStrategyManager {
        if (_strategyManager == address(0x0)) {
            revert ftYieldWrapperZeroAddress();
        }
        pendingStrategyManager = _strategyManager;
        emit PendingStrategyManager(strategyManager, pendingStrategyManager);
    }

    function confirmStrategyManager() external {
        if (msg.sender != treasury && msg.sender != yieldClaimer) {
            revert ftYieldWrapperNotConfirmer();
        }
        if (pendingStrategyManager == address(0x0)) {
            revert ftYieldWrapperZeroAddress();
        }
        if (strategyManager == pendingStrategyManager) {
            revert ftYieldWrapperSettingUnchanged();
        }
        strategyManager = pendingStrategyManager;
        pendingStrategyManager = address(0x0);
        emit UpdateStrategyManager(strategyManager);
    }

    function setTreasury(address _treasury) external {
        if (msg.sender != treasury) revert ftYieldWrapperNotSetter();
        if (_treasury == address(0x0)) revert ftYieldWrapperZeroAddress();
        pendingTreasury = _treasury;
        emit PendingTreasury(treasury, pendingTreasury);
    }

    function confirmTreasury() external {
        if (msg.sender != strategyManager && msg.sender != yieldClaimer) {
            revert ftYieldWrapperNotConfirmer();
        }
        if (pendingTreasury == address(0x0)) revert ftYieldWrapperZeroAddress();
        if (treasury == pendingTreasury) {
            revert ftYieldWrapperSettingUnchanged();
        }
        treasury = pendingTreasury;
        pendingTreasury = address(0x0);
        emit UpdateTreasury(treasury);
    }

    function setPutManager(address _putManager) external onlyStrategyManager {
        if (_putManager == address(0x0)) revert ftYieldWrapperZeroAddress();
        putManager = _putManager;
        emit UpdatePutManager(_putManager);
    }

    function setDepositor(address _depositor) external onlyStrategyManager {
        depositor = _depositor;
        emit UpdateDepositor(_depositor);
    }

    /// @notice Set or disable the circuit breaker
    /// @dev Only callable by strategy manager. Set to address(0) to disable.
    /// @param _circuitBreaker Address of circuit breaker, or address(0) to disable
    function setCircuitBreaker(address _circuitBreaker) external onlyStrategyManager {
        circuitBreaker = _circuitBreaker;
        emit CircuitBreakerUpdated(_circuitBreaker);
    }

    function setStrategy(address _strategy) external onlyStrategyManager {
        if (_strategy == address(0x0)) revert ftYieldWrapperZeroAddress();
        if (isStrategy(_strategy) || IStrategy(_strategy).token() != token) {
            revert ftYieldWrapperNotStrategy();
        }
        uint256 effectiveTime = block.timestamp + DELAY;
        pendingStrategy = _strategy;
        delayStrategy = effectiveTime;
        emit PendingStrategy(strategyManager, pendingStrategy);
    }

    function confirmStrategy() external {
        if (msg.sender != treasury) revert ftYieldWrapperNotConfirmer();
        if (pendingStrategy == address(0x0)) revert ftYieldWrapperZeroAddress();
        if (delayStrategy > block.timestamp) revert ftYieldWrapperDelayNotExpired();
        strategies.push(IStrategy(pendingStrategy));
        emit AddedStrategy(strategyManager, pendingStrategy);
        // Ensure strategy wrapper pointer is set (no-op if already this wrapper)
        try IStrategy(pendingStrategy).setftYieldWrapper(address(this)) {
        // ok
        }
            catch {
            // strategies are expected to support this; ignore to avoid bricking
        }
        pendingStrategy = address(0x0);
        delayStrategy = 0;
        emit PendingStrategy(strategyManager, pendingStrategy);
    }

    /// @notice Remove a strategy whose wrapper share balance is zero.
    function removeStrategy(uint256 index) external onlyStrategyManager {
        uint256 len = strategies.length;
        if (index >= len) {
            revert ftYieldWrapperInvalidStrategyIndex();
        }

        IStrategy s = strategies[index];
        if (deployedToStrategy[address(s)] != 0) {
            revert ftYieldWrapperNotStrategy();
        }

        address removed = address(s);
        // swap & pop
        if (index != len - 1) {
            strategies[index] = strategies[len - 1];
        }
        strategies.pop();
        emit RemovedStrategy(msg.sender, removed);
    }

    /**
     * @dev Check if an address is a registered strategy
     * @param _strategy The address to check
     * @return bool True if the address is a registered strategy, false otherwise
     */
    function isStrategy(address _strategy) public view returns (bool) {
        uint256 strategiesLength = strategies.length;
        for (uint256 i = 0; i < strategiesLength; i++) {
            if (address(strategies[i]) == _strategy) return true;
        }
        return false;
    }

    /**
     * @dev Reorder strategies for withdrawal priority
     * @notice Can only be called by strategy manager
     * @param _newOrder Array of strategy addresses in the desired order
     */
    function setStrategiesOrder(address[] calldata _newOrder) external onlyStrategyManager {
        uint256 currentLength = strategies.length;

        // Check that array sizes match
        if (_newOrder.length != currentLength) {
            revert ftYieldWrapperInvalidStrategiesOrder();
        }

        // Verify all addresses are existing strategies and check for duplicates
        for (uint256 i = 0; i < currentLength; i++) {
            if (!isStrategy(_newOrder[i])) {
                revert ftYieldWrapperInvalidStrategiesOrder();
            }
            // Check for duplicates
            for (uint256 j = i + 1; j < currentLength; j++) {
                if (_newOrder[i] == _newOrder[j]) {
                    revert ftYieldWrapperInvalidStrategiesOrder();
                }
            }
        }

        // Update strategies array with new order
        for (uint256 i = 0; i < currentLength; i++) {
            strategies[i] = IStrategy(_newOrder[i]);
        }

        emit StrategiesReordered(_newOrder);
    }

    /**
     * @dev Claim yield from a specific strategy
     * @notice Can only be called by registered strategies
     * @param _strategy The strategy to claim yield from
     * @return _yield The amount of yield claimed
     */
    function claimYield(address _strategy) external onlyYieldClaimers returns (uint256 _yield) {
        if (!isStrategy(_strategy)) revert ftYieldWrapperNotStrategy();
        _yield = IStrategy(_strategy).claimYield(treasury);
        if (_yield == 0) revert ftYieldWrapperNoYield();
        emit YieldClaimed(msg.sender, address(token), _yield);
    }

    /**
     * @dev Claim yield from all registered strategies
     * @return _yield The total amount of yield claimed
     */
    function claimYields() external onlyYieldClaimers returns (uint256 _yield) {
        uint256 strategiesLength = strategies.length;
        address _treasury = treasury;
        for (uint256 i = 0; i < strategiesLength; i++) {
            _yield += IStrategy(strategies[i]).claimYield(_treasury);
        }
        if (_yield == 0) revert ftYieldWrapperNoYield();
        emit YieldClaimed(msg.sender, address(token), _yield);
    }

    function sweepIdleYield() external nonReentrant onlyYieldClaimers returns (uint256 amount) {
        uint256 idleBalance = IERC20(token).balanceOf(address(this));
        uint256 liabilities = totalSupply();
        if (idleBalance <= liabilities) revert ftYieldWrapperNoYield();
        amount = idleBalance - liabilities;
        IERC20(token).safeTransfer(treasury, amount);
        emit YieldSwept(msg.sender, address(token), amount);
    }

    function execute(
        address _strategy,
        address to,
        uint256 value,
        bytes calldata data
    )
        external
        onlyYieldClaimers
        returns (bool success, bytes memory result)
    {
        if (!isStrategy(_strategy)) revert ftYieldWrapperNotStrategy();
        return IStrategy(_strategy).execute(to, value, data);
    }

    /**
     * @dev Get the number of registered strategies
     * @return uint The number of strategies
     */
    function numberOfStrategies() external view returns (uint256) {
        return strategies.length;
    }

    // simply a 1:1 mapping of capital provided
    /**
     * @dev Get the total capital managed by the wrapper
     * @notice This is equal to totalSupply() of the wrapper token
     * @return uint The total capital (in underlying token) managed by the wrapper
     */
    function capital() external view returns (uint256) {
        return totalSupply();
    }

    // capital + yield
    function valueOfCapital() public view returns (uint256 _capital) {
        _capital = IERC20(token).balanceOf(address(this));
        uint256 strategiesLength = strategies.length;
        for (uint256 i = 0; i < strategiesLength; i++) {
            _capital += strategies[i].valueOfCapital();
        }
    }

    function yield() public view returns (uint256) {
        uint256 _capital = valueOfCapital();
        uint256 _totalSupply = totalSupply();
        return (_capital > _totalSupply) ? (_capital - _totalSupply) : 0;
    }

    // helper functions for strategy management
    function availableToWithdraw(address strategy) public view returns (uint256 liquidity) {
        // Only consider registered strategies; unrecognized addresses return zero
        if (!isStrategy(strategy)) return 0;
        // Defensive: treat failing strategies as having zero liquidity
        uint256 shares;
        try IStrategy(strategy).balanceOf(address(this)) returns (uint256 sb) {
            shares = sb;
        } catch {
            return 0;
        }
        try IStrategy(strategy).maxAbleToWithdraw(shares) returns (uint256 m) {
            liquidity = m;
        } catch {
            return 0;
        }
    }

    // helper functions for put servicing
    function availableToWithdraw() public view returns (uint256 liquidity) {
        liquidity = IERC20(token).balanceOf(address(this));
        uint256 strategiesLength = strategies.length;
        for (uint256 i = 0; i < strategiesLength; i++) {
            // Defensive view calls
            uint256 shares;
            try strategies[i].balanceOf(address(this)) returns (uint256 sb) {
                shares = sb;
            } catch {
                shares = 0;
            }
            if (shares != 0) {
                try strategies[i].maxAbleToWithdraw(shares) returns (uint256 m) {
                    liquidity += m;
                } catch {
                    // treat as zero
                }
            }
        }
    }

    function canWithdraw(uint256 amount) external view returns (bool) {
        // NOTE: returns availability in underlying only (does not count position-token fallback)
        return (availableToWithdraw() >= amount);
    }

    function maxAbleToWithdraw(uint256 amount) external view returns (uint256) {
        uint256 _liquidity = availableToWithdraw();
        return _liquidity > amount ? amount : _liquidity;
    }

    /**
     * @dev Deposit underlying tokens into the wrapper and receive wrapper tokens
     * @param amount The amount of underlying tokens to deposit
     * @notice Mints wrapper tokens to the depositor based on the amount of underlying tokens deposited
     * @notice we do not support fee on transfer tokens
     * @notice this is simply a 1:1 mapping of capital provided, it does not provide a share
     */
    function deposit(uint256 amount) external nonReentrant onlyPutManagerOrDepositor {
        if (amount == 0) revert ftYieldWrapperInsufficientLiquidity();

        // Circuit breaker: record inflow (fail-open)
        address _cb = circuitBreaker;
        if (_cb != address(0)) {
            uint256 preTvl = valueOfCapital();
            try ICircuitBreaker(_cb).recordInflow(token, amount, preTvl) {} catch {}
        }

        IERC20(token).safeTransferFrom(msg.sender, address(this), amount);
        _mint(msg.sender, amount);
        emit Deposit(msg.sender, amount);
    }

    function withdraw(uint256 amount, address to) external nonReentrant onlyPutManagerOrDepositor {
        // Circuit breaker: check rate limit (fail-open)
        address _cb = circuitBreaker;
        if (_cb != address(0)) {
            uint256 preTvl = valueOfCapital();
            try ICircuitBreaker(_cb).checkAndRecordOutflow(token, amount, preTvl) returns (
                bool allowed, uint256 available
            ) {
                if (!allowed) {
                    revert ftYieldWrapperRateLimitExceeded(amount, available);
                }
            } catch {}
        }

        uint256 initialTarget = amount;
        uint256 remaining = amount;

        // 1) Use idle underlying on the wrapper first (accumulate, transfer at end)
        uint256 idle = IERC20(token).balanceOf(address(this));
        if (idle != 0) {
            uint256 toTake = idle > remaining ? remaining : idle;
            remaining -= toTake;
        }

        // 2) Drain strategies in order
        uint256 _strategiesLength = strategies.length;
        for (uint256 i = 0; i < _strategiesLength && remaining != 0; i++) {
            // Check available liquidity for this strategy (defensive)
            uint256 shareBal;
            try strategies[i].balanceOf(address(this)) returns (uint256 sb) {
                shareBal = sb;
            } catch {
                continue;
            }
            if (shareBal == 0) {
                continue;
            }

            uint256 avail;
            try strategies[i].maxAbleToWithdraw(shareBal) returns (uint256 m) {
                avail = m;
            } catch {
                continue;
            }
            if (avail == 0) {
                continue;
            }

            // Withdraw what we can from this strategy
            uint256 toRequest = avail > remaining ? remaining : avail;
            try strategies[i].withdraw(toRequest) returns (uint256 received) {
                if (received != 0) {
                    // Protect against underflow if strategy returns more than deployed
                    uint256 currentDeployed = deployedToStrategy[address(strategies[i])];
                    uint256 toReduce = received > currentDeployed ? currentDeployed : received;

                    deployedToStrategy[address(strategies[i])] -= toReduce;
                    // Also cap the global deployed reduction
                    if (toReduce > deployed) {
                        deployed = 0;
                    } else {
                        deployed -= toReduce;
                    }
                    // Cap remaining reduction to avoid underflow
                    if (received > remaining) {
                        remaining = 0;
                    } else {
                        remaining -= received;
                    }
                }
            } catch {
                // Skip failing strategies and continue
            }
        }

        uint256 totalDelivered = initialTarget - remaining;
        if (remaining != 0) {
            revert ftYieldWrapperInsufficientLiquidity();
        }

        // Burn shares equal to what was actually delivered (no-op if zero)
        if (totalDelivered != 0) {
            _burn(msg.sender, totalDelivered);
        }

        // Single transfer at end (clamp to exact requested amount)
        // Defensive: in case any strategy returned more than requested,
        // only transfer exactly what was requested overall.
        if (totalDelivered != 0) {
            IERC20(token).safeTransfer(to, totalDelivered);
        }
        emit Withdraw(msg.sender, totalDelivered);
    }

    function withdrawUnderlying(
        uint256 amount,
        address to
    )
        external
        nonReentrant
        onlyPutManagerOrDepositor
    {
        // Circuit breaker: check rate limit (fail-open)
        address _cb = circuitBreaker;
        if (_cb != address(0)) {
            uint256 preTvl = valueOfCapital();
            try ICircuitBreaker(_cb).checkAndRecordOutflow(token, amount, preTvl) returns (
                bool allowed, uint256 available
            ) {
                if (!allowed) {
                    revert ftYieldWrapperRateLimitExceeded(amount, available);
                }
            } catch {}
        }

        uint256 initialTarget = amount;

        uint256 remaining = amount;
        uint256 _strategiesLength = strategies.length;

        if (remaining != 0) {
            for (uint256 i = 0; i < _strategiesLength && remaining != 0; ++i) {
                uint256 shareBal = strategies[i].balanceOf(address(this));
                if (shareBal == 0) continue;

                uint256 toExit = shareBal > remaining ? remaining : shareBal;

                // Try exit-in-kind via the lightweight extension
                // (if strategy doesn't implement, call reverts and we skip)
                try strategies[i].withdrawUnderlying(toExit) returns (uint256 got) {
                    if (got != 0) {
                        // Protect against underflow if more is withdrawn than deployed
                        uint256 currentDeployed = deployedToStrategy[address(strategies[i])];
                        uint256 toReduce = toExit > currentDeployed ? currentDeployed : toExit;

                        deployedToStrategy[address(strategies[i])] -= toReduce;
                        // Also cap the global deployed reduction
                        if (toReduce > deployed) {
                            deployed = 0;
                        } else {
                            deployed -= toReduce;
                        }
                        remaining -= toExit;
                        IERC20(strategies[i].positionToken()).safeTransfer(to, got);
                    }
                } catch {
                    // strategy doesn't support exit-in-position-token or failed; skip
                }
            }
        }
        uint256 totalDelivered = initialTarget - remaining;
        // If enforceExact, we must hit exact target (underlying + position tokens)
        if (remaining != 0) {
            revert ftYieldWrapperInsufficientLiquidity();
        }

        // Burn shares equal to what was actually delivered (no-op if zero)
        if (totalDelivered != 0) {
            _burn(msg.sender, totalDelivered);
        }
        emit WithdrawUnderlying(msg.sender, totalDelivered);
    }

    function availableToDeposit() external view returns (uint256) {
        return IERC20(token).balanceOf(address(this));
    }

    /**
     * @dev Deploy capital to registered strategy
     * @param amount The total amount of underlying tokens to deploy
     * @notice Can only be called by the yield claimer
     */
    function deploy(address strategy, uint256 amount) external nonReentrant onlyYieldClaimer {
        if (!isStrategy(strategy)) revert ftYieldWrapperNotStrategy();
        if (IERC20(token).balanceOf(address(this)) < amount) {
            revert ftYieldWrapperInsufficientLiquidity();
        }
        IERC20(token).forceApprove(address(strategy), amount);
        IStrategy(strategy).deposit(amount);
        deployedToStrategy[strategy] += amount;
        deployed += amount;
        emit Deployed(strategy, amount);
    }

    /**
     * @dev Withdraw capital from registered strategy
     * @param amount The total amount of underlying tokens to withdraw
     * @notice Can only be called by the yield claimer
     */
    function forceWithdrawToWrapper(
        address strategy,
        uint256 amount
    )
        external
        nonReentrant
        onlyYieldClaimer
    {
        if (!isStrategy(strategy)) revert ftYieldWrapperNotStrategy();

        uint256 _withdrawn = IStrategy(strategy).withdraw(amount);

        // Protect against underflow if strategy returns more than deployed
        uint256 currentDeployed = deployedToStrategy[strategy];
        uint256 toReduce = _withdrawn > currentDeployed ? currentDeployed : _withdrawn;

        deployedToStrategy[strategy] -= toReduce;
        // Also cap the global deployed reduction
        if (toReduce > deployed) {
            deployed = 0;
        } else {
            deployed -= toReduce;
        }

        emit WithdrawToWrapper(msg.sender, strategy, _withdrawn);
    }

    function withdrawQueued(
        address strategy,
        uint256 amount
    )
        external
        nonReentrant
        onlyYieldClaimer
        returns (uint256 id)
    {
        if (!isStrategy(strategy)) revert ftYieldWrapperNotStrategy();

        id = IStrategyWithQueue(strategy).withdrawQueued(amount);
        emit QueuedToWrapper(msg.sender, strategy, amount);
    }

    function claimQueued(
        address strategy,
        uint256 id
    )
        external
        nonReentrant
        onlyYieldClaimer
        returns (uint256 received)
    {
        if (!isStrategy(strategy)) revert ftYieldWrapperNotStrategy();

        received = IStrategyWithQueue(strategy).claimQueued(id);

        // Protect against underflow if more is claimed than deployed
        uint256 currentDeployed = deployedToStrategy[strategy];
        uint256 toReduce = received > currentDeployed ? currentDeployed : received;

        deployedToStrategy[strategy] -= toReduce;
        // Also cap the global deployed reduction
        if (toReduce > deployed) {
            deployed = 0;
        } else {
            deployed -= toReduce;
        }

        emit WithdrawToWrapper(msg.sender, strategy, received);
    }

    function decimals() public view override(ERC20, IERC20Metadata) returns (uint8) {
        return IERC20Metadata(token).decimals();
    }
}
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);
}
SafeERC20.sol 280 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 {
        if (!_safeTransfer(token, to, value, true)) {
            revert SafeERC20FailedOperation(address(token));
        }
    }

    /**
     * @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 {
        if (!_safeTransferFrom(token, from, to, value, true)) {
            revert SafeERC20FailedOperation(address(token));
        }
    }

    /**
     * @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 _safeTransfer(token, to, value, false);
    }

    /**
     * @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 _safeTransferFrom(token, from, to, value, false);
    }

    /**
     * @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 {
        if (!_safeApprove(token, spender, value, false)) {
            if (!_safeApprove(token, spender, 0, true)) revert SafeERC20FailedOperation(address(token));
            if (!_safeApprove(token, spender, value, true)) revert SafeERC20FailedOperation(address(token));
        }
    }

    /**
     * @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 `token.transfer(to, value)` call, 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 to The recipient of the tokens
     * @param value The amount of token to transfer
     * @param bubble Behavior switch if the transfer call reverts: bubble the revert reason or return a false boolean.
     */
    function _safeTransfer(IERC20 token, address to, uint256 value, bool bubble) private returns (bool success) {
        bytes4 selector = IERC20.transfer.selector;

        assembly ("memory-safe") {
            let fmp := mload(0x40)
            mstore(0x00, selector)
            mstore(0x04, and(to, shr(96, not(0))))
            mstore(0x24, value)
            success := call(gas(), token, 0, 0x00, 0x44, 0x00, 0x20)
            // if call success and return is true, all is good.
            // otherwise (not success or return is not true), we need to perform further checks
            if iszero(and(success, eq(mload(0x00), 1))) {
                // if the call was a failure and bubble is enabled, bubble the error
                if and(iszero(success), bubble) {
                    returndatacopy(fmp, 0x00, returndatasize())
                    revert(fmp, returndatasize())
                }
                // if the return value is not true, then the call is only successful if:
                // - the token address has code
                // - the returndata is empty
                success := and(success, and(iszero(returndatasize()), gt(extcodesize(token), 0)))
            }
            mstore(0x40, fmp)
        }
    }

    /**
     * @dev Imitates a Solidity `token.transferFrom(from, to, value)` call, 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 from The sender of the tokens
     * @param to The recipient of the tokens
     * @param value The amount of token to transfer
     * @param bubble Behavior switch if the transfer call reverts: bubble the revert reason or return a false boolean.
     */
    function _safeTransferFrom(
        IERC20 token,
        address from,
        address to,
        uint256 value,
        bool bubble
    ) private returns (bool success) {
        bytes4 selector = IERC20.transferFrom.selector;

        assembly ("memory-safe") {
            let fmp := mload(0x40)
            mstore(0x00, selector)
            mstore(0x04, and(from, shr(96, not(0))))
            mstore(0x24, and(to, shr(96, not(0))))
            mstore(0x44, value)
            success := call(gas(), token, 0, 0x00, 0x64, 0x00, 0x20)
            // if call success and return is true, all is good.
            // otherwise (not success or return is not true), we need to perform further checks
            if iszero(and(success, eq(mload(0x00), 1))) {
                // if the call was a failure and bubble is enabled, bubble the error
                if and(iszero(success), bubble) {
                    returndatacopy(fmp, 0x00, returndatasize())
                    revert(fmp, returndatasize())
                }
                // if the return value is not true, then the call is only successful if:
                // - the token address has code
                // - the returndata is empty
                success := and(success, and(iszero(returndatasize()), gt(extcodesize(token), 0)))
            }
            mstore(0x40, fmp)
            mstore(0x60, 0)
        }
    }

    /**
     * @dev Imitates a Solidity `token.approve(spender, value)` call, 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 spender The spender of the tokens
     * @param value The amount of token to transfer
     * @param bubble Behavior switch if the transfer call reverts: bubble the revert reason or return a false boolean.
     */
    function _safeApprove(IERC20 token, address spender, uint256 value, bool bubble) private returns (bool success) {
        bytes4 selector = IERC20.approve.selector;

        assembly ("memory-safe") {
            let fmp := mload(0x40)
            mstore(0x00, selector)
            mstore(0x04, and(spender, shr(96, not(0))))
            mstore(0x24, value)
            success := call(gas(), token, 0, 0x00, 0x44, 0x00, 0x20)
            // if call success and return is true, all is good.
            // otherwise (not success or return is not true), we need to perform further checks
            if iszero(and(success, eq(mload(0x00), 1))) {
                // if the call was a failure and bubble is enabled, bubble the error
                if and(iszero(success), bubble) {
                    returndatacopy(fmp, 0x00, returndatasize())
                    revert(fmp, returndatasize())
                }
                // if the return value is not true, then the call is only successful if:
                // - the token address has code
                // - the returndata is empty
                success := and(success, and(iszero(returndatasize()), gt(extcodesize(token), 0)))
            }
            mstore(0x40, fmp)
        }
    }
}
ReentrancyGuardTransient.sol 84 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.3.0) (utils/ReentrancyGuardTransient.sol)

pragma solidity ^0.8.24;

import {TransientSlot} from "./TransientSlot.sol";

/**
 * @dev Variant of {ReentrancyGuard} that uses transient storage.
 *
 * NOTE: This variant only works on networks where EIP-1153 is available.
 *
 * _Available since v5.1._
 *
 * @custom:stateless
 */
abstract contract ReentrancyGuardTransient {
    using TransientSlot for *;

    // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.ReentrancyGuard")) - 1)) & ~bytes32(uint256(0xff))
    bytes32 private constant REENTRANCY_GUARD_STORAGE =
        0x9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00;

    /**
     * @dev Unauthorized reentrant call.
     */
    error ReentrancyGuardReentrantCall();

    /**
     * @dev Prevents a contract from calling itself, directly or indirectly.
     * Calling a `nonReentrant` function from another `nonReentrant`
     * function is not supported. It is possible to prevent this from happening
     * by making the `nonReentrant` function external, and making it call a
     * `private` function that does the actual work.
     */
    modifier nonReentrant() {
        _nonReentrantBefore();
        _;
        _nonReentrantAfter();
    }

    /**
     * @dev A `view` only version of {nonReentrant}. Use to block view functions
     * from being called, preventing reading from inconsistent contract state.
     *
     * CAUTION: This is a "view" modifier and does not change the reentrancy
     * status. Use it only on view functions. For payable or non-payable functions,
     * use the standard {nonReentrant} modifier instead.
     */
    modifier nonReentrantView() {
        _nonReentrantBeforeView();
        _;
    }

    function _nonReentrantBeforeView() private view {
        if (_reentrancyGuardEntered()) {
            revert ReentrancyGuardReentrantCall();
        }
    }

    function _nonReentrantBefore() private {
        // On the first call to nonReentrant, REENTRANCY_GUARD_STORAGE.asBoolean().tload() will be false
        _nonReentrantBeforeView();

        // Any calls to nonReentrant after this point will fail
        _reentrancyGuardStorageSlot().asBoolean().tstore(true);
    }

    function _nonReentrantAfter() private {
        _reentrancyGuardStorageSlot().asBoolean().tstore(false);
    }

    /**
     * @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
     * `nonReentrant` function in the call stack.
     */
    function _reentrancyGuardEntered() internal view returns (bool) {
        return _reentrancyGuardStorageSlot().asBoolean().tload();
    }

    function _reentrancyGuardStorageSlot() internal pure virtual returns (bytes32) {
        return REENTRANCY_GUARD_STORAGE;
    }
}
IStrategy.sol 62 lines
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.30;

import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";

interface IStrategy is IERC20Metadata {
    event YieldClaimed(address yieldClaimer, address treasury, address token, uint256 amount);
    event Deposit(address owner, uint256 amount);
    event Withdraw(address owner, uint256 amount);
    event WithdrawUnderlying(address owner, uint256 amount);
    event UpdateftYieldWrapper(address newftYieldWrapper);

    error StrategyNotYieldWrapper();
    error StrategyZeroAddress();
    error StrategyAmountZero();
    error StrategyInsufficientLiquidity();
    error StrategyCantInteractWithCoreAssets();
    error StrategyCapitalMustNotChange();

    function token() external view returns (address);

    function valueOfCapital() external view returns (uint256);

    function setftYieldWrapper(address _ftYieldWrapper) external;

    function capital() external view returns (uint256);

    function yield() external view returns (uint256);

    function claimYield(address treasury) external returns (uint256);

    function execute(
        address to,
        uint256 value,
        bytes calldata data
    )
        external
        returns (bool success, bytes memory result);

    function availableToWithdraw() external view returns (uint256);

    function maxAbleToWithdraw(uint256 amount) external view returns (uint256);

    function withdraw(uint256 amount) external returns (uint256);

    function deposit(uint256 amount) external;

    /// @dev Address of the strategy's position token (e.g., aToken, stETH, etc)
    function positionToken() external view returns (address);

    /// @dev Burns wrapper's strategy shares and transfers `amount` of the position token to `to`.
    /// Must return the actual amount sent (should be == amount for 1:1 strategies).
    function withdrawUnderlying(uint256 amount) external returns (uint256 received);
}

interface IStrategyWithQueue is IStrategy {
    event WithdrawQueued(address owner, uint256 amount, uint256 id);
    event WithdrawClaimed(address owner, uint256 amount, uint256 id);

    function withdrawQueued(uint256 amount) external returns (uint256 id);
    function claimQueued(uint256 id) external returns (uint256 received);
}
IftYieldWrapper.sol 22 lines
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.30;

import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";

interface IftYieldWrapper is IERC20Metadata {
    function token() external view returns (address);

    function deposit(uint256 amount) external;

    function canWithdraw(uint256 amount) external view returns (bool);

    function maxAbleToWithdraw(uint256 amount) external view returns (uint256);

    function withdraw(uint256 amount, address to) external;

    function withdrawUnderlying(uint256 amount, address to) external;

    function circuitBreaker() external view returns (address);

    function setCircuitBreaker(address _circuitBreaker) external;
}
ICircuitBreaker.sol 177 lines
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.30;

/// @title ICircuitBreaker
/// @notice Interface for the optional circuit breaker module
/// @dev Designed for fail-open behavior - all calls should be wrapped in try/catch
interface ICircuitBreaker {
    // ============ Events ============

    /// @notice Emitted when an inflow (deposit) is recorded
    /// @param asset The collateral token address
    /// @param amount The amount deposited
    /// @param newTvl The TVL after this deposit
    event Inflow(address indexed asset, uint256 amount, uint256 newTvl);

    /// @notice Emitted when an outflow (withdrawal) is recorded
    /// @param asset The collateral token address
    /// @param amount The amount withdrawn
    /// @param newTvl The TVL after this withdrawal
    event Outflow(address indexed asset, uint256 amount, uint256 newTvl);

    /// @notice Emitted when a rate limit is triggered
    /// @param asset The collateral token address
    /// @param requested The amount requested to withdraw
    /// @param available The maximum amount available to withdraw
    event RateLimitTriggered(address indexed asset, uint256 requested, uint256 available);

    /// @notice Emitted when the circuit breaker configuration is updated
    /// @param maxDrawRateWad Maximum withdrawal rate as WAD (1e18 = 100%)
    /// @param mainWindow Time for main buffer to fully replenish (in seconds)
    /// @param elasticWindow Time for elastic buffer to decay (in seconds)
    event ConfigUpdated(uint256 maxDrawRateWad, uint256 mainWindow, uint256 elasticWindow);

    /// @notice Emitted when the circuit breaker is paused
    /// @param by The address that paused the circuit breaker
    event CircuitBreakerPaused(address indexed by);

    /// @notice Emitted when the circuit breaker is unpaused
    /// @param by The address that unpaused the circuit breaker
    event CircuitBreakerUnpaused(address indexed by);

    /// @notice Emitted when an emergency override is performed
    /// @param asset The collateral token address
    /// @param amount The amount added to withdrawal capacity
    event EmergencyOverride(address indexed asset, uint256 amount);

    // ============ Core Functions ============

    /// @notice Record an asset inflow (deposit)
    /// @dev Called after assets have been transferred in
    /// @param asset The collateral token address
    /// @param amount The amount deposited
    /// @param preTvl The TVL before this deposit
    function recordInflow(address asset, uint256 amount, uint256 preTvl) external;

    /// @notice Check if outflow is allowed and record it
    /// @dev Called before assets are transferred out
    /// @param asset The collateral token address
    /// @param amount The amount to withdraw
    /// @param preTvl The TVL before this withdrawal
    /// @return allowed Whether the withdrawal is within rate limits
    /// @return available The maximum amount that could be withdrawn
    function checkAndRecordOutflow(
        address asset,
        uint256 amount,
        uint256 preTvl
    )
        external
        returns (bool allowed, uint256 available);

    // ============ View Functions ============

    /// @notice Get the current withdrawal capacity for an asset
    /// @param asset The collateral token address
    /// @param currentTvl The current TVL
    /// @return capacity The maximum amount that can be withdrawn
    function withdrawalCapacity(
        address asset,
        uint256 currentTvl
    )
        external
        view
        returns (uint256 capacity);

    /// @notice Check if the circuit breaker is currently active (not paused)
    /// @return active True if the circuit breaker is active, false if paused
    function isActive() external view returns (bool active);

    // ============ Monitoring View Functions ============

    /// @notice Get all protected contracts
    /// @return contracts Array of protected contract addresses
    function getProtectedContracts() external view returns (address[] memory contracts);

    /// @notice Get count of protected contracts
    /// @return count Number of protected contracts
    function protectedContractCount() external view returns (uint256 count);

    /// @notice Get all tracked assets
    /// @return assets Array of tracked asset addresses
    function getTrackedAssets() external view returns (address[] memory assets);

    /// @notice Get count of tracked assets
    /// @return count Number of tracked assets
    function trackedAssetCount() external view returns (uint256 count);

    /// @notice Get health metrics for an asset
    /// @param asset The asset to query
    /// @param currentTvl The current TVL
    /// @return mainUtilizationBps Main buffer usage in basis points (0 = full, 10000 = depleted)
    /// @return elasticBuffer Current elastic buffer amount
    /// @return totalCapacity Total withdrawal capacity
    /// @return maxCapacity Maximum possible capacity
    /// @return secondsUntilFullReplenishment Seconds until main buffer fully replenishes
    function getAssetHealth(
        address asset,
        uint256 currentTvl
    )
        external
        view
        returns (
            uint256 mainUtilizationBps,
            uint256 elasticBuffer,
            uint256 totalCapacity,
            uint256 maxCapacity,
            uint256 secondsUntilFullReplenishment
        );

    /// @notice Get comprehensive system status
    /// @return active Whether circuit breaker is active
    /// @return adminAddr Current admin address
    /// @return maxDrawRateBps Max draw rate in basis points
    /// @return mainWindowSecs Main window in seconds
    /// @return elasticWindowSecs Elastic window in seconds
    /// @return numProtectedContracts Number of protected contracts
    /// @return numTrackedAssets Number of tracked assets
    function getSystemStatus()
        external
        view
        returns (
            bool active,
            address adminAddr,
            uint256 maxDrawRateBps,
            uint256 mainWindowSecs,
            uint256 elasticWindowSecs,
            uint256 numProtectedContracts,
            uint256 numTrackedAssets
        );

    // ============ Admin Functions ============

    /// @notice Pause the circuit breaker (allows all transactions)
    /// @dev Only callable by admin
    function pause() external;

    /// @notice Unpause the circuit breaker
    /// @dev Only callable by admin
    function unpause() external;

    /// @notice Update rate limiting configuration
    /// @dev Only callable by admin
    /// @param maxDrawRateWad Maximum withdrawal rate as WAD (1e18 = 100%)
    /// @param mainWindow Time for main buffer to fully replenish (in seconds)
    /// @param elasticWindow Time for elastic buffer to decay (in seconds)
    function updateConfig(
        uint256 maxDrawRateWad,
        uint256 mainWindow,
        uint256 elasticWindow
    )
        external;

    /// @notice Emergency override to allow a specific withdrawal
    /// @dev Only callable by admin, for false positive resolution
    /// @param asset The collateral token address
    /// @param amount The amount to allow for withdrawal
    function emergencyOverride(address asset, uint256 amount) external;
}
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);
}
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;
    }
}
draft-IERC6093.sol 162 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);
}
TransientSlot.sol 183 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.3.0) (utils/TransientSlot.sol)
// This file was procedurally generated from scripts/generate/templates/TransientSlot.js.

pragma solidity ^0.8.24;

/**
 * @dev Library for reading and writing value-types to specific transient storage slots.
 *
 * Transient slots are often used to store temporary values that are removed after the current transaction.
 * This library helps with reading and writing to such slots without the need for inline assembly.
 *
 *  * Example reading and writing values using transient storage:
 * ```solidity
 * contract Lock {
 *     using TransientSlot for *;
 *
 *     // Define the slot. Alternatively, use the SlotDerivation library to derive the slot.
 *     bytes32 internal constant _LOCK_SLOT = 0xf4678858b2b588224636b8522b729e7722d32fc491da849ed75b3fdf3c84f542;
 *
 *     modifier locked() {
 *         require(!_LOCK_SLOT.asBoolean().tload());
 *
 *         _LOCK_SLOT.asBoolean().tstore(true);
 *         _;
 *         _LOCK_SLOT.asBoolean().tstore(false);
 *     }
 * }
 * ```
 *
 * TIP: Consider using this library along with {SlotDerivation}.
 */
library TransientSlot {
    /**
     * @dev UDVT that represents a slot holding an address.
     */
    type AddressSlot is bytes32;

    /**
     * @dev Cast an arbitrary slot to a AddressSlot.
     */
    function asAddress(bytes32 slot) internal pure returns (AddressSlot) {
        return AddressSlot.wrap(slot);
    }

    /**
     * @dev UDVT that represents a slot holding a bool.
     */
    type BooleanSlot is bytes32;

    /**
     * @dev Cast an arbitrary slot to a BooleanSlot.
     */
    function asBoolean(bytes32 slot) internal pure returns (BooleanSlot) {
        return BooleanSlot.wrap(slot);
    }

    /**
     * @dev UDVT that represents a slot holding a bytes32.
     */
    type Bytes32Slot is bytes32;

    /**
     * @dev Cast an arbitrary slot to a Bytes32Slot.
     */
    function asBytes32(bytes32 slot) internal pure returns (Bytes32Slot) {
        return Bytes32Slot.wrap(slot);
    }

    /**
     * @dev UDVT that represents a slot holding a uint256.
     */
    type Uint256Slot is bytes32;

    /**
     * @dev Cast an arbitrary slot to a Uint256Slot.
     */
    function asUint256(bytes32 slot) internal pure returns (Uint256Slot) {
        return Uint256Slot.wrap(slot);
    }

    /**
     * @dev UDVT that represents a slot holding a int256.
     */
    type Int256Slot is bytes32;

    /**
     * @dev Cast an arbitrary slot to a Int256Slot.
     */
    function asInt256(bytes32 slot) internal pure returns (Int256Slot) {
        return Int256Slot.wrap(slot);
    }

    /**
     * @dev Load the value held at location `slot` in transient storage.
     */
    function tload(AddressSlot slot) internal view returns (address value) {
        assembly ("memory-safe") {
            value := tload(slot)
        }
    }

    /**
     * @dev Store `value` at location `slot` in transient storage.
     */
    function tstore(AddressSlot slot, address value) internal {
        assembly ("memory-safe") {
            tstore(slot, value)
        }
    }

    /**
     * @dev Load the value held at location `slot` in transient storage.
     */
    function tload(BooleanSlot slot) internal view returns (bool value) {
        assembly ("memory-safe") {
            value := tload(slot)
        }
    }

    /**
     * @dev Store `value` at location `slot` in transient storage.
     */
    function tstore(BooleanSlot slot, bool value) internal {
        assembly ("memory-safe") {
            tstore(slot, value)
        }
    }

    /**
     * @dev Load the value held at location `slot` in transient storage.
     */
    function tload(Bytes32Slot slot) internal view returns (bytes32 value) {
        assembly ("memory-safe") {
            value := tload(slot)
        }
    }

    /**
     * @dev Store `value` at location `slot` in transient storage.
     */
    function tstore(Bytes32Slot slot, bytes32 value) internal {
        assembly ("memory-safe") {
            tstore(slot, value)
        }
    }

    /**
     * @dev Load the value held at location `slot` in transient storage.
     */
    function tload(Uint256Slot slot) internal view returns (uint256 value) {
        assembly ("memory-safe") {
            value := tload(slot)
        }
    }

    /**
     * @dev Store `value` at location `slot` in transient storage.
     */
    function tstore(Uint256Slot slot, uint256 value) internal {
        assembly ("memory-safe") {
            tstore(slot, value)
        }
    }

    /**
     * @dev Load the value held at location `slot` in transient storage.
     */
    function tload(Int256Slot slot) internal view returns (int256 value) {
        assembly ("memory-safe") {
            value := tload(slot)
        }
    }

    /**
     * @dev Store `value` at location `slot` in transient storage.
     */
    function tstore(Int256Slot slot, int256 value) internal {
        assembly ("memory-safe") {
            tstore(slot, value)
        }
    }
}
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";
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";
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);
}

Read Contract

allowance 0xdd62ed3e → uint256
availableToDeposit 0x7b9282b0 → uint256
availableToWithdraw 0xa25db8ce → uint256
availableToWithdraw 0xe322ad2b → uint256
balanceOf 0x70a08231 → uint256
canWithdraw 0xfbe85f06 → bool
capital 0xd211fd18 → uint256
circuitBreaker 0x16efd941 → address
decimals 0x313ce567 → uint8
delayStrategy 0x5d83f093 → uint256
deployed 0xf905c15a → uint256
deployedToStrategy 0x958da918 → uint256
depositor 0xc7c4ff46 → address
isStrategy 0x2e8ebaae → bool
maxAbleToWithdraw 0xafa92945 → uint256
name 0x06fdde03 → string
numberOfStrategies 0x0956e5a6 → uint256
pendingStrategy 0x465fc5d2 → address
pendingStrategyManager 0x0e845634 → address
pendingTreasury 0x2ed6b75d → address
pendingYieldClaimer 0x7a801f53 → address
putManager 0x4f5e8085 → address
strategies 0xd574ea3d → address
strategyManager 0x39b70e38 → address
subYieldClaimer 0x3066bb27 → address
symbol 0x95d89b41 → string
token 0xfc0c546a → address
totalSupply 0x18160ddd → uint256
treasury 0x61d027b3 → address
valueOfCapital 0x89fe02cb → uint256
yield 0x28593984 → uint256
yieldClaimer 0x78e808d5 → address

Write Contract 28 functions

These functions modify contract state and require a wallet transaction to execute.

approve 0x095ea7b3
address spender
uint256 value
returns: bool
claimQueued 0x1c30e682
address strategy
uint256 id
returns: uint256
claimYield 0x999927df
address _strategy
returns: uint256
claimYields 0x2f278fe8
No parameters
returns: uint256
confirmStrategy 0x4f908e7f
No parameters
confirmStrategyManager 0xaec48f50
No parameters
confirmTreasury 0xedf1d2b3
No parameters
confirmYieldClaimer 0x5e181655
No parameters
deploy 0x4956eaf0
address strategy
uint256 amount
deposit 0xb6b55f25
uint256 amount
execute 0x9aefaff8
address _strategy
address to
uint256 value
bytes data
returns: bool, bytes
forceWithdrawToWrapper 0x57c44f8e
address strategy
uint256 amount
removeStrategy 0xc0cbbca6
uint256 index
setCircuitBreaker 0x82beee89
address _circuitBreaker
setDepositor 0xf2c098b7
address _depositor
setPutManager 0x58e75440
address _putManager
setStrategiesOrder 0x59746aab
address[] _newOrder
setStrategy 0x33a100ca
address _strategy
setStrategyManager 0x5c966646
address _strategyManager
setSubYieldClaimer 0x75efcf77
address _subYieldClaimer
setTreasury 0xf0f44260
address _treasury
setYieldClaimer 0xd8b5138a
address _yieldClaimer
sweepIdleYield 0x8c05b472
No parameters
returns: uint256
transfer 0xa9059cbb
address to
uint256 value
returns: bool
transferFrom 0x23b872dd
address from
address to
uint256 value
returns: bool
withdraw 0x00f714ce
uint256 amount
address to
withdrawQueued 0xe357e92e
address strategy
uint256 amount
returns: uint256
withdrawUnderlying 0x99f428cf
uint256 amount
address to

Recent Transactions

No transactions found for this address