Cryo Explorer Ethereum Mainnet

Address Contract Partially Verified

Address 0x287787F55723f7a816aA37De1dbD72a4671De1cc
Balance 0 ETH
Nonce 1
Code Size 15694 bytes
Indexed Transactions 0
External Etherscan · Sourcify

Contract Bytecode

15694 bytes
0x608060405234801561001057600080fd5b50600436106102535760003560e01c80638da5cb5b11610146578063c6a54924116100c3578063d339785011610087578063d339785014610651578063d9c65c2714610664578063de9b771f14610677578063f2fde38b1461068a578063f79e41641461069d578063f953cec7146106b057600080fd5b8063c6a54924146105d9578063c714b768146105ec578063cc581d79146105ff578063cd931e401461062b578063d0b05d351461063e57600080fd5b8063ad280eb01161010a578063ad280eb014610567578063aea4e49e1461057a578063bbb781cc1461058d578063bded9a7c1461059a578063c0857ba0146105c657600080fd5b80638da5cb5b146104f1578063972c492814610502578063998a1d1514610515578063a04b29b914610528578063a6197a9f1461053b57600080fd5b806345f0791d116101d457806370a082311161019857806370a082311461049d578063715018a6146104b0578063795b396d146104b8578063840d6dcf146104cb5780638d18fa62146104de57600080fd5b806345f0791d146104075780634f04eba414610432578063607f2d421461044557806363c28db1146104685780636a6940cc1461048a57600080fd5b80631959a0021161021b5780631959a002146103265780633723148e146103735780633ac4b3ac146103865780633eee69a9146103b25780633f02d59e146103db57600080fd5b806301ffc9a7146102585780630e1db437146102915780630e387de6146102a6578063150b7a02146102db57806315b31bbb14610313575b600080fd5b61027c6102663660046134a9565b6001600160e01b0319166307f5828d60e41b1490565b60405190151581526020015b60405180910390f35b6102a461029f366004613598565b6106c3565b005b6102cd7f8c5261668696ce22758910d05bab8f186d6eb247ceac2af2e82c7dc17669b03681565b604051908152602001610288565b6102fa6102e9366004613634565b630a85bd0160e11b95945050505050565b6040516001600160e01b03199091168152602001610288565b6102a46103213660046136d2565b6106f8565b6103586103343660046136f4565b60086020526000908152604090206001810154600382015460059092015490919083565b60408051938452602084019290925290820152606001610288565b6102a4610381366004613711565b610722565b6102cd6103943660046136f4565b6001600160a01b031660009081526008602052604090206001015490565b6102cd6103c03660046136f4565b6001600160a01b031660009081526008602052604090205490565b6102cd6103e93660046136f4565b6001600160a01b031660009081526008602052604090206004015490565b60065461041a906001600160a01b031681565b6040516001600160a01b039091168152602001610288565b6102a4610440366004613711565b6108c0565b61027c610453366004613711565b60036020526000908152604090205460ff1681565b61047b6104763660046136f4565b6109ba565b60405161028893929190613765565b60075461041a906001600160a01b031681565b6102cd6104ab3660046136f4565b610b1f565b6102a4610c7b565b6102a46104c63660046137a8565b610cb8565b6102a46104d93660046137a8565b610e2f565b6102a46104ec3660046137a8565b610f7a565b6004546001600160a01b031661041a565b60025461041a906001600160a01b031681565b6102a4610523366004613711565b6110c5565b6102a46105363660046137a8565b611220565b6102cd6105493660046136f4565b6001600160a01b031660009081526008602052604090206002015490565b6102a46105753660046137a8565b6113e5565b6102a46105883660046136f4565b61157b565b60095461027c9060ff1681565b6102cd6105a83660046136f4565b6001600160a01b031660009081526008602052604090206005015490565b60015461041a906001600160a01b031681565b6102a46105e7366004613711565b611609565b6102a46105fa366004613711565b6116da565b6102cd61060d3660046136f4565b6001600160a01b031660009081526008602052604090206003015490565b6102a46106393660046137dc565b611834565b6102a461064c3660046137a8565b611879565b6102a461065f366004613598565b611a11565b6102a4610672366004613711565b611a41565b60005461041a906001600160a01b031681565b6102a46106983660046136f4565b611b0e565b60055461041a906001600160a01b031681565b6102a46106be36600461383c565b611b5b565b8251156106d3576106d3836113e5565b8151156106e3576106e382611879565b8051156106f3576106f381611220565b505050565b6004546001600160a01b0316331461070f57600080fd5b6009805460ff1916911515919091179055565b60095460ff161561074e5760405162461bcd60e51b8152600401610745906138bb565b60405180910390fd5b33600090815260086020908152604091829020805483518184028101840190945280845290926107b692909184918301828280156107ab57602002820191906000526020600020905b815481526020019060010190808311610797575b505050505083611b66565b6107f75760405162461bcd60e51b81526020600482015260126024820152712737ba10323ab733b2b7b71037bbb732b91760711b6044820152606401610745565b6005546040516323b872dd60e01b81526001600160a01b03909116906323b872dd9061082b903090339087906004016138f2565b600060405180830381600087803b15801561084557600080fd5b505af1158015610859573d6000803e3d6000fd5b505050506108678183611bbb565b805460000361087857600060018201555b6108bc3360005b604080516001600160a01b039093166020840152820152600160608201526000608082015260a0015b604051602081830303815290604052611ced565b5050565b60095460ff16156108e35760405162461bcd60e51b8152600401610745906138bb565b336000818152600860209081526040808320600480820180546001810182559086529390942090920185905560075490516323b872dd60e01b815291936001600160a01b03909116926323b872dd92610941929130918891016138f2565b600060405180830381600087803b15801561095b57600080fd5b505af115801561096f573d6000803e3d6000fd5b505050508060050154600003610986574260058201555b6108bc3360025b604080516001600160a01b039093166020840152820152600160608201819052608082015260a0016108a8565b6001600160a01b03811660009081526008602090815260408083208151815460e09481028201850190935260c081018381526060958695869591949284929091849190840182828015610a2c57602002820191906000526020600020905b815481526020019060010190808311610a18575b505050505081526020016001820154815260200160028201805480602002602001604051908101604052809291908181526020018280548015610a8e57602002820191906000526020600020905b815481526020019060010190808311610a7a575b505050505081526020016003820154815260200160048201805480602002602001604051908101604052809291908181526020018280548015610af057602002820191906000526020600020905b815481526020019060010190808311610adc575b505050918352505060059190910154602090910152805160408201516080909201519097919650945092505050565b6001600160a01b03811660009081526008602052604081205481108015610b5f57506001600160a01b038216600090815260086020526040812060020154115b8015610b8457506001600160a01b038216600090815260086020526040812060040154115b15610b9157506003919050565b6001600160a01b038216600090815260086020526040812054118015610bd057506001600160a01b038216600090815260086020526040812060020154115b8015610bf557506001600160a01b038216600090815260086020526040902060040154155b15610c0257506002919050565b6001600160a01b038216600090815260086020526040812054118015610c4157506001600160a01b038216600090815260086020526040902060020154155b8015610c6657506001600160a01b038216600090815260086020526040902060040154155b15610c7357506001919050565b506000919050565b6004546001600160a01b03163314610ca6576040516330cd747160e01b815260040160405180910390fd5b600480546001600160a01b0319169055565b60095460ff1615610cdb5760405162461bcd60e51b815260040161074590613916565b6000815111610cfc5760405162461bcd60e51b81526004016107459061394d565b3360009081526008602052604081206005810154909103610d1e574260058201555b60005b8251811015610df75781600401838281518110610d4057610d4061397c565b6020908102919091018101518254600181018455600093845291909220015560075483516001600160a01b03909116906323b872dd9033903090879086908110610d8c57610d8c61397c565b60200260200101516040518463ffffffff1660e01b8152600401610db2939291906138f2565b600060405180830381600087803b158015610dcc57600080fd5b505af1158015610de0573d6000803e3d6000fd5b505050508080610def906139a8565b915050610d21565b506108bc3360025b8451604080516001600160a01b03909416602085015283019190915260608201526001608082015260a0016108a8565b60095460ff1615610e525760405162461bcd60e51b815260040161074590613916565b6000815111610e735760405162461bcd60e51b81526004016107459061394d565b3360009081526008602052604081206003810154909103610e95574260038201555b60005b8251811015610f6e5781600201838281518110610eb757610eb761397c565b6020908102919091018101518254600181018455600093845291909220015560065483516001600160a01b03909116906323b872dd9033903090879086908110610f0357610f0361397c565b60200260200101516040518463ffffffff1660e01b8152600401610f29939291906138f2565b600060405180830381600087803b158015610f4357600080fd5b505af1158015610f57573d6000803e3d6000fd5b505050508080610f66906139a8565b915050610e98565b506108bc336001610dff565b60095460ff1615610f9d5760405162461bcd60e51b815260040161074590613916565b6000815111610fbe5760405162461bcd60e51b81526004016107459061394d565b3360009081526008602052604081206001810154909103610fe0574260018201555b60005b82518110156110b957816000018382815181106110025761100261397c565b6020908102919091018101518254600181018455600093845291909220015560055483516001600160a01b03909116906323b872dd903390309087908690811061104e5761104e61397c565b60200260200101516040518463ffffffff1660e01b8152600401611074939291906138f2565b600060405180830381600087803b15801561108e57600080fd5b505af11580156110a2573d6000803e3d6000fd5b5050505080806110b1906139a8565b915050610fe3565b506108bc336000610dff565b60095460ff16156110e85760405162461bcd60e51b8152600401610745906138bb565b336000908152600860209081526040918290206002810180548451818502810185019095528085529193611151939092908301828280156107ab576020028201919060005260206000209081548152602001906001019080831161079757505050505083611b66565b6111915760405162461bcd60e51b81526020600482015260116024820152702737ba1030bb30ba30b91037bbb732b91760791b6044820152606401610745565b6006546040516323b872dd60e01b81526001600160a01b03909116906323b872dd906111c5903090339087906004016138f2565b600060405180830381600087803b1580156111df57600080fd5b505af11580156111f3573d6000803e3d6000fd5b505050506112018183611d58565b600281015460000361121557600060038201555b6108bc33600161087f565b60095460ff16156112435760405162461bcd60e51b8152600401610745906138bb565b336000908152600860205260408120905b82518110156113995760008382815181106112715761127161397c565b602002602001015190506112d7836004018054806020026020016040519081016040528092919081815260200182805480156112cc57602002820191906000526020600020905b8154815260200190600101908083116112b8575b505050505082611b66565b6113165760405162461bcd60e51b815260206004820152601060248201526f2737ba1038bab2b9ba1037bbb732b91760811b6044820152606401610745565b6007546040516323b872dd60e01b81526001600160a01b03909116906323b872dd9061134a903090339086906004016138f2565b600060405180830381600087803b15801561136457600080fd5b505af1158015611378573d6000803e3d6000fd5b505050506113868382611e72565b5080611391816139a8565b915050611254565b5060048101546000036113ae57600060058201555b6108bc3360025b8451604080516001600160a01b03909416602085015283019190915260608201526000608082015260a0016108a8565b60095460ff16156114085760405162461bcd60e51b8152600401610745906138bb565b336000908152600860205260408120905b825181101561155e5760008382815181106114365761143661397c565b6020026020010151905061149a836000018054806020026020016040519081016040528092919081815260200182805480156112cc57602002820191906000526020600020908154815260200190600101908083116112b857505050505082611b66565b6114db5760405162461bcd60e51b81526020600482015260126024820152712737ba10323ab733b2b7b71037bbb732b91760711b6044820152606401610745565b6005546040516323b872dd60e01b81526001600160a01b03909116906323b872dd9061150f903090339086906004016138f2565b600060405180830381600087803b15801561152957600080fd5b505af115801561153d573d6000803e3d6000fd5b5050505061154b8382611bbb565b5080611556816139a8565b915050611419565b50805460000361157057600060018201555b6108bc3360006113b5565b6002546001600160a01b0316156115e75760405162461bcd60e51b815260206004820152602a60248201527f467842617365526f6f7454756e6e656c3a204348494c445f54554e4e454c5f4160448201526913149150511657d4d15560b21b6064820152608401610745565b600280546001600160a01b0319166001600160a01b0392909216919091179055565b60095460ff161561162c5760405162461bcd60e51b8152600401610745906138bb565b3360008181526008602090815260408083206002810180546001810182559085529290932090910184905560065490516323b872dd60e01b815291926001600160a01b03909116916323b872dd9161168a91309087906004016138f2565b600060405180830381600087803b1580156116a457600080fd5b505af11580156116b8573d6000803e3d6000fd5b5050505080600301546000036116cf574260038201555b6108bc33600161098d565b60095460ff16156116fd5760405162461bcd60e51b8152600401610745906138bb565b336000908152600860209081526040918290206004810180548451818502810185019095528085529193611766939092908301828280156107ab576020028201919060005260206000209081548152602001906001019080831161079757505050505083611b66565b6117a55760405162461bcd60e51b815260206004820152601060248201526f2737ba1038bab2b9ba1037bbb732b91760811b6044820152606401610745565b6007546040516323b872dd60e01b81526001600160a01b03909116906323b872dd906117d9903090339087906004016138f2565b600060405180830381600087803b1580156117f357600080fd5b505af1158015611807573d6000803e3d6000fd5b505050506118158183611e72565b600481015460000361182957600060058201555b6108bc33600261087f565b6004546001600160a01b0316331461184b57600080fd5b600680546001600160a01b039384166001600160a01b03199182161790915560078054929093169116179055565b60095460ff161561189c5760405162461bcd60e51b8152600401610745906138bb565b336000908152600860205260408120905b82518110156119f15760008382815181106118ca576118ca61397c565b6020026020010151905061192e836002018054806020026020016040519081016040528092919081815260200182805480156112cc57602002820191906000526020600020908154815260200190600101908083116112b857505050505082611b66565b61196e5760405162461bcd60e51b81526020600482015260116024820152702737ba1030bb30ba30b91037bbb732b91760791b6044820152606401610745565b6006546040516323b872dd60e01b81526001600160a01b03909116906323b872dd906119a2903090339086906004016138f2565b600060405180830381600087803b1580156119bc57600080fd5b505af11580156119d0573d6000803e3d6000fd5b505050506119de8382611d58565b50806119e9816139a8565b9150506118ad565b506002810154600003611a0657600060038201555b6108bc3360016113b5565b825115611a2157611a2183610f7a565b815115611a3157611a3182610e2f565b8051156106f3576106f381610cb8565b60095460ff1615611a645760405162461bcd60e51b8152600401610745906138bb565b33600081815260086020908152604080832080546001810182558185529290932090910184905560055490516323b872dd60e01b815291926001600160a01b03909116916323b872dd91611abe91309087906004016138f2565b600060405180830381600087803b158015611ad857600080fd5b505af1158015611aec573d6000803e3d6000fd5b505050508060010154600003611b03574260018201555b6108bc33600061098d565b6004546001600160a01b03163314611b39576040516330cd747160e01b815260040160405180910390fd5b600480546001600160a01b0319166001600160a01b0392909216919091179055565b60006106f382611f8c565b6000805b8351811015611baf5782848281518110611b8657611b8661397c565b602002602001015103611b9d576001915050611bb5565b80611ba7816139a8565b915050611b6a565b50600090505b92915050565b600082600001805480602002602001604051908101604052809291908181526020018280548015611c0b57602002820191906000526020600020905b815481526020019060010190808311611bf7575b505050505090506000805b8251811015611c555783838281518110611c3257611c3261397c565b602002602001015103611c43578091505b80611c4d816139a8565b915050611c16565b5082828281518110611c6957611c6961397c565b602002602001015103611ce75783548290611c86906001906139c1565b81518110611c9657611c9661397c565b6020026020010151846000018281548110611cb357611cb361397c565b6000918252602090912001558354849080611cd057611cd06139d8565b600190038181906000526020600020016000905590555b50505050565b60005460025460405163b472047760e01b81526001600160a01b039283169263b472047792611d23929116908590600401613a1a565b600060405180830381600087803b158015611d3d57600080fd5b505af1158015611d51573d6000803e3d6000fd5b5050505050565b600082600201805480602002602001604051908101604052809291908181526020018280548015611da857602002820191906000526020600020905b815481526020019060010190808311611d94575b505050505090506000805b8251811015611df25783838281518110611dcf57611dcf61397c565b602002602001015103611de0578091505b80611dea816139a8565b915050611db3565b5082828281518110611e0657611e0661397c565b602002602001015103611ce75760028401548290611e26906001906139c1565b81518110611e3657611e3661397c565b6020026020010151846002018281548110611e5357611e5361397c565b60009182526020909120015560028401805480611cd057611cd06139d8565b600082600401805480602002602001604051908101604052809291908181526020018280548015611ec257602002820191906000526020600020905b815481526020019060010190808311611eae575b505050505090506000805b8251811015611f0c5783838281518110611ee957611ee961397c565b602002602001015103611efa578091505b80611f04816139a8565b915050611ecd565b5082828281518110611f2057611f2061397c565b602002602001015103611ce75760048401548290611f40906001906139c1565b81518110611f5057611f5061397c565b6020026020010151846004018281548110611f6d57611f6d61397c565b60009182526020909120015560048401805480611cd057611cd06139d8565b60606000611f9983612275565b90506000611fa6826122d4565b90506000611fb3836122fd565b9050600081611fc184612326565b611fca866124e2565b604051602001611fdc93929190613a5c565b60408051601f1981840301815291815281516020928301206000818152600390935291205490915060ff16156120605760405162461bcd60e51b8152602060048201526024808201527f4678526f6f7454756e6e656c3a20455849545f414c52454144595f50524f434560448201526314d4d15160e21b6064820152608401610745565b6000818152600360205260408120805460ff19166001179055612082856124fe565b9050600061208f82612647565b905061209a816126d7565b6002546001600160a01b039081169116146121055760405162461bcd60e51b815260206004820152602560248201527f4678526f6f7454756e6e656c3a20494e56414c49445f46585f4348494c445f54604482015264155393915360da1b6064820152608401610745565b600061211087612700565b9050612130612120846020015190565b8761212a8a61271c565b84612738565b6121885760405162461bcd60e51b815260206004820152602360248201527f4678526f6f7454756e6e656c3a20494e56414c49445f524543454950545f505260448201526227a7a360e91b6064820152608401610745565b6121b685612195896129eb565b61219e8a612a07565b846121a88c612a23565b6121b18d612a3f565b612a5b565b5060006121c283612b81565b90507f8c5261668696ce22758910d05bab8f186d6eb247ceac2af2e82c7dc17669b0366121f86121f3836000612bbd565b612bf5565b146122455760405162461bcd60e51b815260206004820152601f60248201527f4678526f6f7454756e6e656c3a20494e56414c49445f5349474e4154555245006044820152606401610745565b600061225084612c70565b8060200190518101906122639190613a89565b9b9a5050505050505050505050565b50565b60408051602081019091526060815260006122bf6122ba8460408051808201825260008082526020918201528151808301909252825182529182019181019190915290565b612c8c565b60408051602081019091529081529392505050565b6060611bb582600001516008815181106122f0576122f061397c565b6020026020010151612da1565b6000611bb582600001516002815181106123195761231961397c565b6020026020010151612bf5565b60408051602081019091526000815281516060919015611bb55760008061234e600086612e3d565b60f81c9050600181148061236557508060ff166003145b1561240c5760018551600261237a9190613aff565b61238491906139c1565b6001600160401b0381111561239b5761239b6134d3565b6040519080825280601f01601f1916602001820160405280156123c5576020820181803683370190505b50925060006123d5600187612e3d565b905080846000815181106123eb576123eb61397c565b60200101906001600160f81b031916908160001a905350600192505061246f565b60028551600261241c9190613aff565b61242691906139c1565b6001600160401b0381111561243d5761243d6134d3565b6040519080825280601f01601f191660200182016040528015612467576020820181803683370190505b509250600091505b60ff82165b83518110156124d95761249e61248d60ff8516836139c1565b612498906002613b1e565b87612e3d565b8482815181106124b0576124b061397c565b60200101906001600160f81b031916908160001a905350806124d1816139a8565b915050612474565b50505092915050565b6000611bb582600001516009815181106123195761231961397c565b61252260405180606001604052806060815260200160608152602001600081525090565b61253c82600001516006815181106122f0576122f061397c565b60208281018290526040805180820182526000808252908301528051808201909152825181529181019082015261257281612ebe565b156125875761258081612c8c565b8252612633565b6020820151805160009061259d906001906139c1565b6001600160401b038111156125b4576125b46134d3565b6040519080825280601f01601f1916602001820160405280156125de576020820181803683370190505b5090506000808360210191508260200190506125fc82828551612ef9565b60408051808201825260008082526020918201528151808301909252845182528085019082015261262c90612c8c565b8652505050505b61263c836124e2565b604083015250919050565b60408051608081018252600091810182815260608083019390935281526020810191909152600061269583600001516003815181106126885761268861397c565b6020026020010151612c8c565b8360400151815181106126aa576126aa61397c565b6020026020010151905060405180604001604052808281526020016126ce83612c8c565b90529392505050565b6000611bb582602001516000815181106126f3576126f361397c565b6020026020010151612f77565b6000611bb582600001516005815181106123195761231961397c565b6060611bb582600001516007815181106122f0576122f061397c565b60008061276c8460408051808201825260008082526020918201528151808301909252825182529182019181019190915290565b9050600061277982612c8c565b90506060808560008061278b8b612326565b905080516000036127a65760009750505050505050506129e3565b60005b86518110156129da5781518311156127cc576000985050505050505050506129e3565b6127ee8782815181106127e1576127e161397c565b6020026020010151612f91565b95508580519060200120841461280f576000985050505050505050506129e3565b6128248782815181106126885761268861397c565b945084516011036128f65781518303612883578c80519060200120612855866010815181106122f0576122f061397c565b8051906020012003612872576001985050505050505050506129e3565b6000985050505050505050506129e3565b60008284815181106128975761289761397c565b016020015160f81c905060108111156128bc57600099505050505050505050506129e3565b6128e1868260ff16815181106128d4576128d461397c565b602002602001015161300f565b94506128ee600185613b1e565b9350506129c8565b845160020361287257600061292161291a876000815181106122f0576122f061397c565b848661303d565b83519091506129308286613b1e565b03612983578d80519060200120612953876001815181106122f0576122f061397c565b805190602001200361297157600199505050505050505050506129e3565b600099505050505050505050506129e3565b8060000361299d57600099505050505050505050506129e3565b6129a78185613b1e565b93506129bf866001815181106128d4576128d461397c565b94506129c89050565b806129d2816139a8565b9150506127a9565b50505050505050505b949350505050565b6000611bb582600001516003815181106123195761231961397c565b6000611bb582600001516004815181106123195761231961397c565b6000611bb582600001516000815181106123195761231961397c565b6060611bb582600001516001815181106122f0576122f061397c565b6001546040516320a9cea560e11b8152600481018490526000918291829182916001600160a01b03909116906341539d4a9060240160a060405180830381865afa158015612aad573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ad19190613b36565b5093505092509250612b28828b612ae891906139c1565b6040805160208082018f90528183018e9052606082018d905260808083018d90528351808403909101815260a09092019092528051910120908588613144565b612b745760405162461bcd60e51b815260206004820152601c60248201527f4678526f6f7454756e6e656c3a20494e56414c49445f484541444552000000006044820152606401610745565b9998505050505050505050565b6040805160208101909152606081526040518060200160405280612bb584602001516001815181106126885761268861397c565b905292915050565b60408051808201909152600080825260208201528251805183908110612be557612be561397c565b6020026020010151905092915050565b805160009015801590612c0a57508151602110155b612c1357600080fd5b6000612c2283602001516132ac565b90506000818460000151612c3691906139c1565b9050600080838660200151612c4b9190613b1e565b9050805191506020831015612c6757826020036101000a820491505b50949350505050565b6060611bb582602001516002815181106122f0576122f061397c565b6060612c9782612ebe565b612ca057600080fd5b6000612cab8361332e565b90506000816001600160401b03811115612cc757612cc76134d3565b604051908082528060200260200182016040528015612d0c57816020015b6040805180820190915260008082526020820152815260200190600190039081612ce55790505b5090506000612d1e85602001516132ac565b8560200151612d2d9190613b1e565b90506000805b84811015612d9657612d44836133b3565b9150604051806040016040528083815260200184815250848281518110612d6d57612d6d61397c565b6020908102919091010152612d828284613b1e565b925080612d8e816139a8565b915050612d33565b509195945050505050565b8051606090612daf57600080fd5b6000612dbe83602001516132ac565b90506000818460000151612dd291906139c1565b90506000816001600160401b03811115612dee57612dee6134d3565b6040519080825280601f01601f191660200182016040528015612e18576020820181803683370190505b5090506000816020019050612c67848760200151612e369190613b1e565b8285613457565b6000612e4a600284613b99565b15612e8457601082612e5d600286613bad565b81518110612e6d57612e6d61397c565b0160200151612e7f919060f81c613bc1565b612eb4565b601082612e92600286613bad565b81518110612ea257612ea261397c565b0160200151612eb4919060f81c613be3565b60f81b9392505050565b80516000908103612ed157506000919050565b6020820151805160001a9060c0821015612eef575060009392505050565b5060019392505050565b80600003612f0657505050565b60208110612f3e5782518252612f1d602084613b1e565b9250612f2a602083613b1e565b9150612f376020826139c1565b9050612f06565b60006001612f4d8360206139c1565b612f5990610100613ce9565b612f6391906139c1565b935183518516941916939093179091525050565b8051600090601514612f8857600080fd5b611bb582612bf5565b6060600082600001516001600160401b03811115612fb157612fb16134d3565b6040519080825280601f01601f191660200182016040528015612fdb576020820181803683370190505b5090508051600003612fed5792915050565b60008160200190506130088460200151828660000151613457565b5092915050565b805160009060211461302057600080fd5b600080836020015160016130349190613b1e565b51949350505050565b6000808061304a86612326565b9050600081516001600160401b03811115613067576130676134d3565b6040519080825280601f01601f191660200182016040528015613091576020820181803683370190505b509050845b82516130a29087613b1e565b8110156131155760008782815181106130bd576130bd61397c565b01602001516001600160f81b031916905080836130da89856139c1565b815181106130ea576130ea61397c565b60200101906001600160f81b031916908160001a90535050808061310d906139a8565b915050613096565b5080805190602001208280519060200120036131345781519250613139565b600092505b509095945050505050565b6000602082516131549190613b99565b156131985760405162461bcd60e51b8152602060048201526014602482015273092dcecc2d8d2c840e0e4dedecc40d8cadccee8d60631b6044820152606401610745565b6000602083516131a89190613bad565b90506131b5816002613ce9565b85106131fb5760405162461bcd60e51b81526020600482015260156024820152744c65616620696e64657820697320746f6f2062696760581b6044820152606401610745565b60008660205b8551811161329e5785810151925061321a600289613b99565b60000361325257604080516020810184905290810184905260600160405160208183030381529060405280519060200120915061327f565b60408051602081018590529081018390526060016040516020818303038152906040528051906020012091505b61328a600289613bad565b9750613297602082613b1e565b9050613201565b509094149695505050505050565b8051600090811a60808110156132c55750600092915050565b60b88110806132e0575060c081108015906132e0575060f881105b156132ee5750600192915050565b60c081101561332257613303600160b8613cf5565b6133109060ff16826139c1565b61331b906001613b1e565b9392505050565b613303600160f8613cf5565b8051600090810361334157506000919050565b60008061335184602001516132ac565b84602001516133609190613b1e565b90506000846000015185602001516133789190613b1e565b90505b808210156133aa5761338c826133b3565b6133969083613b1e565b9150826133a2816139a8565b93505061337b565b50909392505050565b80516000908190811a60808110156133ce5760019150613008565b60b88110156133f4576133e26080826139c1565b6133ed906001613b1e565b9150613008565b60c08110156134215760b78103600185019450806020036101000a85510460018201810193505050613008565b60f8811015613435576133e260c0826139c1565b60019390930151602084900360f7016101000a900490920160f5190192915050565b8060000361346457505050565b6020811061349c578251825261347b602084613b1e565b9250613488602083613b1e565b91506134956020826139c1565b9050613464565b80600003612f3e57505050565b6000602082840312156134bb57600080fd5b81356001600160e01b03198116811461331b57600080fd5b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b0381118282101715613511576135116134d3565b604052919050565b600082601f83011261352a57600080fd5b813560206001600160401b03821115613545576135456134d3565b8160051b6135548282016134e9565b928352848101820192828101908785111561356e57600080fd5b83870192505b8483101561358d57823582529183019190830190613574565b979650505050505050565b6000806000606084860312156135ad57600080fd5b83356001600160401b03808211156135c457600080fd5b6135d087838801613519565b945060208601359150808211156135e657600080fd5b6135f287838801613519565b9350604086013591508082111561360857600080fd5b5061361586828701613519565b9150509250925092565b6001600160a01b038116811461227257600080fd5b60008060008060006080868803121561364c57600080fd5b85356136578161361f565b945060208601356136678161361f565b93506040860135925060608601356001600160401b038082111561368a57600080fd5b818801915088601f83011261369e57600080fd5b8135818111156136ad57600080fd5b8960208285010111156136bf57600080fd5b9699959850939650602001949392505050565b6000602082840312156136e457600080fd5b8135801515811461331b57600080fd5b60006020828403121561370657600080fd5b813561331b8161361f565b60006020828403121561372357600080fd5b5035919050565b600081518084526020808501945080840160005b8381101561375a5781518752958201959082019060010161373e565b509495945050505050565b606081526000613778606083018661372a565b828103602084015261378a818661372a565b9050828103604084015261379e818561372a565b9695505050505050565b6000602082840312156137ba57600080fd5b81356001600160401b038111156137d057600080fd5b6129e384828501613519565b600080604083850312156137ef57600080fd5b82356137fa8161361f565b9150602083013561380a8161361f565b809150509250929050565b60006001600160401b0382111561382e5761382e6134d3565b50601f01601f191660200190565b60006020828403121561384e57600080fd5b81356001600160401b0381111561386457600080fd5b8201601f8101841361387557600080fd5b803561388861388382613815565b6134e9565b81815285602083850101111561389d57600080fd5b81602084016020830137600091810160200191909152949350505050565b6020808252601c908201527f5374616b696e672069732063757272656e746c79207061757365642e00000000604082015260600190565b6001600160a01b039384168152919092166020820152604081019190915260600190565b60208082526019908201527f5374616b696e672063757272656e746c79207061757365642e00000000000000604082015260600190565b6020808252601590820152742737903a37b5b2b724b23990383937bb34b232b21760591b604082015260600190565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b6000600182016139ba576139ba613992565b5060010190565b6000828210156139d3576139d3613992565b500390565b634e487b7160e01b600052603160045260246000fd5b60005b83811015613a095781810151838201526020016139f1565b83811115611ce75750506000910152565b60018060a01b03831681526040602082015260008251806040840152613a478160608501602087016139ee565b601f01601f1916919091016060019392505050565b83815260008351613a748160208501602088016139ee565b60209201918201929092526040019392505050565b600060208284031215613a9b57600080fd5b81516001600160401b03811115613ab157600080fd5b8201601f81018413613ac257600080fd5b8051613ad061388382613815565b818152856020838501011115613ae557600080fd5b613af68260208301602086016139ee565b95945050505050565b6000816000190483118215151615613b1957613b19613992565b500290565b60008219821115613b3157613b31613992565b500190565b600080600080600060a08688031215613b4e57600080fd5b855194506020860151935060408601519250606086015191506080860151613b758161361f565b809150509295509295909350565b634e487b7160e01b600052601260045260246000fd5b600082613ba857613ba8613b83565b500690565b600082613bbc57613bbc613b83565b500490565b600060ff831680613bd457613bd4613b83565b8060ff84160691505092915050565b600060ff831680613bf657613bf6613b83565b8060ff84160491505092915050565b600181815b80851115613c40578160001904821115613c2657613c26613992565b80851615613c3357918102915b93841c9390800290613c0a565b509250929050565b600082613c5757506001611bb5565b81613c6457506000611bb5565b8160018114613c7a5760028114613c8457613ca0565b6001915050611bb5565b60ff841115613c9557613c95613992565b50506001821b611bb5565b5060208310610133831016604e8410600b8410161715613cc3575081810a611bb5565b613ccd8383613c05565b8060001904821115613ce157613ce1613992565b029392505050565b600061331b8383613c48565b600060ff821660ff841680821015613d0f57613d0f613992565b9003939250505056fea26469706673582212208e0052f2db19d7a445185f864f84206c0a7108e7286ea9dacdc8eeafcaef33fd64736f6c634300080d0033

Verified Source Code Partial Match

Compiler: v0.8.13+commit.abaa5c0e EVM: london Optimization: Yes (200 runs)
DungeonRewards.sol 1725 lines
// File: default_workspace/contracts/Ownable.sol


pragma solidity ^0.8.10;

error NotOwner();

// https://github.com/m1guelpf/erc721-drop/blob/main/src/LilOwnable.sol
abstract contract Ownable {
    address internal _owner;

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

    modifier onlyOwner() {
        require(_owner == msg.sender);
        _;
    }

    constructor() {
        _owner = msg.sender;
    }

    function owner() external view returns (address) {
        return _owner;
    }

    function transferOwnership(address _newOwner) external {
        if (msg.sender != _owner) revert NotOwner();

        _owner = _newOwner;
    }

    function renounceOwnership() public {
        if (msg.sender != _owner) revert NotOwner();

        _owner = address(0);
    }

    function supportsInterface(bytes4 interfaceId)
        public
        pure
        virtual
        returns (bool)
    {
        return interfaceId == 0x7f5828d0; // ERC165 Interface ID for ERC173
    }
}

// File: default_workspace/contracts/lib/Merkle.sol


pragma solidity ^0.8.0;

library Merkle {
    function checkMembership(
        bytes32 leaf,
        uint256 index,
        bytes32 rootHash,
        bytes memory proof
    ) internal pure returns (bool) {
        require(proof.length % 32 == 0, "Invalid proof length");
        uint256 proofHeight = proof.length / 32;
        // Proof of size n means, height of the tree is n+1.
        // In a tree of height n+1, max #leafs possible is 2 ^ n
        require(index < 2**proofHeight, "Leaf index is too big");

        bytes32 proofElement;
        bytes32 computedHash = leaf;
        for (uint256 i = 32; i <= proof.length; i += 32) {
            assembly {
                proofElement := mload(add(proof, i))
            }

            if (index % 2 == 0) {
                computedHash = keccak256(abi.encodePacked(computedHash, proofElement));
            } else {
                computedHash = keccak256(abi.encodePacked(proofElement, computedHash));
            }

            index = index / 2;
        }
        return computedHash == rootHash;
    }
}

// File: default_workspace/contracts/lib/RLPReader.sol

/*
 * @author Hamdi Allam [email protected]
 * Please reach out with any questions or concerns
 */
pragma solidity ^0.8.0;

library RLPReader {
    uint8 constant STRING_SHORT_START = 0x80;
    uint8 constant STRING_LONG_START = 0xb8;
    uint8 constant LIST_SHORT_START = 0xc0;
    uint8 constant LIST_LONG_START = 0xf8;
    uint8 constant WORD_SIZE = 32;

    struct RLPItem {
        uint256 len;
        uint256 memPtr;
    }

    struct Iterator {
        RLPItem item; // Item that's being iterated over.
        uint256 nextPtr; // Position of the next item in the list.
    }

    /*
     * @dev Returns the next element in the iteration. Reverts if it has not next element.
     * @param self The iterator.
     * @return The next element in the iteration.
     */
    function next(Iterator memory self) internal pure returns (RLPItem memory) {
        require(hasNext(self));

        uint256 ptr = self.nextPtr;
        uint256 itemLength = _itemLength(ptr);
        self.nextPtr = ptr + itemLength;

        return RLPItem(itemLength, ptr);
    }

    /*
     * @dev Returns true if the iteration has more elements.
     * @param self The iterator.
     * @return true if the iteration has more elements.
     */
    function hasNext(Iterator memory self) internal pure returns (bool) {
        RLPItem memory item = self.item;
        return self.nextPtr < item.memPtr + item.len;
    }

    /*
     * @param item RLP encoded bytes
     */
    function toRlpItem(bytes memory item) internal pure returns (RLPItem memory) {
        uint256 memPtr;
        assembly {
            memPtr := add(item, 0x20)
        }

        return RLPItem(item.length, memPtr);
    }

    /*
     * @dev Create an iterator. Reverts if item is not a list.
     * @param self The RLP item.
     * @return An 'Iterator' over the item.
     */
    function iterator(RLPItem memory self) internal pure returns (Iterator memory) {
        require(isList(self));

        uint256 ptr = self.memPtr + _payloadOffset(self.memPtr);
        return Iterator(self, ptr);
    }

    /*
     * @param item RLP encoded bytes
     */
    function rlpLen(RLPItem memory item) internal pure returns (uint256) {
        return item.len;
    }

    /*
     * @param item RLP encoded bytes
     */
    function payloadLen(RLPItem memory item) internal pure returns (uint256) {
        return item.len - _payloadOffset(item.memPtr);
    }

    /*
     * @param item RLP encoded list in bytes
     */
    function toList(RLPItem memory item) internal pure returns (RLPItem[] memory) {
        require(isList(item));

        uint256 items = numItems(item);
        RLPItem[] memory result = new RLPItem[](items);

        uint256 memPtr = item.memPtr + _payloadOffset(item.memPtr);
        uint256 dataLen;
        for (uint256 i = 0; i < items; i++) {
            dataLen = _itemLength(memPtr);
            result[i] = RLPItem(dataLen, memPtr);
            memPtr = memPtr + dataLen;
        }

        return result;
    }

    // @return indicator whether encoded payload is a list. negate this function call for isData.
    function isList(RLPItem memory item) internal pure returns (bool) {
        if (item.len == 0) return false;

        uint8 byte0;
        uint256 memPtr = item.memPtr;
        assembly {
            byte0 := byte(0, mload(memPtr))
        }

        if (byte0 < LIST_SHORT_START) return false;
        return true;
    }

    /*
     * @dev A cheaper version of keccak256(toRlpBytes(item)) that avoids copying memory.
     * @return keccak256 hash of RLP encoded bytes.
     */
    function rlpBytesKeccak256(RLPItem memory item) internal pure returns (bytes32) {
        uint256 ptr = item.memPtr;
        uint256 len = item.len;
        bytes32 result;
        assembly {
            result := keccak256(ptr, len)
        }
        return result;
    }

    function payloadLocation(RLPItem memory item) internal pure returns (uint256, uint256) {
        uint256 offset = _payloadOffset(item.memPtr);
        uint256 memPtr = item.memPtr + offset;
        uint256 len = item.len - offset; // data length
        return (memPtr, len);
    }

    /*
     * @dev A cheaper version of keccak256(toBytes(item)) that avoids copying memory.
     * @return keccak256 hash of the item payload.
     */
    function payloadKeccak256(RLPItem memory item) internal pure returns (bytes32) {
        (uint256 memPtr, uint256 len) = payloadLocation(item);
        bytes32 result;
        assembly {
            result := keccak256(memPtr, len)
        }
        return result;
    }

    /** RLPItem conversions into data types **/

    // @returns raw rlp encoding in bytes
    function toRlpBytes(RLPItem memory item) internal pure returns (bytes memory) {
        bytes memory result = new bytes(item.len);
        if (result.length == 0) return result;

        uint256 ptr;
        assembly {
            ptr := add(0x20, result)
        }

        copy(item.memPtr, ptr, item.len);
        return result;
    }

    // any non-zero byte is considered true
    function toBoolean(RLPItem memory item) internal pure returns (bool) {
        require(item.len == 1);
        uint256 result;
        uint256 memPtr = item.memPtr;
        assembly {
            result := byte(0, mload(memPtr))
        }

        return result == 0 ? false : true;
    }

    function toAddress(RLPItem memory item) internal pure returns (address) {
        // 1 byte for the length prefix
        require(item.len == 21);

        return address(uint160(toUint(item)));
    }

    function toUint(RLPItem memory item) internal pure returns (uint256) {
        require(item.len > 0 && item.len <= 33);

        uint256 offset = _payloadOffset(item.memPtr);
        uint256 len = item.len - offset;

        uint256 result;
        uint256 memPtr = item.memPtr + offset;
        assembly {
            result := mload(memPtr)

            // shfit to the correct location if neccesary
            if lt(len, 32) {
                result := div(result, exp(256, sub(32, len)))
            }
        }

        return result;
    }

    // enforces 32 byte length
    function toUintStrict(RLPItem memory item) internal pure returns (uint256) {
        // one byte prefix
        require(item.len == 33);

        uint256 result;
        uint256 memPtr = item.memPtr + 1;
        assembly {
            result := mload(memPtr)
        }

        return result;
    }

    function toBytes(RLPItem memory item) internal pure returns (bytes memory) {
        require(item.len > 0);

        uint256 offset = _payloadOffset(item.memPtr);
        uint256 len = item.len - offset; // data length
        bytes memory result = new bytes(len);

        uint256 destPtr;
        assembly {
            destPtr := add(0x20, result)
        }

        copy(item.memPtr + offset, destPtr, len);
        return result;
    }

    /*
     * Private Helpers
     */

    // @return number of payload items inside an encoded list.
    function numItems(RLPItem memory item) private pure returns (uint256) {
        if (item.len == 0) return 0;

        uint256 count = 0;
        uint256 currPtr = item.memPtr + _payloadOffset(item.memPtr);
        uint256 endPtr = item.memPtr + item.len;
        while (currPtr < endPtr) {
            currPtr = currPtr + _itemLength(currPtr); // skip over an item
            count++;
        }

        return count;
    }

    // @return entire rlp item byte length
    function _itemLength(uint256 memPtr) private pure returns (uint256) {
        uint256 itemLen;
        uint256 byte0;
        assembly {
            byte0 := byte(0, mload(memPtr))
        }

        if (byte0 < STRING_SHORT_START) itemLen = 1;
        else if (byte0 < STRING_LONG_START) itemLen = byte0 - STRING_SHORT_START + 1;
        else if (byte0 < LIST_SHORT_START) {
            assembly {
                let byteLen := sub(byte0, 0xb7) // # of bytes the actual length is
                memPtr := add(memPtr, 1) // skip over the first byte
                /* 32 byte word size */
                let dataLen := div(mload(memPtr), exp(256, sub(32, byteLen))) // right shifting to get the len
                itemLen := add(dataLen, add(byteLen, 1))
            }
        } else if (byte0 < LIST_LONG_START) {
            itemLen = byte0 - LIST_SHORT_START + 1;
        } else {
            assembly {
                let byteLen := sub(byte0, 0xf7)
                memPtr := add(memPtr, 1)

                let dataLen := div(mload(memPtr), exp(256, sub(32, byteLen))) // right shifting to the correct length
                itemLen := add(dataLen, add(byteLen, 1))
            }
        }

        return itemLen;
    }

    // @return number of bytes until the data
    function _payloadOffset(uint256 memPtr) private pure returns (uint256) {
        uint256 byte0;
        assembly {
            byte0 := byte(0, mload(memPtr))
        }

        if (byte0 < STRING_SHORT_START) return 0;
        else if (byte0 < STRING_LONG_START || (byte0 >= LIST_SHORT_START && byte0 < LIST_LONG_START)) return 1;
        else if (byte0 < LIST_SHORT_START)
            // being explicit
            return byte0 - (STRING_LONG_START - 1) + 1;
        else return byte0 - (LIST_LONG_START - 1) + 1;
    }

    /*
     * @param src Pointer to source
     * @param dest Pointer to destination
     * @param len Amount of memory to copy from the source
     */
    function copy(
        uint256 src,
        uint256 dest,
        uint256 len
    ) private pure {
        if (len == 0) return;

        // copy as many word sizes as possible
        for (; len >= WORD_SIZE; len -= WORD_SIZE) {
            assembly {
                mstore(dest, mload(src))
            }

            src += WORD_SIZE;
            dest += WORD_SIZE;
        }

        if (len == 0) return;

        // left over bytes. Mask is used to remove unwanted bytes from the word
        uint256 mask = 256**(WORD_SIZE - len) - 1;

        assembly {
            let srcpart := and(mload(src), not(mask)) // zero out src
            let destpart := and(mload(dest), mask) // retrieve the bytes
            mstore(dest, or(destpart, srcpart))
        }
    }
}

// File: default_workspace/contracts/lib/ExitPayloadReader.sol

pragma solidity ^0.8.0;


library ExitPayloadReader {
    using RLPReader for bytes;
    using RLPReader for RLPReader.RLPItem;

    uint8 constant WORD_SIZE = 32;

    struct ExitPayload {
        RLPReader.RLPItem[] data;
    }

    struct Receipt {
        RLPReader.RLPItem[] data;
        bytes raw;
        uint256 logIndex;
    }

    struct Log {
        RLPReader.RLPItem data;
        RLPReader.RLPItem[] list;
    }

    struct LogTopics {
        RLPReader.RLPItem[] data;
    }

    // copy paste of private copy() from RLPReader to avoid changing of existing contracts
    function copy(
        uint256 src,
        uint256 dest,
        uint256 len
    ) private pure {
        if (len == 0) return;

        // copy as many word sizes as possible
        for (; len >= WORD_SIZE; len -= WORD_SIZE) {
            assembly {
                mstore(dest, mload(src))
            }

            src += WORD_SIZE;
            dest += WORD_SIZE;
        }

        // left over bytes. Mask is used to remove unwanted bytes from the word
        uint256 mask = 256**(WORD_SIZE - len) - 1;
        assembly {
            let srcpart := and(mload(src), not(mask)) // zero out src
            let destpart := and(mload(dest), mask) // retrieve the bytes
            mstore(dest, or(destpart, srcpart))
        }
    }

    function toExitPayload(bytes memory data) internal pure returns (ExitPayload memory) {
        RLPReader.RLPItem[] memory payloadData = data.toRlpItem().toList();

        return ExitPayload(payloadData);
    }

    function getHeaderNumber(ExitPayload memory payload) internal pure returns (uint256) {
        return payload.data[0].toUint();
    }

    function getBlockProof(ExitPayload memory payload) internal pure returns (bytes memory) {
        return payload.data[1].toBytes();
    }

    function getBlockNumber(ExitPayload memory payload) internal pure returns (uint256) {
        return payload.data[2].toUint();
    }

    function getBlockTime(ExitPayload memory payload) internal pure returns (uint256) {
        return payload.data[3].toUint();
    }

    function getTxRoot(ExitPayload memory payload) internal pure returns (bytes32) {
        return bytes32(payload.data[4].toUint());
    }

    function getReceiptRoot(ExitPayload memory payload) internal pure returns (bytes32) {
        return bytes32(payload.data[5].toUint());
    }

    function getReceipt(ExitPayload memory payload) internal pure returns (Receipt memory receipt) {
        receipt.raw = payload.data[6].toBytes();
        RLPReader.RLPItem memory receiptItem = receipt.raw.toRlpItem();

        if (receiptItem.isList()) {
            // legacy tx
            receipt.data = receiptItem.toList();
        } else {
            // pop first byte before parsting receipt
            bytes memory typedBytes = receipt.raw;
            bytes memory result = new bytes(typedBytes.length - 1);
            uint256 srcPtr;
            uint256 destPtr;
            assembly {
                srcPtr := add(33, typedBytes)
                destPtr := add(0x20, result)
            }

            copy(srcPtr, destPtr, result.length);
            receipt.data = result.toRlpItem().toList();
        }

        receipt.logIndex = getReceiptLogIndex(payload);
        return receipt;
    }

    function getReceiptProof(ExitPayload memory payload) internal pure returns (bytes memory) {
        return payload.data[7].toBytes();
    }

    function getBranchMaskAsBytes(ExitPayload memory payload) internal pure returns (bytes memory) {
        return payload.data[8].toBytes();
    }

    function getBranchMaskAsUint(ExitPayload memory payload) internal pure returns (uint256) {
        return payload.data[8].toUint();
    }

    function getReceiptLogIndex(ExitPayload memory payload) internal pure returns (uint256) {
        return payload.data[9].toUint();
    }

    // Receipt methods
    function toBytes(Receipt memory receipt) internal pure returns (bytes memory) {
        return receipt.raw;
    }

    function getLog(Receipt memory receipt) internal pure returns (Log memory) {
        RLPReader.RLPItem memory logData = receipt.data[3].toList()[receipt.logIndex];
        return Log(logData, logData.toList());
    }

    // Log methods
    function getEmitter(Log memory log) internal pure returns (address) {
        return RLPReader.toAddress(log.list[0]);
    }

    function getTopics(Log memory log) internal pure returns (LogTopics memory) {
        return LogTopics(log.list[1].toList());
    }

    function getData(Log memory log) internal pure returns (bytes memory) {
        return log.list[2].toBytes();
    }

    function toRlpBytes(Log memory log) internal pure returns (bytes memory) {
        return log.data.toRlpBytes();
    }

    // LogTopics methods
    function getField(LogTopics memory topics, uint256 index) internal pure returns (RLPReader.RLPItem memory) {
        return topics.data[index];
    }
}

// File: default_workspace/contracts/lib/MerklePatriciaProof.sol


pragma solidity ^0.8.0;


library MerklePatriciaProof {
    /*
     * @dev Verifies a merkle patricia proof.
     * @param value The terminating value in the trie.
     * @param encodedPath The path in the trie leading to value.
     * @param rlpParentNodes The rlp encoded stack of nodes.
     * @param root The root hash of the trie.
     * @return The boolean validity of the proof.
     */
    function verify(
        bytes memory value,
        bytes memory encodedPath,
        bytes memory rlpParentNodes,
        bytes32 root
    ) internal pure returns (bool) {
        RLPReader.RLPItem memory item = RLPReader.toRlpItem(rlpParentNodes);
        RLPReader.RLPItem[] memory parentNodes = RLPReader.toList(item);

        bytes memory currentNode;
        RLPReader.RLPItem[] memory currentNodeList;

        bytes32 nodeKey = root;
        uint256 pathPtr = 0;

        bytes memory path = _getNibbleArray(encodedPath);
        if (path.length == 0) {
            return false;
        }

        for (uint256 i = 0; i < parentNodes.length; i++) {
            if (pathPtr > path.length) {
                return false;
            }

            currentNode = RLPReader.toRlpBytes(parentNodes[i]);
            if (nodeKey != keccak256(currentNode)) {
                return false;
            }
            currentNodeList = RLPReader.toList(parentNodes[i]);

            if (currentNodeList.length == 17) {
                if (pathPtr == path.length) {
                    if (keccak256(RLPReader.toBytes(currentNodeList[16])) == keccak256(value)) {
                        return true;
                    } else {
                        return false;
                    }
                }

                uint8 nextPathNibble = uint8(path[pathPtr]);
                if (nextPathNibble > 16) {
                    return false;
                }
                nodeKey = bytes32(RLPReader.toUintStrict(currentNodeList[nextPathNibble]));
                pathPtr += 1;
            } else if (currentNodeList.length == 2) {
                uint256 traversed = _nibblesToTraverse(RLPReader.toBytes(currentNodeList[0]), path, pathPtr);
                if (pathPtr + traversed == path.length) {
                    //leaf node
                    if (keccak256(RLPReader.toBytes(currentNodeList[1])) == keccak256(value)) {
                        return true;
                    } else {
                        return false;
                    }
                }

                //extension node
                if (traversed == 0) {
                    return false;
                }

                pathPtr += traversed;
                nodeKey = bytes32(RLPReader.toUintStrict(currentNodeList[1]));
            } else {
                return false;
            }
        }
    }

    function _nibblesToTraverse(
        bytes memory encodedPartialPath,
        bytes memory path,
        uint256 pathPtr
    ) private pure returns (uint256) {
        uint256 len = 0;
        // encodedPartialPath has elements that are each two hex characters (1 byte), but partialPath
        // and slicedPath have elements that are each one hex character (1 nibble)
        bytes memory partialPath = _getNibbleArray(encodedPartialPath);
        bytes memory slicedPath = new bytes(partialPath.length);

        // pathPtr counts nibbles in path
        // partialPath.length is a number of nibbles
        for (uint256 i = pathPtr; i < pathPtr + partialPath.length; i++) {
            bytes1 pathNibble = path[i];
            slicedPath[i - pathPtr] = pathNibble;
        }

        if (keccak256(partialPath) == keccak256(slicedPath)) {
            len = partialPath.length;
        } else {
            len = 0;
        }
        return len;
    }

    // bytes b must be hp encoded
    function _getNibbleArray(bytes memory b) internal pure returns (bytes memory) {
        bytes memory nibbles = "";
        if (b.length > 0) {
            uint8 offset;
            uint8 hpNibble = uint8(_getNthNibbleOfBytes(0, b));
            if (hpNibble == 1 || hpNibble == 3) {
                nibbles = new bytes(b.length * 2 - 1);
                bytes1 oddNibble = _getNthNibbleOfBytes(1, b);
                nibbles[0] = oddNibble;
                offset = 1;
            } else {
                nibbles = new bytes(b.length * 2 - 2);
                offset = 0;
            }

            for (uint256 i = offset; i < nibbles.length; i++) {
                nibbles[i] = _getNthNibbleOfBytes(i - offset + 2, b);
            }
        }
        return nibbles;
    }

    function _getNthNibbleOfBytes(uint256 n, bytes memory str) private pure returns (bytes1) {
        return bytes1(n % 2 == 0 ? uint8(str[n / 2]) / 0x10 : uint8(str[n / 2]) % 0x10);
    }
}

// File: default_workspace/contracts/tunnel/FxBaseRootTunnel.sol


pragma solidity ^0.8.0;





interface IFxStateSender {
    function sendMessageToChild(address _receiver, bytes calldata _data) external;
}

contract ICheckpointManager {
    struct HeaderBlock {
        bytes32 root;
        uint256 start;
        uint256 end;
        uint256 createdAt;
        address proposer;
    }

    /**
     * @notice mapping of checkpoint header numbers to block details
     * @dev These checkpoints are submited by plasma contracts
     */
    mapping(uint256 => HeaderBlock) public headerBlocks;
}

abstract contract FxBaseRootTunnel {
    using RLPReader for RLPReader.RLPItem;
    using Merkle for bytes32;
    using ExitPayloadReader for bytes;
    using ExitPayloadReader for ExitPayloadReader.ExitPayload;
    using ExitPayloadReader for ExitPayloadReader.Log;
    using ExitPayloadReader for ExitPayloadReader.LogTopics;
    using ExitPayloadReader for ExitPayloadReader.Receipt;

    // keccak256(MessageSent(bytes))
    bytes32 public constant SEND_MESSAGE_EVENT_SIG = 0x8c5261668696ce22758910d05bab8f186d6eb247ceac2af2e82c7dc17669b036;

    // state sender contract
    IFxStateSender public fxRoot;
    // root chain manager
    ICheckpointManager public checkpointManager;
    // child tunnel contract which receives and sends messages
    address public fxChildTunnel;

    // storage to avoid duplicate exits
    mapping(bytes32 => bool) public processedExits;

    constructor(address _checkpointManager, address _fxRoot) {
        checkpointManager = ICheckpointManager(_checkpointManager);
        fxRoot = IFxStateSender(_fxRoot);
    }

    // set fxChildTunnel if not set already
    function setFxChildTunnel(address _fxChildTunnel) public virtual {
        require(fxChildTunnel == address(0x0), "FxBaseRootTunnel: CHILD_TUNNEL_ALREADY_SET");
        fxChildTunnel = _fxChildTunnel;
    }

    /**
     * @notice Send bytes message to Child Tunnel
     * @param message bytes message that will be sent to Child Tunnel
     * some message examples -
     *   abi.encode(tokenId);
     *   abi.encode(tokenId, tokenMetadata);
     *   abi.encode(messageType, messageData);
     */
    function _sendMessageToChild(bytes memory message) internal {
        fxRoot.sendMessageToChild(fxChildTunnel, message);
    }

    function _validateAndExtractMessage(bytes memory inputData) internal returns (bytes memory) {
        ExitPayloadReader.ExitPayload memory payload = inputData.toExitPayload();

        bytes memory branchMaskBytes = payload.getBranchMaskAsBytes();
        uint256 blockNumber = payload.getBlockNumber();
        // checking if exit has already been processed
        // unique exit is identified using hash of (blockNumber, branchMask, receiptLogIndex)
        bytes32 exitHash = keccak256(
            abi.encodePacked(
                blockNumber,
                // first 2 nibbles are dropped while generating nibble array
                // this allows branch masks that are valid but bypass exitHash check (changing first 2 nibbles only)
                // so converting to nibble array and then hashing it
                MerklePatriciaProof._getNibbleArray(branchMaskBytes),
                payload.getReceiptLogIndex()
            )
        );
        require(processedExits[exitHash] == false, "FxRootTunnel: EXIT_ALREADY_PROCESSED");
        processedExits[exitHash] = true;

        ExitPayloadReader.Receipt memory receipt = payload.getReceipt();
        ExitPayloadReader.Log memory log = receipt.getLog();

        // check child tunnel
        require(fxChildTunnel == log.getEmitter(), "FxRootTunnel: INVALID_FX_CHILD_TUNNEL");

        bytes32 receiptRoot = payload.getReceiptRoot();
        // verify receipt inclusion
        require(
            MerklePatriciaProof.verify(receipt.toBytes(), branchMaskBytes, payload.getReceiptProof(), receiptRoot),
            "FxRootTunnel: INVALID_RECEIPT_PROOF"
        );

        // verify checkpoint inclusion
        _checkBlockMembershipInCheckpoint(
            blockNumber,
            payload.getBlockTime(),
            payload.getTxRoot(),
            receiptRoot,
            payload.getHeaderNumber(),
            payload.getBlockProof()
        );

        ExitPayloadReader.LogTopics memory topics = log.getTopics();

        require(
            bytes32(topics.getField(0).toUint()) == SEND_MESSAGE_EVENT_SIG, // topic0 is event sig
            "FxRootTunnel: INVALID_SIGNATURE"
        );

        // received message data
        bytes memory message = abi.decode(log.getData(), (bytes)); // event decodes params again, so decoding bytes to get message
        return message;
    }

    function _checkBlockMembershipInCheckpoint(
        uint256 blockNumber,
        uint256 blockTime,
        bytes32 txRoot,
        bytes32 receiptRoot,
        uint256 headerNumber,
        bytes memory blockProof
    ) private view returns (uint256) {
        (bytes32 headerRoot, uint256 startBlock, , uint256 createdAt, ) = checkpointManager.headerBlocks(headerNumber);

        require(
            keccak256(abi.encodePacked(blockNumber, blockTime, txRoot, receiptRoot)).checkMembership(
                blockNumber - startBlock,
                headerRoot,
                blockProof
            ),
            "FxRootTunnel: INVALID_HEADER"
        );
        return createdAt;
    }

    /**
     * @notice receive message from  L2 to L1, validated by proof
     * @dev This function verifies if the transaction actually happened on child chain
     *
     * @param inputData RLP encoded data of the reference tx containing following list of fields
     *  0 - headerNumber - Checkpoint header block number containing the reference tx
     *  1 - blockProof - Proof that the block header (in the child chain) is a leaf in the submitted merkle root
     *  2 - blockNumber - Block number containing the reference tx on child chain
     *  3 - blockTime - Reference tx block time
     *  4 - txRoot - Transactions root of block
     *  5 - receiptRoot - Receipts root of block
     *  6 - receipt - Receipt of the reference transaction
     *  7 - receiptProof - Merkle proof of the reference receipt
     *  8 - branchMask - 32 bits denoting the path of receipt in merkle tree
     *  9 - receiptLogIndex - Log Index to read from the receipt
     */
    function receiveMessage(bytes memory inputData) public virtual {
        bytes memory message = _validateAndExtractMessage(inputData);
        _processMessageFromChild(message);
    }

    /**
     * @notice Process message received from Child Tunnel
     * @dev function needs to be implemented to handle message as per requirement
     * This is called by onStateReceive function.
     * Since it is called via a system call, any event will not be emitted during its execution.
     * @param message bytes message that was sent from Child Tunnel
     */
    function _processMessageFromChild(bytes memory message) internal virtual;
}

// File: default_workspace/contracts/IDungeonRewards.sol


pragma solidity ^0.8.12;

interface IDungeonRewards {

    // so we can confirm whether a wallet holds any staked dungeons, useful for Generative Avatars gas-only mint
    function balanceOfDungeons(address owner) external view returns (uint256);
    // so we can confirm when a wallet staked their dungeons, useful for Generative Avatars gas-only mint
    function dungeonFirstStaked(address owner) external view returns (uint256);

    function balanceOfAvatars(address owner) external view returns (uint256);
    function avatarFirstStaked(address owner) external  view returns (uint256);

    function balanceOfQuests(address owner) external view returns (uint256);
    function questFirstStaked(address owner) external view returns (uint256);

    function getStakedTokens(address user) external view returns (uint256[] memory dungeons, uint256[] memory avatars, 
                                                                  uint256[] memory quests);
  
}
// File: default_workspace/contracts/ERC721.sol


pragma solidity >=0.8.0;

/// @notice Modern, minimalist, and gas efficient ERC-721 implementation.
/// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/tokens/ERC721.sol)
/// @dev Note that balanceOf does not revert if passed the zero address, in defiance of the ERC.
abstract contract ERC721 {
    /*///////////////////////////////////////////////////////////////
                                 EVENTS
    //////////////////////////////////////////////////////////////*/

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

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

    event ApprovalForAll(address indexed owner, address indexed operator, bool approved);

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

    string public name;

    string public symbol;

    function tokenURI(uint256 id) public view virtual returns (string memory);

    /*///////////////////////////////////////////////////////////////
                            ERC721 STORAGE                        
    //////////////////////////////////////////////////////////////*/

    mapping(address => uint256) public balanceOf;

    mapping(uint256 => address) public ownerOf;

    mapping(uint256 => address) public getApproved;

    mapping(address => mapping(address => bool)) public isApprovedForAll;

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

    constructor(string memory _name, string memory _symbol) {
        name = _name;
        symbol = _symbol;
    }

    /*///////////////////////////////////////////////////////////////
                              ERC721 LOGIC
    //////////////////////////////////////////////////////////////*/

    function approve(address spender, uint256 id) public virtual {
        address owner = ownerOf[id];

        require(msg.sender == owner || isApprovedForAll[owner][msg.sender], "NOT_AUTHORIZED");

        getApproved[id] = spender;

        emit Approval(owner, spender, id);
    }

    function setApprovalForAll(address operator, bool approved) public virtual {
        isApprovedForAll[msg.sender][operator] = approved;

        emit ApprovalForAll(msg.sender, operator, approved);
    }

    function transferFrom(
        address from,
        address to,
        uint256 id
    ) public virtual {
        require(from == ownerOf[id], "WRONG_FROM");

        require(to != address(0), "INVALID_RECIPIENT");

        require(
            msg.sender == from || msg.sender == getApproved[id] || isApprovedForAll[from][msg.sender],
            "NOT_AUTHORIZED"
        );

        // Underflow of the sender's balance is impossible because we check for
        // ownership above and the recipient's balance can't realistically overflow.
        unchecked {
            balanceOf[from]--;

            balanceOf[to]++;
        }

        ownerOf[id] = to;

        delete getApproved[id];

        emit Transfer(from, to, id);
    }

    function safeTransferFrom(
        address from,
        address to,
        uint256 id
    ) public virtual {
        transferFrom(from, to, id);

        require(
            to.code.length == 0 ||
                ERC721TokenReceiver(to).onERC721Received(msg.sender, from, id, "") ==
                ERC721TokenReceiver.onERC721Received.selector,
            "UNSAFE_RECIPIENT"
        );
    }

    function safeTransferFrom(
        address from,
        address to,
        uint256 id,
        bytes memory data
    ) public virtual {
        transferFrom(from, to, id);

        require(
            to.code.length == 0 ||
                ERC721TokenReceiver(to).onERC721Received(msg.sender, from, id, data) ==
                ERC721TokenReceiver.onERC721Received.selector,
            "UNSAFE_RECIPIENT"
        );
    }

    /*///////////////////////////////////////////////////////////////
                              ERC165 LOGIC
    //////////////////////////////////////////////////////////////*/

    function supportsInterface(bytes4 interfaceId) public pure virtual returns (bool) {
        return
            interfaceId == 0x01ffc9a7 || // ERC165 Interface ID for ERC165
            interfaceId == 0x80ac58cd || // ERC165 Interface ID for ERC721
            interfaceId == 0x5b5e139f; // ERC165 Interface ID for ERC721Metadata
    }

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

    function _mint(address to, uint256 id) internal virtual {
        require(to != address(0), "INVALID_RECIPIENT");

        require(ownerOf[id] == address(0), "ALREADY_MINTED");

        // Counter overflow is incredibly unrealistic.
        unchecked {
            balanceOf[to]++;
        }

        ownerOf[id] = to;

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

    function _burn(uint256 id) internal virtual {
        address owner = ownerOf[id];

        require(ownerOf[id] != address(0), "NOT_MINTED");

        // Ownership check above ensures no underflow.
        unchecked {
            balanceOf[owner]--;
        }

        delete ownerOf[id];

        delete getApproved[id];

        emit Transfer(owner, address(0), id);
    }

    /*///////////////////////////////////////////////////////////////
                       INTERNAL SAFE MINT LOGIC
    //////////////////////////////////////////////////////////////*/

    function _safeMint(address to, uint256 id) internal virtual {
        _mint(to, id);

        require(
            to.code.length == 0 ||
                ERC721TokenReceiver(to).onERC721Received(msg.sender, address(0), id, "") ==
                ERC721TokenReceiver.onERC721Received.selector,
            "UNSAFE_RECIPIENT"
        );
    }

    function _safeMint(
        address to,
        uint256 id,
        bytes memory data
    ) internal virtual {
        _mint(to, id);

        require(
            to.code.length == 0 ||
                ERC721TokenReceiver(to).onERC721Received(msg.sender, address(0), id, data) ==
                ERC721TokenReceiver.onERC721Received.selector,
            "UNSAFE_RECIPIENT"
        );
    }
}

/// @notice A generic interface for a contract which properly accepts ERC721 tokens.
/// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/tokens/ERC721.sol)
interface ERC721TokenReceiver {
    function onERC721Received(
        address operator,
        address from,
        uint256 id,
        bytes calldata data
    ) external returns (bytes4);
}

// File: default_workspace/contracts/IDNGToken.sol


pragma solidity ^0.8.12;

interface IDNGToken {
    enum NftType {
        Dungeon,
        Avatar,
        Quest
    }
}

// File: default_workspace/contracts/DungeonRewards.sol


pragma solidity ^0.8.12;






/**
 ________  ___  ___  ________   ________  _______   ________  ________          
|\   ___ \|\  \|\  \|\   ___  \|\   ____\|\  ___ \ |\   __  \|\   ___  \        
\ \  \_|\ \ \  \\\  \ \  \\ \  \ \  \___|\ \   __/|\ \  \|\  \ \  \\ \  \       
 \ \  \ \\ \ \  \\\  \ \  \\ \  \ \  \  __\ \  \_|/_\ \  \\\  \ \  \\ \  \      
  \ \  \_\\ \ \  \\\  \ \  \\ \  \ \  \|\  \ \  \_|\ \ \  \\\  \ \  \\ \  \     
   \ \_______\ \_______\ \__\\ \__\ \_______\ \_______\ \_______\ \__\\ \__\    
    \|_______|\|_______|\|__| \|__|\|_______|\|_______|\|_______|\|__| \|__|    
                                                                                
                                                                                
                                                                                
 ________  _______   ___       __   ________  ________  ________  ________      
|\   __  \|\  ___ \ |\  \     |\  \|\   __  \|\   __  \|\   ___ \|\   ____\     
\ \  \|\  \ \   __/|\ \  \    \ \  \ \  \|\  \ \  \|\  \ \  \_|\ \ \  \___|_    
 \ \   _  _\ \  \_|/_\ \  \  __\ \  \ \   __  \ \   _  _\ \  \ \\ \ \_____  \   
  \ \  \\  \\ \  \_|\ \ \  \|\__\_\  \ \  \ \  \ \  \\  \\ \  \_\\ \|____|\  \  
   \ \__\\ _\\ \_______\ \____________\ \__\ \__\ \__\\ _\\ \_______\____\_\  \ 
    \|__|\|__|\|_______|\|____________|\|__|\|__|\|__|\|__|\|_______|\_________\
                                                                    \|_________|
                                                                                
**/

contract DungeonRewards is IDungeonRewards, IDNGToken, FxBaseRootTunnel, Ownable {
    /*///////////////////////////////////////////////////////////////
                            STORAGE
    //////////////////////////////////////////////////////////////*/

    ERC721 public dungeonContract;
    ERC721 public avatarContract;
    ERC721 public questContract;

    struct Staker {
        uint256[] stakedDungeons;
        uint256 dungeonStakedOn;     // timestamp of when holder first staked their dungeon(s) (used to calculated eligibility for avatars).
        uint256[] stakedAvatars;
        uint256 avatarStakedOn;     // timestamp of when holder first staked their avatar(s)
        uint256[] stakedQuests;
        uint256 questStakedOn;     // timestamp of when holder first staked their quest(s)
    }

    mapping(address => Staker) public userInfo;

    bool public stakingPaused;

    constructor(
        address checkpointManager,
        address fxRoot,
        address _dungeonContract
    ) FxBaseRootTunnel(checkpointManager, fxRoot) {
        dungeonContract = ERC721(_dungeonContract);
    }

    // @notice Set the contract addresses for all future instances.
    function setContractAddresses(
        address _avatarContract,
        address _questContract
    ) public onlyOwner {
        avatarContract = ERC721(_avatarContract);
        questContract = ERC721(_questContract);
    }

    // Pause staking and unstaking
    function setStakingPaused(bool paused) public onlyOwner {
        stakingPaused = paused;
    }


    // For collab.land to give a role based on staking status
    function balanceOf(address owner) public view returns (uint256) {
        if(balanceOfDungeons(owner)>0 && balanceOfAvatars(owner)>0 && balanceOfQuests(owner)>0) return 3;
        if(balanceOfDungeons(owner)>0 && balanceOfAvatars(owner)>0 && balanceOfQuests(owner)==0) return 2;
        if(balanceOfDungeons(owner)>0 && balanceOfAvatars(owner)==0 && balanceOfQuests(owner)==0) return 1;
        return 0;
    }

    // so we can confirm whether a wallet holds any staked dungeons, useful for Generative Avatars gas-only mint
    function balanceOfDungeons(address owner) public view returns (uint256) {
        return userInfo[owner].stakedDungeons.length;
    }
    // so we can confirm when a wallet staked their dungeons, useful for Generative Avatars gas-only mint
    function dungeonFirstStaked(address owner) public view returns (uint256) {
        return userInfo[owner].dungeonStakedOn;
    }

    function balanceOfAvatars(address owner) public view returns (uint256) {
        return userInfo[owner].stakedAvatars.length;
    }
    function avatarFirstStaked(address owner) public view returns (uint256) {
        return userInfo[owner].avatarStakedOn;
    }

    function balanceOfQuests(address owner) public view returns (uint256) {
        return userInfo[owner].stakedQuests.length;
    }
    function questFirstStaked(address owner) public view returns (uint256) {
        return userInfo[owner].questStakedOn;
    }


    // get staked tokens for address
    function getStakedTokens(address user) public view returns (
            uint256[] memory dungeons,
            uint256[] memory avatars,
            uint256[] memory quests
        )
    {
        Staker memory staker = userInfo[user];
        return (
            staker.stakedDungeons,
            staker.stakedAvatars,
            staker.stakedQuests
        );
    }

    function bulkStake(
        uint256[] memory dungeons,
        uint256[] memory avatars,
        uint256[] memory quests
    ) public {
        if (dungeons.length > 0) stakeMultipleDungeons(dungeons);
        if (avatars.length > 0) stakeMultipleAvatars(avatars);
        if (quests.length > 0) stakeMultipleQuests(quests);        
    }

    function bulkUnstake(
        uint256[] memory dungeons,
        uint256[] memory avatars,
        uint256[] memory quests
    ) public {
        if (dungeons.length > 0) unstakeMultipleDungeons(dungeons);
        if (avatars.length > 0) unstakeMultipleAvatars(avatars);
        if (quests.length > 0) unstakeMultipleQuests(quests);        
    }

    function stakeMultipleDungeons(uint256[] memory tokenIds) public {
        require(!stakingPaused, "Staking currently paused.");
        require(tokenIds.length>0, "No tokenIds provided.");

        Staker storage staker = userInfo[msg.sender];

        if (staker.dungeonStakedOn == 0) { // set our dungeon staked on once (if they unstake, it resets to zero and will be reset when they stake again)
            staker.dungeonStakedOn = block.timestamp; 
        }

        for (uint256 i = 0; i < tokenIds.length; i++) {
            staker.stakedDungeons.push(tokenIds[i]);
            dungeonContract.transferFrom(
                msg.sender,
                address(this),
                tokenIds[i]
            );
        }
        // start accumulating $DNG rewards on polygon
        _sendMessageToChild(
            abi.encode(
                msg.sender,
                uint256(NftType.Dungeon),
                tokenIds.length,
                true
            )
        );
    }

    function unstakeMultipleDungeons(uint256[] memory tokenIds) public {
        require(!stakingPaused, "Staking is currently paused.");
        Staker storage staker = userInfo[msg.sender];
        for (uint256 i = 0; i < tokenIds.length; i++) {
            uint256 tokenId = tokenIds[i];
            require(containsElement(staker.stakedDungeons, tokenId), "Not dungeon owner.");
            dungeonContract.transferFrom(
                address(this),
                msg.sender,
                tokenId
            );
            removeDungeonFromStaker(staker, tokenId);
        }

        if (staker.stakedDungeons.length == 0) { // no more staked dungeons? 
            staker.dungeonStakedOn = 0; // then we reset the staked on date to 0 (so can be set to block.timestamp when it's staked again)
        }
        // stop accumulating $DNG rewards on polygon for these dungeons
        _sendMessageToChild(
            abi.encode(
                msg.sender,
                uint256(NftType.Dungeon),
                tokenIds.length,
                false
            )
        );
    }

    // Stake a single Dungeon (separate function to optimize for gas)
    // @param tokenId The tokenId of the dungeon to stake
    function stakeDungeon(uint256 tokenId) external {
        require(!stakingPaused, "Staking is currently paused.");
        Staker storage staker = userInfo[msg.sender];
        staker.stakedDungeons.push(tokenId);
        dungeonContract.transferFrom(
            msg.sender,
            address(this),
            tokenId
        );
        if (staker.dungeonStakedOn == 0) { // set our dungeon staked on once (if they unstake, it resets to zero and will be reset when they stake again)
            staker.dungeonStakedOn = block.timestamp; 
        }
        // start accumulating $DNG rewards on polygon
        _sendMessageToChild(
            abi.encode(
                msg.sender,
                uint256(NftType.Dungeon),
                1,
                true
            )
        );
    }

    // Unstake a Dungeon
    // @param tokenId The tokenId of the dungeon to unstake
    function unstakeDungeon(uint256 tokenId) external {
        require(!stakingPaused, "Staking is currently paused.");
        Staker storage staker = userInfo[msg.sender];
        require(containsElement(staker.stakedDungeons, tokenId), "Not dungeon owner.");

        dungeonContract.transferFrom(
            address(this),
            msg.sender,
            tokenId
        );

        removeDungeonFromStaker(staker, tokenId);

        if (staker.stakedDungeons.length == 0) { // no more staked dungeons? 
            staker.dungeonStakedOn = 0; // then we reset the staked on date to 0 (so can be set to block.timestamp when it's staked again)
        }

        // stop accumulating $DNG rewards on polygon for these dungeons
        _sendMessageToChild(
            abi.encode(
                msg.sender,
                uint256(NftType.Dungeon),
                1,
                false
            )
        );

    }

    function stakeMultipleAvatars(uint256[] memory tokenIds) public {
        require(!stakingPaused, "Staking currently paused.");
        require(tokenIds.length>0, "No tokenIds provided.");

        Staker storage staker = userInfo[msg.sender];

        if (staker.avatarStakedOn == 0) { // set our avatar staked on once (if they unstake, it resets to zero and will be reset when they stake again)
            staker.avatarStakedOn = block.timestamp; 
        }

        for (uint256 i = 0; i < tokenIds.length; i++) {
            staker.stakedAvatars.push(tokenIds[i]);
            avatarContract.transferFrom(
                msg.sender,
                address(this),
                tokenIds[i]
            );
        }
        // start accumulating $DNG rewards on polygon
        _sendMessageToChild(
            abi.encode(
                msg.sender,
                uint256(NftType.Avatar),
                tokenIds.length,
                true
            )
        );
    }

    function unstakeMultipleAvatars(uint256[] memory tokenIds) public {
        require(!stakingPaused, "Staking is currently paused.");
        Staker storage staker = userInfo[msg.sender];
        for (uint256 i = 0; i < tokenIds.length; i++) {
            uint256 tokenId = tokenIds[i];
            require(containsElement(...

// [truncated — 59611 bytes total]

Read Contract

SEND_MESSAGE_EVENT_SIG 0x0e387de6 → bytes32
avatarContract 0x45f0791d → address
avatarFirstStaked 0xcc581d79 → uint256
balanceOf 0x70a08231 → uint256
balanceOfAvatars 0xa6197a9f → uint256
balanceOfDungeons 0x3eee69a9 → uint256
balanceOfQuests 0x3f02d59e → uint256
checkpointManager 0xc0857ba0 → address
dungeonContract 0xf79e4164 → address
dungeonFirstStaked 0x3ac4b3ac → uint256
fxChildTunnel 0x972c4928 → address
fxRoot 0xde9b771f → address
getStakedTokens 0x63c28db1 → uint256[], uint256[], uint256[]
onERC721Received 0x150b7a02 → bytes4
owner 0x8da5cb5b → address
processedExits 0x607f2d42 → bool
questContract 0x6a6940cc → address
questFirstStaked 0xbded9a7c → uint256
stakingPaused 0xbbb781cc → bool
supportsInterface 0x01ffc9a7 → bool
userInfo 0x1959a002 → uint256, uint256, uint256

Write Contract 20 functions

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

bulkStake 0xd3397850
uint256[] dungeons
uint256[] avatars
uint256[] quests
bulkUnstake 0x0e1db437
uint256[] dungeons
uint256[] avatars
uint256[] quests
receiveMessage 0xf953cec7
bytes inputData
renounceOwnership 0x715018a6
No parameters
setContractAddresses 0xcd931e40
address _avatarContract
address _questContract
setFxChildTunnel 0xaea4e49e
address _fxChildTunnel
setStakingPaused 0x15b31bbb
bool paused
stakeAvatar 0xc6a54924
uint256 tokenId
stakeDungeon 0xd9c65c27
uint256 tokenId
stakeMultipleAvatars 0x840d6dcf
uint256[] tokenIds
stakeMultipleDungeons 0x8d18fa62
uint256[] tokenIds
stakeMultipleQuests 0x795b396d
uint256[] tokenIds
stakeQuest 0x4f04eba4
uint256 tokenId
transferOwnership 0xf2fde38b
address _newOwner
unstakeAvatar 0x998a1d15
uint256 tokenId
unstakeDungeon 0x3723148e
uint256 tokenId
unstakeMultipleAvatars 0xd0b05d35
uint256[] tokenIds
unstakeMultipleDungeons 0xad280eb0
uint256[] tokenIds
unstakeMultipleQuests 0xa04b29b9
uint256[] tokenIds
unstakeQuest 0xc714b768
uint256 tokenId

Recent Transactions

No transactions found for this address