Address Contract Verified
Address
0x57B68c4EA221ee8Da6eb14ebdfcCEE5177567771
Balance
0 ETH
Nonce
1
Code Size
17342 bytes
Creator
0x7098c187...ff73 at tx 0xab245071...3a0720
Indexed Transactions
0
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