Cryo Explorer Ethereum Mainnet

Address Contract Verified

Address 0x57B68c4EA221ee8Da6eb14ebdfcCEE5177567771
Balance 0 ETH
Nonce 1
Code Size 17342 bytes
Indexed Transactions 0
External Etherscan · Sourcify

Contract Bytecode

17342 bytes
0x6080604052600436106103545760003560e01c8063765cb8d0116101c6578063ba087652116100f7578063d4e3d15111610095578063dd62ed3e1161006f578063dd62ed3e14610b70578063ef8b30f714610ba8578063f1a3291d14610bc8578063f2fde38b14610bde57600080fd5b8063d4e3d15114610b10578063d505accf14610b30578063d905777e14610b5057600080fd5b8063c751fbfb116100d1578063c751fbfb14610a86578063c9a7339f14610aba578063ce96cb7714610ada578063d02914a514610afa57600080fd5b8063ba08765214610a26578063c63d75b614610a46578063c6e6f59214610a6657600080fd5b80639ef0304511610164578063ad5c46481161013e578063ad5c464814610992578063b3d7f6b9146109c6578063b460af94146109e6578063b66ff26114610a0657600080fd5b80639ef0304514610932578063a9059cbb14610952578063ab6fb3801461097257600080fd5b80638f188dd4116101a05780638f188dd4146108bd57806394bf804d146108dd57806395d89b41146108fd5780639671b5871461091257600080fd5b8063765cb8d0146108495780637ecebe00146108695780638da5cb5b1461089657600080fd5b80633644e515116102a057806356d5d4751161023e5780636e553f65116102185780636e553f65146107d257806370a08231146107f2578063715018a61461081f57806371d12ff81461083457600080fd5b806356d5d475146107045780635cf9e54a1461071757806366ef59ef1461073757600080fd5b80634bf470271161027a5780634bf47027146106985780634cdad506146106b85780635014de65146106d8578063523bf8c0146106ee57600080fd5b80633644e5151461062257806338d52e0f14610637578063402d267d1461067857600080fd5b80630a28a4771161030d57806318160ddd116102e757806318160ddd1461059557806323658276146105ab57806323b872dd146105c1578063313ce567146105e157600080fd5b80630a28a477146105405780630b6a97cb146105605780631790c5621461057557600080fd5b806301e1d11414610477578063025d57c2146104a257806306f94a0d146104bb57806306fdde03146104d157806307a2d13a146104f3578063095ea7b31461051357600080fd5b36610472577f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b03167f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b0316146103cb57604051630c86197560e31b815260040160405180910390fd5b336001600160a01b037f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc21614610470577f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b031663d0e30db0476040518263ffffffff1660e01b81526004016000604051808303818588803b15801561045657600080fd5b505af115801561046a573d6000803e3d6000fd5b50505050505b005b600080fd5b34801561048357600080fd5b5061048c610bfe565b604051610499919061309a565b60405180910390f35b3480156104ae57600080fd5b5061048c64174876e80081565b3480156104c757600080fd5b5061048c60075481565b3480156104dd57600080fd5b506104e6610d20565b60405161049991906130fe565b3480156104ff57600080fd5b5061048c61050e366004613127565b610dae565b34801561051f57600080fd5b5061053361052e366004613175565b610ddb565b60405161049991906131ba565b34801561054c57600080fd5b5061048c61055b366004613127565b610e46565b34801561056c57600080fd5b50610470610e66565b34801561058157600080fd5b5061048c6105903660046131df565b610f15565b3480156105a157600080fd5b5061048c60025481565b3480156105b757600080fd5b5061048c600e5481565b3480156105cd57600080fd5b506105336105dc366004613212565b611117565b3480156105ed57600080fd5b506106157f000000000000000000000000000000000000000000000000000000000000001281565b604051610499919061326b565b34801561062e57600080fd5b5061048c6111f5565b34801561064357600080fd5b5061066b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc281565b60405161049991906132bb565b34801561068457600080fd5b5061048c6106933660046132c9565b611250565b3480156106a457600080fd5b506104706106b33660046131df565b6112c2565b3480156106c457600080fd5b5061048c6106d3366004613127565b6113fe565b3480156106e457600080fd5b5061048c60105481565b3480156106fa57600080fd5b5061048c600c5481565b61047061071236600461333c565b611409565b34801561072357600080fd5b506104706107323660046132c9565b611717565b34801561074357600080fd5b506107be6107523660046131df565b60086020908152600092835260408084209091529082529020805460018201546002830154600384015460049094015463ffffffff808516956001600160a01b0364010000000090960486169594851694909290811691600160a01b8204811691600160c01b90041688565b6040516104999897969594939291906133bf565b3480156107de57600080fd5b5061048c6107ed366004613436565b61177d565b3480156107fe57600080fd5b5061048c61080d3660046132c9565b60036020526000908152604090205481565b34801561082b57600080fd5b50610470611840565b34801561084057600080fd5b5061048c611854565b34801561085557600080fd5b50610470610864366004613487565b61186c565b34801561087557600080fd5b5061048c6108843660046132c9565b60056020526000908152604090205481565b3480156108a257600080fd5b506006546001600160a01b03165b6040516104999190613511565b3480156108c957600080fd5b50600a546108b0906001600160a01b031681565b3480156108e957600080fd5b5061048c6108f8366004613436565b61196c565b34801561090957600080fd5b506104e6611a0f565b34801561091e57600080fd5b5061047061092d366004613127565b611a1c565b34801561093e57600080fd5b506104e661094d36600461351f565b611a67565b34801561095e57600080fd5b5061053361096d366004613175565b611a91565b34801561097e57600080fd5b50600b546108b0906001600160a01b031681565b34801561099e57600080fd5b506108b07f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc281565b3480156109d257600080fd5b5061048c6109e1366004613127565b611af5565b3480156109f257600080fd5b5061048c610a01366004613543565b611b14565b348015610a1257600080fd5b50610470610a21366004613589565b611c2e565b348015610a3257600080fd5b5061048c610a41366004613543565b611fb9565b348015610a5257600080fd5b5061048c610a613660046132c9565b6120f3565b348015610a7257600080fd5b5061048c610a81366004613127565b61210a565b348015610a9257600080fd5b506108b07f000000000000000000000000c005dc82818d67af737725bd4bf75435d065d23981565b348015610ac657600080fd5b50610470610ad53660046135be565b61212a565b348015610ae657600080fd5b5061048c610af53660046132c9565b612273565b348015610b0657600080fd5b5061048c600f5481565b348015610b1c57600080fd5b50610470610b2b366004613701565b6122de565b348015610b3c57600080fd5b50610470610b4b366004613736565b61243f565b348015610b5c57600080fd5b5061048c610b6b3660046132c9565b612609565b348015610b7c57600080fd5b5061048c610b8b3660046137d5565b600460209081526000928352604080842090915290825290205481565b348015610bb457600080fd5b5061048c610bc3366004613127565b612620565b348015610bd457600080fd5b5061048c600d5481565b348015610bea57600080fd5b50610470610bf93660046132c9565b61262b565b600a546040516370a0823160e01b815260009182916001600160a01b03909116906370a0823190610c33903090600401613511565b602060405180830381865afa158015610c50573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c749190613802565b600a5460405163266d6a8360e11b81529192506000916001600160a01b0390911690634cdad50690610caa90859060040161309a565b602060405180830381865afa158015610cc7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ceb9190613802565b9050610cf5612666565b600c54600754610d059084613839565b610d0f919061384c565b610d19919061384c565b9250505090565b60008054610d2d90613875565b80601f0160208091040260200160405190810160405280929190818152602001828054610d5990613875565b8015610da65780601f10610d7b57610100808354040283529160200191610da6565b820191906000526020600020905b815481529060010190602001808311610d8957829003601f168201915b505050505081565b6002546000908015610dd257610dcd610dc5610bfe565b8490836126b9565b610dd4565b825b9392505050565b3360008181526004602090815260408083206001600160a01b038716808552925280832085905551919290917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92590610e3490869061309a565b60405180910390a35060015b92915050565b6002546000908015610dd257610dcd81610e5e610bfe565b8591906126d7565b6040516370a0823160e01b81526000906001600160a01b037f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc216906370a0823190610eb5903090600401613511565b602060405180830381865afa158015610ed2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ef69190613802565b90508015610f1257610f07816126fd565b610f10816127e8565b505b50565b63ffffffff821660009081526008602090815260408083206001600160a01b038086168552925282206004810154909116610f705783836040516354f37a5760e11b8152600401610f679291906138a1565b60405180910390fd5b60048101546001600160a01b039081169063aad3ec96907f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc281167f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc290911614610ff9577f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2610ffc565b60005b83600301546040518363ffffffff1660e01b815260040161101e9291906138bc565b6020604051808303816000875af115801561103d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110619190613802565b915061106d8282612888565b611076826126fd565b600481015460009064174876e8009061109c90600160a01b900463ffffffff16856138d7565b6110a6919061390c565b905080600c60008282546110ba919061384c565b909155506110c99050816127e8565b50836001600160a01b03167f50be4e2318c5fc2e6b327c545d7150f7a0263792b687b5498583f8f3502bc92086858460405161110793929190613920565b60405180910390a2505092915050565b6001600160a01b038316600090815260046020908152604080832033845290915281205460001981146111735761114e838261384c565b6001600160a01b03861660009081526004602090815260408083203384529091529020555b6001600160a01b0385166000908152600360205260408120805485929061119b90849061384c565b90915550506001600160a01b0380851660008181526003602052604090819020805487019055519091871690600080516020614369833981519152906111e290879061309a565b60405180910390a3506001949350505050565b60007f0000000000000000000000000000000000000000000000000000000000000001461461122b57611226612904565b905090565b507fdee05fc0a3408f1ee80573362232cb961d901a104b032ceed7b41aa0502a9b5a90565b600a5460405163402d267d60e01b81526000916001600160a01b03169063402d267d90611281903090600401613511565b602060405180830381865afa15801561129e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e409190613802565b63ffffffff80831660009081526008602090815260408083206001600160a01b038087168552908352928190208151610100810183528154808716825264010000000090048516938101939093526001810154841691830182905260028101546060840152600381015460808401526004015492831660a0830152600160a01b8304841660c0830152600160c01b90920490921660e0830152331461137c573360405163d86ad9cf60e01b8152600401610f679190613511565b63ffffffff831660009081526008602090815260408083206001600160a01b0386168452909152808220600201919091556060820151608083015160a084015192517f871fcd42f70c51db10c5be37946e7ba90f777bb6f84ad8f933da40645388ee4c936113f1938893889391929091613948565b60405180910390a1505050565b6000610e4082610dae565b336001600160a01b037f000000000000000000000000c005dc82818d67af737725bd4bf75435d065d2391614611454573360405163d86ad9cf60e01b8152600401610f679190613511565b600061145f8461298d565b63ffffffff861660009081526008602090815260408083206001600160a01b0385168452909152812060028101549293509190036114b45785826040516354f37a5760e11b8152600401610f679291906138a1565b60006114c2848601866139fc565b60048301546060820151919250600160c01b900463ffffffff16906114e7904261384c565b101561152c578683826000015183606001518560040160189054906101000a900463ffffffff16604051630cc7906f60e31b8152600401610f67959493929190613a1d565b63ffffffff871660009081526009602090815260408083206001600160a01b03871684528252808320845184529091528120805461156990613875565b9050111561159157805160405163fbeca95760e01b8152610f67918991869190600401613a5f565b63ffffffff871660009081526009602090815260408083206001600160a01b038716845282528083208451845290915290206115ce858783613b0b565b506004820154604082015160009164174876e800916115fa91600160a01b900463ffffffff16906138d7565b611604919061390c565b905080600c60008282546116189190613839565b90915550506002830154604083015160038501546116369190613839565b111561166e5760028301548251602084015160408086015190516311a58fb160e01b8152610f67948d948a9491939092600401613bce565b61167c8260400151846129ba565b61169981836040015161168f919061384c565b83602001516129e7565b81602001516001600160a01b031682600001517faa0a283a8f952f6b146189e627f62762ff987d8a7ab0d2b7281e12783efcd5e67f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2856040015187866040516117059493929190613d4c565b60405180910390a35050505050505050565b61171f612b59565b600b80546001600160a01b038381166001600160a01b0319831681179093556040519116917fa788a71062c303bd606016d2c906a6e64705cebfb5762489c5d0742cc07f5f0091611771918491613d8c565b60405180910390a15050565b600061178883612620565b9050806000036117aa5760405162461bcd60e51b8152600401610f6790613dbf565b6117df6001600160a01b037f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc216333086612b86565b6117e98282612c08565b816001600160a01b0316336001600160a01b03167fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7858460405161182e929190613dcf565b60405180910390a3610e408382612c66565b611848612b59565b6118526000612c6f565b565b600061185e612666565b600d81905542600e55919050565b611874612b59565b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b0316866001600160a01b0316036118c85785604051631b37a25160e21b8152600401610f679190613511565b600b546118e09087906001600160a01b031687612cc1565b600b5460405163d3cc806b60e01b81526001600160a01b039091169063d3cc806b906119189089908890889088908890600401613df6565b6020604051808303816000875af1158015611937573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061195b9190613802565b50611964610e66565b505050505050565b600061197783611af5565b90506119ae6001600160a01b037f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc216333084612b86565b6119b88284612c08565b816001600160a01b0316336001600160a01b03167fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d783866040516119fd929190613dcf565b60405180910390a3610e408184612c66565b60018054610d2d90613875565b611a24612b59565b611a2c611854565b5060108054908290556040517f34a782ff69728aa1d7ca8340e4de986041b0a3d5a8271de29738bb8d43c4419d906117719083908590613dcf565b600960209081526000938452604080852082529284528284209052825290208054610d2d90613875565b33600090815260036020526040812080548391908390611ab290849061384c565b90915550506001600160a01b0383166000818152600360205260409081902080548501905551339060008051602061436983398151915290610e3490869061309a565b6002546000908015610dd257610dcd611b0c610bfe565b8490836126d7565b6000611b1f84610e46565b9050336001600160a01b03831614611b8f576001600160a01b03821660009081526004602090815260408083203384529091529020546000198114611b8d57611b68828261384c565b6001600160a01b03841660009081526004602090815260408083203384529091529020555b505b611b998482612d1e565b611ba38282612d28565b816001600160a01b0316836001600160a01b0316336001600160a01b03167ffbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db8785604051611bf2929190613dcf565b60405180910390a4610dd46001600160a01b037f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2168486612d8a565b611c36612b59565b600a546040516370a0823160e01b81526001600160a01b039091169060009082906370a0823190611c6b903090600401613511565b602060405180830381865afa158015611c88573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cac9190613802565b90506000826001600160a01b03166307a2d13a846001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015611cfd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d219190613e43565b611d2c90600a613f6d565b6040518263ffffffff1660e01b8152600401611d48919061309a565b602060405180830381865afa158015611d65573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d899190613802565b905084811015611db0578085604051636f393ebf60e11b8152600401610f67929190613dcf565b600a54604051635d043b2960e11b81526000916001600160a01b03169063ba08765290611de590869030908190600401613f82565b6020604051808303816000875af1158015611e04573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e289190613802565b600a80546001600160a01b0319166001600160a01b038a169081179091556040805163313ce56760e01b815290519293506000926307a2d13a91839163313ce567916004808201926020929091908290030181865afa158015611e8f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611eb39190613e43565b611ebe90600a613f6d565b6040518263ffffffff1660e01b8152600401611eda919061309a565b602060405180830381865afa158015611ef7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f1b9190613802565b905085811115611f425780866040516327d54a6d60e11b8152600401610f67929190613dcf565b611f6d7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc28984612dfc565b611f76826126fd565b7f5d762e53f3264338f293b7162f91a331ded939875e7a9e81991fc30f2051c2858589604051611fa7929190613d8c565b60405180910390a15050505050505050565b6000336001600160a01b03831614612029576001600160a01b0382166000908152600460209081526040808320338452909152902054600019811461202757612002858261384c565b6001600160a01b03841660009081526004602090815260408083203384529091529020555b505b612032846113fe565b9050806000036120545760405162461bcd60e51b8152600401610f6790613fcc565b61205e8185612d1e565b6120688285612d28565b816001600160a01b0316836001600160a01b0316336001600160a01b03167ffbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db84886040516120b7929190613dcf565b60405180910390a4610dd46001600160a01b037f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2168483612d8a565b6000806120ff83611250565b9050610dd481612620565b6002546000908015610dd257610dcd81612122610bfe565b8591906126b9565b612132612b59565b63ffffffff841660009081526008602090815260408083206001600160a01b0387168452909152812090612168838501856139fc565b63ffffffff871660009081526009602090815260408083206001600160a01b038a1684528252808320845184529091528120805492935090916121aa90613875565b905011156121d257805160405163fbeca95760e01b8152610f67918891889190600401613a5f565b63ffffffff861660009081526009602090815260408083206001600160a01b0389168452825280832084518452909152902061220f848683613b0b565b5061221e8160400151836129ba565b600061222a8787610f15565b905081604001518110156122585780826040015160405162fae2d560e21b8152600401610f67929190613dcf565b61226a826040015183602001516129e7565b50505050505050565b6040516370a0823160e01b8152600090610e409030906370a082319061229d908690600401613511565b602060405180830381865afa1580156122ba573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061050e9190613802565b6122e6612b59565b60408051610100810182526020808401805163ffffffff908116845285850180516001600160a01b03908116858701908152885182168789019081526080808b01516060808b019182526000928b01838152908d0151861660a0808d019182528e0151891660c0808e019182528f01518a1660e08e019081529a518a16855260088c528d852098518816855297909a52918b902099518a5494518616640100000000026001600160c01b031995861691891691909117178a55915160018a0180549186166001600160a01b031990921691909117905590516002890155516003880155945160049096018054925194518416600160c01b0263ffffffff60c01b1995909416600160a01b02929095169516949094179390931716919091179055517fe5ac862a7bba3152837a19d7b3561a065634e43854aefe302c8a2c058eda64649061243490839061405f565b60405180910390a150565b4284101561245f5760405162461bcd60e51b8152600401610f67906140a1565b6000600161246b6111f5565b6001600160a01b038a1660009081526005602090815260409182902080546001810190915591516124c8927f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9928e928e928e9290918e91016140b1565b604051602081830303815290604052805190602001206040516020016124ef9291906140f9565b6040516020818303038152906040528051906020012085858560405160008152602001604052604051612525949392919061412a565b6020604051602081039080840390855afa158015612547573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b0381161580159061257d5750876001600160a01b0316816001600160a01b0316145b6125995760405162461bcd60e51b8152600401610f6790614184565b6001600160a01b0390811660009081526004602090815260408083208a8516808552925291829020889055905190918916907f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925906125f890899061309a565b60405180910390a350505050505050565b60008061261583612273565b9050610dd481610e46565b6000610e408261210a565b612633612b59565b6001600160a01b03811661265d576000604051631e4fbdf760e01b8152600401610f679190613511565b610f1281612c6f565b6000600f544211156126785750600090565b600e54600f54612688919061384c565b600e54612695904261384c565b600d546126a291906138d7565b6126ac919061390c565b600d54611226919061384c565b60008260001904841183021582026126d057600080fd5b5091020490565b60008260001904841183021582026126ee57600080fd5b50910281810615159190040190565b600a54612735907f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2906001600160a01b031683612dfc565b600a54604051636e553f6560e01b81526001600160a01b0390911690636e553f65906127679084903090600401614194565b6020604051808303816000875af1158015612786573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127aa9190613802565b50600a546040517f8151101725f592af63b48bea397ac83f148fc58812547257268c3af666f10e4b916124349184916001600160a01b031690614194565b6000811561286a576127f8611854565b506000612803612666565b9050600042612814600f5442612e84565b61281e919061384c565b9050600061282c8584613839565b60105461283990876138d7565b61284384866138d7565b61284d9190613839565b612857919061390c565b90506128638142613839565b600f555050505b81600d600082825461287c9190613839565b91829055509392505050565b600381018054908390600061289d838561384c565b90915550506007805490849060006128b5838561384c565b909155505060075460038401546040517fe0ead0b64d9665e04da658994d20421156b0cf1541af6588f0e66ad2fe24907b926128f6928592889188916141a2565b60405180910390a150505050565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60006040516129369190614259565b60405190819003812061297292917fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc69046903090602001614265565b60405160208183030381529060405280519060200120905090565b60006001600160a01b038211156129b65760405162461bcd60e51b8152600401610f6790614280565b5090565b60038101805490839060006129cf8385613839565b90915550506007805490849060006128b58385613839565b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b03167f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b031603612b4f57612a4a8230612e94565b604051632e1a7d4d60e01b81526001600160a01b037f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc21690632e1a7d4d90612a9690859060040161309a565b600060405180830381600087803b158015612ab057600080fd5b505af1158015612ac4573d6000803e3d6000fd5b505050506000816001600160a01b031683604051612ae1906142c8565b60006040518083038185875af1925050503d8060008114612b1e576040519150601f19603f3d011682016040523d82523d6000602084013e612b23565b606091505b5050905080612b49578183604051630d41accb60e21b8152600401610f679291906138bc565b50610f10565b610f108282612e94565b6006546001600160a01b03163314611852573360405163118cdaa760e01b8152600401610f679190613511565b60006040516323b872dd60e01b81526001600160a01b03851660048201526001600160a01b03841660248201528260448201526020600060648360008a5af1915081601f3d1160016000511416151615612be3573d863b15171591505b5080612c015760405162461bcd60e51b8152600401610f67906142fe565b5050505050565b8060026000828254612c1a9190613839565b90915550506001600160a01b0382166000818152600360205260408082208054850190555160008051602061436983398151915290612c5a90859061309a565b60405180910390a35050565b610f10826126fd565b600680546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b612d1983846001600160a01b031663a9059cbb8585604051602401612ce79291906138bc565b604051602081830303815290604052915060e01b6020820180516001600160e01b038381831617835250505050612f49565b505050565b610f108230612e94565b6001600160a01b03821660009081526003602052604081208054839290612d5090849061384c565b90915550506002805482900390556040516000906001600160a01b0384169060008051602061436983398151915290612c5a90859061309a565b600060405163a9059cbb60e01b81526001600160a01b0384166004820152826024820152602060006044836000895af1915081601f3d1160016000511416151615612dd8573d853b15171591505b5080612df65760405162461bcd60e51b8152600401610f6790614334565b50505050565b604051636eb1769f60e11b81526000906001600160a01b0385169063dd62ed3e90612e2d9030908790600401613d8c565b602060405180830381865afa158015612e4a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e6e9190613802565b9050612df68484612e7f8585613839565b612fb1565b6000828218828411028218610dd4565b600a54604051632d182be560e21b81526001600160a01b039091169063b460af9490612ec890859085903090600401613f82565b6020604051808303816000875af1158015612ee7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f0b9190613802565b50600a546040517fbbbb987b866f90a30aa2441be3781842fb93cc31c782aeeb5644a525865efe7f916117719185916001600160a01b031690614194565b600080602060008451602086016000885af180612f6c576040513d6000823e3d81fd5b50506000513d91508115612f84578060011415612f91565b6001600160a01b0384163b155b15612df65783604051635274afe760e01b8152600401610f679190613511565b6000836001600160a01b031663095ea7b38484604051602401612fd59291906138bc565b604051602081830303815290604052915060e01b6020820180516001600160e01b038381831617835250505050905061300e8482613043565b612df65761303984856001600160a01b031663095ea7b3866000604051602401612ce792919061434d565b612df68482612f49565b6000806000806020600086516020880160008a5af192503d91506000519050828015613088575081156130795780600114613088565b6000866001600160a01b03163b115b9695505050505050565b805b82525050565b60208101610e408284613092565b60005b838110156130c35781810151838201526020016130ab565b50506000910152565b60006130d6825190565b8084526020840193506130ed8185602086016130a8565b601f01601f19169290920192915050565b60208082528101610dd481846130cc565b805b8114610f1257600080fd5b8035610e408161310f565b60006020828403121561313c5761313c600080fd5b6000613148848461311c565b949350505050565b60006001600160a01b038216610e40565b61311181613150565b8035610e4081613161565b6000806040838503121561318b5761318b600080fd5b6000613197858561316a565b92505060206131a88582860161311c565b9150509250929050565b801515613094565b60208101610e4082846131b2565b63ffffffff8116613111565b8035610e40816131c8565b600080604083850312156131f5576131f5600080fd5b600061320185856131d4565b92505060206131a88582860161316a565b60008060006060848603121561322a5761322a600080fd5b6000613236868661316a565b93505060206132478682870161316a565b92505060406132588682870161311c565b9150509250925092565b60ff8116613094565b60208101610e408284613262565b6000610e406001600160a01b038316613290565b90565b6001600160a01b031690565b6000610e4082613279565b6000610e408261329c565b613094816132a7565b60208101610e4082846132b2565b6000602082840312156132de576132de600080fd5b6000613148848461316a565b60008083601f8401126132ff576132ff600080fd5b50813567ffffffffffffffff81111561331a5761331a600080fd5b60208301915083600182028301111561333557613335600080fd5b9250929050565b6000806000806060858703121561335557613355600080fd5b600061336187876131d4565b94505060206133728782880161311c565b935050604085013567ffffffffffffffff81111561339257613392600080fd5b61339e878288016132ea565b95989497509550505050565b63ffffffff8116613094565b61309481613150565b61010081016133ce828b6133aa565b6133db602083018a6133b6565b6133e860408301896133b6565b6133f56060830188613092565b6134026080830187613092565b61340f60a08301866133b6565b61341c60c08301856133aa565b61342960e08301846133aa565b9998505050505050505050565b6000806040838503121561344c5761344c600080fd5b6000613201858561311c565b62ffffff8116613111565b8035610e4081613458565b65ffffffffffff8116613111565b8035610e408161346e565b60008060008060008060c087890312156134a3576134a3600080fd5b60006134af898961316a565b96505060206134c089828a0161311c565b95505060406134d189828a01613463565b94505060606134e289828a01613463565b93505060806134f389828a0161347c565b92505060a061350489828a0161311c565b9150509295509295509295565b60208101610e4082846133b6565b60008060006060848603121561353757613537600080fd5b600061323686866131d4565b60008060006060848603121561355b5761355b600080fd5b6000613567868661311c565b93505060206135788682870161316a565b92505060406132588682870161316a565b6000806000606084860312156135a1576135a1600080fd5b60006135ad868661316a565b93505060206132478682870161311c565b600080600080606085870312156135d7576135d7600080fd5b60006135e387876131d4565b94505060206133728782880161316a565b634e487b7160e01b600052604160045260246000fd5b601f19601f830116810181811067ffffffffffffffff82111715613630576136306135f4565b6040525050565b600061364260405190565b905061364e828261360a565b919050565b600060e0828403121561366857613668600080fd5b61367260e0613637565b90506000613680848461316a565b8252506020613691848483016131d4565b60208301525060406136a58482850161316a565b60408301525060606136b98482850161316a565b60608301525060806136cd8482850161311c565b60808301525060a06136e1848285016131d4565b60a08301525060c06136f5848285016131d4565b60c08301525092915050565b600060e0828403121561371657613716600080fd5b60006131488484613653565b60ff8116613111565b8035610e4081613722565b600080600080600080600060e0888a03121561375457613754600080fd5b60006137608a8a61316a565b97505060206137718a828b0161316a565b96505060406137828a828b0161311c565b95505060606137938a828b0161311c565b94505060806137a48a828b0161372b565b93505060a06137b58a828b0161311c565b92505060c06137c68a828b0161311c565b91505092959891949750929550565b600080604083850312156137eb576137eb600080fd5b6000613201858561316a565b8051610e408161310f565b60006020828403121561381757613817600080fd5b600061314884846137f7565b634e487b7160e01b600052601160045260246000fd5b80820180821115610e4057610e40613823565b81810381811115610e4057610e40613823565b634e487b7160e01b600052602260045260246000fd5b60028104600182168061388957607f821691505b60208210810361389b5761389b61385f565b50919050565b604081016138af82856133aa565b610dd460208301846133b6565b604081016138ca82856133b6565b610dd46020830184613092565b8181028082158382048514176138ef576138ef613823565b5092915050565b634e487b7160e01b600052601260045260246000fd5b60008261391b5761391b6138f6565b500490565b6060810161392e82866133aa565b61393b6020830185613092565b6131486040830184613092565b60a0810161395682886133aa565b61396360208301876133b6565b6139706040830186613092565b61397d6060830185613092565b61308860808301846133b6565b60006080828403121561399f5761399f600080fd5b6139a96080613637565b905060006139b7848461311c565b82525060206139c88484830161316a565b60208301525060406139dc8482850161311c565b60408301525060606139f08482850161311c565b60608301525092915050565b600060808284031215613a1157613a11600080fd5b6000613148848461398a565b60a08101613a2b82886133aa565b613a3860208301876133b6565b613a456040830186613092565b613a526060830185613092565b61308860808301846133aa565b60608101613a6d82866133aa565b61393b60208301856133b6565b6000610e4061328d8381565b613a8f83613a7a565b815460001960089490940293841b1916921b91909117905550565b6000612d19818484613a86565b81811015610f1057613aca600082613aaa565b600101613ab7565b601f821115612d19576000818152602090206020601f85010481016020851015613af95750805b612c016020601f860104830182613ab7565b8267ffffffffffffffff811115613b2457613b246135f4565b613b2e8254613875565b613b39828285613ad2565b6000601f831160018114613b6d5760008415613b555750858201355b600019600886021c198116600286021786555061226a565b600085815260208120601f198616915b82811015613b9d5788850135825560209485019460019092019101613b7d565b86831015613bb957600019601f88166008021c19858a01351682555b60016002880201885550505050505050505050565b60c08101613bdc82896133aa565b613be960208301886133b6565b613bf66040830187613092565b613c036060830186613092565b613c1060808301856133b6565b613c1d60a0830184613092565b979650505050505050565b6000610e40825b63ffffffff1690565b6000610e406132908360201c90565b6000610e4082613290565b600081610e40565b6000610e40613c2f8360a01c90565b6000610e40613c2f8360c01c90565b8054610100830190613c8981613c28565b613c9385826133aa565b50613c9d81613c38565b613caa60208601826133b6565b50506001820154613cba81613c47565b613cc760408601826133b6565b50506002820154613cd781613c52565b613ce46060860182613092565b50506003820154613cf481613c52565b613d016080860182613092565b50506004820154613d1181613c47565b613d1e60a08601826133b6565b50613d2881613c5a565b613d3560c08601826133aa565b50613d3f81613c69565b612c0160e08601826133aa565b6101608101613d5b82876132b2565b613d686020830186613092565b613d756040830185613c78565b613d83610140830184613092565b95945050505050565b604081016138af82856133b6565b600b81526000602082016a5a45524f5f53484152455360a81b815291505b5060200190565b60208082528101610e4081613d9a565b604081016138ca8285613092565b62ffffff8116613094565b65ffffffffffff8116613094565b60a08101613e0482886133b6565b613e116020830187613ddd565b613e1e6040830186613ddd565b613e2b6060830185613de8565b6130886080830184613092565b8051610e4081613722565b600060208284031215613e5857613e58600080fd5b60006131488484613e38565b80825b6001851115613ea357808604811115613e8257613e82613823565b6001851615613e9057908102905b8002613e9c8560011c90565b9450613e67565b94509492505050565b600082613ebb57506001610dd4565b81613ec857506000610dd4565b8160018114613ede5760028114613ee857613f15565b6001915050610dd4565b60ff841115613ef957613ef9613823565b8360020a915084821115613f0f57613f0f613823565b50610dd4565b5060208310610133831016604e8410600b8410161715613f43575081810a83811115610dcd57610dcd613823565b613f508484846001613e64565b92509050818404811115613f6657613f66613823565b0292915050565b600060ff83169250610dd46000198484613eac565b60608101613f908286613092565b613f9d60208301856133b6565b61314860408301846133b6565b600b81526000602082016a5a45524f5f41535345545360a81b81529150613db8565b60208082528101610e4081613faa565b805160e0830190613fed84826133b6565b50602082015161400060208501826133aa565b50604082015161401360408501826133b6565b50606082015161402660608501826133b6565b5060808201516140396080850182613092565b5060a082015161404c60a08501826133aa565b5060c0820151612df660c08501826133aa565b60e08101610e408284613fdc565b601781526000602082017f5045524d49545f444541444c494e455f4558504952454400000000000000000081529150613db8565b60208082528101610e408161406d565b60c081016140bf8289613092565b6140cc60208301886133b6565b6140d960408301876133b6565b6140e66060830186613092565b613c106080830185613092565b80613094565b61190160f01b8152600201600061411082856140f3565b60208201915061412082846140f3565b5060200192915050565b608081016141388287613092565b6141456020830186613262565b6141526040830185613092565b613d836060830184613092565b600e81526000602082016d24a72b20a624a22fa9a4a3a722a960911b81529150613db8565b60208082528101610e408161415f565b604081016138af8285613092565b61018081016141b18288613092565b6141be6020830187613092565b6141cb6040830186613c78565b6141d9610140830185613092565b613088610160830184613092565b600081546141f481613875565b60018216801561420b576001811461422057614250565b60ff1983168652811515820286019350614250565b60008581526020902060005b838110156142485781548882015260019091019060200161422c565b838801955050505b50505092915050565b6000610dd482846141e7565b60a081016142738288613092565b6139636020830187613092565b60208082528101610e4081602481527f5479706543617374733a2062797465733332546f41646472657373206f766572602082015263666c6f7760e01b604082015260600190565b6000610e408261328d565b60148152600060208201731514905394d1915497d19493d357d1905253115160621b81529150613db8565b60208082528101610e40816142d3565b600f81526000602082016e1514905394d1915497d19052531151608a1b81529150613db8565b60208082528101610e408161430e565b61309481613a7a565b6040810161435b82856133b6565b610dd4602083018461434456feddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa26469706673582212202761672aef9bf72d16ba38dd11e42f89681346889f04ab00ed79c14ccf3b7a3d64736f6c634300081c0033

Verified Source Code Full Match

Compiler: v0.8.28+commit.7893614a EVM: paris
Ownable.sol 100 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)

pragma solidity ^0.8.20;

import {Context} from "../utils/Context.sol";

/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * The initial owner is set to the address provided by the deployer. This can
 * later be changed with {transferOwnership}.
 *
 * This module is used through inheritance. It will make available the modifier
 * `onlyOwner`, which can be applied to your functions to restrict their use to
 * the owner.
 */
abstract contract Ownable is Context {
    address private _owner;

    /**
     * @dev The caller account is not authorized to perform an operation.
     */
    error OwnableUnauthorizedAccount(address account);

    /**
     * @dev The owner is not a valid owner account. (eg. `address(0)`)
     */
    error OwnableInvalidOwner(address owner);

    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    /**
     * @dev Initializes the contract setting the address provided by the deployer as the initial owner.
     */
    constructor(address initialOwner) {
        if (initialOwner == address(0)) {
            revert OwnableInvalidOwner(address(0));
        }
        _transferOwnership(initialOwner);
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        _checkOwner();
        _;
    }

    /**
     * @dev Returns the address of the current owner.
     */
    function owner() public view virtual returns (address) {
        return _owner;
    }

    /**
     * @dev Throws if the sender is not the owner.
     */
    function _checkOwner() internal view virtual {
        if (owner() != _msgSender()) {
            revert OwnableUnauthorizedAccount(_msgSender());
        }
    }

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby disabling any functionality that is only available to the owner.
     */
    function renounceOwnership() public virtual onlyOwner {
        _transferOwnership(address(0));
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual onlyOwner {
        if (newOwner == address(0)) {
            revert OwnableInvalidOwner(address(0));
        }
        _transferOwnership(newOwner);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Internal function without access restriction.
     */
    function _transferOwnership(address newOwner) internal virtual {
        address oldOwner = _owner;
        _owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }
}
IERC1363.sol 86 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (interfaces/IERC1363.sol)

pragma solidity ^0.8.20;

import {IERC20} from "./IERC20.sol";
import {IERC165} from "./IERC165.sol";

/**
 * @title IERC1363
 * @dev Interface of the ERC-1363 standard as defined in the https://eips.ethereum.org/EIPS/eip-1363[ERC-1363].
 *
 * Defines an extension interface for ERC-20 tokens that supports executing code on a recipient contract
 * after `transfer` or `transferFrom`, or code on a spender contract after `approve`, in a single transaction.
 */
interface IERC1363 is IERC20, IERC165 {
    /*
     * Note: the ERC-165 identifier for this interface is 0xb0202a11.
     * 0xb0202a11 ===
     *   bytes4(keccak256('transferAndCall(address,uint256)')) ^
     *   bytes4(keccak256('transferAndCall(address,uint256,bytes)')) ^
     *   bytes4(keccak256('transferFromAndCall(address,address,uint256)')) ^
     *   bytes4(keccak256('transferFromAndCall(address,address,uint256,bytes)')) ^
     *   bytes4(keccak256('approveAndCall(address,uint256)')) ^
     *   bytes4(keccak256('approveAndCall(address,uint256,bytes)'))
     */

    /**
     * @dev Moves a `value` amount of tokens from the caller's account to `to`
     * and then calls {IERC1363Receiver-onTransferReceived} on `to`.
     * @param to The address which you want to transfer to.
     * @param value The amount of tokens to be transferred.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function transferAndCall(address to, uint256 value) external returns (bool);

    /**
     * @dev Moves a `value` amount of tokens from the caller's account to `to`
     * and then calls {IERC1363Receiver-onTransferReceived} on `to`.
     * @param to The address which you want to transfer to.
     * @param value The amount of tokens to be transferred.
     * @param data Additional data with no specified format, sent in call to `to`.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function transferAndCall(address to, uint256 value, bytes calldata data) external returns (bool);

    /**
     * @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism
     * and then calls {IERC1363Receiver-onTransferReceived} on `to`.
     * @param from The address which you want to send tokens from.
     * @param to The address which you want to transfer to.
     * @param value The amount of tokens to be transferred.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function transferFromAndCall(address from, address to, uint256 value) external returns (bool);

    /**
     * @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism
     * and then calls {IERC1363Receiver-onTransferReceived} on `to`.
     * @param from The address which you want to send tokens from.
     * @param to The address which you want to transfer to.
     * @param value The amount of tokens to be transferred.
     * @param data Additional data with no specified format, sent in call to `to`.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function transferFromAndCall(address from, address to, uint256 value, bytes calldata data) external returns (bool);

    /**
     * @dev Sets a `value` amount of tokens as the allowance of `spender` over the
     * caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.
     * @param spender The address which will spend the funds.
     * @param value The amount of tokens to be spent.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function approveAndCall(address spender, uint256 value) external returns (bool);

    /**
     * @dev Sets a `value` amount of tokens as the allowance of `spender` over the
     * caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.
     * @param spender The address which will spend the funds.
     * @param value The amount of tokens to be spent.
     * @param data Additional data with no specified format, sent in call to `spender`.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function approveAndCall(address spender, uint256 value, bytes calldata data) external returns (bool);
}
IERC165.sol 6 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC165.sol)

pragma solidity ^0.8.20;

import {IERC165} from "../utils/introspection/IERC165.sol";
IERC20.sol 6 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC20.sol)

pragma solidity ^0.8.20;

import {IERC20} from "../token/ERC20/IERC20.sol";
IERC20.sol 79 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.20;

/**
 * @dev Interface of the ERC-20 standard as defined in the ERC.
 */
interface IERC20 {
    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

    /**
     * @dev Emitted when the allowance of a `spender` for an `owner` is set by
     * a call to {approve}. `value` is the new allowance.
     */
    event Approval(address indexed owner, address indexed spender, uint256 value);

    /**
     * @dev Returns the value of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns the value of tokens owned by `account`.
     */
    function balanceOf(address account) external view returns (uint256);

    /**
     * @dev Moves a `value` amount of tokens from the caller's account to `to`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address to, uint256 value) external returns (bool);

    /**
     * @dev Returns the remaining number of tokens that `spender` will be
     * allowed to spend on behalf of `owner` through {transferFrom}. This is
     * zero by default.
     *
     * This value changes when {approve} or {transferFrom} are called.
     */
    function allowance(address owner, address spender) external view returns (uint256);

    /**
     * @dev Sets a `value` amount of tokens as the allowance of `spender` over the
     * caller's tokens.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * IMPORTANT: Beware that changing an allowance with this method brings the risk
     * that someone may use both the old and the new allowance by unfortunate
     * transaction ordering. One possible solution to mitigate this race
     * condition is to first reduce the spender's allowance to 0 and set the
     * desired value afterwards:
     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
     *
     * Emits an {Approval} event.
     */
    function approve(address spender, uint256 value) external returns (bool);

    /**
     * @dev Moves a `value` amount of tokens from `from` to `to` using the
     * allowance mechanism. `value` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(address from, address to, uint256 value) external returns (bool);
}
SafeERC20.sol 212 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.3.0) (token/ERC20/utils/SafeERC20.sol)

pragma solidity ^0.8.20;

import {IERC20} from "../IERC20.sol";
import {IERC1363} from "../../../interfaces/IERC1363.sol";

/**
 * @title SafeERC20
 * @dev Wrappers around ERC-20 operations that throw on failure (when the token
 * contract returns false). Tokens that return no value (and instead revert or
 * throw on failure) are also supported, non-reverting calls are assumed to be
 * successful.
 * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
 * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
 */
library SafeERC20 {
    /**
     * @dev An operation with an ERC-20 token failed.
     */
    error SafeERC20FailedOperation(address token);

    /**
     * @dev Indicates a failed `decreaseAllowance` request.
     */
    error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);

    /**
     * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
     * non-reverting calls are assumed to be successful.
     */
    function safeTransfer(IERC20 token, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));
    }

    /**
     * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
     * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
     */
    function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));
    }

    /**
     * @dev Variant of {safeTransfer} that returns a bool instead of reverting if the operation is not successful.
     */
    function trySafeTransfer(IERC20 token, address to, uint256 value) internal returns (bool) {
        return _callOptionalReturnBool(token, abi.encodeCall(token.transfer, (to, value)));
    }

    /**
     * @dev Variant of {safeTransferFrom} that returns a bool instead of reverting if the operation is not successful.
     */
    function trySafeTransferFrom(IERC20 token, address from, address to, uint256 value) internal returns (bool) {
        return _callOptionalReturnBool(token, abi.encodeCall(token.transferFrom, (from, to, value)));
    }

    /**
     * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
     * non-reverting calls are assumed to be successful.
     *
     * IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client"
     * smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using
     * this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract
     * that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.
     */
    function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
        uint256 oldAllowance = token.allowance(address(this), spender);
        forceApprove(token, spender, oldAllowance + value);
    }

    /**
     * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no
     * value, non-reverting calls are assumed to be successful.
     *
     * IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client"
     * smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using
     * this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract
     * that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.
     */
    function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {
        unchecked {
            uint256 currentAllowance = token.allowance(address(this), spender);
            if (currentAllowance < requestedDecrease) {
                revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);
            }
            forceApprove(token, spender, currentAllowance - requestedDecrease);
        }
    }

    /**
     * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
     * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
     * to be set to zero before setting it to a non-zero value, such as USDT.
     *
     * NOTE: If the token implements ERC-7674, this function will not modify any temporary allowance. This function
     * only sets the "standard" allowance. Any temporary allowance will remain active, in addition to the value being
     * set here.
     */
    function forceApprove(IERC20 token, address spender, uint256 value) internal {
        bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));

        if (!_callOptionalReturnBool(token, approvalCall)) {
            _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));
            _callOptionalReturn(token, approvalCall);
        }
    }

    /**
     * @dev Performs an {ERC1363} transferAndCall, with a fallback to the simple {ERC20} transfer if the target has no
     * code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
     * targeting contracts.
     *
     * Reverts if the returned value is other than `true`.
     */
    function transferAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {
        if (to.code.length == 0) {
            safeTransfer(token, to, value);
        } else if (!token.transferAndCall(to, value, data)) {
            revert SafeERC20FailedOperation(address(token));
        }
    }

    /**
     * @dev Performs an {ERC1363} transferFromAndCall, with a fallback to the simple {ERC20} transferFrom if the target
     * has no code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
     * targeting contracts.
     *
     * Reverts if the returned value is other than `true`.
     */
    function transferFromAndCallRelaxed(
        IERC1363 token,
        address from,
        address to,
        uint256 value,
        bytes memory data
    ) internal {
        if (to.code.length == 0) {
            safeTransferFrom(token, from, to, value);
        } else if (!token.transferFromAndCall(from, to, value, data)) {
            revert SafeERC20FailedOperation(address(token));
        }
    }

    /**
     * @dev Performs an {ERC1363} approveAndCall, with a fallback to the simple {ERC20} approve if the target has no
     * code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
     * targeting contracts.
     *
     * NOTE: When the recipient address (`to`) has no code (i.e. is an EOA), this function behaves as {forceApprove}.
     * Opposedly, when the recipient address (`to`) has code, this function only attempts to call {ERC1363-approveAndCall}
     * once without retrying, and relies on the returned value to be true.
     *
     * Reverts if the returned value is other than `true`.
     */
    function approveAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {
        if (to.code.length == 0) {
            forceApprove(token, to, value);
        } else if (!token.approveAndCall(to, value, data)) {
            revert SafeERC20FailedOperation(address(token));
        }
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     *
     * This is a variant of {_callOptionalReturnBool} that reverts if call fails to meet the requirements.
     */
    function _callOptionalReturn(IERC20 token, bytes memory data) private {
        uint256 returnSize;
        uint256 returnValue;
        assembly ("memory-safe") {
            let success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)
            // bubble errors
            if iszero(success) {
                let ptr := mload(0x40)
                returndatacopy(ptr, 0, returndatasize())
                revert(ptr, returndatasize())
            }
            returnSize := returndatasize()
            returnValue := mload(0)
        }

        if (returnSize == 0 ? address(token).code.length == 0 : returnValue != 1) {
            revert SafeERC20FailedOperation(address(token));
        }
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     *
     * This is a variant of {_callOptionalReturn} that silently catches all reverts and returns a bool instead.
     */
    function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
        bool success;
        uint256 returnSize;
        uint256 returnValue;
        assembly ("memory-safe") {
            success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)
            returnSize := returndatasize()
            returnValue := mload(0)
        }
        return success && (returnSize == 0 ? address(token).code.length > 0 : returnValue == 1);
    }
}
Context.sol 28 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)

pragma solidity ^0.8.20;

/**
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
abstract contract Context {
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes calldata) {
        return msg.data;
    }

    function _contextSuffixLength() internal view virtual returns (uint256) {
        return 0;
    }
}
IERC165.sol 25 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/introspection/IERC165.sol)

pragma solidity ^0.8.20;

/**
 * @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);
}
Math.sol 749 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.3.0) (utils/math/Math.sol)

pragma solidity ^0.8.20;

import {Panic} from "../Panic.sol";
import {SafeCast} from "./SafeCast.sol";

/**
 * @dev Standard math utilities missing in the Solidity language.
 */
library Math {
    enum Rounding {
        Floor, // Toward negative infinity
        Ceil, // Toward positive infinity
        Trunc, // Toward zero
        Expand // Away from zero
    }

    /**
     * @dev Return the 512-bit addition of two uint256.
     *
     * The result is stored in two 256 variables such that sum = high * 2²⁵⁶ + low.
     */
    function add512(uint256 a, uint256 b) internal pure returns (uint256 high, uint256 low) {
        assembly ("memory-safe") {
            low := add(a, b)
            high := lt(low, a)
        }
    }

    /**
     * @dev Return the 512-bit multiplication of two uint256.
     *
     * The result is stored in two 256 variables such that product = high * 2²⁵⁶ + low.
     */
    function mul512(uint256 a, uint256 b) internal pure returns (uint256 high, uint256 low) {
        // 512-bit multiply [high low] = x * y. Compute the product mod 2²⁵⁶ and mod 2²⁵⁶ - 1, then use
        // the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
        // variables such that product = high * 2²⁵⁶ + low.
        assembly ("memory-safe") {
            let mm := mulmod(a, b, not(0))
            low := mul(a, b)
            high := sub(sub(mm, low), lt(mm, low))
        }
    }

    /**
     * @dev Returns the addition of two unsigned integers, with a success flag (no overflow).
     */
    function tryAdd(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {
        unchecked {
            uint256 c = a + b;
            success = c >= a;
            result = c * SafeCast.toUint(success);
        }
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, with a success flag (no overflow).
     */
    function trySub(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {
        unchecked {
            uint256 c = a - b;
            success = c <= a;
            result = c * SafeCast.toUint(success);
        }
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, with a success flag (no overflow).
     */
    function tryMul(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {
        unchecked {
            uint256 c = a * b;
            assembly ("memory-safe") {
                // Only true when the multiplication doesn't overflow
                // (c / a == b) || (a == 0)
                success := or(eq(div(c, a), b), iszero(a))
            }
            // equivalent to: success ? c : 0
            result = c * SafeCast.toUint(success);
        }
    }

    /**
     * @dev Returns the division of two unsigned integers, with a success flag (no division by zero).
     */
    function tryDiv(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {
        unchecked {
            success = b > 0;
            assembly ("memory-safe") {
                // The `DIV` opcode returns zero when the denominator is 0.
                result := div(a, b)
            }
        }
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers, with a success flag (no division by zero).
     */
    function tryMod(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {
        unchecked {
            success = b > 0;
            assembly ("memory-safe") {
                // The `MOD` opcode returns zero when the denominator is 0.
                result := mod(a, b)
            }
        }
    }

    /**
     * @dev Unsigned saturating addition, bounds to `2²⁵⁶ - 1` instead of overflowing.
     */
    function saturatingAdd(uint256 a, uint256 b) internal pure returns (uint256) {
        (bool success, uint256 result) = tryAdd(a, b);
        return ternary(success, result, type(uint256).max);
    }

    /**
     * @dev Unsigned saturating subtraction, bounds to zero instead of overflowing.
     */
    function saturatingSub(uint256 a, uint256 b) internal pure returns (uint256) {
        (, uint256 result) = trySub(a, b);
        return result;
    }

    /**
     * @dev Unsigned saturating multiplication, bounds to `2²⁵⁶ - 1` instead of overflowing.
     */
    function saturatingMul(uint256 a, uint256 b) internal pure returns (uint256) {
        (bool success, uint256 result) = tryMul(a, b);
        return ternary(success, result, type(uint256).max);
    }

    /**
     * @dev Branchless ternary evaluation for `a ? b : c`. Gas costs are constant.
     *
     * IMPORTANT: This function may reduce bytecode size and consume less gas when used standalone.
     * However, the compiler may optimize Solidity ternary operations (i.e. `a ? b : c`) to only compute
     * one branch when needed, making this function more expensive.
     */
    function ternary(bool condition, uint256 a, uint256 b) internal pure returns (uint256) {
        unchecked {
            // branchless ternary works because:
            // b ^ (a ^ b) == a
            // b ^ 0 == b
            return b ^ ((a ^ b) * SafeCast.toUint(condition));
        }
    }

    /**
     * @dev Returns the largest of two numbers.
     */
    function max(uint256 a, uint256 b) internal pure returns (uint256) {
        return ternary(a > b, a, b);
    }

    /**
     * @dev Returns the smallest of two numbers.
     */
    function min(uint256 a, uint256 b) internal pure returns (uint256) {
        return ternary(a < b, a, b);
    }

    /**
     * @dev Returns the average of two numbers. The result is rounded towards
     * zero.
     */
    function average(uint256 a, uint256 b) internal pure returns (uint256) {
        // (a + b) / 2 can overflow.
        return (a & b) + (a ^ b) / 2;
    }

    /**
     * @dev Returns the ceiling of the division of two numbers.
     *
     * This differs from standard division with `/` in that it rounds towards infinity instead
     * of rounding towards zero.
     */
    function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
        if (b == 0) {
            // Guarantee the same behavior as in a regular Solidity division.
            Panic.panic(Panic.DIVISION_BY_ZERO);
        }

        // The following calculation ensures accurate ceiling division without overflow.
        // Since a is non-zero, (a - 1) / b will not overflow.
        // The largest possible result occurs when (a - 1) / b is type(uint256).max,
        // but the largest value we can obtain is type(uint256).max - 1, which happens
        // when a = type(uint256).max and b = 1.
        unchecked {
            return SafeCast.toUint(a > 0) * ((a - 1) / b + 1);
        }
    }

    /**
     * @dev Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or
     * denominator == 0.
     *
     * Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) with further edits by
     * Uniswap Labs also under MIT license.
     */
    function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
        unchecked {
            (uint256 high, uint256 low) = mul512(x, y);

            // Handle non-overflow cases, 256 by 256 division.
            if (high == 0) {
                // Solidity will revert if denominator == 0, unlike the div opcode on its own.
                // The surrounding unchecked block does not change this fact.
                // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.
                return low / denominator;
            }

            // Make sure the result is less than 2²⁵⁶. Also prevents denominator == 0.
            if (denominator <= high) {
                Panic.panic(ternary(denominator == 0, Panic.DIVISION_BY_ZERO, Panic.UNDER_OVERFLOW));
            }

            ///////////////////////////////////////////////
            // 512 by 256 division.
            ///////////////////////////////////////////////

            // Make division exact by subtracting the remainder from [high low].
            uint256 remainder;
            assembly ("memory-safe") {
                // Compute remainder using mulmod.
                remainder := mulmod(x, y, denominator)

                // Subtract 256 bit number from 512 bit number.
                high := sub(high, gt(remainder, low))
                low := sub(low, remainder)
            }

            // Factor powers of two out of denominator and compute largest power of two divisor of denominator.
            // Always >= 1. See https://cs.stackexchange.com/q/138556/92363.

            uint256 twos = denominator & (0 - denominator);
            assembly ("memory-safe") {
                // Divide denominator by twos.
                denominator := div(denominator, twos)

                // Divide [high low] by twos.
                low := div(low, twos)

                // Flip twos such that it is 2²⁵⁶ / twos. If twos is zero, then it becomes one.
                twos := add(div(sub(0, twos), twos), 1)
            }

            // Shift in bits from high into low.
            low |= high * twos;

            // Invert denominator mod 2²⁵⁶. Now that denominator is an odd number, it has an inverse modulo 2²⁵⁶ such
            // that denominator * inv ≡ 1 mod 2²⁵⁶. Compute the inverse by starting with a seed that is correct for
            // four bits. That is, denominator * inv ≡ 1 mod 2⁴.
            uint256 inverse = (3 * denominator) ^ 2;

            // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also
            // works in modular arithmetic, doubling the correct bits in each step.
            inverse *= 2 - denominator * inverse; // inverse mod 2⁸
            inverse *= 2 - denominator * inverse; // inverse mod 2¹⁶
            inverse *= 2 - denominator * inverse; // inverse mod 2³²
            inverse *= 2 - denominator * inverse; // inverse mod 2⁶⁴
            inverse *= 2 - denominator * inverse; // inverse mod 2¹²⁸
            inverse *= 2 - denominator * inverse; // inverse mod 2²⁵⁶

            // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
            // This will give us the correct result modulo 2²⁵⁶. Since the preconditions guarantee that the outcome is
            // less than 2²⁵⁶, this is the final result. We don't need to compute the high bits of the result and high
            // is no longer required.
            result = low * inverse;
            return result;
        }
    }

    /**
     * @dev Calculates x * y / denominator with full precision, following the selected rounding direction.
     */
    function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {
        return mulDiv(x, y, denominator) + SafeCast.toUint(unsignedRoundsUp(rounding) && mulmod(x, y, denominator) > 0);
    }

    /**
     * @dev Calculates floor(x * y >> n) with full precision. Throws if result overflows a uint256.
     */
    function mulShr(uint256 x, uint256 y, uint8 n) internal pure returns (uint256 result) {
        unchecked {
            (uint256 high, uint256 low) = mul512(x, y);
            if (high >= 1 << n) {
                Panic.panic(Panic.UNDER_OVERFLOW);
            }
            return (high << (256 - n)) | (low >> n);
        }
    }

    /**
     * @dev Calculates x * y >> n with full precision, following the selected rounding direction.
     */
    function mulShr(uint256 x, uint256 y, uint8 n, Rounding rounding) internal pure returns (uint256) {
        return mulShr(x, y, n) + SafeCast.toUint(unsignedRoundsUp(rounding) && mulmod(x, y, 1 << n) > 0);
    }

    /**
     * @dev Calculate the modular multiplicative inverse of a number in Z/nZ.
     *
     * If n is a prime, then Z/nZ is a field. In that case all elements are inversible, except 0.
     * If n is not a prime, then Z/nZ is not a field, and some elements might not be inversible.
     *
     * If the input value is not inversible, 0 is returned.
     *
     * NOTE: If you know for sure that n is (big) a prime, it may be cheaper to use Fermat's little theorem and get the
     * inverse using `Math.modExp(a, n - 2, n)`. See {invModPrime}.
     */
    function invMod(uint256 a, uint256 n) internal pure returns (uint256) {
        unchecked {
            if (n == 0) return 0;

            // The inverse modulo is calculated using the Extended Euclidean Algorithm (iterative version)
            // Used to compute integers x and y such that: ax + ny = gcd(a, n).
            // When the gcd is 1, then the inverse of a modulo n exists and it's x.
            // ax + ny = 1
            // ax = 1 + (-y)n
            // ax ≡ 1 (mod n) # x is the inverse of a modulo n

            // If the remainder is 0 the gcd is n right away.
            uint256 remainder = a % n;
            uint256 gcd = n;

            // Therefore the initial coefficients are:
            // ax + ny = gcd(a, n) = n
            // 0a + 1n = n
            int256 x = 0;
            int256 y = 1;

            while (remainder != 0) {
                uint256 quotient = gcd / remainder;

                (gcd, remainder) = (
                    // The old remainder is the next gcd to try.
                    remainder,
                    // Compute the next remainder.
                    // Can't overflow given that (a % gcd) * (gcd // (a % gcd)) <= gcd
                    // where gcd is at most n (capped to type(uint256).max)
                    gcd - remainder * quotient
                );

                (x, y) = (
                    // Increment the coefficient of a.
                    y,
                    // Decrement the coefficient of n.
                    // Can overflow, but the result is casted to uint256 so that the
                    // next value of y is "wrapped around" to a value between 0 and n - 1.
                    x - y * int256(quotient)
                );
            }

            if (gcd != 1) return 0; // No inverse exists.
            return ternary(x < 0, n - uint256(-x), uint256(x)); // Wrap the result if it's negative.
        }
    }

    /**
     * @dev Variant of {invMod}. More efficient, but only works if `p` is known to be a prime greater than `2`.
     *
     * From https://en.wikipedia.org/wiki/Fermat%27s_little_theorem[Fermat's little theorem], we know that if p is
     * prime, then `a**(p-1) ≡ 1 mod p`. As a consequence, we have `a * a**(p-2) ≡ 1 mod p`, which means that
     * `a**(p-2)` is the modular multiplicative inverse of a in Fp.
     *
     * NOTE: this function does NOT check that `p` is a prime greater than `2`.
     */
    function invModPrime(uint256 a, uint256 p) internal view returns (uint256) {
        unchecked {
            return Math.modExp(a, p - 2, p);
        }
    }

    /**
     * @dev Returns the modular exponentiation of the specified base, exponent and modulus (b ** e % m)
     *
     * Requirements:
     * - modulus can't be zero
     * - underlying staticcall to precompile must succeed
     *
     * IMPORTANT: The result is only valid if the underlying call succeeds. When using this function, make
     * sure the chain you're using it on supports the precompiled contract for modular exponentiation
     * at address 0x05 as specified in https://eips.ethereum.org/EIPS/eip-198[EIP-198]. Otherwise,
     * the underlying function will succeed given the lack of a revert, but the result may be incorrectly
     * interpreted as 0.
     */
    function modExp(uint256 b, uint256 e, uint256 m) internal view returns (uint256) {
        (bool success, uint256 result) = tryModExp(b, e, m);
        if (!success) {
            Panic.panic(Panic.DIVISION_BY_ZERO);
        }
        return result;
    }

    /**
     * @dev Returns the modular exponentiation of the specified base, exponent and modulus (b ** e % m).
     * It includes a success flag indicating if the operation succeeded. Operation will be marked as failed if trying
     * to operate modulo 0 or if the underlying precompile reverted.
     *
     * IMPORTANT: The result is only valid if the success flag is true. When using this function, make sure the chain
     * you're using it on supports the precompiled contract for modular exponentiation at address 0x05 as specified in
     * https://eips.ethereum.org/EIPS/eip-198[EIP-198]. Otherwise, the underlying function will succeed given the lack
     * of a revert, but the result may be incorrectly interpreted as 0.
     */
    function tryModExp(uint256 b, uint256 e, uint256 m) internal view returns (bool success, uint256 result) {
        if (m == 0) return (false, 0);
        assembly ("memory-safe") {
            let ptr := mload(0x40)
            // | Offset    | Content    | Content (Hex)                                                      |
            // |-----------|------------|--------------------------------------------------------------------|
            // | 0x00:0x1f | size of b  | 0x0000000000000000000000000000000000000000000000000000000000000020 |
            // | 0x20:0x3f | size of e  | 0x0000000000000000000000000000000000000000000000000000000000000020 |
            // | 0x40:0x5f | size of m  | 0x0000000000000000000000000000000000000000000000000000000000000020 |
            // | 0x60:0x7f | value of b | 0x<.............................................................b> |
            // | 0x80:0x9f | value of e | 0x<.............................................................e> |
            // | 0xa0:0xbf | value of m | 0x<.............................................................m> |
            mstore(ptr, 0x20)
            mstore(add(ptr, 0x20), 0x20)
            mstore(add(ptr, 0x40), 0x20)
            mstore(add(ptr, 0x60), b)
            mstore(add(ptr, 0x80), e)
            mstore(add(ptr, 0xa0), m)

            // Given the result < m, it's guaranteed to fit in 32 bytes,
            // so we can use the memory scratch space located at offset 0.
            success := staticcall(gas(), 0x05, ptr, 0xc0, 0x00, 0x20)
            result := mload(0x00)
        }
    }

    /**
     * @dev Variant of {modExp} that supports inputs of arbitrary length.
     */
    function modExp(bytes memory b, bytes memory e, bytes memory m) internal view returns (bytes memory) {
        (bool success, bytes memory result) = tryModExp(b, e, m);
        if (!success) {
            Panic.panic(Panic.DIVISION_BY_ZERO);
        }
        return result;
    }

    /**
     * @dev Variant of {tryModExp} that supports inputs of arbitrary length.
     */
    function tryModExp(
        bytes memory b,
        bytes memory e,
        bytes memory m
    ) internal view returns (bool success, bytes memory result) {
        if (_zeroBytes(m)) return (false, new bytes(0));

        uint256 mLen = m.length;

        // Encode call args in result and move the free memory pointer
        result = abi.encodePacked(b.length, e.length, mLen, b, e, m);

        assembly ("memory-safe") {
            let dataPtr := add(result, 0x20)
            // Write result on top of args to avoid allocating extra memory.
            success := staticcall(gas(), 0x05, dataPtr, mload(result), dataPtr, mLen)
            // Overwrite the length.
            // result.length > returndatasize() is guaranteed because returndatasize() == m.length
            mstore(result, mLen)
            // Set the memory pointer after the returned data.
            mstore(0x40, add(dataPtr, mLen))
        }
    }

    /**
     * @dev Returns whether the provided byte array is zero.
     */
    function _zeroBytes(bytes memory byteArray) private pure returns (bool) {
        for (uint256 i = 0; i < byteArray.length; ++i) {
            if (byteArray[i] != 0) {
                return false;
            }
        }
        return true;
    }

    /**
     * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded
     * towards zero.
     *
     * This method is based on Newton's method for computing square roots; the algorithm is restricted to only
     * using integer operations.
     */
    function sqrt(uint256 a) internal pure returns (uint256) {
        unchecked {
            // Take care of easy edge cases when a == 0 or a == 1
            if (a <= 1) {
                return a;
            }

            // In this function, we use Newton's method to get a root of `f(x) := x² - a`. It involves building a
            // sequence x_n that converges toward sqrt(a). For each iteration x_n, we also define the error between
            // the current value as `ε_n = | x_n - sqrt(a) |`.
            //
            // For our first estimation, we consider `e` the smallest power of 2 which is bigger than the square root
            // of the target. (i.e. `2**(e-1) ≤ sqrt(a) < 2**e`). We know that `e ≤ 128` because `(2¹²⁸)² = 2²⁵⁶` is
            // bigger than any uint256.
            //
            // By noticing that
            // `2**(e-1) ≤ sqrt(a) < 2**e → (2**(e-1))² ≤ a < (2**e)² → 2**(2*e-2) ≤ a < 2**(2*e)`
            // we can deduce that `e - 1` is `log2(a) / 2`. We can thus compute `x_n = 2**(e-1)` using a method similar
            // to the msb function.
            uint256 aa = a;
            uint256 xn = 1;

            if (aa >= (1 << 128)) {
                aa >>= 128;
                xn <<= 64;
            }
            if (aa >= (1 << 64)) {
                aa >>= 64;
                xn <<= 32;
            }
            if (aa >= (1 << 32)) {
                aa >>= 32;
                xn <<= 16;
            }
            if (aa >= (1 << 16)) {
                aa >>= 16;
                xn <<= 8;
            }
            if (aa >= (1 << 8)) {
                aa >>= 8;
                xn <<= 4;
            }
            if (aa >= (1 << 4)) {
                aa >>= 4;
                xn <<= 2;
            }
            if (aa >= (1 << 2)) {
                xn <<= 1;
            }

            // We now have x_n such that `x_n = 2**(e-1) ≤ sqrt(a) < 2**e = 2 * x_n`. This implies ε_n ≤ 2**(e-1).
            //
            // We can refine our estimation by noticing that the middle of that interval minimizes the error.
            // If we move x_n to equal 2**(e-1) + 2**(e-2), then we reduce the error to ε_n ≤ 2**(e-2).
            // This is going to be our x_0 (and ε_0)
            xn = (3 * xn) >> 1; // ε_0 := | x_0 - sqrt(a) | ≤ 2**(e-2)

            // From here, Newton's method give us:
            // x_{n+1} = (x_n + a / x_n) / 2
            //
            // One should note that:
            // x_{n+1}² - a = ((x_n + a / x_n) / 2)² - a
            //              = ((x_n² + a) / (2 * x_n))² - a
            //              = (x_n⁴ + 2 * a * x_n² + a²) / (4 * x_n²) - a
            //              = (x_n⁴ + 2 * a * x_n² + a² - 4 * a * x_n²) / (4 * x_n²)
            //              = (x_n⁴ - 2 * a * x_n² + a²) / (4 * x_n²)
            //              = (x_n² - a)² / (2 * x_n)²
            //              = ((x_n² - a) / (2 * x_n))²
            //              ≥ 0
            // Which proves that for all n ≥ 1, sqrt(a) ≤ x_n
            //
            // This gives us the proof of quadratic convergence of the sequence:
            // ε_{n+1} = | x_{n+1} - sqrt(a) |
            //         = | (x_n + a / x_n) / 2 - sqrt(a) |
            //         = | (x_n² + a - 2*x_n*sqrt(a)) / (2 * x_n) |
            //         = | (x_n - sqrt(a))² / (2 * x_n) |
            //         = | ε_n² / (2 * x_n) |
            //         = ε_n² / | (2 * x_n) |
            //
            // For the first iteration, we have a special case where x_0 is known:
            // ε_1 = ε_0² / | (2 * x_0) |
            //     ≤ (2**(e-2))² / (2 * (2**(e-1) + 2**(e-2)))
            //     ≤ 2**(2*e-4) / (3 * 2**(e-1))
            //     ≤ 2**(e-3) / 3
            //     ≤ 2**(e-3-log2(3))
            //     ≤ 2**(e-4.5)
            //
            // For the following iterations, we use the fact that, 2**(e-1) ≤ sqrt(a) ≤ x_n:
            // ε_{n+1} = ε_n² / | (2 * x_n) |
            //         ≤ (2**(e-k))² / (2 * 2**(e-1))
            //         ≤ 2**(2*e-2*k) / 2**e
            //         ≤ 2**(e-2*k)
            xn = (xn + a / xn) >> 1; // ε_1 := | x_1 - sqrt(a) | ≤ 2**(e-4.5)  -- special case, see above
            xn = (xn + a / xn) >> 1; // ε_2 := | x_2 - sqrt(a) | ≤ 2**(e-9)    -- general case with k = 4.5
            xn = (xn + a / xn) >> 1; // ε_3 := | x_3 - sqrt(a) | ≤ 2**(e-18)   -- general case with k = 9
            xn = (xn + a / xn) >> 1; // ε_4 := | x_4 - sqrt(a) | ≤ 2**(e-36)   -- general case with k = 18
            xn = (xn + a / xn) >> 1; // ε_5 := | x_5 - sqrt(a) | ≤ 2**(e-72)   -- general case with k = 36
            xn = (xn + a / xn) >> 1; // ε_6 := | x_6 - sqrt(a) | ≤ 2**(e-144)  -- general case with k = 72

            // Because e ≤ 128 (as discussed during the first estimation phase), we know have reached a precision
            // ε_6 ≤ 2**(e-144) < 1. Given we're operating on integers, then we can ensure that xn is now either
            // sqrt(a) or sqrt(a) + 1.
            return xn - SafeCast.toUint(xn > a / xn);
        }
    }

    /**
     * @dev Calculates sqrt(a), following the selected rounding direction.
     */
    function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = sqrt(a);
            return result + SafeCast.toUint(unsignedRoundsUp(rounding) && result * result < a);
        }
    }

    /**
     * @dev Return the log in base 2 of a positive value rounded towards zero.
     * Returns 0 if given 0.
     */
    function log2(uint256 x) internal pure returns (uint256 r) {
        // If value has upper 128 bits set, log2 result is at least 128
        r = SafeCast.toUint(x > 0xffffffffffffffffffffffffffffffff) << 7;
        // If upper 64 bits of 128-bit half set, add 64 to result
        r |= SafeCast.toUint((x >> r) > 0xffffffffffffffff) << 6;
        // If upper 32 bits of 64-bit half set, add 32 to result
        r |= SafeCast.toUint((x >> r) > 0xffffffff) << 5;
        // If upper 16 bits of 32-bit half set, add 16 to result
        r |= SafeCast.toUint((x >> r) > 0xffff) << 4;
        // If upper 8 bits of 16-bit half set, add 8 to result
        r |= SafeCast.toUint((x >> r) > 0xff) << 3;
        // If upper 4 bits of 8-bit half set, add 4 to result
        r |= SafeCast.toUint((x >> r) > 0xf) << 2;

        // Shifts value right by the current result and use it as an index into this lookup table:
        //
        // | x (4 bits) |  index  | table[index] = MSB position |
        // |------------|---------|-----------------------------|
        // |    0000    |    0    |        table[0] = 0         |
        // |    0001    |    1    |        table[1] = 0         |
        // |    0010    |    2    |        table[2] = 1         |
        // |    0011    |    3    |        table[3] = 1         |
        // |    0100    |    4    |        table[4] = 2         |
        // |    0101    |    5    |        table[5] = 2         |
        // |    0110    |    6    |        table[6] = 2         |
        // |    0111    |    7    |        table[7] = 2         |
        // |    1000    |    8    |        table[8] = 3         |
        // |    1001    |    9    |        table[9] = 3         |
        // |    1010    |   10    |        table[10] = 3        |
        // |    1011    |   11    |        table[11] = 3        |
        // |    1100    |   12    |        table[12] = 3        |
        // |    1101    |   13    |        table[13] = 3        |
        // |    1110    |   14    |        table[14] = 3        |
        // |    1111    |   15    |        table[15] = 3        |
        //
        // The lookup table is represented as a 32-byte value with the MSB positions for 0-15 in the last 16 bytes.
        assembly ("memory-safe") {
            r := or(r, byte(shr(r, x), 0x0000010102020202030303030303030300000000000000000000000000000000))
        }
    }

    /**
     * @dev Return the log in base 2, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log2(value);
            return result + SafeCast.toUint(unsignedRoundsUp(rounding) && 1 << result < value);
        }
    }

    /**
     * @dev Return the log in base 10 of a positive value rounded towards zero.
     * Returns 0 if given 0.
     */
    function log10(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >= 10 ** 64) {
                value /= 10 ** 64;
                result += 64;
            }
            if (value >= 10 ** 32) {
                value /= 10 ** 32;
                result += 32;
            }
            if (value >= 10 ** 16) {
                value /= 10 ** 16;
                result += 16;
            }
            if (value >= 10 ** 8) {
                value /= 10 ** 8;
                result += 8;
            }
            if (value >= 10 ** 4) {
                value /= 10 ** 4;
                result += 4;
            }
            if (value >= 10 ** 2) {
                value /= 10 ** 2;
                result += 2;
            }
            if (value >= 10 ** 1) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 10, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log10(value);
            return result + SafeCast.toUint(unsignedRoundsUp(rounding) && 10 ** result < value);
        }
    }

    /**
     * @dev Return the log in base 256 of a positive value rounded towards zero.
     * Returns 0 if given 0.
     *
     * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
     */
    function log256(uint256 x) internal pure returns (uint256 r) {
        // If value has upper 128 bits set, log2 result is at least 128
        r = SafeCast.toUint(x > 0xffffffffffffffffffffffffffffffff) << 7;
        // If upper 64 bits of 128-bit half set, add 64 to result
        r |= SafeCast.toUint((x >> r) > 0xffffffffffffffff) << 6;
        // If upper 32 bits of 64-bit half set, add 32 to result
        r |= SafeCast.toUint((x >> r) > 0xffffffff) << 5;
        // If upper 16 bits of 32-bit half set, add 16 to result
        r |= SafeCast.toUint((x >> r) > 0xffff) << 4;
        // Add 1 if upper 8 bits of 16-bit half set, and divide accumulated result by 8
        return (r >> 3) | SafeCast.toUint((x >> r) > 0xff);
    }

    /**
     * @dev Return the log in base 256, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log256(value);
            return result + SafeCast.toUint(unsignedRoundsUp(rounding) && 1 << (result << 3) < value);
        }
    }

    /**
     * @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers.
     */
    function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) {
        return uint8(rounding) % 2 == 1;
    }
}
SafeCast.sol 1162 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/math/SafeCast.sol)
// This file was procedurally generated from scripts/generate/templates/SafeCast.js.

pragma solidity ^0.8.20;

/**
 * @dev Wrappers over Solidity's uintXX/intXX/bool casting operators with added overflow
 * checks.
 *
 * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can
 * easily result in undesired exploitation or bugs, since developers usually
 * assume that overflows raise errors. `SafeCast` restores this intuition by
 * reverting the transaction when such an operation overflows.
 *
 * Using this library instead of the unchecked operations eliminates an entire
 * class of bugs, so it's recommended to use it always.
 */
library SafeCast {
    /**
     * @dev Value doesn't fit in an uint of `bits` size.
     */
    error SafeCastOverflowedUintDowncast(uint8 bits, uint256 value);

    /**
     * @dev An int value doesn't fit in an uint of `bits` size.
     */
    error SafeCastOverflowedIntToUint(int256 value);

    /**
     * @dev Value doesn't fit in an int of `bits` size.
     */
    error SafeCastOverflowedIntDowncast(uint8 bits, int256 value);

    /**
     * @dev An uint value doesn't fit in an int of `bits` size.
     */
    error SafeCastOverflowedUintToInt(uint256 value);

    /**
     * @dev Returns the downcasted uint248 from uint256, reverting on
     * overflow (when the input is greater than largest uint248).
     *
     * Counterpart to Solidity's `uint248` operator.
     *
     * Requirements:
     *
     * - input must fit into 248 bits
     */
    function toUint248(uint256 value) internal pure returns (uint248) {
        if (value > type(uint248).max) {
            revert SafeCastOverflowedUintDowncast(248, value);
        }
        return uint248(value);
    }

    /**
     * @dev Returns the downcasted uint240 from uint256, reverting on
     * overflow (when the input is greater than largest uint240).
     *
     * Counterpart to Solidity's `uint240` operator.
     *
     * Requirements:
     *
     * - input must fit into 240 bits
     */
    function toUint240(uint256 value) internal pure returns (uint240) {
        if (value > type(uint240).max) {
            revert SafeCastOverflowedUintDowncast(240, value);
        }
        return uint240(value);
    }

    /**
     * @dev Returns the downcasted uint232 from uint256, reverting on
     * overflow (when the input is greater than largest uint232).
     *
     * Counterpart to Solidity's `uint232` operator.
     *
     * Requirements:
     *
     * - input must fit into 232 bits
     */
    function toUint232(uint256 value) internal pure returns (uint232) {
        if (value > type(uint232).max) {
            revert SafeCastOverflowedUintDowncast(232, value);
        }
        return uint232(value);
    }

    /**
     * @dev Returns the downcasted uint224 from uint256, reverting on
     * overflow (when the input is greater than largest uint224).
     *
     * Counterpart to Solidity's `uint224` operator.
     *
     * Requirements:
     *
     * - input must fit into 224 bits
     */
    function toUint224(uint256 value) internal pure returns (uint224) {
        if (value > type(uint224).max) {
            revert SafeCastOverflowedUintDowncast(224, value);
        }
        return uint224(value);
    }

    /**
     * @dev Returns the downcasted uint216 from uint256, reverting on
     * overflow (when the input is greater than largest uint216).
     *
     * Counterpart to Solidity's `uint216` operator.
     *
     * Requirements:
     *
     * - input must fit into 216 bits
     */
    function toUint216(uint256 value) internal pure returns (uint216) {
        if (value > type(uint216).max) {
            revert SafeCastOverflowedUintDowncast(216, value);
        }
        return uint216(value);
    }

    /**
     * @dev Returns the downcasted uint208 from uint256, reverting on
     * overflow (when the input is greater than largest uint208).
     *
     * Counterpart to Solidity's `uint208` operator.
     *
     * Requirements:
     *
     * - input must fit into 208 bits
     */
    function toUint208(uint256 value) internal pure returns (uint208) {
        if (value > type(uint208).max) {
            revert SafeCastOverflowedUintDowncast(208, value);
        }
        return uint208(value);
    }

    /**
     * @dev Returns the downcasted uint200 from uint256, reverting on
     * overflow (when the input is greater than largest uint200).
     *
     * Counterpart to Solidity's `uint200` operator.
     *
     * Requirements:
     *
     * - input must fit into 200 bits
     */
    function toUint200(uint256 value) internal pure returns (uint200) {
        if (value > type(uint200).max) {
            revert SafeCastOverflowedUintDowncast(200, value);
        }
        return uint200(value);
    }

    /**
     * @dev Returns the downcasted uint192 from uint256, reverting on
     * overflow (when the input is greater than largest uint192).
     *
     * Counterpart to Solidity's `uint192` operator.
     *
     * Requirements:
     *
     * - input must fit into 192 bits
     */
    function toUint192(uint256 value) internal pure returns (uint192) {
        if (value > type(uint192).max) {
            revert SafeCastOverflowedUintDowncast(192, value);
        }
        return uint192(value);
    }

    /**
     * @dev Returns the downcasted uint184 from uint256, reverting on
     * overflow (when the input is greater than largest uint184).
     *
     * Counterpart to Solidity's `uint184` operator.
     *
     * Requirements:
     *
     * - input must fit into 184 bits
     */
    function toUint184(uint256 value) internal pure returns (uint184) {
        if (value > type(uint184).max) {
            revert SafeCastOverflowedUintDowncast(184, value);
        }
        return uint184(value);
    }

    /**
     * @dev Returns the downcasted uint176 from uint256, reverting on
     * overflow (when the input is greater than largest uint176).
     *
     * Counterpart to Solidity's `uint176` operator.
     *
     * Requirements:
     *
     * - input must fit into 176 bits
     */
    function toUint176(uint256 value) internal pure returns (uint176) {
        if (value > type(uint176).max) {
            revert SafeCastOverflowedUintDowncast(176, value);
        }
        return uint176(value);
    }

    /**
     * @dev Returns the downcasted uint168 from uint256, reverting on
     * overflow (when the input is greater than largest uint168).
     *
     * Counterpart to Solidity's `uint168` operator.
     *
     * Requirements:
     *
     * - input must fit into 168 bits
     */
    function toUint168(uint256 value) internal pure returns (uint168) {
        if (value > type(uint168).max) {
            revert SafeCastOverflowedUintDowncast(168, value);
        }
        return uint168(value);
    }

    /**
     * @dev Returns the downcasted uint160 from uint256, reverting on
     * overflow (when the input is greater than largest uint160).
     *
     * Counterpart to Solidity's `uint160` operator.
     *
     * Requirements:
     *
     * - input must fit into 160 bits
     */
    function toUint160(uint256 value) internal pure returns (uint160) {
        if (value > type(uint160).max) {
            revert SafeCastOverflowedUintDowncast(160, value);
        }
        return uint160(value);
    }

    /**
     * @dev Returns the downcasted uint152 from uint256, reverting on
     * overflow (when the input is greater than largest uint152).
     *
     * Counterpart to Solidity's `uint152` operator.
     *
     * Requirements:
     *
     * - input must fit into 152 bits
     */
    function toUint152(uint256 value) internal pure returns (uint152) {
        if (value > type(uint152).max) {
            revert SafeCastOverflowedUintDowncast(152, value);
        }
        return uint152(value);
    }

    /**
     * @dev Returns the downcasted uint144 from uint256, reverting on
     * overflow (when the input is greater than largest uint144).
     *
     * Counterpart to Solidity's `uint144` operator.
     *
     * Requirements:
     *
     * - input must fit into 144 bits
     */
    function toUint144(uint256 value) internal pure returns (uint144) {
        if (value > type(uint144).max) {
            revert SafeCastOverflowedUintDowncast(144, value);
        }
        return uint144(value);
    }

    /**
     * @dev Returns the downcasted uint136 from uint256, reverting on
     * overflow (when the input is greater than largest uint136).
     *
     * Counterpart to Solidity's `uint136` operator.
     *
     * Requirements:
     *
     * - input must fit into 136 bits
     */
    function toUint136(uint256 value) internal pure returns (uint136) {
        if (value > type(uint136).max) {
            revert SafeCastOverflowedUintDowncast(136, value);
        }
        return uint136(value);
    }

    /**
     * @dev Returns the downcasted uint128 from uint256, reverting on
     * overflow (when the input is greater than largest uint128).
     *
     * Counterpart to Solidity's `uint128` operator.
     *
     * Requirements:
     *
     * - input must fit into 128 bits
     */
    function toUint128(uint256 value) internal pure returns (uint128) {
        if (value > type(uint128).max) {
            revert SafeCastOverflowedUintDowncast(128, value);
        }
        return uint128(value);
    }

    /**
     * @dev Returns the downcasted uint120 from uint256, reverting on
     * overflow (when the input is greater than largest uint120).
     *
     * Counterpart to Solidity's `uint120` operator.
     *
     * Requirements:
     *
     * - input must fit into 120 bits
     */
    function toUint120(uint256 value) internal pure returns (uint120) {
        if (value > type(uint120).max) {
            revert SafeCastOverflowedUintDowncast(120, value);
        }
        return uint120(value);
    }

    /**
     * @dev Returns the downcasted uint112 from uint256, reverting on
     * overflow (when the input is greater than largest uint112).
     *
     * Counterpart to Solidity's `uint112` operator.
     *
     * Requirements:
     *
     * - input must fit into 112 bits
     */
    function toUint112(uint256 value) internal pure returns (uint112) {
        if (value > type(uint112).max) {
            revert SafeCastOverflowedUintDowncast(112, value);
        }
        return uint112(value);
    }

    /**
     * @dev Returns the downcasted uint104 from uint256, reverting on
     * overflow (when the input is greater than largest uint104).
     *
     * Counterpart to Solidity's `uint104` operator.
     *
     * Requirements:
     *
     * - input must fit into 104 bits
     */
    function toUint104(uint256 value) internal pure returns (uint104) {
        if (value > type(uint104).max) {
            revert SafeCastOverflowedUintDowncast(104, value);
        }
        return uint104(value);
    }

    /**
     * @dev Returns the downcasted uint96 from uint256, reverting on
     * overflow (when the input is greater than largest uint96).
     *
     * Counterpart to Solidity's `uint96` operator.
     *
     * Requirements:
     *
     * - input must fit into 96 bits
     */
    function toUint96(uint256 value) internal pure returns (uint96) {
        if (value > type(uint96).max) {
            revert SafeCastOverflowedUintDowncast(96, value);
        }
        return uint96(value);
    }

    /**
     * @dev Returns the downcasted uint88 from uint256, reverting on
     * overflow (when the input is greater than largest uint88).
     *
     * Counterpart to Solidity's `uint88` operator.
     *
     * Requirements:
     *
     * - input must fit into 88 bits
     */
    function toUint88(uint256 value) internal pure returns (uint88) {
        if (value > type(uint88).max) {
            revert SafeCastOverflowedUintDowncast(88, value);
        }
        return uint88(value);
    }

    /**
     * @dev Returns the downcasted uint80 from uint256, reverting on
     * overflow (when the input is greater than largest uint80).
     *
     * Counterpart to Solidity's `uint80` operator.
     *
     * Requirements:
     *
     * - input must fit into 80 bits
     */
    function toUint80(uint256 value) internal pure returns (uint80) {
        if (value > type(uint80).max) {
            revert SafeCastOverflowedUintDowncast(80, value);
        }
        return uint80(value);
    }

    /**
     * @dev Returns the downcasted uint72 from uint256, reverting on
     * overflow (when the input is greater than largest uint72).
     *
     * Counterpart to Solidity's `uint72` operator.
     *
     * Requirements:
     *
     * - input must fit into 72 bits
     */
    function toUint72(uint256 value) internal pure returns (uint72) {
        if (value > type(uint72).max) {
            revert SafeCastOverflowedUintDowncast(72, value);
        }
        return uint72(value);
    }

    /**
     * @dev Returns the downcasted uint64 from uint256, reverting on
     * overflow (when the input is greater than largest uint64).
     *
     * Counterpart to Solidity's `uint64` operator.
     *
     * Requirements:
     *
     * - input must fit into 64 bits
     */
    function toUint64(uint256 value) internal pure returns (uint64) {
        if (value > type(uint64).max) {
            revert SafeCastOverflowedUintDowncast(64, value);
        }
        return uint64(value);
    }

    /**
     * @dev Returns the downcasted uint56 from uint256, reverting on
     * overflow (when the input is greater than largest uint56).
     *
     * Counterpart to Solidity's `uint56` operator.
     *
     * Requirements:
     *
     * - input must fit into 56 bits
     */
    function toUint56(uint256 value) internal pure returns (uint56) {
        if (value > type(uint56).max) {
            revert SafeCastOverflowedUintDowncast(56, value);
        }
        return uint56(value);
    }

    /**
     * @dev Returns the downcasted uint48 from uint256, reverting on
     * overflow (when the input is greater than largest uint48).
     *
     * Counterpart to Solidity's `uint48` operator.
     *
     * Requirements:
     *
     * - input must fit into 48 bits
     */
    function toUint48(uint256 value) internal pure returns (uint48) {
        if (value > type(uint48).max) {
            revert SafeCastOverflowedUintDowncast(48, value);
        }
        return uint48(value);
    }

    /**
     * @dev Returns the downcasted uint40 from uint256, reverting on
     * overflow (when the input is greater than largest uint40).
     *
     * Counterpart to Solidity's `uint40` operator.
     *
     * Requirements:
     *
     * - input must fit into 40 bits
     */
    function toUint40(uint256 value) internal pure returns (uint40) {
        if (value > type(uint40).max) {
            revert SafeCastOverflowedUintDowncast(40, value);
        }
        return uint40(value);
    }

    /**
     * @dev Returns the downcasted uint32 from uint256, reverting on
     * overflow (when the input is greater than largest uint32).
     *
     * Counterpart to Solidity's `uint32` operator.
     *
     * Requirements:
     *
     * - input must fit into 32 bits
     */
    function toUint32(uint256 value) internal pure returns (uint32) {
        if (value > type(uint32).max) {
            revert SafeCastOverflowedUintDowncast(32, value);
        }
        return uint32(value);
    }

    /**
     * @dev Returns the downcasted uint24 from uint256, reverting on
     * overflow (when the input is greater than largest uint24).
     *
     * Counterpart to Solidity's `uint24` operator.
     *
     * Requirements:
     *
     * - input must fit into 24 bits
     */
    function toUint24(uint256 value) internal pure returns (uint24) {
        if (value > type(uint24).max) {
            revert SafeCastOverflowedUintDowncast(24, value);
        }
        return uint24(value);
    }

    /**
     * @dev Returns the downcasted uint16 from uint256, reverting on
     * overflow (when the input is greater than largest uint16).
     *
     * Counterpart to Solidity's `uint16` operator.
     *
     * Requirements:
     *
     * - input must fit into 16 bits
     */
    function toUint16(uint256 value) internal pure returns (uint16) {
        if (value > type(uint16).max) {
            revert SafeCastOverflowedUintDowncast(16, value);
        }
        return uint16(value);
    }

    /**
     * @dev Returns the downcasted uint8 from uint256, reverting on
     * overflow (when the input is greater than largest uint8).
     *
     * Counterpart to Solidity's `uint8` operator.
     *
     * Requirements:
     *
     * - input must fit into 8 bits
     */
    function toUint8(uint256 value) internal pure returns (uint8) {
        if (value > type(uint8).max) {
            revert SafeCastOverflowedUintDowncast(8, value);
        }
        return uint8(value);
    }

    /**
     * @dev Converts a signed int256 into an unsigned uint256.
     *
     * Requirements:
     *
     * - input must be greater than or equal to 0.
     */
    function toUint256(int256 value) internal pure returns (uint256) {
        if (value < 0) {
            revert SafeCastOverflowedIntToUint(value);
        }
        return uint256(value);
    }

    /**
     * @dev Returns the downcasted int248 from int256, reverting on
     * overflow (when the input is less than smallest int248 or
     * greater than largest int248).
     *
     * Counterpart to Solidity's `int248` operator.
     *
     * Requirements:
     *
     * - input must fit into 248 bits
     */
    function toInt248(int256 value) internal pure returns (int248 downcasted) {
        downcasted = int248(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(248, value);
        }
    }

    /**
     * @dev Returns the downcasted int240 from int256, reverting on
     * overflow (when the input is less than smallest int240 or
     * greater than largest int240).
     *
     * Counterpart to Solidity's `int240` operator.
     *
     * Requirements:
     *
     * - input must fit into 240 bits
     */
    function toInt240(int256 value) internal pure returns (int240 downcasted) {
        downcasted = int240(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(240, value);
        }
    }

    /**
     * @dev Returns the downcasted int232 from int256, reverting on
     * overflow (when the input is less than smallest int232 or
     * greater than largest int232).
     *
     * Counterpart to Solidity's `int232` operator.
     *
     * Requirements:
     *
     * - input must fit into 232 bits
     */
    function toInt232(int256 value) internal pure returns (int232 downcasted) {
        downcasted = int232(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(232, value);
        }
    }

    /**
     * @dev Returns the downcasted int224 from int256, reverting on
     * overflow (when the input is less than smallest int224 or
     * greater than largest int224).
     *
     * Counterpart to Solidity's `int224` operator.
     *
     * Requirements:
     *
     * - input must fit into 224 bits
     */
    function toInt224(int256 value) internal pure returns (int224 downcasted) {
        downcasted = int224(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(224, value);
        }
    }

    /**
     * @dev Returns the downcasted int216 from int256, reverting on
     * overflow (when the input is less than smallest int216 or
     * greater than largest int216).
     *
     * Counterpart to Solidity's `int216` operator.
     *
     * Requirements:
     *
     * - input must fit into 216 bits
     */
    function toInt216(int256 value) internal pure returns (int216 downcasted) {
        downcasted = int216(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(216, value);
        }
    }

    /**
     * @dev Returns the downcasted int208 from int256, reverting on
     * overflow (when the input is less than smallest int208 or
     * greater than largest int208).
     *
     * Counterpart to Solidity's `int208` operator.
     *
     * Requirements:
     *
     * - input must fit into 208 bits
     */
    function toInt208(int256 value) internal pure returns (int208 downcasted) {
        downcasted = int208(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(208, value);
        }
    }

    /**
     * @dev Returns the downcasted int200 from int256, reverting on
     * overflow (when the input is less than smallest int200 or
     * greater than largest int200).
     *
     * Counterpart to Solidity's `int200` operator.
     *
     * Requirements:
     *
     * - input must fit into 200 bits
     */
    function toInt200(int256 value) internal pure returns (int200 downcasted) {
        downcasted = int200(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(200, value);
        }
    }

    /**
     * @dev Returns the downcasted int192 from int256, reverting on
     * overflow (when the input is less than smallest int192 or
     * greater than largest int192).
     *
     * Counterpart to Solidity's `int192` operator.
     *
     * Requirements:
     *
     * - input must fit into 192 bits
     */
    function toInt192(int256 value) internal pure returns (int192 downcasted) {
        downcasted = int192(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(192, value);
        }
    }

    /**
     * @dev Returns the downcasted int184 from int256, reverting on
     * overflow (when the input is less than smallest int184 or
     * greater than largest int184).
     *
     * Counterpart to Solidity's `int184` operator.
     *
     * Requirements:
     *
     * - input must fit into 184 bits
     */
    function toInt184(int256 value) internal pure returns (int184 downcasted) {
        downcasted = int184(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(184, value);
        }
    }

    /**
     * @dev Returns the downcasted int176 from int256, reverting on
     * overflow (when the input is less than smallest int176 or
     * greater than largest int176).
     *
     * Counterpart to Solidity's `int176` operator.
     *
     * Requirements:
     *
     * - input must fit into 176 bits
     */
    function toInt176(int256 value) internal pure returns (int176 downcasted) {
        downcasted = int176(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(176, value);
        }
    }

    /**
     * @dev Returns the downcasted int168 from int256, reverting on
     * overflow (when the input is less than smallest int168 or
     * greater than largest int168).
     *
     * Counterpart to Solidity's `int168` operator.
     *
     * Requirements:
     *
     * - input must fit into 168 bits
     */
    function toInt168(int256 value) internal pure returns (int168 downcasted) {
        downcasted = int168(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(168, value);
        }
    }

    /**
     * @dev Returns the downcasted int160 from int256, reverting on
     * overflow (when the input is less than smallest int160 or
     * greater than largest int160).
     *
     * Counterpart to Solidity's `int160` operator.
     *
     * Requirements:
     *
     * - input must fit into 160 bits
     */
    function toInt160(int256 value) internal pure returns (int160 downcasted) {
        downcasted = int160(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(160, value);
        }
    }

    /**
     * @dev Returns the downcasted int152 from int256, reverting on
     * overflow (when the input is less than smallest int152 or
     * greater than largest int152).
     *
     * Counterpart to Solidity's `int152` operator.
     *
     * Requirements:
     *
     * - input must fit into 152 bits
     */
    function toInt152(int256 value) internal pure returns (int152 downcasted) {
        downcasted = int152(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(152, value);
        }
    }

    /**
     * @dev Returns the downcasted int144 from int256, reverting on
     * overflow (when the input is less than smallest int144 or
     * greater than largest int144).
     *
     * Counterpart to Solidity's `int144` operator.
     *
     * Requirements:
     *
     * - input must fit into 144 bits
     */
    function toInt144(int256 value) internal pure returns (int144 downcasted) {
        downcasted = int144(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(144, value);
        }
    }

    /**
     * @dev Returns the downcasted int136 from int256, reverting on
     * overflow (when the input is less than smallest int136 or
     * greater than largest int136).
     *
     * Counterpart to Solidity's `int136` operator.
     *
     * Requirements:
     *
     * - input must fit into 136 bits
     */
    function toInt136(int256 value) internal pure returns (int136 downcasted) {
        downcasted = int136(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(136, value);
        }
    }

    /**
     * @dev Returns the downcasted int128 from int256, reverting on
     * overflow (when the input is less than smallest int128 or
     * greater than largest int128).
     *
     * Counterpart to Solidity's `int128` operator.
     *
     * Requirements:
     *
     * - input must fit into 128 bits
     */
    function toInt128(int256 value) internal pure returns (int128 downcasted) {
        downcasted = int128(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(128, value);
        }
    }

    /**
     * @dev Returns the downcasted int120 from int256, reverting on
     * overflow (when the input is less than smallest int120 or
     * greater than largest int120).
     *
     * Counterpart to Solidity's `int120` operator.
     *
     * Requirements:
     *
     * - input must fit into 120 bits
     */
    function toInt120(int256 value) internal pure returns (int120 downcasted) {
        downcasted = int120(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(120, value);
        }
    }

    /**
     * @dev Returns the downcasted int112 from int256, reverting on
     * overflow (when the input is less than smallest int112 or
     * greater than largest int112).
     *
     * Counterpart to Solidity's `int112` operator.
     *
     * Requirements:
     *
     * - input must fit into 112 bits
     */
    function toInt112(int256 value) internal pure returns (int112 downcasted) {
        downcasted = int112(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(112, value);
        }
    }

    /**
     * @dev Returns the downcasted int104 from int256, reverting on
     * overflow (when the input is less than smallest int104 or
     * greater than largest int104).
     *
     * Counterpart to Solidity's `int104` operator.
     *
     * Requirements:
     *
     * - input must fit into 104 bits
     */
    function toInt104(int256 value) internal pure returns (int104 downcasted) {
        downcasted = int104(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(104, value);
        }
    }

    /**
     * @dev Returns the downcasted int96 from int256, reverting on
     * overflow (when the input is less than smallest int96 or
     * greater than largest int96).
     *
     * Counterpart to Solidity's `int96` operator.
     *
     * Requirements:
     *
     * - input must fit into 96 bits
     */
    function toInt96(int256 value) internal pure returns (int96 downcasted) {
        downcasted = int96(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(96, value);
        }
    }

    /**
     * @dev Returns the downcasted int88 from int256, reverting on
     * overflow (when the input is less than smallest int88 or
     * greater than largest int88).
     *
     * Counterpart to Solidity's `int88` operator.
     *
     * Requirements:
     *
     * - input must fit into 88 bits
     */
    function toInt88(int256 value) internal pure returns (int88 downcasted) {
        downcasted = int88(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(88, value);
        }
    }

    /**
     * @dev Returns the downcasted int80 from int256, reverting on
     * overflow (when the input is less than smallest int80 or
     * greater than largest int80).
     *
     * Counterpart to Solidity's `int80` operator.
     *
     * Requirements:
     *
     * - input must fit into 80 bits
     */
    function toInt80(int256 value) internal pure returns (int80 downcasted) {
        downcasted = int80(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(80, value);
        }
    }

    /**
     * @dev Returns the downcasted int72 from int256, reverting on
     * overflow (when the input is less than smallest int72 or
     * greater than largest int72).
     *
     * Counterpart to Solidity's `int72` operator.
     *
     * Requirements:
     *
     * - input must fit into 72 bits
     */
    function toInt72(int256 value) internal pure returns (int72 downcasted) {
        downcasted = int72(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(72, value);
        }
    }

    /**
     * @dev Returns the downcasted int64 from int256, reverting on
     * overflow (when the input is less than smallest int64 or
     * greater than largest int64).
     *
     * Counterpart to Solidity's `int64` operator.
     *
     * Requirements:
     *
     * - input must fit into 64 bits
     */
    function toInt64(int256 value) internal pure returns (int64 downcasted) {
        downcasted = int64(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(64, value);
        }
    }

    /**
     * @dev Returns the downcasted int56 from int256, reverting on
     * overflow (when the input is less than smallest int56 or
     * greater than largest int56).
     *
     * Counterpart to Solidity's `int56` operator.
     *
     * Requirements:
     *
     * - input must fit into 56 bits
     */
    function toInt56(int256 value) internal pure returns (int56 downcasted) {
        downcasted = int56(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(56, value);
        }
    }

    /**
     * @dev Returns the downcasted int48 from int256, reverting on
     * overflow (when the input is less than smallest int48 or
     * greater than largest int48).
     *
     * Counterpart to Solidity's `int48` operator.
     *
     * Requirements:
     *
     * - input must fit into 48 bits
     */
    function toInt48(int256 value) internal pure returns (int48 downcasted) {
        downcasted = int48(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(48, value);
        }
    }

    /**
     * @dev Returns the downcasted int40 from int256, reverting on
     * overflow (when the input is less than smallest int40 or
     * greater than largest int40).
     *
     * Counterpart to Solidity's `int40` operator.
     *
     * Requirements:
     *
     * - input must fit into 40 bits
     */
    function toInt40(int256 value) internal pure returns (int40 downcasted) {
        downcasted = int40(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(40, value);
        }
    }

    /**
     * @dev Returns the downcasted int32 from int256, reverting on
     * overflow (when the input is less than smallest int32 or
     * greater than largest int32).
     *
     * Counterpart to Solidity's `int32` operator.
     *
     * Requirements:
     *
     * - input must fit into 32 bits
     */
    function toInt32(int256 value) internal pure returns (int32 downcasted) {
        downcasted = int32(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(32, value);
        }
    }

    /**
     * @dev Returns the downcasted int24 from int256, reverting on
     * overflow (when the input is less than smallest int24 or
     * greater than largest int24).
     *
     * Counterpart to Solidity's `int24` operator.
     *
     * Requirements:
     *
     * - input must fit into 24 bits
     */
    function toInt24(int256 value) internal pure returns (int24 downcasted) {
        downcasted = int24(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(24, value);
        }
    }

    /**
     * @dev Returns the downcasted int16 from int256, reverting on
     * overflow (when the input is less than smallest int16 or
     * greater than largest int16).
     *
     * Counterpart to Solidity's `int16` operator.
     *
     * Requirements:
     *
     * - input must fit into 16 bits
     */
    function toInt16(int256 value) internal pure returns (int16 downcasted) {
        downcasted = int16(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(16, value);
        }
    }

    /**
     * @dev Returns the downcasted int8 from int256, reverting on
     * overflow (when the input is less than smallest int8 or
     * greater than largest int8).
     *
     * Counterpart to Solidity's `int8` operator.
     *
     * Requirements:
     *
     * - input must fit into 8 bits
     */
    function toInt8(int256 value) internal pure returns (int8 downcasted) {
        downcasted = int8(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(8, value);
        }
    }

    /**
     * @dev Converts an unsigned uint256 into a signed int256.
     *
     * Requirements:
     *
     * - input must be less than or equal to maxInt256.
     */
    function toInt256(uint256 value) internal pure returns (int256) {
        // Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive
        if (value > uint256(type(int256).max)) {
            revert SafeCastOverflowedUintToInt(value);
        }
        return int256(value);
    }

    /**
     * @dev Cast a boolean (false or true) to a uint256 (0 or 1) with no jump.
     */
    function toUint(bool b) internal pure returns (uint256 u) {
        assembly ("memory-safe") {
            u := iszero(iszero(b))
        }
    }
}
Panic.sol 57 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/Panic.sol)

pragma solidity ^0.8.20;

/**
 * @dev Helper library for emitting standardized panic codes.
 *
 * ```solidity
 * contract Example {
 *      using Panic for uint256;
 *
 *      // Use any of the declared internal constants
 *      function foo() { Panic.GENERIC.panic(); }
 *
 *      // Alternatively
 *      function foo() { Panic.panic(Panic.GENERIC); }
 * }
 * ```
 *
 * Follows the list from https://github.com/ethereum/solidity/blob/v0.8.24/libsolutil/ErrorCodes.h[libsolutil].
 *
 * _Available since v5.1._
 */
// slither-disable-next-line unused-state
library Panic {
    /// @dev generic / unspecified error
    uint256 internal constant GENERIC = 0x00;
    /// @dev used by the assert() builtin
    uint256 internal constant ASSERT = 0x01;
    /// @dev arithmetic underflow or overflow
    uint256 internal constant UNDER_OVERFLOW = 0x11;
    /// @dev division or modulo by zero
    uint256 internal constant DIVISION_BY_ZERO = 0x12;
    /// @dev enum conversion error
    uint256 internal constant ENUM_CONVERSION_ERROR = 0x21;
    /// @dev invalid encoding in storage
    uint256 internal constant STORAGE_ENCODING_ERROR = 0x22;
    /// @dev empty array pop
    uint256 internal constant EMPTY_ARRAY_POP = 0x31;
    /// @dev array out of bounds access
    uint256 internal constant ARRAY_OUT_OF_BOUNDS = 0x32;
    /// @dev resource error (too large allocation or too large array)
    uint256 internal constant RESOURCE_ERROR = 0x41;
    /// @dev calling invalid internal function
    uint256 internal constant INVALID_INTERNAL_FUNCTION = 0x51;

    /// @dev Reverts with a panic code. Recommended to use with
    /// the internal constants with predefined codes.
    function panic(uint256 code) internal pure {
        assembly ("memory-safe") {
            mstore(0x00, 0x4e487b71)
            mstore(0x20, code)
            revert(0x1c, 0x24)
        }
    }
}
IBridgeProxy.sol 9 lines
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.28;

interface IBridgeProxy {
  function claim(
    address currency,
    uint256 amount
  ) external returns (uint256 balance);
}
ITokenSwap.sol 12 lines
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.28;

interface ITokenSwap {
  function swap(
    address pool,
    uint24 uniswapWethPoolFeeToken,
    uint24 uniswapWethPoolFeeAsset,
    uint48 deadline,
    uint256 amountOutMinimum
  ) external payable returns (uint amount);
}
IWETH.sol 20 lines
// SPDX-License-Identifier: MIT
pragma solidity >=0.7.0 <0.9.0;

interface IWETH {
  function deposit() external payable;

  function transfer(address to, uint256 value) external returns (bool);

  function transferFrom(
    address src,
    address dst,
    uint256 wad
  ) external returns (bool);

  function withdraw(uint256) external;

  function balanceOf(address) external view returns (uint);

  function approve(address spender, uint256 amount) external returns (bool);
}
RelayPool.sol 813 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;

import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {ERC4626} from "solmate/src/tokens/ERC4626.sol";
import {ERC20} from "solmate/src/tokens/ERC20.sol";
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
import {IWETH} from "./interfaces/IWETH.sol";
import {ITokenSwap} from "./interfaces/ITokenSwap.sol";
import {TypeCasts} from "./utils/TypeCasts.sol";
import {HyperlaneMessage} from "./Types.sol";
import {IBridgeProxy} from "./interfaces/IBridgeProxy.sol";
import {Math} from "@openzeppelin/contracts/utils/math/Math.sol";

/// @title RelayPool
/// @author Relay Protocol
/// @notice ERC4626 vault that enables cross-chain asset bridging and yield generation
/// @dev Receives bridged assets via Hyperlane, provides instant liquidity, and deposits idle funds into yield pools
contract RelayPool is ERC4626, Ownable {
  /// @notice Configuration for an authorized origin chain and bridge
  /// @param chainId The chain ID of the origin chain
  /// @param bridge The address of the bridge contract on the origin chain
  /// @param curator The address authorized to disable this origin
  /// @param maxDebt Maximum outstanding debt allowed from this origin
  /// @param outstandingDebt Current outstanding debt from this origin
  /// @param proxyBridge The address of the proxy bridge contract for claiming funds
  /// @param bridgeFee Fee charged for bridging (in fractional basis points)
  /// @param coolDown Minimum time in seconds between message timestamp and processing
  struct OriginSettings {
    uint32 chainId;
    address bridge;
    address curator;
    uint256 maxDebt;
    uint256 outstandingDebt;
    address proxyBridge;
    uint32 bridgeFee; // fractional basis points
    uint32 coolDown; // in seconds
  }

  /// @notice Parameters for adding a new origin
  /// @param curator The address authorized to disable this origin
  /// @param chainId The chain ID of the origin chain
  /// @param bridge The address of the bridge contract on the origin chain
  /// @param proxyBridge The address of the proxy bridge contract for claiming funds
  /// @param maxDebt Maximum outstanding debt allowed from this origin
  /// @param bridgeFee Fee charged for bridging (in fractional basis points)
  /// @param coolDown Minimum time in seconds between message timestamp and processing
  struct OriginParam {
    address curator;
    uint32 chainId;
    address bridge;
    address proxyBridge;
    uint256 maxDebt;
    uint32 bridgeFee; // fractional basis points
    uint32 coolDown; // in seconds
  }

  /// @notice Error when caller is not authorized for the operation
  /// @param sender The address that attempted the unauthorized call
  error UnauthorizedCaller(address sender);

  /// @notice Error when attempting to swap the pool's underlying asset
  /// @param token The token address that was attempted to be swapped
  error UnauthorizedSwap(address token);

  /// @notice Error when message is from an unauthorized origin
  /// @param chainId The chain ID of the unauthorized origin
  /// @param bridge The bridge address of the unauthorized origin
  error UnauthorizedOrigin(uint32 chainId, address bridge);

  /// @notice Error when attempting to process an already processed message
  /// @param chainId The chain ID of the message origin
  /// @param bridge The bridge address of the message origin
  /// @param nonce The nonce of the already processed message
  error MessageAlreadyProcessed(uint32 chainId, address bridge, uint256 nonce);

  /// @notice Error when origin would exceed its maximum allowed debt
  /// @param chainId The chain ID of the origin
  /// @param bridge The bridge address of the origin
  /// @param maxDebt The maximum allowed debt for this origin
  /// @param nonce The nonce of the rejected transaction
  /// @param recipient The intended recipient of the funds
  /// @param amount The amount that would exceed the debt limit
  error TooMuchDebtFromOrigin(
    uint32 chainId,
    address bridge,
    uint256 maxDebt,
    uint256 nonce,
    address recipient,
    uint256 amount
  );

  /// @notice Error when native currency transfer fails
  /// @param recipient The intended recipient of the transfer
  /// @param amount The amount that failed to transfer
  error FailedTransfer(address recipient, uint256 amount);

  /// @notice Error when insufficient funds are available
  /// @param amount The amount available
  /// @param balance The balance required
  error InsufficientFunds(uint256 amount, uint256 balance);

  /// @notice Error when native currency is sent to a non-WETH pool
  error NotAWethPool();

  /// @notice Error when message timestamp is too recent based on cooldown period
  /// @param chainId The chain ID of the message origin
  /// @param bridge The bridge address of the message origin
  /// @param nonce The nonce of the message
  /// @param timestamp The timestamp of the message
  /// @param coolDown The required cooldown period
  error MessageTooRecent(
    uint32 chainId,
    address bridge,
    uint256 nonce,
    uint256 timestamp,
    uint32 coolDown
  );

  /// @notice Error when share price is below minimum acceptable threshold
  /// @param actualPrice The actual share price
  /// @param minPrice The minimum acceptable share price
  error SharePriceTooLow(uint256 actualPrice, uint256 minPrice);

  /// @notice Error when share price is above maximum acceptable threshold
  /// @param actualPrice The actual share price
  /// @param maxPrice The maximum acceptable share price
  error SharePriceTooHigh(uint256 actualPrice, uint256 maxPrice);

  /// @notice The address of the Hyperlane mailbox
  /// @dev Used to receive cross-chain messages
  address public immutable HYPERLANE_MAILBOX;

  /// @notice The address of the WETH contract (used for native pools)
  /// @dev Set to WETH address for native currency pools, otherwise can be address(0)
  address public immutable WETH;

  /// @notice Denominator for fractional basis points calculations (1 = 0.0000001 bps)
  uint256 public constant FRACTIONAL_BPS_DENOMINATOR = 100_000_000_000;

  /// @notice Keeping track of the outstanding debt for ERC4626 computations
  /// @dev Represents funds that have been sent but not yet claimed from bridges
  uint256 public outstandingDebt = 0;

  /// @notice Mapping of origins to their settings
  /// @dev [chainId][bridgeAddress] => OriginSettings
  mapping(uint32 => mapping(address => OriginSettings))
    public authorizedOrigins;

  /// @notice Mapping of messages by origin
  /// @dev [chainId][bridgeAddress][nonce] => message data
  mapping(uint32 => mapping(address => mapping(uint256 => bytes)))
    public messages;

  /// @notice The address of the yield pool where funds are deposited
  /// @dev Must be an ERC4626 vault for the same underlying asset
  address public yieldPool;

  /// @notice UniswapV3 wrapper contract for token swaps
  address public tokenSwapAddress;

  /// @notice Keeping track of the total fees collected
  /// @dev Fees are held in the yield pool until they finish streaming
  uint256 public pendingBridgeFees = 0;

  /// @notice All incoming assets are streamed (even though they are instantly deposited in the yield pool)
  /// @dev Total amount of assets currently being streamed
  uint256 public totalAssetsToStream = 0;

  /// @notice Timestamp when assets were last collected for streaming
  uint256 public lastAssetsCollectedAt = 0;

  /// @notice Timestamp when current streaming period ends
  uint256 public endOfStream = block.timestamp;

  /// @notice Duration over which collected assets are streamed
  uint256 public streamingPeriod = 7 days;

  /// @notice Emitted when a loan is provided to a bridge recipient
  /// @param nonce The unique identifier of the transaction
  /// @param recipient The address receiving the funds
  /// @param asset The asset being transferred
  /// @param amount The total amount including fees
  /// @param origin The origin settings for this bridge
  /// @param fees The fee amount collected
  event LoanEmitted(
    uint256 indexed nonce,
    address indexed recipient,
    ERC20 asset,
    uint256 amount,
    OriginSettings origin,
    uint256 fees
  );

  /// @notice Emitted when bridged funds are claimed and deposited
  /// @param chainId The chain ID of the bridge origin
  /// @param bridge The bridge address on the origin chain
  /// @param amount The total amount claimed
  /// @param fees The fee amount collected
  event BridgeCompleted(
    uint32 chainId,
    address indexed bridge,
    uint256 amount,
    uint256 fees
  );

  /// @notice Emitted when outstanding debt changes
  /// @param oldDebt Previous total outstanding debt
  /// @param newDebt New total outstanding debt
  /// @param origin The origin settings involved
  /// @param oldOriginDebt Previous outstanding debt for the origin
  /// @param newOriginDebt New outstanding debt for the origin
  event OutstandingDebtChanged(
    uint256 oldDebt,
    uint256 newDebt,
    OriginSettings origin,
    uint256 oldOriginDebt,
    uint256 newOriginDebt
  );

  /// @notice Emitted when assets are deposited into the yield pool
  /// @param amount The amount deposited
  /// @param yieldPool The yield pool address
  event AssetsDepositedIntoYieldPool(uint256 amount, address yieldPool);

  /// @notice Emitted when assets are withdrawn from the yield pool
  /// @param amount The amount withdrawn
  /// @param yieldPool The yield pool address
  event AssetsWithdrawnFromYieldPool(uint256 amount, address yieldPool);

  /// @notice Emitted when the token swap address is changed
  /// @param prevAddress The previous swap contract address
  /// @param newAddress The new swap contract address
  event TokenSwapChanged(address prevAddress, address newAddress);

  /// @notice Emitted when the yield pool is changed
  /// @param oldPool The previous yield pool address
  /// @param newPool The new yield pool address
  event YieldPoolChanged(address oldPool, address newPool);

  /// @notice Emitted when the streaming period is changed
  /// @param oldPeriod The previous streaming period
  /// @param newPeriod The new streaming period
  event StreamingPeriodChanged(uint256 oldPeriod, uint256 newPeriod);

  /// @notice Emitted when a new origin is added
  /// @param origin The origin parameters
  event OriginAdded(OriginParam origin);

  /// @notice Emitted when an origin is disabled
  /// @param chainId The chain ID of the disabled origin
  /// @param bridge The bridge address of the disabled origin
  /// @param maxDebt The previous maximum debt limit
  /// @param outstandingDebt The outstanding debt at time of disabling
  /// @param proxyBridge The proxy bridge address
  event OriginDisabled(
    uint32 chainId,
    address bridge,
    uint256 maxDebt,
    uint256 outstandingDebt,
    address proxyBridge
  );

  /// @notice Initializes the RelayPool with core parameters
  /// @dev Warning: the owner should always be a timelock with significant delay
  /// @param hyperlaneMailbox The Hyperlane mailbox contract address
  /// @param asset The underlying asset for this vault
  /// @param name The name of the vault token
  /// @param symbol The symbol of the vault token
  /// @param baseYieldPool The initial yield pool for depositing assets
  /// @param weth The WETH contract address (for native currency pools)
  /// @param curator The address that will own the pool after deployment
  constructor(
    address hyperlaneMailbox,
    ERC20 asset,
    string memory name,
    string memory symbol,
    address baseYieldPool,
    address weth,
    address curator
  ) ERC4626(asset, name, symbol) Ownable(msg.sender) {
    // Set the Hyperlane mailbox
    HYPERLANE_MAILBOX = hyperlaneMailbox;

    // set the yieldPool
    yieldPool = baseYieldPool;

    // set weth
    WETH = weth;

    // Change the owner to the curator
    transferOwnership(curator);
  }

  /// @notice Updates the streaming period for fee accrual
  /// @dev Updates streamed assets before changing the period
  /// @param newPeriod The new streaming period in seconds
  function updateStreamingPeriod(uint256 newPeriod) public onlyOwner {
    updateStreamedAssets();
    uint256 oldPeriod = streamingPeriod;
    streamingPeriod = newPeriod;
    emit StreamingPeriodChanged(oldPeriod, newPeriod);
  }

  /// @notice Updates the yield pool, moving all assets from the old pool to the new one
  /// @dev Implements share price-based slippage protection to ensure fair value transfer
  /// @param newPool The address of the new yield pool
  /// @param minSharePriceFromOldPool The minimum acceptable share price when withdrawing from the old pool
  /// @param maxSharePricePriceFromNewPool The maximum acceptable share price when depositing into the new pool
  function updateYieldPool(
    address newPool,
    uint256 minSharePriceFromOldPool,
    uint256 maxSharePricePriceFromNewPool
  ) public onlyOwner {
    address oldPool = yieldPool;
    uint256 sharesOfOldPool = ERC20(yieldPool).balanceOf(address(this));

    // Calculate share price of old pool using convertToAssets
    uint256 oldPoolSharePrice = ERC4626(oldPool).convertToAssets(
      10 ** ERC20(oldPool).decimals()
    );

    // Check if share price is too low
    if (oldPoolSharePrice < minSharePriceFromOldPool) {
      revert SharePriceTooLow(oldPoolSharePrice, minSharePriceFromOldPool);
    }

    // Redeem all the shares from the old pool
    uint256 withdrawnAssets = ERC4626(yieldPool).redeem(
      sharesOfOldPool,
      address(this),
      address(this)
    );
    yieldPool = newPool;

    // Calculate share price of new pool using convertToAssets
    uint256 newPoolSharePrice = ERC4626(newPool).convertToAssets(
      10 ** ERC20(newPool).decimals()
    );

    // Check if share price is too high
    if (newPoolSharePrice > maxSharePricePriceFromNewPool) {
      revert SharePriceTooHigh(
        newPoolSharePrice,
        maxSharePricePriceFromNewPool
      );
    }

    // Deposit all assets into the new pool
    SafeERC20.safeIncreaseAllowance(
      IERC20(address(asset)),
      newPool,
      withdrawnAssets
    );
    depositAssetsInYieldPool(withdrawnAssets);

    emit YieldPoolChanged(oldPool, newPool);
  }

  /// @notice Adds a new authorized origin for bridging
  /// @dev Only callable by owner, typically a timelock contract
  /// @param origin The origin parameters including chain ID, addresses, and limits
  function addOrigin(OriginParam memory origin) public onlyOwner {
    authorizedOrigins[origin.chainId][origin.bridge] = OriginSettings({
      chainId: origin.chainId,
      bridge: origin.bridge,
      curator: origin.curator, // We can't use msg.sender here, because we recommend msg.sender to be a timelock and this address should be able to disable an origin quickly!
      maxDebt: origin.maxDebt,
      outstandingDebt: 0,
      proxyBridge: origin.proxyBridge,
      bridgeFee: origin.bridgeFee,
      coolDown: origin.coolDown
    });
    emit OriginAdded(origin);
  }

  /// @notice Disables an origin by setting its max debt to zero
  /// @dev Only callable by the origin's curator for emergency response
  /// @param chainId The chain ID of the origin to disable
  /// @param bridge The bridge address of the origin to disable
  function disableOrigin(uint32 chainId, address bridge) public {
    OriginSettings memory origin = authorizedOrigins[chainId][bridge];
    if (msg.sender != origin.curator) {
      revert UnauthorizedCaller(msg.sender);
    }
    authorizedOrigins[chainId][bridge].maxDebt = 0;
    emit OriginDisabled(
      chainId,
      bridge,
      origin.maxDebt,
      origin.outstandingDebt,
      origin.proxyBridge
    );
  }

  /// @notice Increases outstanding debt for an origin
  /// @dev Updates both origin-specific and total outstanding debt
  /// @param amount The amount to increase debt by
  /// @param origin The origin settings to update
  function increaseOutstandingDebt(
    uint256 amount,
    OriginSettings storage origin
  ) internal {
    uint256 currentOriginOutstandingDebt = origin.outstandingDebt;
    origin.outstandingDebt += amount;
    uint256 currentOutstandingDebt = outstandingDebt;
    outstandingDebt += amount;
    emit OutstandingDebtChanged(
      currentOutstandingDebt,
      outstandingDebt,
      origin,
      currentOriginOutstandingDebt,
      origin.outstandingDebt
    );
  }

  /// @notice Decreases outstanding debt for an origin
  /// @dev Updates both origin-specific and total outstanding debt
  /// @param amount The amount to decrease debt by
  /// @param origin The origin settings to update
  function decreaseOutstandingDebt(
    uint256 amount,
    OriginSettings storage origin
  ) internal {
    uint256 currentOriginOutstandingDebt = origin.outstandingDebt;
    origin.outstandingDebt -= amount;
    uint256 currentOutstandingDebt = outstandingDebt;
    outstandingDebt -= amount;
    emit OutstandingDebtChanged(
      currentOutstandingDebt,
      outstandingDebt,
      origin,
      currentOriginOutstandingDebt,
      origin.outstandingDebt
    );
  }

  /// @notice Returns the maximum assets that can be deposited
  /// @dev Limited by the yield pool's capacity
  /// @param /* receiver */ The address that would receive shares (unused)
  /// @return maxAssets The maximum amount of assets that can be deposited
  function maxDeposit(
    address /* receiver */
  ) public view override returns (uint256 maxAssets) {
    return ERC4626(yieldPool).maxDeposit(address(this));
  }

  /// @notice Returns the maximum assets that can be withdrawn by an owner
  /// @dev Limited to the owner's share balance converted to assets
  /// @param owner The address to check withdrawal capacity for
  /// @return maxAssets The maximum amount of assets that can be withdrawn
  function maxWithdraw(
    address owner
  ) public view override returns (uint256 maxAssets) {
    return convertToAssets(this.balanceOf(owner));
  }

  /// @notice Returns the maximum shares that can be minted
  /// @dev Limited by the yield pool's deposit capacity
  /// @param receiver The address that would receive the shares
  /// @return maxShares The maximum amount of shares that can be minted
  function maxMint(
    address receiver
  ) public view override returns (uint256 maxShares) {
    uint256 maxDepositInYieldPool = maxDeposit(receiver);
    return ERC4626.previewDeposit(maxDepositInYieldPool);
  }

  /// @notice Returns the maximum shares that can be redeemed by an owner
  /// @dev Limited by the owner's share balance and yield pool's withdrawal capacity
  /// @param owner The address to check redemption capacity for
  /// @return maxShares The maximum amount of shares that can be redeemed
  function maxRedeem(
    address owner
  ) public view override returns (uint256 maxShares) {
    uint256 maxWithdrawInYieldPool = maxWithdraw(owner);
    return ERC4626.previewWithdraw(maxWithdrawInYieldPool);
  }

  /// @notice Returns the total assets controlled by the pool
  /// @dev Includes yield pool balance, outstanding debt, minus pending fees and streaming assets
  /// @return The total assets under management
  function totalAssets() public view override returns (uint256) {
    uint256 balanceOfYieldPoolTokens = ERC20(yieldPool).balanceOf(
      address(this)
    );
    uint256 yieldPoolBalance = ERC4626(yieldPool).previewRedeem(
      balanceOfYieldPoolTokens
    );
    // Pending bridge fees are still in the yield pool!
    // So we need to extract them from this pool's asset until
    // The bridge is claimed!
    return
      yieldPoolBalance +
      outstandingDebt -
      pendingBridgeFees -
      remainsToStream();
  }

  /// @notice Deposits assets into the yield pool
  /// @dev Internal function that approves and deposits to yield pool
  /// @param amount The amount of assets to deposit
  function depositAssetsInYieldPool(uint256 amount) internal {
    SafeERC20.safeIncreaseAllowance(IERC20(address(asset)), yieldPool, amount);
    ERC4626(yieldPool).deposit(amount, address(this));
    emit AssetsDepositedIntoYieldPool(amount, yieldPool);
  }

  /// @notice Withdraws assets from the yield pool
  /// @dev Internal function that withdraws from yield pool to recipient
  /// @param amount The amount of assets to withdraw
  /// @param recipient The address to receive the withdrawn assets
  function withdrawAssetsFromYieldPool(
    uint256 amount,
    address recipient
  ) internal {
    ERC4626(yieldPool).withdraw(amount, recipient, address(this));
    emit AssetsWithdrawnFromYieldPool(amount, yieldPool);
  }

  /// @notice Handles incoming cross-chain messages from Hyperlane
  /// @dev Only callable by Hyperlane mailbox, provides instant liquidity to recipients
  /// @param chainId The origin chain ID
  /// @param bridgeAddress The origin bridge address (as bytes32)
  /// @param data The encoded message data
  function handle(
    uint32 chainId,
    bytes32 bridgeAddress,
    bytes calldata data
  ) external payable {
    // Only `HYPERLANE_MAILBOX` is authorized to call this method
    if (msg.sender != HYPERLANE_MAILBOX) {
      revert UnauthorizedCaller(msg.sender);
    }

    // convert bytes32 to address
    address bridge = TypeCasts.bytes32ToAddress(bridgeAddress);

    // Check if the origin is authorized
    OriginSettings storage origin = authorizedOrigins[chainId][bridge];
    if (origin.maxDebt == 0) {
      revert UnauthorizedOrigin(chainId, bridge);
    }

    // Parse the data received from the sender chain
    HyperlaneMessage memory message = abi.decode(data, (HyperlaneMessage));

    // if the message is too recent, we reject it
    if (block.timestamp - message.timestamp < origin.coolDown) {
      revert MessageTooRecent(
        chainId,
        bridge,
        message.nonce,
        message.timestamp,
        origin.coolDown
      );
    }

    // Check if message was already processed
    if (messages[chainId][bridge][message.nonce].length > 0) {
      revert MessageAlreadyProcessed(chainId, bridge, message.nonce);
    }
    // Mark as processed if not
    messages[chainId][bridge][message.nonce] = data;

    // Calculate fee using fractional basis points
    uint256 feeAmount = (message.amount * origin.bridgeFee) /
      FRACTIONAL_BPS_DENOMINATOR;
    pendingBridgeFees += feeAmount;

    // Check if origin settings are respected
    // We look at the full amount, because feed are considered debt
    // (they are owed to the pool)
    if (origin.outstandingDebt + message.amount > origin.maxDebt) {
      revert TooMuchDebtFromOrigin(
        chainId,
        bridge,
        origin.maxDebt,
        message.nonce,
        message.recipient,
        message.amount
      );
    }
    increaseOutstandingDebt(message.amount, origin);

    // We only send the amount net of fees
    sendFunds(message.amount - feeAmount, message.recipient);

    emit LoanEmitted(
      message.nonce,
      message.recipient,
      asset,
      message.amount,
      origin,
      feeAmount
    );
  }

  /// @notice Calculates remaining assets to be streamed
  /// @dev Returns zero if streaming period has ended
  /// @return The amount of assets remaining to be streamed
  function remainsToStream() internal view returns (uint256) {
    if (block.timestamp > endOfStream) {
      return 0; // Nothing left to stream
    } else {
      return
        totalAssetsToStream - // total assets to stream
        (totalAssetsToStream * (block.timestamp - lastAssetsCollectedAt)) /
        (endOfStream - lastAssetsCollectedAt); // already streamed
    }
  }

  /// @notice Updates the streamed assets calculation
  /// @dev Resets the streaming calculation to current timestamp
  /// @return The new total assets to stream
  function updateStreamedAssets() public returns (uint256) {
    totalAssetsToStream = remainsToStream();
    lastAssetsCollectedAt = block.timestamp;
    return totalAssetsToStream;
  }

  /// @notice Adds assets to be accounted for in a streaming fashion
  /// @dev Adjusts streaming end time based on weighted average
  /// @param amount The amount of assets to add to streaming
  /// @return The new total assets to stream
  function addToStreamingAssets(uint256 amount) internal returns (uint256) {
    if (amount > 0) {
      updateStreamedAssets();
      // We adjust the end of the stream based on the new amount
      uint256 amountLeft = remainsToStream();
      uint256 timeLeft = Math.max(endOfStream, block.timestamp) -
        block.timestamp;
      uint256 weightedStreamingPeriod = (amountLeft *
        timeLeft +
        amount *
        streamingPeriod) / (amountLeft + amount);
      endOfStream = block.timestamp + weightedStreamingPeriod;
    }
    return totalAssetsToStream += amount;
  }

  /// @notice Claims funds from a bridge after they arrive
  /// @dev Decreases outstanding debt and deposits funds into yield pool
  /// @param chainId The origin chain ID
  /// @param bridge The origin bridge address
  /// @return amount The amount of assets claimed
  function claim(
    uint32 chainId,
    address bridge
  ) public returns (uint256 amount) {
    OriginSettings storage origin = authorizedOrigins[chainId][bridge];
    if (origin.proxyBridge == address(0)) {
      revert UnauthorizedOrigin(chainId, bridge);
    }

    // We need to claim the funds from the bridge proxy contract
    amount = IBridgeProxy(origin.proxyBridge).claim(
      address(asset) == WETH ? address(0) : address(asset),
      origin.outstandingDebt
    );

    // We should have received funds
    decreaseOutstandingDebt(amount, origin);
    // and we should deposit these funds into the yield pool
    depositAssetsInYieldPool(amount);

    // The amount is the amount that was loaned + the fees
    uint256 feeAmount = (amount * origin.bridgeFee) /
      FRACTIONAL_BPS_DENOMINATOR;
    pendingBridgeFees -= feeAmount;
    // We need to account for it in a streaming fashion
    addToStreamingAssets(feeAmount);

    emit BridgeCompleted(chainId, bridge, amount, feeAmount);
  }

  /// @notice Sends funds to a recipient
  /// @dev Handles both ERC20 and native currency transfers
  /// @param amount The amount to send
  /// @param recipient The address to receive the funds
  function sendFunds(uint256 amount, address recipient) internal {
    if (address(asset) == WETH) {
      withdrawAssetsFromYieldPool(amount, address(this));
      IWETH(WETH).withdraw(amount);
      (bool success, ) = recipient.call{value: amount}("");
      if (!success) {
        revert FailedTransfer(recipient, amount);
      }
    } else {
      withdrawAssetsFromYieldPool(amount, recipient);
    }
  }

  /// @notice Sets the token swap contract address
  /// @dev Used for swapping non-asset tokens received by the pool
  /// @param newTokenSwapAddress The new token swap contract address
  function setTokenSwap(address newTokenSwapAddress) external onlyOwner {
    address prevTokenSwapAddress = tokenSwapAddress;
    tokenSwapAddress = newTokenSwapAddress;
    emit TokenSwapChanged(prevTokenSwapAddress, tokenSwapAddress);
  }

  /// @notice Swaps tokens and deposits resulting assets
  /// @dev Swaps via Uniswap V3 through the token swap contract
  /// @param token The token to swap from
  /// @param amount The amount of tokens to swap
  /// @param uniswapWethPoolFeeToken The fee tier for token-WETH pool
  /// @param uniswapWethPoolFeeAsset The fee tier for WETH-asset pool
  /// @param deadline The deadline for the swap
  /// @param amountOutMinimum The minimum amount of assets to receive
  function swapAndDeposit(
    address token,
    uint256 amount,
    uint24 uniswapWethPoolFeeToken,
    uint24 uniswapWethPoolFeeAsset,
    uint48 deadline,
    uint256 amountOutMinimum
  ) public onlyOwner {
    if (token == address(asset)) {
      revert UnauthorizedSwap(token);
    }

    SafeERC20.safeTransfer(IERC20(address(token)), tokenSwapAddress, amount);

    ITokenSwap(tokenSwapAddress).swap(
      token,
      uniswapWethPoolFeeToken,
      uniswapWethPoolFeeAsset,
      deadline,
      amountOutMinimum
    );
    collectNonDepositedAssets();
  }

  /// @notice Collects any assets not yet deposited and starts streaming them
  /// @dev Can be called by anyone to ensure timely asset collection
  function collectNonDepositedAssets() public {
    uint256 balance = ERC20(asset).balanceOf(address(this));
    if (balance > 0) {
      depositAssetsInYieldPool(balance);
      addToStreamingAssets(balance);
    }
  }

  /// @notice Hook called before withdrawing assets from the vault
  /// @dev Withdraws assets from yield pool before processing withdrawal
  /// @param assets The amount of assets to withdraw
  /// @param /* shares */ The amount of shares being burned (unused)
  function beforeWithdraw(
    uint256 assets,
    uint256 /* shares */
  ) internal override {
    // We need to withdraw the assets from the yield pool
    withdrawAssetsFromYieldPool(assets, address(this));
  }

  /// @notice Hook called after depositing assets to the vault
  /// @dev Deposits assets into yield pool after receiving them
  /// @param assets The amount of assets deposited
  /// @param /* shares */ The amount of shares minted (unused)
  function afterDeposit(
    uint256 assets,
    uint256 /* shares */
  ) internal override {
    // We need to deposit the assets into the yield pool
    depositAssetsInYieldPool(assets);
  }

  /// @notice Processes failed Hyperlane messages manually
  /// @dev Only callable by owner, typically after slow bridge resolution
  /// @param chainId The origin chain ID
  /// @param bridge The origin bridge address
  /// @param data The encoded message data
  function processFailedHandler(
    uint32 chainId,
    address bridge,
    bytes calldata data
  ) public onlyOwner {
    OriginSettings storage origin = authorizedOrigins[chainId][bridge]; // no validation here since this is onlyOwner and _may_ be called for a disabled origin.
    HyperlaneMessage memory message = abi.decode(data, (HyperlaneMessage));

    // Check if message was already processed
    if (messages[chainId][bridge][message.nonce].length > 0) {
      revert MessageAlreadyProcessed(chainId, bridge, message.nonce);
    }

    // Mark the message as processed to avoid double processing (if the hyperlane message eventually makes it)
    messages[chainId][bridge][message.nonce] = data;

    // Increase the outstanding debt with the amount
    increaseOutstandingDebt(message.amount, origin);
    // And immediately claim from the bridge to get the funds (and decrease the outstanding debt!)
    uint256 amount = claim(chainId, bridge);
    if (amount < message.amount) {
      revert InsufficientFunds(amount, message.amount);
    }

    // Send the funds to the recipient (we should not take fees because the funds have taken more time to arrive...)
    sendFunds(message.amount, message.recipient);
  }

  /// @notice Receives native currency
  /// @dev Required for WETH unwrapping in native currency pools
  receive() external payable {
    if (address(asset) != WETH) {
      revert NotAWethPool();
    }
    if (msg.sender != WETH) {
      IWETH(WETH).deposit{value: address(this).balance}();
    }
  }
}
Types.sol 17 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;

/// @title HyperlaneMessage
/// @author Relay Protocol
/// @notice Struct representing a cross-chain bridge message sent via Hyperlane
/// @dev Used to encode bridge transaction data for cross-chain messaging
/// @param nonce Unique identifier for the bridge transaction
/// @param recipient Address on the destination chain to receive the bridged assets
/// @param amount Amount of assets being bridged (in asset's smallest unit)
/// @param timestamp Unix timestamp when the message was created on the origin chain
struct HyperlaneMessage {
  uint256 nonce;
  address recipient;
  uint256 amount;
  uint256 timestamp;
}
TypeCasts.sol 19 lines
// SPDX-License-Identifier: MIT OR Apache-2.0
// from https://docs.hyperlane.xyz/docs/reference/libraries/typecasts
pragma solidity >=0.6.11;

library TypeCasts {
  // alignment preserving cast
  function addressToBytes32(address _addr) internal pure returns (bytes32) {
    return bytes32(uint256(uint160(_addr)));
  }

  // alignment preserving cast
  function bytes32ToAddress(bytes32 _buf) internal pure returns (address) {
    require(
      uint256(_buf) <= uint256(type(uint160).max),
      "TypeCasts: bytes32ToAddress overflow"
    );
    return address(uint160(uint256(_buf)));
  }
}
ERC20.sol 206 lines
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;

/// @notice Modern and gas efficient ERC20 + EIP-2612 implementation.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC20.sol)
/// @author Modified from Uniswap (https://github.com/Uniswap/uniswap-v2-core/blob/master/contracts/UniswapV2ERC20.sol)
/// @dev Do not manually set balances without updating totalSupply, as the sum of all user balances must not exceed it.
abstract contract ERC20 {
    /*//////////////////////////////////////////////////////////////
                                 EVENTS
    //////////////////////////////////////////////////////////////*/

    event Transfer(address indexed from, address indexed to, uint256 amount);

    event Approval(address indexed owner, address indexed spender, uint256 amount);

    /*//////////////////////////////////////////////////////////////
                            METADATA STORAGE
    //////////////////////////////////////////////////////////////*/

    string public name;

    string public symbol;

    uint8 public immutable decimals;

    /*//////////////////////////////////////////////////////////////
                              ERC20 STORAGE
    //////////////////////////////////////////////////////////////*/

    uint256 public totalSupply;

    mapping(address => uint256) public balanceOf;

    mapping(address => mapping(address => uint256)) public allowance;

    /*//////////////////////////////////////////////////////////////
                            EIP-2612 STORAGE
    //////////////////////////////////////////////////////////////*/

    uint256 internal immutable INITIAL_CHAIN_ID;

    bytes32 internal immutable INITIAL_DOMAIN_SEPARATOR;

    mapping(address => uint256) public nonces;

    /*//////////////////////////////////////////////////////////////
                               CONSTRUCTOR
    //////////////////////////////////////////////////////////////*/

    constructor(
        string memory _name,
        string memory _symbol,
        uint8 _decimals
    ) {
        name = _name;
        symbol = _symbol;
        decimals = _decimals;

        INITIAL_CHAIN_ID = block.chainid;
        INITIAL_DOMAIN_SEPARATOR = computeDomainSeparator();
    }

    /*//////////////////////////////////////////////////////////////
                               ERC20 LOGIC
    //////////////////////////////////////////////////////////////*/

    function approve(address spender, uint256 amount) public virtual returns (bool) {
        allowance[msg.sender][spender] = amount;

        emit Approval(msg.sender, spender, amount);

        return true;
    }

    function transfer(address to, uint256 amount) public virtual returns (bool) {
        balanceOf[msg.sender] -= amount;

        // Cannot overflow because the sum of all user
        // balances can't exceed the max uint256 value.
        unchecked {
            balanceOf[to] += amount;
        }

        emit Transfer(msg.sender, to, amount);

        return true;
    }

    function transferFrom(
        address from,
        address to,
        uint256 amount
    ) public virtual returns (bool) {
        uint256 allowed = allowance[from][msg.sender]; // Saves gas for limited approvals.

        if (allowed != type(uint256).max) allowance[from][msg.sender] = allowed - amount;

        balanceOf[from] -= amount;

        // Cannot overflow because the sum of all user
        // balances can't exceed the max uint256 value.
        unchecked {
            balanceOf[to] += amount;
        }

        emit Transfer(from, to, amount);

        return true;
    }

    /*//////////////////////////////////////////////////////////////
                             EIP-2612 LOGIC
    //////////////////////////////////////////////////////////////*/

    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) public virtual {
        require(deadline >= block.timestamp, "PERMIT_DEADLINE_EXPIRED");

        // Unchecked because the only math done is incrementing
        // the owner's nonce which cannot realistically overflow.
        unchecked {
            address recoveredAddress = ecrecover(
                keccak256(
                    abi.encodePacked(
                        "\x19\x01",
                        DOMAIN_SEPARATOR(),
                        keccak256(
                            abi.encode(
                                keccak256(
                                    "Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"
                                ),
                                owner,
                                spender,
                                value,
                                nonces[owner]++,
                                deadline
                            )
                        )
                    )
                ),
                v,
                r,
                s
            );

            require(recoveredAddress != address(0) && recoveredAddress == owner, "INVALID_SIGNER");

            allowance[recoveredAddress][spender] = value;
        }

        emit Approval(owner, spender, value);
    }

    function DOMAIN_SEPARATOR() public view virtual returns (bytes32) {
        return block.chainid == INITIAL_CHAIN_ID ? INITIAL_DOMAIN_SEPARATOR : computeDomainSeparator();
    }

    function computeDomainSeparator() internal view virtual returns (bytes32) {
        return
            keccak256(
                abi.encode(
                    keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"),
                    keccak256(bytes(name)),
                    keccak256("1"),
                    block.chainid,
                    address(this)
                )
            );
    }

    /*//////////////////////////////////////////////////////////////
                        INTERNAL MINT/BURN LOGIC
    //////////////////////////////////////////////////////////////*/

    function _mint(address to, uint256 amount) internal virtual {
        totalSupply += amount;

        // Cannot overflow because the sum of all user
        // balances can't exceed the max uint256 value.
        unchecked {
            balanceOf[to] += amount;
        }

        emit Transfer(address(0), to, amount);
    }

    function _burn(address from, uint256 amount) internal virtual {
        balanceOf[from] -= amount;

        // Cannot underflow because a user's balance
        // will never be larger than the total supply.
        unchecked {
            totalSupply -= amount;
        }

        emit Transfer(from, address(0), amount);
    }
}
ERC4626.sol 183 lines
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;

import {ERC20} from "../tokens/ERC20.sol";
import {SafeTransferLib} from "../utils/SafeTransferLib.sol";
import {FixedPointMathLib} from "../utils/FixedPointMathLib.sol";

/// @notice Minimal ERC4626 tokenized Vault implementation.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC4626.sol)
abstract contract ERC4626 is ERC20 {
    using SafeTransferLib for ERC20;
    using FixedPointMathLib for uint256;

    /*//////////////////////////////////////////////////////////////
                                 EVENTS
    //////////////////////////////////////////////////////////////*/

    event Deposit(address indexed caller, address indexed owner, uint256 assets, uint256 shares);

    event Withdraw(
        address indexed caller,
        address indexed receiver,
        address indexed owner,
        uint256 assets,
        uint256 shares
    );

    /*//////////////////////////////////////////////////////////////
                               IMMUTABLES
    //////////////////////////////////////////////////////////////*/

    ERC20 public immutable asset;

    constructor(
        ERC20 _asset,
        string memory _name,
        string memory _symbol
    ) ERC20(_name, _symbol, _asset.decimals()) {
        asset = _asset;
    }

    /*//////////////////////////////////////////////////////////////
                        DEPOSIT/WITHDRAWAL LOGIC
    //////////////////////////////////////////////////////////////*/

    function deposit(uint256 assets, address receiver) public virtual returns (uint256 shares) {
        // Check for rounding error since we round down in previewDeposit.
        require((shares = previewDeposit(assets)) != 0, "ZERO_SHARES");

        // Need to transfer before minting or ERC777s could reenter.
        asset.safeTransferFrom(msg.sender, address(this), assets);

        _mint(receiver, shares);

        emit Deposit(msg.sender, receiver, assets, shares);

        afterDeposit(assets, shares);
    }

    function mint(uint256 shares, address receiver) public virtual returns (uint256 assets) {
        assets = previewMint(shares); // No need to check for rounding error, previewMint rounds up.

        // Need to transfer before minting or ERC777s could reenter.
        asset.safeTransferFrom(msg.sender, address(this), assets);

        _mint(receiver, shares);

        emit Deposit(msg.sender, receiver, assets, shares);

        afterDeposit(assets, shares);
    }

    function withdraw(
        uint256 assets,
        address receiver,
        address owner
    ) public virtual returns (uint256 shares) {
        shares = previewWithdraw(assets); // No need to check for rounding error, previewWithdraw rounds up.

        if (msg.sender != owner) {
            uint256 allowed = allowance[owner][msg.sender]; // Saves gas for limited approvals.

            if (allowed != type(uint256).max) allowance[owner][msg.sender] = allowed - shares;
        }

        beforeWithdraw(assets, shares);

        _burn(owner, shares);

        emit Withdraw(msg.sender, receiver, owner, assets, shares);

        asset.safeTransfer(receiver, assets);
    }

    function redeem(
        uint256 shares,
        address receiver,
        address owner
    ) public virtual returns (uint256 assets) {
        if (msg.sender != owner) {
            uint256 allowed = allowance[owner][msg.sender]; // Saves gas for limited approvals.

            if (allowed != type(uint256).max) allowance[owner][msg.sender] = allowed - shares;
        }

        // Check for rounding error since we round down in previewRedeem.
        require((assets = previewRedeem(shares)) != 0, "ZERO_ASSETS");

        beforeWithdraw(assets, shares);

        _burn(owner, shares);

        emit Withdraw(msg.sender, receiver, owner, assets, shares);

        asset.safeTransfer(receiver, assets);
    }

    /*//////////////////////////////////////////////////////////////
                            ACCOUNTING LOGIC
    //////////////////////////////////////////////////////////////*/

    function totalAssets() public view virtual returns (uint256);

    function convertToShares(uint256 assets) public view virtual returns (uint256) {
        uint256 supply = totalSupply; // Saves an extra SLOAD if totalSupply is non-zero.

        return supply == 0 ? assets : assets.mulDivDown(supply, totalAssets());
    }

    function convertToAssets(uint256 shares) public view virtual returns (uint256) {
        uint256 supply = totalSupply; // Saves an extra SLOAD if totalSupply is non-zero.

        return supply == 0 ? shares : shares.mulDivDown(totalAssets(), supply);
    }

    function previewDeposit(uint256 assets) public view virtual returns (uint256) {
        return convertToShares(assets);
    }

    function previewMint(uint256 shares) public view virtual returns (uint256) {
        uint256 supply = totalSupply; // Saves an extra SLOAD if totalSupply is non-zero.

        return supply == 0 ? shares : shares.mulDivUp(totalAssets(), supply);
    }

    function previewWithdraw(uint256 assets) public view virtual returns (uint256) {
        uint256 supply = totalSupply; // Saves an extra SLOAD if totalSupply is non-zero.

        return supply == 0 ? assets : assets.mulDivUp(supply, totalAssets());
    }

    function previewRedeem(uint256 shares) public view virtual returns (uint256) {
        return convertToAssets(shares);
    }

    /*//////////////////////////////////////////////////////////////
                     DEPOSIT/WITHDRAWAL LIMIT LOGIC
    //////////////////////////////////////////////////////////////*/

    function maxDeposit(address) public view virtual returns (uint256) {
        return type(uint256).max;
    }

    function maxMint(address) public view virtual returns (uint256) {
        return type(uint256).max;
    }

    function maxWithdraw(address owner) public view virtual returns (uint256) {
        return convertToAssets(balanceOf[owner]);
    }

    function maxRedeem(address owner) public view virtual returns (uint256) {
        return balanceOf[owner];
    }

    /*//////////////////////////////////////////////////////////////
                          INTERNAL HOOKS LOGIC
    //////////////////////////////////////////////////////////////*/

    function beforeWithdraw(uint256 assets, uint256 shares) internal virtual {}

    function afterDeposit(uint256 assets, uint256 shares) internal virtual {}
}
FixedPointMathLib.sol 255 lines
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;

/// @notice Arithmetic library with operations for fixed-point numbers.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/FixedPointMathLib.sol)
/// @author Inspired by USM (https://github.com/usmfum/USM/blob/master/contracts/WadMath.sol)
library FixedPointMathLib {
    /*//////////////////////////////////////////////////////////////
                    SIMPLIFIED FIXED POINT OPERATIONS
    //////////////////////////////////////////////////////////////*/

    uint256 internal constant MAX_UINT256 = 2**256 - 1;

    uint256 internal constant WAD = 1e18; // The scalar of ETH and most ERC20s.

    function mulWadDown(uint256 x, uint256 y) internal pure returns (uint256) {
        return mulDivDown(x, y, WAD); // Equivalent to (x * y) / WAD rounded down.
    }

    function mulWadUp(uint256 x, uint256 y) internal pure returns (uint256) {
        return mulDivUp(x, y, WAD); // Equivalent to (x * y) / WAD rounded up.
    }

    function divWadDown(uint256 x, uint256 y) internal pure returns (uint256) {
        return mulDivDown(x, WAD, y); // Equivalent to (x * WAD) / y rounded down.
    }

    function divWadUp(uint256 x, uint256 y) internal pure returns (uint256) {
        return mulDivUp(x, WAD, y); // Equivalent to (x * WAD) / y rounded up.
    }

    /*//////////////////////////////////////////////////////////////
                    LOW LEVEL FIXED POINT OPERATIONS
    //////////////////////////////////////////////////////////////*/

    function mulDivDown(
        uint256 x,
        uint256 y,
        uint256 denominator
    ) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            // Equivalent to require(denominator != 0 && (y == 0 || x <= type(uint256).max / y))
            if iszero(mul(denominator, iszero(mul(y, gt(x, div(MAX_UINT256, y)))))) {
                revert(0, 0)
            }

            // Divide x * y by the denominator.
            z := div(mul(x, y), denominator)
        }
    }

    function mulDivUp(
        uint256 x,
        uint256 y,
        uint256 denominator
    ) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            // Equivalent to require(denominator != 0 && (y == 0 || x <= type(uint256).max / y))
            if iszero(mul(denominator, iszero(mul(y, gt(x, div(MAX_UINT256, y)))))) {
                revert(0, 0)
            }

            // If x * y modulo the denominator is strictly greater than 0,
            // 1 is added to round up the division of x * y by the denominator.
            z := add(gt(mod(mul(x, y), denominator), 0), div(mul(x, y), denominator))
        }
    }

    function rpow(
        uint256 x,
        uint256 n,
        uint256 scalar
    ) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            switch x
            case 0 {
                switch n
                case 0 {
                    // 0 ** 0 = 1
                    z := scalar
                }
                default {
                    // 0 ** n = 0
                    z := 0
                }
            }
            default {
                switch mod(n, 2)
                case 0 {
                    // If n is even, store scalar in z for now.
                    z := scalar
                }
                default {
                    // If n is odd, store x in z for now.
                    z := x
                }

                // Shifting right by 1 is like dividing by 2.
                let half := shr(1, scalar)

                for {
                    // Shift n right by 1 before looping to halve it.
                    n := shr(1, n)
                } n {
                    // Shift n right by 1 each iteration to halve it.
                    n := shr(1, n)
                } {
                    // Revert immediately if x ** 2 would overflow.
                    // Equivalent to iszero(eq(div(xx, x), x)) here.
                    if shr(128, x) {
                        revert(0, 0)
                    }

                    // Store x squared.
                    let xx := mul(x, x)

                    // Round to the nearest number.
                    let xxRound := add(xx, half)

                    // Revert if xx + half overflowed.
                    if lt(xxRound, xx) {
                        revert(0, 0)
                    }

                    // Set x to scaled xxRound.
                    x := div(xxRound, scalar)

                    // If n is even:
                    if mod(n, 2) {
                        // Compute z * x.
                        let zx := mul(z, x)

                        // If z * x overflowed:
                        if iszero(eq(div(zx, x), z)) {
                            // Revert if x is non-zero.
                            if iszero(iszero(x)) {
                                revert(0, 0)
                            }
                        }

                        // Round to the nearest number.
                        let zxRound := add(zx, half)

                        // Revert if zx + half overflowed.
                        if lt(zxRound, zx) {
                            revert(0, 0)
                        }

                        // Return properly scaled zxRound.
                        z := div(zxRound, scalar)
                    }
                }
            }
        }
    }

    /*//////////////////////////////////////////////////////////////
                        GENERAL NUMBER UTILITIES
    //////////////////////////////////////////////////////////////*/

    function sqrt(uint256 x) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            let y := x // We start y at x, which will help us make our initial estimate.

            z := 181 // The "correct" value is 1, but this saves a multiplication later.

            // This segment is to get a reasonable initial estimate for the Babylonian method. With a bad
            // start, the correct # of bits increases ~linearly each iteration instead of ~quadratically.

            // We check y >= 2^(k + 8) but shift right by k bits
            // each branch to ensure that if x >= 256, then y >= 256.
            if iszero(lt(y, 0x10000000000000000000000000000000000)) {
                y := shr(128, y)
                z := shl(64, z)
            }
            if iszero(lt(y, 0x1000000000000000000)) {
                y := shr(64, y)
                z := shl(32, z)
            }
            if iszero(lt(y, 0x10000000000)) {
                y := shr(32, y)
                z := shl(16, z)
            }
            if iszero(lt(y, 0x1000000)) {
                y := shr(16, y)
                z := shl(8, z)
            }

            // Goal was to get z*z*y within a small factor of x. More iterations could
            // get y in a tighter range. Currently, we will have y in [256, 256*2^16).
            // We ensured y >= 256 so that the relative difference between y and y+1 is small.
            // That's not possible if x < 256 but we can just verify those cases exhaustively.

            // Now, z*z*y <= x < z*z*(y+1), and y <= 2^(16+8), and either y >= 256, or x < 256.
            // Correctness can be checked exhaustively for x < 256, so we assume y >= 256.
            // Then z*sqrt(y) is within sqrt(257)/sqrt(256) of sqrt(x), or about 20bps.

            // For s in the range [1/256, 256], the estimate f(s) = (181/1024) * (s+1) is in the range
            // (1/2.84 * sqrt(s), 2.84 * sqrt(s)), with largest error when s = 1 and when s = 256 or 1/256.

            // Since y is in [256, 256*2^16), let a = y/65536, so that a is in [1/256, 256). Then we can estimate
            // sqrt(y) using sqrt(65536) * 181/1024 * (a + 1) = 181/4 * (y + 65536)/65536 = 181 * (y + 65536)/2^18.

            // There is no overflow risk here since y < 2^136 after the first branch above.
            z := shr(18, mul(z, add(y, 65536))) // A mul() is saved from starting z at 181.

            // Given the worst case multiplicative error of 2.84 above, 7 iterations should be enough.
            z := shr(1, add(z, div(x, z)))
            z := shr(1, add(z, div(x, z)))
            z := shr(1, add(z, div(x, z)))
            z := shr(1, add(z, div(x, z)))
            z := shr(1, add(z, div(x, z)))
            z := shr(1, add(z, div(x, z)))
            z := shr(1, add(z, div(x, z)))

            // If x+1 is a perfect square, the Babylonian method cycles between
            // floor(sqrt(x)) and ceil(sqrt(x)). This statement ensures we return floor.
            // See: https://en.wikipedia.org/wiki/Integer_square_root#Using_only_integer_division
            // Since the ceil is rare, we save gas on the assignment and repeat division in the rare case.
            // If you don't care whether the floor or ceil square root is returned, you can remove this statement.
            z := sub(z, lt(div(x, z), z))
        }
    }

    function unsafeMod(uint256 x, uint256 y) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            // Mod x by y. Note this will return
            // 0 instead of reverting if y is zero.
            z := mod(x, y)
        }
    }

    function unsafeDiv(uint256 x, uint256 y) internal pure returns (uint256 r) {
        /// @solidity memory-safe-assembly
        assembly {
            // Divide x by y. Note this will return
            // 0 instead of reverting if y is zero.
            r := div(x, y)
        }
    }

    function unsafeDivUp(uint256 x, uint256 y) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            // Add 1 to x * y if x % y > 0. Note this will
            // return 0 instead of reverting if y is zero.
            z := add(gt(mod(x, y), 0), div(x, y))
        }
    }
}
SafeTransferLib.sol 124 lines
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;

import {ERC20} from "../tokens/ERC20.sol";

/// @notice Safe ETH and ERC20 transfer library that gracefully handles missing return values.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/SafeTransferLib.sol)
/// @dev Use with caution! Some functions in this library knowingly create dirty bits at the destination of the free memory pointer.
library SafeTransferLib {
    /*//////////////////////////////////////////////////////////////
                             ETH OPERATIONS
    //////////////////////////////////////////////////////////////*/

    function safeTransferETH(address to, uint256 amount) internal {
        bool success;

        /// @solidity memory-safe-assembly
        assembly {
            // Transfer the ETH and store if it succeeded or not.
            success := call(gas(), to, amount, 0, 0, 0, 0)
        }

        require(success, "ETH_TRANSFER_FAILED");
    }

    /*//////////////////////////////////////////////////////////////
                            ERC20 OPERATIONS
    //////////////////////////////////////////////////////////////*/

    function safeTransferFrom(
        ERC20 token,
        address from,
        address to,
        uint256 amount
    ) internal {
        bool success;

        /// @solidity memory-safe-assembly
        assembly {
            // Get a pointer to some free memory.
            let freeMemoryPointer := mload(0x40)

            // Write the abi-encoded calldata into memory, beginning with the function selector.
            mstore(freeMemoryPointer, 0x23b872dd00000000000000000000000000000000000000000000000000000000)
            mstore(add(freeMemoryPointer, 4), and(from, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the "from" argument.
            mstore(add(freeMemoryPointer, 36), and(to, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the "to" argument.
            mstore(add(freeMemoryPointer, 68), amount) // Append the "amount" argument. Masking not required as it's a full 32 byte type.

            // We use 100 because the length of our calldata totals up like so: 4 + 32 * 3.
            // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space.
            success := call(gas(), token, 0, freeMemoryPointer, 100, 0, 32)

            // Set success to whether the call reverted, if not we check it either
            // returned exactly 1 (can't just be non-zero data), or had no return data and token has code.
            if and(iszero(and(eq(mload(0), 1), gt(returndatasize(), 31))), success) {
                success := iszero(or(iszero(extcodesize(token)), returndatasize())) 
            }
        }

        require(success, "TRANSFER_FROM_FAILED");
    }

    function safeTransfer(
        ERC20 token,
        address to,
        uint256 amount
    ) internal {
        bool success;

        /// @solidity memory-safe-assembly
        assembly {
            // Get a pointer to some free memory.
            let freeMemoryPointer := mload(0x40)

            // Write the abi-encoded calldata into memory, beginning with the function selector.
            mstore(freeMemoryPointer, 0xa9059cbb00000000000000000000000000000000000000000000000000000000)
            mstore(add(freeMemoryPointer, 4), and(to, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the "to" argument.
            mstore(add(freeMemoryPointer, 36), amount) // Append the "amount" argument. Masking not required as it's a full 32 byte type.

            // We use 68 because the length of our calldata totals up like so: 4 + 32 * 2.
            // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space.
            success := call(gas(), token, 0, freeMemoryPointer, 68, 0, 32)

            // Set success to whether the call reverted, if not we check it either
            // returned exactly 1 (can't just be non-zero data), or had no return data and token has code.
            if and(iszero(and(eq(mload(0), 1), gt(returndatasize(), 31))), success) {
                success := iszero(or(iszero(extcodesize(token)), returndatasize())) 
            }
        }

        require(success, "TRANSFER_FAILED");
    }

    function safeApprove(
        ERC20 token,
        address to,
        uint256 amount
    ) internal {
        bool success;

        /// @solidity memory-safe-assembly
        assembly {
            // Get a pointer to some free memory.
            let freeMemoryPointer := mload(0x40)

            // Write the abi-encoded calldata into memory, beginning with the function selector.
            mstore(freeMemoryPointer, 0x095ea7b300000000000000000000000000000000000000000000000000000000)
            mstore(add(freeMemoryPointer, 4), and(to, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the "to" argument.
            mstore(add(freeMemoryPointer, 36), amount) // Append the "amount" argument. Masking not required as it's a full 32 byte type.

            // We use 68 because the length of our calldata totals up like so: 4 + 32 * 2.
            // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space.
            success := call(gas(), token, 0, freeMemoryPointer, 68, 0, 32)

            // Set success to whether the call reverted, if not we check it either
            // returned exactly 1 (can't just be non-zero data), or had no return data and token has code.
            if and(iszero(and(eq(mload(0), 1), gt(returndatasize(), 31))), success) {
                success := iszero(or(iszero(extcodesize(token)), returndatasize())) 
            }
        }

        require(success, "APPROVE_FAILED");
    }
}

Read Contract

DOMAIN_SEPARATOR 0x3644e515 → bytes32
FRACTIONAL_BPS_DENOMINATOR 0x025d57c2 → uint256
HYPERLANE_MAILBOX 0xc751fbfb → address
WETH 0xad5c4648 → address
allowance 0xdd62ed3e → uint256
asset 0x38d52e0f → address
authorizedOrigins 0x66ef59ef → uint32, address, address, uint256, uint256, address, uint32, uint32
balanceOf 0x70a08231 → uint256
convertToAssets 0x07a2d13a → uint256
convertToShares 0xc6e6f592 → uint256
decimals 0x313ce567 → uint8
endOfStream 0xd02914a5 → uint256
lastAssetsCollectedAt 0x23658276 → uint256
maxDeposit 0x402d267d → uint256
maxMint 0xc63d75b6 → uint256
maxRedeem 0xd905777e → uint256
maxWithdraw 0xce96cb77 → uint256
messages 0x9ef03045 → bytes
name 0x06fdde03 → string
nonces 0x7ecebe00 → uint256
outstandingDebt 0x06f94a0d → uint256
owner 0x8da5cb5b → address
pendingBridgeFees 0x523bf8c0 → uint256
previewDeposit 0xef8b30f7 → uint256
previewMint 0xb3d7f6b9 → uint256
previewRedeem 0x4cdad506 → uint256
previewWithdraw 0x0a28a477 → uint256
streamingPeriod 0x5014de65 → uint256
symbol 0x95d89b41 → string
tokenSwapAddress 0xab6fb380 → address
totalAssets 0x01e1d114 → uint256
totalAssetsToStream 0xf1a3291d → uint256
totalSupply 0x18160ddd → uint256
yieldPool 0x8f188dd4 → address

Write Contract 21 functions

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

addOrigin 0xb95ab625
tuple origin
approve 0x095ea7b3
address spender
uint256 amount
returns: bool
claim 0x1790c562
uint32 chainId
address bridge
returns: uint256
collectNonDepositedAssets 0x0b6a97cb
No parameters
deposit 0x6e553f65
uint256 assets
address receiver
returns: uint256
disableOrigin 0x4bf47027
uint32 chainId
address bridge
handle 0x56d5d475
uint32 chainId
bytes32 bridgeAddress
bytes data
mint 0x94bf804d
uint256 shares
address receiver
returns: uint256
permit 0xd505accf
address owner
address spender
uint256 value
uint256 deadline
uint8 v
bytes32 r
bytes32 s
processFailedHandler 0xc9a7339f
uint32 chainId
address bridge
bytes data
redeem 0xba087652
uint256 shares
address receiver
address owner
returns: uint256
renounceOwnership 0x715018a6
No parameters
setTokenSwap 0x5cf9e54a
address newTokenSwapAddress
swapAndDeposit 0x765cb8d0
address token
uint256 amount
uint24 uniswapWethPoolFeeToken
uint24 uniswapWethPoolFeeAsset
uint48 deadline
uint256 amountOutMinimum
transfer 0xa9059cbb
address to
uint256 amount
returns: bool
transferFrom 0x23b872dd
address from
address to
uint256 amount
returns: bool
transferOwnership 0xf2fde38b
address newOwner
updateStreamedAssets 0x71d12ff8
No parameters
returns: uint256
updateStreamingPeriod 0x9671b587
uint256 newPeriod
updateYieldPool 0xb66ff261
address newPool
uint256 minSharePriceFromOldPool
uint256 maxSharePricePriceFromNewPool
withdraw 0xb460af94
uint256 assets
address receiver
address owner
returns: uint256

Recent Transactions

No transactions found for this address