Cryo Explorer Ethereum Mainnet

Address Contract Partially Verified

Address 0xcafe5De18756817D98F4603F6828397406D4CaFE
Balance 0 ETH
Nonce 1
Code Size 21972 bytes
Indexed Transactions 0
External Etherscan · Sourcify

Contract Bytecode

21972 bytes
0x6080604052600436106102d9575f3560e01c806371d41eb311610189578063b3f120a1116100d8578063e66f53b711610092578063f399e22e1161006d578063f399e22e14610944578063f69a00b614610963578063f7b6604e14610996578063fec53a14146109ac575f5ffd5b8063e66f53b7146108fd578063e78cea9214610911578063ea9e96a614610925575f5ffd5b8063b3f120a114610829578063c65a20f01461083d578063d505accf1461085c578063d6f29e811461087b578063dd62ed3e1461089a578063ddb2bf5c146108de575f5ffd5b806395d89b4111610143578063a53cb8511161011e578063a53cb8511461079e578063a9059cbb146107ca578063aa22dc33146107e9578063acb734bb14610815575f5ffd5b806395d89b411461074c5780639ecb381a14610760578063a41942a41461077f575f5ffd5b806371d41eb31461064657806377cc7a3a146106675780637ecebe001461068657806384b0196e146106a5578063873234cf146106cc5780638a510f271461072d575f5ffd5b8063313ce567116102455780635c975abb116101ff5780636aaa54cf116101da5780636aaa54cf146105c05780636d0d6a7e146105d45780636df0627e146105f357806370a0823114610612575f5ffd5b80635c975abb146105665780635f029ebe14610599578063692ea04b146105ac575f5ffd5b8063313ce567146104a45780633243bc60146104bf5780633644e515146104d357806347a10e56146104e7578063520a54951461053357806357a6d45a14610547575f5ffd5b806318160ddd1161029657806318160ddd146103d257806318bf5077146103e657806323b872dd1461040757806327ae6883146104265780632b8c49e31461045957806330315dc414610478575f5ffd5b806301ffc9a7146102dd57806306fdde0314610311578063095ea7b3146103325780630ed4c438146103515780631014d37514610373578063147040de146103be575b5f5ffd5b3480156102e8575f5ffd5b506102fc6102f7366004614267565b6109c0565b60405190151581526020015b60405180910390f35b34801561031c575f5ffd5b506103256109f6565b60405161030891906142bc565b34801561033d575f5ffd5b506102fc61034c3660046142e2565b610a86565b34801561035c575f5ffd5b50610365610a9d565b604051908152602001610308565b34801561037e575f5ffd5b506103a67f00000000000000000000000077703ae126b971c9946d562f41dd47071da0077781565b6040516001600160a01b039091168152602001610308565b3480156103c9575f5ffd5b50610325610abf565b3480156103dd575f5ffd5b50600254610365565b3480156103f1575f5ffd5b506104056104003660046142e2565b610aec565b005b348015610412575f5ffd5b506102fc61042136600461430c565b610b44565b348015610431575f5ffd5b506103a67f0000000000000000000000008147664fbd1571e3105e942527096f8bf5bf626481565b348015610464575f5ffd5b506104056104733660046142e2565b610b67565b348015610483575f5ffd5b5061048c610bb7565b6040516001600160401b039091168152602001610308565b3480156104af575f5ffd5b5060405160098152602001610308565b3480156104ca575f5ffd5b50610365610bd2565b3480156104de575f5ffd5b50610365610bf4565b3480156104f2575f5ffd5b506102fc61050136600461434a565b7f00000000000000000000000077703ae126b971c9946d562f41dd47071da007776001600160a01b0390811691161490565b34801561053e575f5ffd5b50610365610bfd565b348015610552575f5ffd5b50610405610561366004614374565b610c1b565b348015610571575f5ffd5b5061057a610d2b565b6040805193151584529115156020840152151590820152606001610308565b6103656105a73660046143b4565b610d7b565b3480156105b7575f5ffd5b50610365610ed9565b3480156105cb575f5ffd5b50610365610f00565b3480156105df575f5ffd5b506104056105ee36600461440f565b610f1e565b3480156105fe575f5ffd5b5061040561060d36600461447a565b611208565b34801561061d575f5ffd5b5061036561062c36600461434a565b6001600160a01b03165f9081526020819052604090205490565b348015610651575f5ffd5b5061065a6112da565b60405161030891906144e1565b348015610672575f5ffd5b506103656106813660046143b4565b6113b7565b348015610691575f5ffd5b506103656106a036600461434a565b6113d3565b3480156106b0575f5ffd5b506106b96113f0565b60405161030897969594939291906144f3565b3480156106d7575f5ffd5b506106e0611432565b60405161030891905f60808201905061ffff835116825261ffff60208401511660208301526001600160401b03604084015116604083015262ffffff606084015116606083015292915050565b348015610738575f5ffd5b506103656107473660046145a8565b6114b0565b348015610757575f5ffd5b50610325611803565b34801561076b575f5ffd5b5061040561077a36600461434a565b611812565b34801561078a575f5ffd5b5061040561079936600461434a565b6118d5565b3480156107a9575f5ffd5b506107bd6107b83660046143b4565b611990565b60405161030891906145ed565b3480156107d5575f5ffd5b506102fc6107e43660046142e2565b611a84565b3480156107f4575f5ffd5b506108086108033660046145fb565b611a91565b604051610308919061466a565b348015610820575f5ffd5b50610325611b52565b348015610834575f5ffd5b50610325611c4d565b348015610848575f5ffd5b506104056108573660046146b4565b611c86565b348015610867575f5ffd5b50610405610876366004614700565b611cd3565b348015610886575f5ffd5b5061040561089536600461476c565b611e0e565b3480156108a5575f5ffd5b506103656108b436600461479a565b6001600160a01b039182165f90815260016020908152604080832093909416825291909152205490565b3480156108e9575f5ffd5b506103656108f83660046143b4565b61201f565b348015610908575f5ffd5b506103a661204a565b34801561091c575f5ffd5b506103a6612065565b348015610930575f5ffd5b5061040561093f36600461487b565b61207d565b34801561094f575f5ffd5b5061040561095e36600461498f565b612134565b34801561096e575f5ffd5b506103a67f0000000000000000000000005c9584c0b5fe561fdc041b29878113d446d87e8081565b3480156109a1575f5ffd5b50633b9aca00610365565b3480156109b7575f5ffd5b50610365612492565b5f6001600160e01b03198216630cccc66560e21b14806109f057506301ffc9a760e01b6001600160e01b03198316145b92915050565b606060038054610a05906149ac565b80601f0160208091040260200160405190810160405280929190818152602001828054610a31906149ac565b8015610a7c5780601f10610a5357610100808354040283529160200191610a7c565b820191905f5260205f20905b815481529060010190602001808311610a5f57829003601f168201915b5050505050905090565b5f33610a938185856124a4565b5060019392505050565b5f610aa66124b1565b60020154600160401b90046001600160401b0316919050565b6060610ae760014614610ad06124b1565b6003015460601b6001600160601b031916906124d5565b905090565b610af533612526565b610aff82826125b8565b60405181815233906001600160a01b038416907fde22baff038e3a3e08407cbdf617deed74e869a7ba517df611e33131c6e6ea04906020015b60405180910390a35050565b5f33610b518582856125ec565b610b5c858585612668565b506001949350505050565b610b7033612526565b610b7a82826126c5565b60405181815233906001600160a01b038416907fb90795a66650155983e242cac3e1ac1a4dc26f8ed2987f3ce416a34e00111fd490602001610b38565b5f610bc06124b1565b600201546001600160401b0316919050565b5f610bdb6124b1565b60030154600160a01b90046001600160401b0316919050565b5f610ae76126f9565b5f610c066124b1565b60030154600160e01b900462ffffff16919050565b610c68610c266124b1565b600101546001600160a01b0316336001600160a01b0316146040518060400160405280600c81526020016b1d5b985d5d1a1bdc9a5e995960a21b815250612825565b82610c716124b1565b8054911515600160a01b0260ff60a01b1990921691909117905581610c946124b1565b6003018054911515600160f81b026001600160f81b0390921691909117905580610cbc6124b1565b60020180546001600160f81b0316600160f81b9215159290920291909117905560408051338152841515602082015283151581830152821515606082015290517f66b162f85d23ed59903ee9c03df5a009eb949fb229d6f4ffb235806f6663bbd69181900360800190a1505050565b5f5f5f610d366124b1565b54600160a01b900460ff16610d496124b1565b60030154600160f81b900460ff16610d5f6124b1565b600201601f9054906101000a900460ff16925092509250909192565b5f610d84612833565b610dcb610d8f6124b1565b600201601f9054906101000a900460ff16156040518060400160405280600c81526020016b706175736564206d696e747360a01b815250612825565b604051633752120b60e01b81526001600160a01b037f00000000000000000000000077703ae126b971c9946d562f41dd47071da00777811660048301527f0000000000000000000000005c9584c0b5fe561fdc041b29878113d446d87e801660248201526044810183905273eccc198b53afecb007234d5344e9b965d180c63c90633752120b90606401602060405180830381865af4158015610e70573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610e9491906149de565b9050610eca5f198214156040518060400160405280600e81526020016d185b1c9958591e481b5a5b9d195960921b815250612825565b610ed46001600855565b919050565b5f610ee26124b1565b60020154600160801b90046bffffffffffffffffffffffff16919050565b5f610f096124b1565b60020154600160e01b900462ffffff16919050565b610f26612833565b610f83610f316124b1565b6004015461ffff16610f496080860160608701614a04565b61ffff16101560405180604001604052806016815260200175696e73756666696369656e74207769746e657373657360501b815250612825565b610fce610f9e610f916124b1565b6006015460208601351490565b604051806040016040528060128152602001710d2dcecc2d8d2c840e4c2c8dedc40d0c2e6d60731b815250612825565b604051633686b53f60e11b81525f906001600160a01b037f00000000000000000000000077703ae126b971c9946d562f41dd47071da007771690636d0d6a7e9061102090879087908790600401614a88565b5f604051808303815f875af115801561103b573d5f5f3e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526110629190810190614c98565b6040516367c4440f60e01b815290915073eccc198b53afecb007234d5344e9b965d180c63c906367c4440f9061109c908490600401614dee565b602060405180830381865af49250505080156110d5575060408051601f3d908101601f191682019092526110d291810190614e70565b60015b611148576110e1614e8b565b806308c379a00361110f57506110f5614ea3565b806111005750611111565b6111098161285d565b506111f8565b505b3d80801561113a576040519150601f19603f3d011682016040523d82523d5f602084013e61113f565b606091505b50611109612894565b604080830151608084015182516001600160401b038086168252909116602082015290917f8a01b18bdca3d556adc5e6a85f562b83d2c1933f166e93421ff507cfccb09a07910160405180910390a2806111a06124b1565b60020160086101000a8154816001600160401b0302191690836001600160401b0316021790555081608001516111d46124b1565b600201805467ffffffffffffffff19166001600160401b0392909216919091179055505b506112036001600855565b505050565b611213610c266124b1565b6112c460036112256020840184614a04565b61ffff161015801561124b575060326112446040840160208501614a04565b61ffff1611155b80156112735750630bebc2006112676060840160408501614f25565b6001600160401b031610155b801561129657506203345061128e6080840160608501614f50565b62ffffff1610155b6040518060400160405280601081526020016f696e76616c69642073657474696e677360801b815250612825565b806112cd6124b1565b6004016112038282614f6b565b60606112e46124b1565b600501805480602002602001604051908101604052809291908181526020015f905b828210156113ae578382905f5260205f20018054611323906149ac565b80601f016020809104026020016040519081016040528092919081815260200182805461134f906149ac565b801561139a5780601f106113715761010080835404028352916020019161139a565b820191905f5260205f20905b81548152906001019060200180831161137d57829003601f168201915b505050505081526020019060010190611306565b50505050905090565b5f6113c06124b1565b5f92835260070160205250604090205490565b6001600160a01b0381165f908152600760205260408120546109f0565b5f6060805f5f5f60606114016128ca565b6114096128f7565b604080515f80825260208201909252600f60f81b9b939a50919850469750309650945092509050565b604080516080810182525f80825260208201819052918101829052606081019190915261145d6124b1565b604080516080810182526004929092015461ffff808216845262010000820416602084015264010000000081046001600160401b031691830191909152600160601b900462ffffff166060820152919050565b5f6114f86114bc6124b1565b600301601f9054906101000a900460ff16156040518060400160405280600c81526020016b706175736564206275726e7360a01b815250612825565b6115406001600160401b03851661150e3361062c565b1015604051806040016040528060128152602001716e6f7420656e6f7567682062616c616e636560701b815250612825565b5f6115496124b1565b6002015460408051808201909152601781527f63616e6e6f7420756e777261702074686174206d75636800000000000000000060208201526001600160401b03600160401b909204821692506115a491871683101590612825565b6115f3633b9aca00866001600160401b031610156040518060400160405280601981526020017f63616e6e6f7420756e777261702074686174206c6974746c6500000000000000815250612825565b5f61163785858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250504660011491506129249050565b90506116cb7f70fa10e5bf7a5778ff7a34ae40e9929bb09930b30000000000000000000000006001600160601b03199081169083161415801561169c575061169a6116806124b1565b6003015460601b6001600160601b03199081169084161490565b155b604051806040016040528060118152602001701a5b9d985b1a59081c9958da5c1a595b9d607a1b815250612825565b6116d58683615030565b6116dd6124b1565b60020180546fffffffffffffffff00000000000000001916600160401b6001600160401b039384160217905561171690339088166126c5565b61171e6124b1565b6003018054601c9061173b90600160e01b900462ffffff1661504f565b91906101000a81548162ffffff021916908362ffffff160217905562ffffff169250856117666124b1565b6003018054601490611789908490600160a01b90046001600160401b0316615071565b92506101000a8154816001600160401b0302191690836001600160401b031602179055506117b43390565b6001600160a01b03167f0ac1547df8510f30b54430e0e4e1e93ce326490aec9cebf0f78b8faa55dc1ded868689876040516117f29493929190615090565b60405180910390a250509392505050565b606060048054610a05906149ac565b61181d610c266124b1565b60408051808201909152600b81526a7a65726f2062726964676560a81b6020820152611855906001600160a01b038316151590612825565b7f9d20a3013144fe0ad1f61c921e224f9c4788418e3af6670991d30c5b6804c4843361187f6124b1565b54604080516001600160a01b03938416815291831660208301529184168183015290519081900360600190a1806118b46124b1565b80546001600160a01b0319166001600160a01b039290921691909117905550565b6118e0610c266124b1565b60408051808201909152600c81526b3d32b9379031bab930ba37b960a11b6020820152611919906001600160a01b038316151590612825565b806001600160a01b031661192b6124b1565b600101546040516001600160a01b03909116907fc63757acc12b39558fe5b88c5393e4b0353ffddaae3a2d07e121a8fc62d39c37905f90a38061196c6124b1565b60010180546001600160a01b0319166001600160a01b039290921691909117905550565b5f5f61199a6124b1565b5f848152600791909101602052604081205491508190036119bd57505f92915050565b5f1981036119ce5750600392915050565b6001604051631bc1eaf360e21b8152600481018390527f00000000000000000000000077703ae126b971c9946d562f41dd47071da007776001600160a01b031690636f07abcc90602401602060405180830381865afa158015611a33573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611a5791906150bf565b6006811115611a6857611a686145c5565b14611a74576002611a77565b60015b9392505050565b50919050565b5f33610a93818585612668565b6060816001600160401b03811115611aab57611aab6147d1565b604051908082528060200260200182016040528015611ad4578160200160208202803683370190505b5090505f5b82811015611b4b57611b02848483818110611af657611af66150dd565b90506020020135611990565b828281518110611b1457611b146150dd565b60200260200101906003811115611b2d57611b2d6145c5565b90816003811115611b4057611b406145c5565b905250600101611ad9565b5092915050565b60607f00000000000000000000000077703ae126b971c9946d562f41dd47071da007776001600160a01b0316637b1039996040518163ffffffff1660e01b8152600401602060405180830381865afa158015611bb0573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611bd491906150f1565b6001600160a01b0316638a227764611bea6124b1565b600601546040518263ffffffff1660e01b8152600401611c0c91815260200190565b5f60405180830381865afa158015611c26573d5f5f3e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052610ae7919081019061510c565b6060610ae76001600160601b03197f70fa10e5bf7a5778ff7a34ae40e9929bb09930b300000000000000000000000016466001146124d5565b611c91610c266124b1565b611ccf82828080601f0160208091040260200160405190810160405280939291908181526020018383808284375f920191909152506129d592505050565b5050565b83421115611cfc5760405163313c898160e11b8152600481018590526024015b60405180910390fd5b5f7f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9888888611d478c6001600160a01b03165f90815260076020526040902080546001810190915590565b6040805160208101969096526001600160a01b0394851690860152929091166060840152608083015260a082015260c0810186905260e0016040516020818303038152906040528051906020012090505f611da182612b7f565b90505f611db082878787612bab565b9050896001600160a01b0316816001600160a01b031614611df7576040516325c0072360e11b81526001600160a01b0380831660048301528b166024820152604401611cf3565b611e028a8a8a6124a4565b50505050505050505050565b611e16612833565b611e717f00000000000000000000000077703ae126b971c9946d562f41dd47071da007776001600160a01b031633146040518060400160405280600e81526020016d696e76616c6964206f7261636c6560901b815250612825565b604051635d933eb760e01b815273eccc198b53afecb007234d5344e9b965d180c63c90635d933eb790611eac9086908690869060040161513d565b5f60405180830381865af4925050508015611ee857506040513d5f823e601f3d908101601f19168201604052611ee59190810190615156565b60015b611f5b57611ef4614e8b565b806308c379a003611f225750611f08614ea3565b80611f135750611f24565b611f1c8161285d565b50612015565b505b3d808015611f4d576040519150601f19603f3d011682016040523d82523d5f602084013e611f52565b606091505b50611f1c612894565b611fb77f162f79432c9f1c2ad59cffb77a1a8c184062442a0ca347b39c4e65fb114d47758580519060200120146040518060400160405280601181526020017034b73b30b634b21031bab9ba37b234b0b760791b815250612825565b611fca82826001600160401b03166125b8565b816001600160a01b03167fbae099c209765c02c309f0fac06aec3ac516a3cc60d09f1a3da4b52d673d28a3848388604051612007939291906151ea565b60405180910390a250505050505b6112036001600855565b5f6109f07f00000000000000000000000077703ae126b971c9946d562f41dd47071da0077783612bd7565b5f6120536124b1565b600101546001600160a01b0316919050565b5f61206e6124b1565b546001600160a01b0316919050565b612088610c266124b1565b6120c05f82511160405180604001604052806013815260200172656d707479207270632070726f76696465727360681b815250612825565b806120c96124b1565b60050190805190602001906120df9291906141b1565b506120f8816120f360014614610ad06124b1565b612cdd565b7f3847d0a1ed317f0f886923b234ef1259a67db2f4a0020e85eb0e5b36abf3cae03382604051612129929190615217565b60405180910390a150565b5f61213d612dee565b805490915060ff600160401b82041615906001600160401b03165f811580156121635750825b90505f826001600160401b0316600114801561217e5750303b155b90508115801561218c575080155b156121aa5760405163f92ee8a960e01b815260040160405180910390fd5b845467ffffffffffffffff1916600117855583156121d457845460ff60401b1916600160401b1785555b876121dd6124b1565b60010180546001600160a01b0319166001600160a01b03928316179055604051908916905f907fc63757acc12b39558fe5b88c5393e4b0353ffddaae3a2d07e121a8fc62d39c37908290a36028602160991b016122386124b1565b80546001600160a01b0319166001600160a01b039290921691909117905560408051608081019091528046600114612271576003612274565b600c5b61ffff16815260056020820152630bebc20060408201526203345060609091015261229d6124b1565b8151600491909101805460208085015160408087015160609097015162ffffff16600160601b0262ffffff60601b196001600160401b0390981664010000000002979097166effffffffffffffffffffff000000001961ffff938416620100000263ffffffff199096169390971692909217939093179490941693909317939093179055815160018082528184019093525f92909182015b60608152602001906001900390816123355790505090506001461461238f576040518060400160405280601d81526020017f68747470733a2f2f7270632d746573746e65742e7769746e65742e696f0000008152506123c6565b6040518060400160405280601881526020017f68747470733a2f2f7270632d30312e7769746e65742e696f00000000000000008152505b815f815181106123d8576123d86150dd565b6020026020010181905250806123ec6124b1565b60050190805190602001906124029291906141b1565b5061244188888080601f0160208091040260200160405190810160405280939291908181526020018383808284375f920191909152506129d592505050565b50831561248857845460ff60401b19168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b5050505050505050565b5f61249b6124b1565b60060154905090565b6112038383836001612e16565b7f6116473658e87b023e7f215d122c0048f3d7a669d8df94a5565f0c95871c580090565b6060611a778360601c8361250557604051806040016040528060048152602001631d1dda5d60e21b815250612ee8565b604051806040016040528060038152602001621dda5d60ea1b815250612ee8565b6125736125316124b1565b54604080518082019091526013815272756e617574686f72697a65642062726964676560681b60208201526001600160a01b0384811692169190911490612825565b6125b561257e6124b1565b5460408051808201909152600d81526c7061757365642062726964676560981b6020820152600160a01b90910460ff161590612825565b50565b6001600160a01b0382166125e15760405163ec442f0560e01b81525f6004820152602401611cf3565b611ccf5f8383612f1c565b6001600160a01b038381165f908152600160209081526040808320938616835292905220545f19811015612662578181101561265457604051637dc7a0d960e11b81526001600160a01b03841660048201526024810182905260448101839052606401611cf3565b61266284848484035f612e16565b50505050565b6001600160a01b03831661269157604051634b637e8f60e11b81525f6004820152602401611cf3565b6001600160a01b0382166126ba5760405163ec442f0560e01b81525f6004820152602401611cf3565b611203838383612f1c565b6001600160a01b0382166126ee57604051634b637e8f60e11b81525f6004820152602401611cf3565b611ccf825f83612f1c565b5f306001600160a01b037f000000000000000000000000cafe5de18756817d98f4603f6828397406d4cafe1614801561275157507f000000000000000000000000000000000000000000000000000000000000000146145b1561277b57507f08e1e3a649641b7e6ba6228d0c7379f1fa60b7e3eee2c7e0cc309a975103e11c90565b610ae7604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60208201527fa51b04f7b61713ec5f80ea1d85243b3c6ec21caca925fa934cc35abd7d86dab8918101919091527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a08201525f9060c00160405160208183030381529060405280519060200120905090565b90565b81611ccf57611ccf8161285d565b60026008540361285657604051633ee5aeb560e01b815260040160405180910390fd5b6002600855565b8060405160200161286e9190615251565b60408051601f198184030181529082905262461bcd60e51b8252611cf3916004016142bc565b6128c8604051806040016040528060138152602001723ab73430b7323632b21032bc31b2b83a34b7b760691b81525061285d565b565b6060610ae77f5769746e657400000000000000000000000000000000000000000000000000066005613042565b6060610ae77f31000000000000000000000000000000000000000000000000000000000000016006613042565b5f8161293157602b612934565b602a5b60ff1683511461297f5760405162461bcd60e51b8152602060048201526016602482015275084cac6d066647440d2dcecc2d8d2c840d8cadccee8d60531b6044820152606401611cf3565b6129cb83836129aa57604051806040016040528060048152602001631d1dda5d60e21b8152506130eb565b604051806040016040528060038152602001621dda5d60ea1b8152506130eb565b60601b9392505050565b612a377f162f79432c9f1c2ad59cffb77a1a8c184062442a0ca347b39c4e65fb114d477582805190602001201415604051806040016040528060168152602001753ab730b1b1b2b83a30b13632903ab73bb930b83832b960511b815250612825565b7f844058b2a3856451d27b99dee44bd7cecf3ce6104d17b7f59ab652d3ae03a5d13382604051612a68929190615272565b60405180910390a1612a7d8160014614612924565b612a856124b1565b60030180546001600160a01b03191660609290921c9190911790556125b5612aab6124b1565b600501805480602002602001604051908101604052809291908181526020015f905b82821015612b75578382905f5260205f20018054612aea906149ac565b80601f0160208091040260200160405190810160405280929190818152602001828054612b16906149ac565b8015612b615780601f10612b3857610100808354040283529160200191612b61565b820191905f5260205f20905b815481529060010190602001808311612b4457829003601f168201915b505050505081526020019060010190612acd565b5050505082612cdd565b5f6109f0612b8b6126f9565b8360405161190160f01b8152600281019290925260228201526042902090565b5f5f5f5f612bbb88888888613169565b925092509250612bcb8282613231565b50909695505050505050565b5f806001600160a01b0384166305e742ef847f6116473658e87b023e7f215d122c0048f3d7a669d8df94a5565f0c95871c580060049081015460405160e085901b6001600160e01b031916815291820192909252600160601b90910462ffffff166024820152604401602060405180830381865afa158015612c5b573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612c7f91906149de565b905060647f6116473658e87b023e7f215d122c0048f3d7a669d8df94a5565f0c95871c580060040154612cbd9062010000900461ffff166064615295565b612ccb9061ffff16836152af565b612cd591906152c6565b949350505050565b604080516002808252606082019092525f91816020015b6060815260200190600190039081612cf4579050509050612d13611c4d565b815f81518110612d2557612d256150dd565b60200260200101819052508181600181518110612d4457612d446150dd565b6020908102919091010152604051633c389c6f60e21b81526001600160a01b037f0000000000000000000000008147664fbd1571e3105e942527096f8bf5bf6264169063f0e271bc90612d9d90849087906004016152e5565b6020604051808303815f875af1158015612db9573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612ddd91906149de565b612de56124b1565b60060155505050565b5f807ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a006109f0565b6001600160a01b038416612e3f5760405163e602df0560e01b81525f6004820152602401611cf3565b6001600160a01b038316612e6857604051634a1406b160e11b81525f6004820152602401611cf3565b6001600160a01b038085165f908152600160209081526040808320938716835292905220829055801561266257826001600160a01b0316846001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92584604051612eda91815260200190565b60405180910390a350505050565b604051606083811b6001600160601b031916602083015290611a7790603401604051602081830303815290604052836132e9565b6001600160a01b038316612f46578060025f828254612f3b9190615309565b90915550612fb69050565b6001600160a01b0383165f9081526020819052604090205481811015612f985760405163391434e360e21b81526001600160a01b03851660048201526024810182905260448101839052606401611cf3565b6001600160a01b0384165f9081526020819052604090209082900390555b6001600160a01b038216612fd257600280548290039055612ff0565b6001600160a01b0382165f9081526020819052604090208054820190555b816001600160a01b0316836001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8360405161303591815260200190565b60405180910390a3505050565b606060ff831461305c5761305583613335565b90506109f0565b818054613068906149ac565b80601f0160208091040260200160405190810160405280929190818152602001828054613094906149ac565b80156130df5780601f106130b6576101008083540402835291602001916130df565b820191905f5260205f20905b8154815290600101906020018083116130c257829003601f168201915b505050505090506109f0565b5f5f5f61311885604051602001613102919061531c565b6040516020818303038152906040526001613372565b9150915061314584604051602001613130919061531c565b604051602081830303815290604052836136fc565b5f61315482600560085f613750565b905061315f8161375e565b9695505050505050565b5f80807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08411156131a257505f91506003905082613227565b604080515f808252602082018084528a905260ff891692820192909252606081018790526080810186905260019060a0016020604051602081039080840390855afa1580156131f3573d5f5f3e3d5ffd5b5050604051601f1901519150506001600160a01b03811661321e57505f925060019150829050613227565b92505f91508190505b9450945094915050565b5f826003811115613244576132446145c5565b0361324d575050565b6001826003811115613261576132616145c5565b0361327f5760405163f645eedf60e01b815260040160405180910390fd5b6002826003811115613293576132936145c5565b036132b45760405163fce698f760e01b815260048101829052602401611cf3565b60038260038111156132c8576132c86145c5565b03611ccf576040516335e2f38360e21b815260048101829052602401611cf3565b60605f826040516020016132fd919061531c565b60405160208183030381529060405290505f61331e856008600560016137b8565b905061332c8282600161387e565b95945050505050565b60605f61334183613b00565b6040805160208082528183019092529192505f91906020820181803683375050509182525060208101929092525090565b6060805f605a855111156133c85760405162461bcd60e51b815260206004820152601d60248201527f4265636833323a20696e76616c696420737472696e67206c656e6774680000006044820152606401611cf3565b5f5b85518110156134c3575f8682815181106133e6576133e66150dd565b016020015160f81c9050602181108015906134055750607e8160ff1611155b6134465760405162461bcd60e51b81526020600482015260126024820152712132b1b419991d103bb937b7339031b430b960711b6044820152606401611cf3565b60301960ff8216016134ba5782158015613461575060018210155b8015613471575086518260070111155b6134b65760405162461bcd60e51b81526020600482015260166024820152754265636833323a2077726f6e6720706f73206f66203160501b6044820152606401611cf3565b8192505b506001016133ca565b50806001600160401b038111156134dc576134dc6147d1565b6040519080825280601f01601f191660200182016040528015613506576020820181803683370190505b5092505f5b8181101561356057858181518110613525576135256150dd565b602001015160f81c60f81b848281518110613542576135426150dd565b60200101906001600160f81b03191690815f1a90535060010161350b565b50600181865103036001600160401b0381111561357f5761357f6147d1565b6040519080825280602002602001820160405280156135a8578160200160208202803683370190505b5091505f5b8251811015613699575f604051806101200160405280610100815260200161547f610100913987848401600101815181106135ea576135ea6150dd565b0160200151815160f89190911c908110613606576136066150dd565b01602001516001600160f81b031990811691508190036136685760405162461bcd60e51b815260206004820152601c60248201527f4265636833323a2062797465206e6f7420696e20616c706861626574000000006044820152606401611cf3565b8060f81c84838151811061367e5761367e6150dd565b60ff90921660209283029190910190910152506001016135ad565b506136a5838386613b27565b6136ea5760405162461bcd60e51b81526020600482015260166024820152754265636833323a2077726f6e6720636865636b73756d60501b6044820152606401611cf3565b50805160051901815290939092509050565b8080519060200120828051906020012014611ccf5760405162461bcd60e51b8152602060048201526014602482015273084cac6d066647440d0e4e040dad2e6dac2e8c6d60631b6044820152606401611cf3565b606061332c85858585613c51565b5f81516014146137b05760405162461bcd60e51b815260206004820152601b60248201527f4265636833323a20696e76616c69642064617461206c656e67746800000000006044820152606401611cf3565b506014015190565b60605f85516001600160401b038111156137d4576137d46147d1565b6040519080825280602002602001820160405280156137fd578160200160208202803683370190505b5090505f5b81518163ffffffff16101561387157868163ffffffff1681518110613829576138296150dd565b602001015160f81c60f81b60f81c828263ffffffff168151811061384f5761384f6150dd565b60ff9092166020928302919091019091015261386a81615327565b9050613802565b5061315f81868686613c51565b60605f61388c858585613e1e565b90505f81518551875101016001016001600160401b038111156138b1576138b16147d1565b6040519080825280601f01601f1916602001820160405280156138db576020820181803683370190505b5090505f5b8651811015613936578681815181106138fb576138fb6150dd565b602001015160f81c60f81b828281518110613918576139186150dd565b60200101906001600160f81b03191690815f1a9053506001016138e0565b50603160f81b8187518151811061394f5761394f6150dd565b60200101906001600160f81b03191690815f1a90535085516001015f5b8651811015613a30575f878281518110613988576139886150dd565b01602090810151604080518082019091528281525f51602061557f5f395f51905f529083015260f81c9150811015613a27576040518060400160405280602081526020015f51602061557f5f395f51905f528152508160ff16815181106139f1576139f16150dd565b602001015160f81c60f81b8484840181518110613a1057613a106150dd565b60200101906001600160f81b03191690815f1a9053505b5060010161396c565b508551015f5b8351811015612bcb575f848281518110613a5257613a526150dd565b602002602001015190506040518060400160405280602081526020015f51602061557f5f395f51905f52815250518160ff161015613af7576040518060400160405280602081526020015f51602061557f5f395f51905f528152508160ff1681518110613ac157613ac16150dd565b602001015160f81c60f81b8484840181518110613ae057613ae06150dd565b60200101906001600160f81b03191690815f1a9053505b50600101613a36565b5f60ff8216601f8111156109f057604051632cd44ac360e21b815260040160405180910390fd5b5f5f613b3285613fbd565b90505f84518251016001600160401b03811115613b5157613b516147d1565b604051908082528060200260200182016040528015613b7a578160200160208202803683370190505b5090505f5b8251811015613bd457828181518110613b9a57613b9a6150dd565b602002602001015160ff16828281518110613bb757613bb76150dd565b63ffffffff90921660209283029190910190910152600101613b7f565b505f5b8551811015613c2f57858181518110613bf257613bf26150dd565b602002602001015160ff16828451830181518110613c1257613c126150dd565b63ffffffff90921660209283029190910190910152600101613bd7565b508363ffffffff16613c40826140b7565b63ffffffff16149695505050505050565b60605f8080613c63600180881b615342565b90505f5b8851811015613d57575f898281518110613c8357613c836150dd565b6020908102919091010151905060ff8082168a1c1615613d045760405162461bcd60e51b815260206004820152603660248201527f4265636833323a2076616c7565206d757374206265206e6f6e2d6e6567617469604482015275766520616e642066697420696e2066726f6d6269747360501b6064820152608401611cf3565b93881b60ff85161793928801925b878410613d4e576040519388900393613d3890879087871c861660f81b90602001615355565b6040516020818303038152906040529550613d12565b50600101613c67565b508415613d9f578115613d9a578381613d708489615342565b85901b1660f81b604051602001613d88929190615355565b60405160208183030381529060405293505b613e13565b86821080613db9575080613db38388615342565b84901b16155b613e135760405162461bcd60e51b815260206004820152602560248201527f4265636833323a20696e76616c69642070616464696e67206f722076616c75656044820152642073697a6560d81b6064820152608401611cf3565b505050949350505050565b60605f613e2a85613fbd565b90505f84518251016006016001600160401b03811115613e4c57613e4c6147d1565b604051908082528060200260200182016040528015613e75578160200160208202803683370190505b5090505f5b8551835101811015613f38578251811015613edd57828181518110613ea157613ea16150dd565b602002602001015160ff16828281518110613ebe57613ebe6150dd565b602002602001019063ffffffff16908163ffffffff1681525050613f30565b858351820381518110613ef257613ef26150dd565b602001015160f81c60f81b60f81c60ff16828281518110613f1557613f156150dd565b602002602001019063ffffffff16908163ffffffff16815250505b600101613e7a565b5060408051600680825260e08201909252906020820160c0803683370190505092505f84613f65836140b7565b1890505f5b6006811015613fb257806005036005028263ffffffff16901c601f16858281518110613f9857613f986150dd565b60ff90921660209283029190910190910152600101613f6a565b505050509392505050565b606081518251016001016001600160401b03811115613fde57613fde6147d1565b604051908082528060200260200182016040528015614007578160200160208202803683370190505b5090505f5b8251811015611a7e576005838281518110614029576140296150dd565b602001015160f81c60f81b60f81c60ff16901c82828151811061404e5761404e6150dd565b602002602001019060ff16908160ff1681525050828181518110614074576140746150dd565b602001015160f81c60f81b60f81c601f1682845183016001018151811061409d5761409d6150dd565b60ff9092166020928302919091019091015260010161400c565b6040805160a081018252633b6a57b281526326508e6d6020820152631ea119fa91810191909152633d4233dd6060820152632a1462b360808201525f90600190825b84518163ffffffff1610156141a8575f60198463ffffffff16901c9050858263ffffffff168151811061412e5761412e6150dd565b60200260200101516005856301ffffff1663ffffffff16901b1893505f5f90505b60058163ffffffff16101561419e57600163ffffffff8381169083161c8116900361419657838163ffffffff166005811061418c5761418c6150dd565b6020020151851894505b60010161414f565b50506001016140f9565b50909392505050565b828054828255905f5260205f209081019282156141f5579160200282015b828111156141f557825182906141e590826153c4565b50916020019190600101906141cf565b50614201929150614205565b5090565b80821115614201575f6142188282614221565b50600101614205565b50805461422d906149ac565b5f825580601f1061423c575050565b601f0160209004905f5260205f20908101906125b591905b80821115614201575f8155600101614254565b5f60208284031215614277575f5ffd5b81356001600160e01b031981168114611a77575f5ffd5b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b602081525f611a77602083018461428e565b6001600160a01b03811681146125b5575f5ffd5b5f5f604083850312156142f3575f5ffd5b82356142fe816142ce565b946020939093013593505050565b5f5f5f6060848603121561431e575f5ffd5b8335614329816142ce565b92506020840135614339816142ce565b929592945050506040919091013590565b5f6020828403121561435a575f5ffd5b8135611a77816142ce565b80358015158114610ed4575f5ffd5b5f5f5f60608486031215614386575f5ffd5b61438f84614365565b925061439d60208501614365565b91506143ab60408501614365565b90509250925092565b5f602082840312156143c4575f5ffd5b5035919050565b5f5f83601f8401126143db575f5ffd5b5081356001600160401b038111156143f1575f5ffd5b602083019150836020828501011115614408575f5ffd5b9250929050565b5f5f5f60408486031215614421575f5ffd5b83356001600160401b03811115614436575f5ffd5b840160e08187031215614447575f5ffd5b925060208401356001600160401b03811115614461575f5ffd5b61446d868287016143cb565b9497909650939450505050565b5f608082840312801561448b575f5ffd5b509092915050565b5f82825180855260208501945060208160051b830101602085015f5b83811015612bcb57601f198584030188526144cb83835161428e565b60209889019890935091909101906001016144af565b602081525f611a776020830184614493565b60ff60f81b8816815260e060208201525f61451160e083018961428e565b8281036040840152614523818961428e565b606084018890526001600160a01b038716608085015260a0840186905283810360c0850152845180825260208087019350909101905f5b8181101561457857835183526020938401939092019160010161455a565b50909b9a5050505050505050505050565b6001600160401b03811681146125b5575f5ffd5b8035610ed481614589565b5f5f5f604084860312156145ba575f5ffd5b833561444781614589565b634e487b7160e01b5f52602160045260245ffd5b600481106145e9576145e96145c5565b9052565b602081016109f082846145d9565b5f5f6020838503121561460c575f5ffd5b82356001600160401b03811115614621575f5ffd5b8301601f81018513614631575f5ffd5b80356001600160401b03811115614646575f5ffd5b8560208260051b840101111561465a575f5ffd5b6020919091019590945092505050565b602080825282518282018190525f918401906040840190835b818110156146a9576146968385516145d9565b6020938401939290920191600101614683565b509095945050505050565b5f5f602083850312156146c5575f5ffd5b82356001600160401b038111156146da575f5ffd5b6146e6858286016143cb565b90969095509350505050565b60ff811681146125b5575f5ffd5b5f5f5f5f5f5f5f60e0888a031215614716575f5ffd5b8735614721816142ce565b96506020880135614731816142ce565b95506040880135945060608801359350608088013561474f816146f2565b9699959850939692959460a0840135945060c09093013592915050565b5f5f5f6040848603121561477e575f5ffd5b8335925060208401356001600160401b03811115614461575f5ffd5b5f5f604083850312156147ab575f5ffd5b82356147b6816142ce565b915060208301356147c6816142ce565b809150509250929050565b634e487b7160e01b5f52604160045260245ffd5b60c081018181106001600160401b0382111715614804576148046147d1565b60405250565b604081018181106001600160401b0382111715614804576148046147d1565b601f8201601f191681016001600160401b038111828210171561484e5761484e6147d1565b6040525050565b5f6001600160401b0382111561486d5761486d6147d1565b50601f01601f191660200190565b5f6020828403121561488b575f5ffd5b81356001600160401b038111156148a0575f5ffd5b8201601f810184136148b0575f5ffd5b80356001600160401b038111156148c9576148c96147d1565b8060051b6040516148dd6020830182614829565b9182526020818401810192908101878411156148f7575f5ffd5b6020850192505b838310156149845782356001600160401b0381111561491b575f5ffd5b8501603f8101891361492b575f5ffd5b602081013561493981614855565b6040516149468282614829565b8281526040848401018c101561495a575f5ffd5b826040850160208301375f60208483010152808552505050506020810190506020830192506148fe565b509695505050505050565b5f5f5f604084860312156149a1575f5ffd5b8335614447816142ce565b600181811c908216806149c057607f821691505b602082108103611a7e57634e487b7160e01b5f52602260045260245ffd5b5f602082840312156149ee575f5ffd5b5051919050565b61ffff811681146125b5575f5ffd5b5f60208284031215614a14575f5ffd5b8135611a77816149f5565b5f5f8335601e19843603018112614a34575f5ffd5b83016020810192503590506001600160401b03811115614a52575f5ffd5b803603821315614408575f5ffd5b81835281816020850137505f828201602090810191909152601f909101601f19169091010190565b6040808252843582820152602085013560608301525f90850135614aab816149f5565b61ffff1660808301526060850135614ac2816149f5565b61ffff1660a08301526080850135614ad981614589565b6001600160401b031660c0830152614af360a0860161459d565b6001600160401b031660e0830152614b0e60c0860186614a1f565b60e0610100850152614b2561012085018284614a60565b915050828103602084015261315f818587614a60565b805160148110610ed4575f5ffd5b8051610ed481614589565b5f82601f830112614b63575f5ffd5b8151602083015f614b7383614855565b604051614b808282614829565b809250848152878585011115614b94575f5ffd5b8484602083015e5f60208683010152809550505050505092915050565b8051610ed4816146f2565b5f60c08284031215614bcc575f5ffd5b604051614bd8816147e5565b80915082516001600160401b03811115614bf0575f5ffd5b830160408186031215614c01575f5ffd5b604051614c0d8161480a565b81516001600160401b03811115614c22575f5ffd5b614c2e87828501614b54565b825250602091820151828201528252614c48908401614bb1565b6020820152614c5960408401614bb1565b6040820152614c6a60608401614bb1565b6060820152614c7b60808401614b49565b6080820152614c8c60a08401614b49565b60a08201525092915050565b5f60208284031215614ca8575f5ffd5b81516001600160401b03811115614cbd575f5ffd5b820160c08185031215614cce575f5ffd5b604051614cda816147e5565b81516101008110614ce9575f5ffd5b8152614cf760208301614b3b565b60208201526040828101519082015260608083015190820152614d1c60808301614b49565b608082015260a08201516001600160401b03811115614d39575f5ffd5b614d4586828501614bbc565b60a083015250949350505050565b5f815160c084528051604060c0860152614d7161010086018261428e565b9050602082015160e086015260ff602085015116602086015260408401519150614da0604086018360ff169052565b60608401519150614db6606086018360ff169052565b60808401519150614dd260808601836001600160401b03169052565b60a08401519150612cd560a08601836001600160401b03169052565b602081525f82516101008110614e0657614e066145c5565b80602084015250602083015160148110614e2257614e226145c5565b8060408401525060408301516060830152606083015160808301526080830151614e5760a08401826001600160401b03169052565b5060a083015160c080840152612cd560e0840182614d53565b5f60208284031215614e80575f5ffd5b8151611a7781614589565b5f60033d11156128225760045f5f3e505f5160e01c90565b5f60443d1015614eb05790565b6040513d600319016004823e80513d60248201116001600160401b0382111715614ed957505090565b80820180516001600160401b03811115614ef4575050505090565b3d8401600319018282016020011115614f0e575050505090565b614f1d60208285010185614829565b509392505050565b5f60208284031215614f35575f5ffd5b8135611a7781614589565b62ffffff811681146125b5575f5ffd5b5f60208284031215614f60575f5ffd5b8135611a7781614f40565b8135614f76816149f5565b61ffff8116905081548161ffff1982161783556020840135614f97816149f5565b63ffff00008160101b169050808363ffffffff198416171784556040850135614fbf81614589565b6bffffffffffffffff000000008160201b16846bffffffffffffffffffffffff198516178317178555505050505f6060830135614ffb81614f40565b825462ffffff60601b191660609190911b62ffffff60601b16179091555050565b634e487b7160e01b5f52601160045260245ffd5b6001600160401b0382811682821603908111156109f0576109f061501c565b5f62ffffff821662ffffff81036150685761506861501c565b60010192915050565b6001600160401b0381811683821601908111156109f0576109f061501c565b606081525f6150a3606083018688614a60565b6001600160401b03949094166020830152506040015292915050565b5f602082840312156150cf575f5ffd5b815160078110611a77575f5ffd5b634e487b7160e01b5f52603260045260245ffd5b5f60208284031215615101575f5ffd5b8151611a77816142ce565b5f6020828403121561511c575f5ffd5b81516001600160401b03811115615131575f5ffd5b612cd584828501614b54565b838152604060208201525f61332c604083018486614a60565b5f5f5f5f5f60a0868803121561516a575f5ffd5b855160208701519095506001600160401b03811115615187575f5ffd5b61519388828901614b54565b94505060408601516001600160401b038111156151ae575f5ffd5b6151ba88828901614b54565b93505060608601516151cb816142ce565b60808701519092506151dc81614589565b809150509295509295909350565b606081525f6151fc606083018661428e565b6001600160401b039490941660208301525060400152919050565b6001600160a01b03831681526040602082018190525f90612cd590830184614493565b5f81518060208401855e5f93019283525090919050565b6c02bb4ba3732ba22a92199181d1609d1b81525f611a77600d83018461523a565b6001600160a01b03831681526040602082018190525f90612cd59083018461428e565b61ffff81811683821601908111156109f0576109f061501c565b80820281158282048414176109f0576109f061501c565b5f826152e057634e487b7160e01b5f52601260045260245ffd5b500490565b604081525f6152f76040830185614493565b828103602084015261332c8185614493565b808201808211156109f0576109f061501c565b5f611a77828461523a565b5f63ffffffff821663ffffffff81036150685761506861501c565b818103818111156109f0576109f061501c565b5f615360828561523a565b6001600160f81b03199390931683525050600101919050565b601f82111561120357805f5260205f20601f840160051c8101602085101561539e5750805b601f840160051c820191505b818110156153bd575f81556001016153aa565b5050505050565b81516001600160401b038111156153dd576153dd6147d1565b6153f1816153eb84546149ac565b84615379565b6020601f821160018114615423575f831561540c5750848201515b5f19600385901b1c1916600184901b1784556153bd565b5f84815260208120601f198516915b828110156154525787850151825560209485019460019092019101615432565b508482101561546f57868401515f19600387901b60f8161c191681555b50505050600190811b0190555056feffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0fff0a1115141a1e0705ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1dff180d19090817ff12161f1b13ff010003100b1c0c0e060402ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff71707a7279397838676632747664773073336a6e35346b686365366d7561376ca264697066735822122018feb9d83e3537c88097834461bb31cd06f308bf27e4d9d55af35aaf3d6e204b64736f6c634300081e0033

Verified Source Code Partial Match

Compiler: v0.8.30+commit.73712a01 EVM: prague Optimization: Yes (200 runs)
Initializable.sol 238 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.3.0) (proxy/utils/Initializable.sol)

pragma solidity ^0.8.20;

/**
 * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
 * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
 * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
 * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
 *
 * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
 * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
 * case an upgrade adds a module that needs to be initialized.
 *
 * For example:
 *
 * [.hljs-theme-light.nopadding]
 * ```solidity
 * contract MyToken is ERC20Upgradeable {
 *     function initialize() initializer public {
 *         __ERC20_init("MyToken", "MTK");
 *     }
 * }
 *
 * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
 *     function initializeV2() reinitializer(2) public {
 *         __ERC20Permit_init("MyToken");
 *     }
 * }
 * ```
 *
 * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
 * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
 *
 * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
 * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
 *
 * [CAUTION]
 * ====
 * Avoid leaving a contract uninitialized.
 *
 * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
 * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
 * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
 *
 * [.hljs-theme-light.nopadding]
 * ```
 * /// @custom:oz-upgrades-unsafe-allow constructor
 * constructor() {
 *     _disableInitializers();
 * }
 * ```
 * ====
 */
abstract contract Initializable {
    /**
     * @dev Storage of the initializable contract.
     *
     * It's implemented on a custom ERC-7201 namespace to reduce the risk of storage collisions
     * when using with upgradeable contracts.
     *
     * @custom:storage-location erc7201:openzeppelin.storage.Initializable
     */
    struct InitializableStorage {
        /**
         * @dev Indicates that the contract has been initialized.
         */
        uint64 _initialized;
        /**
         * @dev Indicates that the contract is in the process of being initialized.
         */
        bool _initializing;
    }

    // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Initializable")) - 1)) & ~bytes32(uint256(0xff))
    bytes32 private constant INITIALIZABLE_STORAGE = 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00;

    /**
     * @dev The contract is already initialized.
     */
    error InvalidInitialization();

    /**
     * @dev The contract is not initializing.
     */
    error NotInitializing();

    /**
     * @dev Triggered when the contract has been initialized or reinitialized.
     */
    event Initialized(uint64 version);

    /**
     * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
     * `onlyInitializing` functions can be used to initialize parent contracts.
     *
     * Similar to `reinitializer(1)`, except that in the context of a constructor an `initializer` may be invoked any
     * number of times. This behavior in the constructor can be useful during testing and is not expected to be used in
     * production.
     *
     * Emits an {Initialized} event.
     */
    modifier initializer() {
        // solhint-disable-next-line var-name-mixedcase
        InitializableStorage storage $ = _getInitializableStorage();

        // Cache values to avoid duplicated sloads
        bool isTopLevelCall = !$._initializing;
        uint64 initialized = $._initialized;

        // Allowed calls:
        // - initialSetup: the contract is not in the initializing state and no previous version was
        //                 initialized
        // - construction: the contract is initialized at version 1 (no reinitialization) and the
        //                 current contract is just being deployed
        bool initialSetup = initialized == 0 && isTopLevelCall;
        bool construction = initialized == 1 && address(this).code.length == 0;

        if (!initialSetup && !construction) {
            revert InvalidInitialization();
        }
        $._initialized = 1;
        if (isTopLevelCall) {
            $._initializing = true;
        }
        _;
        if (isTopLevelCall) {
            $._initializing = false;
            emit Initialized(1);
        }
    }

    /**
     * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
     * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
     * used to initialize parent contracts.
     *
     * A reinitializer may be used after the original initialization step. This is essential to configure modules that
     * are added through upgrades and that require initialization.
     *
     * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
     * cannot be nested. If one is invoked in the context of another, execution will revert.
     *
     * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
     * a contract, executing them in the right order is up to the developer or operator.
     *
     * WARNING: Setting the version to 2**64 - 1 will prevent any future reinitialization.
     *
     * Emits an {Initialized} event.
     */
    modifier reinitializer(uint64 version) {
        // solhint-disable-next-line var-name-mixedcase
        InitializableStorage storage $ = _getInitializableStorage();

        if ($._initializing || $._initialized >= version) {
            revert InvalidInitialization();
        }
        $._initialized = version;
        $._initializing = true;
        _;
        $._initializing = false;
        emit Initialized(version);
    }

    /**
     * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
     * {initializer} and {reinitializer} modifiers, directly or indirectly.
     */
    modifier onlyInitializing() {
        _checkInitializing();
        _;
    }

    /**
     * @dev Reverts if the contract is not in an initializing state. See {onlyInitializing}.
     */
    function _checkInitializing() internal view virtual {
        if (!_isInitializing()) {
            revert NotInitializing();
        }
    }

    /**
     * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
     * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
     * to any version. It is recommended to use this to lock implementation contracts that are designed to be called
     * through proxies.
     *
     * Emits an {Initialized} event the first time it is successfully executed.
     */
    function _disableInitializers() internal virtual {
        // solhint-disable-next-line var-name-mixedcase
        InitializableStorage storage $ = _getInitializableStorage();

        if ($._initializing) {
            revert InvalidInitialization();
        }
        if ($._initialized != type(uint64).max) {
            $._initialized = type(uint64).max;
            emit Initialized(type(uint64).max);
        }
    }

    /**
     * @dev Returns the highest version that has been initialized. See {reinitializer}.
     */
    function _getInitializedVersion() internal view returns (uint64) {
        return _getInitializableStorage()._initialized;
    }

    /**
     * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
     */
    function _isInitializing() internal view returns (bool) {
        return _getInitializableStorage()._initializing;
    }

    /**
     * @dev Pointer to storage slot. Allows integrators to override it with a custom storage location.
     *
     * NOTE: Consider following the ERC-7201 formula to derive storage locations.
     */
    function _initializableStorageSlot() internal pure virtual returns (bytes32) {
        return INITIALIZABLE_STORAGE;
    }

    /**
     * @dev Returns a pointer to the storage namespace.
     */
    // solhint-disable-next-line var-name-mixedcase
    function _getInitializableStorage() private pure returns (InitializableStorage storage $) {
        bytes32 slot = _initializableStorageSlot();
        assembly {
            $.slot := slot
        }
    }
}
IERC165.sol 6 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC165.sol)

pragma solidity >=0.4.16;

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

pragma solidity >=0.4.16;

interface IERC5267 {
    /**
     * @dev MAY be emitted to signal that the domain could have changed.
     */
    event EIP712DomainChanged();

    /**
     * @dev returns the fields and values that describe the domain separator used by this contract for EIP-712
     * signature.
     */
    function eip712Domain()
        external
        view
        returns (
            bytes1 fields,
            string memory name,
            string memory version,
            uint256 chainId,
            address verifyingContract,
            bytes32 salt,
            uint256[] memory extensions
        );
}
draft-IERC6093.sol 161 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/draft-IERC6093.sol)
pragma solidity >=0.8.4;

/**
 * @dev Standard ERC-20 Errors
 * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC-20 tokens.
 */
interface IERC20Errors {
    /**
     * @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers.
     * @param sender Address whose tokens are being transferred.
     * @param balance Current balance for the interacting account.
     * @param needed Minimum amount required to perform a transfer.
     */
    error ERC20InsufficientBalance(address sender, uint256 balance, uint256 needed);

    /**
     * @dev Indicates a failure with the token `sender`. Used in transfers.
     * @param sender Address whose tokens are being transferred.
     */
    error ERC20InvalidSender(address sender);

    /**
     * @dev Indicates a failure with the token `receiver`. Used in transfers.
     * @param receiver Address to which tokens are being transferred.
     */
    error ERC20InvalidReceiver(address receiver);

    /**
     * @dev Indicates a failure with the `spender`’s `allowance`. Used in transfers.
     * @param spender Address that may be allowed to operate on tokens without being their owner.
     * @param allowance Amount of tokens a `spender` is allowed to operate with.
     * @param needed Minimum amount required to perform a transfer.
     */
    error ERC20InsufficientAllowance(address spender, uint256 allowance, uint256 needed);

    /**
     * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
     * @param approver Address initiating an approval operation.
     */
    error ERC20InvalidApprover(address approver);

    /**
     * @dev Indicates a failure with the `spender` to be approved. Used in approvals.
     * @param spender Address that may be allowed to operate on tokens without being their owner.
     */
    error ERC20InvalidSpender(address spender);
}

/**
 * @dev Standard ERC-721 Errors
 * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC-721 tokens.
 */
interface IERC721Errors {
    /**
     * @dev Indicates that an address can't be an owner. For example, `address(0)` is a forbidden owner in ERC-20.
     * Used in balance queries.
     * @param owner Address of the current owner of a token.
     */
    error ERC721InvalidOwner(address owner);

    /**
     * @dev Indicates a `tokenId` whose `owner` is the zero address.
     * @param tokenId Identifier number of a token.
     */
    error ERC721NonexistentToken(uint256 tokenId);

    /**
     * @dev Indicates an error related to the ownership over a particular token. Used in transfers.
     * @param sender Address whose tokens are being transferred.
     * @param tokenId Identifier number of a token.
     * @param owner Address of the current owner of a token.
     */
    error ERC721IncorrectOwner(address sender, uint256 tokenId, address owner);

    /**
     * @dev Indicates a failure with the token `sender`. Used in transfers.
     * @param sender Address whose tokens are being transferred.
     */
    error ERC721InvalidSender(address sender);

    /**
     * @dev Indicates a failure with the token `receiver`. Used in transfers.
     * @param receiver Address to which tokens are being transferred.
     */
    error ERC721InvalidReceiver(address receiver);

    /**
     * @dev Indicates a failure with the `operator`’s approval. Used in transfers.
     * @param operator Address that may be allowed to operate on tokens without being their owner.
     * @param tokenId Identifier number of a token.
     */
    error ERC721InsufficientApproval(address operator, uint256 tokenId);

    /**
     * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
     * @param approver Address initiating an approval operation.
     */
    error ERC721InvalidApprover(address approver);

    /**
     * @dev Indicates a failure with the `operator` to be approved. Used in approvals.
     * @param operator Address that may be allowed to operate on tokens without being their owner.
     */
    error ERC721InvalidOperator(address operator);
}

/**
 * @dev Standard ERC-1155 Errors
 * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC-1155 tokens.
 */
interface IERC1155Errors {
    /**
     * @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers.
     * @param sender Address whose tokens are being transferred.
     * @param balance Current balance for the interacting account.
     * @param needed Minimum amount required to perform a transfer.
     * @param tokenId Identifier number of a token.
     */
    error ERC1155InsufficientBalance(address sender, uint256 balance, uint256 needed, uint256 tokenId);

    /**
     * @dev Indicates a failure with the token `sender`. Used in transfers.
     * @param sender Address whose tokens are being transferred.
     */
    error ERC1155InvalidSender(address sender);

    /**
     * @dev Indicates a failure with the token `receiver`. Used in transfers.
     * @param receiver Address to which tokens are being transferred.
     */
    error ERC1155InvalidReceiver(address receiver);

    /**
     * @dev Indicates a failure with the `operator`’s approval. Used in transfers.
     * @param operator Address that may be allowed to operate on tokens without being their owner.
     * @param owner Address of the current owner of a token.
     */
    error ERC1155MissingApprovalForAll(address operator, address owner);

    /**
     * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
     * @param approver Address initiating an approval operation.
     */
    error ERC1155InvalidApprover(address approver);

    /**
     * @dev Indicates a failure with the `operator` to be approved. Used in approvals.
     * @param operator Address that may be allowed to operate on tokens without being their owner.
     */
    error ERC1155InvalidOperator(address operator);

    /**
     * @dev Indicates an array length mismatch between ids and values in a safeBatchTransferFrom operation.
     * Used in batch transfers.
     * @param idsLength Length of the array of token identifiers
     * @param valuesLength Length of the array of token amounts
     */
    error ERC1155InvalidArrayLength(uint256 idsLength, uint256 valuesLength);
}
draft-IERC7802.sol 31 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/draft-IERC7802.sol)
pragma solidity >=0.6.2;

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

/// @title IERC7802
/// @notice Defines the interface for crosschain ERC20 transfers.
interface IERC7802 is IERC165 {
    /// @notice Emitted when a crosschain transfer mints tokens.
    /// @param to       Address of the account tokens are being minted for.
    /// @param amount   Amount of tokens minted.
    /// @param sender   Address of the caller (msg.sender) who invoked crosschainMint.
    event CrosschainMint(address indexed to, uint256 amount, address indexed sender);

    /// @notice Emitted when a crosschain transfer burns tokens.
    /// @param from     Address of the account tokens are being burned from.
    /// @param amount   Amount of tokens burned.
    /// @param sender   Address of the caller (msg.sender) who invoked crosschainBurn.
    event CrosschainBurn(address indexed from, uint256 amount, address indexed sender);

    /// @notice Mint tokens through a crosschain transfer.
    /// @param _to     Address to mint tokens to.
    /// @param _amount Amount of tokens to mint.
    function crosschainMint(address _to, uint256 _amount) external;

    /// @notice Burn tokens through a crosschain transfer.
    /// @param _from   Address to burn tokens from.
    /// @param _amount Amount of tokens to burn.
    function crosschainBurn(address _from, uint256 _amount) external;
}
ERC20.sol 305 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (token/ERC20/ERC20.sol)

pragma solidity ^0.8.20;

import {IERC20} from "./IERC20.sol";
import {IERC20Metadata} from "./extensions/IERC20Metadata.sol";
import {Context} from "../../utils/Context.sol";
import {IERC20Errors} from "../../interfaces/draft-IERC6093.sol";

/**
 * @dev Implementation of the {IERC20} interface.
 *
 * This implementation is agnostic to the way tokens are created. This means
 * that a supply mechanism has to be added in a derived contract using {_mint}.
 *
 * TIP: For a detailed writeup see our guide
 * https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How
 * to implement supply mechanisms].
 *
 * The default value of {decimals} is 18. To change this, you should override
 * this function so it returns a different value.
 *
 * We have followed general OpenZeppelin Contracts guidelines: functions revert
 * instead returning `false` on failure. This behavior is nonetheless
 * conventional and does not conflict with the expectations of ERC-20
 * applications.
 */
abstract contract ERC20 is Context, IERC20, IERC20Metadata, IERC20Errors {
    mapping(address account => uint256) private _balances;

    mapping(address account => mapping(address spender => uint256)) private _allowances;

    uint256 private _totalSupply;

    string private _name;
    string private _symbol;

    /**
     * @dev Sets the values for {name} and {symbol}.
     *
     * Both values are immutable: they can only be set once during construction.
     */
    constructor(string memory name_, string memory symbol_) {
        _name = name_;
        _symbol = symbol_;
    }

    /**
     * @dev Returns the name of the token.
     */
    function name() public view virtual returns (string memory) {
        return _name;
    }

    /**
     * @dev Returns the symbol of the token, usually a shorter version of the
     * name.
     */
    function symbol() public view virtual returns (string memory) {
        return _symbol;
    }

    /**
     * @dev Returns the number of decimals used to get its user representation.
     * For example, if `decimals` equals `2`, a balance of `505` tokens should
     * be displayed to a user as `5.05` (`505 / 10 ** 2`).
     *
     * Tokens usually opt for a value of 18, imitating the relationship between
     * Ether and Wei. This is the default value returned by this function, unless
     * it's overridden.
     *
     * NOTE: This information is only used for _display_ purposes: it in
     * no way affects any of the arithmetic of the contract, including
     * {IERC20-balanceOf} and {IERC20-transfer}.
     */
    function decimals() public view virtual returns (uint8) {
        return 18;
    }

    /// @inheritdoc IERC20
    function totalSupply() public view virtual returns (uint256) {
        return _totalSupply;
    }

    /// @inheritdoc IERC20
    function balanceOf(address account) public view virtual returns (uint256) {
        return _balances[account];
    }

    /**
     * @dev See {IERC20-transfer}.
     *
     * Requirements:
     *
     * - `to` cannot be the zero address.
     * - the caller must have a balance of at least `value`.
     */
    function transfer(address to, uint256 value) public virtual returns (bool) {
        address owner = _msgSender();
        _transfer(owner, to, value);
        return true;
    }

    /// @inheritdoc IERC20
    function allowance(address owner, address spender) public view virtual returns (uint256) {
        return _allowances[owner][spender];
    }

    /**
     * @dev See {IERC20-approve}.
     *
     * NOTE: If `value` is the maximum `uint256`, the allowance is not updated on
     * `transferFrom`. This is semantically equivalent to an infinite approval.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     */
    function approve(address spender, uint256 value) public virtual returns (bool) {
        address owner = _msgSender();
        _approve(owner, spender, value);
        return true;
    }

    /**
     * @dev See {IERC20-transferFrom}.
     *
     * Skips emitting an {Approval} event indicating an allowance update. This is not
     * required by the ERC. See {xref-ERC20-_approve-address-address-uint256-bool-}[_approve].
     *
     * NOTE: Does not update the allowance if the current allowance
     * is the maximum `uint256`.
     *
     * Requirements:
     *
     * - `from` and `to` cannot be the zero address.
     * - `from` must have a balance of at least `value`.
     * - the caller must have allowance for ``from``'s tokens of at least
     * `value`.
     */
    function transferFrom(address from, address to, uint256 value) public virtual returns (bool) {
        address spender = _msgSender();
        _spendAllowance(from, spender, value);
        _transfer(from, to, value);
        return true;
    }

    /**
     * @dev Moves a `value` amount of tokens from `from` to `to`.
     *
     * This internal function is equivalent to {transfer}, and can be used to
     * e.g. implement automatic token fees, slashing mechanisms, etc.
     *
     * Emits a {Transfer} event.
     *
     * NOTE: This function is not virtual, {_update} should be overridden instead.
     */
    function _transfer(address from, address to, uint256 value) internal {
        if (from == address(0)) {
            revert ERC20InvalidSender(address(0));
        }
        if (to == address(0)) {
            revert ERC20InvalidReceiver(address(0));
        }
        _update(from, to, value);
    }

    /**
     * @dev Transfers a `value` amount of tokens from `from` to `to`, or alternatively mints (or burns) if `from`
     * (or `to`) is the zero address. All customizations to transfers, mints, and burns should be done by overriding
     * this function.
     *
     * Emits a {Transfer} event.
     */
    function _update(address from, address to, uint256 value) internal virtual {
        if (from == address(0)) {
            // Overflow check required: The rest of the code assumes that totalSupply never overflows
            _totalSupply += value;
        } else {
            uint256 fromBalance = _balances[from];
            if (fromBalance < value) {
                revert ERC20InsufficientBalance(from, fromBalance, value);
            }
            unchecked {
                // Overflow not possible: value <= fromBalance <= totalSupply.
                _balances[from] = fromBalance - value;
            }
        }

        if (to == address(0)) {
            unchecked {
                // Overflow not possible: value <= totalSupply or value <= fromBalance <= totalSupply.
                _totalSupply -= value;
            }
        } else {
            unchecked {
                // Overflow not possible: balance + value is at most totalSupply, which we know fits into a uint256.
                _balances[to] += value;
            }
        }

        emit Transfer(from, to, value);
    }

    /**
     * @dev Creates a `value` amount of tokens and assigns them to `account`, by transferring it from address(0).
     * Relies on the `_update` mechanism
     *
     * Emits a {Transfer} event with `from` set to the zero address.
     *
     * NOTE: This function is not virtual, {_update} should be overridden instead.
     */
    function _mint(address account, uint256 value) internal {
        if (account == address(0)) {
            revert ERC20InvalidReceiver(address(0));
        }
        _update(address(0), account, value);
    }

    /**
     * @dev Destroys a `value` amount of tokens from `account`, lowering the total supply.
     * Relies on the `_update` mechanism.
     *
     * Emits a {Transfer} event with `to` set to the zero address.
     *
     * NOTE: This function is not virtual, {_update} should be overridden instead
     */
    function _burn(address account, uint256 value) internal {
        if (account == address(0)) {
            revert ERC20InvalidSender(address(0));
        }
        _update(account, address(0), value);
    }

    /**
     * @dev Sets `value` as the allowance of `spender` over the `owner`'s tokens.
     *
     * This internal function is equivalent to `approve`, and can be used to
     * e.g. set automatic allowances for certain subsystems, etc.
     *
     * Emits an {Approval} event.
     *
     * Requirements:
     *
     * - `owner` cannot be the zero address.
     * - `spender` cannot be the zero address.
     *
     * Overrides to this logic should be done to the variant with an additional `bool emitEvent` argument.
     */
    function _approve(address owner, address spender, uint256 value) internal {
        _approve(owner, spender, value, true);
    }

    /**
     * @dev Variant of {_approve} with an optional flag to enable or disable the {Approval} event.
     *
     * By default (when calling {_approve}) the flag is set to true. On the other hand, approval changes made by
     * `_spendAllowance` during the `transferFrom` operation set the flag to false. This saves gas by not emitting any
     * `Approval` event during `transferFrom` operations.
     *
     * Anyone who wishes to continue emitting `Approval` events on the`transferFrom` operation can force the flag to
     * true using the following override:
     *
     * ```solidity
     * function _approve(address owner, address spender, uint256 value, bool) internal virtual override {
     *     super._approve(owner, spender, value, true);
     * }
     * ```
     *
     * Requirements are the same as {_approve}.
     */
    function _approve(address owner, address spender, uint256 value, bool emitEvent) internal virtual {
        if (owner == address(0)) {
            revert ERC20InvalidApprover(address(0));
        }
        if (spender == address(0)) {
            revert ERC20InvalidSpender(address(0));
        }
        _allowances[owner][spender] = value;
        if (emitEvent) {
            emit Approval(owner, spender, value);
        }
    }

    /**
     * @dev Updates `owner`'s allowance for `spender` based on spent `value`.
     *
     * Does not update the allowance value in case of infinite allowance.
     * Revert if not enough allowance is available.
     *
     * Does not emit an {Approval} event.
     */
    function _spendAllowance(address owner, address spender, uint256 value) internal virtual {
        uint256 currentAllowance = allowance(owner, spender);
        if (currentAllowance < type(uint256).max) {
            if (currentAllowance < value) {
                revert ERC20InsufficientAllowance(spender, currentAllowance, value);
            }
            unchecked {
                _approve(owner, spender, currentAllowance - value, false);
            }
        }
    }
}
IERC20.sol 79 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (token/ERC20/IERC20.sol)

pragma solidity >=0.4.16;

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

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

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

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

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

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

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

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

pragma solidity ^0.8.20;

import {IERC20Permit} from "./IERC20Permit.sol";
import {ERC20} from "../ERC20.sol";
import {ECDSA} from "../../../utils/cryptography/ECDSA.sol";
import {EIP712} from "../../../utils/cryptography/EIP712.sol";
import {Nonces} from "../../../utils/Nonces.sol";

/**
 * @dev Implementation of the ERC-20 Permit extension allowing approvals to be made via signatures, as defined in
 * https://eips.ethereum.org/EIPS/eip-2612[ERC-2612].
 *
 * Adds the {permit} method, which can be used to change an account's ERC-20 allowance (see {IERC20-allowance}) by
 * presenting a message signed by the account. By not relying on `{IERC20-approve}`, the token holder account doesn't
 * need to send a transaction, and thus is not required to hold Ether at all.
 */
abstract contract ERC20Permit is ERC20, IERC20Permit, EIP712, Nonces {
    bytes32 private constant PERMIT_TYPEHASH =
        keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)");

    /**
     * @dev Permit deadline has expired.
     */
    error ERC2612ExpiredSignature(uint256 deadline);

    /**
     * @dev Mismatched signature.
     */
    error ERC2612InvalidSigner(address signer, address owner);

    /**
     * @dev Initializes the {EIP712} domain separator using the `name` parameter, and setting `version` to `"1"`.
     *
     * It's a good idea to use the same `name` that is defined as the ERC-20 token name.
     */
    constructor(string memory name) EIP712(name, "1") {}

    /// @inheritdoc IERC20Permit
    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) public virtual {
        if (block.timestamp > deadline) {
            revert ERC2612ExpiredSignature(deadline);
        }

        bytes32 structHash = keccak256(abi.encode(PERMIT_TYPEHASH, owner, spender, value, _useNonce(owner), deadline));

        bytes32 hash = _hashTypedDataV4(structHash);

        address signer = ECDSA.recover(hash, v, r, s);
        if (signer != owner) {
            revert ERC2612InvalidSigner(signer, owner);
        }

        _approve(owner, spender, value);
    }

    /// @inheritdoc IERC20Permit
    function nonces(address owner) public view virtual override(IERC20Permit, Nonces) returns (uint256) {
        return super.nonces(owner);
    }

    /// @inheritdoc IERC20Permit
    // solhint-disable-next-line func-name-mixedcase
    function DOMAIN_SEPARATOR() external view virtual returns (bytes32) {
        return _domainSeparatorV4();
    }
}
IERC20Metadata.sol 26 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (token/ERC20/extensions/IERC20Metadata.sol)

pragma solidity >=0.6.2;

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

/**
 * @dev Interface for the optional metadata functions from the ERC-20 standard.
 */
interface IERC20Metadata is IERC20 {
    /**
     * @dev Returns the name of the token.
     */
    function name() external view returns (string memory);

    /**
     * @dev Returns the symbol of the token.
     */
    function symbol() external view returns (string memory);

    /**
     * @dev Returns the decimals places of the token.
     */
    function decimals() external view returns (uint8);
}
IERC20Permit.sol 90 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (token/ERC20/extensions/IERC20Permit.sol)

pragma solidity >=0.4.16;

/**
 * @dev Interface of the ERC-20 Permit extension allowing approvals to be made via signatures, as defined in
 * https://eips.ethereum.org/EIPS/eip-2612[ERC-2612].
 *
 * Adds the {permit} method, which can be used to change an account's ERC-20 allowance (see {IERC20-allowance}) by
 * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
 * need to send a transaction, and thus is not required to hold Ether at all.
 *
 * ==== Security Considerations
 *
 * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature
 * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be
 * considered as an intention to spend the allowance in any specific way. The second is that because permits have
 * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should
 * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be
 * generally recommended is:
 *
 * ```solidity
 * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {
 *     try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}
 *     doThing(..., value);
 * }
 *
 * function doThing(..., uint256 value) public {
 *     token.safeTransferFrom(msg.sender, address(this), value);
 *     ...
 * }
 * ```
 *
 * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of
 * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also
 * {SafeERC20-safeTransferFrom}).
 *
 * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so
 * contracts should have entry points that don't rely on permit.
 */
interface IERC20Permit {
    /**
     * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
     * given ``owner``'s signed approval.
     *
     * IMPORTANT: The same issues {IERC20-approve} has related to transaction
     * ordering also apply here.
     *
     * Emits an {Approval} event.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     * - `deadline` must be a timestamp in the future.
     * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
     * over the EIP712-formatted function arguments.
     * - the signature must use ``owner``'s current nonce (see {nonces}).
     *
     * For more information on the signature format, see the
     * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
     * section].
     *
     * CAUTION: See Security Considerations above.
     */
    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external;

    /**
     * @dev Returns the current nonce for `owner`. This value must be
     * included whenever a signature is generated for {permit}.
     *
     * Every successful call to {permit} increases ``owner``'s nonce by one. This
     * prevents a signature from being used multiple times.
     */
    function nonces(address owner) external view returns (uint256);

    /**
     * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
     */
    // solhint-disable-next-line func-name-mixedcase
    function DOMAIN_SEPARATOR() external view returns (bytes32);
}
draft-ERC20Bridgeable.sol 51 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (token/ERC20/extensions/draft-ERC20Bridgeable.sol)

pragma solidity ^0.8.20;

import {ERC20} from "../ERC20.sol";
import {ERC165, IERC165} from "../../../utils/introspection/ERC165.sol";
import {IERC7802} from "../../../interfaces/draft-IERC7802.sol";

/**
 * @dev ERC20 extension that implements the standard token interface according to
 * https://eips.ethereum.org/EIPS/eip-7802[ERC-7802].
 */
abstract contract ERC20Bridgeable is ERC20, ERC165, IERC7802 {
    /// @dev Modifier to restrict access to the token bridge.
    modifier onlyTokenBridge() {
        // Token bridge should never be impersonated using a relayer/forwarder. Using msg.sender is preferable to
        // _msgSender() for security reasons.
        _checkTokenBridge(msg.sender);
        _;
    }

    /// @inheritdoc ERC165
    function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {
        return interfaceId == type(IERC7802).interfaceId || super.supportsInterface(interfaceId);
    }

    /**
     * @dev See {IERC7802-crosschainMint}. Emits a {IERC7802-CrosschainMint} event.
     */
    function crosschainMint(address to, uint256 value) public virtual override onlyTokenBridge {
        _mint(to, value);
        emit CrosschainMint(to, value, _msgSender());
    }

    /**
     * @dev See {IERC7802-crosschainBurn}. Emits a {IERC7802-CrosschainBurn} event.
     */
    function crosschainBurn(address from, uint256 value) public virtual override onlyTokenBridge {
        _burn(from, value);
        emit CrosschainBurn(from, value, _msgSender());
    }

    /**
     * @dev Checks if the caller is a trusted token bridge. MUST revert otherwise.
     *
     * Developers should implement this function using an access control mechanism that allows
     * customizing the list of allowed senders. Consider using {AccessControl} or {AccessManaged}.
     */
    function _checkTokenBridge(address caller) internal virtual;
}
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;
    }
}
Nonces.sol 46 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Nonces.sol)
pragma solidity ^0.8.20;

/**
 * @dev Provides tracking nonces for addresses. Nonces will only increment.
 */
abstract contract Nonces {
    /**
     * @dev The nonce used for an `account` is not the expected current nonce.
     */
    error InvalidAccountNonce(address account, uint256 currentNonce);

    mapping(address account => uint256) private _nonces;

    /**
     * @dev Returns the next unused nonce for an address.
     */
    function nonces(address owner) public view virtual returns (uint256) {
        return _nonces[owner];
    }

    /**
     * @dev Consumes a nonce.
     *
     * Returns the current value and increments nonce.
     */
    function _useNonce(address owner) internal virtual returns (uint256) {
        // For each account, the nonce has an initial value of 0, can only be incremented by one, and cannot be
        // decremented or reset. This guarantees that the nonce never overflows.
        unchecked {
            // It is important to do x++ and not ++x here.
            return _nonces[owner]++;
        }
    }

    /**
     * @dev Same as {_useNonce} but checking that `nonce` is the next valid for `owner`.
     */
    function _useCheckedNonce(address owner, uint256 nonce) internal virtual {
        uint256 current = _useNonce(owner);
        if (nonce != current) {
            revert InvalidAccountNonce(owner, current);
        }
    }
}
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)
        }
    }
}
ReentrancyGuard.sol 87 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/ReentrancyGuard.sol)

pragma solidity ^0.8.20;

/**
 * @dev Contract module that helps prevent reentrant calls to a function.
 *
 * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
 * available, which can be applied to functions to make sure there are no nested
 * (reentrant) calls to them.
 *
 * Note that because there is a single `nonReentrant` guard, functions marked as
 * `nonReentrant` may not call one another. This can be worked around by making
 * those functions `private`, and then adding `external` `nonReentrant` entry
 * points to them.
 *
 * TIP: If EIP-1153 (transient storage) is available on the chain you're deploying at,
 * consider using {ReentrancyGuardTransient} instead.
 *
 * TIP: If you would like to learn more about reentrancy and alternative ways
 * to protect against it, check out our blog post
 * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
 */
abstract contract ReentrancyGuard {
    // Booleans are more expensive than uint256 or any type that takes up a full
    // word because each write operation emits an extra SLOAD to first read the
    // slot's contents, replace the bits taken up by the boolean, and then write
    // back. This is the compiler's defense against contract upgrades and
    // pointer aliasing, and it cannot be disabled.

    // The values being non-zero value makes deployment a bit more expensive,
    // but in exchange the refund on every call to nonReentrant will be lower in
    // amount. Since refunds are capped to a percentage of the total
    // transaction's gas, it is best to keep them low in cases like this one, to
    // increase the likelihood of the full refund coming into effect.
    uint256 private constant NOT_ENTERED = 1;
    uint256 private constant ENTERED = 2;

    uint256 private _status;

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

    constructor() {
        _status = NOT_ENTERED;
    }

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

    function _nonReentrantBefore() private {
        // On the first call to nonReentrant, _status will be NOT_ENTERED
        if (_status == ENTERED) {
            revert ReentrancyGuardReentrantCall();
        }

        // Any calls to nonReentrant after this point will fail
        _status = ENTERED;
    }

    function _nonReentrantAfter() private {
        // By storing the original value once again, a refund is triggered (see
        // https://eips.ethereum.org/EIPS/eip-2200)
        _status = NOT_ENTERED;
    }

    /**
     * @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
     * `nonReentrant` function in the call stack.
     */
    function _reentrancyGuardEntered() internal view returns (bool) {
        return _status == ENTERED;
    }
}
ShortStrings.sol 122 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.3.0) (utils/ShortStrings.sol)

pragma solidity ^0.8.20;

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

// | string  | 0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA   |
// | length  | 0x                                                              BB |
type ShortString is bytes32;

/**
 * @dev This library provides functions to convert short memory strings
 * into a `ShortString` type that can be used as an immutable variable.
 *
 * Strings of arbitrary length can be optimized using this library if
 * they are short enough (up to 31 bytes) by packing them with their
 * length (1 byte) in a single EVM word (32 bytes). Additionally, a
 * fallback mechanism can be used for every other case.
 *
 * Usage example:
 *
 * ```solidity
 * contract Named {
 *     using ShortStrings for *;
 *
 *     ShortString private immutable _name;
 *     string private _nameFallback;
 *
 *     constructor(string memory contractName) {
 *         _name = contractName.toShortStringWithFallback(_nameFallback);
 *     }
 *
 *     function name() external view returns (string memory) {
 *         return _name.toStringWithFallback(_nameFallback);
 *     }
 * }
 * ```
 */
library ShortStrings {
    // Used as an identifier for strings longer than 31 bytes.
    bytes32 private constant FALLBACK_SENTINEL = 0x00000000000000000000000000000000000000000000000000000000000000FF;

    error StringTooLong(string str);
    error InvalidShortString();

    /**
     * @dev Encode a string of at most 31 chars into a `ShortString`.
     *
     * This will trigger a `StringTooLong` error is the input string is too long.
     */
    function toShortString(string memory str) internal pure returns (ShortString) {
        bytes memory bstr = bytes(str);
        if (bstr.length > 31) {
            revert StringTooLong(str);
        }
        return ShortString.wrap(bytes32(uint256(bytes32(bstr)) | bstr.length));
    }

    /**
     * @dev Decode a `ShortString` back to a "normal" string.
     */
    function toString(ShortString sstr) internal pure returns (string memory) {
        uint256 len = byteLength(sstr);
        // using `new string(len)` would work locally but is not memory safe.
        string memory str = new string(32);
        assembly ("memory-safe") {
            mstore(str, len)
            mstore(add(str, 0x20), sstr)
        }
        return str;
    }

    /**
     * @dev Return the length of a `ShortString`.
     */
    function byteLength(ShortString sstr) internal pure returns (uint256) {
        uint256 result = uint256(ShortString.unwrap(sstr)) & 0xFF;
        if (result > 31) {
            revert InvalidShortString();
        }
        return result;
    }

    /**
     * @dev Encode a string into a `ShortString`, or write it to storage if it is too long.
     */
    function toShortStringWithFallback(string memory value, string storage store) internal returns (ShortString) {
        if (bytes(value).length < 32) {
            return toShortString(value);
        } else {
            StorageSlot.getStringSlot(store).value = value;
            return ShortString.wrap(FALLBACK_SENTINEL);
        }
    }

    /**
     * @dev Decode a string that was encoded to `ShortString` or written to storage using {toShortStringWithFallback}.
     */
    function toStringWithFallback(ShortString value, string storage store) internal pure returns (string memory) {
        if (ShortString.unwrap(value) != FALLBACK_SENTINEL) {
            return toString(value);
        } else {
            return store;
        }
    }

    /**
     * @dev Return the length of a string that was encoded to `ShortString` or written to storage using
     * {toShortStringWithFallback}.
     *
     * WARNING: This will return the "byte length" of the string. This may not reflect the actual length in terms of
     * actual characters as the UTF-8 encoding of a single character can span over multiple bytes.
     */
    function byteLengthWithFallback(ShortString value, string storage store) internal view returns (uint256) {
        if (ShortString.unwrap(value) != FALLBACK_SENTINEL) {
            return byteLength(value);
        } else {
            return bytes(store).length;
        }
    }
}
StorageSlot.sol 143 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/StorageSlot.sol)
// This file was procedurally generated from scripts/generate/templates/StorageSlot.js.

pragma solidity ^0.8.20;

/**
 * @dev Library for reading and writing primitive types to specific storage slots.
 *
 * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.
 * This library helps with reading and writing to such slots without the need for inline assembly.
 *
 * The functions in this library return Slot structs that contain a `value` member that can be used to read or write.
 *
 * Example usage to set ERC-1967 implementation slot:
 * ```solidity
 * contract ERC1967 {
 *     // Define the slot. Alternatively, use the SlotDerivation library to derive the slot.
 *     bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
 *
 *     function _getImplementation() internal view returns (address) {
 *         return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
 *     }
 *
 *     function _setImplementation(address newImplementation) internal {
 *         require(newImplementation.code.length > 0);
 *         StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
 *     }
 * }
 * ```
 *
 * TIP: Consider using this library along with {SlotDerivation}.
 */
library StorageSlot {
    struct AddressSlot {
        address value;
    }

    struct BooleanSlot {
        bool value;
    }

    struct Bytes32Slot {
        bytes32 value;
    }

    struct Uint256Slot {
        uint256 value;
    }

    struct Int256Slot {
        int256 value;
    }

    struct StringSlot {
        string value;
    }

    struct BytesSlot {
        bytes value;
    }

    /**
     * @dev Returns an `AddressSlot` with member `value` located at `slot`.
     */
    function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
        assembly ("memory-safe") {
            r.slot := slot
        }
    }

    /**
     * @dev Returns a `BooleanSlot` with member `value` located at `slot`.
     */
    function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
        assembly ("memory-safe") {
            r.slot := slot
        }
    }

    /**
     * @dev Returns a `Bytes32Slot` with member `value` located at `slot`.
     */
    function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
        assembly ("memory-safe") {
            r.slot := slot
        }
    }

    /**
     * @dev Returns a `Uint256Slot` with member `value` located at `slot`.
     */
    function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
        assembly ("memory-safe") {
            r.slot := slot
        }
    }

    /**
     * @dev Returns a `Int256Slot` with member `value` located at `slot`.
     */
    function getInt256Slot(bytes32 slot) internal pure returns (Int256Slot storage r) {
        assembly ("memory-safe") {
            r.slot := slot
        }
    }

    /**
     * @dev Returns a `StringSlot` with member `value` located at `slot`.
     */
    function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) {
        assembly ("memory-safe") {
            r.slot := slot
        }
    }

    /**
     * @dev Returns an `StringSlot` representation of the string storage pointer `store`.
     */
    function getStringSlot(string storage store) internal pure returns (StringSlot storage r) {
        assembly ("memory-safe") {
            r.slot := store.slot
        }
    }

    /**
     * @dev Returns a `BytesSlot` with member `value` located at `slot`.
     */
    function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) {
        assembly ("memory-safe") {
            r.slot := slot
        }
    }

    /**
     * @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`.
     */
    function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) {
        assembly ("memory-safe") {
            r.slot := store.slot
        }
    }
}
Strings.sol 490 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (utils/Strings.sol)

pragma solidity ^0.8.20;

import {Math} from "./math/Math.sol";
import {SafeCast} from "./math/SafeCast.sol";
import {SignedMath} from "./math/SignedMath.sol";

/**
 * @dev String operations.
 */
library Strings {
    using SafeCast for *;

    bytes16 private constant HEX_DIGITS = "0123456789abcdef";
    uint8 private constant ADDRESS_LENGTH = 20;
    uint256 private constant SPECIAL_CHARS_LOOKUP =
        (1 << 0x08) | // backspace
            (1 << 0x09) | // tab
            (1 << 0x0a) | // newline
            (1 << 0x0c) | // form feed
            (1 << 0x0d) | // carriage return
            (1 << 0x22) | // double quote
            (1 << 0x5c); // backslash

    /**
     * @dev The `value` string doesn't fit in the specified `length`.
     */
    error StringsInsufficientHexLength(uint256 value, uint256 length);

    /**
     * @dev The string being parsed contains characters that are not in scope of the given base.
     */
    error StringsInvalidChar();

    /**
     * @dev The string being parsed is not a properly formatted address.
     */
    error StringsInvalidAddressFormat();

    /**
     * @dev Converts a `uint256` to its ASCII `string` decimal representation.
     */
    function toString(uint256 value) internal pure returns (string memory) {
        unchecked {
            uint256 length = Math.log10(value) + 1;
            string memory buffer = new string(length);
            uint256 ptr;
            assembly ("memory-safe") {
                ptr := add(add(buffer, 0x20), length)
            }
            while (true) {
                ptr--;
                assembly ("memory-safe") {
                    mstore8(ptr, byte(mod(value, 10), HEX_DIGITS))
                }
                value /= 10;
                if (value == 0) break;
            }
            return buffer;
        }
    }

    /**
     * @dev Converts a `int256` to its ASCII `string` decimal representation.
     */
    function toStringSigned(int256 value) internal pure returns (string memory) {
        return string.concat(value < 0 ? "-" : "", toString(SignedMath.abs(value)));
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
     */
    function toHexString(uint256 value) internal pure returns (string memory) {
        unchecked {
            return toHexString(value, Math.log256(value) + 1);
        }
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
     */
    function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
        uint256 localValue = value;
        bytes memory buffer = new bytes(2 * length + 2);
        buffer[0] = "0";
        buffer[1] = "x";
        for (uint256 i = 2 * length + 1; i > 1; --i) {
            buffer[i] = HEX_DIGITS[localValue & 0xf];
            localValue >>= 4;
        }
        if (localValue != 0) {
            revert StringsInsufficientHexLength(value, length);
        }
        return string(buffer);
    }

    /**
     * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal
     * representation.
     */
    function toHexString(address addr) internal pure returns (string memory) {
        return toHexString(uint256(uint160(addr)), ADDRESS_LENGTH);
    }

    /**
     * @dev Converts an `address` with fixed length of 20 bytes to its checksummed ASCII `string` hexadecimal
     * representation, according to EIP-55.
     */
    function toChecksumHexString(address addr) internal pure returns (string memory) {
        bytes memory buffer = bytes(toHexString(addr));

        // hash the hex part of buffer (skip length + 2 bytes, length 40)
        uint256 hashValue;
        assembly ("memory-safe") {
            hashValue := shr(96, keccak256(add(buffer, 0x22), 40))
        }

        for (uint256 i = 41; i > 1; --i) {
            // possible values for buffer[i] are 48 (0) to 57 (9) and 97 (a) to 102 (f)
            if (hashValue & 0xf > 7 && uint8(buffer[i]) > 96) {
                // case shift by xoring with 0x20
                buffer[i] ^= 0x20;
            }
            hashValue >>= 4;
        }
        return string(buffer);
    }

    /**
     * @dev Returns true if the two strings are equal.
     */
    function equal(string memory a, string memory b) internal pure returns (bool) {
        return bytes(a).length == bytes(b).length && keccak256(bytes(a)) == keccak256(bytes(b));
    }

    /**
     * @dev Parse a decimal string and returns the value as a `uint256`.
     *
     * Requirements:
     * - The string must be formatted as `[0-9]*`
     * - The result must fit into an `uint256` type
     */
    function parseUint(string memory input) internal pure returns (uint256) {
        return parseUint(input, 0, bytes(input).length);
    }

    /**
     * @dev Variant of {parseUint-string} that parses a substring of `input` located between position `begin` (included) and
     * `end` (excluded).
     *
     * Requirements:
     * - The substring must be formatted as `[0-9]*`
     * - The result must fit into an `uint256` type
     */
    function parseUint(string memory input, uint256 begin, uint256 end) internal pure returns (uint256) {
        (bool success, uint256 value) = tryParseUint(input, begin, end);
        if (!success) revert StringsInvalidChar();
        return value;
    }

    /**
     * @dev Variant of {parseUint-string} that returns false if the parsing fails because of an invalid character.
     *
     * NOTE: This function will revert if the result does not fit in a `uint256`.
     */
    function tryParseUint(string memory input) internal pure returns (bool success, uint256 value) {
        return _tryParseUintUncheckedBounds(input, 0, bytes(input).length);
    }

    /**
     * @dev Variant of {parseUint-string-uint256-uint256} that returns false if the parsing fails because of an invalid
     * character.
     *
     * NOTE: This function will revert if the result does not fit in a `uint256`.
     */
    function tryParseUint(
        string memory input,
        uint256 begin,
        uint256 end
    ) internal pure returns (bool success, uint256 value) {
        if (end > bytes(input).length || begin > end) return (false, 0);
        return _tryParseUintUncheckedBounds(input, begin, end);
    }

    /**
     * @dev Implementation of {tryParseUint-string-uint256-uint256} that does not check bounds. Caller should make sure that
     * `begin <= end <= input.length`. Other inputs would result in undefined behavior.
     */
    function _tryParseUintUncheckedBounds(
        string memory input,
        uint256 begin,
        uint256 end
    ) private pure returns (bool success, uint256 value) {
        bytes memory buffer = bytes(input);

        uint256 result = 0;
        for (uint256 i = begin; i < end; ++i) {
            uint8 chr = _tryParseChr(bytes1(_unsafeReadBytesOffset(buffer, i)));
            if (chr > 9) return (false, 0);
            result *= 10;
            result += chr;
        }
        return (true, result);
    }

    /**
     * @dev Parse a decimal string and returns the value as a `int256`.
     *
     * Requirements:
     * - The string must be formatted as `[-+]?[0-9]*`
     * - The result must fit in an `int256` type.
     */
    function parseInt(string memory input) internal pure returns (int256) {
        return parseInt(input, 0, bytes(input).length);
    }

    /**
     * @dev Variant of {parseInt-string} that parses a substring of `input` located between position `begin` (included) and
     * `end` (excluded).
     *
     * Requirements:
     * - The substring must be formatted as `[-+]?[0-9]*`
     * - The result must fit in an `int256` type.
     */
    function parseInt(string memory input, uint256 begin, uint256 end) internal pure returns (int256) {
        (bool success, int256 value) = tryParseInt(input, begin, end);
        if (!success) revert StringsInvalidChar();
        return value;
    }

    /**
     * @dev Variant of {parseInt-string} that returns false if the parsing fails because of an invalid character or if
     * the result does not fit in a `int256`.
     *
     * NOTE: This function will revert if the absolute value of the result does not fit in a `uint256`.
     */
    function tryParseInt(string memory input) internal pure returns (bool success, int256 value) {
        return _tryParseIntUncheckedBounds(input, 0, bytes(input).length);
    }

    uint256 private constant ABS_MIN_INT256 = 2 ** 255;

    /**
     * @dev Variant of {parseInt-string-uint256-uint256} that returns false if the parsing fails because of an invalid
     * character or if the result does not fit in a `int256`.
     *
     * NOTE: This function will revert if the absolute value of the result does not fit in a `uint256`.
     */
    function tryParseInt(
        string memory input,
        uint256 begin,
        uint256 end
    ) internal pure returns (bool success, int256 value) {
        if (end > bytes(input).length || begin > end) return (false, 0);
        return _tryParseIntUncheckedBounds(input, begin, end);
    }

    /**
     * @dev Implementation of {tryParseInt-string-uint256-uint256} that does not check bounds. Caller should make sure that
     * `begin <= end <= input.length`. Other inputs would result in undefined behavior.
     */
    function _tryParseIntUncheckedBounds(
        string memory input,
        uint256 begin,
        uint256 end
    ) private pure returns (bool success, int256 value) {
        bytes memory buffer = bytes(input);

        // Check presence of a negative sign.
        bytes1 sign = begin == end ? bytes1(0) : bytes1(_unsafeReadBytesOffset(buffer, begin)); // don't do out-of-bound (possibly unsafe) read if sub-string is empty
        bool positiveSign = sign == bytes1("+");
        bool negativeSign = sign == bytes1("-");
        uint256 offset = (positiveSign || negativeSign).toUint();

        (bool absSuccess, uint256 absValue) = tryParseUint(input, begin + offset, end);

        if (absSuccess && absValue < ABS_MIN_INT256) {
            return (true, negativeSign ? -int256(absValue) : int256(absValue));
        } else if (absSuccess && negativeSign && absValue == ABS_MIN_INT256) {
            return (true, type(int256).min);
        } else return (false, 0);
    }

    /**
     * @dev Parse a hexadecimal string (with or without "0x" prefix), and returns the value as a `uint256`.
     *
     * Requirements:
     * - The string must be formatted as `(0x)?[0-9a-fA-F]*`
     * - The result must fit in an `uint256` type.
     */
    function parseHexUint(string memory input) internal pure returns (uint256) {
        return parseHexUint(input, 0, bytes(input).length);
    }

    /**
     * @dev Variant of {parseHexUint-string} that parses a substring of `input` located between position `begin` (included) and
     * `end` (excluded).
     *
     * Requirements:
     * - The substring must be formatted as `(0x)?[0-9a-fA-F]*`
     * - The result must fit in an `uint256` type.
     */
    function parseHexUint(string memory input, uint256 begin, uint256 end) internal pure returns (uint256) {
        (bool success, uint256 value) = tryParseHexUint(input, begin, end);
        if (!success) revert StringsInvalidChar();
        return value;
    }

    /**
     * @dev Variant of {parseHexUint-string} that returns false if the parsing fails because of an invalid character.
     *
     * NOTE: This function will revert if the result does not fit in a `uint256`.
     */
    function tryParseHexUint(string memory input) internal pure returns (bool success, uint256 value) {
        return _tryParseHexUintUncheckedBounds(input, 0, bytes(input).length);
    }

    /**
     * @dev Variant of {parseHexUint-string-uint256-uint256} that returns false if the parsing fails because of an
     * invalid character.
     *
     * NOTE: This function will revert if the result does not fit in a `uint256`.
     */
    function tryParseHexUint(
        string memory input,
        uint256 begin,
        uint256 end
    ) internal pure returns (bool success, uint256 value) {
        if (end > bytes(input).length || begin > end) return (false, 0);
        return _tryParseHexUintUncheckedBounds(input, begin, end);
    }

    /**
     * @dev Implementation of {tryParseHexUint-string-uint256-uint256} that does not check bounds. Caller should make sure that
     * `begin <= end <= input.length`. Other inputs would result in undefined behavior.
     */
    function _tryParseHexUintUncheckedBounds(
        string memory input,
        uint256 begin,
        uint256 end
    ) private pure returns (bool success, uint256 value) {
        bytes memory buffer = bytes(input);

        // skip 0x prefix if present
        bool hasPrefix = (end > begin + 1) && bytes2(_unsafeReadBytesOffset(buffer, begin)) == bytes2("0x"); // don't do out-of-bound (possibly unsafe) read if sub-string is empty
        uint256 offset = hasPrefix.toUint() * 2;

        uint256 result = 0;
        for (uint256 i = begin + offset; i < end; ++i) {
            uint8 chr = _tryParseChr(bytes1(_unsafeReadBytesOffset(buffer, i)));
            if (chr > 15) return (false, 0);
            result *= 16;
            unchecked {
                // Multiplying by 16 is equivalent to a shift of 4 bits (with additional overflow check).
                // This guarantees that adding a value < 16 will not cause an overflow, hence the unchecked.
                result += chr;
            }
        }
        return (true, result);
    }

    /**
     * @dev Parse a hexadecimal string (with or without "0x" prefix), and returns the value as an `address`.
     *
     * Requirements:
     * - The string must be formatted as `(0x)?[0-9a-fA-F]{40}`
     */
    function parseAddress(string memory input) internal pure returns (address) {
        return parseAddress(input, 0, bytes(input).length);
    }

    /**
     * @dev Variant of {parseAddress-string} that parses a substring of `input` located between position `begin` (included) and
     * `end` (excluded).
     *
     * Requirements:
     * - The substring must be formatted as `(0x)?[0-9a-fA-F]{40}`
     */
    function parseAddress(string memory input, uint256 begin, uint256 end) internal pure returns (address) {
        (bool success, address value) = tryParseAddress(input, begin, end);
        if (!success) revert StringsInvalidAddressFormat();
        return value;
    }

    /**
     * @dev Variant of {parseAddress-string} that returns false if the parsing fails because the input is not a properly
     * formatted address. See {parseAddress-string} requirements.
     */
    function tryParseAddress(string memory input) internal pure returns (bool success, address value) {
        return tryParseAddress(input, 0, bytes(input).length);
    }

    /**
     * @dev Variant of {parseAddress-string-uint256-uint256} that returns false if the parsing fails because input is not a properly
     * formatted address. See {parseAddress-string-uint256-uint256} requirements.
     */
    function tryParseAddress(
        string memory input,
        uint256 begin,
        uint256 end
    ) internal pure returns (bool success, address value) {
        if (end > bytes(input).length || begin > end) return (false, address(0));

        bool hasPrefix = (end > begin + 1) && bytes2(_unsafeReadBytesOffset(bytes(input), begin)) == bytes2("0x"); // don't do out-of-bound (possibly unsafe) read if sub-string is empty
        uint256 expectedLength = 40 + hasPrefix.toUint() * 2;

        // check that input is the correct length
        if (end - begin == expectedLength) {
            // length guarantees that this does not overflow, and value is at most type(uint160).max
            (bool s, uint256 v) = _tryParseHexUintUncheckedBounds(input, begin, end);
            return (s, address(uint160(v)));
        } else {
            return (false, address(0));
        }
    }

    function _tryParseChr(bytes1 chr) private pure returns (uint8) {
        uint8 value = uint8(chr);

        // Try to parse `chr`:
        // - Case 1: [0-9]
        // - Case 2: [a-f]
        // - Case 3: [A-F]
        // - otherwise not supported
        unchecked {
            if (value > 47 && value < 58) value -= 48;
            else if (value > 96 && value < 103) value -= 87;
            else if (value > 64 && value < 71) value -= 55;
            else return type(uint8).max;
        }

        return value;
    }

    /**
     * @dev Escape special characters in JSON strings. This can be useful to prevent JSON injection in NFT metadata.
     *
     * WARNING: This function should only be used in double quoted JSON strings. Single quotes are not escaped.
     *
     * NOTE: This function escapes all unicode characters, and not just the ones in ranges defined in section 2.5 of
     * RFC-4627 (U+0000 to U+001F, U+0022 and U+005C). ECMAScript's `JSON.parse` does recover escaped unicode
     * characters that are not in this range, but other tooling may provide different results.
     */
    function escapeJSON(string memory input) internal pure returns (string memory) {
        bytes memory buffer = bytes(input);
        bytes memory output = new bytes(2 * buffer.length); // worst case scenario
        uint256 outputLength = 0;

        for (uint256 i; i < buffer.length; ++i) {
            bytes1 char = bytes1(_unsafeReadBytesOffset(buffer, i));
            if (((SPECIAL_CHARS_LOOKUP & (1 << uint8(char))) != 0)) {
                output[outputLength++] = "\\";
                if (char == 0x08) output[outputLength++] = "b";
                else if (char == 0x09) output[outputLength++] = "t";
                else if (char == 0x0a) output[outputLength++] = "n";
                else if (char == 0x0c) output[outputLength++] = "f";
                else if (char == 0x0d) output[outputLength++] = "r";
                else if (char == 0x5c) output[outputLength++] = "\\";
                else if (char == 0x22) {
                    // solhint-disable-next-line quotes
                    output[outputLength++] = '"';
                }
            } else {
                output[outputLength++] = char;
            }
        }
        // write the actual length and deallocate unused memory
        assembly ("memory-safe") {
            mstore(output, outputLength)
            mstore(0x40, add(output, shl(5, shr(5, add(outputLength, 63)))))
        }

        return string(output);
    }

    /**
     * @dev Reads a bytes32 from a bytes array without bounds checking.
     *
     * NOTE: making this function internal would mean it could be used with memory unsafe offset, and marking the
     * assembly block as such would prevent some optimizations.
     */
    function _unsafeReadBytesOffset(bytes memory buffer, uint256 offset) private pure returns (bytes32 value) {
        // This is not memory safe in the general case, but all calls to this private function are within bounds.
        assembly ("memory-safe") {
            value := mload(add(add(buffer, 0x20), offset))
        }
    }
}
ECDSA.sol 180 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/cryptography/ECDSA.sol)

pragma solidity ^0.8.20;

/**
 * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.
 *
 * These functions can be used to verify that a message was signed by the holder
 * of the private keys of a given address.
 */
library ECDSA {
    enum RecoverError {
        NoError,
        InvalidSignature,
        InvalidSignatureLength,
        InvalidSignatureS
    }

    /**
     * @dev The signature derives the `address(0)`.
     */
    error ECDSAInvalidSignature();

    /**
     * @dev The signature has an invalid length.
     */
    error ECDSAInvalidSignatureLength(uint256 length);

    /**
     * @dev The signature has an S value that is in the upper half order.
     */
    error ECDSAInvalidSignatureS(bytes32 s);

    /**
     * @dev Returns the address that signed a hashed message (`hash`) with `signature` or an error. This will not
     * return address(0) without also returning an error description. Errors are documented using an enum (error type)
     * and a bytes32 providing additional information about the error.
     *
     * If no error is returned, then the address can be used for verification purposes.
     *
     * The `ecrecover` EVM precompile allows for malleable (non-unique) signatures:
     * this function rejects them by requiring the `s` value to be in the lower
     * half order, and the `v` value to be either 27 or 28.
     *
     * IMPORTANT: `hash` _must_ be the result of a hash operation for the
     * verification to be secure: it is possible to craft signatures that
     * recover to arbitrary addresses for non-hashed data. A safe way to ensure
     * this is by receiving a hash of the original message (which may otherwise
     * be too long), and then calling {MessageHashUtils-toEthSignedMessageHash} on it.
     *
     * Documentation for signature generation:
     * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]
     * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]
     */
    function tryRecover(
        bytes32 hash,
        bytes memory signature
    ) internal pure returns (address recovered, RecoverError err, bytes32 errArg) {
        if (signature.length == 65) {
            bytes32 r;
            bytes32 s;
            uint8 v;
            // ecrecover takes the signature parameters, and the only way to get them
            // currently is to use assembly.
            assembly ("memory-safe") {
                r := mload(add(signature, 0x20))
                s := mload(add(signature, 0x40))
                v := byte(0, mload(add(signature, 0x60)))
            }
            return tryRecover(hash, v, r, s);
        } else {
            return (address(0), RecoverError.InvalidSignatureLength, bytes32(signature.length));
        }
    }

    /**
     * @dev Returns the address that signed a hashed message (`hash`) with
     * `signature`. This address can then be used for verification purposes.
     *
     * The `ecrecover` EVM precompile allows for malleable (non-unique) signatures:
     * this function rejects them by requiring the `s` value to be in the lower
     * half order, and the `v` value to be either 27 or 28.
     *
     * IMPORTANT: `hash` _must_ be the result of a hash operation for the
     * verification to be secure: it is possible to craft signatures that
     * recover to arbitrary addresses for non-hashed data. A safe way to ensure
     * this is by receiving a hash of the original message (which may otherwise
     * be too long), and then calling {MessageHashUtils-toEthSignedMessageHash} on it.
     */
    function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
        (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, signature);
        _throwError(error, errorArg);
        return recovered;
    }

    /**
     * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.
     *
     * See https://eips.ethereum.org/EIPS/eip-2098[ERC-2098 short signatures]
     */
    function tryRecover(
        bytes32 hash,
        bytes32 r,
        bytes32 vs
    ) internal pure returns (address recovered, RecoverError err, bytes32 errArg) {
        unchecked {
            bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);
            // We do not check for an overflow here since the shift operation results in 0 or 1.
            uint8 v = uint8((uint256(vs) >> 255) + 27);
            return tryRecover(hash, v, r, s);
        }
    }

    /**
     * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.
     */
    function recover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address) {
        (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, r, vs);
        _throwError(error, errorArg);
        return recovered;
    }

    /**
     * @dev Overload of {ECDSA-tryRecover} that receives the `v`,
     * `r` and `s` signature fields separately.
     */
    function tryRecover(
        bytes32 hash,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) internal pure returns (address recovered, RecoverError err, bytes32 errArg) {
        // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature
        // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines
        // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most
        // signatures from current libraries generate a unique signature with an s-value in the lower half order.
        //
        // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value
        // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or
        // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept
        // these malleable signatures as well.
        if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
            return (address(0), RecoverError.InvalidSignatureS, s);
        }

        // If the signature is valid (and not malleable), return the signer address
        address signer = ecrecover(hash, v, r, s);
        if (signer == address(0)) {
            return (address(0), RecoverError.InvalidSignature, bytes32(0));
        }

        return (signer, RecoverError.NoError, bytes32(0));
    }

    /**
     * @dev Overload of {ECDSA-recover} that receives the `v`,
     * `r` and `s` signature fields separately.
     */
    function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address) {
        (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, v, r, s);
        _throwError(error, errorArg);
        return recovered;
    }

    /**
     * @dev Optionally reverts with the corresponding custom error according to the `error` argument provided.
     */
    function _throwError(RecoverError error, bytes32 errorArg) private pure {
        if (error == RecoverError.NoError) {
            return; // no error: do nothing
        } else if (error == RecoverError.InvalidSignature) {
            revert ECDSAInvalidSignature();
        } else if (error == RecoverError.InvalidSignatureLength) {
            revert ECDSAInvalidSignatureLength(uint256(errorArg));
        } else if (error == RecoverError.InvalidSignatureS) {
            revert ECDSAInvalidSignatureS(errorArg);
        }
    }
}
EIP712.sol 160 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (utils/cryptography/EIP712.sol)

pragma solidity ^0.8.20;

import {MessageHashUtils} from "./MessageHashUtils.sol";
import {ShortStrings, ShortString} from "../ShortStrings.sol";
import {IERC5267} from "../../interfaces/IERC5267.sol";

/**
 * @dev https://eips.ethereum.org/EIPS/eip-712[EIP-712] is a standard for hashing and signing of typed structured data.
 *
 * The encoding scheme specified in the EIP requires a domain separator and a hash of the typed structured data, whose
 * encoding is very generic and therefore its implementation in Solidity is not feasible, thus this contract
 * does not implement the encoding itself. Protocols need to implement the type-specific encoding they need in order to
 * produce the hash of their typed data using a combination of `abi.encode` and `keccak256`.
 *
 * This contract implements the EIP-712 domain separator ({_domainSeparatorV4}) that is used as part of the encoding
 * scheme, and the final step of the encoding to obtain the message digest that is then signed via ECDSA
 * ({_hashTypedDataV4}).
 *
 * The implementation of the domain separator was designed to be as efficient as possible while still properly updating
 * the chain id to protect against replay attacks on an eventual fork of the chain.
 *
 * NOTE: This contract implements the version of the encoding known as "v4", as implemented by the JSON RPC method
 * https://docs.metamask.io/guide/signing-data.html[`eth_signTypedDataV4` in MetaMask].
 *
 * NOTE: In the upgradeable version of this contract, the cached values will correspond to the address, and the domain
 * separator of the implementation contract. This will cause the {_domainSeparatorV4} function to always rebuild the
 * separator from the immutable values, which is cheaper than accessing a cached version in cold storage.
 *
 * @custom:oz-upgrades-unsafe-allow state-variable-immutable
 */
abstract contract EIP712 is IERC5267 {
    using ShortStrings for *;

    bytes32 private constant TYPE_HASH =
        keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)");

    // Cache the domain separator as an immutable value, but also store the chain id that it corresponds to, in order to
    // invalidate the cached domain separator if the chain id changes.
    bytes32 private immutable _cachedDomainSeparator;
    uint256 private immutable _cachedChainId;
    address private immutable _cachedThis;

    bytes32 private immutable _hashedName;
    bytes32 private immutable _hashedVersion;

    ShortString private immutable _name;
    ShortString private immutable _version;
    // slither-disable-next-line constable-states
    string private _nameFallback;
    // slither-disable-next-line constable-states
    string private _versionFallback;

    /**
     * @dev Initializes the domain separator and parameter caches.
     *
     * The meaning of `name` and `version` is specified in
     * https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator[EIP-712]:
     *
     * - `name`: the user readable name of the signing domain, i.e. the name of the DApp or the protocol.
     * - `version`: the current major version of the signing domain.
     *
     * NOTE: These parameters cannot be changed except through a xref:learn::upgrading-smart-contracts.adoc[smart
     * contract upgrade].
     */
    constructor(string memory name, string memory version) {
        _name = name.toShortStringWithFallback(_nameFallback);
        _version = version.toShortStringWithFallback(_versionFallback);
        _hashedName = keccak256(bytes(name));
        _hashedVersion = keccak256(bytes(version));

        _cachedChainId = block.chainid;
        _cachedDomainSeparator = _buildDomainSeparator();
        _cachedThis = address(this);
    }

    /**
     * @dev Returns the domain separator for the current chain.
     */
    function _domainSeparatorV4() internal view returns (bytes32) {
        if (address(this) == _cachedThis && block.chainid == _cachedChainId) {
            return _cachedDomainSeparator;
        } else {
            return _buildDomainSeparator();
        }
    }

    function _buildDomainSeparator() private view returns (bytes32) {
        return keccak256(abi.encode(TYPE_HASH, _hashedName, _hashedVersion, block.chainid, address(this)));
    }

    /**
     * @dev Given an already https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct[hashed struct], this
     * function returns the hash of the fully encoded EIP712 message for this domain.
     *
     * This hash can be used together with {ECDSA-recover} to obtain the signer of a message. For example:
     *
     * ```solidity
     * bytes32 digest = _hashTypedDataV4(keccak256(abi.encode(
     *     keccak256("Mail(address to,string contents)"),
     *     mailTo,
     *     keccak256(bytes(mailContents))
     * )));
     * address signer = ECDSA.recover(digest, signature);
     * ```
     */
    function _hashTypedDataV4(bytes32 structHash) internal view virtual returns (bytes32) {
        return MessageHashUtils.toTypedDataHash(_domainSeparatorV4(), structHash);
    }

    /// @inheritdoc IERC5267
    function eip712Domain()
        public
        view
        virtual
        returns (
            bytes1 fields,
            string memory name,
            string memory version,
            uint256 chainId,
            address verifyingContract,
            bytes32 salt,
            uint256[] memory extensions
        )
    {
        return (
            hex"0f", // 01111
            _EIP712Name(),
            _EIP712Version(),
            block.chainid,
            address(this),
            bytes32(0),
            new uint256[](0)
        );
    }

    /**
     * @dev The name parameter for the EIP712 domain.
     *
     * NOTE: By default this function reads _name which is an immutable value.
     * It only reads from storage if necessary (in case the value is too large to fit in a ShortString).
     */
    // solhint-disable-next-line func-name-mixedcase
    function _EIP712Name() internal view returns (string memory) {
        return _name.toStringWithFallback(_nameFallback);
    }

    /**
     * @dev The version parameter for the EIP712 domain.
     *
     * NOTE: By default this function reads _version which is an immutable value.
     * It only reads from storage if necessary (in case the value is too large to fit in a ShortString).
     */
    // solhint-disable-next-line func-name-mixedcase
    function _EIP712Version() internal view returns (string memory) {
        return _version.toStringWithFallback(_versionFallback);
    }
}
MessageHashUtils.sol 99 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.3.0) (utils/cryptography/MessageHashUtils.sol)

pragma solidity ^0.8.20;

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

/**
 * @dev Signature message hash utilities for producing digests to be consumed by {ECDSA} recovery or signing.
 *
 * The library provides methods for generating a hash of a message that conforms to the
 * https://eips.ethereum.org/EIPS/eip-191[ERC-191] and https://eips.ethereum.org/EIPS/eip-712[EIP 712]
 * specifications.
 */
library MessageHashUtils {
    /**
     * @dev Returns the keccak256 digest of an ERC-191 signed data with version
     * `0x45` (`personal_sign` messages).
     *
     * The digest is calculated by prefixing a bytes32 `messageHash` with
     * `"\x19Ethereum Signed Message:\n32"` and hashing the result. It corresponds with the
     * hash signed when using the https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_sign[`eth_sign`] JSON-RPC method.
     *
     * NOTE: The `messageHash` parameter is intended to be the result of hashing a raw message with
     * keccak256, although any bytes32 value can be safely used because the final digest will
     * be re-hashed.
     *
     * See {ECDSA-recover}.
     */
    function toEthSignedMessageHash(bytes32 messageHash) internal pure returns (bytes32 digest) {
        assembly ("memory-safe") {
            mstore(0x00, "\x19Ethereum Signed Message:\n32") // 32 is the bytes-length of messageHash
            mstore(0x1c, messageHash) // 0x1c (28) is the length of the prefix
            digest := keccak256(0x00, 0x3c) // 0x3c is the length of the prefix (0x1c) + messageHash (0x20)
        }
    }

    /**
     * @dev Returns the keccak256 digest of an ERC-191 signed data with version
     * `0x45` (`personal_sign` messages).
     *
     * The digest is calculated by prefixing an arbitrary `message` with
     * `"\x19Ethereum Signed Message:\n" + len(message)` and hashing the result. It corresponds with the
     * hash signed when using the https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_sign[`eth_sign`] JSON-RPC method.
     *
     * See {ECDSA-recover}.
     */
    function toEthSignedMessageHash(bytes memory message) internal pure returns (bytes32) {
        return
            keccak256(bytes.concat("\x19Ethereum Signed Message:\n", bytes(Strings.toString(message.length)), message));
    }

    /**
     * @dev Returns the keccak256 digest of an ERC-191 signed data with version
     * `0x00` (data with intended validator).
     *
     * The digest is calculated by prefixing an arbitrary `data` with `"\x19\x00"` and the intended
     * `validator` address. Then hashing the result.
     *
     * See {ECDSA-recover}.
     */
    function toDataWithIntendedValidatorHash(address validator, bytes memory data) internal pure returns (bytes32) {
        return keccak256(abi.encodePacked(hex"19_00", validator, data));
    }

    /**
     * @dev Variant of {toDataWithIntendedValidatorHash-address-bytes} optimized for cases where `data` is a bytes32.
     */
    function toDataWithIntendedValidatorHash(
        address validator,
        bytes32 messageHash
    ) internal pure returns (bytes32 digest) {
        assembly ("memory-safe") {
            mstore(0x00, hex"19_00")
            mstore(0x02, shl(96, validator))
            mstore(0x16, messageHash)
            digest := keccak256(0x00, 0x36)
        }
    }

    /**
     * @dev Returns the keccak256 digest of an EIP-712 typed data (ERC-191 version `0x01`).
     *
     * The digest is calculated from a `domainSeparator` and a `structHash`, by prefixing them with
     * `\x19\x01` and hashing the result. It corresponds to the hash signed by the
     * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`] JSON-RPC method as part of EIP-712.
     *
     * See {ECDSA-recover}.
     */
    function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32 digest) {
        assembly ("memory-safe") {
            let ptr := mload(0x40)
            mstore(ptr, hex"19_01")
            mstore(add(ptr, 0x02), domainSeparator)
            mstore(add(ptr, 0x22), structHash)
            digest := keccak256(ptr, 0x42)
        }
    }
}
ERC165.sol 25 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (utils/introspection/ERC165.sol)

pragma solidity ^0.8.20;

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

/**
 * @dev Implementation of the {IERC165} interface.
 *
 * Contracts that want to implement ERC-165 should inherit from this contract and override {supportsInterface} to check
 * for the additional interface id that will be supported. For example:
 *
 * ```solidity
 * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
 *     return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
 * }
 * ```
 */
abstract contract ERC165 is IERC165 {
    /// @inheritdoc IERC165
    function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {
        return interfaceId == type(IERC165).interfaceId;
    }
}
IERC165.sol 25 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (utils/introspection/IERC165.sol)

pragma solidity >=0.4.16;

/**
 * @dev Interface of the ERC-165 standard, as defined in the
 * https://eips.ethereum.org/EIPS/eip-165[ERC].
 *
 * Implementers can declare support of contract interfaces, which can then be
 * queried by others ({ERC165Checker}).
 *
 * For an implementation, see {ERC165}.
 */
interface IERC165 {
    /**
     * @dev Returns true if this contract implements the interface defined by
     * `interfaceId`. See the corresponding
     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[ERC section]
     * to learn more about how these ids are created.
     *
     * This function call must use less than 30 000 gas.
     */
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}
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))
        }
    }
}
SignedMath.sol 68 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/math/SignedMath.sol)

pragma solidity ^0.8.20;

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

/**
 * @dev Standard signed math utilities missing in the Solidity language.
 */
library SignedMath {
    /**
     * @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, int256 a, int256 b) internal pure returns (int256) {
        unchecked {
            // branchless ternary works because:
            // b ^ (a ^ b) == a
            // b ^ 0 == b
            return b ^ ((a ^ b) * int256(SafeCast.toUint(condition)));
        }
    }

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

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

    /**
     * @dev Returns the average of two signed numbers without overflow.
     * The result is rounded towards zero.
     */
    function average(int256 a, int256 b) internal pure returns (int256) {
        // Formula from the book "Hacker's Delight"
        int256 x = (a & b) + ((a ^ b) >> 1);
        return x + (int256(uint256(x) >> 255) & (a ^ b));
    }

    /**
     * @dev Returns the absolute unsigned value of a signed value.
     */
    function abs(int256 n) internal pure returns (uint256) {
        unchecked {
            // Formula from the "Bit Twiddling Hacks" by Sean Eron Anderson.
            // Since `n` is a signed integer, the generated bytecode will use the SAR opcode to perform the right shift,
            // taking advantage of the most significant (or "sign" bit) in two's complement representation.
            // This opcode adds new most significant bits set to the value of the previous most significant bit. As a result,
            // the mask will either be `bytes32(0)` (if n is positive) or `~bytes32(0)` (if n is negative).
            int256 mask = n >> 255;

            // A `bytes32(0)` mask leaves the input unchanged, while a `~bytes32(0)` mask complements it.
            return uint256((n + mask) ^ mask);
        }
    }
}
WitOracle.sol 25 lines
// SPDX-License-Identifier: MIT

pragma solidity >=0.8.0 <0.9.0;

import "./interfaces/IWitOracle.sol";
import "./interfaces/IWitOracleAppliance.sol";
import "./interfaces/IWitOracleQueriable.sol";
import "./interfaces/IWitOracleQueriableEvents.sol";

/// @title Witnet Request Board functionality base contract.
/// @author The Witnet Foundation.
abstract contract WitOracle
    is
        IWitAppliance,
        IWitOracle,
        IWitOracleQueriable,
        IWitOracleQueriableEvents
{
    function specs() virtual override external pure returns (bytes4) {
        return (
            type(IWitOracle).interfaceId
                ^ type(IWitOracleQueriable).interfaceId
        );
    }
}
WitOracleRadonRequestFactory.sol 20 lines
// SPDX-License-Identifier: MIT

pragma solidity >=0.8.0 <0.9.0;

import "./interfaces/IWitOracleAppliance.sol";
import "./interfaces/IWitOracleRadonRegistryEvents.sol";
import "./interfaces/IWitOracleRadonRequestFactory.sol";

abstract contract WitOracleRadonRequestFactory
    is
        IWitOracleAppliance, 
        IWitOracleRadonRegistryEvents,
        IWitOracleRadonRequestFactory
{
    function specs() virtual override external pure returns (bytes4) {
        return (
            type(WitOracleRadonRequestFactory).interfaceId
        );
    }
}
IWitAppliance.sol 29 lines
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

abstract contract IWitAppliance {

    /// @notice Returns the name of the actual contract implementing the logic of this Witnet appliance.
    function class() virtual public view returns (string memory);

    /// @notice Returns the ERC-165 id of the minimal functionality expected for this appliance.
    function specs() virtual external view returns (bytes4);

    function _require(bool _condition, string memory _message) virtual internal view {
        if (!_condition) {
            _revert(_message);
        }
    }

    function _revert(string memory _message) virtual internal view {
        revert(
            string(abi.encodePacked(
                class(),
                ": ",
                _message
            ))
        );
    }

}
IWitOracle.sol 39 lines
// SPDX-License-Identifier: MIT

pragma solidity >=0.8.0 <0.9.0;

import "./IWitOracleRadonRegistry.sol";

interface IWitOracle {

    error InvalidDataReport();
    
    event WitOracleReport(
            address indexed evmOrigin, 
            address indexed evmConsumer, 
            address evmReporter,
            Witnet.TransactionHash witDrTxHash,
            Witnet.RadonHash queryRadHash,
            Witnet.QuerySLA  queryParams,
            Witnet.Timestamp resultTimestamp,
            bytes resultCborBytes
        );

    /// @notice Uniquely identifies the WitOracle instance and the chain on which it's deployed.
    function channel() external view returns (bytes4);

    /// @notice Verify the data report (as provided by Wit/Kermit API) is well-formed and authentic,
    /// returning the parsed Witnet.DataResult if so, or reverting otherwise.
    function parseDataReport(Witnet.DataPushReport calldata report, bytes calldata proof) external view returns (Witnet.DataResult memory);

    /// @notice Same as `parseDataReport` but on certain implementations it may store roll-up information 
    /// that will contribute to reduce the cost of verifying and/or rolling-up future data reports.
    /// Emits `DataReport` if report is authentic. 
    function pushDataReport(Witnet.DataPushReport calldata report, bytes calldata proof) external returns (Witnet.DataResult memory);

    /// @notice Returns the WitOracleRadonRegistry in which Witnet-compliant Radon requests
    /// @notice can be formally verified and forever registered as a away to let smart contracts
    /// and users to track actual data sources and offchain computations applied on data updates
    /// safely reported from the Wit/Oracle blockchain. 
    function registry() external view returns (IWitOracleRadonRegistry);
}
IWitOracleAppliance.sol 13 lines
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "./IWitAppliance.sol";

abstract contract IWitOracleAppliance
    is
        IWitAppliance
{
    /// @notice Returns the WitOracle address that this appliance is bound to.
    function witOracle() virtual external view returns (address);
}
IWitOracleConsumer.sol 14 lines
// SPDX-License-Identifier: MIT

pragma solidity >=0.8.0 <0.9.0;

import "./IWitOracle.sol";

interface IWitOracleConsumer {

    /// @notice Accepts a data report from the Wit/oracle blockchain that ought to be
    /// verified by the WitOracle contract pointed out by `witOracle()`. 
    /// @dev The referred `witOracle()` contract emits a `IWitOracle.DataReport` for
    /// every `Witnet.DataPushReport` proven to be authentic. 
    function pushDataReport(Witnet.DataPushReport calldata report, bytes calldata proof) external;
}
IWitOracleQueriable.sol 102 lines
// SPDX-License-Identifier: MIT

pragma solidity >=0.8.0 <0.9.0;

import "../libs/Witnet.sol";

interface IWitOracleQueriable {
    
    /// @notice Removes all query data from storage. Pays back reward on expired queries.
    /// @dev Fails if the query is not in a final status, or not called from the actual requester.
    /// @param queryId The unique query identifier.
    function deleteQuery(uint256 queryId) external returns (Witnet.QueryEvmReward);

    /// @notice Estimate the minimum reward required for posting a data request.
    /// @param evmGasPrice Expected gas price to pay upon posting the data request.
    function estimateBaseFee(uint256 evmGasPrice) external view returns (uint256);
    
    /// @notice Estimate the minimum reward required for posting a data request with a callback.
    /// @param evmGasPrice Expected gas price to pay upon posting the data request.
    /// @param callbackGas Maximum gas to be spent when reporting the data request result.
    function estimateBaseFeeWithCallback(uint256 evmGasPrice, uint24 callbackGas) external view returns (uint256);

    /// @notice Estimate the extra reward (i.e. over the base fee) to be paid when posting a new
    /// @notice data query in order to avoid getting provable "too low incentives" results from
    /// @notice the Wit/Oracle blockchain. 
    /// @dev The extra fee gets calculated in proportion to:
    /// @param evmGasPrice Tentative EVM gas price at the moment the query result is ready.
    /// @param evmWitPrice  Tentative nanoWit price in Wei at the moment the query is solved on the Wit/Oracle blockchain.
    /// @param querySLA The query SLA data security parameters as required for the Wit/Oracle blockchain. 
    function estimateExtraFee(uint256 evmGasPrice, uint256 evmWitPrice, Witnet.QuerySLA calldata querySLA) external view returns (uint256);

    /// @notice Returns next query id to be generated by the Witnet Request Board.
    function getNextQueryId() external view returns (Witnet.QueryId);

    /// @notice Gets the whole Query data contents, if any, no matter its current status.
    function getQuery(Witnet.QueryId queryId) external view returns (Witnet.Query memory);

    /// @notice Gets the current EVM reward the reporter can claim, if not done yet.
    function getQueryEvmReward(uint256) external view returns (Witnet.QueryEvmReward);

    /// @notice Retrieves the RAD hash and SLA parameters of the given query.
    function getQueryRequest(Witnet.QueryId) external view returns (Witnet.QueryRequest memory);

    /// @notice Retrieves the whole `Witnet.QueryResponse` record referred to a previously posted Witnet Data Request.
    function getQueryResponse(Witnet.QueryId) external view returns (Witnet.QueryResponse memory);

    function getQueryResult(uint256) external view returns (Witnet.DataResult memory);
    function getQueryResultStatus(uint256) external view returns (Witnet.ResultStatus);
    function getQueryResultStatusDescription(uint256) external view returns (string memory);
    
    /// @notice Gets query's result back tracing trails
    function getQueryResultTrails(uint256) 
        external view returns (
            bytes32 queryUUID,
            Witnet.TransactionHash resultDrTxHash,
            Witnet.Timestamp resultTimestamp,
            uint256 resultFinalityBlock
        );

    /// @notice Gets current status of given query.
    function getQueryStatus(uint256) external view returns (Witnet.QueryStatus);
    function getQueryStatusString(uint256) external view returns (string memory);
    
    /// @notice Get current status of all given query ids.
    function getQueryStatusBatch(uint256[] calldata) external view returns (Witnet.QueryStatus[] memory);

    /// @notice Request real world data from the Wit/Oracle sidechain. 
    /// @notice The paid fee is escrowed as a reward for the reporter that eventually relays back 
    /// @notice a valid query result from the Wit/Oracle sidechain.
    /// @notice Query results are CBOR-encoded, and can contain either some     data, or an error.
    /// @dev Reasons to revert:
    /// @dev - the data request's RAD hash was not previously verified into the WitOracleRadonRegistry contract;
    /// @dev - invalid query SLA parameters were provided;
    /// @dev - insufficient value is paid as reward.
    /// @param radonHash The unique hash of the Radon Request to be solved by Wit/Oracle sidechain. 
    function queryData(
            Witnet.RadonHash radonHash,
            Witnet.QuerySLA calldata
        )
        external payable returns (uint256);

    /// @notice Request real world data from the Wit/Oracle sidechain. 
    /// @notice The paid fee is escrowed as a reward for the reporter that eventually relays back 
    /// @notice a valid query result from the Wit/Oracle sidechain.
    /// @notice The Witnet-provable result will be reported directly to the requesting contract. 
    /// @notice Query results are CBOR-encoded, and can contain either some data, or an error.
    /// @dev Reasons to revert:
    /// @dev - the data request's RAD hash was not previously verified into the Radon Registry;
    /// @dev - invalid query SLA parameters were provided;
    /// @dev - insufficient value is paid as reward.
    /// @dev - passed `consumer` is not a contract implementing the IWitOracleQueriableConsumer interface;
    /// @param radonHash The unique hash of the Radon Request to be solved by Wit/Oracle sidechain. 
    function queryDataWithCallback(
            Witnet.RadonHash radonHash, 
            Witnet.QuerySLA calldata, 
            Witnet.QueryCallback calldata
        )
        external payable returns (uint256);

    /// @notice Increments the reward of a previously posted request by adding the transaction value to it.
    function upgradeQueryEvmReward(uint256) external payable;
}
IWitOracleQueriableConsumer.sol 22 lines
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "./IWitOracleQueriable.sol";

interface IWitOracleQueriableConsumer {

    /// Method to be called from the WitOracle contract as soon as the given Witnet `queryId` gets reported.
    /// @dev It should revert if called from an address different to the WitOracle instance being used by consumer.
    /// @param queryId The unique identifier of the Witnet query being reported.
    /// @param queryResult Abi-encoded Witnet.DataResult containing the CBOR-encoded query's result, and metadata.
    function reportWitOracleQueryResult(
            uint256 queryId,
            bytes calldata queryResult
        ) external;

    /// @notice Determines if Witnet queries can be reported from given address.
    /// @dev In practice, must only be true on the WitOracle address that's being used by
    /// @dev the WitOracleQueriableConsumer to post queries. 
    function reportableFrom(address) external view returns (bool);
}
IWitOracleQueriableEvents.sol 56 lines
// SPDX-License-Identifier: MIT

pragma solidity >=0.8.0 <0.9.0;

import "../libs/Witnet.sol";

interface IWitOracleQueriableEvents {

    /// Emitted every time a new query containing some verified data request is posted to the WitOracle.
    event WitOracleQuery(
        address indexed evmRequester,
        uint256 evmGasPrice,
        uint256 evmReward,
        Witnet.QueryId queryId, 
        Witnet.RadonHash radonHash,
        Witnet.QuerySLA radonParams
    );

    /// Emitted when the reward of some not-yet reported query gets upgraded.
    event WitOracleQueryUpgrade(
        Witnet.QueryId queryId,
        address evmSender,
        uint256 evmGasPrice,
        uint256 evmReward
    );


    /// Emitted when a query with no callback gets reported into the WRB.
    event WitOracleQueryReport(
        Witnet.QueryId queryId, 
        uint256 evmGasPrice
    );

    event WitOracleQueryReportDispute(
        Witnet.QueryId queryId,
        address evmDisputer
    );

    /// Emitted when a query with a callback gets successfully reported into the WRB.
    event WitOracleQueryReportDelivery(
        Witnet.QueryId queryId, 
        address evmConsumer,
        uint256 evmGasPrice, 
        uint256 evmCallbackGas
    );

    /// Emitted when a query with a callback cannot get reported into the WRB.
    event WitOracleResportDeliveryFailed(
        Witnet.QueryId queryId, 
        address evmConsumer,
        uint256 evmGasPrice, 
        uint256 evmCallbackActualGas, 
        string  evmCallbackRevertReason,
        bytes   resultCborBytes
    );
}
IWitOracleRadonRegistry.sol 184 lines
// SPDX-License-Identifier: MIT

pragma solidity >=0.8.0 <0.9.0;

import "../libs/Witnet.sol";

interface IWitOracleRadonRegistry {

    /// @notice Returns the Witnet-compliant DRO bytecode for some data request object 
    /// made out of the given Radon Request and Radon SLA security parameters. 
    function bytecodeOf(
            Witnet.RadonHash radonRequestHash, 
            Witnet.QuerySLA calldata queryParams
        ) external view returns (bytes memory);
    
    /// @notice Returns the Witnet-compliant DRO bytecode for some data request object 
    /// made out of the given RAD bytecode and Radon SLA security parameters. 
    function bytecodeOf(
            bytes calldata radonRequestBytecode, 
            Witnet.QuerySLA calldata queryParams
        ) external view returns (bytes memory);

    /// @notice Returns the hash of the given Witnet-compliant bytecode. Returned value
    /// can be used to trace back in the Witnet blockchain all past resolutions 
    /// of the given data request payload.
    function hashOf(bytes calldata) external view returns (Witnet.RadonHash);

    /// @notice Tells whether the specified Radon Reducer has been formally verified into the registry.
    function isVerifiedRadonReducer(bytes32) external view returns (bool);
    
    /// @notice Tells whether the given Radon Hash has been formally verified into the registry.
    function isVerifiedRadonRequest(Witnet.RadonHash) external view returns (bool);
    
    /// @notice Tells whether the specified Radon Retrieval has been formally verified into the registry.
    function isVerifiedRadonRetrieval(bytes32) external view returns (bool);
    
    /// @notice Returns the whole Witnet.RadonReducer metadata struct for the given hash.
    /// @dev Reverts if unknown.
    function lookupRadonReducer(bytes32 hash) external view returns (Witnet.RadonReducer memory);

    // /// @notice Returns the whole Witnet.RadonRequest metadata struct for the given RAD hash value. 
    // /// @dev Reverts if unknown.
    // function lookupRadonRequest(Witnet.RadonHash radonRequestHash) external view returns (Witnet.RadonRequest memory);

    /// @notice Returns the Witnet-compliant RAD bytecode for some Radon Request 
    /// identified by its unique RAD hash. 
    function lookupRadonRequestBytecode(Witnet.RadonHash radonRequestHash) external view returns (bytes memory);

    /// @notice Returns the Tally reducer that is applied to aggregated values revealed by the witnessing nodes on the 
    /// Witnet blockchain. 
    /// @dev Reverts if unknown.
    function lookupRadonRequestCrowdAttestationTally(Witnet.RadonHash radonRequestHash) external view returns (Witnet.RadonReducer memory);
    
    /// @notice Returns the deterministic data type returned by successful resolutions of the given Radon Request. 
    /// @dev Reverts if unknown.
    function lookupRadonRequestResultDataType(Witnet.RadonHash radonRequestHash) external view returns (Witnet.RadonDataTypes);

    /// @notice Returns introspective metadata for the index-th data source of some pre-verified Radon Request. 
    /// @dev Reverts if out of range.
    // function lookupRadonRequestRetrievalByIndex(Witnet.RadonHash radonRequestHash, uint256 index) external view returns (Witnet.RadonRetrieval memory);

    /// @notice Returns an array (one or more items) containing the introspective metadata of the given Radon Request's 
    /// data sources (i.e. Radon Retrievals). 
    /// @dev Reverts if unknown.
    function lookupRadonRequestRetrievals(Witnet.RadonHash radonRequestHash) external view returns (Witnet.RadonRetrieval[] memory);

    /// @notice Returns the Aggregate reducer that is applied to the data extracted from the data sources 
    /// (i.e. Radon Retrievals) whenever the given Radon Request gets solved on the Witnet blockchain. 
    /// @dev Reverts if unknown.
    function lookupRadonRequestRetrievalsAggregator(Witnet.RadonHash radonRequestHash) external view returns (Witnet.RadonReducer memory);

    function lookupRadonRequestRetrievalsCount(Witnet.RadonHash radonRequestHash) external view returns (uint8);

    /// @notice Returns introspective metadata of some previously verified Radon Retrieval (i.e. public data source). 
    ///@dev Reverts if unknown.
    function lookupRadonRetrieval(bytes32 hash) external view returns (Witnet.RadonRetrieval memory);
    
    /// @notice Returns the number of indexed parameters required to be fulfilled when 
    /// eventually using the given Radon Retrieval. 
    /// @dev Reverts if unknown.
    function lookupRadonRetrievalArgsCount(bytes32 hash) external view returns (uint8);

    /// @notice Returns the type of the data that would be retrieved by the given Radon Retrieval 
    /// (i.e. public data source). 
    /// @dev Reverts if unknown.
    function lookupRadonRetrievalResultDataType(bytes32 hash) external view returns (Witnet.RadonDataTypes);

    /// @notice Verifies and registers the given sequence of dataset filters and reducing function to be 
    /// potentially used as either Aggregate or Tally reducers within the resolution workflow
    /// of Radon Requests in the Wit/Oracle blockchain. Returns a unique hash that identifies the 
    /// given Radon Reducer in the registry. 
    /// @dev Reverts if unsupported reducing or filtering methods are specified.
    function verifyRadonReducer(Witnet.RadonReducer calldata reducer) external returns (bytes32 hash);
    
    /// @notice Verifies and registers the specified Radon Request out of the given data sources (i.e. retrievals)
    /// and the aggregate and tally Radon Reducers. Returns a unique RAD hash that identifies the 
    /// verified Radon Request. 
    /// @dev Reverts if:
    /// - unverified retrievals are passed;
    /// - retrievals return different data types;
    /// - any of passed retrievals is parameterized;
    /// - unsupported reducers are passed.
    function verifyRadonRequest(
            bytes32[] calldata radonRetrieveHashes,
            Witnet.RadonReducer calldata dataSourcesAggregator,
            Witnet.RadonReducer calldata crowsAttestationTally
        ) external returns (Witnet.RadonHash radonRequestHash);

    /// @notice Verifies and registers the specified Radon Request out of the given data sources (i.e. retrievals), 
    /// data sources parameters (if required), and some pre-verified aggregate and tally Radon Reducers. 
    /// Returns a unique RAD hash that identifies the verified Radon Request.
    /// @dev Reverts if:
    /// - unverified retrievals are passed;
    /// - retrievals return different data types;
    /// - ranks of passed args don't match with those required by each given retrieval;
    /// - unverified reducers are passed.
    function verifyRadonRequest(
            bytes32[] calldata retrieveHashes,
            bytes32 aggregateReducerHash,
            bytes32 tallyReducerHash
        ) external returns (Witnet.RadonHash radonRequestHash);

    /// @notice Verifies and registers the specified Radon Request out of the given data sources (i.e. retrievals), 
    /// data sources parameters (if required), and the aggregate and tally Radon Reducers. Returns a unique 
    /// RAD hash that identifies the verified Radon Request.
    /// @dev Reverts if:
    /// - unverified retrievals are passed;
    /// - retrievals return different data types;
    /// - ranks of passed args don't match with those required by each given retrieval;
    /// - unsupported reducers are passed.
    function verifyRadonRequest(
            bytes32[] calldata radonRetrieveHashes,
            string[][] calldata radonRetrieveArgs,
            Witnet.RadonReducer calldata dataSourcesAggregator,
            Witnet.RadonReducer calldata crowdAttestationTally
        ) external returns (Witnet.RadonHash radonRequestHash);

    /// @notice Verifies and registers the specified Radon Request out of a single modal retrieval where first 
    /// parameter corresponds to data provider's URL, an array of data providers (i.e. URLs), and an array
    /// of parmeter values common to all data providers. Some pre-verified aggregate and tally Radon Reducers
    /// must also be provided. Returns a unique RAD hash that identifies the verified Radon Request.
    /// @dev Reverts if:
    /// - unverified retrieval is passed;
    /// - ranks of passed args don't match with those expected by given retrieval, after replacing the data provider URL.
    /// - unverified reducers are passed.
    function verifyRadonRequest(
            bytes32[] calldata radonRetrieveHashes,
            string[][] calldata radonRetrieveArgs,
            bytes32 dataSourcesAggregatorHash,
            bytes32 crowdAttestationTallyHash
        ) external returns (Witnet.RadonHash radonRequestHash);

    function verifyRadonRequest(
            bytes32 commonRetrieveHash,
            string[] calldata commonRetrieveArgs,
            string[] calldata dataProviders,
            bytes32 dataSourcesAggregatorHash,
            bytes32 crowdAttestationTallyHash
        ) external returns (Witnet.RadonHash radonRequestHash);

    /// @notice Verifies and registers the specified Radon Retrieval (i.e. public data source) into this registry contract. 
    /// Returns a unique retrieval hash that identifies the verified Radon Retrieval.
    /// All parameters but the retrieval method are parameterizable by using embedded wildcard \x\ substrings (with x='0'..'9').
    /// @dev Reverts if:
    /// - unsupported retrieval method is given;
    /// - no URL is provided Http/* requests;
    /// - non-empty strings given on RNG reqs.
    function verifyRadonRetrieval(
            Witnet.RadonRetrievalMethods requestMethod,
            string calldata requestURL,
            string calldata requestBody,
            string[2][] calldata requestHeaders,
            bytes calldata requestRadonScript
        ) external returns (bytes32 hash);

//     /// Verifies a new Radon Retrieval by specifying the value to the highest indexed parameter of an already existing one.
//     /// Returns the unique hash that identifies the resulting Radon Retrieval.
//     /// Reverts if an unverified retrieval hash is passed.
//     function verifyRadonRetrieval(
//             bytes32 retrieveHash,
//             string calldata lastArgValue
//         ) external returns (bytes32 hash);
// }
}
IWitOracleRadonRegistryEvents.sol 20 lines
// SPDX-License-Identifier: MIT

pragma solidity >=0.8.0 <0.9.0;

import "../libs/Witnet.sol";

interface IWitOracleRadonRegistryEvents {

    /// Emitted every time a new Radon Reducer gets successfully verified and
    /// stored into the WitOracleRadonRegistry.
    event NewRadonReducer(bytes32 hash);

    /// Emitted every time a new Radon Retrieval gets successfully verified and
    /// stored into the WitOracleRadonRegistry.
    event NewRadonRetrieval(bytes32 hash);

    /// Emitted every time a new Radon Request gets successfully verified and
    /// stored into the WitOracleRadonRegistry.
    event NewRadonRequest(Witnet.RadonHash radonHash);
}
IWitOracleRadonRequestFactory.sol 43 lines
// SPDX-License-Identifier: MIT

pragma solidity >=0.8.0 <0.9.0;

import "./IWitOracleRadonRequestModal.sol";
import "./IWitOracleRadonRequestTemplate.sol";

interface IWitOracleRadonRequestFactory {

    event NewRadonRequestModal(address witOracleRadonRequestModal);
    event NewRadonRequestTemplate(address witOracleRadonRequestTemplate);

    struct DataSource {
        string url;
        DataSourceRequest request;
    }

    struct DataSourceRequest {
        Witnet.RadonRetrievalMethods method;
        string body;
        string[2][] headers;
        bytes script;
    }

    function buildRadonRequestModal(
            DataSourceRequest calldata commonDataRequest,
            Witnet.RadonReducer calldata crowdAttestationTally
        )
        external returns (IWitOracleRadonRequestModal);

    function buildRadonRequestTemplate(
            bytes32[] calldata dataRetrieveHashes,
            Witnet.RadonReducer calldata dataSourcesAggregator,
            Witnet.RadonReducer calldata crowdAttestationTally
        ) external returns (IWitOracleRadonRequestTemplate);
        
    function buildRadonRequestTemplate(
            DataSource[] calldata dataSources,
            Witnet.RadonReducer calldata dataSourcesAggregator,
            Witnet.RadonReducer calldata crowdAttestationTally
        )
        external returns (IWitOracleRadonRequestTemplate);
}
IWitOracleRadonRequestModal.sol 18 lines
// SPDX-License-Identifier: MIT

pragma solidity >=0.8.0 <0.9.0;

import "../libs/Witnet.sol";

interface IWitOracleRadonRequestModal {

    function getCrowdAttestationTally() external view returns (Witnet.RadonReducer memory);
    function getDataResultType() external view returns (Witnet.RadonDataTypes); 
    function getDataSourceArgsCount(string calldata url) external view returns (uint8);
    function getDataSourcesAggregator() external view returns (Witnet.RadonReducer memory);
    
    function getRadonModalRetrieval() external view returns (Witnet.RadonRetrieval memory);

    function verifyRadonRequest(string[] calldata commonRetrievalArgs, string[] calldata dataProviders) external returns (Witnet.RadonHash);
    function witOracle() external view returns (address);
}
IWitOracleRadonRequestTemplate.sol 31 lines
// SPDX-License-Identifier: MIT

pragma solidity >=0.8.0 <0.9.0;

import "../libs/Witnet.sol";

interface IWitOracleRadonRequestTemplate {

    function getArgsCount() external view returns (uint8[] memory);
    function getCrowdAttestationTally() external view returns (Witnet.RadonReducer memory);
    function getDataResultType() external view returns (Witnet.RadonDataTypes); 
    function getDataSources() external view returns (Witnet.RadonRetrieval[] memory);
    function getDataSourcesAggregator() external view returns (Witnet.RadonReducer memory);
    
    /// Verifies into the bounded WitOracle's registry the actual bytecode 
    /// and RAD hash of the Witnet-compliant Radon Request that gets provably 
    /// made out of the data sources, aggregate and tally Radon Reducers that 
    /// compose this WitOracleRequestTemplate. While no WitOracleRequest instance is 
    /// actually constructed, the returned value will be accepted as a valid
    /// RAD hash on the witOracle() contract from now on. 
    /// Reverts if:
    /// - the ranks of passed array don't match either the number of this 
    ///   template's data sources, or the number of required parameters by 
    ///   each one of those.
    /// @dev This method requires less gas than buildWitOracleRequest(string[][]), and 
    /// @dev it's usually preferred when data requests built out of this template
    /// @dev are intended to be used just once in lifetime.    
    function verifyRadonRequest(string[][] calldata args) external returns (Witnet.RadonHash);

    function witOracle() external view returns (address);
}
Bech32.sol 390 lines
// SPDX-License-Identifier: MIT
// Stratonet Contracts (last updated v1.0.0) (utils/Bech32.sol)

pragma solidity ^0.8.0;

/**
 * @dev Collection of functions related to the Bech32 address generation
 */
library Bech32 {
    bytes constant ALPHABET = "qpzry9x8gf2tvdw0s3jn54khce6mua7l";
    bytes constant ALPHABET_REV = hex"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0fff0a1115141a1e0705ffffffffffffff1dff180d19090817ff12161f1b13ff010003100b1c0c0e060402ffffffffffff1dff180d19090817ff12161f1b13ff010003100b1c0c0e060402ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff";
    bytes constant ALPHABET_REV_LOWER_ONLY = hex"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0fff0a1115141a1e0705ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1dff180d19090817ff12161f1b13ff010003100b1c0c0e060402ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff";

    // 0f <= 0: 48      | 30
    // 0a <= 2: 50      | 32
    // 11 <= 3: 51      | 33
    // 15 <= 4: 52      | 34
    // 14 <= 5: 53      | 35
    // 1a <= 6: 54      | 36
    // 1e <= 7: 55      | 37
    // 07 <= 8: 56      | 38
    // 05 <= 9: 57      | 39
    
    // 1d <= a: 97, 65  | 61, 41
    // 18 <= c: 99, 67  | 63, 43
    // 0d <= d: 100, 68 | 64, 44
    // 19 <= e: 101, 69 | 65, 45
    // 09 <= f: 102, 70 | 66, 46
    // 08 <= g: 103, 71 | 67, 47
    // 17 <= h: 104, 72 | 68, 48
    // 12 <= j: 106, 74 | 6A, 4A
    // 16 <= k: 107, 75 | 6B, 4B
    // 1f <= l: 108, 76 | 6C, 4C
    // 1b <= m: 109, 77 | 6D, 4D
    // 13 <= n: 110, 78 | 6E, 4E
    
    // 01 <= p: 112, 80 | 70, 50
    // 00 <= q: 113, 81 | 71, 51
    // 03 <= r: 114, 82 | 72, 52
    // 10 <= s: 115, 83 | 73, 53
    // 0b <= t: 116, 84 | 74, 54
    // 1c <= u: 117, 85 | 75, 55
    // 0c <= v: 118, 86 | 76, 56
    // 0e <= w: 119, 87 | 77, 57
    // 06 <= x: 120, 88 | 78, 58
    // 04 <= y: 121, 89 | 79, 59
    // 02 <= z: 122, 90 | 7A, 5A
    
    uint32 constant ENC_BECH32 = 1;
    uint32 constant ENC_BECH32M = 0x2bc830a3;


    function toBech32(
        address addr,
        string memory prefix
    ) internal pure returns (string memory) {
        return toBech32(abi.encodePacked(addr), prefix);
    }

    function toBech32(
        bytes memory data,
        string memory prefix
    ) internal pure returns (string memory) {
        bytes memory hrp = abi.encodePacked(prefix);
        bytes memory input = convertBits(data, 8, 5, true);
        return encode(hrp, input, ENC_BECH32);
    }

    function toBech32(
        address addr,
        string memory prefix,
        uint8 version
    ) internal pure returns (string memory) {
        return toBech32(abi.encodePacked(addr), prefix, version);
    }

    function toBech32(
        bytes memory data,
        string memory prefix,
        uint8 version
    ) internal pure returns (string memory) {
        bytes memory hrp = abi.encodePacked(prefix);
        bytes memory input = convertBits(data, 8, 5, true);
        uint32 enc = ENC_BECH32;
        if (version > 0) {
            enc = ENC_BECH32M;
        }
        bytes memory inputWithV = abi.encodePacked(bytes1(version), input);
        return encode(hrp, inputWithV, enc);
    }

    function fromBech32(
        string memory bechAddr
    ) internal pure returns (address) {
        (, uint8[] memory data) = decode(
            abi.encodePacked(bechAddr),
            ENC_BECH32
        );
        bytes memory input = convertBits(data, 5, 8, false);
        return getAddressFromBytes(input);
    }

    function fromBech32(
        string memory bechAddr,
        string memory prefix
    ) internal pure returns (address) {
        (bytes memory dHrp, uint8[] memory data) = decode(
            abi.encodePacked(bechAddr),
            ENC_BECH32
        );
        _requireHrpMatch(abi.encodePacked(prefix), dHrp);
        bytes memory input = convertBits(data, 5, 8, false);
        return getAddressFromBytes(input);
    }

    function fromBech32WithVersion(
        string memory bechAddr,
        string memory prefix,
        uint32 enc
    ) internal pure returns (uint8, bytes memory) {
        (bytes memory dHrp, uint8[] memory data) = decode(
            abi.encodePacked(bechAddr),
            enc
        );
        _requireHrpMatch(abi.encodePacked(prefix), dHrp);
        require(!(data.length < 1 || data[0] > 16), "Bech32: wrong version");
        uint8[] memory dataNoV = new uint8[](data.length - 1);
        for (uint8 i = 1; i < data.length; ++i) {
            dataNoV[i - 1] = data[i];
        }
        bytes memory input = convertBits(dataNoV, 5, 8, false);
        require(
            input.length >= 2 && input.length <= 40,
            "Bech32: wrong bits length"
        );
        require(
            !(data[0] == 0 && input.length != 20 && input.length != 32),
            "Bech32: wrong bits length for version"
        );
        return (uint8(data[0]), input);
    }

    function _requireHrpMatch(
        bytes memory hrp1,
        bytes memory hrp2
    ) internal pure {
        require(keccak256(hrp1) == keccak256(hrp2), "Bech32: hrp mismatch");
    }

    function getAddressFromBytes(
        bytes memory data
    ) internal pure returns (address) {
        require(data.length == 20, "Bech32: invalid data length");

        address addr;
        assembly {
            addr := mload(add(data, 20))
        }
        return addr;
    }

    function encode(
        bytes memory hrp,
        bytes memory input,
        uint32 enc
    ) internal pure returns (string memory) {
        unchecked {
            uint8[] memory checksum = createChecksum(hrp, input, enc);
            bytes memory result = new bytes(hrp.length + input.length + checksum.length + 1);
            for (uint i; i < hrp.length; ++ i) {
                result[i] = hrp[i];
            }
            result[hrp.length] = bytes1("1");
            uint offset = hrp.length + 1;
            for (uint i; i < input.length; ++ i) {
                uint8 _data = uint8(input[i]);
                if (_data < ALPHABET.length) {
                    result[i + offset] = ALPHABET[_data];
                }
            }
            offset += input.length;
            for (uint i; i < checksum.length; ++ i) {
                uint8 _data = uint8(checksum[i]);
                if (_data < ALPHABET.length) {
                    result[i + offset] = ALPHABET[_data];
                }
            }
            return string(result);
        }
    }

    function decode(bytes memory bechStr, uint32 enc) 
        internal pure 
        returns (bytes memory hrp, uint8[] memory data)
    {
        unchecked {
            uint pos;
            require(
                bechStr.length <= 90, 
                "Bech32: invalid string length"
            );
            for (uint p = 0; p < bechStr.length; ++ p) {
                uint8 charAt = uint8(bechStr[p]);
                require(
                    charAt >= 33 
                        && charAt <= 126, 
                    "Bech32: wrong char"
                );
                if (charAt == uint8(bytes1("1"))) {
                    require(
                        pos == 0 
                            && p >= 1 
                            && p + 7 <= bechStr.length, 
                        "Bech32: wrong pos of 1"
                    );
                    pos = p;
                }
            }
            hrp = new bytes(pos);
            for (uint i; i < pos; ++ i) {
                hrp[i] = bechStr[i]; 
            }
            data = new uint8[](bechStr.length - pos - 1);
            for (uint i; i < data.length; ++ i) {
                bytes1 charAt = ALPHABET_REV_LOWER_ONLY[uint8(bechStr[i + pos + 1])];
                require(charAt != 0xff, "Bech32: byte not in alphabet");
                data[i] = uint8(charAt);
            }
            require(
                verifyChecksum(hrp, data, enc), 
                "Bech32: wrong checksum"
            );
            uint dataLength = data.length - 6;
            assembly {
                mstore(data, dataLength)
            }
        }
    }

    function hrpExpand(
        bytes memory hrp
    ) internal pure returns (uint8[] memory ret) {
        unchecked {
            ret = new uint8[](hrp.length + hrp.length + 1);
            for (uint p; p < hrp.length; ++ p) {
                ret[p] = uint8(hrp[p]) >> 5;
                ret[p + hrp.length + 1] = uint8(hrp[p]) & 31;
            }
        }
    }

    function polymod(uint32[] memory values) internal pure returns (uint32) {
        uint32 chk = 1;
        uint32[5] memory GEN = [
            0x3b6a57b2,
            0x26508e6d,
            0x1ea119fa,
            0x3d4233dd,
            0x2a1462b3
        ];

        unchecked {
            for (uint32 i = 0; i < values.length; ++i) {
                uint32 top = chk >> 25;
                chk = (uint32(chk & 0x1ffffff) << 5) ^ uint32(values[i]);
                for (uint32 j = 0; j < 5; ++j) {
                    if (((top >> j) & 1) == 1) {
                        chk ^= GEN[j];
                    }
                }
            }
        }

        return chk;
    }

    function createChecksum(
        bytes memory hrp,
        bytes memory data,
        uint32 enc
    ) internal pure returns (uint8[] memory res) {
        unchecked {
            uint8[] memory values = hrpExpand(hrp);
            uint32[] memory comb = new uint32[](values.length + data.length + 6);

            for (uint i; i < values.length + data.length; ++ i) {
                if (i < values.length) {
                    comb[i] = uint32(values[i]);
                } else {
                    comb[i] = uint32(uint8(data[i - values.length]));
                }
            }
            
            res = new uint8[](6);
            uint32 mod = polymod(comb) ^ enc;
            for (uint p = 0; p < 6; ++ p) {
                res[p] = uint8((mod >> (5 * (5 - p))) & 31);
            }
        }
    }

    function verifyChecksum(
        bytes memory hrp,
        uint8[] memory data,
        uint32 enc
    ) internal pure returns (bool) {
        unchecked {
            uint8[] memory ehrp = hrpExpand(hrp);
            uint32[] memory cData = new uint32[](ehrp.length + data.length);
            for (uint i; i < ehrp.length; ++ i) {
                cData[i] = uint32(ehrp[i]);
            }
            for (uint i; i < data.length; ++ i) {
                cData[i + ehrp.length] = uint32(data[i]);
            }
            return polymod(cData) == enc;
        }
    }

    function convertBits(
        bytes memory data,
        uint frombits,
        uint tobits,
        bool pad
    ) internal pure returns (bytes memory) {
        uint8[] memory dataBits = new uint8[](data.length);

        for (uint32 p = 0; p < dataBits.length; ++p) {
            dataBits[p] = uint8(data[p]);
        }

        return _convertBits(dataBits, frombits, tobits, pad);
    }

    function convertBits(
        uint8[] memory data,
        uint frombits,
        uint tobits,
        bool pad
    ) internal pure returns (bytes memory) {
        return _convertBits(data, frombits, tobits, pad);
    }

    function _convertBits(
        uint8[] memory dataBits,
        uint frombits,
        uint tobits,
        bool pad
    ) internal pure returns (bytes memory ret) {
        uint acc = 0;
        uint bits = 0;

        uint maxv = (1 << tobits) - 1;

        unchecked {
            for (uint p; p < dataBits.length; ++p) {
                uint8 value = dataBits[p];
                require(
                    value >= 0 && (value >> frombits) == 0,
                    "Bech32: value must be non-negative and fit in frombits"
                );

                acc = (acc << frombits) | value;
                bits += frombits;

                while (bits >= tobits) {
                    bits -= tobits;
                    ret = abi.encodePacked(
                        ret,
                        bytes1(uint8((acc >> bits) & maxv))
                    );
                }
            }
        }

        if (pad) {
            if (bits > 0) {
                ret = abi.encodePacked(
                    ret,
                    bytes1(uint8((acc << (tobits - bits)) & maxv))
                );
            }
        } else {
            require(
                bits < frombits || ((acc << (tobits - bits)) & maxv) == 0,
                "Bech32: invalid padding or value size"
            );
        }
    }
}
Secp256k1.sol 302 lines
// SPDX-License-Identifier: MIT

pragma solidity >= 0.8.17;

/**
 * @title Secp256k1 public key recovery Library
 * @dev Library providing arithmetic operations over signed `secpk256k1` signed message due to recover the signer public key EC point in `Solidity`.
 * @author cyphered.eth
 */
library Secp256k1 {
    // Elliptic curve Constants
    uint256 private constant U255_MAX_PLUS_1 =
        57896044618658097711785492504343953926634992332820282019728792003956564819968;

    // Curve Constants
    uint256 private constant A = 0;
    uint256 private constant B = 7;
    uint256 private constant GX = 0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798;
    uint256 private constant GY = 0x483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8;
    uint256 private constant P = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F;
    uint256 private constant N = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141;

    /// @dev recovers signer public key point value.
    /// @param digest hashed message
    /// @param v recovery
    /// @param r first 32 bytes of signature
    /// @param v last 32 bytes of signature
    /// @return (x, y) EC point
    function recover(
        uint256 digest,
        uint8 v,
        uint256 r,
        uint256 s
    ) internal pure returns (uint256, uint256) {
        uint256 x = addmod(r, P * (v >> 1), P);
        if (x > P || s > N || r > N || s == 0 || r == 0 || v > 1) {
            return (0, 0);
        }
        uint256 rInv = invMod(r, N);

        uint256 y2 = addmod(mulmod(x, mulmod(x, x, P), P), addmod(mulmod(x, A, P), B, P), P);
        y2 = expMod(y2, (P + 1) / 4);
        uint256 y = ((y2 + v + 2) & 1 == 0) ? y2 : P - y2;

        (uint256 qx, uint256 qy, uint256 qz) = jacMul(mulmod(rInv, N - digest, N), GX, GY, 1);
        (uint256 qx2, uint256 qy2, uint256 qz2) = jacMul(mulmod(rInv, s, N), x, y, 1);
        (uint256 qx3, uint256 qy3) = ecAdd(qx, qy, qz, qx2, qy2, qz2);

        return (qx3, qy3);
    }

    /// @dev Modular exponentiation, b^e % P.
    /// Source: https://github.com/witnet/elliptic-curve-solidity/blob/master/contracts/EllipticCurve.sol
    /// Source: https://github.com/androlo/standard-contracts/blob/master/contracts/src/crypto/ECCMath.sol
    /// @param _base base
    /// @param _exp exponent
    /// @return r such that r = b**e (mod P)
    function expMod(uint256 _base, uint256 _exp) internal pure returns (uint256) {
        if (_base == 0) return 0;
        if (_exp == 0) return 1;

        uint256 r = 1;
        uint256 bit = U255_MAX_PLUS_1;
        assembly {
            for {

            } gt(bit, 0) {

            } {
                r := mulmod(mulmod(r, r, P), exp(_base, iszero(iszero(and(_exp, bit)))), P)
                r := mulmod(mulmod(r, r, P), exp(_base, iszero(iszero(and(_exp, div(bit, 2))))), P)
                r := mulmod(mulmod(r, r, P), exp(_base, iszero(iszero(and(_exp, div(bit, 4))))), P)
                r := mulmod(mulmod(r, r, P), exp(_base, iszero(iszero(and(_exp, div(bit, 8))))), P)
                bit := div(bit, 16)
            }
        }

        return r;
    }

    /// @dev Adds two points (x1, y1, z1) and (x2 y2, z2).
    /// Source: https://github.com/witnet/elliptic-curve-solidity/blob/master/contracts/EllipticCurve.sol
    /// @param _x1 coordinate x of P1
    /// @param _y1 coordinate y of P1
    /// @param _z1 coordinate z of P1
    /// @param _x2 coordinate x of square
    /// @param _y2 coordinate y of square
    /// @param _z2 coordinate z of square
    /// @return (qx, qy, qz) P1+square in Jacobian
    function jacAdd(
        uint256 _x1,
        uint256 _y1,
        uint256 _z1,
        uint256 _x2,
        uint256 _y2,
        uint256 _z2
    )
        internal
        pure
        returns (
            uint256,
            uint256,
            uint256
        )
    {
        if (_x1 == 0 && _y1 == 0) return (_x2, _y2, _z2);
        if (_x2 == 0 && _y2 == 0) return (_x1, _y1, _z1);

        // We follow the equations described in https://pdfs.semanticscholar.org/5c64/29952e08025a9649c2b0ba32518e9a7fb5c2.pdf Section 5
        uint256[4] memory zs; // z1^2, z1^3, z2^2, z2^3
        zs[0] = mulmod(_z1, _z1, P);
        zs[1] = mulmod(_z1, zs[0], P);
        zs[2] = mulmod(_z2, _z2, P);
        zs[3] = mulmod(_z2, zs[2], P);

        // u1, s1, u2, s2
        zs = [mulmod(_x1, zs[2], P), mulmod(_y1, zs[3], P), mulmod(_x2, zs[0], P), mulmod(_y2, zs[1], P)];

        // In case of zs[0] == zs[2] && zs[1] == zs[3], double function should be used
        require(zs[0] != zs[2] || zs[1] != zs[3], 'Use jacDouble function instead');

        uint256[4] memory hr;
        //h
        hr[0] = addmod(zs[2], P - zs[0], P);
        //r
        hr[1] = addmod(zs[3], P - zs[1], P);
        //h^2
        hr[2] = mulmod(hr[0], hr[0], P);
        // h^3
        hr[3] = mulmod(hr[2], hr[0], P);
        // qx = -h^3  -2u1h^2+r^2
        uint256 qx = addmod(mulmod(hr[1], hr[1], P), P - hr[3], P);
        qx = addmod(qx, P - mulmod(2, mulmod(zs[0], hr[2], P), P), P);
        // qy = -s1*z1*h^3+r(u1*h^2 -x^3)
        uint256 qy = mulmod(hr[1], addmod(mulmod(zs[0], hr[2], P), P - qx, P), P);
        qy = addmod(qy, P - mulmod(zs[1], hr[3], P), P);
        // qz = h*z1*z2
        uint256 qz = mulmod(hr[0], mulmod(_z1, _z2, P), P);
        return (qx, qy, qz);
    }

    /// @dev Multiply point (x, y, z) times d.
    /// Source: https://github.com/witnet/elliptic-curve-solidity/blob/master/contracts/EllipticCurve.sol
    /// @param _d scalar to multiply
    /// @param _x coordinate x of P1
    /// @param _y coordinate y of P1
    /// @param _z coordinate z of P1
    /// @return (qx, qy, qz) d*P1 in Jacobian
    function jacMul(
        uint256 _d,
        uint256 _x,
        uint256 _y,
        uint256 _z
    )
        internal
        pure
        returns (
            uint256,
            uint256,
            uint256
        )
    {
        // Early return in case that `_d == 0`
        if (_d == 0) {
            return (_x, _y, _z);
        }

        uint256 remaining = _d;
        uint256 qx = 0;
        uint256 qy = 0;
        uint256 qz = 1;

        // Double and add algorithm
        while (remaining != 0) {
            if ((remaining & 1) != 0) {
                (qx, qy, qz) = jacAdd(qx, qy, qz, _x, _y, _z);
            }
            remaining = remaining / 2;
            (_x, _y, _z) = jacDouble(_x, _y, _z);
        }
        return (qx, qy, qz);
    }

    /// @dev Doubles a points (x, y, z).
    /// Source: https://github.com/witnet/elliptic-curve-solidity/blob/master/contracts/EllipticCurve.sol
    /// @param _x coordinate x of P1
    /// @param _y coordinate y of P1
    /// @param _z coordinate z of P1
    /// @return (qx, qy, qz) 2P in Jacobian
    function jacDouble(
        uint256 _x,
        uint256 _y,
        uint256 _z
    )
        internal
        pure
        returns (
            uint256,
            uint256,
            uint256
        )
    {
        if (_z == 0) return (_x, _y, _z);

        // We follow the equations described in https://pdfs.semanticscholar.org/5c64/29952e08025a9649c2b0ba32518e9a7fb5c2.pdf Section 5
        // Note: there is a bug in the paper regarding the m parameter, M=3*(x1^2)+a*(z1^4)
        // x, y, z at this point represent the squares of _x, _y, _z
        uint256 x = mulmod(_x, _x, P); //x1^2
        uint256 y = mulmod(_y, _y, P); //y1^2
        uint256 z = mulmod(_z, _z, P); //z1^2

        // s
        uint256 s = mulmod(4, mulmod(_x, y, P), P);
        // m
        uint256 m = addmod(mulmod(3, x, P), mulmod(A, mulmod(z, z, P), P), P);

        // x, y, z at this point will be reassigned and rather represent qx, qy, qz from the paper
        // This allows to reduce the gas cost and stack footprint of the algorithm
        // qx
        x = addmod(mulmod(m, m, P), P - addmod(s, s, P), P);
        // qy = -8*y1^4 + M(S-T)
        y = addmod(mulmod(m, addmod(s, P - x, P), P), P - mulmod(8, mulmod(y, y, P), P), P);
        // qz = 2*y1*z1
        z = mulmod(2, mulmod(_y, _z, P), P);

        return (x, y, z);
    }

    /// @dev Add two points (x1, y1) and (x2, y2) in affine coordinates.
    /// Source: https://github.com/witnet/elliptic-curve-solidity/blob/master/contracts/EllipticCurve.sol
    /// @param _x1 coordinate x of P1
    /// @param _y1 coordinate y of P1
    /// @param _x2 coordinate x of P2
    /// @param _y2 coordinate y of P2
    /// @return (qx, qy) = P1+P2 in affine coordinates
    function ecAdd(
        uint256 _x1,
        uint256 _y1,
        uint256 _z1,
        uint256 _x2,
        uint256 _y2,
        uint256 _z2
    ) internal pure returns (uint256, uint256) {
        uint256 x = 0;
        uint256 y = 0;
        uint256 z = 0;

        // Double if x1==x2 else add
        if (_x1 == _x2) {
            // y1 = -y2 mod p
            if (addmod(_y1, _y2, P) == 0) {
                return (0, 0);
            } else {
                // P1 = P2
                (x, y, z) = jacDouble(_x1, _y1, _z1);
            }
        } else {
            (x, y, z) = jacAdd(_x1, _y1, _z1, _x2, _y2, _z2);
        }
        // Get back to affine
        return toAffine(x, y, z);
    }

    /// @dev Converts a point (x, y, z) expressed in Jacobian coordinates to affine coordinates (x', y', 1).
    /// Source: https://github.com/witnet/elliptic-curve-solidity/blob/master/contracts/EllipticCurve.sol
    /// @param _x coordinate x
    /// @param _y coordinate y
    /// @param _z coordinate z
    /// @return (x', y') affine coordinates
    function toAffine(
        uint256 _x,
        uint256 _y,
        uint256 _z
    ) internal pure returns (uint256, uint256) {
        uint256 zInv = invMod(_z, P);
        uint256 zInv2 = mulmod(zInv, zInv, P);
        uint256 x2 = mulmod(_x, zInv2, P);
        uint256 y2 = mulmod(_y, mulmod(zInv, zInv2, P), P);

        return (x2, y2);
    }

    /// @dev Modular euclidean inverse of a number (mod p).
    /// Source: https://github.com/witnet/elliptic-curve-solidity/blob/master/contracts/EllipticCurve.sol
    /// @param _x The number
    /// @param _pp The modulus
    /// @return q such that x*q = 1 (mod _pp)
    function invMod(uint256 _x, uint256 _pp) internal pure returns (uint256) {
        require(_x != 0 && _x != _pp && _pp != 0, 'Invalid number');
        uint256 q = 0;
        uint256 newT = 1;
        uint256 r = _pp;
        uint256 t;
        while (_x != 0) {
            t = r / _x;
            (q, newT) = (newT, addmod(q, (_pp - mulmod(t, newT, _pp)), _pp));
            (r, _x) = (_x, r - t * _x);
        }

        return q;
    }
}
Witnet.sol 1328 lines
// SPDX-License-Identifier: MIT

pragma solidity >=0.8.0 <0.9.0;

import "./Bech32.sol";
import "./Secp256k1.sol";
import "./WitnetCBOR.sol";

library Witnet {

    using Bech32 for Witnet.Address;
    using WitnetBuffer for WitnetBuffer.Buffer;
    using WitnetCBOR for WitnetCBOR.CBOR;
    using WitnetCBOR for WitnetCBOR.CBOR[];

    type Address is bytes20;

    type BlockNumber is uint64;
    
    type QueryEvmReward is uint72;
    type QueryUUID is bytes15;
    type QueryId is uint64;

    type RadonHash is bytes32;
    type ServiceProvider is bytes20;
    
    type Timestamp is uint64;
    type TransactionHash is bytes32;

    uint32  constant internal WIT_1_GENESIS_TIMESTAMP = 0; // TBD    
    uint32  constant internal WIT_1_SECS_PER_EPOCH = 45;

    uint32  constant internal WIT_2_GENESIS_BEACON_INDEX = 0;       // TBD
    uint32  constant internal WIT_2_GENESIS_BEACON_PREV_INDEX = 0;  // TBD
    bytes24 constant internal WIT_2_GENESIS_BEACON_PREV_ROOT = 0;   // TBD
    bytes16 constant internal WIT_2_GENESIS_BEACON_DDR_TALLIES_MERKLE_ROOT = 0;  // TBD
    bytes16 constant internal WIT_2_GENESIS_BEACON_DRO_TALLIES_MERKLE_ROOT = 0;  // TBD
    uint256 constant internal WIT_2_GENESIS_BEACON_NEXT_COMMITTEE_AGG_PUBKEY_0 = 0; // TBD
    uint256 constant internal WIT_2_GENESIS_BEACON_NEXT_COMMITTEE_AGG_PUBKEY_1 = 0; // TBD
    uint256 constant internal WIT_2_GENESIS_BEACON_NEXT_COMMITTEE_AGG_PUBKEY_2 = 0; // TBD
    uint256 constant internal WIT_2_GENESIS_BEACON_NEXT_COMMITTEE_AGG_PUBKEY_3 = 0; // TBD
    uint32  constant internal WIT_2_GENESIS_EPOCH = 0;      // TBD
    uint32  constant internal WIT_2_GENESIS_TIMESTAMP = 0;  // TBD
    uint32  constant internal WIT_2_SECS_PER_EPOCH = 20;    // TBD
    uint32  constant internal WIT_2_FAST_FORWARD_COMMITTEE_SIZE = 64; // TBD


    function channel(address wrb) internal view returns (bytes4) {
        return bytes4(keccak256(abi.encode(address(wrb), block.chainid)));
    }

    struct Beacon {
        uint32  index;
        uint32  prevIndex;
        bytes24 prevRoot;
        bytes16 ddrTalliesMerkleRoot;
        bytes16 droTalliesMerkleRoot;
        uint256[4] nextCommitteeAggPubkey;
    }

    struct DataPullReport {
        QueryId queryId;
        QueryUUID queryHash;           // KECCAK256(channel | blockhash(block.number - 1) | ...)
        bytes witDrRelayerSignature;   // ECDSA.signature(queryHash)
        BlockNumber witDrResultEpoch;
        bytes witDrResultCborBytes;
        TransactionHash witDrTxHash;
    }

    struct DataPushReport {
        TransactionHash witDrTxHash;
        RadonHash queryRadHash;
        QuerySLA  queryParams;
        Timestamp resultTimestamp;
        bytes resultCborBytes;
    }

    /// Data struct containing the Witnet-provided result to a Data Request.
    struct DataResult {
        ResultStatus status;
        RadonDataTypes dataType;
        TransactionHash drTxHash;
        uint256 finality;
        Timestamp timestamp;
        WitnetCBOR.CBOR value;
    }

    struct FastForward {
        Beacon beacon;
        uint256[2] committeeAggSignature;
        uint256[4][] committeeMissingPubkeys;
    }

    /// Struct containing both request and response data related to every query posted to the Witnet Request Board
    struct Query {
        QueryRequest request;
        QueryResponse response;
        QuerySLA slaParams;      // Minimum Service-Level parameters to be committed by the Witnet blockchain.
        QueryUUID uuid;          // Universal unique identifier determined by the payload, WRB instance, chain id and EVM's previous block hash.
        QueryEvmReward reward;   // EVM amount in wei eventually to be paid to the legit reporter.
        BlockNumber checkpoint;
    }

    /// Possible status of a Witnet query.
    enum QueryStatus {
        Unknown,
        Posted,
        Reported,
        Finalized,
        Delayed,
        Expired,
        Disputed
    }

    struct QueryCallback {
        address consumer;               // consumer contract address to which the query result will be reported
        uint24  gasLimit;               // expected max amount of gas required by the callback method in the consumer contract
    }

    /// Data kept in EVM-storage for every Request posted to the Witnet Request Board.
    struct QueryRequest {
        address   requester;     // EVM address from which the request was posted.
        uint24    callbackGas;   // Max callback gas limit upon response, if a callback is required.
        bytes     radonBytecode; // Optional: Witnet Data Request bytecode to be solved by the Witnet blockchain.
        RadonHash radonHash;     // Optional: Previously verified hash of the Witnet Data Request to be solved.
    }

    /// QueryResponse metadata and result as resolved by the Witnet blockchain.
    struct QueryResponse {
        address reporter;               // EVM address from which the Data Request result was reported.
        Timestamp resultTimestamp;      // Unix timestamp (seconds) at which the data request was resolved in the Witnet blockchain.
        TransactionHash resultDrTxHash; // Unique hash of the commit/reveal act in the Witnet blockchain that resolved the data request.
        bytes resultCborBytes;          // CBOR-encode result to the request, as resolved in the Witnet blockchain.
        address disputer;
    }

    /// Structure containing all possible SLA security parameters for Wit/2.1 Data Requests
    struct QuerySLA {
        uint16  witResultMaxSize; // max size permitted to whatever query result may come from the Wit/Oracle blockchain.
        uint16  witCommitteeSize; // max number of eligibile witnesses in the Wit/Oracle blockchain for solving some query.
        uint64  witUnitaryReward; // min fees in nanowits to be paid for getting the query solved and reported from the Wit/Oracle.
    }

    enum ResultStatus {
        /// 0x00: No errors.
        NoErrors,
        
        ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        /// Source-specific format error sub-codes ============================================================================
        
        /// 0x01: At least one of the source scripts is not a valid CBOR-encoded value.
        SourceScriptNotCBOR, 
        
        /// 0x02: The CBOR value decoded from a source script is not an Array.
        SourceScriptNotArray,
        
        /// 0x03: The Array value decoded form a source script is not a valid Data Request.
        SourceScriptNotRADON,
        
        /// 0x04: The request body of at least one data source was not properly formated.
        SourceRequestBody,
        
        /// 0x05: The request headers of at least one data source was not properly formated.
        SourceRequestHeaders,
        
        /// 0x06: The request URL of at least one data source was not properly formated.
        SourceRequestURL,
        
        /// Unallocated
        SourceFormat0x07, SourceFormat0x08, SourceFormat0x09, SourceFormat0x0A, SourceFormat0x0B, SourceFormat0x0C,
        SourceFormat0x0D, SourceFormat0x0E, SourceFormat0x0F, 
        
        
        ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        /// Complexity error sub-codes ========================================================================================
        
        /// 0x10: The request contains too many sources.
        RequestTooManySources,
        
        /// 0x11: The script contains too many calls.
        ScriptTooManyCalls,
        
        /// Unallocated
        Complexity0x12, Complexity0x13, Complexity0x14, Complexity0x15, Complexity0x16, Complexity0x17, Complexity0x18,
        Complexity0x19, Complexity0x1A, Complexity0x1B, Complexity0x1C, Complexity0x1D, Complexity0x1E, Complexity0x1F,

        
        ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        /// Lack of support error sub-codes ===================================================================================
        
        /// 0x20: Some Radon operator code was found that is not supported (1+ args).
        UnsupportedOperator,
        
        /// 0x21: Some Radon filter opcode is not currently supported (1+ args).
        UnsupportedFilter,
        
        /// 0x22: Some Radon request type is not currently supported (1+ args).
        UnsupportedHashFunction,
        
        /// 0x23: Some Radon reducer opcode is not currently supported (1+ args)
        UnsupportedReducer,
        
        /// 0x24: Some Radon hash function is not currently supported (1+ args).
        UnsupportedRequestType, 
        
        /// 0x25: Some Radon encoding function is not currently supported (1+ args).
        UnsupportedEncodingFunction,
        
        /// Unallocated
        Operator0x26, Operator0x27, 
        
        /// 0x28: Wrong number (or type) of arguments were passed to some Radon operator.
        WrongArguments,
        
        /// Unallocated
        Operator0x29, Operator0x2A, Operator0x2B, Operator0x2C, Operator0x2D, Operator0x2E, Operator0x2F,
        
        
        ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        /// Retrieve-specific circumstantial error sub-codes ================================================================================
        /// 0x30: A majority of data sources returned an HTTP status code other than 200 (1+ args):
        HttpErrors,
        
        /// 0x31: A majority of data sources timed out:
        RetrievalsTimeout,
        
        /// Unallocated
        RetrieveCircumstance0x32, RetrieveCircumstance0x33, RetrieveCircumstance0x34, RetrieveCircumstance0x35,
        RetrieveCircumstance0x36, RetrieveCircumstance0x37, RetrieveCircumstance0x38, RetrieveCircumstance0x39,
        RetrieveCircumstance0x3A, RetrieveCircumstance0x3B, RetrieveCircumstance0x3C, RetrieveCircumstance0x3D,
        RetrieveCircumstance0x3E, RetrieveCircumstance0x3F,
        
        
        ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        /// Scripting-specific runtime error sub-code =========================================================================
        /// 0x40: Math operator caused an underflow.
        MathUnderflow,
        
        /// 0x41: Math operator caused an overflow.
        MathOverflow,
        
        /// 0x42: Math operator tried to divide by zero.
        MathDivisionByZero,            
        
        /// 0x43: Wrong input to subscript call.
        WrongSubscriptInput,
        
        /// 0x44: Value cannot be extracted from input binary buffer.
        BufferIsNotValue,
        
        /// 0x45: Value cannot be decoded from expected type.
        Decode,
        
        /// 0x46: Unexpected empty array.
        EmptyArray,
        
        /// 0x47: Value cannot be encoded to expected type.
        Encode,
        
        /// 0x48: Failed to filter input values (1+ args).
        Filter,
        
        /// 0x49: Failed to hash input value.
        Hash,
        
        /// 0x4A: Mismatching array ranks.
        MismatchingArrays,
        
        /// 0x4B: Failed to process non-homogenous array.
        NonHomegeneousArray,
        
        /// 0x4C: Failed to parse syntax of some input value, or argument.
        Parse,
        
        /// 0x4D: Parsing logic limits were exceeded.
        ParseOverflow,
        
        /// Unallocated
        ScriptError0x4E, ScriptError0x4F,
    
        
        ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        /// Actual first-order result error codes =============================================================================
        
        /// 0x50: Not enough reveals were received in due time:
        InsufficientReveals,
        
        /// 0x51: No actual reveal majority was reached on tally stage:
        InsufficientMajority,
        
        /// 0x52: Not enough commits were received before tally stage:
        InsufficientCommits,
        
        /// 0x53: Generic error during tally execution (to be deprecated after WIP #0028)
        TallyExecution,
        
        /// 0x54: A majority of data sources could either be temporarily unresponsive or failing to report the requested data:
        CircumstantialFailure,
        
        /// 0x55: At least one data source is inconsistent when queried through multiple transports at once:
        InconsistentSources,
        
        /// 0x56: Any one of the (multiple) Retrieve, Aggregate or Tally scripts were badly formated:
        MalformedDataRequest,
        
        /// 0x57: Values returned from a majority of data sources don't match the expected schema:
        MalformedQueryResponses,
        
        /// Unallocated:    
        OtherError0x58, OtherError0x59, OtherError0x5A, OtherError0x5B, OtherError0x5C, OtherError0x5D, OtherError0x5E, 
        
        /// 0x5F: Size of serialized tally result exceeds allowance:
        OversizedTallyResult,

        
        ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        /// Inter-stage runtime error sub-codes ===============================================================================
        
        /// 0x60: Data aggregation reveals could not get decoded on the tally stage:
        MalformedReveals,
        
        /// 0x61: The result to data aggregation could not get encoded:
        EncodeReveals,  
        
        /// 0x62: A mode tie ocurred when calculating some mode value on the aggregation or the tally stage:
        ModeTie, 
        
        /// Unallocated:
        OtherError0x63, OtherError0x64, OtherError0x65, OtherError0x66, OtherError0x67, OtherError0x68, OtherError0x69, 
        OtherError0x6A, OtherError0x6B, OtherError0x6C, OtherError0x6D, OtherError0x6E, OtherError0x6F,
        
        
        ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        /// Runtime access error sub-codes ====================================================================================
        
        /// 0x70: Tried to access a value from an array using an index that is out of bounds (1+ args):
        ArrayIndexOutOfBounds,
        
        /// 0x71: Tried to access a value from a map using a key that does not exist (1+ args):
        MapKeyNotFound,
        
        /// 0X72: Tried to extract value from a map using a JSON Path that returns no values (+1 args):
        JsonPathNotFound,
        
        /// Unallocated:
        OtherError0x73, OtherError0x74, OtherError0x75, OtherError0x76, OtherError0x77, OtherError0x78, 
        OtherError0x79, OtherError0x7A, OtherError0x7B, OtherError0x7C, OtherError0x7D, OtherError0x7E, OtherError0x7F, 
        OtherError0x80, OtherError0x81, OtherError0x82, OtherError0x83, OtherError0x84, OtherError0x85, OtherError0x86, 
        OtherError0x87, OtherError0x88, OtherError0x89, OtherError0x8A, OtherError0x8B, OtherError0x8C, OtherError0x8D, 
        OtherError0x8E, OtherError0x8F, OtherError0x90, OtherError0x91, OtherError0x92, OtherError0x93, OtherError0x94, 
        OtherError0x95, OtherError0x96, OtherError0x97, OtherError0x98, OtherError0x99, OtherError0x9A, OtherError0x9B,
        OtherError0x9C, OtherError0x9D, OtherError0x9E, OtherError0x9F, OtherError0xA0, OtherError0xA1, OtherError0xA2, 
        OtherError0xA3, OtherError0xA4, OtherError0xA5, OtherError0xA6, OtherError0xA7, OtherError0xA8, OtherError0xA9, 
        OtherError0xAA, OtherError0xAB, OtherError0xAC, OtherError0xAD, OtherError0xAE, OtherError0xAF, OtherError0xB0,
        OtherError0xB1, OtherError0xB2, OtherError0xB3, OtherError0xB4, OtherError0xB5, OtherError0xB6, OtherError0xB7,
        OtherError0xB8, OtherError0xB9, OtherError0xBA, OtherError0xBB, OtherError0xBC, OtherError0xBD, OtherError0xBE,
        OtherError0xBF, OtherError0xC0, OtherError0xC1, OtherError0xC2, OtherError0xC3, OtherError0xC4, OtherError0xC5,
        OtherError0xC6, OtherError0xC7, OtherError0xC8, OtherError0xC9, OtherError0xCA, OtherError0xCB, OtherError0xCC,
        OtherError0xCD, OtherError0xCE, OtherError0xCF, OtherError0xD0, OtherError0xD1, OtherError0xD2, OtherError0xD3,
        OtherError0xD4, OtherError0xD5, OtherError0xD6, OtherError0xD7, OtherError0xD8, OtherError0xD9, OtherError0xDA,
        OtherError0xDB, OtherError0xDC, OtherError0xDD, OtherError0xDE, OtherError0xDF,
        
        
        ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        /// Inter-client generic error codes ==================================================================================
        /// Data requests that cannot be relayed into the Witnet blockchain should be reported
        /// with one of these errors. 
        
        /// 0xE0: Requests that cannot be parsed must always get this error as their result.
        BridgeMalformedDataRequest,
        
        /// 0xE1: Witnesses exceeds 100
        BridgePoorIncentives,
        
        /// 0xE2: The request is rejected on the grounds that it may cause the submitter to spend or stake an
        /// amount of value that is unjustifiably high when compared with the reward they will be getting
        BridgeOversizedTallyResult,
        
        /// Unallocated:
        OtherError0xE3, OtherError0xE4, OtherError0xE5, OtherError0xE6, OtherError0xE7, OtherError0xE8, OtherError0xE9,
        OtherError0xEA, OtherError0xEB, OtherError0xEC, OtherError0xED, OtherError0xEE, OtherError0xEF, 
        
        
        ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        /// Transient errors as determined by the Request Board contract ======================================================
        
        /// 0xF0: 
        BoardAwaitingResult,

        /// 0xF1:
        BoardFinalizingResult,

        /// 0xF2:
        BoardBeingDisputed,

        /// Unallocated
        OtherError0xF3, OtherError0xF4, OtherError0xF5, OtherError0xF6, OtherError0xF7,

        
        ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        /// Final errors as determined by the Request Board contract ==========================================================

        /// 0xF8:
        BoardAlreadyDelivered,

        /// 0xF9:
        BoardResolutionTimeout,

        /// Unallocated:
        OtherError0xFA, OtherError0xFB, OtherError0xFC, OtherError0xFD, OtherError0xFE,
        
        
        ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        /// 0xFF: Some tally error is not intercepted but it should (0+ args)
        UnhandledIntercept
    }

    /// Possible types either processed by Witnet Radon Scripts or included within results to Witnet Data Requests.
    enum RadonDataTypes {
        /* 0x00 */ Any, 
        /* 0x01 */ Array,
        /* 0x02 */ Bool,
        /* 0x03 */ Bytes,
        /* 0x04 */ Integer,
        /* 0x05 */ Float,
        /* 0x06 */ Map,
        /* 0x07 */ String,
        Unused0x08, Unused0x09, Unused0x0A, Unused0x0B,
        Unused0x0C, Unused0x0D, Unused0x0E, Unused0x0F,
        /* 0x10 */ Same,
        /* 0x11 */ Inner,
        /* 0x12 */ Match,
        /* 0x13 */ Subscript
    }

    /// Structure defining some data filtering that can be applied at the Aggregation or the Tally stages
    /// within a Witnet Data Request resolution workflow.
    struct RadonFilter {
        RadonFilterOpcodes opcode;
        bytes cborArgs;
    }

    /// Filtering methods currently supported on the Witnet blockchain. 
    enum RadonFilterOpcodes {
        /* 0x00 */ Reserved0x00, //GreaterThan,
        /* 0x01 */ Reserved0x01, //LessThan,
        /* 0x02 */ Reserved0x02, //Equals,
        /* 0x03 */ Reserved0x03, //AbsoluteDeviation,
        /* 0x04 */ Reserved0x04, //RelativeDeviation
        /* 0x05 */ StandardDeviation,
        /* 0x06 */ Reserved0x06, //Top,
        /* 0x07 */ Reserved0x07, //Bottom,
        /* 0x08 */ Mode,
        /* 0x09 */ Reserved0x09  //LessOrEqualThan
    }

    /// Structure defining the array of filters and reducting function to be applied at either the Aggregation
    /// or the Tally stages within a Witnet Data Request resolution workflow.
    struct RadonReducer {
        RadonReduceOpcodes opcode;
        RadonFilter[] filters;
    }

    /// Reducting functions currently supported on the Witnet blockchain.
    enum RadonReduceOpcodes {
        /* 0x00 */ Reserved0x00, //Minimum,
        /* 0x01 */ Reserved0x01, //Maximum,
        /* 0x02 */ Mode,
        /* 0x03 */ AverageMean,
        /* 0x04 */ Reserved0x04, //AverageMeanWeighted,
        /* 0x05 */ AverageMedian,
        /* 0x06 */ Reserved0x06, //AverageMedianWeighted,
        /* 0x07 */ StandardDeviation,
        /* 0x08 */ Reserved0x08, //AverageDeviation,
        /* 0x09 */ Reserved0x09, //MedianDeviation,
        /* 0x0A */ Reserved0x10, //MaximumDeviation,
        /* 0x0B */ ConcatenateAndHash
    }
    
    /// Structure containing the Retrieve-Attestation-Delivery parts of a Witnet-compliant Data Request.
    struct RadonRequest {
        RadonRetrieval[] retrieve;
        RadonReducer aggregate;
        RadonReducer tally;
    }

    /// Structure containing all the parameters that fully describe a Witnet Radon Retrieval within a Witnet Data Request.
    struct RadonRetrieval {
        uint8 argsCount;
        RadonRetrievalMethods method;
        RadonDataTypes dataType;
        string url;
        string body;
        string[2][] headers;
        bytes radonScript;
    }

    /// Possible Radon retrieval methods that can be used within a Radon Retrieval. 
    enum RadonRetrievalMethods {
        /* 0 */ Unknown,
        /* 1 */ HttpGet,
        /* 2 */ RNG,
        /* 3 */ HttpPost,
        /* 4 */ HttpHead
    }

    /// Structure containing all possible SLA security parameters of a Witnet-compliant Data Request.

    struct RadonSLAv1 {
        uint8 numWitnesses;
        uint8 minConsensusPercentage;
        uint64 witnessReward;
        uint64 witnessCollateral;
        uint64 minerCommitRevealFee;
    }


    /// =======================================================================
    /// --- Witnet.Address helper functions -----------------------------------

    function eq(Address a, Address b) internal pure returns (bool) {
        return Address.unwrap(a) == Address.unwrap(b);
    }

    function fromBech32(string memory pkh, bool mainnet) internal pure returns (Address) {
        require(bytes(pkh).length == (mainnet ? 42 : 43), "Bech32: invalid length");
        return Address.wrap(bytes20(Bech32.fromBech32(pkh, mainnet ? "wit" : "twit")));
    }

    function toBech32(Address witAddress, bool mainnet) internal pure returns (string memory) {
        return Bech32.toBech32(address(Address.unwrap(witAddress)), mainnet ? "wit" : "twit");
    }

    function isZero(Address a) internal pure returns (bool) {
        return Address.unwrap(a) == bytes20(0);
    }

    
    /// =======================================================================
    /// --- Witnet.Beacon helper functions ------------------------------------

    function equals(Beacon storage self, Beacon calldata other)
        internal view returns (bool)
    {
        return (
            root(self) == root(other)
        );
    }

    function root(Beacon calldata self) internal pure returns (bytes24) {
        return bytes24(keccak256(abi.encode(
            self.index,
            self.prevIndex,
            self.prevRoot,
            self.ddrTalliesMerkleRoot,
            self.droTalliesMerkleRoot,
            self.nextCommitteeAggPubkey
        )));
    }
    
    function root(Beacon storage self) internal view returns (bytes24) {
        return bytes24(keccak256(abi.encode(
            self.index,
            self.prevIndex,
            self.prevRoot,
            self.ddrTalliesMerkleRoot,
            self.droTalliesMerkleRoot,
            self.nextCommitteeAggPubkey
        )));
    }

    
    /// =======================================================================
    /// --- BlockNumber helper functions --------------------------------------

    function egt(BlockNumber a, BlockNumber b) internal pure returns (bool) {
        return BlockNumber.unwrap(a) >= BlockNumber.unwrap(b);
    }

    function elt(BlockNumber a, BlockNumber b) internal pure returns (bool) {
        return BlockNumber.unwrap(a) <= BlockNumber.unwrap(b);
    }

    function gt(BlockNumber a, BlockNumber b) internal pure returns (bool) {
        return BlockNumber.unwrap(a) > BlockNumber.unwrap(b);
    }

    function lt(BlockNumber a, BlockNumber b) internal pure returns (bool) {
        return BlockNumber.unwrap(a) < BlockNumber.unwrap(b);
    }

    function isZero(BlockNumber b) internal pure returns (bool) {
        return (BlockNumber.unwrap(b) == 0);
    }


    /// ===============================================================================================================
    /// --- Data*Report helper methods --------------------------------------------------------------------------------

    function queryRelayer(DataPullReport calldata self) internal pure returns (address) {
        return recoverEvmAddr(
            self.witDrRelayerSignature, 
            hashify(self.queryHash)
        );
    }

    function tallyHash(DataPullReport calldata self) internal pure returns (bytes32) {
        return keccak256(abi.encode(
            self.queryHash,
            self.witDrRelayerSignature,
            self.witDrTxHash,
            self.witDrResultEpoch,
            self.witDrResultCborBytes
        ));
    }

    function digest(DataPushReport calldata self) internal pure returns (bytes32) {
        return keccak256(abi.encode(
            self.witDrTxHash,
            self.queryRadHash,
            self.queryParams.witResultMaxSize,
            self.queryParams.witCommitteeSize,
            self.queryParams.witUnitaryReward,
            self.resultTimestamp,
            self.resultCborBytes
        ));
    }
    
    /// ========================================================================================================
    /// --- 'DataResult' helper methods ------------------------------------------------------------------------

    function noErrors(DataResult memory self) internal pure returns (bool) {
        return self.status == ResultStatus.NoErrors;
    }

    function keepWaiting(DataResult memory self) internal pure returns (bool) {
        return keepWaiting(self.status);
    }

    function hasErrors(DataResult memory self) internal pure returns (bool) {
        return hasErrors(self.status);
    }

    modifier _checkDataType(DataResult memory self, RadonDataTypes expectedDataType) {
        require(
            !keepWaiting(self)
                && self.dataType == expectedDataType
            , "cbor: cannot fetch data"
        ); _; 
        self.dataType = peekRadonDataType(self.value);
    }

    function fetchAddress(DataResult memory self) 
        internal pure 
        _checkDataType(self, RadonDataTypes.Bytes) 
        returns (address _res)
    {
        return toAddress(self.value.readBytes());
    }

    function fetchBool(DataResult memory self) 
        internal pure 
        _checkDataType(self, RadonDataTypes.Bool) 
        returns (bool)
    {
        return self.value.readBool();
    }

    function fetchBytes(DataResult memory self)
        internal pure 
        _checkDataType(self, RadonDataTypes.Bytes) 
        returns (bytes memory)
    {
        return self.value.readBytes();
    }

    function fetchBytes4(DataResult memory self)
        internal pure 
        _checkDataType(self, RadonDataTypes.Bytes) 
        returns (bytes4)
    {
        return toBytes4(self.value.readBytes());
    }

    function fetchBytes32(DataResult memory self)
        internal pure 
        _checkDataType(self, RadonDataTypes.Bytes) 
        returns (bytes32)
    {
        return toBytes32(self.value.readBytes());
    }

    function fetchCborArray(DataResult memory self)
        internal pure 
        _checkDataType(self, RadonDataTypes.Array) 
        returns (WitnetCBOR.CBOR[] memory)
    {
        return self.value.readArray();
    }

    /// @dev Decode a fixed16 (half-precision) numeric value from the Result's CBOR value.
    /// @dev Due to the lack of support for floating or fixed point arithmetic in the EVM, this method offsets all values.
    /// by 5 decimal orders so as to get a fixed precision of 5 decimal positions, which should be OK for most `fixed16`.
    /// use cases. In other words, the output of this method is 10,000 times the actual value, encoded into an `int32`.
    function fetchFloatFixed16(DataResult memory self)
        internal pure 
        _checkDataType(self, RadonDataTypes.Float) 
        returns (int32)
    {
        return self.value.readFloat16();
    }

    /// @dev Decode an array of fixed16 values from the Result's CBOR value.
    function fetchFloatFixed16Array(DataResult memory self)
        internal pure
        _checkDataType(self, RadonDataTypes.Array)
        returns (int32[] memory)
    {
        return self.value.readFloat16Array();
    }

    /// @dev Decode a `int64` value from the DataResult's CBOR value.
    function fetchInt(DataResult memory self)
        internal pure
        _checkDataType(self, RadonDataTypes.Integer)
        returns (int64)
    {
        return self.value.readInt();
    }

    function fetchInt64Array(DataResult memory self)
        internal pure
        _checkDataType(self, RadonDataTypes.Array)
        returns (int64[] memory)
    {
        return self.value.readIntArray();
    }

    function fetchString(DataResult memory self)
        internal pure
        _checkDataType(self, RadonDataTypes.String)
        returns (string memory)
    {
        return self.value.readString();
    }

    function fetchStringArray(DataResult memory self)
        internal pure
        _checkDataType(self, RadonDataTypes.Array)
        returns (string[] memory)
    {
        return self.value.readStringArray();
    }

    /// @dev Decode a `uint64` value from the DataResult's CBOR value.
    function fetchUint(DataResult memory self)
        internal pure
        _checkDataType(self, RadonDataTypes.Integer)
        returns (uint64)
    {
        return self.value.readUint();
    }

    function fetchUint64Array(DataResult memory self)
        internal pure
        _checkDataType(self, RadonDataTypes.Array)
        returns (uint64[] memory)
    {
        return self.value.readUintArray();
    }

    bytes7 private constant _CBOR_MAJOR_TYPE_TO_RADON_DATA_TYPES_MAP = 0x04040307010600;
    function peekRadonDataType(WitnetCBOR.CBOR memory cbor) internal pure returns (RadonDataTypes _type) {
        _type = RadonDataTypes.Any;
        if (!cbor.eof()) {
            if (cbor.majorType <= 6) {
                return RadonDataTypes(uint8(bytes1(_CBOR_MAJOR_TYPE_TO_RADON_DATA_TYPES_MAP[cbor.majorType])));
            
            } else if (cbor.majorType == 7) {
                if (cbor.additionalInformation == 20 || cbor.additionalInformation == 21) {
                    return RadonDataTypes.Bool;
                
                } else if (cbor.additionalInformation >= 25 && cbor.additionalInformation <= 27) {
                    return RadonDataTypes.Float;
                }
            }
        }
    }


    /// =======================================================================
    /// --- FastForward helper functions --------------------------------------

    function head(FastForward[] calldata rollup)
        internal pure returns (Beacon calldata)
    {
        return rollup[rollup.length - 1].beacon;
    }


    /// ===============================================================================================================
    /// --- Query* helper methods -------------------------------------------------------------------------------------

    function equalOrGreaterThan(QuerySLA calldata self, QuerySLA storage stored) internal view returns (bool) {
        return (
                self.witCommitteeSize >= stored.witCommitteeSize
                && self.witUnitaryReward >= stored.witUnitaryReward 
                && self.witResultMaxSize <= stored.witResultMaxSize
        );
    }

    function hashify(QueryUUID hash) internal pure returns (bytes32) {
        return keccak256(abi.encode(QueryUUID.unwrap(hash)));
    }

    function hashify(QueryId _queryId, Witnet.RadonHash _radHash, bytes32 _slaHash) internal view returns (Witnet.QueryUUID) {
        return Witnet.QueryUUID.wrap(bytes15(
            keccak256(abi.encode(
                channel(address(this)), 
                blockhash(block.number - 1),
                _queryId, Witnet.RadonHash.unwrap(_radHash), _slaHash
            ))
        ));
    }

    function hashify(QuerySLA memory querySLA) internal pure returns (bytes32) {
        return keccak256(abi.encodePacked(
            querySLA.witResultMaxSize,
            querySLA.witCommitteeSize,
            querySLA.witUnitaryReward
        ));
    }

    function isValid(QuerySLA memory self) internal pure returns (bool) {
        return (
            self.witResultMaxSize >= 0
                && self.witCommitteeSize > 0
                && self.witCommitteeSize <= 127
                && self.witUnitaryReward > 0
        );
    }

    function isZero(QueryId a) internal pure returns (bool) {
        return (QueryId.unwrap(a) == 0);
    }

    function toV1(QuerySLA calldata self) internal pure returns (RadonSLAv1 memory) {
        return RadonSLAv1({
            numWitnesses: uint8(self.witCommitteeSize),
            minConsensusPercentage: 51,
            witnessReward: self.witUnitaryReward,
            witnessCollateral: self.witUnitaryReward * self.witCommitteeSize,
            minerCommitRevealFee: self.witUnitaryReward / self.witCommitteeSize
        });
    }


    /// ===============================================================================================================
    /// --- RadonHash helper methods ----------------------------------------------------------------------------------

    function eq(RadonHash a, RadonHash b) internal pure returns (bool) {
        return RadonHash.unwrap(a) == RadonHash.unwrap(b);
    }
    
    function isZero(RadonHash h) internal pure returns (bool) {
        return RadonHash.unwrap(h) == bytes32(0);
    }

    
    /// ===============================================================================================================
    /// --- ResultStatus helper methods -------------------------------------------------------------------------------

    function hasErrors(ResultStatus self) internal pure returns (bool) {
        return (
            self != ResultStatus.NoErrors
                && !keepWaiting(self)
        );
    }

    function isCircumstantial(ResultStatus self) internal pure returns (bool) {
        return (self == ResultStatus.CircumstantialFailure);
    }

    function isRetriable(ResultStatus self) internal pure returns (bool) {
        return (
            lackOfConsensus(self)
                || isCircumstantial(self)
                || poorIncentives(self)
        );
    }

    function keepWaiting(ResultStatus self) internal pure returns (bool) {
        return (
            self == ResultStatus.BoardAwaitingResult
                || self == ResultStatus.BoardFinalizingResult
        );
    }

    function lackOfConsensus(ResultStatus self) internal pure returns (bool) {
        return (
            self == ResultStatus.InsufficientCommits
                || self == ResultStatus.InsufficientMajority
                || self == ResultStatus.InsufficientReveals
        );
    }

    function poorIncentives(ResultStatus self) internal pure returns (bool) {
        return (
            self == ResultStatus.OversizedTallyResult
                || self == ResultStatus.InsufficientCommits
                || self == ResultStatus.BridgePoorIncentives
                || self == ResultStatus.BridgeOversizedTallyResult
        );
    }


    /// ===============================================================================================================
    /// --- Timestamp helper methods ----------------------------------------------------------------------------------

    function gt(Timestamp a, Timestamp b) internal pure returns (bool) {
        return Timestamp.unwrap(a) > Timestamp.unwrap(b);
    }

    function egt(Timestamp a, Timestamp b) internal pure returns (bool) {
        return Timestamp.unwrap(a) >= Timestamp.unwrap(b);
    }

    function elt(Timestamp a, Timestamp b) internal pure returns (bool) {
        return Timestamp.unwrap(a) <= Timestamp.unwrap(b);
    }

    function isZero(Timestamp t) internal pure returns (bool) {
        return Timestamp.unwrap(t) == 0;
    }


    /// ===============================================================================================================
    /// --- 'bytes*' helper methods -----------------------------------------------------------------------------------

    function intoMemArray(bytes32[1] memory _values) internal pure returns (bytes32[] memory) {
        return abi.decode(abi.encode(uint256(32), 1, _values), (bytes32[]));
    }

    function intoMemArray(bytes32[2] memory _values) internal pure returns (bytes32[] memory) {
        return abi.decode(abi.encode(uint256(32), 2, _values), (bytes32[]));
    }

    function intoMemArray(bytes32[3] memory _values) internal pure returns (bytes32[] memory) {
        return abi.decode(abi.encode(uint256(32), 3, _values), (bytes32[]));
    }

    function intoMemArray(bytes32[4] memory _values) internal pure returns (bytes32[] memory) {
        return abi.decode(abi.encode(uint256(32), 4, _values), (bytes32[]));
    }

    function intoMemArray(bytes32[5] memory _values) internal pure returns (bytes32[] memory) {
        return abi.decode(abi.encode(uint256(32), 5, _values), (bytes32[]));
    }

    function intoMemArray(bytes32[6] memory _values) internal pure returns (bytes32[] memory) {
        return abi.decode(abi.encode(uint256(32), 6, _values), (bytes32[]));
    }

    function intoMemArray(bytes32[7] memory _values) internal pure returns (bytes32[] memory) {
        return abi.decode(abi.encode(uint256(32), 7, _values), (bytes32[]));
    }

    function intoMemArray(bytes32[8] memory _values) internal pure returns (bytes32[] memory) {
        return abi.decode(abi.encode(uint256(32), 8, _values), (bytes32[]));
    }
    
    function merkleHash(bytes32 a, bytes32 b) internal pure returns (bytes32) {
        return (a < b
            ? _merkleHash(a, b)
            : _merkleHash(b, a)
        );
    }

    function merkleRoot(bytes32[] calldata proof, bytes32 leaf) internal pure returns (bytes32 _root) {
        _root = leaf;
        for (uint _ix = 0; _ix < proof.length; _ix ++) {
            _root = merkleHash(_root, proof[_ix]);
        }
    }

    function radHash(bytes calldata bytecode) internal pure returns (Witnet.RadonHash) {
        return Witnet.RadonHash.wrap(keccak256(bytecode));
    }

    function recoverEvmAddr(bytes memory signature, bytes32 hash_)
        internal pure 
        returns (address)
    {
        if (signature.length != 65) {
            return (address(0));
        }
        bytes32 r;
        bytes32 s;
        uint8 v;
        assembly {
            r := mload(add(signature, 0x20))
            s := mload(add(signature, 0x40))
            v := byte(0, mload(add(signature, 0x60)))
        }
        if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
            return address(0);
        }
        if (v != 27 && v != 28) {
            return address(0);
        }
        return ecrecover(hash_, v, r, s);
    }

    function verifyWitAddressAuthorization(
            address evmAuthorized, 
            Address witSigner,
            bytes memory witSignature
        )
        internal pure
        returns (bool)
    {
        bytes32 _publicKeyX = recoverWitPublicKey(keccak256(abi.encodePacked(evmAuthorized)), witSignature);
        bytes20 _witSigner = Address.unwrap(witSigner);
        return (
            _witSigner == bytes20(sha256(abi.encodePacked(bytes1(0x00), _publicKeyX)))
                || _witSigner == bytes20(sha256(abi.encodePacked(bytes1(0x01), _publicKeyX)))
                || _witSigner == bytes20(sha256(abi.encodePacked(bytes1(0x02), _publicKeyX)))
                || _witSigner == bytes20(sha256(abi.encodePacked(bytes1(0x03), _publicKeyX)))
        );
    }

    function recoverWitPublicKey(bytes32 evmDigest, bytes memory witSignature)
        internal pure
        returns (bytes32 _witPublicKey)
    {
        if (witSignature.length == 65) {
            bytes32 r;
            bytes32 s;
            uint8 v;
            assembly {
                r := mload(add(witSignature, 0x20))
                s := mload(add(witSignature, 0x40))
                v := byte(0, mload(add(witSignature, 0x60)))
            }
            if (
                uint256(s) <= 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0
                    && (v == 27 || v == 28)
            ) {
                (uint256 x,) = Secp256k1.recover(uint256(evmDigest), v - 27, uint256(r), uint256(s));
                _witPublicKey = bytes32(x);
            }
        }
    }

    function toAddress(bytes memory _value) internal pure returns (address) {
        return address(toBytes20(_value));
    }

    function toBytes4(bytes memory _value) internal pure returns (bytes4) {
        return bytes4(toFixedBytes(_value, 4));
    }
    
    function toBytes20(bytes memory _value) internal pure returns (bytes20) {
        return bytes20(toFixedBytes(_value, 20));
    }
    
    function toBytes32(bytes memory _value) internal pure returns (bytes32) {
        return toFixedBytes(_value, 32);
    }

    function toFixedBytes(bytes memory _value, uint8 _numBytes)
        internal pure
        returns (bytes32 _bytes32)
    {
        assert(_numBytes <= 32);
        unchecked {
            uint _len = _value.length > _numBytes ? _numBytes : _value.length;
            for (uint _i = 0; _i < _len; _i ++) {
                _bytes32 |= bytes32(_value[_i] & 0xff) >> (_i * 8);
            }
        }
    }
    
    /// @notice Converts bytes32 into string.
    function asAscii(bytes32 _bytes32)
        internal pure
        returns (string memory)
    {
        bytes memory _bytes = new bytes(_toStringLength(_bytes32));
        for (uint _i = 0; _i < _bytes.length;) {
            _bytes[_i] = _bytes32[_i];
            unchecked {
                _i ++;
            }
        }
        return string(_bytes);
    }

    function toHexString(bytes32 _bytes32) 
        internal pure
        returns (string memory)
    {
        bytes memory _bytes = new bytes(64);
        for (uint8 _i; _i < _bytes.length;) {
            _bytes[_i ++] = _toHexChar(uint8(_bytes32[_i / 2] >> 4));
            _bytes[_i ++] = _toHexChar(uint8(_bytes32[_i / 2] & 0x0f));
        }
        return string(_bytes);
    }


    /// ===============================================================================================================
    /// --- 'string' helper methods -----------------------------------------------------------------------------------

    function toLowerCase(string memory str)
        internal pure
        returns (string memory)
    {
        bytes memory lowered = new bytes(bytes(str).length);
        unchecked {
            for (uint i = 0; i < lowered.length; i ++) {
                uint8 char = uint8(bytes(str)[i]);
                if (char >= 65 && char <= 90) {
                    lowered[i] = bytes1(char + 32);
                } else {
                    lowered[i] = bytes1(char);
                }
            }
        }
        return string(lowered);
    }

    // Function to parse a hex string into a byte array
    function parseHexString(string memory hexString) internal pure returns (bytes memory result) {
        unchecked {
            result = new bytes(bytes(hexString).length / 2);
            for (uint256 i; i < result.length; i ++) {
                uint8 byte1 = _hexCharToByte(uint8(bytes(hexString)[2 * i]));
                uint8 byte2 = _hexCharToByte(uint8(bytes(hexString)[2 * i + 1]));
                result[i] = bytes1(byte1 * 16 + byte2); // Combining the two hex digits into one byte
            }
        }
    }

    function tryUint(string memory str)
        internal pure
        returns (uint res, bool)
    {
        unchecked {
            for (uint256 i = 0; i < bytes(str).length; i++) {
                if (
                    (uint8(bytes(str)[i]) - 48) < 0
                        || (uint8(bytes(str)[i]) - 48) > 9
                ) {
                    return (0, false);
                }
                res += (uint8(bytes(str)[i]) - 48) * 10 ** (bytes(str).length - i - 1);
            }
            return (res, true);
        }
    }


    /// ===============================================================================================================
    /// --- 'uint*' helper methods ------------------------------------------------------------------------------------

    function determineBeaconIndexFromEpoch(BlockNumber epoch) internal pure returns (uint64) {
        return BlockNumber.unwrap(epoch) / 10;
    }
    
    function determineBeaconIndexFromTimestamp(Timestamp timestamp) internal pure returns (uint64) {
        return determineBeaconIndexFromEpoch(
            determineEpochFromTimestamp(
                timestamp
            )
        );
    }

    function determineEpochFromTimestamp(Timestamp timestamp) internal pure returns (BlockNumber) {
        if (Timestamp.unwrap(timestamp) > WIT_2_GENESIS_TIMESTAMP) {
            return BlockNumber.wrap(
                WIT_2_GENESIS_EPOCH
                    + (Timestamp.unwrap(timestamp) - WIT_2_GENESIS_TIMESTAMP)
                        / WIT_2_SECS_PER_EPOCH
            );
        } else if (Timestamp.unwrap(timestamp) > WIT_1_GENESIS_TIMESTAMP) {
            return BlockNumber.wrap(
                (Timestamp.unwrap(timestamp) - WIT_1_GENESIS_TIMESTAMP)
                    / WIT_1_SECS_PER_EPOCH
            );
        } else {
            return BlockNumber.wrap(0);
        }
    }

    function determineTimestampFromEpoch(BlockNumber epoch) internal pure returns (Timestamp) {
        if (BlockNumber.unwrap(epoch) >= WIT_2_GENESIS_EPOCH) {
            return Timestamp.wrap(
                WIT_2_GENESIS_TIMESTAMP
                    + (WIT_2_SECS_PER_EPOCH * (
                        BlockNumber.unwrap(epoch)
                            - WIT_2_GENESIS_EPOCH)
                    )
            );
        } else return Timestamp.wrap(
            WIT_1_GENESIS_TIMESTAMP
                + (WIT_1_SECS_PER_EPOCH * BlockNumber.unwrap(epoch))
        );
    }

    /// Generates a pseudo-random uint32 number uniformly distributed within the range `[0 .. range)`, based on
    /// the given `nonce` and `seed` values. 
    function randomUniformUint64(uint64 range, uint256 nonce, bytes32 seed)
        internal pure 
        returns (uint64) 
    {
        uint256 _number = uint256(
            keccak256(
                abi.encode(seed, nonce)
            )
        ) & uint256(2 ** 192 - 1);
        return uint64((_number * range) >> 192);
    }

    /// @notice Convert a `uint8` into a 2 characters long `string` representing its two less significant hexadecimal values.
    function toHexString(uint8 _u)
        internal pure
        returns (string memory)
    {
        bytes memory b2 = new bytes(2);
        uint8 d0 = uint8(_u / 16) + 48;
        uint8 d1 = uint8(_u % 16) + 48;
        if (d0 > 57)
            d0 += 7;
        if (d1 > 57)
            d1 += 7;
        b2[0] = bytes1(d0);
        b2[1] = bytes1(d1);
        return string(b2);
    }

    /// @notice Convert a `uint8` into a 1, 2 or 3 characters long `string` representing its.
    /// three less significant decimal values....

// [truncated — 52859 bytes total]
WitnetBuffer.sol 825 lines
// SPDX-License-Identifier: MIT

pragma solidity >=0.8.0 <0.9.0;

/// @title A convenient wrapper around the `bytes memory` type that exposes a buffer-like interface
/// @notice The buffer has an inner cursor that tracks the final offset of every read, i.e. any subsequent read will
/// start with the byte that goes right after the last one in the previous read.
/// @dev `uint32` is used here for `cursor` because `uint16` would only enable seeking up to 8KB, which could in some
/// theoretical use cases be exceeded. Conversely, `uint32` supports up to 512MB, which cannot credibly be exceeded.
/// @author The Witnet Foundation.
library WitnetBuffer {

  error EmptyBuffer();
  error IndexOutOfBounds(uint index, uint range);
  error MissingArgs(uint expected, uint given);

  /// Iterable bytes buffer.
  struct Buffer {
      bytes data;
      uint cursor;
  }

  // Ensures we access an existing index in an array
  modifier withinRange(uint index, uint _range) {
    if (index > _range) {
      revert IndexOutOfBounds(index, _range);
    }
    _;
  }

  /// @notice Concatenate undefinite number of bytes chunks.
  /// @dev Faster than looping on `abi.encodePacked(output, _buffs[ix])`.
  function concat(bytes[] memory _buffs)
    internal pure
    returns (bytes memory output)
  {
    unchecked {
      uint destinationPointer;
      uint destinationLength;
      assembly {
        // get safe scratch location
        output := mload(0x40)
        // set starting destination pointer
        destinationPointer := add(output, 32)
      }      
      for (uint ix = 1; ix <= _buffs.length; ix ++) {  
        uint source;
        uint sourceLength;
        uint sourcePointer;        
        assembly {
          // load source length pointer
          source := mload(add(_buffs, mul(ix, 32)))
          // load source length
          sourceLength := mload(source)
          // sets source memory pointer
          sourcePointer := add(source, 32)
        }
        memcpy(
          destinationPointer,
          sourcePointer,
          sourceLength
        );
        assembly {          
          // increase total destination length
          destinationLength := add(destinationLength, sourceLength)
          // sets destination memory pointer
          destinationPointer := add(destinationPointer, sourceLength)
        }
      }
      assembly {
        // protect output bytes
        mstore(output, destinationLength)
        // set final output length
        mstore(0x40, add(mload(0x40), add(destinationLength, 32)))
      }
    }
  }

  function fork(WitnetBuffer.Buffer memory buffer)
    internal pure
    returns (WitnetBuffer.Buffer memory)
  {
    return Buffer(
      buffer.data,
      buffer.cursor
    );
  }

  function mutate(
      WitnetBuffer.Buffer memory buffer,
      uint length,
      bytes memory pokes
    )
    internal pure
    withinRange(length, buffer.data.length - buffer.cursor + 1)
  {
    bytes[] memory parts = new bytes[](3);
    parts[0] = peek(
      buffer,
      0,
      buffer.cursor
    );
    parts[1] = pokes;
    parts[2] = peek(
      buffer,
      buffer.cursor + length,
      buffer.data.length - buffer.cursor - length
    );
    buffer.data = concat(parts);
  }

  /// @notice Read and consume the next byte from the buffer.
  /// @param buffer An instance of `Buffer`.
  /// @return The next byte in the buffer counting from the cursor position.
  function next(Buffer memory buffer)
    internal pure
    withinRange(buffer.cursor, buffer.data.length)
    returns (bytes1)
  {
    // Return the byte at the position marked by the cursor and advance the cursor all at once
    return buffer.data[buffer.cursor ++];
  }

  function peek(
      WitnetBuffer.Buffer memory buffer,
      uint offset,
      uint length
    )
    internal pure
    withinRange(offset + length, buffer.data.length)
    returns (bytes memory)
  {
    bytes memory data = buffer.data;
    bytes memory peeks = new bytes(length);
    uint destinationPointer;
    uint sourcePointer;
    assembly {
      destinationPointer := add(peeks, 32)
      sourcePointer := add(add(data, 32), offset)
    }
    memcpy(
      destinationPointer,
      sourcePointer,
      length
    );
    return peeks;
  }

  // @notice Extract bytes array from buffer starting from current cursor.
  /// @param buffer An instance of `Buffer`.
  /// @param length How many bytes to peek from the Buffer.
  // solium-disable-next-line security/no-assign-params
  function peek(
      WitnetBuffer.Buffer memory buffer,
      uint length
    )
    internal pure
    withinRange(length, buffer.data.length - buffer.cursor)
    returns (bytes memory)
  {
    return peek(
      buffer,
      buffer.cursor,
      length
    );
  }

  /// @notice Read and consume a certain amount of bytes from the buffer.
  /// @param buffer An instance of `Buffer`.
  /// @param length How many bytes to read and consume from the buffer.
  /// @return output A `bytes memory` containing the first `length` bytes from the buffer, counting from the cursor position.
  function read(Buffer memory buffer, uint length)
    internal pure
    withinRange(buffer.cursor + length, buffer.data.length)
    returns (bytes memory output)
  {
    // Create a new `bytes memory destination` value
    output = new bytes(length);
    // Early return in case that bytes length is 0
    if (length > 0) {
      bytes memory input = buffer.data;
      uint offset = buffer.cursor;
      // Get raw pointers for source and destination
      uint sourcePointer;
      uint destinationPointer;
      assembly {
        sourcePointer := add(add(input, 32), offset)
        destinationPointer := add(output, 32)
      }
      // Copy `length` bytes from source to destination
      memcpy(
        destinationPointer,
        sourcePointer,
        length
      );
      // Move the cursor forward by `length` bytes
      seek(
        buffer,
        length,
        true
      );
    }
  }
  
  /// @notice Read and consume the next 2 bytes from the buffer as an IEEE 754-2008 floating point number enclosed in an
  /// `int32`.
  /// @dev Due to the lack of support for floating or fixed point arithmetic in the EVM, this method offsets all values
  /// by 5 decimal orders so as to get a fixed precision of 5 decimal positions, which should be OK for most `float16`
  /// use cases. In other words, the integer output of this method is 10,000 times the actual value. The input bytes are
  /// expected to follow the 16-bit base-2 format (a.k.a. `binary16`) in the IEEE 754-2008 standard.
  /// @param buffer An instance of `Buffer`.
  /// @return result The `int32` value of the next 4 bytes in the buffer counting from the cursor position.
  function readFloat16(Buffer memory buffer)
    internal pure
    returns (int32 result)
  {
    uint32 value = readUint16(buffer);
    // Get bit at position 0
    uint32 sign = value & 0x8000;
    // Get bits 1 to 5, then normalize to the [-15, 16] range so as to counterweight the IEEE 754 exponent bias
    int32 exponent = (int32(value & 0x7c00) >> 10) - 15;
    // Get bits 6 to 15
    int32 fraction = int32(value & 0x03ff);
    // Add 2^10 to the fraction if exponent is not -15
    if (exponent != -15) {
      fraction |= 0x400;
    } else if (exponent == 16) {
      revert(
        string(abi.encodePacked(
          "WitnetBuffer.readFloat16: ",
          sign != 0 ? "negative" : hex"",
          " infinity"
        ))
      );
    }
    // Compute `2 ^ exponent · (1 + fraction / 1024)`
    if (exponent >= 0) {
      result = int32(int(
        int(1 << uint256(int256(exponent)))
          * 10000
          * fraction
      ) >> 10);
    } else {
      result = int32(int(
        int(fraction)
          * 10000
          / int(1 << uint(int(- exponent)))
      ) >> 10);
    }
    // Make the result negative if the sign bit is not 0
    if (sign != 0) {
      result *= -1;
    }
  }

  /// @notice Consume the next 4 bytes from the buffer as an IEEE 754-2008 floating point number enclosed into an `int`.
  /// @dev Due to the lack of support for floating or fixed point arithmetic in the EVM, this method offsets all values
  /// by 9 decimal orders so as to get a fixed precision of 9 decimal positions, which should be OK for most `float32`
  /// use cases. In other words, the integer output of this method is 10^9 times the actual value. The input bytes are
  /// expected to follow the 64-bit base-2 format (a.k.a. `binary32`) in the IEEE 754-2008 standard.
  /// @param buffer An instance of `Buffer`.
  /// @return result The `int` value of the next 8 bytes in the buffer counting from the cursor position.
  function readFloat32(Buffer memory buffer)
    internal pure
    returns (int result)
  {
    uint value = readUint32(buffer);
    // Get bit at position 0
    uint sign = value & 0x80000000;
    // Get bits 1 to 8, then normalize to the [-127, 128] range so as to counterweight the IEEE 754 exponent bias
    int exponent = (int(value & 0x7f800000) >> 23) - 127;
    // Get bits 9 to 31
    int fraction = int(value & 0x007fffff);
    // Add 2^23 to the fraction if exponent is not -127
    if (exponent != -127) {
      fraction |= 0x800000;
    } else if (exponent == 128) {
      revert(
        string(abi.encodePacked(
          "WitnetBuffer.readFloat32: ",
          sign != 0 ? "negative" : hex"",
          " infinity"
        ))
      );
    }
    // Compute `2 ^ exponent · (1 + fraction / 2^23)`
    if (exponent >= 0) {
      result = (
        int(1 << uint(exponent))
          * (10 ** 9)
          * fraction
      ) >> 23;
    } else {
      result = (
        fraction 
          * (10 ** 9)
          / int(1 << uint(-exponent)) 
      ) >> 23;
    }
    // Make the result negative if the sign bit is not 0
    if (sign != 0) {
      result *= -1;
    }
  }

  /// @notice Consume the next 8 bytes from the buffer as an IEEE 754-2008 floating point number enclosed into an `int`.
  /// @dev Due to the lack of support for floating or fixed point arithmetic in the EVM, this method offsets all values
  /// by 15 decimal orders so as to get a fixed precision of 15 decimal positions, which should be OK for most `float64`
  /// use cases. In other words, the integer output of this method is 10^15 times the actual value. The input bytes are
  /// expected to follow the 64-bit base-2 format (a.k.a. `binary64`) in the IEEE 754-2008 standard.
  /// @param buffer An instance of `Buffer`.
  /// @return result The `int` value of the next 8 bytes in the buffer counting from the cursor position.
  function readFloat64(Buffer memory buffer)
    internal pure
    returns (int result)
  {
    uint value = readUint64(buffer);
    // Get bit at position 0
    uint sign = value & 0x8000000000000000;
    // Get bits 1 to 12, then normalize to the [-1023, 1024] range so as to counterweight the IEEE 754 exponent bias
    int exponent = (int(value & 0x7ff0000000000000) >> 52) - 1023;
    // Get bits 6 to 15
    int fraction = int(value & 0x000fffffffffffff);
    // Add 2^52 to the fraction if exponent is not -1023
    if (exponent != -1023) {
      fraction |= 0x10000000000000;
    } else if (exponent == 1024) {
      revert(
        string(abi.encodePacked(
          "WitnetBuffer.readFloat64: ",
          sign != 0 ? "negative" : hex"",
          " infinity"
        ))
      );
    }
    // Compute `2 ^ exponent · (1 + fraction / 1024)`
    if (exponent >= 0) {
      result = (
        int(1 << uint(exponent))
          * (10 ** 15)
          * fraction
      ) >> 52;
    } else {
      result = (
        fraction 
          * (10 ** 15)
          / int(1 << uint(-exponent)) 
      ) >> 52;
    }
    // Make the result negative if the sign bit is not 0
    if (sign != 0) {
      result *= -1;
    }
  }

  // Read a text string of a given length from a buffer. Returns a `bytes memory` value for the sake of genericness,
  /// but it can be easily casted into a string with `string(result)`.
  // solium-disable-next-line security/no-assign-params
  function readText(
      WitnetBuffer.Buffer memory buffer,
      uint64 length
    )
    internal pure
    returns (bytes memory text)
  {
    text = new bytes(length);
    unchecked {
      for (uint64 index = 0; index < length; index ++) {
        uint8 char = readUint8(buffer);
        if (char & 0x80 != 0) {
          if (char < 0xe0) {
            char = (char & 0x1f) << 6
              | (readUint8(buffer) & 0x3f);
            length -= 1;
          } else if (char < 0xf0) {
            char  = (char & 0x0f) << 12
              | (readUint8(buffer) & 0x3f) << 6
              | (readUint8(buffer) & 0x3f);
            length -= 2;
          } else {
            char = (char & 0x0f) << 18
              | (readUint8(buffer) & 0x3f) << 12
              | (readUint8(buffer) & 0x3f) << 6  
              | (readUint8(buffer) & 0x3f);
            length -= 3;
          }
        }
        text[index] = bytes1(char);
      }
      // Adjust text to actual length:
      assembly {
        mstore(text, length)
      }
    }
  }

  /// @notice Read and consume the next byte from the buffer as an `uint8`.
  /// @param buffer An instance of `Buffer`.
  /// @return value The `uint8` value of the next byte in the buffer counting from the cursor position.
  function readUint8(Buffer memory buffer)
    internal pure
    withinRange(buffer.cursor, buffer.data.length)
    returns (uint8 value)
  {
    bytes memory data = buffer.data;
    uint offset = buffer.cursor;
    assembly {
      value := mload(add(add(data, 1), offset))
    }
    buffer.cursor ++;
  }

  /// @notice Read and consume the next 2 bytes from the buffer as an `uint16`.
  /// @param buffer An instance of `Buffer`.
  /// @return value The `uint16` value of the next 2 bytes in the buffer counting from the cursor position.
  function readUint16(Buffer memory buffer)
    internal pure
    withinRange(buffer.cursor + 2, buffer.data.length)
    returns (uint16 value)
  {
    bytes memory data = buffer.data;
    uint offset = buffer.cursor;
    assembly {
      value := mload(add(add(data, 2), offset))
    }
    buffer.cursor += 2;
  }

  /// @notice Read and consume the next 4 bytes from the buffer as an `uint32`.
  /// @param buffer An instance of `Buffer`.
  /// @return value The `uint32` value of the next 4 bytes in the buffer counting from the cursor position.
  function readUint32(Buffer memory buffer)
    internal pure
    withinRange(buffer.cursor + 4, buffer.data.length)
    returns (uint32 value)
  {
    bytes memory data = buffer.data;
    uint offset = buffer.cursor;
    assembly {
      value := mload(add(add(data, 4), offset))
    }
    buffer.cursor += 4;
  }

  /// @notice Read and consume the next 8 bytes from the buffer as an `uint64`.
  /// @param buffer An instance of `Buffer`.
  /// @return value The `uint64` value of the next 8 bytes in the buffer counting from the cursor position.
  function readUint64(Buffer memory buffer)
    internal pure
    withinRange(buffer.cursor + 8, buffer.data.length)
    returns (uint64 value)
  {
    bytes memory data = buffer.data;
    uint offset = buffer.cursor;
    assembly {
      value := mload(add(add(data, 8), offset))
    }
    buffer.cursor += 8;
  }

  /// @notice Read and consume the next 16 bytes from the buffer as an `uint128`.
  /// @param buffer An instance of `Buffer`.
  /// @return value The `uint128` value of the next 16 bytes in the buffer counting from the cursor position.
  function readUint128(Buffer memory buffer)
    internal pure
    withinRange(buffer.cursor + 16, buffer.data.length)
    returns (uint128 value)
  {
    bytes memory data = buffer.data;
    uint offset = buffer.cursor;
    assembly {
      value := mload(add(add(data, 16), offset))
    }
    buffer.cursor += 16;
  }

  /// @notice Read and consume the next 32 bytes from the buffer as an `uint256`.
  /// @param buffer An instance of `Buffer`.
  /// @return value The `uint256` value of the next 32 bytes in the buffer counting from the cursor position.
  function readUint256(Buffer memory buffer)
    internal pure
    withinRange(buffer.cursor + 32, buffer.data.length)
    returns (uint256 value)
  {
    bytes memory data = buffer.data;
    uint offset = buffer.cursor;
    assembly {
      value := mload(add(add(data, 32), offset))
    }
    buffer.cursor += 32;
  }

  /// @notice Count number of required parameters for given bytes arrays
  /// @dev Wildcard format: "\#\", with # in ["0".."9"].
  /// @param input Bytes array containing strings.
  /// @param count Highest wildcard index found, plus 1.
  function argsCountOf(bytes memory input)
    internal pure
    returns (uint8 count)
  {
    if (input.length < 3) {
      return 0;
    }
    unchecked {
      uint ix = 0; 
      uint length = input.length - 2;
      for (; ix < length; ) {
        if (
          input[ix] == bytes1("\\")
            && input[ix + 2] == bytes1("\\")
            && input[ix + 1] >= bytes1("0")
            && input[ix + 1] <= bytes1("9")
        ) {
          uint8 ax = uint8(uint8(input[ix + 1]) - uint8(bytes1("0")) + 1);
          if (ax > count) {
            count = ax;
          }
          ix += 3;
        } else {
          ix ++;
        }
      }
    }
  }

  /// @notice Replace indexed bytes-wildcards by correspondent substrings.
  /// @dev Wildcard format: "\#\", with # in ["0".."9"].
  /// @param input Bytes array containing strings.
  /// @param args Array of substring values for replacing indexed wildcards.
  /// @return output Resulting bytes array after replacing all wildcards.
  /// @return hits Total number of replaced wildcards.
  function replace(bytes memory input, string[] memory args)
    internal pure
    returns (bytes memory output, uint hits)
  {
    uint ix = 0; uint lix = 0;
    uint inputLength;
    uint inputPointer;
    uint outputLength;
    uint outputPointer;    
    uint source;
    uint sourceLength;
    uint sourcePointer;

    if (input.length < 3) {
      return (input, 0);
    }
    
    assembly {
      // set starting input pointer
      inputPointer := add(input, 32)
      // get safe output location
      output := mload(0x40)
      // set starting output pointer
      outputPointer := add(output, 32)
    }         

    unchecked {
      uint length = input.length - 2;
      for (; ix < length; ) {
        if (
          input[ix] == bytes1("\\")
            && input[ix + 2] == bytes1("\\")
            && input[ix + 1] >= bytes1("0")
            && input[ix + 1] <= bytes1("9")
        ) {
          inputLength = (ix - lix);
          if (ix > lix) {
            memcpy(
              outputPointer,
              inputPointer,
              inputLength
            );
            inputPointer += inputLength + 3;
            outputPointer += inputLength;
          } else {
            inputPointer += 3;
          }
          uint ax = uint(uint8(input[ix + 1]) - uint8(bytes1("0")));
          if (ax >= args.length) {
            revert MissingArgs(ax + 1, args.length);
          }
          assembly {
            source := mload(add(args, mul(32, add(ax, 1))))
            sourceLength := mload(source)
            sourcePointer := add(source, 32)      
          }        
          memcpy(
            outputPointer,
            sourcePointer,
            sourceLength
          );
          outputLength += inputLength + sourceLength;
          outputPointer += sourceLength;
          ix += 3;
          lix = ix;
          hits ++;
        } else {
          ix ++;
        }
      }
      ix = input.length;    
    }
    if (outputLength > 0) {
      if (ix > lix ) {
        memcpy(
          outputPointer,
          inputPointer,
          ix - lix
        );
        outputLength += (ix - lix);
      }
      assembly {
        // set final output length
        mstore(output, outputLength)
        // protect output bytes
        mstore(0x40, add(mload(0x40), add(outputLength, 32)))
      }
    }
    else {
      return (input, 0);
    }
  }

  /// @notice Replace indexed bytes-wildcard by given substring.
  /// @dev Wildcard format: "\#\", with # in ["0".."9"].
  /// @param input Bytes array containing strings.
  /// @param argIndex Index of the wildcard to be replaced.
  /// @param argValue Replacing substring to be used.
  /// @return output Resulting bytes array after replacing all wildcards.
  /// @return hits Total number of replaced wildcards.
  function replace(bytes memory input, uint8 argIndex, string memory argValue)
    internal pure
    returns (bytes memory output, uint hits)
  {
    uint ix = 0; uint lix = 0;
    uint inputLength;
    uint inputPointer;
    uint outputLength;
    uint outputPointer; 
    uint argValueLength;
    uint argValuePointer;

    if (input.length < 3) {
      return (input, 0);
    }
    
    assembly {
      // set starting input pointer
      inputPointer := add(input, 32)
      // get safe output location
      output := mload(0x40)
      // set starting output pointer
      outputPointer := add(output, 32)
      // set pointer to arg value substring
      argValuePointer := add(argValue, 32)
      // set arg value substring length
      argValueLength := mload(argValue)
    }         

    unchecked {
      uint length = input.length - 2;
      for (; ix < length; ) {
        if (
          input[ix] == bytes1("\\")
            && input[ix + 2] == bytes1("\\")
            && input[ix + 1] >= bytes1("0")
            && input[ix + 1] <= bytes1("9")
            && uint8(input[ix + 1]) - uint8(bytes1("0")) == argIndex
        ) {
          inputLength = (ix - lix);
          if (ix > lix) {
            memcpy(
              outputPointer,
              inputPointer,
              inputLength
            );
            inputPointer += inputLength + 3;
            outputPointer += inputLength;
          } else {
            inputPointer += 3;
          }
          memcpy(
            outputPointer,
            argValuePointer,
            argValueLength
          );
          outputLength += inputLength + argValueLength;
          outputPointer += argValueLength;
          ix += 3;
          lix = ix;
          hits ++;
        } else {
          ix ++;
        }
      }
      ix = input.length;    
    }
    if (outputLength > 0) {
      if (ix > lix ) {
        memcpy(
          outputPointer,
          inputPointer,
          ix - lix
        );
        outputLength += (ix - lix);
      }
      assembly {
        // set final output length
        mstore(output, outputLength)
        // protect output bytes
        mstore(0x40, add(mload(0x40), add(outputLength, 32)))
      }
    }
    else {
      return (input, 0);
    }
  }

  /// @notice Replace indexed string wildcards by correspondent substrings.
  /// @dev Wildcard format: "\#\", with # in ["0".."9"].
  /// @param input String potentially containing wildcards.
  /// @param args Array of substring values for replacing indexed wildcards.
  /// @return output Resulting string after replacing all wildcards.
  function replace(string memory input, string[] memory args)
    internal pure
    returns (string memory)
  {
    (bytes memory _outputBytes, ) = replace(bytes(input), args);
    return string(_outputBytes);
  }

  /// @notice Replace last indexed wildcard by given substring.
  /// @dev Wildcard format: "\#\", with # in ["0".."9"].
  /// @param input String potentially containing wildcards.
  /// @param argIndex Index of the wildcard to be replaced.
  /// @param argValue Replacing string to be used.
  /// @return output Resulting string after replacing all wildcards.
  function replace(string memory input, uint8 argIndex, string memory argValue)
    internal pure
    returns (string memory)
  {
    (bytes memory _outputBytes, ) = replace(bytes(input), argIndex, argValue);
    return string(_outputBytes);
  }

  /// @notice Move the inner cursor of the buffer to a relative or absolute position.
  /// @param buffer An instance of `Buffer`.
  /// @param offset How many bytes to move the cursor forward.
  /// @param relative Whether to count `offset` from the last position of the cursor (`true`) or the beginning of the
  /// buffer (`true`).
  /// @return The final position of the cursor (will equal `offset` if `relative` is `false`).
  // solium-disable-next-line security/no-assign-params
  function seek(
      Buffer memory buffer,
      uint offset,
      bool relative
    )
    internal pure
    withinRange(offset, buffer.data.length)
    returns (uint)
  {
    // Deal with relative offsets
    if (relative) {
      offset += buffer.cursor;
    }
    buffer.cursor = offset;
    return offset;
  }

  /// @notice Move the inner cursor a number of bytes forward.
  /// @dev This is a simple wrapper around the relative offset case of `seek()`.
  /// @param buffer An instance of `Buffer`.
  /// @param relativeOffset How many bytes to move the cursor forward.
  /// @return The final position of the cursor.
  function seek(
      Buffer memory buffer,
      uint relativeOffset
    )
    internal pure
    returns (uint)
  {
    return seek(
      buffer,
      relativeOffset,
      true
    );
  }

  /// @notice Copy bytes from one memory address into another.
  /// @dev This function was borrowed from Nick Johnson's `solidity-stringutils` lib, and reproduced here under the terms
  /// of [Apache License 2.0](https://github.com/Arachnid/solidity-stringutils/blob/master/LICENSE).
  /// @param dest Address of the destination memory.
  /// @param src Address to the source memory.
  /// @param len How many bytes to copy.
  // solium-disable-next-line security/no-assign-params
  function memcpy(
      uint dest,
      uint src,
      uint len
    )
    private pure
  {
    unchecked {
      // Copy word-length chunks while possible
      for (; len >= 32; len -= 32) {
        assembly {
          mstore(dest, mload(src))
        }
        dest += 32;
        src += 32;
      }
      if (len > 0) {
        // Copy remaining bytes
        uint _mask = 256 ** (32 - len) - 1;
        assembly {
          let srcpart := and(mload(src), not(_mask))
          let destpart := and(mload(dest), _mask)
          mstore(dest, or(destpart, srcpart))
        }
      }
    }
  }

}
WitnetCBOR.sol 583 lines
// SPDX-License-Identifier: MIT

pragma solidity >=0.8.0 <0.9.0;

import "./WitnetBuffer.sol";

/// @title A minimalistic implementation of “RFC 7049 Concise Binary Object Representation”
/// @notice This library leverages a buffer-like structure for step-by-step decoding of bytes so as to minimize
/// the gas cost of decoding them into a useful native type.
/// @dev Most of the logic has been borrowed from Patrick Gansterer’s cbor.js library: https://github.com/paroga/cbor-js
/// @author The Witnet Foundation.

library WitnetCBOR {

  using WitnetBuffer for WitnetBuffer.Buffer;
  using WitnetCBOR for WitnetCBOR.CBOR;

  /// Data struct following the RFC-7049 standard: Concise Binary Object Representation.
  struct CBOR {
      WitnetBuffer.Buffer buffer;
      uint8 initialByte;
      uint8 majorType;
      uint8 additionalInformation;
      uint64 len;
      uint64 tag;
  }

  uint8 internal constant MAJOR_TYPE_INT = 0;
  uint8 internal constant MAJOR_TYPE_NEGATIVE_INT = 1;
  uint8 internal constant MAJOR_TYPE_BYTES = 2;
  uint8 internal constant MAJOR_TYPE_STRING = 3;
  uint8 internal constant MAJOR_TYPE_ARRAY = 4;
  uint8 internal constant MAJOR_TYPE_MAP = 5;
  uint8 internal constant MAJOR_TYPE_TAG = 6;
  uint8 internal constant MAJOR_TYPE_CONTENT_FREE = 7;

  uint32 internal constant UINT32_MAX = type(uint32).max;
  uint64 internal constant UINT64_MAX = type(uint64).max;
  
  error EmptyArray();
  error InvalidLengthEncoding(uint length);
  error UnexpectedMajorType(uint read, uint expected);
  error UnsupportedPrimitive(uint primitive);
  error UnsupportedMajorType(uint unexpected);  

  modifier isMajorType(
      WitnetCBOR.CBOR memory cbor,
      uint8 expected
  ) {
    if (cbor.majorType != expected) {
      revert UnexpectedMajorType(cbor.majorType, expected);
    }
    _;
  }

  modifier notEmpty(WitnetBuffer.Buffer memory buffer) {
    if (buffer.data.length == 0) {
      revert WitnetBuffer.EmptyBuffer();
    }
    _;
  }

  function eof(CBOR memory cbor)
    internal pure
    returns (bool)
  {
    return cbor.buffer.cursor >= cbor.buffer.data.length;
  }

  /// @notice Decode a CBOR structure from raw bytes.
  /// @dev This is the main factory for CBOR instances, which can be later decoded into native EVM types.
  /// @param bytecode Raw bytes representing a CBOR-encoded value.
  /// @return A `CBOR` instance containing a partially decoded value.
  function fromBytes(bytes memory bytecode)
    internal pure
    returns (CBOR memory)
  {
    WitnetBuffer.Buffer memory buffer = WitnetBuffer.Buffer(bytecode, 0);
    return fromBuffer(buffer);
  }

  /// @notice Decode a CBOR structure from raw bytes.
  /// @dev This is an alternate factory for CBOR instances, which can be later decoded into native EVM types.
  /// @param buffer A Buffer structure representing a CBOR-encoded value.
  /// @return A `CBOR` instance containing a partially decoded value.
  function fromBuffer(WitnetBuffer.Buffer memory buffer)
    internal pure
    notEmpty(buffer)
    returns (CBOR memory)
  {
    uint8 initialByte;
    uint8 majorType = 255;
    uint8 additionalInformation;
    uint64 tag = UINT64_MAX;
    uint256 len;
    bool isTagged = true;
    while (isTagged) {
      // Extract basic CBOR properties from input bytes
      initialByte = buffer.readUint8();
      len ++;
      majorType = initialByte >> 5;
      additionalInformation = initialByte & 0x1f;
      // Early CBOR tag parsing.
      if (majorType == MAJOR_TYPE_TAG) {
        uint _cursor = buffer.cursor;
        tag = readLength(buffer, additionalInformation);
        len += buffer.cursor - _cursor;
      } else {
        isTagged = false;
      }
    }
    if (majorType > MAJOR_TYPE_CONTENT_FREE) {
      revert UnsupportedMajorType(majorType);
    }
    return CBOR(
      buffer,
      initialByte,
      majorType,
      additionalInformation,
      uint64(len),
      tag
    );
  }

  function fork(WitnetCBOR.CBOR memory self)
    internal pure
    returns (WitnetCBOR.CBOR memory)
  {
    return CBOR({
      buffer: self.buffer.fork(),
      initialByte: self.initialByte,
      majorType: self.majorType,
      additionalInformation: self.additionalInformation,
      len: self.len,
      tag: self.tag
    });
  }

  function settle(CBOR memory self)
      internal pure
      returns (WitnetCBOR.CBOR memory)
  {
    if (!self.eof()) {
      return fromBuffer(self.buffer);
    } else {
      return self;
    }
  }

  function skip(CBOR memory self)
      internal pure
      returns (WitnetCBOR.CBOR memory)
  {
    if (
      self.majorType == MAJOR_TYPE_INT
        || self.majorType == MAJOR_TYPE_NEGATIVE_INT
        || (
          self.majorType == MAJOR_TYPE_CONTENT_FREE 
            && self.additionalInformation >= 25
            && self.additionalInformation <= 27
        )
    ) {
      self.buffer.cursor += self.peekLength();
    } else if (
        self.majorType == MAJOR_TYPE_STRING
          || self.majorType == MAJOR_TYPE_BYTES
    ) {
      uint64 len = readLength(self.buffer, self.additionalInformation);
      self.buffer.cursor += len;
    } else if (
      self.majorType == MAJOR_TYPE_ARRAY
        || self.majorType == MAJOR_TYPE_MAP
    ) { 
      self.len = readLength(self.buffer, self.additionalInformation);      
    } else if (
       self.majorType != MAJOR_TYPE_CONTENT_FREE
        || (
          self.additionalInformation != 20
            && self.additionalInformation != 21
        )
    ) {
      revert("WitnetCBOR.skip: unsupported major type");
    }
    return self;
  }

  function peekLength(CBOR memory self)
    internal pure
    returns (uint64)
  {
    if (self.additionalInformation < 24) {
      return 0;
    } else if (self.additionalInformation < 28) {
      return uint64(1 << (self.additionalInformation - 24));
    } else {
      revert InvalidLengthEncoding(self.additionalInformation);
    }
  }

  function readArray(CBOR memory self)
    internal pure
    isMajorType(self, MAJOR_TYPE_ARRAY)
    returns (CBOR[] memory items)
  {
    // read array's length and move self cursor forward to the first array element:
    uint64 len = readLength(self.buffer, self.additionalInformation);
    items = new CBOR[](len + 1);
    for (uint ix = 0; ix < len; ix ++) {
      // settle next element in the array:
      self = self.settle();
      // fork it and added to the list of items to be returned:
      items[ix] = self.fork();
      if (self.majorType == MAJOR_TYPE_ARRAY) {
        CBOR[] memory _subitems = self.readArray();
        // move forward to the first element after inner array:
        self = _subitems[_subitems.length - 1];
      } else if (self.majorType == MAJOR_TYPE_MAP) {
        CBOR[] memory _subitems = self.readMap();
        // move forward to the first element after inner map:
        self = _subitems[_subitems.length - 1];
      } else {
        // move forward to the next element:
        self.skip();
      }
    }
    // return self cursor as extra item at the end of the list,
    // as to optimize recursion when jumping over nested arrays:
    items[len] = self;
  }

  function readMap(CBOR memory self)
    internal pure
    isMajorType(self, MAJOR_TYPE_MAP)
    returns (CBOR[] memory items)
  {
    // read number of items within the map and move self cursor forward to the first inner element:
    uint64 len = readLength(self.buffer, self.additionalInformation) * 2;
    items = new CBOR[](len + 1);
    for (uint ix = 0; ix < len; ix ++) {
      // settle next element in the array:
      self = self.settle();
      // fork it and added to the list of items to be returned:
      items[ix] = self.fork();
      if (ix % 2 == 0 && self.majorType != MAJOR_TYPE_STRING) {
        revert UnexpectedMajorType(self.majorType, MAJOR_TYPE_STRING);
      } else if (self.majorType == MAJOR_TYPE_ARRAY || self.majorType == MAJOR_TYPE_MAP) {
        CBOR[] memory _subitems = (self.majorType == MAJOR_TYPE_ARRAY
            ? self.readArray()
            : self.readMap()
        );
        // move forward to the first element after inner array or map:
        self = _subitems[_subitems.length - 1];
      } else {
        // move forward to the next element:
        self.skip();
      }
    }
    // return self cursor as extra item at the end of the list,
    // as to optimize recursion when jumping over nested arrays:
    items[len] = self;
  }

  /// Reads the length of the settle CBOR item from a buffer, consuming a different number of bytes depending on the
  /// value of the `additionalInformation` argument.
  function readLength(
      WitnetBuffer.Buffer memory buffer,
      uint8 additionalInformation
    ) 
    internal pure
    returns (uint64)
  {
    if (additionalInformation < 24) {
      return additionalInformation;
    }
    if (additionalInformation == 24) {
      return buffer.readUint8();
    }
    if (additionalInformation == 25) {
      return buffer.readUint16();
    }
    if (additionalInformation == 26) {
      return buffer.readUint32();
    }
    if (additionalInformation == 27) {
      return buffer.readUint64();
    }
    if (additionalInformation == 31) {
      return UINT64_MAX;
    }
    revert InvalidLengthEncoding(additionalInformation);
  }

  /// @notice Read a `CBOR` structure into a native `bool` value.
  /// @param cbor An instance of `CBOR`.
  /// @return The value represented by the input, as a `bool` value.
  function readBool(CBOR memory cbor)
    internal pure
    isMajorType(cbor, MAJOR_TYPE_CONTENT_FREE)
    returns (bool)
  {
    if (cbor.additionalInformation == 20) {
      return false;
    } else if (cbor.additionalInformation == 21) {
      return true;
    } else {
      revert UnsupportedPrimitive(cbor.additionalInformation);
    }
  }

  /// @notice Decode a `CBOR` structure into a native `bytes` value.
  /// @param cbor An instance of `CBOR`.
  /// @return output The value represented by the input, as a `bytes` value.   
  function readBytes(CBOR memory cbor)
    internal pure
    isMajorType(cbor, MAJOR_TYPE_BYTES)
    returns (bytes memory output)
  {
    cbor.len = readLength(
      cbor.buffer,
      cbor.additionalInformation
    );
    if (cbor.len == UINT32_MAX) {
      // These checks look repetitive but the equivalent loop would be more expensive.
      uint32 length = uint32(_readIndefiniteStringLength(
        cbor.buffer,
        cbor.majorType
      ));
      if (length < UINT32_MAX) {
        output = abi.encodePacked(cbor.buffer.read(length));
        length = uint32(_readIndefiniteStringLength(
          cbor.buffer,
          cbor.majorType
        ));
        if (length < UINT32_MAX) {
          output = abi.encodePacked(
            output,
            cbor.buffer.read(length)
          );
        }
      }
    } else {
      return cbor.buffer.read(uint32(cbor.len));
    }
  }

  /// @notice Decode a `CBOR` structure into a `fixed16` value.
  /// @dev Due to the lack of support for floating or fixed point arithmetic in the EVM, this method offsets all values
  /// by 5 decimal orders so as to get a fixed precision of 5 decimal positions, which should be OK for most `fixed16`
  /// use cases. In other words, the output of this method is 10,000 times the actual value, encoded into an `int32`.
  /// @param cbor An instance of `CBOR`.
  /// @return The value represented by the input, as an `int128` value.
  function readFloat16(CBOR memory cbor)
    internal pure
    isMajorType(cbor, MAJOR_TYPE_CONTENT_FREE)
    returns (int32)
  {
    if (cbor.additionalInformation == 25) {
      return cbor.buffer.readFloat16();
    } else {
      revert UnsupportedPrimitive(cbor.additionalInformation);
    }
  }

  /// @notice Decode a `CBOR` structure into a `fixed32` value.
  /// @dev Due to the lack of support for floating or fixed point arithmetic in the EVM, this method offsets all values
  /// by 9 decimal orders so as to get a fixed precision of 9 decimal positions, which should be OK for most `fixed64`
  /// use cases. In other words, the output of this method is 10^9 times the actual value, encoded into an `int`.
  /// @param cbor An instance of `CBOR`.
  /// @return The value represented by the input, as an `int` value.
  function readFloat32(CBOR memory cbor)
    internal pure
    isMajorType(cbor, MAJOR_TYPE_CONTENT_FREE)
    returns (int)
  {
    if (cbor.additionalInformation == 26) {
      return cbor.buffer.readFloat32();
    } else {
      revert UnsupportedPrimitive(cbor.additionalInformation);
    }
  }

  /// @notice Decode a `CBOR` structure into a `fixed64` value.
  /// @dev Due to the lack of support for floating or fixed point arithmetic in the EVM, this method offsets all values
  /// by 15 decimal orders so as to get a fixed precision of 15 decimal positions, which should be OK for most `fixed64`
  /// use cases. In other words, the output of this method is 10^15 times the actual value, encoded into an `int`.
  /// @param cbor An instance of `CBOR`.
  /// @return The value represented by the input, as an `int` value.
  function readFloat64(CBOR memory cbor)
    internal pure
    isMajorType(cbor, MAJOR_TYPE_CONTENT_FREE)
    returns (int)
  {
    if (cbor.additionalInformation == 27) {
      return cbor.buffer.readFloat64();
    } else {
      revert UnsupportedPrimitive(cbor.additionalInformation);
    }
  }

  /// @notice Decode a `CBOR` structure into a native `int128[]` value whose inner values follow the same convention 
  /// @notice as explained in `decodeFixed16`.
  /// @param cbor An instance of `CBOR`.
  function readFloat16Array(CBOR memory cbor)
    internal pure
    isMajorType(cbor, MAJOR_TYPE_ARRAY)
    returns (int32[] memory values)
  {
    uint64 length = readLength(cbor.buffer, cbor.additionalInformation);
    if (length < UINT64_MAX) {
      values = new int32[](length);
      for (uint64 i = 0; i < length; ) {
        CBOR memory item = fromBuffer(cbor.buffer);
        values[i] = readFloat16(item);
        unchecked {
          i ++;
        }
      }
    } else {
      revert InvalidLengthEncoding(length);
    }
  }

  /// @notice Decode a `CBOR` structure into a native `int128` value.
  /// @param cbor An instance of `CBOR`.
  /// @return The value represented by the input, as an `int128` value.
  function readInt(CBOR memory cbor)
    internal pure
    returns (int64)
  {
    if (cbor.majorType == 1) {
      uint64 _value = readLength(
        cbor.buffer,
        cbor.additionalInformation
      );
      return int64(-1) - int64(uint64(_value));
    } else if (cbor.majorType == 0) {
      // Any `uint64` can be safely casted to `int128`, so this method supports majorType 1 as well so as to have offer
      // a uniform API for positive and negative numbers
      return int64(readUint(cbor));
    }
    else {
      revert UnexpectedMajorType(cbor.majorType, 1);
    }
  }

  /// @notice Decode a `CBOR` structure into a native `int[]` value.
  /// @param cbor instance of `CBOR`.
  /// @return array The value represented by the input, as an `int[]` value.
  function readIntArray(CBOR memory cbor)
    internal pure
    isMajorType(cbor, MAJOR_TYPE_ARRAY)
    returns (int64[] memory array)
  {
    uint64 length = readLength(cbor.buffer, cbor.additionalInformation);
    if (length < UINT64_MAX) {
      array = new int64[](length);
      for (uint i = 0; i < length; ) {
        CBOR memory item = fromBuffer(cbor.buffer);
        array[i] = readInt(item);
        unchecked {
          i ++;
        }
      }
    } else {
      revert InvalidLengthEncoding(length);
    }
  }

  /// @notice Decode a `CBOR` structure into a native `string` value.
  /// @param cbor An instance of `CBOR`.
  /// @return text The value represented by the input, as a `string` value.
  function readString(CBOR memory cbor)
    internal pure
    isMajorType(cbor, MAJOR_TYPE_STRING)
    returns (string memory text)
  {
    cbor.len = readLength(cbor.buffer, cbor.additionalInformation);
    if (cbor.len == UINT64_MAX) {
      bool _done;
      while (!_done) {
        uint64 length = _readIndefiniteStringLength(
          cbor.buffer,
          cbor.majorType
        );
        if (length < UINT64_MAX) {
          text = string(abi.encodePacked(
            text,
            cbor.buffer.readText(length / 4)
          ));
        } else {
          _done = true;
        }
      }
    } else {
      return string(cbor.buffer.readText(cbor.len));
    }
  }

  /// @notice Decode a `CBOR` structure into a native `string[]` value.
  /// @param cbor An instance of `CBOR`.
  /// @return strings The value represented by the input, as an `string[]` value.
  function readStringArray(CBOR memory cbor)
    internal pure
    isMajorType(cbor, MAJOR_TYPE_ARRAY)
    returns (string[] memory strings)
  {
    uint length = readLength(cbor.buffer, cbor.additionalInformation);
    if (length < UINT64_MAX) {
      strings = new string[](length);
      for (uint i = 0; i < length; ) {
        CBOR memory item = fromBuffer(cbor.buffer);
        strings[i] = readString(item);
        unchecked {
          i ++;
        }
      }
    } else {
      revert InvalidLengthEncoding(length);
    }
  }

  /// @notice Decode a `CBOR` structure into a native `uint64` value.
  /// @param cbor An instance of `CBOR`.
  /// @return The value represented by the input, as an `uint64` value.
  function readUint(CBOR memory cbor)
    internal pure
    isMajorType(cbor, MAJOR_TYPE_INT)
    returns (uint64)
  {
    return readLength(
      cbor.buffer,
      cbor.additionalInformation
    );
  }

  /// @notice Decode a `CBOR` structure into a native `uint64[]` value.
  /// @param cbor An instance of `CBOR`.
  /// @return values The value represented by the input, as an `uint64[]` value.
  function readUintArray(CBOR memory cbor)
    internal pure
    isMajorType(cbor, MAJOR_TYPE_ARRAY)
    returns (uint64[] memory values)
  {
    uint64 length = readLength(cbor.buffer, cbor.additionalInformation);
    if (length < UINT64_MAX) {
      values = new uint64[](length);
      for (uint ix = 0; ix < length; ) {
        CBOR memory item = fromBuffer(cbor.buffer);
        values[ix] = readUint(item);
        unchecked {
          ix ++;
        }
      }
    } else {
      revert InvalidLengthEncoding(length);
    }
  }  

  /// Read the length of a CBOR indifinite-length item (arrays, maps, byte strings and text) from a buffer, consuming
  /// as many bytes as specified by the first byte.
  function _readIndefiniteStringLength(
      WitnetBuffer.Buffer memory buffer,
      uint8 majorType
    )
    private pure
    returns (uint64 len)
  {
    uint8 initialByte = buffer.readUint8();
    if (initialByte == 0xff) {
      return UINT64_MAX;
    }
    len = readLength(
      buffer,
      initialByte & 0x1f
    );
    if (len >= UINT64_MAX) {
      revert InvalidLengthEncoding(len);
    } else if (majorType != (initialByte >> 5)) {
      revert UnexpectedMajorType((initialByte >> 5), majorType);
    }
  }
 
}
WitnetERC20.sol 614 lines
// SPDX-License-Identifier: MIT
// Compatible with OpenZeppelin Contracts ^5.0.0
pragma solidity >=0.8.20 <0.9.0;

import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import {ERC20Bridgeable} from "@openzeppelin/contracts/token/ERC20/extensions/draft-ERC20Bridgeable.sol";
import {ERC20Permit} from "@openzeppelin/contracts/token/ERC20/extensions/ERC20Permit.sol";
import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import {ReentrancyGuard} from "@openzeppelin/contracts/utils/ReentrancyGuard.sol";

import "witnet-solidity-bridge/contracts/WitOracle.sol";

import {
    IWitOracleRadonRequestModal,
    IWitOracleRadonRequestFactory
} from "witnet-solidity-bridge/contracts/WitOracleRadonRequestFactory.sol";

import {IWitOracleConsumer} from "witnet-solidity-bridge/contracts/interfaces/IWitOracleConsumer.sol";
import {IWitOracleQueriableConsumer} from "witnet-solidity-bridge/contracts/interfaces/IWitOracleQueriableConsumer.sol";

import {IWitnetMintableERC20, WitnetERC20Lib} from "./libs/WitnetERC20Lib.sol";

/// @custom:security-contact [email protected]
contract WitnetERC20
    is 
        ERC20,
        ERC20Bridgeable,
        ERC20Permit,
        Initializable,
        IWitnetMintableERC20,
        IWitOracleConsumer,
        IWitOracleQueriableConsumer,
        ReentrancyGuard
{
    using Witnet for Witnet.Address;
    using Witnet for Witnet.RadonHash;

    uint256 internal constant _CANONICAL_CHAIN_ID = 1; // Ethereum Mainnet
    uint8   internal constant _DECIMALS = 9;
    uint256 internal constant _MIN_UNWRAPPABLE_NANOWITS = 1_000_000_000; // 1.0 $WIT
    address internal constant _SUPERCHAIN_TOKEN_BRIDGE = 0x4200000000000000000000000000000000000028; // Superchain default bridge
    
    uint16 internal constant _WIT_ORACLE_REPORTS_MIN_MIN_WITNESSES = 3;
    uint16 internal constant _WIT_ORACLE_QUERIABLE_CONSUMER_MAX_EXTRA_FEE_PERCENTAGE = 50;
    uint64 internal constant _WIT_ORACLE_QUERIABLE_CONSUMER_MIN_UNITARY_REWARD = 200_000_000; // 0.2 $WIT
    uint24 internal constant _WIT_ORACLE_QUERIABLE_CONSUMER_MIN_RESPONSE_CALLBACK_GAS = 210_000;
    
    WitOracle public immutable witOracle;
    IWitOracleRadonRequestModal public immutable witOracleCrossChainProofOfReserveTemplate;
    IWitOracleRadonRequestModal public immutable witOracleCrossChainProofOfInclusionTemplate;
    
    Witnet.Address internal immutable __witCustodianWrapper;
    bytes32 internal immutable __witCustodianWrapperBech32Hash;

    modifier onlyCurator {
        _require(
            _msgSender() == __storage().curator, 
            "unauthorized"
        ); _;
    }

    modifier whenWitnetBurnsNotPaused {
        _require(
            !__storage().pausedWitnetBurns,
            "paused burns"
        ); _;
    }

    modifier whenWitnetMintsNotPaused {
        _require(
            !__storage().pausedWitnetMints,
            "paused mints"
        ); _;
    }

    constructor(
            IWitOracleRadonRequestFactory _witOracleRadonRequestFactory,
            string memory _witCustodianBech32
        )
        ERC20("Witnet", "WIT")
        ERC20Permit("Witnet")
    {
        // Settle immutable parameters --------------------------------------------------------------------------------
        __witCustodianWrapper = Witnet.fromBech32(_witCustodianBech32, block.chainid == _CANONICAL_CHAIN_ID);
        __witCustodianWrapperBech32Hash = keccak256(bytes(_witCustodianBech32));

        witOracle = WitOracle(IWitOracleAppliance(address(_witOracleRadonRequestFactory)).witOracle());

        string[2][] memory _httpRequestHeaders = new string[2][](1);
        _httpRequestHeaders[0] = [ "Content-Type", "application/json;charset=UTF-8" ];
        witOracleCrossChainProofOfReserveTemplate = _witOracleRadonRequestFactory.buildRadonRequestModal(
            IWitOracleRadonRequestFactory.DataSourceRequest({
                method: Witnet.RadonRetrievalMethods.HttpPost,
                body: '{"jsonrpc":"2.0","method":"getBalance2","params":{"pkh":"\\0\\;\\1\\"},"id":1}',
                headers: _httpRequestHeaders,
                script: // [RadonString] parseJSONMap()
                        // [RadonMap]    getMap("result")
                        // [RadonArray]  values()
                        hex"83187782186666726573756c741869" 
            }),
            Witnet.RadonReducer({
                opcode: Witnet.RadonReduceOpcodes.Mode,
                filters: new Witnet.RadonFilter[](0)
            })
        );
        witOracleCrossChainProofOfInclusionTemplate = _witOracleRadonRequestFactory.buildRadonRequestModal(
            IWitOracleRadonRequestFactory.DataSourceRequest({
                method: Witnet.RadonRetrievalMethods.HttpPost,
                body: '{"jsonrpc":"2.0","method":"getValueTransfer","params":{"hash":"\\0\\","mode":"ethereal","force":true},"id":1}',
                headers: _httpRequestHeaders,         
                script: // [RadonString] parseJSONMap()
                        // [RadonMap]    getMap("result")
                        // [RadonArray]  values()
                        hex"83187782186666726573756c741869"
            }),
            Witnet.RadonReducer({
                opcode: Witnet.RadonReduceOpcodes.Mode,
                filters: new Witnet.RadonFilter[](0)
            })
        );
    }

    function initialize(
            address _curator,
            string calldata _witCustodianUnwrapperBech32
        ) 
        external 
        initializer
    {
        // Initialize curatorship:
        __storage().curator = _curator;
        emit CuratorshipTransferred(address(0), _curator);
        
        // Initialize default parameters:
        __storage().bridge = _SUPERCHAIN_TOKEN_BRIDGE;
        __storage().witOracleQuerySettings = WitOracleSettings({
            minWitnesses: block.chainid == _CANONICAL_CHAIN_ID ? 12 : _WIT_ORACLE_REPORTS_MIN_MIN_WITNESSES,
            extraFeePercentage: 5, // 5 %
            unitaryRewardNanowits: _WIT_ORACLE_QUERIABLE_CONSUMER_MIN_UNITARY_REWARD,
            responseCallbackGasLimit: _WIT_ORACLE_QUERIABLE_CONSUMER_MIN_RESPONSE_CALLBACK_GAS
        });
        string[] memory _witOracleRpcProviders = new string[](1);
        _witOracleRpcProviders[0] = (
            block.chainid == _CANONICAL_CHAIN_ID 
                ? "https://rpc-01.witnet.io" 
                : "https://rpc-testnet.witnet.io"
        );
        __storage().witOracleCrossChainRpcProviders = _witOracleRpcProviders;

        // Settle Wit/ Unwrapper address and formally verify parameterized Radon assets:
        __settleWitCustodianUnwrapper(_witCustodianUnwrapperBech32);
    }

 
    /// ===============================================================================================================
    /// --- ERC20 -----------------------------------------------------------------------------------------------------

    function decimals() override public pure returns (uint8) {
        return _DECIMALS;
    }


    /// ===============================================================================================================
    /// --- ERC20Bridgeable -------------------------------------------------------------------------------------------

    function _checkTokenBridge(address caller) override internal view {
        _require(
            caller == __storage().bridge,
            "unauthorized bridge"
        );
        _require(
            !__storage().pausedBridge,
            "paused bridge"
        );
    }


    /// ===============================================================================================================
    /// --- Wrapped/WIT read-only methods -----------------------------------------------------------------------------
    
    function bridge() override external view returns (address) {
        return __storage().bridge;
    }

    function curator() override external view returns (address) {
        return __storage().curator;
    }

    function getWrapTransactionLastQueryId(Witnet.TransactionHash _witnetValueTransferTransactionHash)
        override external view 
        returns (uint256)
    {
        return __storage().witOracleWrappingTransactionLastQueryId[_witnetValueTransferTransactionHash];
    }

    function getWrapTransactionStatus(Witnet.TransactionHash _witnetValueTransferTransactionHash) 
        override public view 
        returns (WrappingStatus)
    {
        uint256 _witOracleLastQueryId = __storage().witOracleWrappingTransactionLastQueryId[
            _witnetValueTransferTransactionHash
        ];
        if (_witOracleLastQueryId == 0) {
            return WrappingStatus.Unknown;
        
        } else if (_witOracleLastQueryId == WitnetERC20Lib._WIT_ORACLE_QUERIABLE_CONSUMER_CALLBACK_PROCESSED) {
            return WrappingStatus.Done;
        
        } else {
            return (
                witOracle.getQueryStatus(_witOracleLastQueryId) == Witnet.QueryStatus.Posted
                ? WrappingStatus.Awaiting
                : WrappingStatus.Retry
            );
        }
    }

    function getWrapTransactionStatuses(Witnet.TransactionHash[] calldata _hashes)
        override external view
        returns (WrappingStatus[] memory _statuses)
    {
        _statuses = new WrappingStatus[](_hashes.length);
        for (uint256 _ix = 0; _ix < _hashes.length; ++ _ix) {
            _statuses[_ix] = getWrapTransactionStatus(_hashes[_ix]);
        }
    }

    function minUnwrappableNanowits()
        override external pure
        returns (uint256)
    {
        return _MIN_UNWRAPPABLE_NANOWITS;
    }

    function paused()
        override external view
        returns (bool, bool, bool)
    {
        return (
            __storage().pausedBridge,
            __storage().pausedWitnetBurns,
            __storage().pausedWitnetMints
        );
    }

    function totalReserveNanowits() override external view returns (uint256) {
        return __storage().evmLastReserveNanowits;
    }

    function totalUnwrappings() override external view returns (uint256) {
        return __storage().evmUnwrappings;
    }

    function totalUnwraps() override external view returns (uint256) {
        return __storage().evmUnwraps;
    }

    function totalWrappings() override external view returns (uint256) {
        return __storage().evmWrappings;
    }
    
    function totalWraps() override external view returns (uint256) {
        return __storage().evmWraps;
    }

    function witCustodianWrapper() override public view returns (string memory) {
        return __witCustodianWrapper.toBech32(block.chainid == _CANONICAL_CHAIN_ID);
    }

    function witCustodianUnwrapper() override public view returns (string memory) {
        return __storage().witCustodianUnwrapper.toBech32(block.chainid == _CANONICAL_CHAIN_ID);
    }

    function witOracleCrossChainRpcProviders() override external view returns (string[] memory) {
        return __storage().witOracleCrossChainRpcProviders;
    }

    function witOracleEstimateWrappingFee(uint256 evmGasPrice) override external view returns (uint256) {
        return WitnetERC20Lib.witOracleEstimateWrappingFee(
            witOracle, 
            evmGasPrice
        );
    }

    function witOracleProofOfReserveLastUpdate() override external view returns (Witnet.Timestamp) {
        return __storage().evmLastReserveTimestamp;
    }

    function witOracleProofOfReserveRadonBytecode() override external view returns (bytes memory) {
        return witOracle
            .registry()
            .lookupRadonRequestBytecode(
                __storage().witOracleProofOfReserveRadonHash
            );
    }

    function witOracleProofOfReserveRadonHash() override external view returns (Witnet.RadonHash) {
        return __storage().witOracleProofOfReserveRadonHash;
    }

    function witOracleQuerySettings() override external view returns (WitOracleSettings memory) {
        return __storage().witOracleQuerySettings;
    }


    /// ===============================================================================================================
    /// --- Wrapped/WIT authoritative methods -------------------------------------------------------------------------

    function crosschainPause(
            bool _erc7802,
            bool _witnetBurns,
            bool _witnetMints
        )
        external
        onlyCurator
    {
        __storage().pausedBridge = _erc7802;
        __storage().pausedWitnetBurns = _witnetBurns;
        __storage().pausedWitnetMints = _witnetMints;
        emit PauseFlags(msg.sender, _erc7802, _witnetBurns, _witnetMints);
    }

    function settleBridge(address _newBridge)
        external
        onlyCurator
    {
        _require(_newBridge != address(0), "zero bridge");
        emit SettledBridge(msg.sender, __storage().bridge, _newBridge);
        __storage().bridge = _newBridge;
    }

    function settleWitOracleCrossChainRpcProviders(string[] memory _witRpcProviders)
        external
        onlyCurator
    {
        _require(_witRpcProviders.length > 0, "empty rpc providers");
        __storage().witOracleCrossChainRpcProviders = _witRpcProviders;
        __formallyVerifyRadonAssets(
            _witRpcProviders, 
            __storage().witCustodianUnwrapper.toBech32(block.chainid == _CANONICAL_CHAIN_ID)
        );
        emit WitRpcProvidersChanged(msg.sender, _witRpcProviders);
    }

    function settleWitOracleSettings(WitOracleSettings calldata _settings)
        external
        onlyCurator
    {
        _require(
            _settings.minWitnesses >= _WIT_ORACLE_REPORTS_MIN_MIN_WITNESSES
                && _settings.extraFeePercentage <= _WIT_ORACLE_QUERIABLE_CONSUMER_MAX_EXTRA_FEE_PERCENTAGE
                && _settings.unitaryRewardNanowits >= _WIT_ORACLE_QUERIABLE_CONSUMER_MIN_UNITARY_REWARD
                && _settings.responseCallbackGasLimit >= _WIT_ORACLE_QUERIABLE_CONSUMER_MIN_RESPONSE_CALLBACK_GAS,
            "invalid settings"
        );
        __storage().witOracleQuerySettings = _settings;
    }

    function settleWitCustodianUnwrapper(string calldata _witCustodianUnwrapperBech32)
        external
        onlyCurator
    {
        __settleWitCustodianUnwrapper(_witCustodianUnwrapperBech32);
    }

    function transferCuratorship(address _newCurator)
        external 
        onlyCurator
    {
        _require(_newCurator != address(0), "zero curator");
        emit CuratorshipTransferred(__storage().curator, _newCurator);
        __storage().curator = _newCurator;
    }

    
    /// ===============================================================================================================
    /// --- Wrapped/WIT permissionless wrap/unwrap operations ---------------------------------------------------------

    function wrap(Witnet.TransactionHash _witnetValueTransferTransactionHash)
        override public payable
        nonReentrant
        whenWitnetMintsNotPaused
        returns (uint256 _witOracleQueryId)
    {
        // Fee sanity checks are perfomed by the underlying WitOracle contract, so providing
        // a `msg.value` smaller than by `witOracleEstimateWrappingFee(tx.gasprice)`,
        // or 10x greater than, would make this transaction to revert.

        _witOracleQueryId = WitnetERC20Lib.witOracleQueryWitnetValueTransferProofOfInclusion(
            witOracle,
            witOracleCrossChainProofOfInclusionTemplate,
            _witnetValueTransferTransactionHash
        );
        _require(
            _witOracleQueryId != WitnetERC20Lib._WIT_ORACLE_QUERIABLE_CONSUMER_CALLBACK_PROCESSED, 
            "already minted"
        );
    }

    function unwrap(uint64 value, string calldata witRecipientBech32)
        override external
        whenWitnetBurnsNotPaused
        returns (uint256 evmUnwrapId)
    {
        _require(
            balanceOf(_msgSender()) >= value,
            "not enough balance"
        );
        uint64 _evmLastReserveNanowits = __storage().evmLastReserveNanowits;
        _require(
            value <= _evmLastReserveNanowits,
            "cannot unwrap that much"
        );
        _require(
            value >= _MIN_UNWRAPPABLE_NANOWITS,
            "cannot unwrap that little"
        );
        Witnet.Address _recipient = Witnet.fromBech32(
            witRecipientBech32, 
            block.chainid == _CANONICAL_CHAIN_ID
        );
        _require(
            !_recipient.eq(__witCustodianWrapper)
                && !_recipient.eq(__storage().witCustodianUnwrapper),
            "invalid recipient"
        );

        // immediate reduction of reserve supply:
        __storage().evmLastReserveNanowits = _evmLastReserveNanowits - value;

        // immediate burning of wrapped wit tokens:
        _burn(_msgSender(), value);

        // increase unwrapping meters:
        evmUnwrapId = ++ __storage().evmUnwraps;
        __storage().evmUnwrappings += value;

        // emit events
        emit Unwrapped(
            _msgSender(), 
            witRecipientBech32, 
            value, 
            evmUnwrapId
        );
    }

    
    /// ===============================================================================================================
    /// --- Implementation of IWitOracleQueriableConsumer -------------------------------------------------------------

    /// @notice Determines if Wit/Oracle query results can be reported from the given address.
    function reportableFrom(address _from) override public view returns (bool) {
        return address(_from) == address(witOracle);
    }

    /// @notice Method called from the WitOracle as soon as the specified `queryId` gets reported from the Witnet blockchain.
    /// @param queryId The unique identifier of the Witnet query being reported.
    /// @param queryResult Abi-encoded Witnet.DataResult containing the CBOR-encoded query's result, and metadata.
    function reportWitOracleQueryResult(
            uint256 queryId,
            bytes calldata queryResult
        )
        override external 
        nonReentrant
    {
        _require(reportableFrom(msg.sender), "invalid oracle");

        try WitnetERC20Lib.processWitOracleQueryResult(
            queryId, 
            queryResult
        
        ) returns (
            Witnet.TransactionHash _witValueTransferTransactionHash,
            string memory _witRecipientBech32,
            string memory _witSenderBech32,
            address _evmRecipient,
            uint64 _value
        ) {
            _require(
                keccak256(bytes(_witRecipientBech32)) == __witCustodianWrapperBech32Hash,
                "invalid custodian"
            );

            // mint newly wrapped tokens:
            _mint(_evmRecipient, _value);

            // emit events:
            emit Wrapped(
                _witSenderBech32, 
                _evmRecipient, 
                _value, 
                _witValueTransferTransactionHash
            );

        } catch Error(string memory _reason) {
            _revert(_reason);
        
        } catch (bytes memory) {
            _revertUnhandled();
        }
    }


    /// ===============================================================================================================
    /// --- Implementation of IWitOracleConsumer ----------------------------------------------------------------------

    /// @notice Process canonical Proof-of-Reserve reports from the Wit/Oracle blockchain, permissionlessly.    
    function pushDataReport(
            Witnet.DataPushReport calldata report, 
            bytes calldata proof
        )
        override external
        nonReentrant
    {
        _require(
            report.queryParams.witCommitteeSize >= __storage().witOracleQuerySettings.minWitnesses,
            "insufficient witnesses"
        );
        
        _require(
            report.queryRadHash.eq(__storage().witOracleProofOfReserveRadonHash),
            "invalid radon hash"
        );

        // Ask the Wit/Oracle to validate and parse the posted query's result: 
        Witnet.DataResult memory _witOracleProofOfReserve = witOracle
            .pushDataReport(
                report,
                proof
            );

        // Parse expected integer from the posted query's result:
        try WitnetERC20Lib.parseWitOracleProofOfReserve(
            _witOracleProofOfReserve
        
        ) returns (
            uint64 _totalReserve
        
        ) {
            emit ReserveUpdate(
                _totalReserve, 
                _witOracleProofOfReserve.timestamp,
                _witOracleProofOfReserve.drTxHash 
            );
            __storage().evmLastReserveNanowits = _totalReserve;
            __storage().evmLastReserveTimestamp = _witOracleProofOfReserve.timestamp;

        } catch Error(string memory _reason) {
            _revert(_reason);
        
        } catch (bytes memory) {
            _revertUnhandled();
        }
    }


    /// ===============================================================================================================
    /// --- Internal methods ------------------------------------------------------------------------------------------

    /// @dev Formally verify cross-chain Radon request for notarizing custodian's proofs of reserve.
    function __formallyVerifyRadonAssets(
            string[] memory _witRpcProviders,
            string memory _witCustodianUnwrapperBech32
        )
        internal
    {    
        string[] memory _commonArgs = new string[](2);
        _commonArgs[0] = witCustodianWrapper();
        _commonArgs[1] = _witCustodianUnwrapperBech32;
        __storage().witOracleProofOfReserveRadonHash = witOracleCrossChainProofOfReserveTemplate
            .verifyRadonRequest(
                _commonArgs,
                _witRpcProviders
            );
    }

    function _require(bool condition, string memory reason) internal pure {
        if (!condition) {
            _revert(reason);
        }
    }

    function _revert(string memory reason) internal pure {
        revert(
            string(abi.encodePacked(
                "WitnetERC20: ",
                reason
            ))
        );
    }

    function _revertUnhandled() internal pure {
        _revert("unhandled exception");
    }

    function __settleWitCustodianUnwrapper(string memory _witCustodianUnwrapperBech32)
        internal
    {
        _require(
            keccak256(bytes(_witCustodianUnwrapperBech32)) != __witCustodianWrapperBech32Hash,
            "unacceptable unwrapper"
        );
        emit NewCustodianUnwrapper(msg.sender, _witCustodianUnwrapperBech32);
        __storage().witCustodianUnwrapper = Witnet.fromBech32(_witCustodianUnwrapperBech32, block.chainid == _CANONICAL_CHAIN_ID);
        __formallyVerifyRadonAssets(
            __storage().witOracleCrossChainRpcProviders,
            _witCustodianUnwrapperBech32
        );
    }

    function __storage() internal pure returns (WitnetERC20Lib.Storage storage) {
        return WitnetERC20Lib.data();
    }
}
IWitnetMintableERC20.sol 77 lines
// SPDX-License-Identifier: MIT

pragma solidity >=0.8.20 <0.9.0;

import "witnet-solidity-bridge/contracts/WitOracle.sol";

interface IWitnetMintableERC20 {

    event CuratorshipTransferred(address indexed evmPrevCurator, address indexed evmNewCurator);
    event NewCustodianUnwrapper(address curator, string witCustodianUnwrapper);
    event PauseFlags(address curator, bool erc7802, bool witnetBurns, bool witnetMints);
    event ReserveUpdate(uint256 value, Witnet.Timestamp timestamp, Witnet.TransactionHash indexed witDrTxHash);
    event SettledBridge(address curator, address from, address into);
    event WitRpcProvidersChanged(address curator, string[] witRpcProviders);
    event Wrapped(string witSender, address indexed evmRecipient, uint256 value, Witnet.TransactionHash witVttHash);
    event Unwrapped(address indexed evmSender, string witRecipient, uint256 value, uint256 nonce);

    struct WitOracleSettings {
        uint16 minWitnesses;
        uint16 extraFeePercentage;
        uint64 unitaryRewardNanowits;
        uint24 responseCallbackGasLimit;
    }

    enum WrappingStatus {
        Unknown,
        Awaiting,
        Retry,
        Done
    }

    // ====================================================================================================================
    /// --- Read-only methods ---------------------------------------------------------------------------------------------
    
    function bridge() external view returns (address);
    function curator() external view returns (address);
    
    function getWrapTransactionLastQueryId(Witnet.TransactionHash) external view returns (uint256);
    function getWrapTransactionStatus(Witnet.TransactionHash) external view returns (WrappingStatus);
    function getWrapTransactionStatuses(Witnet.TransactionHash[] calldata) external view returns (WrappingStatus[] memory);

    function minUnwrappableNanowits() external view returns (uint256);

    function paused() external view returns (bool bridge, bool witnetBurns, bool witnetMints);
    
    function totalReserveNanowits() external view returns (uint256);
    function totalUnwrappings() external view returns (uint256);
    function totalUnwraps() external view returns (uint256);
    function totalWrappings() external view returns (uint256);
    function totalWraps()   external view returns (uint256);
    
    function witCustodianWrapper() external view returns (string memory);
    function witCustodianUnwrapper() external view returns (string memory);

    function witOracleCrossChainRpcProviders() external view returns (string[] memory);
    function witOracleEstimateWrappingFee(uint256) external view returns (uint256);
    function witOracleProofOfReserveLastUpdate() external view returns (Witnet.Timestamp);
    function witOracleProofOfReserveRadonBytecode() external view returns (bytes memory);
    function witOracleProofOfReserveRadonHash() external view returns (Witnet.RadonHash);
    function witOracleQuerySettings() external view returns (WitOracleSettings memory);
    
    /// ===================================================================================================================    
    /// --- Authoritative methods -----------------------------------------------------------------------------------------
    
    function crosschainPause(bool erc7802, bool witnetBurns, bool witnetMints) external;
    function settleBridge(address) external;
    function settleWitCustodianUnwrapper(string calldata) external;
    function settleWitOracleCrossChainRpcProviders(string[] memory) external;
    function settleWitOracleSettings(WitOracleSettings calldata) external;
    function transferCuratorship(address) external;

    /// ====================================================================================================================
    // --- Permissionless state-modifying methods --------------------------------------------------------------------------
    
    function wrap(Witnet.TransactionHash witTxHash) external payable returns (uint256 witOracleQueryId);
    function unwrap(uint64, string calldata) external returns (uint256 evmUnwrapId);
}
WitnetERC20Lib.sol 213 lines
// SPDX-License-Identifier: MIT

pragma solidity >=0.8.20 <0.9.0;

import "../interfaces/IWitnetMintableERC20.sol";
import {IWitOracleRadonRequestModal} from "witnet-solidity-bridge/contracts/WitOracleRadonRequestFactory.sol";

/// @title Witnet Request Board base data model library
/// @author The Witnet Foundation.
library WitnetERC20Lib {  

    using Witnet for Witnet.DataResult;
    using Witnet for Witnet.Timestamp;
    using WitnetCBOR for WitnetCBOR.CBOR;
    
    bytes32 internal constant _WRAPPED_WIT_STORAGE_SLOT =
        /* keccak256("io.witnet.tokens.WIT") & ~bytes32(uint256(0xff) */
        0x6116473658e87b023e7f215d122c0048f3d7a669d8df94a5565f0c95871c5800;

    uint256 internal constant _WIT_ORACLE_QUERIABLE_CONSUMER_CALLBACK_PROCESSED = type(uint256).max;
    uint16  internal constant _WIT_ORACLE_QUERIABLE_CONSUMER_MAX_RESULT_SIZE = 256;

    struct Storage {
        address bridge; bool pausedBridge; uint88 _0;
        address curator; uint96 _1;
        
        Witnet.Timestamp evmLastReserveTimestamp;
        uint64 evmLastReserveNanowits; 
        uint96 evmWrappings;
        uint24 evmWraps;
        bool   pausedWitnetMints;

        Witnet.Address witCustodianUnwrapper;
        uint64 evmUnwrappings;
        uint24 evmUnwraps;
        bool   pausedWitnetBurns;
        
        IWitnetMintableERC20.WitOracleSettings witOracleQuerySettings;
        
        string[] witOracleCrossChainRpcProviders;
        Witnet.RadonHash witOracleProofOfReserveRadonHash;
        
        mapping (Witnet.TransactionHash => uint256) witOracleWrappingTransactionLastQueryId;
        mapping (uint256 => Witnet.TransactionHash) witOracleWrappingQueryTransactionHash;
    }

    
    // ================================================================================================================
    // --- Public functions -------------------------------------------------------------------------------------------

    function parseWitOracleProofOfReserve(Witnet.DataResult memory witOracleProofOfReserve)
        external view
        returns (uint64)
    {
        uint64[] memory _witBalance;
        if (witOracleProofOfReserve.status == Witnet.ResultStatus.NoErrors) {
            _witBalance = witOracleProofOfReserve.fetchUint64Array();
        }
        require(
            witOracleProofOfReserve.status == Witnet.ResultStatus.NoErrors
                && witOracleProofOfReserve.timestamp.gt(data().evmLastReserveTimestamp)
                && _witBalance.length >= 3,
            "invalid report"
        );
        return (
            _witBalance[0]
                + _witBalance[1]
                + _witBalance[2]
        );
    }

    function processWitOracleQueryResult(
            uint256 witOracleQueryId,
            bytes calldata witOracleQueryResult
        )
        external
        returns (
            Witnet.TransactionHash _witValueTransferTransactionHash,
            string memory _witRecipientBech32,
            string memory _witSenderBech32,
            address _evmRecipient,
            uint64 _value
        )
    {
        _witValueTransferTransactionHash = data().witOracleWrappingQueryTransactionHash[witOracleQueryId];

        // Check that the query id actually refers to a wit/wrap tx that's being validated:
        require(
            Witnet.TransactionHash.unwrap(_witValueTransferTransactionHash) != bytes32(0), 
            "invalid query id"
        );

        // Check that the Wit/wrap tx being reported has not yet been validated:
        require(
            data().witOracleWrappingTransactionLastQueryId[_witValueTransferTransactionHash]
                != _WIT_ORACLE_QUERIABLE_CONSUMER_CALLBACK_PROCESSED, 
            "wit/wrap tx already minted"
        );

        // Deserialize the query's result data:
        Witnet.DataResult memory _witOracleQueryResult = abi.decode(witOracleQueryResult, (Witnet.DataResult));
        
        // Check that the query was successfully solved:
        require(
            _witOracleQueryResult.status == Witnet.ResultStatus.NoErrors,
            "query solved with errors"
        );
        
        // Check that the query result contains an heterogenous array of values:
        require(
            _witOracleQueryResult.dataType == Witnet.RadonDataTypes.Array, 
            "invalid query result"
        );

        // Try to parse Witnet Value Transfer metadata being reported:
        WitnetCBOR.CBOR[] memory _metadata = _witOracleQueryResult.fetchCborArray();
        require(_metadata.length >= 6, "invalid query result shape");
        /**
         * [
         *   0 -> finalized: uint8,
         *   1 -> metadata: string,
         *   2 -> recipient: string,
         *   3 -> sender: string,
         *   4 -> timestamp: uint64,
         *   5 -> value: uint64,
         * ]
         **/

        // Revert if the referred Witnet transaction is reported to not be finalized just yet:
        require(_metadata[0].readUint() == 1, "unfinalized query result");
        
        // Parse data result:
        _witRecipientBech32 = _metadata[2].readString();
        _witSenderBech32 = _metadata[3].readString();
        _evmRecipient = Witnet.toAddress(
            Witnet.parseHexString(
                _metadata[1].readString()
            )
        );
        Witnet.Timestamp _valueTimestamp = Witnet.Timestamp.wrap(_metadata[4].readUint());
        _value = _metadata[5].readUint();
        
        // Increase wrapping meters:
        data().evmWraps ++;
        data().evmWrappings += uint96(_value);
        
        // Also increase the burnable supply, only if the VTT's inclusion timestamp is fresher than last PoR's timestamp:
        if (_valueTimestamp.gt(data().evmLastReserveTimestamp)) {
            data().evmLastReserveNanowits += _value;
        }

        // Mark as processed only after all validations succeeded
        data().witOracleWrappingTransactionLastQueryId[_witValueTransferTransactionHash] = _WIT_ORACLE_QUERIABLE_CONSUMER_CALLBACK_PROCESSED;
    }

    function witOracleQueryWitnetValueTransferProofOfInclusion(
            WitOracle witOracle, 
            IWitOracleRadonRequestModal witOracleCrossChainProofOfInclusionTemplate,
            Witnet.TransactionHash witValueTransferTransactionHash
        ) 
        external 
        returns (uint256 _witQueryId)
    {
        _witQueryId = data().witOracleWrappingTransactionLastQueryId[witValueTransferTransactionHash];
        if (
            _witQueryId != _WIT_ORACLE_QUERIABLE_CONSUMER_CALLBACK_PROCESSED
        ) {
            // Redundant re-queries when a query is already “Posted” are allowed on purpose,
            // as to overcome past queries that could eventually take longer than usual to resolve.
            string[] memory _commonArgs = new string[](1);
            _commonArgs[0] = Witnet.toHexString(Witnet.TransactionHash.unwrap(witValueTransferTransactionHash));
            Witnet.RadonHash _radonHash = witOracleCrossChainProofOfInclusionTemplate
                .verifyRadonRequest(
                    _commonArgs,
                    data().witOracleCrossChainRpcProviders
                );
            _witQueryId = IWitOracleQueriable(witOracle).queryDataWithCallback{
                value: msg.value
            }(
                _radonHash,
                Witnet.QuerySLA({
                    witCommitteeSize: data().witOracleQuerySettings.minWitnesses,
                    witUnitaryReward: data().witOracleQuerySettings.unitaryRewardNanowits,
                    witResultMaxSize: _WIT_ORACLE_QUERIABLE_CONSUMER_MAX_RESULT_SIZE
                }),
                Witnet.QueryCallback({
                    consumer: address(this),
                    gasLimit: data().witOracleQuerySettings.responseCallbackGasLimit
                })
            );
            data().witOracleWrappingTransactionLastQueryId[witValueTransferTransactionHash] = _witQueryId;
            data().witOracleWrappingQueryTransactionHash[_witQueryId] = witValueTransferTransactionHash;
        }
    }


    // ================================================================================================================
    // --- Internal functions -----------------------------------------------------------------------------------------

    function data() internal pure returns (Storage storage _ptr) {
        assembly {
            _ptr.slot := _WRAPPED_WIT_STORAGE_SLOT
        }
    }

    function witOracleEstimateWrappingFee(WitOracle witOracle, uint256 evmGasPrice) internal view returns (uint256) {
        uint256 _baseFee = witOracle.estimateBaseFeeWithCallback(
            evmGasPrice, 
            data().witOracleQuerySettings.responseCallbackGasLimit
        );
        return _baseFee * (100 + data().witOracleQuerySettings.extraFeePercentage) / 100;
    }
}

Read Contract

DOMAIN_SEPARATOR 0x3644e515 → bytes32
allowance 0xdd62ed3e → uint256
balanceOf 0x70a08231 → uint256
bridge 0xe78cea92 → address
curator 0xe66f53b7 → address
decimals 0x313ce567 → uint8
eip712Domain 0x84b0196e → bytes1, string, string, uint256, address, bytes32, uint256[]
getWrapTransactionLastQueryId 0x77cc7a3a → uint256
getWrapTransactionStatus 0xa53cb851 → uint8
getWrapTransactionStatuses 0xaa22dc33 → uint8[]
minUnwrappableNanowits 0xf7b6604e → uint256
name 0x06fdde03 → string
nonces 0x7ecebe00 → uint256
paused 0x5c975abb → bool, bool, bool
reportableFrom 0x47a10e56 → bool
supportsInterface 0x01ffc9a7 → bool
symbol 0x95d89b41 → string
totalReserveNanowits 0x0ed4c438 → uint256
totalSupply 0x18160ddd → uint256
totalUnwrappings 0x3243bc60 → uint256
totalUnwraps 0x520a5495 → uint256
totalWrappings 0x692ea04b → uint256
totalWraps 0x6aaa54cf → uint256
witCustodianUnwrapper 0x147040de → string
witCustodianWrapper 0xb3f120a1 → string
witOracle 0x1014d375 → address
witOracleCrossChainProofOfInclusionTemplate 0xf69a00b6 → address
witOracleCrossChainProofOfReserveTemplate 0x27ae6883 → address
witOracleCrossChainRpcProviders 0x71d41eb3 → string[]
witOracleEstimateWrappingFee 0xddb2bf5c → uint256
witOracleProofOfReserveLastUpdate 0x30315dc4 → uint64
witOracleProofOfReserveRadonBytecode 0xacb734bb → bytes
witOracleProofOfReserveRadonHash 0xfec53a14 → bytes32
witOracleQuerySettings 0x873234cf → tuple

Write Contract 17 functions

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

approve 0x095ea7b3
address spender
uint256 value
returns: bool
crosschainBurn 0x2b8c49e3
address from
uint256 value
crosschainMint 0x18bf5077
address to
uint256 value
crosschainPause 0x57a6d45a
bool _erc7802
bool _witnetBurns
bool _witnetMints
initialize 0xf399e22e
address _curator
string _witCustodianUnwrapperBech32
permit 0xd505accf
address owner
address spender
uint256 value
uint256 deadline
uint8 v
bytes32 r
bytes32 s
pushDataReport 0x3d4e3cc7
tuple report
bytes proof
reportWitOracleQueryResult 0xd6f29e81
uint256 queryId
bytes queryResult
settleBridge 0x9ecb381a
address _newBridge
settleWitCustodianUnwrapper 0xc65a20f0
string _witCustodianUnwrapperBech32
settleWitOracleCrossChainRpcProviders 0xea9e96a6
string[] _witRpcProviders
settleWitOracleSettings 0xd9bb7258
tuple _settings
transfer 0xa9059cbb
address to
uint256 value
returns: bool
transferCuratorship 0xa41942a4
address _newCurator
transferFrom 0x23b872dd
address from
address to
uint256 value
returns: bool
unwrap 0x8a510f27
uint64 value
string witRecipientBech32
returns: uint256
wrap 0x5f029ebe
bytes32 _witnetValueTransferTransactionHash
returns: uint256

Recent Transactions

No transactions found for this address