Address Contract Verified
Address
0x0e4152204995877DF34BD26d6dab78baf9393Ae2
Balance
0 ETH
Nonce
1
Code Size
23023 bytes
Creator
0x529a0c17...1819 at tx 0xd34877b5...d80c65
Indexed Transactions
0
Contract Bytecode
23023 bytes
0x608060405260043610610435575f3560e01c806382ff53a111610237578063bb7ecb211161013c578063cfa45128116100b7578063e854e31a11610087578063f3c0ce221161006d578063f3c0ce2214610e08578063fa24f74314610e3b578063fcddca9814610e5e575f80fd5b8063e854e31a14610dd0578063eb45ec0d14610def575f80fd5b8063cfa4512814610d18578063dbbf2c4714610d4b578063dce87e6814610d7e578063e1f3c01014610db1575f80fd5b8063bd8da9561161010c578063c7265bc6116100f2578063c7265bc614610cb1578063ca0dc97314610ce5578063cf09e0d014610cf8575f80fd5b8063bd8da95614610c6e578063c5f956af14610c8d575f80fd5b8063bb7ecb2114610bc2578063bbdc02db14610bf6578063bc586c4814610c39578063bcef3b5514610c4d575f80fd5b8063a09159a6116101cc578063a9b51cb61161019c578063afdaec5011610182578063afdaec5014610b22578063b425dcb714610b55578063b84c278614610b8d575f80fd5b8063a9b51cb614610ae4578063aebda6f814610b03575f80fd5b8063a09159a614610a5e578063a401bc8c14610a7d578063a875459414610a9c578063a8e4fb9014610ad0575f80fd5b80638e8abdb1116102075780638e8abdb1146109a95780638f0ac453146109dc57806393294bc314610a00578063971805d814610a2b575f80fd5b806382ff53a11461090b57806385734ee11461093e5780638b85902b146109715780638bc3bbc014610995575f80fd5b80634a1890f01161033d57806369d5324d116102d2578063716e5b4a116102a257806377e4b3d51161028857806377e4b3d5146108d05780638129fc1c146108ef578063817804af146108f7575f80fd5b8063716e5b4a1461089b578063768c7204146108b0575f80fd5b806369d5324d146108105780636e0234431461082f5780637002ce421461085d57806370a87a981461087c575f80fd5b806354fd4d501161030d57806354fd4d50146107715780635654a341146107c6578063609d3334146107db5780636361506d146107ef575f80fd5b80634a1890f0146106ed5780634c6f8414146107205780634dafd7891461073e57806351ff48471461075d575f80fd5b8063250e69bd116103cd5780632a90b48f1161039d578063326f819511610383578063326f81951461067a57806337b1b229146106ad578063429e88d0146106ce575f80fd5b80632a90b48f146106305780632b44606d1461064f575f80fd5b8063250e69bd146105a55780632810e1d6146105d35780632a6375da146105e75780632a6648741461061a575f80fd5b80631bbd66f3116104085780631bbd66f3146104f05780631d9e47f4146105105780631e24fdd514610536578063200d2ed21461056b575f80fd5b8063077fb4691461043957806312f9650f1461047657806316112bcf1461049957806319effeb4146104c4575b5f80fd5b348015610444575f80fd5b50610458610453366004614eec565b610e72565b60405167ffffffffffffffff90911681526020015b60405180910390f35b348015610481575f80fd5b5061048b600e5481565b60405190815260200161046d565b3480156104a4575f80fd5b5061048b6104b3366004614f1a565b600b6020525f908152604090205481565b3480156104cf575f80fd5b50600a546104589068010000000000000000900467ffffffffffffffff1681565b3480156104fb575f80fd5b506008546104589067ffffffffffffffff1681565b34801561051b575f80fd5b50305b6040516001600160a01b03909116815260200161046d565b348015610541575f80fd5b5061055b610550366004614f96565b5f9695505050505050565b604051901515815260200161046d565b348015610576575f80fd5b50600a5461059890700100000000000000000000000000000000900460ff1681565b60405161046d919061507e565b3480156105b0575f80fd5b50600a5461055b9071010000000000000000000000000000000000900460ff1681565b3480156105de575f80fd5b50610598610ead565b3480156105f2575f80fd5b5061048b7f639c7a318b887270efc27af2079bbc86ec71797952f8472f12bc2a1736e9bd5281565b348015610625575f80fd5b5061062e611117565b005b34801561063b575f80fd5b5061062e61064a366004615091565b61136e565b34801561065a575f80fd5b5061048b610669366004614f1a565b60116020525f908152604090205481565b348015610685575f80fd5b506104587f00000000000000000000000000000000000000000000000000000000014e88a081565b3480156106b8575f80fd5b503660011981013560f01c90033560601c61051e565b3480156106d9575f80fd5b5061048b6106e8366004614eec565b61159a565b3480156106f8575f80fd5b5061048b7fdba4350757a9fad3b30dc28b53bde996295ef74bad7b5221bcda499d9fdd5ee481565b34801561072b575f80fd5b50600a5467ffffffffffffffff16610458565b348015610749575f80fd5b5061062e6107583660046150d8565b6115b8565b348015610768575f80fd5b5061048b611a6b565b34801561077c575f80fd5b506107b96040518060400160405280600581526020017f302e312e3000000000000000000000000000000000000000000000000000000081525081565b60405161046d91906151bc565b3480156107d1575f80fd5b5061048b60015481565b3480156107e6575f80fd5b506107b9611af1565b3480156107fa575f80fd5b503660011981013560f01c90036034013561048b565b34801561081b575f80fd5b5061062e61082a3660046151ce565b611aff565b34801561083a575f80fd5b50610598610849366004614eec565b60046020525f908152604090205460ff1681565b348015610868575f80fd5b5061051e610877366004614eec565b611f96565b348015610887575f80fd5b5061051e610896366004614eec565b611fbe565b3480156108a6575f80fd5b5061048b60095481565b3480156108bb575f80fd5b506006546104589067ffffffffffffffff1681565b3480156108db575f80fd5b5060135461051e906001600160a01b031681565b61062e612acb565b348015610902575f80fd5b5061062e612cbb565b348015610916575f80fd5b5061051e7f00000000000000000000000096123dbfc3253185b594c6a7472ee5a21e9b107981565b348015610949575f80fd5b5061051e7f0000000000000000000000008adee124447435fe03e3cd24df3f4cae32e65a3e81565b34801561097c575f80fd5b503660011981013560f01c90036054013560c01c61048b565b3480156109a0575f80fd5b5060055461048b565b3480156109b4575f80fd5b506104587f000000000000000000000000000000000000000000000000000000000000000681565b3480156109e7575f80fd5b50600d5461051e9061010090046001600160a01b031681565b348015610a0b575f80fd5b5061048b610a1a366004614f1a565b600f6020525f908152604090205481565b348015610a36575f80fd5b5061048b7f7ce98c36408e86dac21fc16af301740d07a849be0a80529debcb0797fd66f5e381565b348015610a69575f80fd5b5061055b610a78366004614eec565b612d39565b348015610a88575f80fd5b5061062e610a9736600461529b565b612d79565b348015610aa7575f80fd5b5061051e610ab6366004614eec565b60026020525f90815260409020546001600160a01b031681565b348015610adb575f80fd5b5061051e61352b565b348015610aef575f80fd5b5061062e610afe366004615379565b6135cc565b348015610b0e575f80fd5b5061062e610b1d366004614eec565b61372a565b348015610b2d575f80fd5b5061051e7f0000000000000000000000000e4152204995877df34bd26d6dab78baf9393ae281565b348015610b60575f80fd5b506013546104589074010000000000000000000000000000000000000000900467ffffffffffffffff1681565b348015610b98575f80fd5b50610458610ba7366004614eec565b60036020525f908152604090205467ffffffffffffffff1681565b348015610bcd575f80fd5b5061051e610bdc366004614f1a565b600c6020525f90815260409020546001600160a01b031681565b348015610c01575f80fd5b507f00000000000000000000000000000000000000000000000000000000000005395b60405163ffffffff909116815260200161046d565b348015610c44575f80fd5b5061062e6138c6565b348015610c58575f80fd5b503660011981013560f01c90036014013561048b565b348015610c79575f80fd5b50610458610c88366004614eec565b505f90565b348015610c98575f80fd5b503660011981013560f01c9003605c013560601c61051e565b348015610cbc575f80fd5b5061051e610ccb366004614f1a565b60126020525f90815260409020546001600160a01b031681565b61051e610cf33660046153a5565b613c2b565b348015610d03575f80fd5b50600a546104589067ffffffffffffffff1681565b348015610d23575f80fd5b506104587f0000000000000000000000000000000000000000000000000000000000000e1081565b348015610d56575f80fd5b50610c247f000000000000000000000000000000000000000000000000000000000000053981565b348015610d89575f80fd5b506104587f000000000000000000000000000000000000000000000000000000000000000181565b348015610dbc575f80fd5b5061051e610dcb3660046153ed565b614213565b348015610ddb575f80fd5b5061062e610dea366004614eec565b614247565b348015610dfa575f80fd5b50600d5461055b9060ff1681565b348015610e13575f80fd5b5061051e7f0000000000000000000000008eab2d97dfce405a1692a21b3ff3a172d593d31981565b348015610e46575f80fd5b50610e4f614381565b60405161046d93929190615417565b348015610e69575f80fd5b5061048b614473565b60078181548110610e81575f80fd5b905f5260205f209060049182820401919006600802915054906101000a900467ffffffffffffffff1681565b5f807f00000000000000000000000096123dbfc3253185b594c6a7472ee5a21e9b10799050806001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610f0e573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610f329190615444565b6001600160a01b0316336001600160a01b031614610fb1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600960248201527f6e6f74206f776e6572000000000000000000000000000000000000000000000060448201526064015b60405180910390fd5b5f600a54700100000000000000000000000000000000900460ff166002811115610fdd57610fdd61501c565b14611014576040517f67fe195000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600a80547fffffffffffffffffffffffffffffff00ffffffffffffffffffffffffffffffff1670020000000000000000000000000000000017905560029150816040517f5e186f09b9c93491f14e277eea7faa5de6a2d4bda75a79af7a3684fbfb42da60905f90a242600a60086101000a81548167ffffffffffffffff021916908367ffffffffffffffff1602179055507f0000000000000000000000000e4152204995877df34bd26d6dab78baf9393ae26001600160a01b031663817804af6040518163ffffffff1660e01b81526004015f604051808303815f87803b1580156110fd575f80fd5b505af115801561110f573d5f803e3d5ffd5b505050505090565b7f0000000000000000000000000e4152204995877df34bd26d6dab78baf9393ae26001600160a01b031663eb45ec0d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611173573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611197919061545f565b6111cd576040517f9d3e7d2400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b303303611206576040517f5f53dd9800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60055460065467ffffffffffffffff161080156112dc57506006546005805460029267ffffffffffffffff169081106112415761124161547e565b5f9182526020918290200154604080517f200d2ed200000000000000000000000000000000000000000000000000000000815290516001600160a01b039092169263200d2ed2926004808401938290030181865afa1580156112a5573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906112c991906154ab565b60028111156112da576112da61501c565b145b15611313576040517ff1a9458100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600580546001810182555f919091527f036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db00180547fffffffffffffffffffffffff00000000000000000000000000000000000000001633179055565b5f8290505f816001600160a01b0316631d9e47f46040518163ffffffff1660e01b8152600401602060405180830381865afa1580156113af573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906113d39190615444565b9050336001600160a01b03821614611428576040517fd36871fd0000000000000000000000000000000000000000000000000000000081523360048201526001600160a01b0382166024820152604401610fa8565b6001600160a01b038083165f908152600c60205260409020541680611479576040517ff2a87d5e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b0381165f908152600b6020526040902054156114c8576040517f8b1dfa2200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b826001600160a01b0316635654a3416040518163ffffffff1660e01b8152600401602060405180830381865afa158015611504573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061152891906154c9565b6001600160a01b039182165f818152600b60209081526040808320949094559690931683526010865290822080546001810182559083529490912090930180547fffffffffffffffffffffffff000000000000000000000000000000000000000016909317909255505050565b905090565b5f81815481106115a8575f80fd5b5f91825260209091200154905081565b5f60056115c860208901896154e0565b67ffffffffffffffff16815481106115e2576115e261547e565b5f9182526020822001546001600160a01b03169150816001600160a01b031663200d2ed26040518163ffffffff1660e01b8152600401602060405180830381865afa158015611633573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061165791906154ab565b60028111156116685761166861501c565b1461169f576040517f67fe195000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60055460065467ffffffffffffffff1610801561177557506006546005805460029267ffffffffffffffff169081106116da576116da61547e565b5f9182526020918290200154604080517f200d2ed200000000000000000000000000000000000000000000000000000000815290516001600160a01b039092169263200d2ed2926004808401938290030181865afa15801561173e573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061176291906154ab565b60028111156117735761177361501c565b145b156117ac576040517ff1a9458100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f0000000000000000000000000000000000000000000000000000000000000e1067ffffffffffffffff166117e76040890160208a016154e0565b67ffffffffffffffff161015611829576040517f3014033200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b855f03611862576040517f7412124e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f600161187560408a0160208b016154e0565b61187f9190615528565b90506118ac60017f0000000000000000000000000000000000000000000000000000000000000001615528565b67ffffffffffffffff166118c98267ffffffffffffffff16614487565b14611900576040517f5c5537b800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f1e24fdd50000000000000000000000000000000000000000000000000000000081526001600160a01b03831690631e24fdd59061194f9084908b908b908b908b908b90600401615579565b6020604051808303815f875af115801561196b573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061198f919061545f565b6119f5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f6261642070726f706f7365644f7574707574206b7a67000000000000000000006044820152606401610fa8565b611a6089836001600160a01b03166351ff48476040518163ffffffff1660e01b8152600401602060405180830381865afa158015611a35573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611a5991906154c9565b600161449a565b505050505050505050565b5f6002611a873660011981013560f01c90036014013590565b90565b5f604051602001611a999291906155f6565b60408051601f1981840301815290829052611ab39161560f565b602060405180830381855afa158015611ace573d5f803e3d5ffd5b5050506040513d601f19601f8201168201806040525081019061159591906154c9565b60606115956054601c6145fd565b5f60058467ffffffffffffffff1681548110611b1d57611b1d61547e565b5f9182526020822001546001600160a01b03169150816001600160a01b031663200d2ed26040518163ffffffff1660e01b8152600401602060405180830381865afa158015611b6e573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611b9291906154ab565b6002811115611ba357611ba361501c565b14611bda576040517f67fe195000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b806001600160a01b03166351ff48476040518163ffffffff1660e01b8152600401602060405180830381865afa158015611c16573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611c3a91906154c9565b60095560055460065467ffffffffffffffff16108015611d1357506006546005805460029267ffffffffffffffff16908110611c7857611c7861547e565b5f9182526020918290200154604080517f200d2ed200000000000000000000000000000000000000000000000000000000815290516001600160a01b039092169263200d2ed2926004808401938290030181865afa158015611cdc573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611d0091906154ab565b6002811115611d1157611d1161501c565b145b15611d4a576040517ff1a9458100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f600167ffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000e10161115611ee15760023660011981013560f01c90036054013560c01c7f0000000000000000000000000000000000000000000000000000000000000e107f0000000000000000000000000000000000000000000000000000000000000006856001600160a01b031663fcddca986040518163ffffffff1660e01b8152600401602060405180830381865afa158015611e11573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611e3591906154c9565b6040517fffffffffffffffff00000000000000000000000000000000000000000000000060c095861b8116602083015293851b841660288201529190931b9091166030820152603881019190915260580160408051601f1981840301815290829052611ea09161560f565b602060405180830381855afa158015611ebb573d5f803e3d5ffd5b5050506040513d601f19601f82011682018060405250810190611ede91906154c9565b90505b611f8d868883611efd3660011981013560f01c90036014013590565b611f60876001600160a01b031663bcef3b556040518163ffffffff1660e01b8152600401602060405180830381865afa158015611f3c573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611a8491906154c9565b7f0000000000000000000000000000000000000000000000000000000000000e108a8a6009546002614630565b50505050505050565b60058181548110611fa5575f80fd5b5f918252602090912001546001600160a01b0316905081565b5f6002600a54700100000000000000000000000000000000900460ff166002811115611fec57611fec61501c565b14612023576040517fc105260a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6005545f0361205e576040517ff2a87d5e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60065460085460055467ffffffffffffffff9283169290911690820361208757505f9392505050565b8167ffffffffffffffff168167ffffffffffffffff16116120b0576120ad82600161562a565b90505b5f60058367ffffffffffffffff16815481106120ce576120ce61547e565b5f918252602080832090910154604080517f51ff484700000000000000000000000000000000000000000000000000000000815290516001600160a01b03909216945084926351ff4847926004808401938290030181865afa158015612136573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061215a91906154c9565b90506002826001600160a01b031663200d2ed26040518163ffffffff1660e01b8152600401602060405180830381865afa15801561219a573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906121be91906154ab565b60028111156121cf576121cf61501c565b036121dd5750949350505050565b6121e681612d39565b15806121f657506121f682614981565b1561266c575f61220582614b51565b6007549091505b5f8111801561221a57505f88115b156123bc575f6005600761222f60018561564b565b8154811061223f5761223f61547e565b905f5260205f2090600491828204019190066008029054906101000a900467ffffffffffffffff1667ffffffffffffffff16815481106122815761228161547e565b5f918252602090912001546001600160a01b031690506122a081614981565b61233c576040517f2a90b48f0000000000000000000000000000000000000000000000000000000081526001600160a01b03828116600483015284811660248301527f0000000000000000000000000e4152204995877df34bd26d6dab78baf9393ae21690632a90b48f906044015f604051808303815f87803b158015612325575f80fd5b505af1158015612337573d5f803e3d5ffd5b505050505b600780548061234d5761234d61565e565b5f8281526020902060047fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90920191820401805467ffffffffffffffff600860038516026101000a0219169055905550806123a78161568b565b9150886123b38161568b565b9950505061220c565b50865f036123d057505f9695505050505050565b6123d983614981565b612475576040517f2a90b48f0000000000000000000000000000000000000000000000000000000081526001600160a01b03848116600483015282811660248301527f0000000000000000000000000e4152204995877df34bd26d6dab78baf9393ae21690632a90b48f906044015f604051808303815f87803b15801561245e575f80fd5b505af1158015612470573d5f803e3d5ffd5b505050505b8661247f8161568b565b9750508394505b60055467ffffffffffffffff86161080156124a057505f87115b156126295760058567ffffffffffffffff16815481106124c2576124c261547e565b5f918252602090912001546001600160a01b031692506124e183614981565b61260a57826001600160a01b03166351ff48476040518163ffffffff1660e01b8152600401602060405180830381865afa158015612521573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061254591906154c9565b915061255082612d39565b612605577f0000000000000000000000000e4152204995877df34bd26d6dab78baf9393ae26001600160a01b0316632a90b48f8461258d85614b51565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b1681526001600160a01b039283166004820152911660248201526044015f604051808303815f87803b1580156125ea575f80fd5b505af11580156125fc573d5f803e3d5ffd5b5050505061260a565b612629565b84612614816156bf565b9550876126208161568b565b98505050612486565b600680547fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000001667ffffffffffffffff871617905561266885600161562a565b9350505b60055467ffffffffffffffff851610801561272a575061272a60058567ffffffffffffffff16815481106126a2576126a261547e565b5f9182526020918290200154604080517f51ff484700000000000000000000000000000000000000000000000000000000815290516001600160a01b03909216926351ff4847926004808401938290030181865afa158015612706573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610a7891906154c9565b15612ac0575b60055467ffffffffffffffff841610801561274a57505f86115b15612a6d575f60058467ffffffffffffffff168154811061276d5761276d61547e565b905f5260205f20015f9054906101000a90046001600160a01b03169050612867836001600160a01b031663bd8da95661280c846001600160a01b031663cf09e0d06040518163ffffffff1660e01b8152600401602060405180830381865afa1580156127db573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906127ff91906156e5565b67ffffffffffffffff1690565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b16815267ffffffffffffffff9091166004820152602401602060405180830381865afa1580156127db573d5f803e3d5ffd5b67ffffffffffffffff165f0361287d5750612a6d565b61288681614981565b156128915750612a4e565b5f816001600160a01b03166351ff48476040518163ffffffff1660e01b8152600401602060405180830381865afa1580156128ce573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906128f291906154c9565b905082810361295f575050600780546001810182555f919091527fa66cc928b5edb82af9bd49922954155ab7b0942694bea4ce44661d9a8736c6886004820401805460039092166008026101000a67ffffffffffffffff8181021990931692861602919091179055612a4e565b61296881612d39565b1561299f576040517fa506d33400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f0000000000000000000000000e4152204995877df34bd26d6dab78baf9393ae26001600160a01b0316632a90b48f836129d884614b51565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b1681526001600160a01b039283166004820152911660248201526044015f604051808303815f87803b158015612a35575f80fd5b505af1158015612a47573d5f803e3d5ffd5b5050505050505b82612a58816156bf565b935086612a648161568b565b97505050612730565b600880547fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000001667ffffffffffffffff85169081179091556005541480612ab257505f86115b15612ac05750949350505050565b505f95945050505050565b612ad3614b8c565b60763614612b0d576040517f9824bdab00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7fdba4350757a9fad3b30dc28b53bde996295ef74bad7b5221bcda499d9fdd5ee4612b443660011981013560f01c90036014013590565b14612b8c576040517ff40239db0000000000000000000000000000000000000000000000000000000081523660011981013560f01c9003601401356004820152602401610fa8565b67ffffffffffffffff7f00000000000000000000000000000000000000000000000000000000014e88a0163660011981013560f01c90036054013560c01c14612c45576040517feaa0996e0000000000000000000000000000000000000000000000000000000081523660011981013560f01c90036054013560c01c600482015267ffffffffffffffff7f00000000000000000000000000000000000000000000000000000000014e88a0166024820152604401610fa8565b6001600160a01b037f0000000000000000000000000e4152204995877df34bd26d6dab78baf9393ae2163660011981013560f01c9003605c013560601c14612cb9576040517f9824bdab00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b565b335f908152600c60205260409020546001600160a01b0316612d09576040517ff2a87d5e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600d80547fffffffffffffffffffffff0000000000000000000000000000000000000000ff163361010002179055565b6009545f9015612d4b57506009541490565b60015f8381526004602052604090205460ff166002811115612d6f57612d6f61501c565b141590505b919050565b5f6005612d8960208901896154e0565b67ffffffffffffffff1681548110612da357612da361547e565b5f9182526020822001546001600160a01b03169150816001600160a01b031663200d2ed26040518163ffffffff1660e01b8152600401602060405180830381865afa158015612df4573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612e1891906154ab565b6002811115612e2957612e2961501c565b14612e60576040517f67fe195000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60055460065467ffffffffffffffff16108015612f3657506006546005805460029267ffffffffffffffff16908110612e9b57612e9b61547e565b5f9182526020918290200154604080517f200d2ed200000000000000000000000000000000000000000000000000000000815290516001600160a01b039092169263200d2ed2926004808401938290030181865afa158015612eff573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612f2391906154ab565b6002811115612f3457612f3461501c565b145b15612f6d576040517ff1a9458100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f0000000000000000000000000000000000000000000000000000000000000e1067ffffffffffffffff16612fa86040890160208a016154e0565b67ffffffffffffffff1610612fe9576040517f3014033200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612ff960408801602089016154e0565b67ffffffffffffffff165f0361308d5761301f3660011981013560f01c90036014013590565b845114613088576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f6261642061636365707465644f757470757400000000000000000000000000006044820152606401610fa8565b6131ea565b6001600160a01b038116631e24fdd560016130ae60408b0160208c016154e0565b6130b89190615528565b6130c8875f5b6020020151614e33565b6130d28680615700565b5f8181106130e2576130e261547e565b90506020028101906130f49190615764565b6131016020890189615700565b5f8181106131115761311161547e565b90506020028101906131239190615764565b6040518763ffffffff1660e01b815260040161314496959493929190615579565b6020604051808303815f875af1158015613160573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613184919061545f565b6131ea576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f6261642061636365707465644f7574707574206b7a67000000000000000000006044820152606401610fa8565b61321560017f0000000000000000000000000000000000000000000000000000000000000e10615528565b67ffffffffffffffff1661322f6040890160208a016154e0565b67ffffffffffffffff16036132be5761327d816001600160a01b031663bcef3b556040518163ffffffff1660e01b8152600401602060405180830381865afa158015611f3c573d5f803e3d5ffd5b6020850151036132b9576040517f7412124e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b613472565b6001600160a01b038116631e24fdd56132dd60408a0160208b016154e0565b856132e88680615700565b60016132f48980615700565b6132ff92915061564b565b81811061330e5761330e61547e565b90506020028101906133209190615764565b61332d6020890189615700565b600161333c60208c018c615700565b61334792915061564b565b8181106133565761335661547e565b90506020028101906133689190615764565b6040518763ffffffff1660e01b815260040161338996959493929190615579565b6020604051808303815f875af11580156133a5573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906133c9919061545f565b61342f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f6261642070726f706f7365644f7574707574206b7a67000000000000000000006044820152606401610fa8565b8261343b8560016130be565b03613472576040517f7412124e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61352161348560408a0160208b01614f1a565b61349260208b018b614f1a565b86516020808901515f92916134ad9060408f01908f016154e0565b6134b890600161562a565b8c8c896001600160a01b03166351ff48476040518163ffffffff1660e01b8152600401602060405180830381865afa1580156134f6573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061351a91906154c9565b6001614630565b5050505050505050565b6040517fbb7ecb210000000000000000000000000000000000000000000000000000000081523060048201525f907f0000000000000000000000000e4152204995877df34bd26d6dab78baf9393ae26001600160a01b03169063bb7ecb2190602401602060405180830381865afa1580156135a8573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906115959190615444565b5f7f00000000000000000000000096123dbfc3253185b594c6a7472ee5a21e9b10799050806001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561362c573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906136509190615444565b6001600160a01b0316336001600160a01b0316146136ca576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600960248201527f6e6f74206f776e657200000000000000000000000000000000000000000000006044820152606401610fa8565b506013805467ffffffffffffffff90921674010000000000000000000000000000000000000000027fffffffff000000000000000000000000000000000000000000000000000000009092166001600160a01b0390931692909217179055565b6013547c0100000000000000000000000000000000000000000000000000000000900460ff1615613759575f80fd5b601380547fffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffff167c0100000000000000000000000000000000000000000000000000000000179055335f9081526011602052604081205481905b83831080156137ce5750335f9081526010602052604090205481105b1561385e57335f9081526010602052604081208054839081106137f3576137f361547e565b5f9182526020808320909101546001600160a01b0316808352600f90915260409091205490915061382490846157c5565b6001600160a01b039091165f908152600f6020526040812055915080613849816157d8565b915083613855816157d8565b945050506137b2565b50811561388957335f90815260116020526040812080548492906138839084906157c5565b90915550505b8015613899576138998133614e5e565b5050601380547fffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffff16905550565b6013547c0100000000000000000000000000000000000000000000000000000000900460ff16156138f5575f80fd5b601380547fffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffff167c0100000000000000000000000000000000000000000000000000000000179055335f908152600b602052604090205415613982576040517f8b1dfa2200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b335f908152601260205260409020546001600160a01b03168015613b9c575f816001600160a01b0316631d9e47f46040518163ffffffff1660e01b8152600401602060405180830381865afa1580156139dd573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613a019190615444565b90506002816001600160a01b0316637002ce42836001600160a01b031663768c72046040518163ffffffff1660e01b8152600401602060405180830381865afa158015613a50573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613a7491906156e5565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b16815267ffffffffffffffff9091166004820152602401602060405180830381865afa158015613acf573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613af39190615444565b6001600160a01b031663200d2ed26040518163ffffffff1660e01b8152600401602060405180830381865afa158015613b2e573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613b5291906154ab565b6002811115613b6357613b6361501c565b14613b9a576040517fc105260a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505b335f908152600f602052604081205490819003613be5576040517f17bfe5f700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b335f818152600f6020526040812055613bff908290614e5e565b5050601380547fffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffff169055565b335f908152600b602052604081205415613c71576040517fd386ef3e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3415613c9b57335f908152600f602052604081208054349290613c959084906157c5565b90915550505b600e54335f908152600f60205260409020541015613ce5576040517f8620aa1900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600d80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790556040517f82ecf2f60000000000000000000000000000000000000000000000000000000081526001600160a01b037f00000000000000000000000096123dbfc3253185b594c6a7472ee5a21e9b107916906382ecf2f690613d9b907f00000000000000000000000000000000000000000000000000000000000005399088908890889060040161580f565b6020604051808303815f875af1158015613db7573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613ddb9190615444565b600d80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055335f908152601260205260409020549091506001600160a01b03168015613fe457816001600160a01b0316638b85902b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613e60573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613e8491906154c9565b816001600160a01b0316638b85902b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613ec0573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613ee491906154c9565b10613fe457806001600160a01b0316638b85902b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613f25573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613f4991906154c9565b826001600160a01b0316638b85902b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613f85573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613fa991906154c9565b6040517feaa0996e00000000000000000000000000000000000000000000000000000000815260048101929092526024820152604401610fa8565b6013546001600160a01b03161580159061400957506013546001600160a01b03163314155b156141b0575f826001600160a01b0316631d9e47f46040518163ffffffff1660e01b8152600401602060405180830381865afa15801561404b573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061406f9190615444565b9050806001600160a01b0316638bc3bbc06040518163ffffffff1660e01b8152600401602060405180830381865afa1580156140ad573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906140d191906154c9565b6001036141ae575f614118846001600160a01b0316634c6f84146040518163ffffffff1660e01b8152600401602060405180830381865afa1580156127db573d5f803e3d5ffd5b61412c9067ffffffffffffffff164261564b565b60135490915074010000000000000000000000000000000000000000900467ffffffffffffffff1667ffffffffffffffff168167ffffffffffffffff1610156141ac576040517f627fad6e0000000000000000000000000000000000000000000000000000000081526001600160a01b0383166004820152602401610fa8565b505b505b506001600160a01b0381165f818152600c602090815260408083208054337fffffffffffffffffffffffff000000000000000000000000000000000000000091821681179092559084526012909252909120805490911690911790559392505050565b6010602052815f5260405f20818154811061422c575f80fd5b5f918252602090912001546001600160a01b03169150829050565b5f7f00000000000000000000000096123dbfc3253185b594c6a7472ee5a21e9b10799050806001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156142a7573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906142cb9190615444565b6001600160a01b0316336001600160a01b031614614345576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600960248201527f6e6f74206f776e657200000000000000000000000000000000000000000000006044820152606401610fa8565b600e8290556040518281527f344368f837b372e83f2e2044df76bd67c40d4a4d9fce6710769e8ed7393b45ed9060200160405180910390a15050565b5f8060607f00000000000000000000000000000000000000000000000000000000000005399250306001600160a01b031663bcef3b556040518163ffffffff1660e01b8152600401602060405180830381865afa1580156143e4573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061440891906154c9565b9150306001600160a01b031663609d33346040518163ffffffff1660e01b81526004015f60405180830381865afa158015614445573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f1916820160405261446c919081019061583e565b9050909192565b5f60025f604051602001611a9991906158e6565b5f6144946110008361591e565b92915050565b5f8281526004602052604081205460ff1660028111156144bc576144bc61501c565b146144f3576040517f2c06a36400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f82815260046020526040902080548291907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600183600281111561453b5761453b61501c565b02179055508060028111156145525761455261501c565b60405183907f2d4e0491b639866a8d4d57a9faeb546a13f536e3e916a20af0aa4ae33f7bfc2d905f90a3505f90815260026020908152604080832080547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b039590951694909417909355600390522080547fffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000164267ffffffffffffffff16179055565b6040518181523660011981013560f01c90038284820160208401378260208301015f815260208101604052505092915050565b6040517fbb7ecb210000000000000000000000000000000000000000000000000000000081526001600160a01b038b811660048301525f917f0000000000000000000000000e4152204995877df34bd26d6dab78baf9393ae29091169063bb7ecb2190602401602060405180830381865afa1580156146b1573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906146d59190615444565b6001600160a01b031603614715576040517f9d3e7d2400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f89896147578d6001600160a01b0316636361506d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611f3c573d5f803e3d5ffd5b8a8a6147837f00000000000000000000000000000000000000000000000000000000000000068c615931565b67ffffffffffffffff163660011981013560f01c90036054013560c01c6147aa91906157c5565b60405160609690961b7fffffffffffffffffffffffffffffffffffffffff000000000000000000000000166020870152603486019490945260548501929092526074840152609483015260c01b7fffffffffffffffff0000000000000000000000000000000000000000000000001660b48201527f639c7a318b887270efc27af2079bbc86ec71797952f8472f12bc2a1736e9bd5260bc8201527f7ce98c36408e86dac21fc16af301740d07a849be0a80529debcb0797fd66f5e360dc82015260fc0160405160208183030381529060405290507f0000000000000000000000008eab2d97dfce405a1692a21b3ff3a172d593d3196001600160a01b031663ab750e7586867f7ce98c36408e86dac21fc16af301740d07a849be0a80529debcb0797fd66f5e36002866040516148e0919061560f565b602060405180830381855afa1580156148fb573d5f803e3d5ffd5b5050506040513d601f19601f8201168201806040525081019061491e91906154c9565b6040518563ffffffff1660e01b815260040161493d949392919061595d565b5f6040518083038186803b158015614953575f80fd5b505afa158015614965573d5f803e3d5ffd5b505050506149748a848461449a565b5050505050505050505050565b6040517fbb7ecb210000000000000000000000000000000000000000000000000000000081526001600160a01b0382811660048301525f9182917f0000000000000000000000000e4152204995877df34bd26d6dab78baf9393ae2169063bb7ecb2190602401602060405180830381865afa158015614a02573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190614a269190615444565b6040517f16112bcf0000000000000000000000000000000000000000000000000000000081526001600160a01b0380831660048301529192505f917f0000000000000000000000000e4152204995877df34bd26d6dab78baf9393ae216906316112bcf90602401602060405180830381865afa158015614aa8573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190614acc91906154c9565b9050801580614b395750836001600160a01b0316635654a3416040518163ffffffff1660e01b8152600401602060405180830381865afa158015614b12573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190614b3691906154c9565b81115b15614b4757505f9392505050565b5060019392505050565b5f818152600260205260409020546001600160a01b031680612d745750506009545f908152600260205260409020546001600160a01b031690565b600a5467ffffffffffffffff1615614bd0576040517f0dc149f000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b037f0000000000000000000000000e4152204995877df34bd26d6dab78baf9393ae2163660011981013560f01c90033560601c14614c81576040517fd36871fd0000000000000000000000000000000000000000000000000000000081523660011981013560f01c90033560601c60048201526001600160a01b037f0000000000000000000000000e4152204995877df34bd26d6dab78baf9393ae2166024820152604401610fa8565b600a80547fffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000164267ffffffffffffffff16179055604080517f4d1975b400000000000000000000000000000000000000000000000000000000815290517f00000000000000000000000096123dbfc3253185b594c6a7472ee5a21e9b10796001600160a01b031691634d1975b49160048083019260209291908290030181865afa158015614d31573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190614d5591906154c9565b6001557f000000000000000000000000000000000000000000000000000000000000053963ffffffff1663ffffffff16614e117f0000000000000000000000008adee124447435fe03e3cd24df3f4cae32e65a3e6001600160a01b0316633c9f397c6040518163ffffffff1660e01b8152600401602060405180830381865afa158015614de4573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190614e089190615983565b63ffffffff1690565b63ffffffff1614600a60116101000a81548160ff021916908315150217905550565b5f6144947f73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001836159a6565b5f816001600160a01b0316836040515f6040518083038185875af1925050503d805f8114614ea7576040519150601f19603f3d011682016040523d82523d5f602084013e614eac565b606091505b5050905080614ee7576040517f83e6cc6b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505050565b5f60208284031215614efc575f80fd5b5035919050565b6001600160a01b0381168114614f17575f80fd5b50565b5f60208284031215614f2a575f80fd5b8135614f3581614f03565b9392505050565b67ffffffffffffffff81168114614f17575f80fd5b5f8083601f840112614f61575f80fd5b50813567ffffffffffffffff811115614f78575f80fd5b602083019150836020828501011115614f8f575f80fd5b9250929050565b5f805f805f8060808789031215614fab575f80fd5b8635614fb681614f3c565b955060208701359450604087013567ffffffffffffffff80821115614fd9575f80fd5b614fe58a838b01614f51565b90965094506060890135915080821115614ffd575f80fd5b5061500a89828a01614f51565b979a9699509497509295939492505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b60038110614f17577f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b6020810161508b83615049565b91905290565b5f80604083850312156150a2575f80fd5b82356150ad81614f03565b915060208301356150bd81614f03565b809150509250929050565b8060408101831015614494575f80fd5b5f805f805f805f60c0888a0312156150ee575f80fd5b87356150f981614f03565b96506151088960208a016150c8565b955060608801359450608088013567ffffffffffffffff8082111561512b575f80fd5b6151378b838c01614f51565b909650945060a08a013591508082111561514f575f80fd5b5061515c8a828b01614f51565b989b979a50959850939692959293505050565b5f5b83811015615189578181015183820152602001615171565b50505f910152565b5f81518084526151a881602086016020860161516f565b601f01601f19169290920160200192915050565b602081525f614f356020830184615191565b5f805f805f608086880312156151e2575f80fd5b85356151ed81614f03565b945060208601356151fd81614f03565b9350604086013561520d81614f3c565b9250606086013567ffffffffffffffff811115615228575f80fd5b61523488828901614f51565b969995985093965092949392505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b6040805190810167ffffffffffffffff8111828210171561529557615295615245565b60405290565b5f805f805f805f610120888a0312156152b2575f80fd5b6152bc89896150c8565b96506152cb8960408a016150c8565b9550608088013567ffffffffffffffff808211156152e7575f80fd5b6152f38b838c01614f51565b9250809750508195508a60bf8b011261530a575f80fd5b615312615272565b91508160e08b018c811115615325575f80fd5b60a08c015b8181101561534257803585526020948501940161532a565b509095503593506101008a013591508082111561535d575f80fd5b5061536a8a828b016150c8565b91505092959891949750929550565b5f806040838503121561538a575f80fd5b823561539581614f03565b915060208301356150bd81614f3c565b5f805f604084860312156153b7575f80fd5b83359250602084013567ffffffffffffffff8111156153d4575f80fd5b6153e086828701614f51565b9497909650939450505050565b5f80604083850312156153fe575f80fd5b823561540981614f03565b946020939093013593505050565b63ffffffff84168152826020820152606060408201525f61543b6060830184615191565b95945050505050565b5f60208284031215615454575f80fd5b8151614f3581614f03565b5f6020828403121561546f575f80fd5b81518015158114614f35575f80fd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f602082840312156154bb575f80fd5b815160038110614f35575f80fd5b5f602082840312156154d9575f80fd5b5051919050565b5f602082840312156154f0575f80fd5b8135614f3581614f3c565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b67ffffffffffffffff828116828216039080821115615549576155496154fb565b5092915050565b81835281816020850137505f602082840101525f6020601f19601f840116840101905092915050565b67ffffffffffffffff87168152856020820152608060408201525f6155a2608083018688615550565b82810360608401526155b5818587615550565b9998505050505050505050565b5f8154825f526020805f205f5b838110156155eb578154875295820195600191820191016155cf565b509495945050505050565b8281525f61560760208301846155c2565b949350505050565b5f825161562081846020870161516f565b9190910192915050565b67ffffffffffffffff818116838216019080821115615549576155496154fb565b81810381811115614494576144946154fb565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603160045260245ffd5b5f81615699576156996154fb565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190565b5f67ffffffffffffffff8083168181036156db576156db6154fb565b6001019392505050565b5f602082840312156156f5575f80fd5b8151614f3581614f3c565b5f8083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112615733575f80fd5b83018035915067ffffffffffffffff82111561574d575f80fd5b6020019150600581901b3603821315614f8f575f80fd5b5f8083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112615797575f80fd5b83018035915067ffffffffffffffff8211156157b1575f80fd5b602001915036819003821315614f8f575f80fd5b80820180821115614494576144946154fb565b5f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203615808576158086154fb565b5060010190565b63ffffffff85168152836020820152606060408201525f615834606083018486615550565b9695505050505050565b5f6020828403121561584e575f80fd5b815167ffffffffffffffff80821115615865575f80fd5b818401915084601f830112615878575f80fd5b81518181111561588a5761588a615245565b604051601f8201601f19908116603f011681019083821181831017156158b2576158b2615245565b816040528281528760208487010111156158ca575f80fd5b6158db83602083016020880161516f565b979650505050505050565b5f614f3582846155c2565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b5f8261592c5761592c6158f1565b500490565b67ffffffffffffffff818116838216028082169190828114615955576159556154fb565b505092915050565b606081525f615970606083018688615550565b6020830194909452506040015292915050565b5f60208284031215615993575f80fd5b815163ffffffff81168114614f35575f80fd5b5f826159b4576159b46158f1565b50069056fea264697066735822122026a3741c70b872247b4f4ec94a0bd3fa91f542158d060f34c9fd3d236e4b5a3864736f6c63430008180033
Verified Source Code Full Match
Compiler: v0.8.24+commit.e11b9ed9
EVM: cancun
Optimization: Yes (10000 runs)
KailuaTreasury.sol 379 lines
// Copyright 2024, 2025 RISC Zero, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.15;
import "./vendor/FlatOPImportV1.4.0.sol";
import "./vendor/FlatR0ImportV2.0.2.sol";
import "./KailuaLib.sol";
import "./KailuaTournament.sol";
contract KailuaTreasury is KailuaTournament, IKailuaTreasury {
/// @notice Semantic version.
/// @custom:semver 0.1.0
string public constant version = "0.1.0";
// ------------------------------
// Immutable configuration
// ------------------------------
/// @notice The initial root claim for the deployment
Claim public immutable ROOT_CLAIM;
/// @notice The L2 block number of the initial root claim for the deployment
uint64 public immutable L2_BLOCK_NUMBER;
constructor(
IRiscZeroVerifier _verifierContract,
bytes32 _imageId,
bytes32 _configHash,
uint64 _proposalOutputCount,
uint64 _outputBlockSpan,
GameType _gameType,
OptimismPortal2 _optimismPortal,
Claim _rootClaim,
uint64 _l2BlockNumber
)
KailuaTournament(
KailuaTreasury(this),
_verifierContract,
_imageId,
_configHash,
_proposalOutputCount,
_outputBlockSpan,
_gameType,
_optimismPortal
)
{
ROOT_CLAIM = _rootClaim;
L2_BLOCK_NUMBER = _l2BlockNumber;
}
// ------------------------------
// IInitializable implementation
// ------------------------------
/// @inheritdoc IInitializable
function initialize() external payable override {
super.initializeInternal();
// Revert if the calldata size is not the expected length.
//
// This is to prevent adding extra or omitting bytes from to `extraData` that result in a different game UUID
// in the factory, but are not used by the game, which would allow for multiple dispute games for the same
// output proposal to be created.
//
// Expected length: 0x76
// - 0x04 selector 0x00 0x04
// - 0x14 creator address 0x04 0x18
// - 0x20 root claim 0x18 0x38
// - 0x20 l1 head 0x38 0x58
// - 0x1c extraData: 0x58 0x74
// + 0x08 l2BlockNumber 0x58 0x60
// + 0x14 kailuaTreasuryAddress 0x60 0x74
// - 0x02 CWIA bytes 0x74 0x76
if (msg.data.length != 0x76) {
revert BadExtraData();
}
// Accept only the initialized root claim
if (rootClaim().raw() != ROOT_CLAIM.raw()) {
revert UnexpectedRootClaim(rootClaim());
}
// Accept only the initialized l2 block number
if (l2BlockNumber() != L2_BLOCK_NUMBER) {
revert BlockNumberMismatch(l2BlockNumber(), L2_BLOCK_NUMBER);
}
// Accept only the address of the deployment treasury
if (treasuryAddress() != address(KAILUA_TREASURY)) {
revert BadExtraData();
}
}
/// @notice Returns the treasury address used in initialization
function treasuryAddress() public pure returns (address treasuryAddress_) {
treasuryAddress_ = _getArgAddress(0x5c);
}
// ------------------------------
// IDisputeGame implementation
// ------------------------------
/// @inheritdoc IDisputeGame
function extraData() external pure returns (bytes memory extraData_) {
// The extra data starts at the second word within the cwia calldata and
// is 32 bytes long.
extraData_ = _getArgBytes(0x54, 0x1c);
}
/// @inheritdoc IDisputeGame
function resolve() external onlyFactoryOwner returns (GameStatus status_) {
// INVARIANT: Resolution cannot occur unless the game is currently in progress.
if (status != GameStatus.IN_PROGRESS) {
revert GameNotInProgress();
}
// Update the status and emit the resolved event, note that we're performing a storage update here.
emit Resolved(status = status_ = GameStatus.DEFENDER_WINS);
// Mark resolution timestamp
resolvedAt = Timestamp.wrap(uint64(block.timestamp));
// Update lastResolved
KAILUA_TREASURY.updateLastResolved();
}
// ------------------------------
// Fault proving
// ------------------------------
/// @inheritdoc KailuaTournament
function verifyIntermediateOutput(uint64, uint256, bytes calldata, bytes calldata)
external
pure
override
returns (bool success)
{
// No known blobs to reference
}
/// @inheritdoc KailuaTournament
function getChallengerDuration(uint256) public pure override returns (Duration duration_) {
// No challenge period
}
/// @inheritdoc KailuaTournament
function minCreationTime() public view override returns (Timestamp minCreationTime_) {
minCreationTime_ = createdAt;
}
/// @inheritdoc KailuaTournament
function parentGame() public view override returns (KailuaTournament parentGame_) {
parentGame_ = this;
}
// ------------------------------
// IKailuaTreasury implementation
// ------------------------------
/// @inheritdoc IKailuaTreasury
mapping(address => uint256) public eliminationRound;
/// @inheritdoc IKailuaTreasury
mapping(address => address) public proposerOf;
/// @inheritdoc IKailuaTreasury
function eliminate(address _child, address prover) external {
KailuaTournament child = KailuaTournament(_child);
// INVARIANT: Only the child's parent may call this
KailuaTournament parent = child.parentGame();
if (msg.sender != address(parent)) {
revert Blacklisted(msg.sender, address(parent));
}
// INVARIANT: Only known proposals may be eliminated
address eliminated = proposerOf[address(child)];
if (eliminated == address(0x0)) {
revert NotProposed();
}
// INVARIANT: Cannot double-eliminate players
if (eliminationRound[eliminated] > 0) {
revert AlreadyEliminated();
}
// Record elimination round
eliminationRound[eliminated] = child.gameIndex();
// Allocate bond to prover
eliminations[prover].push(eliminated);
}
/// @inheritdoc IKailuaTreasury
bool public isProposing;
/// @inheritdoc IKailuaTreasury
address public lastResolved;
/// @inheritdoc IKailuaTreasury
function updateLastResolved() external {
// INVARIANT: Only known proposal contracts may call this function
if (proposerOf[msg.sender] == address(0x0)) {
revert NotProposed();
}
lastResolved = msg.sender;
}
// ------------------------------
// Treasury
// ------------------------------
/// @notice The locked collateral required for proposal submission
uint256 public participationBond;
/// @notice The locked collateral still paid by proposers for participation
mapping(address => uint256) public paidBonds;
/// @notice The list of players each prover has eliminated
mapping(address => address[]) public eliminations;
/// @notice The number of eliminations paid out to each prover
mapping(address => uint256) public eliminationsPaid;
/// @notice The last proposal made by each proposer
mapping(address => KailuaTournament) public lastProposal;
/// @notice The leading proposer that can extend the proposal tree
address public vanguard;
/// @notice The duration for which the vanguard may lead
Duration public vanguardAdvantage;
/// @notice Boolean flag to prevent re-entrant calls
bool internal isLocked;
modifier nonReentrant() {
require(!isLocked);
isLocked = true;
_;
isLocked = false;
}
modifier onlyFactoryOwner() {
OwnableUpgradeable factoryContract = OwnableUpgradeable(address(DISPUTE_GAME_FACTORY));
require(msg.sender == factoryContract.owner(), "not owner");
_;
}
/// @notice Pays out the prover for the eliminations it has accrued
function claimEliminationBonds(uint256 claims) public nonReentrant {
uint256 claimed = 0;
uint256 payout = 0;
for (
uint256 i = eliminationsPaid[msg.sender];
claimed < claims && i < eliminations[msg.sender].length;
(i++, claimed++)
) {
address eliminated = eliminations[msg.sender][i];
payout += paidBonds[eliminated];
paidBonds[eliminated] = 0;
}
// Increase number of bonds claimed
if (claimed > 0) {
eliminationsPaid[msg.sender] += claimed;
}
// Transfer payout
if (payout > 0) {
pay(payout, msg.sender);
}
}
/// @notice Pays the proposer back its bond
function claimProposerBond() public nonReentrant {
// INVARIANT: Can only claim back bond if not eliminated
if (eliminationRound[msg.sender] != 0) {
revert AlreadyEliminated();
}
// INVARIANT: Can only claim bond back if no pending proposals are left
KailuaTournament previousGame = lastProposal[msg.sender];
if (address(previousGame) != address(0x0)) {
KailuaTournament lastTournament = previousGame.parentGame();
if (lastTournament.children(lastTournament.contenderIndex()).status() != GameStatus.DEFENDER_WINS) {
revert GameNotResolved();
}
}
uint256 payout = paidBonds[msg.sender];
// INVARIANT: Can only claim bond if it is paid
if (payout == 0) {
revert NoCreditToClaim();
}
// Pay out and clear bond
paidBonds[msg.sender] = 0;
pay(payout, msg.sender);
}
/// @notice Transfers ETH from the contract's balance to the recipient
function pay(uint256 amount, address recipient) internal {
(bool success,) = recipient.call{value: amount}(hex"");
if (!success) revert BondTransferFailed();
}
/// @notice Updates the required bond for new proposals
function setParticipationBond(uint256 amount) external onlyFactoryOwner {
participationBond = amount;
emit BondUpdated(amount);
}
/// @notice Updates the vanguard address and advantage duration
function assignVanguard(address _vanguard, Duration _vanguardAdvantage) external onlyFactoryOwner {
vanguard = _vanguard;
vanguardAdvantage = _vanguardAdvantage;
}
/// @notice Checks the proposer's bonded amount and creates a new proposal through the factory
function propose(Claim _rootClaim, bytes calldata _extraData)
external
payable
returns (KailuaTournament tournament)
{
// Check proposer honesty
if (eliminationRound[msg.sender] > 0) {
revert BadAuth();
}
// Update proposer bond
if (msg.value > 0) {
paidBonds[msg.sender] += msg.value;
}
// Check proposer bond
if (paidBonds[msg.sender] < participationBond) {
revert IncorrectBondAmount();
}
// Create proposal
isProposing = true;
tournament = KailuaTournament(address(DISPUTE_GAME_FACTORY.create(GAME_TYPE, _rootClaim, _extraData)));
isProposing = false;
// Check proposal progression
KailuaTournament previousGame = lastProposal[msg.sender];
if (address(previousGame) != address(0x0)) {
// INVARIANT: Proposers may only extend the proposal set incrementally
if (previousGame.l2BlockNumber() >= tournament.l2BlockNumber()) {
revert BlockNumberMismatch(previousGame.l2BlockNumber(), tournament.l2BlockNumber());
}
}
// Check whether the proposer must follow a vanguard if one is set
if (vanguard != address(0x0) && vanguard != msg.sender) {
// The proposer may only counter the vanguard during the advantage time
KailuaTournament proposalParent = tournament.parentGame();
if (proposalParent.childCount() == 1) {
// Count the advantage clock since proposal was possible
uint64 elapsedAdvantage = uint64(block.timestamp - tournament.minCreationTime().raw());
if (elapsedAdvantage < vanguardAdvantage.raw()) {
revert VanguardError(address(proposalParent));
}
}
}
// Record proposer
proposerOf[address(tournament)] = msg.sender;
// Record proposal
lastProposal[msg.sender] = tournament;
}
}
FlatOPImportV1.4.0.sol 7568 lines
//import { SuperchainConfig } from "./L1/SuperchainConfig.sol";
//import { SystemConfig } from "./L1/SystemConfig.sol";
//import { OptimismPortal2 } from "./L1/OptimismPortal2.sol";
//import { DisputeGameFactory } from "./dispute/DisputeGameFactory.sol";
//import { AnchorStateRegistry } from "./dispute/AnchorStateRegistry.sol";
//import { Safe } from "../lib/safe-contracts/contracts/Safe.sol";
//import { Clone } from "@solady/utils/Clone.sol";
// The below code is copied as is from various files under https://github.com/ethereum-optimism/optimism/tree/op-contracts/v1.4.0/packages/contracts-bedrock
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.15;
// lib/openzeppelin-contracts/contracts/utils/Address.sol
// OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol)
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
* ====
*
* [IMPORTANT]
* ====
* You shouldn't rely on `isContract` to protect against flash loan attacks!
*
* Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
* like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
* constructor.
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize/address.code.length, which returns 0
// for contracts in construction, since the code is only stored at the end
// of the constructor execution.
return account.code.length > 0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success,) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCall(target, data, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data, string memory errorMessage)
internal
returns (bytes memory)
{
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage)
internal
returns (bytes memory)
{
require(address(this).balance >= value, "Address: insufficient balance for call");
require(isContract(target), "Address: call to non-contract");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data, string memory errorMessage)
internal
view
returns (bytes memory)
{
require(isContract(target), "Address: static call to non-contract");
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(address target, bytes memory data, string memory errorMessage)
internal
returns (bytes memory)
{
require(isContract(target), "Address: delegate call to non-contract");
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason using the provided one.
*
* _Available since v4.3._
*/
function verifyCallResult(bool success, bytes memory returndata, string memory errorMessage)
internal
pure
returns (bytes memory)
{
if (success) {
return returndata;
} else {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
}
// lib/openzeppelin-contracts/contracts/utils/math/Math.sol
// OpenZeppelin Contracts (last updated v4.7.0) (utils/math/Math.sol)
/**
* @dev Standard math utilities missing in the Solidity language.
*/
library Math {
enum Rounding {
Down, // Toward negative infinity
Up, // Toward infinity
Zero // Toward zero
}
/**
* @dev Returns the largest of two numbers.
*/
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a >= b ? a : b;
}
/**
* @dev Returns the smallest of two numbers.
*/
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return 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 up instead
* of rounding down.
*/
function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b - 1) / b can overflow on addition, so we distribute.
return a == 0 ? 0 : (a - 1) / b + 1;
}
/**
* @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
* @dev 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 {
// 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
// use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
// variables such that product = prod1 * 2^256 + prod0.
uint256 prod0; // Least significant 256 bits of the product
uint256 prod1; // Most significant 256 bits of the product
assembly {
let mm := mulmod(x, y, not(0))
prod0 := mul(x, y)
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}
// Handle non-overflow cases, 256 by 256 division.
if (prod1 == 0) {
return prod0 / denominator;
}
// Make sure the result is less than 2^256. Also prevents denominator == 0.
require(denominator > prod1);
///////////////////////////////////////////////
// 512 by 256 division.
///////////////////////////////////////////////
// Make division exact by subtracting the remainder from [prod1 prod0].
uint256 remainder;
assembly {
// Compute remainder using mulmod.
remainder := mulmod(x, y, denominator)
// Subtract 256 bit number from 512 bit number.
prod1 := sub(prod1, gt(remainder, prod0))
prod0 := sub(prod0, 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.
// Does not overflow because the denominator cannot be zero at this stage in the function.
uint256 twos = denominator & (~denominator + 1);
assembly {
// Divide denominator by twos.
denominator := div(denominator, twos)
// Divide [prod1 prod0] by twos.
prod0 := div(prod0, twos)
// Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
twos := add(div(sub(0, twos), twos), 1)
}
// Shift in bits from prod1 into prod0.
prod0 |= prod1 * twos;
// Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
// that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
// four bits. That is, denominator * inv = 1 mod 2^4.
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^8
inverse *= 2 - denominator * inverse; // inverse mod 2^16
inverse *= 2 - denominator * inverse; // inverse mod 2^32
inverse *= 2 - denominator * inverse; // inverse mod 2^64
inverse *= 2 - denominator * inverse; // inverse mod 2^128
inverse *= 2 - denominator * inverse; // inverse mod 2^256
// 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^256. Since the preconditions guarantee that the outcome is
// less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
// is no longer required.
result = prod0 * inverse;
return result;
}
}
/**
* @notice 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) {
uint256 result = mulDiv(x, y, denominator);
if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {
result += 1;
}
return result;
}
/**
* @dev Returns the square root of a number. It the number is not a perfect square, the value is rounded down.
*
* Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
*/
function sqrt(uint256 a) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
// For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
// We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
// `msb(a) <= a < 2*msb(a)`.
// We also know that `k`, the position of the most significant bit, is such that `msb(a) = 2**k`.
// This gives `2**k < a <= 2**(k+1)` → `2**(k/2) <= sqrt(a) < 2 ** (k/2+1)`.
// Using an algorithm similar to the msb conmputation, we are able to compute `result = 2**(k/2)` which is a
// good first aproximation of `sqrt(a)` with at least 1 correct bit.
uint256 result = 1;
uint256 x = a;
if (x >> 128 > 0) {
x >>= 128;
result <<= 64;
}
if (x >> 64 > 0) {
x >>= 64;
result <<= 32;
}
if (x >> 32 > 0) {
x >>= 32;
result <<= 16;
}
if (x >> 16 > 0) {
x >>= 16;
result <<= 8;
}
if (x >> 8 > 0) {
x >>= 8;
result <<= 4;
}
if (x >> 4 > 0) {
x >>= 4;
result <<= 2;
}
if (x >> 2 > 0) {
result <<= 1;
}
// At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
// since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
// every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
// into the expected uint128 result.
unchecked {
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
return min(result, a / result);
}
}
/**
* @notice Calculates sqrt(a), following the selected rounding direction.
*/
function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
uint256 result = sqrt(a);
if (rounding == Rounding.Up && result * result < a) {
result += 1;
}
return result;
}
}
// lib/openzeppelin-contracts/contracts/utils/math/SignedMath.sol
// OpenZeppelin Contracts (last updated v4.5.0) (utils/math/SignedMath.sol)
/**
* @dev Standard signed math utilities missing in the Solidity language.
*/
library SignedMath {
/**
* @dev Returns the largest of two signed numbers.
*/
function max(int256 a, int256 b) internal pure returns (int256) {
return a >= b ? a : b;
}
/**
* @dev Returns the smallest of two signed numbers.
*/
function min(int256 a, int256 b) internal pure returns (int256) {
return 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 {
// must be unchecked in order to support `n = type(int256).min`
return uint256(n >= 0 ? n : -n);
}
}
}
// lib/openzeppelin-contracts-upgradeable/contracts/utils/AddressUpgradeable.sol
// OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol)
/**
* @dev Collection of functions related to the address type
*/
library AddressUpgradeable {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
* ====
*
* [IMPORTANT]
* ====
* You shouldn't rely on `isContract` to protect against flash loan attacks!
*
* Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
* like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
* constructor.
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize/address.code.length, which returns 0
// for contracts in construction, since the code is only stored at the end
// of the constructor execution.
return account.code.length > 0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success,) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCall(target, data, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data, string memory errorMessage)
internal
returns (bytes memory)
{
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage)
internal
returns (bytes memory)
{
require(address(this).balance >= value, "Address: insufficient balance for call");
require(isContract(target), "Address: call to non-contract");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data, string memory errorMessage)
internal
view
returns (bytes memory)
{
require(isContract(target), "Address: static call to non-contract");
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason using the provided one.
*
* _Available since v4.3._
*/
function verifyCallResult(bool success, bytes memory returndata, string memory errorMessage)
internal
pure
returns (bytes memory)
{
if (success) {
return returndata;
} else {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
}
// lib/safe-contracts/contracts/common/Enum.sol
/**
* @title Enum - Collection of enums used in Safe contracts.
* @author Richard Meissner - @rmeissner
*/
abstract contract Enum {
enum Operation {
Call,
DelegateCall
}
}
// lib/safe-contracts/contracts/common/NativeCurrencyPaymentFallback.sol
/**
* @title NativeCurrencyPaymentFallback - A contract that has a fallback to accept native currency payments.
* @author Richard Meissner - @rmeissner
*/
abstract contract NativeCurrencyPaymentFallback {
event SafeReceived(address indexed sender, uint256 value);
/**
* @notice Receive function accepts native currency transactions.
* @dev Emits an event with sender and received value.
*/
receive() external payable {
emit SafeReceived(msg.sender, msg.value);
}
}
// lib/safe-contracts/contracts/common/SecuredTokenTransfer.sol
/**
* @title SecuredTokenTransfer - Secure token transfer.
* @author Richard Meissner - @rmeissner
*/
abstract contract SecuredTokenTransfer {
/**
* @notice Transfers a token and returns a boolean if it was a success
* @dev It checks the return data of the transfer call and returns true if the transfer was successful.
* It doesn't check if the `token` address is a contract or not.
* @param token Token that should be transferred
* @param receiver Receiver to whom the token should be transferred
* @param amount The amount of tokens that should be transferred
* @return transferred Returns true if the transfer was successful
*/
function transferToken(address token, address receiver, uint256 amount) internal returns (bool transferred) {
// 0xa9059cbb - keccack("transfer(address,uint256)")
bytes memory data = abi.encodeWithSelector(0xa9059cbb, receiver, amount);
// solhint-disable-next-line no-inline-assembly
assembly {
// We write the return value to scratch space.
// See https://docs.soliditylang.org/en/v0.7.6/internals/layout_in_memory.html#layout-in-memory
let success := call(sub(gas(), 10000), token, 0, add(data, 0x20), mload(data), 0, 0x20)
switch returndatasize()
case 0 { transferred := success }
case 0x20 { transferred := iszero(or(iszero(success), iszero(mload(0)))) }
default { transferred := 0 }
}
}
}
// lib/safe-contracts/contracts/common/SelfAuthorized.sol
/**
* @title SelfAuthorized - Authorizes current contract to perform actions to itself.
* @author Richard Meissner - @rmeissner
*/
abstract contract SelfAuthorized {
function requireSelfCall() private view {
require(msg.sender == address(this), "GS031");
}
modifier authorized() {
// Modifiers are copied around during compilation. This is a function call as it minimized the bytecode size
requireSelfCall();
_;
}
}
// lib/safe-contracts/contracts/common/SignatureDecoder.sol
/**
* @title SignatureDecoder - Decodes signatures encoded as bytes
* @author Richard Meissner - @rmeissner
*/
abstract contract SignatureDecoder {
/**
* @notice Splits signature bytes into `uint8 v, bytes32 r, bytes32 s`.
* @dev Make sure to perform a bounds check for @param pos, to avoid out of bounds access on @param signatures
* The signature format is a compact form of {bytes32 r}{bytes32 s}{uint8 v}
* Compact means uint8 is not padded to 32 bytes.
* @param pos Which signature to read.
* A prior bounds check of this parameter should be performed, to avoid out of bounds access.
* @param signatures Concatenated {r, s, v} signatures.
* @return v Recovery ID or Safe signature type.
* @return r Output value r of the signature.
* @return s Output value s of the signature.
*/
function signatureSplit(bytes memory signatures, uint256 pos)
internal
pure
returns (uint8 v, bytes32 r, bytes32 s)
{
// solhint-disable-next-line no-inline-assembly
assembly {
let signaturePos := mul(0x41, pos)
r := mload(add(signatures, add(signaturePos, 0x20)))
s := mload(add(signatures, add(signaturePos, 0x40)))
/**
* Here we are loading the last 32 bytes, including 31 bytes
* of 's'. There is no 'mload8' to do this.
* 'byte' is not working due to the Solidity parser, so lets
* use the second best option, 'and'
*/
v := and(mload(add(signatures, add(signaturePos, 0x41))), 0xff)
}
}
}
// lib/safe-contracts/contracts/common/Singleton.sol
/**
* @title Singleton - Base for singleton contracts (should always be the first super contract)
* This contract is tightly coupled to our proxy contract (see `proxies/SafeProxy.sol`)
* @author Richard Meissner - @rmeissner
*/
abstract contract Singleton {
// singleton always has to be the first declared variable to ensure the same location as in the Proxy contract.
// It should also always be ensured the address is stored alone (uses a full word)
address private singleton;
}
// lib/safe-contracts/contracts/common/StorageAccessible.sol
/**
* @title StorageAccessible - A generic base contract that allows callers to access all internal storage.
* @notice See https://github.com/gnosis/util-contracts/blob/bb5fe5fb5df6d8400998094fb1b32a178a47c3a1/contracts/StorageAccessible.sol
* It removes a method from the original contract not needed for the Safe contracts.
* @author Gnosis Developers
*/
abstract contract StorageAccessible {
/**
* @notice Reads `length` bytes of storage in the currents contract
* @param offset - the offset in the current contract's storage in words to start reading from
* @param length - the number of words (32 bytes) of data to read
* @return the bytes that were read.
*/
function getStorageAt(uint256 offset, uint256 length) public view returns (bytes memory) {
bytes memory result = new bytes(length * 32);
for (uint256 index = 0; index < length; index++) {
// solhint-disable-next-line no-inline-assembly
assembly {
let word := sload(add(offset, index))
mstore(add(add(result, 0x20), mul(index, 0x20)), word)
}
}
return result;
}
/**
* @dev Performs a delegatecall on a targetContract in the context of self.
* Internally reverts execution to avoid side effects (making it static).
*
* This method reverts with data equal to `abi.encode(bool(success), bytes(response))`.
* Specifically, the `returndata` after a call to this method will be:
* `success:bool || response.length:uint256 || response:bytes`.
*
* @param targetContract Address of the contract containing the code to execute.
* @param calldataPayload Calldata that should be sent to the target contract (encoded method name and arguments).
*/
function simulateAndRevert(address targetContract, bytes memory calldataPayload) external {
// solhint-disable-next-line no-inline-assembly
assembly {
let success := delegatecall(gas(), targetContract, add(calldataPayload, 0x20), mload(calldataPayload), 0, 0)
mstore(0x00, success)
mstore(0x20, returndatasize())
returndatacopy(0x40, 0, returndatasize())
revert(0, add(returndatasize(), 0x40))
}
}
}
// lib/safe-contracts/contracts/external/SafeMath.sol
/**
* @title SafeMath
* @notice Math operations with safety checks that revert on error (overflow/underflow)
*/
library SafeMath {
/**
* @notice Multiplies two numbers, reverts on overflow.
* @param a First number
* @param b Second number
* @return Product of a and b
*/
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the
// benefit is lost if 'b' is also tested.
// See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522
if (a == 0) {
return 0;
}
uint256 c = a * b;
require(c / a == b);
return c;
}
/**
* @notice Subtracts two numbers, reverts on overflow (i.e. if subtrahend is greater than minuend).
* @param a First number
* @param b Second number
* @return Difference of a and b
*/
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
require(b <= a);
uint256 c = a - b;
return c;
}
/**
* @notice Adds two numbers, reverts on overflow.
* @param a First number
* @param b Second number
* @return Sum of a and b
*/
function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
require(c >= a);
return c;
}
/**
* @notice Returns the largest of two numbers.
* @param a First number
* @param b Second number
* @return Largest of a and b
*/
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a >= b ? a : b;
}
}
// lib/safe-contracts/contracts/interfaces/IERC165.sol
/// @notice More details at https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/introspection/IERC165.sol
interface IERC165 {
/**
* @dev Returns true if this contract implements the interface defined by `interfaceId`.
* See the corresponding EIP section
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified
* 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);
}
// lib/safe-contracts/contracts/interfaces/ISignatureValidator.sol
contract ISignatureValidatorConstants {
// bytes4(keccak256("isValidSignature(bytes,bytes)")
bytes4 internal constant EIP1271_MAGIC_VALUE = 0x20c13b0b;
}
abstract contract ISignatureValidator is ISignatureValidatorConstants {
/**
* @notice Legacy EIP1271 method to validate a signature.
* @param _data Arbitrary length data signed on the behalf of address(this).
* @param _signature Signature byte array associated with _data.
*
* MUST return the bytes4 magic value 0x20c13b0b when function passes.
* MUST NOT modify state (using STATICCALL for solc < 0.5, view modifier for solc > 0.5)
* MUST allow external calls
*/
function isValidSignature(bytes memory _data, bytes memory _signature) public view virtual returns (bytes4);
}
// lib/solady/src/utils/Clone.sol
/// @notice Class with helper read functions for clone with immutable args.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/Clone.sol)
/// @author Adapted from clones with immutable args by zefram.eth, Saw-mon & Natalie
/// (https://github.com/Saw-mon-and-Natalie/clones-with-immutable-args)
abstract contract Clone {
/// @dev Reads all of the immutable args.
function _getArgBytes() internal pure returns (bytes memory arg) {
uint256 offset = _getImmutableArgsOffset();
/// @solidity memory-safe-assembly
assembly {
arg := mload(0x40)
let length := sub(calldatasize(), add(2, offset)) // 2 bytes are used for the length.
mstore(arg, length) // Store the length.
calldatacopy(add(arg, 0x20), offset, length)
let o := add(add(arg, 0x20), length)
mstore(o, 0) // Zeroize the slot after the bytes.
mstore(0x40, add(o, 0x20)) // Allocate the memory.
}
}
/// @dev Reads an immutable arg with type bytes.
function _getArgBytes(uint256 argOffset, uint256 length) internal pure returns (bytes memory arg) {
uint256 offset = _getImmutableArgsOffset();
/// @solidity memory-safe-assembly
assembly {
arg := mload(0x40)
mstore(arg, length) // Store the length.
calldatacopy(add(arg, 0x20), add(offset, argOffset), length)
let o := add(add(arg, 0x20), length)
mstore(o, 0) // Zeroize the slot after the bytes.
mstore(0x40, add(o, 0x20)) // Allocate the memory.
}
}
/// @dev Reads an immutable arg with type address.
function _getArgAddress(uint256 argOffset) internal pure returns (address arg) {
uint256 offset = _getImmutableArgsOffset();
/// @solidity memory-safe-assembly
assembly {
arg := shr(96, calldataload(add(offset, argOffset)))
}
}
/// @dev Reads a uint256 array stored in the immutable args.
function _getArgUint256Array(uint256 argOffset, uint256 length) internal pure returns (uint256[] memory arg) {
uint256 offset = _getImmutableArgsOffset();
/// @solidity memory-safe-assembly
assembly {
arg := mload(0x40)
mstore(arg, length) // Store the length.
calldatacopy(add(arg, 0x20), add(offset, argOffset), shl(5, length))
mstore(0x40, add(add(arg, 0x20), shl(5, length))) // Allocate the memory.
}
}
/// @dev Reads a bytes32 array stored in the immutable args.
function _getArgBytes32Array(uint256 argOffset, uint256 length) internal pure returns (bytes32[] memory arg) {
uint256 offset = _getImmutableArgsOffset();
/// @solidity memory-safe-assembly
assembly {
arg := mload(0x40)
mstore(arg, length) // Store the length.
calldatacopy(add(arg, 0x20), add(offset, argOffset), shl(5, length))
mstore(0x40, add(add(arg, 0x20), shl(5, length))) // Allocate the memory.
}
}
/// @dev Reads an immutable arg with type bytes32.
function _getArgBytes32(uint256 argOffset) internal pure returns (bytes32 arg) {
uint256 offset = _getImmutableArgsOffset();
/// @solidity memory-safe-assembly
assembly {
arg := calldataload(add(offset, argOffset))
}
}
/// @dev Reads an immutable arg with type uint256.
function _getArgUint256(uint256 argOffset) internal pure returns (uint256 arg) {
uint256 offset = _getImmutableArgsOffset();
/// @solidity memory-safe-assembly
assembly {
arg := calldataload(add(offset, argOffset))
}
}
/// @dev Reads an immutable arg with type uint248.
function _getArgUint248(uint256 argOffset) internal pure returns (uint248 arg) {
uint256 offset = _getImmutableArgsOffset();
/// @solidity memory-safe-assembly
assembly {
arg := shr(8, calldataload(add(offset, argOffset)))
}
}
/// @dev Reads an immutable arg with type uint240.
function _getArgUint240(uint256 argOffset) internal pure returns (uint240 arg) {
uint256 offset = _getImmutableArgsOffset();
/// @solidity memory-safe-assembly
assembly {
arg := shr(16, calldataload(add(offset, argOffset)))
}
}
/// @dev Reads an immutable arg with type uint232.
function _getArgUint232(uint256 argOffset) internal pure returns (uint232 arg) {
uint256 offset = _getImmutableArgsOffset();
/// @solidity memory-safe-assembly
assembly {
arg := shr(24, calldataload(add(offset, argOffset)))
}
}
/// @dev Reads an immutable arg with type uint224.
function _getArgUint224(uint256 argOffset) internal pure returns (uint224 arg) {
uint256 offset = _getImmutableArgsOffset();
/// @solidity memory-safe-assembly
assembly {
arg := shr(0x20, calldataload(add(offset, argOffset)))
}
}
/// @dev Reads an immutable arg with type uint216.
function _getArgUint216(uint256 argOffset) internal pure returns (uint216 arg) {
uint256 offset = _getImmutableArgsOffset();
/// @solidity memory-safe-assembly
assembly {
arg := shr(40, calldataload(add(offset, argOffset)))
}
}
/// @dev Reads an immutable arg with type uint208.
function _getArgUint208(uint256 argOffset) internal pure returns (uint208 arg) {
uint256 offset = _getImmutableArgsOffset();
/// @solidity memory-safe-assembly
assembly {
arg := shr(48, calldataload(add(offset, argOffset)))
}
}
/// @dev Reads an immutable arg with type uint200.
function _getArgUint200(uint256 argOffset) internal pure returns (uint200 arg) {
uint256 offset = _getImmutableArgsOffset();
/// @solidity memory-safe-assembly
assembly {
arg := shr(56, calldataload(add(offset, argOffset)))
}
}
/// @dev Reads an immutable arg with type uint192.
function _getArgUint192(uint256 argOffset) internal pure returns (uint192 arg) {
uint256 offset = _getImmutableArgsOffset();
/// @solidity memory-safe-assembly
assembly {
arg := shr(64, calldataload(add(offset, argOffset)))
}
}
/// @dev Reads an immutable arg with type uint184.
function _getArgUint184(uint256 argOffset) internal pure returns (uint184 arg) {
uint256 offset = _getImmutableArgsOffset();
/// @solidity memory-safe-assembly
assembly {
arg := shr(72, calldataload(add(offset, argOffset)))
}
}
/// @dev Reads an immutable arg with type uint176.
function _getArgUint176(uint256 argOffset) internal pure returns (uint176 arg) {
uint256 offset = _getImmutableArgsOffset();
/// @solidity memory-safe-assembly
assembly {
arg := shr(80, calldataload(add(offset, argOffset)))
}
}
/// @dev Reads an immutable arg with type uint168.
function _getArgUint168(uint256 argOffset) internal pure returns (uint168 arg) {
uint256 offset = _getImmutableArgsOffset();
/// @solidity memory-safe-assembly
assembly {
arg := shr(88, calldataload(add(offset, argOffset)))
}
}
/// @dev Reads an immutable arg with type uint160.
function _getArgUint160(uint256 argOffset) internal pure returns (uint160 arg) {
uint256 offset = _getImmutableArgsOffset();
/// @solidity memory-safe-assembly
assembly {
arg := shr(96, calldataload(add(offset, argOffset)))
}
}
/// @dev Reads an immutable arg with type uint152.
function _getArgUint152(uint256 argOffset) internal pure returns (uint152 arg) {
uint256 offset = _getImmutableArgsOffset();
/// @solidity memory-safe-assembly
assembly {
arg := shr(104, calldataload(add(offset, argOffset)))
}
}
/// @dev Reads an immutable arg with type uint144.
function _getArgUint144(uint256 argOffset) internal pure returns (uint144 arg) {
uint256 offset = _getImmutableArgsOffset();
/// @solidity memory-safe-assembly
assembly {
arg := shr(112, calldataload(add(offset, argOffset)))
}
}
/// @dev Reads an immutable arg with type uint136.
function _getArgUint136(uint256 argOffset) internal pure returns (uint136 arg) {
uint256 offset = _getImmutableArgsOffset();
/// @solidity memory-safe-assembly
assembly {
arg := shr(120, calldataload(add(offset, argOffset)))
}
}
/// @dev Reads an immutable arg with type uint128.
function _getArgUint128(uint256 argOffset) internal pure returns (uint128 arg) {
uint256 offset = _getImmutableArgsOffset();
/// @solidity memory-safe-assembly
assembly {
arg := shr(128, calldataload(add(offset, argOffset)))
}
}
/// @dev Reads an immutable arg with type uint120.
function _getArgUint120(uint256 argOffset) internal pure returns (uint120 arg) {
uint256 offset = _getImmutableArgsOffset();
/// @solidity memory-safe-assembly
assembly {
arg := shr(136, calldataload(add(offset, argOffset)))
}
}
/// @dev Reads an immutable arg with type uint112.
function _getArgUint112(uint256 argOffset) internal pure returns (uint112 arg) {
uint256 offset = _getImmutableArgsOffset();
/// @solidity memory-safe-assembly
assembly {
arg := shr(144, calldataload(add(offset, argOffset)))
}
}
/// @dev Reads an immutable arg with type uint104.
function _getArgUint104(uint256 argOffset) internal pure returns (uint104 arg) {
uint256 offset = _getImmutableArgsOffset();
/// @solidity memory-safe-assembly
assembly {
arg := shr(152, calldataload(add(offset, argOffset)))
}
}
/// @dev Reads an immutable arg with type uint96.
function _getArgUint96(uint256 argOffset) internal pure returns (uint96 arg) {
uint256 offset = _getImmutableArgsOffset();
/// @solidity memory-safe-assembly
assembly {
arg := shr(160, calldataload(add(offset, argOffset)))
}
}
/// @dev Reads an immutable arg with type uint88.
function _getArgUint88(uint256 argOffset) internal pure returns (uint88 arg) {
uint256 offset = _getImmutableArgsOffset();
/// @solidity memory-safe-assembly
assembly {
arg := shr(168, calldataload(add(offset, argOffset)))
}
}
/// @dev Reads an immutable arg with type uint80.
function _getArgUint80(uint256 argOffset) internal pure returns (uint80 arg) {
uint256 offset = _getImmutableArgsOffset();
/// @solidity memory-safe-assembly
assembly {
arg := shr(176, calldataload(add(offset, argOffset)))
}
}
/// @dev Reads an immutable arg with type uint72.
function _getArgUint72(uint256 argOffset) internal pure returns (uint72 arg) {
uint256 offset = _getImmutableArgsOffset();
/// @solidity memory-safe-assembly
assembly {
arg := shr(184, calldataload(add(offset, argOffset)))
}
}
/// @dev Reads an immutable arg with type uint64.
function _getArgUint64(uint256 argOffset) internal pure returns (uint64 arg) {
uint256 offset = _getImmutableArgsOffset();
/// @solidity memory-safe-assembly
assembly {
arg := shr(192, calldataload(add(offset, argOffset)))
}
}
/// @dev Reads an immutable arg with type uint56.
function _getArgUint56(uint256 argOffset) internal pure returns (uint56 arg) {
uint256 offset = _getImmutableArgsOffset();
/// @solidity memory-safe-assembly
assembly {
arg := shr(200, calldataload(add(offset, argOffset)))
}
}
/// @dev Reads an immutable arg with type uint48.
function _getArgUint48(uint256 argOffset) internal pure returns (uint48 arg) {
uint256 offset = _getImmutableArgsOffset();
/// @solidity memory-safe-assembly
assembly {
arg := shr(208, calldataload(add(offset, argOffset)))
}
}
/// @dev Reads an immutable arg with type uint40.
function _getArgUint40(uint256 argOffset) internal pure returns (uint40 arg) {
uint256 offset = _getImmutableArgsOffset();
/// @solidity memory-safe-assembly
assembly {
arg := shr(216, calldataload(add(offset, argOffset)))
}
}
/// @dev Reads an immutable arg with type uint32.
function _getArgUint32(uint256 argOf...
// [truncated — 346795 bytes total]
FlatR0ImportV2.0.2.sol 2277 lines
// Copyright 2025 RISC Zero, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
pragma solidity ^0.8.20;
// ../lib/openzeppelin-contracts/contracts/utils/math/SafeCast.sol
// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/SafeCast.sol)
// This file was procedurally generated from scripts/generate/templates/SafeCast.js.
/**
* @dev Wrappers over Solidity's uintXX/intXX 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);
}
}
// src/IRiscZeroSelectable.sol
// Copyright 2025 RISC Zero, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
/// @notice Selectable interface for RISC Zero verifier.
interface IRiscZeroSelectable {
/// @notice A short key attached to the seal to select the correct verifier implementation.
/// @dev The selector is taken from the hash of the verifier parameters. If two
/// receipts have different selectors (i.e. different verifier parameters), then it can
/// generally be assumed that they need distinct verifier implementations. This is used as
/// part of the RISC Zero versioning mechanism.
///
/// A selector is not intended to be collision resistant, in that it is possible to find
/// two preimages that result in the same selector. This is acceptable since it's purpose
/// to a route a request among a set of trusted verifiers, and to make errors of sending a
/// receipt to a mismatching verifiers easier to debug. It is analogous to the ABI
/// function selectors.
function SELECTOR() external view returns (bytes4);
}
// src/Util.sol
// Copyright 2024 RISC Zero, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
/// @notice reverse the byte order of the uint256 value.
/// @dev Solidity uses a big-endian ABI encoding. Reversing the byte order before encoding
/// ensure that the encoded value will be little-endian.
/// Written by k06a. https://ethereum.stackexchange.com/a/83627
function reverseByteOrderUint256(uint256 input) pure returns (uint256 v) {
v = input;
// swap bytes
v = ((v & 0xFF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00) >> 8)
| ((v & 0x00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF) << 8);
// swap 2-byte long pairs
v = ((v & 0xFFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000) >> 16)
| ((v & 0x0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF) << 16);
// swap 4-byte long pairs
v = ((v & 0xFFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000) >> 32)
| ((v & 0x00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF) << 32);
// swap 8-byte long pairs
v = ((v & 0xFFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF0000000000000000) >> 64)
| ((v & 0x0000000000000000FFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF) << 64);
// swap 16-byte long pairs
v = (v >> 128) | (v << 128);
}
/// @notice reverse the byte order of the uint32 value.
/// @dev Solidity uses a big-endian ABI encoding. Reversing the byte order before encoding
/// ensure that the encoded value will be little-endian.
/// Written by k06a. https://ethereum.stackexchange.com/a/83627
function reverseByteOrderUint32(uint32 input) pure returns (uint32 v) {
v = input;
// swap bytes
v = ((v & 0xFF00FF00) >> 8) | ((v & 0x00FF00FF) << 8);
// swap 2-byte long pairs
v = (v >> 16) | (v << 16);
}
/// @notice reverse the byte order of the uint16 value.
/// @dev Solidity uses a big-endian ABI encoding. Reversing the byte order before encoding
/// ensure that the encoded value will be little-endian.
/// Written by k06a. https://ethereum.stackexchange.com/a/83627
function reverseByteOrderUint16(uint16 input) pure returns (uint16 v) {
v = input;
// swap bytes
v = (v >> 8) | ((v & 0x00FF) << 8);
}
// src/groth16/ControlID.sol
// Copyright 2025 RISC Zero, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// This file is automatically generated by:
// cargo xtask bootstrap-groth16
library ControlID {
bytes32 public constant CONTROL_ROOT = hex"539032186827b06719244873b17b2d4c122e2d02cfb1994fe958b2523b844576";
// NOTE: This has the opposite byte order to the value in the risc0 repository.
bytes32 public constant BN254_CONTROL_ID = hex"04446e66d300eb7fb45c9726bb53c793dda407a62e9601618bb43c5c14657ac0";
}
// src/groth16/Groth16Verifier.sol
/*
Copyright 2021 0KIMS association.
This file is generated with [snarkJS](https://github.com/iden3/snarkjs).
snarkJS is a free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
snarkJS is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU General Public License
along with snarkJS. If not, see <https://www.gnu.org/licenses/>.
*/
contract Groth16Verifier {
// Scalar field size
uint256 constant r = 21888242871839275222246405745257275088548364400416034343698204186575808495617;
// Base field size
uint256 constant q = 21888242871839275222246405745257275088696311157297823662689037894645226208583;
// Verification Key data
uint256 constant alphax = 20491192805390485299153009773594534940189261866228447918068658471970481763042;
uint256 constant alphay = 9383485363053290200918347156157836566562967994039712273449902621266178545958;
uint256 constant betax1 = 4252822878758300859123897981450591353533073413197771768651442665752259397132;
uint256 constant betax2 = 6375614351688725206403948262868962793625744043794305715222011528459656738731;
uint256 constant betay1 = 21847035105528745403288232691147584728191162732299865338377159692350059136679;
uint256 constant betay2 = 10505242626370262277552901082094356697409835680220590971873171140371331206856;
uint256 constant gammax1 = 11559732032986387107991004021392285783925812861821192530917403151452391805634;
uint256 constant gammax2 = 10857046999023057135944570762232829481370756359578518086990519993285655852781;
uint256 constant gammay1 = 4082367875863433681332203403145435568316851327593401208105741076214120093531;
uint256 constant gammay2 = 8495653923123431417604973247489272438418190587263600148770280649306958101930;
uint256 constant deltax1 = 1668323501672964604911431804142266013250380587483576094566949227275849579036;
uint256 constant deltax2 = 12043754404802191763554326994664886008979042643626290185762540825416902247219;
uint256 constant deltay1 = 7710631539206257456743780535472368339139328733484942210876916214502466455394;
uint256 constant deltay2 = 13740680757317479711909903993315946540841369848973133181051452051592786724563;
uint256 constant IC0x = 8446592859352799428420270221449902464741693648963397251242447530457567083492;
uint256 constant IC0y = 1064796367193003797175961162477173481551615790032213185848276823815288302804;
uint256 constant IC1x = 3179835575189816632597428042194253779818690147323192973511715175294048485951;
uint256 constant IC1y = 20895841676865356752879376687052266198216014795822152491318012491767775979074;
uint256 constant IC2x = 5332723250224941161709478398807683311971555792614491788690328996478511465287;
uint256 constant IC2y = 21199491073419440416471372042641226693637837098357067793586556692319371762571;
uint256 constant IC3x = 12457994489566736295787256452575216703923664299075106359829199968023158780583;
uint256 constant IC3y = 19706766271952591897761291684837117091856807401404423804318744964752784280790;
uint256 constant IC4x = 19617808913178163826953378459323299110911217259216006187355745713323154132237;
uint256 constant IC4y = 21663537384585072695701846972542344484111393047775983928357046779215877070466;
uint256 constant IC5x = 6834578911681792552110317589222010969491336870276623105249474534788043166867;
uint256 constant IC5y = 15060583660288623605191393599883223885678013570733629274538391874953353488393;
// Memory data
uint16 constant pVk = 0;
uint16 constant pPairing = 128;
uint16 constant pLastMem = 896;
function verifyProof(
uint256[2] calldata _pA,
uint256[2][2] calldata _pB,
uint256[2] calldata _pC,
uint256[5] calldata _pubSignals
) public view returns (bool) {
assembly {
function checkField(v) {
if iszero(lt(v, r)) {
mstore(0, 0)
return(0, 0x20)
}
}
// G1 function to multiply a G1 value(x,y) to value in an address
function g1_mulAccC(pR, x, y, s) {
let success
let mIn := mload(0x40)
mstore(mIn, x)
mstore(add(mIn, 32), y)
mstore(add(mIn, 64), s)
success := staticcall(sub(gas(), 2000), 7, mIn, 96, mIn, 64)
if iszero(success) {
mstore(0, 0)
return(0, 0x20)
}
mstore(add(mIn, 64), mload(pR))
mstore(add(mIn, 96), mload(add(pR, 32)))
success := staticcall(sub(gas(), 2000), 6, mIn, 128, pR, 64)
if iszero(success) {
mstore(0, 0)
return(0, 0x20)
}
}
function checkPairing(pA, pB, pC, pubSignals, pMem) -> isOk {
let _pPairing := add(pMem, pPairing)
let _pVk := add(pMem, pVk)
mstore(_pVk, IC0x)
mstore(add(_pVk, 32), IC0y)
// Compute the linear combination vk_x
g1_mulAccC(_pVk, IC1x, IC1y, calldataload(add(pubSignals, 0)))
g1_mulAccC(_pVk, IC2x, IC2y, calldataload(add(pubSignals, 32)))
g1_mulAccC(_pVk, IC3x, IC3y, calldataload(add(pubSignals, 64)))
g1_mulAccC(_pVk, IC4x, IC4y, calldataload(add(pubSignals, 96)))
g1_mulAccC(_pVk, IC5x, IC5y, calldataload(add(pubSignals, 128)))
// -A
mstore(_pPairing, calldataload(pA))
mstore(add(_pPairing, 32), mod(sub(q, calldataload(add(pA, 32))), q))
// B
mstore(add(_pPairing, 64), calldataload(pB))
mstore(add(_pPairing, 96), calldataload(add(pB, 32)))
mstore(add(_pPairing, 128), calldataload(add(pB, 64)))
mstore(add(_pPairing, 160), calldataload(add(pB, 96)))
// alpha1
mstore(add(_pPairing, 192), alphax)
mstore(add(_pPairing, 224), alphay)
// beta2
mstore(add(_pPairing, 256), betax1)
mstore(add(_pPairing, 288), betax2)
mstore(add(_pPairing, 320), betay1)
mstore(add(_pPairing, 352), betay2)
// vk_x
mstore(add(_pPairing, 384), mload(add(pMem, pVk)))
mstore(add(_pPairing, 416), mload(add(pMem, add(pVk, 32))))
// gamma2
mstore(add(_pPairing, 448), gammax1)
mstore(add(_pPairing, 480), gammax2)
mstore(add(_pPairing, 512), gammay1)
mstore(add(_pPairing, 544), gammay2)
// C
mstore(add(_pPairing, 576), calldataload(pC))
mstore(add(_pPairing, 608), calldataload(add(pC, 32)))
// delta2
mstore(add(_pPairing, 640), deltax1)
mstore(add(_pPairing, 672), deltax2)
mstore(add(_pPairing, 704), deltay1)
mstore(add(_pPairing, 736), deltay2)
let success := staticcall(sub(gas(), 2000), 8, _pPairing, 768, _pPairing, 0x20)
isOk := and(success, mload(_pPairing))
}
let pMem := mload(0x40)
mstore(0x40, add(pMem, pLastMem))
// Validate that all evaluations ∈ F
checkField(calldataload(add(_pubSignals, 0)))
checkField(calldataload(add(_pubSignals, 32)))
checkField(calldataload(add(_pubSignals, 64)))
checkField(calldataload(add(_pubSignals, 96)))
checkField(calldataload(add(_pubSignals, 128)))
// Validate all evaluations
let isValid := checkPairing(_pA, _pB, _pC, _pubSignals, pMem)
mstore(0, isValid)
return(0, 0x20)
}
}
}
// /Users/ramikhalil/risczero/risc0-ethereum/lib/openzeppelin-contracts/contracts/utils/Context.sol
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)
/**
* @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;
}
fu...
// [truncated — 83328 bytes total]
KailuaLib.sol 206 lines
// Copyright 2024, 2025 RISC Zero, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.24;
import "./vendor/FlatOPImportV1.4.0.sol";
import "./vendor/FlatR0ImportV2.0.2.sol";
/// @notice Denotes the proven status of the game
/// @custom:value NONE indicates that no proof has been submitted yet.
enum ProofStatus {
NONE,
FAULT,
VALIDITY
}
// 0xd36871fd
/// @notice Thrown when a blacklisted address attempts to interact with the game.
error Blacklisted(address source, address expected);
// 0x9d3e7d24
/// @notice Thrown when a child from an unknown source appends itself to a tournament
error UnknownGame();
// 0xc105260a
/// @notice Thrown when pruning children of an unresolved parent
error GameNotResolved();
// 0x8b1dfa22
/// @notice Thrown when eliminating an already removed child
error AlreadyEliminated();
// 0x2c06a364
/// @notice Thrown when a proof is submitted for an already proven game
error AlreadyProven();
// 0xa506d334
/// @notice Thrown when a resolution is attempted for an unproven claim
error NotProven();
// 0x5e22e582
/// @notice Thrown when resolving a faulty proposal
error ProvenFaulty();
// 0xf2a87d5e
/// @notice Thrown when pruning is attempted with no children
error NotProposed();
// 0x7412124e
/// @notice Thrown when proving is attempted with two agreeing outputs
error NoConflict();
// 0x9276ab5a
/// @notice Thrown when proposing before the minimum creation time
error ProposalGapRemaining(uint256 currentTime, uint256 minCreationTime);
// 0x1434391f
/// @notice Thrown when a blob hash is missing
error BlobHashMissing(uint256 index, uint256 count);
// 0x19e3a1dc
/// @notice Occurs when the duplication counter is wrong
error InvalidDuplicationCounter();
// 0xeaa0996e
/// @notice Occurs when the anchored game block number is different
/// @param anchored The L2 block number of the anchored game
/// @param initialized This game's l2 block number
error BlockNumberMismatch(uint256 anchored, uint256 initialized);
// 0x627fad6e
/// @notice Occurs when a proposer attempts to extend the chain before the vanguard
/// @param parentGame The address of the parent proposal being extended
error VanguardError(address parentGame);
/// @notice Emitted when a proof is submitted.
/// @param signature The proposal signature
/// @param status The proven status
event Proven(bytes32 indexed signature, ProofStatus indexed status);
/// @notice Emitted when the participation bond is updated
/// @param amount The new required bond amount
event BondUpdated(uint256 amount);
interface IKailuaTreasury {
/// @notice Returns the game index at which proposer was proven faulty
function eliminationRound(address proposer) external view returns (uint256);
/// @notice Returns the proposer of a game
function proposerOf(address game) external view returns (address);
/// @notice Eliminates a child's proposer and allocates their bond to the prover
function eliminate(address child, address prover) external;
/// @notice Returns true iff a proposal is currently being submitted
function isProposing() external view returns (bool);
/// @notice Returns the last resolved proposal contract address
function lastResolved() external view returns (address);
/// @notice Updates the last resolved contract address to that of the caller
function updateLastResolved() external;
}
library KailuaKZGLib {
/// @notice The KZG commitment version
bytes32 internal constant KZG_COMMITMENT_VERSION =
bytes32(0x0100000000000000000000000000000000000000000000000000000000000000);
/// @notice The modular exponentiation precompile
address internal constant MOD_EXP = address(0x05);
/// @notice The point evaluation precompile
address internal constant KZG = address(0x0a);
/// @notice The expected result from the point evaluation precompile
bytes32 internal constant KZG_RESULT = keccak256(abi.encodePacked(FIELD_ELEMENTS_PER_BLOB, BLS_MODULUS));
/// @notice Scalar field modulus of BLS12-381
uint256 internal constant BLS_MODULUS =
52435875175126190479447740508185965837690552500527637822603658699938581184513;
/// @notice The base root of unity for indexing blob field elements
uint256 internal constant ROOT_OF_UNITY =
39033254847818212395286706435128746857159659164139250548781411570340225835782;
/// @notice The po2 for the number of field elements in a single blob
uint256 internal constant FIELD_ELEMENTS_PER_BLOB_PO2 = 12;
/// @notice The number of field elements in a single blob
uint256 internal constant FIELD_ELEMENTS_PER_BLOB = uint64(1 << FIELD_ELEMENTS_PER_BLOB_PO2);
/// @notice The index of the blob containing the FE at the provided offset
function blobIndex(uint256 outputOffset) internal pure returns (uint256 index) {
index = outputOffset / FIELD_ELEMENTS_PER_BLOB;
}
/// @notice The index of the FE at the provided offset in the blob that contains it
function fieldElementIndex(uint256 outputOffset) internal pure returns (uint32 position) {
position = uint32(outputOffset % FIELD_ELEMENTS_PER_BLOB);
}
/// @notice The versioned KZG hash of the provided blob commitment
function versionedKZGHash(bytes calldata blobCommitment) internal pure returns (bytes32 hash) {
require(blobCommitment.length == 48);
hash = ((sha256(blobCommitment) << 8) >> 8) | KZG_COMMITMENT_VERSION;
}
/// @notice The mapped FE corresponding to the input hash
function hashToFe(bytes32 hash) internal pure returns (uint256 fe) {
fe = uint256(hash) % BLS_MODULUS;
}
/// @notice Returns true iff the proof shows that the FE is part of the blob at the provided position
function verifyKZGBlobProof(
bytes32 versionedBlobHash,
uint32 index,
uint256 value,
bytes calldata blobCommitment,
bytes calldata proof
) internal returns (bool success) {
uint256 rootOfUnity = modExp(reverseBits(index));
// Byte range Name Description
// [0:32] versioned_hash Reference to a blob in the execution layer.
// [32:64] x x-coordinate at which the blob is being evaluated.
// [64:96] y y-coordinate at which the blob is being evaluated.
// [96:144] commitment Commitment to the blob being evaluated.
// [144:192] proof Proof associated with the commitment.
bytes memory kzgCallData = abi.encodePacked(versionedBlobHash, rootOfUnity, value, blobCommitment, proof);
// The precompile will reject non-canonical field elements (i.e. value must be less than BLS_MODULUS).
(bool _success, bytes memory kzgResult) = KZG.call(kzgCallData);
// Validate the precompile response
require(keccak256(kzgResult) == KZG_RESULT);
// Return the result
success = _success;
}
/// @notice Calls the modular exponentiation precompile with a fixed base and modulus
function modExp(uint256 exponent) internal returns (uint256 result) {
bytes memory modExpData =
abi.encodePacked(uint256(32), uint256(32), uint256(32), ROOT_OF_UNITY, exponent, BLS_MODULUS);
(bool success, bytes memory mexpResult) = MOD_EXP.call(modExpData);
require(success);
result = uint256(bytes32(mexpResult));
}
/// @notice Reverses the bits of the input index
function reverseBits(uint32 index) internal pure returns (uint256 result) {
for (uint256 i = 0; i < FIELD_ELEMENTS_PER_BLOB_PO2; i++) {
result <<= 1;
result |= ((1 << i) & index) >> i;
}
}
}
KailuaTournament.sol 657 lines
// Copyright 2024, 2025 RISC Zero, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.24;
import "./KailuaLib.sol";
import "./vendor/FlatOPImportV1.4.0.sol";
import "./vendor/FlatOPImportV1.4.0.sol";
import "./vendor/FlatR0ImportV2.0.2.sol";
abstract contract KailuaTournament is Clone, IDisputeGame {
// ------------------------------
// Immutable configuration
// ------------------------------
/// @notice The Kailua Treasury Implementation contract address
IKailuaTreasury public immutable KAILUA_TREASURY;
/// @notice The RISC Zero verifier contract
IRiscZeroVerifier public immutable RISC_ZERO_VERIFIER;
/// @notice The RISC Zero image id of the fault proof program
bytes32 public immutable FPVM_IMAGE_ID;
/// @notice The hash of the game configuration
bytes32 public immutable ROLLUP_CONFIG_HASH;
/// @notice The number of outputs a proposal must publish
uint64 public immutable PROPOSAL_OUTPUT_COUNT;
/// @notice The number of blocks each output must cover
uint64 public immutable OUTPUT_BLOCK_SPAN;
/// @notice The number of blobs a claim must provide
uint64 public immutable PROPOSAL_BLOBS;
/// @notice The game type ID
GameType public immutable GAME_TYPE;
/// @notice The OptimismPortal2 instance
OptimismPortal2 public immutable OPTIMISM_PORTAL;
/// @notice The DisputeGameFactory instance
DisputeGameFactory public immutable DISPUTE_GAME_FACTORY;
constructor(
IKailuaTreasury _kailuaTreasury,
IRiscZeroVerifier _verifierContract,
bytes32 _imageId,
bytes32 _configHash,
uint64 _proposalOutputCount,
uint64 _outputBlockSpan,
GameType _gameType,
OptimismPortal2 _optimismPortal
) {
KAILUA_TREASURY = _kailuaTreasury;
RISC_ZERO_VERIFIER = _verifierContract;
FPVM_IMAGE_ID = _imageId;
ROLLUP_CONFIG_HASH = _configHash;
PROPOSAL_OUTPUT_COUNT = _proposalOutputCount;
OUTPUT_BLOCK_SPAN = _outputBlockSpan;
// discard published root commitment in calldata
_proposalOutputCount--;
PROPOSAL_BLOBS = (_proposalOutputCount / uint64(KailuaKZGLib.FIELD_ELEMENTS_PER_BLOB))
+ ((_proposalOutputCount % uint64(KailuaKZGLib.FIELD_ELEMENTS_PER_BLOB)) == 0 ? 0 : 1);
GAME_TYPE = _gameType;
OPTIMISM_PORTAL = _optimismPortal;
DISPUTE_GAME_FACTORY = OPTIMISM_PORTAL.disputeGameFactory();
}
function initializeInternal() internal {
// INVARIANT: The game must not have already been initialized.
if (createdAt.raw() > 0) revert AlreadyInitialized();
// Allow only the treasury to create new games
if (gameCreator() != address(KAILUA_TREASURY)) {
revert Blacklisted(gameCreator(), address(KAILUA_TREASURY));
}
// Set the game's starting timestamp
createdAt = Timestamp.wrap(uint64(block.timestamp));
// Set the game's index in the factory
gameIndex = DISPUTE_GAME_FACTORY.gameCount();
// Read respected status
wasRespectedGameTypeWhenCreated = OPTIMISM_PORTAL.respectedGameType().raw() == GAME_TYPE.raw();
}
// ------------------------------
// Game State
// ------------------------------
/// @notice The blob hashes used to create the game
Hash[] public proposalBlobHashes;
/// @notice The game's index in the factory
uint256 public gameIndex;
/// @notice The address of the prover of a proposal signature
mapping(bytes32 => address) public prover;
/// @notice The timestamp of when the first proof for a proposal signature was made
mapping(bytes32 => Timestamp) public provenAt;
/// @notice The current proof status of a proposal signature
mapping(bytes32 => ProofStatus) public proofStatus;
/// @notice The proposals extending this proposal
KailuaTournament[] public children;
/// @notice The first surviving contender
uint64 public contenderIndex;
/// @notice Duplicates of the last surviving contender proposal
uint64[] public contenderDuplicates;
/// @notice The next unprocessed opponent
uint64 public opponentIndex;
/// @notice The signature of the child accepted through a validity proof
bytes32 public validChildSignature;
/// @notice Returns the hash of the output claim and all blob hashes associated with this proposal
function signature() public view returns (bytes32 signature_) {
// note: the absence of the l1Head in the signature implies that
// proofs will eventually demonstrate derivation
signature_ = sha256(abi.encodePacked(rootClaim().raw(), proposalBlobHashes));
}
/// @notice Returns whether a child can be considered valid
function isViableSignature(bytes32 childSignature) public view returns (bool isViableSignature_) {
if (validChildSignature != 0) {
isViableSignature_ = childSignature == validChildSignature;
} else {
isViableSignature_ = proofStatus[childSignature] != ProofStatus.FAULT;
}
}
/// @notice Returns the address of the prover of the specified signature or the prover of the valid signature
function getPayoutRecipient(bytes32 childSignature) internal view returns (address payoutRecipient) {
payoutRecipient = prover[childSignature];
if (payoutRecipient == address(0x0)) {
payoutRecipient = prover[validChildSignature];
}
}
/// @notice Returns true iff the child proposal was eliminated
function isChildEliminated(KailuaTournament child) internal view returns (bool) {
address _proposer = KAILUA_TREASURY.proposerOf(address(child));
uint256 eliminationRound = KAILUA_TREASURY.eliminationRound(_proposer);
if (eliminationRound == 0 || eliminationRound > child.gameIndex()) {
// This proposer has not been eliminated as of their proposal at gameIndex
return false;
}
return true;
}
/// @notice Returns the number of children
function childCount() external view returns (uint256 count_) {
count_ = children.length;
}
/// @notice Registers a new proposal that extends this one
function appendChild() external {
// INVARIANT: The calling contract is a newly deployed contract by the dispute game factory
if (!KAILUA_TREASURY.isProposing()) {
revert UnknownGame();
}
// INVARIANT: The calling KailuaGame contract is not referring to itself as a parent
if (msg.sender == address(this)) {
revert InvalidParent();
}
// INVARIANT: No longer accept proposals after resolution
if (contenderIndex < children.length && children[contenderIndex].status() == GameStatus.DEFENDER_WINS) {
revert ClaimAlreadyResolved();
}
// Append new child to children list
children.push(KailuaTournament(msg.sender));
}
/// @notice Returns the amount of time left for challenges as of the input timestamp.
function getChallengerDuration(uint256 asOfTimestamp) public view virtual returns (Duration duration_);
/// @notice Returns the earliest time at which this proposal could have been created
function minCreationTime() public view virtual returns (Timestamp minCreationTime_);
/// @notice Returns the parent game contract.
function parentGame() public view virtual returns (KailuaTournament parentGame_);
/// @notice Returns the proposer address
function proposer() public view returns (address proposer_) {
proposer_ = KAILUA_TREASURY.proposerOf(address(this));
}
/// @notice Verifies that an intermediate output was part of the proposal
function verifyIntermediateOutput(
uint64 outputNumber,
uint256 outputFe,
bytes calldata blobCommitment,
bytes calldata kzgProof
) external virtual returns (bool success);
function updateProofStatus(address payoutRecipient, bytes32 childSignature, ProofStatus outcome) internal {
// INVARIANT: Proofs can only be submitted once
if (proofStatus[childSignature] != ProofStatus.NONE) {
revert AlreadyProven();
}
// Update proof status
proofStatus[childSignature] = outcome;
// Announce proof status
emit Proven(childSignature, outcome);
// Set the game's prover address
prover[childSignature] = payoutRecipient;
// Set the game's proving timestamp
provenAt[childSignature] = Timestamp.wrap(uint64(block.timestamp));
}
// ------------------------------
// IDisputeGame implementation
// ------------------------------
/// @inheritdoc IDisputeGame
Timestamp public createdAt;
/// @inheritdoc IDisputeGame
Timestamp public resolvedAt;
/// @inheritdoc IDisputeGame
GameStatus public status;
/// @inheritdoc IDisputeGame
function gameType() external view returns (GameType gameType_) {
gameType_ = GAME_TYPE;
}
/// @inheritdoc IDisputeGame
function gameCreator() public pure returns (address creator_) {
creator_ = _getArgAddress(0x00);
}
/// @inheritdoc IDisputeGame
function rootClaim() public pure returns (Claim rootClaim_) {
rootClaim_ = Claim.wrap(_getArgBytes32(0x14));
}
/// @inheritdoc IDisputeGame
function l1Head() public pure returns (Hash l1Head_) {
l1Head_ = Hash.wrap(_getArgBytes32(0x34));
}
/// @notice The l2BlockNumber of the claim's output root.
function l2BlockNumber() public pure returns (uint256 l2BlockNumber_) {
l2BlockNumber_ = uint256(_getArgUint64(0x54));
}
/// @inheritdoc IDisputeGame
function gameData() external view returns (GameType gameType_, Claim rootClaim_, bytes memory extraData_) {
gameType_ = GAME_TYPE;
rootClaim_ = this.rootClaim();
extraData_ = this.extraData();
}
/// @notice True iff the Kailua GameType was respected by OptimismPortal at time of creation
bool public wasRespectedGameTypeWhenCreated;
// ------------------------------
// Tournament
// ------------------------------
/// @notice Eliminates children until at least one remains
function pruneChildren(uint256 stepLimit) external returns (KailuaTournament) {
// INVARIANT: Only finalized proposals may prune tournaments
if (status != GameStatus.DEFENDER_WINS) {
revert GameNotResolved();
}
// INVARIANT: No tournament to play without at least one child
if (children.length == 0) {
revert NotProposed();
}
// Resume from prior surviving contender
uint64 u = contenderIndex;
// Resume from prior unprocessed opponent
uint64 v = opponentIndex;
// Abort if out of bounds
if (u == children.length) {
return KailuaTournament(address(0x0));
}
// Advance v if needed
if (v <= u) {
// INVARIANT: contenderDuplicates is empty
v = u + 1;
}
// Note: u < children.length
// Fetch contender details
KailuaTournament contender = children[u];
bytes32 contenderSignature = contender.signature();
// Ensure survivor decision finality after resolution
if (contender.status() == GameStatus.DEFENDER_WINS) {
return contender;
}
// If the contender is invalid then we eliminate it and find the next viable contender using the opponent
// pointer. This search could terminate early if the elimination limit is reached.
// If the contender is valid and its proposer is not eliminated, this is skipped.
if (!isViableSignature(contenderSignature) || isChildEliminated(contender)) {
// INVARIANT: If branch entered through isChildEliminated condition, contenderDuplicates is empty
// Eliminate duplicates
address payoutRecipient = getPayoutRecipient(contenderSignature);
for (uint256 i = contenderDuplicates.length; i > 0 && stepLimit > 0; (i--, stepLimit--)) {
KailuaTournament duplicate = children[contenderDuplicates[i - 1]];
if (!isChildEliminated(duplicate)) {
KAILUA_TREASURY.eliminate(address(duplicate), payoutRecipient);
}
contenderDuplicates.pop();
}
// Abort if elimination allowance exhausted before eliminating all duplicate contenders
if (stepLimit == 0) {
return KailuaTournament(address(0x0));
}
// Eliminate contender
if (!isChildEliminated(contender)) {
KAILUA_TREASURY.eliminate(address(contender), payoutRecipient);
}
stepLimit--;
// Find next viable contender
// INVARIANT: v > max(u, contenderDuplicates);
u = v;
for (; u < children.length && stepLimit > 0; (u++, stepLimit--)) {
// Skip if previously eliminated
contender = children[u];
if (isChildEliminated(contender)) {
continue;
}
// Eliminate if faulty
contenderSignature = contender.signature();
if (!isViableSignature(contenderSignature)) {
// eliminate the unviable contender
KAILUA_TREASURY.eliminate(address(contender), getPayoutRecipient(contenderSignature));
continue;
}
// Select u as next viable contender
break;
}
// Store contender
contenderIndex = u;
// Select the next possible opponent
v = u + 1;
}
// Eliminate faulty opponents if we've landed on a viable contender
if (u < children.length && isViableSignature(children[u].signature())) {
// Iterate over opponents to eliminate them
for (; v < children.length && stepLimit > 0; (v++, stepLimit--)) {
KailuaTournament opponent = children[v];
// If the contender hasn't been challenged for as long as the timeout, declare them winner
if (contender.getChallengerDuration(opponent.createdAt().raw()).raw() == 0) {
// Note: This implies eliminationLimit > 0
break;
}
// If the opponent proposer is eliminated, skip
if (isChildEliminated(opponent)) {
continue;
}
// Append contender duplicate
bytes32 opponentSignature = opponent.signature();
if (opponentSignature == contenderSignature) {
contenderDuplicates.push(v);
continue;
}
// If there is insufficient proof data, abort
// Validity: The contender is the proven child, the opponent must be incorrect
// Fault: The contender is not proven faulty, the opponent may (not) be.
if (isViableSignature(opponentSignature)) {
revert NotProven();
}
// eliminate the opponent with the unviable proposal
KAILUA_TREASURY.eliminate(address(opponent), getPayoutRecipient(opponentSignature));
}
// INVARIANT: v > u && contender == children[u]
// Record incremental opponent elimination progress
opponentIndex = v;
// Return the sole survivor if no more matches can be played
if (v == children.length || stepLimit > 0) {
return contender;
}
}
// No survivor yet
return KailuaTournament(address(0x0));
}
// ------------------------------
// Validity proving
// ------------------------------
/// @notice Returns the hash of all blob hashes associated with this proposal
function blobsHash() public view returns (bytes32 blobsHash_) {
blobsHash_ = sha256(abi.encodePacked(proposalBlobHashes));
}
/// @notice Proves that a proposal is valid
function proveValidity(address payoutRecipient, address l1HeadSource, uint64 childIndex, bytes calldata encodedSeal)
external
{
KailuaTournament childContract = children[childIndex];
// INVARIANT: Can only prove validity of unresolved proposals
if (childContract.status() != GameStatus.IN_PROGRESS) {
revert GameNotInProgress();
}
// Store validity proof data (deleted on revert)
validChildSignature = childContract.signature();
// INVARIANT: No longer accept proofs after resolution
if (contenderIndex < children.length && children[contenderIndex].status() == GameStatus.DEFENDER_WINS) {
revert ClaimAlreadyResolved();
}
// Calculate the expected precondition hash if blob data is necessary for proposal
bytes32 preconditionHash = bytes32(0x0);
if (PROPOSAL_OUTPUT_COUNT > 1) {
preconditionHash = sha256(
abi.encodePacked(
uint64(l2BlockNumber()),
uint64(PROPOSAL_OUTPUT_COUNT),
uint64(OUTPUT_BLOCK_SPAN),
childContract.blobsHash()
)
);
}
// update proof status
prove(
l1HeadSource,
payoutRecipient,
preconditionHash,
rootClaim().raw(),
childContract.rootClaim().raw(),
PROPOSAL_OUTPUT_COUNT,
encodedSeal,
validChildSignature,
ProofStatus.VALIDITY
);
}
// ------------------------------
// Fault proving
// ------------------------------
/// @notice Proves that a proposal committed to an incorrect transition
function proveOutputFault(
// [ payoutRecipient, l1HeadSource ]
address[2] calldata prHs,
// [ childIndex, outputOffset ]
uint64[2] calldata co,
bytes calldata encodedSeal,
// [ acceptedOutputHash, computedOutputHash ]
bytes32[2] memory ac,
uint256 proposedOutputFe,
bytes[][2] calldata kzgCommitmentsProofs
) external {
KailuaTournament childContract = children[co[0]];
// INVARIANT: Proofs cannot be submitted unless the child is playing.
if (childContract.status() != GameStatus.IN_PROGRESS) {
revert GameNotInProgress();
}
// INVARIANT: No longer accept proofs after resolution
if (contenderIndex < children.length && children[contenderIndex].status() == GameStatus.DEFENDER_WINS) {
revert ClaimAlreadyResolved();
}
// INVARIANT: Proofs can only pertain to intermediate outputs
if (co[1] >= PROPOSAL_OUTPUT_COUNT) {
revert InvalidDisputedClaimIndex();
}
// Validate the common output root.
if (co[1] == 0) {
// Note: acceptedOutputHash cannot be a reduced fe because the comparison below will fail
// The safe output is the parent game's output when proving the first output
require(ac[0] == rootClaim().raw(), "bad acceptedOutput");
} else {
// Note: acceptedOutputHash cannot be a reduced fe because the journal would not be provable
// Prove common output publication
require(
childContract.verifyIntermediateOutput(
co[1] - 1, KailuaKZGLib.hashToFe(ac[0]), kzgCommitmentsProofs[0][0], kzgCommitmentsProofs[1][0]
),
"bad acceptedOutput kzg"
);
}
// Validate the claimed output root.
if (co[1] == PROPOSAL_OUTPUT_COUNT - 1) {
// INVARIANT: Proofs can only show disparities
if (ac[1] == childContract.rootClaim().raw()) {
revert NoConflict();
}
} else {
// Note: proposedOutputFe must be a canonical point or point eval precompile call will fail
// Prove divergent output publication
require(
childContract.verifyIntermediateOutput(
co[1],
proposedOutputFe,
kzgCommitmentsProofs[0][kzgCommitmentsProofs[0].length - 1],
kzgCommitmentsProofs[1][kzgCommitmentsProofs[1].length - 1]
),
"bad proposedOutput kzg"
);
// INVARIANT: Proofs can only show disparities
if (KailuaKZGLib.hashToFe(ac[1]) == proposedOutputFe) {
revert NoConflict();
}
}
// update proof status
prove(
prHs[1],
prHs[0],
bytes32(0),
ac[0],
ac[1],
co[1] + 1,
encodedSeal,
childContract.signature(),
ProofStatus.FAULT
);
}
/// @notice Proves that a proposal contains invalid intermediate data
function proveTrailFault(
address payoutRecipient,
uint64[2] calldata co,
uint256 proposedOutputFe,
bytes calldata blobCommitment,
bytes calldata kzgProof
) external {
KailuaTournament childContract = children[co[0]];
// INVARIANT: Proofs cannot be submitted unless the children are playing.
if (childContract.status() != GameStatus.IN_PROGRESS) {
revert GameNotInProgress();
}
// INVARIANT: No longer accept proofs after resolution
if (contenderIndex < children.length && children[contenderIndex].status() == GameStatus.DEFENDER_WINS) {
revert ClaimAlreadyResolved();
}
// INVARIANT: Proofs can only pertain to trail data
if (co[1] < PROPOSAL_OUTPUT_COUNT) {
revert InvalidDisputedClaimIndex();
}
// We expect all trail data to be zeroed
if (proposedOutputFe == 0) {
revert NoConflict();
}
// Because the root claim is considered the last published output, we shift the provided output offset down by
// one to correctly point to the target trailing zero output
// INVARIANT: The divergence occurs in the last blob
uint64 feOffset = co[1] - 1;
if (KailuaKZGLib.blobIndex(feOffset) != PROPOSAL_BLOBS - 1) {
revert InvalidDataRemainder();
}
// Validate the claimed output root publications
// Note: proposedOutputFe must be a canonical field element or point eval precompile call will fail
require(
childContract.verifyIntermediateOutput(feOffset, proposedOutputFe, blobCommitment, kzgProof),
"bad proposedOutput kzg"
);
// Update dispute status based on trailing data
updateProofStatus(payoutRecipient, childContract.signature(), ProofStatus.FAULT);
}
// ------------------------------
// ZK Proving
// ------------------------------
/// @notice Verifies a ZK proof and updates the proof status according to the provided outcome if the proof is valid
function prove(
address l1HeadSource,
address payoutRecipient,
bytes32 preconditionHash,
bytes32 acceptedOutputHash,
bytes32 computedOutputHash,
uint64 outputCount,
bytes calldata encodedSeal,
bytes32 childSignature,
ProofStatus outcome
) internal {
// Validate the l1Head source
if (KAILUA_TREASURY.proposerOf(l1HeadSource) == address(0x0)) {
revert UnknownGame();
}
// Construct the expected journal
bytes memory journal = abi.encodePacked(
// The address of the recipient of the payout for this proof
payoutRecipient,
// The blob equivalence precondition hash
preconditionHash,
// The L1 head hash containing the safe L2 chain data that may reproduce the L2 head hash.
KailuaTournament(l1HeadSource).l1Head().raw(),
// The accepted output
acceptedOutputHash,
// The proposed output
computedOutputHash,
// The claim block number
uint64(l2BlockNumber() + outputCount * OUTPUT_BLOCK_SPAN),
// The rollup configuration hash
ROLLUP_CONFIG_HASH,
// The FPVM Image ID
FPVM_IMAGE_ID
);
// Revert on proof verification failure
RISC_ZERO_VERIFIER.verify(encodedSeal, FPVM_IMAGE_ID, sha256(journal));
// Mark the child as proven
updateProofStatus(payoutRecipient, childSignature, outcome);
}
}
Read Contract
DISPUTE_GAME_FACTORY 0x82ff53a1 → address
FPVM_IMAGE_ID 0x971805d8 → bytes32
GAME_TYPE 0xdbbf2c47 → uint32
KAILUA_TREASURY 0xafdaec50 → address
L2_BLOCK_NUMBER 0x326f8195 → uint64
OPTIMISM_PORTAL 0x85734ee1 → address
OUTPUT_BLOCK_SPAN 0x8e8abdb1 → uint64
PROPOSAL_BLOBS 0xdce87e68 → uint64
PROPOSAL_OUTPUT_COUNT 0xcfa45128 → uint64
RISC_ZERO_VERIFIER 0xf3c0ce22 → address
ROLLUP_CONFIG_HASH 0x2a6375da → bytes32
ROOT_CLAIM 0x4a1890f0 → bytes32
blobsHash 0xfcddca98 → bytes32
childCount 0x8bc3bbc0 → uint256
children 0x7002ce42 → address
contenderDuplicates 0x077fb469 → uint64
contenderIndex 0x768c7204 → uint64
createdAt 0xcf09e0d0 → uint64
eliminationRound 0x16112bcf → uint256
eliminations 0xe1f3c010 → address
eliminationsPaid 0x2b44606d → uint256
extraData 0x609d3334 → bytes
gameCreator 0x37b1b229 → address
gameData 0xfa24f743 → uint32, bytes32, bytes
gameIndex 0x5654a341 → uint256
gameType 0xbbdc02db → uint32
getChallengerDuration 0xbd8da956 → uint64
isProposing 0xeb45ec0d → bool
isViableSignature 0xa09159a6 → bool
l1Head 0x6361506d → bytes32
l2BlockNumber 0x8b85902b → uint256
lastProposal 0xc7265bc6 → address
lastResolved 0x8f0ac453 → address
minCreationTime 0x4c6f8414 → uint64
opponentIndex 0x1bbd66f3 → uint64
paidBonds 0x93294bc3 → uint256
parentGame 0x1d9e47f4 → address
participationBond 0x12f9650f → uint256
proofStatus 0x6e023443 → uint8
proposalBlobHashes 0x429e88d0 → bytes32
proposer 0xa8e4fb90 → address
proposerOf 0xbb7ecb21 → address
provenAt 0xb84c2786 → uint64
prover 0xa8754594 → address
resolvedAt 0x19effeb4 → uint64
rootClaim 0xbcef3b55 → bytes32
signature 0x51ff4847 → bytes32
status 0x200d2ed2 → uint8
treasuryAddress 0xc5f956af → address
validChildSignature 0x716e5b4a → bytes32
vanguard 0x77e4b3d5 → address
vanguardAdvantage 0xb425dcb7 → uint64
verifyIntermediateOutput 0x1e24fdd5 → bool
version 0x54fd4d50 → string
wasRespectedGameTypeWhenCreated 0x250e69bd → bool
Write Contract 14 functions
These functions modify contract state and require a wallet transaction to execute.
appendChild 0x2a664874
No parameters
assignVanguard 0xa9b51cb6
address _vanguard
uint64 _vanguardAdvantage
claimEliminationBonds 0xaebda6f8
uint256 claims
claimProposerBond 0xbc586c48
No parameters
eliminate 0x2a90b48f
address _child
address prover
initialize 0x8129fc1c
No parameters
propose 0xca0dc973
bytes32 _rootClaim
bytes _extraData
returns: address
proveOutputFault 0xa401bc8c
address[2] prHs
uint64[2] co
bytes encodedSeal
bytes32[2] ac
uint256 proposedOutputFe
bytes[][2] kzgCommitmentsProofs
proveTrailFault 0x4dafd789
address payoutRecipient
uint64[2] co
uint256 proposedOutputFe
bytes blobCommitment
bytes kzgProof
proveValidity 0x69d5324d
address payoutRecipient
address l1HeadSource
uint64 childIndex
bytes encodedSeal
pruneChildren 0x70a87a98
uint256 stepLimit
returns: address
resolve 0x2810e1d6
No parameters
returns: uint8
setParticipationBond 0xe854e31a
uint256 amount
updateLastResolved 0x817804af
No parameters
Recent Transactions
No transactions found for this address