From f8a9bcefcf1d8faa6181420616578576cac1e797 Mon Sep 17 00:00:00 2001 From: Claudiu Date: Mon, 1 Apr 2024 20:03:28 +0300 Subject: [PATCH 01/10] fix(scripts): Fix artifacts --- abi/common/BaseERC721A.json | 92 +++ abi/common/IBaseERC721A.json | 661 ------------------- abi/common/INonceRegistry.json | 229 ------- abi/common/ITreasury.json | 47 -- abi/pookyball/IPookyball.json | 675 ------------------- abi/pookyball/Pookyball.json | 110 ++++ abi/stickers/IStickers.json | 747 ---------------------- abi/stickers/IStickersController.json | 199 ------ abi/stickers/Stickers.json | 92 +++ abi/tokens/IPOK.json | 393 ------------ abi/tokens/POK.json | 8 +- abi/types/VRFConfig.json | 1 - bytecode/common/BaseERC721A.bin | 2 +- bytecode/common/IBaseERC721A.bin | 1 - bytecode/common/INonceRegistry.bin | 1 - bytecode/common/ITreasury.bin | 1 - bytecode/pookyball/IPookyball.bin | 1 - bytecode/pookyball/Pookyball.bin | 2 +- bytecode/stickers/IStickers.bin | 1 - bytecode/stickers/IStickersController.bin | 1 - bytecode/stickers/Stickers.bin | 2 +- bytecode/tokens/IPOK.bin | 1 - bytecode/tokens/POK.bin | 2 +- bytecode/types/VRFConfig.bin | 1 - lefthook.yml | 2 +- script/artifacts.ts | 28 +- 26 files changed, 324 insertions(+), 2976 deletions(-) delete mode 100644 abi/common/IBaseERC721A.json delete mode 100644 abi/common/INonceRegistry.json delete mode 100644 abi/common/ITreasury.json delete mode 100644 abi/pookyball/IPookyball.json delete mode 100644 abi/stickers/IStickers.json delete mode 100644 abi/stickers/IStickersController.json delete mode 100644 abi/tokens/IPOK.json delete mode 100644 abi/types/VRFConfig.json delete mode 100644 bytecode/common/IBaseERC721A.bin delete mode 100644 bytecode/common/INonceRegistry.bin delete mode 100644 bytecode/common/ITreasury.bin delete mode 100644 bytecode/pookyball/IPookyball.bin delete mode 100644 bytecode/stickers/IStickers.bin delete mode 100644 bytecode/stickers/IStickersController.bin delete mode 100644 bytecode/tokens/IPOK.bin delete mode 100644 bytecode/types/VRFConfig.bin diff --git a/abi/common/BaseERC721A.json b/abi/common/BaseERC721A.json index e3dd08bc..882201e0 100644 --- a/abi/common/BaseERC721A.json +++ b/abi/common/BaseERC721A.json @@ -148,6 +148,32 @@ "outputs": [], "stateMutability": "nonpayable" }, + { + "type": "function", + "name": "canUpdateVRF", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "canUseVRF", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, { "type": "function", "name": "cancelOwnershipHandover", @@ -181,6 +207,20 @@ ], "stateMutability": "view" }, + { + "type": "function", + "name": "disableUpdateVRF", + "inputs": [], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "enableVRF", + "inputs": [], + "outputs": [], + "stateMutability": "nonpayable" + }, { "type": "function", "name": "explicitOwnershipOf", @@ -263,6 +303,25 @@ ], "stateMutability": "view" }, + { + "type": "function", + "name": "generateRandomSeed", + "inputs": [ + { + "name": "tokenId", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, { "type": "function", "name": "getApproved", @@ -724,6 +783,39 @@ "outputs": [], "stateMutability": "payable" }, + { + "type": "function", + "name": "updateVRF", + "inputs": [ + { + "name": "_vrfCoordinator", + "type": "address", + "internalType": "address" + }, + { + "name": "_vrfKeyHash", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "_vrfSubId", + "type": "uint64", + "internalType": "uint64" + }, + { + "name": "_vrfMinimumRequestConfirmations", + "type": "uint16", + "internalType": "uint16" + }, + { + "name": "_vrfCallbackGasLimit", + "type": "uint32", + "internalType": "uint32" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, { "type": "function", "name": "vrf", diff --git a/abi/common/IBaseERC721A.json b/abi/common/IBaseERC721A.json deleted file mode 100644 index 1ad76ef2..00000000 --- a/abi/common/IBaseERC721A.json +++ /dev/null @@ -1,661 +0,0 @@ -[ - { - "type": "function", - "name": "approve", - "inputs": [ - { - "name": "to", - "type": "address", - "internalType": "address" - }, - { - "name": "tokenId", - "type": "uint256", - "internalType": "uint256" - } - ], - "outputs": [], - "stateMutability": "payable" - }, - { - "type": "function", - "name": "balanceOf", - "inputs": [ - { - "name": "owner", - "type": "address", - "internalType": "address" - } - ], - "outputs": [ - { - "name": "balance", - "type": "uint256", - "internalType": "uint256" - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "burn", - "inputs": [ - { - "name": "tokenId", - "type": "uint256", - "internalType": "uint256" - } - ], - "outputs": [], - "stateMutability": "nonpayable" - }, - { - "type": "function", - "name": "explicitOwnershipOf", - "inputs": [ - { - "name": "tokenId", - "type": "uint256", - "internalType": "uint256" - } - ], - "outputs": [ - { - "name": "", - "type": "tuple", - "internalType": "struct IERC721A.TokenOwnership", - "components": [ - { - "name": "addr", - "type": "address", - "internalType": "address" - }, - { - "name": "startTimestamp", - "type": "uint64", - "internalType": "uint64" - }, - { - "name": "burned", - "type": "bool", - "internalType": "bool" - }, - { - "name": "extraData", - "type": "uint24", - "internalType": "uint24" - } - ] - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "explicitOwnershipsOf", - "inputs": [ - { - "name": "tokenIds", - "type": "uint256[]", - "internalType": "uint256[]" - } - ], - "outputs": [ - { - "name": "", - "type": "tuple[]", - "internalType": "struct IERC721A.TokenOwnership[]", - "components": [ - { - "name": "addr", - "type": "address", - "internalType": "address" - }, - { - "name": "startTimestamp", - "type": "uint64", - "internalType": "uint64" - }, - { - "name": "burned", - "type": "bool", - "internalType": "bool" - }, - { - "name": "extraData", - "type": "uint24", - "internalType": "uint24" - } - ] - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "getApproved", - "inputs": [ - { - "name": "tokenId", - "type": "uint256", - "internalType": "uint256" - } - ], - "outputs": [ - { - "name": "operator", - "type": "address", - "internalType": "address" - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "isApprovedForAll", - "inputs": [ - { - "name": "owner", - "type": "address", - "internalType": "address" - }, - { - "name": "operator", - "type": "address", - "internalType": "address" - } - ], - "outputs": [ - { - "name": "", - "type": "bool", - "internalType": "bool" - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "name", - "inputs": [], - "outputs": [ - { - "name": "", - "type": "string", - "internalType": "string" - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "nextTokenId", - "inputs": [], - "outputs": [ - { - "name": "", - "type": "uint256", - "internalType": "uint256" - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "ownerOf", - "inputs": [ - { - "name": "tokenId", - "type": "uint256", - "internalType": "uint256" - } - ], - "outputs": [ - { - "name": "owner", - "type": "address", - "internalType": "address" - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "royaltyInfo", - "inputs": [ - { - "name": "tokenId", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "salePrice", - "type": "uint256", - "internalType": "uint256" - } - ], - "outputs": [ - { - "name": "receiver", - "type": "address", - "internalType": "address" - }, - { - "name": "royaltyAmount", - "type": "uint256", - "internalType": "uint256" - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "safeTransferFrom", - "inputs": [ - { - "name": "from", - "type": "address", - "internalType": "address" - }, - { - "name": "to", - "type": "address", - "internalType": "address" - }, - { - "name": "tokenId", - "type": "uint256", - "internalType": "uint256" - } - ], - "outputs": [], - "stateMutability": "payable" - }, - { - "type": "function", - "name": "safeTransferFrom", - "inputs": [ - { - "name": "from", - "type": "address", - "internalType": "address" - }, - { - "name": "to", - "type": "address", - "internalType": "address" - }, - { - "name": "tokenId", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "data", - "type": "bytes", - "internalType": "bytes" - } - ], - "outputs": [], - "stateMutability": "payable" - }, - { - "type": "function", - "name": "setApprovalForAll", - "inputs": [ - { - "name": "operator", - "type": "address", - "internalType": "address" - }, - { - "name": "_approved", - "type": "bool", - "internalType": "bool" - } - ], - "outputs": [], - "stateMutability": "nonpayable" - }, - { - "type": "function", - "name": "supportsInterface", - "inputs": [ - { - "name": "interfaceId", - "type": "bytes4", - "internalType": "bytes4" - } - ], - "outputs": [ - { - "name": "", - "type": "bool", - "internalType": "bool" - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "symbol", - "inputs": [], - "outputs": [ - { - "name": "", - "type": "string", - "internalType": "string" - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "tokenURI", - "inputs": [ - { - "name": "tokenId", - "type": "uint256", - "internalType": "uint256" - } - ], - "outputs": [ - { - "name": "", - "type": "string", - "internalType": "string" - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "tokensOfOwner", - "inputs": [ - { - "name": "owner", - "type": "address", - "internalType": "address" - } - ], - "outputs": [ - { - "name": "", - "type": "uint256[]", - "internalType": "uint256[]" - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "tokensOfOwnerIn", - "inputs": [ - { - "name": "owner", - "type": "address", - "internalType": "address" - }, - { - "name": "start", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "stop", - "type": "uint256", - "internalType": "uint256" - } - ], - "outputs": [ - { - "name": "", - "type": "uint256[]", - "internalType": "uint256[]" - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "totalSupply", - "inputs": [], - "outputs": [ - { - "name": "", - "type": "uint256", - "internalType": "uint256" - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "transferFrom", - "inputs": [ - { - "name": "from", - "type": "address", - "internalType": "address" - }, - { - "name": "to", - "type": "address", - "internalType": "address" - }, - { - "name": "tokenId", - "type": "uint256", - "internalType": "uint256" - } - ], - "outputs": [], - "stateMutability": "payable" - }, - { - "type": "event", - "name": "Approval", - "inputs": [ - { - "name": "owner", - "type": "address", - "indexed": true, - "internalType": "address" - }, - { - "name": "approved", - "type": "address", - "indexed": true, - "internalType": "address" - }, - { - "name": "tokenId", - "type": "uint256", - "indexed": true, - "internalType": "uint256" - } - ], - "anonymous": false - }, - { - "type": "event", - "name": "ApprovalForAll", - "inputs": [ - { - "name": "owner", - "type": "address", - "indexed": true, - "internalType": "address" - }, - { - "name": "operator", - "type": "address", - "indexed": true, - "internalType": "address" - }, - { - "name": "approved", - "type": "bool", - "indexed": false, - "internalType": "bool" - } - ], - "anonymous": false - }, - { - "type": "event", - "name": "ConsecutiveTransfer", - "inputs": [ - { - "name": "fromTokenId", - "type": "uint256", - "indexed": true, - "internalType": "uint256" - }, - { - "name": "toTokenId", - "type": "uint256", - "indexed": false, - "internalType": "uint256" - }, - { - "name": "from", - "type": "address", - "indexed": true, - "internalType": "address" - }, - { - "name": "to", - "type": "address", - "indexed": true, - "internalType": "address" - } - ], - "anonymous": false - }, - { - "type": "event", - "name": "SeedSet", - "inputs": [ - { - "name": "tokenId", - "type": "uint256", - "indexed": true, - "internalType": "uint256" - }, - { - "name": "seed", - "type": "uint256", - "indexed": false, - "internalType": "uint256" - } - ], - "anonymous": false - }, - { - "type": "event", - "name": "Transfer", - "inputs": [ - { - "name": "from", - "type": "address", - "indexed": true, - "internalType": "address" - }, - { - "name": "to", - "type": "address", - "indexed": true, - "internalType": "address" - }, - { - "name": "tokenId", - "type": "uint256", - "indexed": true, - "internalType": "uint256" - } - ], - "anonymous": false - }, - { - "type": "error", - "name": "ApprovalCallerNotOwnerNorApproved", - "inputs": [] - }, - { - "type": "error", - "name": "ApprovalQueryForNonexistentToken", - "inputs": [] - }, - { - "type": "error", - "name": "BalanceQueryForZeroAddress", - "inputs": [] - }, - { - "type": "error", - "name": "InvalidQueryRange", - "inputs": [] - }, - { - "type": "error", - "name": "MintERC2309QuantityExceedsLimit", - "inputs": [] - }, - { - "type": "error", - "name": "MintToZeroAddress", - "inputs": [] - }, - { - "type": "error", - "name": "MintZeroQuantity", - "inputs": [] - }, - { - "type": "error", - "name": "NonExistentToken", - "inputs": [ - { - "name": "tokenId", - "type": "uint256", - "internalType": "uint256" - } - ] - }, - { - "type": "error", - "name": "OwnerQueryForNonexistentToken", - "inputs": [] - }, - { - "type": "error", - "name": "OwnershipNotInitializedForExtraData", - "inputs": [] - }, - { - "type": "error", - "name": "TransferCallerNotOwnerNorApproved", - "inputs": [] - }, - { - "type": "error", - "name": "TransferFromIncorrectOwner", - "inputs": [] - }, - { - "type": "error", - "name": "TransferToNonERC721ReceiverImplementer", - "inputs": [] - }, - { - "type": "error", - "name": "TransferToZeroAddress", - "inputs": [] - }, - { - "type": "error", - "name": "URIQueryForNonexistentToken", - "inputs": [] - } -] diff --git a/abi/common/INonceRegistry.json b/abi/common/INonceRegistry.json deleted file mode 100644 index 74400d98..00000000 --- a/abi/common/INonceRegistry.json +++ /dev/null @@ -1,229 +0,0 @@ -[ - { - "type": "function", - "name": "getRoleAdmin", - "inputs": [ - { - "name": "role", - "type": "bytes32", - "internalType": "bytes32" - } - ], - "outputs": [ - { - "name": "", - "type": "bytes32", - "internalType": "bytes32" - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "grantRole", - "inputs": [ - { - "name": "role", - "type": "bytes32", - "internalType": "bytes32" - }, - { - "name": "account", - "type": "address", - "internalType": "address" - } - ], - "outputs": [], - "stateMutability": "nonpayable" - }, - { - "type": "function", - "name": "has", - "inputs": [ - { - "name": "nonce", - "type": "bytes32", - "internalType": "bytes32" - } - ], - "outputs": [ - { - "name": "", - "type": "bool", - "internalType": "bool" - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "hasRole", - "inputs": [ - { - "name": "role", - "type": "bytes32", - "internalType": "bytes32" - }, - { - "name": "account", - "type": "address", - "internalType": "address" - } - ], - "outputs": [ - { - "name": "", - "type": "bool", - "internalType": "bool" - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "renounceRole", - "inputs": [ - { - "name": "role", - "type": "bytes32", - "internalType": "bytes32" - }, - { - "name": "account", - "type": "address", - "internalType": "address" - } - ], - "outputs": [], - "stateMutability": "nonpayable" - }, - { - "type": "function", - "name": "revokeRole", - "inputs": [ - { - "name": "role", - "type": "bytes32", - "internalType": "bytes32" - }, - { - "name": "account", - "type": "address", - "internalType": "address" - } - ], - "outputs": [], - "stateMutability": "nonpayable" - }, - { - "type": "function", - "name": "set", - "inputs": [ - { - "name": "nonce", - "type": "bytes32", - "internalType": "bytes32" - }, - { - "name": "value", - "type": "bool", - "internalType": "bool" - } - ], - "outputs": [], - "stateMutability": "nonpayable" - }, - { - "type": "function", - "name": "setBatch", - "inputs": [ - { - "name": "nonces", - "type": "bytes32[]", - "internalType": "bytes32[]" - }, - { - "name": "values", - "type": "bool[]", - "internalType": "bool[]" - } - ], - "outputs": [], - "stateMutability": "nonpayable" - }, - { - "type": "event", - "name": "RoleAdminChanged", - "inputs": [ - { - "name": "role", - "type": "bytes32", - "indexed": true, - "internalType": "bytes32" - }, - { - "name": "previousAdminRole", - "type": "bytes32", - "indexed": true, - "internalType": "bytes32" - }, - { - "name": "newAdminRole", - "type": "bytes32", - "indexed": true, - "internalType": "bytes32" - } - ], - "anonymous": false - }, - { - "type": "event", - "name": "RoleGranted", - "inputs": [ - { - "name": "role", - "type": "bytes32", - "indexed": true, - "internalType": "bytes32" - }, - { - "name": "account", - "type": "address", - "indexed": true, - "internalType": "address" - }, - { - "name": "sender", - "type": "address", - "indexed": true, - "internalType": "address" - } - ], - "anonymous": false - }, - { - "type": "event", - "name": "RoleRevoked", - "inputs": [ - { - "name": "role", - "type": "bytes32", - "indexed": true, - "internalType": "bytes32" - }, - { - "name": "account", - "type": "address", - "indexed": true, - "internalType": "address" - }, - { - "name": "sender", - "type": "address", - "indexed": true, - "internalType": "address" - } - ], - "anonymous": false - } -] diff --git a/abi/common/ITreasury.json b/abi/common/ITreasury.json deleted file mode 100644 index 07e168e5..00000000 --- a/abi/common/ITreasury.json +++ /dev/null @@ -1,47 +0,0 @@ -[ - { - "type": "function", - "name": "changeTreasury", - "inputs": [ - { - "name": "_treasury", - "type": "address", - "internalType": "address" - } - ], - "outputs": [], - "stateMutability": "nonpayable" - }, - { - "type": "error", - "name": "InsufficientValue", - "inputs": [ - { - "name": "expected", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "actual", - "type": "uint256", - "internalType": "uint256" - } - ] - }, - { - "type": "error", - "name": "TransferFailed", - "inputs": [ - { - "name": "recipient", - "type": "address", - "internalType": "address" - }, - { - "name": "amount", - "type": "uint256", - "internalType": "uint256" - } - ] - } -] diff --git a/abi/pookyball/IPookyball.json b/abi/pookyball/IPookyball.json deleted file mode 100644 index 65f55ecf..00000000 --- a/abi/pookyball/IPookyball.json +++ /dev/null @@ -1,675 +0,0 @@ -[ - { - "type": "function", - "name": "approve", - "inputs": [ - { - "name": "to", - "type": "address", - "internalType": "address" - }, - { - "name": "tokenId", - "type": "uint256", - "internalType": "uint256" - } - ], - "outputs": [], - "stateMutability": "nonpayable" - }, - { - "type": "function", - "name": "balanceOf", - "inputs": [ - { - "name": "owner", - "type": "address", - "internalType": "address" - } - ], - "outputs": [ - { - "name": "balance", - "type": "uint256", - "internalType": "uint256" - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "getApproved", - "inputs": [ - { - "name": "tokenId", - "type": "uint256", - "internalType": "uint256" - } - ], - "outputs": [ - { - "name": "operator", - "type": "address", - "internalType": "address" - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "getRoleAdmin", - "inputs": [ - { - "name": "role", - "type": "bytes32", - "internalType": "bytes32" - } - ], - "outputs": [ - { - "name": "", - "type": "bytes32", - "internalType": "bytes32" - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "grantRole", - "inputs": [ - { - "name": "role", - "type": "bytes32", - "internalType": "bytes32" - }, - { - "name": "account", - "type": "address", - "internalType": "address" - } - ], - "outputs": [], - "stateMutability": "nonpayable" - }, - { - "type": "function", - "name": "hasRole", - "inputs": [ - { - "name": "role", - "type": "bytes32", - "internalType": "bytes32" - }, - { - "name": "account", - "type": "address", - "internalType": "address" - } - ], - "outputs": [ - { - "name": "", - "type": "bool", - "internalType": "bool" - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "isApprovedForAll", - "inputs": [ - { - "name": "owner", - "type": "address", - "internalType": "address" - }, - { - "name": "operator", - "type": "address", - "internalType": "address" - } - ], - "outputs": [ - { - "name": "", - "type": "bool", - "internalType": "bool" - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "metadata", - "inputs": [ - { - "name": "tokenId", - "type": "uint256", - "internalType": "uint256" - } - ], - "outputs": [ - { - "name": "", - "type": "tuple", - "internalType": "struct PookyballMetadata", - "components": [ - { - "name": "rarity", - "type": "uint8", - "internalType": "enum PookyballRarity" - }, - { - "name": "level", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "pxp", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "seed", - "type": "uint256", - "internalType": "uint256" - } - ] - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "mint", - "inputs": [ - { - "name": "recipients", - "type": "address[]", - "internalType": "address[]" - }, - { - "name": "rarities", - "type": "uint8[]", - "internalType": "enum PookyballRarity[]" - } - ], - "outputs": [ - { - "name": "", - "type": "uint256", - "internalType": "uint256" - } - ], - "stateMutability": "nonpayable" - }, - { - "type": "function", - "name": "ownerOf", - "inputs": [ - { - "name": "tokenId", - "type": "uint256", - "internalType": "uint256" - } - ], - "outputs": [ - { - "name": "owner", - "type": "address", - "internalType": "address" - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "renounceRole", - "inputs": [ - { - "name": "role", - "type": "bytes32", - "internalType": "bytes32" - }, - { - "name": "account", - "type": "address", - "internalType": "address" - } - ], - "outputs": [], - "stateMutability": "nonpayable" - }, - { - "type": "function", - "name": "revokeRole", - "inputs": [ - { - "name": "role", - "type": "bytes32", - "internalType": "bytes32" - }, - { - "name": "account", - "type": "address", - "internalType": "address" - } - ], - "outputs": [], - "stateMutability": "nonpayable" - }, - { - "type": "function", - "name": "royaltyInfo", - "inputs": [ - { - "name": "tokenId", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "salePrice", - "type": "uint256", - "internalType": "uint256" - } - ], - "outputs": [ - { - "name": "receiver", - "type": "address", - "internalType": "address" - }, - { - "name": "royaltyAmount", - "type": "uint256", - "internalType": "uint256" - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "safeTransferFrom", - "inputs": [ - { - "name": "from", - "type": "address", - "internalType": "address" - }, - { - "name": "to", - "type": "address", - "internalType": "address" - }, - { - "name": "tokenId", - "type": "uint256", - "internalType": "uint256" - } - ], - "outputs": [], - "stateMutability": "nonpayable" - }, - { - "type": "function", - "name": "safeTransferFrom", - "inputs": [ - { - "name": "from", - "type": "address", - "internalType": "address" - }, - { - "name": "to", - "type": "address", - "internalType": "address" - }, - { - "name": "tokenId", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "data", - "type": "bytes", - "internalType": "bytes" - } - ], - "outputs": [], - "stateMutability": "nonpayable" - }, - { - "type": "function", - "name": "setApprovalForAll", - "inputs": [ - { - "name": "operator", - "type": "address", - "internalType": "address" - }, - { - "name": "approved", - "type": "bool", - "internalType": "bool" - } - ], - "outputs": [], - "stateMutability": "nonpayable" - }, - { - "type": "function", - "name": "setERC2981Receiver", - "inputs": [ - { - "name": "newReceiver", - "type": "address", - "internalType": "address" - } - ], - "outputs": [], - "stateMutability": "nonpayable" - }, - { - "type": "function", - "name": "setLevel", - "inputs": [ - { - "name": "tokenId", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "newLevel", - "type": "uint256", - "internalType": "uint256" - } - ], - "outputs": [], - "stateMutability": "nonpayable" - }, - { - "type": "function", - "name": "setPXP", - "inputs": [ - { - "name": "tokenId", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "newPXP", - "type": "uint256", - "internalType": "uint256" - } - ], - "outputs": [], - "stateMutability": "nonpayable" - }, - { - "type": "function", - "name": "supportsInterface", - "inputs": [ - { - "name": "interfaceId", - "type": "bytes4", - "internalType": "bytes4" - } - ], - "outputs": [ - { - "name": "", - "type": "bool", - "internalType": "bool" - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "transferFrom", - "inputs": [ - { - "name": "from", - "type": "address", - "internalType": "address" - }, - { - "name": "to", - "type": "address", - "internalType": "address" - }, - { - "name": "tokenId", - "type": "uint256", - "internalType": "uint256" - } - ], - "outputs": [], - "stateMutability": "nonpayable" - }, - { - "type": "event", - "name": "Approval", - "inputs": [ - { - "name": "owner", - "type": "address", - "indexed": true, - "internalType": "address" - }, - { - "name": "approved", - "type": "address", - "indexed": true, - "internalType": "address" - }, - { - "name": "tokenId", - "type": "uint256", - "indexed": true, - "internalType": "uint256" - } - ], - "anonymous": false - }, - { - "type": "event", - "name": "ApprovalForAll", - "inputs": [ - { - "name": "owner", - "type": "address", - "indexed": true, - "internalType": "address" - }, - { - "name": "operator", - "type": "address", - "indexed": true, - "internalType": "address" - }, - { - "name": "approved", - "type": "bool", - "indexed": false, - "internalType": "bool" - } - ], - "anonymous": false - }, - { - "type": "event", - "name": "LevelChanged", - "inputs": [ - { - "name": "tokenId", - "type": "uint256", - "indexed": true, - "internalType": "uint256" - }, - { - "name": "level", - "type": "uint256", - "indexed": false, - "internalType": "uint256" - } - ], - "anonymous": false - }, - { - "type": "event", - "name": "PXPChanged", - "inputs": [ - { - "name": "tokenId", - "type": "uint256", - "indexed": true, - "internalType": "uint256" - }, - { - "name": "amount", - "type": "uint256", - "indexed": false, - "internalType": "uint256" - } - ], - "anonymous": false - }, - { - "type": "event", - "name": "RoleAdminChanged", - "inputs": [ - { - "name": "role", - "type": "bytes32", - "indexed": true, - "internalType": "bytes32" - }, - { - "name": "previousAdminRole", - "type": "bytes32", - "indexed": true, - "internalType": "bytes32" - }, - { - "name": "newAdminRole", - "type": "bytes32", - "indexed": true, - "internalType": "bytes32" - } - ], - "anonymous": false - }, - { - "type": "event", - "name": "RoleGranted", - "inputs": [ - { - "name": "role", - "type": "bytes32", - "indexed": true, - "internalType": "bytes32" - }, - { - "name": "account", - "type": "address", - "indexed": true, - "internalType": "address" - }, - { - "name": "sender", - "type": "address", - "indexed": true, - "internalType": "address" - } - ], - "anonymous": false - }, - { - "type": "event", - "name": "RoleRevoked", - "inputs": [ - { - "name": "role", - "type": "bytes32", - "indexed": true, - "internalType": "bytes32" - }, - { - "name": "account", - "type": "address", - "indexed": true, - "internalType": "address" - }, - { - "name": "sender", - "type": "address", - "indexed": true, - "internalType": "address" - } - ], - "anonymous": false - }, - { - "type": "event", - "name": "SeedSet", - "inputs": [ - { - "name": "tokenId", - "type": "uint256", - "indexed": true, - "internalType": "uint256" - }, - { - "name": "seed", - "type": "uint256", - "indexed": false, - "internalType": "uint256" - } - ], - "anonymous": false - }, - { - "type": "event", - "name": "Transfer", - "inputs": [ - { - "name": "from", - "type": "address", - "indexed": true, - "internalType": "address" - }, - { - "name": "to", - "type": "address", - "indexed": true, - "internalType": "address" - }, - { - "name": "tokenId", - "type": "uint256", - "indexed": true, - "internalType": "uint256" - } - ], - "anonymous": false - }, - { - "type": "error", - "name": "ArgumentSizeMismatch", - "inputs": [ - { - "name": "x", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "y", - "type": "uint256", - "internalType": "uint256" - } - ] - } -] diff --git a/abi/pookyball/Pookyball.json b/abi/pookyball/Pookyball.json index 7d61e2b4..755be3cd 100644 --- a/abi/pookyball/Pookyball.json +++ b/abi/pookyball/Pookyball.json @@ -12,6 +12,11 @@ "type": "string", "internalType": "string" }, + { + "name": "_admin", + "type": "address", + "internalType": "address" + }, { "name": "_receiver", "type": "address", @@ -160,6 +165,32 @@ ], "stateMutability": "view" }, + { + "type": "function", + "name": "canUpdateVRF", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "canUseVRF", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, { "type": "function", "name": "contractURI", @@ -173,6 +204,39 @@ ], "stateMutability": "view" }, + { + "type": "function", + "name": "disableUpdateVRF", + "inputs": [], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "enableVRF", + "inputs": [], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "generateRandomSeed", + "inputs": [ + { + "name": "tokenId", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, { "type": "function", "name": "getApproved", @@ -688,6 +752,39 @@ "outputs": [], "stateMutability": "nonpayable" }, + { + "type": "function", + "name": "updateVRF", + "inputs": [ + { + "name": "_vrfCoordinator", + "type": "address", + "internalType": "address" + }, + { + "name": "_vrfKeyHash", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "_vrfSubId", + "type": "uint64", + "internalType": "uint64" + }, + { + "name": "_vrfMinimumRequestConfirmations", + "type": "uint16", + "internalType": "uint16" + }, + { + "name": "_vrfCallbackGasLimit", + "type": "uint32", + "internalType": "uint32" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, { "type": "function", "name": "vrfCallbackGasLimit", @@ -701,6 +798,19 @@ ], "stateMutability": "view" }, + { + "type": "function", + "name": "vrfCoordinator", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "contract VRFCoordinatorV2Interface" + } + ], + "stateMutability": "view" + }, { "type": "function", "name": "vrfKeyHash", diff --git a/abi/stickers/IStickers.json b/abi/stickers/IStickers.json deleted file mode 100644 index 319257a8..00000000 --- a/abi/stickers/IStickers.json +++ /dev/null @@ -1,747 +0,0 @@ -[ - { - "type": "function", - "name": "approve", - "inputs": [ - { - "name": "to", - "type": "address", - "internalType": "address" - }, - { - "name": "tokenId", - "type": "uint256", - "internalType": "uint256" - } - ], - "outputs": [], - "stateMutability": "payable" - }, - { - "type": "function", - "name": "balanceOf", - "inputs": [ - { - "name": "owner", - "type": "address", - "internalType": "address" - } - ], - "outputs": [ - { - "name": "balance", - "type": "uint256", - "internalType": "uint256" - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "burn", - "inputs": [ - { - "name": "tokenId", - "type": "uint256", - "internalType": "uint256" - } - ], - "outputs": [], - "stateMutability": "nonpayable" - }, - { - "type": "function", - "name": "explicitOwnershipOf", - "inputs": [ - { - "name": "tokenId", - "type": "uint256", - "internalType": "uint256" - } - ], - "outputs": [ - { - "name": "", - "type": "tuple", - "internalType": "struct IERC721A.TokenOwnership", - "components": [ - { - "name": "addr", - "type": "address", - "internalType": "address" - }, - { - "name": "startTimestamp", - "type": "uint64", - "internalType": "uint64" - }, - { - "name": "burned", - "type": "bool", - "internalType": "bool" - }, - { - "name": "extraData", - "type": "uint24", - "internalType": "uint24" - } - ] - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "explicitOwnershipsOf", - "inputs": [ - { - "name": "tokenIds", - "type": "uint256[]", - "internalType": "uint256[]" - } - ], - "outputs": [ - { - "name": "", - "type": "tuple[]", - "internalType": "struct IERC721A.TokenOwnership[]", - "components": [ - { - "name": "addr", - "type": "address", - "internalType": "address" - }, - { - "name": "startTimestamp", - "type": "uint64", - "internalType": "uint64" - }, - { - "name": "burned", - "type": "bool", - "internalType": "bool" - }, - { - "name": "extraData", - "type": "uint24", - "internalType": "uint24" - } - ] - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "getApproved", - "inputs": [ - { - "name": "tokenId", - "type": "uint256", - "internalType": "uint256" - } - ], - "outputs": [ - { - "name": "operator", - "type": "address", - "internalType": "address" - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "isApprovedForAll", - "inputs": [ - { - "name": "owner", - "type": "address", - "internalType": "address" - }, - { - "name": "operator", - "type": "address", - "internalType": "address" - } - ], - "outputs": [ - { - "name": "", - "type": "bool", - "internalType": "bool" - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "metadata", - "inputs": [ - { - "name": "tokenId", - "type": "uint256", - "internalType": "uint256" - } - ], - "outputs": [ - { - "name": "", - "type": "tuple", - "internalType": "struct StickerMetadata", - "components": [ - { - "name": "level", - "type": "uint248", - "internalType": "uint248" - }, - { - "name": "rarity", - "type": "uint8", - "internalType": "enum StickerRarity" - } - ] - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "mint", - "inputs": [ - { - "name": "recipient", - "type": "address", - "internalType": "address" - }, - { - "name": "rarities", - "type": "uint8[]", - "internalType": "enum StickerRarity[]" - } - ], - "outputs": [], - "stateMutability": "nonpayable" - }, - { - "type": "function", - "name": "name", - "inputs": [], - "outputs": [ - { - "name": "", - "type": "string", - "internalType": "string" - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "nextTokenId", - "inputs": [], - "outputs": [ - { - "name": "", - "type": "uint256", - "internalType": "uint256" - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "ownerOf", - "inputs": [ - { - "name": "tokenId", - "type": "uint256", - "internalType": "uint256" - } - ], - "outputs": [ - { - "name": "owner", - "type": "address", - "internalType": "address" - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "royaltyInfo", - "inputs": [ - { - "name": "tokenId", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "salePrice", - "type": "uint256", - "internalType": "uint256" - } - ], - "outputs": [ - { - "name": "receiver", - "type": "address", - "internalType": "address" - }, - { - "name": "royaltyAmount", - "type": "uint256", - "internalType": "uint256" - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "safeTransferFrom", - "inputs": [ - { - "name": "from", - "type": "address", - "internalType": "address" - }, - { - "name": "to", - "type": "address", - "internalType": "address" - }, - { - "name": "tokenId", - "type": "uint256", - "internalType": "uint256" - } - ], - "outputs": [], - "stateMutability": "payable" - }, - { - "type": "function", - "name": "safeTransferFrom", - "inputs": [ - { - "name": "from", - "type": "address", - "internalType": "address" - }, - { - "name": "to", - "type": "address", - "internalType": "address" - }, - { - "name": "tokenId", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "data", - "type": "bytes", - "internalType": "bytes" - } - ], - "outputs": [], - "stateMutability": "payable" - }, - { - "type": "function", - "name": "setApprovalForAll", - "inputs": [ - { - "name": "operator", - "type": "address", - "internalType": "address" - }, - { - "name": "_approved", - "type": "bool", - "internalType": "bool" - } - ], - "outputs": [], - "stateMutability": "nonpayable" - }, - { - "type": "function", - "name": "setLevel", - "inputs": [ - { - "name": "tokenId", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "newLevel", - "type": "uint248", - "internalType": "uint248" - } - ], - "outputs": [], - "stateMutability": "nonpayable" - }, - { - "type": "function", - "name": "supportsInterface", - "inputs": [ - { - "name": "interfaceId", - "type": "bytes4", - "internalType": "bytes4" - } - ], - "outputs": [ - { - "name": "", - "type": "bool", - "internalType": "bool" - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "symbol", - "inputs": [], - "outputs": [ - { - "name": "", - "type": "string", - "internalType": "string" - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "tokenURI", - "inputs": [ - { - "name": "tokenId", - "type": "uint256", - "internalType": "uint256" - } - ], - "outputs": [ - { - "name": "", - "type": "string", - "internalType": "string" - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "tokensOfOwner", - "inputs": [ - { - "name": "owner", - "type": "address", - "internalType": "address" - } - ], - "outputs": [ - { - "name": "", - "type": "uint256[]", - "internalType": "uint256[]" - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "tokensOfOwnerIn", - "inputs": [ - { - "name": "owner", - "type": "address", - "internalType": "address" - }, - { - "name": "start", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "stop", - "type": "uint256", - "internalType": "uint256" - } - ], - "outputs": [ - { - "name": "", - "type": "uint256[]", - "internalType": "uint256[]" - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "totalSupply", - "inputs": [], - "outputs": [ - { - "name": "", - "type": "uint256", - "internalType": "uint256" - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "transferFrom", - "inputs": [ - { - "name": "from", - "type": "address", - "internalType": "address" - }, - { - "name": "to", - "type": "address", - "internalType": "address" - }, - { - "name": "tokenId", - "type": "uint256", - "internalType": "uint256" - } - ], - "outputs": [], - "stateMutability": "payable" - }, - { - "type": "event", - "name": "Approval", - "inputs": [ - { - "name": "owner", - "type": "address", - "indexed": true, - "internalType": "address" - }, - { - "name": "approved", - "type": "address", - "indexed": true, - "internalType": "address" - }, - { - "name": "tokenId", - "type": "uint256", - "indexed": true, - "internalType": "uint256" - } - ], - "anonymous": false - }, - { - "type": "event", - "name": "ApprovalForAll", - "inputs": [ - { - "name": "owner", - "type": "address", - "indexed": true, - "internalType": "address" - }, - { - "name": "operator", - "type": "address", - "indexed": true, - "internalType": "address" - }, - { - "name": "approved", - "type": "bool", - "indexed": false, - "internalType": "bool" - } - ], - "anonymous": false - }, - { - "type": "event", - "name": "ConsecutiveTransfer", - "inputs": [ - { - "name": "fromTokenId", - "type": "uint256", - "indexed": true, - "internalType": "uint256" - }, - { - "name": "toTokenId", - "type": "uint256", - "indexed": false, - "internalType": "uint256" - }, - { - "name": "from", - "type": "address", - "indexed": true, - "internalType": "address" - }, - { - "name": "to", - "type": "address", - "indexed": true, - "internalType": "address" - } - ], - "anonymous": false - }, - { - "type": "event", - "name": "LevelChanged", - "inputs": [ - { - "name": "tokenId", - "type": "uint256", - "indexed": true, - "internalType": "uint256" - }, - { - "name": "level", - "type": "uint256", - "indexed": false, - "internalType": "uint256" - } - ], - "anonymous": false - }, - { - "type": "event", - "name": "SeedSet", - "inputs": [ - { - "name": "tokenId", - "type": "uint256", - "indexed": true, - "internalType": "uint256" - }, - { - "name": "seed", - "type": "uint256", - "indexed": false, - "internalType": "uint256" - } - ], - "anonymous": false - }, - { - "type": "event", - "name": "Transfer", - "inputs": [ - { - "name": "from", - "type": "address", - "indexed": true, - "internalType": "address" - }, - { - "name": "to", - "type": "address", - "indexed": true, - "internalType": "address" - }, - { - "name": "tokenId", - "type": "uint256", - "indexed": true, - "internalType": "uint256" - } - ], - "anonymous": false - }, - { - "type": "error", - "name": "ApprovalCallerNotOwnerNorApproved", - "inputs": [] - }, - { - "type": "error", - "name": "ApprovalQueryForNonexistentToken", - "inputs": [] - }, - { - "type": "error", - "name": "BalanceQueryForZeroAddress", - "inputs": [] - }, - { - "type": "error", - "name": "InvalidQueryRange", - "inputs": [] - }, - { - "type": "error", - "name": "MintERC2309QuantityExceedsLimit", - "inputs": [] - }, - { - "type": "error", - "name": "MintToZeroAddress", - "inputs": [] - }, - { - "type": "error", - "name": "MintZeroQuantity", - "inputs": [] - }, - { - "type": "error", - "name": "NonExistentToken", - "inputs": [ - { - "name": "tokenId", - "type": "uint256", - "internalType": "uint256" - } - ] - }, - { - "type": "error", - "name": "OwnerQueryForNonexistentToken", - "inputs": [] - }, - { - "type": "error", - "name": "OwnershipNotInitializedForExtraData", - "inputs": [] - }, - { - "type": "error", - "name": "TransferCallerNotOwnerNorApproved", - "inputs": [] - }, - { - "type": "error", - "name": "TransferFromIncorrectOwner", - "inputs": [] - }, - { - "type": "error", - "name": "TransferToNonERC721ReceiverImplementer", - "inputs": [] - }, - { - "type": "error", - "name": "TransferToZeroAddress", - "inputs": [] - }, - { - "type": "error", - "name": "URIQueryForNonexistentToken", - "inputs": [] - } -] diff --git a/abi/stickers/IStickersController.json b/abi/stickers/IStickersController.json deleted file mode 100644 index ecf345eb..00000000 --- a/abi/stickers/IStickersController.json +++ /dev/null @@ -1,199 +0,0 @@ -[ - { - "type": "function", - "name": "attach", - "inputs": [ - { - "name": "stickerId", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "pookyballId", - "type": "uint256", - "internalType": "uint256" - } - ], - "outputs": [], - "stateMutability": "nonpayable" - }, - { - "type": "function", - "name": "attachedTo", - "inputs": [ - { - "name": "stickerId", - "type": "uint256", - "internalType": "uint256" - } - ], - "outputs": [ - { - "name": "", - "type": "uint256", - "internalType": "uint256" - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "detach", - "inputs": [ - { - "name": "stickerId", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "recepient", - "type": "address", - "internalType": "address" - } - ], - "outputs": [], - "stateMutability": "nonpayable" - }, - { - "type": "function", - "name": "pookyball", - "inputs": [], - "outputs": [ - { - "name": "", - "type": "address", - "internalType": "contract IPookyball" - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "replace", - "inputs": [ - { - "name": "stickerId", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "previousStickerId", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "pookyballId", - "type": "uint256", - "internalType": "uint256" - } - ], - "outputs": [], - "stateMutability": "nonpayable" - }, - { - "type": "function", - "name": "slots", - "inputs": [ - { - "name": "pookyballId", - "type": "uint256", - "internalType": "uint256" - } - ], - "outputs": [ - { - "name": "", - "type": "uint256[]", - "internalType": "uint256[]" - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "stickers", - "inputs": [], - "outputs": [ - { - "name": "", - "type": "address", - "internalType": "contract IStickers" - } - ], - "stateMutability": "view" - }, - { - "type": "event", - "name": "StickerAttached", - "inputs": [ - { - "name": "stickerId", - "type": "uint256", - "indexed": false, - "internalType": "uint256" - }, - { - "name": "pookyballId", - "type": "uint256", - "indexed": false, - "internalType": "uint256" - } - ], - "anonymous": false - }, - { - "type": "event", - "name": "StickerDetached", - "inputs": [ - { - "name": "stickerId", - "type": "uint256", - "indexed": false, - "internalType": "uint256" - }, - { - "name": "pookyballId", - "type": "uint256", - "indexed": false, - "internalType": "uint256" - } - ], - "anonymous": false - }, - { - "type": "event", - "name": "StickerReplaced", - "inputs": [ - { - "name": "stickerId", - "type": "uint256", - "indexed": false, - "internalType": "uint256" - }, - { - "name": "previousStickerId", - "type": "uint256", - "indexed": false, - "internalType": "uint256" - }, - { - "name": "pookyballId", - "type": "uint256", - "indexed": false, - "internalType": "uint256" - } - ], - "anonymous": false - }, - { - "type": "error", - "name": "InvalidSticker", - "inputs": [ - { - "name": "stickerId", - "type": "uint256", - "internalType": "uint256" - } - ] - } -] diff --git a/abi/stickers/Stickers.json b/abi/stickers/Stickers.json index 14faad7b..bb5fc4e7 100644 --- a/abi/stickers/Stickers.json +++ b/abi/stickers/Stickers.json @@ -149,6 +149,32 @@ "outputs": [], "stateMutability": "nonpayable" }, + { + "type": "function", + "name": "canUpdateVRF", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "canUseVRF", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, { "type": "function", "name": "cancelOwnershipHandover", @@ -182,6 +208,20 @@ ], "stateMutability": "view" }, + { + "type": "function", + "name": "disableUpdateVRF", + "inputs": [], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "enableVRF", + "inputs": [], + "outputs": [], + "stateMutability": "nonpayable" + }, { "type": "function", "name": "explicitOwnershipOf", @@ -264,6 +304,25 @@ ], "stateMutability": "view" }, + { + "type": "function", + "name": "generateRandomSeed", + "inputs": [ + { + "name": "tokenId", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, { "type": "function", "name": "getApproved", @@ -908,6 +967,39 @@ "outputs": [], "stateMutability": "payable" }, + { + "type": "function", + "name": "updateVRF", + "inputs": [ + { + "name": "_vrfCoordinator", + "type": "address", + "internalType": "address" + }, + { + "name": "_vrfKeyHash", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "_vrfSubId", + "type": "uint64", + "internalType": "uint64" + }, + { + "name": "_vrfMinimumRequestConfirmations", + "type": "uint16", + "internalType": "uint16" + }, + { + "name": "_vrfCallbackGasLimit", + "type": "uint32", + "internalType": "uint32" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, { "type": "function", "name": "vrf", diff --git a/abi/tokens/IPOK.json b/abi/tokens/IPOK.json deleted file mode 100644 index e2f493fd..00000000 --- a/abi/tokens/IPOK.json +++ /dev/null @@ -1,393 +0,0 @@ -[ - { - "type": "function", - "name": "allowance", - "inputs": [ - { - "name": "owner", - "type": "address", - "internalType": "address" - }, - { - "name": "spender", - "type": "address", - "internalType": "address" - } - ], - "outputs": [ - { - "name": "", - "type": "uint256", - "internalType": "uint256" - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "approve", - "inputs": [ - { - "name": "spender", - "type": "address", - "internalType": "address" - }, - { - "name": "amount", - "type": "uint256", - "internalType": "uint256" - } - ], - "outputs": [ - { - "name": "", - "type": "bool", - "internalType": "bool" - } - ], - "stateMutability": "nonpayable" - }, - { - "type": "function", - "name": "balanceOf", - "inputs": [ - { - "name": "account", - "type": "address", - "internalType": "address" - } - ], - "outputs": [ - { - "name": "", - "type": "uint256", - "internalType": "uint256" - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "burn", - "inputs": [ - { - "name": "to", - "type": "address", - "internalType": "address" - }, - { - "name": "amount", - "type": "uint256", - "internalType": "uint256" - } - ], - "outputs": [], - "stateMutability": "nonpayable" - }, - { - "type": "function", - "name": "getRoleAdmin", - "inputs": [ - { - "name": "role", - "type": "bytes32", - "internalType": "bytes32" - } - ], - "outputs": [ - { - "name": "", - "type": "bytes32", - "internalType": "bytes32" - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "grantRole", - "inputs": [ - { - "name": "role", - "type": "bytes32", - "internalType": "bytes32" - }, - { - "name": "account", - "type": "address", - "internalType": "address" - } - ], - "outputs": [], - "stateMutability": "nonpayable" - }, - { - "type": "function", - "name": "hasRole", - "inputs": [ - { - "name": "role", - "type": "bytes32", - "internalType": "bytes32" - }, - { - "name": "account", - "type": "address", - "internalType": "address" - } - ], - "outputs": [ - { - "name": "", - "type": "bool", - "internalType": "bool" - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "mint", - "inputs": [ - { - "name": "to", - "type": "address", - "internalType": "address" - }, - { - "name": "amount", - "type": "uint256", - "internalType": "uint256" - } - ], - "outputs": [], - "stateMutability": "nonpayable" - }, - { - "type": "function", - "name": "renounceRole", - "inputs": [ - { - "name": "role", - "type": "bytes32", - "internalType": "bytes32" - }, - { - "name": "account", - "type": "address", - "internalType": "address" - } - ], - "outputs": [], - "stateMutability": "nonpayable" - }, - { - "type": "function", - "name": "revokeRole", - "inputs": [ - { - "name": "role", - "type": "bytes32", - "internalType": "bytes32" - }, - { - "name": "account", - "type": "address", - "internalType": "address" - } - ], - "outputs": [], - "stateMutability": "nonpayable" - }, - { - "type": "function", - "name": "totalSupply", - "inputs": [], - "outputs": [ - { - "name": "", - "type": "uint256", - "internalType": "uint256" - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "transfer", - "inputs": [ - { - "name": "to", - "type": "address", - "internalType": "address" - }, - { - "name": "amount", - "type": "uint256", - "internalType": "uint256" - } - ], - "outputs": [ - { - "name": "", - "type": "bool", - "internalType": "bool" - } - ], - "stateMutability": "nonpayable" - }, - { - "type": "function", - "name": "transferFrom", - "inputs": [ - { - "name": "from", - "type": "address", - "internalType": "address" - }, - { - "name": "to", - "type": "address", - "internalType": "address" - }, - { - "name": "amount", - "type": "uint256", - "internalType": "uint256" - } - ], - "outputs": [ - { - "name": "", - "type": "bool", - "internalType": "bool" - } - ], - "stateMutability": "nonpayable" - }, - { - "type": "event", - "name": "Approval", - "inputs": [ - { - "name": "owner", - "type": "address", - "indexed": true, - "internalType": "address" - }, - { - "name": "spender", - "type": "address", - "indexed": true, - "internalType": "address" - }, - { - "name": "value", - "type": "uint256", - "indexed": false, - "internalType": "uint256" - } - ], - "anonymous": false - }, - { - "type": "event", - "name": "RoleAdminChanged", - "inputs": [ - { - "name": "role", - "type": "bytes32", - "indexed": true, - "internalType": "bytes32" - }, - { - "name": "previousAdminRole", - "type": "bytes32", - "indexed": true, - "internalType": "bytes32" - }, - { - "name": "newAdminRole", - "type": "bytes32", - "indexed": true, - "internalType": "bytes32" - } - ], - "anonymous": false - }, - { - "type": "event", - "name": "RoleGranted", - "inputs": [ - { - "name": "role", - "type": "bytes32", - "indexed": true, - "internalType": "bytes32" - }, - { - "name": "account", - "type": "address", - "indexed": true, - "internalType": "address" - }, - { - "name": "sender", - "type": "address", - "indexed": true, - "internalType": "address" - } - ], - "anonymous": false - }, - { - "type": "event", - "name": "RoleRevoked", - "inputs": [ - { - "name": "role", - "type": "bytes32", - "indexed": true, - "internalType": "bytes32" - }, - { - "name": "account", - "type": "address", - "indexed": true, - "internalType": "address" - }, - { - "name": "sender", - "type": "address", - "indexed": true, - "internalType": "address" - } - ], - "anonymous": false - }, - { - "type": "event", - "name": "Transfer", - "inputs": [ - { - "name": "from", - "type": "address", - "indexed": true, - "internalType": "address" - }, - { - "name": "to", - "type": "address", - "indexed": true, - "internalType": "address" - }, - { - "name": "value", - "type": "uint256", - "indexed": false, - "internalType": "uint256" - } - ], - "anonymous": false - } -] diff --git a/abi/tokens/POK.json b/abi/tokens/POK.json index 5efb6b65..d48443ac 100644 --- a/abi/tokens/POK.json +++ b/abi/tokens/POK.json @@ -1,7 +1,13 @@ [ { "type": "constructor", - "inputs": [], + "inputs": [ + { + "name": "_admin", + "type": "address", + "internalType": "address" + } + ], "stateMutability": "nonpayable" }, { diff --git a/abi/types/VRFConfig.json b/abi/types/VRFConfig.json deleted file mode 100644 index fe51488c..00000000 --- a/abi/types/VRFConfig.json +++ /dev/null @@ -1 +0,0 @@ -[] diff --git a/bytecode/common/BaseERC721A.bin b/bytecode/common/BaseERC721A.bin index 483877b0..057a16f8 100644 --- a/bytecode/common/BaseERC721A.bin +++ b/bytecode/common/BaseERC721A.bin @@ -1 +1 @@ -0x60a06040523480156200001157600080fd5b50604051620029d2380380620029d283398101604081905262000034916200063d565b8251733cc6cdda760b79bafa08df41ecfa224f810dceb66001898960026200005d8382620007d6565b5060036200006c8282620007d6565b50600160005550506daaeb6d7670e522a718067333cd4e3b15620001b95780156200010757604051633e9f1edf60e11b81523060048201526001600160a01b03831660248201526daaeb6d7670e522a718067333cd4e90637d3e3dbe906044015b600060405180830381600087803b158015620000e857600080fd5b505af1158015620000fd573d6000803e3d6000fd5b50505050620001b9565b6001600160a01b03821615620001585760405163a0af290360e01b81523060048201526001600160a01b03831660248201526daaeb6d7670e522a718067333cd4e9063a0af290390604401620000cd565b604051632210724360e11b81523060048201526daaeb6d7670e522a718067333cd4e90634420e48690602401600060405180830381600087803b1580156200019f57600080fd5b505af1158015620001b4573d6000803e3d6000fd5b505050505b50506001600160a01b0316608052620001d28862000321565b600a620001e08682620007d6565b50600b8054620001f09062000745565b80601f01602080910402602001604051908101604052809291908181526020018280546200021e9062000745565b80156200026f5780601f1062000243576101008083540402835291602001916200026f565b820191906000526020600020905b8154815290600101906020018083116200025157829003601f168201915b50508651600c80546001600160a01b039092166001600160a01b03199092169190911790555050506020840151600d556040840151600e80546060870151608088015163ffffffff166a01000000000000000000000263ffffffff60501b1961ffff90921668010000000000000000026001600160501b03199093166001600160401b0390951694909417919091171691909117905593506200031382826200035d565b5050505050505050620008a2565b6001600160a01b0316638b78c6d8198190558060007f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08180a350565b6127106001600160601b0382161115620003d15760405162461bcd60e51b815260206004820152602a60248201527f455243323938313a20726f79616c7479206665652077696c6c206578636565646044820152692073616c65507269636560b01b60648201526084015b60405180910390fd5b6001600160a01b038216620004295760405162461bcd60e51b815260206004820152601960248201527f455243323938313a20696e76616c6964207265636569766572000000000000006044820152606401620003c8565b604080518082019091526001600160a01b039092168083526001600160601b039091166020909201829052600160a01b90910217600855565b6001600160a01b03811681146200047857600080fd5b50565b8051620004888162000462565b919050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b0381118282101715620004ce57620004ce6200048d565b604052919050565b600082601f830112620004e857600080fd5b81516001600160401b038111156200050457620005046200048d565b60206200051a601f8301601f19168201620004a3565b82815285828487010111156200052f57600080fd5b60005b838110156200054f57858101830151828201840152820162000532565b506000928101909101919091529392505050565b805163ffffffff811681146200048857600080fd5b600060a082840312156200058b57600080fd5b60405160a081016001600160401b038082118383101715620005b157620005b16200048d565b8160405282935084519150620005c78262000462565b81835260208501516020840152604085015191508082168214620005ea57600080fd5b506040820152606083015161ffff811681146200060657600080fd5b6060820152620006196080840162000563565b60808201525092915050565b80516001600160601b03811681146200048857600080fd5b600080600080600080600080610180898b0312156200065b57600080fd5b62000666896200047b565b60208a01519098506001600160401b03808211156200068457600080fd5b620006928c838d01620004d6565b985060408b0151915080821115620006a957600080fd5b620006b78c838d01620004d6565b975060608b0151915080821115620006ce57600080fd5b620006dc8c838d01620004d6565b965060808b0151915080821115620006f357600080fd5b50620007028b828c01620004d6565b945050620007148a60a08b0162000578565b9250620007256101408a016200047b565b9150620007366101608a0162000625565b90509295985092959890939650565b600181811c908216806200075a57607f821691505b6020821081036200077b57634e487b7160e01b600052602260045260246000fd5b50919050565b601f821115620007d1576000816000526020600020601f850160051c81016020861015620007ac5750805b601f850160051c820191505b81811015620007cd57828155600101620007b8565b5050505b505050565b81516001600160401b03811115620007f257620007f26200048d565b6200080a8162000803845462000745565b8462000781565b602080601f831160018114620008425760008415620008295750858301515b600019600386901b1c1916600185901b178555620007cd565b600085815260208120601f198616915b82811015620008735788860151825594840194600190910190840162000852565b5085821015620008925787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b60805161210d620008c56000396000818161089801526108da015261210d6000f3fe6080604052600436106102255760003560e01c80636c0360eb11610123578063a22cb465116100ab578063e985e9c51161006f578063e985e9c5146106a2578063f04e283e146106eb578063f0503e80146106fe578063f2fde38b1461072b578063fee81cf41461073e57600080fd5b8063a22cb4651461060d578063b88d4fde1461062d578063c23dc68f14610640578063c87b56dd1461066d578063e8a3d4851461068d57600080fd5b80638462151c116100f25780638462151c146105725780638da5cb5b1461059f578063938e3d7b146105b857806395d89b41146105d857806399a2557a146105ed57600080fd5b80636c0360eb1461052057806370a0823114610535578063715018a61461055557806375794a3c1461055d57600080fd5b806323b872dd116101b157806342966c681161017557806342966c681461048b57806354d1f13d146104ab57806355f804b3146104b35780635bbb2177146104d35780636352211e1461050057600080fd5b806323b872dd146103fc578063256929621461040f5780632a55205a1461041757806341f434341461045657806342842e0e1461047857600080fd5b8063095ea7b3116101f8578063095ea7b3146102db5780630c949043146102ee57806318160ddd146103885780631a1d9252146103af5780631fe543e3146103dc57600080fd5b806301ffc9a71461022a57806304634d8d1461025f57806306fdde0314610281578063081812fc146102a3575b600080fd5b34801561023657600080fd5b5061024a610245366004611910565b610771565b60405190151581526020015b60405180910390f35b34801561026b57600080fd5b5061027f61027a366004611944565b610791565b005b34801561028d57600080fd5b506102966107a7565b60405161025691906119d7565b3480156102af57600080fd5b506102c36102be3660046119ea565b610839565b6040516001600160a01b039091168152602001610256565b61027f6102e9366004611a03565b610874565b3480156102fa57600080fd5b50600c54600d54600e5461033f926001600160a01b031691906001600160401b0381169068010000000000000000810461ffff1690600160501b900463ffffffff1685565b604080516001600160a01b03909616865260208601949094526001600160401b039092169284019290925261ffff909116606083015263ffffffff16608082015260a001610256565b34801561039457600080fd5b5060015460005403600019015b604051908152602001610256565b3480156103bb57600080fd5b506103a16103ca3660046119ea565b600f6020526000908152604090205481565b3480156103e857600080fd5b5061027f6103f7366004611a73565b61088d565b61027f61040a366004611b24565b610916565b61027f610941565b34801561042357600080fd5b50610437610432366004611b60565b610990565b604080516001600160a01b039093168352602083019190915201610256565b34801561046257600080fd5b506102c36daaeb6d7670e522a718067333cd4e81565b61027f610486366004611b24565b610a3c565b34801561049757600080fd5b5061027f6104a63660046119ea565b610a61565b61027f610a6f565b3480156104bf57600080fd5b5061027f6104ce366004611bd9565b610aab565b3480156104df57600080fd5b506104f36104ee366004611c21565b610abf565b6040516102569190611cd1565b34801561050c57600080fd5b506102c361051b3660046119ea565b610b0b565b34801561052c57600080fd5b50610296610b16565b34801561054157600080fd5b506103a1610550366004611d13565b610ba4565b61027f610be9565b34801561056957600080fd5b506000546103a1565b34801561057e57600080fd5b5061059261058d366004611d13565b610bfd565b6040516102569190611d2e565b3480156105ab57600080fd5b50638b78c6d819546102c3565b3480156105c457600080fd5b5061027f6105d3366004611bd9565b610c24565b3480156105e457600080fd5b50610296610c38565b3480156105f957600080fd5b50610592610608366004611d66565b610c47565b34801561061957600080fd5b5061027f610628366004611da7565b610c54565b61027f61063b366004611dd3565b610c68565b34801561064c57600080fd5b5061066061065b3660046119ea565b610c95565b6040516102569190611e4e565b34801561067957600080fd5b506102966106883660046119ea565b610cf9565b34801561069957600080fd5b50610296610d74565b3480156106ae57600080fd5b5061024a6106bd366004611e5c565b6001600160a01b03918216600090815260076020908152604080832093909416825291909152205460ff1690565b61027f6106f9366004611d13565b610d81565b34801561070a57600080fd5b506103a16107193660046119ea565b60106020526000908152604090205481565b61027f610739366004611d13565b610dbe565b34801561074a57600080fd5b506103a1610759366004611d13565b63389a75e1600c908152600091909152602090205490565b600061077c82610de5565b8061078b575061078b82610e1a565b92915050565b610799610e68565b6107a38282610e83565b5050565b6060600280546107b690611e8f565b80601f01602080910402602001604051908101604052809291908181526020018280546107e290611e8f565b801561082f5780601f106108045761010080835404028352916020019161082f565b820191906000526020600020905b81548152906001019060200180831161081257829003601f168201915b5050505050905090565b600061084482610f80565b610858576108586333d1c03960e21b610fcc565b506000908152600660205260409020546001600160a01b031690565b8161087e81610fd6565b610888838361108f565b505050565b336001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161461090c5760405163073e64fd60e21b81523360048201526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001660248201526044015b60405180910390fd5b6107a3828261109b565b826001600160a01b03811633146109305761093033610fd6565b61093b848484611154565b50505050565b60006202a3006001600160401b03164201905063389a75e1600c5233600052806020600c2055337fdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d600080a250565b60008281526009602090815260408083208151808301909252546001600160a01b038116808352600160a01b9091046001600160601b0316928201929092528291610a055750604080518082019091526008546001600160a01b0381168252600160a01b90046001600160601b031660208201525b602081015160009061271090610a24906001600160601b031687611edf565b610a2e9190611ef6565b915196919550909350505050565b826001600160a01b0381163314610a5657610a5633610fd6565b61093b8484846112c3565b610a6c8160016112de565b50565b63389a75e1600c523360005260006020600c2055337ffa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92600080a2565b610ab3610e68565b600a6107a38282611f68565b60408051828152600583901b8082016020019092526060915b8015610b0357601f1980820191860101356000610af482610c95565b8484016020015250610ad89050565b509392505050565b600061078b8261141f565b600a8054610b2390611e8f565b80601f0160208091040260200160405190810160405280929190818152602001828054610b4f90611e8f565b8015610b9c5780601f10610b7157610100808354040283529160200191610b9c565b820191906000526020600020905b815481529060010190602001808311610b7f57829003601f168201915b505050505081565b60006001600160a01b038216610bc457610bc46323d3ad8160e21b610fcc565b506001600160a01b03166000908152600560205260409020546001600160401b031690565b610bf1610e68565b610bfb60006114c0565b565b60005460609060019082828214610c1c57610c198584846114fe565b90505b949350505050565b610c2c610e68565b600b6107a38282611f68565b6060600380546107b690611e8f565b6060610c1c8484846114fe565b81610c5e81610fd6565b61088883836115fd565b836001600160a01b0381163314610c8257610c8233610fd6565b610c8e85858585611669565b5050505050565b60408051608081018252600080825260208201819052918101829052606081019190915260018210610cf457600054821015610cf4575b600082815260046020526040902054610ceb5760001990910190610ccc565b61078b826116a4565b919050565b6060610d0482610f80565b610d1857610d18630a14c4b560e41b610fcc565b6000610d22611722565b90508051600003610d425760405180602001604052806000815250610d6d565b80610d4c84611731565b604051602001610d5d929190612027565b6040516020818303038152906040525b9392505050565b600b8054610b2390611e8f565b610d89610e68565b63389a75e1600c52806000526020600c208054421115610db157636f5e88186000526004601cfd5b60009055610a6c816114c0565b610dc6610e68565b8060601b610ddc57637448fbae6000526004601cfd5b610a6c816114c0565b60006001600160e01b0319821663152a902d60e11b148061078b57506301ffc9a760e01b6001600160e01b031983161461078b565b60006301ffc9a760e01b6001600160e01b031983161480610e4b57506380ac58cd60e01b6001600160e01b03198316145b8061078b5750506001600160e01b031916635b5e139f60e01b1490565b638b78c6d819543314610bfb576382b429006000526004601cfd5b6127106001600160601b0382161115610ef15760405162461bcd60e51b815260206004820152602a60248201527f455243323938313a20726f79616c7479206665652077696c6c206578636565646044820152692073616c65507269636560b01b6064820152608401610903565b6001600160a01b038216610f475760405162461bcd60e51b815260206004820152601960248201527f455243323938313a20696e76616c6964207265636569766572000000000000006044820152606401610903565b604080518082019091526001600160a01b039092168083526001600160601b039091166020909201829052600160a01b90910217600855565b600081600111610cf457600054821015610cf45760005b5060008281526004602052604081205490819003610fbf57610fb883612056565b9250610f97565b600160e01b161592915050565b8060005260046000fd5b6daaeb6d7670e522a718067333cd4e3b15610a6c57604051633185c44d60e21b81523060048201526001600160a01b03821660248201526daaeb6d7670e522a718067333cd4e9063c617113490604401602060405180830381865afa158015611043573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611067919061206d565b610a6c57604051633b79c77360e21b81526001600160a01b0382166004820152602401610903565b6107a382826001611775565b6000828152600f6020526040812054905b825181101561093b578281815181106110c7576110c761208a565b60200260200101516010600083856110df91906120a0565b81526020810191909152604001600020556110fa81836120a0565b7f14296754697e325872a9c14eb682f467bc46b15a78ae9420d7a13a7cd3833b2c84838151811061112d5761112d61208a565b602002602001015160405161114491815260200190565b60405180910390a26001016110ac565b600061115f8261141f565b6001600160a01b0394851694909150811684146111855761118562a1148160e81b610fcc565b600082815260066020526040902080546111b18187335b6001600160a01b039081169116811491141790565b6111d3576111bf86336106bd565b6111d3576111d3632ce44b5f60e11b610fcc565b80156111de57600082555b6001600160a01b038681166000908152600560205260408082208054600019019055918716808252919020805460010190554260a01b17600160e11b17600085815260046020526040812091909155600160e11b841690036112705760018401600081815260046020526040812054900361126e57600054811461126e5760008181526004602052604090208490555b505b6001600160a01b0385168481887fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef600080a4806000036112ba576112ba633a954ecd60e21b610fcc565b50505050505050565b61088883838360405180602001604052806000815250610c68565b60006112e98361141f565b90508060008061130786600090815260066020526040902080549091565b91509150841561133e5761131c81843361119c565b61133e5761132a83336106bd565b61133e5761133e632ce44b5f60e11b610fcc565b801561134957600082555b6001600160a01b038316600081815260056020526040902080546fffffffffffffffffffffffffffffffff0190554260a01b17600360e01b17600087815260046020526040812091909155600160e11b851690036113d7576001860160008181526004602052604081205490036113d55760005481146113d55760008181526004602052604090208590555b505b60405186906000906001600160a01b038616907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908390a45050600180548101905550505050565b6000816001116114b057506000818152600460205260408120549081900361149d57600054821061145a5761145a636f96cda160e11b610fcc565b5b5060001901600081815260046020526040902054801561145b57600160e01b811660000361148857919050565b611498636f96cda160e11b610fcc565b61145b565b600160e01b81166000036114b057919050565b610cf4636f96cda160e11b610fcc565b638b78c6d81980546001600160a01b039092169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a355565b606081831061151757611517631960ccad60e11b610fcc565b600183101561152557600192505b600054808310611533578092505b6060600061154087610ba4565b858710908102915081156115f157818787031161155d5786860391505b60405192506001820160051b8301604052600061157988610c95565b90506000816040015161158a575080515b60005b6115968a6116a4565b92506040830151600081146115ae57600092506115d3565b8351156115ba57835192505b8b831860601b6115d3576001820191508a8260051b8801525b5060018a019950888a14806115e757508481145b1561158d57855250505b50909695505050505050565b3360008181526007602090815260408083206001600160a01b03871680855290835292819020805460ff191686151590811790915590519081529192917f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a35050565b611674848484610916565b6001600160a01b0383163b1561093b5761169084848484611818565b61093b5761093b6368d2bf6b60e11b610fcc565b60408051608081018252600080825260208201819052918101829052606081019190915260008281526004602052604090205461078b90604080516080810182526001600160a01b038316815260a083901c6001600160401b03166020820152600160e01b831615159181019190915260e89190911c606082015290565b6060600a80546107b690611e8f565b606060a06040510180604052602081039150506000815280825b600183039250600a81066030018353600a90048061174b5750819003601f19909101908152919050565b600061178083610b0b565b90508180156117985750336001600160a01b03821614155b156117bb576117a781336106bd565b6117bb576117bb6367d9dca160e11b610fcc565b60008381526006602052604080822080546001600160a01b0319166001600160a01b0388811691821790925591518693918516917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591a450505050565b604051630a85bd0160e11b81526000906001600160a01b0385169063150b7a029061184d9033908990889088906004016120b3565b6020604051808303816000875af1925050508015611888575060408051601f3d908101601f19168201909252611885918101906120f0565b60015b6118dd573d8080156118b6576040519150601f19603f3d011682016040523d82523d6000602084013e6118bb565b606091505b5080516000036118d5576118d56368d2bf6b60e11b610fcc565b805181602001fd5b6001600160e01b031916630a85bd0160e11b149050949350505050565b6001600160e01b031981168114610a6c57600080fd5b60006020828403121561192257600080fd5b8135610d6d816118fa565b80356001600160a01b0381168114610cf457600080fd5b6000806040838503121561195757600080fd5b6119608361192d565b915060208301356001600160601b038116811461197c57600080fd5b809150509250929050565b60005b838110156119a257818101518382015260200161198a565b50506000910152565b600081518084526119c3816020860160208601611987565b601f01601f19169290920160200192915050565b602081526000610d6d60208301846119ab565b6000602082840312156119fc57600080fd5b5035919050565b60008060408385031215611a1657600080fd5b611a1f8361192d565b946020939093013593505050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b0381118282101715611a6b57611a6b611a2d565b604052919050565b60008060408385031215611a8657600080fd5b823591506020808401356001600160401b0380821115611aa557600080fd5b818601915086601f830112611ab957600080fd5b813581811115611acb57611acb611a2d565b8060051b9150611adc848301611a43565b8181529183018401918481019089841115611af657600080fd5b938501935b83851015611b1457843582529385019390850190611afb565b8096505050505050509250929050565b600080600060608486031215611b3957600080fd5b611b428461192d565b9250611b506020850161192d565b9150604084013590509250925092565b60008060408385031215611b7357600080fd5b50508035926020909101359150565b60006001600160401b03831115611b9b57611b9b611a2d565b611bae601f8401601f1916602001611a43565b9050828152838383011115611bc257600080fd5b828260208301376000602084830101529392505050565b600060208284031215611beb57600080fd5b81356001600160401b03811115611c0157600080fd5b8201601f81018413611c1257600080fd5b610c1c84823560208401611b82565b60008060208385031215611c3457600080fd5b82356001600160401b0380821115611c4b57600080fd5b818501915085601f830112611c5f57600080fd5b813581811115611c6e57600080fd5b8660208260051b8501011115611c8357600080fd5b60209290920196919550909350505050565b80516001600160a01b031682526020808201516001600160401b03169083015260408082015115159083015260609081015162ffffff16910152565b6020808252825182820181905260009190848201906040850190845b818110156115f157611d00838551611c95565b9284019260809290920191600101611ced565b600060208284031215611d2557600080fd5b610d6d8261192d565b6020808252825182820181905260009190848201906040850190845b818110156115f157835183529284019291840191600101611d4a565b600080600060608486031215611d7b57600080fd5b611d848461192d565b95602085013595506040909401359392505050565b8015158114610a6c57600080fd5b60008060408385031215611dba57600080fd5b611dc38361192d565b9150602083013561197c81611d99565b60008060008060808587031215611de957600080fd5b611df28561192d565b9350611e006020860161192d565b92506040850135915060608501356001600160401b03811115611e2257600080fd5b8501601f81018713611e3357600080fd5b611e4287823560208401611b82565b91505092959194509250565b6080810161078b8284611c95565b60008060408385031215611e6f57600080fd5b611e788361192d565b9150611e866020840161192d565b90509250929050565b600181811c90821680611ea357607f821691505b602082108103611ec357634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052601160045260246000fd5b808202811582820484141761078b5761078b611ec9565b600082611f1357634e487b7160e01b600052601260045260246000fd5b500490565b601f821115610888576000816000526020600020601f850160051c81016020861015611f415750805b601f850160051c820191505b81811015611f6057828155600101611f4d565b505050505050565b81516001600160401b03811115611f8157611f81611a2d565b611f9581611f8f8454611e8f565b84611f18565b602080601f831160018114611fca5760008415611fb25750858301515b600019600386901b1c1916600185901b178555611f60565b600085815260208120601f198616915b82811015611ff957888601518255948401946001909101908401611fda565b50858210156120175787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b60008351612039818460208801611987565b83519083019061204d818360208801611987565b01949350505050565b60008161206557612065611ec9565b506000190190565b60006020828403121561207f57600080fd5b8151610d6d81611d99565b634e487b7160e01b600052603260045260246000fd5b8181038181111561078b5761078b611ec9565b6001600160a01b03858116825284166020820152604081018390526080606082018190526000906120e6908301846119ab565b9695505050505050565b60006020828403121561210257600080fd5b8151610d6d816118fa56 +0x60a06040526010805461ffff191660011790553480156200001f57600080fd5b5060405162002ca338038062002ca383398101604081905262000042916200064b565b8251733cc6cdda760b79bafa08df41ecfa224f810dceb66001898960026200006b8382620007e4565b5060036200007a8282620007e4565b50600160005550506daaeb6d7670e522a718067333cd4e3b15620001c75780156200011557604051633e9f1edf60e11b81523060048201526001600160a01b03831660248201526daaeb6d7670e522a718067333cd4e90637d3e3dbe906044015b600060405180830381600087803b158015620000f657600080fd5b505af11580156200010b573d6000803e3d6000fd5b50505050620001c7565b6001600160a01b03821615620001665760405163a0af290360e01b81523060048201526001600160a01b03831660248201526daaeb6d7670e522a718067333cd4e9063a0af290390604401620000db565b604051632210724360e11b81523060048201526daaeb6d7670e522a718067333cd4e90634420e48690602401600060405180830381600087803b158015620001ad57600080fd5b505af1158015620001c2573d6000803e3d6000fd5b505050505b50506001600160a01b0316608052620001e0886200032f565b600a620001ee8682620007e4565b50600b8054620001fe9062000753565b80601f01602080910402602001604051908101604052809291908181526020018280546200022c9062000753565b80156200027d5780601f1062000251576101008083540402835291602001916200027d565b820191906000526020600020905b8154815290600101906020018083116200025f57829003601f168201915b50508651600c80546001600160a01b039092166001600160a01b03199092169190911790555050506020840151600d556040840151600e80546060870151608088015163ffffffff166a01000000000000000000000263ffffffff60501b1961ffff90921668010000000000000000026001600160501b03199093166001600160401b0390951694909417919091171691909117905593506200032182826200036b565b5050505050505050620008b0565b6001600160a01b0316638b78c6d8198190558060007f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08180a350565b6127106001600160601b0382161115620003df5760405162461bcd60e51b815260206004820152602a60248201527f455243323938313a20726f79616c7479206665652077696c6c206578636565646044820152692073616c65507269636560b01b60648201526084015b60405180910390fd5b6001600160a01b038216620004375760405162461bcd60e51b815260206004820152601960248201527f455243323938313a20696e76616c6964207265636569766572000000000000006044820152606401620003d6565b604080518082019091526001600160a01b039092168083526001600160601b039091166020909201829052600160a01b90910217600855565b6001600160a01b03811681146200048657600080fd5b50565b8051620004968162000470565b919050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b0381118282101715620004dc57620004dc6200049b565b604052919050565b600082601f830112620004f657600080fd5b81516001600160401b038111156200051257620005126200049b565b602062000528601f8301601f19168201620004b1565b82815285828487010111156200053d57600080fd5b60005b838110156200055d57858101830151828201840152820162000540565b506000928101909101919091529392505050565b805163ffffffff811681146200049657600080fd5b600060a082840312156200059957600080fd5b60405160a081016001600160401b038082118383101715620005bf57620005bf6200049b565b8160405282935084519150620005d58262000470565b81835260208501516020840152604085015191508082168214620005f857600080fd5b506040820152606083015161ffff811681146200061457600080fd5b6060820152620006276080840162000571565b60808201525092915050565b80516001600160601b03811681146200049657600080fd5b600080600080600080600080610180898b0312156200066957600080fd5b620006748962000489565b60208a01519098506001600160401b03808211156200069257600080fd5b620006a08c838d01620004e4565b985060408b0151915080821115620006b757600080fd5b620006c58c838d01620004e4565b975060608b0151915080821115620006dc57600080fd5b620006ea8c838d01620004e4565b965060808b01519150808211156200070157600080fd5b50620007108b828c01620004e4565b945050620007228a60a08b0162000586565b9250620007336101408a0162000489565b9150620007446101608a0162000633565b90509295985092959890939650565b600181811c908216806200076857607f821691505b6020821081036200078957634e487b7160e01b600052602260045260246000fd5b50919050565b601f821115620007df576000816000526020600020601f850160051c81016020861015620007ba5750805b601f850160051c820191505b81811015620007db57828155600101620007c6565b5050505b505050565b81516001600160401b038111156200080057620008006200049b565b620008188162000811845462000753565b846200078f565b602080601f831160018114620008505760008415620008375750858301515b600019600386901b1c1916600185901b178555620007db565b600085815260208120601f198616915b82811015620008815788860151825594840194600190910190840162000860565b5085821015620008a05787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6080516123d0620008d3600039600081816109bb01526109fd01526123d06000f3fe6080604052600436106102675760003560e01c80636d2ebc5c11610144578063b88d4fde116100b6578063e8a3d4851161007a578063e8a3d485146107b0578063e985e9c5146107c5578063f04e283e1461080e578063f0503e8014610821578063f2fde38b1461084e578063fee81cf41461086157600080fd5b8063b88d4fde146106d8578063b9881734146106eb578063c23dc68f14610700578063c87b56dd1461072d578063d54bcf9c1461074d57600080fd5b80638da5cb5b116101085780638da5cb5b14610630578063938e3d7b1461064957806395d89b4114610669578063960783071461067e57806399a2557a14610698578063a22cb465146106b857600080fd5b80636d2ebc5c146105b157806370a08231146105c6578063715018a6146105e657806375794a3c146105ee5780638462151c1461060357600080fd5b80632a55205a116101dd57806354d1f13d116101a157806354d1f13d1461050757806355f804b31461050f5780635bbb21771461052f5780636352211e1461055c5780636a2d83621461057c5780636c0360eb1461059c57600080fd5b80632a55205a1461045457806341f434341461049357806342842e0e146104b557806342966c68146104c857806346e5350c146104e857600080fd5b80630c9490431161022f5780630c9490431461033057806318160ddd146103c55780631a1d9252146103ec5780631fe543e31461041957806323b872dd14610439578063256929621461044c57600080fd5b806301ffc9a71461026c57806304634d8d146102a157806306fdde03146102c3578063081812fc146102e5578063095ea7b31461031d575b600080fd5b34801561027857600080fd5b5061028c610287366004611b51565b610894565b60405190151581526020015b60405180910390f35b3480156102ad57600080fd5b506102c16102bc366004611b85565b6108b4565b005b3480156102cf57600080fd5b506102d86108ca565b6040516102989190611c18565b3480156102f157600080fd5b50610305610300366004611c2b565b61095c565b6040516001600160a01b039091168152602001610298565b6102c161032b366004611c44565b610997565b34801561033c57600080fd5b50600c54600d54600e5461037c926001600160a01b031691906001600160401b03811690600160401b810461ffff1690600160501b900463ffffffff1685565b604080516001600160a01b03909616865260208601949094526001600160401b039092169284019290925261ffff909116606083015263ffffffff16608082015260a001610298565b3480156103d157600080fd5b5060015460005403600019015b604051908152602001610298565b3480156103f857600080fd5b506103de610407366004611c2b565b600f6020526000908152604090205481565b34801561042557600080fd5b506102c1610434366004611cb4565b6109b0565b6102c1610447366004611d65565b610a39565b6102c1610a64565b34801561046057600080fd5b5061047461046f366004611da1565b610ab3565b604080516001600160a01b039093168352602083019190915201610298565b34801561049f57600080fd5b506103056daaeb6d7670e522a718067333cd4e81565b6102c16104c3366004611d65565b610b5f565b3480156104d457600080fd5b506102c16104e3366004611c2b565b610b84565b3480156104f457600080fd5b5060105461028c90610100900460ff1681565b6102c1610b92565b34801561051b57600080fd5b506102c161052a366004611e1a565b610bce565b34801561053b57600080fd5b5061054f61054a366004611e62565b610be2565b6040516102989190611f12565b34801561056857600080fd5b50610305610577366004611c2b565b610c2e565b34801561058857600080fd5b506102c1610597366004611f54565b610c39565b3480156105a857600080fd5b506102d8610d2a565b3480156105bd57600080fd5b506102c1610db8565b3480156105d257600080fd5b506103de6105e1366004611fd6565b610dcc565b6102c1610e11565b3480156105fa57600080fd5b506000546103de565b34801561060f57600080fd5b5061062361061e366004611fd6565b610e25565b6040516102989190611ff1565b34801561063c57600080fd5b50638b78c6d81954610305565b34801561065557600080fd5b506102c1610664366004611e1a565b610e4c565b34801561067557600080fd5b506102d8610e60565b34801561068a57600080fd5b5060105461028c9060ff1681565b3480156106a457600080fd5b506106236106b3366004612029565b610e6f565b3480156106c457600080fd5b506102c16106d336600461206a565b610e7c565b6102c16106e6366004612096565b610e90565b3480156106f757600080fd5b506102c1610ebd565b34801561070c57600080fd5b5061072061071b366004611c2b565b610ed6565b6040516102989190612111565b34801561073957600080fd5b506102d8610748366004611c2b565b610f3a565b34801561075957600080fd5b506103de610768366004611c2b565b60408051426020808301919091523360601b6bffffffffffffffffffffffff191682840152605480830194909452825180830390940184526074909101909152815191012090565b3480156107bc57600080fd5b506102d8610fb5565b3480156107d157600080fd5b5061028c6107e036600461211f565b6001600160a01b03918216600090815260076020908152604080832093909416825291909152205460ff1690565b6102c161081c366004611fd6565b610fc2565b34801561082d57600080fd5b506103de61083c366004611c2b565b60116020526000908152604090205481565b6102c161085c366004611fd6565b610fff565b34801561086d57600080fd5b506103de61087c366004611fd6565b63389a75e1600c908152600091909152602090205490565b600061089f82611026565b806108ae57506108ae8261105b565b92915050565b6108bc6110a9565b6108c682826110c4565b5050565b6060600280546108d990612152565b80601f016020809104026020016040519081016040528092919081815260200182805461090590612152565b80156109525780601f1061092757610100808354040283529160200191610952565b820191906000526020600020905b81548152906001019060200180831161093557829003601f168201915b5050505050905090565b6000610967826111c1565b61097b5761097b6333d1c03960e21b61120d565b506000908152600660205260409020546001600160a01b031690565b816109a181611217565b6109ab83836112d0565b505050565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610a2f5760405163073e64fd60e21b81523360048201526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001660248201526044015b60405180910390fd5b6108c682826112dc565b826001600160a01b0381163314610a5357610a5333611217565b610a5e848484611395565b50505050565b60006202a3006001600160401b03164201905063389a75e1600c5233600052806020600c2055337fdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d600080a250565b60008281526009602090815260408083208151808301909252546001600160a01b038116808352600160a01b9091046001600160601b0316928201929092528291610b285750604080518082019091526008546001600160a01b0381168252600160a01b90046001600160601b031660208201525b602081015160009061271090610b47906001600160601b0316876121a2565b610b5191906121b9565b915196919550909350505050565b826001600160a01b0381163314610b7957610b7933611217565b610a5e848484611504565b610b8f81600161151f565b50565b63389a75e1600c523360005260006020600c2055337ffa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92600080a2565b610bd66110a9565b600a6108c6828261222b565b60408051828152600583901b8082016020019092526060915b8015610c2657601f1980820191860101356000610c1782610ed6565b8484016020015250610bfb9050565b509392505050565b60006108ae82611660565b610c416110a9565b60105460ff16610c8a5760405162461bcd60e51b81526020600482015260146024820152731594918818d85b89dd081899481d5c19185d195960621b6044820152606401610a26565b6040805160a0810182526001600160a01b03909616808752602087018690526001600160401b0390941690860181905261ffff9092166060860181905263ffffffff9091166080909501859052600c80546001600160a01b031916909317909255600d92909255600e8054600160501b90940263ffffffff60501b19600160401b90930269ffffffffffffffffffff199095169093179390931716179055565b600a8054610d3790612152565b80601f0160208091040260200160405190810160405280929190818152602001828054610d6390612152565b8015610db05780601f10610d8557610100808354040283529160200191610db0565b820191906000526020600020905b815481529060010190602001808311610d9357829003601f168201915b505050505081565b610dc06110a9565b6010805460ff19169055565b60006001600160a01b038216610dec57610dec6323d3ad8160e21b61120d565b506001600160a01b03166000908152600560205260409020546001600160401b031690565b610e196110a9565b610e236000611701565b565b60005460609060019082828214610e4457610e4185848461173f565b90505b949350505050565b610e546110a9565b600b6108c6828261222b565b6060600380546108d990612152565b6060610e4484848461173f565b81610e8681611217565b6109ab838361183e565b836001600160a01b0381163314610eaa57610eaa33611217565b610eb6858585856118aa565b5050505050565b610ec56110a9565b6010805461ff001916610100179055565b60408051608081018252600080825260208201819052918101829052606081019190915260018210610f3557600054821015610f35575b600082815260046020526040902054610f2c5760001990910190610f0d565b6108ae826118e5565b919050565b6060610f45826111c1565b610f5957610f59630a14c4b560e41b61120d565b6000610f63611963565b90508051600003610f835760405180602001604052806000815250610fae565b80610f8d84611972565b604051602001610f9e9291906122ea565b6040516020818303038152906040525b9392505050565b600b8054610d3790612152565b610fca6110a9565b63389a75e1600c52806000526020600c208054421115610ff257636f5e88186000526004601cfd5b60009055610b8f81611701565b6110076110a9565b8060601b61101d57637448fbae6000526004601cfd5b610b8f81611701565b60006001600160e01b0319821663152a902d60e11b14806108ae57506301ffc9a760e01b6001600160e01b03198316146108ae565b60006301ffc9a760e01b6001600160e01b03198316148061108c57506380ac58cd60e01b6001600160e01b03198316145b806108ae5750506001600160e01b031916635b5e139f60e01b1490565b638b78c6d819543314610e23576382b429006000526004601cfd5b6127106001600160601b03821611156111325760405162461bcd60e51b815260206004820152602a60248201527f455243323938313a20726f79616c7479206665652077696c6c206578636565646044820152692073616c65507269636560b01b6064820152608401610a26565b6001600160a01b0382166111885760405162461bcd60e51b815260206004820152601960248201527f455243323938313a20696e76616c6964207265636569766572000000000000006044820152606401610a26565b604080518082019091526001600160a01b039092168083526001600160601b039091166020909201829052600160a01b90910217600855565b600081600111610f3557600054821015610f355760005b5060008281526004602052604081205490819003611200576111f983612319565b92506111d8565b600160e01b161592915050565b8060005260046000fd5b6daaeb6d7670e522a718067333cd4e3b15610b8f57604051633185c44d60e21b81523060048201526001600160a01b03821660248201526daaeb6d7670e522a718067333cd4e9063c617113490604401602060405180830381865afa158015611284573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112a89190612330565b610b8f57604051633b79c77360e21b81526001600160a01b0382166004820152602401610a26565b6108c6828260016119b6565b6000828152600f6020526040812054905b8251811015610a5e578281815181106113085761130861234d565b60200260200101516011600083856113209190612363565b815260208101919091526040016000205561133b8183612363565b7f14296754697e325872a9c14eb682f467bc46b15a78ae9420d7a13a7cd3833b2c84838151811061136e5761136e61234d565b602002602001015160405161138591815260200190565b60405180910390a26001016112ed565b60006113a082611660565b6001600160a01b0394851694909150811684146113c6576113c662a1148160e81b61120d565b600082815260066020526040902080546113f28187335b6001600160a01b039081169116811491141790565b6114145761140086336107e0565b61141457611414632ce44b5f60e11b61120d565b801561141f57600082555b6001600160a01b038681166000908152600560205260408082208054600019019055918716808252919020805460010190554260a01b17600160e11b17600085815260046020526040812091909155600160e11b841690036114b1576001840160008181526004602052604081205490036114af5760005481146114af5760008181526004602052604090208490555b505b6001600160a01b0385168481887fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef600080a4806000036114fb576114fb633a954ecd60e21b61120d565b50505050505050565b6109ab83838360405180602001604052806000815250610e90565b600061152a83611660565b90508060008061154886600090815260066020526040902080549091565b91509150841561157f5761155d8184336113dd565b61157f5761156b83336107e0565b61157f5761157f632ce44b5f60e11b61120d565b801561158a57600082555b6001600160a01b038316600081815260056020526040902080546fffffffffffffffffffffffffffffffff0190554260a01b17600360e01b17600087815260046020526040812091909155600160e11b85169003611618576001860160008181526004602052604081205490036116165760005481146116165760008181526004602052604090208590555b505b60405186906000906001600160a01b038616907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908390a45050600180548101905550505050565b6000816001116116f15750600081815260046020526040812054908190036116de57600054821061169b5761169b636f96cda160e11b61120d565b5b5060001901600081815260046020526040902054801561169c57600160e01b81166000036116c957919050565b6116d9636f96cda160e11b61120d565b61169c565b600160e01b81166000036116f157919050565b610f35636f96cda160e11b61120d565b638b78c6d81980546001600160a01b039092169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a355565b606081831061175857611758631960ccad60e11b61120d565b600183101561176657600192505b600054808310611774578092505b6060600061178187610dcc565b8587109081029150811561183257818787031161179e5786860391505b60405192506001820160051b830160405260006117ba88610ed6565b9050600081604001516117cb575080515b60005b6117d78a6118e5565b92506040830151600081146117ef5760009250611814565b8351156117fb57835192505b8b831860601b611814576001820191508a8260051b8801525b5060018a019950888a148061182857508481145b156117ce57855250505b50909695505050505050565b3360008181526007602090815260408083206001600160a01b03871680855290835292819020805460ff191686151590811790915590519081529192917f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a35050565b6118b5848484610a39565b6001600160a01b0383163b15610a5e576118d184848484611a59565b610a5e57610a5e6368d2bf6b60e11b61120d565b6040805160808101825260008082526020820181905291810182905260608101919091526000828152600460205260409020546108ae90604080516080810182526001600160a01b038316815260a083901c6001600160401b03166020820152600160e01b831615159181019190915260e89190911c606082015290565b6060600a80546108d990612152565b606060a06040510180604052602081039150506000815280825b600183039250600a81066030018353600a90048061198c5750819003601f19909101908152919050565b60006119c183610c2e565b90508180156119d95750336001600160a01b03821614155b156119fc576119e881336107e0565b6119fc576119fc6367d9dca160e11b61120d565b60008381526006602052604080822080546001600160a01b0319166001600160a01b0388811691821790925591518693918516917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591a450505050565b604051630a85bd0160e11b81526000906001600160a01b0385169063150b7a0290611a8e903390899088908890600401612376565b6020604051808303816000875af1925050508015611ac9575060408051601f3d908101601f19168201909252611ac6918101906123b3565b60015b611b1e573d808015611af7576040519150601f19603f3d011682016040523d82523d6000602084013e611afc565b606091505b508051600003611b1657611b166368d2bf6b60e11b61120d565b805181602001fd5b6001600160e01b031916630a85bd0160e11b149050949350505050565b6001600160e01b031981168114610b8f57600080fd5b600060208284031215611b6357600080fd5b8135610fae81611b3b565b80356001600160a01b0381168114610f3557600080fd5b60008060408385031215611b9857600080fd5b611ba183611b6e565b915060208301356001600160601b0381168114611bbd57600080fd5b809150509250929050565b60005b83811015611be3578181015183820152602001611bcb565b50506000910152565b60008151808452611c04816020860160208601611bc8565b601f01601f19169290920160200192915050565b602081526000610fae6020830184611bec565b600060208284031215611c3d57600080fd5b5035919050565b60008060408385031215611c5757600080fd5b611c6083611b6e565b946020939093013593505050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b0381118282101715611cac57611cac611c6e565b604052919050565b60008060408385031215611cc757600080fd5b823591506020808401356001600160401b0380821115611ce657600080fd5b818601915086601f830112611cfa57600080fd5b813581811115611d0c57611d0c611c6e565b8060051b9150611d1d848301611c84565b8181529183018401918481019089841115611d3757600080fd5b938501935b83851015611d5557843582529385019390850190611d3c565b8096505050505050509250929050565b600080600060608486031215611d7a57600080fd5b611d8384611b6e565b9250611d9160208501611b6e565b9150604084013590509250925092565b60008060408385031215611db457600080fd5b50508035926020909101359150565b60006001600160401b03831115611ddc57611ddc611c6e565b611def601f8401601f1916602001611c84565b9050828152838383011115611e0357600080fd5b828260208301376000602084830101529392505050565b600060208284031215611e2c57600080fd5b81356001600160401b03811115611e4257600080fd5b8201601f81018413611e5357600080fd5b610e4484823560208401611dc3565b60008060208385031215611e7557600080fd5b82356001600160401b0380821115611e8c57600080fd5b818501915085601f830112611ea057600080fd5b813581811115611eaf57600080fd5b8660208260051b8501011115611ec457600080fd5b60209290920196919550909350505050565b80516001600160a01b031682526020808201516001600160401b03169083015260408082015115159083015260609081015162ffffff16910152565b6020808252825182820181905260009190848201906040850190845b8181101561183257611f41838551611ed6565b9284019260809290920191600101611f2e565b600080600080600060a08688031215611f6c57600080fd5b611f7586611b6e565b94506020860135935060408601356001600160401b0381168114611f9857600080fd5b9250606086013561ffff81168114611faf57600080fd5b9150608086013563ffffffff81168114611fc857600080fd5b809150509295509295909350565b600060208284031215611fe857600080fd5b610fae82611b6e565b6020808252825182820181905260009190848201906040850190845b818110156118325783518352928401929184019160010161200d565b60008060006060848603121561203e57600080fd5b61204784611b6e565b95602085013595506040909401359392505050565b8015158114610b8f57600080fd5b6000806040838503121561207d57600080fd5b61208683611b6e565b91506020830135611bbd8161205c565b600080600080608085870312156120ac57600080fd5b6120b585611b6e565b93506120c360208601611b6e565b92506040850135915060608501356001600160401b038111156120e557600080fd5b8501601f810187136120f657600080fd5b61210587823560208401611dc3565b91505092959194509250565b608081016108ae8284611ed6565b6000806040838503121561213257600080fd5b61213b83611b6e565b915061214960208401611b6e565b90509250929050565b600181811c9082168061216657607f821691505b60208210810361218657634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052601160045260246000fd5b80820281158282048414176108ae576108ae61218c565b6000826121d657634e487b7160e01b600052601260045260246000fd5b500490565b601f8211156109ab576000816000526020600020601f850160051c810160208610156122045750805b601f850160051c820191505b8181101561222357828155600101612210565b505050505050565b81516001600160401b0381111561224457612244611c6e565b612258816122528454612152565b846121db565b602080601f83116001811461228d57600084156122755750858301515b600019600386901b1c1916600185901b178555612223565b600085815260208120601f198616915b828110156122bc5788860151825594840194600190910190840161229d565b50858210156122da5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b600083516122fc818460208801611bc8565b835190830190612310818360208801611bc8565b01949350505050565b6000816123285761232861218c565b506000190190565b60006020828403121561234257600080fd5b8151610fae8161205c565b634e487b7160e01b600052603260045260246000fd5b818103818111156108ae576108ae61218c565b6001600160a01b03858116825284166020820152604081018390526080606082018190526000906123a990830184611bec565b9695505050505050565b6000602082840312156123c557600080fd5b8151610fae81611b3b56 diff --git a/bytecode/common/IBaseERC721A.bin b/bytecode/common/IBaseERC721A.bin deleted file mode 100644 index ec687260..00000000 --- a/bytecode/common/IBaseERC721A.bin +++ /dev/null @@ -1 +0,0 @@ -0x diff --git a/bytecode/common/INonceRegistry.bin b/bytecode/common/INonceRegistry.bin deleted file mode 100644 index ec687260..00000000 --- a/bytecode/common/INonceRegistry.bin +++ /dev/null @@ -1 +0,0 @@ -0x diff --git a/bytecode/common/ITreasury.bin b/bytecode/common/ITreasury.bin deleted file mode 100644 index ec687260..00000000 --- a/bytecode/common/ITreasury.bin +++ /dev/null @@ -1 +0,0 @@ -0x diff --git a/bytecode/pookyball/IPookyball.bin b/bytecode/pookyball/IPookyball.bin deleted file mode 100644 index ec687260..00000000 --- a/bytecode/pookyball/IPookyball.bin +++ /dev/null @@ -1 +0,0 @@ -0x diff --git a/bytecode/pookyball/Pookyball.bin b/bytecode/pookyball/Pookyball.bin index 309f623a..4de63353 100644 --- a/bytecode/pookyball/Pookyball.bin +++ b/bytecode/pookyball/Pookyball.bin @@ -1 +1 @@ -0x60a06040523480156200001157600080fd5b50604051620030c6380380620030c683398101604081905262000034916200056d565b733cc6cdda760b79bafa08df41ecfa224f810dceb660018660405180604001604052806009815260200168141bdbdade58985b1b60ba1b815250604051806040016040528060048152602001632825aca160e11b81525081600090816200009c9190620006d6565b506001620000ab8282620006d6565b5050506001600160a01b03166080526daaeb6d7670e522a718067333cd4e3b15620001ff5780156200014d57604051633e9f1edf60e11b81523060048201526001600160a01b03831660248201526daaeb6d7670e522a718067333cd4e90637d3e3dbe906044015b600060405180830381600087803b1580156200012e57600080fd5b505af115801562000143573d6000803e3d6000fd5b50505050620001ff565b6001600160a01b038216156200019e5760405163a0af290360e01b81523060048201526001600160a01b03831660248201526daaeb6d7670e522a718067333cd4e9063a0af29039060440162000113565b604051632210724360e11b81523060048201526daaeb6d7670e522a718067333cd4e90634420e48690602401600060405180830381600087803b158015620001e557600080fd5b505af1158015620001fa573d6000803e3d6000fd5b505050505b5060099050620002108982620006d6565b50600a6200021f8882620006d6565b50600d80546001600160a01b0319166001600160a01b038716179055600e849055600f80546001600160401b0385166001600160501b0319909116176801000000000000000061ffff8516021763ffffffff60501b19166a010000000000000000000063ffffffff8416021790556200029b866101f4620002b6565b620002a8600033620003bb565b5050505050505050620007a2565b6127106001600160601b03821611156200032a5760405162461bcd60e51b815260206004820152602a60248201527f455243323938313a20726f79616c7479206665652077696c6c206578636565646044820152692073616c65507269636560b01b60648201526084015b60405180910390fd5b6001600160a01b038216620003825760405162461bcd60e51b815260206004820152601960248201527f455243323938313a20696e76616c696420726563656976657200000000000000604482015260640162000321565b604080518082019091526001600160a01b039092168083526001600160601b039091166020909201829052600160a01b90910217600655565b60008281526008602090815260408083206001600160a01b038516845290915290205460ff166200045c5760008281526008602090815260408083206001600160a01b03851684529091529020805460ff191660011790556200041b3390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45b5050565b634e487b7160e01b600052604160045260246000fd5b600082601f8301126200048857600080fd5b81516001600160401b0380821115620004a557620004a562000460565b604051601f8301601f19908116603f01168101908282118183101715620004d057620004d062000460565b8160405283815260209250866020858801011115620004ee57600080fd5b600091505b83821015620005125785820183015181830184015290820190620004f3565b6000602085830101528094505050505092915050565b80516001600160a01b03811681146200054057600080fd5b919050565b805161ffff811681146200054057600080fd5b805163ffffffff811681146200054057600080fd5b600080600080600080600080610100898b0312156200058b57600080fd5b88516001600160401b0380821115620005a357600080fd5b620005b18c838d0162000476565b995060208b0151915080821115620005c857600080fd5b620005d68c838d0162000476565b9850620005e660408c0162000528565b9750620005f660608c0162000528565b965060808b0151955060a08b0151915080821682146200061557600080fd5b5092506200062660c08a0162000545565b91506200063660e08a0162000558565b90509295985092959890939650565b600181811c908216806200065a57607f821691505b6020821081036200067b57634e487b7160e01b600052602260045260246000fd5b50919050565b601f821115620006d1576000816000526020600020601f850160051c81016020861015620006ac5750805b601f850160051c820191505b81811015620006cd57828155600101620006b8565b5050505b505050565b81516001600160401b03811115620006f257620006f262000460565b6200070a8162000703845462000645565b8462000681565b602080601f831160018114620007425760008415620007295750858301515b600019600386901b1c1916600185901b178555620006cd565b600085815260208120601f198616915b82811015620007735788860151825594840194600190910190840162000752565b5085821015620007925787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b608051612901620007c5600039600081816106f7015261073901526129016000f3fe608060405234801561001057600080fd5b506004361061023d5760003560e01c80636c0360eb1161013b578063b7cf12cf116100b8578063e3684e391161007c578063e3684e3914610575578063e8a3d48514610595578063e985e9c51461059d578063f84ddf0b146105d9578063fe6d8124146105e257600080fd5b8063b7cf12cf14610516578063b88d4fde14610529578063c87b56dd1461053c578063d36d68981461054f578063d547741f1461056257600080fd5b8063938e3d7b116100ff578063938e3d7b146104cd57806395d89b41146104e05780639b14e5d3146104e8578063a217fddf146104fb578063a22cb4651461050357600080fd5b80636c0360eb1461046b57806370a082311461047357806370a93b36146104865780638704a2081461049957806391d14854146104ba57600080fd5b80632a55205a116101c957806341f434341161018d57806341f43434146103f557806342842e0e1461040a57806355f804b31461041d5780636174da30146104305780636352211e1461045857600080fd5b80632a55205a146103465780632f2ff15d14610378578063326156401461038b57806336568abe146103b65780633b7ed734146103c957600080fd5b8063095ea7b311610210578063095ea7b3146102c15780631fe543e3146102d657806323b872dd146102e9578063248a9ca3146102fc57806327730d121461031f57600080fd5b806301ffc9a714610242578063041d443e1461026a57806306fdde0314610281578063081812fc14610296575b600080fd5b610255610250366004611ed9565b610609565b60405190151581526020015b60405180910390f35b610273600e5481565b604051908152602001610261565b61028961061a565b6040516102619190611f46565b6102a96102a4366004611f59565b6106ac565b6040516001600160a01b039091168152602001610261565b6102d46102cf366004611f8e565b6106d3565b005b6102d46102e4366004612021565b6106ec565b6102d46102f73660046120c2565b610779565b61027361030a366004611f59565b60009081526008602052604090206001015490565b6102737fd13d8e3c8822ff4d0a39994f3616e22d61c97585cee7a1baf4e9a875726b5f1581565b6103596103543660046120fe565b6107a4565b604080516001600160a01b039093168352602083019190915201610261565b6102d4610386366004612120565b610850565b600f5461039e906001600160401b031681565b6040516001600160401b039091168152602001610261565b6102d46103c4366004612120565b610875565b600f546103e090600160501b900463ffffffff1681565b60405163ffffffff9091168152602001610261565b6102a96daaeb6d7670e522a718067333cd4e81565b6102d46104183660046120c2565b6108ef565b6102d461042b3660046121a3565b610914565b600f5461044590600160401b900461ffff1681565b60405161ffff9091168152602001610261565b6102a9610466366004611f59565b61092b565b61028961098b565b6102736104813660046121eb565b610a19565b6102d46104943660046120fe565b610a9f565b6104a26101f481565b6040516001600160601b039091168152602001610261565b6102556104c8366004612120565b610b27565b6102d46104db3660046121a3565b610b52565b610289610b69565b6102d46104f63660046121eb565b610b78565b610273600081565b6102d4610511366004612214565b610b8f565b6102d46105243660046120fe565b610ba3565b6102d461053736600461224b565b610c1e565b61028961054a366004611f59565b610c4b565b61027361055d366004612341565b610c88565b6102d4610570366004612120565b610e9f565b610588610583366004611f59565b610ec4565b6040516102619190612416565b610289610f63565b6102556105ab366004612463565b6001600160a01b03918216600090815260056020908152604080832093909416825291909152205460ff1690565b610273600b5481565b6102737ff0887ba65ee2024ea881d91b74c2450ef19e1557f03bed3ea9f16b037cbe2dc981565b600061061482610f70565b92915050565b6060600080546106299061248d565b80601f01602080910402602001604051908101604052809291908181526020018280546106559061248d565b80156106a25780601f10610677576101008083540402835291602001916106a2565b820191906000526020600020905b81548152906001019060200180831161068557829003601f168201915b5050505050905090565b60006106b782610f95565b506000908152600460205260409020546001600160a01b031690565b816106dd81610ff7565b6106e783836110b0565b505050565b336001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161461076b5760405163073e64fd60e21b81523360048201526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001660248201526044015b60405180910390fd5b61077582826111c0565b5050565b826001600160a01b03811633146107935761079333610ff7565b61079e84848461127c565b50505050565b60008281526007602090815260408083208151808301909252546001600160a01b038116808352600160a01b9091046001600160601b03169282019290925282916108195750604080518082019091526006546001600160a01b0381168252600160a01b90046001600160601b031660208201525b602081015160009061271090610838906001600160601b0316876124dd565b61084291906124f4565b915196919550909350505050565b60008281526008602052604090206001015461086b816112ad565b6106e783836112b7565b6001600160a01b03811633146108e55760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201526e103937b632b9903337b91039b2b63360891b6064820152608401610762565b610775828261133d565b826001600160a01b03811633146109095761090933610ff7565b61079e8484846113a4565b600061091f816112ad565b60096106e78382612566565b6000818152600260205260408120546001600160a01b0316806106145760405162461bcd60e51b8152602060048201526018602482015277115490cdcc8c4e881a5b9d985b1a59081d1bdad95b88125160421b6044820152606401610762565b600980546109989061248d565b80601f01602080910402602001604051908101604052809291908181526020018280546109c49061248d565b8015610a115780601f106109e657610100808354040283529160200191610a11565b820191906000526020600020905b8154815290600101906020018083116109f457829003601f168201915b505050505081565b60006001600160a01b038216610a835760405162461bcd60e51b815260206004820152602960248201527f4552433732313a2061646472657373207a65726f206973206e6f7420612076616044820152683634b21037bbb732b960b91b6064820152608401610762565b506001600160a01b031660009081526003602052604090205490565b7fd13d8e3c8822ff4d0a39994f3616e22d61c97585cee7a1baf4e9a875726b5f15610ac9816112ad565b610ad283610f95565b6000838152600c6020526040908190206001018390555183907f8bdaee675270281b7bc2d5b9ced20517ecf5ce96158973ef78072a7bc1491b4490610b1a9085815260200190565b60405180910390a2505050565b60009182526008602090815260408084206001600160a01b0393909316845291905290205460ff1690565b6000610b5d816112ad565b600a6106e78382612566565b6060600180546106299061248d565b6000610b83816112ad565b610775826101f46113bf565b81610b9981610ff7565b6106e783836114bc565b7fd13d8e3c8822ff4d0a39994f3616e22d61c97585cee7a1baf4e9a875726b5f15610bcd816112ad565b610bd683610f95565b6000838152600c6020526040908190206002018390555183907f334246ed50b046a9933ddd38bbb387c51e3709753687788af1c5207d3689761b90610b1a9085815260200190565b836001600160a01b0381163314610c3857610c3833610ff7565b610c44858585856114c7565b5050505050565b6060610c5682610f95565b6009610c61836114f9565b604051602001610c72929190612625565b6040516020818303038152906040529050919050565b60007ff0887ba65ee2024ea881d91b74c2450ef19e1557f03bed3ea9f16b037cbe2dc9610cb4816112ad565b8251845114610ce3578351835160405163990d9df760e01b815260048101929092526024820152604401610762565b60005b8451811015610dce57610d25858281518110610d0457610d046126ac565b6020026020010151600b60008154610d1b906126c2565b918290555061158b565b6040518060800160405280858381518110610d4257610d426126ac565b60200260200101516004811115610d5b57610d5b612400565b81526000602080830182905260408084018390526060909301829052600b548252600c90522081518154829060ff19166001836004811115610d9f57610d9f612400565b021790555060208201516001808301919091556040830151600283015560609092015160039091015501610ce6565b50600d54600e54600f5486516040516305d3b1d360e41b815260048101939093526001600160401b038216602484015261ffff600160401b830416604484015263ffffffff600160501b909204821660648401521660848201526000916001600160a01b031690635d3b1d309060a4016020604051808303816000875af1158015610e5d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e8191906126db565b600b5460009182526010602052604090912081905595945050505050565b600082815260086020526040902060010154610eba816112ad565b6106e7838361133d565b610ef0604080516080810190915280600081526020016000815260200160008152602001600081525090565b610ef982610f95565b6000828152600c6020526040908190208151608081019092528054829060ff166004811115610f2a57610f2a612400565b6004811115610f3b57610f3b612400565b8152600182015460208201526002820154604082015260039091015460609091015292915050565b600a80546109989061248d565b60006001600160e01b03198216637965db0b60e01b1480610614575061061482611716565b6000818152600260205260409020546001600160a01b0316610ff45760405162461bcd60e51b8152602060048201526018602482015277115490cdcc8c4e881a5b9d985b1a59081d1bdad95b88125160421b6044820152606401610762565b50565b6daaeb6d7670e522a718067333cd4e3b15610ff457604051633185c44d60e21b81523060048201526001600160a01b03821660248201526daaeb6d7670e522a718067333cd4e9063c617113490604401602060405180830381865afa158015611064573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061108891906126f4565b610ff457604051633b79c77360e21b81526001600160a01b0382166004820152602401610762565b60006110bb8261092b565b9050806001600160a01b0316836001600160a01b0316036111285760405162461bcd60e51b815260206004820152602160248201527f4552433732313a20617070726f76616c20746f2063757272656e74206f776e656044820152603960f91b6064820152608401610762565b336001600160a01b0382161480611144575061114481336105ab565b6111b65760405162461bcd60e51b815260206004820152603d60248201527f4552433732313a20617070726f76652063616c6c6572206973206e6f7420746f60448201527f6b656e206f776e6572206f7220617070726f76656420666f7220616c6c0000006064820152608401610762565b6106e7838361173b565b600082815260106020526040812054905b825181101561079e578281815181106111ec576111ec6126ac565b6020026020010151600c600083856112049190612711565b81526020810191909152604001600020600301556112228183612711565b7f14296754697e325872a9c14eb682f467bc46b15a78ae9420d7a13a7cd3833b2c848381518110611255576112556126ac565b602002602001015160405161126c91815260200190565b60405180910390a26001016111d1565b61128633826117a9565b6112a25760405162461bcd60e51b815260040161076290612724565b6106e7838383611828565b610ff4813361198c565b6112c18282610b27565b6107755760008281526008602090815260408083206001600160a01b03851684529091529020805460ff191660011790556112f93390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b6113478282610b27565b156107755760008281526008602090815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b6106e783838360405180602001604052806000815250610c1e565b6127106001600160601b038216111561142d5760405162461bcd60e51b815260206004820152602a60248201527f455243323938313a20726f79616c7479206665652077696c6c206578636565646044820152692073616c65507269636560b01b6064820152608401610762565b6001600160a01b0382166114835760405162461bcd60e51b815260206004820152601960248201527f455243323938313a20696e76616c6964207265636569766572000000000000006044820152606401610762565b604080518082019091526001600160a01b039092168083526001600160601b039091166020909201829052600160a01b90910217600655565b6107753383836119e5565b6114d133836117a9565b6114ed5760405162461bcd60e51b815260040161076290612724565b61079e84848484611ab3565b6060600061150683611ae6565b60010190506000816001600160401b0381111561152557611525611fb8565b6040519080825280601f01601f19166020018201604052801561154f576020820181803683370190505b5090508181016020015b600019016f181899199a1a9b1b9c1cb0b131b232b360811b600a86061a8153600a850494508461155957509392505050565b6001600160a01b0382166115e15760405162461bcd60e51b815260206004820181905260248201527f4552433732313a206d696e7420746f20746865207a65726f20616464726573736044820152606401610762565b6000818152600260205260409020546001600160a01b0316156116465760405162461bcd60e51b815260206004820152601c60248201527f4552433732313a20746f6b656e20616c7265616479206d696e746564000000006044820152606401610762565b6000818152600260205260409020546001600160a01b0316156116ab5760405162461bcd60e51b815260206004820152601c60248201527f4552433732313a20746f6b656e20616c7265616479206d696e746564000000006044820152606401610762565b6001600160a01b038216600081815260036020908152604080832080546001019055848352600290915280822080546001600160a01b0319168417905551839291907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a45050565b60006001600160e01b0319821663152a902d60e11b1480610614575061061482611bbe565b600081815260046020526040902080546001600160a01b0319166001600160a01b03841690811790915581906117708261092b565b6001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45050565b6000806117b58361092b565b9050806001600160a01b0316846001600160a01b031614806117fc57506001600160a01b0380821660009081526005602090815260408083209388168352929052205460ff165b806118205750836001600160a01b0316611815846106ac565b6001600160a01b0316145b949350505050565b826001600160a01b031661183b8261092b565b6001600160a01b0316146118615760405162461bcd60e51b815260040161076290612771565b6001600160a01b0382166118c35760405162461bcd60e51b8152602060048201526024808201527f4552433732313a207472616e7366657220746f20746865207a65726f206164646044820152637265737360e01b6064820152608401610762565b826001600160a01b03166118d68261092b565b6001600160a01b0316146118fc5760405162461bcd60e51b815260040161076290612771565b600081815260046020908152604080832080546001600160a01b03199081169091556001600160a01b0387811680865260038552838620805460001901905590871680865283862080546001019055868652600290945282852080549092168417909155905184937fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4505050565b6119968282610b27565b610775576119a381611c0e565b6119ae836020611c20565b6040516020016119bf9291906127b6565b60408051601f198184030181529082905262461bcd60e51b825261076291600401611f46565b816001600160a01b0316836001600160a01b031603611a465760405162461bcd60e51b815260206004820152601960248201527f4552433732313a20617070726f766520746f2063616c6c6572000000000000006044820152606401610762565b6001600160a01b03838116600081815260056020908152604080832094871680845294825291829020805460ff191686151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a3505050565b611abe848484611828565b611aca84848484611dc2565b61079e5760405162461bcd60e51b81526004016107629061282b565b60008072184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b8310611b255772184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b830492506040015b6d04ee2d6d415b85acef81000000008310611b51576d04ee2d6d415b85acef8100000000830492506020015b662386f26fc100008310611b6f57662386f26fc10000830492506010015b6305f5e1008310611b87576305f5e100830492506008015b6127108310611b9b57612710830492506004015b60648310611bad576064830492506002015b600a83106106145760010192915050565b60006001600160e01b031982166380ac58cd60e01b1480611bef57506001600160e01b03198216635b5e139f60e01b145b8061061457506301ffc9a760e01b6001600160e01b0319831614610614565b60606106146001600160a01b03831660145b60606000611c2f8360026124dd565b611c3a90600261287d565b6001600160401b03811115611c5157611c51611fb8565b6040519080825280601f01601f191660200182016040528015611c7b576020820181803683370190505b509050600360fc1b81600081518110611c9657611c966126ac565b60200101906001600160f81b031916908160001a905350600f60fb1b81600181518110611cc557611cc56126ac565b60200101906001600160f81b031916908160001a9053506000611ce98460026124dd565b611cf490600161287d565b90505b6001811115611d6c576f181899199a1a9b1b9c1cb0b131b232b360811b85600f1660108110611d2857611d286126ac565b1a60f81b828281518110611d3e57611d3e6126ac565b60200101906001600160f81b031916908160001a90535060049490941c93611d6581612890565b9050611cf7565b508315611dbb5760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401610762565b9392505050565b60006001600160a01b0384163b15611eb857604051630a85bd0160e11b81526001600160a01b0385169063150b7a0290611e069033908990889088906004016128a7565b6020604051808303816000875af1925050508015611e41575060408051601f3d908101601f19168201909252611e3e918101906128e4565b60015b611e9e573d808015611e6f576040519150601f19603f3d011682016040523d82523d6000602084013e611e74565b606091505b508051600003611e965760405162461bcd60e51b81526004016107629061282b565b805181602001fd5b6001600160e01b031916630a85bd0160e11b149050611820565b506001949350505050565b6001600160e01b031981168114610ff457600080fd5b600060208284031215611eeb57600080fd5b8135611dbb81611ec3565b60005b83811015611f11578181015183820152602001611ef9565b50506000910152565b60008151808452611f32816020860160208601611ef6565b601f01601f19169290920160200192915050565b602081526000611dbb6020830184611f1a565b600060208284031215611f6b57600080fd5b5035919050565b80356001600160a01b0381168114611f8957600080fd5b919050565b60008060408385031215611fa157600080fd5b611faa83611f72565b946020939093013593505050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b0381118282101715611ff657611ff6611fb8565b604052919050565b60006001600160401b0382111561201757612017611fb8565b5060051b60200190565b6000806040838503121561203457600080fd5b823591506020808401356001600160401b0381111561205257600080fd5b8401601f8101861361206357600080fd5b803561207661207182611ffe565b611fce565b81815260059190911b8201830190838101908883111561209557600080fd5b928401925b828410156120b35783358252928401929084019061209a565b80955050505050509250929050565b6000806000606084860312156120d757600080fd5b6120e084611f72565b92506120ee60208501611f72565b9150604084013590509250925092565b6000806040838503121561211157600080fd5b50508035926020909101359150565b6000806040838503121561213357600080fd5b8235915061214360208401611f72565b90509250929050565b60006001600160401b0383111561216557612165611fb8565b612178601f8401601f1916602001611fce565b905082815283838301111561218c57600080fd5b828260208301376000602084830101529392505050565b6000602082840312156121b557600080fd5b81356001600160401b038111156121cb57600080fd5b8201601f810184136121dc57600080fd5b6118208482356020840161214c565b6000602082840312156121fd57600080fd5b611dbb82611f72565b8015158114610ff457600080fd5b6000806040838503121561222757600080fd5b61223083611f72565b9150602083013561224081612206565b809150509250929050565b6000806000806080858703121561226157600080fd5b61226a85611f72565b935061227860208601611f72565b92506040850135915060608501356001600160401b0381111561229a57600080fd5b8501601f810187136122ab57600080fd5b6122ba8782356020840161214c565b91505092959194509250565b600082601f8301126122d757600080fd5b813560206122e761207183611ffe565b80838252602082019150600560208560051b88010194508785111561230b57600080fd5b602087015b858110156123345780358281106123275760008081fd5b8452928401928401612310565b5090979650505050505050565b6000806040838503121561235457600080fd5b82356001600160401b038082111561236b57600080fd5b818501915085601f83011261237f57600080fd5b8135602061238f61207183611ffe565b82815260059290921b840181019181810190898411156123ae57600080fd5b948201945b838610156123d3576123c486611f72565b825294820194908201906123b3565b965050860135925050808211156123e957600080fd5b506123f6858286016122c6565b9150509250929050565b634e487b7160e01b600052602160045260246000fd5b815160808201906005811061243b57634e487b7160e01b600052602160045260246000fd5b8083525060208301516020830152604083015160408301526060830151606083015292915050565b6000806040838503121561247657600080fd5b61247f83611f72565b915061214360208401611f72565b600181811c908216806124a157607f821691505b6020821081036124c157634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052601160045260246000fd5b8082028115828204841417610614576106146124c7565b60008261251157634e487b7160e01b600052601260045260246000fd5b500490565b601f8211156106e7576000816000526020600020601f850160051c8101602086101561253f5750805b601f850160051c820191505b8181101561255e5782815560010161254b565b505050505050565b81516001600160401b0381111561257f5761257f611fb8565b6125938161258d845461248d565b84612516565b602080601f8311600181146125c857600084156125b05750858301515b600019600386901b1c1916600185901b17855561255e565b600085815260208120601f198616915b828110156125f7578886015182559484019460019091019084016125d8565b50858210156126155787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b60008084546126338161248d565b6001828116801561264b57600181146126605761268f565b60ff198416875282151583028701945061268f565b8860005260208060002060005b858110156126865781548a82015290840190820161266d565b50505082870194505b5050505083516126a3818360208801611ef6565b01949350505050565b634e487b7160e01b600052603260045260246000fd5b6000600182016126d4576126d46124c7565b5060010190565b6000602082840312156126ed57600080fd5b5051919050565b60006020828403121561270657600080fd5b8151611dbb81612206565b81810381811115610614576106146124c7565b6020808252602d908201527f4552433732313a2063616c6c6572206973206e6f7420746f6b656e206f776e6560408201526c1c881bdc88185c1c1c9bdd9959609a1b606082015260800190565b60208082526025908201527f4552433732313a207472616e736665722066726f6d20696e636f72726563742060408201526437bbb732b960d91b606082015260800190565b7f416363657373436f6e74726f6c3a206163636f756e74200000000000000000008152600083516127ee816017850160208801611ef6565b7001034b99036b4b9b9b4b733903937b6329607d1b601791840191820152835161281f816028840160208801611ef6565b01602801949350505050565b60208082526032908201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560408201527131b2b4bb32b91034b6b83632b6b2b73a32b960711b606082015260800190565b80820180821115610614576106146124c7565b60008161289f5761289f6124c7565b506000190190565b6001600160a01b03858116825284166020820152604081018390526080606082018190526000906128da90830184611f1a565b9695505050505050565b6000602082840312156128f657600080fd5b8151611dbb81611ec356 +0x60a06040526011805461ffff191660011790553480156200001f57600080fd5b50604051620034093803806200340983398101604081905262000042916200057c565b733cc6cdda760b79bafa08df41ecfa224f810dceb660018660405180604001604052806009815260200168141bdbdade58985b1b60ba1b815250604051806040016040528060048152602001632825aca160e11b8152508160009081620000aa9190620006f8565b506001620000b98282620006f8565b5050506001600160a01b03166080526daaeb6d7670e522a718067333cd4e3b156200020d5780156200015b57604051633e9f1edf60e11b81523060048201526001600160a01b03831660248201526daaeb6d7670e522a718067333cd4e90637d3e3dbe906044015b600060405180830381600087803b1580156200013c57600080fd5b505af115801562000151573d6000803e3d6000fd5b505050506200020d565b6001600160a01b03821615620001ac5760405163a0af290360e01b81523060048201526001600160a01b03831660248201526daaeb6d7670e522a718067333cd4e9063a0af29039060440162000121565b604051632210724360e11b81523060048201526daaeb6d7670e522a718067333cd4e90634420e48690602401600060405180830381600087803b158015620001f357600080fd5b505af115801562000208573d6000803e3d6000fd5b505050505b50600990506200021e8a82620006f8565b50600a6200022d8982620006f8565b50600d80546001600160a01b0319166001600160a01b038716179055600e849055600f80546001600160401b0385166001600160501b0319909116176801000000000000000061ffff8516021763ffffffff60501b19166a010000000000000000000063ffffffff841602179055620002a9866101f4620002c5565b620002b6600088620003ca565b505050505050505050620007c4565b6127106001600160601b0382161115620003395760405162461bcd60e51b815260206004820152602a60248201527f455243323938313a20726f79616c7479206665652077696c6c206578636565646044820152692073616c65507269636560b01b60648201526084015b60405180910390fd5b6001600160a01b038216620003915760405162461bcd60e51b815260206004820152601960248201527f455243323938313a20696e76616c696420726563656976657200000000000000604482015260640162000330565b604080518082019091526001600160a01b039092168083526001600160601b039091166020909201829052600160a01b90910217600655565b60008281526008602090815260408083206001600160a01b038516845290915290205460ff166200046b5760008281526008602090815260408083206001600160a01b03851684529091529020805460ff191660011790556200042a3390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45b5050565b634e487b7160e01b600052604160045260246000fd5b600082601f8301126200049757600080fd5b81516001600160401b0380821115620004b457620004b46200046f565b604051601f8301601f19908116603f01168101908282118183101715620004df57620004df6200046f565b8160405283815260209250866020858801011115620004fd57600080fd5b600091505b8382101562000521578582018301518183018401529082019062000502565b6000602085830101528094505050505092915050565b80516001600160a01b03811681146200054f57600080fd5b919050565b805161ffff811681146200054f57600080fd5b805163ffffffff811681146200054f57600080fd5b60008060008060008060008060006101208a8c0312156200059c57600080fd5b89516001600160401b0380821115620005b457600080fd5b620005c28d838e0162000485565b9a5060208c0151915080821115620005d957600080fd5b620005e78d838e0162000485565b9950620005f760408d0162000537565b98506200060760608d0162000537565b97506200061760808d0162000537565b965060a08c0151955060c08c0151915080821682146200063657600080fd5b5092506200064760e08b0162000554565b9150620006586101008b0162000567565b90509295985092959850929598565b600181811c908216806200067c57607f821691505b6020821081036200069d57634e487b7160e01b600052602260045260246000fd5b50919050565b601f821115620006f3576000816000526020600020601f850160051c81016020861015620006ce5750805b601f850160051c820191505b81811015620006ef57828155600101620006da565b5050505b505050565b81516001600160401b038111156200071457620007146200046f565b6200072c8162000725845462000667565b84620006a3565b602080601f8311600181146200076457600084156200074b5750858301515b600019600386901b1c1916600185901b178555620006ef565b600085815260208120601f198616915b82811015620007955788860151825594840194600190910190840162000774565b5085821015620007b45787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b608051612c22620007e7600039600081816107ac01526107ee0152612c226000f3fe608060405234801561001057600080fd5b506004361061028a5760003560e01c806370a082311161015c578063b7cf12cf116100ce578063d54bcf9c11610087578063d54bcf9c14610617578063e3684e391461062a578063e8a3d4851461064a578063e985e9c514610652578063f84ddf0b1461068e578063fe6d81241461069757600080fd5b8063b7cf12cf146105b0578063b88d4fde146105c3578063b9881734146105d6578063c87b56dd146105de578063d36d6898146105f1578063d547741f1461060457600080fd5b806395d89b411161012057806395d89b411461055a57806396078307146105625780639b14e5d31461056f578063a217fddf14610582578063a22cb4651461058a578063a3e56fa81461059d57600080fd5b806370a08231146104ed57806370a93b36146105005780638704a2081461051357806391d1485414610534578063938e3d7b1461054757600080fd5b8063326156401161020057806355f804b3116101b957806355f804b31461047c5780636174da301461048f5780636352211e146104b75780636a2d8362146104ca5780636c0360eb146104dd5780636d2ebc5c146104e557600080fd5b806332615640146103d857806336568abe146104035780633b7ed7341461041657806341f434341461044257806342842e0e1461045757806346e5350c1461046a57600080fd5b80631fe543e3116102525780631fe543e31461032357806323b872dd14610336578063248a9ca31461034957806327730d121461036c5780632a55205a146103935780632f2ff15d146103c557600080fd5b806301ffc9a71461028f578063041d443e146102b757806306fdde03146102ce578063081812fc146102e3578063095ea7b31461030e575b600080fd5b6102a261029d366004612178565b6106be565b60405190151581526020015b60405180910390f35b6102c0600e5481565b6040519081526020016102ae565b6102d66106cf565b6040516102ae91906121e5565b6102f66102f13660046121f8565b610761565b6040516001600160a01b0390911681526020016102ae565b61032161031c36600461222d565b610788565b005b6103216103313660046122c0565b6107a1565b610321610344366004612361565b61082e565b6102c06103573660046121f8565b60009081526008602052604090206001015490565b6102c07fd13d8e3c8822ff4d0a39994f3616e22d61c97585cee7a1baf4e9a875726b5f1581565b6103a66103a136600461239d565b610859565b604080516001600160a01b0390931683526020830191909152016102ae565b6103216103d33660046123bf565b610905565b600f546103eb906001600160401b031681565b6040516001600160401b0390911681526020016102ae565b6103216104113660046123bf565b61092a565b600f5461042d90600160501b900463ffffffff1681565b60405163ffffffff90911681526020016102ae565b6102f66daaeb6d7670e522a718067333cd4e81565b610321610465366004612361565b6109a4565b6011546102a290610100900460ff1681565b61032161048a366004612442565b6109c9565b600f546104a490600160401b900461ffff1681565b60405161ffff90911681526020016102ae565b6102f66104c53660046121f8565b6109e0565b6103216104d836600461248a565b610a40565b6102d6610b0f565b610321610b9d565b6102c06104fb36600461250c565b610bb5565b61032161050e36600461239d565b610c3b565b61051c6101f481565b6040516001600160601b0390911681526020016102ae565b6102a26105423660046123bf565b610cc3565b610321610555366004612442565b610cee565b6102d6610d05565b6011546102a29060ff1681565b61032161057d36600461250c565b610d14565b6102c0600081565b610321610598366004612535565b610d2b565b600d546102f6906001600160a01b031681565b6103216105be36600461239d565b610d3f565b6103216105d136600461256c565b610dba565b610321610de7565b6102d66105ec3660046121f8565b610e04565b6102c06105ff366004612662565b610e41565b6103216106123660046123bf565b6110f6565b6102c06106253660046121f8565b61111b565b61063d6106383660046121f8565b611163565b6040516102ae9190612737565b6102d6611202565b6102a2610660366004612784565b6001600160a01b03918216600090815260056020908152604080832093909416825291909152205460ff1690565b6102c0600b5481565b6102c07ff0887ba65ee2024ea881d91b74c2450ef19e1557f03bed3ea9f16b037cbe2dc981565b60006106c98261120f565b92915050565b6060600080546106de906127ae565b80601f016020809104026020016040519081016040528092919081815260200182805461070a906127ae565b80156107575780601f1061072c57610100808354040283529160200191610757565b820191906000526020600020905b81548152906001019060200180831161073a57829003601f168201915b5050505050905090565b600061076c82611234565b506000908152600460205260409020546001600160a01b031690565b8161079281611296565b61079c838361134f565b505050565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146108205760405163073e64fd60e21b81523360048201526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001660248201526044015b60405180910390fd5b61082a828261145f565b5050565b826001600160a01b03811633146108485761084833611296565b61085384848461151b565b50505050565b60008281526007602090815260408083208151808301909252546001600160a01b038116808352600160a01b9091046001600160601b03169282019290925282916108ce5750604080518082019091526006546001600160a01b0381168252600160a01b90046001600160601b031660208201525b6020810151600090612710906108ed906001600160601b0316876127fe565b6108f79190612815565b915196919550909350505050565b6000828152600860205260409020600101546109208161154c565b61079c8383611556565b6001600160a01b038116331461099a5760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201526e103937b632b9903337b91039b2b63360891b6064820152608401610817565b61082a82826115dc565b826001600160a01b03811633146109be576109be33611296565b610853848484611643565b60006109d48161154c565b600961079c8382612887565b6000818152600260205260408120546001600160a01b0316806106c95760405162461bcd60e51b8152602060048201526018602482015277115490cdcc8c4e881a5b9d985b1a59081d1bdad95b88125160421b6044820152606401610817565b6000610a4b8161154c565b60115460ff16610a945760405162461bcd60e51b81526020600482015260146024820152731594918818d85b89dd081899481d5c19185d195960621b6044820152606401610817565b50600d80546001600160a01b039096166001600160a01b031990961695909517909455600e92909255600f805463ffffffff909416600160501b0263ffffffff60501b1961ffff909416600160401b0269ffffffffffffffffffff199095166001600160401b03909316929092179390931791909116179055565b60098054610b1c906127ae565b80601f0160208091040260200160405190810160405280929190818152602001828054610b48906127ae565b8015610b955780601f10610b6a57610100808354040283529160200191610b95565b820191906000526020600020905b815481529060010190602001808311610b7857829003601f168201915b505050505081565b6000610ba88161154c565b506011805460ff19169055565b60006001600160a01b038216610c1f5760405162461bcd60e51b815260206004820152602960248201527f4552433732313a2061646472657373207a65726f206973206e6f7420612076616044820152683634b21037bbb732b960b91b6064820152608401610817565b506001600160a01b031660009081526003602052604090205490565b7fd13d8e3c8822ff4d0a39994f3616e22d61c97585cee7a1baf4e9a875726b5f15610c658161154c565b610c6e83611234565b6000838152600c6020526040908190206001018390555183907f8bdaee675270281b7bc2d5b9ced20517ecf5ce96158973ef78072a7bc1491b4490610cb69085815260200190565b60405180910390a2505050565b60009182526008602090815260408084206001600160a01b0393909316845291905290205460ff1690565b6000610cf98161154c565b600a61079c8382612887565b6060600180546106de906127ae565b6000610d1f8161154c565b61082a826101f461165e565b81610d3581611296565b61079c838361175b565b7fd13d8e3c8822ff4d0a39994f3616e22d61c97585cee7a1baf4e9a875726b5f15610d698161154c565b610d7283611234565b6000838152600c6020526040908190206002018390555183907f334246ed50b046a9933ddd38bbb387c51e3709753687788af1c5207d3689761b90610cb69085815260200190565b836001600160a01b0381163314610dd457610dd433611296565b610de085858585611766565b5050505050565b6000610df28161154c565b506011805461ff001916610100179055565b6060610e0f82611234565b6009610e1a83611798565b604051602001610e2b929190612946565b6040516020818303038152906040529050919050565b60007ff0887ba65ee2024ea881d91b74c2450ef19e1557f03bed3ea9f16b037cbe2dc9610e6d8161154c565b8251845114610e9c578351835160405163990d9df760e01b815260048101929092526024820152604401610817565b60005b8451811015610f8757610ede858281518110610ebd57610ebd6129cd565b6020026020010151600b60008154610ed4906129e3565b918290555061182a565b6040518060800160405280858381518110610efb57610efb6129cd565b60200260200101516004811115610f1457610f14612721565b81526000602080830182905260408084018390526060909301829052600b548252600c90522081518154829060ff19166001836004811115610f5857610f58612721565b021790555060208201516001808301919091556040830151600283015560609092015160039091015501610e9f565b50601154610100900460ff161561106357600d54600e54600f5486516040516305d3b1d360e41b815260048101939093526001600160401b038216602484015261ffff600160401b830416604484015263ffffffff600160501b909204821660648401521660848201526000916001600160a01b031690635d3b1d309060a4016020604051808303816000875af1158015611026573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061104a91906129fc565b600b5460009182526010602052604090912055506110eb565b60005b84518110156110e957600081600b5461107f9190612a15565b9050600061108c8261111b565b6000838152600c6020526040908190206003018290555190915082907f14296754697e325872a9c14eb682f467bc46b15a78ae9420d7a13a7cd3833b2c906110d79084815260200190565b60405180910390a25050600101611066565b505b5050600b5492915050565b6000828152600860205260409020600101546111118161154c565b61079c83836115dc565b60408051426020808301919091523360601b6bffffffffffffffffffffffff191682840152605480830194909452825180830390940184526074909101909152815191012090565b61118f604080516080810190915280600081526020016000815260200160008152602001600081525090565b61119882611234565b6000828152600c6020526040908190208151608081019092528054829060ff1660048111156111c9576111c9612721565b60048111156111da576111da612721565b8152600182015460208201526002820154604082015260039091015460609091015292915050565b600a8054610b1c906127ae565b60006001600160e01b03198216637965db0b60e01b14806106c957506106c9826119b5565b6000818152600260205260409020546001600160a01b03166112935760405162461bcd60e51b8152602060048201526018602482015277115490cdcc8c4e881a5b9d985b1a59081d1bdad95b88125160421b6044820152606401610817565b50565b6daaeb6d7670e522a718067333cd4e3b1561129357604051633185c44d60e21b81523060048201526001600160a01b03821660248201526daaeb6d7670e522a718067333cd4e9063c617113490604401602060405180830381865afa158015611303573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113279190612a28565b61129357604051633b79c77360e21b81526001600160a01b0382166004820152602401610817565b600061135a826109e0565b9050806001600160a01b0316836001600160a01b0316036113c75760405162461bcd60e51b815260206004820152602160248201527f4552433732313a20617070726f76616c20746f2063757272656e74206f776e656044820152603960f91b6064820152608401610817565b336001600160a01b03821614806113e357506113e38133610660565b6114555760405162461bcd60e51b815260206004820152603d60248201527f4552433732313a20617070726f76652063616c6c6572206973206e6f7420746f60448201527f6b656e206f776e6572206f7220617070726f76656420666f7220616c6c0000006064820152608401610817565b61079c83836119da565b600082815260106020526040812054905b82518110156108535782818151811061148b5761148b6129cd565b6020026020010151600c600083856114a39190612a15565b81526020810191909152604001600020600301556114c18183612a15565b7f14296754697e325872a9c14eb682f467bc46b15a78ae9420d7a13a7cd3833b2c8483815181106114f4576114f46129cd565b602002602001015160405161150b91815260200190565b60405180910390a2600101611470565b6115253382611a48565b6115415760405162461bcd60e51b815260040161081790612a45565b61079c838383611ac7565b6112938133611c2b565b6115608282610cc3565b61082a5760008281526008602090815260408083206001600160a01b03851684529091529020805460ff191660011790556115983390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b6115e68282610cc3565b1561082a5760008281526008602090815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b61079c83838360405180602001604052806000815250610dba565b6127106001600160601b03821611156116cc5760405162461bcd60e51b815260206004820152602a60248201527f455243323938313a20726f79616c7479206665652077696c6c206578636565646044820152692073616c65507269636560b01b6064820152608401610817565b6001600160a01b0382166117225760405162461bcd60e51b815260206004820152601960248201527f455243323938313a20696e76616c6964207265636569766572000000000000006044820152606401610817565b604080518082019091526001600160a01b039092168083526001600160601b039091166020909201829052600160a01b90910217600655565b61082a338383611c84565b6117703383611a48565b61178c5760405162461bcd60e51b815260040161081790612a45565b61085384848484611d52565b606060006117a583611d85565b60010190506000816001600160401b038111156117c4576117c4612257565b6040519080825280601f01601f1916602001820160405280156117ee576020820181803683370190505b5090508181016020015b600019016f181899199a1a9b1b9c1cb0b131b232b360811b600a86061a8153600a85049450846117f857509392505050565b6001600160a01b0382166118805760405162461bcd60e51b815260206004820181905260248201527f4552433732313a206d696e7420746f20746865207a65726f20616464726573736044820152606401610817565b6000818152600260205260409020546001600160a01b0316156118e55760405162461bcd60e51b815260206004820152601c60248201527f4552433732313a20746f6b656e20616c7265616479206d696e746564000000006044820152606401610817565b6000818152600260205260409020546001600160a01b03161561194a5760405162461bcd60e51b815260206004820152601c60248201527f4552433732313a20746f6b656e20616c7265616479206d696e746564000000006044820152606401610817565b6001600160a01b038216600081815260036020908152604080832080546001019055848352600290915280822080546001600160a01b0319168417905551839291907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a45050565b60006001600160e01b0319821663152a902d60e11b14806106c957506106c982611e5d565b600081815260046020526040902080546001600160a01b0319166001600160a01b0384169081179091558190611a0f826109e0565b6001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45050565b600080611a54836109e0565b9050806001600160a01b0316846001600160a01b03161480611a9b57506001600160a01b0380821660009081526005602090815260408083209388168352929052205460ff165b80611abf5750836001600160a01b0316611ab484610761565b6001600160a01b0316145b949350505050565b826001600160a01b0316611ada826109e0565b6001600160a01b031614611b005760405162461bcd60e51b815260040161081790612a92565b6001600160a01b038216611b625760405162461bcd60e51b8152602060048201526024808201527f4552433732313a207472616e7366657220746f20746865207a65726f206164646044820152637265737360e01b6064820152608401610817565b826001600160a01b0316611b75826109e0565b6001600160a01b031614611b9b5760405162461bcd60e51b815260040161081790612a92565b600081815260046020908152604080832080546001600160a01b03199081169091556001600160a01b0387811680865260038552838620805460001901905590871680865283862080546001019055868652600290945282852080549092168417909155905184937fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4505050565b611c358282610cc3565b61082a57611c4281611ead565b611c4d836020611ebf565b604051602001611c5e929190612ad7565b60408051601f198184030181529082905262461bcd60e51b8252610817916004016121e5565b816001600160a01b0316836001600160a01b031603611ce55760405162461bcd60e51b815260206004820152601960248201527f4552433732313a20617070726f766520746f2063616c6c6572000000000000006044820152606401610817565b6001600160a01b03838116600081815260056020908152604080832094871680845294825291829020805460ff191686151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a3505050565b611d5d848484611ac7565b611d6984848484612061565b6108535760405162461bcd60e51b815260040161081790612b4c565b60008072184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b8310611dc45772184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b830492506040015b6d04ee2d6d415b85acef81000000008310611df0576d04ee2d6d415b85acef8100000000830492506020015b662386f26fc100008310611e0e57662386f26fc10000830492506010015b6305f5e1008310611e26576305f5e100830492506008015b6127108310611e3a57612710830492506004015b60648310611e4c576064830492506002015b600a83106106c95760010192915050565b60006001600160e01b031982166380ac58cd60e01b1480611e8e57506001600160e01b03198216635b5e139f60e01b145b806106c957506301ffc9a760e01b6001600160e01b03198316146106c9565b60606106c96001600160a01b03831660145b60606000611ece8360026127fe565b611ed9906002612b9e565b6001600160401b03811115611ef057611ef0612257565b6040519080825280601f01601f191660200182016040528015611f1a576020820181803683370190505b509050600360fc1b81600081518110611f3557611f356129cd565b60200101906001600160f81b031916908160001a905350600f60fb1b81600181518110611f6457611f646129cd565b60200101906001600160f81b031916908160001a9053506000611f888460026127fe565b611f93906001612b9e565b90505b600181111561200b576f181899199a1a9b1b9c1cb0b131b232b360811b85600f1660108110611fc757611fc76129cd565b1a60f81b828281518110611fdd57611fdd6129cd565b60200101906001600160f81b031916908160001a90535060049490941c9361200481612bb1565b9050611f96565b50831561205a5760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401610817565b9392505050565b60006001600160a01b0384163b1561215757604051630a85bd0160e11b81526001600160a01b0385169063150b7a02906120a5903390899088908890600401612bc8565b6020604051808303816000875af19250505080156120e0575060408051601f3d908101601f191682019092526120dd91810190612c05565b60015b61213d573d80801561210e576040519150601f19603f3d011682016040523d82523d6000602084013e612113565b606091505b5080516000036121355760405162461bcd60e51b815260040161081790612b4c565b805181602001fd5b6001600160e01b031916630a85bd0160e11b149050611abf565b506001949350505050565b6001600160e01b03198116811461129357600080fd5b60006020828403121561218a57600080fd5b813561205a81612162565b60005b838110156121b0578181015183820152602001612198565b50506000910152565b600081518084526121d1816020860160208601612195565b601f01601f19169290920160200192915050565b60208152600061205a60208301846121b9565b60006020828403121561220a57600080fd5b5035919050565b80356001600160a01b038116811461222857600080fd5b919050565b6000806040838503121561224057600080fd5b61224983612211565b946020939093013593505050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b038111828210171561229557612295612257565b604052919050565b60006001600160401b038211156122b6576122b6612257565b5060051b60200190565b600080604083850312156122d357600080fd5b823591506020808401356001600160401b038111156122f157600080fd5b8401601f8101861361230257600080fd5b80356123156123108261229d565b61226d565b81815260059190911b8201830190838101908883111561233457600080fd5b928401925b8284101561235257833582529284019290840190612339565b80955050505050509250929050565b60008060006060848603121561237657600080fd5b61237f84612211565b925061238d60208501612211565b9150604084013590509250925092565b600080604083850312156123b057600080fd5b50508035926020909101359150565b600080604083850312156123d257600080fd5b823591506123e260208401612211565b90509250929050565b60006001600160401b0383111561240457612404612257565b612417601f8401601f191660200161226d565b905082815283838301111561242b57600080fd5b828260208301376000602084830101529392505050565b60006020828403121561245457600080fd5b81356001600160401b0381111561246a57600080fd5b8201601f8101841361247b57600080fd5b611abf848235602084016123eb565b600080600080600060a086880312156124a257600080fd5b6124ab86612211565b94506020860135935060408601356001600160401b03811681146124ce57600080fd5b9250606086013561ffff811681146124e557600080fd5b9150608086013563ffffffff811681146124fe57600080fd5b809150509295509295909350565b60006020828403121561251e57600080fd5b61205a82612211565b801515811461129357600080fd5b6000806040838503121561254857600080fd5b61255183612211565b9150602083013561256181612527565b809150509250929050565b6000806000806080858703121561258257600080fd5b61258b85612211565b935061259960208601612211565b92506040850135915060608501356001600160401b038111156125bb57600080fd5b8501601f810187136125cc57600080fd5b6125db878235602084016123eb565b91505092959194509250565b600082601f8301126125f857600080fd5b813560206126086123108361229d565b80838252602082019150600560208560051b88010194508785111561262c57600080fd5b602087015b858110156126555780358281106126485760008081fd5b8452928401928401612631565b5090979650505050505050565b6000806040838503121561267557600080fd5b82356001600160401b038082111561268c57600080fd5b818501915085601f8301126126a057600080fd5b813560206126b06123108361229d565b82815260059290921b840181019181810190898411156126cf57600080fd5b948201945b838610156126f4576126e586612211565b825294820194908201906126d4565b9650508601359250508082111561270a57600080fd5b50612717858286016125e7565b9150509250929050565b634e487b7160e01b600052602160045260246000fd5b815160808201906005811061275c57634e487b7160e01b600052602160045260246000fd5b8083525060208301516020830152604083015160408301526060830151606083015292915050565b6000806040838503121561279757600080fd5b6127a083612211565b91506123e260208401612211565b600181811c908216806127c257607f821691505b6020821081036127e257634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052601160045260246000fd5b80820281158282048414176106c9576106c96127e8565b60008261283257634e487b7160e01b600052601260045260246000fd5b500490565b601f82111561079c576000816000526020600020601f850160051c810160208610156128605750805b601f850160051c820191505b8181101561287f5782815560010161286c565b505050505050565b81516001600160401b038111156128a0576128a0612257565b6128b4816128ae84546127ae565b84612837565b602080601f8311600181146128e957600084156128d15750858301515b600019600386901b1c1916600185901b17855561287f565b600085815260208120601f198616915b82811015612918578886015182559484019460019091019084016128f9565b50858210156129365787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6000808454612954816127ae565b6001828116801561296c5760018114612981576129b0565b60ff19841687528215158302870194506129b0565b8860005260208060002060005b858110156129a75781548a82015290840190820161298e565b50505082870194505b5050505083516129c4818360208801612195565b01949350505050565b634e487b7160e01b600052603260045260246000fd5b6000600182016129f5576129f56127e8565b5060010190565b600060208284031215612a0e57600080fd5b5051919050565b818103818111156106c9576106c96127e8565b600060208284031215612a3a57600080fd5b815161205a81612527565b6020808252602d908201527f4552433732313a2063616c6c6572206973206e6f7420746f6b656e206f776e6560408201526c1c881bdc88185c1c1c9bdd9959609a1b606082015260800190565b60208082526025908201527f4552433732313a207472616e736665722066726f6d20696e636f72726563742060408201526437bbb732b960d91b606082015260800190565b7f416363657373436f6e74726f6c3a206163636f756e7420000000000000000000815260008351612b0f816017850160208801612195565b7001034b99036b4b9b9b4b733903937b6329607d1b6017918401918201528351612b40816028840160208801612195565b01602801949350505050565b60208082526032908201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560408201527131b2b4bb32b91034b6b83632b6b2b73a32b960711b606082015260800190565b808201808211156106c9576106c96127e8565b600081612bc057612bc06127e8565b506000190190565b6001600160a01b0385811682528416602082015260408101839052608060608201819052600090612bfb908301846121b9565b9695505050505050565b600060208284031215612c1757600080fd5b815161205a8161216256 diff --git a/bytecode/stickers/IStickers.bin b/bytecode/stickers/IStickers.bin deleted file mode 100644 index ec687260..00000000 --- a/bytecode/stickers/IStickers.bin +++ /dev/null @@ -1 +0,0 @@ -0x diff --git a/bytecode/stickers/IStickersController.bin b/bytecode/stickers/IStickersController.bin deleted file mode 100644 index ec687260..00000000 --- a/bytecode/stickers/IStickersController.bin +++ /dev/null @@ -1 +0,0 @@ -0x diff --git a/bytecode/stickers/Stickers.bin b/bytecode/stickers/Stickers.bin index 17c04326..e3b8513f 100644 --- a/bytecode/stickers/Stickers.bin +++ b/bytecode/stickers/Stickers.bin @@ -1 +1 @@ -0x60a06040523480156200001157600080fd5b506040516200310738038062003107833981016040819052620000349162000559565b826040518060400160405280600e81526020016d506f6f6b7920537469636b65727360901b8152506040518060400160405280600381526020016253544b60e81b815250604051806060016040528060238152602001620030b360239139604051806060016040528060318152602001620030d6603191398551869088906101f490733cc6cdda760b79bafa08df41ecfa224f810dceb6600189896002620000dd8382620006bf565b506003620000ec8282620006bf565b50600160005550506daaeb6d7670e522a718067333cd4e3b15620002395780156200018757604051633e9f1edf60e11b81523060048201526001600160a01b03831660248201526daaeb6d7670e522a718067333cd4e90637d3e3dbe906044015b600060405180830381600087803b1580156200016857600080fd5b505af11580156200017d573d6000803e3d6000fd5b5050505062000239565b6001600160a01b03821615620001d85760405163a0af290360e01b81523060048201526001600160a01b03831660248201526daaeb6d7670e522a718067333cd4e9063a0af2903906044016200014d565b604051632210724360e11b81523060048201526daaeb6d7670e522a718067333cd4e90634420e48690602401600060405180830381600087803b1580156200021f57600080fd5b505af115801562000234573d6000803e3d6000fd5b505050505b50506001600160a01b03166080526200025288620003a4565b600a620002608682620006bf565b50600b805462000270906200062e565b80601f01602080910402602001604051908101604052809291908181526020018280546200029e906200062e565b8015620002ef5780601f10620002c357610100808354040283529160200191620002ef565b820191906000526020600020905b815481529060010190602001808311620002d157829003601f168201915b50508651600c80546001600160a01b039092166001600160a01b03199092169190911790555050506020840151600d556040840151600e80546060870151608088015163ffffffff166a01000000000000000000000263ffffffff60501b1961ffff90921668010000000000000000026001600160501b03199093166001600160401b039095169490941791909117169190911790559350620003938282620003e0565b50505050505050505050506200078b565b6001600160a01b0316638b78c6d8198190558060007f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08180a350565b6127106001600160601b0382161115620004545760405162461bcd60e51b815260206004820152602a60248201527f455243323938313a20726f79616c7479206665652077696c6c206578636565646044820152692073616c65507269636560b01b60648201526084015b60405180910390fd5b6001600160a01b038216620004ac5760405162461bcd60e51b815260206004820152601960248201527f455243323938313a20696e76616c69642072656365697665720000000000000060448201526064016200044b565b604080518082019091526001600160a01b039092168083526001600160601b039091166020909201829052600160a01b90910217600855565b6001600160a01b0381168114620004fb57600080fd5b50565b634e487b7160e01b600052604160045260246000fd5b80516001600160401b03811681146200052c57600080fd5b919050565b805161ffff811681146200052c57600080fd5b805163ffffffff811681146200052c57600080fd5b600080600083850360e08112156200057057600080fd5b84516200057d81620004e5565b60208601519094506200059081620004e5565b925060a0603f1982011215620005a557600080fd5b5060405160a081016001600160401b0381118282101715620005cb57620005cb620004fe565b6040908152850151620005de81620004e5565b815260608501516020820152620005f86080860162000514565b60408201526200060b60a0860162000531565b60608201526200061e60c0860162000544565b6080820152809150509250925092565b600181811c908216806200064357607f821691505b6020821081036200066457634e487b7160e01b600052602260045260246000fd5b50919050565b601f821115620006ba576000816000526020600020601f850160051c81016020861015620006955750805b601f850160051c820191505b81811015620006b657828155600101620006a1565b5050505b505050565b81516001600160401b03811115620006db57620006db620004fe565b620006f381620006ec84546200062e565b846200066a565b602080601f8311600181146200072b5760008415620007125750858301515b600019600386901b1c1916600185901b178555620006b6565b600085815260208120601f198616915b828110156200075c578886015182559484019460019091019084016200073b565b50858210156200077b5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b608051612905620007ae60003960008181610a9d0152610adf01526129056000f3fe6080604052600436106102ae5760003560e01c806355f804b311610175578063a22cb465116100dc578063e8a3d48511610095578063f0503e801161006f578063f0503e80146108de578063f2fde38b1461090b578063fe6d81241461091e578063fee81cf41461093357600080fd5b8063e8a3d4851461086d578063e985e9c514610882578063f04e283e146108cb57600080fd5b8063a22cb465146107a0578063b88d4fde146107c0578063c23dc68f146107d3578063c87b56dd14610800578063d01fa1f914610820578063e3684e391461084057600080fd5b806375794a3c1161012e57806375794a3c146106f05780638462151c146107055780638da5cb5b14610732578063938e3d7b1461074b57806395d89b411461076b57806399a2557a1461078057600080fd5b806355f804b3146106465780635bbb2177146106665780636352211e146106935780636c0360eb146106b357806370a08231146106c8578063715018a6146106e857600080fd5b806323b872dd1161021957806341f43434116101d257806341f434341461059f57806342842e0e146105c157806342966c68146105d45780634a4ee7b1146105f4578063514e62fc1461060757806354d1f13d1461063e57600080fd5b806323b872dd146104dd57806325692962146104f057806327730d12146104f85780632a55205a1461050d5780632de948071461054c57806331660fc51461057f57600080fd5b806318160ddd1161026b57806318160ddd1461040c578063183a4f6e146104335780631a1d9252146104465780631c10893f146104735780631cd64df4146104865780631fe543e3146104bd57600080fd5b806301ffc9a7146102b357806304634d8d146102e857806306fdde031461030a578063081812fc1461032c578063095ea7b3146103645780630c94904314610377575b600080fd5b3480156102bf57600080fd5b506102d36102ce366004611f9d565b610966565b60405190151581526020015b60405180910390f35b3480156102f457600080fd5b50610308610303366004611fd1565b610977565b005b34801561031657600080fd5b5061031f61098d565b6040516102df9190612064565b34801561033857600080fd5b5061034c610347366004612077565b610a1f565b6040516001600160a01b0390911681526020016102df565b610308610372366004612090565b610a5a565b34801561038357600080fd5b50600c54600d54600e546103c3926001600160a01b031691906001600160401b03811690600160401b810461ffff1690600160501b900463ffffffff1685565b604080516001600160a01b03909616865260208601949094526001600160401b039092169284019290925261ffff909116606083015263ffffffff16608082015260a0016102df565b34801561041857600080fd5b5060015460005403600019015b6040519081526020016102df565b610308610441366004612077565b610a73565b34801561045257600080fd5b50610425610461366004612077565b600f6020526000908152604090205481565b610308610481366004612090565b610a80565b34801561049257600080fd5b506102d36104a1366004612090565b638b78c6d8600c90815260009290925260209091205481161490565b3480156104c957600080fd5b506103086104d8366004612123565b610a92565b6103086104eb3660046121c4565b610b1b565b610308610b46565b34801561050457600080fd5b50610425600281565b34801561051957600080fd5b5061052d610528366004612200565b610b95565b604080516001600160a01b0390931683526020830191909152016102df565b34801561055857600080fd5b50610425610567366004612222565b638b78c6d8600c908152600091909152602090205490565b34801561058b57600080fd5b5061030861059a36600461223d565b610c41565b3480156105ab57600080fd5b5061034c6daaeb6d7670e522a718067333cd4e81565b6103086105cf3660046121c4565b610cdc565b3480156105e057600080fd5b506103086105ef366004612077565b610d01565b610308610602366004612090565b610d0c565b34801561061357600080fd5b506102d3610622366004612090565b638b78c6d8600c90815260009290925260209091205416151590565b610308610d1e565b34801561065257600080fd5b506103086106613660046122c5565b610d5a565b34801561067257600080fd5b5061068661068136600461230d565b610d6e565b6040516102df91906123bd565b34801561069f57600080fd5b5061034c6106ae366004612077565b610dba565b3480156106bf57600080fd5b5061031f610dc5565b3480156106d457600080fd5b506104256106e3366004612222565b610e53565b610308610e98565b3480156106fc57600080fd5b50600054610425565b34801561071157600080fd5b50610725610720366004612222565b610eac565b6040516102df91906123ff565b34801561073e57600080fd5b50638b78c6d8195461034c565b34801561075757600080fd5b506103086107663660046122c5565b610ed3565b34801561077757600080fd5b5061031f610ee7565b34801561078c57600080fd5b5061072561079b366004612437565b610ef6565b3480156107ac57600080fd5b506103086107bb366004612478565b610f03565b6103086107ce3660046124a4565b610f17565b3480156107df57600080fd5b506107f36107ee366004612077565b610f44565b6040516102df919061251f565b34801561080c57600080fd5b5061031f61081b366004612077565b610fa8565b34801561082c57600080fd5b5061030861083b36600461252d565b611023565b34801561084c57600080fd5b5061086061085b366004612077565b611103565b6040516102df91906125f4565b34801561087957600080fd5b5061031f6111a6565b34801561088e57600080fd5b506102d361089d366004612636565b6001600160a01b03918216600090815260076020908152604080832093909416825291909152205460ff1690565b6103086108d9366004612222565b6111b3565b3480156108ea57600080fd5b506104256108f9366004612077565b60106020526000908152604090205481565b610308610919366004612222565b6111f0565b34801561092a57600080fd5b50610425600181565b34801561093f57600080fd5b5061042561094e366004612222565b63389a75e1600c908152600091909152602090205490565b600061097182611217565b92915050565b61097f611231565b610989828261124c565b5050565b60606002805461099c90612669565b80601f01602080910402602001604051908101604052809291908181526020018280546109c890612669565b8015610a155780601f106109ea57610100808354040283529160200191610a15565b820191906000526020600020905b8154815290600101906020018083116109f857829003601f168201915b5050505050905090565b6000610a2a82611349565b610a3e57610a3e6333d1c03960e21b611395565b506000908152600660205260409020546001600160a01b031690565b81610a648161139f565b610a6e8383611458565b505050565b610a7d3382611464565b50565b610a88611231565b6109898282611470565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610b115760405163073e64fd60e21b81523360048201526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001660248201526044015b60405180910390fd5b610989828261147c565b826001600160a01b0381163314610b3557610b353361139f565b610b40848484611535565b50505050565b60006202a3006001600160401b03164201905063389a75e1600c5233600052806020600c2055337fdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d600080a250565b60008281526009602090815260408083208151808301909252546001600160a01b038116808352600160a01b9091046001600160601b0316928201929092528291610c0a5750604080518082019091526008546001600160a01b0381168252600160a01b90046001600160601b031660208201525b602081015160009061271090610c29906001600160601b0316876126b3565b610c3391906126ca565b915196919550909350505050565b81610c4b81611349565b610c6b576040516338077a2b60e01b815260048101829052602401610b08565b6002610c76816116a4565b60008481526011602090815260409182902080546001600160f81b0319166001600160f81b038716908117909155915191825285917f8bdaee675270281b7bc2d5b9ced20517ecf5ce96158973ef78072a7bc1491b44910160405180910390a250505050565b826001600160a01b0381163314610cf657610cf63361139f565b610b408484846116d7565b610a7d8160016116f2565b610d14611231565b6109898282611464565b63389a75e1600c523360005260006020600c2055337ffa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92600080a2565b610d62611231565b600a6109898282612734565b60408051828152600583901b8082016020019092526060915b8015610db257601f1980820191860101356000610da382610f44565b8484016020015250610d879050565b509392505050565b600061097182611833565b600a8054610dd290612669565b80601f0160208091040260200160405190810160405280929190818152602001828054610dfe90612669565b8015610e4b5780601f10610e2057610100808354040283529160200191610e4b565b820191906000526020600020905b815481529060010190602001808311610e2e57829003601f168201915b505050505081565b60006001600160a01b038216610e7357610e736323d3ad8160e21b611395565b506001600160a01b03166000908152600560205260409020546001600160401b031690565b610ea0611231565b610eaa60006118d4565b565b60005460609060019082828214610ecb57610ec8858484611912565b90505b949350505050565b610edb611231565b600b6109898282612734565b60606003805461099c90612669565b6060610ecb848484611912565b81610f0d8161139f565b610a6e8383611a11565b836001600160a01b0381163314610f3157610f313361139f565b610f3d85858585611a7d565b5050505050565b60408051608081018252600080825260208201819052918101829052606081019190915260018210610fa357600054821015610fa3575b600082815260046020526040902054610f9a5760001990910190610f7b565b61097182611ab8565b919050565b6060610fb382611349565b610fc757610fc7630a14c4b560e41b611395565b6000610fd1611b36565b90508051600003610ff1576040518060200160405280600081525061101c565b80610ffb84611b45565b60405160200161100c9291906127f3565b6040516020818303038152906040525b9392505050565b600161102e816116a4565b815160005461103d8583611b89565b60005b828110156110fb57604051806040016040528060006001600160f81b0316815260200186838151811061107557611075612822565b6020026020010151600481111561108e5761108e6125de565b90526011600061109e8486612838565b8152602080820192909252604001600020825181546001600160f81b0319166001600160f81b0390911690811782559183015190918290600160f81b8360048111156110ec576110ec6125de565b02179055505050600101611040565b505050505050565b60408051808201909152600080825260208201528161112181611349565b611141576040516338077a2b60e01b815260048101829052602401610b08565b600083815260116020908152604091829020825180840190935280546001600160f81b03811684529091830190600160f81b900460ff166004811115611189576111896125de565b600481111561119a5761119a6125de565b90525091505b50919050565b600b8054610dd290612669565b6111bb611231565b63389a75e1600c52806000526020600c2080544211156111e357636f5e88186000526004601cfd5b60009055610a7d816118d4565b6111f8611231565b8060601b61120e57637448fbae6000526004601cfd5b610a7d816118d4565b600061122282611c67565b80610971575061097182611c9c565b638b78c6d819543314610eaa576382b429006000526004601cfd5b6127106001600160601b03821611156112ba5760405162461bcd60e51b815260206004820152602a60248201527f455243323938313a20726f79616c7479206665652077696c6c206578636565646044820152692073616c65507269636560b01b6064820152608401610b08565b6001600160a01b0382166113105760405162461bcd60e51b815260206004820152601960248201527f455243323938313a20696e76616c6964207265636569766572000000000000006044820152606401610b08565b604080518082019091526001600160a01b039092168083526001600160601b039091166020909201829052600160a01b90910217600855565b600081600111610fa357600054821015610fa35760005b5060008281526004602052604081205490819003611388576113818361284b565b9250611360565b600160e01b161592915050565b8060005260046000fd5b6daaeb6d7670e522a718067333cd4e3b15610a7d57604051633185c44d60e21b81523060048201526001600160a01b03821660248201526daaeb6d7670e522a718067333cd4e9063c617113490604401602060405180830381865afa15801561140c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114309190612862565b610a7d57604051633b79c77360e21b81526001600160a01b0382166004820152602401610b08565b61098982826001611cea565b61098982826000611d8d565b61098982826001611d8d565b6000828152600f6020526040812054905b8251811015610b40578281815181106114a8576114a8612822565b60200260200101516010600083856114c0919061287f565b81526020810191909152604001600020556114db818361287f565b7f14296754697e325872a9c14eb682f467bc46b15a78ae9420d7a13a7cd3833b2c84838151811061150e5761150e612822565b602002602001015160405161152591815260200190565b60405180910390a260010161148d565b600061154082611833565b6001600160a01b0394851694909150811684146115665761156662a1148160e81b611395565b600082815260066020526040902080546115928187335b6001600160a01b039081169116811491141790565b6115b4576115a0863361089d565b6115b4576115b4632ce44b5f60e11b611395565b80156115bf57600082555b6001600160a01b038681166000908152600560205260408082208054600019019055918716808252919020805460010190554260a01b17600160e11b17600085815260046020526040812091909155600160e11b841690036116515760018401600081815260046020526040812054900361164f57600054811461164f5760008181526004602052604090208490555b505b6001600160a01b0385168481887fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef600080a48060000361169b5761169b633a954ecd60e21b611395565b50505050505050565b638b78c6d8600c5233600052806020600c205416610a7d57638b78c6d819543314610a7d576382b429006000526004601cfd5b610a6e83838360405180602001604052806000815250610f17565b60006116fd83611833565b90508060008061171b86600090815260066020526040902080549091565b9150915084156117525761173081843361157d565b6117525761173e833361089d565b61175257611752632ce44b5f60e11b611395565b801561175d57600082555b6001600160a01b038316600081815260056020526040902080546fffffffffffffffffffffffffffffffff0190554260a01b17600360e01b17600087815260046020526040812091909155600160e11b851690036117eb576001860160008181526004602052604081205490036117e95760005481146117e95760008181526004602052604090208590555b505b60405186906000906001600160a01b038616907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908390a45050600180548101905550505050565b6000816001116118c45750600081815260046020526040812054908190036118b157600054821061186e5761186e636f96cda160e11b611395565b5b5060001901600081815260046020526040902054801561186f57600160e01b811660000361189c57919050565b6118ac636f96cda160e11b611395565b61186f565b600160e01b81166000036118c457919050565b610fa3636f96cda160e11b611395565b638b78c6d81980546001600160a01b039092169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a355565b606081831061192b5761192b631960ccad60e11b611395565b600183101561193957600192505b600054808310611947578092505b6060600061195487610e53565b85871090810291508115611a055781878703116119715786860391505b60405192506001820160051b8301604052600061198d88610f44565b90506000816040015161199e575080515b60005b6119aa8a611ab8565b92506040830151600081146119c257600092506119e7565b8351156119ce57835192505b8b831860601b6119e7576001820191508a8260051b8801525b5060018a019950888a14806119fb57508481145b156119a157855250505b50909695505050505050565b3360008181526007602090815260408083206001600160a01b03871680855290835292819020805460ff191686151590811790915590519081529192917f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a35050565b611a88848484610b1b565b6001600160a01b0383163b15610b4057611aa484848484611de6565b610b4057610b406368d2bf6b60e11b611395565b60408051608081018252600080825260208201819052918101829052606081019190915260008281526004602052604090205461097190604080516080810182526001600160a01b038316815260a083901c6001600160401b03166020820152600160e01b831615159181019190915260e89190911c606082015290565b6060600a805461099c90612669565b606060a06040510180604052602081039150506000815280825b600183039250600a81066030018353600a900480611b5f5750819003601f19909101908152919050565b611b938282611ec8565b600c54600d54600e546040516305d3b1d360e41b815260048101929092526001600160401b0381166024830152600160401b810461ffff166044830152600160501b900463ffffffff9081166064830152831660848201526000916001600160a01b031690635d3b1d309060a4016020604051808303816000875af1158015611c20573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c449190612892565b9050611c536000546000190190565b6000918252600f6020526040909120555050565b60006001600160e01b0319821663152a902d60e11b148061097157506301ffc9a760e01b6001600160e01b0319831614610971565b60006301ffc9a760e01b6001600160e01b031983161480611ccd57506380ac58cd60e01b6001600160e01b03198316145b806109715750506001600160e01b031916635b5e139f60e01b1490565b6000611cf583610dba565b9050818015611d0d5750336001600160a01b03821614155b15611d3057611d1c813361089d565b611d3057611d306367d9dca160e11b611395565b60008381526006602052604080822080546001600160a01b0319166001600160a01b0388811691821790925591518693918516917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591a450505050565b638b78c6d8600c52826000526020600c20805483811783611daf575080841681185b80835580600c5160601c7f715ad5ce61fc9595c7b415289d59cf203f23a94fa06f04af7e489a0a76e1fe26600080a3505050505050565b604051630a85bd0160e11b81526000906001600160a01b0385169063150b7a0290611e1b9033908990889088906004016128ab565b6020604051808303816000875af1925050508015611e56575060408051601f3d908101601f19168201909252611e53918101906128e8565b60015b611eab573d808015611e84576040519150601f19603f3d011682016040523d82523d6000602084013e611e89565b606091505b508051600003611ea357611ea36368d2bf6b60e11b611395565b805181602001fd5b6001600160e01b031916630a85bd0160e11b149050949350505050565b6000805490829003611ee457611ee463b562e8dd60e01b611395565b60008181526004602090815260408083206001600160a01b0387164260a01b6001881460e11b17811790915580845260059092528220805468010000000000000001860201905590819003611f4257611f42622e076360e81b611395565b818301825b808360007fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef600080a4818160010191508103611f47575060005550505050565b6001600160e01b031981168114610a7d57600080fd5b600060208284031215611faf57600080fd5b813561101c81611f87565b80356001600160a01b0381168114610fa357600080fd5b60008060408385031215611fe457600080fd5b611fed83611fba565b915060208301356001600160601b038116811461200957600080fd5b809150509250929050565b60005b8381101561202f578181015183820152602001612017565b50506000910152565b60008151808452612050816020860160208601612014565b601f01601f19169290920160200192915050565b60208152600061101c6020830184612038565b60006020828403121561208957600080fd5b5035919050565b600080604083850312156120a357600080fd5b6120ac83611fba565b946020939093013593505050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b03811182821017156120f8576120f86120ba565b604052919050565b60006001600160401b03821115612119576121196120ba565b5060051b60200190565b6000806040838503121561213657600080fd5b823591506020808401356001600160401b0381111561215457600080fd5b8401601f8101861361216557600080fd5b803561217861217382612100565b6120d0565b81815260059190911b8201830190838101908883111561219757600080fd5b928401925b828410156121b55783358252928401929084019061219c565b80955050505050509250929050565b6000806000606084860312156121d957600080fd5b6121e284611fba565b92506121f060208501611fba565b9150604084013590509250925092565b6000806040838503121561221357600080fd5b50508035926020909101359150565b60006020828403121561223457600080fd5b61101c82611fba565b6000806040838503121561225057600080fd5b8235915060208301356001600160f81b038116811461200957600080fd5b60006001600160401b03831115612287576122876120ba565b61229a601f8401601f19166020016120d0565b90508281528383830111156122ae57600080fd5b828260208301376000602084830101529392505050565b6000602082840312156122d757600080fd5b81356001600160401b038111156122ed57600080fd5b8201601f810184136122fe57600080fd5b610ecb8482356020840161226e565b6000806020838503121561232057600080fd5b82356001600160401b038082111561233757600080fd5b818501915085601f83011261234b57600080fd5b81358181111561235a57600080fd5b8660208260051b850101111561236f57600080fd5b60209290920196919550909350505050565b80516001600160a01b031682526020808201516001600160401b03169083015260408082015115159083015260609081015162ffffff16910152565b6020808252825182820181905260009190848201906040850190845b81811015611a05576123ec838551612381565b92840192608092909201916001016123d9565b6020808252825182820181905260009190848201906040850190845b81811015611a055783518352928401929184019160010161241b565b60008060006060848603121561244c57600080fd5b61245584611fba565b95602085013595506040909401359392505050565b8015158114610a7d57600080fd5b6000806040838503121561248b57600080fd5b61249483611fba565b915060208301356120098161246a565b600080600080608085870312156124ba57600080fd5b6124c385611fba565b93506124d160208601611fba565b92506040850135915060608501356001600160401b038111156124f357600080fd5b8501601f8101871361250457600080fd5b6125138782356020840161226e565b91505092959194509250565b608081016109718284612381565b6000806040838503121561254057600080fd5b61254983611fba565b91506020808401356001600160401b0381111561256557600080fd5b8401601f8101861361257657600080fd5b803561258461217382612100565b818152600591821b83018401918482019190898411156125a357600080fd5b938501935b838510156125ce5784358181106125bf5760008081fd5b835293850193918501916125a8565b5080955050505050509250929050565b634e487b7160e01b600052602160045260246000fd5b81516001600160f81b03168152602082015160408201906005811061262957634e487b7160e01b600052602160045260246000fd5b8060208401525092915050565b6000806040838503121561264957600080fd5b61265283611fba565b915061266060208401611fba565b90509250929050565b600181811c9082168061267d57607f821691505b6020821081036111a057634e487b7160e01b600052602260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b80820281158282048414176109715761097161269d565b6000826126e757634e487b7160e01b600052601260045260246000fd5b500490565b601f821115610a6e576000816000526020600020601f850160051c810160208610156127155750805b601f850160051c820191505b818110156110fb57828155600101612721565b81516001600160401b0381111561274d5761274d6120ba565b6127618161275b8454612669565b846126ec565b602080601f831160018114612796576000841561277e5750858301515b600019600386901b1c1916600185901b1785556110fb565b600085815260208120601f198616915b828110156127c5578886015182559484019460019091019084016127a6565b50858210156127e35787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b60008351612805818460208801612014565b835190830190612819818360208801612014565b01949350505050565b634e487b7160e01b600052603260045260246000fd5b808201808211156109715761097161269d565b60008161285a5761285a61269d565b506000190190565b60006020828403121561287457600080fd5b815161101c8161246a565b818103818111156109715761097161269d565b6000602082840312156128a457600080fd5b5051919050565b6001600160a01b03858116825284166020820152604081018390526080606082018190526000906128de90830184612038565b9695505050505050565b6000602082840312156128fa57600080fd5b815161101c81611f875668747470733a2f2f6d657461646174612e706f6f6b792e67672f737469636b6572732f68747470733a2f2f6d657461646174612e706f6f6b792e67672f636f6e7472616374732f537469636b6572732e6a736f6e +0x60a06040526010805461ffff191660011790553480156200001f57600080fd5b50604051620034d7380380620034d7833981016040819052620000429162000567565b826040518060400160405280600e81526020016d506f6f6b7920537469636b65727360901b8152506040518060400160405280600381526020016253544b60e81b8152506040518060600160405280602381526020016200348360239139604051806060016040528060318152602001620034a6603191398551869088906101f490733cc6cdda760b79bafa08df41ecfa224f810dceb6600189896002620000eb8382620006cd565b506003620000fa8282620006cd565b50600160005550506daaeb6d7670e522a718067333cd4e3b15620002475780156200019557604051633e9f1edf60e11b81523060048201526001600160a01b03831660248201526daaeb6d7670e522a718067333cd4e90637d3e3dbe906044015b600060405180830381600087803b1580156200017657600080fd5b505af11580156200018b573d6000803e3d6000fd5b5050505062000247565b6001600160a01b03821615620001e65760405163a0af290360e01b81523060048201526001600160a01b03831660248201526daaeb6d7670e522a718067333cd4e9063a0af2903906044016200015b565b604051632210724360e11b81523060048201526daaeb6d7670e522a718067333cd4e90634420e48690602401600060405180830381600087803b1580156200022d57600080fd5b505af115801562000242573d6000803e3d6000fd5b505050505b50506001600160a01b03166080526200026088620003b2565b600a6200026e8682620006cd565b50600b80546200027e906200063c565b80601f0160208091040260200160405190810160405280929190818152602001828054620002ac906200063c565b8015620002fd5780601f10620002d157610100808354040283529160200191620002fd565b820191906000526020600020905b815481529060010190602001808311620002df57829003601f168201915b50508651600c80546001600160a01b039092166001600160a01b03199092169190911790555050506020840151600d556040840151600e80546060870151608088015163ffffffff166a01000000000000000000000263ffffffff60501b1961ffff90921668010000000000000000026001600160501b03199093166001600160401b039095169490941791909117169190911790559350620003a18282620003ee565b505050505050505050505062000799565b6001600160a01b0316638b78c6d8198190558060007f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08180a350565b6127106001600160601b0382161115620004625760405162461bcd60e51b815260206004820152602a60248201527f455243323938313a20726f79616c7479206665652077696c6c206578636565646044820152692073616c65507269636560b01b60648201526084015b60405180910390fd5b6001600160a01b038216620004ba5760405162461bcd60e51b815260206004820152601960248201527f455243323938313a20696e76616c696420726563656976657200000000000000604482015260640162000459565b604080518082019091526001600160a01b039092168083526001600160601b039091166020909201829052600160a01b90910217600855565b6001600160a01b03811681146200050957600080fd5b50565b634e487b7160e01b600052604160045260246000fd5b80516001600160401b03811681146200053a57600080fd5b919050565b805161ffff811681146200053a57600080fd5b805163ffffffff811681146200053a57600080fd5b600080600083850360e08112156200057e57600080fd5b84516200058b81620004f3565b60208601519094506200059e81620004f3565b925060a0603f1982011215620005b357600080fd5b5060405160a081016001600160401b0381118282101715620005d957620005d96200050c565b6040908152850151620005ec81620004f3565b815260608501516020820152620006066080860162000522565b60408201526200061960a086016200053f565b60608201526200062c60c0860162000552565b6080820152809150509250925092565b600181811c908216806200065157607f821691505b6020821081036200067257634e487b7160e01b600052602260045260246000fd5b50919050565b601f821115620006c8576000816000526020600020601f850160051c81016020861015620006a35750805b601f850160051c820191505b81811015620006c457828155600101620006af565b5050505b505050565b81516001600160401b03811115620006e957620006e96200050c565b6200070181620006fa84546200063c565b8462000678565b602080601f831160018114620007395760008415620007205750858301515b600019600386901b1c1916600185901b178555620006c4565b600085815260208120601f198616915b828110156200076a5788860151825594840194600190910190840162000749565b5085821015620007895787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b608051612cc7620007bc60003960008181610be20152610c240152612cc76000f3fe6080604052600436106103505760003560e01c80636352211e116101c6578063b88d4fde116100f7578063e8a3d48511610095578063f0503e801161006f578063f0503e8014610a23578063f2fde38b14610a50578063fe6d812414610a63578063fee81cf414610a7857600080fd5b8063e8a3d485146109b2578063e985e9c5146109c7578063f04e283e14610a1057600080fd5b8063c87b56dd116100d1578063c87b56dd14610925578063d01fa1f914610945578063d54bcf9c14610965578063e3684e391461098557600080fd5b8063b88d4fde146108d0578063b9881734146108e3578063c23dc68f146108f857600080fd5b80638462151c1161016457806395d89b411161013e57806395d89b4114610861578063960783071461087657806399a2557a14610890578063a22cb465146108b057600080fd5b80638462151c146107fb5780638da5cb5b14610828578063938e3d7b1461084157600080fd5b80636d2ebc5c116101a05780636d2ebc5c146107a957806370a08231146107be578063715018a6146107de57806375794a3c146107e657600080fd5b80636352211e146107545780636a2d8362146107745780636c0360eb1461079457600080fd5b806325692962116102a057806342966c681161023e578063514e62fc11610218578063514e62fc146106c857806354d1f13d146106ff57806355f804b3146107075780635bbb21771461072757600080fd5b806342966c681461067657806346e5350c146106965780634a4ee7b1146106b557600080fd5b80632de948071161027a5780632de94807146105ee57806331660fc51461062157806341f434341461064157806342842e0e1461066357600080fd5b8063256929621461059257806327730d121461059a5780632a55205a146105af57600080fd5b806318160ddd1161030d5780631c10893f116102e75780631c10893f146105155780631cd64df4146105285780631fe543e31461055f57806323b872dd1461057f57600080fd5b806318160ddd146104ae578063183a4f6e146104d55780631a1d9252146104e857600080fd5b806301ffc9a71461035557806304634d8d1461038a57806306fdde03146103ac578063081812fc146103ce578063095ea7b3146104065780630c94904314610419575b600080fd5b34801561036157600080fd5b506103756103703660046122dd565b610aab565b60405190151581526020015b60405180910390f35b34801561039657600080fd5b506103aa6103a5366004612311565b610abc565b005b3480156103b857600080fd5b506103c1610ad2565b60405161038191906123a4565b3480156103da57600080fd5b506103ee6103e93660046123b7565b610b64565b6040516001600160a01b039091168152602001610381565b6103aa6104143660046123d0565b610b9f565b34801561042557600080fd5b50600c54600d54600e54610465926001600160a01b031691906001600160401b03811690600160401b810461ffff1690600160501b900463ffffffff1685565b604080516001600160a01b03909616865260208601949094526001600160401b039092169284019290925261ffff909116606083015263ffffffff16608082015260a001610381565b3480156104ba57600080fd5b5060015460005403600019015b604051908152602001610381565b6103aa6104e33660046123b7565b610bb8565b3480156104f457600080fd5b506104c76105033660046123b7565b600f6020526000908152604090205481565b6103aa6105233660046123d0565b610bc5565b34801561053457600080fd5b506103756105433660046123d0565b638b78c6d8600c90815260009290925260209091205481161490565b34801561056b57600080fd5b506103aa61057a366004612463565b610bd7565b6103aa61058d366004612504565b610c60565b6103aa610c8b565b3480156105a657600080fd5b506104c7600281565b3480156105bb57600080fd5b506105cf6105ca366004612540565b610cda565b604080516001600160a01b039093168352602083019190915201610381565b3480156105fa57600080fd5b506104c7610609366004612562565b638b78c6d8600c908152600091909152602090205490565b34801561062d57600080fd5b506103aa61063c36600461257d565b610d86565b34801561064d57600080fd5b506103ee6daaeb6d7670e522a718067333cd4e81565b6103aa610671366004612504565b610e21565b34801561068257600080fd5b506103aa6106913660046123b7565b610e46565b3480156106a257600080fd5b5060105461037590610100900460ff1681565b6103aa6106c33660046123d0565b610e51565b3480156106d457600080fd5b506103756106e33660046123d0565b638b78c6d8600c90815260009290925260209091205416151590565b6103aa610e63565b34801561071357600080fd5b506103aa610722366004612605565b610e9f565b34801561073357600080fd5b5061074761074236600461264d565b610eb3565b60405161038191906126fd565b34801561076057600080fd5b506103ee61076f3660046123b7565b610eff565b34801561078057600080fd5b506103aa61078f36600461273f565b610f0a565b3480156107a057600080fd5b506103c1610ffb565b3480156107b557600080fd5b506103aa611089565b3480156107ca57600080fd5b506104c76107d9366004612562565b61109d565b6103aa6110e2565b3480156107f257600080fd5b506000546104c7565b34801561080757600080fd5b5061081b610816366004612562565b6110f6565b60405161038191906127c1565b34801561083457600080fd5b50638b78c6d819546103ee565b34801561084d57600080fd5b506103aa61085c366004612605565b61111d565b34801561086d57600080fd5b506103c1611131565b34801561088257600080fd5b506010546103759060ff1681565b34801561089c57600080fd5b5061081b6108ab3660046127f9565b611140565b3480156108bc57600080fd5b506103aa6108cb36600461283a565b61114d565b6103aa6108de366004612866565b611161565b3480156108ef57600080fd5b506103aa61118e565b34801561090457600080fd5b506109186109133660046123b7565b6111a7565b60405161038191906128e1565b34801561093157600080fd5b506103c16109403660046123b7565b61120b565b34801561095157600080fd5b506103aa6109603660046128ef565b611286565b34801561097157600080fd5b506104c76109803660046123b7565b611366565b34801561099157600080fd5b506109a56109a03660046123b7565b6113ae565b60405161038191906129b6565b3480156109be57600080fd5b506103c1611451565b3480156109d357600080fd5b506103756109e23660046129f8565b6001600160a01b03918216600090815260076020908152604080832093909416825291909152205460ff1690565b6103aa610a1e366004612562565b61145e565b348015610a2f57600080fd5b506104c7610a3e3660046123b7565b60116020526000908152604090205481565b6103aa610a5e366004612562565b61149b565b348015610a6f57600080fd5b506104c7600181565b348015610a8457600080fd5b506104c7610a93366004612562565b63389a75e1600c908152600091909152602090205490565b6000610ab6826114c2565b92915050565b610ac46114dc565b610ace82826114f7565b5050565b606060028054610ae190612a2b565b80601f0160208091040260200160405190810160405280929190818152602001828054610b0d90612a2b565b8015610b5a5780601f10610b2f57610100808354040283529160200191610b5a565b820191906000526020600020905b815481529060010190602001808311610b3d57829003601f168201915b5050505050905090565b6000610b6f826115f4565b610b8357610b836333d1c03960e21b611640565b506000908152600660205260409020546001600160a01b031690565b81610ba98161164a565b610bb38383611703565b505050565b610bc2338261170f565b50565b610bcd6114dc565b610ace828261171b565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610c565760405163073e64fd60e21b81523360048201526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001660248201526044015b60405180910390fd5b610ace8282611727565b826001600160a01b0381163314610c7a57610c7a3361164a565b610c858484846117e0565b50505050565b60006202a3006001600160401b03164201905063389a75e1600c5233600052806020600c2055337fdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d600080a250565b60008281526009602090815260408083208151808301909252546001600160a01b038116808352600160a01b9091046001600160601b0316928201929092528291610d4f5750604080518082019091526008546001600160a01b0381168252600160a01b90046001600160601b031660208201525b602081015160009061271090610d6e906001600160601b031687612a75565b610d789190612a8c565b915196919550909350505050565b81610d90816115f4565b610db0576040516338077a2b60e01b815260048101829052602401610c4d565b6002610dbb8161194f565b60008481526012602090815260409182902080546001600160f81b0319166001600160f81b038716908117909155915191825285917f8bdaee675270281b7bc2d5b9ced20517ecf5ce96158973ef78072a7bc1491b44910160405180910390a250505050565b826001600160a01b0381163314610e3b57610e3b3361164a565b610c85848484611982565b610bc281600161199d565b610e596114dc565b610ace828261170f565b63389a75e1600c523360005260006020600c2055337ffa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92600080a2565b610ea76114dc565b600a610ace8282612af6565b60408051828152600583901b8082016020019092526060915b8015610ef757601f1980820191860101356000610ee8826111a7565b8484016020015250610ecc9050565b509392505050565b6000610ab682611ade565b610f126114dc565b60105460ff16610f5b5760405162461bcd60e51b81526020600482015260146024820152731594918818d85b89dd081899481d5c19185d195960621b6044820152606401610c4d565b6040805160a0810182526001600160a01b03909616808752602087018690526001600160401b0390941690860181905261ffff9092166060860181905263ffffffff9091166080909501859052600c80546001600160a01b031916909317909255600d92909255600e8054600160501b90940263ffffffff60501b19600160401b90930269ffffffffffffffffffff199095169093179390931716179055565b600a805461100890612a2b565b80601f016020809104026020016040519081016040528092919081815260200182805461103490612a2b565b80156110815780601f1061105657610100808354040283529160200191611081565b820191906000526020600020905b81548152906001019060200180831161106457829003601f168201915b505050505081565b6110916114dc565b6010805460ff19169055565b60006001600160a01b0382166110bd576110bd6323d3ad8160e21b611640565b506001600160a01b03166000908152600560205260409020546001600160401b031690565b6110ea6114dc565b6110f46000611b7f565b565b6000546060906001908282821461111557611112858484611bbd565b90505b949350505050565b6111256114dc565b600b610ace8282612af6565b606060038054610ae190612a2b565b6060611115848484611bbd565b816111578161164a565b610bb38383611cbc565b836001600160a01b038116331461117b5761117b3361164a565b61118785858585611d28565b5050505050565b6111966114dc565b6010805461ff001916610100179055565b6040805160808101825260008082526020820181905291810182905260608101919091526001821061120657600054821015611206575b6000828152600460205260409020546111fd57600019909101906111de565b610ab682611d63565b919050565b6060611216826115f4565b61122a5761122a630a14c4b560e41b611640565b6000611234611de1565b90508051600003611254576040518060200160405280600081525061127f565b8061125e84611df0565b60405160200161126f929190612bb5565b6040516020818303038152906040525b9392505050565b60016112918161194f565b81516000546112a08583611e34565b60005b8281101561135e57604051806040016040528060006001600160f81b031681526020018683815181106112d8576112d8612be4565b602002602001015160048111156112f1576112f16129a0565b9052601260006113018486612bfa565b8152602080820192909252604001600020825181546001600160f81b0319166001600160f81b0390911690811782559183015190918290600160f81b83600481111561134f5761134f6129a0565b021790555050506001016112a3565b505050505050565b60408051426020808301919091523360601b6bffffffffffffffffffffffff191682840152605480830194909452825180830390940184526074909101909152815191012090565b6040805180820190915260008082526020820152816113cc816115f4565b6113ec576040516338077a2b60e01b815260048101829052602401610c4d565b600083815260126020908152604091829020825180840190935280546001600160f81b03811684529091830190600160f81b900460ff166004811115611434576114346129a0565b6004811115611445576114456129a0565b90525091505b50919050565b600b805461100890612a2b565b6114666114dc565b63389a75e1600c52806000526020600c20805442111561148e57636f5e88186000526004601cfd5b60009055610bc281611b7f565b6114a36114dc565b8060601b6114b957637448fbae6000526004601cfd5b610bc281611b7f565b60006114cd82611fa7565b80610ab65750610ab682611fdc565b638b78c6d8195433146110f4576382b429006000526004601cfd5b6127106001600160601b03821611156115655760405162461bcd60e51b815260206004820152602a60248201527f455243323938313a20726f79616c7479206665652077696c6c206578636565646044820152692073616c65507269636560b01b6064820152608401610c4d565b6001600160a01b0382166115bb5760405162461bcd60e51b815260206004820152601960248201527f455243323938313a20696e76616c6964207265636569766572000000000000006044820152606401610c4d565b604080518082019091526001600160a01b039092168083526001600160601b039091166020909201829052600160a01b90910217600855565b600081600111611206576000548210156112065760005b50600082815260046020526040812054908190036116335761162c83612c0d565b925061160b565b600160e01b161592915050565b8060005260046000fd5b6daaeb6d7670e522a718067333cd4e3b15610bc257604051633185c44d60e21b81523060048201526001600160a01b03821660248201526daaeb6d7670e522a718067333cd4e9063c617113490604401602060405180830381865afa1580156116b7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116db9190612c24565b610bc257604051633b79c77360e21b81526001600160a01b0382166004820152602401610c4d565b610ace8282600161202a565b610ace828260006120cd565b610ace828260016120cd565b6000828152600f6020526040812054905b8251811015610c855782818151811061175357611753612be4565b602002602001015160116000838561176b9190612c41565b81526020810191909152604001600020556117868183612c41565b7f14296754697e325872a9c14eb682f467bc46b15a78ae9420d7a13a7cd3833b2c8483815181106117b9576117b9612be4565b60200260200101516040516117d091815260200190565b60405180910390a2600101611738565b60006117eb82611ade565b6001600160a01b0394851694909150811684146118115761181162a1148160e81b611640565b6000828152600660205260409020805461183d8187335b6001600160a01b039081169116811491141790565b61185f5761184b86336109e2565b61185f5761185f632ce44b5f60e11b611640565b801561186a57600082555b6001600160a01b038681166000908152600560205260408082208054600019019055918716808252919020805460010190554260a01b17600160e11b17600085815260046020526040812091909155600160e11b841690036118fc576001840160008181526004602052604081205490036118fa5760005481146118fa5760008181526004602052604090208490555b505b6001600160a01b0385168481887fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef600080a48060000361194657611946633a954ecd60e21b611640565b50505050505050565b638b78c6d8600c5233600052806020600c205416610bc257638b78c6d819543314610bc2576382b429006000526004601cfd5b610bb383838360405180602001604052806000815250611161565b60006119a883611ade565b9050806000806119c686600090815260066020526040902080549091565b9150915084156119fd576119db818433611828565b6119fd576119e983336109e2565b6119fd576119fd632ce44b5f60e11b611640565b8015611a0857600082555b6001600160a01b038316600081815260056020526040902080546fffffffffffffffffffffffffffffffff0190554260a01b17600360e01b17600087815260046020526040812091909155600160e11b85169003611a9657600186016000818152600460205260408120549003611a94576000548114611a945760008181526004602052604090208590555b505b60405186906000906001600160a01b038616907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908390a45050600180548101905550505050565b600081600111611b6f575060008181526004602052604081205490819003611b5c576000548210611b1957611b19636f96cda160e11b611640565b5b50600019016000818152600460205260409020548015611b1a57600160e01b8116600003611b4757919050565b611b57636f96cda160e11b611640565b611b1a565b600160e01b8116600003611b6f57919050565b611206636f96cda160e11b611640565b638b78c6d81980546001600160a01b039092169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a355565b6060818310611bd657611bd6631960ccad60e11b611640565b6001831015611be457600192505b600054808310611bf2578092505b60606000611bff8761109d565b85871090810291508115611cb0578187870311611c1c5786860391505b60405192506001820160051b83016040526000611c38886111a7565b905060008160400151611c49575080515b60005b611c558a611d63565b9250604083015160008114611c6d5760009250611c92565b835115611c7957835192505b8b831860601b611c92576001820191508a8260051b8801525b5060018a019950888a1480611ca657508481145b15611c4c57855250505b50909695505050505050565b3360008181526007602090815260408083206001600160a01b03871680855290835292819020805460ff191686151590811790915590519081529192917f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a35050565b611d33848484610c60565b6001600160a01b0383163b15610c8557611d4f84848484612126565b610c8557610c856368d2bf6b60e11b611640565b604080516080810182526000808252602082018190529181018290526060810191909152600082815260046020526040902054610ab690604080516080810182526001600160a01b038316815260a083901c6001600160401b03166020820152600160e01b831615159181019190915260e89190911c606082015290565b6060600a8054610ae190612a2b565b606060a06040510180604052602081039150506000815280825b600183039250600a81066030018353600a900480611e0a5750819003601f19909101908152919050565b611e3e8282612208565b601054610100900460ff1615611f2257600c54600d54600e546040516305d3b1d360e41b815260048101929092526001600160401b0381166024830152600160401b810461ffff166044830152600160501b900463ffffffff9081166064830152831660848201526000916001600160a01b031690635d3b1d309060a4016020604051808303816000875af1158015611edb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611eff9190612c54565b9050611f0e6000546000190190565b6000918252600f6020526040909120555050565b60005b81811015610bb357600081611f3d6000546000190190565b611f479190612c41565b9050611f5281611366565b600082815260116020526040908190208290555182917f14296754697e325872a9c14eb682f467bc46b15a78ae9420d7a13a7cd3833b2c91611f9691815260200190565b60405180910390a250600101611f25565b60006001600160e01b0319821663152a902d60e11b1480610ab657506301ffc9a760e01b6001600160e01b0319831614610ab6565b60006301ffc9a760e01b6001600160e01b03198316148061200d57506380ac58cd60e01b6001600160e01b03198316145b80610ab65750506001600160e01b031916635b5e139f60e01b1490565b600061203583610eff565b905081801561204d5750336001600160a01b03821614155b156120705761205c81336109e2565b612070576120706367d9dca160e11b611640565b60008381526006602052604080822080546001600160a01b0319166001600160a01b0388811691821790925591518693918516917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591a450505050565b638b78c6d8600c52826000526020600c208054838117836120ef575080841681185b80835580600c5160601c7f715ad5ce61fc9595c7b415289d59cf203f23a94fa06f04af7e489a0a76e1fe26600080a3505050505050565b604051630a85bd0160e11b81526000906001600160a01b0385169063150b7a029061215b903390899088908890600401612c6d565b6020604051808303816000875af1925050508015612196575060408051601f3d908101601f1916820190925261219391810190612caa565b60015b6121eb573d8080156121c4576040519150601f19603f3d011682016040523d82523d6000602084013e6121c9565b606091505b5080516000036121e3576121e36368d2bf6b60e11b611640565b805181602001fd5b6001600160e01b031916630a85bd0160e11b149050949350505050565b60008054908290036122245761222463b562e8dd60e01b611640565b60008181526004602090815260408083206001600160a01b0387164260a01b6001881460e11b1781179091558084526005909252822080546801000000000000000186020190559081900361228257612282622e076360e81b611640565b818301825b808360007fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef600080a4818160010191508103612287575060005550505050565b6001600160e01b031981168114610bc257600080fd5b6000602082840312156122ef57600080fd5b813561127f816122c7565b80356001600160a01b038116811461120657600080fd5b6000806040838503121561232457600080fd5b61232d836122fa565b915060208301356001600160601b038116811461234957600080fd5b809150509250929050565b60005b8381101561236f578181015183820152602001612357565b50506000910152565b60008151808452612390816020860160208601612354565b601f01601f19169290920160200192915050565b60208152600061127f6020830184612378565b6000602082840312156123c957600080fd5b5035919050565b600080604083850312156123e357600080fd5b6123ec836122fa565b946020939093013593505050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b0381118282101715612438576124386123fa565b604052919050565b60006001600160401b03821115612459576124596123fa565b5060051b60200190565b6000806040838503121561247657600080fd5b823591506020808401356001600160401b0381111561249457600080fd5b8401601f810186136124a557600080fd5b80356124b86124b382612440565b612410565b81815260059190911b820183019083810190888311156124d757600080fd5b928401925b828410156124f5578335825292840192908401906124dc565b80955050505050509250929050565b60008060006060848603121561251957600080fd5b612522846122fa565b9250612530602085016122fa565b9150604084013590509250925092565b6000806040838503121561255357600080fd5b50508035926020909101359150565b60006020828403121561257457600080fd5b61127f826122fa565b6000806040838503121561259057600080fd5b8235915060208301356001600160f81b038116811461234957600080fd5b60006001600160401b038311156125c7576125c76123fa565b6125da601f8401601f1916602001612410565b90508281528383830111156125ee57600080fd5b828260208301376000602084830101529392505050565b60006020828403121561261757600080fd5b81356001600160401b0381111561262d57600080fd5b8201601f8101841361263e57600080fd5b611115848235602084016125ae565b6000806020838503121561266057600080fd5b82356001600160401b038082111561267757600080fd5b818501915085601f83011261268b57600080fd5b81358181111561269a57600080fd5b8660208260051b85010111156126af57600080fd5b60209290920196919550909350505050565b80516001600160a01b031682526020808201516001600160401b03169083015260408082015115159083015260609081015162ffffff16910152565b6020808252825182820181905260009190848201906040850190845b81811015611cb05761272c8385516126c1565b9284019260809290920191600101612719565b600080600080600060a0868803121561275757600080fd5b612760866122fa565b94506020860135935060408601356001600160401b038116811461278357600080fd5b9250606086013561ffff8116811461279a57600080fd5b9150608086013563ffffffff811681146127b357600080fd5b809150509295509295909350565b6020808252825182820181905260009190848201906040850190845b81811015611cb0578351835292840192918401916001016127dd565b60008060006060848603121561280e57600080fd5b612817846122fa565b95602085013595506040909401359392505050565b8015158114610bc257600080fd5b6000806040838503121561284d57600080fd5b612856836122fa565b915060208301356123498161282c565b6000806000806080858703121561287c57600080fd5b612885856122fa565b9350612893602086016122fa565b92506040850135915060608501356001600160401b038111156128b557600080fd5b8501601f810187136128c657600080fd5b6128d5878235602084016125ae565b91505092959194509250565b60808101610ab682846126c1565b6000806040838503121561290257600080fd5b61290b836122fa565b91506020808401356001600160401b0381111561292757600080fd5b8401601f8101861361293857600080fd5b80356129466124b382612440565b818152600591821b830184019184820191908984111561296557600080fd5b938501935b838510156129905784358181106129815760008081fd5b8352938501939185019161296a565b5080955050505050509250929050565b634e487b7160e01b600052602160045260246000fd5b81516001600160f81b0316815260208201516040820190600581106129eb57634e487b7160e01b600052602160045260246000fd5b8060208401525092915050565b60008060408385031215612a0b57600080fd5b612a14836122fa565b9150612a22602084016122fa565b90509250929050565b600181811c90821680612a3f57607f821691505b60208210810361144b57634e487b7160e01b600052602260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b8082028115828204841417610ab657610ab6612a5f565b600082612aa957634e487b7160e01b600052601260045260246000fd5b500490565b601f821115610bb3576000816000526020600020601f850160051c81016020861015612ad75750805b601f850160051c820191505b8181101561135e57828155600101612ae3565b81516001600160401b03811115612b0f57612b0f6123fa565b612b2381612b1d8454612a2b565b84612aae565b602080601f831160018114612b585760008415612b405750858301515b600019600386901b1c1916600185901b17855561135e565b600085815260208120601f198616915b82811015612b8757888601518255948401946001909101908401612b68565b5085821015612ba55787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b60008351612bc7818460208801612354565b835190830190612bdb818360208801612354565b01949350505050565b634e487b7160e01b600052603260045260246000fd5b80820180821115610ab657610ab6612a5f565b600081612c1c57612c1c612a5f565b506000190190565b600060208284031215612c3657600080fd5b815161127f8161282c565b81810381811115610ab657610ab6612a5f565b600060208284031215612c6657600080fd5b5051919050565b6001600160a01b0385811682528416602082015260408101839052608060608201819052600090612ca090830184612378565b9695505050505050565b600060208284031215612cbc57600080fd5b815161127f816122c75668747470733a2f2f6d657461646174612e706f6f6b792e67672f737469636b6572732f68747470733a2f2f6d657461646174612e706f6f6b792e67672f636f6e7472616374732f537469636b6572732e6a736f6e diff --git a/bytecode/tokens/IPOK.bin b/bytecode/tokens/IPOK.bin deleted file mode 100644 index ec687260..00000000 --- a/bytecode/tokens/IPOK.bin +++ /dev/null @@ -1 +0,0 @@ -0x diff --git a/bytecode/tokens/POK.bin b/bytecode/tokens/POK.bin index 3dbb550d..d53a556d 100644 --- a/bytecode/tokens/POK.bin +++ b/bytecode/tokens/POK.bin @@ -1 +1 @@ -0x60806040523480156200001157600080fd5b50604080518082018252600380825262504f4b60e81b602080840182905284518086019095528285528401529091906200004c8382620001bf565b5060046200005b8282620001bf565b506200006d9150600090503362000073565b6200028b565b60008281526005602090815260408083206001600160a01b038516845290915290205460ff16620001145760008281526005602090815260408083206001600160a01b03851684529091529020805460ff19166001179055620000d33390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45b5050565b634e487b7160e01b600052604160045260246000fd5b600181811c908216806200014357607f821691505b6020821081036200016457634e487b7160e01b600052602260045260246000fd5b50919050565b601f821115620001ba576000816000526020600020601f850160051c81016020861015620001955750805b601f850160051c820191505b81811015620001b657828155600101620001a1565b5050505b505050565b81516001600160401b03811115620001db57620001db62000118565b620001f381620001ec84546200012e565b846200016a565b602080601f8311600181146200022b5760008415620002125750858301515b600019600386901b1c1916600185901b178555620001b6565b600085815260208120601f198616915b828110156200025c578886015182559484019460019091019084016200023b565b50858210156200027b5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6111e5806200029b6000396000f3fe608060405234801561001057600080fd5b50600436106101425760003560e01c806340c10f19116100b8578063a217fddf1161007c578063a217fddf146102be578063a457c2d7146102c6578063a9059cbb146102d9578063d547741f146102ec578063dd62ed3e146102ff578063fe6d81241461031257600080fd5b806340c10f191461025457806370a082311461026757806391d148541461029057806395d89b41146102a35780639dc29fac146102ab57600080fd5b806323b872dd1161010a57806323b872dd146101d4578063248a9ca3146101e75780632f2ff15d1461020a578063313ce5671461021f57806336568abe1461022e578063395093511461024157600080fd5b806301ffc9a71461014757806306fdde031461016f578063095ea7b314610184578063118c4f131461019757806318160ddd146101cc575b600080fd5b61015a610155366004610f26565b610339565b60405190151581526020015b60405180910390f35b610177610370565b6040516101669190610f74565b61015a610192366004610fc3565b610402565b6101be7f9667e80708b6eeeb0053fa0cca44e028ff548e2a9f029edfeac87c118b08b7c881565b604051908152602001610166565b6002546101be565b61015a6101e2366004610fed565b61041a565b6101be6101f5366004611029565b60009081526005602052604090206001015490565b61021d610218366004611042565b61043e565b005b60405160128152602001610166565b61021d61023c366004611042565b610468565b61015a61024f366004610fc3565b6104eb565b61021d610262366004610fc3565b61050d565b6101be61027536600461106e565b6001600160a01b031660009081526020819052604090205490565b61015a61029e366004611042565b610541565b61017761056c565b61021d6102b9366004610fc3565b61057b565b6101be600081565b61015a6102d4366004610fc3565b6105af565b61015a6102e7366004610fc3565b61062a565b61021d6102fa366004611042565b610638565b6101be61030d366004611089565b61065d565b6101be7ff0887ba65ee2024ea881d91b74c2450ef19e1557f03bed3ea9f16b037cbe2dc981565b60006001600160e01b03198216637965db0b60e01b148061036a57506301ffc9a760e01b6001600160e01b03198316145b92915050565b60606003805461037f906110b3565b80601f01602080910402602001604051908101604052809291908181526020018280546103ab906110b3565b80156103f85780601f106103cd576101008083540402835291602001916103f8565b820191906000526020600020905b8154815290600101906020018083116103db57829003601f168201915b5050505050905090565b600033610410818585610688565b5060019392505050565b6000336104288582856107ac565b610433858585610826565b506001949350505050565b600082815260056020526040902060010154610459816109d5565b61046383836109e2565b505050565b6001600160a01b03811633146104dd5760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201526e103937b632b9903337b91039b2b63360891b60648201526084015b60405180910390fd5b6104e78282610a68565b5050565b6000336104108185856104fe838361065d565b6105089190611103565b610688565b7ff0887ba65ee2024ea881d91b74c2450ef19e1557f03bed3ea9f16b037cbe2dc9610537816109d5565b6104638383610acf565b60009182526005602090815260408084206001600160a01b0393909316845291905290205460ff1690565b60606004805461037f906110b3565b7f9667e80708b6eeeb0053fa0cca44e028ff548e2a9f029edfeac87c118b08b7c86105a5816109d5565b6104638383610b9a565b600033816105bd828661065d565b90508381101561061d5760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b60648201526084016104d4565b6104338286868403610688565b600033610410818585610826565b600082815260056020526040902060010154610653816109d5565b6104638383610a68565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b6001600160a01b0383166106ea5760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b60648201526084016104d4565b6001600160a01b03821661074b5760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b60648201526084016104d4565b6001600160a01b0383811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b60006107b8848461065d565b9050600019811461082057818110156108135760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e636500000060448201526064016104d4565b6108208484848403610688565b50505050565b6001600160a01b03831661088a5760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b60648201526084016104d4565b6001600160a01b0382166108ec5760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b60648201526084016104d4565b6108f7838383610cd8565b6001600160a01b0383166000908152602081905260409020548181101561096f5760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b60648201526084016104d4565b6001600160a01b03848116600081815260208181526040808320878703905593871680835291849020805487019055925185815290927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a3610820565b6109df8133610d18565b50565b6109ec8282610541565b6104e75760008281526005602090815260408083206001600160a01b03851684529091529020805460ff19166001179055610a243390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b610a728282610541565b156104e75760008281526005602090815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b6001600160a01b038216610b255760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f20616464726573730060448201526064016104d4565b610b3160008383610cd8565b8060026000828254610b439190611103565b90915550506001600160a01b038216600081815260208181526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a35050565b6001600160a01b038216610bfa5760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b60648201526084016104d4565b610c0682600083610cd8565b6001600160a01b03821660009081526020819052604090205481811015610c7a5760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b60648201526084016104d4565b6001600160a01b0383166000818152602081815260408083208686039055600280548790039055518581529192917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a3505050565b6001600160a01b0383161580610cf557506001600160a01b038216155b15610cff57505050565b60405163c02d675560e01b815260040160405180910390fd5b610d228282610541565b6104e757610d2f81610d71565b610d3a836020610d83565b604051602001610d4b929190611116565b60408051601f198184030181529082905262461bcd60e51b82526104d491600401610f74565b606061036a6001600160a01b03831660145b60606000610d9283600261118b565b610d9d906002611103565b67ffffffffffffffff811115610db557610db56111a2565b6040519080825280601f01601f191660200182016040528015610ddf576020820181803683370190505b509050600360fc1b81600081518110610dfa57610dfa6111b8565b60200101906001600160f81b031916908160001a905350600f60fb1b81600181518110610e2957610e296111b8565b60200101906001600160f81b031916908160001a9053506000610e4d84600261118b565b610e58906001611103565b90505b6001811115610ed0576f181899199a1a9b1b9c1cb0b131b232b360811b85600f1660108110610e8c57610e8c6111b8565b1a60f81b828281518110610ea257610ea26111b8565b60200101906001600160f81b031916908160001a90535060049490941c93610ec9816111ce565b9050610e5b565b508315610f1f5760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e7460448201526064016104d4565b9392505050565b600060208284031215610f3857600080fd5b81356001600160e01b031981168114610f1f57600080fd5b60005b83811015610f6b578181015183820152602001610f53565b50506000910152565b6020815260008251806020840152610f93816040850160208701610f50565b601f01601f19169190910160400192915050565b80356001600160a01b0381168114610fbe57600080fd5b919050565b60008060408385031215610fd657600080fd5b610fdf83610fa7565b946020939093013593505050565b60008060006060848603121561100257600080fd5b61100b84610fa7565b925061101960208501610fa7565b9150604084013590509250925092565b60006020828403121561103b57600080fd5b5035919050565b6000806040838503121561105557600080fd5b8235915061106560208401610fa7565b90509250929050565b60006020828403121561108057600080fd5b610f1f82610fa7565b6000806040838503121561109c57600080fd5b6110a583610fa7565b915061106560208401610fa7565b600181811c908216806110c757607f821691505b6020821081036110e757634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052601160045260246000fd5b8082018082111561036a5761036a6110ed565b7f416363657373436f6e74726f6c3a206163636f756e742000000000000000000081526000835161114e816017850160208801610f50565b7001034b99036b4b9b9b4b733903937b6329607d1b601791840191820152835161117f816028840160208801610f50565b01602801949350505050565b808202811582820484141761036a5761036a6110ed565b634e487b7160e01b600052604160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b6000816111dd576111dd6110ed565b50600019019056 +0x60806040523480156200001157600080fd5b50604051620014d5380380620014d583398101604081905262000034916200013b565b604080518082018252600380825262504f4b60e81b602080840182905284518086019095528285528401529091906200006e838262000214565b5060046200007d828262000214565b506200008f9150600090508262000096565b50620002e0565b60008281526005602090815260408083206001600160a01b038516845290915290205460ff16620001375760008281526005602090815260408083206001600160a01b03851684529091529020805460ff19166001179055620000f63390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45b5050565b6000602082840312156200014e57600080fd5b81516001600160a01b03811681146200016657600080fd5b9392505050565b634e487b7160e01b600052604160045260246000fd5b600181811c908216806200019857607f821691505b602082108103620001b957634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200020f576000816000526020600020601f850160051c81016020861015620001ea5750805b601f850160051c820191505b818110156200020b57828155600101620001f6565b5050505b505050565b81516001600160401b038111156200023057620002306200016d565b620002488162000241845462000183565b84620001bf565b602080601f831160018114620002805760008415620002675750858301515b600019600386901b1c1916600185901b1785556200020b565b600085815260208120601f198616915b82811015620002b15788860151825594840194600190910190840162000290565b5085821015620002d05787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6111e580620002f06000396000f3fe608060405234801561001057600080fd5b50600436106101425760003560e01c806340c10f19116100b8578063a217fddf1161007c578063a217fddf146102be578063a457c2d7146102c6578063a9059cbb146102d9578063d547741f146102ec578063dd62ed3e146102ff578063fe6d81241461031257600080fd5b806340c10f191461025457806370a082311461026757806391d148541461029057806395d89b41146102a35780639dc29fac146102ab57600080fd5b806323b872dd1161010a57806323b872dd146101d4578063248a9ca3146101e75780632f2ff15d1461020a578063313ce5671461021f57806336568abe1461022e578063395093511461024157600080fd5b806301ffc9a71461014757806306fdde031461016f578063095ea7b314610184578063118c4f131461019757806318160ddd146101cc575b600080fd5b61015a610155366004610f26565b610339565b60405190151581526020015b60405180910390f35b610177610370565b6040516101669190610f74565b61015a610192366004610fc3565b610402565b6101be7f9667e80708b6eeeb0053fa0cca44e028ff548e2a9f029edfeac87c118b08b7c881565b604051908152602001610166565b6002546101be565b61015a6101e2366004610fed565b61041a565b6101be6101f5366004611029565b60009081526005602052604090206001015490565b61021d610218366004611042565b61043e565b005b60405160128152602001610166565b61021d61023c366004611042565b610468565b61015a61024f366004610fc3565b6104eb565b61021d610262366004610fc3565b61050d565b6101be61027536600461106e565b6001600160a01b031660009081526020819052604090205490565b61015a61029e366004611042565b610541565b61017761056c565b61021d6102b9366004610fc3565b61057b565b6101be600081565b61015a6102d4366004610fc3565b6105af565b61015a6102e7366004610fc3565b61062a565b61021d6102fa366004611042565b610638565b6101be61030d366004611089565b61065d565b6101be7ff0887ba65ee2024ea881d91b74c2450ef19e1557f03bed3ea9f16b037cbe2dc981565b60006001600160e01b03198216637965db0b60e01b148061036a57506301ffc9a760e01b6001600160e01b03198316145b92915050565b60606003805461037f906110b3565b80601f01602080910402602001604051908101604052809291908181526020018280546103ab906110b3565b80156103f85780601f106103cd576101008083540402835291602001916103f8565b820191906000526020600020905b8154815290600101906020018083116103db57829003601f168201915b5050505050905090565b600033610410818585610688565b5060019392505050565b6000336104288582856107ac565b610433858585610826565b506001949350505050565b600082815260056020526040902060010154610459816109d5565b61046383836109e2565b505050565b6001600160a01b03811633146104dd5760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201526e103937b632b9903337b91039b2b63360891b60648201526084015b60405180910390fd5b6104e78282610a68565b5050565b6000336104108185856104fe838361065d565b6105089190611103565b610688565b7ff0887ba65ee2024ea881d91b74c2450ef19e1557f03bed3ea9f16b037cbe2dc9610537816109d5565b6104638383610acf565b60009182526005602090815260408084206001600160a01b0393909316845291905290205460ff1690565b60606004805461037f906110b3565b7f9667e80708b6eeeb0053fa0cca44e028ff548e2a9f029edfeac87c118b08b7c86105a5816109d5565b6104638383610b9a565b600033816105bd828661065d565b90508381101561061d5760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b60648201526084016104d4565b6104338286868403610688565b600033610410818585610826565b600082815260056020526040902060010154610653816109d5565b6104638383610a68565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b6001600160a01b0383166106ea5760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b60648201526084016104d4565b6001600160a01b03821661074b5760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b60648201526084016104d4565b6001600160a01b0383811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b60006107b8848461065d565b9050600019811461082057818110156108135760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e636500000060448201526064016104d4565b6108208484848403610688565b50505050565b6001600160a01b03831661088a5760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b60648201526084016104d4565b6001600160a01b0382166108ec5760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b60648201526084016104d4565b6108f7838383610cd8565b6001600160a01b0383166000908152602081905260409020548181101561096f5760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b60648201526084016104d4565b6001600160a01b03848116600081815260208181526040808320878703905593871680835291849020805487019055925185815290927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a3610820565b6109df8133610d18565b50565b6109ec8282610541565b6104e75760008281526005602090815260408083206001600160a01b03851684529091529020805460ff19166001179055610a243390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b610a728282610541565b156104e75760008281526005602090815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b6001600160a01b038216610b255760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f20616464726573730060448201526064016104d4565b610b3160008383610cd8565b8060026000828254610b439190611103565b90915550506001600160a01b038216600081815260208181526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a35050565b6001600160a01b038216610bfa5760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b60648201526084016104d4565b610c0682600083610cd8565b6001600160a01b03821660009081526020819052604090205481811015610c7a5760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b60648201526084016104d4565b6001600160a01b0383166000818152602081815260408083208686039055600280548790039055518581529192917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a3505050565b6001600160a01b0383161580610cf557506001600160a01b038216155b15610cff57505050565b60405163c02d675560e01b815260040160405180910390fd5b610d228282610541565b6104e757610d2f81610d71565b610d3a836020610d83565b604051602001610d4b929190611116565b60408051601f198184030181529082905262461bcd60e51b82526104d491600401610f74565b606061036a6001600160a01b03831660145b60606000610d9283600261118b565b610d9d906002611103565b67ffffffffffffffff811115610db557610db56111a2565b6040519080825280601f01601f191660200182016040528015610ddf576020820181803683370190505b509050600360fc1b81600081518110610dfa57610dfa6111b8565b60200101906001600160f81b031916908160001a905350600f60fb1b81600181518110610e2957610e296111b8565b60200101906001600160f81b031916908160001a9053506000610e4d84600261118b565b610e58906001611103565b90505b6001811115610ed0576f181899199a1a9b1b9c1cb0b131b232b360811b85600f1660108110610e8c57610e8c6111b8565b1a60f81b828281518110610ea257610ea26111b8565b60200101906001600160f81b031916908160001a90535060049490941c93610ec9816111ce565b9050610e5b565b508315610f1f5760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e7460448201526064016104d4565b9392505050565b600060208284031215610f3857600080fd5b81356001600160e01b031981168114610f1f57600080fd5b60005b83811015610f6b578181015183820152602001610f53565b50506000910152565b6020815260008251806020840152610f93816040850160208701610f50565b601f01601f19169190910160400192915050565b80356001600160a01b0381168114610fbe57600080fd5b919050565b60008060408385031215610fd657600080fd5b610fdf83610fa7565b946020939093013593505050565b60008060006060848603121561100257600080fd5b61100b84610fa7565b925061101960208501610fa7565b9150604084013590509250925092565b60006020828403121561103b57600080fd5b5035919050565b6000806040838503121561105557600080fd5b8235915061106560208401610fa7565b90509250929050565b60006020828403121561108057600080fd5b610f1f82610fa7565b6000806040838503121561109c57600080fd5b6110a583610fa7565b915061106560208401610fa7565b600181811c908216806110c757607f821691505b6020821081036110e757634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052601160045260246000fd5b8082018082111561036a5761036a6110ed565b7f416363657373436f6e74726f6c3a206163636f756e742000000000000000000081526000835161114e816017850160208801610f50565b7001034b99036b4b9b9b4b733903937b6329607d1b601791840191820152835161117f816028840160208801610f50565b01602801949350505050565b808202811582820484141761036a5761036a6110ed565b634e487b7160e01b600052604160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b6000816111dd576111dd6110ed565b50600019019056 diff --git a/bytecode/types/VRFConfig.bin b/bytecode/types/VRFConfig.bin deleted file mode 100644 index ec687260..00000000 --- a/bytecode/types/VRFConfig.bin +++ /dev/null @@ -1 +0,0 @@ -0x diff --git a/lefthook.yml b/lefthook.yml index 53d16a8b..5a6fc3d2 100644 --- a/lefthook.yml +++ b/lefthook.yml @@ -5,7 +5,7 @@ pre-commit: parallel: true commands: test: - run: NO_COLOR=1 forge test + run: bash -c "NO_COLOR=1 forge test" artifacts: run: | pnpm rimraf abi bytecode diff --git a/script/artifacts.ts b/script/artifacts.ts index 38f65250..7bad4c2d 100644 --- a/script/artifacts.ts +++ b/script/artifacts.ts @@ -1,8 +1,9 @@ -import glob from 'fast-glob'; -import { exec as execAsync } from 'node:child_process'; -import { mkdir, writeFile } from 'node:fs/promises'; -import { basename, dirname } from 'node:path'; -import { promisify } from 'util'; +import glob from "fast-glob"; +import { basename, dirname } from "node:path"; +import { exec as execAsync } from "node:child_process"; +import { mkdir, writeFile } from "node:fs/promises"; +import { promisify } from "util"; + const exec = promisify(execAsync); /** @@ -10,8 +11,8 @@ const exec = promisify(execAsync); * @param contract The contract path. */ async function abi(contract: string): Promise { - const name = basename(contract).replace(/\.sol$/, ''); - const output = contract.replace(/^src/, 'abi').replace(/\.sol$/, '.json'); + const name = basename(contract).replace(/\.sol$/, ""); + const output = contract.replace(/^src/, "abi").replace(/\.sol$/, ".json"); await mkdir(dirname(output), { recursive: true }); const { stdout } = await exec(`forge inspect ${contract}:${name} abi`); @@ -23,16 +24,23 @@ async function abi(contract: string): Promise { * @param contract The contract path. */ async function bytecode(contract: string): Promise { - const name = basename(contract).replace(/\.sol$/, ''); - const output = contract.replace(/^src/, 'bytecode').replace(/\.sol$/, '.bin'); + const name = basename(contract).replace(/\.sol$/, ""); + const output = contract.replace(/^src/, "bytecode").replace(/\.sol$/, ".bin"); await mkdir(dirname(output), { recursive: true }); const { stdout } = await exec(`forge inspect ${contract}:${name} bytecode`); await writeFile(output, stdout); } -const contracts = await glob('src/**/*.sol'); +// Get all contracts +let contracts = await glob("src/**/*.sol"); +// Filter out types directory +contracts = contracts.filter((contract) => !contract.includes("/types/")); +// Filter out interfaces +contracts = contracts.filter((contract) => !contract.includes("/I")); + const jobs = contracts.reduce[]>((acc, contract) => { + console.log(contract); acc.push(abi(contract), bytecode(contract)); return acc; }, []); From 1a057e77df7700d3e75be2f828cc272ca76942aa Mon Sep 17 00:00:00 2001 From: Claudiu Date: Mon, 1 Apr 2024 20:05:40 +0300 Subject: [PATCH 02/10] feat(scripts): Add flatten script --- script/shell/deploy.sh | 21 ++++++--- script/shell/flatten.sh | 99 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 115 insertions(+), 5 deletions(-) create mode 100644 script/shell/flatten.sh diff --git a/script/shell/deploy.sh b/script/shell/deploy.sh index 218f8de0..f38624af 100644 --- a/script/shell/deploy.sh +++ b/script/shell/deploy.sh @@ -13,14 +13,17 @@ ALLOWED_CONTRACTS=( "BoostPXP" "Pookyball" "PookyballLevelUp" + "RefillableSale" + "Pressure" "PookyballReroll" - "PookyballAscension" "Stickers" - "StickersController" - "StickersManager" "StickersLevelUp" "StickersSale" + "StickersController" + "StickersManager" "StickersAscension" + "PookyballAscension" + "Rewards" ) # Define the networks @@ -34,8 +37,13 @@ function usage { echo "Examples:" # Iterate over each contract for contract in "${ALLOWED_CONTRACTS[@]}"; do + # Display the example usage for the current contract on the current network - echo "$0 local $contract" + if [[ " ${NETWORKS[@]} " =~ " ${NETWORK} " ]]; then + echo "$0 $NETWORK $contract" + else + echo "$0 local $contract" + fi done exit 1 } @@ -64,7 +72,7 @@ if [[ "$NETWORK" == "local" ]]; then RPC_URL_ARG="--fork-url $RPC_URL" else DEPLOYMENT_SCRIPTS="script/$NETWORK" - RPC_URL_ARG="--verify --rpc-url $RPC_URL" + RPC_URL_ARG="--rpc-url $RPC_URL" fi # Dynamically find the contract file @@ -77,3 +85,6 @@ fi # Execute the forge script forge script $CONTRACT_FILE --tc Deploy$CONTRACT_NAME $RPC_URL_ARG --broadcast + +# Flatten the contract whru flatten ( ./flatten.sh: No such file or directory ) +$PWD/script/shell/flatten.sh $CONTRACT_NAME \ No newline at end of file diff --git a/script/shell/flatten.sh b/script/shell/flatten.sh new file mode 100644 index 00000000..5f8be7b8 --- /dev/null +++ b/script/shell/flatten.sh @@ -0,0 +1,99 @@ +#!/bin/bash + +ALLOWED_CONTRACTS=( + "POK" + "Energy" + "NonceRegistry" + "BoostPXP" + "Pookyball" + "PookyballLevelUp" + "RefillableSale" + "Pressure" + "PookyballReroll" + "PookyballAscension" + "Stickers" + "StickersLevelUp" + "StickersSale" + "StickersController" + "StickersManager" + "StickersAscension" + "Rewards" +) + +# Usage message +function usage { + echo "Usage: $0 {ContractName}" + echo "Allowed contracts: ${ALLOWED_CONTRACTS[*]}" + exit 1 +} + +CONTRACT_NAME=$1 + +if [[ ! " ${ALLOWED_CONTRACTS[@]} " =~ " ${CONTRACT_NAME} " ]]; then + echo "Contract not allowed" + exit 1 +fi + +case $CONTRACT_NAME in + "POK") + CONTRACT_PATH="src/tokens/POK.sol" + ;; + "Energy") + CONTRACT_PATH="src/common/Energy.sol" + ;; + "NonceRegistry") + CONTRACT_PATH="src/common/NonceRegistry.sol" + ;; + "BoostPXP") + CONTRACT_PATH="src/common/BoostPXP.sol" + ;; + "Pookyball") + CONTRACT_PATH="src/pookyball/Pookyball.sol" + ;; + "PookyballLevelUp") + CONTRACT_PATH="src/pookyball/PookyballLevelUp.sol" + ;; + "RefillableSale") + CONTRACT_PATH="src/pookyball/RefillableSale.sol" + ;; + "Pressure") + CONTRACT_PATH="src/pookyball/Pressure.sol" + ;; + "PookyballReroll") + CONTRACT_PATH="src/pookyball/PookyballReroll.sol" + ;; + "PookyballAscension") + CONTRACT_PATH="src/pookyball/PookyballAscension.sol" + ;; + "Stickers") + CONTRACT_PATH="src/stickers/Stickers.sol" + ;; + "StickersLevelUp") + CONTRACT_PATH="src/stickers/StickersLevelUp.sol" + ;; + "StickersSale") + CONTRACT_PATH="src/stickers/StickersSale.sol" + ;; + "StickersController") + CONTRACT_PATH="src/stickers/StickersController.sol" + ;; + "StickersManager") + CONTRACT_PATH="src/stickers/StickersManager.sol" + ;; + "StickersAscension") + CONTRACT_PATH="src/stickers/StickersAscension.sol" + ;; + "Rewards") + CONTRACT_PATH="src/common/Rewards.sol" + ;; + *) + echo "Contract not allowed" + exit 1 + ;; +esac + + +forge flatten $CONTRACT_PATH --output flattened/$CONTRACT_NAME.sol + + + From 33fc00b9c917ed6e7e7575183c33fa69c0c99dc8 Mon Sep 17 00:00:00 2001 From: Claudiu Date: Mon, 1 Apr 2024 20:08:50 +0300 Subject: [PATCH 03/10] feat(pookyball): Add pseudo random seed and vrf update func --- src/pookyball/Pookyball.sol | 68 +++++++++++++++++++++++++++++----- test/pookyball/Pookyball.t.sol | 57 ++++++++++++++++++++++++++-- 2 files changed, 113 insertions(+), 12 deletions(-) diff --git a/src/pookyball/Pookyball.sol b/src/pookyball/Pookyball.sol index db003a76..e9211c1d 100644 --- a/src/pookyball/Pookyball.sol +++ b/src/pookyball/Pookyball.sol @@ -57,12 +57,14 @@ contract Pookyball is mapping(uint256 => PookyballMetadata) _metadata; // VRF parameters - VRFCoordinatorV2Interface vrfCoordinator; + VRFCoordinatorV2Interface public vrfCoordinator; bytes32 public vrfKeyHash; uint64 public vrfSubId; uint16 public vrfMinimumRequestConfirmations; uint32 public vrfCallbackGasLimit; mapping(uint256 => uint256) vrfRequests; + bool public canUpdateVRF = true; + bool public canUseVRF = false; constructor( string memory _baseURI, @@ -148,14 +150,25 @@ contract Pookyball is _metadata[lastTokenId] = PookyballMetadata(rarities[i], 0, 0, 0); } - uint256 requestId = vrfCoordinator.requestRandomWords( - vrfKeyHash, - vrfSubId, - vrfMinimumRequestConfirmations, - vrfCallbackGasLimit, - uint32(recipients.length) - ); - vrfRequests[requestId] = lastTokenId; + if (canUseVRF) { + // Request entropy from the VRF coordinator + uint256 requestId = vrfCoordinator.requestRandomWords( + vrfKeyHash, + vrfSubId, + vrfMinimumRequestConfirmations, + vrfCallbackGasLimit, + uint32(recipients.length) + ); + vrfRequests[requestId] = lastTokenId; + } else { + // Generate pseudo random seed + for (uint256 i = 0; i < recipients.length; i++) { + uint256 tokenId = lastTokenId - i; + uint256 seed = generateRandomSeed(tokenId); + _metadata[tokenId].seed = seed; + emit SeedSet(tokenId, seed); + } + } return lastTokenId; } @@ -257,4 +270,41 @@ contract Pookyball is { super.safeTransferFrom(from, to, tokenId, data); } + + // disable update vrf + function disableUpdateVRF() external onlyRole(DEFAULT_ADMIN_ROLE) { + canUpdateVRF = false; + } + + // enable vrf usage + function enableVRF() external onlyRole(DEFAULT_ADMIN_ROLE) { + canUseVRF = true; + } + + // update vrf + function updateVRF( + address _vrfCoordinator, + bytes32 _vrfKeyHash, + uint64 _vrfSubId, + uint16 _vrfMinimumRequestConfirmations, + uint32 _vrfCallbackGasLimit + ) external onlyRole(DEFAULT_ADMIN_ROLE) { + require(canUpdateVRF, "VRF can't be updated"); + vrfCoordinator = VRFCoordinatorV2Interface(_vrfCoordinator); + vrfKeyHash = _vrfKeyHash; + vrfSubId = _vrfSubId; + vrfMinimumRequestConfirmations = _vrfMinimumRequestConfirmations; + vrfCallbackGasLimit = _vrfCallbackGasLimit; + } + + // generate pseudo random seed + function generateRandomSeed(uint256 tokenId) public view returns (uint256) { + // Hash the combination of block timestamp, sender's address, and token ID + bytes32 hash = keccak256(abi.encodePacked(block.timestamp, msg.sender, tokenId)); + + // Convert the hash to a uint256 + uint256 randomSeed = uint256(hash); + + return randomSeed; + } } diff --git a/test/pookyball/Pookyball.t.sol b/test/pookyball/Pookyball.t.sol index 51d5114c..ba720e74 100644 --- a/test/pookyball/Pookyball.t.sol +++ b/test/pookyball/Pookyball.t.sol @@ -138,10 +138,39 @@ contract PookyballTest is BaseTest, AccessControlAssertions, PookyballSetup { assertEq(pookyball.metadata(tokenId).pxp, newPXP); } + function testFuzz_updateVRF() public { + uint64 subscriptionId = vrf.createSubscription(); + + vm.prank(admin); + pookyball.updateVRF(address(vrf), keccak256("foobar"), subscriptionId, 10, 2500000); + assertEq(address(pookyball.vrfCoordinator()), address(vrf)); + assertEq(pookyball.vrfKeyHash(), keccak256("foobar")); + assertEq(pookyball.vrfSubId(), subscriptionId); + assertEq(pookyball.vrfMinimumRequestConfirmations(), 10); + assertEq(pookyball.vrfCallbackGasLimit(), 2500000); + } + + function testFuzz_disable_vrf_changes() public { + assertEq(pookyball.canUpdateVRF(), true); + vm.prank(admin); + pookyball.disableUpdateVRF(); + assertEq(pookyball.canUpdateVRF(), false); + } + + function testFuzz_enable_vrf_usage() public { + assertEq(pookyball.canUseVRF(), false); + vm.prank(admin); + pookyball.enableVRF(); + assertEq(pookyball.canUseVRF(), true); + } + function testFuzz_fullfillRandomWords_revertOnlyCoordinatorCanFulfill(uint256 seed) public { + vm.prank(admin); + pookyball.enableVRF(); + uint256 tokenId = mintPookyball(user1); - uint256[] memory words = new uint[](1); + uint256[] memory words = new uint256[](1); words[0] = seed; vm.expectRevert( @@ -156,9 +185,12 @@ contract PookyballTest is BaseTest, AccessControlAssertions, PookyballSetup { } function testFuzz_fullfillRandomWords_passSingle(uint256 seed) public { + vm.prank(admin); + pookyball.enableVRF(); + uint256 tokenId = mintPookyball(user1); - uint256[] memory words = new uint[](1); + uint256[] memory words = new uint256[](1); words[0] = seed; vm.prank(address(vrf)); @@ -168,6 +200,9 @@ contract PookyballTest is BaseTest, AccessControlAssertions, PookyballSetup { } function testFuzz_fullfillRandomWords_passMulti(uint8 seed1, uint8 seed2) public { + vm.prank(admin); + pookyball.enableVRF(); + address[] memory addresses = new address[](2); addresses[0] = user1; addresses[1] = user1; @@ -181,7 +216,7 @@ contract PookyballTest is BaseTest, AccessControlAssertions, PookyballSetup { uint256 tokenId1 = tokenId2 - 1; // seeds are assigned in the reverse order - uint256[] memory words = new uint[](2); + uint256[] memory words = new uint256[](2); words[0] = seed2; words[1] = seed1; @@ -192,6 +227,22 @@ contract PookyballTest is BaseTest, AccessControlAssertions, PookyballSetup { assertEq(pookyball.metadata(tokenId2).seed, seed2); } + function testFuzz_mint_without_vrf() public { + assertEq(pookyball.canUseVRF(), false); + + address[] memory addresses = new address[](1); + addresses[0] = user1; + + PookyballRarity[] memory rarities = new PookyballRarity[](1); + rarities[0] = PookyballRarity.COMMON; + + vm.prank(minter); + uint256 tokenId1 = pookyball.mint(addresses, rarities); + assertEq(tokenId1, 1); + + assertNotEq(pookyball.metadata(tokenId1).seed, 0x0); + } + function test_setApprovalForAll_pass() public { vm.prank(user1); pookyball.setApprovalForAll(user2, true); From b0a752339b3e34b08d7375d70a53335ef3c6e549 Mon Sep 17 00:00:00 2001 From: Claudiu Date: Mon, 1 Apr 2024 20:09:17 +0300 Subject: [PATCH 04/10] feat(stickers): Add pseudo random seed and vrf update func --- src/common/BaseERC721A.sol | 75 ++++++++++++++++++++++++++++++------ test/stickers/Stickers.t.sol | 44 ++++++++++++++++++--- 2 files changed, 101 insertions(+), 18 deletions(-) diff --git a/src/common/BaseERC721A.sol b/src/common/BaseERC721A.sol index 2e2b3a7f..0f3ac7b8 100644 --- a/src/common/BaseERC721A.sol +++ b/src/common/BaseERC721A.sol @@ -1,16 +1,17 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.21; -import { VRFConsumerBaseV2 } from "chainlink/vrf/VRFConsumerBaseV2.sol"; +import { DefaultOperatorFilterer } from "operator-filter-registry/DefaultOperatorFilterer.sol"; +import { ERC2981 } from "openzeppelin/token/common/ERC2981.sol"; import { ERC721A } from "ERC721A/ERC721A.sol"; import { ERC721ABurnable } from "ERC721A/extensions/ERC721ABurnable.sol"; import { ERC721AQueryable } from "ERC721A/extensions/ERC721AQueryable.sol"; +import { IBaseERC721A } from "@/common/IBaseERC721A.sol"; import { IERC721A } from "ERC721A/IERC721A.sol"; -import { ERC2981 } from "openzeppelin/token/common/ERC2981.sol"; -import { DefaultOperatorFilterer } from "operator-filter-registry/DefaultOperatorFilterer.sol"; import { Ownable } from "solady/auth/Ownable.sol"; -import { IBaseERC721A } from "@/common/IBaseERC721A.sol"; import { VRFConfig } from "@/types/VRFConfig.sol"; +import { VRFConsumerBaseV2 } from "chainlink/vrf/VRFConsumerBaseV2.sol"; +import { VRFCoordinatorV2Interface } from "chainlink/interfaces/VRFCoordinatorV2Interface.sol"; /// @title BaseERC721A /// @author Mathieu Bour for Pooky Labs Ltd. @@ -41,6 +42,8 @@ contract BaseERC721A is // VRF parameters VRFConfig public vrf; mapping(uint256 => uint256) public vrfRequests; + bool public canUpdateVRF = true; + bool public canUseVRF = false; /// The random numbers associated with the tokens: tokenId => randomWord. mapping(uint256 => uint256) public seeds; @@ -115,15 +118,24 @@ contract BaseERC721A is function _mint(address to, uint256 quantity) internal virtual override { super._mint(to, quantity); - uint256 requestId = vrf.coordinator.requestRandomWords( - vrf.keyHash, - vrf.subcriptionId, - vrf.minimumRequestConfirmations, - vrf.callbackGasLimit, - uint32(quantity) - ); + if (canUseVRF) { + // Request entropy from the VRF coordinator + uint256 requestId = vrf.coordinator.requestRandomWords( + vrf.keyHash, + vrf.subcriptionId, + vrf.minimumRequestConfirmations, + vrf.callbackGasLimit, + uint32(quantity) + ); - vrfRequests[requestId] = _totalMinted(); + vrfRequests[requestId] = _totalMinted(); + } else { + for (uint256 i = 0; i < quantity; i++) { + uint256 tokenId = _totalMinted() - i; + seeds[tokenId] = generateRandomSeed(tokenId); + emit SeedSet(tokenId, seeds[tokenId]); + } + } } /// @notice Receive the entropy from the VRF coordinator. @@ -217,4 +229,43 @@ contract BaseERC721A is { return super.supportsInterface(interfaceId) || ERC721A.supportsInterface(interfaceId); } + + // disable update vrf + function disableUpdateVRF() external onlyOwner { + canUpdateVRF = false; + } + + // enable vrf usage + function enableVRF() external onlyOwner { + canUseVRF = true; + } + + // update vrf + function updateVRF( + address _vrfCoordinator, + bytes32 _vrfKeyHash, + uint64 _vrfSubId, + uint16 _vrfMinimumRequestConfirmations, + uint32 _vrfCallbackGasLimit + ) external onlyOwner { + require(canUpdateVRF, "VRF can't be updated"); + vrf = VRFConfig( + VRFCoordinatorV2Interface(_vrfCoordinator), + _vrfKeyHash, + _vrfSubId, + _vrfMinimumRequestConfirmations, + _vrfCallbackGasLimit + ); + } + + // generate pseudo random seed + function generateRandomSeed(uint256 tokenId) public view returns (uint256) { + // Hash the combination of block timestamp, sender's address, and token ID + bytes32 hash = keccak256(abi.encodePacked(block.timestamp, msg.sender, tokenId)); + + // Convert the hash to a uint256 + uint256 randomSeed = uint256(hash); + + return randomSeed; + } } diff --git a/test/stickers/Stickers.t.sol b/test/stickers/Stickers.t.sol index 087164a4..efe19e9e 100644 --- a/test/stickers/Stickers.t.sol +++ b/test/stickers/Stickers.t.sol @@ -1,12 +1,14 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.21; -import { VRFConsumerBaseV2 } from "chainlink/vrf/VRFConsumerBaseV2.sol"; -import { Strings } from "openzeppelin/utils/Strings.sol"; +import { BaseTest } from "@test/BaseTest.sol"; import { Ownable } from "solady/auth/Ownable.sol"; import { StickerMetadata, StickerMint, StickerRarity } from "@/stickers/IStickers.sol"; -import { BaseTest } from "@test/BaseTest.sol"; import { StickersSetup } from "@test/setup/StickersSetup.sol"; +import { Strings } from "openzeppelin/utils/Strings.sol"; +import { VRFConfig } from "@/types/VRFConfig.sol"; +import { VRFConsumerBaseV2 } from "chainlink/vrf/VRFConsumerBaseV2.sol"; +import { VRFCoordinatorV2Interface } from "chainlink/interfaces/VRFCoordinatorV2Interface.sol"; contract StickersTest is BaseTest, StickersSetup { using Strings for uint256; @@ -45,6 +47,27 @@ contract StickersTest is BaseTest, StickersSetup { assertEq(bytes(stickers.baseURI()), bytes(newURI)); } + function testFuzz_updateVRF() public { + uint64 subscriptionId = vrf.createSubscription(); + + vm.prank(admin); + stickers.updateVRF(address(vrf), keccak256("foobar"), subscriptionId, 10, 2500000); + } + + function testFuzz_disable_vrf_changes() public { + assertEq(stickers.canUpdateVRF(), true); + vm.prank(admin); + stickers.disableUpdateVRF(); + assertEq(stickers.canUpdateVRF(), false); + } + + function testFuzz_enable_vrf_usage() public { + assertEq(stickers.canUseVRF(), false); + vm.prank(admin); + stickers.enableVRF(); + assertEq(stickers.canUseVRF(), true); + } + function test_tokenURI_pass() public { uint256 tokenId = mintSticker(user1); @@ -96,9 +119,12 @@ contract StickersTest is BaseTest, StickersSetup { } function testFuzz_fullfillRandomWords_revertOnlyCoordinatorCanFulfill(uint256 seed) public { + vm.prank(admin); + stickers.enableVRF(); + uint256 tokenId = mintSticker(user1); - uint256[] memory words = new uint[](1); + uint256[] memory words = new uint256[](1); words[0] = seed; vm.expectRevert( @@ -113,9 +139,12 @@ contract StickersTest is BaseTest, StickersSetup { } function testFuzz_fullfillRandomWords_passSingle(uint256 seed) public { + vm.prank(admin); + stickers.enableVRF(); + uint256 tokenId = mintSticker(user1); - uint256[] memory words = new uint[](1); + uint256[] memory words = new uint256[](1); words[0] = seed; vm.prank(address(vrf)); @@ -125,6 +154,9 @@ contract StickersTest is BaseTest, StickersSetup { } function testFuzz_fullfillRandomWords_passMulti(uint256 seed1, uint256 seed2) public { + vm.prank(admin); + stickers.enableVRF(); + StickerRarity[] memory rarities = new StickerRarity[](2); rarities[0] = randomStickerRarity(seed1); rarities[1] = randomStickerRarity(seed2); @@ -135,7 +167,7 @@ contract StickersTest is BaseTest, StickersSetup { uint256 tokenId1 = tokenId2 - 1; // seeds are assigned in the reverse order - uint256[] memory words = new uint[](2); + uint256[] memory words = new uint256[](2); words[0] = seed2; words[1] = seed1; From 044fbf249fee64ed821acb7000d0ad15354df39a Mon Sep 17 00:00:00 2001 From: Claudiu Date: Mon, 1 Apr 2024 20:09:50 +0300 Subject: [PATCH 05/10] feat(contracts): Add flattened contracts --- flattened/BoostPXP.sol | 1705 +++++++++++++ flattened/Energy.sol | 4009 ++++++++++++++++++++++++++++++ flattened/NonceRegistry.sol | 974 ++++++++ flattened/POK.sol | 1459 +++++++++++ flattened/Pookyball.sol | 2818 +++++++++++++++++++++ flattened/PookyballAscension.sol | 2407 ++++++++++++++++++ flattened/PookyballLevelUp.sol | 1968 +++++++++++++++ flattened/PookyballReroll.sol | 1704 +++++++++++++ flattened/Pressure.sol | 313 +++ flattened/RefillableSale.sol | 1787 +++++++++++++ flattened/Rewards.sol | 2275 +++++++++++++++++ flattened/Stickers.sol | 3741 ++++++++++++++++++++++++++++ flattened/StickersAscension.sol | 2470 ++++++++++++++++++ flattened/StickersController.sol | 2128 ++++++++++++++++ flattened/StickersLevelUp.sol | 2432 ++++++++++++++++++ flattened/StickersManager.sol | 965 +++++++ flattened/StickersSale.sol | 1544 ++++++++++++ 17 files changed, 34699 insertions(+) create mode 100644 flattened/BoostPXP.sol create mode 100644 flattened/Energy.sol create mode 100644 flattened/NonceRegistry.sol create mode 100644 flattened/POK.sol create mode 100644 flattened/Pookyball.sol create mode 100644 flattened/PookyballAscension.sol create mode 100644 flattened/PookyballLevelUp.sol create mode 100644 flattened/PookyballReroll.sol create mode 100644 flattened/Pressure.sol create mode 100644 flattened/RefillableSale.sol create mode 100644 flattened/Rewards.sol create mode 100644 flattened/Stickers.sol create mode 100644 flattened/StickersAscension.sol create mode 100644 flattened/StickersController.sol create mode 100644 flattened/StickersLevelUp.sol create mode 100644 flattened/StickersManager.sol create mode 100644 flattened/StickersSale.sol diff --git a/flattened/BoostPXP.sol b/flattened/BoostPXP.sol new file mode 100644 index 00000000..8ff5f7d4 --- /dev/null +++ b/flattened/BoostPXP.sol @@ -0,0 +1,1705 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0 ^0.8.17 ^0.8.21 ^0.8.4; + +// lib/openzeppelin-contracts/contracts\access/IAccessControl.sol + +// OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol) + + + +/** + * @dev External interface of AccessControl declared to support ERC165 detection. + */ +interface IAccessControl { + /** + * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` + * + * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite + * {RoleAdminChanged} not being emitted signaling this. + * + * _Available since v3.1._ + */ + event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole); + + /** + * @dev Emitted when `account` is granted `role`. + * + * `sender` is the account that originated the contract call, an admin role + * bearer except when using {AccessControl-_setupRole}. + */ + event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender); + + /** + * @dev Emitted when `account` is revoked `role`. + * + * `sender` is the account that originated the contract call: + * - if using `revokeRole`, it is the admin role bearer + * - if using `renounceRole`, it is the role bearer (i.e. `account`) + */ + event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender); + + /** + * @dev Returns `true` if `account` has been granted `role`. + */ + function hasRole(bytes32 role, address account) external view returns (bool); + + /** + * @dev Returns the admin role that controls `role`. See {grantRole} and + * {revokeRole}. + * + * To change a role's admin, use {AccessControl-_setRoleAdmin}. + */ + function getRoleAdmin(bytes32 role) external view returns (bytes32); + + /** + * @dev Grants `role` to `account`. + * + * If `account` had not been already granted `role`, emits a {RoleGranted} + * event. + * + * Requirements: + * + * - the caller must have ``role``'s admin role. + */ + function grantRole(bytes32 role, address account) external; + + /** + * @dev Revokes `role` from `account`. + * + * If `account` had been granted `role`, emits a {RoleRevoked} event. + * + * Requirements: + * + * - the caller must have ``role``'s admin role. + */ + function revokeRole(bytes32 role, address account) external; + + /** + * @dev Revokes `role` from the calling account. + * + * Roles are often managed via {grantRole} and {revokeRole}: this function's + * purpose is to provide a mechanism for accounts to lose their privileges + * if they are compromised (such as when a trusted device is misplaced). + * + * If the calling account had been granted `role`, emits a {RoleRevoked} + * event. + * + * Requirements: + * + * - the caller must be `account`. + */ + function renounceRole(bytes32 role, address account) external; +} + +// lib/openzeppelin-contracts/contracts/utils/introspection/IERC165.sol + +// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol) + + + +/** + * @dev Interface of the ERC165 standard, as defined in the + * https://eips.ethereum.org/EIPS/eip-165[EIP]. + * + * Implementers can declare support of contract interfaces, which can then be + * queried by others ({ERC165Checker}). + * + * For an implementation, see {ERC165}. + */ +interface IERC165 { + /** + * @dev Returns true if this contract implements the interface defined by + * `interfaceId`. See the corresponding + * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] + * to learn more about how these ids are created. + * + * This function call must use less than 30 000 gas. + */ + function supportsInterface(bytes4 interfaceId) external view returns (bool); +} + +// lib/solady/src/auth/Ownable.sol + + + +/// @notice Simple single owner authorization mixin. +/// @author Solady (https://github.com/vectorized/solady/blob/main/src/auth/Ownable.sol) +/// @dev While the ownable portion follows +/// [EIP-173](https://eips.ethereum.org/EIPS/eip-173) for compatibility, +/// the nomenclature for the 2-step ownership handover may be unique to this codebase. +abstract contract Ownable { + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* CUSTOM ERRORS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev The caller is not authorized to call the function. + error Unauthorized(); + + /// @dev The `newOwner` cannot be the zero address. + error NewOwnerIsZeroAddress(); + + /// @dev The `pendingOwner` does not have a valid handover request. + error NoHandoverRequest(); + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* EVENTS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev The ownership is transferred from `oldOwner` to `newOwner`. + /// This event is intentionally kept the same as OpenZeppelin's Ownable to be + /// compatible with indexers and [EIP-173](https://eips.ethereum.org/EIPS/eip-173), + /// despite it not being as lightweight as a single argument event. + event OwnershipTransferred(address indexed oldOwner, address indexed newOwner); + + /// @dev An ownership handover to `pendingOwner` has been requested. + event OwnershipHandoverRequested(address indexed pendingOwner); + + /// @dev The ownership handover to `pendingOwner` has been canceled. + event OwnershipHandoverCanceled(address indexed pendingOwner); + + /// @dev `keccak256(bytes("OwnershipTransferred(address,address)"))`. + uint256 private constant _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE = + 0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0; + + /// @dev `keccak256(bytes("OwnershipHandoverRequested(address)"))`. + uint256 private constant _OWNERSHIP_HANDOVER_REQUESTED_EVENT_SIGNATURE = + 0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d; + + /// @dev `keccak256(bytes("OwnershipHandoverCanceled(address)"))`. + uint256 private constant _OWNERSHIP_HANDOVER_CANCELED_EVENT_SIGNATURE = + 0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92; + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* STORAGE */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev The owner slot is given by: `not(_OWNER_SLOT_NOT)`. + /// It is intentionally chosen to be a high value + /// to avoid collision with lower slots. + /// The choice of manual storage layout is to enable compatibility + /// with both regular and upgradeable contracts. + uint256 private constant _OWNER_SLOT_NOT = 0x8b78c6d8; + + /// The ownership handover slot of `newOwner` is given by: + /// ``` + /// mstore(0x00, or(shl(96, user), _HANDOVER_SLOT_SEED)) + /// let handoverSlot := keccak256(0x00, 0x20) + /// ``` + /// It stores the expiry timestamp of the two-step ownership handover. + uint256 private constant _HANDOVER_SLOT_SEED = 0x389a75e1; + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* INTERNAL FUNCTIONS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev Initializes the owner directly without authorization guard. + /// This function must be called upon initialization, + /// regardless of whether the contract is upgradeable or not. + /// This is to enable generalization to both regular and upgradeable contracts, + /// and to save gas in case the initial owner is not the caller. + /// For performance reasons, this function will not check if there + /// is an existing owner. + function _initializeOwner(address newOwner) internal virtual { + /// @solidity memory-safe-assembly + assembly { + // Clean the upper 96 bits. + newOwner := shr(96, shl(96, newOwner)) + // Store the new value. + sstore(not(_OWNER_SLOT_NOT), newOwner) + // Emit the {OwnershipTransferred} event. + log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, 0, newOwner) + } + } + + /// @dev Sets the owner directly without authorization guard. + function _setOwner(address newOwner) internal virtual { + /// @solidity memory-safe-assembly + assembly { + let ownerSlot := not(_OWNER_SLOT_NOT) + // Clean the upper 96 bits. + newOwner := shr(96, shl(96, newOwner)) + // Emit the {OwnershipTransferred} event. + log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, sload(ownerSlot), newOwner) + // Store the new value. + sstore(ownerSlot, newOwner) + } + } + + /// @dev Throws if the sender is not the owner. + function _checkOwner() internal view virtual { + /// @solidity memory-safe-assembly + assembly { + // If the caller is not the stored owner, revert. + if iszero(eq(caller(), sload(not(_OWNER_SLOT_NOT)))) { + mstore(0x00, 0x82b42900) // `Unauthorized()`. + revert(0x1c, 0x04) + } + } + } + + /// @dev Returns how long a two-step ownership handover is valid for in seconds. + /// Override to return a different value if needed. + /// Made internal to conserve bytecode. Wrap it in a public function if needed. + function _ownershipHandoverValidFor() internal view virtual returns (uint64) { + return 48 * 3600; + } + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* PUBLIC UPDATE FUNCTIONS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev Allows the owner to transfer the ownership to `newOwner`. + function transferOwnership(address newOwner) public payable virtual onlyOwner { + /// @solidity memory-safe-assembly + assembly { + if iszero(shl(96, newOwner)) { + mstore(0x00, 0x7448fbae) // `NewOwnerIsZeroAddress()`. + revert(0x1c, 0x04) + } + } + _setOwner(newOwner); + } + + /// @dev Allows the owner to renounce their ownership. + function renounceOwnership() public payable virtual onlyOwner { + _setOwner(address(0)); + } + + /// @dev Request a two-step ownership handover to the caller. + /// The request will automatically expire in 48 hours (172800 seconds) by default. + function requestOwnershipHandover() public payable virtual { + unchecked { + uint256 expires = block.timestamp + _ownershipHandoverValidFor(); + /// @solidity memory-safe-assembly + assembly { + // Compute and set the handover slot to `expires`. + mstore(0x0c, _HANDOVER_SLOT_SEED) + mstore(0x00, caller()) + sstore(keccak256(0x0c, 0x20), expires) + // Emit the {OwnershipHandoverRequested} event. + log2(0, 0, _OWNERSHIP_HANDOVER_REQUESTED_EVENT_SIGNATURE, caller()) + } + } + } + + /// @dev Cancels the two-step ownership handover to the caller, if any. + function cancelOwnershipHandover() public payable virtual { + /// @solidity memory-safe-assembly + assembly { + // Compute and set the handover slot to 0. + mstore(0x0c, _HANDOVER_SLOT_SEED) + mstore(0x00, caller()) + sstore(keccak256(0x0c, 0x20), 0) + // Emit the {OwnershipHandoverCanceled} event. + log2(0, 0, _OWNERSHIP_HANDOVER_CANCELED_EVENT_SIGNATURE, caller()) + } + } + + /// @dev Allows the owner to complete the two-step ownership handover to `pendingOwner`. + /// Reverts if there is no existing ownership handover requested by `pendingOwner`. + function completeOwnershipHandover(address pendingOwner) public payable virtual onlyOwner { + /// @solidity memory-safe-assembly + assembly { + // Compute and set the handover slot to 0. + mstore(0x0c, _HANDOVER_SLOT_SEED) + mstore(0x00, pendingOwner) + let handoverSlot := keccak256(0x0c, 0x20) + // If the handover does not exist, or has expired. + if gt(timestamp(), sload(handoverSlot)) { + mstore(0x00, 0x6f5e8818) // `NoHandoverRequest()`. + revert(0x1c, 0x04) + } + // Set the handover slot to 0. + sstore(handoverSlot, 0) + } + _setOwner(pendingOwner); + } + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* PUBLIC READ FUNCTIONS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev Returns the owner of the contract. + function owner() public view virtual returns (address result) { + /// @solidity memory-safe-assembly + assembly { + result := sload(not(_OWNER_SLOT_NOT)) + } + } + + /// @dev Returns the expiry timestamp for the two-step ownership handover to `pendingOwner`. + function ownershipHandoverExpiresAt(address pendingOwner) + public + view + virtual + returns (uint256 result) + { + /// @solidity memory-safe-assembly + assembly { + // Compute the handover slot. + mstore(0x0c, _HANDOVER_SLOT_SEED) + mstore(0x00, pendingOwner) + // Load the handover slot. + result := sload(keccak256(0x0c, 0x20)) + } + } + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* MODIFIERS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev Marks a function as only callable by the owner. + modifier onlyOwner() virtual { + _checkOwner(); + _; + } +} + +// lib/solady/src\utils/ECDSA.sol + + + +/// @notice Gas optimized ECDSA wrapper. +/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/ECDSA.sol) +/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/ECDSA.sol) +/// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/cryptography/ECDSA.sol) +library ECDSA { + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* CUSTOM ERRORS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev The signature is invalid. + error InvalidSignature(); + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* CONSTANTS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev The number which `s` must be less than in order for + /// the signature to be non-malleable. + bytes32 private constant _MALLEABILITY_THRESHOLD_PLUS_ONE = + 0x7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a1; + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* RECOVERY OPERATIONS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + // Note: as of Solady version 0.0.68, these functions will + // revert upon recovery failure for more safety by default. + + /// @dev Recovers the signer's address from a message digest `hash`, + /// and the `signature`. + /// + /// This function does NOT accept EIP-2098 short form signatures. + /// Use `recover(bytes32 hash, bytes32 r, bytes32 vs)` for EIP-2098 + /// short form signatures instead. + function recover(bytes32 hash, bytes memory signature) internal view returns (address result) { + /// @solidity memory-safe-assembly + assembly { + let m := mload(0x40) // Cache the free memory pointer. + mstore(0x00, hash) + mstore(0x20, byte(0, mload(add(signature, 0x60)))) // `v`. + mstore(0x40, mload(add(signature, 0x20))) // `r`. + mstore(0x60, mload(add(signature, 0x40))) // `s`. + pop( + staticcall( + gas(), // Amount of gas left for the transaction. + and( + // If the signature is exactly 65 bytes in length. + eq(mload(signature), 65), + // If `s` in lower half order, such that the signature is not malleable. + lt(mload(0x60), _MALLEABILITY_THRESHOLD_PLUS_ONE) + ), // Address of `ecrecover`. + 0x00, // Start of input. + 0x80, // Size of input. + 0x00, // Start of output. + 0x20 // Size of output. + ) + ) + result := mload(0x00) + // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise. + if iszero(returndatasize()) { + mstore(0x00, 0x8baa579f) // `InvalidSignature()`. + revert(0x1c, 0x04) + } + mstore(0x60, 0) // Restore the zero slot. + mstore(0x40, m) // Restore the free memory pointer. + } + } + + /// @dev Recovers the signer's address from a message digest `hash`, + /// and the `signature`. + /// + /// This function does NOT accept EIP-2098 short form signatures. + /// Use `recover(bytes32 hash, bytes32 r, bytes32 vs)` for EIP-2098 + /// short form signatures instead. + function recoverCalldata(bytes32 hash, bytes calldata signature) + internal + view + returns (address result) + { + /// @solidity memory-safe-assembly + assembly { + let m := mload(0x40) // Cache the free memory pointer. + mstore(0x00, hash) + mstore(0x20, byte(0, calldataload(add(signature.offset, 0x40)))) // `v`. + calldatacopy(0x40, signature.offset, 0x40) // Copy `r` and `s`. + pop( + staticcall( + gas(), // Amount of gas left for the transaction. + and( + // If the signature is exactly 65 bytes in length. + eq(signature.length, 65), + // If `s` in lower half order, such that the signature is not malleable. + lt(mload(0x60), _MALLEABILITY_THRESHOLD_PLUS_ONE) + ), // Address of `ecrecover`. + 0x00, // Start of input. + 0x80, // Size of input. + 0x00, // Start of output. + 0x20 // Size of output. + ) + ) + result := mload(0x00) + // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise. + if iszero(returndatasize()) { + mstore(0x00, 0x8baa579f) // `InvalidSignature()`. + revert(0x1c, 0x04) + } + mstore(0x60, 0) // Restore the zero slot. + mstore(0x40, m) // Restore the free memory pointer. + } + } + + /// @dev Recovers the signer's address from a message digest `hash`, + /// and the EIP-2098 short form signature defined by `r` and `vs`. + /// + /// This function only accepts EIP-2098 short form signatures. + /// See: https://eips.ethereum.org/EIPS/eip-2098 + function recover(bytes32 hash, bytes32 r, bytes32 vs) internal view returns (address result) { + /// @solidity memory-safe-assembly + assembly { + let m := mload(0x40) // Cache the free memory pointer. + mstore(0x00, hash) + mstore(0x20, add(shr(255, vs), 27)) // `v`. + mstore(0x40, r) + mstore(0x60, shr(1, shl(1, vs))) // `s`. + pop( + staticcall( + gas(), // Amount of gas left for the transaction. + // If `s` in lower half order, such that the signature is not malleable. + lt(mload(0x60), _MALLEABILITY_THRESHOLD_PLUS_ONE), // Address of `ecrecover`. + 0x00, // Start of input. + 0x80, // Size of input. + 0x00, // Start of output. + 0x20 // Size of output. + ) + ) + result := mload(0x00) + // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise. + if iszero(returndatasize()) { + mstore(0x00, 0x8baa579f) // `InvalidSignature()`. + revert(0x1c, 0x04) + } + mstore(0x60, 0) // Restore the zero slot. + mstore(0x40, m) // Restore the free memory pointer. + } + } + + /// @dev Recovers the signer's address from a message digest `hash`, + /// and the signature defined by `v`, `r`, `s`. + function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) + internal + view + returns (address result) + { + /// @solidity memory-safe-assembly + assembly { + let m := mload(0x40) // Cache the free memory pointer. + mstore(0x00, hash) + mstore(0x20, and(v, 0xff)) + mstore(0x40, r) + mstore(0x60, s) + pop( + staticcall( + gas(), // Amount of gas left for the transaction. + // If `s` in lower half order, such that the signature is not malleable. + lt(s, _MALLEABILITY_THRESHOLD_PLUS_ONE), // Address of `ecrecover`. + 0x00, // Start of input. + 0x80, // Size of input. + 0x00, // Start of output. + 0x20 // Size of output. + ) + ) + result := mload(0x00) + // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise. + if iszero(returndatasize()) { + mstore(0x00, 0x8baa579f) // `InvalidSignature()`. + revert(0x1c, 0x04) + } + mstore(0x60, 0) // Restore the zero slot. + mstore(0x40, m) // Restore the free memory pointer. + } + } + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* TRY-RECOVER OPERATIONS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + // WARNING! + // These functions will NOT revert upon recovery failure. + // Instead, they will return the zero address upon recovery failure. + // It is critical that the returned address is NEVER compared against + // a zero address (e.g. an uninitialized address variable). + + /// @dev Recovers the signer's address from a message digest `hash`, + /// and the `signature`. + /// + /// This function does NOT accept EIP-2098 short form signatures. + /// Use `recover(bytes32 hash, bytes32 r, bytes32 vs)` for EIP-2098 + /// short form signatures instead. + function tryRecover(bytes32 hash, bytes memory signature) + internal + view + returns (address result) + { + /// @solidity memory-safe-assembly + assembly { + let m := mload(0x40) // Cache the free memory pointer. + mstore(0x00, hash) + mstore(0x20, byte(0, mload(add(signature, 0x60)))) // `v`. + mstore(0x40, mload(add(signature, 0x20))) // `r`. + mstore(0x60, mload(add(signature, 0x40))) // `s`. + pop( + staticcall( + gas(), // Amount of gas left for the transaction. + and( + // If the signature is exactly 65 bytes in length. + eq(mload(signature), 65), + // If `s` in lower half order, such that the signature is not malleable. + lt(mload(0x60), _MALLEABILITY_THRESHOLD_PLUS_ONE) + ), // Address of `ecrecover`. + 0x00, // Start of input. + 0x80, // Size of input. + 0x40, // Start of output. + 0x20 // Size of output. + ) + ) + mstore(0x60, 0) // Restore the zero slot. + // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise. + result := mload(xor(0x60, returndatasize())) + mstore(0x40, m) // Restore the free memory pointer. + } + } + + /// @dev Recovers the signer's address from a message digest `hash`, + /// and the `signature`. + /// + /// This function does NOT accept EIP-2098 short form signatures. + /// Use `recover(bytes32 hash, bytes32 r, bytes32 vs)` for EIP-2098 + /// short form signatures instead. + function tryRecoverCalldata(bytes32 hash, bytes calldata signature) + internal + view + returns (address result) + { + /// @solidity memory-safe-assembly + assembly { + let m := mload(0x40) // Cache the free memory pointer. + mstore(0x00, hash) + mstore(0x20, byte(0, calldataload(add(signature.offset, 0x40)))) // `v`. + calldatacopy(0x40, signature.offset, 0x40) // Copy `r` and `s`. + pop( + staticcall( + gas(), // Amount of gas left for the transaction. + and( + // If the signature is exactly 65 bytes in length. + eq(signature.length, 65), + // If `s` in lower half order, such that the signature is not malleable. + lt(mload(0x60), _MALLEABILITY_THRESHOLD_PLUS_ONE) + ), // Address of `ecrecover`. + 0x00, // Start of input. + 0x80, // Size of input. + 0x40, // Start of output. + 0x20 // Size of output. + ) + ) + mstore(0x60, 0) // Restore the zero slot. + // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise. + result := mload(xor(0x60, returndatasize())) + mstore(0x40, m) // Restore the free memory pointer. + } + } + + /// @dev Recovers the signer's address from a message digest `hash`, + /// and the EIP-2098 short form signature defined by `r` and `vs`. + /// + /// This function only accepts EIP-2098 short form signatures. + /// See: https://eips.ethereum.org/EIPS/eip-2098 + function tryRecover(bytes32 hash, bytes32 r, bytes32 vs) + internal + view + returns (address result) + { + /// @solidity memory-safe-assembly + assembly { + let m := mload(0x40) // Cache the free memory pointer. + mstore(0x00, hash) + mstore(0x20, add(shr(255, vs), 27)) // `v`. + mstore(0x40, r) + mstore(0x60, shr(1, shl(1, vs))) // `s`. + pop( + staticcall( + gas(), // Amount of gas left for the transaction. + // If `s` in lower half order, such that the signature is not malleable. + lt(mload(0x60), _MALLEABILITY_THRESHOLD_PLUS_ONE), // Address of `ecrecover`. + 0x00, // Start of input. + 0x80, // Size of input. + 0x40, // Start of output. + 0x20 // Size of output. + ) + ) + mstore(0x60, 0) // Restore the zero slot. + // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise. + result := mload(xor(0x60, returndatasize())) + mstore(0x40, m) // Restore the free memory pointer. + } + } + + /// @dev Recovers the signer's address from a message digest `hash`, + /// and the signature defined by `v`, `r`, `s`. + function tryRecover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) + internal + view + returns (address result) + { + /// @solidity memory-safe-assembly + assembly { + let m := mload(0x40) // Cache the free memory pointer. + mstore(0x00, hash) + mstore(0x20, and(v, 0xff)) + mstore(0x40, r) + mstore(0x60, s) + pop( + staticcall( + gas(), // Amount of gas left for the transaction. + // If `s` in lower half order, such that the signature is not malleable. + lt(s, _MALLEABILITY_THRESHOLD_PLUS_ONE), // Address of `ecrecover`. + 0x00, // Start of input. + 0x80, // Size of input. + 0x40, // Start of output. + 0x20 // Size of output. + ) + ) + mstore(0x60, 0) // Restore the zero slot. + // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise. + result := mload(xor(0x60, returndatasize())) + mstore(0x40, m) // Restore the free memory pointer. + } + } + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* HASHING OPERATIONS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev Returns an Ethereum Signed Message, created from a `hash`. + /// This produces a hash corresponding to the one signed with the + /// [`eth_sign`](https://eth.wiki/json-rpc/API#eth_sign) + /// JSON-RPC method as part of EIP-191. + function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32 result) { + /// @solidity memory-safe-assembly + assembly { + mstore(0x20, hash) // Store into scratch space for keccak256. + mstore(0x00, "\x00\x00\x00\x00\x19Ethereum Signed Message:\n32") // 28 bytes. + result := keccak256(0x04, 0x3c) // `32 * 2 - (32 - 28) = 60 = 0x3c`. + } + } + + /// @dev Returns an Ethereum Signed Message, created from `s`. + /// This produces a hash corresponding to the one signed with the + /// [`eth_sign`](https://eth.wiki/json-rpc/API#eth_sign) + /// JSON-RPC method as part of EIP-191. + /// Note: Supports lengths of `s` up to 999999 bytes. + function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32 result) { + /// @solidity memory-safe-assembly + assembly { + let sLength := mload(s) + let o := 0x20 + mstore(o, "\x19Ethereum Signed Message:\n") // 26 bytes, zero-right-padded. + mstore(0x00, 0x00) + // Convert the `s.length` to ASCII decimal representation: `base10(s.length)`. + for { let temp := sLength } 1 {} { + o := sub(o, 1) + mstore8(o, add(48, mod(temp, 10))) + temp := div(temp, 10) + if iszero(temp) { break } + } + let n := sub(0x3a, o) // Header length: `26 + 32 - o`. + // Throw an out-of-offset error (consumes all gas) if the header exceeds 32 bytes. + returndatacopy(returndatasize(), returndatasize(), gt(n, 0x20)) + mstore(s, or(mload(0x00), mload(n))) // Temporarily store the header. + result := keccak256(add(s, sub(0x20, n)), add(n, sLength)) + mstore(s, sLength) // Restore the length. + } + } + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* EMPTY CALLDATA HELPERS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev Returns an empty calldata bytes. + function emptySignature() internal pure returns (bytes calldata signature) { + /// @solidity memory-safe-assembly + assembly { + signature.length := 0 + } + } +} + +// src\common/ITreasury.sol + + + +/// @title ITreasury +/// @author Mathieu Bour for Pooky Labs Ltd. +interface ITreasury { + /// Thrown when the msg.value of the mint function does not cover the mint cost. + error InsufficientValue(uint256 expected, uint256 actual); + /// Thrown when the native transfer has failed. + error TransferFailed(address recipient, uint256 amount); + + /// Change the native currency destination address. + /// @param _treasury The new treasury address. + function changeTreasury(address _treasury) external; +} + +// lib/openzeppelin-contracts/contracts\interfaces/IERC2981.sol + +// OpenZeppelin Contracts (last updated v4.9.0) (interfaces/IERC2981.sol) + + + + + +/** + * @dev Interface for the NFT Royalty Standard. + * + * A standardized way to retrieve royalty payment information for non-fungible tokens (NFTs) to enable universal + * support for royalty payments across all NFT marketplaces and ecosystem participants. + * + * _Available since v4.5._ + */ +interface IERC2981 is IERC165 { + /** + * @dev Returns how much royalty is owed and to whom, based on a sale price that may be denominated in any unit of + * exchange. The royalty amount is denominated and should be paid in that same unit of exchange. + */ + function royaltyInfo( + uint256 tokenId, + uint256 salePrice + ) external view returns (address receiver, uint256 royaltyAmount); +} + +// lib/openzeppelin-contracts/contracts\token/ERC721/IERC721.sol + +// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC721/IERC721.sol) + + + + + +/** + * @dev Required interface of an ERC721 compliant contract. + */ +interface IERC721 is IERC165 { + /** + * @dev Emitted when `tokenId` token is transferred from `from` to `to`. + */ + event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); + + /** + * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token. + */ + event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); + + /** + * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets. + */ + event ApprovalForAll(address indexed owner, address indexed operator, bool approved); + + /** + * @dev Returns the number of tokens in ``owner``'s account. + */ + function balanceOf(address owner) external view returns (uint256 balance); + + /** + * @dev Returns the owner of the `tokenId` token. + * + * Requirements: + * + * - `tokenId` must exist. + */ + function ownerOf(uint256 tokenId) external view returns (address owner); + + /** + * @dev Safely transfers `tokenId` token from `from` to `to`. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must exist and be owned by `from`. + * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. + * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. + * + * Emits a {Transfer} event. + */ + function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external; + + /** + * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients + * are aware of the ERC721 protocol to prevent tokens from being forever locked. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must exist and be owned by `from`. + * - If the caller is not `from`, it must have been allowed to move this token by either {approve} or {setApprovalForAll}. + * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. + * + * Emits a {Transfer} event. + */ + function safeTransferFrom(address from, address to, uint256 tokenId) external; + + /** + * @dev Transfers `tokenId` token from `from` to `to`. + * + * WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721 + * or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must + * understand this adds an external call which potentially creates a reentrancy vulnerability. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must be owned by `from`. + * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. + * + * Emits a {Transfer} event. + */ + function transferFrom(address from, address to, uint256 tokenId) external; + + /** + * @dev Gives permission to `to` to transfer `tokenId` token to another account. + * The approval is cleared when the token is transferred. + * + * Only a single account can be approved at a time, so approving the zero address clears previous approvals. + * + * Requirements: + * + * - The caller must own the token or be an approved operator. + * - `tokenId` must exist. + * + * Emits an {Approval} event. + */ + function approve(address to, uint256 tokenId) external; + + /** + * @dev Approve or remove `operator` as an operator for the caller. + * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller. + * + * Requirements: + * + * - The `operator` cannot be the caller. + * + * Emits an {ApprovalForAll} event. + */ + function setApprovalForAll(address operator, bool approved) external; + + /** + * @dev Returns the account approved for `tokenId` token. + * + * Requirements: + * + * - `tokenId` must exist. + */ + function getApproved(uint256 tokenId) external view returns (address operator); + + /** + * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`. + * + * See {setApprovalForAll} + */ + function isApprovedForAll(address owner, address operator) external view returns (bool); +} + +// lib/solady/src\auth/OwnableRoles.sol + + + + + +/// @notice Simple single owner and multiroles authorization mixin. +/// @author Solady (https://github.com/vectorized/solady/blob/main/src/auth/Ownable.sol) +/// @dev While the ownable portion follows [EIP-173](https://eips.ethereum.org/EIPS/eip-173) +/// for compatibility, the nomenclature for the 2-step ownership handover and roles +/// may be unique to this codebase. +abstract contract OwnableRoles is Ownable { + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* EVENTS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev The `user`'s roles is updated to `roles`. + /// Each bit of `roles` represents whether the role is set. + event RolesUpdated(address indexed user, uint256 indexed roles); + + /// @dev `keccak256(bytes("RolesUpdated(address,uint256)"))`. + uint256 private constant _ROLES_UPDATED_EVENT_SIGNATURE = + 0x715ad5ce61fc9595c7b415289d59cf203f23a94fa06f04af7e489a0a76e1fe26; + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* STORAGE */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev The role slot of `user` is given by: + /// ``` + /// mstore(0x00, or(shl(96, user), _ROLE_SLOT_SEED)) + /// let roleSlot := keccak256(0x00, 0x20) + /// ``` + /// This automatically ignores the upper bits of the `user` in case + /// they are not clean, as well as keep the `keccak256` under 32-bytes. + /// + /// Note: This is equal to `_OWNER_SLOT_NOT` in for gas efficiency. + uint256 private constant _ROLE_SLOT_SEED = 0x8b78c6d8; + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* INTERNAL FUNCTIONS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev Overwrite the roles directly without authorization guard. + function _setRoles(address user, uint256 roles) internal virtual { + /// @solidity memory-safe-assembly + assembly { + mstore(0x0c, _ROLE_SLOT_SEED) + mstore(0x00, user) + // Store the new value. + sstore(keccak256(0x0c, 0x20), roles) + // Emit the {RolesUpdated} event. + log3(0, 0, _ROLES_UPDATED_EVENT_SIGNATURE, shr(96, mload(0x0c)), roles) + } + } + + /// @dev Updates the roles directly without authorization guard. + /// If `on` is true, each set bit of `roles` will be turned on, + /// otherwise, each set bit of `roles` will be turned off. + function _updateRoles(address user, uint256 roles, bool on) internal virtual { + /// @solidity memory-safe-assembly + assembly { + mstore(0x0c, _ROLE_SLOT_SEED) + mstore(0x00, user) + let roleSlot := keccak256(0x0c, 0x20) + // Load the current value. + let current := sload(roleSlot) + // Compute the updated roles if `on` is true. + let updated := or(current, roles) + // Compute the updated roles if `on` is false. + // Use `and` to compute the intersection of `current` and `roles`, + // `xor` it with `current` to flip the bits in the intersection. + if iszero(on) { updated := xor(current, and(current, roles)) } + // Then, store the new value. + sstore(roleSlot, updated) + // Emit the {RolesUpdated} event. + log3(0, 0, _ROLES_UPDATED_EVENT_SIGNATURE, shr(96, mload(0x0c)), updated) + } + } + + /// @dev Grants the roles directly without authorization guard. + /// Each bit of `roles` represents the role to turn on. + function _grantRoles(address user, uint256 roles) internal virtual { + _updateRoles(user, roles, true); + } + + /// @dev Removes the roles directly without authorization guard. + /// Each bit of `roles` represents the role to turn off. + function _removeRoles(address user, uint256 roles) internal virtual { + _updateRoles(user, roles, false); + } + + /// @dev Throws if the sender does not have any of the `roles`. + function _checkRoles(uint256 roles) internal view virtual { + /// @solidity memory-safe-assembly + assembly { + // Compute the role slot. + mstore(0x0c, _ROLE_SLOT_SEED) + mstore(0x00, caller()) + // Load the stored value, and if the `and` intersection + // of the value and `roles` is zero, revert. + if iszero(and(sload(keccak256(0x0c, 0x20)), roles)) { + mstore(0x00, 0x82b42900) // `Unauthorized()`. + revert(0x1c, 0x04) + } + } + } + + /// @dev Throws if the sender is not the owner, + /// and does not have any of the `roles`. + /// Checks for ownership first, then lazily checks for roles. + function _checkOwnerOrRoles(uint256 roles) internal view virtual { + /// @solidity memory-safe-assembly + assembly { + // If the caller is not the stored owner. + // Note: `_ROLE_SLOT_SEED` is equal to `_OWNER_SLOT_NOT`. + if iszero(eq(caller(), sload(not(_ROLE_SLOT_SEED)))) { + // Compute the role slot. + mstore(0x0c, _ROLE_SLOT_SEED) + mstore(0x00, caller()) + // Load the stored value, and if the `and` intersection + // of the value and `roles` is zero, revert. + if iszero(and(sload(keccak256(0x0c, 0x20)), roles)) { + mstore(0x00, 0x82b42900) // `Unauthorized()`. + revert(0x1c, 0x04) + } + } + } + } + + /// @dev Throws if the sender does not have any of the `roles`, + /// and is not the owner. + /// Checks for roles first, then lazily checks for ownership. + function _checkRolesOrOwner(uint256 roles) internal view virtual { + /// @solidity memory-safe-assembly + assembly { + // Compute the role slot. + mstore(0x0c, _ROLE_SLOT_SEED) + mstore(0x00, caller()) + // Load the stored value, and if the `and` intersection + // of the value and `roles` is zero, revert. + if iszero(and(sload(keccak256(0x0c, 0x20)), roles)) { + // If the caller is not the stored owner. + // Note: `_ROLE_SLOT_SEED` is equal to `_OWNER_SLOT_NOT`. + if iszero(eq(caller(), sload(not(_ROLE_SLOT_SEED)))) { + mstore(0x00, 0x82b42900) // `Unauthorized()`. + revert(0x1c, 0x04) + } + } + } + } + + /// @dev Convenience function to return a `roles` bitmap from an array of `ordinals`. + /// This is meant for frontends like Etherscan, and is therefore not fully optimized. + /// Not recommended to be called on-chain. + /// Made internal to conserve bytecode. Wrap it in a public function if needed. + function _rolesFromOrdinals(uint8[] memory ordinals) internal pure returns (uint256 roles) { + /// @solidity memory-safe-assembly + assembly { + for { let i := shl(5, mload(ordinals)) } i { i := sub(i, 0x20) } { + // We don't need to mask the values of `ordinals`, as Solidity + // cleans dirty upper bits when storing variables into memory. + roles := or(shl(mload(add(ordinals, i)), 1), roles) + } + } + } + + /// @dev Convenience function to return an array of `ordinals` from the `roles` bitmap. + /// This is meant for frontends like Etherscan, and is therefore not fully optimized. + /// Not recommended to be called on-chain. + /// Made internal to conserve bytecode. Wrap it in a public function if needed. + function _ordinalsFromRoles(uint256 roles) internal pure returns (uint8[] memory ordinals) { + /// @solidity memory-safe-assembly + assembly { + // Grab the pointer to the free memory. + ordinals := mload(0x40) + let ptr := add(ordinals, 0x20) + let o := 0 + // The absence of lookup tables, De Bruijn, etc., here is intentional for + // smaller bytecode, as this function is not meant to be called on-chain. + for { let t := roles } 1 {} { + mstore(ptr, o) + // `shr` 5 is equivalent to multiplying by 0x20. + // Push back into the ordinals array if the bit is set. + ptr := add(ptr, shl(5, and(t, 1))) + o := add(o, 1) + t := shr(o, roles) + if iszero(t) { break } + } + // Store the length of `ordinals`. + mstore(ordinals, shr(5, sub(ptr, add(ordinals, 0x20)))) + // Allocate the memory. + mstore(0x40, ptr) + } + } + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* PUBLIC UPDATE FUNCTIONS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev Allows the owner to grant `user` `roles`. + /// If the `user` already has a role, then it will be an no-op for the role. + function grantRoles(address user, uint256 roles) public payable virtual onlyOwner { + _grantRoles(user, roles); + } + + /// @dev Allows the owner to remove `user` `roles`. + /// If the `user` does not have a role, then it will be an no-op for the role. + function revokeRoles(address user, uint256 roles) public payable virtual onlyOwner { + _removeRoles(user, roles); + } + + /// @dev Allow the caller to remove their own roles. + /// If the caller does not have a role, then it will be an no-op for the role. + function renounceRoles(uint256 roles) public payable virtual { + _removeRoles(msg.sender, roles); + } + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* PUBLIC READ FUNCTIONS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev Returns the roles of `user`. + function rolesOf(address user) public view virtual returns (uint256 roles) { + /// @solidity memory-safe-assembly + assembly { + // Compute the role slot. + mstore(0x0c, _ROLE_SLOT_SEED) + mstore(0x00, user) + // Load the stored value. + roles := sload(keccak256(0x0c, 0x20)) + } + } + + /// @dev Returns whether `user` has any of `roles`. + function hasAnyRole(address user, uint256 roles) public view virtual returns (bool) { + return rolesOf(user) & roles != 0; + } + + /// @dev Returns whether `user` has all of `roles`. + function hasAllRoles(address user, uint256 roles) public view virtual returns (bool) { + return rolesOf(user) & roles == roles; + } + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* MODIFIERS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev Marks a function as only callable by an account with `roles`. + modifier onlyRoles(uint256 roles) virtual { + _checkRoles(roles); + _; + } + + /// @dev Marks a function as only callable by the owner or by an account + /// with `roles`. Checks for ownership first, then lazily checks for roles. + modifier onlyOwnerOrRoles(uint256 roles) virtual { + _checkOwnerOrRoles(roles); + _; + } + + /// @dev Marks a function as only callable by an account with `roles` + /// or the owner. Checks for roles first, then lazily checks for ownership. + modifier onlyRolesOrOwner(uint256 roles) virtual { + _checkRolesOrOwner(roles); + _; + } + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* ROLE CONSTANTS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + // IYKYK + + uint256 internal constant _ROLE_0 = 1 << 0; + uint256 internal constant _ROLE_1 = 1 << 1; + uint256 internal constant _ROLE_2 = 1 << 2; + uint256 internal constant _ROLE_3 = 1 << 3; + uint256 internal constant _ROLE_4 = 1 << 4; + uint256 internal constant _ROLE_5 = 1 << 5; + uint256 internal constant _ROLE_6 = 1 << 6; + uint256 internal constant _ROLE_7 = 1 << 7; + uint256 internal constant _ROLE_8 = 1 << 8; + uint256 internal constant _ROLE_9 = 1 << 9; + uint256 internal constant _ROLE_10 = 1 << 10; + uint256 internal constant _ROLE_11 = 1 << 11; + uint256 internal constant _ROLE_12 = 1 << 12; + uint256 internal constant _ROLE_13 = 1 << 13; + uint256 internal constant _ROLE_14 = 1 << 14; + uint256 internal constant _ROLE_15 = 1 << 15; + uint256 internal constant _ROLE_16 = 1 << 16; + uint256 internal constant _ROLE_17 = 1 << 17; + uint256 internal constant _ROLE_18 = 1 << 18; + uint256 internal constant _ROLE_19 = 1 << 19; + uint256 internal constant _ROLE_20 = 1 << 20; + uint256 internal constant _ROLE_21 = 1 << 21; + uint256 internal constant _ROLE_22 = 1 << 22; + uint256 internal constant _ROLE_23 = 1 << 23; + uint256 internal constant _ROLE_24 = 1 << 24; + uint256 internal constant _ROLE_25 = 1 << 25; + uint256 internal constant _ROLE_26 = 1 << 26; + uint256 internal constant _ROLE_27 = 1 << 27; + uint256 internal constant _ROLE_28 = 1 << 28; + uint256 internal constant _ROLE_29 = 1 << 29; + uint256 internal constant _ROLE_30 = 1 << 30; + uint256 internal constant _ROLE_31 = 1 << 31; + uint256 internal constant _ROLE_32 = 1 << 32; + uint256 internal constant _ROLE_33 = 1 << 33; + uint256 internal constant _ROLE_34 = 1 << 34; + uint256 internal constant _ROLE_35 = 1 << 35; + uint256 internal constant _ROLE_36 = 1 << 36; + uint256 internal constant _ROLE_37 = 1 << 37; + uint256 internal constant _ROLE_38 = 1 << 38; + uint256 internal constant _ROLE_39 = 1 << 39; + uint256 internal constant _ROLE_40 = 1 << 40; + uint256 internal constant _ROLE_41 = 1 << 41; + uint256 internal constant _ROLE_42 = 1 << 42; + uint256 internal constant _ROLE_43 = 1 << 43; + uint256 internal constant _ROLE_44 = 1 << 44; + uint256 internal constant _ROLE_45 = 1 << 45; + uint256 internal constant _ROLE_46 = 1 << 46; + uint256 internal constant _ROLE_47 = 1 << 47; + uint256 internal constant _ROLE_48 = 1 << 48; + uint256 internal constant _ROLE_49 = 1 << 49; + uint256 internal constant _ROLE_50 = 1 << 50; + uint256 internal constant _ROLE_51 = 1 << 51; + uint256 internal constant _ROLE_52 = 1 << 52; + uint256 internal constant _ROLE_53 = 1 << 53; + uint256 internal constant _ROLE_54 = 1 << 54; + uint256 internal constant _ROLE_55 = 1 << 55; + uint256 internal constant _ROLE_56 = 1 << 56; + uint256 internal constant _ROLE_57 = 1 << 57; + uint256 internal constant _ROLE_58 = 1 << 58; + uint256 internal constant _ROLE_59 = 1 << 59; + uint256 internal constant _ROLE_60 = 1 << 60; + uint256 internal constant _ROLE_61 = 1 << 61; + uint256 internal constant _ROLE_62 = 1 << 62; + uint256 internal constant _ROLE_63 = 1 << 63; + uint256 internal constant _ROLE_64 = 1 << 64; + uint256 internal constant _ROLE_65 = 1 << 65; + uint256 internal constant _ROLE_66 = 1 << 66; + uint256 internal constant _ROLE_67 = 1 << 67; + uint256 internal constant _ROLE_68 = 1 << 68; + uint256 internal constant _ROLE_69 = 1 << 69; + uint256 internal constant _ROLE_70 = 1 << 70; + uint256 internal constant _ROLE_71 = 1 << 71; + uint256 internal constant _ROLE_72 = 1 << 72; + uint256 internal constant _ROLE_73 = 1 << 73; + uint256 internal constant _ROLE_74 = 1 << 74; + uint256 internal constant _ROLE_75 = 1 << 75; + uint256 internal constant _ROLE_76 = 1 << 76; + uint256 internal constant _ROLE_77 = 1 << 77; + uint256 internal constant _ROLE_78 = 1 << 78; + uint256 internal constant _ROLE_79 = 1 << 79; + uint256 internal constant _ROLE_80 = 1 << 80; + uint256 internal constant _ROLE_81 = 1 << 81; + uint256 internal constant _ROLE_82 = 1 << 82; + uint256 internal constant _ROLE_83 = 1 << 83; + uint256 internal constant _ROLE_84 = 1 << 84; + uint256 internal constant _ROLE_85 = 1 << 85; + uint256 internal constant _ROLE_86 = 1 << 86; + uint256 internal constant _ROLE_87 = 1 << 87; + uint256 internal constant _ROLE_88 = 1 << 88; + uint256 internal constant _ROLE_89 = 1 << 89; + uint256 internal constant _ROLE_90 = 1 << 90; + uint256 internal constant _ROLE_91 = 1 << 91; + uint256 internal constant _ROLE_92 = 1 << 92; + uint256 internal constant _ROLE_93 = 1 << 93; + uint256 internal constant _ROLE_94 = 1 << 94; + uint256 internal constant _ROLE_95 = 1 << 95; + uint256 internal constant _ROLE_96 = 1 << 96; + uint256 internal constant _ROLE_97 = 1 << 97; + uint256 internal constant _ROLE_98 = 1 << 98; + uint256 internal constant _ROLE_99 = 1 << 99; + uint256 internal constant _ROLE_100 = 1 << 100; + uint256 internal constant _ROLE_101 = 1 << 101; + uint256 internal constant _ROLE_102 = 1 << 102; + uint256 internal constant _ROLE_103 = 1 << 103; + uint256 internal constant _ROLE_104 = 1 << 104; + uint256 internal constant _ROLE_105 = 1 << 105; + uint256 internal constant _ROLE_106 = 1 << 106; + uint256 internal constant _ROLE_107 = 1 << 107; + uint256 internal constant _ROLE_108 = 1 << 108; + uint256 internal constant _ROLE_109 = 1 << 109; + uint256 internal constant _ROLE_110 = 1 << 110; + uint256 internal constant _ROLE_111 = 1 << 111; + uint256 internal constant _ROLE_112 = 1 << 112; + uint256 internal constant _ROLE_113 = 1 << 113; + uint256 internal constant _ROLE_114 = 1 << 114; + uint256 internal constant _ROLE_115 = 1 << 115; + uint256 internal constant _ROLE_116 = 1 << 116; + uint256 internal constant _ROLE_117 = 1 << 117; + uint256 internal constant _ROLE_118 = 1 << 118; + uint256 internal constant _ROLE_119 = 1 << 119; + uint256 internal constant _ROLE_120 = 1 << 120; + uint256 internal constant _ROLE_121 = 1 << 121; + uint256 internal constant _ROLE_122 = 1 << 122; + uint256 internal constant _ROLE_123 = 1 << 123; + uint256 internal constant _ROLE_124 = 1 << 124; + uint256 internal constant _ROLE_125 = 1 << 125; + uint256 internal constant _ROLE_126 = 1 << 126; + uint256 internal constant _ROLE_127 = 1 << 127; + uint256 internal constant _ROLE_128 = 1 << 128; + uint256 internal constant _ROLE_129 = 1 << 129; + uint256 internal constant _ROLE_130 = 1 << 130; + uint256 internal constant _ROLE_131 = 1 << 131; + uint256 internal constant _ROLE_132 = 1 << 132; + uint256 internal constant _ROLE_133 = 1 << 133; + uint256 internal constant _ROLE_134 = 1 << 134; + uint256 internal constant _ROLE_135 = 1 << 135; + uint256 internal constant _ROLE_136 = 1 << 136; + uint256 internal constant _ROLE_137 = 1 << 137; + uint256 internal constant _ROLE_138 = 1 << 138; + uint256 internal constant _ROLE_139 = 1 << 139; + uint256 internal constant _ROLE_140 = 1 << 140; + uint256 internal constant _ROLE_141 = 1 << 141; + uint256 internal constant _ROLE_142 = 1 << 142; + uint256 internal constant _ROLE_143 = 1 << 143; + uint256 internal constant _ROLE_144 = 1 << 144; + uint256 internal constant _ROLE_145 = 1 << 145; + uint256 internal constant _ROLE_146 = 1 << 146; + uint256 internal constant _ROLE_147 = 1 << 147; + uint256 internal constant _ROLE_148 = 1 << 148; + uint256 internal constant _ROLE_149 = 1 << 149; + uint256 internal constant _ROLE_150 = 1 << 150; + uint256 internal constant _ROLE_151 = 1 << 151; + uint256 internal constant _ROLE_152 = 1 << 152; + uint256 internal constant _ROLE_153 = 1 << 153; + uint256 internal constant _ROLE_154 = 1 << 154; + uint256 internal constant _ROLE_155 = 1 << 155; + uint256 internal constant _ROLE_156 = 1 << 156; + uint256 internal constant _ROLE_157 = 1 << 157; + uint256 internal constant _ROLE_158 = 1 << 158; + uint256 internal constant _ROLE_159 = 1 << 159; + uint256 internal constant _ROLE_160 = 1 << 160; + uint256 internal constant _ROLE_161 = 1 << 161; + uint256 internal constant _ROLE_162 = 1 << 162; + uint256 internal constant _ROLE_163 = 1 << 163; + uint256 internal constant _ROLE_164 = 1 << 164; + uint256 internal constant _ROLE_165 = 1 << 165; + uint256 internal constant _ROLE_166 = 1 << 166; + uint256 internal constant _ROLE_167 = 1 << 167; + uint256 internal constant _ROLE_168 = 1 << 168; + uint256 internal constant _ROLE_169 = 1 << 169; + uint256 internal constant _ROLE_170 = 1 << 170; + uint256 internal constant _ROLE_171 = 1 << 171; + uint256 internal constant _ROLE_172 = 1 << 172; + uint256 internal constant _ROLE_173 = 1 << 173; + uint256 internal constant _ROLE_174 = 1 << 174; + uint256 internal constant _ROLE_175 = 1 << 175; + uint256 internal constant _ROLE_176 = 1 << 176; + uint256 internal constant _ROLE_177 = 1 << 177; + uint256 internal constant _ROLE_178 = 1 << 178; + uint256 internal constant _ROLE_179 = 1 << 179; + uint256 internal constant _ROLE_180 = 1 << 180; + uint256 internal constant _ROLE_181 = 1 << 181; + uint256 internal constant _ROLE_182 = 1 << 182; + uint256 internal constant _ROLE_183 = 1 << 183; + uint256 internal constant _ROLE_184 = 1 << 184; + uint256 internal constant _ROLE_185 = 1 << 185; + uint256 internal constant _ROLE_186 = 1 << 186; + uint256 internal constant _ROLE_187 = 1 << 187; + uint256 internal constant _ROLE_188 = 1 << 188; + uint256 internal constant _ROLE_189 = 1 << 189; + uint256 internal constant _ROLE_190 = 1 << 190; + uint256 internal constant _ROLE_191 = 1 << 191; + uint256 internal constant _ROLE_192 = 1 << 192; + uint256 internal constant _ROLE_193 = 1 << 193; + uint256 internal constant _ROLE_194 = 1 << 194; + uint256 internal constant _ROLE_195 = 1 << 195; + uint256 internal constant _ROLE_196 = 1 << 196; + uint256 internal constant _ROLE_197 = 1 << 197; + uint256 internal constant _ROLE_198 = 1 << 198; + uint256 internal constant _ROLE_199 = 1 << 199; + uint256 internal constant _ROLE_200 = 1 << 200; + uint256 internal constant _ROLE_201 = 1 << 201; + uint256 internal constant _ROLE_202 = 1 << 202; + uint256 internal constant _ROLE_203 = 1 << 203; + uint256 internal constant _ROLE_204 = 1 << 204; + uint256 internal constant _ROLE_205 = 1 << 205; + uint256 internal constant _ROLE_206 = 1 << 206; + uint256 internal constant _ROLE_207 = 1 << 207; + uint256 internal constant _ROLE_208 = 1 << 208; + uint256 internal constant _ROLE_209 = 1 << 209; + uint256 internal constant _ROLE_210 = 1 << 210; + uint256 internal constant _ROLE_211 = 1 << 211; + uint256 internal constant _ROLE_212 = 1 << 212; + uint256 internal constant _ROLE_213 = 1 << 213; + uint256 internal constant _ROLE_214 = 1 << 214; + uint256 internal constant _ROLE_215 = 1 << 215; + uint256 internal constant _ROLE_216 = 1 << 216; + uint256 internal constant _ROLE_217 = 1 << 217; + uint256 internal constant _ROLE_218 = 1 << 218; + uint256 internal constant _ROLE_219 = 1 << 219; + uint256 internal constant _ROLE_220 = 1 << 220; + uint256 internal constant _ROLE_221 = 1 << 221; + uint256 internal constant _ROLE_222 = 1 << 222; + uint256 internal constant _ROLE_223 = 1 << 223; + uint256 internal constant _ROLE_224 = 1 << 224; + uint256 internal constant _ROLE_225 = 1 << 225; + uint256 internal constant _ROLE_226 = 1 << 226; + uint256 internal constant _ROLE_227 = 1 << 227; + uint256 internal constant _ROLE_228 = 1 << 228; + uint256 internal constant _ROLE_229 = 1 << 229; + uint256 internal constant _ROLE_230 = 1 << 230; + uint256 internal constant _ROLE_231 = 1 << 231; + uint256 internal constant _ROLE_232 = 1 << 232; + uint256 internal constant _ROLE_233 = 1 << 233; + uint256 internal constant _ROLE_234 = 1 << 234; + uint256 internal constant _ROLE_235 = 1 << 235; + uint256 internal constant _ROLE_236 = 1 << 236; + uint256 internal constant _ROLE_237 = 1 << 237; + uint256 internal constant _ROLE_238 = 1 << 238; + uint256 internal constant _ROLE_239 = 1 << 239; + uint256 internal constant _ROLE_240 = 1 << 240; + uint256 internal constant _ROLE_241 = 1 << 241; + uint256 internal constant _ROLE_242 = 1 << 242; + uint256 internal constant _ROLE_243 = 1 << 243; + uint256 internal constant _ROLE_244 = 1 << 244; + uint256 internal constant _ROLE_245 = 1 << 245; + uint256 internal constant _ROLE_246 = 1 << 246; + uint256 internal constant _ROLE_247 = 1 << 247; + uint256 internal constant _ROLE_248 = 1 << 248; + uint256 internal constant _ROLE_249 = 1 << 249; + uint256 internal constant _ROLE_250 = 1 << 250; + uint256 internal constant _ROLE_251 = 1 << 251; + uint256 internal constant _ROLE_252 = 1 << 252; + uint256 internal constant _ROLE_253 = 1 << 253; + uint256 internal constant _ROLE_254 = 1 << 254; + uint256 internal constant _ROLE_255 = 1 << 255; +} + +// src\common/INonceRegistry.sol + + + + + +/// @title INoncesRegistry +/// @author Mathieu Bour for Pooky Labs Ltd. +/// +/// @notice Minimal NoncesRegistry interface. +interface INonceRegistry is IAccessControl { + /// @notice Get the value of a given nonce. + function has(bytes32 nonce) external view returns (bool); + + /// @notice Set the value of a given nonce. + function set(bytes32 nonce, bool value) external; + + /// @notice Set the value of a multiple nonces. + function setBatch(bytes32[] memory nonces, bool[] memory values) external; +} + +// src\common/Treasury.sol + + + + + + +/// @title Treasury +/// @author Mathieu Bour for Pooky Labs Ltd. +/// +/// @notice Base class for contracts that are made to receive native currency. +/// The destination address is controller by the contract owner. +abstract contract Treasury is Ownable, ITreasury { + /// The native currency destination address. + address public treasury; + + constructor(address _treasury) { + treasury = _treasury; + } + + /// @notice Forward the funds to the treasury wallet at the end of the transaction. + /// Since `treasury` is a trusted address, this modifier should not lead to any re-entrancy issue. + modifier forwarder() { + _; + + uint256 value = address(this).balance; + (bool sent,) = treasury.call{ value: value }(""); + if (!sent) { + revert TransferFailed(treasury, value); + } + } + + /// Change the native currency destination address. + /// @param _treasury The new treasury address. + function changeTreasury(address _treasury) external onlyOwner { + treasury = _treasury; + } +} + +// src\common/Signer.sol + + + + + + +/// @title Signer +/// @author Mathieu Bour for Pooky Labs Ltd. +/// +/// @dev Provide the `verify` function and the `onlyVerify` modifier to child contracts. +abstract contract Signer is OwnableRoles { + using ECDSA for bytes32; + + uint256 public constant SIGNER = _ROLE_42; + + /// Thrown when the signature is invalid. + error InvalidSignature(); + + constructor(address signer) { + _grantRoles(signer, SIGNER); + } + + /// @notice Ensure that `data` has been signed by a `SIGNER` using the `proof`. + function verify(bytes memory data, bytes calldata proof) internal view { + // Generate the signed message from the tokenId and currentPXP + bytes32 hash = keccak256(data).toEthSignedMessageHash(); + + if (!hasAllRoles(hash.recoverCalldata(proof), SIGNER)) { + revert InvalidSignature(); + } + } + + /// @notice Modifier version of the `verify` function. + modifier onlyVerify(bytes memory data, bytes calldata proof) { + verify(data, proof); + _; + } +} + +// src\pookyball/IPookyball.sol + + + + + + + +/// @title PookyballMetadata +/// @notice The Pookyball rarities are represented on chain by this enum. +enum PookyballRarity { + COMMON, + RARE, + EPIC, + LEGENDARY, + MYTHIC +} + +/// @title PookyballMetadata +/// @notice Pookyballs NFT have the following features: +/// - rarity: integer enum. +/// - level: token level, can be increase by spending token experiences points (PXP). +/// - pxp: token experience points. +/// - seed: a random uint256 word provided by Chainlink VRF service that will be used by Pooky's NFT generator +/// back-end to generate the NFT visuals and in-game statistics\. +struct PookyballMetadata { + PookyballRarity rarity; + uint256 level; + uint256 pxp; + uint256 seed; +} + +/// @title IPookyball +/// @author Mathieu Bour for Pooky Labs Ltd. +/// @notice Minimal Pookyball interface. +interface IPookyball is IAccessControl, IERC2981, IERC721 { + /// Fired when the seed of a Pookyball token is set by the VRFCoordinator + event SeedSet(uint256 indexed tokenId, uint256 seed); + /// Fired when the level of a Pookyball token is changed + event LevelChanged(uint256 indexed tokenId, uint256 level); + /// Fired when the PXP of a Pookyball token is changed + event PXPChanged(uint256 indexed tokenId, uint256 amount); + + /// Thrown when the length of two parameters mismatch. Used in the mint batched function. + error ArgumentSizeMismatch(uint256 x, uint256 y); + + /// @notice PookyballMetadata of the token {tokenId}. + /// @dev Requirements: + /// - Pookyball {tokenId} should exist (minted and not burned). + function metadata(uint256 tokenId) external view returns (PookyballMetadata memory); + + /// @notice Change the secondary sale royalties receiver address. + function setERC2981Receiver(address newReceiver) external; + + /// @notice Mint a new Pookyball token with a given rarity. + function mint(address[] memory recipients, PookyballRarity[] memory rarities) + external + returns (uint256); + + /// @notice Change the level of a Pookyball token. + /// @dev Requirements: + /// - Pookyball {tokenId} should exist (minted and not burned). + function setLevel(uint256 tokenId, uint256 newLevel) external; + + /// @notice Change the PXP of a Pookyball token. + /// @dev Requirements: + /// - Pookyball {tokenId} should exist (minted and not burned). + function setPXP(uint256 tokenId, uint256 newPXP) external; +} + +// src\common\BoostPXP.sol + + + + + + + + + +struct Boost { + /// The Pookyball rarity. + PookyballRarity rarity; + /// The number of boosted predictions. + uint256 predictions; + /// The boost value. + uint256 value; +} + +/// @title BoostPXP +/// @author Mathieu Bour for Pooky Labs Ltd. +/// Allow player to purchase temporary PXP boosts for their Pookyball. +contract BoostPXP is OwnableRoles, Signer, Treasury { + /// Fired when a boost has been purchased. + /// @param account The account who purchased the boost. + /// @param details The boost details. + /// @param price The amount in native currency paid for the boost. + event Boosted(address indexed account, Boost details, uint256 price); + + /// Thrown when user attempts to use a nonce that was already used in the past. + error NonceAlreadyUsed(bytes32 nonce); + + /// The NonceRegistry contract. + INonceRegistry public immutable nonces; + + constructor(INonceRegistry _nonces, address admin, address _signer, address _treasury) + Signer(_signer) + Treasury(_treasury) + { + _initializeOwner(admin); + nonces = _nonces; + } + + /// @notice Boost the received PXP of a Pookyball. + /// @dev Pricing is controlled by the backend, which need to provide a proof to the end user. + /// @param details The Pookyball boost data. + /// @param price The price in native currency, provided by the Pooky back-end. + /// @param nonce The nonce, provided by the Pooky back-end. + /// @param proof The signature of `abi.encode(details, price, nonce, address(this))`. + function boost(Boost memory details, uint256 price, bytes32 nonce, bytes calldata proof) + external + payable + onlyVerify(abi.encode(details, price, nonce, address(this)), proof) + forwarder + { + if (nonces.has(nonce)) { + revert NonceAlreadyUsed(nonce); + } + + nonces.set(nonce, true); + + if (msg.value < price) { + revert InsufficientValue(price, msg.value); + } + + emit Boosted(msg.sender, details, price); + } +} diff --git a/flattened/Energy.sol b/flattened/Energy.sol new file mode 100644 index 00000000..162e63e9 --- /dev/null +++ b/flattened/Energy.sol @@ -0,0 +1,4009 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.21 ^0.8.4; + +// lib/ERC721A/contracts/IERC721A.sol + +// ERC721A Contracts v4.2.3 +// Creator: Chiru Labs + + + +/** + * @dev Interface of ERC721A. + */ +interface IERC721A { + /** + * The caller must own the token or be an approved operator. + */ + error ApprovalCallerNotOwnerNorApproved(); + + /** + * The token does not exist. + */ + error ApprovalQueryForNonexistentToken(); + + /** + * Cannot query the balance for the zero address. + */ + error BalanceQueryForZeroAddress(); + + /** + * Cannot mint to the zero address. + */ + error MintToZeroAddress(); + + /** + * The quantity of tokens minted must be more than zero. + */ + error MintZeroQuantity(); + + /** + * The token does not exist. + */ + error OwnerQueryForNonexistentToken(); + + /** + * The caller must own the token or be an approved operator. + */ + error TransferCallerNotOwnerNorApproved(); + + /** + * The token must be owned by `from`. + */ + error TransferFromIncorrectOwner(); + + /** + * Cannot safely transfer to a contract that does not implement the + * ERC721Receiver interface. + */ + error TransferToNonERC721ReceiverImplementer(); + + /** + * Cannot transfer to the zero address. + */ + error TransferToZeroAddress(); + + /** + * The token does not exist. + */ + error URIQueryForNonexistentToken(); + + /** + * The `quantity` minted with ERC2309 exceeds the safety limit. + */ + error MintERC2309QuantityExceedsLimit(); + + /** + * The `extraData` cannot be set on an unintialized ownership slot. + */ + error OwnershipNotInitializedForExtraData(); + + // ============================================================= + // STRUCTS + // ============================================================= + + struct TokenOwnership { + // The address of the owner. + address addr; + // Stores the start time of ownership with minimal overhead for tokenomics. + uint64 startTimestamp; + // Whether the token has been burned. + bool burned; + // Arbitrary data similar to `startTimestamp` that can be set via {_extraData}. + uint24 extraData; + } + + // ============================================================= + // TOKEN COUNTERS + // ============================================================= + + /** + * @dev Returns the total number of tokens in existence. + * Burned tokens will reduce the count. + * To get the total number of tokens minted, please see {_totalMinted}. + */ + function totalSupply() external view returns (uint256); + + // ============================================================= + // 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 30000 gas. + */ + function supportsInterface(bytes4 interfaceId) external view returns (bool); + + // ============================================================= + // IERC721 + // ============================================================= + + /** + * @dev Emitted when `tokenId` token is transferred from `from` to `to`. + */ + event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); + + /** + * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token. + */ + event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); + + /** + * @dev Emitted when `owner` enables or disables + * (`approved`) `operator` to manage all of its assets. + */ + event ApprovalForAll(address indexed owner, address indexed operator, bool approved); + + /** + * @dev Returns the number of tokens in `owner`'s account. + */ + function balanceOf(address owner) external view returns (uint256 balance); + + /** + * @dev Returns the owner of the `tokenId` token. + * + * Requirements: + * + * - `tokenId` must exist. + */ + function ownerOf(uint256 tokenId) external view returns (address owner); + + /** + * @dev Safely transfers `tokenId` token from `from` to `to`, + * checking first that contract recipients are aware of the ERC721 protocol + * to prevent tokens from being forever locked. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must exist and be owned by `from`. + * - If the caller is not `from`, it must be have been allowed to move + * this token by either {approve} or {setApprovalForAll}. + * - If `to` refers to a smart contract, it must implement + * {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. + * + * Emits a {Transfer} event. + */ + function safeTransferFrom( + address from, + address to, + uint256 tokenId, + bytes calldata data + ) external payable; + + /** + * @dev Equivalent to `safeTransferFrom(from, to, tokenId, '')`. + */ + function safeTransferFrom( + address from, + address to, + uint256 tokenId + ) external payable; + + /** + * @dev Transfers `tokenId` from `from` to `to`. + * + * WARNING: Usage of this method is discouraged, use {safeTransferFrom} + * whenever possible. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must be owned by `from`. + * - If the caller is not `from`, it must be approved to move this token + * by either {approve} or {setApprovalForAll}. + * + * Emits a {Transfer} event. + */ + function transferFrom( + address from, + address to, + uint256 tokenId + ) external payable; + + /** + * @dev Gives permission to `to` to transfer `tokenId` token to another account. + * The approval is cleared when the token is transferred. + * + * Only a single account can be approved at a time, so approving the + * zero address clears previous approvals. + * + * Requirements: + * + * - The caller must own the token or be an approved operator. + * - `tokenId` must exist. + * + * Emits an {Approval} event. + */ + function approve(address to, uint256 tokenId) external payable; + + /** + * @dev Approve or remove `operator` as an operator for the caller. + * Operators can call {transferFrom} or {safeTransferFrom} + * for any token owned by the caller. + * + * Requirements: + * + * - The `operator` cannot be the caller. + * + * Emits an {ApprovalForAll} event. + */ + function setApprovalForAll(address operator, bool _approved) external; + + /** + * @dev Returns the account approved for `tokenId` token. + * + * Requirements: + * + * - `tokenId` must exist. + */ + function getApproved(uint256 tokenId) external view returns (address operator); + + /** + * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`. + * + * See {setApprovalForAll}. + */ + function isApprovedForAll(address owner, address operator) external view returns (bool); + + // ============================================================= + // IERC721Metadata + // ============================================================= + + /** + * @dev Returns the token collection name. + */ + function name() external view returns (string memory); + + /** + * @dev Returns the token collection symbol. + */ + function symbol() external view returns (string memory); + + /** + * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token. + */ + function tokenURI(uint256 tokenId) external view returns (string memory); + + // ============================================================= + // IERC2309 + // ============================================================= + + /** + * @dev Emitted when tokens in `fromTokenId` to `toTokenId` + * (inclusive) is transferred from `from` to `to`, as defined in the + * [ERC2309](https://eips.ethereum.org/EIPS/eip-2309) standard. + * + * See {_mintERC2309} for more details. + */ + event ConsecutiveTransfer(uint256 indexed fromTokenId, uint256 toTokenId, address indexed from, address indexed to); +} + +// lib/solady/src/auth/Ownable.sol + + + +/// @notice Simple single owner authorization mixin. +/// @author Solady (https://github.com/vectorized/solady/blob/main/src/auth/Ownable.sol) +/// @dev While the ownable portion follows +/// [EIP-173](https://eips.ethereum.org/EIPS/eip-173) for compatibility, +/// the nomenclature for the 2-step ownership handover may be unique to this codebase. +abstract contract Ownable { + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* CUSTOM ERRORS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev The caller is not authorized to call the function. + error Unauthorized(); + + /// @dev The `newOwner` cannot be the zero address. + error NewOwnerIsZeroAddress(); + + /// @dev The `pendingOwner` does not have a valid handover request. + error NoHandoverRequest(); + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* EVENTS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev The ownership is transferred from `oldOwner` to `newOwner`. + /// This event is intentionally kept the same as OpenZeppelin's Ownable to be + /// compatible with indexers and [EIP-173](https://eips.ethereum.org/EIPS/eip-173), + /// despite it not being as lightweight as a single argument event. + event OwnershipTransferred(address indexed oldOwner, address indexed newOwner); + + /// @dev An ownership handover to `pendingOwner` has been requested. + event OwnershipHandoverRequested(address indexed pendingOwner); + + /// @dev The ownership handover to `pendingOwner` has been canceled. + event OwnershipHandoverCanceled(address indexed pendingOwner); + + /// @dev `keccak256(bytes("OwnershipTransferred(address,address)"))`. + uint256 private constant _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE = + 0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0; + + /// @dev `keccak256(bytes("OwnershipHandoverRequested(address)"))`. + uint256 private constant _OWNERSHIP_HANDOVER_REQUESTED_EVENT_SIGNATURE = + 0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d; + + /// @dev `keccak256(bytes("OwnershipHandoverCanceled(address)"))`. + uint256 private constant _OWNERSHIP_HANDOVER_CANCELED_EVENT_SIGNATURE = + 0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92; + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* STORAGE */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev The owner slot is given by: `not(_OWNER_SLOT_NOT)`. + /// It is intentionally chosen to be a high value + /// to avoid collision with lower slots. + /// The choice of manual storage layout is to enable compatibility + /// with both regular and upgradeable contracts. + uint256 private constant _OWNER_SLOT_NOT = 0x8b78c6d8; + + /// The ownership handover slot of `newOwner` is given by: + /// ``` + /// mstore(0x00, or(shl(96, user), _HANDOVER_SLOT_SEED)) + /// let handoverSlot := keccak256(0x00, 0x20) + /// ``` + /// It stores the expiry timestamp of the two-step ownership handover. + uint256 private constant _HANDOVER_SLOT_SEED = 0x389a75e1; + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* INTERNAL FUNCTIONS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev Initializes the owner directly without authorization guard. + /// This function must be called upon initialization, + /// regardless of whether the contract is upgradeable or not. + /// This is to enable generalization to both regular and upgradeable contracts, + /// and to save gas in case the initial owner is not the caller. + /// For performance reasons, this function will not check if there + /// is an existing owner. + function _initializeOwner(address newOwner) internal virtual { + /// @solidity memory-safe-assembly + assembly { + // Clean the upper 96 bits. + newOwner := shr(96, shl(96, newOwner)) + // Store the new value. + sstore(not(_OWNER_SLOT_NOT), newOwner) + // Emit the {OwnershipTransferred} event. + log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, 0, newOwner) + } + } + + /// @dev Sets the owner directly without authorization guard. + function _setOwner(address newOwner) internal virtual { + /// @solidity memory-safe-assembly + assembly { + let ownerSlot := not(_OWNER_SLOT_NOT) + // Clean the upper 96 bits. + newOwner := shr(96, shl(96, newOwner)) + // Emit the {OwnershipTransferred} event. + log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, sload(ownerSlot), newOwner) + // Store the new value. + sstore(ownerSlot, newOwner) + } + } + + /// @dev Throws if the sender is not the owner. + function _checkOwner() internal view virtual { + /// @solidity memory-safe-assembly + assembly { + // If the caller is not the stored owner, revert. + if iszero(eq(caller(), sload(not(_OWNER_SLOT_NOT)))) { + mstore(0x00, 0x82b42900) // `Unauthorized()`. + revert(0x1c, 0x04) + } + } + } + + /// @dev Returns how long a two-step ownership handover is valid for in seconds. + /// Override to return a different value if needed. + /// Made internal to conserve bytecode. Wrap it in a public function if needed. + function _ownershipHandoverValidFor() internal view virtual returns (uint64) { + return 48 * 3600; + } + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* PUBLIC UPDATE FUNCTIONS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev Allows the owner to transfer the ownership to `newOwner`. + function transferOwnership(address newOwner) public payable virtual onlyOwner { + /// @solidity memory-safe-assembly + assembly { + if iszero(shl(96, newOwner)) { + mstore(0x00, 0x7448fbae) // `NewOwnerIsZeroAddress()`. + revert(0x1c, 0x04) + } + } + _setOwner(newOwner); + } + + /// @dev Allows the owner to renounce their ownership. + function renounceOwnership() public payable virtual onlyOwner { + _setOwner(address(0)); + } + + /// @dev Request a two-step ownership handover to the caller. + /// The request will automatically expire in 48 hours (172800 seconds) by default. + function requestOwnershipHandover() public payable virtual { + unchecked { + uint256 expires = block.timestamp + _ownershipHandoverValidFor(); + /// @solidity memory-safe-assembly + assembly { + // Compute and set the handover slot to `expires`. + mstore(0x0c, _HANDOVER_SLOT_SEED) + mstore(0x00, caller()) + sstore(keccak256(0x0c, 0x20), expires) + // Emit the {OwnershipHandoverRequested} event. + log2(0, 0, _OWNERSHIP_HANDOVER_REQUESTED_EVENT_SIGNATURE, caller()) + } + } + } + + /// @dev Cancels the two-step ownership handover to the caller, if any. + function cancelOwnershipHandover() public payable virtual { + /// @solidity memory-safe-assembly + assembly { + // Compute and set the handover slot to 0. + mstore(0x0c, _HANDOVER_SLOT_SEED) + mstore(0x00, caller()) + sstore(keccak256(0x0c, 0x20), 0) + // Emit the {OwnershipHandoverCanceled} event. + log2(0, 0, _OWNERSHIP_HANDOVER_CANCELED_EVENT_SIGNATURE, caller()) + } + } + + /// @dev Allows the owner to complete the two-step ownership handover to `pendingOwner`. + /// Reverts if there is no existing ownership handover requested by `pendingOwner`. + function completeOwnershipHandover(address pendingOwner) public payable virtual onlyOwner { + /// @solidity memory-safe-assembly + assembly { + // Compute and set the handover slot to 0. + mstore(0x0c, _HANDOVER_SLOT_SEED) + mstore(0x00, pendingOwner) + let handoverSlot := keccak256(0x0c, 0x20) + // If the handover does not exist, or has expired. + if gt(timestamp(), sload(handoverSlot)) { + mstore(0x00, 0x6f5e8818) // `NoHandoverRequest()`. + revert(0x1c, 0x04) + } + // Set the handover slot to 0. + sstore(handoverSlot, 0) + } + _setOwner(pendingOwner); + } + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* PUBLIC READ FUNCTIONS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev Returns the owner of the contract. + function owner() public view virtual returns (address result) { + /// @solidity memory-safe-assembly + assembly { + result := sload(not(_OWNER_SLOT_NOT)) + } + } + + /// @dev Returns the expiry timestamp for the two-step ownership handover to `pendingOwner`. + function ownershipHandoverExpiresAt(address pendingOwner) + public + view + virtual + returns (uint256 result) + { + /// @solidity memory-safe-assembly + assembly { + // Compute the handover slot. + mstore(0x0c, _HANDOVER_SLOT_SEED) + mstore(0x00, pendingOwner) + // Load the handover slot. + result := sload(keccak256(0x0c, 0x20)) + } + } + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* MODIFIERS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev Marks a function as only callable by the owner. + modifier onlyOwner() virtual { + _checkOwner(); + _; + } +} + +// lib/solady/src\utils/Base64.sol + + + +/// @notice Library to encode strings in Base64. +/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/Base64.sol) +/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/Base64.sol) +/// @author Modified from (https://github.com/Brechtpd/base64/blob/main/base64.sol) by Brecht Devos - . +library Base64 { + /// @dev Encodes `data` using the base64 encoding described in RFC 4648. + /// See: https://datatracker.ietf.org/doc/html/rfc4648 + /// @param fileSafe Whether to replace '+' with '-' and '/' with '_'. + /// @param noPadding Whether to strip away the padding. + function encode(bytes memory data, bool fileSafe, bool noPadding) + internal + pure + returns (string memory result) + { + /// @solidity memory-safe-assembly + assembly { + let dataLength := mload(data) + + if dataLength { + // Multiply by 4/3 rounded up. + // The `shl(2, ...)` is equivalent to multiplying by 4. + let encodedLength := shl(2, div(add(dataLength, 2), 3)) + + // Set `result` to point to the start of the free memory. + result := mload(0x40) + + // Store the table into the scratch space. + // Offsetted by -1 byte so that the `mload` will load the character. + // We will rewrite the free memory pointer at `0x40` later with + // the allocated size. + // The magic constant 0x0230 will translate "-_" + "+/". + mstore(0x1f, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdef") + mstore(0x3f, sub("ghijklmnopqrstuvwxyz0123456789-_", mul(iszero(fileSafe), 0x0230))) + + // Skip the first slot, which stores the length. + let ptr := add(result, 0x20) + let end := add(ptr, encodedLength) + + // Run over the input, 3 bytes at a time. + for {} 1 {} { + data := add(data, 3) // Advance 3 bytes. + let input := mload(data) + + // Write 4 bytes. Optimized for fewer stack operations. + mstore8(0, mload(and(shr(18, input), 0x3F))) + mstore8(1, mload(and(shr(12, input), 0x3F))) + mstore8(2, mload(and(shr(6, input), 0x3F))) + mstore8(3, mload(and(input, 0x3F))) + mstore(ptr, mload(0x00)) + + ptr := add(ptr, 4) // Advance 4 bytes. + if iszero(lt(ptr, end)) { break } + } + mstore(0x40, add(end, 0x20)) // Allocate the memory. + // Equivalent to `o = [0, 2, 1][dataLength % 3]`. + let o := div(2, mod(dataLength, 3)) + // Offset `ptr` and pad with '='. We can simply write over the end. + mstore(sub(ptr, o), shl(240, 0x3d3d)) + // Set `o` to zero if there is padding. + o := mul(iszero(iszero(noPadding)), o) + mstore(sub(ptr, o), 0) // Zeroize the slot after the string. + mstore(result, sub(encodedLength, o)) // Store the length. + } + } + } + + /// @dev Encodes `data` using the base64 encoding described in RFC 4648. + /// Equivalent to `encode(data, false, false)`. + function encode(bytes memory data) internal pure returns (string memory result) { + result = encode(data, false, false); + } + + /// @dev Encodes `data` using the base64 encoding described in RFC 4648. + /// Equivalent to `encode(data, fileSafe, false)`. + function encode(bytes memory data, bool fileSafe) + internal + pure + returns (string memory result) + { + result = encode(data, fileSafe, false); + } + + /// @dev Decodes base64 encoded `data`. + /// + /// Supports: + /// - RFC 4648 (both standard and file-safe mode). + /// - RFC 3501 (63: ','). + /// + /// Does not support: + /// - Line breaks. + /// + /// Note: For performance reasons, + /// this function will NOT revert on invalid `data` inputs. + /// Outputs for invalid inputs will simply be undefined behaviour. + /// It is the user's responsibility to ensure that the `data` + /// is a valid base64 encoded string. + function decode(string memory data) internal pure returns (bytes memory result) { + /// @solidity memory-safe-assembly + assembly { + let dataLength := mload(data) + + if dataLength { + let decodedLength := mul(shr(2, dataLength), 3) + + for {} 1 {} { + // If padded. + if iszero(and(dataLength, 3)) { + let t := xor(mload(add(data, dataLength)), 0x3d3d) + // forgefmt: disable-next-item + decodedLength := sub( + decodedLength, + add(iszero(byte(30, t)), iszero(byte(31, t))) + ) + break + } + // If non-padded. + decodedLength := add(decodedLength, sub(and(dataLength, 3), 1)) + break + } + result := mload(0x40) + + // Write the length of the bytes. + mstore(result, decodedLength) + + // Skip the first slot, which stores the length. + let ptr := add(result, 0x20) + let end := add(ptr, decodedLength) + + // Load the table into the scratch space. + // Constants are optimized for smaller bytecode with zero gas overhead. + // `m` also doubles as the mask of the upper 6 bits. + let m := 0xfc000000fc00686c7074787c8084888c9094989ca0a4a8acb0b4b8bcc0c4c8cc + mstore(0x5b, m) + mstore(0x3b, 0x04080c1014181c2024282c3034383c4044484c5054585c6064) + mstore(0x1a, 0xf8fcf800fcd0d4d8dce0e4e8ecf0f4) + + for {} 1 {} { + // Read 4 bytes. + data := add(data, 4) + let input := mload(data) + + // Write 3 bytes. + // forgefmt: disable-next-item + mstore(ptr, or( + and(m, mload(byte(28, input))), + shr(6, or( + and(m, mload(byte(29, input))), + shr(6, or( + and(m, mload(byte(30, input))), + shr(6, mload(byte(31, input))) + )) + )) + )) + ptr := add(ptr, 3) + if iszero(lt(ptr, end)) { break } + } + mstore(0x40, add(end, 0x20)) // Allocate the memory. + mstore(end, 0) // Zeroize the slot after the bytes. + mstore(0x60, 0) // Restore the zero slot. + } + } + } +} + +// lib/solady/src\utils/LibString.sol + + + +/// @notice Library for converting numbers into strings and other string operations. +/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/LibString.sol) +/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/LibString.sol) +library LibString { + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* CUSTOM ERRORS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev The `length` of the output is too small to contain all the hex digits. + error HexLengthInsufficient(); + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* CONSTANTS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev The constant returned when the `search` is not found in the string. + uint256 internal constant NOT_FOUND = type(uint256).max; + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* DECIMAL OPERATIONS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev Returns the base 10 decimal representation of `value`. + function toString(uint256 value) internal pure returns (string memory str) { + /// @solidity memory-safe-assembly + assembly { + // The maximum value of a uint256 contains 78 digits (1 byte per digit), but + // we allocate 0xa0 bytes to keep the free memory pointer 32-byte word aligned. + // We will need 1 word for the trailing zeros padding, 1 word for the length, + // and 3 words for a maximum of 78 digits. + str := add(mload(0x40), 0x80) + // Update the free memory pointer to allocate. + mstore(0x40, add(str, 0x20)) + // Zeroize the slot after the string. + mstore(str, 0) + + // Cache the end of the memory to calculate the length later. + let end := str + + let w := not(0) // Tsk. + // We write the string from rightmost digit to leftmost digit. + // The following is essentially a do-while loop that also handles the zero case. + for { let temp := value } 1 {} { + str := add(str, w) // `sub(str, 1)`. + // Write the character to the pointer. + // The ASCII index of the '0' character is 48. + mstore8(str, add(48, mod(temp, 10))) + // Keep dividing `temp` until zero. + temp := div(temp, 10) + if iszero(temp) { break } + } + + let length := sub(end, str) + // Move the pointer 32 bytes leftwards to make room for the length. + str := sub(str, 0x20) + // Store the length. + mstore(str, length) + } + } + + /// @dev Returns the base 10 decimal representation of `value`. + function toString(int256 value) internal pure returns (string memory str) { + if (value >= 0) { + return toString(uint256(value)); + } + unchecked { + str = toString(uint256(-value)); + } + /// @solidity memory-safe-assembly + assembly { + // We still have some spare memory space on the left, + // as we have allocated 3 words (96 bytes) for up to 78 digits. + let length := mload(str) // Load the string length. + mstore(str, 0x2d) // Store the '-' character. + str := sub(str, 1) // Move back the string pointer by a byte. + mstore(str, add(length, 1)) // Update the string length. + } + } + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* HEXADECIMAL OPERATIONS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev Returns the hexadecimal representation of `value`, + /// left-padded to an input length of `length` bytes. + /// The output is prefixed with "0x" encoded using 2 hexadecimal digits per byte, + /// giving a total length of `length * 2 + 2` bytes. + /// Reverts if `length` is too small for the output to contain all the digits. + function toHexString(uint256 value, uint256 length) internal pure returns (string memory str) { + str = toHexStringNoPrefix(value, length); + /// @solidity memory-safe-assembly + assembly { + let strLength := add(mload(str), 2) // Compute the length. + mstore(str, 0x3078) // Write the "0x" prefix. + str := sub(str, 2) // Move the pointer. + mstore(str, strLength) // Write the length. + } + } + + /// @dev Returns the hexadecimal representation of `value`, + /// left-padded to an input length of `length` bytes. + /// The output is prefixed with "0x" encoded using 2 hexadecimal digits per byte, + /// giving a total length of `length * 2` bytes. + /// Reverts if `length` is too small for the output to contain all the digits. + function toHexStringNoPrefix(uint256 value, uint256 length) + internal + pure + returns (string memory str) + { + /// @solidity memory-safe-assembly + assembly { + // We need 0x20 bytes for the trailing zeros padding, `length * 2` bytes + // for the digits, 0x02 bytes for the prefix, and 0x20 bytes for the length. + // We add 0x20 to the total and round down to a multiple of 0x20. + // (0x20 + 0x20 + 0x02 + 0x20) = 0x62. + str := add(mload(0x40), and(add(shl(1, length), 0x42), not(0x1f))) + // Allocate the memory. + mstore(0x40, add(str, 0x20)) + // Zeroize the slot after the string. + mstore(str, 0) + + // Cache the end to calculate the length later. + let end := str + // Store "0123456789abcdef" in scratch space. + mstore(0x0f, 0x30313233343536373839616263646566) + + let start := sub(str, add(length, length)) + let w := not(1) // Tsk. + let temp := value + // We write the string from rightmost digit to leftmost digit. + // The following is essentially a do-while loop that also handles the zero case. + for {} 1 {} { + str := add(str, w) // `sub(str, 2)`. + mstore8(add(str, 1), mload(and(temp, 15))) + mstore8(str, mload(and(shr(4, temp), 15))) + temp := shr(8, temp) + if iszero(xor(str, start)) { break } + } + + if temp { + // Store the function selector of `HexLengthInsufficient()`. + mstore(0x00, 0x2194895a) + // Revert with (offset, size). + revert(0x1c, 0x04) + } + + // Compute the string's length. + let strLength := sub(end, str) + // Move the pointer and write the length. + str := sub(str, 0x20) + mstore(str, strLength) + } + } + + /// @dev Returns the hexadecimal representation of `value`. + /// The output is prefixed with "0x" and encoded using 2 hexadecimal digits per byte. + /// As address are 20 bytes long, the output will left-padded to have + /// a length of `20 * 2 + 2` bytes. + function toHexString(uint256 value) internal pure returns (string memory str) { + str = toHexStringNoPrefix(value); + /// @solidity memory-safe-assembly + assembly { + let strLength := add(mload(str), 2) // Compute the length. + mstore(str, 0x3078) // Write the "0x" prefix. + str := sub(str, 2) // Move the pointer. + mstore(str, strLength) // Write the length. + } + } + + /// @dev Returns the hexadecimal representation of `value`. + /// The output is prefixed with "0x". + /// The output excludes leading "0" from the `toHexString` output. + /// `0x00: "0x0", 0x01: "0x1", 0x12: "0x12", 0x123: "0x123"`. + function toMinimalHexString(uint256 value) internal pure returns (string memory str) { + str = toHexStringNoPrefix(value); + /// @solidity memory-safe-assembly + assembly { + let o := eq(byte(0, mload(add(str, 0x20))), 0x30) // Whether leading zero is present. + let strLength := add(mload(str), 2) // Compute the length. + mstore(add(str, o), 0x3078) // Write the "0x" prefix, accounting for leading zero. + str := sub(add(str, o), 2) // Move the pointer, accounting for leading zero. + mstore(str, sub(strLength, o)) // Write the length, accounting for leading zero. + } + } + + /// @dev Returns the hexadecimal representation of `value`. + /// The output excludes leading "0" from the `toHexStringNoPrefix` output. + /// `0x00: "0", 0x01: "1", 0x12: "12", 0x123: "123"`. + function toMinimalHexStringNoPrefix(uint256 value) internal pure returns (string memory str) { + str = toHexStringNoPrefix(value); + /// @solidity memory-safe-assembly + assembly { + let o := eq(byte(0, mload(add(str, 0x20))), 0x30) // Whether leading zero is present. + let strLength := mload(str) // Get the length. + str := add(str, o) // Move the pointer, accounting for leading zero. + mstore(str, sub(strLength, o)) // Write the length, accounting for leading zero. + } + } + + /// @dev Returns the hexadecimal representation of `value`. + /// The output is encoded using 2 hexadecimal digits per byte. + /// As address are 20 bytes long, the output will left-padded to have + /// a length of `20 * 2` bytes. + function toHexStringNoPrefix(uint256 value) internal pure returns (string memory str) { + /// @solidity memory-safe-assembly + assembly { + // We need 0x20 bytes for the trailing zeros padding, 0x20 bytes for the length, + // 0x02 bytes for the prefix, and 0x40 bytes for the digits. + // The next multiple of 0x20 above (0x20 + 0x20 + 0x02 + 0x40) is 0xa0. + str := add(mload(0x40), 0x80) + // Allocate the memory. + mstore(0x40, add(str, 0x20)) + // Zeroize the slot after the string. + mstore(str, 0) + + // Cache the end to calculate the length later. + let end := str + // Store "0123456789abcdef" in scratch space. + mstore(0x0f, 0x30313233343536373839616263646566) + + let w := not(1) // Tsk. + // We write the string from rightmost digit to leftmost digit. + // The following is essentially a do-while loop that also handles the zero case. + for { let temp := value } 1 {} { + str := add(str, w) // `sub(str, 2)`. + mstore8(add(str, 1), mload(and(temp, 15))) + mstore8(str, mload(and(shr(4, temp), 15))) + temp := shr(8, temp) + if iszero(temp) { break } + } + + // Compute the string's length. + let strLength := sub(end, str) + // Move the pointer and write the length. + str := sub(str, 0x20) + mstore(str, strLength) + } + } + + /// @dev Returns the hexadecimal representation of `value`. + /// The output is prefixed with "0x", encoded using 2 hexadecimal digits per byte, + /// and the alphabets are capitalized conditionally according to + /// https://eips.ethereum.org/EIPS/eip-55 + function toHexStringChecksummed(address value) internal pure returns (string memory str) { + str = toHexString(value); + /// @solidity memory-safe-assembly + assembly { + let mask := shl(6, div(not(0), 255)) // `0b010000000100000000 ...` + let o := add(str, 0x22) + let hashed := and(keccak256(o, 40), mul(34, mask)) // `0b10001000 ... ` + let t := shl(240, 136) // `0b10001000 << 240` + for { let i := 0 } 1 {} { + mstore(add(i, i), mul(t, byte(i, hashed))) + i := add(i, 1) + if eq(i, 20) { break } + } + mstore(o, xor(mload(o), shr(1, and(mload(0x00), and(mload(o), mask))))) + o := add(o, 0x20) + mstore(o, xor(mload(o), shr(1, and(mload(0x20), and(mload(o), mask))))) + } + } + + /// @dev Returns the hexadecimal representation of `value`. + /// The output is prefixed with "0x" and encoded using 2 hexadecimal digits per byte. + function toHexString(address value) internal pure returns (string memory str) { + str = toHexStringNoPrefix(value); + /// @solidity memory-safe-assembly + assembly { + let strLength := add(mload(str), 2) // Compute the length. + mstore(str, 0x3078) // Write the "0x" prefix. + str := sub(str, 2) // Move the pointer. + mstore(str, strLength) // Write the length. + } + } + + /// @dev Returns the hexadecimal representation of `value`. + /// The output is encoded using 2 hexadecimal digits per byte. + function toHexStringNoPrefix(address value) internal pure returns (string memory str) { + /// @solidity memory-safe-assembly + assembly { + str := mload(0x40) + + // Allocate the memory. + // We need 0x20 bytes for the trailing zeros padding, 0x20 bytes for the length, + // 0x02 bytes for the prefix, and 0x28 bytes for the digits. + // The next multiple of 0x20 above (0x20 + 0x20 + 0x02 + 0x28) is 0x80. + mstore(0x40, add(str, 0x80)) + + // Store "0123456789abcdef" in scratch space. + mstore(0x0f, 0x30313233343536373839616263646566) + + str := add(str, 2) + mstore(str, 40) + + let o := add(str, 0x20) + mstore(add(o, 40), 0) + + value := shl(96, value) + + // We write the string from rightmost digit to leftmost digit. + // The following is essentially a do-while loop that also handles the zero case. + for { let i := 0 } 1 {} { + let p := add(o, add(i, i)) + let temp := byte(i, value) + mstore8(add(p, 1), mload(and(temp, 15))) + mstore8(p, mload(shr(4, temp))) + i := add(i, 1) + if eq(i, 20) { break } + } + } + } + + /// @dev Returns the hex encoded string from the raw bytes. + /// The output is encoded using 2 hexadecimal digits per byte. + function toHexString(bytes memory raw) internal pure returns (string memory str) { + str = toHexStringNoPrefix(raw); + /// @solidity memory-safe-assembly + assembly { + let strLength := add(mload(str), 2) // Compute the length. + mstore(str, 0x3078) // Write the "0x" prefix. + str := sub(str, 2) // Move the pointer. + mstore(str, strLength) // Write the length. + } + } + + /// @dev Returns the hex encoded string from the raw bytes. + /// The output is encoded using 2 hexadecimal digits per byte. + function toHexStringNoPrefix(bytes memory raw) internal pure returns (string memory str) { + /// @solidity memory-safe-assembly + assembly { + let length := mload(raw) + str := add(mload(0x40), 2) // Skip 2 bytes for the optional prefix. + mstore(str, add(length, length)) // Store the length of the output. + + // Store "0123456789abcdef" in scratch space. + mstore(0x0f, 0x30313233343536373839616263646566) + + let o := add(str, 0x20) + let end := add(raw, length) + + for {} iszero(eq(raw, end)) {} { + raw := add(raw, 1) + mstore8(add(o, 1), mload(and(mload(raw), 15))) + mstore8(o, mload(and(shr(4, mload(raw)), 15))) + o := add(o, 2) + } + mstore(o, 0) // Zeroize the slot after the string. + mstore(0x40, add(o, 0x20)) // Allocate the memory. + } + } + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* RUNE STRING OPERATIONS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev Returns the number of UTF characters in the string. + function runeCount(string memory s) internal pure returns (uint256 result) { + /// @solidity memory-safe-assembly + assembly { + if mload(s) { + mstore(0x00, div(not(0), 255)) + mstore(0x20, 0x0202020202020202020202020202020202020202020202020303030304040506) + let o := add(s, 0x20) + let end := add(o, mload(s)) + for { result := 1 } 1 { result := add(result, 1) } { + o := add(o, byte(0, mload(shr(250, mload(o))))) + if iszero(lt(o, end)) { break } + } + } + } + } + + /// @dev Returns if this string is a 7-bit ASCII string. + /// (i.e. all characters codes are in [0..127]) + function is7BitASCII(string memory s) internal pure returns (bool result) { + /// @solidity memory-safe-assembly + assembly { + let mask := shl(7, div(not(0), 255)) + result := 1 + let n := mload(s) + if n { + let o := add(s, 0x20) + let end := add(o, n) + let last := mload(end) + mstore(end, 0) + for {} 1 {} { + if and(mask, mload(o)) { + result := 0 + break + } + o := add(o, 0x20) + if iszero(lt(o, end)) { break } + } + mstore(end, last) + } + } + } + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* BYTE STRING OPERATIONS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + // For performance and bytecode compactness, all indices of the following operations + // are byte (ASCII) offsets, not UTF character offsets. + + /// @dev Returns `subject` all occurrences of `search` replaced with `replacement`. + function replace(string memory subject, string memory search, string memory replacement) + internal + pure + returns (string memory result) + { + /// @solidity memory-safe-assembly + assembly { + let subjectLength := mload(subject) + let searchLength := mload(search) + let replacementLength := mload(replacement) + + subject := add(subject, 0x20) + search := add(search, 0x20) + replacement := add(replacement, 0x20) + result := add(mload(0x40), 0x20) + + let subjectEnd := add(subject, subjectLength) + if iszero(gt(searchLength, subjectLength)) { + let subjectSearchEnd := add(sub(subjectEnd, searchLength), 1) + let h := 0 + if iszero(lt(searchLength, 0x20)) { h := keccak256(search, searchLength) } + let m := shl(3, sub(0x20, and(searchLength, 0x1f))) + let s := mload(search) + for {} 1 {} { + let t := mload(subject) + // Whether the first `searchLength % 32` bytes of + // `subject` and `search` matches. + if iszero(shr(m, xor(t, s))) { + if h { + if iszero(eq(keccak256(subject, searchLength), h)) { + mstore(result, t) + result := add(result, 1) + subject := add(subject, 1) + if iszero(lt(subject, subjectSearchEnd)) { break } + continue + } + } + // Copy the `replacement` one word at a time. + for { let o := 0 } 1 {} { + mstore(add(result, o), mload(add(replacement, o))) + o := add(o, 0x20) + if iszero(lt(o, replacementLength)) { break } + } + result := add(result, replacementLength) + subject := add(subject, searchLength) + if searchLength { + if iszero(lt(subject, subjectSearchEnd)) { break } + continue + } + } + mstore(result, t) + result := add(result, 1) + subject := add(subject, 1) + if iszero(lt(subject, subjectSearchEnd)) { break } + } + } + + let resultRemainder := result + result := add(mload(0x40), 0x20) + let k := add(sub(resultRemainder, result), sub(subjectEnd, subject)) + // Copy the rest of the string one word at a time. + for {} lt(subject, subjectEnd) {} { + mstore(resultRemainder, mload(subject)) + resultRemainder := add(resultRemainder, 0x20) + subject := add(subject, 0x20) + } + result := sub(result, 0x20) + let last := add(add(result, 0x20), k) // Zeroize the slot after the string. + mstore(last, 0) + mstore(0x40, add(last, 0x20)) // Allocate the memory. + mstore(result, k) // Store the length. + } + } + + /// @dev Returns the byte index of the first location of `search` in `subject`, + /// searching from left to right, starting from `from`. + /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `search` is not found. + function indexOf(string memory subject, string memory search, uint256 from) + internal + pure + returns (uint256 result) + { + /// @solidity memory-safe-assembly + assembly { + for { let subjectLength := mload(subject) } 1 {} { + if iszero(mload(search)) { + if iszero(gt(from, subjectLength)) { + result := from + break + } + result := subjectLength + break + } + let searchLength := mload(search) + let subjectStart := add(subject, 0x20) + + result := not(0) // Initialize to `NOT_FOUND`. + + subject := add(subjectStart, from) + let end := add(sub(add(subjectStart, subjectLength), searchLength), 1) + + let m := shl(3, sub(0x20, and(searchLength, 0x1f))) + let s := mload(add(search, 0x20)) + + if iszero(and(lt(subject, end), lt(from, subjectLength))) { break } + + if iszero(lt(searchLength, 0x20)) { + for { let h := keccak256(add(search, 0x20), searchLength) } 1 {} { + if iszero(shr(m, xor(mload(subject), s))) { + if eq(keccak256(subject, searchLength), h) { + result := sub(subject, subjectStart) + break + } + } + subject := add(subject, 1) + if iszero(lt(subject, end)) { break } + } + break + } + for {} 1 {} { + if iszero(shr(m, xor(mload(subject), s))) { + result := sub(subject, subjectStart) + break + } + subject := add(subject, 1) + if iszero(lt(subject, end)) { break } + } + break + } + } + } + + /// @dev Returns the byte index of the first location of `search` in `subject`, + /// searching from left to right. + /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `search` is not found. + function indexOf(string memory subject, string memory search) + internal + pure + returns (uint256 result) + { + result = indexOf(subject, search, 0); + } + + /// @dev Returns the byte index of the first location of `search` in `subject`, + /// searching from right to left, starting from `from`. + /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `search` is not found. + function lastIndexOf(string memory subject, string memory search, uint256 from) + internal + pure + returns (uint256 result) + { + /// @solidity memory-safe-assembly + assembly { + for {} 1 {} { + result := not(0) // Initialize to `NOT_FOUND`. + let searchLength := mload(search) + if gt(searchLength, mload(subject)) { break } + let w := result + + let fromMax := sub(mload(subject), searchLength) + if iszero(gt(fromMax, from)) { from := fromMax } + + let end := add(add(subject, 0x20), w) + subject := add(add(subject, 0x20), from) + if iszero(gt(subject, end)) { break } + // As this function is not too often used, + // we shall simply use keccak256 for smaller bytecode size. + for { let h := keccak256(add(search, 0x20), searchLength) } 1 {} { + if eq(keccak256(subject, searchLength), h) { + result := sub(subject, add(end, 1)) + break + } + subject := add(subject, w) // `sub(subject, 1)`. + if iszero(gt(subject, end)) { break } + } + break + } + } + } + + /// @dev Returns the byte index of the first location of `search` in `subject`, + /// searching from right to left. + /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `search` is not found. + function lastIndexOf(string memory subject, string memory search) + internal + pure + returns (uint256 result) + { + result = lastIndexOf(subject, search, uint256(int256(-1))); + } + + /// @dev Returns whether `subject` starts with `search`. + function startsWith(string memory subject, string memory search) + internal + pure + returns (bool result) + { + /// @solidity memory-safe-assembly + assembly { + let searchLength := mload(search) + // Just using keccak256 directly is actually cheaper. + // forgefmt: disable-next-item + result := and( + iszero(gt(searchLength, mload(subject))), + eq( + keccak256(add(subject, 0x20), searchLength), + keccak256(add(search, 0x20), searchLength) + ) + ) + } + } + + /// @dev Returns whether `subject` ends with `search`. + function endsWith(string memory subject, string memory search) + internal + pure + returns (bool result) + { + /// @solidity memory-safe-assembly + assembly { + let searchLength := mload(search) + let subjectLength := mload(subject) + // Whether `search` is not longer than `subject`. + let withinRange := iszero(gt(searchLength, subjectLength)) + // Just using keccak256 directly is actually cheaper. + // forgefmt: disable-next-item + result := and( + withinRange, + eq( + keccak256( + // `subject + 0x20 + max(subjectLength - searchLength, 0)`. + add(add(subject, 0x20), mul(withinRange, sub(subjectLength, searchLength))), + searchLength + ), + keccak256(add(search, 0x20), searchLength) + ) + ) + } + } + + /// @dev Returns `subject` repeated `times`. + function repeat(string memory subject, uint256 times) + internal + pure + returns (string memory result) + { + /// @solidity memory-safe-assembly + assembly { + let subjectLength := mload(subject) + if iszero(or(iszero(times), iszero(subjectLength))) { + subject := add(subject, 0x20) + result := mload(0x40) + let output := add(result, 0x20) + for {} 1 {} { + // Copy the `subject` one word at a time. + for { let o := 0 } 1 {} { + mstore(add(output, o), mload(add(subject, o))) + o := add(o, 0x20) + if iszero(lt(o, subjectLength)) { break } + } + output := add(output, subjectLength) + times := sub(times, 1) + if iszero(times) { break } + } + mstore(output, 0) // Zeroize the slot after the string. + let resultLength := sub(output, add(result, 0x20)) + mstore(result, resultLength) // Store the length. + // Allocate the memory. + mstore(0x40, add(result, add(resultLength, 0x20))) + } + } + } + + /// @dev Returns a copy of `subject` sliced from `start` to `end` (exclusive). + /// `start` and `end` are byte offsets. + function slice(string memory subject, uint256 start, uint256 end) + internal + pure + returns (string memory result) + { + /// @solidity memory-safe-assembly + assembly { + let subjectLength := mload(subject) + if iszero(gt(subjectLength, end)) { end := subjectLength } + if iszero(gt(subjectLength, start)) { start := subjectLength } + if lt(start, end) { + result := mload(0x40) + let resultLength := sub(end, start) + mstore(result, resultLength) + subject := add(subject, start) + let w := not(0x1f) + // Copy the `subject` one word at a time, backwards. + for { let o := and(add(resultLength, 0x1f), w) } 1 {} { + mstore(add(result, o), mload(add(subject, o))) + o := add(o, w) // `sub(o, 0x20)`. + if iszero(o) { break } + } + // Zeroize the slot after the string. + mstore(add(add(result, 0x20), resultLength), 0) + // Allocate memory for the length and the bytes, + // rounded up to a multiple of 32. + mstore(0x40, add(result, and(add(resultLength, 0x3f), w))) + } + } + } + + /// @dev Returns a copy of `subject` sliced from `start` to the end of the string. + /// `start` is a byte offset. + function slice(string memory subject, uint256 start) + internal + pure + returns (string memory result) + { + result = slice(subject, start, uint256(int256(-1))); + } + + /// @dev Returns all the indices of `search` in `subject`. + /// The indices are byte offsets. + function indicesOf(string memory subject, string memory search) + internal + pure + returns (uint256[] memory result) + { + /// @solidity memory-safe-assembly + assembly { + let subjectLength := mload(subject) + let searchLength := mload(search) + + if iszero(gt(searchLength, subjectLength)) { + subject := add(subject, 0x20) + search := add(search, 0x20) + result := add(mload(0x40), 0x20) + + let subjectStart := subject + let subjectSearchEnd := add(sub(add(subject, subjectLength), searchLength), 1) + let h := 0 + if iszero(lt(searchLength, 0x20)) { h := keccak256(search, searchLength) } + let m := shl(3, sub(0x20, and(searchLength, 0x1f))) + let s := mload(search) + for {} 1 {} { + let t := mload(subject) + // Whether the first `searchLength % 32` bytes of + // `subject` and `search` matches. + if iszero(shr(m, xor(t, s))) { + if h { + if iszero(eq(keccak256(subject, searchLength), h)) { + subject := add(subject, 1) + if iszero(lt(subject, subjectSearchEnd)) { break } + continue + } + } + // Append to `result`. + mstore(result, sub(subject, subjectStart)) + result := add(result, 0x20) + // Advance `subject` by `searchLength`. + subject := add(subject, searchLength) + if searchLength { + if iszero(lt(subject, subjectSearchEnd)) { break } + continue + } + } + subject := add(subject, 1) + if iszero(lt(subject, subjectSearchEnd)) { break } + } + let resultEnd := result + // Assign `result` to the free memory pointer. + result := mload(0x40) + // Store the length of `result`. + mstore(result, shr(5, sub(resultEnd, add(result, 0x20)))) + // Allocate memory for result. + // We allocate one more word, so this array can be recycled for {split}. + mstore(0x40, add(resultEnd, 0x20)) + } + } + } + + /// @dev Returns a arrays of strings based on the `delimiter` inside of the `subject` string. + function split(string memory subject, string memory delimiter) + internal + pure + returns (string[] memory result) + { + uint256[] memory indices = indicesOf(subject, delimiter); + /// @solidity memory-safe-assembly + assembly { + let w := not(0x1f) + let indexPtr := add(indices, 0x20) + let indicesEnd := add(indexPtr, shl(5, add(mload(indices), 1))) + mstore(add(indicesEnd, w), mload(subject)) + mstore(indices, add(mload(indices), 1)) + let prevIndex := 0 + for {} 1 {} { + let index := mload(indexPtr) + mstore(indexPtr, 0x60) + if iszero(eq(index, prevIndex)) { + let element := mload(0x40) + let elementLength := sub(index, prevIndex) + mstore(element, elementLength) + // Copy the `subject` one word at a time, backwards. + for { let o := and(add(elementLength, 0x1f), w) } 1 {} { + mstore(add(element, o), mload(add(add(subject, prevIndex), o))) + o := add(o, w) // `sub(o, 0x20)`. + if iszero(o) { break } + } + // Zeroize the slot after the string. + mstore(add(add(element, 0x20), elementLength), 0) + // Allocate memory for the length and the bytes, + // rounded up to a multiple of 32. + mstore(0x40, add(element, and(add(elementLength, 0x3f), w))) + // Store the `element` into the array. + mstore(indexPtr, element) + } + prevIndex := add(index, mload(delimiter)) + indexPtr := add(indexPtr, 0x20) + if iszero(lt(indexPtr, indicesEnd)) { break } + } + result := indices + if iszero(mload(delimiter)) { + result := add(indices, 0x20) + mstore(result, sub(mload(indices), 2)) + } + } + } + + /// @dev Returns a concatenated string of `a` and `b`. + /// Cheaper than `string.concat()` and does not de-align the free memory pointer. + function concat(string memory a, string memory b) + internal + pure + returns (string memory result) + { + /// @solidity memory-safe-assembly + assembly { + let w := not(0x1f) + result := mload(0x40) + let aLength := mload(a) + // Copy `a` one word at a time, backwards. + for { let o := and(add(aLength, 0x20), w) } 1 {} { + mstore(add(result, o), mload(add(a, o))) + o := add(o, w) // `sub(o, 0x20)`. + if iszero(o) { break } + } + let bLength := mload(b) + let output := add(result, aLength) + // Copy `b` one word at a time, backwards. + for { let o := and(add(bLength, 0x20), w) } 1 {} { + mstore(add(output, o), mload(add(b, o))) + o := add(o, w) // `sub(o, 0x20)`. + if iszero(o) { break } + } + let totalLength := add(aLength, bLength) + let last := add(add(result, 0x20), totalLength) + // Zeroize the slot after the string. + mstore(last, 0) + // Stores the length. + mstore(result, totalLength) + // Allocate memory for the length and the bytes, + // rounded up to a multiple of 32. + mstore(0x40, and(add(last, 0x1f), w)) + } + } + + /// @dev Returns a copy of the string in either lowercase or UPPERCASE. + /// WARNING! This function is only compatible with 7-bit ASCII strings. + function toCase(string memory subject, bool toUpper) + internal + pure + returns (string memory result) + { + /// @solidity memory-safe-assembly + assembly { + let length := mload(subject) + if length { + result := add(mload(0x40), 0x20) + subject := add(subject, 1) + let flags := shl(add(70, shl(5, toUpper)), 0x3ffffff) + let w := not(0) + for { let o := length } 1 {} { + o := add(o, w) + let b := and(0xff, mload(add(subject, o))) + mstore8(add(result, o), xor(b, and(shr(b, flags), 0x20))) + if iszero(o) { break } + } + result := mload(0x40) + mstore(result, length) // Store the length. + let last := add(add(result, 0x20), length) + mstore(last, 0) // Zeroize the slot after the string. + mstore(0x40, add(last, 0x20)) // Allocate the memory. + } + } + } + + /// @dev Returns a lowercased copy of the string. + /// WARNING! This function is only compatible with 7-bit ASCII strings. + function lower(string memory subject) internal pure returns (string memory result) { + result = toCase(subject, false); + } + + /// @dev Returns an UPPERCASED copy of the string. + /// WARNING! This function is only compatible with 7-bit ASCII strings. + function upper(string memory subject) internal pure returns (string memory result) { + result = toCase(subject, true); + } + + /// @dev Escapes the string to be used within HTML tags. + function escapeHTML(string memory s) internal pure returns (string memory result) { + /// @solidity memory-safe-assembly + assembly { + for { + let end := add(s, mload(s)) + result := add(mload(0x40), 0x20) + // Store the bytes of the packed offsets and strides into the scratch space. + // `packed = (stride << 5) | offset`. Max offset is 20. Max stride is 6. + mstore(0x1f, 0x900094) + mstore(0x08, 0xc0000000a6ab) + // Store ""&'<>" into the scratch space. + mstore(0x00, shl(64, 0x2671756f743b26616d703b262333393b266c743b2667743b)) + } iszero(eq(s, end)) {} { + s := add(s, 1) + let c := and(mload(s), 0xff) + // Not in `["\"","'","&","<",">"]`. + if iszero(and(shl(c, 1), 0x500000c400000000)) { + mstore8(result, c) + result := add(result, 1) + continue + } + let t := shr(248, mload(c)) + mstore(result, mload(and(t, 0x1f))) + result := add(result, shr(5, t)) + } + let last := result + mstore(last, 0) // Zeroize the slot after the string. + result := mload(0x40) + mstore(result, sub(last, add(result, 0x20))) // Store the length. + mstore(0x40, add(last, 0x20)) // Allocate the memory. + } + } + + /// @dev Escapes the string to be used within double-quotes in a JSON. + function escapeJSON(string memory s) internal pure returns (string memory result) { + /// @solidity memory-safe-assembly + assembly { + for { + let end := add(s, mload(s)) + result := add(mload(0x40), 0x20) + // Store "\\u0000" in scratch space. + // Store "0123456789abcdef" in scratch space. + // Also, store `{0x08:"b", 0x09:"t", 0x0a:"n", 0x0c:"f", 0x0d:"r"}`. + // into the scratch space. + mstore(0x15, 0x5c75303030303031323334353637383961626364656662746e006672) + // Bitmask for detecting `["\"","\\"]`. + let e := or(shl(0x22, 1), shl(0x5c, 1)) + } iszero(eq(s, end)) {} { + s := add(s, 1) + let c := and(mload(s), 0xff) + if iszero(lt(c, 0x20)) { + if iszero(and(shl(c, 1), e)) { + // Not in `["\"","\\"]`. + mstore8(result, c) + result := add(result, 1) + continue + } + mstore8(result, 0x5c) // "\\". + mstore8(add(result, 1), c) + result := add(result, 2) + continue + } + if iszero(and(shl(c, 1), 0x3700)) { + // Not in `["\b","\t","\n","\f","\d"]`. + mstore8(0x1d, mload(shr(4, c))) // Hex value. + mstore8(0x1e, mload(and(c, 15))) // Hex value. + mstore(result, mload(0x19)) // "\\u00XX". + result := add(result, 6) + continue + } + mstore8(result, 0x5c) // "\\". + mstore8(add(result, 1), mload(add(c, 8))) + result := add(result, 2) + } + let last := result + mstore(last, 0) // Zeroize the slot after the string. + result := mload(0x40) + mstore(result, sub(last, add(result, 0x20))) // Store the length. + mstore(0x40, add(last, 0x20)) // Allocate the memory. + } + } + + /// @dev Returns whether `a` equals `b`. + function eq(string memory a, string memory b) internal pure returns (bool result) { + assembly { + result := eq(keccak256(add(a, 0x20), mload(a)), keccak256(add(b, 0x20), mload(b))) + } + } + + /// @dev Packs a single string with its length into a single word. + /// Returns `bytes32(0)` if the length is zero or greater than 31. + function packOne(string memory a) internal pure returns (bytes32 result) { + /// @solidity memory-safe-assembly + assembly { + // We don't need to zero right pad the string, + // since this is our own custom non-standard packing scheme. + result := + mul( + // Load the length and the bytes. + mload(add(a, 0x1f)), + // `length != 0 && length < 32`. Abuses underflow. + // Assumes that the length is valid and within the block gas limit. + lt(sub(mload(a), 1), 0x1f) + ) + } + } + + /// @dev Unpacks a string packed using {packOne}. + /// Returns the empty string if `packed` is `bytes32(0)`. + /// If `packed` is not an output of {packOne}, the output behaviour is undefined. + function unpackOne(bytes32 packed) internal pure returns (string memory result) { + /// @solidity memory-safe-assembly + assembly { + // Grab the free memory pointer. + result := mload(0x40) + // Allocate 2 words (1 for the length, 1 for the bytes). + mstore(0x40, add(result, 0x40)) + // Zeroize the length slot. + mstore(result, 0) + // Store the length and bytes. + mstore(add(result, 0x1f), packed) + // Right pad with zeroes. + mstore(add(add(result, 0x20), mload(result)), 0) + } + } + + /// @dev Packs two strings with their lengths into a single word. + /// Returns `bytes32(0)` if combined length is zero or greater than 30. + function packTwo(string memory a, string memory b) internal pure returns (bytes32 result) { + /// @solidity memory-safe-assembly + assembly { + let aLength := mload(a) + // We don't need to zero right pad the strings, + // since this is our own custom non-standard packing scheme. + result := + mul( + // Load the length and the bytes of `a` and `b`. + or( + shl(shl(3, sub(0x1f, aLength)), mload(add(a, aLength))), + mload(sub(add(b, 0x1e), aLength)) + ), + // `totalLength != 0 && totalLength < 31`. Abuses underflow. + // Assumes that the lengths are valid and within the block gas limit. + lt(sub(add(aLength, mload(b)), 1), 0x1e) + ) + } + } + + /// @dev Unpacks strings packed using {packTwo}. + /// Returns the empty strings if `packed` is `bytes32(0)`. + /// If `packed` is not an output of {packTwo}, the output behaviour is undefined. + function unpackTwo(bytes32 packed) + internal + pure + returns (string memory resultA, string memory resultB) + { + /// @solidity memory-safe-assembly + assembly { + // Grab the free memory pointer. + resultA := mload(0x40) + resultB := add(resultA, 0x40) + // Allocate 2 words for each string (1 for the length, 1 for the byte). Total 4 words. + mstore(0x40, add(resultB, 0x40)) + // Zeroize the length slots. + mstore(resultA, 0) + mstore(resultB, 0) + // Store the lengths and bytes. + mstore(add(resultA, 0x1f), packed) + mstore(add(resultB, 0x1f), mload(add(add(resultA, 0x20), mload(resultA)))) + // Right pad with zeroes. + mstore(add(add(resultA, 0x20), mload(resultA)), 0) + mstore(add(add(resultB, 0x20), mload(resultB)), 0) + } + } + + /// @dev Directly returns `a` without copying. + function directReturn(string memory a) internal pure { + assembly { + // Assumes that the string does not start from the scratch space. + let retStart := sub(a, 0x20) + let retSize := add(mload(a), 0x40) + // Right pad with zeroes. Just in case the string is produced + // by a method that doesn't zero right pad. + mstore(add(retStart, retSize), 0) + // Store the return offset. + mstore(retStart, 0x20) + // End the transaction, returning the string. + return(retStart, retSize) + } + } +} + +// src\common/ITreasury.sol + + + +/// @title ITreasury +/// @author Mathieu Bour for Pooky Labs Ltd. +interface ITreasury { + /// Thrown when the msg.value of the mint function does not cover the mint cost. + error InsufficientValue(uint256 expected, uint256 actual); + /// Thrown when the native transfer has failed. + error TransferFailed(address recipient, uint256 amount); + + /// Change the native currency destination address. + /// @param _treasury The new treasury address. + function changeTreasury(address _treasury) external; +} + +// lib/ERC721A/contracts\ERC721A.sol + +// ERC721A Contracts v4.2.3 +// Creator: Chiru Labs + + + + + +/** + * @dev Interface of ERC721 token receiver. + */ +interface ERC721A__IERC721Receiver { + function onERC721Received( + address operator, + address from, + uint256 tokenId, + bytes calldata data + ) external returns (bytes4); +} + +/** + * @title ERC721A + * + * @dev Implementation of the [ERC721](https://eips.ethereum.org/EIPS/eip-721) + * Non-Fungible Token Standard, including the Metadata extension. + * Optimized for lower gas during batch mints. + * + * Token IDs are minted in sequential order (e.g. 0, 1, 2, 3, ...) + * starting from `_startTokenId()`. + * + * Assumptions: + * + * - An owner cannot have more than 2**64 - 1 (max value of uint64) of supply. + * - The maximum token ID cannot exceed 2**256 - 1 (max value of uint256). + */ +contract ERC721A is IERC721A { + // Bypass for a `--via-ir` bug (https://github.com/chiru-labs/ERC721A/pull/364). + struct TokenApprovalRef { + address value; + } + + // ============================================================= + // CONSTANTS + // ============================================================= + + // Mask of an entry in packed address data. + uint256 private constant _BITMASK_ADDRESS_DATA_ENTRY = (1 << 64) - 1; + + // The bit position of `numberMinted` in packed address data. + uint256 private constant _BITPOS_NUMBER_MINTED = 64; + + // The bit position of `numberBurned` in packed address data. + uint256 private constant _BITPOS_NUMBER_BURNED = 128; + + // The bit position of `aux` in packed address data. + uint256 private constant _BITPOS_AUX = 192; + + // Mask of all 256 bits in packed address data except the 64 bits for `aux`. + uint256 private constant _BITMASK_AUX_COMPLEMENT = (1 << 192) - 1; + + // The bit position of `startTimestamp` in packed ownership. + uint256 private constant _BITPOS_START_TIMESTAMP = 160; + + // The bit mask of the `burned` bit in packed ownership. + uint256 private constant _BITMASK_BURNED = 1 << 224; + + // The bit position of the `nextInitialized` bit in packed ownership. + uint256 private constant _BITPOS_NEXT_INITIALIZED = 225; + + // The bit mask of the `nextInitialized` bit in packed ownership. + uint256 private constant _BITMASK_NEXT_INITIALIZED = 1 << 225; + + // The bit position of `extraData` in packed ownership. + uint256 private constant _BITPOS_EXTRA_DATA = 232; + + // Mask of all 256 bits in a packed ownership except the 24 bits for `extraData`. + uint256 private constant _BITMASK_EXTRA_DATA_COMPLEMENT = (1 << 232) - 1; + + // The mask of the lower 160 bits for addresses. + uint256 private constant _BITMASK_ADDRESS = (1 << 160) - 1; + + // The maximum `quantity` that can be minted with {_mintERC2309}. + // This limit is to prevent overflows on the address data entries. + // For a limit of 5000, a total of 3.689e15 calls to {_mintERC2309} + // is required to cause an overflow, which is unrealistic. + uint256 private constant _MAX_MINT_ERC2309_QUANTITY_LIMIT = 5000; + + // The `Transfer` event signature is given by: + // `keccak256(bytes("Transfer(address,address,uint256)"))`. + bytes32 private constant _TRANSFER_EVENT_SIGNATURE = + 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef; + + // ============================================================= + // STORAGE + // ============================================================= + + // The next token ID to be minted. + uint256 private _currentIndex; + + // The number of tokens burned. + uint256 private _burnCounter; + + // Token name + string private _name; + + // Token symbol + string private _symbol; + + // Mapping from token ID to ownership details + // An empty struct value does not necessarily mean the token is unowned. + // See {_packedOwnershipOf} implementation for details. + // + // Bits Layout: + // - [0..159] `addr` + // - [160..223] `startTimestamp` + // - [224] `burned` + // - [225] `nextInitialized` + // - [232..255] `extraData` + mapping(uint256 => uint256) private _packedOwnerships; + + // Mapping owner address to address data. + // + // Bits Layout: + // - [0..63] `balance` + // - [64..127] `numberMinted` + // - [128..191] `numberBurned` + // - [192..255] `aux` + mapping(address => uint256) private _packedAddressData; + + // Mapping from token ID to approved address. + mapping(uint256 => TokenApprovalRef) private _tokenApprovals; + + // Mapping from owner to operator approvals + mapping(address => mapping(address => bool)) private _operatorApprovals; + + // ============================================================= + // CONSTRUCTOR + // ============================================================= + + constructor(string memory name_, string memory symbol_) { + _name = name_; + _symbol = symbol_; + _currentIndex = _startTokenId(); + } + + // ============================================================= + // TOKEN COUNTING OPERATIONS + // ============================================================= + + /** + * @dev Returns the starting token ID. + * To change the starting token ID, please override this function. + */ + function _startTokenId() internal view virtual returns (uint256) { + return 0; + } + + /** + * @dev Returns the next token ID to be minted. + */ + function _nextTokenId() internal view virtual returns (uint256) { + return _currentIndex; + } + + /** + * @dev Returns the total number of tokens in existence. + * Burned tokens will reduce the count. + * To get the total number of tokens minted, please see {_totalMinted}. + */ + function totalSupply() public view virtual override returns (uint256) { + // Counter underflow is impossible as _burnCounter cannot be incremented + // more than `_currentIndex - _startTokenId()` times. + unchecked { + return _currentIndex - _burnCounter - _startTokenId(); + } + } + + /** + * @dev Returns the total amount of tokens minted in the contract. + */ + function _totalMinted() internal view virtual returns (uint256) { + // Counter underflow is impossible as `_currentIndex` does not decrement, + // and it is initialized to `_startTokenId()`. + unchecked { + return _currentIndex - _startTokenId(); + } + } + + /** + * @dev Returns the total number of tokens burned. + */ + function _totalBurned() internal view virtual returns (uint256) { + return _burnCounter; + } + + // ============================================================= + // ADDRESS DATA OPERATIONS + // ============================================================= + + /** + * @dev Returns the number of tokens in `owner`'s account. + */ + function balanceOf(address owner) public view virtual override returns (uint256) { + if (owner == address(0)) _revert(BalanceQueryForZeroAddress.selector); + return _packedAddressData[owner] & _BITMASK_ADDRESS_DATA_ENTRY; + } + + /** + * Returns the number of tokens minted by `owner`. + */ + function _numberMinted(address owner) internal view returns (uint256) { + return (_packedAddressData[owner] >> _BITPOS_NUMBER_MINTED) & _BITMASK_ADDRESS_DATA_ENTRY; + } + + /** + * Returns the number of tokens burned by or on behalf of `owner`. + */ + function _numberBurned(address owner) internal view returns (uint256) { + return (_packedAddressData[owner] >> _BITPOS_NUMBER_BURNED) & _BITMASK_ADDRESS_DATA_ENTRY; + } + + /** + * Returns the auxiliary data for `owner`. (e.g. number of whitelist mint slots used). + */ + function _getAux(address owner) internal view returns (uint64) { + return uint64(_packedAddressData[owner] >> _BITPOS_AUX); + } + + /** + * Sets the auxiliary data for `owner`. (e.g. number of whitelist mint slots used). + * If there are multiple variables, please pack them into a uint64. + */ + function _setAux(address owner, uint64 aux) internal virtual { + uint256 packed = _packedAddressData[owner]; + uint256 auxCasted; + // Cast `aux` with assembly to avoid redundant masking. + assembly { + auxCasted := aux + } + packed = (packed & _BITMASK_AUX_COMPLEMENT) | (auxCasted << _BITPOS_AUX); + _packedAddressData[owner] = packed; + } + + // ============================================================= + // 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 30000 gas. + */ + function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { + // The interface IDs are constants representing the first 4 bytes + // of the XOR of all function selectors in the interface. + // See: [ERC165](https://eips.ethereum.org/EIPS/eip-165) + // (e.g. `bytes4(i.functionA.selector ^ i.functionB.selector ^ ...)`) + return + interfaceId == 0x01ffc9a7 || // ERC165 interface ID for ERC165. + interfaceId == 0x80ac58cd || // ERC165 interface ID for ERC721. + interfaceId == 0x5b5e139f; // ERC165 interface ID for ERC721Metadata. + } + + // ============================================================= + // IERC721Metadata + // ============================================================= + + /** + * @dev Returns the token collection name. + */ + function name() public view virtual override returns (string memory) { + return _name; + } + + /** + * @dev Returns the token collection symbol. + */ + function symbol() public view virtual override returns (string memory) { + return _symbol; + } + + /** + * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token. + */ + function tokenURI(uint256 tokenId) public view virtual override returns (string memory) { + if (!_exists(tokenId)) _revert(URIQueryForNonexistentToken.selector); + + string memory baseURI = _baseURI(); + return bytes(baseURI).length != 0 ? string(abi.encodePacked(baseURI, _toString(tokenId))) : ''; + } + + /** + * @dev Base URI for computing {tokenURI}. If set, the resulting URI for each + * token will be the concatenation of the `baseURI` and the `tokenId`. Empty + * by default, it can be overridden in child contracts. + */ + function _baseURI() internal view virtual returns (string memory) { + return ''; + } + + // ============================================================= + // OWNERSHIPS OPERATIONS + // ============================================================= + + /** + * @dev Returns the owner of the `tokenId` token. + * + * Requirements: + * + * - `tokenId` must exist. + */ + function ownerOf(uint256 tokenId) public view virtual override returns (address) { + return address(uint160(_packedOwnershipOf(tokenId))); + } + + /** + * @dev Gas spent here starts off proportional to the maximum mint batch size. + * It gradually moves to O(1) as tokens get transferred around over time. + */ + function _ownershipOf(uint256 tokenId) internal view virtual returns (TokenOwnership memory) { + return _unpackedOwnership(_packedOwnershipOf(tokenId)); + } + + /** + * @dev Returns the unpacked `TokenOwnership` struct at `index`. + */ + function _ownershipAt(uint256 index) internal view virtual returns (TokenOwnership memory) { + return _unpackedOwnership(_packedOwnerships[index]); + } + + /** + * @dev Returns whether the ownership slot at `index` is initialized. + * An uninitialized slot does not necessarily mean that the slot has no owner. + */ + function _ownershipIsInitialized(uint256 index) internal view virtual returns (bool) { + return _packedOwnerships[index] != 0; + } + + /** + * @dev Initializes the ownership slot minted at `index` for efficiency purposes. + */ + function _initializeOwnershipAt(uint256 index) internal virtual { + if (_packedOwnerships[index] == 0) { + _packedOwnerships[index] = _packedOwnershipOf(index); + } + } + + /** + * Returns the packed ownership data of `tokenId`. + */ + function _packedOwnershipOf(uint256 tokenId) private view returns (uint256 packed) { + if (_startTokenId() <= tokenId) { + packed = _packedOwnerships[tokenId]; + // If the data at the starting slot does not exist, start the scan. + if (packed == 0) { + if (tokenId >= _currentIndex) _revert(OwnerQueryForNonexistentToken.selector); + // Invariant: + // There will always be an initialized ownership slot + // (i.e. `ownership.addr != address(0) && ownership.burned == false`) + // before an unintialized ownership slot + // (i.e. `ownership.addr == address(0) && ownership.burned == false`) + // Hence, `tokenId` will not underflow. + // + // We can directly compare the packed value. + // If the address is zero, packed will be zero. + for (;;) { + unchecked { + packed = _packedOwnerships[--tokenId]; + } + if (packed == 0) continue; + if (packed & _BITMASK_BURNED == 0) return packed; + // Otherwise, the token is burned, and we must revert. + // This handles the case of batch burned tokens, where only the burned bit + // of the starting slot is set, and remaining slots are left uninitialized. + _revert(OwnerQueryForNonexistentToken.selector); + } + } + // Otherwise, the data exists and we can skip the scan. + // This is possible because we have already achieved the target condition. + // This saves 2143 gas on transfers of initialized tokens. + // If the token is not burned, return `packed`. Otherwise, revert. + if (packed & _BITMASK_BURNED == 0) return packed; + } + _revert(OwnerQueryForNonexistentToken.selector); + } + + /** + * @dev Returns the unpacked `TokenOwnership` struct from `packed`. + */ + function _unpackedOwnership(uint256 packed) private pure returns (TokenOwnership memory ownership) { + ownership.addr = address(uint160(packed)); + ownership.startTimestamp = uint64(packed >> _BITPOS_START_TIMESTAMP); + ownership.burned = packed & _BITMASK_BURNED != 0; + ownership.extraData = uint24(packed >> _BITPOS_EXTRA_DATA); + } + + /** + * @dev Packs ownership data into a single uint256. + */ + function _packOwnershipData(address owner, uint256 flags) private view returns (uint256 result) { + assembly { + // Mask `owner` to the lower 160 bits, in case the upper bits somehow aren't clean. + owner := and(owner, _BITMASK_ADDRESS) + // `owner | (block.timestamp << _BITPOS_START_TIMESTAMP) | flags`. + result := or(owner, or(shl(_BITPOS_START_TIMESTAMP, timestamp()), flags)) + } + } + + /** + * @dev Returns the `nextInitialized` flag set if `quantity` equals 1. + */ + function _nextInitializedFlag(uint256 quantity) private pure returns (uint256 result) { + // For branchless setting of the `nextInitialized` flag. + assembly { + // `(quantity == 1) << _BITPOS_NEXT_INITIALIZED`. + result := shl(_BITPOS_NEXT_INITIALIZED, eq(quantity, 1)) + } + } + + // ============================================================= + // APPROVAL OPERATIONS + // ============================================================= + + /** + * @dev Gives permission to `to` to transfer `tokenId` token to another account. See {ERC721A-_approve}. + * + * Requirements: + * + * - The caller must own the token or be an approved operator. + */ + function approve(address to, uint256 tokenId) public payable virtual override { + _approve(to, tokenId, true); + } + + /** + * @dev Returns the account approved for `tokenId` token. + * + * Requirements: + * + * - `tokenId` must exist. + */ + function getApproved(uint256 tokenId) public view virtual override returns (address) { + if (!_exists(tokenId)) _revert(ApprovalQueryForNonexistentToken.selector); + + return _tokenApprovals[tokenId].value; + } + + /** + * @dev Approve or remove `operator` as an operator for the caller. + * Operators can call {transferFrom} or {safeTransferFrom} + * for any token owned by the caller. + * + * Requirements: + * + * - The `operator` cannot be the caller. + * + * Emits an {ApprovalForAll} event. + */ + function setApprovalForAll(address operator, bool approved) public virtual override { + _operatorApprovals[_msgSenderERC721A()][operator] = approved; + emit ApprovalForAll(_msgSenderERC721A(), operator, approved); + } + + /** + * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`. + * + * See {setApprovalForAll}. + */ + function isApprovedForAll(address owner, address operator) public view virtual override returns (bool) { + return _operatorApprovals[owner][operator]; + } + + /** + * @dev Returns whether `tokenId` exists. + * + * Tokens can be managed by their owner or approved accounts via {approve} or {setApprovalForAll}. + * + * Tokens start existing when they are minted. See {_mint}. + */ + function _exists(uint256 tokenId) internal view virtual returns (bool result) { + if (_startTokenId() <= tokenId) { + if (tokenId < _currentIndex) { + uint256 packed; + while ((packed = _packedOwnerships[tokenId]) == 0) --tokenId; + result = packed & _BITMASK_BURNED == 0; + } + } + } + + /** + * @dev Returns whether `msgSender` is equal to `approvedAddress` or `owner`. + */ + function _isSenderApprovedOrOwner( + address approvedAddress, + address owner, + address msgSender + ) private pure returns (bool result) { + assembly { + // Mask `owner` to the lower 160 bits, in case the upper bits somehow aren't clean. + owner := and(owner, _BITMASK_ADDRESS) + // Mask `msgSender` to the lower 160 bits, in case the upper bits somehow aren't clean. + msgSender := and(msgSender, _BITMASK_ADDRESS) + // `msgSender == owner || msgSender == approvedAddress`. + result := or(eq(msgSender, owner), eq(msgSender, approvedAddress)) + } + } + + /** + * @dev Returns the storage slot and value for the approved address of `tokenId`. + */ + function _getApprovedSlotAndAddress(uint256 tokenId) + private + view + returns (uint256 approvedAddressSlot, address approvedAddress) + { + TokenApprovalRef storage tokenApproval = _tokenApprovals[tokenId]; + // The following is equivalent to `approvedAddress = _tokenApprovals[tokenId].value`. + assembly { + approvedAddressSlot := tokenApproval.slot + approvedAddress := sload(approvedAddressSlot) + } + } + + // ============================================================= + // TRANSFER OPERATIONS + // ============================================================= + + /** + * @dev Transfers `tokenId` from `from` to `to`. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must be owned by `from`. + * - If the caller is not `from`, it must be approved to move this token + * by either {approve} or {setApprovalForAll}. + * + * Emits a {Transfer} event. + */ + function transferFrom( + address from, + address to, + uint256 tokenId + ) public payable virtual override { + uint256 prevOwnershipPacked = _packedOwnershipOf(tokenId); + + // Mask `from` to the lower 160 bits, in case the upper bits somehow aren't clean. + from = address(uint160(uint256(uint160(from)) & _BITMASK_ADDRESS)); + + if (address(uint160(prevOwnershipPacked)) != from) _revert(TransferFromIncorrectOwner.selector); + + (uint256 approvedAddressSlot, address approvedAddress) = _getApprovedSlotAndAddress(tokenId); + + // The nested ifs save around 20+ gas over a compound boolean condition. + if (!_isSenderApprovedOrOwner(approvedAddress, from, _msgSenderERC721A())) + if (!isApprovedForAll(from, _msgSenderERC721A())) _revert(TransferCallerNotOwnerNorApproved.selector); + + _beforeTokenTransfers(from, to, tokenId, 1); + + // Clear approvals from the previous owner. + assembly { + if approvedAddress { + // This is equivalent to `delete _tokenApprovals[tokenId]`. + sstore(approvedAddressSlot, 0) + } + } + + // Underflow of the sender's balance is impossible because we check for + // ownership above and the recipient's balance can't realistically overflow. + // Counter overflow is incredibly unrealistic as `tokenId` would have to be 2**256. + unchecked { + // We can directly increment and decrement the balances. + --_packedAddressData[from]; // Updates: `balance -= 1`. + ++_packedAddressData[to]; // Updates: `balance += 1`. + + // Updates: + // - `address` to the next owner. + // - `startTimestamp` to the timestamp of transfering. + // - `burned` to `false`. + // - `nextInitialized` to `true`. + _packedOwnerships[tokenId] = _packOwnershipData( + to, + _BITMASK_NEXT_INITIALIZED | _nextExtraData(from, to, prevOwnershipPacked) + ); + + // If the next slot may not have been initialized (i.e. `nextInitialized == false`) . + if (prevOwnershipPacked & _BITMASK_NEXT_INITIALIZED == 0) { + uint256 nextTokenId = tokenId + 1; + // If the next slot's address is zero and not burned (i.e. packed value is zero). + if (_packedOwnerships[nextTokenId] == 0) { + // If the next slot is within bounds. + if (nextTokenId != _currentIndex) { + // Initialize the next slot to maintain correctness for `ownerOf(tokenId + 1)`. + _packedOwnerships[nextTokenId] = prevOwnershipPacked; + } + } + } + } + + // Mask `to` to the lower 160 bits, in case the upper bits somehow aren't clean. + uint256 toMasked = uint256(uint160(to)) & _BITMASK_ADDRESS; + assembly { + // Emit the `Transfer` event. + log4( + 0, // Start of data (0, since no data). + 0, // End of data (0, since no data). + _TRANSFER_EVENT_SIGNATURE, // Signature. + from, // `from`. + toMasked, // `to`. + tokenId // `tokenId`. + ) + } + if (toMasked == 0) _revert(TransferToZeroAddress.selector); + + _afterTokenTransfers(from, to, tokenId, 1); + } + + /** + * @dev Equivalent to `safeTransferFrom(from, to, tokenId, '')`. + */ + function safeTransferFrom( + address from, + address to, + uint256 tokenId + ) public payable virtual override { + safeTransferFrom(from, to, tokenId, ''); + } + + /** + * @dev Safely transfers `tokenId` token from `from` to `to`. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must exist and be owned by `from`. + * - If the caller is not `from`, it must be approved to move this token + * by either {approve} or {setApprovalForAll}. + * - If `to` refers to a smart contract, it must implement + * {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. + * + * Emits a {Transfer} event. + */ + function safeTransferFrom( + address from, + address to, + uint256 tokenId, + bytes memory _data + ) public payable virtual override { + transferFrom(from, to, tokenId); + if (to.code.length != 0) + if (!_checkContractOnERC721Received(from, to, tokenId, _data)) { + _revert(TransferToNonERC721ReceiverImplementer.selector); + } + } + + /** + * @dev Hook that is called before a set of serially-ordered token IDs + * are about to be transferred. This includes minting. + * And also called before burning one token. + * + * `startTokenId` - the first token ID to be transferred. + * `quantity` - the amount to be transferred. + * + * Calling conditions: + * + * - When `from` and `to` are both non-zero, `from`'s `tokenId` will be + * transferred to `to`. + * - When `from` is zero, `tokenId` will be minted for `to`. + * - When `to` is zero, `tokenId` will be burned by `from`. + * - `from` and `to` are never both zero. + */ + function _beforeTokenTransfers( + address from, + address to, + uint256 startTokenId, + uint256 quantity + ) internal virtual {} + + /** + * @dev Hook that is called after a set of serially-ordered token IDs + * have been transferred. This includes minting. + * And also called after one token has been burned. + * + * `startTokenId` - the first token ID to be transferred. + * `quantity` - the amount to be transferred. + * + * Calling conditions: + * + * - When `from` and `to` are both non-zero, `from`'s `tokenId` has been + * transferred to `to`. + * - When `from` is zero, `tokenId` has been minted for `to`. + * - When `to` is zero, `tokenId` has been burned by `from`. + * - `from` and `to` are never both zero. + */ + function _afterTokenTransfers( + address from, + address to, + uint256 startTokenId, + uint256 quantity + ) internal virtual {} + + /** + * @dev Private function to invoke {IERC721Receiver-onERC721Received} on a target contract. + * + * `from` - Previous owner of the given token ID. + * `to` - Target address that will receive the token. + * `tokenId` - Token ID to be transferred. + * `_data` - Optional data to send along with the call. + * + * Returns whether the call correctly returned the expected magic value. + */ + function _checkContractOnERC721Received( + address from, + address to, + uint256 tokenId, + bytes memory _data + ) private returns (bool) { + try ERC721A__IERC721Receiver(to).onERC721Received(_msgSenderERC721A(), from, tokenId, _data) returns ( + bytes4 retval + ) { + return retval == ERC721A__IERC721Receiver(to).onERC721Received.selector; + } catch (bytes memory reason) { + if (reason.length == 0) { + _revert(TransferToNonERC721ReceiverImplementer.selector); + } + assembly { + revert(add(32, reason), mload(reason)) + } + } + } + + // ============================================================= + // MINT OPERATIONS + // ============================================================= + + /** + * @dev Mints `quantity` tokens and transfers them to `to`. + * + * Requirements: + * + * - `to` cannot be the zero address. + * - `quantity` must be greater than 0. + * + * Emits a {Transfer} event for each mint. + */ + function _mint(address to, uint256 quantity) internal virtual { + uint256 startTokenId = _currentIndex; + if (quantity == 0) _revert(MintZeroQuantity.selector); + + _beforeTokenTransfers(address(0), to, startTokenId, quantity); + + // Overflows are incredibly unrealistic. + // `balance` and `numberMinted` have a maximum limit of 2**64. + // `tokenId` has a maximum limit of 2**256. + unchecked { + // Updates: + // - `address` to the owner. + // - `startTimestamp` to the timestamp of minting. + // - `burned` to `false`. + // - `nextInitialized` to `quantity == 1`. + _packedOwnerships[startTokenId] = _packOwnershipData( + to, + _nextInitializedFlag(quantity) | _nextExtraData(address(0), to, 0) + ); + + // Updates: + // - `balance += quantity`. + // - `numberMinted += quantity`. + // + // We can directly add to the `balance` and `numberMinted`. + _packedAddressData[to] += quantity * ((1 << _BITPOS_NUMBER_MINTED) | 1); + + // Mask `to` to the lower 160 bits, in case the upper bits somehow aren't clean. + uint256 toMasked = uint256(uint160(to)) & _BITMASK_ADDRESS; + + if (toMasked == 0) _revert(MintToZeroAddress.selector); + + uint256 end = startTokenId + quantity; + uint256 tokenId = startTokenId; + + do { + assembly { + // Emit the `Transfer` event. + log4( + 0, // Start of data (0, since no data). + 0, // End of data (0, since no data). + _TRANSFER_EVENT_SIGNATURE, // Signature. + 0, // `address(0)`. + toMasked, // `to`. + tokenId // `tokenId`. + ) + } + // The `!=` check ensures that large values of `quantity` + // that overflows uint256 will make the loop run out of gas. + } while (++tokenId != end); + + _currentIndex = end; + } + _afterTokenTransfers(address(0), to, startTokenId, quantity); + } + + /** + * @dev Mints `quantity` tokens and transfers them to `to`. + * + * This function is intended for efficient minting only during contract creation. + * + * It emits only one {ConsecutiveTransfer} as defined in + * [ERC2309](https://eips.ethereum.org/EIPS/eip-2309), + * instead of a sequence of {Transfer} event(s). + * + * Calling this function outside of contract creation WILL make your contract + * non-compliant with the ERC721 standard. + * For full ERC721 compliance, substituting ERC721 {Transfer} event(s) with the ERC2309 + * {ConsecutiveTransfer} event is only permissible during contract creation. + * + * Requirements: + * + * - `to` cannot be the zero address. + * - `quantity` must be greater than 0. + * + * Emits a {ConsecutiveTransfer} event. + */ + function _mintERC2309(address to, uint256 quantity) internal virtual { + uint256 startTokenId = _currentIndex; + if (to == address(0)) _revert(MintToZeroAddress.selector); + if (quantity == 0) _revert(MintZeroQuantity.selector); + if (quantity > _MAX_MINT_ERC2309_QUANTITY_LIMIT) _revert(MintERC2309QuantityExceedsLimit.selector); + + _beforeTokenTransfers(address(0), to, startTokenId, quantity); + + // Overflows are unrealistic due to the above check for `quantity` to be below the limit. + unchecked { + // Updates: + // - `balance += quantity`. + // - `numberMinted += quantity`. + // + // We can directly add to the `balance` and `numberMinted`. + _packedAddressData[to] += quantity * ((1 << _BITPOS_NUMBER_MINTED) | 1); + + // Updates: + // - `address` to the owner. + // - `startTimestamp` to the timestamp of minting. + // - `burned` to `false`. + // - `nextInitialized` to `quantity == 1`. + _packedOwnerships[startTokenId] = _packOwnershipData( + to, + _nextInitializedFlag(quantity) | _nextExtraData(address(0), to, 0) + ); + + emit ConsecutiveTransfer(startTokenId, startTokenId + quantity - 1, address(0), to); + + _currentIndex = startTokenId + quantity; + } + _afterTokenTransfers(address(0), to, startTokenId, quantity); + } + + /** + * @dev Safely mints `quantity` tokens and transfers them to `to`. + * + * Requirements: + * + * - If `to` refers to a smart contract, it must implement + * {IERC721Receiver-onERC721Received}, which is called for each safe transfer. + * - `quantity` must be greater than 0. + * + * See {_mint}. + * + * Emits a {Transfer} event for each mint. + */ + function _safeMint( + address to, + uint256 quantity, + bytes memory _data + ) internal virtual { + _mint(to, quantity); + + unchecked { + if (to.code.length != 0) { + uint256 end = _currentIndex; + uint256 index = end - quantity; + do { + if (!_checkContractOnERC721Received(address(0), to, index++, _data)) { + _revert(TransferToNonERC721ReceiverImplementer.selector); + } + } while (index < end); + // Reentrancy protection. + if (_currentIndex != end) _revert(bytes4(0)); + } + } + } + + /** + * @dev Equivalent to `_safeMint(to, quantity, '')`. + */ + function _safeMint(address to, uint256 quantity) internal virtual { + _safeMint(to, quantity, ''); + } + + // ============================================================= + // APPROVAL OPERATIONS + // ============================================================= + + /** + * @dev Equivalent to `_approve(to, tokenId, false)`. + */ + function _approve(address to, uint256 tokenId) internal virtual { + _approve(to, tokenId, false); + } + + /** + * @dev Gives permission to `to` to transfer `tokenId` token to another account. + * The approval is cleared when the token is transferred. + * + * Only a single account can be approved at a time, so approving the + * zero address clears previous approvals. + * + * Requirements: + * + * - `tokenId` must exist. + * + * Emits an {Approval} event. + */ + function _approve( + address to, + uint256 tokenId, + bool approvalCheck + ) internal virtual { + address owner = ownerOf(tokenId); + + if (approvalCheck && _msgSenderERC721A() != owner) + if (!isApprovedForAll(owner, _msgSenderERC721A())) { + _revert(ApprovalCallerNotOwnerNorApproved.selector); + } + + _tokenApprovals[tokenId].value = to; + emit Approval(owner, to, tokenId); + } + + // ============================================================= + // BURN OPERATIONS + // ============================================================= + + /** + * @dev Equivalent to `_burn(tokenId, false)`. + */ + function _burn(uint256 tokenId) internal virtual { + _burn(tokenId, false); + } + + /** + * @dev Destroys `tokenId`. + * The approval is cleared when the token is burned. + * + * Requirements: + * + * - `tokenId` must exist. + * + * Emits a {Transfer} event. + */ + function _burn(uint256 tokenId, bool approvalCheck) internal virtual { + uint256 prevOwnershipPacked = _packedOwnershipOf(tokenId); + + address from = address(uint160(prevOwnershipPacked)); + + (uint256 approvedAddressSlot, address approvedAddress) = _getApprovedSlotAndAddress(tokenId); + + if (approvalCheck) { + // The nested ifs save around 20+ gas over a compound boolean condition. + if (!_isSenderApprovedOrOwner(approvedAddress, from, _msgSenderERC721A())) + if (!isApprovedForAll(from, _msgSenderERC721A())) _revert(TransferCallerNotOwnerNorApproved.selector); + } + + _beforeTokenTransfers(from, address(0), tokenId, 1); + + // Clear approvals from the previous owner. + assembly { + if approvedAddress { + // This is equivalent to `delete _tokenApprovals[tokenId]`. + sstore(approvedAddressSlot, 0) + } + } + + // Underflow of the sender's balance is impossible because we check for + // ownership above and the recipient's balance can't realistically overflow. + // Counter overflow is incredibly unrealistic as `tokenId` would have to be 2**256. + unchecked { + // Updates: + // - `balance -= 1`. + // - `numberBurned += 1`. + // + // We can directly decrement the balance, and increment the number burned. + // This is equivalent to `packed -= 1; packed += 1 << _BITPOS_NUMBER_BURNED;`. + _packedAddressData[from] += (1 << _BITPOS_NUMBER_BURNED) - 1; + + // Updates: + // - `address` to the last owner. + // - `startTimestamp` to the timestamp of burning. + // - `burned` to `true`. + // - `nextInitialized` to `true`. + _packedOwnerships[tokenId] = _packOwnershipData( + from, + (_BITMASK_BURNED | _BITMASK_NEXT_INITIALIZED) | _nextExtraData(from, address(0), prevOwnershipPacked) + ); + + // If the next slot may not have been initialized (i.e. `nextInitialized == false`) . + if (prevOwnershipPacked & _BITMASK_NEXT_INITIALIZED == 0) { + uint256 nextTokenId = tokenId + 1; + // If the next slot's address is zero and not burned (i.e. packed value is zero). + if (_packedOwnerships[nextTokenId] == 0) { + // If the next slot is within bounds. + if (nextTokenId != _currentIndex) { + // Initialize the next slot to maintain correctness for `ownerOf(tokenId + 1)`. + _packedOwnerships[nextTokenId] = prevOwnershipPacked; + } + } + } + } + + emit Transfer(from, address(0), tokenId); + _afterTokenTransfers(from, address(0), tokenId, 1); + + // Overflow not possible, as _burnCounter cannot be exceed _currentIndex times. + unchecked { + _burnCounter++; + } + } + + // ============================================================= + // EXTRA DATA OPERATIONS + // ============================================================= + + /** + * @dev Directly sets the extra data for the ownership data `index`. + */ + function _setExtraDataAt(uint256 index, uint24 extraData) internal virtual { + uint256 packed = _packedOwnerships[index]; + if (packed == 0) _revert(OwnershipNotInitializedForExtraData.selector); + uint256 extraDataCasted; + // Cast `extraData` with assembly to avoid redundant masking. + assembly { + extraDataCasted := extraData + } + packed = (packed & _BITMASK_EXTRA_DATA_COMPLEMENT) | (extraDataCasted << _BITPOS_EXTRA_DATA); + _packedOwnerships[index] = packed; + } + + /** + * @dev Called during each token transfer to set the 24bit `extraData` field. + * Intended to be overridden by the cosumer contract. + * + * `previousExtraData` - the value of `extraData` before transfer. + * + * Calling conditions: + * + * - When `from` and `to` are both non-zero, `from`'s `tokenId` will be + * transferred to `to`. + * - When `from` is zero, `tokenId` will be minted for `to`. + * - When `to` is zero, `tokenId` will be burned by `from`. + * - `from` and `to` are never both zero. + */ + function _extraData( + address from, + address to, + uint24 previousExtraData + ) internal view virtual returns (uint24) {} + + /** + * @dev Returns the next extra data for the packed ownership data. + * The returned result is shifted into position. + */ + function _nextExtraData( + address from, + address to, + uint256 prevOwnershipPacked + ) private view returns (uint256) { + uint24 extraData = uint24(prevOwnershipPacked >> _BITPOS_EXTRA_DATA); + return uint256(_extraData(from, to, extraData)) << _BITPOS_EXTRA_DATA; + } + + // ============================================================= + // OTHER OPERATIONS + // ============================================================= + + /** + * @dev Returns the message sender (defaults to `msg.sender`). + * + * If you are writing GSN compatible contracts, you need to override this function. + */ + function _msgSenderERC721A() internal view virtual returns (address) { + return msg.sender; + } + + /** + * @dev Converts a uint256 to its ASCII string decimal representation. + */ + function _toString(uint256 value) internal pure virtual returns (string memory str) { + assembly { + // The maximum value of a uint256 contains 78 digits (1 byte per digit), but + // we allocate 0xa0 bytes to keep the free memory pointer 32-byte word aligned. + // We will need 1 word for the trailing zeros padding, 1 word for the length, + // and 3 words for a maximum of 78 digits. Total: 5 * 0x20 = 0xa0. + let m := add(mload(0x40), 0xa0) + // Update the free memory pointer to allocate. + mstore(0x40, m) + // Assign the `str` to the end. + str := sub(m, 0x20) + // Zeroize the slot after the string. + mstore(str, 0) + + // Cache the end of the memory to calculate the length later. + let end := str + + // We write the string from rightmost digit to leftmost digit. + // The following is essentially a do-while loop that also handles the zero case. + // prettier-ignore + for { let temp := value } 1 {} { + str := sub(str, 1) + // Write the character to the pointer. + // The ASCII index of the '0' character is 48. + mstore8(str, add(48, mod(temp, 10))) + // Keep dividing `temp` until zero. + temp := div(temp, 10) + // prettier-ignore + if iszero(temp) { break } + } + + let length := sub(end, str) + // Move the pointer 32 bytes leftwards to make room for the length. + str := sub(str, 0x20) + // Store the length. + mstore(str, length) + } + } + + /** + * @dev For more efficient reverts. + */ + function _revert(bytes4 errorSelector) internal pure { + assembly { + mstore(0x00, errorSelector) + revert(0x00, 0x04) + } + } +} + +// lib/ERC721A/contracts/extensions/IERC721ABurnable.sol + +// ERC721A Contracts v4.2.3 +// Creator: Chiru Labs + + + + + +/** + * @dev Interface of ERC721ABurnable. + */ +interface IERC721ABurnable is IERC721A { + /** + * @dev Burns `tokenId`. See {ERC721A-_burn}. + * + * Requirements: + * + * - The caller must own `tokenId` or be an approved operator. + */ + function burn(uint256 tokenId) external; +} + +// lib/ERC721A/contracts/extensions/IERC721AQueryable.sol + +// ERC721A Contracts v4.2.3 +// Creator: Chiru Labs + + + + + +/** + * @dev Interface of ERC721AQueryable. + */ +interface IERC721AQueryable is IERC721A { + /** + * Invalid query range (`start` >= `stop`). + */ + error InvalidQueryRange(); + + /** + * @dev Returns the `TokenOwnership` struct at `tokenId` without reverting. + * + * If the `tokenId` is out of bounds: + * + * - `addr = address(0)` + * - `startTimestamp = 0` + * - `burned = false` + * - `extraData = 0` + * + * If the `tokenId` is burned: + * + * - `addr =
` + * - `startTimestamp = ` + * - `burned = true` + * - `extraData = ` + * + * Otherwise: + * + * - `addr =
` + * - `startTimestamp = ` + * - `burned = false` + * - `extraData = ` + */ + function explicitOwnershipOf(uint256 tokenId) external view returns (TokenOwnership memory); + + /** + * @dev Returns an array of `TokenOwnership` structs at `tokenIds` in order. + * See {ERC721AQueryable-explicitOwnershipOf} + */ + function explicitOwnershipsOf(uint256[] memory tokenIds) external view returns (TokenOwnership[] memory); + + /** + * @dev Returns an array of token IDs owned by `owner`, + * in the range [`start`, `stop`) + * (i.e. `start <= tokenId < stop`). + * + * This function allows for tokens to be queried if the collection + * grows too big for a single call of {ERC721AQueryable-tokensOfOwner}. + * + * Requirements: + * + * - `start < stop` + */ + function tokensOfOwnerIn( + address owner, + uint256 start, + uint256 stop + ) external view returns (uint256[] memory); + + /** + * @dev Returns an array of token IDs owned by `owner`. + * + * This function scans the ownership mapping and is O(`totalSupply`) in complexity. + * It is meant to be called off-chain. + * + * See {ERC721AQueryable-tokensOfOwnerIn} for splitting the scan into + * multiple smaller scans if the collection is large enough to cause + * an out-of-gas error (10K collections should be fine). + */ + function tokensOfOwner(address owner) external view returns (uint256[] memory); +} + +// lib/solady/src\auth/OwnableRoles.sol + + + + + +/// @notice Simple single owner and multiroles authorization mixin. +/// @author Solady (https://github.com/vectorized/solady/blob/main/src/auth/Ownable.sol) +/// @dev While the ownable portion follows [EIP-173](https://eips.ethereum.org/EIPS/eip-173) +/// for compatibility, the nomenclature for the 2-step ownership handover and roles +/// may be unique to this codebase. +abstract contract OwnableRoles is Ownable { + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* EVENTS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev The `user`'s roles is updated to `roles`. + /// Each bit of `roles` represents whether the role is set. + event RolesUpdated(address indexed user, uint256 indexed roles); + + /// @dev `keccak256(bytes("RolesUpdated(address,uint256)"))`. + uint256 private constant _ROLES_UPDATED_EVENT_SIGNATURE = + 0x715ad5ce61fc9595c7b415289d59cf203f23a94fa06f04af7e489a0a76e1fe26; + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* STORAGE */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev The role slot of `user` is given by: + /// ``` + /// mstore(0x00, or(shl(96, user), _ROLE_SLOT_SEED)) + /// let roleSlot := keccak256(0x00, 0x20) + /// ``` + /// This automatically ignores the upper bits of the `user` in case + /// they are not clean, as well as keep the `keccak256` under 32-bytes. + /// + /// Note: This is equal to `_OWNER_SLOT_NOT` in for gas efficiency. + uint256 private constant _ROLE_SLOT_SEED = 0x8b78c6d8; + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* INTERNAL FUNCTIONS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev Overwrite the roles directly without authorization guard. + function _setRoles(address user, uint256 roles) internal virtual { + /// @solidity memory-safe-assembly + assembly { + mstore(0x0c, _ROLE_SLOT_SEED) + mstore(0x00, user) + // Store the new value. + sstore(keccak256(0x0c, 0x20), roles) + // Emit the {RolesUpdated} event. + log3(0, 0, _ROLES_UPDATED_EVENT_SIGNATURE, shr(96, mload(0x0c)), roles) + } + } + + /// @dev Updates the roles directly without authorization guard. + /// If `on` is true, each set bit of `roles` will be turned on, + /// otherwise, each set bit of `roles` will be turned off. + function _updateRoles(address user, uint256 roles, bool on) internal virtual { + /// @solidity memory-safe-assembly + assembly { + mstore(0x0c, _ROLE_SLOT_SEED) + mstore(0x00, user) + let roleSlot := keccak256(0x0c, 0x20) + // Load the current value. + let current := sload(roleSlot) + // Compute the updated roles if `on` is true. + let updated := or(current, roles) + // Compute the updated roles if `on` is false. + // Use `and` to compute the intersection of `current` and `roles`, + // `xor` it with `current` to flip the bits in the intersection. + if iszero(on) { updated := xor(current, and(current, roles)) } + // Then, store the new value. + sstore(roleSlot, updated) + // Emit the {RolesUpdated} event. + log3(0, 0, _ROLES_UPDATED_EVENT_SIGNATURE, shr(96, mload(0x0c)), updated) + } + } + + /// @dev Grants the roles directly without authorization guard. + /// Each bit of `roles` represents the role to turn on. + function _grantRoles(address user, uint256 roles) internal virtual { + _updateRoles(user, roles, true); + } + + /// @dev Removes the roles directly without authorization guard. + /// Each bit of `roles` represents the role to turn off. + function _removeRoles(address user, uint256 roles) internal virtual { + _updateRoles(user, roles, false); + } + + /// @dev Throws if the sender does not have any of the `roles`. + function _checkRoles(uint256 roles) internal view virtual { + /// @solidity memory-safe-assembly + assembly { + // Compute the role slot. + mstore(0x0c, _ROLE_SLOT_SEED) + mstore(0x00, caller()) + // Load the stored value, and if the `and` intersection + // of the value and `roles` is zero, revert. + if iszero(and(sload(keccak256(0x0c, 0x20)), roles)) { + mstore(0x00, 0x82b42900) // `Unauthorized()`. + revert(0x1c, 0x04) + } + } + } + + /// @dev Throws if the sender is not the owner, + /// and does not have any of the `roles`. + /// Checks for ownership first, then lazily checks for roles. + function _checkOwnerOrRoles(uint256 roles) internal view virtual { + /// @solidity memory-safe-assembly + assembly { + // If the caller is not the stored owner. + // Note: `_ROLE_SLOT_SEED` is equal to `_OWNER_SLOT_NOT`. + if iszero(eq(caller(), sload(not(_ROLE_SLOT_SEED)))) { + // Compute the role slot. + mstore(0x0c, _ROLE_SLOT_SEED) + mstore(0x00, caller()) + // Load the stored value, and if the `and` intersection + // of the value and `roles` is zero, revert. + if iszero(and(sload(keccak256(0x0c, 0x20)), roles)) { + mstore(0x00, 0x82b42900) // `Unauthorized()`. + revert(0x1c, 0x04) + } + } + } + } + + /// @dev Throws if the sender does not have any of the `roles`, + /// and is not the owner. + /// Checks for roles first, then lazily checks for ownership. + function _checkRolesOrOwner(uint256 roles) internal view virtual { + /// @solidity memory-safe-assembly + assembly { + // Compute the role slot. + mstore(0x0c, _ROLE_SLOT_SEED) + mstore(0x00, caller()) + // Load the stored value, and if the `and` intersection + // of the value and `roles` is zero, revert. + if iszero(and(sload(keccak256(0x0c, 0x20)), roles)) { + // If the caller is not the stored owner. + // Note: `_ROLE_SLOT_SEED` is equal to `_OWNER_SLOT_NOT`. + if iszero(eq(caller(), sload(not(_ROLE_SLOT_SEED)))) { + mstore(0x00, 0x82b42900) // `Unauthorized()`. + revert(0x1c, 0x04) + } + } + } + } + + /// @dev Convenience function to return a `roles` bitmap from an array of `ordinals`. + /// This is meant for frontends like Etherscan, and is therefore not fully optimized. + /// Not recommended to be called on-chain. + /// Made internal to conserve bytecode. Wrap it in a public function if needed. + function _rolesFromOrdinals(uint8[] memory ordinals) internal pure returns (uint256 roles) { + /// @solidity memory-safe-assembly + assembly { + for { let i := shl(5, mload(ordinals)) } i { i := sub(i, 0x20) } { + // We don't need to mask the values of `ordinals`, as Solidity + // cleans dirty upper bits when storing variables into memory. + roles := or(shl(mload(add(ordinals, i)), 1), roles) + } + } + } + + /// @dev Convenience function to return an array of `ordinals` from the `roles` bitmap. + /// This is meant for frontends like Etherscan, and is therefore not fully optimized. + /// Not recommended to be called on-chain. + /// Made internal to conserve bytecode. Wrap it in a public function if needed. + function _ordinalsFromRoles(uint256 roles) internal pure returns (uint8[] memory ordinals) { + /// @solidity memory-safe-assembly + assembly { + // Grab the pointer to the free memory. + ordinals := mload(0x40) + let ptr := add(ordinals, 0x20) + let o := 0 + // The absence of lookup tables, De Bruijn, etc., here is intentional for + // smaller bytecode, as this function is not meant to be called on-chain. + for { let t := roles } 1 {} { + mstore(ptr, o) + // `shr` 5 is equivalent to multiplying by 0x20. + // Push back into the ordinals array if the bit is set. + ptr := add(ptr, shl(5, and(t, 1))) + o := add(o, 1) + t := shr(o, roles) + if iszero(t) { break } + } + // Store the length of `ordinals`. + mstore(ordinals, shr(5, sub(ptr, add(ordinals, 0x20)))) + // Allocate the memory. + mstore(0x40, ptr) + } + } + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* PUBLIC UPDATE FUNCTIONS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev Allows the owner to grant `user` `roles`. + /// If the `user` already has a role, then it will be an no-op for the role. + function grantRoles(address user, uint256 roles) public payable virtual onlyOwner { + _grantRoles(user, roles); + } + + /// @dev Allows the owner to remove `user` `roles`. + /// If the `user` does not have a role, then it will be an no-op for the role. + function revokeRoles(address user, uint256 roles) public payable virtual onlyOwner { + _removeRoles(user, roles); + } + + /// @dev Allow the caller to remove their own roles. + /// If the caller does not have a role, then it will be an no-op for the role. + function renounceRoles(uint256 roles) public payable virtual { + _removeRoles(msg.sender, roles); + } + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* PUBLIC READ FUNCTIONS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev Returns the roles of `user`. + function rolesOf(address user) public view virtual returns (uint256 roles) { + /// @solidity memory-safe-assembly + assembly { + // Compute the role slot. + mstore(0x0c, _ROLE_SLOT_SEED) + mstore(0x00, user) + // Load the stored value. + roles := sload(keccak256(0x0c, 0x20)) + } + } + + /// @dev Returns whether `user` has any of `roles`. + function hasAnyRole(address user, uint256 roles) public view virtual returns (bool) { + return rolesOf(user) & roles != 0; + } + + /// @dev Returns whether `user` has all of `roles`. + function hasAllRoles(address user, uint256 roles) public view virtual returns (bool) { + return rolesOf(user) & roles == roles; + } + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* MODIFIERS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev Marks a function as only callable by an account with `roles`. + modifier onlyRoles(uint256 roles) virtual { + _checkRoles(roles); + _; + } + + /// @dev Marks a function as only callable by the owner or by an account + /// with `roles`. Checks for ownership first, then lazily checks for roles. + modifier onlyOwnerOrRoles(uint256 roles) virtual { + _checkOwnerOrRoles(roles); + _; + } + + /// @dev Marks a function as only callable by an account with `roles` + /// or the owner. Checks for roles first, then lazily checks for ownership. + modifier onlyRolesOrOwner(uint256 roles) virtual { + _checkRolesOrOwner(roles); + _; + } + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* ROLE CONSTANTS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + // IYKYK + + uint256 internal constant _ROLE_0 = 1 << 0; + uint256 internal constant _ROLE_1 = 1 << 1; + uint256 internal constant _ROLE_2 = 1 << 2; + uint256 internal constant _ROLE_3 = 1 << 3; + uint256 internal constant _ROLE_4 = 1 << 4; + uint256 internal constant _ROLE_5 = 1 << 5; + uint256 internal constant _ROLE_6 = 1 << 6; + uint256 internal constant _ROLE_7 = 1 << 7; + uint256 internal constant _ROLE_8 = 1 << 8; + uint256 internal constant _ROLE_9 = 1 << 9; + uint256 internal constant _ROLE_10 = 1 << 10; + uint256 internal constant _ROLE_11 = 1 << 11; + uint256 internal constant _ROLE_12 = 1 << 12; + uint256 internal constant _ROLE_13 = 1 << 13; + uint256 internal constant _ROLE_14 = 1 << 14; + uint256 internal constant _ROLE_15 = 1 << 15; + uint256 internal constant _ROLE_16 = 1 << 16; + uint256 internal constant _ROLE_17 = 1 << 17; + uint256 internal constant _ROLE_18 = 1 << 18; + uint256 internal constant _ROLE_19 = 1 << 19; + uint256 internal constant _ROLE_20 = 1 << 20; + uint256 internal constant _ROLE_21 = 1 << 21; + uint256 internal constant _ROLE_22 = 1 << 22; + uint256 internal constant _ROLE_23 = 1 << 23; + uint256 internal constant _ROLE_24 = 1 << 24; + uint256 internal constant _ROLE_25 = 1 << 25; + uint256 internal constant _ROLE_26 = 1 << 26; + uint256 internal constant _ROLE_27 = 1 << 27; + uint256 internal constant _ROLE_28 = 1 << 28; + uint256 internal constant _ROLE_29 = 1 << 29; + uint256 internal constant _ROLE_30 = 1 << 30; + uint256 internal constant _ROLE_31 = 1 << 31; + uint256 internal constant _ROLE_32 = 1 << 32; + uint256 internal constant _ROLE_33 = 1 << 33; + uint256 internal constant _ROLE_34 = 1 << 34; + uint256 internal constant _ROLE_35 = 1 << 35; + uint256 internal constant _ROLE_36 = 1 << 36; + uint256 internal constant _ROLE_37 = 1 << 37; + uint256 internal constant _ROLE_38 = 1 << 38; + uint256 internal constant _ROLE_39 = 1 << 39; + uint256 internal constant _ROLE_40 = 1 << 40; + uint256 internal constant _ROLE_41 = 1 << 41; + uint256 internal constant _ROLE_42 = 1 << 42; + uint256 internal constant _ROLE_43 = 1 << 43; + uint256 internal constant _ROLE_44 = 1 << 44; + uint256 internal constant _ROLE_45 = 1 << 45; + uint256 internal constant _ROLE_46 = 1 << 46; + uint256 internal constant _ROLE_47 = 1 << 47; + uint256 internal constant _ROLE_48 = 1 << 48; + uint256 internal constant _ROLE_49 = 1 << 49; + uint256 internal constant _ROLE_50 = 1 << 50; + uint256 internal constant _ROLE_51 = 1 << 51; + uint256 internal constant _ROLE_52 = 1 << 52; + uint256 internal constant _ROLE_53 = 1 << 53; + uint256 internal constant _ROLE_54 = 1 << 54; + uint256 internal constant _ROLE_55 = 1 << 55; + uint256 internal constant _ROLE_56 = 1 << 56; + uint256 internal constant _ROLE_57 = 1 << 57; + uint256 internal constant _ROLE_58 = 1 << 58; + uint256 internal constant _ROLE_59 = 1 << 59; + uint256 internal constant _ROLE_60 = 1 << 60; + uint256 internal constant _ROLE_61 = 1 << 61; + uint256 internal constant _ROLE_62 = 1 << 62; + uint256 internal constant _ROLE_63 = 1 << 63; + uint256 internal constant _ROLE_64 = 1 << 64; + uint256 internal constant _ROLE_65 = 1 << 65; + uint256 internal constant _ROLE_66 = 1 << 66; + uint256 internal constant _ROLE_67 = 1 << 67; + uint256 internal constant _ROLE_68 = 1 << 68; + uint256 internal constant _ROLE_69 = 1 << 69; + uint256 internal constant _ROLE_70 = 1 << 70; + uint256 internal constant _ROLE_71 = 1 << 71; + uint256 internal constant _ROLE_72 = 1 << 72; + uint256 internal constant _ROLE_73 = 1 << 73; + uint256 internal constant _ROLE_74 = 1 << 74; + uint256 internal constant _ROLE_75 = 1 << 75; + uint256 internal constant _ROLE_76 = 1 << 76; + uint256 internal constant _ROLE_77 = 1 << 77; + uint256 internal constant _ROLE_78 = 1 << 78; + uint256 internal constant _ROLE_79 = 1 << 79; + uint256 internal constant _ROLE_80 = 1 << 80; + uint256 internal constant _ROLE_81 = 1 << 81; + uint256 internal constant _ROLE_82 = 1 << 82; + uint256 internal constant _ROLE_83 = 1 << 83; + uint256 internal constant _ROLE_84 = 1 << 84; + uint256 internal constant _ROLE_85 = 1 << 85; + uint256 internal constant _ROLE_86 = 1 << 86; + uint256 internal constant _ROLE_87 = 1 << 87; + uint256 internal constant _ROLE_88 = 1 << 88; + uint256 internal constant _ROLE_89 = 1 << 89; + uint256 internal constant _ROLE_90 = 1 << 90; + uint256 internal constant _ROLE_91 = 1 << 91; + uint256 internal constant _ROLE_92 = 1 << 92; + uint256 internal constant _ROLE_93 = 1 << 93; + uint256 internal constant _ROLE_94 = 1 << 94; + uint256 internal constant _ROLE_95 = 1 << 95; + uint256 internal constant _ROLE_96 = 1 << 96; + uint256 internal constant _ROLE_97 = 1 << 97; + uint256 internal constant _ROLE_98 = 1 << 98; + uint256 internal constant _ROLE_99 = 1 << 99; + uint256 internal constant _ROLE_100 = 1 << 100; + uint256 internal constant _ROLE_101 = 1 << 101; + uint256 internal constant _ROLE_102 = 1 << 102; + uint256 internal constant _ROLE_103 = 1 << 103; + uint256 internal constant _ROLE_104 = 1 << 104; + uint256 internal constant _ROLE_105 = 1 << 105; + uint256 internal constant _ROLE_106 = 1 << 106; + uint256 internal constant _ROLE_107 = 1 << 107; + uint256 internal constant _ROLE_108 = 1 << 108; + uint256 internal constant _ROLE_109 = 1 << 109; + uint256 internal constant _ROLE_110 = 1 << 110; + uint256 internal constant _ROLE_111 = 1 << 111; + uint256 internal constant _ROLE_112 = 1 << 112; + uint256 internal constant _ROLE_113 = 1 << 113; + uint256 internal constant _ROLE_114 = 1 << 114; + uint256 internal constant _ROLE_115 = 1 << 115; + uint256 internal constant _ROLE_116 = 1 << 116; + uint256 internal constant _ROLE_117 = 1 << 117; + uint256 internal constant _ROLE_118 = 1 << 118; + uint256 internal constant _ROLE_119 = 1 << 119; + uint256 internal constant _ROLE_120 = 1 << 120; + uint256 internal constant _ROLE_121 = 1 << 121; + uint256 internal constant _ROLE_122 = 1 << 122; + uint256 internal constant _ROLE_123 = 1 << 123; + uint256 internal constant _ROLE_124 = 1 << 124; + uint256 internal constant _ROLE_125 = 1 << 125; + uint256 internal constant _ROLE_126 = 1 << 126; + uint256 internal constant _ROLE_127 = 1 << 127; + uint256 internal constant _ROLE_128 = 1 << 128; + uint256 internal constant _ROLE_129 = 1 << 129; + uint256 internal constant _ROLE_130 = 1 << 130; + uint256 internal constant _ROLE_131 = 1 << 131; + uint256 internal constant _ROLE_132 = 1 << 132; + uint256 internal constant _ROLE_133 = 1 << 133; + uint256 internal constant _ROLE_134 = 1 << 134; + uint256 internal constant _ROLE_135 = 1 << 135; + uint256 internal constant _ROLE_136 = 1 << 136; + uint256 internal constant _ROLE_137 = 1 << 137; + uint256 internal constant _ROLE_138 = 1 << 138; + uint256 internal constant _ROLE_139 = 1 << 139; + uint256 internal constant _ROLE_140 = 1 << 140; + uint256 internal constant _ROLE_141 = 1 << 141; + uint256 internal constant _ROLE_142 = 1 << 142; + uint256 internal constant _ROLE_143 = 1 << 143; + uint256 internal constant _ROLE_144 = 1 << 144; + uint256 internal constant _ROLE_145 = 1 << 145; + uint256 internal constant _ROLE_146 = 1 << 146; + uint256 internal constant _ROLE_147 = 1 << 147; + uint256 internal constant _ROLE_148 = 1 << 148; + uint256 internal constant _ROLE_149 = 1 << 149; + uint256 internal constant _ROLE_150 = 1 << 150; + uint256 internal constant _ROLE_151 = 1 << 151; + uint256 internal constant _ROLE_152 = 1 << 152; + uint256 internal constant _ROLE_153 = 1 << 153; + uint256 internal constant _ROLE_154 = 1 << 154; + uint256 internal constant _ROLE_155 = 1 << 155; + uint256 internal constant _ROLE_156 = 1 << 156; + uint256 internal constant _ROLE_157 = 1 << 157; + uint256 internal constant _ROLE_158 = 1 << 158; + uint256 internal constant _ROLE_159 = 1 << 159; + uint256 internal constant _ROLE_160 = 1 << 160; + uint256 internal constant _ROLE_161 = 1 << 161; + uint256 internal constant _ROLE_162 = 1 << 162; + uint256 internal constant _ROLE_163 = 1 << 163; + uint256 internal constant _ROLE_164 = 1 << 164; + uint256 internal constant _ROLE_165 = 1 << 165; + uint256 internal constant _ROLE_166 = 1 << 166; + uint256 internal constant _ROLE_167 = 1 << 167; + uint256 internal constant _ROLE_168 = 1 << 168; + uint256 internal constant _ROLE_169 = 1 << 169; + uint256 internal constant _ROLE_170 = 1 << 170; + uint256 internal constant _ROLE_171 = 1 << 171; + uint256 internal constant _ROLE_172 = 1 << 172; + uint256 internal constant _ROLE_173 = 1 << 173; + uint256 internal constant _ROLE_174 = 1 << 174; + uint256 internal constant _ROLE_175 = 1 << 175; + uint256 internal constant _ROLE_176 = 1 << 176; + uint256 internal constant _ROLE_177 = 1 << 177; + uint256 internal constant _ROLE_178 = 1 << 178; + uint256 internal constant _ROLE_179 = 1 << 179; + uint256 internal constant _ROLE_180 = 1 << 180; + uint256 internal constant _ROLE_181 = 1 << 181; + uint256 internal constant _ROLE_182 = 1 << 182; + uint256 internal constant _ROLE_183 = 1 << 183; + uint256 internal constant _ROLE_184 = 1 << 184; + uint256 internal constant _ROLE_185 = 1 << 185; + uint256 internal constant _ROLE_186 = 1 << 186; + uint256 internal constant _ROLE_187 = 1 << 187; + uint256 internal constant _ROLE_188 = 1 << 188; + uint256 internal constant _ROLE_189 = 1 << 189; + uint256 internal constant _ROLE_190 = 1 << 190; + uint256 internal constant _ROLE_191 = 1 << 191; + uint256 internal constant _ROLE_192 = 1 << 192; + uint256 internal constant _ROLE_193 = 1 << 193; + uint256 internal constant _ROLE_194 = 1 << 194; + uint256 internal constant _ROLE_195 = 1 << 195; + uint256 internal constant _ROLE_196 = 1 << 196; + uint256 internal constant _ROLE_197 = 1 << 197; + uint256 internal constant _ROLE_198 = 1 << 198; + uint256 internal constant _ROLE_199 = 1 << 199; + uint256 internal constant _ROLE_200 = 1 << 200; + uint256 internal constant _ROLE_201 = 1 << 201; + uint256 internal constant _ROLE_202 = 1 << 202; + uint256 internal constant _ROLE_203 = 1 << 203; + uint256 internal constant _ROLE_204 = 1 << 204; + uint256 internal constant _ROLE_205 = 1 << 205; + uint256 internal constant _ROLE_206 = 1 << 206; + uint256 internal constant _ROLE_207 = 1 << 207; + uint256 internal constant _ROLE_208 = 1 << 208; + uint256 internal constant _ROLE_209 = 1 << 209; + uint256 internal constant _ROLE_210 = 1 << 210; + uint256 internal constant _ROLE_211 = 1 << 211; + uint256 internal constant _ROLE_212 = 1 << 212; + uint256 internal constant _ROLE_213 = 1 << 213; + uint256 internal constant _ROLE_214 = 1 << 214; + uint256 internal constant _ROLE_215 = 1 << 215; + uint256 internal constant _ROLE_216 = 1 << 216; + uint256 internal constant _ROLE_217 = 1 << 217; + uint256 internal constant _ROLE_218 = 1 << 218; + uint256 internal constant _ROLE_219 = 1 << 219; + uint256 internal constant _ROLE_220 = 1 << 220; + uint256 internal constant _ROLE_221 = 1 << 221; + uint256 internal constant _ROLE_222 = 1 << 222; + uint256 internal constant _ROLE_223 = 1 << 223; + uint256 internal constant _ROLE_224 = 1 << 224; + uint256 internal constant _ROLE_225 = 1 << 225; + uint256 internal constant _ROLE_226 = 1 << 226; + uint256 internal constant _ROLE_227 = 1 << 227; + uint256 internal constant _ROLE_228 = 1 << 228; + uint256 internal constant _ROLE_229 = 1 << 229; + uint256 internal constant _ROLE_230 = 1 << 230; + uint256 internal constant _ROLE_231 = 1 << 231; + uint256 internal constant _ROLE_232 = 1 << 232; + uint256 internal constant _ROLE_233 = 1 << 233; + uint256 internal constant _ROLE_234 = 1 << 234; + uint256 internal constant _ROLE_235 = 1 << 235; + uint256 internal constant _ROLE_236 = 1 << 236; + uint256 internal constant _ROLE_237 = 1 << 237; + uint256 internal constant _ROLE_238 = 1 << 238; + uint256 internal constant _ROLE_239 = 1 << 239; + uint256 internal constant _ROLE_240 = 1 << 240; + uint256 internal constant _ROLE_241 = 1 << 241; + uint256 internal constant _ROLE_242 = 1 << 242; + uint256 internal constant _ROLE_243 = 1 << 243; + uint256 internal constant _ROLE_244 = 1 << 244; + uint256 internal constant _ROLE_245 = 1 << 245; + uint256 internal constant _ROLE_246 = 1 << 246; + uint256 internal constant _ROLE_247 = 1 << 247; + uint256 internal constant _ROLE_248 = 1 << 248; + uint256 internal constant _ROLE_249 = 1 << 249; + uint256 internal constant _ROLE_250 = 1 << 250; + uint256 internal constant _ROLE_251 = 1 << 251; + uint256 internal constant _ROLE_252 = 1 << 252; + uint256 internal constant _ROLE_253 = 1 << 253; + uint256 internal constant _ROLE_254 = 1 << 254; + uint256 internal constant _ROLE_255 = 1 << 255; +} + +// src\common/Treasury.sol + + + + + + +/// @title Treasury +/// @author Mathieu Bour for Pooky Labs Ltd. +/// +/// @notice Base class for contracts that are made to receive native currency. +/// The destination address is controller by the contract owner. +abstract contract Treasury is Ownable, ITreasury { + /// The native currency destination address. + address public treasury; + + constructor(address _treasury) { + treasury = _treasury; + } + + /// @notice Forward the funds to the treasury wallet at the end of the transaction. + /// Since `treasury` is a trusted address, this modifier should not lead to any re-entrancy issue. + modifier forwarder() { + _; + + uint256 value = address(this).balance; + (bool sent,) = treasury.call{ value: value }(""); + if (!sent) { + revert TransferFailed(treasury, value); + } + } + + /// Change the native currency destination address. + /// @param _treasury The new treasury address. + function changeTreasury(address _treasury) external onlyOwner { + treasury = _treasury; + } +} + +// lib/ERC721A/contracts\extensions/ERC721ABurnable.sol + +// ERC721A Contracts v4.2.3 +// Creator: Chiru Labs + + + + + + +/** + * @title ERC721ABurnable. + * + * @dev ERC721A token that can be irreversibly burned (destroyed). + */ +abstract contract ERC721ABurnable is ERC721A, IERC721ABurnable { + /** + * @dev Burns `tokenId`. See {ERC721A-_burn}. + * + * Requirements: + * + * - The caller must own `tokenId` or be an approved operator. + */ + function burn(uint256 tokenId) public virtual override { + _burn(tokenId, true); + } +} + +// lib/ERC721A/contracts\extensions/ERC721AQueryable.sol + +// ERC721A Contracts v4.2.3 +// Creator: Chiru Labs + + + + + + +/** + * @title ERC721AQueryable. + * + * @dev ERC721A subclass with convenience query functions. + */ +abstract contract ERC721AQueryable is ERC721A, IERC721AQueryable { + /** + * @dev Returns the `TokenOwnership` struct at `tokenId` without reverting. + * + * If the `tokenId` is out of bounds: + * + * - `addr = address(0)` + * - `startTimestamp = 0` + * - `burned = false` + * - `extraData = 0` + * + * If the `tokenId` is burned: + * + * - `addr =
` + * - `startTimestamp = ` + * - `burned = true` + * - `extraData = ` + * + * Otherwise: + * + * - `addr =
` + * - `startTimestamp = ` + * - `burned = false` + * - `extraData = ` + */ + function explicitOwnershipOf(uint256 tokenId) + public + view + virtual + override + returns (TokenOwnership memory ownership) + { + unchecked { + if (tokenId >= _startTokenId()) { + if (tokenId < _nextTokenId()) { + // If the `tokenId` is within bounds, + // scan backwards for the initialized ownership slot. + while (!_ownershipIsInitialized(tokenId)) --tokenId; + return _ownershipAt(tokenId); + } + } + } + } + + /** + * @dev Returns an array of `TokenOwnership` structs at `tokenIds` in order. + * See {ERC721AQueryable-explicitOwnershipOf} + */ + function explicitOwnershipsOf(uint256[] calldata tokenIds) + external + view + virtual + override + returns (TokenOwnership[] memory) + { + TokenOwnership[] memory ownerships; + uint256 i = tokenIds.length; + assembly { + // Grab the free memory pointer. + ownerships := mload(0x40) + // Store the length. + mstore(ownerships, i) + // Allocate one word for the length, + // `tokenIds.length` words for the pointers. + i := shl(5, i) // Multiply `i` by 32. + mstore(0x40, add(add(ownerships, 0x20), i)) + } + while (i != 0) { + uint256 tokenId; + assembly { + i := sub(i, 0x20) + tokenId := calldataload(add(tokenIds.offset, i)) + } + TokenOwnership memory ownership = explicitOwnershipOf(tokenId); + assembly { + // Store the pointer of `ownership` in the `ownerships` array. + mstore(add(add(ownerships, 0x20), i), ownership) + } + } + return ownerships; + } + + /** + * @dev Returns an array of token IDs owned by `owner`, + * in the range [`start`, `stop`) + * (i.e. `start <= tokenId < stop`). + * + * This function allows for tokens to be queried if the collection + * grows too big for a single call of {ERC721AQueryable-tokensOfOwner}. + * + * Requirements: + * + * - `start < stop` + */ + function tokensOfOwnerIn( + address owner, + uint256 start, + uint256 stop + ) external view virtual override returns (uint256[] memory) { + return _tokensOfOwnerIn(owner, start, stop); + } + + /** + * @dev Returns an array of token IDs owned by `owner`. + * + * This function scans the ownership mapping and is O(`totalSupply`) in complexity. + * It is meant to be called off-chain. + * + * See {ERC721AQueryable-tokensOfOwnerIn} for splitting the scan into + * multiple smaller scans if the collection is large enough to cause + * an out-of-gas error (10K collections should be fine). + */ + function tokensOfOwner(address owner) external view virtual override returns (uint256[] memory) { + uint256 start = _startTokenId(); + uint256 stop = _nextTokenId(); + uint256[] memory tokenIds; + if (start != stop) tokenIds = _tokensOfOwnerIn(owner, start, stop); + return tokenIds; + } + + /** + * @dev Helper function for returning an array of token IDs owned by `owner`. + * + * Note that this function is optimized for smaller bytecode size over runtime gas, + * since it is meant to be called off-chain. + */ + function _tokensOfOwnerIn( + address owner, + uint256 start, + uint256 stop + ) private view returns (uint256[] memory) { + unchecked { + if (start >= stop) _revert(InvalidQueryRange.selector); + // Set `start = max(start, _startTokenId())`. + if (start < _startTokenId()) { + start = _startTokenId(); + } + uint256 stopLimit = _nextTokenId(); + // Set `stop = min(stop, stopLimit)`. + if (stop >= stopLimit) { + stop = stopLimit; + } + uint256[] memory tokenIds; + uint256 tokenIdsMaxLength = balanceOf(owner); + bool startLtStop = start < stop; + assembly { + // Set `tokenIdsMaxLength` to zero if `start` is less than `stop`. + tokenIdsMaxLength := mul(tokenIdsMaxLength, startLtStop) + } + if (tokenIdsMaxLength != 0) { + // Set `tokenIdsMaxLength = min(balanceOf(owner), stop - start)`, + // to cater for cases where `balanceOf(owner)` is too big. + if (stop - start <= tokenIdsMaxLength) { + tokenIdsMaxLength = stop - start; + } + assembly { + // Grab the free memory pointer. + tokenIds := mload(0x40) + // Allocate one word for the length, and `tokenIdsMaxLength` words + // for the data. `shl(5, x)` is equivalent to `mul(32, x)`. + mstore(0x40, add(tokenIds, shl(5, add(tokenIdsMaxLength, 1)))) + } + // We need to call `explicitOwnershipOf(start)`, + // because the slot at `start` may not be initialized. + TokenOwnership memory ownership = explicitOwnershipOf(start); + address currOwnershipAddr; + // If the starting slot exists (i.e. not burned), + // initialize `currOwnershipAddr`. + // `ownership.address` will not be zero, + // as `start` is clamped to the valid token ID range. + if (!ownership.burned) { + currOwnershipAddr = ownership.addr; + } + uint256 tokenIdsIdx; + // Use a do-while, which is slightly more efficient for this case, + // as the array will at least contain one element. + do { + ownership = _ownershipAt(start); + assembly { + switch mload(add(ownership, 0x40)) + // if `ownership.burned == false`. + case 0 { + // if `ownership.addr != address(0)`. + // The `addr` already has it's upper 96 bits clearned, + // since it is written to memory with regular Solidity. + if mload(ownership) { + currOwnershipAddr := mload(ownership) + } + // if `currOwnershipAddr == owner`. + // The `shl(96, x)` is to make the comparison agnostic to any + // dirty upper 96 bits in `owner`. + if iszero(shl(96, xor(currOwnershipAddr, owner))) { + tokenIdsIdx := add(tokenIdsIdx, 1) + mstore(add(tokenIds, shl(5, tokenIdsIdx)), start) + } + } + // Otherwise, reset `currOwnershipAddr`. + // This handles the case of batch burned tokens + // (burned bit of first slot set, remaining slots left uninitialized). + default { + currOwnershipAddr := 0 + } + start := add(start, 1) + } + } while (!(start == stop || tokenIdsIdx == tokenIdsMaxLength)); + // Store the length of the array. + assembly { + mstore(tokenIds, tokenIdsIdx) + } + } + return tokenIds; + } + } +} + +// src\common\Energy.sol + + + + + + + + + + + + +/// @title Energy +/// @author Mathieu Bour for Pooky Labs Ltd. +/// Allow players to purchase a voucher representing energy on the Pooky.gg game. +contract Energy is ERC721A, ERC721ABurnable, ERC721AQueryable, OwnableRoles, Treasury { + using LibString for uint256; + + /// Role allowed to change the pricing + uint256 public constant OPERATOR = _ROLE_0; + + /// How much cost 1 Energy point + uint256 public pricing; + + /// How much Energy is worth each token + mapping(uint256 => uint256) public values; + + constructor(address admin, address[] memory operators, address _treasury, uint256 _pricing) + ERC721A("Pooky Energy", "PERG") + Treasury(_treasury) + { + _initializeOwner(admin); + for (uint256 i; i < operators.length;) { + _grantRoles(operators[i], OPERATOR); + unchecked { + i++; + } + } + + pricing = _pricing; + } + + /// @notice Change the Energy pricing + function setPricing(uint256 _pricing) external onlyRolesOrOwner(OPERATOR) { + pricing = _pricing; + } + + /// @dev Voucher token IDs start at 1. + function _startTokenId() internal pure override returns (uint256) { + return 1; + } + + /// @notice Generate the on-chain metadata + /// @dev Expected pattern: + /// ``` + /// { + /// "name": "Voucher {tokenId}", + /// "description": "Voucher granting XX Energy on Pooky.gg", + /// "attributes": [ + /// { "trait_type": "Value", "value": XX } + /// ] + /// } + /// ``` + /// The function is deliberatly gas-inefficient, but far more clear. + function tokenURI(uint256 tokenId) + public + view + override(ERC721A, IERC721A) + returns (string memory) + { + string memory value = values[tokenId].toString(); + bytes memory dataURI = abi.encodePacked( + "{", + abi.encodePacked('"name": "Voucher #', tokenId.toString(), '",'), + abi.encodePacked('"description": "Voucher granting ', value, ' Energy on Pooky.gg",'), + abi.encodePacked( + '"attributes": [', + abi.encodePacked('{ "trait_type": "Value", "value": ', value, " }"), // Energy attribute + "]" + ), + "}" + ); + + return string(abi.encodePacked("data:application/json;base64,", Base64.encode(dataURI))); + } + + /// Mint a new Energy voucher + /// @param quantity The amount of Energy points + /// @param recipient The address that should receive the voucher + /// @dev Requirements + /// - msg.value must be greater than pricing*quantity + function mint(uint256 quantity, address recipient) + external + payable + forwarder + returns (uint256 tokenId) + { + uint256 expected = quantity * pricing; + + if (msg.value < expected) { + revert InsufficientValue(expected, msg.value); + } + + tokenId = _nextTokenId(); + _mint(recipient, 1); + values[tokenId] = quantity; + } +} diff --git a/flattened/NonceRegistry.sol b/flattened/NonceRegistry.sol new file mode 100644 index 00000000..cc45fbc3 --- /dev/null +++ b/flattened/NonceRegistry.sol @@ -0,0 +1,974 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +// lib/openzeppelin-contracts/contracts/access/IAccessControl.sol + +// OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol) + + + +/** + * @dev External interface of AccessControl declared to support ERC165 detection. + */ +interface IAccessControl { + /** + * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` + * + * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite + * {RoleAdminChanged} not being emitted signaling this. + * + * _Available since v3.1._ + */ + event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole); + + /** + * @dev Emitted when `account` is granted `role`. + * + * `sender` is the account that originated the contract call, an admin role + * bearer except when using {AccessControl-_setupRole}. + */ + event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender); + + /** + * @dev Emitted when `account` is revoked `role`. + * + * `sender` is the account that originated the contract call: + * - if using `revokeRole`, it is the admin role bearer + * - if using `renounceRole`, it is the role bearer (i.e. `account`) + */ + event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender); + + /** + * @dev Returns `true` if `account` has been granted `role`. + */ + function hasRole(bytes32 role, address account) external view returns (bool); + + /** + * @dev Returns the admin role that controls `role`. See {grantRole} and + * {revokeRole}. + * + * To change a role's admin, use {AccessControl-_setRoleAdmin}. + */ + function getRoleAdmin(bytes32 role) external view returns (bytes32); + + /** + * @dev Grants `role` to `account`. + * + * If `account` had not been already granted `role`, emits a {RoleGranted} + * event. + * + * Requirements: + * + * - the caller must have ``role``'s admin role. + */ + function grantRole(bytes32 role, address account) external; + + /** + * @dev Revokes `role` from `account`. + * + * If `account` had been granted `role`, emits a {RoleRevoked} event. + * + * Requirements: + * + * - the caller must have ``role``'s admin role. + */ + function revokeRole(bytes32 role, address account) external; + + /** + * @dev Revokes `role` from the calling account. + * + * Roles are often managed via {grantRole} and {revokeRole}: this function's + * purpose is to provide a mechanism for accounts to lose their privileges + * if they are compromised (such as when a trusted device is misplaced). + * + * If the calling account had been granted `role`, emits a {RoleRevoked} + * event. + * + * Requirements: + * + * - the caller must be `account`. + */ + function renounceRole(bytes32 role, address account) external; +} + +// lib/openzeppelin-contracts/contracts/utils/Context.sol + +// OpenZeppelin Contracts v4.4.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; + } + + function _msgData() internal view virtual returns (bytes calldata) { + return msg.data; + } +} + +// lib/openzeppelin-contracts/contracts/utils/introspection/IERC165.sol + +// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol) + + + +/** + * @dev Interface of the ERC165 standard, as defined in the + * https://eips.ethereum.org/EIPS/eip-165[EIP]. + * + * Implementers can declare support of contract interfaces, which can then be + * queried by others ({ERC165Checker}). + * + * For an implementation, see {ERC165}. + */ +interface IERC165 { + /** + * @dev Returns true if this contract implements the interface defined by + * `interfaceId`. See the corresponding + * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] + * to learn more about how these ids are created. + * + * This function call must use less than 30 000 gas. + */ + function supportsInterface(bytes4 interfaceId) external view returns (bool); +} + +// lib/openzeppelin-contracts/contracts/utils/math/Math.sol + +// OpenZeppelin Contracts (last updated v4.9.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) { + // Solidity will revert if denominator == 0, unlike the div opcode on its own. + // The surrounding unchecked block does not change this fact. + // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic. + return prod0 / denominator; + } + + // Make sure the result is less than 2^256. Also prevents denominator == 0. + require(denominator > prod1, "Math: mulDiv overflow"); + + /////////////////////////////////////////////// + // 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. If 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)`. This value can be written `msb(a)=2**k` with `k=log2(a)`. + // + // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)` + // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))` + // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)` + // + // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit. + uint256 result = 1 << (log2(a) >> 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) { + unchecked { + uint256 result = sqrt(a); + return result + (rounding == Rounding.Up && result * result < a ? 1 : 0); + } + } + + /** + * @dev Return the log in base 2, rounded down, of a positive value. + * Returns 0 if given 0. + */ + function log2(uint256 value) internal pure returns (uint256) { + uint256 result = 0; + unchecked { + if (value >> 128 > 0) { + value >>= 128; + result += 128; + } + if (value >> 64 > 0) { + value >>= 64; + result += 64; + } + if (value >> 32 > 0) { + value >>= 32; + result += 32; + } + if (value >> 16 > 0) { + value >>= 16; + result += 16; + } + if (value >> 8 > 0) { + value >>= 8; + result += 8; + } + if (value >> 4 > 0) { + value >>= 4; + result += 4; + } + if (value >> 2 > 0) { + value >>= 2; + result += 2; + } + if (value >> 1 > 0) { + result += 1; + } + } + return result; + } + + /** + * @dev Return the log in base 2, following the selected rounding direction, of a positive value. + * Returns 0 if given 0. + */ + function log2(uint256 value, Rounding rounding) internal pure returns (uint256) { + unchecked { + uint256 result = log2(value); + return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0); + } + } + + /** + * @dev Return the log in base 10, rounded down, of a positive value. + * Returns 0 if given 0. + */ + function log10(uint256 value) internal pure returns (uint256) { + uint256 result = 0; + unchecked { + if (value >= 10 ** 64) { + value /= 10 ** 64; + result += 64; + } + if (value >= 10 ** 32) { + value /= 10 ** 32; + result += 32; + } + if (value >= 10 ** 16) { + value /= 10 ** 16; + result += 16; + } + if (value >= 10 ** 8) { + value /= 10 ** 8; + result += 8; + } + if (value >= 10 ** 4) { + value /= 10 ** 4; + result += 4; + } + if (value >= 10 ** 2) { + value /= 10 ** 2; + result += 2; + } + if (value >= 10 ** 1) { + result += 1; + } + } + return result; + } + + /** + * @dev Return the log in base 10, following the selected rounding direction, of a positive value. + * Returns 0 if given 0. + */ + function log10(uint256 value, Rounding rounding) internal pure returns (uint256) { + unchecked { + uint256 result = log10(value); + return result + (rounding == Rounding.Up && 10 ** result < value ? 1 : 0); + } + } + + /** + * @dev Return the log in base 256, rounded down, of a positive value. + * Returns 0 if given 0. + * + * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string. + */ + function log256(uint256 value) internal pure returns (uint256) { + uint256 result = 0; + unchecked { + if (value >> 128 > 0) { + value >>= 128; + result += 16; + } + if (value >> 64 > 0) { + value >>= 64; + result += 8; + } + if (value >> 32 > 0) { + value >>= 32; + result += 4; + } + if (value >> 16 > 0) { + value >>= 16; + result += 2; + } + if (value >> 8 > 0) { + result += 1; + } + } + return result; + } + + /** + * @dev Return the log in base 256, following the selected rounding direction, of a positive value. + * Returns 0 if given 0. + */ + function log256(uint256 value, Rounding rounding) internal pure returns (uint256) { + unchecked { + uint256 result = log256(value); + return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0); + } + } +} + +// lib/openzeppelin-contracts/contracts/utils/math/SignedMath.sol + +// OpenZeppelin Contracts (last updated v4.8.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/contracts/utils/introspection/ERC165.sol + +// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol) + + + + + +/** + * @dev Implementation of the {IERC165} interface. + * + * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check + * for the additional interface id that will be supported. For example: + * + * ```solidity + * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { + * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId); + * } + * ``` + * + * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation. + */ +abstract contract ERC165 is IERC165 { + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { + return interfaceId == type(IERC165).interfaceId; + } +} + +// src\common/INonceRegistry.sol + + + + + +/// @title INoncesRegistry +/// @author Mathieu Bour for Pooky Labs Ltd. +/// +/// @notice Minimal NoncesRegistry interface. +interface INonceRegistry is IAccessControl { + /// @notice Get the value of a given nonce. + function has(bytes32 nonce) external view returns (bool); + + /// @notice Set the value of a given nonce. + function set(bytes32 nonce, bool value) external; + + /// @notice Set the value of a multiple nonces. + function setBatch(bytes32[] memory nonces, bool[] memory values) external; +} + +// lib/openzeppelin-contracts/contracts/utils/Strings.sol + +// OpenZeppelin Contracts (last updated v4.9.0) (utils/Strings.sol) + + + + + + +/** + * @dev String operations. + */ +library Strings { + bytes16 private constant _SYMBOLS = "0123456789abcdef"; + uint8 private constant _ADDRESS_LENGTH = 20; + + /** + * @dev Converts a `uint256` to its ASCII `string` decimal representation. + */ + function toString(uint256 value) internal pure returns (string memory) { + unchecked { + uint256 length = Math.log10(value) + 1; + string memory buffer = new string(length); + uint256 ptr; + /// @solidity memory-safe-assembly + assembly { + ptr := add(buffer, add(32, length)) + } + while (true) { + ptr--; + /// @solidity memory-safe-assembly + assembly { + mstore8(ptr, byte(mod(value, 10), _SYMBOLS)) + } + value /= 10; + if (value == 0) break; + } + return buffer; + } + } + + /** + * @dev Converts a `int256` to its ASCII `string` decimal representation. + */ + function toString(int256 value) internal pure returns (string memory) { + return string(abi.encodePacked(value < 0 ? "-" : "", toString(SignedMath.abs(value)))); + } + + /** + * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation. + */ + function toHexString(uint256 value) internal pure returns (string memory) { + unchecked { + return toHexString(value, Math.log256(value) + 1); + } + } + + /** + * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length. + */ + function toHexString(uint256 value, uint256 length) internal pure returns (string memory) { + bytes memory buffer = new bytes(2 * length + 2); + buffer[0] = "0"; + buffer[1] = "x"; + for (uint256 i = 2 * length + 1; i > 1; --i) { + buffer[i] = _SYMBOLS[value & 0xf]; + value >>= 4; + } + require(value == 0, "Strings: hex length insufficient"); + return string(buffer); + } + + /** + * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation. + */ + function toHexString(address addr) internal pure returns (string memory) { + return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH); + } + + /** + * @dev Returns true if the two strings are equal. + */ + function equal(string memory a, string memory b) internal pure returns (bool) { + return keccak256(bytes(a)) == keccak256(bytes(b)); + } +} + +// lib/openzeppelin-contracts/contracts\access/AccessControl.sol + +// OpenZeppelin Contracts (last updated v4.9.0) (access/AccessControl.sol) + + + + + + + + +/** + * @dev Contract module that allows children to implement role-based access + * control mechanisms. This is a lightweight version that doesn't allow enumerating role + * members except through off-chain means by accessing the contract event logs. Some + * applications may benefit from on-chain enumerability, for those cases see + * {AccessControlEnumerable}. + * + * Roles are referred to by their `bytes32` identifier. These should be exposed + * in the external API and be unique. The best way to achieve this is by + * using `public constant` hash digests: + * + * ```solidity + * bytes32 public constant MY_ROLE = keccak256("MY_ROLE"); + * ``` + * + * Roles can be used to represent a set of permissions. To restrict access to a + * function call, use {hasRole}: + * + * ```solidity + * function foo() public { + * require(hasRole(MY_ROLE, msg.sender)); + * ... + * } + * ``` + * + * Roles can be granted and revoked dynamically via the {grantRole} and + * {revokeRole} functions. Each role has an associated admin role, and only + * accounts that have a role's admin role can call {grantRole} and {revokeRole}. + * + * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means + * that only accounts with this role will be able to grant or revoke other + * roles. More complex role relationships can be created by using + * {_setRoleAdmin}. + * + * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to + * grant and revoke this role. Extra precautions should be taken to secure + * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules} + * to enforce additional security measures for this role. + */ +abstract contract AccessControl is Context, IAccessControl, ERC165 { + struct RoleData { + mapping(address => bool) members; + bytes32 adminRole; + } + + mapping(bytes32 => RoleData) private _roles; + + bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00; + + /** + * @dev Modifier that checks that an account has a specific role. Reverts + * with a standardized message including the required role. + * + * The format of the revert reason is given by the following regular expression: + * + * /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/ + * + * _Available since v4.1._ + */ + modifier onlyRole(bytes32 role) { + _checkRole(role); + _; + } + + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { + return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId); + } + + /** + * @dev Returns `true` if `account` has been granted `role`. + */ + function hasRole(bytes32 role, address account) public view virtual override returns (bool) { + return _roles[role].members[account]; + } + + /** + * @dev Revert with a standard message if `_msgSender()` is missing `role`. + * Overriding this function changes the behavior of the {onlyRole} modifier. + * + * Format of the revert message is described in {_checkRole}. + * + * _Available since v4.6._ + */ + function _checkRole(bytes32 role) internal view virtual { + _checkRole(role, _msgSender()); + } + + /** + * @dev Revert with a standard message if `account` is missing `role`. + * + * The format of the revert reason is given by the following regular expression: + * + * /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/ + */ + function _checkRole(bytes32 role, address account) internal view virtual { + if (!hasRole(role, account)) { + revert( + string( + abi.encodePacked( + "AccessControl: account ", + Strings.toHexString(account), + " is missing role ", + Strings.toHexString(uint256(role), 32) + ) + ) + ); + } + } + + /** + * @dev Returns the admin role that controls `role`. See {grantRole} and + * {revokeRole}. + * + * To change a role's admin, use {_setRoleAdmin}. + */ + function getRoleAdmin(bytes32 role) public view virtual override returns (bytes32) { + return _roles[role].adminRole; + } + + /** + * @dev Grants `role` to `account`. + * + * If `account` had not been already granted `role`, emits a {RoleGranted} + * event. + * + * Requirements: + * + * - the caller must have ``role``'s admin role. + * + * May emit a {RoleGranted} event. + */ + function grantRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) { + _grantRole(role, account); + } + + /** + * @dev Revokes `role` from `account`. + * + * If `account` had been granted `role`, emits a {RoleRevoked} event. + * + * Requirements: + * + * - the caller must have ``role``'s admin role. + * + * May emit a {RoleRevoked} event. + */ + function revokeRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) { + _revokeRole(role, account); + } + + /** + * @dev Revokes `role` from the calling account. + * + * Roles are often managed via {grantRole} and {revokeRole}: this function's + * purpose is to provide a mechanism for accounts to lose their privileges + * if they are compromised (such as when a trusted device is misplaced). + * + * If the calling account had been revoked `role`, emits a {RoleRevoked} + * event. + * + * Requirements: + * + * - the caller must be `account`. + * + * May emit a {RoleRevoked} event. + */ + function renounceRole(bytes32 role, address account) public virtual override { + require(account == _msgSender(), "AccessControl: can only renounce roles for self"); + + _revokeRole(role, account); + } + + /** + * @dev Grants `role` to `account`. + * + * If `account` had not been already granted `role`, emits a {RoleGranted} + * event. Note that unlike {grantRole}, this function doesn't perform any + * checks on the calling account. + * + * May emit a {RoleGranted} event. + * + * [WARNING] + * ==== + * This function should only be called from the constructor when setting + * up the initial roles for the system. + * + * Using this function in any other way is effectively circumventing the admin + * system imposed by {AccessControl}. + * ==== + * + * NOTE: This function is deprecated in favor of {_grantRole}. + */ + function _setupRole(bytes32 role, address account) internal virtual { + _grantRole(role, account); + } + + /** + * @dev Sets `adminRole` as ``role``'s admin role. + * + * Emits a {RoleAdminChanged} event. + */ + function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual { + bytes32 previousAdminRole = getRoleAdmin(role); + _roles[role].adminRole = adminRole; + emit RoleAdminChanged(role, previousAdminRole, adminRole); + } + + /** + * @dev Grants `role` to `account`. + * + * Internal function without access restriction. + * + * May emit a {RoleGranted} event. + */ + function _grantRole(bytes32 role, address account) internal virtual { + if (!hasRole(role, account)) { + _roles[role].members[account] = true; + emit RoleGranted(role, account, _msgSender()); + } + } + + /** + * @dev Revokes `role` from `account`. + * + * Internal function without access restriction. + * + * May emit a {RoleRevoked} event. + */ + function _revokeRole(bytes32 role, address account) internal virtual { + if (hasRole(role, account)) { + _roles[role].members[account] = false; + emit RoleRevoked(role, account, _msgSender()); + } + } +} + +// src\common\NonceRegistry.sol + + + + + + +/// @title NonceRegistry +/// @author Mathieu Bour for Pooky Labs Ltd. +/// +/// @notice A nonce registry is just a mapping shared between multiple contracts. +/// @dev Only OPERATOR role can set the nonces. +contract NonceRegistry is INonceRegistry, AccessControl { + /// The internal nonces mapping + mapping(bytes32 => bool) private nonces; + + // Roles + bytes32 public constant OPERATOR = keccak256("OPERATOR"); + + /// Thrown when the length of two parameters mismatch. Used in batched functions. + error ArgumentSizeMismatch(uint256 x, uint256 y); + + constructor(address[] memory admins, address[] memory operators) { + for (uint256 i = 0; i < admins.length; i++) { + _grantRole(DEFAULT_ADMIN_ROLE, admins[i]); + } + + for (uint256 i = 0; i < operators.length; i++) { + _grantRole(OPERATOR, operators[i]); + } + } + + /// @notice Get the value of a given nonce. + function has(bytes32 nonce) external view returns (bool) { + return nonces[nonce]; + } + + /// @notice Set the value of a given nonce. + function set(bytes32 nonce, bool value) public onlyRole(OPERATOR) { + nonces[nonce] = value; + } + + /// @notice Set the value of a multiple nonces. + function setBatch(bytes32[] memory _nonces, bool[] memory values) external onlyRole(OPERATOR) { + if (_nonces.length != values.length) { + revert ArgumentSizeMismatch(_nonces.length, values.length); + } + + for (uint256 i = 0; i < _nonces.length; i++) { + set(_nonces[i], values[i]); + } + } +} diff --git a/flattened/POK.sol b/flattened/POK.sol new file mode 100644 index 00000000..178f3cd1 --- /dev/null +++ b/flattened/POK.sol @@ -0,0 +1,1459 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0 ^0.8.17; + +// lib/openzeppelin-contracts/contracts/access/IAccessControl.sol + +// OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol) + + + +/** + * @dev External interface of AccessControl declared to support ERC165 detection. + */ +interface IAccessControl { + /** + * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` + * + * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite + * {RoleAdminChanged} not being emitted signaling this. + * + * _Available since v3.1._ + */ + event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole); + + /** + * @dev Emitted when `account` is granted `role`. + * + * `sender` is the account that originated the contract call, an admin role + * bearer except when using {AccessControl-_setupRole}. + */ + event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender); + + /** + * @dev Emitted when `account` is revoked `role`. + * + * `sender` is the account that originated the contract call: + * - if using `revokeRole`, it is the admin role bearer + * - if using `renounceRole`, it is the role bearer (i.e. `account`) + */ + event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender); + + /** + * @dev Returns `true` if `account` has been granted `role`. + */ + function hasRole(bytes32 role, address account) external view returns (bool); + + /** + * @dev Returns the admin role that controls `role`. See {grantRole} and + * {revokeRole}. + * + * To change a role's admin, use {AccessControl-_setRoleAdmin}. + */ + function getRoleAdmin(bytes32 role) external view returns (bytes32); + + /** + * @dev Grants `role` to `account`. + * + * If `account` had not been already granted `role`, emits a {RoleGranted} + * event. + * + * Requirements: + * + * - the caller must have ``role``'s admin role. + */ + function grantRole(bytes32 role, address account) external; + + /** + * @dev Revokes `role` from `account`. + * + * If `account` had been granted `role`, emits a {RoleRevoked} event. + * + * Requirements: + * + * - the caller must have ``role``'s admin role. + */ + function revokeRole(bytes32 role, address account) external; + + /** + * @dev Revokes `role` from the calling account. + * + * Roles are often managed via {grantRole} and {revokeRole}: this function's + * purpose is to provide a mechanism for accounts to lose their privileges + * if they are compromised (such as when a trusted device is misplaced). + * + * If the calling account had been granted `role`, emits a {RoleRevoked} + * event. + * + * Requirements: + * + * - the caller must be `account`. + */ + function renounceRole(bytes32 role, address account) external; +} + +// lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol + +// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol) + + + +/** + * @dev Interface of the ERC20 standard as defined in the EIP. + */ +interface IERC20 { + /** + * @dev Emitted when `value` tokens are moved from one account (`from`) to + * another (`to`). + * + * Note that `value` may be zero. + */ + event Transfer(address indexed from, address indexed to, uint256 value); + + /** + * @dev Emitted when the allowance of a `spender` for an `owner` is set by + * a call to {approve}. `value` is the new allowance. + */ + event Approval(address indexed owner, address indexed spender, uint256 value); + + /** + * @dev Returns the amount of tokens in existence. + */ + function totalSupply() external view returns (uint256); + + /** + * @dev Returns the amount of tokens owned by `account`. + */ + function balanceOf(address account) external view returns (uint256); + + /** + * @dev Moves `amount` tokens from the caller's account to `to`. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * Emits a {Transfer} event. + */ + function transfer(address to, uint256 amount) external returns (bool); + + /** + * @dev Returns the remaining number of tokens that `spender` will be + * allowed to spend on behalf of `owner` through {transferFrom}. This is + * zero by default. + * + * This value changes when {approve} or {transferFrom} are called. + */ + function allowance(address owner, address spender) external view returns (uint256); + + /** + * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * IMPORTANT: Beware that changing an allowance with this method brings the risk + * that someone may use both the old and the new allowance by unfortunate + * transaction ordering. One possible solution to mitigate this race + * condition is to first reduce the spender's allowance to 0 and set the + * desired value afterwards: + * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 + * + * Emits an {Approval} event. + */ + function approve(address spender, uint256 amount) external returns (bool); + + /** + * @dev Moves `amount` tokens from `from` to `to` using the + * allowance mechanism. `amount` is then deducted from the caller's + * allowance. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * Emits a {Transfer} event. + */ + function transferFrom(address from, address to, uint256 amount) external returns (bool); +} + +// lib/openzeppelin-contracts/contracts/utils/Context.sol + +// OpenZeppelin Contracts v4.4.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; + } + + function _msgData() internal view virtual returns (bytes calldata) { + return msg.data; + } +} + +// lib/openzeppelin-contracts/contracts/utils/introspection/IERC165.sol + +// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol) + + + +/** + * @dev Interface of the ERC165 standard, as defined in the + * https://eips.ethereum.org/EIPS/eip-165[EIP]. + * + * Implementers can declare support of contract interfaces, which can then be + * queried by others ({ERC165Checker}). + * + * For an implementation, see {ERC165}. + */ +interface IERC165 { + /** + * @dev Returns true if this contract implements the interface defined by + * `interfaceId`. See the corresponding + * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] + * to learn more about how these ids are created. + * + * This function call must use less than 30 000 gas. + */ + function supportsInterface(bytes4 interfaceId) external view returns (bool); +} + +// lib/openzeppelin-contracts/contracts/utils/math/Math.sol + +// OpenZeppelin Contracts (last updated v4.9.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) { + // Solidity will revert if denominator == 0, unlike the div opcode on its own. + // The surrounding unchecked block does not change this fact. + // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic. + return prod0 / denominator; + } + + // Make sure the result is less than 2^256. Also prevents denominator == 0. + require(denominator > prod1, "Math: mulDiv overflow"); + + /////////////////////////////////////////////// + // 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. If 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)`. This value can be written `msb(a)=2**k` with `k=log2(a)`. + // + // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)` + // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))` + // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)` + // + // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit. + uint256 result = 1 << (log2(a) >> 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) { + unchecked { + uint256 result = sqrt(a); + return result + (rounding == Rounding.Up && result * result < a ? 1 : 0); + } + } + + /** + * @dev Return the log in base 2, rounded down, of a positive value. + * Returns 0 if given 0. + */ + function log2(uint256 value) internal pure returns (uint256) { + uint256 result = 0; + unchecked { + if (value >> 128 > 0) { + value >>= 128; + result += 128; + } + if (value >> 64 > 0) { + value >>= 64; + result += 64; + } + if (value >> 32 > 0) { + value >>= 32; + result += 32; + } + if (value >> 16 > 0) { + value >>= 16; + result += 16; + } + if (value >> 8 > 0) { + value >>= 8; + result += 8; + } + if (value >> 4 > 0) { + value >>= 4; + result += 4; + } + if (value >> 2 > 0) { + value >>= 2; + result += 2; + } + if (value >> 1 > 0) { + result += 1; + } + } + return result; + } + + /** + * @dev Return the log in base 2, following the selected rounding direction, of a positive value. + * Returns 0 if given 0. + */ + function log2(uint256 value, Rounding rounding) internal pure returns (uint256) { + unchecked { + uint256 result = log2(value); + return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0); + } + } + + /** + * @dev Return the log in base 10, rounded down, of a positive value. + * Returns 0 if given 0. + */ + function log10(uint256 value) internal pure returns (uint256) { + uint256 result = 0; + unchecked { + if (value >= 10 ** 64) { + value /= 10 ** 64; + result += 64; + } + if (value >= 10 ** 32) { + value /= 10 ** 32; + result += 32; + } + if (value >= 10 ** 16) { + value /= 10 ** 16; + result += 16; + } + if (value >= 10 ** 8) { + value /= 10 ** 8; + result += 8; + } + if (value >= 10 ** 4) { + value /= 10 ** 4; + result += 4; + } + if (value >= 10 ** 2) { + value /= 10 ** 2; + result += 2; + } + if (value >= 10 ** 1) { + result += 1; + } + } + return result; + } + + /** + * @dev Return the log in base 10, following the selected rounding direction, of a positive value. + * Returns 0 if given 0. + */ + function log10(uint256 value, Rounding rounding) internal pure returns (uint256) { + unchecked { + uint256 result = log10(value); + return result + (rounding == Rounding.Up && 10 ** result < value ? 1 : 0); + } + } + + /** + * @dev Return the log in base 256, rounded down, of a positive value. + * Returns 0 if given 0. + * + * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string. + */ + function log256(uint256 value) internal pure returns (uint256) { + uint256 result = 0; + unchecked { + if (value >> 128 > 0) { + value >>= 128; + result += 16; + } + if (value >> 64 > 0) { + value >>= 64; + result += 8; + } + if (value >> 32 > 0) { + value >>= 32; + result += 4; + } + if (value >> 16 > 0) { + value >>= 16; + result += 2; + } + if (value >> 8 > 0) { + result += 1; + } + } + return result; + } + + /** + * @dev Return the log in base 256, following the selected rounding direction, of a positive value. + * Returns 0 if given 0. + */ + function log256(uint256 value, Rounding rounding) internal pure returns (uint256) { + unchecked { + uint256 result = log256(value); + return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0); + } + } +} + +// lib/openzeppelin-contracts/contracts/utils/math/SignedMath.sol + +// OpenZeppelin Contracts (last updated v4.8.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/contracts/token/ERC20/extensions/IERC20Metadata.sol + +// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol) + + + + + +/** + * @dev Interface for the optional metadata functions from the ERC20 standard. + * + * _Available since v4.1._ + */ +interface IERC20Metadata is IERC20 { + /** + * @dev Returns the name of the token. + */ + function name() external view returns (string memory); + + /** + * @dev Returns the symbol of the token. + */ + function symbol() external view returns (string memory); + + /** + * @dev Returns the decimals places of the token. + */ + function decimals() external view returns (uint8); +} + +// lib/openzeppelin-contracts/contracts/utils/introspection/ERC165.sol + +// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol) + + + + + +/** + * @dev Implementation of the {IERC165} interface. + * + * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check + * for the additional interface id that will be supported. For example: + * + * ```solidity + * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { + * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId); + * } + * ``` + * + * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation. + */ +abstract contract ERC165 is IERC165 { + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { + return interfaceId == type(IERC165).interfaceId; + } +} + +// lib/openzeppelin-contracts/contracts/utils/Strings.sol + +// OpenZeppelin Contracts (last updated v4.9.0) (utils/Strings.sol) + + + + + + +/** + * @dev String operations. + */ +library Strings { + bytes16 private constant _SYMBOLS = "0123456789abcdef"; + uint8 private constant _ADDRESS_LENGTH = 20; + + /** + * @dev Converts a `uint256` to its ASCII `string` decimal representation. + */ + function toString(uint256 value) internal pure returns (string memory) { + unchecked { + uint256 length = Math.log10(value) + 1; + string memory buffer = new string(length); + uint256 ptr; + /// @solidity memory-safe-assembly + assembly { + ptr := add(buffer, add(32, length)) + } + while (true) { + ptr--; + /// @solidity memory-safe-assembly + assembly { + mstore8(ptr, byte(mod(value, 10), _SYMBOLS)) + } + value /= 10; + if (value == 0) break; + } + return buffer; + } + } + + /** + * @dev Converts a `int256` to its ASCII `string` decimal representation. + */ + function toString(int256 value) internal pure returns (string memory) { + return string(abi.encodePacked(value < 0 ? "-" : "", toString(SignedMath.abs(value)))); + } + + /** + * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation. + */ + function toHexString(uint256 value) internal pure returns (string memory) { + unchecked { + return toHexString(value, Math.log256(value) + 1); + } + } + + /** + * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length. + */ + function toHexString(uint256 value, uint256 length) internal pure returns (string memory) { + bytes memory buffer = new bytes(2 * length + 2); + buffer[0] = "0"; + buffer[1] = "x"; + for (uint256 i = 2 * length + 1; i > 1; --i) { + buffer[i] = _SYMBOLS[value & 0xf]; + value >>= 4; + } + require(value == 0, "Strings: hex length insufficient"); + return string(buffer); + } + + /** + * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation. + */ + function toHexString(address addr) internal pure returns (string memory) { + return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH); + } + + /** + * @dev Returns true if the two strings are equal. + */ + function equal(string memory a, string memory b) internal pure returns (bool) { + return keccak256(bytes(a)) == keccak256(bytes(b)); + } +} + +// src\tokens/IPOK.sol + + + + + + +/// @title IPOK +/// @author Mathieu Bour, Dusan Zdravkovic for Pooky Labs Ltd. +/// +/// @notice Minimal $POK ERC20 token interface. +interface IPOK is IAccessControl, IERC20 { + /// @notice Mint an arbitrary amount of $POK to an account. + /// @dev Requirements: + /// - only MINTER role can mint $POK tokens + function mint(address to, uint256 amount) external; + + /// @notice Burn an arbitrary amount of $POK of an sender account. + /// It is acknowledged that burning directly from the user wallet is anti-pattern + /// but since $POK is soulbounded, this allow to skip the ERC20 approve call. + /// @dev Requirements: + /// - only BURNER role can burn $POK tokens + function burn(address to, uint256 amount) external; +} + +// lib/openzeppelin-contracts/contracts\token/ERC20/ERC20.sol + +// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/ERC20.sol) + + + + + + + +/** + * @dev Implementation of the {IERC20} interface. + * + * This implementation is agnostic to the way tokens are created. This means + * that a supply mechanism has to be added in a derived contract using {_mint}. + * For a generic mechanism see {ERC20PresetMinterPauser}. + * + * TIP: For a detailed writeup see our guide + * https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How + * to implement supply mechanisms]. + * + * The default value of {decimals} is 18. To change this, you should override + * this function so it returns a different value. + * + * We have followed general OpenZeppelin Contracts guidelines: functions revert + * instead returning `false` on failure. This behavior is nonetheless + * conventional and does not conflict with the expectations of ERC20 + * applications. + * + * Additionally, an {Approval} event is emitted on calls to {transferFrom}. + * This allows applications to reconstruct the allowance for all accounts just + * by listening to said events. Other implementations of the EIP may not emit + * these events, as it isn't required by the specification. + * + * Finally, the non-standard {decreaseAllowance} and {increaseAllowance} + * functions have been added to mitigate the well-known issues around setting + * allowances. See {IERC20-approve}. + */ +contract ERC20 is Context, IERC20, IERC20Metadata { + mapping(address => uint256) private _balances; + + mapping(address => mapping(address => uint256)) private _allowances; + + uint256 private _totalSupply; + + string private _name; + string private _symbol; + + /** + * @dev Sets the values for {name} and {symbol}. + * + * All two of these values are immutable: they can only be set once during + * construction. + */ + constructor(string memory name_, string memory symbol_) { + _name = name_; + _symbol = symbol_; + } + + /** + * @dev Returns the name of the token. + */ + function name() public view virtual override returns (string memory) { + return _name; + } + + /** + * @dev Returns the symbol of the token, usually a shorter version of the + * name. + */ + function symbol() public view virtual override returns (string memory) { + return _symbol; + } + + /** + * @dev Returns the number of decimals used to get its user representation. + * For example, if `decimals` equals `2`, a balance of `505` tokens should + * be displayed to a user as `5.05` (`505 / 10 ** 2`). + * + * Tokens usually opt for a value of 18, imitating the relationship between + * Ether and Wei. This is the default value returned by this function, unless + * it's overridden. + * + * NOTE: This information is only used for _display_ purposes: it in + * no way affects any of the arithmetic of the contract, including + * {IERC20-balanceOf} and {IERC20-transfer}. + */ + function decimals() public view virtual override returns (uint8) { + return 18; + } + + /** + * @dev See {IERC20-totalSupply}. + */ + function totalSupply() public view virtual override returns (uint256) { + return _totalSupply; + } + + /** + * @dev See {IERC20-balanceOf}. + */ + function balanceOf(address account) public view virtual override returns (uint256) { + return _balances[account]; + } + + /** + * @dev See {IERC20-transfer}. + * + * Requirements: + * + * - `to` cannot be the zero address. + * - the caller must have a balance of at least `amount`. + */ + function transfer(address to, uint256 amount) public virtual override returns (bool) { + address owner = _msgSender(); + _transfer(owner, to, amount); + return true; + } + + /** + * @dev See {IERC20-allowance}. + */ + function allowance(address owner, address spender) public view virtual override returns (uint256) { + return _allowances[owner][spender]; + } + + /** + * @dev See {IERC20-approve}. + * + * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on + * `transferFrom`. This is semantically equivalent to an infinite approval. + * + * Requirements: + * + * - `spender` cannot be the zero address. + */ + function approve(address spender, uint256 amount) public virtual override returns (bool) { + address owner = _msgSender(); + _approve(owner, spender, amount); + return true; + } + + /** + * @dev See {IERC20-transferFrom}. + * + * Emits an {Approval} event indicating the updated allowance. This is not + * required by the EIP. See the note at the beginning of {ERC20}. + * + * NOTE: Does not update the allowance if the current allowance + * is the maximum `uint256`. + * + * Requirements: + * + * - `from` and `to` cannot be the zero address. + * - `from` must have a balance of at least `amount`. + * - the caller must have allowance for ``from``'s tokens of at least + * `amount`. + */ + function transferFrom(address from, address to, uint256 amount) public virtual override returns (bool) { + address spender = _msgSender(); + _spendAllowance(from, spender, amount); + _transfer(from, to, amount); + return true; + } + + /** + * @dev Atomically increases the allowance granted to `spender` by the caller. + * + * This is an alternative to {approve} that can be used as a mitigation for + * problems described in {IERC20-approve}. + * + * Emits an {Approval} event indicating the updated allowance. + * + * Requirements: + * + * - `spender` cannot be the zero address. + */ + function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) { + address owner = _msgSender(); + _approve(owner, spender, allowance(owner, spender) + addedValue); + return true; + } + + /** + * @dev Atomically decreases the allowance granted to `spender` by the caller. + * + * This is an alternative to {approve} that can be used as a mitigation for + * problems described in {IERC20-approve}. + * + * Emits an {Approval} event indicating the updated allowance. + * + * Requirements: + * + * - `spender` cannot be the zero address. + * - `spender` must have allowance for the caller of at least + * `subtractedValue`. + */ + function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) { + address owner = _msgSender(); + uint256 currentAllowance = allowance(owner, spender); + require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero"); + unchecked { + _approve(owner, spender, currentAllowance - subtractedValue); + } + + return true; + } + + /** + * @dev Moves `amount` of tokens from `from` to `to`. + * + * This internal function is equivalent to {transfer}, and can be used to + * e.g. implement automatic token fees, slashing mechanisms, etc. + * + * Emits a {Transfer} event. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `from` must have a balance of at least `amount`. + */ + function _transfer(address from, address to, uint256 amount) internal virtual { + require(from != address(0), "ERC20: transfer from the zero address"); + require(to != address(0), "ERC20: transfer to the zero address"); + + _beforeTokenTransfer(from, to, amount); + + uint256 fromBalance = _balances[from]; + require(fromBalance >= amount, "ERC20: transfer amount exceeds balance"); + unchecked { + _balances[from] = fromBalance - amount; + // Overflow not possible: the sum of all balances is capped by totalSupply, and the sum is preserved by + // decrementing then incrementing. + _balances[to] += amount; + } + + emit Transfer(from, to, amount); + + _afterTokenTransfer(from, to, amount); + } + + /** @dev Creates `amount` tokens and assigns them to `account`, increasing + * the total supply. + * + * Emits a {Transfer} event with `from` set to the zero address. + * + * Requirements: + * + * - `account` cannot be the zero address. + */ + function _mint(address account, uint256 amount) internal virtual { + require(account != address(0), "ERC20: mint to the zero address"); + + _beforeTokenTransfer(address(0), account, amount); + + _totalSupply += amount; + unchecked { + // Overflow not possible: balance + amount is at most totalSupply + amount, which is checked above. + _balances[account] += amount; + } + emit Transfer(address(0), account, amount); + + _afterTokenTransfer(address(0), account, amount); + } + + /** + * @dev Destroys `amount` tokens from `account`, reducing the + * total supply. + * + * Emits a {Transfer} event with `to` set to the zero address. + * + * Requirements: + * + * - `account` cannot be the zero address. + * - `account` must have at least `amount` tokens. + */ + function _burn(address account, uint256 amount) internal virtual { + require(account != address(0), "ERC20: burn from the zero address"); + + _beforeTokenTransfer(account, address(0), amount); + + uint256 accountBalance = _balances[account]; + require(accountBalance >= amount, "ERC20: burn amount exceeds balance"); + unchecked { + _balances[account] = accountBalance - amount; + // Overflow not possible: amount <= accountBalance <= totalSupply. + _totalSupply -= amount; + } + + emit Transfer(account, address(0), amount); + + _afterTokenTransfer(account, address(0), amount); + } + + /** + * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens. + * + * This internal function is equivalent to `approve`, and can be used to + * e.g. set automatic allowances for certain subsystems, etc. + * + * Emits an {Approval} event. + * + * Requirements: + * + * - `owner` cannot be the zero address. + * - `spender` cannot be the zero address. + */ + function _approve(address owner, address spender, uint256 amount) internal virtual { + require(owner != address(0), "ERC20: approve from the zero address"); + require(spender != address(0), "ERC20: approve to the zero address"); + + _allowances[owner][spender] = amount; + emit Approval(owner, spender, amount); + } + + /** + * @dev Updates `owner` s allowance for `spender` based on spent `amount`. + * + * Does not update the allowance amount in case of infinite allowance. + * Revert if not enough allowance is available. + * + * Might emit an {Approval} event. + */ + function _spendAllowance(address owner, address spender, uint256 amount) internal virtual { + uint256 currentAllowance = allowance(owner, spender); + if (currentAllowance != type(uint256).max) { + require(currentAllowance >= amount, "ERC20: insufficient allowance"); + unchecked { + _approve(owner, spender, currentAllowance - amount); + } + } + } + + /** + * @dev Hook that is called before any transfer of tokens. This includes + * minting and burning. + * + * Calling conditions: + * + * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens + * will be transferred to `to`. + * - when `from` is zero, `amount` tokens will be minted for `to`. + * - when `to` is zero, `amount` of ``from``'s tokens will be burned. + * - `from` and `to` are never both zero. + * + * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. + */ + function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual {} + + /** + * @dev Hook that is called after any transfer of tokens. This includes + * minting and burning. + * + * Calling conditions: + * + * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens + * has been transferred to `to`. + * - when `from` is zero, `amount` tokens have been minted for `to`. + * - when `to` is zero, `amount` of ``from``'s tokens have been burned. + * - `from` and `to` are never both zero. + * + * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. + */ + function _afterTokenTransfer(address from, address to, uint256 amount) internal virtual {} +} + +// lib/openzeppelin-contracts/contracts\access/AccessControl.sol + +// OpenZeppelin Contracts (last updated v4.9.0) (access/AccessControl.sol) + + + + + + + + +/** + * @dev Contract module that allows children to implement role-based access + * control mechanisms. This is a lightweight version that doesn't allow enumerating role + * members except through off-chain means by accessing the contract event logs. Some + * applications may benefit from on-chain enumerability, for those cases see + * {AccessControlEnumerable}. + * + * Roles are referred to by their `bytes32` identifier. These should be exposed + * in the external API and be unique. The best way to achieve this is by + * using `public constant` hash digests: + * + * ```solidity + * bytes32 public constant MY_ROLE = keccak256("MY_ROLE"); + * ``` + * + * Roles can be used to represent a set of permissions. To restrict access to a + * function call, use {hasRole}: + * + * ```solidity + * function foo() public { + * require(hasRole(MY_ROLE, msg.sender)); + * ... + * } + * ``` + * + * Roles can be granted and revoked dynamically via the {grantRole} and + * {revokeRole} functions. Each role has an associated admin role, and only + * accounts that have a role's admin role can call {grantRole} and {revokeRole}. + * + * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means + * that only accounts with this role will be able to grant or revoke other + * roles. More complex role relationships can be created by using + * {_setRoleAdmin}. + * + * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to + * grant and revoke this role. Extra precautions should be taken to secure + * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules} + * to enforce additional security measures for this role. + */ +abstract contract AccessControl is Context, IAccessControl, ERC165 { + struct RoleData { + mapping(address => bool) members; + bytes32 adminRole; + } + + mapping(bytes32 => RoleData) private _roles; + + bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00; + + /** + * @dev Modifier that checks that an account has a specific role. Reverts + * with a standardized message including the required role. + * + * The format of the revert reason is given by the following regular expression: + * + * /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/ + * + * _Available since v4.1._ + */ + modifier onlyRole(bytes32 role) { + _checkRole(role); + _; + } + + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { + return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId); + } + + /** + * @dev Returns `true` if `account` has been granted `role`. + */ + function hasRole(bytes32 role, address account) public view virtual override returns (bool) { + return _roles[role].members[account]; + } + + /** + * @dev Revert with a standard message if `_msgSender()` is missing `role`. + * Overriding this function changes the behavior of the {onlyRole} modifier. + * + * Format of the revert message is described in {_checkRole}. + * + * _Available since v4.6._ + */ + function _checkRole(bytes32 role) internal view virtual { + _checkRole(role, _msgSender()); + } + + /** + * @dev Revert with a standard message if `account` is missing `role`. + * + * The format of the revert reason is given by the following regular expression: + * + * /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/ + */ + function _checkRole(bytes32 role, address account) internal view virtual { + if (!hasRole(role, account)) { + revert( + string( + abi.encodePacked( + "AccessControl: account ", + Strings.toHexString(account), + " is missing role ", + Strings.toHexString(uint256(role), 32) + ) + ) + ); + } + } + + /** + * @dev Returns the admin role that controls `role`. See {grantRole} and + * {revokeRole}. + * + * To change a role's admin, use {_setRoleAdmin}. + */ + function getRoleAdmin(bytes32 role) public view virtual override returns (bytes32) { + return _roles[role].adminRole; + } + + /** + * @dev Grants `role` to `account`. + * + * If `account` had not been already granted `role`, emits a {RoleGranted} + * event. + * + * Requirements: + * + * - the caller must have ``role``'s admin role. + * + * May emit a {RoleGranted} event. + */ + function grantRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) { + _grantRole(role, account); + } + + /** + * @dev Revokes `role` from `account`. + * + * If `account` had been granted `role`, emits a {RoleRevoked} event. + * + * Requirements: + * + * - the caller must have ``role``'s admin role. + * + * May emit a {RoleRevoked} event. + */ + function revokeRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) { + _revokeRole(role, account); + } + + /** + * @dev Revokes `role` from the calling account. + * + * Roles are often managed via {grantRole} and {revokeRole}: this function's + * purpose is to provide a mechanism for accounts to lose their privileges + * if they are compromised (such as when a trusted device is misplaced). + * + * If the calling account had been revoked `role`, emits a {RoleRevoked} + * event. + * + * Requirements: + * + * - the caller must be `account`. + * + * May emit a {RoleRevoked} event. + */ + function renounceRole(bytes32 role, address account) public virtual override { + require(account == _msgSender(), "AccessControl: can only renounce roles for self"); + + _revokeRole(role, account); + } + + /** + * @dev Grants `role` to `account`. + * + * If `account` had not been already granted `role`, emits a {RoleGranted} + * event. Note that unlike {grantRole}, this function doesn't perform any + * checks on the calling account. + * + * May emit a {RoleGranted} event. + * + * [WARNING] + * ==== + * This function should only be called from the constructor when setting + * up the initial roles for the system. + * + * Using this function in any other way is effectively circumventing the admin + * system imposed by {AccessControl}. + * ==== + * + * NOTE: This function is deprecated in favor of {_grantRole}. + */ + function _setupRole(bytes32 role, address account) internal virtual { + _grantRole(role, account); + } + + /** + * @dev Sets `adminRole` as ``role``'s admin role. + * + * Emits a {RoleAdminChanged} event. + */ + function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual { + bytes32 previousAdminRole = getRoleAdmin(role); + _roles[role].adminRole = adminRole; + emit RoleAdminChanged(role, previousAdminRole, adminRole); + } + + /** + * @dev Grants `role` to `account`. + * + * Internal function without access restriction. + * + * May emit a {RoleGranted} event. + */ + function _grantRole(bytes32 role, address account) internal virtual { + if (!hasRole(role, account)) { + _roles[role].members[account] = true; + emit RoleGranted(role, account, _msgSender()); + } + } + + /** + * @dev Revokes `role` from `account`. + * + * Internal function without access restriction. + * + * May emit a {RoleRevoked} event. + */ + function _revokeRole(bytes32 role, address account) internal virtual { + if (hasRole(role, account)) { + _roles[role].members[account] = false; + emit RoleRevoked(role, account, _msgSender()); + } + } +} + +// src\tokens\POK.sol + + + + + + + +/// @title POK +/// @author Mathieu Bour, Dusan Zdravkovic for Pooky Labs Ltd. +/// +/// @notice POK is ERC20 token used inside of the game, $POK is soul-bounded and serves as in-game currency. +/// Mintable by other Pooky game contracts. +/// +/// @dev Implemented roles: +/// - DEFAULT_ADMIN_ROLE can add/remove roles, it will be granted to the deployer and then quickly transferred to a +/// Gnosis Safe multi-signature wallet. +/// - MINTER role can freely mint new $POK tokens. +/// - BURNER role can freely burning existing $POK tokens. +contract POK is IPOK, ERC20, AccessControl { + /// Role that allows to freely mint new $POK tokens + bytes32 public constant MINTER = keccak256("MINTER"); + /// Role that allows to freely burning existing $POK tokens + bytes32 public constant BURNER = keccak256("BURNER"); + + /// Thrown when a POK transfer is attempted. + error Soulbounded(); + + constructor(address _admin) ERC20("POK", "POK") { + _grantRole(DEFAULT_ADMIN_ROLE, _admin); + } + + /// @notice Mint an arbitrary amount of $POK to an account. + /// @dev Requirements: + /// - only MINTER role can mint $POK tokens + function mint(address to, uint256 amount) external onlyRole(MINTER) { + _mint(to, amount); + } + + /// @notice Burn an arbitrary amount of $POK of an sender account. + /// It is acknowledged that burning directly from the user wallet is anti-pattern + /// but since $POK is soulbounded, this allow to skip the ERC20 approve call. + /// @dev Requirements: + /// - only BURNER role can burn $POK tokens + function burn(address to, uint256 amount) external onlyRole(BURNER) { + _burn(to, amount); + } + + /// @dev Restrict the $POK transfers between accounts. + /// Requirements: + /// - Transfer between accounts if they are disabled. + /// - Mints and burns are always allowed. + function _beforeTokenTransfer(address from, address to, uint256) internal pure override { + if (from == address(0) || to == address(0)) return; + revert Soulbounded(); + } +} diff --git a/flattened/Pookyball.sol b/flattened/Pookyball.sol new file mode 100644 index 00000000..f00dc98e --- /dev/null +++ b/flattened/Pookyball.sol @@ -0,0 +1,2818 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0 ^0.8.1 ^0.8.13 ^0.8.17 ^0.8.4; + +// lib/chainlink/contracts/src/v0.8\interfaces/VRFCoordinatorV2Interface.sol + + + +interface VRFCoordinatorV2Interface { + /** + * @notice Get configuration relevant for making requests + * @return minimumRequestConfirmations global min for request confirmations + * @return maxGasLimit global max for request gas limit + * @return s_provingKeyHashes list of registered key hashes + */ + function getRequestConfig() external view returns (uint16, uint32, bytes32[] memory); + + /** + * @notice Request a set of random words. + * @param keyHash - Corresponds to a particular oracle job which uses + * that key for generating the VRF proof. Different keyHash's have different gas price + * ceilings, so you can select a specific one to bound your maximum per request cost. + * @param subId - The ID of the VRF subscription. Must be funded + * with the minimum subscription balance required for the selected keyHash. + * @param minimumRequestConfirmations - How many blocks you'd like the + * oracle to wait before responding to the request. See SECURITY CONSIDERATIONS + * for why you may want to request more. The acceptable range is + * [minimumRequestBlockConfirmations, 200]. + * @param callbackGasLimit - How much gas you'd like to receive in your + * fulfillRandomWords callback. Note that gasleft() inside fulfillRandomWords + * may be slightly less than this amount because of gas used calling the function + * (argument decoding etc.), so you may need to request slightly more than you expect + * to have inside fulfillRandomWords. The acceptable range is + * [0, maxGasLimit] + * @param numWords - The number of uint256 random values you'd like to receive + * in your fulfillRandomWords callback. Note these numbers are expanded in a + * secure way by the VRFCoordinator from a single random value supplied by the oracle. + * @return requestId - A unique identifier of the request. Can be used to match + * a request to a response in fulfillRandomWords. + */ + function requestRandomWords( + bytes32 keyHash, + uint64 subId, + uint16 minimumRequestConfirmations, + uint32 callbackGasLimit, + uint32 numWords + ) external returns (uint256 requestId); + + /** + * @notice Create a VRF subscription. + * @return subId - A unique subscription id. + * @dev You can manage the consumer set dynamically with addConsumer/removeConsumer. + * @dev Note to fund the subscription, use transferAndCall. For example + * @dev LINKTOKEN.transferAndCall( + * @dev address(COORDINATOR), + * @dev amount, + * @dev abi.encode(subId)); + */ + function createSubscription() external returns (uint64 subId); + + /** + * @notice Get a VRF subscription. + * @param subId - ID of the subscription + * @return balance - LINK balance of the subscription in juels. + * @return reqCount - number of requests for this subscription, determines fee tier. + * @return owner - owner of the subscription. + * @return consumers - list of consumer address which are able to use this subscription. + */ + function getSubscription( + uint64 subId + ) external view returns (uint96 balance, uint64 reqCount, address owner, address[] memory consumers); + + /** + * @notice Request subscription owner transfer. + * @param subId - ID of the subscription + * @param newOwner - proposed new owner of the subscription + */ + function requestSubscriptionOwnerTransfer(uint64 subId, address newOwner) external; + + /** + * @notice Request subscription owner transfer. + * @param subId - ID of the subscription + * @dev will revert if original owner of subId has + * not requested that msg.sender become the new owner. + */ + function acceptSubscriptionOwnerTransfer(uint64 subId) external; + + /** + * @notice Add a consumer to a VRF subscription. + * @param subId - ID of the subscription + * @param consumer - New consumer which can use the subscription + */ + function addConsumer(uint64 subId, address consumer) external; + + /** + * @notice Remove a consumer from a VRF subscription. + * @param subId - ID of the subscription + * @param consumer - Consumer to remove from the subscription + */ + function removeConsumer(uint64 subId, address consumer) external; + + /** + * @notice Cancel a subscription + * @param subId - ID of the subscription + * @param to - Where to send the remaining LINK to + */ + function cancelSubscription(uint64 subId, address to) external; + + /* + * @notice Check to see if there exists a request commitment consumers + * for all consumers and keyhashes for a given sub. + * @param subId - ID of the subscription + * @return true if there exists at least one unfulfilled request for the subscription, false + * otherwise. + */ + function pendingRequestExists(uint64 subId) external view returns (bool); +} + +// lib/chainlink/contracts/src/v0.8\vrf/VRFConsumerBaseV2.sol + + + +/** **************************************************************************** + * @notice Interface for contracts using VRF randomness + * ***************************************************************************** + * @dev PURPOSE + * + * @dev Reggie the Random Oracle (not his real job) wants to provide randomness + * @dev to Vera the verifier in such a way that Vera can be sure he's not + * @dev making his output up to suit himself. Reggie provides Vera a public key + * @dev to which he knows the secret key. Each time Vera provides a seed to + * @dev Reggie, he gives back a value which is computed completely + * @dev deterministically from the seed and the secret key. + * + * @dev Reggie provides a proof by which Vera can verify that the output was + * @dev correctly computed once Reggie tells it to her, but without that proof, + * @dev the output is indistinguishable to her from a uniform random sample + * @dev from the output space. + * + * @dev The purpose of this contract is to make it easy for unrelated contracts + * @dev to talk to Vera the verifier about the work Reggie is doing, to provide + * @dev simple access to a verifiable source of randomness. It ensures 2 things: + * @dev 1. The fulfillment came from the VRFCoordinator + * @dev 2. The consumer contract implements fulfillRandomWords. + * ***************************************************************************** + * @dev USAGE + * + * @dev Calling contracts must inherit from VRFConsumerBase, and can + * @dev initialize VRFConsumerBase's attributes in their constructor as + * @dev shown: + * + * @dev contract VRFConsumer { + * @dev constructor(, address _vrfCoordinator, address _link) + * @dev VRFConsumerBase(_vrfCoordinator) public { + * @dev + * @dev } + * @dev } + * + * @dev The oracle will have given you an ID for the VRF keypair they have + * @dev committed to (let's call it keyHash). Create subscription, fund it + * @dev and your consumer contract as a consumer of it (see VRFCoordinatorInterface + * @dev subscription management functions). + * @dev Call requestRandomWords(keyHash, subId, minimumRequestConfirmations, + * @dev callbackGasLimit, numWords), + * @dev see (VRFCoordinatorInterface for a description of the arguments). + * + * @dev Once the VRFCoordinator has received and validated the oracle's response + * @dev to your request, it will call your contract's fulfillRandomWords method. + * + * @dev The randomness argument to fulfillRandomWords is a set of random words + * @dev generated from your requestId and the blockHash of the request. + * + * @dev If your contract could have concurrent requests open, you can use the + * @dev requestId returned from requestRandomWords to track which response is associated + * @dev with which randomness request. + * @dev See "SECURITY CONSIDERATIONS" for principles to keep in mind, + * @dev if your contract could have multiple requests in flight simultaneously. + * + * @dev Colliding `requestId`s are cryptographically impossible as long as seeds + * @dev differ. + * + * ***************************************************************************** + * @dev SECURITY CONSIDERATIONS + * + * @dev A method with the ability to call your fulfillRandomness method directly + * @dev could spoof a VRF response with any random value, so it's critical that + * @dev it cannot be directly called by anything other than this base contract + * @dev (specifically, by the VRFConsumerBase.rawFulfillRandomness method). + * + * @dev For your users to trust that your contract's random behavior is free + * @dev from malicious interference, it's best if you can write it so that all + * @dev behaviors implied by a VRF response are executed *during* your + * @dev fulfillRandomness method. If your contract must store the response (or + * @dev anything derived from it) and use it later, you must ensure that any + * @dev user-significant behavior which depends on that stored value cannot be + * @dev manipulated by a subsequent VRF request. + * + * @dev Similarly, both miners and the VRF oracle itself have some influence + * @dev over the order in which VRF responses appear on the blockchain, so if + * @dev your contract could have multiple VRF requests in flight simultaneously, + * @dev you must ensure that the order in which the VRF responses arrive cannot + * @dev be used to manipulate your contract's user-significant behavior. + * + * @dev Since the block hash of the block which contains the requestRandomness + * @dev call is mixed into the input to the VRF *last*, a sufficiently powerful + * @dev miner could, in principle, fork the blockchain to evict the block + * @dev containing the request, forcing the request to be included in a + * @dev different block with a different hash, and therefore a different input + * @dev to the VRF. However, such an attack would incur a substantial economic + * @dev cost. This cost scales with the number of blocks the VRF oracle waits + * @dev until it calls responds to a request. It is for this reason that + * @dev that you can signal to an oracle you'd like them to wait longer before + * @dev responding to the request (however this is not enforced in the contract + * @dev and so remains effective only in the case of unmodified oracle software). + */ +abstract contract VRFConsumerBaseV2 { + error OnlyCoordinatorCanFulfill(address have, address want); + address private immutable vrfCoordinator; + + /** + * @param _vrfCoordinator address of VRFCoordinator contract + */ + constructor(address _vrfCoordinator) { + vrfCoordinator = _vrfCoordinator; + } + + /** + * @notice fulfillRandomness handles the VRF response. Your contract must + * @notice implement it. See "SECURITY CONSIDERATIONS" above for important + * @notice principles to keep in mind when implementing your fulfillRandomness + * @notice method. + * + * @dev VRFConsumerBaseV2 expects its subcontracts to have a method with this + * @dev signature, and will call it once it has verified the proof + * @dev associated with the randomness. (It is triggered via a call to + * @dev rawFulfillRandomness, below.) + * + * @param requestId The Id initially returned by requestRandomness + * @param randomWords the VRF output expanded to the requested number of words + */ + function fulfillRandomWords(uint256 requestId, uint256[] memory randomWords) internal virtual; + + // rawFulfillRandomness is called by VRFCoordinator when it receives a valid VRF + // proof. rawFulfillRandomness then calls fulfillRandomness, after validating + // the origin of the call + function rawFulfillRandomWords(uint256 requestId, uint256[] memory randomWords) external { + if (msg.sender != vrfCoordinator) { + revert OnlyCoordinatorCanFulfill(msg.sender, vrfCoordinator); + } + fulfillRandomWords(requestId, randomWords); + } +} + +// lib/openzeppelin-contracts/contracts/access/IAccessControl.sol + +// OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol) + + + +/** + * @dev External interface of AccessControl declared to support ERC165 detection. + */ +interface IAccessControl { + /** + * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` + * + * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite + * {RoleAdminChanged} not being emitted signaling this. + * + * _Available since v3.1._ + */ + event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole); + + /** + * @dev Emitted when `account` is granted `role`. + * + * `sender` is the account that originated the contract call, an admin role + * bearer except when using {AccessControl-_setupRole}. + */ + event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender); + + /** + * @dev Emitted when `account` is revoked `role`. + * + * `sender` is the account that originated the contract call: + * - if using `revokeRole`, it is the admin role bearer + * - if using `renounceRole`, it is the role bearer (i.e. `account`) + */ + event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender); + + /** + * @dev Returns `true` if `account` has been granted `role`. + */ + function hasRole(bytes32 role, address account) external view returns (bool); + + /** + * @dev Returns the admin role that controls `role`. See {grantRole} and + * {revokeRole}. + * + * To change a role's admin, use {AccessControl-_setRoleAdmin}. + */ + function getRoleAdmin(bytes32 role) external view returns (bytes32); + + /** + * @dev Grants `role` to `account`. + * + * If `account` had not been already granted `role`, emits a {RoleGranted} + * event. + * + * Requirements: + * + * - the caller must have ``role``'s admin role. + */ + function grantRole(bytes32 role, address account) external; + + /** + * @dev Revokes `role` from `account`. + * + * If `account` had been granted `role`, emits a {RoleRevoked} event. + * + * Requirements: + * + * - the caller must have ``role``'s admin role. + */ + function revokeRole(bytes32 role, address account) external; + + /** + * @dev Revokes `role` from the calling account. + * + * Roles are often managed via {grantRole} and {revokeRole}: this function's + * purpose is to provide a mechanism for accounts to lose their privileges + * if they are compromised (such as when a trusted device is misplaced). + * + * If the calling account had been granted `role`, emits a {RoleRevoked} + * event. + * + * Requirements: + * + * - the caller must be `account`. + */ + function renounceRole(bytes32 role, address account) external; +} + +// lib/openzeppelin-contracts/contracts/token/ERC721/IERC721Receiver.sol + +// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC721/IERC721Receiver.sol) + + + +/** + * @title ERC721 token receiver interface + * @dev Interface for any contract that wants to support safeTransfers + * from ERC721 asset contracts. + */ +interface IERC721Receiver { + /** + * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom} + * by `operator` from `from`, this function is called. + * + * It must return its Solidity selector to confirm the token transfer. + * If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted. + * + * The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`. + */ + function onERC721Received( + address operator, + address from, + uint256 tokenId, + bytes calldata data + ) external returns (bytes4); +} + +// lib/openzeppelin-contracts/contracts/utils/Address.sol + +// OpenZeppelin Contracts (last updated v4.9.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 + * + * Furthermore, `isContract` will also return true if the target contract within + * the same transaction is already scheduled for destruction by `SELFDESTRUCT`, + * which only has an effect at the end of a transaction. + * ==== + * + * [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://consensys.net/diligence/blog/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.8.0/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 functionCallWithValue(target, data, 0, "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"); + (bool success, bytes memory returndata) = target.call{value: value}(data); + return verifyCallResultFromTarget(target, 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) { + (bool success, bytes memory returndata) = target.staticcall(data); + return verifyCallResultFromTarget(target, 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) { + (bool success, bytes memory returndata) = target.delegatecall(data); + return verifyCallResultFromTarget(target, success, returndata, errorMessage); + } + + /** + * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling + * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract. + * + * _Available since v4.8._ + */ + function verifyCallResultFromTarget( + address target, + bool success, + bytes memory returndata, + string memory errorMessage + ) internal view returns (bytes memory) { + if (success) { + if (returndata.length == 0) { + // only check isContract if the call was successful and the return data is empty + // otherwise we already know that it was a contract + require(isContract(target), "Address: call to non-contract"); + } + return returndata; + } else { + _revert(returndata, errorMessage); + } + } + + /** + * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the + * revert reason or 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 { + _revert(returndata, errorMessage); + } + } + + function _revert(bytes memory returndata, string memory errorMessage) private pure { + // 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/Context.sol + +// OpenZeppelin Contracts v4.4.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; + } + + function _msgData() internal view virtual returns (bytes calldata) { + return msg.data; + } +} + +// lib/openzeppelin-contracts/contracts/utils/introspection/IERC165.sol + +// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol) + + + +/** + * @dev Interface of the ERC165 standard, as defined in the + * https://eips.ethereum.org/EIPS/eip-165[EIP]. + * + * Implementers can declare support of contract interfaces, which can then be + * queried by others ({ERC165Checker}). + * + * For an implementation, see {ERC165}. + */ +interface IERC165 { + /** + * @dev Returns true if this contract implements the interface defined by + * `interfaceId`. See the corresponding + * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] + * to learn more about how these ids are created. + * + * This function call must use less than 30 000 gas. + */ + function supportsInterface(bytes4 interfaceId) external view returns (bool); +} + +// lib/openzeppelin-contracts/contracts/utils/math/Math.sol + +// OpenZeppelin Contracts (last updated v4.9.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) { + // Solidity will revert if denominator == 0, unlike the div opcode on its own. + // The surrounding unchecked block does not change this fact. + // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic. + return prod0 / denominator; + } + + // Make sure the result is less than 2^256. Also prevents denominator == 0. + require(denominator > prod1, "Math: mulDiv overflow"); + + /////////////////////////////////////////////// + // 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. If 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)`. This value can be written `msb(a)=2**k` with `k=log2(a)`. + // + // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)` + // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))` + // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)` + // + // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit. + uint256 result = 1 << (log2(a) >> 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) { + unchecked { + uint256 result = sqrt(a); + return result + (rounding == Rounding.Up && result * result < a ? 1 : 0); + } + } + + /** + * @dev Return the log in base 2, rounded down, of a positive value. + * Returns 0 if given 0. + */ + function log2(uint256 value) internal pure returns (uint256) { + uint256 result = 0; + unchecked { + if (value >> 128 > 0) { + value >>= 128; + result += 128; + } + if (value >> 64 > 0) { + value >>= 64; + result += 64; + } + if (value >> 32 > 0) { + value >>= 32; + result += 32; + } + if (value >> 16 > 0) { + value >>= 16; + result += 16; + } + if (value >> 8 > 0) { + value >>= 8; + result += 8; + } + if (value >> 4 > 0) { + value >>= 4; + result += 4; + } + if (value >> 2 > 0) { + value >>= 2; + result += 2; + } + if (value >> 1 > 0) { + result += 1; + } + } + return result; + } + + /** + * @dev Return the log in base 2, following the selected rounding direction, of a positive value. + * Returns 0 if given 0. + */ + function log2(uint256 value, Rounding rounding) internal pure returns (uint256) { + unchecked { + uint256 result = log2(value); + return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0); + } + } + + /** + * @dev Return the log in base 10, rounded down, of a positive value. + * Returns 0 if given 0. + */ + function log10(uint256 value) internal pure returns (uint256) { + uint256 result = 0; + unchecked { + if (value >= 10 ** 64) { + value /= 10 ** 64; + result += 64; + } + if (value >= 10 ** 32) { + value /= 10 ** 32; + result += 32; + } + if (value >= 10 ** 16) { + value /= 10 ** 16; + result += 16; + } + if (value >= 10 ** 8) { + value /= 10 ** 8; + result += 8; + } + if (value >= 10 ** 4) { + value /= 10 ** 4; + result += 4; + } + if (value >= 10 ** 2) { + value /= 10 ** 2; + result += 2; + } + if (value >= 10 ** 1) { + result += 1; + } + } + return result; + } + + /** + * @dev Return the log in base 10, following the selected rounding direction, of a positive value. + * Returns 0 if given 0. + */ + function log10(uint256 value, Rounding rounding) internal pure returns (uint256) { + unchecked { + uint256 result = log10(value); + return result + (rounding == Rounding.Up && 10 ** result < value ? 1 : 0); + } + } + + /** + * @dev Return the log in base 256, rounded down, of a positive value. + * Returns 0 if given 0. + * + * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string. + */ + function log256(uint256 value) internal pure returns (uint256) { + uint256 result = 0; + unchecked { + if (value >> 128 > 0) { + value >>= 128; + result += 16; + } + if (value >> 64 > 0) { + value >>= 64; + result += 8; + } + if (value >> 32 > 0) { + value >>= 32; + result += 4; + } + if (value >> 16 > 0) { + value >>= 16; + result += 2; + } + if (value >> 8 > 0) { + result += 1; + } + } + return result; + } + + /** + * @dev Return the log in base 256, following the selected rounding direction, of a positive value. + * Returns 0 if given 0. + */ + function log256(uint256 value, Rounding rounding) internal pure returns (uint256) { + unchecked { + uint256 result = log256(value); + return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0); + } + } +} + +// lib/openzeppelin-contracts/contracts/utils/math/SignedMath.sol + +// OpenZeppelin Contracts (last updated v4.8.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/operator-filter-registry/src/IOperatorFilterRegistry.sol + + + +interface IOperatorFilterRegistry { + /** + * @notice Returns true if operator is not filtered for a given token, either by address or codeHash. Also returns + * true if supplied registrant address is not registered. + */ + function isOperatorAllowed(address registrant, address operator) external view returns (bool); + + /** + * @notice Registers an address with the registry. May be called by address itself or by EIP-173 owner. + */ + function register(address registrant) external; + + /** + * @notice Registers an address with the registry and "subscribes" to another address's filtered operators and codeHashes. + */ + function registerAndSubscribe(address registrant, address subscription) external; + + /** + * @notice Registers an address with the registry and copies the filtered operators and codeHashes from another + * address without subscribing. + */ + function registerAndCopyEntries(address registrant, address registrantToCopy) external; + + /** + * @notice Unregisters an address with the registry and removes its subscription. May be called by address itself or by EIP-173 owner. + * Note that this does not remove any filtered addresses or codeHashes. + * Also note that any subscriptions to this registrant will still be active and follow the existing filtered addresses and codehashes. + */ + function unregister(address addr) external; + + /** + * @notice Update an operator address for a registered address - when filtered is true, the operator is filtered. + */ + function updateOperator(address registrant, address operator, bool filtered) external; + + /** + * @notice Update multiple operators for a registered address - when filtered is true, the operators will be filtered. Reverts on duplicates. + */ + function updateOperators(address registrant, address[] calldata operators, bool filtered) external; + + /** + * @notice Update a codeHash for a registered address - when filtered is true, the codeHash is filtered. + */ + function updateCodeHash(address registrant, bytes32 codehash, bool filtered) external; + + /** + * @notice Update multiple codeHashes for a registered address - when filtered is true, the codeHashes will be filtered. Reverts on duplicates. + */ + function updateCodeHashes(address registrant, bytes32[] calldata codeHashes, bool filtered) external; + + /** + * @notice Subscribe an address to another registrant's filtered operators and codeHashes. Will remove previous + * subscription if present. + * Note that accounts with subscriptions may go on to subscribe to other accounts - in this case, + * subscriptions will not be forwarded. Instead the former subscription's existing entries will still be + * used. + */ + function subscribe(address registrant, address registrantToSubscribe) external; + + /** + * @notice Unsubscribe an address from its current subscribed registrant, and optionally copy its filtered operators and codeHashes. + */ + function unsubscribe(address registrant, bool copyExistingEntries) external; + + /** + * @notice Get the subscription address of a given registrant, if any. + */ + function subscriptionOf(address addr) external returns (address registrant); + + /** + * @notice Get the set of addresses subscribed to a given registrant. + * Note that order is not guaranteed as updates are made. + */ + function subscribers(address registrant) external returns (address[] memory); + + /** + * @notice Get the subscriber at a given index in the set of addresses subscribed to a given registrant. + * Note that order is not guaranteed as updates are made. + */ + function subscriberAt(address registrant, uint256 index) external returns (address); + + /** + * @notice Copy filtered operators and codeHashes from a different registrantToCopy to addr. + */ + function copyEntriesOf(address registrant, address registrantToCopy) external; + + /** + * @notice Returns true if operator is filtered by a given address or its subscription. + */ + function isOperatorFiltered(address registrant, address operator) external returns (bool); + + /** + * @notice Returns true if the hash of an address's code is filtered by a given address or its subscription. + */ + function isCodeHashOfFiltered(address registrant, address operatorWithCode) external returns (bool); + + /** + * @notice Returns true if a codeHash is filtered by a given address or its subscription. + */ + function isCodeHashFiltered(address registrant, bytes32 codeHash) external returns (bool); + + /** + * @notice Returns a list of filtered operators for a given address or its subscription. + */ + function filteredOperators(address addr) external returns (address[] memory); + + /** + * @notice Returns the set of filtered codeHashes for a given address or its subscription. + * Note that order is not guaranteed as updates are made. + */ + function filteredCodeHashes(address addr) external returns (bytes32[] memory); + + /** + * @notice Returns the filtered operator at the given index of the set of filtered operators for a given address or + * its subscription. + * Note that order is not guaranteed as updates are made. + */ + function filteredOperatorAt(address registrant, uint256 index) external returns (address); + + /** + * @notice Returns the filtered codeHash at the given index of the list of filtered codeHashes for a given address or + * its subscription. + * Note that order is not guaranteed as updates are made. + */ + function filteredCodeHashAt(address registrant, uint256 index) external returns (bytes32); + + /** + * @notice Returns true if an address has registered + */ + function isRegistered(address addr) external returns (bool); + + /** + * @dev Convenience method to compute the code hash of an arbitrary contract + */ + function codeHashOf(address addr) external returns (bytes32); +} + +// lib/operator-filter-registry/src/lib/Constants.sol + + + +address constant CANONICAL_OPERATOR_FILTER_REGISTRY_ADDRESS = 0x000000000000AAeB6D7670E522A718067333cd4E; +address constant CANONICAL_CORI_SUBSCRIPTION = 0x3cc6CddA760b79bAfa08dF41ECFA224f810dCeB6; + +// lib/openzeppelin-contracts/contracts/interfaces/IERC2981.sol + +// OpenZeppelin Contracts (last updated v4.9.0) (interfaces/IERC2981.sol) + + + + + +/** + * @dev Interface for the NFT Royalty Standard. + * + * A standardized way to retrieve royalty payment information for non-fungible tokens (NFTs) to enable universal + * support for royalty payments across all NFT marketplaces and ecosystem participants. + * + * _Available since v4.5._ + */ +interface IERC2981 is IERC165 { + /** + * @dev Returns how much royalty is owed and to whom, based on a sale price that may be denominated in any unit of + * exchange. The royalty amount is denominated and should be paid in that same unit of exchange. + */ + function royaltyInfo( + uint256 tokenId, + uint256 salePrice + ) external view returns (address receiver, uint256 royaltyAmount); +} + +// lib/openzeppelin-contracts/contracts/token/ERC721/IERC721.sol + +// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC721/IERC721.sol) + + + + + +/** + * @dev Required interface of an ERC721 compliant contract. + */ +interface IERC721 is IERC165 { + /** + * @dev Emitted when `tokenId` token is transferred from `from` to `to`. + */ + event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); + + /** + * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token. + */ + event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); + + /** + * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets. + */ + event ApprovalForAll(address indexed owner, address indexed operator, bool approved); + + /** + * @dev Returns the number of tokens in ``owner``'s account. + */ + function balanceOf(address owner) external view returns (uint256 balance); + + /** + * @dev Returns the owner of the `tokenId` token. + * + * Requirements: + * + * - `tokenId` must exist. + */ + function ownerOf(uint256 tokenId) external view returns (address owner); + + /** + * @dev Safely transfers `tokenId` token from `from` to `to`. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must exist and be owned by `from`. + * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. + * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. + * + * Emits a {Transfer} event. + */ + function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external; + + /** + * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients + * are aware of the ERC721 protocol to prevent tokens from being forever locked. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must exist and be owned by `from`. + * - If the caller is not `from`, it must have been allowed to move this token by either {approve} or {setApprovalForAll}. + * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. + * + * Emits a {Transfer} event. + */ + function safeTransferFrom(address from, address to, uint256 tokenId) external; + + /** + * @dev Transfers `tokenId` token from `from` to `to`. + * + * WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721 + * or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must + * understand this adds an external call which potentially creates a reentrancy vulnerability. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must be owned by `from`. + * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. + * + * Emits a {Transfer} event. + */ + function transferFrom(address from, address to, uint256 tokenId) external; + + /** + * @dev Gives permission to `to` to transfer `tokenId` token to another account. + * The approval is cleared when the token is transferred. + * + * Only a single account can be approved at a time, so approving the zero address clears previous approvals. + * + * Requirements: + * + * - The caller must own the token or be an approved operator. + * - `tokenId` must exist. + * + * Emits an {Approval} event. + */ + function approve(address to, uint256 tokenId) external; + + /** + * @dev Approve or remove `operator` as an operator for the caller. + * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller. + * + * Requirements: + * + * - The `operator` cannot be the caller. + * + * Emits an {ApprovalForAll} event. + */ + function setApprovalForAll(address operator, bool approved) external; + + /** + * @dev Returns the account approved for `tokenId` token. + * + * Requirements: + * + * - `tokenId` must exist. + */ + function getApproved(uint256 tokenId) external view returns (address operator); + + /** + * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`. + * + * See {setApprovalForAll} + */ + function isApprovedForAll(address owner, address operator) external view returns (bool); +} + +// lib/openzeppelin-contracts/contracts/utils/introspection/ERC165.sol + +// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol) + + + + + +/** + * @dev Implementation of the {IERC165} interface. + * + * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check + * for the additional interface id that will be supported. For example: + * + * ```solidity + * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { + * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId); + * } + * ``` + * + * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation. + */ +abstract contract ERC165 is IERC165 { + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { + return interfaceId == type(IERC165).interfaceId; + } +} + +// lib/openzeppelin-contracts/contracts/token/ERC721/extensions/IERC721Metadata.sol + +// OpenZeppelin Contracts v4.4.1 (token/ERC721/extensions/IERC721Metadata.sol) + + + + + +/** + * @title ERC-721 Non-Fungible Token Standard, optional metadata extension + * @dev See https://eips.ethereum.org/EIPS/eip-721 + */ +interface IERC721Metadata is IERC721 { + /** + * @dev Returns the token collection name. + */ + function name() external view returns (string memory); + + /** + * @dev Returns the token collection symbol. + */ + function symbol() external view returns (string memory); + + /** + * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token. + */ + function tokenURI(uint256 tokenId) external view returns (string memory); +} + +// lib/openzeppelin-contracts/contracts/utils/Strings.sol + +// OpenZeppelin Contracts (last updated v4.9.0) (utils/Strings.sol) + + + + + + +/** + * @dev String operations. + */ +library Strings { + bytes16 private constant _SYMBOLS = "0123456789abcdef"; + uint8 private constant _ADDRESS_LENGTH = 20; + + /** + * @dev Converts a `uint256` to its ASCII `string` decimal representation. + */ + function toString(uint256 value) internal pure returns (string memory) { + unchecked { + uint256 length = Math.log10(value) + 1; + string memory buffer = new string(length); + uint256 ptr; + /// @solidity memory-safe-assembly + assembly { + ptr := add(buffer, add(32, length)) + } + while (true) { + ptr--; + /// @solidity memory-safe-assembly + assembly { + mstore8(ptr, byte(mod(value, 10), _SYMBOLS)) + } + value /= 10; + if (value == 0) break; + } + return buffer; + } + } + + /** + * @dev Converts a `int256` to its ASCII `string` decimal representation. + */ + function toString(int256 value) internal pure returns (string memory) { + return string(abi.encodePacked(value < 0 ? "-" : "", toString(SignedMath.abs(value)))); + } + + /** + * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation. + */ + function toHexString(uint256 value) internal pure returns (string memory) { + unchecked { + return toHexString(value, Math.log256(value) + 1); + } + } + + /** + * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length. + */ + function toHexString(uint256 value, uint256 length) internal pure returns (string memory) { + bytes memory buffer = new bytes(2 * length + 2); + buffer[0] = "0"; + buffer[1] = "x"; + for (uint256 i = 2 * length + 1; i > 1; --i) { + buffer[i] = _SYMBOLS[value & 0xf]; + value >>= 4; + } + require(value == 0, "Strings: hex length insufficient"); + return string(buffer); + } + + /** + * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation. + */ + function toHexString(address addr) internal pure returns (string memory) { + return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH); + } + + /** + * @dev Returns true if the two strings are equal. + */ + function equal(string memory a, string memory b) internal pure returns (bool) { + return keccak256(bytes(a)) == keccak256(bytes(b)); + } +} + +// lib/operator-filter-registry/src/OperatorFilterer.sol + + + + + +/** + * @title OperatorFilterer + * @notice Abstract contract whose constructor automatically registers and optionally subscribes to or copies another + * registrant's entries in the OperatorFilterRegistry. + * @dev This smart contract is meant to be inherited by token contracts so they can use the following: + * - `onlyAllowedOperator` modifier for `transferFrom` and `safeTransferFrom` methods. + * - `onlyAllowedOperatorApproval` modifier for `approve` and `setApprovalForAll` methods. + * Please note that if your token contract does not provide an owner with EIP-173, it must provide + * administration methods on the contract itself to interact with the registry otherwise the subscription + * will be locked to the options set during construction. + */ + +abstract contract OperatorFilterer { + /// @dev Emitted when an operator is not allowed. + error OperatorNotAllowed(address operator); + + IOperatorFilterRegistry public constant OPERATOR_FILTER_REGISTRY = + IOperatorFilterRegistry(CANONICAL_OPERATOR_FILTER_REGISTRY_ADDRESS); + + /// @dev The constructor that is called when the contract is being deployed. + constructor(address subscriptionOrRegistrantToCopy, bool subscribe) { + // If an inheriting token contract is deployed to a network without the registry deployed, the modifier + // will not revert, but the contract will need to be registered with the registry once it is deployed in + // order for the modifier to filter addresses. + if (address(OPERATOR_FILTER_REGISTRY).code.length > 0) { + if (subscribe) { + OPERATOR_FILTER_REGISTRY.registerAndSubscribe(address(this), subscriptionOrRegistrantToCopy); + } else { + if (subscriptionOrRegistrantToCopy != address(0)) { + OPERATOR_FILTER_REGISTRY.registerAndCopyEntries(address(this), subscriptionOrRegistrantToCopy); + } else { + OPERATOR_FILTER_REGISTRY.register(address(this)); + } + } + } + } + + /** + * @dev A helper function to check if an operator is allowed. + */ + modifier onlyAllowedOperator(address from) virtual { + // Allow spending tokens from addresses with balance + // Note that this still allows listings and marketplaces with escrow to transfer tokens if transferred + // from an EOA. + if (from != msg.sender) { + _checkFilterOperator(msg.sender); + } + _; + } + + /** + * @dev A helper function to check if an operator approval is allowed. + */ + modifier onlyAllowedOperatorApproval(address operator) virtual { + _checkFilterOperator(operator); + _; + } + + /** + * @dev A helper function to check if an operator is allowed. + */ + function _checkFilterOperator(address operator) internal view virtual { + // Check registry code length to facilitate testing in environments without a deployed registry. + if (address(OPERATOR_FILTER_REGISTRY).code.length > 0) { + // under normal circumstances, this function will revert rather than return false, but inheriting contracts + // may specify their own OperatorFilterRegistry implementations, which may behave differently + if (!OPERATOR_FILTER_REGISTRY.isOperatorAllowed(address(this), operator)) { + revert OperatorNotAllowed(operator); + } + } + } +} + +// lib/openzeppelin-contracts/contracts\token/common/ERC2981.sol + +// OpenZeppelin Contracts (last updated v4.9.0) (token/common/ERC2981.sol) + + + + + + +/** + * @dev Implementation of the NFT Royalty Standard, a standardized way to retrieve royalty payment information. + * + * Royalty information can be specified globally for all token ids via {_setDefaultRoyalty}, and/or individually for + * specific token ids via {_setTokenRoyalty}. The latter takes precedence over the first. + * + * Royalty is specified as a fraction of sale price. {_feeDenominator} is overridable but defaults to 10000, meaning the + * fee is specified in basis points by default. + * + * IMPORTANT: ERC-2981 only specifies a way to signal royalty information and does not enforce its payment. See + * https://eips.ethereum.org/EIPS/eip-2981#optional-royalty-payments[Rationale] in the EIP. Marketplaces are expected to + * voluntarily pay royalties together with sales, but note that this standard is not yet widely supported. + * + * _Available since v4.5._ + */ +abstract contract ERC2981 is IERC2981, ERC165 { + struct RoyaltyInfo { + address receiver; + uint96 royaltyFraction; + } + + RoyaltyInfo private _defaultRoyaltyInfo; + mapping(uint256 => RoyaltyInfo) private _tokenRoyaltyInfo; + + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface(bytes4 interfaceId) public view virtual override(IERC165, ERC165) returns (bool) { + return interfaceId == type(IERC2981).interfaceId || super.supportsInterface(interfaceId); + } + + /** + * + */ + function royaltyInfo(uint256 tokenId, uint256 salePrice) public view virtual override returns (address, uint256) { + RoyaltyInfo memory royalty = _tokenRoyaltyInfo[tokenId]; + + if (royalty.receiver == address(0)) { + royalty = _defaultRoyaltyInfo; + } + + uint256 royaltyAmount = (salePrice * royalty.royaltyFraction) / _feeDenominator(); + + return (royalty.receiver, royaltyAmount); + } + + /** + * @dev The denominator with which to interpret the fee set in {_setTokenRoyalty} and {_setDefaultRoyalty} as a + * fraction of the sale price. Defaults to 10000 so fees are expressed in basis points, but may be customized by an + * override. + */ + function _feeDenominator() internal pure virtual returns (uint96) { + return 10000; + } + + /** + * @dev Sets the royalty information that all ids in this contract will default to. + * + * Requirements: + * + * - `receiver` cannot be the zero address. + * - `feeNumerator` cannot be greater than the fee denominator. + */ + function _setDefaultRoyalty(address receiver, uint96 feeNumerator) internal virtual { + require(feeNumerator <= _feeDenominator(), "ERC2981: royalty fee will exceed salePrice"); + require(receiver != address(0), "ERC2981: invalid receiver"); + + _defaultRoyaltyInfo = RoyaltyInfo(receiver, feeNumerator); + } + + /** + * @dev Removes default royalty information. + */ + function _deleteDefaultRoyalty() internal virtual { + delete _defaultRoyaltyInfo; + } + + /** + * @dev Sets the royalty information for a specific token id, overriding the global default. + * + * Requirements: + * + * - `receiver` cannot be the zero address. + * - `feeNumerator` cannot be greater than the fee denominator. + */ + function _setTokenRoyalty(uint256 tokenId, address receiver, uint96 feeNumerator) internal virtual { + require(feeNumerator <= _feeDenominator(), "ERC2981: royalty fee will exceed salePrice"); + require(receiver != address(0), "ERC2981: Invalid parameters"); + + _tokenRoyaltyInfo[tokenId] = RoyaltyInfo(receiver, feeNumerator); + } + + /** + * @dev Resets royalty information for the token id back to the global default. + */ + function _resetTokenRoyalty(uint256 tokenId) internal virtual { + delete _tokenRoyaltyInfo[tokenId]; + } +} + +// lib/operator-filter-registry/src\DefaultOperatorFilterer.sol + + + + + +/** + * @title DefaultOperatorFilterer + * @notice Inherits from OperatorFilterer and automatically subscribes to the default OpenSea subscription. + * @dev Please note that if your token contract does not provide an owner with EIP-173, it must provide + * administration methods on the contract itself to interact with the registry otherwise the subscription + * will be locked to the options set during construction. + */ + +abstract contract DefaultOperatorFilterer is OperatorFilterer { + /// @dev The constructor that is called when the contract is being deployed. + constructor() OperatorFilterer(CANONICAL_CORI_SUBSCRIPTION, true) {} +} + +// src\pookyball/IPookyball.sol + + + + + + + +/// @title PookyballMetadata +/// @notice The Pookyball rarities are represented on chain by this enum. +enum PookyballRarity { + COMMON, + RARE, + EPIC, + LEGENDARY, + MYTHIC +} + +/// @title PookyballMetadata +/// @notice Pookyballs NFT have the following features: +/// - rarity: integer enum. +/// - level: token level, can be increase by spending token experiences points (PXP). +/// - pxp: token experience points. +/// - seed: a random uint256 word provided by Chainlink VRF service that will be used by Pooky's NFT generator +/// back-end to generate the NFT visuals and in-game statistics\. +struct PookyballMetadata { + PookyballRarity rarity; + uint256 level; + uint256 pxp; + uint256 seed; +} + +/// @title IPookyball +/// @author Mathieu Bour for Pooky Labs Ltd. +/// @notice Minimal Pookyball interface. +interface IPookyball is IAccessControl, IERC2981, IERC721 { + /// Fired when the seed of a Pookyball token is set by the VRFCoordinator + event SeedSet(uint256 indexed tokenId, uint256 seed); + /// Fired when the level of a Pookyball token is changed + event LevelChanged(uint256 indexed tokenId, uint256 level); + /// Fired when the PXP of a Pookyball token is changed + event PXPChanged(uint256 indexed tokenId, uint256 amount); + + /// Thrown when the length of two parameters mismatch. Used in the mint batched function. + error ArgumentSizeMismatch(uint256 x, uint256 y); + + /// @notice PookyballMetadata of the token {tokenId}. + /// @dev Requirements: + /// - Pookyball {tokenId} should exist (minted and not burned). + function metadata(uint256 tokenId) external view returns (PookyballMetadata memory); + + /// @notice Change the secondary sale royalties receiver address. + function setERC2981Receiver(address newReceiver) external; + + /// @notice Mint a new Pookyball token with a given rarity. + function mint(address[] memory recipients, PookyballRarity[] memory rarities) + external + returns (uint256); + + /// @notice Change the level of a Pookyball token. + /// @dev Requirements: + /// - Pookyball {tokenId} should exist (minted and not burned). + function setLevel(uint256 tokenId, uint256 newLevel) external; + + /// @notice Change the PXP of a Pookyball token. + /// @dev Requirements: + /// - Pookyball {tokenId} should exist (minted and not burned). + function setPXP(uint256 tokenId, uint256 newPXP) external; +} + +// lib/openzeppelin-contracts/contracts\access/AccessControl.sol + +// OpenZeppelin Contracts (last updated v4.9.0) (access/AccessControl.sol) + + + + + + + + +/** + * @dev Contract module that allows children to implement role-based access + * control mechanisms. This is a lightweight version that doesn't allow enumerating role + * members except through off-chain means by accessing the contract event logs. Some + * applications may benefit from on-chain enumerability, for those cases see + * {AccessControlEnumerable}. + * + * Roles are referred to by their `bytes32` identifier. These should be exposed + * in the external API and be unique. The best way to achieve this is by + * using `public constant` hash digests: + * + * ```solidity + * bytes32 public constant MY_ROLE = keccak256("MY_ROLE"); + * ``` + * + * Roles can be used to represent a set of permissions. To restrict access to a + * function call, use {hasRole}: + * + * ```solidity + * function foo() public { + * require(hasRole(MY_ROLE, msg.sender)); + * ... + * } + * ``` + * + * Roles can be granted and revoked dynamically via the {grantRole} and + * {revokeRole} functions. Each role has an associated admin role, and only + * accounts that have a role's admin role can call {grantRole} and {revokeRole}. + * + * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means + * that only accounts with this role will be able to grant or revoke other + * roles. More complex role relationships can be created by using + * {_setRoleAdmin}. + * + * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to + * grant and revoke this role. Extra precautions should be taken to secure + * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules} + * to enforce additional security measures for this role. + */ +abstract contract AccessControl is Context, IAccessControl, ERC165 { + struct RoleData { + mapping(address => bool) members; + bytes32 adminRole; + } + + mapping(bytes32 => RoleData) private _roles; + + bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00; + + /** + * @dev Modifier that checks that an account has a specific role. Reverts + * with a standardized message including the required role. + * + * The format of the revert reason is given by the following regular expression: + * + * /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/ + * + * _Available since v4.1._ + */ + modifier onlyRole(bytes32 role) { + _checkRole(role); + _; + } + + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { + return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId); + } + + /** + * @dev Returns `true` if `account` has been granted `role`. + */ + function hasRole(bytes32 role, address account) public view virtual override returns (bool) { + return _roles[role].members[account]; + } + + /** + * @dev Revert with a standard message if `_msgSender()` is missing `role`. + * Overriding this function changes the behavior of the {onlyRole} modifier. + * + * Format of the revert message is described in {_checkRole}. + * + * _Available since v4.6._ + */ + function _checkRole(bytes32 role) internal view virtual { + _checkRole(role, _msgSender()); + } + + /** + * @dev Revert with a standard message if `account` is missing `role`. + * + * The format of the revert reason is given by the following regular expression: + * + * /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/ + */ + function _checkRole(bytes32 role, address account) internal view virtual { + if (!hasRole(role, account)) { + revert( + string( + abi.encodePacked( + "AccessControl: account ", + Strings.toHexString(account), + " is missing role ", + Strings.toHexString(uint256(role), 32) + ) + ) + ); + } + } + + /** + * @dev Returns the admin role that controls `role`. See {grantRole} and + * {revokeRole}. + * + * To change a role's admin, use {_setRoleAdmin}. + */ + function getRoleAdmin(bytes32 role) public view virtual override returns (bytes32) { + return _roles[role].adminRole; + } + + /** + * @dev Grants `role` to `account`. + * + * If `account` had not been already granted `role`, emits a {RoleGranted} + * event. + * + * Requirements: + * + * - the caller must have ``role``'s admin role. + * + * May emit a {RoleGranted} event. + */ + function grantRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) { + _grantRole(role, account); + } + + /** + * @dev Revokes `role` from `account`. + * + * If `account` had been granted `role`, emits a {RoleRevoked} event. + * + * Requirements: + * + * - the caller must have ``role``'s admin role. + * + * May emit a {RoleRevoked} event. + */ + function revokeRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) { + _revokeRole(role, account); + } + + /** + * @dev Revokes `role` from the calling account. + * + * Roles are often managed via {grantRole} and {revokeRole}: this function's + * purpose is to provide a mechanism for accounts to lose their privileges + * if they are compromised (such as when a trusted device is misplaced). + * + * If the calling account had been revoked `role`, emits a {RoleRevoked} + * event. + * + * Requirements: + * + * - the caller must be `account`. + * + * May emit a {RoleRevoked} event. + */ + function renounceRole(bytes32 role, address account) public virtual override { + require(account == _msgSender(), "AccessControl: can only renounce roles for self"); + + _revokeRole(role, account); + } + + /** + * @dev Grants `role` to `account`. + * + * If `account` had not been already granted `role`, emits a {RoleGranted} + * event. Note that unlike {grantRole}, this function doesn't perform any + * checks on the calling account. + * + * May emit a {RoleGranted} event. + * + * [WARNING] + * ==== + * This function should only be called from the constructor when setting + * up the initial roles for the system. + * + * Using this function in any other way is effectively circumventing the admin + * system imposed by {AccessControl}. + * ==== + * + * NOTE: This function is deprecated in favor of {_grantRole}. + */ + function _setupRole(bytes32 role, address account) internal virtual { + _grantRole(role, account); + } + + /** + * @dev Sets `adminRole` as ``role``'s admin role. + * + * Emits a {RoleAdminChanged} event. + */ + function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual { + bytes32 previousAdminRole = getRoleAdmin(role); + _roles[role].adminRole = adminRole; + emit RoleAdminChanged(role, previousAdminRole, adminRole); + } + + /** + * @dev Grants `role` to `account`. + * + * Internal function without access restriction. + * + * May emit a {RoleGranted} event. + */ + function _grantRole(bytes32 role, address account) internal virtual { + if (!hasRole(role, account)) { + _roles[role].members[account] = true; + emit RoleGranted(role, account, _msgSender()); + } + } + + /** + * @dev Revokes `role` from `account`. + * + * Internal function without access restriction. + * + * May emit a {RoleRevoked} event. + */ + function _revokeRole(bytes32 role, address account) internal virtual { + if (hasRole(role, account)) { + _roles[role].members[account] = false; + emit RoleRevoked(role, account, _msgSender()); + } + } +} + +// lib/openzeppelin-contracts/contracts\token/ERC721/ERC721.sol + +// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC721/ERC721.sol) + + + + + + + + + + + +/** + * @dev Implementation of https://eips.ethereum.org/EIPS/eip-721[ERC721] Non-Fungible Token Standard, including + * the Metadata extension, but not including the Enumerable extension, which is available separately as + * {ERC721Enumerable}. + */ +contract ERC721 is Context, ERC165, IERC721, IERC721Metadata { + using Address for address; + using Strings for uint256; + + // Token name + string private _name; + + // Token symbol + string private _symbol; + + // Mapping from token ID to owner address + mapping(uint256 => address) private _owners; + + // Mapping owner address to token count + mapping(address => uint256) private _balances; + + // Mapping from token ID to approved address + mapping(uint256 => address) private _tokenApprovals; + + // Mapping from owner to operator approvals + mapping(address => mapping(address => bool)) private _operatorApprovals; + + /** + * @dev Initializes the contract by setting a `name` and a `symbol` to the token collection. + */ + constructor(string memory name_, string memory symbol_) { + _name = name_; + _symbol = symbol_; + } + + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) { + return + interfaceId == type(IERC721).interfaceId || + interfaceId == type(IERC721Metadata).interfaceId || + super.supportsInterface(interfaceId); + } + + /** + * @dev See {IERC721-balanceOf}. + */ + function balanceOf(address owner) public view virtual override returns (uint256) { + require(owner != address(0), "ERC721: address zero is not a valid owner"); + return _balances[owner]; + } + + /** + * @dev See {IERC721-ownerOf}. + */ + function ownerOf(uint256 tokenId) public view virtual override returns (address) { + address owner = _ownerOf(tokenId); + require(owner != address(0), "ERC721: invalid token ID"); + return owner; + } + + /** + * @dev See {IERC721Metadata-name}. + */ + function name() public view virtual override returns (string memory) { + return _name; + } + + /** + * @dev See {IERC721Metadata-symbol}. + */ + function symbol() public view virtual override returns (string memory) { + return _symbol; + } + + /** + * @dev See {IERC721Metadata-tokenURI}. + */ + function tokenURI(uint256 tokenId) public view virtual override returns (string memory) { + _requireMinted(tokenId); + + string memory baseURI = _baseURI(); + return bytes(baseURI).length > 0 ? string(abi.encodePacked(baseURI, tokenId.toString())) : ""; + } + + /** + * @dev Base URI for computing {tokenURI}. If set, the resulting URI for each + * token will be the concatenation of the `baseURI` and the `tokenId`. Empty + * by default, can be overridden in child contracts. + */ + function _baseURI() internal view virtual returns (string memory) { + return ""; + } + + /** + * @dev See {IERC721-approve}. + */ + function approve(address to, uint256 tokenId) public virtual override { + address owner = ERC721.ownerOf(tokenId); + require(to != owner, "ERC721: approval to current owner"); + + require( + _msgSender() == owner || isApprovedForAll(owner, _msgSender()), + "ERC721: approve caller is not token owner or approved for all" + ); + + _approve(to, tokenId); + } + + /** + * @dev See {IERC721-getApproved}. + */ + function getApproved(uint256 tokenId) public view virtual override returns (address) { + _requireMinted(tokenId); + + return _tokenApprovals[tokenId]; + } + + /** + * @dev See {IERC721-setApprovalForAll}. + */ + function setApprovalForAll(address operator, bool approved) public virtual override { + _setApprovalForAll(_msgSender(), operator, approved); + } + + /** + * @dev See {IERC721-isApprovedForAll}. + */ + function isApprovedForAll(address owner, address operator) public view virtual override returns (bool) { + return _operatorApprovals[owner][operator]; + } + + /** + * @dev See {IERC721-transferFrom}. + */ + function transferFrom(address from, address to, uint256 tokenId) public virtual override { + //solhint-disable-next-line max-line-length + require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: caller is not token owner or approved"); + + _transfer(from, to, tokenId); + } + + /** + * @dev See {IERC721-safeTransferFrom}. + */ + function safeTransferFrom(address from, address to, uint256 tokenId) public virtual override { + safeTransferFrom(from, to, tokenId, ""); + } + + /** + * @dev See {IERC721-safeTransferFrom}. + */ + function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory data) public virtual override { + require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: caller is not token owner or approved"); + _safeTransfer(from, to, tokenId, data); + } + + /** + * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients + * are aware of the ERC721 protocol to prevent tokens from being forever locked. + * + * `data` is additional data, it has no specified format and it is sent in call to `to`. + * + * This internal function is equivalent to {safeTransferFrom}, and can be used to e.g. + * implement alternative mechanisms to perform token transfer, such as signature-based. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must exist and be owned by `from`. + * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. + * + * Emits a {Transfer} event. + */ + function _safeTransfer(address from, address to, uint256 tokenId, bytes memory data) internal virtual { + _transfer(from, to, tokenId); + require(_checkOnERC721Received(from, to, tokenId, data), "ERC721: transfer to non ERC721Receiver implementer"); + } + + /** + * @dev Returns the owner of the `tokenId`. Does NOT revert if token doesn't exist + */ + function _ownerOf(uint256 tokenId) internal view virtual returns (address) { + return _owners[tokenId]; + } + + /** + * @dev Returns whether `tokenId` exists. + * + * Tokens can be managed by their owner or approved accounts via {approve} or {setApprovalForAll}. + * + * Tokens start existing when they are minted (`_mint`), + * and stop existing when they are burned (`_burn`). + */ + function _exists(uint256 tokenId) internal view virtual returns (bool) { + return _ownerOf(tokenId) != address(0); + } + + /** + * @dev Returns whether `spender` is allowed to manage `tokenId`. + * + * Requirements: + * + * - `tokenId` must exist. + */ + function _isApprovedOrOwner(address spender, uint256 tokenId) internal view virtual returns (bool) { + address owner = ERC721.ownerOf(tokenId); + return (spender == owner || isApprovedForAll(owner, spender) || getApproved(tokenId) == spender); + } + + /** + * @dev Safely mints `tokenId` and transfers it to `to`. + * + * Requirements: + * + * - `tokenId` must not exist. + * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. + * + * Emits a {Transfer} event. + */ + function _safeMint(address to, uint256 tokenId) internal virtual { + _safeMint(to, tokenId, ""); + } + + /** + * @dev Same as {xref-ERC721-_safeMint-address-uint256-}[`_safeMint`], with an additional `data` parameter which is + * forwarded in {IERC721Receiver-onERC721Received} to contract recipients. + */ + function _safeMint(address to, uint256 tokenId, bytes memory data) internal virtual { + _mint(to, tokenId); + require( + _checkOnERC721Received(address(0), to, tokenId, data), + "ERC721: transfer to non ERC721Receiver implementer" + ); + } + + /** + * @dev Mints `tokenId` and transfers it to `to`. + * + * WARNING: Usage of this method is discouraged, use {_safeMint} whenever possible + * + * Requirements: + * + * - `tokenId` must not exist. + * - `to` cannot be the zero address. + * + * Emits a {Transfer} event. + */ + function _mint(address to, uint256 tokenId) internal virtual { + require(to != address(0), "ERC721: mint to the zero address"); + require(!_exists(tokenId), "ERC721: token already minted"); + + _beforeTokenTransfer(address(0), to, tokenId, 1); + + // Check that tokenId was not minted by `_beforeTokenTransfer` hook + require(!_exists(tokenId), "ERC721: token already minted"); + + unchecked { + // Will not overflow unless all 2**256 token ids are minted to the same owner. + // Given that tokens are minted one by one, it is impossible in practice that + // this ever happens. Might change if we allow batch minting. + // The ERC fails to describe this case. + _balances[to] += 1; + } + + _owners[tokenId] = to; + + emit Transfer(address(0), to, tokenId); + + _afterTokenTransfer(address(0), to, tokenId, 1); + } + + /** + * @dev Destroys `tokenId`. + * The approval is cleared when the token is burned. + * This is an internal function that does not check if the sender is authorized to operate on the token. + * + * Requirements: + * + * - `tokenId` must exist. + * + * Emits a {Transfer} event. + */ + function _burn(uint256 tokenId) internal virtual { + address owner = ERC721.ownerOf(tokenId); + + _beforeTokenTransfer(owner, address(0), tokenId, 1); + + // Update ownership in case tokenId was transferred by `_beforeTokenTransfer` hook + owner = ERC721.ownerOf(tokenId); + + // Clear approvals + delete _tokenApprovals[tokenId]; + + unchecked { + // Cannot overflow, as that would require more tokens to be burned/transferred + // out than the owner initially received through minting and transferring in. + _balances[owner] -= 1; + } + delete _owners[tokenId]; + + emit Transfer(owner, address(0), tokenId); + + _afterTokenTransfer(owner, address(0), tokenId, 1); + } + + /** + * @dev Transfers `tokenId` from `from` to `to`. + * As opposed to {transferFrom}, this imposes no restrictions on msg.sender. + * + * Requirements: + * + * - `to` cannot be the zero address. + * - `tokenId` token must be owned by `from`. + * + * Emits a {Transfer} event. + */ + function _transfer(address from, address to, uint256 tokenId) internal virtual { + require(ERC721.ownerOf(tokenId) == from, "ERC721: transfer from incorrect owner"); + require(to != address(0), "ERC721: transfer to the zero address"); + + _beforeTokenTransfer(from, to, tokenId, 1); + + // Check that tokenId was not transferred by `_beforeTokenTransfer` hook + require(ERC721.ownerOf(tokenId) == from, "ERC721: transfer from incorrect owner"); + + // Clear approvals from the previous owner + delete _tokenApprovals[tokenId]; + + unchecked { + // `_balances[from]` cannot overflow for the same reason as described in `_burn`: + // `from`'s balance is the number of token held, which is at least one before the current + // transfer. + // `_balances[to]` could overflow in the conditions described in `_mint`. That would require + // all 2**256 token ids to be minted, which in practice is impossible. + _balances[from] -= 1; + _balances[to] += 1; + } + _owners[tokenId] = to; + + emit Transfer(from, to, tokenId); + + _afterTokenTransfer(from, to, tokenId, 1); + } + + /** + * @dev Approve `to` to operate on `tokenId` + * + * Emits an {Approval} event. + */ + function _approve(address to, uint256 tokenId) internal virtual { + _tokenApprovals[tokenId] = to; + emit Approval(ERC721.ownerOf(tokenId), to, tokenId); + } + + /** + * @dev Approve `operator` to operate on all of `owner` tokens + * + * Emits an {ApprovalForAll} event. + */ + function _setApprovalForAll(address owner, address operator, bool approved) internal virtual { + require(owner != operator, "ERC721: approve to caller"); + _operatorApprovals[owner][operator] = approved; + emit ApprovalForAll(owner, operator, approved); + } + + /** + * @dev Reverts if the `tokenId` has not been minted yet. + */ + function _requireMinted(uint256 tokenId) internal view virtual { + require(_exists(tokenId), "ERC721: invalid token ID"); + } + + /** + * @dev Internal function to invoke {IERC721Receiver-onERC721Received} on a target address. + * The call is not executed if the target address is not a contract. + * + * @param from address representing the previous owner of the given token ID + * @param to target address that will receive the tokens + * @param tokenId uint256 ID of the token to be transferred + * @param data bytes optional data to send along with the call + * @return bool whether the call correctly returned the expected magic value + */ + function _checkOnERC721Received( + address from, + address to, + uint256 tokenId, + bytes memory data + ) private returns (bool) { + if (to.isContract()) { + try IERC721Receiver(to).onERC721Received(_msgSender(), from, tokenId, data) returns (bytes4 retval) { + return retval == IERC721Receiver.onERC721Received.selector; + } catch (bytes memory reason) { + if (reason.length == 0) { + revert("ERC721: transfer to non ERC721Receiver implementer"); + } else { + /// @solidity memory-safe-assembly + assembly { + revert(add(32, reason), mload(reason)) + } + } + } + } else { + return true; + } + } + + /** + * @dev Hook that is called before any token transfer. This includes minting and burning. If {ERC721Consecutive} is + * used, the hook may be called as part of a consecutive (batch) mint, as indicated by `batchSize` greater than 1. + * + * Calling conditions: + * + * - When `from` and `to` are both non-zero, ``from``'s tokens will be transferred to `to`. + * - When `from` is zero, the tokens will be minted for `to`. + * - When `to` is zero, ``from``'s tokens will be burned. + * - `from` and `to` are never both zero. + * - `batchSize` is non-zero. + * + * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. + */ + function _beforeTokenTransfer(address from, address to, uint256 firstTokenId, uint256 batchSize) internal virtual {} + + /** + * @dev Hook that is called after any token transfer. This includes minting and burning. If {ERC721Consecutive} is + * used, the hook may be called as part of a consecutive (batch) mint, as indicated by `batchSize` greater than 1. + * + * Calling conditions: + * + * - When `from` and `to` are both non-zero, ``from``'s tokens were transferred to `to`. + * - When `from` is zero, the tokens were minted for `to`. + * - When `to` is zero, ``from``'s tokens were burned. + * - `from` and `to` are never both zero. + * - `batchSize` is non-zero. + * + * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. + */ + function _afterTokenTransfer(address from, address to, uint256 firstTokenId, uint256 batchSize) internal virtual {} + + /** + * @dev Unsafe write access to the balances, used by extensions that "mint" tokens using an {ownerOf} override. + * + * WARNING: Anyone calling this MUST ensure that the balances remain consistent with the ownership. The invariant + * being that for any address `a` the value returned by `balanceOf(a)` must be equal to the number of tokens such + * that `ownerOf(tokenId)` is `a`. + */ + // solhint-disable-next-line func-name-mixedcase + function __unsafe_increaseBalance(address account, uint256 amount) internal { + _balances[account] += amount; + } +} + +// src\pookyball\Pookyball.sol + + + + + + + + + + + + + + +/// @title Pookyball +/// @author Mathieu Bour, Dusan Zdravkovic for Pooky Labs Ltd. +/// +/// @notice Pookyball is ERC721 token representing Pookyball NFTs. Balls are mintable by other Pooky game contracts. +/// This contract does not hold any aspect of the Pooky gameplay and only serves as Pookyball information storage. +/// +/// In order to enforce the creator fees on secondary sales, we chose to adhere to the Operator Filter Registry +/// standard that was initially developed by OpenSea. +/// For more information, see https://github.com/ProjectOpenSea/operator-filter-registry +/// +/// Roles: +/// - DEFAULT_ADMIN_ROLE can add/remove roles. +/// - MINTER role can mint new tokens. +/// - GAME role can change the mutable token metadata (level and PXP). +contract Pookyball is + IPookyball, + ERC721, + ERC2981, + AccessControl, + VRFConsumerBaseV2, + DefaultOperatorFilterer +{ + using Strings for uint256; + + // Roles + bytes32 public constant MINTER = keccak256("MINTER"); + bytes32 public constant GAME = keccak256("GAME"); + + /// Secondary sales royalties, over 10,000 (5%) + uint96 public constant ROYALTY = 500; + + /// @notice The prefix of all the Pookyball metadata. + string public baseURI; + + /// @notice URI of the contract-level metadata. + /// Specified by OpenSea documentation (https://docs.opensea.io/docs/contract-level-metadata). + string public contractURI; + + /// Last minted tokenId, will always exist + uint256 public lastTokenId; + + /// Tokens gameplay metadata, see {PookyballMetadata} + mapping(uint256 => PookyballMetadata) _metadata; + + // VRF parameters + VRFCoordinatorV2Interface public vrfCoordinator; + bytes32 public vrfKeyHash; + uint64 public vrfSubId; + uint16 public vrfMinimumRequestConfirmations; + uint32 public vrfCallbackGasLimit; + mapping(uint256 => uint256) vrfRequests; + bool public canUpdateVRF = true; + bool public canUseVRF = false; + + constructor( + string memory _baseURI, + string memory _contractURI, + address _admin, + address _receiver, + address _vrfCoordinator, + bytes32 _vrfKeyHash, + uint64 _vrfSubId, + uint16 _vrfMinimumRequestConfirmations, + uint32 _vrfCallbackGasLimit + ) ERC721("Pookyball", "PKYB") VRFConsumerBaseV2(_vrfCoordinator) { + baseURI = _baseURI; + contractURI = _contractURI; + + vrfCoordinator = VRFCoordinatorV2Interface(_vrfCoordinator); + vrfKeyHash = _vrfKeyHash; + vrfSubId = _vrfSubId; + vrfMinimumRequestConfirmations = _vrfMinimumRequestConfirmations; + vrfCallbackGasLimit = _vrfCallbackGasLimit; + + _setDefaultRoyalty(_receiver, ROYALTY); + _grantRole(DEFAULT_ADMIN_ROLE, _admin); + } + + /// @notice Set the URI of the contract-level metadata. + /// @dev We keep this function as an escape hatch in case of a migration to another token metadata platform. + /// Requirements: + /// - Only DEFAULT_ADMIN_ROLE role can set the contract URI. + function setContractURI(string memory newContractURI) external onlyRole(DEFAULT_ADMIN_ROLE) { + contractURI = newContractURI; + } + + /// @notice Change the base URI of the tokens URI. + /// @dev We keep this function as an escape hatch in case of a migration to another token metadata platform. + /// Requirements: + /// - Only DEFAULT_ADMIN_ROLE role can set base URI. + function setBaseURI(string memory newBaseURI) external onlyRole(DEFAULT_ADMIN_ROLE) { + baseURI = newBaseURI; + } + + /// @notice Metadata URI of the token {tokenId}. + /// @dev See {IERC721Metadata-tokenURI}. + /// Requirements: + /// - Ball {tokenId} should exist (minted and not burned). + function tokenURI(uint256 tokenId) public view virtual override returns (string memory) { + _requireMinted(tokenId); + return string(abi.encodePacked(baseURI, tokenId.toString())); + } + + /// @notice PookyballMetadata of the token {tokenId}. + /// @dev Requirements: + /// - Pookyball {tokenId} should exist (minted and not burned). + function metadata(uint256 tokenId) external view returns (PookyballMetadata memory) { + _requireMinted(tokenId); + return _metadata[tokenId]; + } + + /// @notice Change the secondary sale royalties receiver address. + /// @dev Requirements: + /// - Only DEFAULT_ADMIN_ROLE role can set base URI. + function setERC2981Receiver(address newReceiver) external onlyRole(DEFAULT_ADMIN_ROLE) { + _setDefaultRoyalty(newReceiver, ROYALTY); + } + + /// @notice Mint a new Pookyball token with a given rarity. Level, PXP and seed are set to zero, entropy is + /// requested to the VRF coordinator. + /// @dev Requirements: + /// - sender must have the MINTER role. + /// - `recipients` and `rarities` arguments must have the same size + function mint(address[] memory recipients, PookyballRarity[] memory rarities) + external + onlyRole(MINTER) + returns (uint256) + { + // Check the arguments length + if (recipients.length != rarities.length) { + revert ArgumentSizeMismatch(recipients.length, rarities.length); + } + + for (uint256 i = 0; i < recipients.length; i++) { + _mint(recipients[i], ++lastTokenId); + _metadata[lastTokenId] = PookyballMetadata(rarities[i], 0, 0, 0); + } + + if (canUseVRF) { + // Request entropy from the VRF coordinator + uint256 requestId = vrfCoordinator.requestRandomWords( + vrfKeyHash, + vrfSubId, + vrfMinimumRequestConfirmations, + vrfCallbackGasLimit, + uint32(recipients.length) + ); + vrfRequests[requestId] = lastTokenId; + } else { + // Generate pseudo random seed + for (uint256 i = 0; i < recipients.length; i++) { + uint256 tokenId = lastTokenId - i; + uint256 seed = generateRandomSeed(tokenId); + _metadata[tokenId].seed = seed; + emit SeedSet(tokenId, seed); + } + } + + return lastTokenId; + } + + /// @notice Change the level of a Pookyball token. + /// @dev Requirements: + /// - sender must have the GAME role. + /// - Pookyball {tokenId} should exist (minted and not burned). + function setLevel(uint256 tokenId, uint256 newLevel) external onlyRole(GAME) { + _requireMinted(tokenId); + _metadata[tokenId].level = newLevel; + emit LevelChanged(tokenId, newLevel); + } + + /// @notice Change the PXP of a Pookyball token. + /// @dev Requirements: + /// - sender must have the GAME role. + /// - Pookyball {tokenId} should exist (minted and not burned). + function setPXP(uint256 tokenId, uint256 newPXP) external onlyRole(GAME) { + _requireMinted(tokenId); + _metadata[tokenId].pxp = newPXP; + emit PXPChanged(tokenId, newPXP); + } + + /// @notice Receive the entropy from the VRF coordinator. + /// @dev randomWords will only have one word as entropy is requested per token. + function fulfillRandomWords(uint256 requestId, uint256[] memory randomWords) internal override { + uint256 tokenId = vrfRequests[requestId]; + + // Apply the random words + for (uint256 i = 0; i < randomWords.length; i++) { + _metadata[tokenId - i].seed = randomWords[i]; + emit SeedSet(tokenId - i, randomWords[i]); + } + } + + /// @notice IERC165 declaration. + /// @dev Supports the following `interfaceId`s: + /// - IERC165: 0x01ffc9a7 + /// - IERC721: 0x80ac58cd + /// - IERC721Metadata: 0x5b5e139f + /// - IERC2981: 0x2a55205a + function supportsInterface(bytes4 interfaceId) + public + view + virtual + override(IERC165, ERC721, ERC2981, AccessControl) + returns (bool) + { + return super.supportsInterface(interfaceId); + } + + /// Operator Filter Registry implementation + /// @dev See {IERC721-setApprovalForAll}. + function setApprovalForAll(address operator, bool approved) + public + override(ERC721, IERC721) + onlyAllowedOperatorApproval(operator) + { + super.setApprovalForAll(operator, approved); + } + + /// Operator Filter Registry implementation + /// @dev See {IERC721-approve}. + function approve(address operator, uint256 tokenId) + public + override(ERC721, IERC721) + onlyAllowedOperatorApproval(operator) + { + super.approve(operator, tokenId); + } + + /// Operator Filter Registry implementation + /// @dev See {IERC721-transferFrom}. + function transferFrom(address from, address to, uint256 tokenId) + public + override(ERC721, IERC721) + onlyAllowedOperator(from) + { + super.transferFrom(from, to, tokenId); + } + + /// Operator Filter Registry implementation + /// @dev See {IERC721-safeTransferFrom}. + function safeTransferFrom(address from, address to, uint256 tokenId) + public + override(ERC721, IERC721) + onlyAllowedOperator(from) + { + super.safeTransferFrom(from, to, tokenId); + } + + /// Operator Filter Registry implementation + /// @dev See {IERC721-safeTransferFrom}. + function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory data) + public + override(ERC721, IERC721) + onlyAllowedOperator(from) + { + super.safeTransferFrom(from, to, tokenId, data); + } + + // disable update vrf + function disableUpdateVRF() external onlyRole(DEFAULT_ADMIN_ROLE) { + canUpdateVRF = false; + } + + // enable vrf usage + function enableVRF() external onlyRole(DEFAULT_ADMIN_ROLE) { + canUseVRF = true; + } + + // update vrf + function updateVRF( + address _vrfCoordinator, + bytes32 _vrfKeyHash, + uint64 _vrfSubId, + uint16 _vrfMinimumRequestConfirmations, + uint32 _vrfCallbackGasLimit + ) external onlyRole(DEFAULT_ADMIN_ROLE) { + require(canUpdateVRF, "VRF can't be updated"); + vrfCoordinator = VRFCoordinatorV2Interface(_vrfCoordinator); + vrfKeyHash = _vrfKeyHash; + vrfSubId = _vrfSubId; + vrfMinimumRequestConfirmations = _vrfMinimumRequestConfirmations; + vrfCallbackGasLimit = _vrfCallbackGasLimit; + } + + // generate pseudo random seed + function generateRandomSeed(uint256 tokenId) public view returns (uint256) { + // Hash the combination of block timestamp, sender's address, and token ID + bytes32 hash = keccak256(abi.encodePacked(block.timestamp, msg.sender, tokenId)); + + // Convert the hash to a uint256 + uint256 randomSeed = uint256(hash); + + return randomSeed; + } +} diff --git a/flattened/PookyballAscension.sol b/flattened/PookyballAscension.sol new file mode 100644 index 00000000..e0fa467b --- /dev/null +++ b/flattened/PookyballAscension.sol @@ -0,0 +1,2407 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0 ^0.8.17 ^0.8.21 ^0.8.4; + +// lib/ERC721A/contracts\IERC721A.sol + +// ERC721A Contracts v4.2.3 +// Creator: Chiru Labs + + + +/** + * @dev Interface of ERC721A. + */ +interface IERC721A { + /** + * The caller must own the token or be an approved operator. + */ + error ApprovalCallerNotOwnerNorApproved(); + + /** + * The token does not exist. + */ + error ApprovalQueryForNonexistentToken(); + + /** + * Cannot query the balance for the zero address. + */ + error BalanceQueryForZeroAddress(); + + /** + * Cannot mint to the zero address. + */ + error MintToZeroAddress(); + + /** + * The quantity of tokens minted must be more than zero. + */ + error MintZeroQuantity(); + + /** + * The token does not exist. + */ + error OwnerQueryForNonexistentToken(); + + /** + * The caller must own the token or be an approved operator. + */ + error TransferCallerNotOwnerNorApproved(); + + /** + * The token must be owned by `from`. + */ + error TransferFromIncorrectOwner(); + + /** + * Cannot safely transfer to a contract that does not implement the + * ERC721Receiver interface. + */ + error TransferToNonERC721ReceiverImplementer(); + + /** + * Cannot transfer to the zero address. + */ + error TransferToZeroAddress(); + + /** + * The token does not exist. + */ + error URIQueryForNonexistentToken(); + + /** + * The `quantity` minted with ERC2309 exceeds the safety limit. + */ + error MintERC2309QuantityExceedsLimit(); + + /** + * The `extraData` cannot be set on an unintialized ownership slot. + */ + error OwnershipNotInitializedForExtraData(); + + // ============================================================= + // STRUCTS + // ============================================================= + + struct TokenOwnership { + // The address of the owner. + address addr; + // Stores the start time of ownership with minimal overhead for tokenomics. + uint64 startTimestamp; + // Whether the token has been burned. + bool burned; + // Arbitrary data similar to `startTimestamp` that can be set via {_extraData}. + uint24 extraData; + } + + // ============================================================= + // TOKEN COUNTERS + // ============================================================= + + /** + * @dev Returns the total number of tokens in existence. + * Burned tokens will reduce the count. + * To get the total number of tokens minted, please see {_totalMinted}. + */ + function totalSupply() external view returns (uint256); + + // ============================================================= + // 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 30000 gas. + */ + function supportsInterface(bytes4 interfaceId) external view returns (bool); + + // ============================================================= + // IERC721 + // ============================================================= + + /** + * @dev Emitted when `tokenId` token is transferred from `from` to `to`. + */ + event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); + + /** + * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token. + */ + event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); + + /** + * @dev Emitted when `owner` enables or disables + * (`approved`) `operator` to manage all of its assets. + */ + event ApprovalForAll(address indexed owner, address indexed operator, bool approved); + + /** + * @dev Returns the number of tokens in `owner`'s account. + */ + function balanceOf(address owner) external view returns (uint256 balance); + + /** + * @dev Returns the owner of the `tokenId` token. + * + * Requirements: + * + * - `tokenId` must exist. + */ + function ownerOf(uint256 tokenId) external view returns (address owner); + + /** + * @dev Safely transfers `tokenId` token from `from` to `to`, + * checking first that contract recipients are aware of the ERC721 protocol + * to prevent tokens from being forever locked. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must exist and be owned by `from`. + * - If the caller is not `from`, it must be have been allowed to move + * this token by either {approve} or {setApprovalForAll}. + * - If `to` refers to a smart contract, it must implement + * {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. + * + * Emits a {Transfer} event. + */ + function safeTransferFrom( + address from, + address to, + uint256 tokenId, + bytes calldata data + ) external payable; + + /** + * @dev Equivalent to `safeTransferFrom(from, to, tokenId, '')`. + */ + function safeTransferFrom( + address from, + address to, + uint256 tokenId + ) external payable; + + /** + * @dev Transfers `tokenId` from `from` to `to`. + * + * WARNING: Usage of this method is discouraged, use {safeTransferFrom} + * whenever possible. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must be owned by `from`. + * - If the caller is not `from`, it must be approved to move this token + * by either {approve} or {setApprovalForAll}. + * + * Emits a {Transfer} event. + */ + function transferFrom( + address from, + address to, + uint256 tokenId + ) external payable; + + /** + * @dev Gives permission to `to` to transfer `tokenId` token to another account. + * The approval is cleared when the token is transferred. + * + * Only a single account can be approved at a time, so approving the + * zero address clears previous approvals. + * + * Requirements: + * + * - The caller must own the token or be an approved operator. + * - `tokenId` must exist. + * + * Emits an {Approval} event. + */ + function approve(address to, uint256 tokenId) external payable; + + /** + * @dev Approve or remove `operator` as an operator for the caller. + * Operators can call {transferFrom} or {safeTransferFrom} + * for any token owned by the caller. + * + * Requirements: + * + * - The `operator` cannot be the caller. + * + * Emits an {ApprovalForAll} event. + */ + function setApprovalForAll(address operator, bool _approved) external; + + /** + * @dev Returns the account approved for `tokenId` token. + * + * Requirements: + * + * - `tokenId` must exist. + */ + function getApproved(uint256 tokenId) external view returns (address operator); + + /** + * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`. + * + * See {setApprovalForAll}. + */ + function isApprovedForAll(address owner, address operator) external view returns (bool); + + // ============================================================= + // IERC721Metadata + // ============================================================= + + /** + * @dev Returns the token collection name. + */ + function name() external view returns (string memory); + + /** + * @dev Returns the token collection symbol. + */ + function symbol() external view returns (string memory); + + /** + * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token. + */ + function tokenURI(uint256 tokenId) external view returns (string memory); + + // ============================================================= + // IERC2309 + // ============================================================= + + /** + * @dev Emitted when tokens in `fromTokenId` to `toTokenId` + * (inclusive) is transferred from `from` to `to`, as defined in the + * [ERC2309](https://eips.ethereum.org/EIPS/eip-2309) standard. + * + * See {_mintERC2309} for more details. + */ + event ConsecutiveTransfer(uint256 indexed fromTokenId, uint256 toTokenId, address indexed from, address indexed to); +} + +// lib/openzeppelin-contracts/contracts\access/IAccessControl.sol + +// OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol) + + + +/** + * @dev External interface of AccessControl declared to support ERC165 detection. + */ +interface IAccessControl { + /** + * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` + * + * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite + * {RoleAdminChanged} not being emitted signaling this. + * + * _Available since v3.1._ + */ + event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole); + + /** + * @dev Emitted when `account` is granted `role`. + * + * `sender` is the account that originated the contract call, an admin role + * bearer except when using {AccessControl-_setupRole}. + */ + event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender); + + /** + * @dev Emitted when `account` is revoked `role`. + * + * `sender` is the account that originated the contract call: + * - if using `revokeRole`, it is the admin role bearer + * - if using `renounceRole`, it is the role bearer (i.e. `account`) + */ + event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender); + + /** + * @dev Returns `true` if `account` has been granted `role`. + */ + function hasRole(bytes32 role, address account) external view returns (bool); + + /** + * @dev Returns the admin role that controls `role`. See {grantRole} and + * {revokeRole}. + * + * To change a role's admin, use {AccessControl-_setRoleAdmin}. + */ + function getRoleAdmin(bytes32 role) external view returns (bytes32); + + /** + * @dev Grants `role` to `account`. + * + * If `account` had not been already granted `role`, emits a {RoleGranted} + * event. + * + * Requirements: + * + * - the caller must have ``role``'s admin role. + */ + function grantRole(bytes32 role, address account) external; + + /** + * @dev Revokes `role` from `account`. + * + * If `account` had been granted `role`, emits a {RoleRevoked} event. + * + * Requirements: + * + * - the caller must have ``role``'s admin role. + */ + function revokeRole(bytes32 role, address account) external; + + /** + * @dev Revokes `role` from the calling account. + * + * Roles are often managed via {grantRole} and {revokeRole}: this function's + * purpose is to provide a mechanism for accounts to lose their privileges + * if they are compromised (such as when a trusted device is misplaced). + * + * If the calling account had been granted `role`, emits a {RoleRevoked} + * event. + * + * Requirements: + * + * - the caller must be `account`. + */ + function renounceRole(bytes32 role, address account) external; +} + +// lib/openzeppelin-contracts/contracts\token/ERC20/IERC20.sol + +// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol) + + + +/** + * @dev Interface of the ERC20 standard as defined in the EIP. + */ +interface IERC20 { + /** + * @dev Emitted when `value` tokens are moved from one account (`from`) to + * another (`to`). + * + * Note that `value` may be zero. + */ + event Transfer(address indexed from, address indexed to, uint256 value); + + /** + * @dev Emitted when the allowance of a `spender` for an `owner` is set by + * a call to {approve}. `value` is the new allowance. + */ + event Approval(address indexed owner, address indexed spender, uint256 value); + + /** + * @dev Returns the amount of tokens in existence. + */ + function totalSupply() external view returns (uint256); + + /** + * @dev Returns the amount of tokens owned by `account`. + */ + function balanceOf(address account) external view returns (uint256); + + /** + * @dev Moves `amount` tokens from the caller's account to `to`. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * Emits a {Transfer} event. + */ + function transfer(address to, uint256 amount) external returns (bool); + + /** + * @dev Returns the remaining number of tokens that `spender` will be + * allowed to spend on behalf of `owner` through {transferFrom}. This is + * zero by default. + * + * This value changes when {approve} or {transferFrom} are called. + */ + function allowance(address owner, address spender) external view returns (uint256); + + /** + * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * IMPORTANT: Beware that changing an allowance with this method brings the risk + * that someone may use both the old and the new allowance by unfortunate + * transaction ordering. One possible solution to mitigate this race + * condition is to first reduce the spender's allowance to 0 and set the + * desired value afterwards: + * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 + * + * Emits an {Approval} event. + */ + function approve(address spender, uint256 amount) external returns (bool); + + /** + * @dev Moves `amount` tokens from `from` to `to` using the + * allowance mechanism. `amount` is then deducted from the caller's + * allowance. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * Emits a {Transfer} event. + */ + function transferFrom(address from, address to, uint256 amount) external returns (bool); +} + +// lib/openzeppelin-contracts/contracts/utils/introspection/IERC165.sol + +// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol) + + + +/** + * @dev Interface of the ERC165 standard, as defined in the + * https://eips.ethereum.org/EIPS/eip-165[EIP]. + * + * Implementers can declare support of contract interfaces, which can then be + * queried by others ({ERC165Checker}). + * + * For an implementation, see {ERC165}. + */ +interface IERC165 { + /** + * @dev Returns true if this contract implements the interface defined by + * `interfaceId`. See the corresponding + * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] + * to learn more about how these ids are created. + * + * This function call must use less than 30 000 gas. + */ + function supportsInterface(bytes4 interfaceId) external view returns (bool); +} + +// lib/solady/src/auth/Ownable.sol + + + +/// @notice Simple single owner authorization mixin. +/// @author Solady (https://github.com/vectorized/solady/blob/main/src/auth/Ownable.sol) +/// @dev While the ownable portion follows +/// [EIP-173](https://eips.ethereum.org/EIPS/eip-173) for compatibility, +/// the nomenclature for the 2-step ownership handover may be unique to this codebase. +abstract contract Ownable { + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* CUSTOM ERRORS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev The caller is not authorized to call the function. + error Unauthorized(); + + /// @dev The `newOwner` cannot be the zero address. + error NewOwnerIsZeroAddress(); + + /// @dev The `pendingOwner` does not have a valid handover request. + error NoHandoverRequest(); + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* EVENTS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev The ownership is transferred from `oldOwner` to `newOwner`. + /// This event is intentionally kept the same as OpenZeppelin's Ownable to be + /// compatible with indexers and [EIP-173](https://eips.ethereum.org/EIPS/eip-173), + /// despite it not being as lightweight as a single argument event. + event OwnershipTransferred(address indexed oldOwner, address indexed newOwner); + + /// @dev An ownership handover to `pendingOwner` has been requested. + event OwnershipHandoverRequested(address indexed pendingOwner); + + /// @dev The ownership handover to `pendingOwner` has been canceled. + event OwnershipHandoverCanceled(address indexed pendingOwner); + + /// @dev `keccak256(bytes("OwnershipTransferred(address,address)"))`. + uint256 private constant _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE = + 0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0; + + /// @dev `keccak256(bytes("OwnershipHandoverRequested(address)"))`. + uint256 private constant _OWNERSHIP_HANDOVER_REQUESTED_EVENT_SIGNATURE = + 0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d; + + /// @dev `keccak256(bytes("OwnershipHandoverCanceled(address)"))`. + uint256 private constant _OWNERSHIP_HANDOVER_CANCELED_EVENT_SIGNATURE = + 0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92; + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* STORAGE */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev The owner slot is given by: `not(_OWNER_SLOT_NOT)`. + /// It is intentionally chosen to be a high value + /// to avoid collision with lower slots. + /// The choice of manual storage layout is to enable compatibility + /// with both regular and upgradeable contracts. + uint256 private constant _OWNER_SLOT_NOT = 0x8b78c6d8; + + /// The ownership handover slot of `newOwner` is given by: + /// ``` + /// mstore(0x00, or(shl(96, user), _HANDOVER_SLOT_SEED)) + /// let handoverSlot := keccak256(0x00, 0x20) + /// ``` + /// It stores the expiry timestamp of the two-step ownership handover. + uint256 private constant _HANDOVER_SLOT_SEED = 0x389a75e1; + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* INTERNAL FUNCTIONS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev Initializes the owner directly without authorization guard. + /// This function must be called upon initialization, + /// regardless of whether the contract is upgradeable or not. + /// This is to enable generalization to both regular and upgradeable contracts, + /// and to save gas in case the initial owner is not the caller. + /// For performance reasons, this function will not check if there + /// is an existing owner. + function _initializeOwner(address newOwner) internal virtual { + /// @solidity memory-safe-assembly + assembly { + // Clean the upper 96 bits. + newOwner := shr(96, shl(96, newOwner)) + // Store the new value. + sstore(not(_OWNER_SLOT_NOT), newOwner) + // Emit the {OwnershipTransferred} event. + log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, 0, newOwner) + } + } + + /// @dev Sets the owner directly without authorization guard. + function _setOwner(address newOwner) internal virtual { + /// @solidity memory-safe-assembly + assembly { + let ownerSlot := not(_OWNER_SLOT_NOT) + // Clean the upper 96 bits. + newOwner := shr(96, shl(96, newOwner)) + // Emit the {OwnershipTransferred} event. + log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, sload(ownerSlot), newOwner) + // Store the new value. + sstore(ownerSlot, newOwner) + } + } + + /// @dev Throws if the sender is not the owner. + function _checkOwner() internal view virtual { + /// @solidity memory-safe-assembly + assembly { + // If the caller is not the stored owner, revert. + if iszero(eq(caller(), sload(not(_OWNER_SLOT_NOT)))) { + mstore(0x00, 0x82b42900) // `Unauthorized()`. + revert(0x1c, 0x04) + } + } + } + + /// @dev Returns how long a two-step ownership handover is valid for in seconds. + /// Override to return a different value if needed. + /// Made internal to conserve bytecode. Wrap it in a public function if needed. + function _ownershipHandoverValidFor() internal view virtual returns (uint64) { + return 48 * 3600; + } + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* PUBLIC UPDATE FUNCTIONS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev Allows the owner to transfer the ownership to `newOwner`. + function transferOwnership(address newOwner) public payable virtual onlyOwner { + /// @solidity memory-safe-assembly + assembly { + if iszero(shl(96, newOwner)) { + mstore(0x00, 0x7448fbae) // `NewOwnerIsZeroAddress()`. + revert(0x1c, 0x04) + } + } + _setOwner(newOwner); + } + + /// @dev Allows the owner to renounce their ownership. + function renounceOwnership() public payable virtual onlyOwner { + _setOwner(address(0)); + } + + /// @dev Request a two-step ownership handover to the caller. + /// The request will automatically expire in 48 hours (172800 seconds) by default. + function requestOwnershipHandover() public payable virtual { + unchecked { + uint256 expires = block.timestamp + _ownershipHandoverValidFor(); + /// @solidity memory-safe-assembly + assembly { + // Compute and set the handover slot to `expires`. + mstore(0x0c, _HANDOVER_SLOT_SEED) + mstore(0x00, caller()) + sstore(keccak256(0x0c, 0x20), expires) + // Emit the {OwnershipHandoverRequested} event. + log2(0, 0, _OWNERSHIP_HANDOVER_REQUESTED_EVENT_SIGNATURE, caller()) + } + } + } + + /// @dev Cancels the two-step ownership handover to the caller, if any. + function cancelOwnershipHandover() public payable virtual { + /// @solidity memory-safe-assembly + assembly { + // Compute and set the handover slot to 0. + mstore(0x0c, _HANDOVER_SLOT_SEED) + mstore(0x00, caller()) + sstore(keccak256(0x0c, 0x20), 0) + // Emit the {OwnershipHandoverCanceled} event. + log2(0, 0, _OWNERSHIP_HANDOVER_CANCELED_EVENT_SIGNATURE, caller()) + } + } + + /// @dev Allows the owner to complete the two-step ownership handover to `pendingOwner`. + /// Reverts if there is no existing ownership handover requested by `pendingOwner`. + function completeOwnershipHandover(address pendingOwner) public payable virtual onlyOwner { + /// @solidity memory-safe-assembly + assembly { + // Compute and set the handover slot to 0. + mstore(0x0c, _HANDOVER_SLOT_SEED) + mstore(0x00, pendingOwner) + let handoverSlot := keccak256(0x0c, 0x20) + // If the handover does not exist, or has expired. + if gt(timestamp(), sload(handoverSlot)) { + mstore(0x00, 0x6f5e8818) // `NoHandoverRequest()`. + revert(0x1c, 0x04) + } + // Set the handover slot to 0. + sstore(handoverSlot, 0) + } + _setOwner(pendingOwner); + } + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* PUBLIC READ FUNCTIONS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev Returns the owner of the contract. + function owner() public view virtual returns (address result) { + /// @solidity memory-safe-assembly + assembly { + result := sload(not(_OWNER_SLOT_NOT)) + } + } + + /// @dev Returns the expiry timestamp for the two-step ownership handover to `pendingOwner`. + function ownershipHandoverExpiresAt(address pendingOwner) + public + view + virtual + returns (uint256 result) + { + /// @solidity memory-safe-assembly + assembly { + // Compute the handover slot. + mstore(0x0c, _HANDOVER_SLOT_SEED) + mstore(0x00, pendingOwner) + // Load the handover slot. + result := sload(keccak256(0x0c, 0x20)) + } + } + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* MODIFIERS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev Marks a function as only callable by the owner. + modifier onlyOwner() virtual { + _checkOwner(); + _; + } +} + +// lib/solady/src\utils/ECDSA.sol + + + +/// @notice Gas optimized ECDSA wrapper. +/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/ECDSA.sol) +/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/ECDSA.sol) +/// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/cryptography/ECDSA.sol) +library ECDSA { + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* CUSTOM ERRORS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev The signature is invalid. + error InvalidSignature(); + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* CONSTANTS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev The number which `s` must be less than in order for + /// the signature to be non-malleable. + bytes32 private constant _MALLEABILITY_THRESHOLD_PLUS_ONE = + 0x7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a1; + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* RECOVERY OPERATIONS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + // Note: as of Solady version 0.0.68, these functions will + // revert upon recovery failure for more safety by default. + + /// @dev Recovers the signer's address from a message digest `hash`, + /// and the `signature`. + /// + /// This function does NOT accept EIP-2098 short form signatures. + /// Use `recover(bytes32 hash, bytes32 r, bytes32 vs)` for EIP-2098 + /// short form signatures instead. + function recover(bytes32 hash, bytes memory signature) internal view returns (address result) { + /// @solidity memory-safe-assembly + assembly { + let m := mload(0x40) // Cache the free memory pointer. + mstore(0x00, hash) + mstore(0x20, byte(0, mload(add(signature, 0x60)))) // `v`. + mstore(0x40, mload(add(signature, 0x20))) // `r`. + mstore(0x60, mload(add(signature, 0x40))) // `s`. + pop( + staticcall( + gas(), // Amount of gas left for the transaction. + and( + // If the signature is exactly 65 bytes in length. + eq(mload(signature), 65), + // If `s` in lower half order, such that the signature is not malleable. + lt(mload(0x60), _MALLEABILITY_THRESHOLD_PLUS_ONE) + ), // Address of `ecrecover`. + 0x00, // Start of input. + 0x80, // Size of input. + 0x00, // Start of output. + 0x20 // Size of output. + ) + ) + result := mload(0x00) + // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise. + if iszero(returndatasize()) { + mstore(0x00, 0x8baa579f) // `InvalidSignature()`. + revert(0x1c, 0x04) + } + mstore(0x60, 0) // Restore the zero slot. + mstore(0x40, m) // Restore the free memory pointer. + } + } + + /// @dev Recovers the signer's address from a message digest `hash`, + /// and the `signature`. + /// + /// This function does NOT accept EIP-2098 short form signatures. + /// Use `recover(bytes32 hash, bytes32 r, bytes32 vs)` for EIP-2098 + /// short form signatures instead. + function recoverCalldata(bytes32 hash, bytes calldata signature) + internal + view + returns (address result) + { + /// @solidity memory-safe-assembly + assembly { + let m := mload(0x40) // Cache the free memory pointer. + mstore(0x00, hash) + mstore(0x20, byte(0, calldataload(add(signature.offset, 0x40)))) // `v`. + calldatacopy(0x40, signature.offset, 0x40) // Copy `r` and `s`. + pop( + staticcall( + gas(), // Amount of gas left for the transaction. + and( + // If the signature is exactly 65 bytes in length. + eq(signature.length, 65), + // If `s` in lower half order, such that the signature is not malleable. + lt(mload(0x60), _MALLEABILITY_THRESHOLD_PLUS_ONE) + ), // Address of `ecrecover`. + 0x00, // Start of input. + 0x80, // Size of input. + 0x00, // Start of output. + 0x20 // Size of output. + ) + ) + result := mload(0x00) + // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise. + if iszero(returndatasize()) { + mstore(0x00, 0x8baa579f) // `InvalidSignature()`. + revert(0x1c, 0x04) + } + mstore(0x60, 0) // Restore the zero slot. + mstore(0x40, m) // Restore the free memory pointer. + } + } + + /// @dev Recovers the signer's address from a message digest `hash`, + /// and the EIP-2098 short form signature defined by `r` and `vs`. + /// + /// This function only accepts EIP-2098 short form signatures. + /// See: https://eips.ethereum.org/EIPS/eip-2098 + function recover(bytes32 hash, bytes32 r, bytes32 vs) internal view returns (address result) { + /// @solidity memory-safe-assembly + assembly { + let m := mload(0x40) // Cache the free memory pointer. + mstore(0x00, hash) + mstore(0x20, add(shr(255, vs), 27)) // `v`. + mstore(0x40, r) + mstore(0x60, shr(1, shl(1, vs))) // `s`. + pop( + staticcall( + gas(), // Amount of gas left for the transaction. + // If `s` in lower half order, such that the signature is not malleable. + lt(mload(0x60), _MALLEABILITY_THRESHOLD_PLUS_ONE), // Address of `ecrecover`. + 0x00, // Start of input. + 0x80, // Size of input. + 0x00, // Start of output. + 0x20 // Size of output. + ) + ) + result := mload(0x00) + // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise. + if iszero(returndatasize()) { + mstore(0x00, 0x8baa579f) // `InvalidSignature()`. + revert(0x1c, 0x04) + } + mstore(0x60, 0) // Restore the zero slot. + mstore(0x40, m) // Restore the free memory pointer. + } + } + + /// @dev Recovers the signer's address from a message digest `hash`, + /// and the signature defined by `v`, `r`, `s`. + function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) + internal + view + returns (address result) + { + /// @solidity memory-safe-assembly + assembly { + let m := mload(0x40) // Cache the free memory pointer. + mstore(0x00, hash) + mstore(0x20, and(v, 0xff)) + mstore(0x40, r) + mstore(0x60, s) + pop( + staticcall( + gas(), // Amount of gas left for the transaction. + // If `s` in lower half order, such that the signature is not malleable. + lt(s, _MALLEABILITY_THRESHOLD_PLUS_ONE), // Address of `ecrecover`. + 0x00, // Start of input. + 0x80, // Size of input. + 0x00, // Start of output. + 0x20 // Size of output. + ) + ) + result := mload(0x00) + // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise. + if iszero(returndatasize()) { + mstore(0x00, 0x8baa579f) // `InvalidSignature()`. + revert(0x1c, 0x04) + } + mstore(0x60, 0) // Restore the zero slot. + mstore(0x40, m) // Restore the free memory pointer. + } + } + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* TRY-RECOVER OPERATIONS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + // WARNING! + // These functions will NOT revert upon recovery failure. + // Instead, they will return the zero address upon recovery failure. + // It is critical that the returned address is NEVER compared against + // a zero address (e.g. an uninitialized address variable). + + /// @dev Recovers the signer's address from a message digest `hash`, + /// and the `signature`. + /// + /// This function does NOT accept EIP-2098 short form signatures. + /// Use `recover(bytes32 hash, bytes32 r, bytes32 vs)` for EIP-2098 + /// short form signatures instead. + function tryRecover(bytes32 hash, bytes memory signature) + internal + view + returns (address result) + { + /// @solidity memory-safe-assembly + assembly { + let m := mload(0x40) // Cache the free memory pointer. + mstore(0x00, hash) + mstore(0x20, byte(0, mload(add(signature, 0x60)))) // `v`. + mstore(0x40, mload(add(signature, 0x20))) // `r`. + mstore(0x60, mload(add(signature, 0x40))) // `s`. + pop( + staticcall( + gas(), // Amount of gas left for the transaction. + and( + // If the signature is exactly 65 bytes in length. + eq(mload(signature), 65), + // If `s` in lower half order, such that the signature is not malleable. + lt(mload(0x60), _MALLEABILITY_THRESHOLD_PLUS_ONE) + ), // Address of `ecrecover`. + 0x00, // Start of input. + 0x80, // Size of input. + 0x40, // Start of output. + 0x20 // Size of output. + ) + ) + mstore(0x60, 0) // Restore the zero slot. + // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise. + result := mload(xor(0x60, returndatasize())) + mstore(0x40, m) // Restore the free memory pointer. + } + } + + /// @dev Recovers the signer's address from a message digest `hash`, + /// and the `signature`. + /// + /// This function does NOT accept EIP-2098 short form signatures. + /// Use `recover(bytes32 hash, bytes32 r, bytes32 vs)` for EIP-2098 + /// short form signatures instead. + function tryRecoverCalldata(bytes32 hash, bytes calldata signature) + internal + view + returns (address result) + { + /// @solidity memory-safe-assembly + assembly { + let m := mload(0x40) // Cache the free memory pointer. + mstore(0x00, hash) + mstore(0x20, byte(0, calldataload(add(signature.offset, 0x40)))) // `v`. + calldatacopy(0x40, signature.offset, 0x40) // Copy `r` and `s`. + pop( + staticcall( + gas(), // Amount of gas left for the transaction. + and( + // If the signature is exactly 65 bytes in length. + eq(signature.length, 65), + // If `s` in lower half order, such that the signature is not malleable. + lt(mload(0x60), _MALLEABILITY_THRESHOLD_PLUS_ONE) + ), // Address of `ecrecover`. + 0x00, // Start of input. + 0x80, // Size of input. + 0x40, // Start of output. + 0x20 // Size of output. + ) + ) + mstore(0x60, 0) // Restore the zero slot. + // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise. + result := mload(xor(0x60, returndatasize())) + mstore(0x40, m) // Restore the free memory pointer. + } + } + + /// @dev Recovers the signer's address from a message digest `hash`, + /// and the EIP-2098 short form signature defined by `r` and `vs`. + /// + /// This function only accepts EIP-2098 short form signatures. + /// See: https://eips.ethereum.org/EIPS/eip-2098 + function tryRecover(bytes32 hash, bytes32 r, bytes32 vs) + internal + view + returns (address result) + { + /// @solidity memory-safe-assembly + assembly { + let m := mload(0x40) // Cache the free memory pointer. + mstore(0x00, hash) + mstore(0x20, add(shr(255, vs), 27)) // `v`. + mstore(0x40, r) + mstore(0x60, shr(1, shl(1, vs))) // `s`. + pop( + staticcall( + gas(), // Amount of gas left for the transaction. + // If `s` in lower half order, such that the signature is not malleable. + lt(mload(0x60), _MALLEABILITY_THRESHOLD_PLUS_ONE), // Address of `ecrecover`. + 0x00, // Start of input. + 0x80, // Size of input. + 0x40, // Start of output. + 0x20 // Size of output. + ) + ) + mstore(0x60, 0) // Restore the zero slot. + // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise. + result := mload(xor(0x60, returndatasize())) + mstore(0x40, m) // Restore the free memory pointer. + } + } + + /// @dev Recovers the signer's address from a message digest `hash`, + /// and the signature defined by `v`, `r`, `s`. + function tryRecover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) + internal + view + returns (address result) + { + /// @solidity memory-safe-assembly + assembly { + let m := mload(0x40) // Cache the free memory pointer. + mstore(0x00, hash) + mstore(0x20, and(v, 0xff)) + mstore(0x40, r) + mstore(0x60, s) + pop( + staticcall( + gas(), // Amount of gas left for the transaction. + // If `s` in lower half order, such that the signature is not malleable. + lt(s, _MALLEABILITY_THRESHOLD_PLUS_ONE), // Address of `ecrecover`. + 0x00, // Start of input. + 0x80, // Size of input. + 0x40, // Start of output. + 0x20 // Size of output. + ) + ) + mstore(0x60, 0) // Restore the zero slot. + // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise. + result := mload(xor(0x60, returndatasize())) + mstore(0x40, m) // Restore the free memory pointer. + } + } + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* HASHING OPERATIONS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev Returns an Ethereum Signed Message, created from a `hash`. + /// This produces a hash corresponding to the one signed with the + /// [`eth_sign`](https://eth.wiki/json-rpc/API#eth_sign) + /// JSON-RPC method as part of EIP-191. + function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32 result) { + /// @solidity memory-safe-assembly + assembly { + mstore(0x20, hash) // Store into scratch space for keccak256. + mstore(0x00, "\x00\x00\x00\x00\x19Ethereum Signed Message:\n32") // 28 bytes. + result := keccak256(0x04, 0x3c) // `32 * 2 - (32 - 28) = 60 = 0x3c`. + } + } + + /// @dev Returns an Ethereum Signed Message, created from `s`. + /// This produces a hash corresponding to the one signed with the + /// [`eth_sign`](https://eth.wiki/json-rpc/API#eth_sign) + /// JSON-RPC method as part of EIP-191. + /// Note: Supports lengths of `s` up to 999999 bytes. + function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32 result) { + /// @solidity memory-safe-assembly + assembly { + let sLength := mload(s) + let o := 0x20 + mstore(o, "\x19Ethereum Signed Message:\n") // 26 bytes, zero-right-padded. + mstore(0x00, 0x00) + // Convert the `s.length` to ASCII decimal representation: `base10(s.length)`. + for { let temp := sLength } 1 {} { + o := sub(o, 1) + mstore8(o, add(48, mod(temp, 10))) + temp := div(temp, 10) + if iszero(temp) { break } + } + let n := sub(0x3a, o) // Header length: `26 + 32 - o`. + // Throw an out-of-offset error (consumes all gas) if the header exceeds 32 bytes. + returndatacopy(returndatasize(), returndatasize(), gt(n, 0x20)) + mstore(s, or(mload(0x00), mload(n))) // Temporarily store the header. + result := keccak256(add(s, sub(0x20, n)), add(n, sLength)) + mstore(s, sLength) // Restore the length. + } + } + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* EMPTY CALLDATA HELPERS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev Returns an empty calldata bytes. + function emptySignature() internal pure returns (bytes calldata signature) { + /// @solidity memory-safe-assembly + assembly { + signature.length := 0 + } + } +} + +// src\common/ITreasury.sol + + + +/// @title ITreasury +/// @author Mathieu Bour for Pooky Labs Ltd. +interface ITreasury { + /// Thrown when the msg.value of the mint function does not cover the mint cost. + error InsufficientValue(uint256 expected, uint256 actual); + /// Thrown when the native transfer has failed. + error TransferFailed(address recipient, uint256 amount); + + /// Change the native currency destination address. + /// @param _treasury The new treasury address. + function changeTreasury(address _treasury) external; +} + +// lib/ERC721A/contracts\extensions/IERC721ABurnable.sol + +// ERC721A Contracts v4.2.3 +// Creator: Chiru Labs + + + + + +/** + * @dev Interface of ERC721ABurnable. + */ +interface IERC721ABurnable is IERC721A { + /** + * @dev Burns `tokenId`. See {ERC721A-_burn}. + * + * Requirements: + * + * - The caller must own `tokenId` or be an approved operator. + */ + function burn(uint256 tokenId) external; +} + +// lib/ERC721A/contracts\extensions/IERC721AQueryable.sol + +// ERC721A Contracts v4.2.3 +// Creator: Chiru Labs + + + + + +/** + * @dev Interface of ERC721AQueryable. + */ +interface IERC721AQueryable is IERC721A { + /** + * Invalid query range (`start` >= `stop`). + */ + error InvalidQueryRange(); + + /** + * @dev Returns the `TokenOwnership` struct at `tokenId` without reverting. + * + * If the `tokenId` is out of bounds: + * + * - `addr = address(0)` + * - `startTimestamp = 0` + * - `burned = false` + * - `extraData = 0` + * + * If the `tokenId` is burned: + * + * - `addr =
` + * - `startTimestamp = ` + * - `burned = true` + * - `extraData = ` + * + * Otherwise: + * + * - `addr =
` + * - `startTimestamp = ` + * - `burned = false` + * - `extraData = ` + */ + function explicitOwnershipOf(uint256 tokenId) external view returns (TokenOwnership memory); + + /** + * @dev Returns an array of `TokenOwnership` structs at `tokenIds` in order. + * See {ERC721AQueryable-explicitOwnershipOf} + */ + function explicitOwnershipsOf(uint256[] memory tokenIds) external view returns (TokenOwnership[] memory); + + /** + * @dev Returns an array of token IDs owned by `owner`, + * in the range [`start`, `stop`) + * (i.e. `start <= tokenId < stop`). + * + * This function allows for tokens to be queried if the collection + * grows too big for a single call of {ERC721AQueryable-tokensOfOwner}. + * + * Requirements: + * + * - `start < stop` + */ + function tokensOfOwnerIn( + address owner, + uint256 start, + uint256 stop + ) external view returns (uint256[] memory); + + /** + * @dev Returns an array of token IDs owned by `owner`. + * + * This function scans the ownership mapping and is O(`totalSupply`) in complexity. + * It is meant to be called off-chain. + * + * See {ERC721AQueryable-tokensOfOwnerIn} for splitting the scan into + * multiple smaller scans if the collection is large enough to cause + * an out-of-gas error (10K collections should be fine). + */ + function tokensOfOwner(address owner) external view returns (uint256[] memory); +} + +// lib/openzeppelin-contracts/contracts\interfaces/IERC165.sol + +// OpenZeppelin Contracts v4.4.1 (interfaces/IERC165.sol) + + + + + +// lib/openzeppelin-contracts/contracts\interfaces/IERC2981.sol + +// OpenZeppelin Contracts (last updated v4.9.0) (interfaces/IERC2981.sol) + + + + + +/** + * @dev Interface for the NFT Royalty Standard. + * + * A standardized way to retrieve royalty payment information for non-fungible tokens (NFTs) to enable universal + * support for royalty payments across all NFT marketplaces and ecosystem participants. + * + * _Available since v4.5._ + */ +interface IERC2981 is IERC165 { + /** + * @dev Returns how much royalty is owed and to whom, based on a sale price that may be denominated in any unit of + * exchange. The royalty amount is denominated and should be paid in that same unit of exchange. + */ + function royaltyInfo( + uint256 tokenId, + uint256 salePrice + ) external view returns (address receiver, uint256 royaltyAmount); +} + +// lib/openzeppelin-contracts/contracts\token/ERC721/IERC721.sol + +// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC721/IERC721.sol) + + + + + +/** + * @dev Required interface of an ERC721 compliant contract. + */ +interface IERC721 is IERC165 { + /** + * @dev Emitted when `tokenId` token is transferred from `from` to `to`. + */ + event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); + + /** + * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token. + */ + event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); + + /** + * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets. + */ + event ApprovalForAll(address indexed owner, address indexed operator, bool approved); + + /** + * @dev Returns the number of tokens in ``owner``'s account. + */ + function balanceOf(address owner) external view returns (uint256 balance); + + /** + * @dev Returns the owner of the `tokenId` token. + * + * Requirements: + * + * - `tokenId` must exist. + */ + function ownerOf(uint256 tokenId) external view returns (address owner); + + /** + * @dev Safely transfers `tokenId` token from `from` to `to`. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must exist and be owned by `from`. + * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. + * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. + * + * Emits a {Transfer} event. + */ + function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external; + + /** + * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients + * are aware of the ERC721 protocol to prevent tokens from being forever locked. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must exist and be owned by `from`. + * - If the caller is not `from`, it must have been allowed to move this token by either {approve} or {setApprovalForAll}. + * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. + * + * Emits a {Transfer} event. + */ + function safeTransferFrom(address from, address to, uint256 tokenId) external; + + /** + * @dev Transfers `tokenId` token from `from` to `to`. + * + * WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721 + * or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must + * understand this adds an external call which potentially creates a reentrancy vulnerability. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must be owned by `from`. + * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. + * + * Emits a {Transfer} event. + */ + function transferFrom(address from, address to, uint256 tokenId) external; + + /** + * @dev Gives permission to `to` to transfer `tokenId` token to another account. + * The approval is cleared when the token is transferred. + * + * Only a single account can be approved at a time, so approving the zero address clears previous approvals. + * + * Requirements: + * + * - The caller must own the token or be an approved operator. + * - `tokenId` must exist. + * + * Emits an {Approval} event. + */ + function approve(address to, uint256 tokenId) external; + + /** + * @dev Approve or remove `operator` as an operator for the caller. + * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller. + * + * Requirements: + * + * - The `operator` cannot be the caller. + * + * Emits an {ApprovalForAll} event. + */ + function setApprovalForAll(address operator, bool approved) external; + + /** + * @dev Returns the account approved for `tokenId` token. + * + * Requirements: + * + * - `tokenId` must exist. + */ + function getApproved(uint256 tokenId) external view returns (address operator); + + /** + * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`. + * + * See {setApprovalForAll} + */ + function isApprovedForAll(address owner, address operator) external view returns (bool); +} + +// lib/solady/src\auth/OwnableRoles.sol + + + + + +/// @notice Simple single owner and multiroles authorization mixin. +/// @author Solady (https://github.com/vectorized/solady/blob/main/src/auth/Ownable.sol) +/// @dev While the ownable portion follows [EIP-173](https://eips.ethereum.org/EIPS/eip-173) +/// for compatibility, the nomenclature for the 2-step ownership handover and roles +/// may be unique to this codebase. +abstract contract OwnableRoles is Ownable { + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* EVENTS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev The `user`'s roles is updated to `roles`. + /// Each bit of `roles` represents whether the role is set. + event RolesUpdated(address indexed user, uint256 indexed roles); + + /// @dev `keccak256(bytes("RolesUpdated(address,uint256)"))`. + uint256 private constant _ROLES_UPDATED_EVENT_SIGNATURE = + 0x715ad5ce61fc9595c7b415289d59cf203f23a94fa06f04af7e489a0a76e1fe26; + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* STORAGE */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev The role slot of `user` is given by: + /// ``` + /// mstore(0x00, or(shl(96, user), _ROLE_SLOT_SEED)) + /// let roleSlot := keccak256(0x00, 0x20) + /// ``` + /// This automatically ignores the upper bits of the `user` in case + /// they are not clean, as well as keep the `keccak256` under 32-bytes. + /// + /// Note: This is equal to `_OWNER_SLOT_NOT` in for gas efficiency. + uint256 private constant _ROLE_SLOT_SEED = 0x8b78c6d8; + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* INTERNAL FUNCTIONS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev Overwrite the roles directly without authorization guard. + function _setRoles(address user, uint256 roles) internal virtual { + /// @solidity memory-safe-assembly + assembly { + mstore(0x0c, _ROLE_SLOT_SEED) + mstore(0x00, user) + // Store the new value. + sstore(keccak256(0x0c, 0x20), roles) + // Emit the {RolesUpdated} event. + log3(0, 0, _ROLES_UPDATED_EVENT_SIGNATURE, shr(96, mload(0x0c)), roles) + } + } + + /// @dev Updates the roles directly without authorization guard. + /// If `on` is true, each set bit of `roles` will be turned on, + /// otherwise, each set bit of `roles` will be turned off. + function _updateRoles(address user, uint256 roles, bool on) internal virtual { + /// @solidity memory-safe-assembly + assembly { + mstore(0x0c, _ROLE_SLOT_SEED) + mstore(0x00, user) + let roleSlot := keccak256(0x0c, 0x20) + // Load the current value. + let current := sload(roleSlot) + // Compute the updated roles if `on` is true. + let updated := or(current, roles) + // Compute the updated roles if `on` is false. + // Use `and` to compute the intersection of `current` and `roles`, + // `xor` it with `current` to flip the bits in the intersection. + if iszero(on) { updated := xor(current, and(current, roles)) } + // Then, store the new value. + sstore(roleSlot, updated) + // Emit the {RolesUpdated} event. + log3(0, 0, _ROLES_UPDATED_EVENT_SIGNATURE, shr(96, mload(0x0c)), updated) + } + } + + /// @dev Grants the roles directly without authorization guard. + /// Each bit of `roles` represents the role to turn on. + function _grantRoles(address user, uint256 roles) internal virtual { + _updateRoles(user, roles, true); + } + + /// @dev Removes the roles directly without authorization guard. + /// Each bit of `roles` represents the role to turn off. + function _removeRoles(address user, uint256 roles) internal virtual { + _updateRoles(user, roles, false); + } + + /// @dev Throws if the sender does not have any of the `roles`. + function _checkRoles(uint256 roles) internal view virtual { + /// @solidity memory-safe-assembly + assembly { + // Compute the role slot. + mstore(0x0c, _ROLE_SLOT_SEED) + mstore(0x00, caller()) + // Load the stored value, and if the `and` intersection + // of the value and `roles` is zero, revert. + if iszero(and(sload(keccak256(0x0c, 0x20)), roles)) { + mstore(0x00, 0x82b42900) // `Unauthorized()`. + revert(0x1c, 0x04) + } + } + } + + /// @dev Throws if the sender is not the owner, + /// and does not have any of the `roles`. + /// Checks for ownership first, then lazily checks for roles. + function _checkOwnerOrRoles(uint256 roles) internal view virtual { + /// @solidity memory-safe-assembly + assembly { + // If the caller is not the stored owner. + // Note: `_ROLE_SLOT_SEED` is equal to `_OWNER_SLOT_NOT`. + if iszero(eq(caller(), sload(not(_ROLE_SLOT_SEED)))) { + // Compute the role slot. + mstore(0x0c, _ROLE_SLOT_SEED) + mstore(0x00, caller()) + // Load the stored value, and if the `and` intersection + // of the value and `roles` is zero, revert. + if iszero(and(sload(keccak256(0x0c, 0x20)), roles)) { + mstore(0x00, 0x82b42900) // `Unauthorized()`. + revert(0x1c, 0x04) + } + } + } + } + + /// @dev Throws if the sender does not have any of the `roles`, + /// and is not the owner. + /// Checks for roles first, then lazily checks for ownership. + function _checkRolesOrOwner(uint256 roles) internal view virtual { + /// @solidity memory-safe-assembly + assembly { + // Compute the role slot. + mstore(0x0c, _ROLE_SLOT_SEED) + mstore(0x00, caller()) + // Load the stored value, and if the `and` intersection + // of the value and `roles` is zero, revert. + if iszero(and(sload(keccak256(0x0c, 0x20)), roles)) { + // If the caller is not the stored owner. + // Note: `_ROLE_SLOT_SEED` is equal to `_OWNER_SLOT_NOT`. + if iszero(eq(caller(), sload(not(_ROLE_SLOT_SEED)))) { + mstore(0x00, 0x82b42900) // `Unauthorized()`. + revert(0x1c, 0x04) + } + } + } + } + + /// @dev Convenience function to return a `roles` bitmap from an array of `ordinals`. + /// This is meant for frontends like Etherscan, and is therefore not fully optimized. + /// Not recommended to be called on-chain. + /// Made internal to conserve bytecode. Wrap it in a public function if needed. + function _rolesFromOrdinals(uint8[] memory ordinals) internal pure returns (uint256 roles) { + /// @solidity memory-safe-assembly + assembly { + for { let i := shl(5, mload(ordinals)) } i { i := sub(i, 0x20) } { + // We don't need to mask the values of `ordinals`, as Solidity + // cleans dirty upper bits when storing variables into memory. + roles := or(shl(mload(add(ordinals, i)), 1), roles) + } + } + } + + /// @dev Convenience function to return an array of `ordinals` from the `roles` bitmap. + /// This is meant for frontends like Etherscan, and is therefore not fully optimized. + /// Not recommended to be called on-chain. + /// Made internal to conserve bytecode. Wrap it in a public function if needed. + function _ordinalsFromRoles(uint256 roles) internal pure returns (uint8[] memory ordinals) { + /// @solidity memory-safe-assembly + assembly { + // Grab the pointer to the free memory. + ordinals := mload(0x40) + let ptr := add(ordinals, 0x20) + let o := 0 + // The absence of lookup tables, De Bruijn, etc., here is intentional for + // smaller bytecode, as this function is not meant to be called on-chain. + for { let t := roles } 1 {} { + mstore(ptr, o) + // `shr` 5 is equivalent to multiplying by 0x20. + // Push back into the ordinals array if the bit is set. + ptr := add(ptr, shl(5, and(t, 1))) + o := add(o, 1) + t := shr(o, roles) + if iszero(t) { break } + } + // Store the length of `ordinals`. + mstore(ordinals, shr(5, sub(ptr, add(ordinals, 0x20)))) + // Allocate the memory. + mstore(0x40, ptr) + } + } + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* PUBLIC UPDATE FUNCTIONS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev Allows the owner to grant `user` `roles`. + /// If the `user` already has a role, then it will be an no-op for the role. + function grantRoles(address user, uint256 roles) public payable virtual onlyOwner { + _grantRoles(user, roles); + } + + /// @dev Allows the owner to remove `user` `roles`. + /// If the `user` does not have a role, then it will be an no-op for the role. + function revokeRoles(address user, uint256 roles) public payable virtual onlyOwner { + _removeRoles(user, roles); + } + + /// @dev Allow the caller to remove their own roles. + /// If the caller does not have a role, then it will be an no-op for the role. + function renounceRoles(uint256 roles) public payable virtual { + _removeRoles(msg.sender, roles); + } + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* PUBLIC READ FUNCTIONS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev Returns the roles of `user`. + function rolesOf(address user) public view virtual returns (uint256 roles) { + /// @solidity memory-safe-assembly + assembly { + // Compute the role slot. + mstore(0x0c, _ROLE_SLOT_SEED) + mstore(0x00, user) + // Load the stored value. + roles := sload(keccak256(0x0c, 0x20)) + } + } + + /// @dev Returns whether `user` has any of `roles`. + function hasAnyRole(address user, uint256 roles) public view virtual returns (bool) { + return rolesOf(user) & roles != 0; + } + + /// @dev Returns whether `user` has all of `roles`. + function hasAllRoles(address user, uint256 roles) public view virtual returns (bool) { + return rolesOf(user) & roles == roles; + } + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* MODIFIERS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev Marks a function as only callable by an account with `roles`. + modifier onlyRoles(uint256 roles) virtual { + _checkRoles(roles); + _; + } + + /// @dev Marks a function as only callable by the owner or by an account + /// with `roles`. Checks for ownership first, then lazily checks for roles. + modifier onlyOwnerOrRoles(uint256 roles) virtual { + _checkOwnerOrRoles(roles); + _; + } + + /// @dev Marks a function as only callable by an account with `roles` + /// or the owner. Checks for roles first, then lazily checks for ownership. + modifier onlyRolesOrOwner(uint256 roles) virtual { + _checkRolesOrOwner(roles); + _; + } + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* ROLE CONSTANTS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + // IYKYK + + uint256 internal constant _ROLE_0 = 1 << 0; + uint256 internal constant _ROLE_1 = 1 << 1; + uint256 internal constant _ROLE_2 = 1 << 2; + uint256 internal constant _ROLE_3 = 1 << 3; + uint256 internal constant _ROLE_4 = 1 << 4; + uint256 internal constant _ROLE_5 = 1 << 5; + uint256 internal constant _ROLE_6 = 1 << 6; + uint256 internal constant _ROLE_7 = 1 << 7; + uint256 internal constant _ROLE_8 = 1 << 8; + uint256 internal constant _ROLE_9 = 1 << 9; + uint256 internal constant _ROLE_10 = 1 << 10; + uint256 internal constant _ROLE_11 = 1 << 11; + uint256 internal constant _ROLE_12 = 1 << 12; + uint256 internal constant _ROLE_13 = 1 << 13; + uint256 internal constant _ROLE_14 = 1 << 14; + uint256 internal constant _ROLE_15 = 1 << 15; + uint256 internal constant _ROLE_16 = 1 << 16; + uint256 internal constant _ROLE_17 = 1 << 17; + uint256 internal constant _ROLE_18 = 1 << 18; + uint256 internal constant _ROLE_19 = 1 << 19; + uint256 internal constant _ROLE_20 = 1 << 20; + uint256 internal constant _ROLE_21 = 1 << 21; + uint256 internal constant _ROLE_22 = 1 << 22; + uint256 internal constant _ROLE_23 = 1 << 23; + uint256 internal constant _ROLE_24 = 1 << 24; + uint256 internal constant _ROLE_25 = 1 << 25; + uint256 internal constant _ROLE_26 = 1 << 26; + uint256 internal constant _ROLE_27 = 1 << 27; + uint256 internal constant _ROLE_28 = 1 << 28; + uint256 internal constant _ROLE_29 = 1 << 29; + uint256 internal constant _ROLE_30 = 1 << 30; + uint256 internal constant _ROLE_31 = 1 << 31; + uint256 internal constant _ROLE_32 = 1 << 32; + uint256 internal constant _ROLE_33 = 1 << 33; + uint256 internal constant _ROLE_34 = 1 << 34; + uint256 internal constant _ROLE_35 = 1 << 35; + uint256 internal constant _ROLE_36 = 1 << 36; + uint256 internal constant _ROLE_37 = 1 << 37; + uint256 internal constant _ROLE_38 = 1 << 38; + uint256 internal constant _ROLE_39 = 1 << 39; + uint256 internal constant _ROLE_40 = 1 << 40; + uint256 internal constant _ROLE_41 = 1 << 41; + uint256 internal constant _ROLE_42 = 1 << 42; + uint256 internal constant _ROLE_43 = 1 << 43; + uint256 internal constant _ROLE_44 = 1 << 44; + uint256 internal constant _ROLE_45 = 1 << 45; + uint256 internal constant _ROLE_46 = 1 << 46; + uint256 internal constant _ROLE_47 = 1 << 47; + uint256 internal constant _ROLE_48 = 1 << 48; + uint256 internal constant _ROLE_49 = 1 << 49; + uint256 internal constant _ROLE_50 = 1 << 50; + uint256 internal constant _ROLE_51 = 1 << 51; + uint256 internal constant _ROLE_52 = 1 << 52; + uint256 internal constant _ROLE_53 = 1 << 53; + uint256 internal constant _ROLE_54 = 1 << 54; + uint256 internal constant _ROLE_55 = 1 << 55; + uint256 internal constant _ROLE_56 = 1 << 56; + uint256 internal constant _ROLE_57 = 1 << 57; + uint256 internal constant _ROLE_58 = 1 << 58; + uint256 internal constant _ROLE_59 = 1 << 59; + uint256 internal constant _ROLE_60 = 1 << 60; + uint256 internal constant _ROLE_61 = 1 << 61; + uint256 internal constant _ROLE_62 = 1 << 62; + uint256 internal constant _ROLE_63 = 1 << 63; + uint256 internal constant _ROLE_64 = 1 << 64; + uint256 internal constant _ROLE_65 = 1 << 65; + uint256 internal constant _ROLE_66 = 1 << 66; + uint256 internal constant _ROLE_67 = 1 << 67; + uint256 internal constant _ROLE_68 = 1 << 68; + uint256 internal constant _ROLE_69 = 1 << 69; + uint256 internal constant _ROLE_70 = 1 << 70; + uint256 internal constant _ROLE_71 = 1 << 71; + uint256 internal constant _ROLE_72 = 1 << 72; + uint256 internal constant _ROLE_73 = 1 << 73; + uint256 internal constant _ROLE_74 = 1 << 74; + uint256 internal constant _ROLE_75 = 1 << 75; + uint256 internal constant _ROLE_76 = 1 << 76; + uint256 internal constant _ROLE_77 = 1 << 77; + uint256 internal constant _ROLE_78 = 1 << 78; + uint256 internal constant _ROLE_79 = 1 << 79; + uint256 internal constant _ROLE_80 = 1 << 80; + uint256 internal constant _ROLE_81 = 1 << 81; + uint256 internal constant _ROLE_82 = 1 << 82; + uint256 internal constant _ROLE_83 = 1 << 83; + uint256 internal constant _ROLE_84 = 1 << 84; + uint256 internal constant _ROLE_85 = 1 << 85; + uint256 internal constant _ROLE_86 = 1 << 86; + uint256 internal constant _ROLE_87 = 1 << 87; + uint256 internal constant _ROLE_88 = 1 << 88; + uint256 internal constant _ROLE_89 = 1 << 89; + uint256 internal constant _ROLE_90 = 1 << 90; + uint256 internal constant _ROLE_91 = 1 << 91; + uint256 internal constant _ROLE_92 = 1 << 92; + uint256 internal constant _ROLE_93 = 1 << 93; + uint256 internal constant _ROLE_94 = 1 << 94; + uint256 internal constant _ROLE_95 = 1 << 95; + uint256 internal constant _ROLE_96 = 1 << 96; + uint256 internal constant _ROLE_97 = 1 << 97; + uint256 internal constant _ROLE_98 = 1 << 98; + uint256 internal constant _ROLE_99 = 1 << 99; + uint256 internal constant _ROLE_100 = 1 << 100; + uint256 internal constant _ROLE_101 = 1 << 101; + uint256 internal constant _ROLE_102 = 1 << 102; + uint256 internal constant _ROLE_103 = 1 << 103; + uint256 internal constant _ROLE_104 = 1 << 104; + uint256 internal constant _ROLE_105 = 1 << 105; + uint256 internal constant _ROLE_106 = 1 << 106; + uint256 internal constant _ROLE_107 = 1 << 107; + uint256 internal constant _ROLE_108 = 1 << 108; + uint256 internal constant _ROLE_109 = 1 << 109; + uint256 internal constant _ROLE_110 = 1 << 110; + uint256 internal constant _ROLE_111 = 1 << 111; + uint256 internal constant _ROLE_112 = 1 << 112; + uint256 internal constant _ROLE_113 = 1 << 113; + uint256 internal constant _ROLE_114 = 1 << 114; + uint256 internal constant _ROLE_115 = 1 << 115; + uint256 internal constant _ROLE_116 = 1 << 116; + uint256 internal constant _ROLE_117 = 1 << 117; + uint256 internal constant _ROLE_118 = 1 << 118; + uint256 internal constant _ROLE_119 = 1 << 119; + uint256 internal constant _ROLE_120 = 1 << 120; + uint256 internal constant _ROLE_121 = 1 << 121; + uint256 internal constant _ROLE_122 = 1 << 122; + uint256 internal constant _ROLE_123 = 1 << 123; + uint256 internal constant _ROLE_124 = 1 << 124; + uint256 internal constant _ROLE_125 = 1 << 125; + uint256 internal constant _ROLE_126 = 1 << 126; + uint256 internal constant _ROLE_127 = 1 << 127; + uint256 internal constant _ROLE_128 = 1 << 128; + uint256 internal constant _ROLE_129 = 1 << 129; + uint256 internal constant _ROLE_130 = 1 << 130; + uint256 internal constant _ROLE_131 = 1 << 131; + uint256 internal constant _ROLE_132 = 1 << 132; + uint256 internal constant _ROLE_133 = 1 << 133; + uint256 internal constant _ROLE_134 = 1 << 134; + uint256 internal constant _ROLE_135 = 1 << 135; + uint256 internal constant _ROLE_136 = 1 << 136; + uint256 internal constant _ROLE_137 = 1 << 137; + uint256 internal constant _ROLE_138 = 1 << 138; + uint256 internal constant _ROLE_139 = 1 << 139; + uint256 internal constant _ROLE_140 = 1 << 140; + uint256 internal constant _ROLE_141 = 1 << 141; + uint256 internal constant _ROLE_142 = 1 << 142; + uint256 internal constant _ROLE_143 = 1 << 143; + uint256 internal constant _ROLE_144 = 1 << 144; + uint256 internal constant _ROLE_145 = 1 << 145; + uint256 internal constant _ROLE_146 = 1 << 146; + uint256 internal constant _ROLE_147 = 1 << 147; + uint256 internal constant _ROLE_148 = 1 << 148; + uint256 internal constant _ROLE_149 = 1 << 149; + uint256 internal constant _ROLE_150 = 1 << 150; + uint256 internal constant _ROLE_151 = 1 << 151; + uint256 internal constant _ROLE_152 = 1 << 152; + uint256 internal constant _ROLE_153 = 1 << 153; + uint256 internal constant _ROLE_154 = 1 << 154; + uint256 internal constant _ROLE_155 = 1 << 155; + uint256 internal constant _ROLE_156 = 1 << 156; + uint256 internal constant _ROLE_157 = 1 << 157; + uint256 internal constant _ROLE_158 = 1 << 158; + uint256 internal constant _ROLE_159 = 1 << 159; + uint256 internal constant _ROLE_160 = 1 << 160; + uint256 internal constant _ROLE_161 = 1 << 161; + uint256 internal constant _ROLE_162 = 1 << 162; + uint256 internal constant _ROLE_163 = 1 << 163; + uint256 internal constant _ROLE_164 = 1 << 164; + uint256 internal constant _ROLE_165 = 1 << 165; + uint256 internal constant _ROLE_166 = 1 << 166; + uint256 internal constant _ROLE_167 = 1 << 167; + uint256 internal constant _ROLE_168 = 1 << 168; + uint256 internal constant _ROLE_169 = 1 << 169; + uint256 internal constant _ROLE_170 = 1 << 170; + uint256 internal constant _ROLE_171 = 1 << 171; + uint256 internal constant _ROLE_172 = 1 << 172; + uint256 internal constant _ROLE_173 = 1 << 173; + uint256 internal constant _ROLE_174 = 1 << 174; + uint256 internal constant _ROLE_175 = 1 << 175; + uint256 internal constant _ROLE_176 = 1 << 176; + uint256 internal constant _ROLE_177 = 1 << 177; + uint256 internal constant _ROLE_178 = 1 << 178; + uint256 internal constant _ROLE_179 = 1 << 179; + uint256 internal constant _ROLE_180 = 1 << 180; + uint256 internal constant _ROLE_181 = 1 << 181; + uint256 internal constant _ROLE_182 = 1 << 182; + uint256 internal constant _ROLE_183 = 1 << 183; + uint256 internal constant _ROLE_184 = 1 << 184; + uint256 internal constant _ROLE_185 = 1 << 185; + uint256 internal constant _ROLE_186 = 1 << 186; + uint256 internal constant _ROLE_187 = 1 << 187; + uint256 internal constant _ROLE_188 = 1 << 188; + uint256 internal constant _ROLE_189 = 1 << 189; + uint256 internal constant _ROLE_190 = 1 << 190; + uint256 internal constant _ROLE_191 = 1 << 191; + uint256 internal constant _ROLE_192 = 1 << 192; + uint256 internal constant _ROLE_193 = 1 << 193; + uint256 internal constant _ROLE_194 = 1 << 194; + uint256 internal constant _ROLE_195 = 1 << 195; + uint256 internal constant _ROLE_196 = 1 << 196; + uint256 internal constant _ROLE_197 = 1 << 197; + uint256 internal constant _ROLE_198 = 1 << 198; + uint256 internal constant _ROLE_199 = 1 << 199; + uint256 internal constant _ROLE_200 = 1 << 200; + uint256 internal constant _ROLE_201 = 1 << 201; + uint256 internal constant _ROLE_202 = 1 << 202; + uint256 internal constant _ROLE_203 = 1 << 203; + uint256 internal constant _ROLE_204 = 1 << 204; + uint256 internal constant _ROLE_205 = 1 << 205; + uint256 internal constant _ROLE_206 = 1 << 206; + uint256 internal constant _ROLE_207 = 1 << 207; + uint256 internal constant _ROLE_208 = 1 << 208; + uint256 internal constant _ROLE_209 = 1 << 209; + uint256 internal constant _ROLE_210 = 1 << 210; + uint256 internal constant _ROLE_211 = 1 << 211; + uint256 internal constant _ROLE_212 = 1 << 212; + uint256 internal constant _ROLE_213 = 1 << 213; + uint256 internal constant _ROLE_214 = 1 << 214; + uint256 internal constant _ROLE_215 = 1 << 215; + uint256 internal constant _ROLE_216 = 1 << 216; + uint256 internal constant _ROLE_217 = 1 << 217; + uint256 internal constant _ROLE_218 = 1 << 218; + uint256 internal constant _ROLE_219 = 1 << 219; + uint256 internal constant _ROLE_220 = 1 << 220; + uint256 internal constant _ROLE_221 = 1 << 221; + uint256 internal constant _ROLE_222 = 1 << 222; + uint256 internal constant _ROLE_223 = 1 << 223; + uint256 internal constant _ROLE_224 = 1 << 224; + uint256 internal constant _ROLE_225 = 1 << 225; + uint256 internal constant _ROLE_226 = 1 << 226; + uint256 internal constant _ROLE_227 = 1 << 227; + uint256 internal constant _ROLE_228 = 1 << 228; + uint256 internal constant _ROLE_229 = 1 << 229; + uint256 internal constant _ROLE_230 = 1 << 230; + uint256 internal constant _ROLE_231 = 1 << 231; + uint256 internal constant _ROLE_232 = 1 << 232; + uint256 internal constant _ROLE_233 = 1 << 233; + uint256 internal constant _ROLE_234 = 1 << 234; + uint256 internal constant _ROLE_235 = 1 << 235; + uint256 internal constant _ROLE_236 = 1 << 236; + uint256 internal constant _ROLE_237 = 1 << 237; + uint256 internal constant _ROLE_238 = 1 << 238; + uint256 internal constant _ROLE_239 = 1 << 239; + uint256 internal constant _ROLE_240 = 1 << 240; + uint256 internal constant _ROLE_241 = 1 << 241; + uint256 internal constant _ROLE_242 = 1 << 242; + uint256 internal constant _ROLE_243 = 1 << 243; + uint256 internal constant _ROLE_244 = 1 << 244; + uint256 internal constant _ROLE_245 = 1 << 245; + uint256 internal constant _ROLE_246 = 1 << 246; + uint256 internal constant _ROLE_247 = 1 << 247; + uint256 internal constant _ROLE_248 = 1 << 248; + uint256 internal constant _ROLE_249 = 1 << 249; + uint256 internal constant _ROLE_250 = 1 << 250; + uint256 internal constant _ROLE_251 = 1 << 251; + uint256 internal constant _ROLE_252 = 1 << 252; + uint256 internal constant _ROLE_253 = 1 << 253; + uint256 internal constant _ROLE_254 = 1 << 254; + uint256 internal constant _ROLE_255 = 1 << 255; +} + +// src\common/Treasury.sol + + + + + + +/// @title Treasury +/// @author Mathieu Bour for Pooky Labs Ltd. +/// +/// @notice Base class for contracts that are made to receive native currency. +/// The destination address is controller by the contract owner. +abstract contract Treasury is Ownable, ITreasury { + /// The native currency destination address. + address public treasury; + + constructor(address _treasury) { + treasury = _treasury; + } + + /// @notice Forward the funds to the treasury wallet at the end of the transaction. + /// Since `treasury` is a trusted address, this modifier should not lead to any re-entrancy issue. + modifier forwarder() { + _; + + uint256 value = address(this).balance; + (bool sent,) = treasury.call{ value: value }(""); + if (!sent) { + revert TransferFailed(treasury, value); + } + } + + /// Change the native currency destination address. + /// @param _treasury The new treasury address. + function changeTreasury(address _treasury) external onlyOwner { + treasury = _treasury; + } +} + +// src\tokens/IPOK.sol + + + + + + +/// @title IPOK +/// @author Mathieu Bour, Dusan Zdravkovic for Pooky Labs Ltd. +/// +/// @notice Minimal $POK ERC20 token interface. +interface IPOK is IAccessControl, IERC20 { + /// @notice Mint an arbitrary amount of $POK to an account. + /// @dev Requirements: + /// - only MINTER role can mint $POK tokens + function mint(address to, uint256 amount) external; + + /// @notice Burn an arbitrary amount of $POK of an sender account. + /// It is acknowledged that burning directly from the user wallet is anti-pattern + /// but since $POK is soulbounded, this allow to skip the ERC20 approve call. + /// @dev Requirements: + /// - only BURNER role can burn $POK tokens + function burn(address to, uint256 amount) external; +} + +// src\common/Signer.sol + + + + + + +/// @title Signer +/// @author Mathieu Bour for Pooky Labs Ltd. +/// +/// @dev Provide the `verify` function and the `onlyVerify` modifier to child contracts. +abstract contract Signer is OwnableRoles { + using ECDSA for bytes32; + + uint256 public constant SIGNER = _ROLE_42; + + /// Thrown when the signature is invalid. + error InvalidSignature(); + + constructor(address signer) { + _grantRoles(signer, SIGNER); + } + + /// @notice Ensure that `data` has been signed by a `SIGNER` using the `proof`. + function verify(bytes memory data, bytes calldata proof) internal view { + // Generate the signed message from the tokenId and currentPXP + bytes32 hash = keccak256(data).toEthSignedMessageHash(); + + if (!hasAllRoles(hash.recoverCalldata(proof), SIGNER)) { + revert InvalidSignature(); + } + } + + /// @notice Modifier version of the `verify` function. + modifier onlyVerify(bytes memory data, bytes calldata proof) { + verify(data, proof); + _; + } +} + +// src\pookyball/IPookyball.sol + + + + + + + +/// @title PookyballMetadata +/// @notice The Pookyball rarities are represented on chain by this enum. +enum PookyballRarity { + COMMON, + RARE, + EPIC, + LEGENDARY, + MYTHIC +} + +/// @title PookyballMetadata +/// @notice Pookyballs NFT have the following features: +/// - rarity: integer enum. +/// - level: token level, can be increase by spending token experiences points (PXP). +/// - pxp: token experience points. +/// - seed: a random uint256 word provided by Chainlink VRF service that will be used by Pooky's NFT generator +/// back-end to generate the NFT visuals and in-game statistics\. +struct PookyballMetadata { + PookyballRarity rarity; + uint256 level; + uint256 pxp; + uint256 seed; +} + +/// @title IPookyball +/// @author Mathieu Bour for Pooky Labs Ltd. +/// @notice Minimal Pookyball interface. +interface IPookyball is IAccessControl, IERC2981, IERC721 { + /// Fired when the seed of a Pookyball token is set by the VRFCoordinator + event SeedSet(uint256 indexed tokenId, uint256 seed); + /// Fired when the level of a Pookyball token is changed + event LevelChanged(uint256 indexed tokenId, uint256 level); + /// Fired when the PXP of a Pookyball token is changed + event PXPChanged(uint256 indexed tokenId, uint256 amount); + + /// Thrown when the length of two parameters mismatch. Used in the mint batched function. + error ArgumentSizeMismatch(uint256 x, uint256 y); + + /// @notice PookyballMetadata of the token {tokenId}. + /// @dev Requirements: + /// - Pookyball {tokenId} should exist (minted and not burned). + function metadata(uint256 tokenId) external view returns (PookyballMetadata memory); + + /// @notice Change the secondary sale royalties receiver address. + function setERC2981Receiver(address newReceiver) external; + + /// @notice Mint a new Pookyball token with a given rarity. + function mint(address[] memory recipients, PookyballRarity[] memory rarities) + external + returns (uint256); + + /// @notice Change the level of a Pookyball token. + /// @dev Requirements: + /// - Pookyball {tokenId} should exist (minted and not burned). + function setLevel(uint256 tokenId, uint256 newLevel) external; + + /// @notice Change the PXP of a Pookyball token. + /// @dev Requirements: + /// - Pookyball {tokenId} should exist (minted and not burned). + function setPXP(uint256 tokenId, uint256 newPXP) external; +} + +// src\common/IBaseERC721A.sol + + + + + + + + + +/// @title IBaseERC721 +/// +/// @author Mathieu Bour for Pooky Labs Ltd. +interface IBaseERC721A is IERC165, IERC721A, IERC721ABurnable, IERC721AQueryable, IERC2981 { + /// Fired when the seed of a Pookyball token is set by the VRFCoordinator, + event SeedSet(uint256 indexed tokenId, uint256 seed); + + /// Thrown when the token {tokenId} does not exist. + error NonExistentToken(uint256 tokenId); + + // ----- ERC721A patches ----- + /// @dev This allow to iterate over the token ids. + function nextTokenId() external view returns (uint256); + + function supportsInterface(bytes4 interfaceId) + external + view + override(IERC165, IERC721A) + returns (bool); +} + +// src\stickers/IStickers.sol + + + + + +enum StickerRarity { + COMMON, + RARE, + EPIC, + LEGENDARY, + MYTHIC +} + +struct StickerMint { + address recipient; + StickerRarity rarity; +} + +struct StickerMetadata { + uint248 level; + StickerRarity rarity; +} + +/// @title IStickers +/// @author Mathieu Bour for Pooky Labs Ltd. +interface IStickers is IBaseERC721A { + /// Fired when the level of a Pookyball token is changed, + event LevelChanged(uint256 indexed tokenId, uint256 level); + + /// @notice StickerMetadata of the token {tokenId}. + /// @dev Requirements: + /// - Sticker {tokenId} should exist (minted and not burned). + function metadata(uint256 tokenId) external view returns (StickerMetadata memory); + + /// @notice Change the level of a Sticker token. + /// @dev Requirements: + /// - Sticker {tokenId} should exist (minted and not burned). + function setLevel(uint256 tokenId, uint248 newLevel) external; + + /// @notice Mint multiple Stickers at once. + /// @param recipient The mint recipient. + /// @param rarities The Sticker rarities. + function mint(address recipient, StickerRarity[] memory rarities) external; +} + +// src\stickers/IStickersController.sol + + + + + + +/// @notice IStickersController +/// @author Mathieu Bour for Pooky Labs Ltd. +interface IStickersController { + /// @notice Fired when a sticker is attached to a Pookyball. + event StickerAttached(uint256 stickerId, uint256 pookyballId); + /// @notice Fired when a sticker is replace from a Pookyball. + event StickerReplaced(uint256 stickerId, uint256 previousStickerId, uint256 pookyballId); + /// @notice Fired when a sticker is detached from a Pookyball. + event StickerDetached(uint256 stickerId, uint256 pookyballId); + + /// @notice Thrown when a sticker is invalid. + error InvalidSticker(uint256 stickerId); + + /// @notice The Stickers ERC-721 contract. + function stickers() external view returns (IStickers); + + /// @notice The Pookyball ERC-721 contract. + function pookyball() external view returns (IPookyball); + + /// @notice Get the Pookyball token id linked to a Sticker. + /// @param stickerId The Sticker token id. + function attachedTo(uint256 stickerId) external view returns (uint256); + + /// @notice Get the Stickers token ids attached to a Pookyball. + /// @param pookyballId The Pookyball token id. + function slots(uint256 pookyballId) external view returns (uint256[] memory); + + /// @notice Attach a sticker to a Pookyball. + /// @param stickerId The sticker token id. + /// @param pookyballId The Pookyball token id. + /// @dev Caution: no ownership checks are run. + function attach(uint256 stickerId, uint256 pookyballId) external; + + /// @notice Replace a sticker from a Pookyball, burning the previous one. + /// @param stickerId The sticker token id. + /// @param previousStickerId The previous sticker token id that will be burned. + /// @param pookyballId The Pookyball token id. + /// @dev Caution: no ownership checks are run. + function replace(uint256 stickerId, uint256 previousStickerId, uint256 pookyballId) external; + + /// @notice Detach (remove) a sticker from a Pookyball. + /// @param stickerId The Sstickerticker token id. + /// @param recepient The address when to send the detached sticker. + function detach(uint256 stickerId, address recepient) external; +} + +// src\pookyball\PookyballAscension.sol + + + + + + + + + + +/// @title PookyballAscension +/// @author Mathieu Bour for Pooky Labs Ltd. +/// +/// @notice This contract allow Pooky players to upgrade their Pookyballs by merging two Pookyballs into a better single Pookyball. +/// @dev This contract requires the following roles: +/// - `Pookyball.MINTER` +/// - `StickersController.REMOVER` to unslot all Stickers attached to ascended Pookyballs. +contract PookyballAscension is OwnableRoles, Treasury, Signer { + /// @notice Fired when a token is ascended. + /// @param tokenId The new ascended token id. + /// @param rarity The rarity of the new ascended token. + /// @param left The first token id. + /// @param right The second token id. + /// @param data Abitrary data. + event Ascended( + uint256 indexed tokenId, + PookyballRarity rarity, + uint256 indexed left, + uint256 indexed right, + string data + ); + + /// @notice Thrown when the `tokenId` is not eligible for the ascension. + error Ineligible(uint256 tokenId); + + /// @notice Thrown when the rarities of the two source tokens do not match. + error RarityMismatch(PookyballRarity left, PookyballRarity right); + + /// @notice Since Pookyball are not burnable by design, we will use the "0xdead" address instead. + address public constant dead = 0x000000000000000000000000000000000000dEaD; + + /// @notice The Pookyball ERC-721 smart contract. + IPookyball public immutable pookyball; + IStickersController public immutable controller; + + /// @param _pookyball The Pookyball ERC-721 smart contract. + /// @param admin The initial contract admin. + /// @param _treasury The initial treasury. + /// @param signer The initial signer. + constructor( + IPookyball _pookyball, + IStickersController _controller, + address admin, + address signer, + address _treasury + ) Signer(signer) Treasury(_treasury) { + _initializeOwner(admin); + pookyball = _pookyball; + controller = _controller; + } + + /// @notice Check if the `tokenId` is at its maximum level. + /// @param sender The account that want to ascend the stickers, used for ownership test. + /// @param tokenId The token id to check. + /// @return The ascended rarity. + function ascendable(address sender, uint256 tokenId) public view returns (PookyballRarity) { + if (pookyball.ownerOf(tokenId) != sender) { + revert Ineligible(tokenId); + } + + PookyballMetadata memory m = pookyball.metadata(tokenId); + + if (m.rarity == PookyballRarity.COMMON && m.level >= 40) { + return PookyballRarity.RARE; + } + + if (m.rarity == PookyballRarity.RARE && m.level >= 60) { + return PookyballRarity.EPIC; + } + + if (m.rarity == PookyballRarity.EPIC && m.level >= 80) { + return PookyballRarity.LEGENDARY; + } + + if (m.rarity == PookyballRarity.LEGENDARY && m.level >= 100) { + return PookyballRarity.MYTHIC; + } + + revert Ineligible(tokenId); + } + + /// @notice Burn the Pookyball `tokenId` by sending it to the `dead` address. + /// @dev This burn requires the owner to approve this contract as operator for the Pookyball collection. + function _burn(uint256 tokenId) internal { + uint256[] memory stickers = controller.slots(tokenId); + address owner = pookyball.ownerOf(tokenId); + + for (uint256 i; i < stickers.length;) { + controller.detach(stickers[i], owner); + unchecked { + ++i; + } + } + + pookyball.transferFrom(owner, dead, tokenId); // send Pookyball to dead address + } + + /// @notice Mint the new ascended Pookyball. + /// @param rarity The ascended Pookyball rarity. + /// @param recipient The recipient of the Pookyball. + /// @return The ascended Pookyball token id. + function _mint(PookyballRarity rarity, address recipient) internal returns (uint256) { + address[] memory recipients = new address[](1); + recipients[0] = recipient; + PookyballRarity[] memory rarities = new PookyballRarity[](1); + rarities[0] = rarity; + return pookyball.mint(recipients, rarities); + } + + /// @notice Ascend Pookyballs `left` and `right` into a new Pookyball. + /// @dev The signer has all autority on the pricing, since the formula requires off-chain data. + /// @param left The first Pookyball token id. + /// @param right The second Pookyball token id. + /// @param priceNAT The price in native currency. + /// @param data Abitrary data repeated in the `Ascended` event. + /// @param proof The proof of `abi.encode(left, right, priceNAT, data, address(this))`. + function ascend( + uint256 left, + uint256 right, + uint256 priceNAT, + string calldata data, + bytes calldata proof + ) + external + payable + onlyVerify(abi.encode(left, right, priceNAT, data, address(this)), proof) + forwarder + returns (uint256) + { + if (priceNAT > msg.value) { + revert InsufficientValue(priceNAT, msg.value); + } + + PookyballRarity rarity = ascendable(msg.sender, left); + PookyballRarity rarity2 = ascendable(msg.sender, right); + + if (rarity != rarity2) { + revert RarityMismatch(rarity, rarity2); + } + + // Actual ascension: burn the two source Pookyballs and mint a new one. + _burn(left); + _burn(right); + uint256 ascendedId = _mint(rarity, msg.sender); + + emit Ascended(ascendedId, rarity, left, right, data); + return ascendedId; + } +} diff --git a/flattened/PookyballLevelUp.sol b/flattened/PookyballLevelUp.sol new file mode 100644 index 00000000..2e1129b9 --- /dev/null +++ b/flattened/PookyballLevelUp.sol @@ -0,0 +1,1968 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0 ^0.8.17 ^0.8.21 ^0.8.22 ^0.8.4; + +// lib/openzeppelin-contracts/contracts\access/IAccessControl.sol + +// OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol) + + + +/** + * @dev External interface of AccessControl declared to support ERC165 detection. + */ +interface IAccessControl { + /** + * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` + * + * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite + * {RoleAdminChanged} not being emitted signaling this. + * + * _Available since v3.1._ + */ + event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole); + + /** + * @dev Emitted when `account` is granted `role`. + * + * `sender` is the account that originated the contract call, an admin role + * bearer except when using {AccessControl-_setupRole}. + */ + event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender); + + /** + * @dev Emitted when `account` is revoked `role`. + * + * `sender` is the account that originated the contract call: + * - if using `revokeRole`, it is the admin role bearer + * - if using `renounceRole`, it is the role bearer (i.e. `account`) + */ + event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender); + + /** + * @dev Returns `true` if `account` has been granted `role`. + */ + function hasRole(bytes32 role, address account) external view returns (bool); + + /** + * @dev Returns the admin role that controls `role`. See {grantRole} and + * {revokeRole}. + * + * To change a role's admin, use {AccessControl-_setRoleAdmin}. + */ + function getRoleAdmin(bytes32 role) external view returns (bytes32); + + /** + * @dev Grants `role` to `account`. + * + * If `account` had not been already granted `role`, emits a {RoleGranted} + * event. + * + * Requirements: + * + * - the caller must have ``role``'s admin role. + */ + function grantRole(bytes32 role, address account) external; + + /** + * @dev Revokes `role` from `account`. + * + * If `account` had been granted `role`, emits a {RoleRevoked} event. + * + * Requirements: + * + * - the caller must have ``role``'s admin role. + */ + function revokeRole(bytes32 role, address account) external; + + /** + * @dev Revokes `role` from the calling account. + * + * Roles are often managed via {grantRole} and {revokeRole}: this function's + * purpose is to provide a mechanism for accounts to lose their privileges + * if they are compromised (such as when a trusted device is misplaced). + * + * If the calling account had been granted `role`, emits a {RoleRevoked} + * event. + * + * Requirements: + * + * - the caller must be `account`. + */ + function renounceRole(bytes32 role, address account) external; +} + +// lib/openzeppelin-contracts/contracts\token/ERC20/IERC20.sol + +// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol) + + + +/** + * @dev Interface of the ERC20 standard as defined in the EIP. + */ +interface IERC20 { + /** + * @dev Emitted when `value` tokens are moved from one account (`from`) to + * another (`to`). + * + * Note that `value` may be zero. + */ + event Transfer(address indexed from, address indexed to, uint256 value); + + /** + * @dev Emitted when the allowance of a `spender` for an `owner` is set by + * a call to {approve}. `value` is the new allowance. + */ + event Approval(address indexed owner, address indexed spender, uint256 value); + + /** + * @dev Returns the amount of tokens in existence. + */ + function totalSupply() external view returns (uint256); + + /** + * @dev Returns the amount of tokens owned by `account`. + */ + function balanceOf(address account) external view returns (uint256); + + /** + * @dev Moves `amount` tokens from the caller's account to `to`. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * Emits a {Transfer} event. + */ + function transfer(address to, uint256 amount) external returns (bool); + + /** + * @dev Returns the remaining number of tokens that `spender` will be + * allowed to spend on behalf of `owner` through {transferFrom}. This is + * zero by default. + * + * This value changes when {approve} or {transferFrom} are called. + */ + function allowance(address owner, address spender) external view returns (uint256); + + /** + * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * IMPORTANT: Beware that changing an allowance with this method brings the risk + * that someone may use both the old and the new allowance by unfortunate + * transaction ordering. One possible solution to mitigate this race + * condition is to first reduce the spender's allowance to 0 and set the + * desired value afterwards: + * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 + * + * Emits an {Approval} event. + */ + function approve(address spender, uint256 amount) external returns (bool); + + /** + * @dev Moves `amount` tokens from `from` to `to` using the + * allowance mechanism. `amount` is then deducted from the caller's + * allowance. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * Emits a {Transfer} event. + */ + function transferFrom(address from, address to, uint256 amount) external returns (bool); +} + +// lib/openzeppelin-contracts/contracts/utils/introspection/IERC165.sol + +// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol) + + + +/** + * @dev Interface of the ERC165 standard, as defined in the + * https://eips.ethereum.org/EIPS/eip-165[EIP]. + * + * Implementers can declare support of contract interfaces, which can then be + * queried by others ({ERC165Checker}). + * + * For an implementation, see {ERC165}. + */ +interface IERC165 { + /** + * @dev Returns true if this contract implements the interface defined by + * `interfaceId`. See the corresponding + * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] + * to learn more about how these ids are created. + * + * This function call must use less than 30 000 gas. + */ + function supportsInterface(bytes4 interfaceId) external view returns (bool); +} + +// lib/solady/src/auth/Ownable.sol + + + +/// @notice Simple single owner authorization mixin. +/// @author Solady (https://github.com/vectorized/solady/blob/main/src/auth/Ownable.sol) +/// @dev While the ownable portion follows +/// [EIP-173](https://eips.ethereum.org/EIPS/eip-173) for compatibility, +/// the nomenclature for the 2-step ownership handover may be unique to this codebase. +abstract contract Ownable { + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* CUSTOM ERRORS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev The caller is not authorized to call the function. + error Unauthorized(); + + /// @dev The `newOwner` cannot be the zero address. + error NewOwnerIsZeroAddress(); + + /// @dev The `pendingOwner` does not have a valid handover request. + error NoHandoverRequest(); + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* EVENTS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev The ownership is transferred from `oldOwner` to `newOwner`. + /// This event is intentionally kept the same as OpenZeppelin's Ownable to be + /// compatible with indexers and [EIP-173](https://eips.ethereum.org/EIPS/eip-173), + /// despite it not being as lightweight as a single argument event. + event OwnershipTransferred(address indexed oldOwner, address indexed newOwner); + + /// @dev An ownership handover to `pendingOwner` has been requested. + event OwnershipHandoverRequested(address indexed pendingOwner); + + /// @dev The ownership handover to `pendingOwner` has been canceled. + event OwnershipHandoverCanceled(address indexed pendingOwner); + + /// @dev `keccak256(bytes("OwnershipTransferred(address,address)"))`. + uint256 private constant _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE = + 0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0; + + /// @dev `keccak256(bytes("OwnershipHandoverRequested(address)"))`. + uint256 private constant _OWNERSHIP_HANDOVER_REQUESTED_EVENT_SIGNATURE = + 0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d; + + /// @dev `keccak256(bytes("OwnershipHandoverCanceled(address)"))`. + uint256 private constant _OWNERSHIP_HANDOVER_CANCELED_EVENT_SIGNATURE = + 0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92; + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* STORAGE */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev The owner slot is given by: `not(_OWNER_SLOT_NOT)`. + /// It is intentionally chosen to be a high value + /// to avoid collision with lower slots. + /// The choice of manual storage layout is to enable compatibility + /// with both regular and upgradeable contracts. + uint256 private constant _OWNER_SLOT_NOT = 0x8b78c6d8; + + /// The ownership handover slot of `newOwner` is given by: + /// ``` + /// mstore(0x00, or(shl(96, user), _HANDOVER_SLOT_SEED)) + /// let handoverSlot := keccak256(0x00, 0x20) + /// ``` + /// It stores the expiry timestamp of the two-step ownership handover. + uint256 private constant _HANDOVER_SLOT_SEED = 0x389a75e1; + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* INTERNAL FUNCTIONS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev Initializes the owner directly without authorization guard. + /// This function must be called upon initialization, + /// regardless of whether the contract is upgradeable or not. + /// This is to enable generalization to both regular and upgradeable contracts, + /// and to save gas in case the initial owner is not the caller. + /// For performance reasons, this function will not check if there + /// is an existing owner. + function _initializeOwner(address newOwner) internal virtual { + /// @solidity memory-safe-assembly + assembly { + // Clean the upper 96 bits. + newOwner := shr(96, shl(96, newOwner)) + // Store the new value. + sstore(not(_OWNER_SLOT_NOT), newOwner) + // Emit the {OwnershipTransferred} event. + log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, 0, newOwner) + } + } + + /// @dev Sets the owner directly without authorization guard. + function _setOwner(address newOwner) internal virtual { + /// @solidity memory-safe-assembly + assembly { + let ownerSlot := not(_OWNER_SLOT_NOT) + // Clean the upper 96 bits. + newOwner := shr(96, shl(96, newOwner)) + // Emit the {OwnershipTransferred} event. + log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, sload(ownerSlot), newOwner) + // Store the new value. + sstore(ownerSlot, newOwner) + } + } + + /// @dev Throws if the sender is not the owner. + function _checkOwner() internal view virtual { + /// @solidity memory-safe-assembly + assembly { + // If the caller is not the stored owner, revert. + if iszero(eq(caller(), sload(not(_OWNER_SLOT_NOT)))) { + mstore(0x00, 0x82b42900) // `Unauthorized()`. + revert(0x1c, 0x04) + } + } + } + + /// @dev Returns how long a two-step ownership handover is valid for in seconds. + /// Override to return a different value if needed. + /// Made internal to conserve bytecode. Wrap it in a public function if needed. + function _ownershipHandoverValidFor() internal view virtual returns (uint64) { + return 48 * 3600; + } + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* PUBLIC UPDATE FUNCTIONS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev Allows the owner to transfer the ownership to `newOwner`. + function transferOwnership(address newOwner) public payable virtual onlyOwner { + /// @solidity memory-safe-assembly + assembly { + if iszero(shl(96, newOwner)) { + mstore(0x00, 0x7448fbae) // `NewOwnerIsZeroAddress()`. + revert(0x1c, 0x04) + } + } + _setOwner(newOwner); + } + + /// @dev Allows the owner to renounce their ownership. + function renounceOwnership() public payable virtual onlyOwner { + _setOwner(address(0)); + } + + /// @dev Request a two-step ownership handover to the caller. + /// The request will automatically expire in 48 hours (172800 seconds) by default. + function requestOwnershipHandover() public payable virtual { + unchecked { + uint256 expires = block.timestamp + _ownershipHandoverValidFor(); + /// @solidity memory-safe-assembly + assembly { + // Compute and set the handover slot to `expires`. + mstore(0x0c, _HANDOVER_SLOT_SEED) + mstore(0x00, caller()) + sstore(keccak256(0x0c, 0x20), expires) + // Emit the {OwnershipHandoverRequested} event. + log2(0, 0, _OWNERSHIP_HANDOVER_REQUESTED_EVENT_SIGNATURE, caller()) + } + } + } + + /// @dev Cancels the two-step ownership handover to the caller, if any. + function cancelOwnershipHandover() public payable virtual { + /// @solidity memory-safe-assembly + assembly { + // Compute and set the handover slot to 0. + mstore(0x0c, _HANDOVER_SLOT_SEED) + mstore(0x00, caller()) + sstore(keccak256(0x0c, 0x20), 0) + // Emit the {OwnershipHandoverCanceled} event. + log2(0, 0, _OWNERSHIP_HANDOVER_CANCELED_EVENT_SIGNATURE, caller()) + } + } + + /// @dev Allows the owner to complete the two-step ownership handover to `pendingOwner`. + /// Reverts if there is no existing ownership handover requested by `pendingOwner`. + function completeOwnershipHandover(address pendingOwner) public payable virtual onlyOwner { + /// @solidity memory-safe-assembly + assembly { + // Compute and set the handover slot to 0. + mstore(0x0c, _HANDOVER_SLOT_SEED) + mstore(0x00, pendingOwner) + let handoverSlot := keccak256(0x0c, 0x20) + // If the handover does not exist, or has expired. + if gt(timestamp(), sload(handoverSlot)) { + mstore(0x00, 0x6f5e8818) // `NoHandoverRequest()`. + revert(0x1c, 0x04) + } + // Set the handover slot to 0. + sstore(handoverSlot, 0) + } + _setOwner(pendingOwner); + } + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* PUBLIC READ FUNCTIONS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev Returns the owner of the contract. + function owner() public view virtual returns (address result) { + /// @solidity memory-safe-assembly + assembly { + result := sload(not(_OWNER_SLOT_NOT)) + } + } + + /// @dev Returns the expiry timestamp for the two-step ownership handover to `pendingOwner`. + function ownershipHandoverExpiresAt(address pendingOwner) + public + view + virtual + returns (uint256 result) + { + /// @solidity memory-safe-assembly + assembly { + // Compute the handover slot. + mstore(0x0c, _HANDOVER_SLOT_SEED) + mstore(0x00, pendingOwner) + // Load the handover slot. + result := sload(keccak256(0x0c, 0x20)) + } + } + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* MODIFIERS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev Marks a function as only callable by the owner. + modifier onlyOwner() virtual { + _checkOwner(); + _; + } +} + +// lib/solady/src\utils/ECDSA.sol + + + +/// @notice Gas optimized ECDSA wrapper. +/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/ECDSA.sol) +/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/ECDSA.sol) +/// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/cryptography/ECDSA.sol) +library ECDSA { + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* CUSTOM ERRORS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev The signature is invalid. + error InvalidSignature(); + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* CONSTANTS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev The number which `s` must be less than in order for + /// the signature to be non-malleable. + bytes32 private constant _MALLEABILITY_THRESHOLD_PLUS_ONE = + 0x7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a1; + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* RECOVERY OPERATIONS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + // Note: as of Solady version 0.0.68, these functions will + // revert upon recovery failure for more safety by default. + + /// @dev Recovers the signer's address from a message digest `hash`, + /// and the `signature`. + /// + /// This function does NOT accept EIP-2098 short form signatures. + /// Use `recover(bytes32 hash, bytes32 r, bytes32 vs)` for EIP-2098 + /// short form signatures instead. + function recover(bytes32 hash, bytes memory signature) internal view returns (address result) { + /// @solidity memory-safe-assembly + assembly { + let m := mload(0x40) // Cache the free memory pointer. + mstore(0x00, hash) + mstore(0x20, byte(0, mload(add(signature, 0x60)))) // `v`. + mstore(0x40, mload(add(signature, 0x20))) // `r`. + mstore(0x60, mload(add(signature, 0x40))) // `s`. + pop( + staticcall( + gas(), // Amount of gas left for the transaction. + and( + // If the signature is exactly 65 bytes in length. + eq(mload(signature), 65), + // If `s` in lower half order, such that the signature is not malleable. + lt(mload(0x60), _MALLEABILITY_THRESHOLD_PLUS_ONE) + ), // Address of `ecrecover`. + 0x00, // Start of input. + 0x80, // Size of input. + 0x00, // Start of output. + 0x20 // Size of output. + ) + ) + result := mload(0x00) + // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise. + if iszero(returndatasize()) { + mstore(0x00, 0x8baa579f) // `InvalidSignature()`. + revert(0x1c, 0x04) + } + mstore(0x60, 0) // Restore the zero slot. + mstore(0x40, m) // Restore the free memory pointer. + } + } + + /// @dev Recovers the signer's address from a message digest `hash`, + /// and the `signature`. + /// + /// This function does NOT accept EIP-2098 short form signatures. + /// Use `recover(bytes32 hash, bytes32 r, bytes32 vs)` for EIP-2098 + /// short form signatures instead. + function recoverCalldata(bytes32 hash, bytes calldata signature) + internal + view + returns (address result) + { + /// @solidity memory-safe-assembly + assembly { + let m := mload(0x40) // Cache the free memory pointer. + mstore(0x00, hash) + mstore(0x20, byte(0, calldataload(add(signature.offset, 0x40)))) // `v`. + calldatacopy(0x40, signature.offset, 0x40) // Copy `r` and `s`. + pop( + staticcall( + gas(), // Amount of gas left for the transaction. + and( + // If the signature is exactly 65 bytes in length. + eq(signature.length, 65), + // If `s` in lower half order, such that the signature is not malleable. + lt(mload(0x60), _MALLEABILITY_THRESHOLD_PLUS_ONE) + ), // Address of `ecrecover`. + 0x00, // Start of input. + 0x80, // Size of input. + 0x00, // Start of output. + 0x20 // Size of output. + ) + ) + result := mload(0x00) + // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise. + if iszero(returndatasize()) { + mstore(0x00, 0x8baa579f) // `InvalidSignature()`. + revert(0x1c, 0x04) + } + mstore(0x60, 0) // Restore the zero slot. + mstore(0x40, m) // Restore the free memory pointer. + } + } + + /// @dev Recovers the signer's address from a message digest `hash`, + /// and the EIP-2098 short form signature defined by `r` and `vs`. + /// + /// This function only accepts EIP-2098 short form signatures. + /// See: https://eips.ethereum.org/EIPS/eip-2098 + function recover(bytes32 hash, bytes32 r, bytes32 vs) internal view returns (address result) { + /// @solidity memory-safe-assembly + assembly { + let m := mload(0x40) // Cache the free memory pointer. + mstore(0x00, hash) + mstore(0x20, add(shr(255, vs), 27)) // `v`. + mstore(0x40, r) + mstore(0x60, shr(1, shl(1, vs))) // `s`. + pop( + staticcall( + gas(), // Amount of gas left for the transaction. + // If `s` in lower half order, such that the signature is not malleable. + lt(mload(0x60), _MALLEABILITY_THRESHOLD_PLUS_ONE), // Address of `ecrecover`. + 0x00, // Start of input. + 0x80, // Size of input. + 0x00, // Start of output. + 0x20 // Size of output. + ) + ) + result := mload(0x00) + // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise. + if iszero(returndatasize()) { + mstore(0x00, 0x8baa579f) // `InvalidSignature()`. + revert(0x1c, 0x04) + } + mstore(0x60, 0) // Restore the zero slot. + mstore(0x40, m) // Restore the free memory pointer. + } + } + + /// @dev Recovers the signer's address from a message digest `hash`, + /// and the signature defined by `v`, `r`, `s`. + function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) + internal + view + returns (address result) + { + /// @solidity memory-safe-assembly + assembly { + let m := mload(0x40) // Cache the free memory pointer. + mstore(0x00, hash) + mstore(0x20, and(v, 0xff)) + mstore(0x40, r) + mstore(0x60, s) + pop( + staticcall( + gas(), // Amount of gas left for the transaction. + // If `s` in lower half order, such that the signature is not malleable. + lt(s, _MALLEABILITY_THRESHOLD_PLUS_ONE), // Address of `ecrecover`. + 0x00, // Start of input. + 0x80, // Size of input. + 0x00, // Start of output. + 0x20 // Size of output. + ) + ) + result := mload(0x00) + // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise. + if iszero(returndatasize()) { + mstore(0x00, 0x8baa579f) // `InvalidSignature()`. + revert(0x1c, 0x04) + } + mstore(0x60, 0) // Restore the zero slot. + mstore(0x40, m) // Restore the free memory pointer. + } + } + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* TRY-RECOVER OPERATIONS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + // WARNING! + // These functions will NOT revert upon recovery failure. + // Instead, they will return the zero address upon recovery failure. + // It is critical that the returned address is NEVER compared against + // a zero address (e.g. an uninitialized address variable). + + /// @dev Recovers the signer's address from a message digest `hash`, + /// and the `signature`. + /// + /// This function does NOT accept EIP-2098 short form signatures. + /// Use `recover(bytes32 hash, bytes32 r, bytes32 vs)` for EIP-2098 + /// short form signatures instead. + function tryRecover(bytes32 hash, bytes memory signature) + internal + view + returns (address result) + { + /// @solidity memory-safe-assembly + assembly { + let m := mload(0x40) // Cache the free memory pointer. + mstore(0x00, hash) + mstore(0x20, byte(0, mload(add(signature, 0x60)))) // `v`. + mstore(0x40, mload(add(signature, 0x20))) // `r`. + mstore(0x60, mload(add(signature, 0x40))) // `s`. + pop( + staticcall( + gas(), // Amount of gas left for the transaction. + and( + // If the signature is exactly 65 bytes in length. + eq(mload(signature), 65), + // If `s` in lower half order, such that the signature is not malleable. + lt(mload(0x60), _MALLEABILITY_THRESHOLD_PLUS_ONE) + ), // Address of `ecrecover`. + 0x00, // Start of input. + 0x80, // Size of input. + 0x40, // Start of output. + 0x20 // Size of output. + ) + ) + mstore(0x60, 0) // Restore the zero slot. + // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise. + result := mload(xor(0x60, returndatasize())) + mstore(0x40, m) // Restore the free memory pointer. + } + } + + /// @dev Recovers the signer's address from a message digest `hash`, + /// and the `signature`. + /// + /// This function does NOT accept EIP-2098 short form signatures. + /// Use `recover(bytes32 hash, bytes32 r, bytes32 vs)` for EIP-2098 + /// short form signatures instead. + function tryRecoverCalldata(bytes32 hash, bytes calldata signature) + internal + view + returns (address result) + { + /// @solidity memory-safe-assembly + assembly { + let m := mload(0x40) // Cache the free memory pointer. + mstore(0x00, hash) + mstore(0x20, byte(0, calldataload(add(signature.offset, 0x40)))) // `v`. + calldatacopy(0x40, signature.offset, 0x40) // Copy `r` and `s`. + pop( + staticcall( + gas(), // Amount of gas left for the transaction. + and( + // If the signature is exactly 65 bytes in length. + eq(signature.length, 65), + // If `s` in lower half order, such that the signature is not malleable. + lt(mload(0x60), _MALLEABILITY_THRESHOLD_PLUS_ONE) + ), // Address of `ecrecover`. + 0x00, // Start of input. + 0x80, // Size of input. + 0x40, // Start of output. + 0x20 // Size of output. + ) + ) + mstore(0x60, 0) // Restore the zero slot. + // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise. + result := mload(xor(0x60, returndatasize())) + mstore(0x40, m) // Restore the free memory pointer. + } + } + + /// @dev Recovers the signer's address from a message digest `hash`, + /// and the EIP-2098 short form signature defined by `r` and `vs`. + /// + /// This function only accepts EIP-2098 short form signatures. + /// See: https://eips.ethereum.org/EIPS/eip-2098 + function tryRecover(bytes32 hash, bytes32 r, bytes32 vs) + internal + view + returns (address result) + { + /// @solidity memory-safe-assembly + assembly { + let m := mload(0x40) // Cache the free memory pointer. + mstore(0x00, hash) + mstore(0x20, add(shr(255, vs), 27)) // `v`. + mstore(0x40, r) + mstore(0x60, shr(1, shl(1, vs))) // `s`. + pop( + staticcall( + gas(), // Amount of gas left for the transaction. + // If `s` in lower half order, such that the signature is not malleable. + lt(mload(0x60), _MALLEABILITY_THRESHOLD_PLUS_ONE), // Address of `ecrecover`. + 0x00, // Start of input. + 0x80, // Size of input. + 0x40, // Start of output. + 0x20 // Size of output. + ) + ) + mstore(0x60, 0) // Restore the zero slot. + // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise. + result := mload(xor(0x60, returndatasize())) + mstore(0x40, m) // Restore the free memory pointer. + } + } + + /// @dev Recovers the signer's address from a message digest `hash`, + /// and the signature defined by `v`, `r`, `s`. + function tryRecover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) + internal + view + returns (address result) + { + /// @solidity memory-safe-assembly + assembly { + let m := mload(0x40) // Cache the free memory pointer. + mstore(0x00, hash) + mstore(0x20, and(v, 0xff)) + mstore(0x40, r) + mstore(0x60, s) + pop( + staticcall( + gas(), // Amount of gas left for the transaction. + // If `s` in lower half order, such that the signature is not malleable. + lt(s, _MALLEABILITY_THRESHOLD_PLUS_ONE), // Address of `ecrecover`. + 0x00, // Start of input. + 0x80, // Size of input. + 0x40, // Start of output. + 0x20 // Size of output. + ) + ) + mstore(0x60, 0) // Restore the zero slot. + // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise. + result := mload(xor(0x60, returndatasize())) + mstore(0x40, m) // Restore the free memory pointer. + } + } + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* HASHING OPERATIONS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev Returns an Ethereum Signed Message, created from a `hash`. + /// This produces a hash corresponding to the one signed with the + /// [`eth_sign`](https://eth.wiki/json-rpc/API#eth_sign) + /// JSON-RPC method as part of EIP-191. + function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32 result) { + /// @solidity memory-safe-assembly + assembly { + mstore(0x20, hash) // Store into scratch space for keccak256. + mstore(0x00, "\x00\x00\x00\x00\x19Ethereum Signed Message:\n32") // 28 bytes. + result := keccak256(0x04, 0x3c) // `32 * 2 - (32 - 28) = 60 = 0x3c`. + } + } + + /// @dev Returns an Ethereum Signed Message, created from `s`. + /// This produces a hash corresponding to the one signed with the + /// [`eth_sign`](https://eth.wiki/json-rpc/API#eth_sign) + /// JSON-RPC method as part of EIP-191. + /// Note: Supports lengths of `s` up to 999999 bytes. + function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32 result) { + /// @solidity memory-safe-assembly + assembly { + let sLength := mload(s) + let o := 0x20 + mstore(o, "\x19Ethereum Signed Message:\n") // 26 bytes, zero-right-padded. + mstore(0x00, 0x00) + // Convert the `s.length` to ASCII decimal representation: `base10(s.length)`. + for { let temp := sLength } 1 {} { + o := sub(o, 1) + mstore8(o, add(48, mod(temp, 10))) + temp := div(temp, 10) + if iszero(temp) { break } + } + let n := sub(0x3a, o) // Header length: `26 + 32 - o`. + // Throw an out-of-offset error (consumes all gas) if the header exceeds 32 bytes. + returndatacopy(returndatasize(), returndatasize(), gt(n, 0x20)) + mstore(s, or(mload(0x00), mload(n))) // Temporarily store the header. + result := keccak256(add(s, sub(0x20, n)), add(n, sLength)) + mstore(s, sLength) // Restore the length. + } + } + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* EMPTY CALLDATA HELPERS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev Returns an empty calldata bytes. + function emptySignature() internal pure returns (bytes calldata signature) { + /// @solidity memory-safe-assembly + assembly { + signature.length := 0 + } + } +} + +// src\common/ITreasury.sol + + + +/// @title ITreasury +/// @author Mathieu Bour for Pooky Labs Ltd. +interface ITreasury { + /// Thrown when the msg.value of the mint function does not cover the mint cost. + error InsufficientValue(uint256 expected, uint256 actual); + /// Thrown when the native transfer has failed. + error TransferFailed(address recipient, uint256 amount); + + /// Change the native currency destination address. + /// @param _treasury The new treasury address. + function changeTreasury(address _treasury) external; +} + +// lib/openzeppelin-contracts/contracts\interfaces/IERC2981.sol + +// OpenZeppelin Contracts (last updated v4.9.0) (interfaces/IERC2981.sol) + + + + + +/** + * @dev Interface for the NFT Royalty Standard. + * + * A standardized way to retrieve royalty payment information for non-fungible tokens (NFTs) to enable universal + * support for royalty payments across all NFT marketplaces and ecosystem participants. + * + * _Available since v4.5._ + */ +interface IERC2981 is IERC165 { + /** + * @dev Returns how much royalty is owed and to whom, based on a sale price that may be denominated in any unit of + * exchange. The royalty amount is denominated and should be paid in that same unit of exchange. + */ + function royaltyInfo( + uint256 tokenId, + uint256 salePrice + ) external view returns (address receiver, uint256 royaltyAmount); +} + +// lib/openzeppelin-contracts/contracts\token/ERC721/IERC721.sol + +// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC721/IERC721.sol) + + + + + +/** + * @dev Required interface of an ERC721 compliant contract. + */ +interface IERC721 is IERC165 { + /** + * @dev Emitted when `tokenId` token is transferred from `from` to `to`. + */ + event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); + + /** + * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token. + */ + event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); + + /** + * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets. + */ + event ApprovalForAll(address indexed owner, address indexed operator, bool approved); + + /** + * @dev Returns the number of tokens in ``owner``'s account. + */ + function balanceOf(address owner) external view returns (uint256 balance); + + /** + * @dev Returns the owner of the `tokenId` token. + * + * Requirements: + * + * - `tokenId` must exist. + */ + function ownerOf(uint256 tokenId) external view returns (address owner); + + /** + * @dev Safely transfers `tokenId` token from `from` to `to`. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must exist and be owned by `from`. + * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. + * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. + * + * Emits a {Transfer} event. + */ + function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external; + + /** + * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients + * are aware of the ERC721 protocol to prevent tokens from being forever locked. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must exist and be owned by `from`. + * - If the caller is not `from`, it must have been allowed to move this token by either {approve} or {setApprovalForAll}. + * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. + * + * Emits a {Transfer} event. + */ + function safeTransferFrom(address from, address to, uint256 tokenId) external; + + /** + * @dev Transfers `tokenId` token from `from` to `to`. + * + * WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721 + * or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must + * understand this adds an external call which potentially creates a reentrancy vulnerability. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must be owned by `from`. + * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. + * + * Emits a {Transfer} event. + */ + function transferFrom(address from, address to, uint256 tokenId) external; + + /** + * @dev Gives permission to `to` to transfer `tokenId` token to another account. + * The approval is cleared when the token is transferred. + * + * Only a single account can be approved at a time, so approving the zero address clears previous approvals. + * + * Requirements: + * + * - The caller must own the token or be an approved operator. + * - `tokenId` must exist. + * + * Emits an {Approval} event. + */ + function approve(address to, uint256 tokenId) external; + + /** + * @dev Approve or remove `operator` as an operator for the caller. + * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller. + * + * Requirements: + * + * - The `operator` cannot be the caller. + * + * Emits an {ApprovalForAll} event. + */ + function setApprovalForAll(address operator, bool approved) external; + + /** + * @dev Returns the account approved for `tokenId` token. + * + * Requirements: + * + * - `tokenId` must exist. + */ + function getApproved(uint256 tokenId) external view returns (address operator); + + /** + * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`. + * + * See {setApprovalForAll} + */ + function isApprovedForAll(address owner, address operator) external view returns (bool); +} + +// lib/solady/src\auth/OwnableRoles.sol + + + + + +/// @notice Simple single owner and multiroles authorization mixin. +/// @author Solady (https://github.com/vectorized/solady/blob/main/src/auth/Ownable.sol) +/// @dev While the ownable portion follows [EIP-173](https://eips.ethereum.org/EIPS/eip-173) +/// for compatibility, the nomenclature for the 2-step ownership handover and roles +/// may be unique to this codebase. +abstract contract OwnableRoles is Ownable { + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* EVENTS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev The `user`'s roles is updated to `roles`. + /// Each bit of `roles` represents whether the role is set. + event RolesUpdated(address indexed user, uint256 indexed roles); + + /// @dev `keccak256(bytes("RolesUpdated(address,uint256)"))`. + uint256 private constant _ROLES_UPDATED_EVENT_SIGNATURE = + 0x715ad5ce61fc9595c7b415289d59cf203f23a94fa06f04af7e489a0a76e1fe26; + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* STORAGE */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev The role slot of `user` is given by: + /// ``` + /// mstore(0x00, or(shl(96, user), _ROLE_SLOT_SEED)) + /// let roleSlot := keccak256(0x00, 0x20) + /// ``` + /// This automatically ignores the upper bits of the `user` in case + /// they are not clean, as well as keep the `keccak256` under 32-bytes. + /// + /// Note: This is equal to `_OWNER_SLOT_NOT` in for gas efficiency. + uint256 private constant _ROLE_SLOT_SEED = 0x8b78c6d8; + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* INTERNAL FUNCTIONS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev Overwrite the roles directly without authorization guard. + function _setRoles(address user, uint256 roles) internal virtual { + /// @solidity memory-safe-assembly + assembly { + mstore(0x0c, _ROLE_SLOT_SEED) + mstore(0x00, user) + // Store the new value. + sstore(keccak256(0x0c, 0x20), roles) + // Emit the {RolesUpdated} event. + log3(0, 0, _ROLES_UPDATED_EVENT_SIGNATURE, shr(96, mload(0x0c)), roles) + } + } + + /// @dev Updates the roles directly without authorization guard. + /// If `on` is true, each set bit of `roles` will be turned on, + /// otherwise, each set bit of `roles` will be turned off. + function _updateRoles(address user, uint256 roles, bool on) internal virtual { + /// @solidity memory-safe-assembly + assembly { + mstore(0x0c, _ROLE_SLOT_SEED) + mstore(0x00, user) + let roleSlot := keccak256(0x0c, 0x20) + // Load the current value. + let current := sload(roleSlot) + // Compute the updated roles if `on` is true. + let updated := or(current, roles) + // Compute the updated roles if `on` is false. + // Use `and` to compute the intersection of `current` and `roles`, + // `xor` it with `current` to flip the bits in the intersection. + if iszero(on) { updated := xor(current, and(current, roles)) } + // Then, store the new value. + sstore(roleSlot, updated) + // Emit the {RolesUpdated} event. + log3(0, 0, _ROLES_UPDATED_EVENT_SIGNATURE, shr(96, mload(0x0c)), updated) + } + } + + /// @dev Grants the roles directly without authorization guard. + /// Each bit of `roles` represents the role to turn on. + function _grantRoles(address user, uint256 roles) internal virtual { + _updateRoles(user, roles, true); + } + + /// @dev Removes the roles directly without authorization guard. + /// Each bit of `roles` represents the role to turn off. + function _removeRoles(address user, uint256 roles) internal virtual { + _updateRoles(user, roles, false); + } + + /// @dev Throws if the sender does not have any of the `roles`. + function _checkRoles(uint256 roles) internal view virtual { + /// @solidity memory-safe-assembly + assembly { + // Compute the role slot. + mstore(0x0c, _ROLE_SLOT_SEED) + mstore(0x00, caller()) + // Load the stored value, and if the `and` intersection + // of the value and `roles` is zero, revert. + if iszero(and(sload(keccak256(0x0c, 0x20)), roles)) { + mstore(0x00, 0x82b42900) // `Unauthorized()`. + revert(0x1c, 0x04) + } + } + } + + /// @dev Throws if the sender is not the owner, + /// and does not have any of the `roles`. + /// Checks for ownership first, then lazily checks for roles. + function _checkOwnerOrRoles(uint256 roles) internal view virtual { + /// @solidity memory-safe-assembly + assembly { + // If the caller is not the stored owner. + // Note: `_ROLE_SLOT_SEED` is equal to `_OWNER_SLOT_NOT`. + if iszero(eq(caller(), sload(not(_ROLE_SLOT_SEED)))) { + // Compute the role slot. + mstore(0x0c, _ROLE_SLOT_SEED) + mstore(0x00, caller()) + // Load the stored value, and if the `and` intersection + // of the value and `roles` is zero, revert. + if iszero(and(sload(keccak256(0x0c, 0x20)), roles)) { + mstore(0x00, 0x82b42900) // `Unauthorized()`. + revert(0x1c, 0x04) + } + } + } + } + + /// @dev Throws if the sender does not have any of the `roles`, + /// and is not the owner. + /// Checks for roles first, then lazily checks for ownership. + function _checkRolesOrOwner(uint256 roles) internal view virtual { + /// @solidity memory-safe-assembly + assembly { + // Compute the role slot. + mstore(0x0c, _ROLE_SLOT_SEED) + mstore(0x00, caller()) + // Load the stored value, and if the `and` intersection + // of the value and `roles` is zero, revert. + if iszero(and(sload(keccak256(0x0c, 0x20)), roles)) { + // If the caller is not the stored owner. + // Note: `_ROLE_SLOT_SEED` is equal to `_OWNER_SLOT_NOT`. + if iszero(eq(caller(), sload(not(_ROLE_SLOT_SEED)))) { + mstore(0x00, 0x82b42900) // `Unauthorized()`. + revert(0x1c, 0x04) + } + } + } + } + + /// @dev Convenience function to return a `roles` bitmap from an array of `ordinals`. + /// This is meant for frontends like Etherscan, and is therefore not fully optimized. + /// Not recommended to be called on-chain. + /// Made internal to conserve bytecode. Wrap it in a public function if needed. + function _rolesFromOrdinals(uint8[] memory ordinals) internal pure returns (uint256 roles) { + /// @solidity memory-safe-assembly + assembly { + for { let i := shl(5, mload(ordinals)) } i { i := sub(i, 0x20) } { + // We don't need to mask the values of `ordinals`, as Solidity + // cleans dirty upper bits when storing variables into memory. + roles := or(shl(mload(add(ordinals, i)), 1), roles) + } + } + } + + /// @dev Convenience function to return an array of `ordinals` from the `roles` bitmap. + /// This is meant for frontends like Etherscan, and is therefore not fully optimized. + /// Not recommended to be called on-chain. + /// Made internal to conserve bytecode. Wrap it in a public function if needed. + function _ordinalsFromRoles(uint256 roles) internal pure returns (uint8[] memory ordinals) { + /// @solidity memory-safe-assembly + assembly { + // Grab the pointer to the free memory. + ordinals := mload(0x40) + let ptr := add(ordinals, 0x20) + let o := 0 + // The absence of lookup tables, De Bruijn, etc., here is intentional for + // smaller bytecode, as this function is not meant to be called on-chain. + for { let t := roles } 1 {} { + mstore(ptr, o) + // `shr` 5 is equivalent to multiplying by 0x20. + // Push back into the ordinals array if the bit is set. + ptr := add(ptr, shl(5, and(t, 1))) + o := add(o, 1) + t := shr(o, roles) + if iszero(t) { break } + } + // Store the length of `ordinals`. + mstore(ordinals, shr(5, sub(ptr, add(ordinals, 0x20)))) + // Allocate the memory. + mstore(0x40, ptr) + } + } + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* PUBLIC UPDATE FUNCTIONS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev Allows the owner to grant `user` `roles`. + /// If the `user` already has a role, then it will be an no-op for the role. + function grantRoles(address user, uint256 roles) public payable virtual onlyOwner { + _grantRoles(user, roles); + } + + /// @dev Allows the owner to remove `user` `roles`. + /// If the `user` does not have a role, then it will be an no-op for the role. + function revokeRoles(address user, uint256 roles) public payable virtual onlyOwner { + _removeRoles(user, roles); + } + + /// @dev Allow the caller to remove their own roles. + /// If the caller does not have a role, then it will be an no-op for the role. + function renounceRoles(uint256 roles) public payable virtual { + _removeRoles(msg.sender, roles); + } + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* PUBLIC READ FUNCTIONS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev Returns the roles of `user`. + function rolesOf(address user) public view virtual returns (uint256 roles) { + /// @solidity memory-safe-assembly + assembly { + // Compute the role slot. + mstore(0x0c, _ROLE_SLOT_SEED) + mstore(0x00, user) + // Load the stored value. + roles := sload(keccak256(0x0c, 0x20)) + } + } + + /// @dev Returns whether `user` has any of `roles`. + function hasAnyRole(address user, uint256 roles) public view virtual returns (bool) { + return rolesOf(user) & roles != 0; + } + + /// @dev Returns whether `user` has all of `roles`. + function hasAllRoles(address user, uint256 roles) public view virtual returns (bool) { + return rolesOf(user) & roles == roles; + } + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* MODIFIERS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev Marks a function as only callable by an account with `roles`. + modifier onlyRoles(uint256 roles) virtual { + _checkRoles(roles); + _; + } + + /// @dev Marks a function as only callable by the owner or by an account + /// with `roles`. Checks for ownership first, then lazily checks for roles. + modifier onlyOwnerOrRoles(uint256 roles) virtual { + _checkOwnerOrRoles(roles); + _; + } + + /// @dev Marks a function as only callable by an account with `roles` + /// or the owner. Checks for roles first, then lazily checks for ownership. + modifier onlyRolesOrOwner(uint256 roles) virtual { + _checkRolesOrOwner(roles); + _; + } + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* ROLE CONSTANTS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + // IYKYK + + uint256 internal constant _ROLE_0 = 1 << 0; + uint256 internal constant _ROLE_1 = 1 << 1; + uint256 internal constant _ROLE_2 = 1 << 2; + uint256 internal constant _ROLE_3 = 1 << 3; + uint256 internal constant _ROLE_4 = 1 << 4; + uint256 internal constant _ROLE_5 = 1 << 5; + uint256 internal constant _ROLE_6 = 1 << 6; + uint256 internal constant _ROLE_7 = 1 << 7; + uint256 internal constant _ROLE_8 = 1 << 8; + uint256 internal constant _ROLE_9 = 1 << 9; + uint256 internal constant _ROLE_10 = 1 << 10; + uint256 internal constant _ROLE_11 = 1 << 11; + uint256 internal constant _ROLE_12 = 1 << 12; + uint256 internal constant _ROLE_13 = 1 << 13; + uint256 internal constant _ROLE_14 = 1 << 14; + uint256 internal constant _ROLE_15 = 1 << 15; + uint256 internal constant _ROLE_16 = 1 << 16; + uint256 internal constant _ROLE_17 = 1 << 17; + uint256 internal constant _ROLE_18 = 1 << 18; + uint256 internal constant _ROLE_19 = 1 << 19; + uint256 internal constant _ROLE_20 = 1 << 20; + uint256 internal constant _ROLE_21 = 1 << 21; + uint256 internal constant _ROLE_22 = 1 << 22; + uint256 internal constant _ROLE_23 = 1 << 23; + uint256 internal constant _ROLE_24 = 1 << 24; + uint256 internal constant _ROLE_25 = 1 << 25; + uint256 internal constant _ROLE_26 = 1 << 26; + uint256 internal constant _ROLE_27 = 1 << 27; + uint256 internal constant _ROLE_28 = 1 << 28; + uint256 internal constant _ROLE_29 = 1 << 29; + uint256 internal constant _ROLE_30 = 1 << 30; + uint256 internal constant _ROLE_31 = 1 << 31; + uint256 internal constant _ROLE_32 = 1 << 32; + uint256 internal constant _ROLE_33 = 1 << 33; + uint256 internal constant _ROLE_34 = 1 << 34; + uint256 internal constant _ROLE_35 = 1 << 35; + uint256 internal constant _ROLE_36 = 1 << 36; + uint256 internal constant _ROLE_37 = 1 << 37; + uint256 internal constant _ROLE_38 = 1 << 38; + uint256 internal constant _ROLE_39 = 1 << 39; + uint256 internal constant _ROLE_40 = 1 << 40; + uint256 internal constant _ROLE_41 = 1 << 41; + uint256 internal constant _ROLE_42 = 1 << 42; + uint256 internal constant _ROLE_43 = 1 << 43; + uint256 internal constant _ROLE_44 = 1 << 44; + uint256 internal constant _ROLE_45 = 1 << 45; + uint256 internal constant _ROLE_46 = 1 << 46; + uint256 internal constant _ROLE_47 = 1 << 47; + uint256 internal constant _ROLE_48 = 1 << 48; + uint256 internal constant _ROLE_49 = 1 << 49; + uint256 internal constant _ROLE_50 = 1 << 50; + uint256 internal constant _ROLE_51 = 1 << 51; + uint256 internal constant _ROLE_52 = 1 << 52; + uint256 internal constant _ROLE_53 = 1 << 53; + uint256 internal constant _ROLE_54 = 1 << 54; + uint256 internal constant _ROLE_55 = 1 << 55; + uint256 internal constant _ROLE_56 = 1 << 56; + uint256 internal constant _ROLE_57 = 1 << 57; + uint256 internal constant _ROLE_58 = 1 << 58; + uint256 internal constant _ROLE_59 = 1 << 59; + uint256 internal constant _ROLE_60 = 1 << 60; + uint256 internal constant _ROLE_61 = 1 << 61; + uint256 internal constant _ROLE_62 = 1 << 62; + uint256 internal constant _ROLE_63 = 1 << 63; + uint256 internal constant _ROLE_64 = 1 << 64; + uint256 internal constant _ROLE_65 = 1 << 65; + uint256 internal constant _ROLE_66 = 1 << 66; + uint256 internal constant _ROLE_67 = 1 << 67; + uint256 internal constant _ROLE_68 = 1 << 68; + uint256 internal constant _ROLE_69 = 1 << 69; + uint256 internal constant _ROLE_70 = 1 << 70; + uint256 internal constant _ROLE_71 = 1 << 71; + uint256 internal constant _ROLE_72 = 1 << 72; + uint256 internal constant _ROLE_73 = 1 << 73; + uint256 internal constant _ROLE_74 = 1 << 74; + uint256 internal constant _ROLE_75 = 1 << 75; + uint256 internal constant _ROLE_76 = 1 << 76; + uint256 internal constant _ROLE_77 = 1 << 77; + uint256 internal constant _ROLE_78 = 1 << 78; + uint256 internal constant _ROLE_79 = 1 << 79; + uint256 internal constant _ROLE_80 = 1 << 80; + uint256 internal constant _ROLE_81 = 1 << 81; + uint256 internal constant _ROLE_82 = 1 << 82; + uint256 internal constant _ROLE_83 = 1 << 83; + uint256 internal constant _ROLE_84 = 1 << 84; + uint256 internal constant _ROLE_85 = 1 << 85; + uint256 internal constant _ROLE_86 = 1 << 86; + uint256 internal constant _ROLE_87 = 1 << 87; + uint256 internal constant _ROLE_88 = 1 << 88; + uint256 internal constant _ROLE_89 = 1 << 89; + uint256 internal constant _ROLE_90 = 1 << 90; + uint256 internal constant _ROLE_91 = 1 << 91; + uint256 internal constant _ROLE_92 = 1 << 92; + uint256 internal constant _ROLE_93 = 1 << 93; + uint256 internal constant _ROLE_94 = 1 << 94; + uint256 internal constant _ROLE_95 = 1 << 95; + uint256 internal constant _ROLE_96 = 1 << 96; + uint256 internal constant _ROLE_97 = 1 << 97; + uint256 internal constant _ROLE_98 = 1 << 98; + uint256 internal constant _ROLE_99 = 1 << 99; + uint256 internal constant _ROLE_100 = 1 << 100; + uint256 internal constant _ROLE_101 = 1 << 101; + uint256 internal constant _ROLE_102 = 1 << 102; + uint256 internal constant _ROLE_103 = 1 << 103; + uint256 internal constant _ROLE_104 = 1 << 104; + uint256 internal constant _ROLE_105 = 1 << 105; + uint256 internal constant _ROLE_106 = 1 << 106; + uint256 internal constant _ROLE_107 = 1 << 107; + uint256 internal constant _ROLE_108 = 1 << 108; + uint256 internal constant _ROLE_109 = 1 << 109; + uint256 internal constant _ROLE_110 = 1 << 110; + uint256 internal constant _ROLE_111 = 1 << 111; + uint256 internal constant _ROLE_112 = 1 << 112; + uint256 internal constant _ROLE_113 = 1 << 113; + uint256 internal constant _ROLE_114 = 1 << 114; + uint256 internal constant _ROLE_115 = 1 << 115; + uint256 internal constant _ROLE_116 = 1 << 116; + uint256 internal constant _ROLE_117 = 1 << 117; + uint256 internal constant _ROLE_118 = 1 << 118; + uint256 internal constant _ROLE_119 = 1 << 119; + uint256 internal constant _ROLE_120 = 1 << 120; + uint256 internal constant _ROLE_121 = 1 << 121; + uint256 internal constant _ROLE_122 = 1 << 122; + uint256 internal constant _ROLE_123 = 1 << 123; + uint256 internal constant _ROLE_124 = 1 << 124; + uint256 internal constant _ROLE_125 = 1 << 125; + uint256 internal constant _ROLE_126 = 1 << 126; + uint256 internal constant _ROLE_127 = 1 << 127; + uint256 internal constant _ROLE_128 = 1 << 128; + uint256 internal constant _ROLE_129 = 1 << 129; + uint256 internal constant _ROLE_130 = 1 << 130; + uint256 internal constant _ROLE_131 = 1 << 131; + uint256 internal constant _ROLE_132 = 1 << 132; + uint256 internal constant _ROLE_133 = 1 << 133; + uint256 internal constant _ROLE_134 = 1 << 134; + uint256 internal constant _ROLE_135 = 1 << 135; + uint256 internal constant _ROLE_136 = 1 << 136; + uint256 internal constant _ROLE_137 = 1 << 137; + uint256 internal constant _ROLE_138 = 1 << 138; + uint256 internal constant _ROLE_139 = 1 << 139; + uint256 internal constant _ROLE_140 = 1 << 140; + uint256 internal constant _ROLE_141 = 1 << 141; + uint256 internal constant _ROLE_142 = 1 << 142; + uint256 internal constant _ROLE_143 = 1 << 143; + uint256 internal constant _ROLE_144 = 1 << 144; + uint256 internal constant _ROLE_145 = 1 << 145; + uint256 internal constant _ROLE_146 = 1 << 146; + uint256 internal constant _ROLE_147 = 1 << 147; + uint256 internal constant _ROLE_148 = 1 << 148; + uint256 internal constant _ROLE_149 = 1 << 149; + uint256 internal constant _ROLE_150 = 1 << 150; + uint256 internal constant _ROLE_151 = 1 << 151; + uint256 internal constant _ROLE_152 = 1 << 152; + uint256 internal constant _ROLE_153 = 1 << 153; + uint256 internal constant _ROLE_154 = 1 << 154; + uint256 internal constant _ROLE_155 = 1 << 155; + uint256 internal constant _ROLE_156 = 1 << 156; + uint256 internal constant _ROLE_157 = 1 << 157; + uint256 internal constant _ROLE_158 = 1 << 158; + uint256 internal constant _ROLE_159 = 1 << 159; + uint256 internal constant _ROLE_160 = 1 << 160; + uint256 internal constant _ROLE_161 = 1 << 161; + uint256 internal constant _ROLE_162 = 1 << 162; + uint256 internal constant _ROLE_163 = 1 << 163; + uint256 internal constant _ROLE_164 = 1 << 164; + uint256 internal constant _ROLE_165 = 1 << 165; + uint256 internal constant _ROLE_166 = 1 << 166; + uint256 internal constant _ROLE_167 = 1 << 167; + uint256 internal constant _ROLE_168 = 1 << 168; + uint256 internal constant _ROLE_169 = 1 << 169; + uint256 internal constant _ROLE_170 = 1 << 170; + uint256 internal constant _ROLE_171 = 1 << 171; + uint256 internal constant _ROLE_172 = 1 << 172; + uint256 internal constant _ROLE_173 = 1 << 173; + uint256 internal constant _ROLE_174 = 1 << 174; + uint256 internal constant _ROLE_175 = 1 << 175; + uint256 internal constant _ROLE_176 = 1 << 176; + uint256 internal constant _ROLE_177 = 1 << 177; + uint256 internal constant _ROLE_178 = 1 << 178; + uint256 internal constant _ROLE_179 = 1 << 179; + uint256 internal constant _ROLE_180 = 1 << 180; + uint256 internal constant _ROLE_181 = 1 << 181; + uint256 internal constant _ROLE_182 = 1 << 182; + uint256 internal constant _ROLE_183 = 1 << 183; + uint256 internal constant _ROLE_184 = 1 << 184; + uint256 internal constant _ROLE_185 = 1 << 185; + uint256 internal constant _ROLE_186 = 1 << 186; + uint256 internal constant _ROLE_187 = 1 << 187; + uint256 internal constant _ROLE_188 = 1 << 188; + uint256 internal constant _ROLE_189 = 1 << 189; + uint256 internal constant _ROLE_190 = 1 << 190; + uint256 internal constant _ROLE_191 = 1 << 191; + uint256 internal constant _ROLE_192 = 1 << 192; + uint256 internal constant _ROLE_193 = 1 << 193; + uint256 internal constant _ROLE_194 = 1 << 194; + uint256 internal constant _ROLE_195 = 1 << 195; + uint256 internal constant _ROLE_196 = 1 << 196; + uint256 internal constant _ROLE_197 = 1 << 197; + uint256 internal constant _ROLE_198 = 1 << 198; + uint256 internal constant _ROLE_199 = 1 << 199; + uint256 internal constant _ROLE_200 = 1 << 200; + uint256 internal constant _ROLE_201 = 1 << 201; + uint256 internal constant _ROLE_202 = 1 << 202; + uint256 internal constant _ROLE_203 = 1 << 203; + uint256 internal constant _ROLE_204 = 1 << 204; + uint256 internal constant _ROLE_205 = 1 << 205; + uint256 internal constant _ROLE_206 = 1 << 206; + uint256 internal constant _ROLE_207 = 1 << 207; + uint256 internal constant _ROLE_208 = 1 << 208; + uint256 internal constant _ROLE_209 = 1 << 209; + uint256 internal constant _ROLE_210 = 1 << 210; + uint256 internal constant _ROLE_211 = 1 << 211; + uint256 internal constant _ROLE_212 = 1 << 212; + uint256 internal constant _ROLE_213 = 1 << 213; + uint256 internal constant _ROLE_214 = 1 << 214; + uint256 internal constant _ROLE_215 = 1 << 215; + uint256 internal constant _ROLE_216 = 1 << 216; + uint256 internal constant _ROLE_217 = 1 << 217; + uint256 internal constant _ROLE_218 = 1 << 218; + uint256 internal constant _ROLE_219 = 1 << 219; + uint256 internal constant _ROLE_220 = 1 << 220; + uint256 internal constant _ROLE_221 = 1 << 221; + uint256 internal constant _ROLE_222 = 1 << 222; + uint256 internal constant _ROLE_223 = 1 << 223; + uint256 internal constant _ROLE_224 = 1 << 224; + uint256 internal constant _ROLE_225 = 1 << 225; + uint256 internal constant _ROLE_226 = 1 << 226; + uint256 internal constant _ROLE_227 = 1 << 227; + uint256 internal constant _ROLE_228 = 1 << 228; + uint256 internal constant _ROLE_229 = 1 << 229; + uint256 internal constant _ROLE_230 = 1 << 230; + uint256 internal constant _ROLE_231 = 1 << 231; + uint256 internal constant _ROLE_232 = 1 << 232; + uint256 internal constant _ROLE_233 = 1 << 233; + uint256 internal constant _ROLE_234 = 1 << 234; + uint256 internal constant _ROLE_235 = 1 << 235; + uint256 internal constant _ROLE_236 = 1 << 236; + uint256 internal constant _ROLE_237 = 1 << 237; + uint256 internal constant _ROLE_238 = 1 << 238; + uint256 internal constant _ROLE_239 = 1 << 239; + uint256 internal constant _ROLE_240 = 1 << 240; + uint256 internal constant _ROLE_241 = 1 << 241; + uint256 internal constant _ROLE_242 = 1 << 242; + uint256 internal constant _ROLE_243 = 1 << 243; + uint256 internal constant _ROLE_244 = 1 << 244; + uint256 internal constant _ROLE_245 = 1 << 245; + uint256 internal constant _ROLE_246 = 1 << 246; + uint256 internal constant _ROLE_247 = 1 << 247; + uint256 internal constant _ROLE_248 = 1 << 248; + uint256 internal constant _ROLE_249 = 1 << 249; + uint256 internal constant _ROLE_250 = 1 << 250; + uint256 internal constant _ROLE_251 = 1 << 251; + uint256 internal constant _ROLE_252 = 1 << 252; + uint256 internal constant _ROLE_253 = 1 << 253; + uint256 internal constant _ROLE_254 = 1 << 254; + uint256 internal constant _ROLE_255 = 1 << 255; +} + +// src\common/Treasury.sol + + + + + + +/// @title Treasury +/// @author Mathieu Bour for Pooky Labs Ltd. +/// +/// @notice Base class for contracts that are made to receive native currency. +/// The destination address is controller by the contract owner. +abstract contract Treasury is Ownable, ITreasury { + /// The native currency destination address. + address public treasury; + + constructor(address _treasury) { + treasury = _treasury; + } + + /// @notice Forward the funds to the treasury wallet at the end of the transaction. + /// Since `treasury` is a trusted address, this modifier should not lead to any re-entrancy issue. + modifier forwarder() { + _; + + uint256 value = address(this).balance; + (bool sent,) = treasury.call{ value: value }(""); + if (!sent) { + revert TransferFailed(treasury, value); + } + } + + /// Change the native currency destination address. + /// @param _treasury The new treasury address. + function changeTreasury(address _treasury) external onlyOwner { + treasury = _treasury; + } +} + +// src\tokens/IPOK.sol + + + + + + +/// @title IPOK +/// @author Mathieu Bour, Dusan Zdravkovic for Pooky Labs Ltd. +/// +/// @notice Minimal $POK ERC20 token interface. +interface IPOK is IAccessControl, IERC20 { + /// @notice Mint an arbitrary amount of $POK to an account. + /// @dev Requirements: + /// - only MINTER role can mint $POK tokens + function mint(address to, uint256 amount) external; + + /// @notice Burn an arbitrary amount of $POK of an sender account. + /// It is acknowledged that burning directly from the user wallet is anti-pattern + /// but since $POK is soulbounded, this allow to skip the ERC20 approve call. + /// @dev Requirements: + /// - only BURNER role can burn $POK tokens + function burn(address to, uint256 amount) external; +} + +// src\common/Signer.sol + + + + + + +/// @title Signer +/// @author Mathieu Bour for Pooky Labs Ltd. +/// +/// @dev Provide the `verify` function and the `onlyVerify` modifier to child contracts. +abstract contract Signer is OwnableRoles { + using ECDSA for bytes32; + + uint256 public constant SIGNER = _ROLE_42; + + /// Thrown when the signature is invalid. + error InvalidSignature(); + + constructor(address signer) { + _grantRoles(signer, SIGNER); + } + + /// @notice Ensure that `data` has been signed by a `SIGNER` using the `proof`. + function verify(bytes memory data, bytes calldata proof) internal view { + // Generate the signed message from the tokenId and currentPXP + bytes32 hash = keccak256(data).toEthSignedMessageHash(); + + if (!hasAllRoles(hash.recoverCalldata(proof), SIGNER)) { + revert InvalidSignature(); + } + } + + /// @notice Modifier version of the `verify` function. + modifier onlyVerify(bytes memory data, bytes calldata proof) { + verify(data, proof); + _; + } +} + +// src\pookyball/IPookyball.sol + + + + + + + +/// @title PookyballMetadata +/// @notice The Pookyball rarities are represented on chain by this enum. +enum PookyballRarity { + COMMON, + RARE, + EPIC, + LEGENDARY, + MYTHIC +} + +/// @title PookyballMetadata +/// @notice Pookyballs NFT have the following features: +/// - rarity: integer enum. +/// - level: token level, can be increase by spending token experiences points (PXP). +/// - pxp: token experience points. +/// - seed: a random uint256 word provided by Chainlink VRF service that will be used by Pooky's NFT generator +/// back-end to generate the NFT visuals and in-game statistics\. +struct PookyballMetadata { + PookyballRarity rarity; + uint256 level; + uint256 pxp; + uint256 seed; +} + +/// @title IPookyball +/// @author Mathieu Bour for Pooky Labs Ltd. +/// @notice Minimal Pookyball interface. +interface IPookyball is IAccessControl, IERC2981, IERC721 { + /// Fired when the seed of a Pookyball token is set by the VRFCoordinator + event SeedSet(uint256 indexed tokenId, uint256 seed); + /// Fired when the level of a Pookyball token is changed + event LevelChanged(uint256 indexed tokenId, uint256 level); + /// Fired when the PXP of a Pookyball token is changed + event PXPChanged(uint256 indexed tokenId, uint256 amount); + + /// Thrown when the length of two parameters mismatch. Used in the mint batched function. + error ArgumentSizeMismatch(uint256 x, uint256 y); + + /// @notice PookyballMetadata of the token {tokenId}. + /// @dev Requirements: + /// - Pookyball {tokenId} should exist (minted and not burned). + function metadata(uint256 tokenId) external view returns (PookyballMetadata memory); + + /// @notice Change the secondary sale royalties receiver address. + function setERC2981Receiver(address newReceiver) external; + + /// @notice Mint a new Pookyball token with a given rarity. + function mint(address[] memory recipients, PookyballRarity[] memory rarities) + external + returns (uint256); + + /// @notice Change the level of a Pookyball token. + /// @dev Requirements: + /// - Pookyball {tokenId} should exist (minted and not burned). + function setLevel(uint256 tokenId, uint256 newLevel) external; + + /// @notice Change the PXP of a Pookyball token. + /// @dev Requirements: + /// - Pookyball {tokenId} should exist (minted and not burned). + function setPXP(uint256 tokenId, uint256 newPXP) external; +} + +// src\common/LevelUp.sol + + + + + + + + + + +struct Pricing { + uint256 requiredPXP; + uint256 remainingPXP; + uint256 newLevel; + uint256 gapPOK; + uint256 feePOK; +} + +/// @title LevelUp +/// @author Mathieu Bour for Pooky Labs Ltd. +/// +/// @notice Base level up contract for tokens using exponential level growth, POK/NAT integration and offchain PXP. +/// @dev Implemented roles: +/// - Owner: allowed to change the pricing +/// - `SIGNER`: allowed to sign the current PXP +abstract contract LevelUp is OwnableRoles, Signer, Treasury { + uint256 public constant PXP_DECIMALS = 18; + uint256 public constant BASE_RATIO = 10000; + + /// @notice How much PXP is necessary is required to pass to the level 0 => 1. + uint256 public basePXP; + + /// @notice How much POK is 1 PXP point (over 10000). + uint256 public ratePXP_POK = 1250; + + /// @notice How much POK is 1 native currency (over 10000). + uint256 public rateNAT_POK = 350; + + /// @notice Level PXP growth factor (over 10000). + /// Example: 10750 means that every level requires 7.5% more PXP that the previous one. + uint256 public growth = 10750; + + /// @notice The POK fee required to pass the level (over 10000). + /// Example: 800 means that every level requires 8% of the level PXP in POK. + uint256 public fee = 800; + + /// @notice The POK token destination address. + IPOK public immutable pok; + + mapping(uint256 => uint256) public slots; + + /// Thrown when an account tries to level a ball above its maximum level. + error MaximumLevelReached(uint256 tokenId, uint256 maxLevel); + /// Thrown when an account does own enough $POK token to pay the level up fee + error InsufficientPOK(uint256 expected, uint256 actual); + + constructor( + IPOK _pok, + address admin, + address _signer, + address _treasury, + uint256 _basePXP, + uint256 precompute + ) Signer(_signer) Treasury(_treasury) { + pok = _pok; + _initializeOwner(admin); + basePXP = _basePXP; + slots[1] = _basePXP; + compute(2, precompute); + } + + function compute(uint256 from, uint256 to) public { + for (uint256 i = from; i <= to;) { + slots[i] = slots[i - 1] * growth / 10000; + unchecked { + i++; + } + } + } + + /// Change how much PXP is necessary is required to pass to the level 0 => 1. + /// @param _basePXP The new base PXP value. + function changeBasePXP(uint256 _basePXP) external onlyOwner { + basePXP = _basePXP; + } + + /// Change how much POK is 1 PXP point (over 10000). + /// @param _ratePXP_POK The new PXP/POK rate value. + function changeRatePXP_POK(uint256 _ratePXP_POK) external onlyOwner { + ratePXP_POK = _ratePXP_POK; + } + + /// Change how much POK is 1 native currency (over 10000). + /// @param _rateNAT_POK The new NAT/POK rate value. + function changeRateNAT_POK(uint256 _rateNAT_POK) external onlyOwner { + rateNAT_POK = _rateNAT_POK; + } + + /// Change the level PXP growth factor. + /// @param _growth The new growth factor. + function changeGrowth(uint256 _growth) external onlyOwner { + growth = _growth; + } + + /// Change the POK fee required to pass the level. + /// @param _fee The new POK fee. + function changeFee(uint256 _fee) external onlyOwner { + fee = _fee; + } + + /// @notice Get the levelling parameters for a given token. + /// @param tokenId The token id. + /// @return currentLevel The current token level. + /// @return maxLevel The maximum allowed level. + function getParams(uint256 tokenId) + public + virtual + returns (uint256 currentLevel, uint256 maxLevel); + + /// Apply the new level and PXP change. + /// @param tokenId The token id. + /// @param newLevel The new level. + /// @param newPXP The new PXP amount. + function _apply(uint256 tokenId, uint256 newLevel, uint256 newPXP) internal virtual; + + /// Compute the level up pricing given the token parameters. + /// @param currentLevel The token current level. + /// @param currentPXP The token current PXP. + /// @param increase The number of level to increase. + /// @param value The transaction value in native currency. + function getPricing(uint256 currentLevel, uint256 currentPXP, uint256 increase, uint256 value) + public + view + returns (Pricing memory pricing) + { + for (uint256 i = 1; i <= increase; i++) { + pricing.requiredPXP += slots[currentLevel + i]; + } + + if (pricing.requiredPXP > currentPXP) { + pricing.gapPOK = (pricing.requiredPXP - currentPXP) * ratePXP_POK / BASE_RATIO; + } else { + pricing.remainingPXP = currentPXP - pricing.requiredPXP; + } + + pricing.feePOK = pricing.requiredPXP * fee / BASE_RATIO; + uint256 coverPOK = value * BASE_RATIO / rateNAT_POK; + + if (pricing.feePOK > coverPOK) { + pricing.feePOK -= coverPOK; + } else { + pricing.feePOK = 0; + } + + pricing.newLevel = currentLevel + increase; + } + + /// Level up a token with offchain PXP validation. + /// @param tokenId The token id. + /// @param increase The number of levels to increase. + /// @param currentPXP The token current PXP. + /// @param proof The signature of `abi.encode(tokenId, currentLevel, currentPXP, address(this))`. + function levelUp(uint256 tokenId, uint256 increase, uint256 currentPXP, bytes calldata proof) + external + payable + forwarder + { + (uint256 currentLevel, uint256 maxLevel) = getParams(tokenId); + if (currentLevel + increase > maxLevel) { + revert MaximumLevelReached(tokenId, maxLevel); + } + + verify(abi.encode(tokenId, currentLevel, currentPXP, address(this)), proof); + + Pricing memory pricing = getPricing(currentLevel, currentPXP, increase, msg.value); + uint256 requiredPOK = pricing.gapPOK + pricing.feePOK; + + uint256 balancePOK = pok.balanceOf(msg.sender); + if (requiredPOK > balancePOK) { + revert InsufficientPOK(requiredPOK, balancePOK); + } + + // Burn $POK tokens + pok.burn(msg.sender, requiredPOK); + + _apply(tokenId, pricing.newLevel, pricing.remainingPXP); + } +} + +// src\pookyball\PookyballLevelUp.sol + + + + + + + +/// @title PookyballLevelUp +/// @author Mathieu Bour for Pooky Labs Ltd. +/// +/// @notice Allow to level up Pooky Pookyball tokens. +contract PookyballLevelUp is LevelUp { + /// The Pookyball contract. + IPookyball pookyball; + + /// @param _pookyball The Pookyball ERC-721 contract. + /// @param _pok The POK ERC-20 contract. + /// @param admin The new admin address. + /// @param _signer The inital signer address. + /// @param _treasury The initial treasury address. + constructor(IPookyball _pookyball, IPOK _pok, address admin, address _signer, address _treasury) + LevelUp(_pok, admin, _signer, _treasury, 60e18, 120) + { + pookyball = _pookyball; + } + + /// @notice Get the levelling parameters for a given token. + /// @param tokenId The token id. + /// @return currentLevel The current token level. + /// @return maxLevel The maximum allowed level. + function getParams(uint256 tokenId) + public + view + override + returns (uint256 currentLevel, uint256 maxLevel) + { + PookyballMetadata memory metadata = pookyball.metadata(tokenId); + currentLevel = metadata.level; + + if (metadata.rarity == PookyballRarity.COMMON) { + maxLevel = 40; + } else if (metadata.rarity == PookyballRarity.RARE) { + maxLevel = 60; + } else if (metadata.rarity == PookyballRarity.EPIC) { + maxLevel = 80; + } else if (metadata.rarity == PookyballRarity.LEGENDARY) { + maxLevel = 100; + } else if (metadata.rarity == PookyballRarity.MYTHIC) { + maxLevel = 120; + } + } + + function _apply(uint256 tokenId, uint256 newLevel, uint256) internal virtual override { + pookyball.setLevel(tokenId, newLevel); + } +} diff --git a/flattened/PookyballReroll.sol b/flattened/PookyballReroll.sol new file mode 100644 index 00000000..a0ff4498 --- /dev/null +++ b/flattened/PookyballReroll.sol @@ -0,0 +1,1704 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0 ^0.8.17 ^0.8.21 ^0.8.4; + +// lib/openzeppelin-contracts/contracts\access/IAccessControl.sol + +// OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol) + + + +/** + * @dev External interface of AccessControl declared to support ERC165 detection. + */ +interface IAccessControl { + /** + * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` + * + * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite + * {RoleAdminChanged} not being emitted signaling this. + * + * _Available since v3.1._ + */ + event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole); + + /** + * @dev Emitted when `account` is granted `role`. + * + * `sender` is the account that originated the contract call, an admin role + * bearer except when using {AccessControl-_setupRole}. + */ + event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender); + + /** + * @dev Emitted when `account` is revoked `role`. + * + * `sender` is the account that originated the contract call: + * - if using `revokeRole`, it is the admin role bearer + * - if using `renounceRole`, it is the role bearer (i.e. `account`) + */ + event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender); + + /** + * @dev Returns `true` if `account` has been granted `role`. + */ + function hasRole(bytes32 role, address account) external view returns (bool); + + /** + * @dev Returns the admin role that controls `role`. See {grantRole} and + * {revokeRole}. + * + * To change a role's admin, use {AccessControl-_setRoleAdmin}. + */ + function getRoleAdmin(bytes32 role) external view returns (bytes32); + + /** + * @dev Grants `role` to `account`. + * + * If `account` had not been already granted `role`, emits a {RoleGranted} + * event. + * + * Requirements: + * + * - the caller must have ``role``'s admin role. + */ + function grantRole(bytes32 role, address account) external; + + /** + * @dev Revokes `role` from `account`. + * + * If `account` had been granted `role`, emits a {RoleRevoked} event. + * + * Requirements: + * + * - the caller must have ``role``'s admin role. + */ + function revokeRole(bytes32 role, address account) external; + + /** + * @dev Revokes `role` from the calling account. + * + * Roles are often managed via {grantRole} and {revokeRole}: this function's + * purpose is to provide a mechanism for accounts to lose their privileges + * if they are compromised (such as when a trusted device is misplaced). + * + * If the calling account had been granted `role`, emits a {RoleRevoked} + * event. + * + * Requirements: + * + * - the caller must be `account`. + */ + function renounceRole(bytes32 role, address account) external; +} + +// lib/openzeppelin-contracts/contracts/utils/introspection/IERC165.sol + +// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol) + + + +/** + * @dev Interface of the ERC165 standard, as defined in the + * https://eips.ethereum.org/EIPS/eip-165[EIP]. + * + * Implementers can declare support of contract interfaces, which can then be + * queried by others ({ERC165Checker}). + * + * For an implementation, see {ERC165}. + */ +interface IERC165 { + /** + * @dev Returns true if this contract implements the interface defined by + * `interfaceId`. See the corresponding + * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] + * to learn more about how these ids are created. + * + * This function call must use less than 30 000 gas. + */ + function supportsInterface(bytes4 interfaceId) external view returns (bool); +} + +// lib/solady/src/auth/Ownable.sol + + + +/// @notice Simple single owner authorization mixin. +/// @author Solady (https://github.com/vectorized/solady/blob/main/src/auth/Ownable.sol) +/// @dev While the ownable portion follows +/// [EIP-173](https://eips.ethereum.org/EIPS/eip-173) for compatibility, +/// the nomenclature for the 2-step ownership handover may be unique to this codebase. +abstract contract Ownable { + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* CUSTOM ERRORS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev The caller is not authorized to call the function. + error Unauthorized(); + + /// @dev The `newOwner` cannot be the zero address. + error NewOwnerIsZeroAddress(); + + /// @dev The `pendingOwner` does not have a valid handover request. + error NoHandoverRequest(); + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* EVENTS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev The ownership is transferred from `oldOwner` to `newOwner`. + /// This event is intentionally kept the same as OpenZeppelin's Ownable to be + /// compatible with indexers and [EIP-173](https://eips.ethereum.org/EIPS/eip-173), + /// despite it not being as lightweight as a single argument event. + event OwnershipTransferred(address indexed oldOwner, address indexed newOwner); + + /// @dev An ownership handover to `pendingOwner` has been requested. + event OwnershipHandoverRequested(address indexed pendingOwner); + + /// @dev The ownership handover to `pendingOwner` has been canceled. + event OwnershipHandoverCanceled(address indexed pendingOwner); + + /// @dev `keccak256(bytes("OwnershipTransferred(address,address)"))`. + uint256 private constant _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE = + 0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0; + + /// @dev `keccak256(bytes("OwnershipHandoverRequested(address)"))`. + uint256 private constant _OWNERSHIP_HANDOVER_REQUESTED_EVENT_SIGNATURE = + 0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d; + + /// @dev `keccak256(bytes("OwnershipHandoverCanceled(address)"))`. + uint256 private constant _OWNERSHIP_HANDOVER_CANCELED_EVENT_SIGNATURE = + 0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92; + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* STORAGE */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev The owner slot is given by: `not(_OWNER_SLOT_NOT)`. + /// It is intentionally chosen to be a high value + /// to avoid collision with lower slots. + /// The choice of manual storage layout is to enable compatibility + /// with both regular and upgradeable contracts. + uint256 private constant _OWNER_SLOT_NOT = 0x8b78c6d8; + + /// The ownership handover slot of `newOwner` is given by: + /// ``` + /// mstore(0x00, or(shl(96, user), _HANDOVER_SLOT_SEED)) + /// let handoverSlot := keccak256(0x00, 0x20) + /// ``` + /// It stores the expiry timestamp of the two-step ownership handover. + uint256 private constant _HANDOVER_SLOT_SEED = 0x389a75e1; + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* INTERNAL FUNCTIONS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev Initializes the owner directly without authorization guard. + /// This function must be called upon initialization, + /// regardless of whether the contract is upgradeable or not. + /// This is to enable generalization to both regular and upgradeable contracts, + /// and to save gas in case the initial owner is not the caller. + /// For performance reasons, this function will not check if there + /// is an existing owner. + function _initializeOwner(address newOwner) internal virtual { + /// @solidity memory-safe-assembly + assembly { + // Clean the upper 96 bits. + newOwner := shr(96, shl(96, newOwner)) + // Store the new value. + sstore(not(_OWNER_SLOT_NOT), newOwner) + // Emit the {OwnershipTransferred} event. + log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, 0, newOwner) + } + } + + /// @dev Sets the owner directly without authorization guard. + function _setOwner(address newOwner) internal virtual { + /// @solidity memory-safe-assembly + assembly { + let ownerSlot := not(_OWNER_SLOT_NOT) + // Clean the upper 96 bits. + newOwner := shr(96, shl(96, newOwner)) + // Emit the {OwnershipTransferred} event. + log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, sload(ownerSlot), newOwner) + // Store the new value. + sstore(ownerSlot, newOwner) + } + } + + /// @dev Throws if the sender is not the owner. + function _checkOwner() internal view virtual { + /// @solidity memory-safe-assembly + assembly { + // If the caller is not the stored owner, revert. + if iszero(eq(caller(), sload(not(_OWNER_SLOT_NOT)))) { + mstore(0x00, 0x82b42900) // `Unauthorized()`. + revert(0x1c, 0x04) + } + } + } + + /// @dev Returns how long a two-step ownership handover is valid for in seconds. + /// Override to return a different value if needed. + /// Made internal to conserve bytecode. Wrap it in a public function if needed. + function _ownershipHandoverValidFor() internal view virtual returns (uint64) { + return 48 * 3600; + } + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* PUBLIC UPDATE FUNCTIONS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev Allows the owner to transfer the ownership to `newOwner`. + function transferOwnership(address newOwner) public payable virtual onlyOwner { + /// @solidity memory-safe-assembly + assembly { + if iszero(shl(96, newOwner)) { + mstore(0x00, 0x7448fbae) // `NewOwnerIsZeroAddress()`. + revert(0x1c, 0x04) + } + } + _setOwner(newOwner); + } + + /// @dev Allows the owner to renounce their ownership. + function renounceOwnership() public payable virtual onlyOwner { + _setOwner(address(0)); + } + + /// @dev Request a two-step ownership handover to the caller. + /// The request will automatically expire in 48 hours (172800 seconds) by default. + function requestOwnershipHandover() public payable virtual { + unchecked { + uint256 expires = block.timestamp + _ownershipHandoverValidFor(); + /// @solidity memory-safe-assembly + assembly { + // Compute and set the handover slot to `expires`. + mstore(0x0c, _HANDOVER_SLOT_SEED) + mstore(0x00, caller()) + sstore(keccak256(0x0c, 0x20), expires) + // Emit the {OwnershipHandoverRequested} event. + log2(0, 0, _OWNERSHIP_HANDOVER_REQUESTED_EVENT_SIGNATURE, caller()) + } + } + } + + /// @dev Cancels the two-step ownership handover to the caller, if any. + function cancelOwnershipHandover() public payable virtual { + /// @solidity memory-safe-assembly + assembly { + // Compute and set the handover slot to 0. + mstore(0x0c, _HANDOVER_SLOT_SEED) + mstore(0x00, caller()) + sstore(keccak256(0x0c, 0x20), 0) + // Emit the {OwnershipHandoverCanceled} event. + log2(0, 0, _OWNERSHIP_HANDOVER_CANCELED_EVENT_SIGNATURE, caller()) + } + } + + /// @dev Allows the owner to complete the two-step ownership handover to `pendingOwner`. + /// Reverts if there is no existing ownership handover requested by `pendingOwner`. + function completeOwnershipHandover(address pendingOwner) public payable virtual onlyOwner { + /// @solidity memory-safe-assembly + assembly { + // Compute and set the handover slot to 0. + mstore(0x0c, _HANDOVER_SLOT_SEED) + mstore(0x00, pendingOwner) + let handoverSlot := keccak256(0x0c, 0x20) + // If the handover does not exist, or has expired. + if gt(timestamp(), sload(handoverSlot)) { + mstore(0x00, 0x6f5e8818) // `NoHandoverRequest()`. + revert(0x1c, 0x04) + } + // Set the handover slot to 0. + sstore(handoverSlot, 0) + } + _setOwner(pendingOwner); + } + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* PUBLIC READ FUNCTIONS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev Returns the owner of the contract. + function owner() public view virtual returns (address result) { + /// @solidity memory-safe-assembly + assembly { + result := sload(not(_OWNER_SLOT_NOT)) + } + } + + /// @dev Returns the expiry timestamp for the two-step ownership handover to `pendingOwner`. + function ownershipHandoverExpiresAt(address pendingOwner) + public + view + virtual + returns (uint256 result) + { + /// @solidity memory-safe-assembly + assembly { + // Compute the handover slot. + mstore(0x0c, _HANDOVER_SLOT_SEED) + mstore(0x00, pendingOwner) + // Load the handover slot. + result := sload(keccak256(0x0c, 0x20)) + } + } + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* MODIFIERS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev Marks a function as only callable by the owner. + modifier onlyOwner() virtual { + _checkOwner(); + _; + } +} + +// lib/solady/src\utils/ECDSA.sol + + + +/// @notice Gas optimized ECDSA wrapper. +/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/ECDSA.sol) +/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/ECDSA.sol) +/// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/cryptography/ECDSA.sol) +library ECDSA { + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* CUSTOM ERRORS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev The signature is invalid. + error InvalidSignature(); + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* CONSTANTS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev The number which `s` must be less than in order for + /// the signature to be non-malleable. + bytes32 private constant _MALLEABILITY_THRESHOLD_PLUS_ONE = + 0x7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a1; + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* RECOVERY OPERATIONS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + // Note: as of Solady version 0.0.68, these functions will + // revert upon recovery failure for more safety by default. + + /// @dev Recovers the signer's address from a message digest `hash`, + /// and the `signature`. + /// + /// This function does NOT accept EIP-2098 short form signatures. + /// Use `recover(bytes32 hash, bytes32 r, bytes32 vs)` for EIP-2098 + /// short form signatures instead. + function recover(bytes32 hash, bytes memory signature) internal view returns (address result) { + /// @solidity memory-safe-assembly + assembly { + let m := mload(0x40) // Cache the free memory pointer. + mstore(0x00, hash) + mstore(0x20, byte(0, mload(add(signature, 0x60)))) // `v`. + mstore(0x40, mload(add(signature, 0x20))) // `r`. + mstore(0x60, mload(add(signature, 0x40))) // `s`. + pop( + staticcall( + gas(), // Amount of gas left for the transaction. + and( + // If the signature is exactly 65 bytes in length. + eq(mload(signature), 65), + // If `s` in lower half order, such that the signature is not malleable. + lt(mload(0x60), _MALLEABILITY_THRESHOLD_PLUS_ONE) + ), // Address of `ecrecover`. + 0x00, // Start of input. + 0x80, // Size of input. + 0x00, // Start of output. + 0x20 // Size of output. + ) + ) + result := mload(0x00) + // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise. + if iszero(returndatasize()) { + mstore(0x00, 0x8baa579f) // `InvalidSignature()`. + revert(0x1c, 0x04) + } + mstore(0x60, 0) // Restore the zero slot. + mstore(0x40, m) // Restore the free memory pointer. + } + } + + /// @dev Recovers the signer's address from a message digest `hash`, + /// and the `signature`. + /// + /// This function does NOT accept EIP-2098 short form signatures. + /// Use `recover(bytes32 hash, bytes32 r, bytes32 vs)` for EIP-2098 + /// short form signatures instead. + function recoverCalldata(bytes32 hash, bytes calldata signature) + internal + view + returns (address result) + { + /// @solidity memory-safe-assembly + assembly { + let m := mload(0x40) // Cache the free memory pointer. + mstore(0x00, hash) + mstore(0x20, byte(0, calldataload(add(signature.offset, 0x40)))) // `v`. + calldatacopy(0x40, signature.offset, 0x40) // Copy `r` and `s`. + pop( + staticcall( + gas(), // Amount of gas left for the transaction. + and( + // If the signature is exactly 65 bytes in length. + eq(signature.length, 65), + // If `s` in lower half order, such that the signature is not malleable. + lt(mload(0x60), _MALLEABILITY_THRESHOLD_PLUS_ONE) + ), // Address of `ecrecover`. + 0x00, // Start of input. + 0x80, // Size of input. + 0x00, // Start of output. + 0x20 // Size of output. + ) + ) + result := mload(0x00) + // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise. + if iszero(returndatasize()) { + mstore(0x00, 0x8baa579f) // `InvalidSignature()`. + revert(0x1c, 0x04) + } + mstore(0x60, 0) // Restore the zero slot. + mstore(0x40, m) // Restore the free memory pointer. + } + } + + /// @dev Recovers the signer's address from a message digest `hash`, + /// and the EIP-2098 short form signature defined by `r` and `vs`. + /// + /// This function only accepts EIP-2098 short form signatures. + /// See: https://eips.ethereum.org/EIPS/eip-2098 + function recover(bytes32 hash, bytes32 r, bytes32 vs) internal view returns (address result) { + /// @solidity memory-safe-assembly + assembly { + let m := mload(0x40) // Cache the free memory pointer. + mstore(0x00, hash) + mstore(0x20, add(shr(255, vs), 27)) // `v`. + mstore(0x40, r) + mstore(0x60, shr(1, shl(1, vs))) // `s`. + pop( + staticcall( + gas(), // Amount of gas left for the transaction. + // If `s` in lower half order, such that the signature is not malleable. + lt(mload(0x60), _MALLEABILITY_THRESHOLD_PLUS_ONE), // Address of `ecrecover`. + 0x00, // Start of input. + 0x80, // Size of input. + 0x00, // Start of output. + 0x20 // Size of output. + ) + ) + result := mload(0x00) + // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise. + if iszero(returndatasize()) { + mstore(0x00, 0x8baa579f) // `InvalidSignature()`. + revert(0x1c, 0x04) + } + mstore(0x60, 0) // Restore the zero slot. + mstore(0x40, m) // Restore the free memory pointer. + } + } + + /// @dev Recovers the signer's address from a message digest `hash`, + /// and the signature defined by `v`, `r`, `s`. + function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) + internal + view + returns (address result) + { + /// @solidity memory-safe-assembly + assembly { + let m := mload(0x40) // Cache the free memory pointer. + mstore(0x00, hash) + mstore(0x20, and(v, 0xff)) + mstore(0x40, r) + mstore(0x60, s) + pop( + staticcall( + gas(), // Amount of gas left for the transaction. + // If `s` in lower half order, such that the signature is not malleable. + lt(s, _MALLEABILITY_THRESHOLD_PLUS_ONE), // Address of `ecrecover`. + 0x00, // Start of input. + 0x80, // Size of input. + 0x00, // Start of output. + 0x20 // Size of output. + ) + ) + result := mload(0x00) + // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise. + if iszero(returndatasize()) { + mstore(0x00, 0x8baa579f) // `InvalidSignature()`. + revert(0x1c, 0x04) + } + mstore(0x60, 0) // Restore the zero slot. + mstore(0x40, m) // Restore the free memory pointer. + } + } + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* TRY-RECOVER OPERATIONS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + // WARNING! + // These functions will NOT revert upon recovery failure. + // Instead, they will return the zero address upon recovery failure. + // It is critical that the returned address is NEVER compared against + // a zero address (e.g. an uninitialized address variable). + + /// @dev Recovers the signer's address from a message digest `hash`, + /// and the `signature`. + /// + /// This function does NOT accept EIP-2098 short form signatures. + /// Use `recover(bytes32 hash, bytes32 r, bytes32 vs)` for EIP-2098 + /// short form signatures instead. + function tryRecover(bytes32 hash, bytes memory signature) + internal + view + returns (address result) + { + /// @solidity memory-safe-assembly + assembly { + let m := mload(0x40) // Cache the free memory pointer. + mstore(0x00, hash) + mstore(0x20, byte(0, mload(add(signature, 0x60)))) // `v`. + mstore(0x40, mload(add(signature, 0x20))) // `r`. + mstore(0x60, mload(add(signature, 0x40))) // `s`. + pop( + staticcall( + gas(), // Amount of gas left for the transaction. + and( + // If the signature is exactly 65 bytes in length. + eq(mload(signature), 65), + // If `s` in lower half order, such that the signature is not malleable. + lt(mload(0x60), _MALLEABILITY_THRESHOLD_PLUS_ONE) + ), // Address of `ecrecover`. + 0x00, // Start of input. + 0x80, // Size of input. + 0x40, // Start of output. + 0x20 // Size of output. + ) + ) + mstore(0x60, 0) // Restore the zero slot. + // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise. + result := mload(xor(0x60, returndatasize())) + mstore(0x40, m) // Restore the free memory pointer. + } + } + + /// @dev Recovers the signer's address from a message digest `hash`, + /// and the `signature`. + /// + /// This function does NOT accept EIP-2098 short form signatures. + /// Use `recover(bytes32 hash, bytes32 r, bytes32 vs)` for EIP-2098 + /// short form signatures instead. + function tryRecoverCalldata(bytes32 hash, bytes calldata signature) + internal + view + returns (address result) + { + /// @solidity memory-safe-assembly + assembly { + let m := mload(0x40) // Cache the free memory pointer. + mstore(0x00, hash) + mstore(0x20, byte(0, calldataload(add(signature.offset, 0x40)))) // `v`. + calldatacopy(0x40, signature.offset, 0x40) // Copy `r` and `s`. + pop( + staticcall( + gas(), // Amount of gas left for the transaction. + and( + // If the signature is exactly 65 bytes in length. + eq(signature.length, 65), + // If `s` in lower half order, such that the signature is not malleable. + lt(mload(0x60), _MALLEABILITY_THRESHOLD_PLUS_ONE) + ), // Address of `ecrecover`. + 0x00, // Start of input. + 0x80, // Size of input. + 0x40, // Start of output. + 0x20 // Size of output. + ) + ) + mstore(0x60, 0) // Restore the zero slot. + // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise. + result := mload(xor(0x60, returndatasize())) + mstore(0x40, m) // Restore the free memory pointer. + } + } + + /// @dev Recovers the signer's address from a message digest `hash`, + /// and the EIP-2098 short form signature defined by `r` and `vs`. + /// + /// This function only accepts EIP-2098 short form signatures. + /// See: https://eips.ethereum.org/EIPS/eip-2098 + function tryRecover(bytes32 hash, bytes32 r, bytes32 vs) + internal + view + returns (address result) + { + /// @solidity memory-safe-assembly + assembly { + let m := mload(0x40) // Cache the free memory pointer. + mstore(0x00, hash) + mstore(0x20, add(shr(255, vs), 27)) // `v`. + mstore(0x40, r) + mstore(0x60, shr(1, shl(1, vs))) // `s`. + pop( + staticcall( + gas(), // Amount of gas left for the transaction. + // If `s` in lower half order, such that the signature is not malleable. + lt(mload(0x60), _MALLEABILITY_THRESHOLD_PLUS_ONE), // Address of `ecrecover`. + 0x00, // Start of input. + 0x80, // Size of input. + 0x40, // Start of output. + 0x20 // Size of output. + ) + ) + mstore(0x60, 0) // Restore the zero slot. + // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise. + result := mload(xor(0x60, returndatasize())) + mstore(0x40, m) // Restore the free memory pointer. + } + } + + /// @dev Recovers the signer's address from a message digest `hash`, + /// and the signature defined by `v`, `r`, `s`. + function tryRecover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) + internal + view + returns (address result) + { + /// @solidity memory-safe-assembly + assembly { + let m := mload(0x40) // Cache the free memory pointer. + mstore(0x00, hash) + mstore(0x20, and(v, 0xff)) + mstore(0x40, r) + mstore(0x60, s) + pop( + staticcall( + gas(), // Amount of gas left for the transaction. + // If `s` in lower half order, such that the signature is not malleable. + lt(s, _MALLEABILITY_THRESHOLD_PLUS_ONE), // Address of `ecrecover`. + 0x00, // Start of input. + 0x80, // Size of input. + 0x40, // Start of output. + 0x20 // Size of output. + ) + ) + mstore(0x60, 0) // Restore the zero slot. + // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise. + result := mload(xor(0x60, returndatasize())) + mstore(0x40, m) // Restore the free memory pointer. + } + } + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* HASHING OPERATIONS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev Returns an Ethereum Signed Message, created from a `hash`. + /// This produces a hash corresponding to the one signed with the + /// [`eth_sign`](https://eth.wiki/json-rpc/API#eth_sign) + /// JSON-RPC method as part of EIP-191. + function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32 result) { + /// @solidity memory-safe-assembly + assembly { + mstore(0x20, hash) // Store into scratch space for keccak256. + mstore(0x00, "\x00\x00\x00\x00\x19Ethereum Signed Message:\n32") // 28 bytes. + result := keccak256(0x04, 0x3c) // `32 * 2 - (32 - 28) = 60 = 0x3c`. + } + } + + /// @dev Returns an Ethereum Signed Message, created from `s`. + /// This produces a hash corresponding to the one signed with the + /// [`eth_sign`](https://eth.wiki/json-rpc/API#eth_sign) + /// JSON-RPC method as part of EIP-191. + /// Note: Supports lengths of `s` up to 999999 bytes. + function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32 result) { + /// @solidity memory-safe-assembly + assembly { + let sLength := mload(s) + let o := 0x20 + mstore(o, "\x19Ethereum Signed Message:\n") // 26 bytes, zero-right-padded. + mstore(0x00, 0x00) + // Convert the `s.length` to ASCII decimal representation: `base10(s.length)`. + for { let temp := sLength } 1 {} { + o := sub(o, 1) + mstore8(o, add(48, mod(temp, 10))) + temp := div(temp, 10) + if iszero(temp) { break } + } + let n := sub(0x3a, o) // Header length: `26 + 32 - o`. + // Throw an out-of-offset error (consumes all gas) if the header exceeds 32 bytes. + returndatacopy(returndatasize(), returndatasize(), gt(n, 0x20)) + mstore(s, or(mload(0x00), mload(n))) // Temporarily store the header. + result := keccak256(add(s, sub(0x20, n)), add(n, sLength)) + mstore(s, sLength) // Restore the length. + } + } + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* EMPTY CALLDATA HELPERS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev Returns an empty calldata bytes. + function emptySignature() internal pure returns (bytes calldata signature) { + /// @solidity memory-safe-assembly + assembly { + signature.length := 0 + } + } +} + +// src\common/ITreasury.sol + + + +/// @title ITreasury +/// @author Mathieu Bour for Pooky Labs Ltd. +interface ITreasury { + /// Thrown when the msg.value of the mint function does not cover the mint cost. + error InsufficientValue(uint256 expected, uint256 actual); + /// Thrown when the native transfer has failed. + error TransferFailed(address recipient, uint256 amount); + + /// Change the native currency destination address. + /// @param _treasury The new treasury address. + function changeTreasury(address _treasury) external; +} + +// lib/openzeppelin-contracts/contracts\interfaces/IERC2981.sol + +// OpenZeppelin Contracts (last updated v4.9.0) (interfaces/IERC2981.sol) + + + + + +/** + * @dev Interface for the NFT Royalty Standard. + * + * A standardized way to retrieve royalty payment information for non-fungible tokens (NFTs) to enable universal + * support for royalty payments across all NFT marketplaces and ecosystem participants. + * + * _Available since v4.5._ + */ +interface IERC2981 is IERC165 { + /** + * @dev Returns how much royalty is owed and to whom, based on a sale price that may be denominated in any unit of + * exchange. The royalty amount is denominated and should be paid in that same unit of exchange. + */ + function royaltyInfo( + uint256 tokenId, + uint256 salePrice + ) external view returns (address receiver, uint256 royaltyAmount); +} + +// lib/openzeppelin-contracts/contracts\token/ERC721/IERC721.sol + +// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC721/IERC721.sol) + + + + + +/** + * @dev Required interface of an ERC721 compliant contract. + */ +interface IERC721 is IERC165 { + /** + * @dev Emitted when `tokenId` token is transferred from `from` to `to`. + */ + event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); + + /** + * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token. + */ + event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); + + /** + * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets. + */ + event ApprovalForAll(address indexed owner, address indexed operator, bool approved); + + /** + * @dev Returns the number of tokens in ``owner``'s account. + */ + function balanceOf(address owner) external view returns (uint256 balance); + + /** + * @dev Returns the owner of the `tokenId` token. + * + * Requirements: + * + * - `tokenId` must exist. + */ + function ownerOf(uint256 tokenId) external view returns (address owner); + + /** + * @dev Safely transfers `tokenId` token from `from` to `to`. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must exist and be owned by `from`. + * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. + * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. + * + * Emits a {Transfer} event. + */ + function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external; + + /** + * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients + * are aware of the ERC721 protocol to prevent tokens from being forever locked. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must exist and be owned by `from`. + * - If the caller is not `from`, it must have been allowed to move this token by either {approve} or {setApprovalForAll}. + * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. + * + * Emits a {Transfer} event. + */ + function safeTransferFrom(address from, address to, uint256 tokenId) external; + + /** + * @dev Transfers `tokenId` token from `from` to `to`. + * + * WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721 + * or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must + * understand this adds an external call which potentially creates a reentrancy vulnerability. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must be owned by `from`. + * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. + * + * Emits a {Transfer} event. + */ + function transferFrom(address from, address to, uint256 tokenId) external; + + /** + * @dev Gives permission to `to` to transfer `tokenId` token to another account. + * The approval is cleared when the token is transferred. + * + * Only a single account can be approved at a time, so approving the zero address clears previous approvals. + * + * Requirements: + * + * - The caller must own the token or be an approved operator. + * - `tokenId` must exist. + * + * Emits an {Approval} event. + */ + function approve(address to, uint256 tokenId) external; + + /** + * @dev Approve or remove `operator` as an operator for the caller. + * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller. + * + * Requirements: + * + * - The `operator` cannot be the caller. + * + * Emits an {ApprovalForAll} event. + */ + function setApprovalForAll(address operator, bool approved) external; + + /** + * @dev Returns the account approved for `tokenId` token. + * + * Requirements: + * + * - `tokenId` must exist. + */ + function getApproved(uint256 tokenId) external view returns (address operator); + + /** + * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`. + * + * See {setApprovalForAll} + */ + function isApprovedForAll(address owner, address operator) external view returns (bool); +} + +// lib/solady/src\auth/OwnableRoles.sol + + + + + +/// @notice Simple single owner and multiroles authorization mixin. +/// @author Solady (https://github.com/vectorized/solady/blob/main/src/auth/Ownable.sol) +/// @dev While the ownable portion follows [EIP-173](https://eips.ethereum.org/EIPS/eip-173) +/// for compatibility, the nomenclature for the 2-step ownership handover and roles +/// may be unique to this codebase. +abstract contract OwnableRoles is Ownable { + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* EVENTS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev The `user`'s roles is updated to `roles`. + /// Each bit of `roles` represents whether the role is set. + event RolesUpdated(address indexed user, uint256 indexed roles); + + /// @dev `keccak256(bytes("RolesUpdated(address,uint256)"))`. + uint256 private constant _ROLES_UPDATED_EVENT_SIGNATURE = + 0x715ad5ce61fc9595c7b415289d59cf203f23a94fa06f04af7e489a0a76e1fe26; + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* STORAGE */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev The role slot of `user` is given by: + /// ``` + /// mstore(0x00, or(shl(96, user), _ROLE_SLOT_SEED)) + /// let roleSlot := keccak256(0x00, 0x20) + /// ``` + /// This automatically ignores the upper bits of the `user` in case + /// they are not clean, as well as keep the `keccak256` under 32-bytes. + /// + /// Note: This is equal to `_OWNER_SLOT_NOT` in for gas efficiency. + uint256 private constant _ROLE_SLOT_SEED = 0x8b78c6d8; + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* INTERNAL FUNCTIONS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev Overwrite the roles directly without authorization guard. + function _setRoles(address user, uint256 roles) internal virtual { + /// @solidity memory-safe-assembly + assembly { + mstore(0x0c, _ROLE_SLOT_SEED) + mstore(0x00, user) + // Store the new value. + sstore(keccak256(0x0c, 0x20), roles) + // Emit the {RolesUpdated} event. + log3(0, 0, _ROLES_UPDATED_EVENT_SIGNATURE, shr(96, mload(0x0c)), roles) + } + } + + /// @dev Updates the roles directly without authorization guard. + /// If `on` is true, each set bit of `roles` will be turned on, + /// otherwise, each set bit of `roles` will be turned off. + function _updateRoles(address user, uint256 roles, bool on) internal virtual { + /// @solidity memory-safe-assembly + assembly { + mstore(0x0c, _ROLE_SLOT_SEED) + mstore(0x00, user) + let roleSlot := keccak256(0x0c, 0x20) + // Load the current value. + let current := sload(roleSlot) + // Compute the updated roles if `on` is true. + let updated := or(current, roles) + // Compute the updated roles if `on` is false. + // Use `and` to compute the intersection of `current` and `roles`, + // `xor` it with `current` to flip the bits in the intersection. + if iszero(on) { updated := xor(current, and(current, roles)) } + // Then, store the new value. + sstore(roleSlot, updated) + // Emit the {RolesUpdated} event. + log3(0, 0, _ROLES_UPDATED_EVENT_SIGNATURE, shr(96, mload(0x0c)), updated) + } + } + + /// @dev Grants the roles directly without authorization guard. + /// Each bit of `roles` represents the role to turn on. + function _grantRoles(address user, uint256 roles) internal virtual { + _updateRoles(user, roles, true); + } + + /// @dev Removes the roles directly without authorization guard. + /// Each bit of `roles` represents the role to turn off. + function _removeRoles(address user, uint256 roles) internal virtual { + _updateRoles(user, roles, false); + } + + /// @dev Throws if the sender does not have any of the `roles`. + function _checkRoles(uint256 roles) internal view virtual { + /// @solidity memory-safe-assembly + assembly { + // Compute the role slot. + mstore(0x0c, _ROLE_SLOT_SEED) + mstore(0x00, caller()) + // Load the stored value, and if the `and` intersection + // of the value and `roles` is zero, revert. + if iszero(and(sload(keccak256(0x0c, 0x20)), roles)) { + mstore(0x00, 0x82b42900) // `Unauthorized()`. + revert(0x1c, 0x04) + } + } + } + + /// @dev Throws if the sender is not the owner, + /// and does not have any of the `roles`. + /// Checks for ownership first, then lazily checks for roles. + function _checkOwnerOrRoles(uint256 roles) internal view virtual { + /// @solidity memory-safe-assembly + assembly { + // If the caller is not the stored owner. + // Note: `_ROLE_SLOT_SEED` is equal to `_OWNER_SLOT_NOT`. + if iszero(eq(caller(), sload(not(_ROLE_SLOT_SEED)))) { + // Compute the role slot. + mstore(0x0c, _ROLE_SLOT_SEED) + mstore(0x00, caller()) + // Load the stored value, and if the `and` intersection + // of the value and `roles` is zero, revert. + if iszero(and(sload(keccak256(0x0c, 0x20)), roles)) { + mstore(0x00, 0x82b42900) // `Unauthorized()`. + revert(0x1c, 0x04) + } + } + } + } + + /// @dev Throws if the sender does not have any of the `roles`, + /// and is not the owner. + /// Checks for roles first, then lazily checks for ownership. + function _checkRolesOrOwner(uint256 roles) internal view virtual { + /// @solidity memory-safe-assembly + assembly { + // Compute the role slot. + mstore(0x0c, _ROLE_SLOT_SEED) + mstore(0x00, caller()) + // Load the stored value, and if the `and` intersection + // of the value and `roles` is zero, revert. + if iszero(and(sload(keccak256(0x0c, 0x20)), roles)) { + // If the caller is not the stored owner. + // Note: `_ROLE_SLOT_SEED` is equal to `_OWNER_SLOT_NOT`. + if iszero(eq(caller(), sload(not(_ROLE_SLOT_SEED)))) { + mstore(0x00, 0x82b42900) // `Unauthorized()`. + revert(0x1c, 0x04) + } + } + } + } + + /// @dev Convenience function to return a `roles` bitmap from an array of `ordinals`. + /// This is meant for frontends like Etherscan, and is therefore not fully optimized. + /// Not recommended to be called on-chain. + /// Made internal to conserve bytecode. Wrap it in a public function if needed. + function _rolesFromOrdinals(uint8[] memory ordinals) internal pure returns (uint256 roles) { + /// @solidity memory-safe-assembly + assembly { + for { let i := shl(5, mload(ordinals)) } i { i := sub(i, 0x20) } { + // We don't need to mask the values of `ordinals`, as Solidity + // cleans dirty upper bits when storing variables into memory. + roles := or(shl(mload(add(ordinals, i)), 1), roles) + } + } + } + + /// @dev Convenience function to return an array of `ordinals` from the `roles` bitmap. + /// This is meant for frontends like Etherscan, and is therefore not fully optimized. + /// Not recommended to be called on-chain. + /// Made internal to conserve bytecode. Wrap it in a public function if needed. + function _ordinalsFromRoles(uint256 roles) internal pure returns (uint8[] memory ordinals) { + /// @solidity memory-safe-assembly + assembly { + // Grab the pointer to the free memory. + ordinals := mload(0x40) + let ptr := add(ordinals, 0x20) + let o := 0 + // The absence of lookup tables, De Bruijn, etc., here is intentional for + // smaller bytecode, as this function is not meant to be called on-chain. + for { let t := roles } 1 {} { + mstore(ptr, o) + // `shr` 5 is equivalent to multiplying by 0x20. + // Push back into the ordinals array if the bit is set. + ptr := add(ptr, shl(5, and(t, 1))) + o := add(o, 1) + t := shr(o, roles) + if iszero(t) { break } + } + // Store the length of `ordinals`. + mstore(ordinals, shr(5, sub(ptr, add(ordinals, 0x20)))) + // Allocate the memory. + mstore(0x40, ptr) + } + } + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* PUBLIC UPDATE FUNCTIONS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev Allows the owner to grant `user` `roles`. + /// If the `user` already has a role, then it will be an no-op for the role. + function grantRoles(address user, uint256 roles) public payable virtual onlyOwner { + _grantRoles(user, roles); + } + + /// @dev Allows the owner to remove `user` `roles`. + /// If the `user` does not have a role, then it will be an no-op for the role. + function revokeRoles(address user, uint256 roles) public payable virtual onlyOwner { + _removeRoles(user, roles); + } + + /// @dev Allow the caller to remove their own roles. + /// If the caller does not have a role, then it will be an no-op for the role. + function renounceRoles(uint256 roles) public payable virtual { + _removeRoles(msg.sender, roles); + } + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* PUBLIC READ FUNCTIONS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev Returns the roles of `user`. + function rolesOf(address user) public view virtual returns (uint256 roles) { + /// @solidity memory-safe-assembly + assembly { + // Compute the role slot. + mstore(0x0c, _ROLE_SLOT_SEED) + mstore(0x00, user) + // Load the stored value. + roles := sload(keccak256(0x0c, 0x20)) + } + } + + /// @dev Returns whether `user` has any of `roles`. + function hasAnyRole(address user, uint256 roles) public view virtual returns (bool) { + return rolesOf(user) & roles != 0; + } + + /// @dev Returns whether `user` has all of `roles`. + function hasAllRoles(address user, uint256 roles) public view virtual returns (bool) { + return rolesOf(user) & roles == roles; + } + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* MODIFIERS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev Marks a function as only callable by an account with `roles`. + modifier onlyRoles(uint256 roles) virtual { + _checkRoles(roles); + _; + } + + /// @dev Marks a function as only callable by the owner or by an account + /// with `roles`. Checks for ownership first, then lazily checks for roles. + modifier onlyOwnerOrRoles(uint256 roles) virtual { + _checkOwnerOrRoles(roles); + _; + } + + /// @dev Marks a function as only callable by an account with `roles` + /// or the owner. Checks for roles first, then lazily checks for ownership. + modifier onlyRolesOrOwner(uint256 roles) virtual { + _checkRolesOrOwner(roles); + _; + } + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* ROLE CONSTANTS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + // IYKYK + + uint256 internal constant _ROLE_0 = 1 << 0; + uint256 internal constant _ROLE_1 = 1 << 1; + uint256 internal constant _ROLE_2 = 1 << 2; + uint256 internal constant _ROLE_3 = 1 << 3; + uint256 internal constant _ROLE_4 = 1 << 4; + uint256 internal constant _ROLE_5 = 1 << 5; + uint256 internal constant _ROLE_6 = 1 << 6; + uint256 internal constant _ROLE_7 = 1 << 7; + uint256 internal constant _ROLE_8 = 1 << 8; + uint256 internal constant _ROLE_9 = 1 << 9; + uint256 internal constant _ROLE_10 = 1 << 10; + uint256 internal constant _ROLE_11 = 1 << 11; + uint256 internal constant _ROLE_12 = 1 << 12; + uint256 internal constant _ROLE_13 = 1 << 13; + uint256 internal constant _ROLE_14 = 1 << 14; + uint256 internal constant _ROLE_15 = 1 << 15; + uint256 internal constant _ROLE_16 = 1 << 16; + uint256 internal constant _ROLE_17 = 1 << 17; + uint256 internal constant _ROLE_18 = 1 << 18; + uint256 internal constant _ROLE_19 = 1 << 19; + uint256 internal constant _ROLE_20 = 1 << 20; + uint256 internal constant _ROLE_21 = 1 << 21; + uint256 internal constant _ROLE_22 = 1 << 22; + uint256 internal constant _ROLE_23 = 1 << 23; + uint256 internal constant _ROLE_24 = 1 << 24; + uint256 internal constant _ROLE_25 = 1 << 25; + uint256 internal constant _ROLE_26 = 1 << 26; + uint256 internal constant _ROLE_27 = 1 << 27; + uint256 internal constant _ROLE_28 = 1 << 28; + uint256 internal constant _ROLE_29 = 1 << 29; + uint256 internal constant _ROLE_30 = 1 << 30; + uint256 internal constant _ROLE_31 = 1 << 31; + uint256 internal constant _ROLE_32 = 1 << 32; + uint256 internal constant _ROLE_33 = 1 << 33; + uint256 internal constant _ROLE_34 = 1 << 34; + uint256 internal constant _ROLE_35 = 1 << 35; + uint256 internal constant _ROLE_36 = 1 << 36; + uint256 internal constant _ROLE_37 = 1 << 37; + uint256 internal constant _ROLE_38 = 1 << 38; + uint256 internal constant _ROLE_39 = 1 << 39; + uint256 internal constant _ROLE_40 = 1 << 40; + uint256 internal constant _ROLE_41 = 1 << 41; + uint256 internal constant _ROLE_42 = 1 << 42; + uint256 internal constant _ROLE_43 = 1 << 43; + uint256 internal constant _ROLE_44 = 1 << 44; + uint256 internal constant _ROLE_45 = 1 << 45; + uint256 internal constant _ROLE_46 = 1 << 46; + uint256 internal constant _ROLE_47 = 1 << 47; + uint256 internal constant _ROLE_48 = 1 << 48; + uint256 internal constant _ROLE_49 = 1 << 49; + uint256 internal constant _ROLE_50 = 1 << 50; + uint256 internal constant _ROLE_51 = 1 << 51; + uint256 internal constant _ROLE_52 = 1 << 52; + uint256 internal constant _ROLE_53 = 1 << 53; + uint256 internal constant _ROLE_54 = 1 << 54; + uint256 internal constant _ROLE_55 = 1 << 55; + uint256 internal constant _ROLE_56 = 1 << 56; + uint256 internal constant _ROLE_57 = 1 << 57; + uint256 internal constant _ROLE_58 = 1 << 58; + uint256 internal constant _ROLE_59 = 1 << 59; + uint256 internal constant _ROLE_60 = 1 << 60; + uint256 internal constant _ROLE_61 = 1 << 61; + uint256 internal constant _ROLE_62 = 1 << 62; + uint256 internal constant _ROLE_63 = 1 << 63; + uint256 internal constant _ROLE_64 = 1 << 64; + uint256 internal constant _ROLE_65 = 1 << 65; + uint256 internal constant _ROLE_66 = 1 << 66; + uint256 internal constant _ROLE_67 = 1 << 67; + uint256 internal constant _ROLE_68 = 1 << 68; + uint256 internal constant _ROLE_69 = 1 << 69; + uint256 internal constant _ROLE_70 = 1 << 70; + uint256 internal constant _ROLE_71 = 1 << 71; + uint256 internal constant _ROLE_72 = 1 << 72; + uint256 internal constant _ROLE_73 = 1 << 73; + uint256 internal constant _ROLE_74 = 1 << 74; + uint256 internal constant _ROLE_75 = 1 << 75; + uint256 internal constant _ROLE_76 = 1 << 76; + uint256 internal constant _ROLE_77 = 1 << 77; + uint256 internal constant _ROLE_78 = 1 << 78; + uint256 internal constant _ROLE_79 = 1 << 79; + uint256 internal constant _ROLE_80 = 1 << 80; + uint256 internal constant _ROLE_81 = 1 << 81; + uint256 internal constant _ROLE_82 = 1 << 82; + uint256 internal constant _ROLE_83 = 1 << 83; + uint256 internal constant _ROLE_84 = 1 << 84; + uint256 internal constant _ROLE_85 = 1 << 85; + uint256 internal constant _ROLE_86 = 1 << 86; + uint256 internal constant _ROLE_87 = 1 << 87; + uint256 internal constant _ROLE_88 = 1 << 88; + uint256 internal constant _ROLE_89 = 1 << 89; + uint256 internal constant _ROLE_90 = 1 << 90; + uint256 internal constant _ROLE_91 = 1 << 91; + uint256 internal constant _ROLE_92 = 1 << 92; + uint256 internal constant _ROLE_93 = 1 << 93; + uint256 internal constant _ROLE_94 = 1 << 94; + uint256 internal constant _ROLE_95 = 1 << 95; + uint256 internal constant _ROLE_96 = 1 << 96; + uint256 internal constant _ROLE_97 = 1 << 97; + uint256 internal constant _ROLE_98 = 1 << 98; + uint256 internal constant _ROLE_99 = 1 << 99; + uint256 internal constant _ROLE_100 = 1 << 100; + uint256 internal constant _ROLE_101 = 1 << 101; + uint256 internal constant _ROLE_102 = 1 << 102; + uint256 internal constant _ROLE_103 = 1 << 103; + uint256 internal constant _ROLE_104 = 1 << 104; + uint256 internal constant _ROLE_105 = 1 << 105; + uint256 internal constant _ROLE_106 = 1 << 106; + uint256 internal constant _ROLE_107 = 1 << 107; + uint256 internal constant _ROLE_108 = 1 << 108; + uint256 internal constant _ROLE_109 = 1 << 109; + uint256 internal constant _ROLE_110 = 1 << 110; + uint256 internal constant _ROLE_111 = 1 << 111; + uint256 internal constant _ROLE_112 = 1 << 112; + uint256 internal constant _ROLE_113 = 1 << 113; + uint256 internal constant _ROLE_114 = 1 << 114; + uint256 internal constant _ROLE_115 = 1 << 115; + uint256 internal constant _ROLE_116 = 1 << 116; + uint256 internal constant _ROLE_117 = 1 << 117; + uint256 internal constant _ROLE_118 = 1 << 118; + uint256 internal constant _ROLE_119 = 1 << 119; + uint256 internal constant _ROLE_120 = 1 << 120; + uint256 internal constant _ROLE_121 = 1 << 121; + uint256 internal constant _ROLE_122 = 1 << 122; + uint256 internal constant _ROLE_123 = 1 << 123; + uint256 internal constant _ROLE_124 = 1 << 124; + uint256 internal constant _ROLE_125 = 1 << 125; + uint256 internal constant _ROLE_126 = 1 << 126; + uint256 internal constant _ROLE_127 = 1 << 127; + uint256 internal constant _ROLE_128 = 1 << 128; + uint256 internal constant _ROLE_129 = 1 << 129; + uint256 internal constant _ROLE_130 = 1 << 130; + uint256 internal constant _ROLE_131 = 1 << 131; + uint256 internal constant _ROLE_132 = 1 << 132; + uint256 internal constant _ROLE_133 = 1 << 133; + uint256 internal constant _ROLE_134 = 1 << 134; + uint256 internal constant _ROLE_135 = 1 << 135; + uint256 internal constant _ROLE_136 = 1 << 136; + uint256 internal constant _ROLE_137 = 1 << 137; + uint256 internal constant _ROLE_138 = 1 << 138; + uint256 internal constant _ROLE_139 = 1 << 139; + uint256 internal constant _ROLE_140 = 1 << 140; + uint256 internal constant _ROLE_141 = 1 << 141; + uint256 internal constant _ROLE_142 = 1 << 142; + uint256 internal constant _ROLE_143 = 1 << 143; + uint256 internal constant _ROLE_144 = 1 << 144; + uint256 internal constant _ROLE_145 = 1 << 145; + uint256 internal constant _ROLE_146 = 1 << 146; + uint256 internal constant _ROLE_147 = 1 << 147; + uint256 internal constant _ROLE_148 = 1 << 148; + uint256 internal constant _ROLE_149 = 1 << 149; + uint256 internal constant _ROLE_150 = 1 << 150; + uint256 internal constant _ROLE_151 = 1 << 151; + uint256 internal constant _ROLE_152 = 1 << 152; + uint256 internal constant _ROLE_153 = 1 << 153; + uint256 internal constant _ROLE_154 = 1 << 154; + uint256 internal constant _ROLE_155 = 1 << 155; + uint256 internal constant _ROLE_156 = 1 << 156; + uint256 internal constant _ROLE_157 = 1 << 157; + uint256 internal constant _ROLE_158 = 1 << 158; + uint256 internal constant _ROLE_159 = 1 << 159; + uint256 internal constant _ROLE_160 = 1 << 160; + uint256 internal constant _ROLE_161 = 1 << 161; + uint256 internal constant _ROLE_162 = 1 << 162; + uint256 internal constant _ROLE_163 = 1 << 163; + uint256 internal constant _ROLE_164 = 1 << 164; + uint256 internal constant _ROLE_165 = 1 << 165; + uint256 internal constant _ROLE_166 = 1 << 166; + uint256 internal constant _ROLE_167 = 1 << 167; + uint256 internal constant _ROLE_168 = 1 << 168; + uint256 internal constant _ROLE_169 = 1 << 169; + uint256 internal constant _ROLE_170 = 1 << 170; + uint256 internal constant _ROLE_171 = 1 << 171; + uint256 internal constant _ROLE_172 = 1 << 172; + uint256 internal constant _ROLE_173 = 1 << 173; + uint256 internal constant _ROLE_174 = 1 << 174; + uint256 internal constant _ROLE_175 = 1 << 175; + uint256 internal constant _ROLE_176 = 1 << 176; + uint256 internal constant _ROLE_177 = 1 << 177; + uint256 internal constant _ROLE_178 = 1 << 178; + uint256 internal constant _ROLE_179 = 1 << 179; + uint256 internal constant _ROLE_180 = 1 << 180; + uint256 internal constant _ROLE_181 = 1 << 181; + uint256 internal constant _ROLE_182 = 1 << 182; + uint256 internal constant _ROLE_183 = 1 << 183; + uint256 internal constant _ROLE_184 = 1 << 184; + uint256 internal constant _ROLE_185 = 1 << 185; + uint256 internal constant _ROLE_186 = 1 << 186; + uint256 internal constant _ROLE_187 = 1 << 187; + uint256 internal constant _ROLE_188 = 1 << 188; + uint256 internal constant _ROLE_189 = 1 << 189; + uint256 internal constant _ROLE_190 = 1 << 190; + uint256 internal constant _ROLE_191 = 1 << 191; + uint256 internal constant _ROLE_192 = 1 << 192; + uint256 internal constant _ROLE_193 = 1 << 193; + uint256 internal constant _ROLE_194 = 1 << 194; + uint256 internal constant _ROLE_195 = 1 << 195; + uint256 internal constant _ROLE_196 = 1 << 196; + uint256 internal constant _ROLE_197 = 1 << 197; + uint256 internal constant _ROLE_198 = 1 << 198; + uint256 internal constant _ROLE_199 = 1 << 199; + uint256 internal constant _ROLE_200 = 1 << 200; + uint256 internal constant _ROLE_201 = 1 << 201; + uint256 internal constant _ROLE_202 = 1 << 202; + uint256 internal constant _ROLE_203 = 1 << 203; + uint256 internal constant _ROLE_204 = 1 << 204; + uint256 internal constant _ROLE_205 = 1 << 205; + uint256 internal constant _ROLE_206 = 1 << 206; + uint256 internal constant _ROLE_207 = 1 << 207; + uint256 internal constant _ROLE_208 = 1 << 208; + uint256 internal constant _ROLE_209 = 1 << 209; + uint256 internal constant _ROLE_210 = 1 << 210; + uint256 internal constant _ROLE_211 = 1 << 211; + uint256 internal constant _ROLE_212 = 1 << 212; + uint256 internal constant _ROLE_213 = 1 << 213; + uint256 internal constant _ROLE_214 = 1 << 214; + uint256 internal constant _ROLE_215 = 1 << 215; + uint256 internal constant _ROLE_216 = 1 << 216; + uint256 internal constant _ROLE_217 = 1 << 217; + uint256 internal constant _ROLE_218 = 1 << 218; + uint256 internal constant _ROLE_219 = 1 << 219; + uint256 internal constant _ROLE_220 = 1 << 220; + uint256 internal constant _ROLE_221 = 1 << 221; + uint256 internal constant _ROLE_222 = 1 << 222; + uint256 internal constant _ROLE_223 = 1 << 223; + uint256 internal constant _ROLE_224 = 1 << 224; + uint256 internal constant _ROLE_225 = 1 << 225; + uint256 internal constant _ROLE_226 = 1 << 226; + uint256 internal constant _ROLE_227 = 1 << 227; + uint256 internal constant _ROLE_228 = 1 << 228; + uint256 internal constant _ROLE_229 = 1 << 229; + uint256 internal constant _ROLE_230 = 1 << 230; + uint256 internal constant _ROLE_231 = 1 << 231; + uint256 internal constant _ROLE_232 = 1 << 232; + uint256 internal constant _ROLE_233 = 1 << 233; + uint256 internal constant _ROLE_234 = 1 << 234; + uint256 internal constant _ROLE_235 = 1 << 235; + uint256 internal constant _ROLE_236 = 1 << 236; + uint256 internal constant _ROLE_237 = 1 << 237; + uint256 internal constant _ROLE_238 = 1 << 238; + uint256 internal constant _ROLE_239 = 1 << 239; + uint256 internal constant _ROLE_240 = 1 << 240; + uint256 internal constant _ROLE_241 = 1 << 241; + uint256 internal constant _ROLE_242 = 1 << 242; + uint256 internal constant _ROLE_243 = 1 << 243; + uint256 internal constant _ROLE_244 = 1 << 244; + uint256 internal constant _ROLE_245 = 1 << 245; + uint256 internal constant _ROLE_246 = 1 << 246; + uint256 internal constant _ROLE_247 = 1 << 247; + uint256 internal constant _ROLE_248 = 1 << 248; + uint256 internal constant _ROLE_249 = 1 << 249; + uint256 internal constant _ROLE_250 = 1 << 250; + uint256 internal constant _ROLE_251 = 1 << 251; + uint256 internal constant _ROLE_252 = 1 << 252; + uint256 internal constant _ROLE_253 = 1 << 253; + uint256 internal constant _ROLE_254 = 1 << 254; + uint256 internal constant _ROLE_255 = 1 << 255; +} + +// src\common/INonceRegistry.sol + + + + + +/// @title INoncesRegistry +/// @author Mathieu Bour for Pooky Labs Ltd. +/// +/// @notice Minimal NoncesRegistry interface. +interface INonceRegistry is IAccessControl { + /// @notice Get the value of a given nonce. + function has(bytes32 nonce) external view returns (bool); + + /// @notice Set the value of a given nonce. + function set(bytes32 nonce, bool value) external; + + /// @notice Set the value of a multiple nonces. + function setBatch(bytes32[] memory nonces, bool[] memory values) external; +} + +// src\common/Treasury.sol + + + + + + +/// @title Treasury +/// @author Mathieu Bour for Pooky Labs Ltd. +/// +/// @notice Base class for contracts that are made to receive native currency. +/// The destination address is controller by the contract owner. +abstract contract Treasury is Ownable, ITreasury { + /// The native currency destination address. + address public treasury; + + constructor(address _treasury) { + treasury = _treasury; + } + + /// @notice Forward the funds to the treasury wallet at the end of the transaction. + /// Since `treasury` is a trusted address, this modifier should not lead to any re-entrancy issue. + modifier forwarder() { + _; + + uint256 value = address(this).balance; + (bool sent,) = treasury.call{ value: value }(""); + if (!sent) { + revert TransferFailed(treasury, value); + } + } + + /// Change the native currency destination address. + /// @param _treasury The new treasury address. + function changeTreasury(address _treasury) external onlyOwner { + treasury = _treasury; + } +} + +// src\common/Signer.sol + + + + + + +/// @title Signer +/// @author Mathieu Bour for Pooky Labs Ltd. +/// +/// @dev Provide the `verify` function and the `onlyVerify` modifier to child contracts. +abstract contract Signer is OwnableRoles { + using ECDSA for bytes32; + + uint256 public constant SIGNER = _ROLE_42; + + /// Thrown when the signature is invalid. + error InvalidSignature(); + + constructor(address signer) { + _grantRoles(signer, SIGNER); + } + + /// @notice Ensure that `data` has been signed by a `SIGNER` using the `proof`. + function verify(bytes memory data, bytes calldata proof) internal view { + // Generate the signed message from the tokenId and currentPXP + bytes32 hash = keccak256(data).toEthSignedMessageHash(); + + if (!hasAllRoles(hash.recoverCalldata(proof), SIGNER)) { + revert InvalidSignature(); + } + } + + /// @notice Modifier version of the `verify` function. + modifier onlyVerify(bytes memory data, bytes calldata proof) { + verify(data, proof); + _; + } +} + +// src\pookyball/IPookyball.sol + + + + + + + +/// @title PookyballMetadata +/// @notice The Pookyball rarities are represented on chain by this enum. +enum PookyballRarity { + COMMON, + RARE, + EPIC, + LEGENDARY, + MYTHIC +} + +/// @title PookyballMetadata +/// @notice Pookyballs NFT have the following features: +/// - rarity: integer enum. +/// - level: token level, can be increase by spending token experiences points (PXP). +/// - pxp: token experience points. +/// - seed: a random uint256 word provided by Chainlink VRF service that will be used by Pooky's NFT generator +/// back-end to generate the NFT visuals and in-game statistics\. +struct PookyballMetadata { + PookyballRarity rarity; + uint256 level; + uint256 pxp; + uint256 seed; +} + +/// @title IPookyball +/// @author Mathieu Bour for Pooky Labs Ltd. +/// @notice Minimal Pookyball interface. +interface IPookyball is IAccessControl, IERC2981, IERC721 { + /// Fired when the seed of a Pookyball token is set by the VRFCoordinator + event SeedSet(uint256 indexed tokenId, uint256 seed); + /// Fired when the level of a Pookyball token is changed + event LevelChanged(uint256 indexed tokenId, uint256 level); + /// Fired when the PXP of a Pookyball token is changed + event PXPChanged(uint256 indexed tokenId, uint256 amount); + + /// Thrown when the length of two parameters mismatch. Used in the mint batched function. + error ArgumentSizeMismatch(uint256 x, uint256 y); + + /// @notice PookyballMetadata of the token {tokenId}. + /// @dev Requirements: + /// - Pookyball {tokenId} should exist (minted and not burned). + function metadata(uint256 tokenId) external view returns (PookyballMetadata memory); + + /// @notice Change the secondary sale royalties receiver address. + function setERC2981Receiver(address newReceiver) external; + + /// @notice Mint a new Pookyball token with a given rarity. + function mint(address[] memory recipients, PookyballRarity[] memory rarities) + external + returns (uint256); + + /// @notice Change the level of a Pookyball token. + /// @dev Requirements: + /// - Pookyball {tokenId} should exist (minted and not burned). + function setLevel(uint256 tokenId, uint256 newLevel) external; + + /// @notice Change the PXP of a Pookyball token. + /// @dev Requirements: + /// - Pookyball {tokenId} should exist (minted and not burned). + function setPXP(uint256 tokenId, uint256 newPXP) external; +} + +// src\pookyball\PookyballReroll.sol + + + + + + + + + +/// @title PookyballReroll +/// @author Mathieu Bour for Pooky Labs Ltd. +/// Allow player to reroll their Pookyball attributes. +contract PookyballReroll is OwnableRoles, Signer, Treasury { + /// Fired when a Pookyball stats have been rerolled. + event Reroll(uint256 indexed tokenId, uint256 price); + + /// Thrown when user attempts to use a nonce that was already used in the past. + error NonceAlreadyUsed(bytes32 nonce); + /// Thrown when user attempts to reroll a Pookyball he does not own. + error OwnershipRequired(uint256 tokenId); + + /// The Pookyball contract. + IPookyball public immutable pookyball; + /// The NonceRegistry contract. + INonceRegistry public immutable nonces; + + constructor( + IPookyball _pookyball, + INonceRegistry _nonces, + address admin, + address _signer, + address _treasury + ) Signer(_signer) Treasury(_treasury) { + _initializeOwner(admin); + pookyball = _pookyball; + nonces = _nonces; + } + + /// @notice Reroll the attributes of an existing Pookyball. + /// @dev Pricing is controlled by the backend, which need to provide a proof to the end user. + /// @param tokenId The Pookyball token id to reroll. + /// @param price The price in native currency, provided by the Pooky back-end. + /// @param nonce The nonce, provided by the Pooky back-end. + /// @param proof The signature of `abi.encode(tokenId, price, nonce, address(this))`. + function reroll(uint256 tokenId, uint256 price, bytes32 nonce, bytes calldata proof) + external + payable + onlyVerify(abi.encode(tokenId, price, nonce, address(this)), proof) + forwarder + { + if (nonces.has(nonce)) { + revert NonceAlreadyUsed(nonce); + } + nonces.set(nonce, true); + + if (pookyball.ownerOf(tokenId) != msg.sender) { + revert OwnershipRequired(tokenId); + } + + if (msg.value < price) { + revert InsufficientValue(price, msg.value); + } + + emit Reroll(tokenId, price); + } +} diff --git a/flattened/Pressure.sol b/flattened/Pressure.sol new file mode 100644 index 00000000..d7cdebb3 --- /dev/null +++ b/flattened/Pressure.sol @@ -0,0 +1,313 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0 ^0.8.17; + +// lib/openzeppelin-contracts/contracts\access/IAccessControl.sol + +// OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol) + + + +/** + * @dev External interface of AccessControl declared to support ERC165 detection. + */ +interface IAccessControl { + /** + * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` + * + * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite + * {RoleAdminChanged} not being emitted signaling this. + * + * _Available since v3.1._ + */ + event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole); + + /** + * @dev Emitted when `account` is granted `role`. + * + * `sender` is the account that originated the contract call, an admin role + * bearer except when using {AccessControl-_setupRole}. + */ + event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender); + + /** + * @dev Emitted when `account` is revoked `role`. + * + * `sender` is the account that originated the contract call: + * - if using `revokeRole`, it is the admin role bearer + * - if using `renounceRole`, it is the role bearer (i.e. `account`) + */ + event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender); + + /** + * @dev Returns `true` if `account` has been granted `role`. + */ + function hasRole(bytes32 role, address account) external view returns (bool); + + /** + * @dev Returns the admin role that controls `role`. See {grantRole} and + * {revokeRole}. + * + * To change a role's admin, use {AccessControl-_setRoleAdmin}. + */ + function getRoleAdmin(bytes32 role) external view returns (bytes32); + + /** + * @dev Grants `role` to `account`. + * + * If `account` had not been already granted `role`, emits a {RoleGranted} + * event. + * + * Requirements: + * + * - the caller must have ``role``'s admin role. + */ + function grantRole(bytes32 role, address account) external; + + /** + * @dev Revokes `role` from `account`. + * + * If `account` had been granted `role`, emits a {RoleRevoked} event. + * + * Requirements: + * + * - the caller must have ``role``'s admin role. + */ + function revokeRole(bytes32 role, address account) external; + + /** + * @dev Revokes `role` from the calling account. + * + * Roles are often managed via {grantRole} and {revokeRole}: this function's + * purpose is to provide a mechanism for accounts to lose their privileges + * if they are compromised (such as when a trusted device is misplaced). + * + * If the calling account had been granted `role`, emits a {RoleRevoked} + * event. + * + * Requirements: + * + * - the caller must be `account`. + */ + function renounceRole(bytes32 role, address account) external; +} + +// lib/openzeppelin-contracts/contracts\token/ERC20/IERC20.sol + +// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol) + + + +/** + * @dev Interface of the ERC20 standard as defined in the EIP. + */ +interface IERC20 { + /** + * @dev Emitted when `value` tokens are moved from one account (`from`) to + * another (`to`). + * + * Note that `value` may be zero. + */ + event Transfer(address indexed from, address indexed to, uint256 value); + + /** + * @dev Emitted when the allowance of a `spender` for an `owner` is set by + * a call to {approve}. `value` is the new allowance. + */ + event Approval(address indexed owner, address indexed spender, uint256 value); + + /** + * @dev Returns the amount of tokens in existence. + */ + function totalSupply() external view returns (uint256); + + /** + * @dev Returns the amount of tokens owned by `account`. + */ + function balanceOf(address account) external view returns (uint256); + + /** + * @dev Moves `amount` tokens from the caller's account to `to`. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * Emits a {Transfer} event. + */ + function transfer(address to, uint256 amount) external returns (bool); + + /** + * @dev Returns the remaining number of tokens that `spender` will be + * allowed to spend on behalf of `owner` through {transferFrom}. This is + * zero by default. + * + * This value changes when {approve} or {transferFrom} are called. + */ + function allowance(address owner, address spender) external view returns (uint256); + + /** + * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * IMPORTANT: Beware that changing an allowance with this method brings the risk + * that someone may use both the old and the new allowance by unfortunate + * transaction ordering. One possible solution to mitigate this race + * condition is to first reduce the spender's allowance to 0 and set the + * desired value afterwards: + * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 + * + * Emits an {Approval} event. + */ + function approve(address spender, uint256 amount) external returns (bool); + + /** + * @dev Moves `amount` tokens from `from` to `to` using the + * allowance mechanism. `amount` is then deducted from the caller's + * allowance. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * Emits a {Transfer} event. + */ + function transferFrom(address from, address to, uint256 amount) external returns (bool); +} + +// src\tokens/IPOK.sol + + + + + + +/// @title IPOK +/// @author Mathieu Bour, Dusan Zdravkovic for Pooky Labs Ltd. +/// +/// @notice Minimal $POK ERC20 token interface. +interface IPOK is IAccessControl, IERC20 { + /// @notice Mint an arbitrary amount of $POK to an account. + /// @dev Requirements: + /// - only MINTER role can mint $POK tokens + function mint(address to, uint256 amount) external; + + /// @notice Burn an arbitrary amount of $POK of an sender account. + /// It is acknowledged that burning directly from the user wallet is anti-pattern + /// but since $POK is soulbounded, this allow to skip the ERC20 approve call. + /// @dev Requirements: + /// - only BURNER role can burn $POK tokens + function burn(address to, uint256 amount) external; +} + +// src\pookyball\Pressure.sol + + + + + +/// @title Pressure +/// @author Mathieu Bour for Pooky Labs Ltd. +/// +/// @notice Gameplay contract that allow to inflate/repair Pookyball tokens by spending $POK tokens and native currency. +/// @dev This contract has the POK.BURNER role. +contract Pressure { + // Constants + uint8[] public floors = [10, 20, 30, 40, 50, 60, 75, 100]; + uint256[] public floorsNAT = + [0.064e18, 0.0538e18, 0.0452e18, 0.0379e18, 0.0319e18, 0.0268e18, 0.0225e18, 0.0189e18]; + uint256[] public floorsPOK = + [2.286e18, 1.92e18, 1.613e18, 1.355e18, 1.138e18, 0.956e18, 0.803e18, 0.674e18]; + + // Contracts + IPOK immutable pok; + address immutable treasury; + + /// Emitted when the Pookyball has been inflated. + event Inflated(uint256 indexed tokenId, uint8 current, uint8 amount); + + /// Thrown when the inflate parameters greater than 100 + error InvalidParameters(uint256 current, uint256 amount); + /// Thrown when the msg.value of the inflate function does not cover the inflate cost. + error InsufficientValue(uint256 expected, uint256 actual); + /// Thrown when the sender does own enough $POK tokens. + error InsufficientPOK(uint256 expected, uint256 actual); + /// Thrown when the native transfer has failed. + error TransferFailed(address recipient, uint256 amount); + + constructor(IPOK _pok, address _treasury) { + pok = _pok; + treasury = _treasury; + } + + /// @notice Compute the cost using the floors. + /// @param current The current token pressure. + /// @param amount The desired pressure increase. + /// @param values The floor values. + function compute(uint8 current, uint8 amount, uint256[] memory values) + internal + view + returns (uint256) + { + if (current + amount > 100) { + revert InvalidParameters(current, amount); + } + + uint256 sum = 0; + + for (uint256 i = 0; i < floors.length; i++) { + if (amount == 0) break; + if (current > floors[i]) continue; + + uint8 size = floors[i] + 1 - current; + uint8 delta = size > amount ? amount : size; + + sum += values[i] * delta; + current += delta; + amount -= delta; + } + + return sum; + } + + /// @notice Get the price to inflate a Pookyball token in native currency. + /// @param current The current token pressure. + /// @param amount The desired pressure increase. + function priceNAT(uint8 current, uint8 amount) public view returns (uint256) { + return compute(current, amount, floorsNAT); + } + + /// @notice Get the price to inflate a Pookyball token in $POK tokens. + /// @param current The current token pressure. + /// @param amount The desired pressure increase. + function pricePOK(uint8 current, uint8 amount) public view returns (uint256) { + return compute(current, amount, floorsPOK); + } + + /// @notice Compute the cost using the floors. + /// @param tokenId The Pookyball token id to inflate. + /// @param current The current token pressure. + /// @param amount The desired pressure increase. + function inflate(uint256 tokenId, uint8 current, uint8 amount) external payable { + if (msg.value > 0) { + // Sender is paying with native currency + uint256 amountNAT = priceNAT(current, amount); + + if (msg.value < amountNAT) { + revert InsufficientValue(msg.value, amountNAT); + } + + (bool sent,) = address(treasury).call{ value: amountNAT }(""); + if (!sent) { + revert TransferFailed(msg.sender, amountNAT); + } + } else { + // Sender is paying with $POK tokens + uint256 amountPOK = pricePOK(current, amount); + + if (pok.balanceOf(msg.sender) < amountPOK) { + revert InsufficientPOK(pok.balanceOf(msg.sender), amountPOK); + } + + pok.burn(msg.sender, amountPOK); + } + + emit Inflated(tokenId, current, amount); + } +} diff --git a/flattened/RefillableSale.sol b/flattened/RefillableSale.sol new file mode 100644 index 00000000..1d481866 --- /dev/null +++ b/flattened/RefillableSale.sol @@ -0,0 +1,1787 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0 ^0.8.17 ^0.8.18; + +// lib/openzeppelin-contracts/contracts/access/IAccessControl.sol + +// OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol) + + + +/** + * @dev External interface of AccessControl declared to support ERC165 detection. + */ +interface IAccessControl { + /** + * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` + * + * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite + * {RoleAdminChanged} not being emitted signaling this. + * + * _Available since v3.1._ + */ + event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole); + + /** + * @dev Emitted when `account` is granted `role`. + * + * `sender` is the account that originated the contract call, an admin role + * bearer except when using {AccessControl-_setupRole}. + */ + event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender); + + /** + * @dev Emitted when `account` is revoked `role`. + * + * `sender` is the account that originated the contract call: + * - if using `revokeRole`, it is the admin role bearer + * - if using `renounceRole`, it is the role bearer (i.e. `account`) + */ + event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender); + + /** + * @dev Returns `true` if `account` has been granted `role`. + */ + function hasRole(bytes32 role, address account) external view returns (bool); + + /** + * @dev Returns the admin role that controls `role`. See {grantRole} and + * {revokeRole}. + * + * To change a role's admin, use {AccessControl-_setRoleAdmin}. + */ + function getRoleAdmin(bytes32 role) external view returns (bytes32); + + /** + * @dev Grants `role` to `account`. + * + * If `account` had not been already granted `role`, emits a {RoleGranted} + * event. + * + * Requirements: + * + * - the caller must have ``role``'s admin role. + */ + function grantRole(bytes32 role, address account) external; + + /** + * @dev Revokes `role` from `account`. + * + * If `account` had been granted `role`, emits a {RoleRevoked} event. + * + * Requirements: + * + * - the caller must have ``role``'s admin role. + */ + function revokeRole(bytes32 role, address account) external; + + /** + * @dev Revokes `role` from the calling account. + * + * Roles are often managed via {grantRole} and {revokeRole}: this function's + * purpose is to provide a mechanism for accounts to lose their privileges + * if they are compromised (such as when a trusted device is misplaced). + * + * If the calling account had been granted `role`, emits a {RoleRevoked} + * event. + * + * Requirements: + * + * - the caller must be `account`. + */ + function renounceRole(bytes32 role, address account) external; +} + +// lib/openzeppelin-contracts/contracts/utils/Context.sol + +// OpenZeppelin Contracts v4.4.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; + } + + function _msgData() internal view virtual returns (bytes calldata) { + return msg.data; + } +} + +// lib/openzeppelin-contracts/contracts/utils/introspection/IERC165.sol + +// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol) + + + +/** + * @dev Interface of the ERC165 standard, as defined in the + * https://eips.ethereum.org/EIPS/eip-165[EIP]. + * + * Implementers can declare support of contract interfaces, which can then be + * queried by others ({ERC165Checker}). + * + * For an implementation, see {ERC165}. + */ +interface IERC165 { + /** + * @dev Returns true if this contract implements the interface defined by + * `interfaceId`. See the corresponding + * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] + * to learn more about how these ids are created. + * + * This function call must use less than 30 000 gas. + */ + function supportsInterface(bytes4 interfaceId) external view returns (bool); +} + +// lib/openzeppelin-contracts/contracts/utils/math/Math.sol + +// OpenZeppelin Contracts (last updated v4.9.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) { + // Solidity will revert if denominator == 0, unlike the div opcode on its own. + // The surrounding unchecked block does not change this fact. + // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic. + return prod0 / denominator; + } + + // Make sure the result is less than 2^256. Also prevents denominator == 0. + require(denominator > prod1, "Math: mulDiv overflow"); + + /////////////////////////////////////////////// + // 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. If 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)`. This value can be written `msb(a)=2**k` with `k=log2(a)`. + // + // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)` + // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))` + // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)` + // + // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit. + uint256 result = 1 << (log2(a) >> 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) { + unchecked { + uint256 result = sqrt(a); + return result + (rounding == Rounding.Up && result * result < a ? 1 : 0); + } + } + + /** + * @dev Return the log in base 2, rounded down, of a positive value. + * Returns 0 if given 0. + */ + function log2(uint256 value) internal pure returns (uint256) { + uint256 result = 0; + unchecked { + if (value >> 128 > 0) { + value >>= 128; + result += 128; + } + if (value >> 64 > 0) { + value >>= 64; + result += 64; + } + if (value >> 32 > 0) { + value >>= 32; + result += 32; + } + if (value >> 16 > 0) { + value >>= 16; + result += 16; + } + if (value >> 8 > 0) { + value >>= 8; + result += 8; + } + if (value >> 4 > 0) { + value >>= 4; + result += 4; + } + if (value >> 2 > 0) { + value >>= 2; + result += 2; + } + if (value >> 1 > 0) { + result += 1; + } + } + return result; + } + + /** + * @dev Return the log in base 2, following the selected rounding direction, of a positive value. + * Returns 0 if given 0. + */ + function log2(uint256 value, Rounding rounding) internal pure returns (uint256) { + unchecked { + uint256 result = log2(value); + return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0); + } + } + + /** + * @dev Return the log in base 10, rounded down, of a positive value. + * Returns 0 if given 0. + */ + function log10(uint256 value) internal pure returns (uint256) { + uint256 result = 0; + unchecked { + if (value >= 10 ** 64) { + value /= 10 ** 64; + result += 64; + } + if (value >= 10 ** 32) { + value /= 10 ** 32; + result += 32; + } + if (value >= 10 ** 16) { + value /= 10 ** 16; + result += 16; + } + if (value >= 10 ** 8) { + value /= 10 ** 8; + result += 8; + } + if (value >= 10 ** 4) { + value /= 10 ** 4; + result += 4; + } + if (value >= 10 ** 2) { + value /= 10 ** 2; + result += 2; + } + if (value >= 10 ** 1) { + result += 1; + } + } + return result; + } + + /** + * @dev Return the log in base 10, following the selected rounding direction, of a positive value. + * Returns 0 if given 0. + */ + function log10(uint256 value, Rounding rounding) internal pure returns (uint256) { + unchecked { + uint256 result = log10(value); + return result + (rounding == Rounding.Up && 10 ** result < value ? 1 : 0); + } + } + + /** + * @dev Return the log in base 256, rounded down, of a positive value. + * Returns 0 if given 0. + * + * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string. + */ + function log256(uint256 value) internal pure returns (uint256) { + uint256 result = 0; + unchecked { + if (value >> 128 > 0) { + value >>= 128; + result += 16; + } + if (value >> 64 > 0) { + value >>= 64; + result += 8; + } + if (value >> 32 > 0) { + value >>= 32; + result += 4; + } + if (value >> 16 > 0) { + value >>= 16; + result += 2; + } + if (value >> 8 > 0) { + result += 1; + } + } + return result; + } + + /** + * @dev Return the log in base 256, following the selected rounding direction, of a positive value. + * Returns 0 if given 0. + */ + function log256(uint256 value, Rounding rounding) internal pure returns (uint256) { + unchecked { + uint256 result = log256(value); + return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0); + } + } +} + +// lib/openzeppelin-contracts/contracts/utils/math/SignedMath.sol + +// OpenZeppelin Contracts (last updated v4.8.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/contracts/utils/structs/EnumerableSet.sol + +// OpenZeppelin Contracts (last updated v4.9.0) (utils/structs/EnumerableSet.sol) +// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js. + + + +/** + * @dev Library for managing + * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive + * types. + * + * Sets have the following properties: + * + * - Elements are added, removed, and checked for existence in constant time + * (O(1)). + * - Elements are enumerated in O(n). No guarantees are made on the ordering. + * + * ```solidity + * contract Example { + * // Add the library methods + * using EnumerableSet for EnumerableSet.AddressSet; + * + * // Declare a set state variable + * EnumerableSet.AddressSet private mySet; + * } + * ``` + * + * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`) + * and `uint256` (`UintSet`) are supported. + * + * [WARNING] + * ==== + * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure + * unusable. + * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info. + * + * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an + * array of EnumerableSet. + * ==== + */ +library EnumerableSet { + // To implement this library for multiple types with as little code + // repetition as possible, we write it in terms of a generic Set type with + // bytes32 values. + // The Set implementation uses private functions, and user-facing + // implementations (such as AddressSet) are just wrappers around the + // underlying Set. + // This means that we can only create new EnumerableSets for types that fit + // in bytes32. + + struct Set { + // Storage of set values + bytes32[] _values; + // Position of the value in the `values` array, plus 1 because index 0 + // means a value is not in the set. + mapping(bytes32 => uint256) _indexes; + } + + /** + * @dev Add a value to a set. O(1). + * + * Returns true if the value was added to the set, that is if it was not + * already present. + */ + function _add(Set storage set, bytes32 value) private returns (bool) { + if (!_contains(set, value)) { + set._values.push(value); + // The value is stored at length-1, but we add 1 to all indexes + // and use 0 as a sentinel value + set._indexes[value] = set._values.length; + return true; + } else { + return false; + } + } + + /** + * @dev Removes a value from a set. O(1). + * + * Returns true if the value was removed from the set, that is if it was + * present. + */ + function _remove(Set storage set, bytes32 value) private returns (bool) { + // We read and store the value's index to prevent multiple reads from the same storage slot + uint256 valueIndex = set._indexes[value]; + + if (valueIndex != 0) { + // Equivalent to contains(set, value) + // To delete an element from the _values array in O(1), we swap the element to delete with the last one in + // the array, and then remove the last element (sometimes called as 'swap and pop'). + // This modifies the order of the array, as noted in {at}. + + uint256 toDeleteIndex = valueIndex - 1; + uint256 lastIndex = set._values.length - 1; + + if (lastIndex != toDeleteIndex) { + bytes32 lastValue = set._values[lastIndex]; + + // Move the last value to the index where the value to delete is + set._values[toDeleteIndex] = lastValue; + // Update the index for the moved value + set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex + } + + // Delete the slot where the moved value was stored + set._values.pop(); + + // Delete the index for the deleted slot + delete set._indexes[value]; + + return true; + } else { + return false; + } + } + + /** + * @dev Returns true if the value is in the set. O(1). + */ + function _contains(Set storage set, bytes32 value) private view returns (bool) { + return set._indexes[value] != 0; + } + + /** + * @dev Returns the number of values on the set. O(1). + */ + function _length(Set storage set) private view returns (uint256) { + return set._values.length; + } + + /** + * @dev Returns the value stored at position `index` in the set. O(1). + * + * Note that there are no guarantees on the ordering of values inside the + * array, and it may change when more values are added or removed. + * + * Requirements: + * + * - `index` must be strictly less than {length}. + */ + function _at(Set storage set, uint256 index) private view returns (bytes32) { + return set._values[index]; + } + + /** + * @dev Return the entire set in an array + * + * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed + * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that + * this function has an unbounded cost, and using it as part of a state-changing function may render the function + * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. + */ + function _values(Set storage set) private view returns (bytes32[] memory) { + return set._values; + } + + // Bytes32Set + + struct Bytes32Set { + Set _inner; + } + + /** + * @dev Add a value to a set. O(1). + * + * Returns true if the value was added to the set, that is if it was not + * already present. + */ + function add(Bytes32Set storage set, bytes32 value) internal returns (bool) { + return _add(set._inner, value); + } + + /** + * @dev Removes a value from a set. O(1). + * + * Returns true if the value was removed from the set, that is if it was + * present. + */ + function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) { + return _remove(set._inner, value); + } + + /** + * @dev Returns true if the value is in the set. O(1). + */ + function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) { + return _contains(set._inner, value); + } + + /** + * @dev Returns the number of values in the set. O(1). + */ + function length(Bytes32Set storage set) internal view returns (uint256) { + return _length(set._inner); + } + + /** + * @dev Returns the value stored at position `index` in the set. O(1). + * + * Note that there are no guarantees on the ordering of values inside the + * array, and it may change when more values are added or removed. + * + * Requirements: + * + * - `index` must be strictly less than {length}. + */ + function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) { + return _at(set._inner, index); + } + + /** + * @dev Return the entire set in an array + * + * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed + * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that + * this function has an unbounded cost, and using it as part of a state-changing function may render the function + * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. + */ + function values(Bytes32Set storage set) internal view returns (bytes32[] memory) { + bytes32[] memory store = _values(set._inner); + bytes32[] memory result; + + /// @solidity memory-safe-assembly + assembly { + result := store + } + + return result; + } + + // AddressSet + + struct AddressSet { + Set _inner; + } + + /** + * @dev Add a value to a set. O(1). + * + * Returns true if the value was added to the set, that is if it was not + * already present. + */ + function add(AddressSet storage set, address value) internal returns (bool) { + return _add(set._inner, bytes32(uint256(uint160(value)))); + } + + /** + * @dev Removes a value from a set. O(1). + * + * Returns true if the value was removed from the set, that is if it was + * present. + */ + function remove(AddressSet storage set, address value) internal returns (bool) { + return _remove(set._inner, bytes32(uint256(uint160(value)))); + } + + /** + * @dev Returns true if the value is in the set. O(1). + */ + function contains(AddressSet storage set, address value) internal view returns (bool) { + return _contains(set._inner, bytes32(uint256(uint160(value)))); + } + + /** + * @dev Returns the number of values in the set. O(1). + */ + function length(AddressSet storage set) internal view returns (uint256) { + return _length(set._inner); + } + + /** + * @dev Returns the value stored at position `index` in the set. O(1). + * + * Note that there are no guarantees on the ordering of values inside the + * array, and it may change when more values are added or removed. + * + * Requirements: + * + * - `index` must be strictly less than {length}. + */ + function at(AddressSet storage set, uint256 index) internal view returns (address) { + return address(uint160(uint256(_at(set._inner, index)))); + } + + /** + * @dev Return the entire set in an array + * + * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed + * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that + * this function has an unbounded cost, and using it as part of a state-changing function may render the function + * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. + */ + function values(AddressSet storage set) internal view returns (address[] memory) { + bytes32[] memory store = _values(set._inner); + address[] memory result; + + /// @solidity memory-safe-assembly + assembly { + result := store + } + + return result; + } + + // UintSet + + struct UintSet { + Set _inner; + } + + /** + * @dev Add a value to a set. O(1). + * + * Returns true if the value was added to the set, that is if it was not + * already present. + */ + function add(UintSet storage set, uint256 value) internal returns (bool) { + return _add(set._inner, bytes32(value)); + } + + /** + * @dev Removes a value from a set. O(1). + * + * Returns true if the value was removed from the set, that is if it was + * present. + */ + function remove(UintSet storage set, uint256 value) internal returns (bool) { + return _remove(set._inner, bytes32(value)); + } + + /** + * @dev Returns true if the value is in the set. O(1). + */ + function contains(UintSet storage set, uint256 value) internal view returns (bool) { + return _contains(set._inner, bytes32(value)); + } + + /** + * @dev Returns the number of values in the set. O(1). + */ + function length(UintSet storage set) internal view returns (uint256) { + return _length(set._inner); + } + + /** + * @dev Returns the value stored at position `index` in the set. O(1). + * + * Note that there are no guarantees on the ordering of values inside the + * array, and it may change when more values are added or removed. + * + * Requirements: + * + * - `index` must be strictly less than {length}. + */ + function at(UintSet storage set, uint256 index) internal view returns (uint256) { + return uint256(_at(set._inner, index)); + } + + /** + * @dev Return the entire set in an array + * + * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed + * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that + * this function has an unbounded cost, and using it as part of a state-changing function may render the function + * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. + */ + function values(UintSet storage set) internal view returns (uint256[] memory) { + bytes32[] memory store = _values(set._inner); + uint256[] memory result; + + /// @solidity memory-safe-assembly + assembly { + result := store + } + + return result; + } +} + +// lib/openzeppelin-contracts/contracts/access/IAccessControlEnumerable.sol + +// OpenZeppelin Contracts v4.4.1 (access/IAccessControlEnumerable.sol) + + + + + +/** + * @dev External interface of AccessControlEnumerable declared to support ERC165 detection. + */ +interface IAccessControlEnumerable is IAccessControl { + /** + * @dev Returns one of the accounts that have `role`. `index` must be a + * value between 0 and {getRoleMemberCount}, non-inclusive. + * + * Role bearers are not sorted in any particular way, and their ordering may + * change at any point. + * + * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure + * you perform all queries on the same block. See the following + * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] + * for more information. + */ + function getRoleMember(bytes32 role, uint256 index) external view returns (address); + + /** + * @dev Returns the number of accounts that have `role`. Can be used + * together with {getRoleMember} to enumerate all bearers of a role. + */ + function getRoleMemberCount(bytes32 role) external view returns (uint256); +} + +// lib/openzeppelin-contracts/contracts\interfaces/IERC2981.sol + +// OpenZeppelin Contracts (last updated v4.9.0) (interfaces/IERC2981.sol) + + + + + +/** + * @dev Interface for the NFT Royalty Standard. + * + * A standardized way to retrieve royalty payment information for non-fungible tokens (NFTs) to enable universal + * support for royalty payments across all NFT marketplaces and ecosystem participants. + * + * _Available since v4.5._ + */ +interface IERC2981 is IERC165 { + /** + * @dev Returns how much royalty is owed and to whom, based on a sale price that may be denominated in any unit of + * exchange. The royalty amount is denominated and should be paid in that same unit of exchange. + */ + function royaltyInfo( + uint256 tokenId, + uint256 salePrice + ) external view returns (address receiver, uint256 royaltyAmount); +} + +// lib/openzeppelin-contracts/contracts\token/ERC721/IERC721.sol + +// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC721/IERC721.sol) + + + + + +/** + * @dev Required interface of an ERC721 compliant contract. + */ +interface IERC721 is IERC165 { + /** + * @dev Emitted when `tokenId` token is transferred from `from` to `to`. + */ + event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); + + /** + * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token. + */ + event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); + + /** + * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets. + */ + event ApprovalForAll(address indexed owner, address indexed operator, bool approved); + + /** + * @dev Returns the number of tokens in ``owner``'s account. + */ + function balanceOf(address owner) external view returns (uint256 balance); + + /** + * @dev Returns the owner of the `tokenId` token. + * + * Requirements: + * + * - `tokenId` must exist. + */ + function ownerOf(uint256 tokenId) external view returns (address owner); + + /** + * @dev Safely transfers `tokenId` token from `from` to `to`. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must exist and be owned by `from`. + * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. + * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. + * + * Emits a {Transfer} event. + */ + function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external; + + /** + * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients + * are aware of the ERC721 protocol to prevent tokens from being forever locked. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must exist and be owned by `from`. + * - If the caller is not `from`, it must have been allowed to move this token by either {approve} or {setApprovalForAll}. + * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. + * + * Emits a {Transfer} event. + */ + function safeTransferFrom(address from, address to, uint256 tokenId) external; + + /** + * @dev Transfers `tokenId` token from `from` to `to`. + * + * WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721 + * or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must + * understand this adds an external call which potentially creates a reentrancy vulnerability. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must be owned by `from`. + * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. + * + * Emits a {Transfer} event. + */ + function transferFrom(address from, address to, uint256 tokenId) external; + + /** + * @dev Gives permission to `to` to transfer `tokenId` token to another account. + * The approval is cleared when the token is transferred. + * + * Only a single account can be approved at a time, so approving the zero address clears previous approvals. + * + * Requirements: + * + * - The caller must own the token or be an approved operator. + * - `tokenId` must exist. + * + * Emits an {Approval} event. + */ + function approve(address to, uint256 tokenId) external; + + /** + * @dev Approve or remove `operator` as an operator for the caller. + * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller. + * + * Requirements: + * + * - The `operator` cannot be the caller. + * + * Emits an {ApprovalForAll} event. + */ + function setApprovalForAll(address operator, bool approved) external; + + /** + * @dev Returns the account approved for `tokenId` token. + * + * Requirements: + * + * - `tokenId` must exist. + */ + function getApproved(uint256 tokenId) external view returns (address operator); + + /** + * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`. + * + * See {setApprovalForAll} + */ + function isApprovedForAll(address owner, address operator) external view returns (bool); +} + +// lib/openzeppelin-contracts/contracts/utils/introspection/ERC165.sol + +// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol) + + + + + +/** + * @dev Implementation of the {IERC165} interface. + * + * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check + * for the additional interface id that will be supported. For example: + * + * ```solidity + * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { + * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId); + * } + * ``` + * + * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation. + */ +abstract contract ERC165 is IERC165 { + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { + return interfaceId == type(IERC165).interfaceId; + } +} + +// lib/openzeppelin-contracts/contracts/utils/Strings.sol + +// OpenZeppelin Contracts (last updated v4.9.0) (utils/Strings.sol) + + + + + + +/** + * @dev String operations. + */ +library Strings { + bytes16 private constant _SYMBOLS = "0123456789abcdef"; + uint8 private constant _ADDRESS_LENGTH = 20; + + /** + * @dev Converts a `uint256` to its ASCII `string` decimal representation. + */ + function toString(uint256 value) internal pure returns (string memory) { + unchecked { + uint256 length = Math.log10(value) + 1; + string memory buffer = new string(length); + uint256 ptr; + /// @solidity memory-safe-assembly + assembly { + ptr := add(buffer, add(32, length)) + } + while (true) { + ptr--; + /// @solidity memory-safe-assembly + assembly { + mstore8(ptr, byte(mod(value, 10), _SYMBOLS)) + } + value /= 10; + if (value == 0) break; + } + return buffer; + } + } + + /** + * @dev Converts a `int256` to its ASCII `string` decimal representation. + */ + function toString(int256 value) internal pure returns (string memory) { + return string(abi.encodePacked(value < 0 ? "-" : "", toString(SignedMath.abs(value)))); + } + + /** + * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation. + */ + function toHexString(uint256 value) internal pure returns (string memory) { + unchecked { + return toHexString(value, Math.log256(value) + 1); + } + } + + /** + * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length. + */ + function toHexString(uint256 value, uint256 length) internal pure returns (string memory) { + bytes memory buffer = new bytes(2 * length + 2); + buffer[0] = "0"; + buffer[1] = "x"; + for (uint256 i = 2 * length + 1; i > 1; --i) { + buffer[i] = _SYMBOLS[value & 0xf]; + value >>= 4; + } + require(value == 0, "Strings: hex length insufficient"); + return string(buffer); + } + + /** + * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation. + */ + function toHexString(address addr) internal pure returns (string memory) { + return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH); + } + + /** + * @dev Returns true if the two strings are equal. + */ + function equal(string memory a, string memory b) internal pure returns (bool) { + return keccak256(bytes(a)) == keccak256(bytes(b)); + } +} + +// src\pookyball/IPookyball.sol + + + + + + + +/// @title PookyballMetadata +/// @notice The Pookyball rarities are represented on chain by this enum. +enum PookyballRarity { + COMMON, + RARE, + EPIC, + LEGENDARY, + MYTHIC +} + +/// @title PookyballMetadata +/// @notice Pookyballs NFT have the following features: +/// - rarity: integer enum. +/// - level: token level, can be increase by spending token experiences points (PXP). +/// - pxp: token experience points. +/// - seed: a random uint256 word provided by Chainlink VRF service that will be used by Pooky's NFT generator +/// back-end to generate the NFT visuals and in-game statistics\. +struct PookyballMetadata { + PookyballRarity rarity; + uint256 level; + uint256 pxp; + uint256 seed; +} + +/// @title IPookyball +/// @author Mathieu Bour for Pooky Labs Ltd. +/// @notice Minimal Pookyball interface. +interface IPookyball is IAccessControl, IERC2981, IERC721 { + /// Fired when the seed of a Pookyball token is set by the VRFCoordinator + event SeedSet(uint256 indexed tokenId, uint256 seed); + /// Fired when the level of a Pookyball token is changed + event LevelChanged(uint256 indexed tokenId, uint256 level); + /// Fired when the PXP of a Pookyball token is changed + event PXPChanged(uint256 indexed tokenId, uint256 amount); + + /// Thrown when the length of two parameters mismatch. Used in the mint batched function. + error ArgumentSizeMismatch(uint256 x, uint256 y); + + /// @notice PookyballMetadata of the token {tokenId}. + /// @dev Requirements: + /// - Pookyball {tokenId} should exist (minted and not burned). + function metadata(uint256 tokenId) external view returns (PookyballMetadata memory); + + /// @notice Change the secondary sale royalties receiver address. + function setERC2981Receiver(address newReceiver) external; + + /// @notice Mint a new Pookyball token with a given rarity. + function mint(address[] memory recipients, PookyballRarity[] memory rarities) + external + returns (uint256); + + /// @notice Change the level of a Pookyball token. + /// @dev Requirements: + /// - Pookyball {tokenId} should exist (minted and not burned). + function setLevel(uint256 tokenId, uint256 newLevel) external; + + /// @notice Change the PXP of a Pookyball token. + /// @dev Requirements: + /// - Pookyball {tokenId} should exist (minted and not burned). + function setPXP(uint256 tokenId, uint256 newPXP) external; +} + +// lib/openzeppelin-contracts/contracts/access/AccessControl.sol + +// OpenZeppelin Contracts (last updated v4.9.0) (access/AccessControl.sol) + + + + + + + + +/** + * @dev Contract module that allows children to implement role-based access + * control mechanisms. This is a lightweight version that doesn't allow enumerating role + * members except through off-chain means by accessing the contract event logs. Some + * applications may benefit from on-chain enumerability, for those cases see + * {AccessControlEnumerable}. + * + * Roles are referred to by their `bytes32` identifier. These should be exposed + * in the external API and be unique. The best way to achieve this is by + * using `public constant` hash digests: + * + * ```solidity + * bytes32 public constant MY_ROLE = keccak256("MY_ROLE"); + * ``` + * + * Roles can be used to represent a set of permissions. To restrict access to a + * function call, use {hasRole}: + * + * ```solidity + * function foo() public { + * require(hasRole(MY_ROLE, msg.sender)); + * ... + * } + * ``` + * + * Roles can be granted and revoked dynamically via the {grantRole} and + * {revokeRole} functions. Each role has an associated admin role, and only + * accounts that have a role's admin role can call {grantRole} and {revokeRole}. + * + * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means + * that only accounts with this role will be able to grant or revoke other + * roles. More complex role relationships can be created by using + * {_setRoleAdmin}. + * + * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to + * grant and revoke this role. Extra precautions should be taken to secure + * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules} + * to enforce additional security measures for this role. + */ +abstract contract AccessControl is Context, IAccessControl, ERC165 { + struct RoleData { + mapping(address => bool) members; + bytes32 adminRole; + } + + mapping(bytes32 => RoleData) private _roles; + + bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00; + + /** + * @dev Modifier that checks that an account has a specific role. Reverts + * with a standardized message including the required role. + * + * The format of the revert reason is given by the following regular expression: + * + * /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/ + * + * _Available since v4.1._ + */ + modifier onlyRole(bytes32 role) { + _checkRole(role); + _; + } + + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { + return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId); + } + + /** + * @dev Returns `true` if `account` has been granted `role`. + */ + function hasRole(bytes32 role, address account) public view virtual override returns (bool) { + return _roles[role].members[account]; + } + + /** + * @dev Revert with a standard message if `_msgSender()` is missing `role`. + * Overriding this function changes the behavior of the {onlyRole} modifier. + * + * Format of the revert message is described in {_checkRole}. + * + * _Available since v4.6._ + */ + function _checkRole(bytes32 role) internal view virtual { + _checkRole(role, _msgSender()); + } + + /** + * @dev Revert with a standard message if `account` is missing `role`. + * + * The format of the revert reason is given by the following regular expression: + * + * /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/ + */ + function _checkRole(bytes32 role, address account) internal view virtual { + if (!hasRole(role, account)) { + revert( + string( + abi.encodePacked( + "AccessControl: account ", + Strings.toHexString(account), + " is missing role ", + Strings.toHexString(uint256(role), 32) + ) + ) + ); + } + } + + /** + * @dev Returns the admin role that controls `role`. See {grantRole} and + * {revokeRole}. + * + * To change a role's admin, use {_setRoleAdmin}. + */ + function getRoleAdmin(bytes32 role) public view virtual override returns (bytes32) { + return _roles[role].adminRole; + } + + /** + * @dev Grants `role` to `account`. + * + * If `account` had not been already granted `role`, emits a {RoleGranted} + * event. + * + * Requirements: + * + * - the caller must have ``role``'s admin role. + * + * May emit a {RoleGranted} event. + */ + function grantRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) { + _grantRole(role, account); + } + + /** + * @dev Revokes `role` from `account`. + * + * If `account` had been granted `role`, emits a {RoleRevoked} event. + * + * Requirements: + * + * - the caller must have ``role``'s admin role. + * + * May emit a {RoleRevoked} event. + */ + function revokeRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) { + _revokeRole(role, account); + } + + /** + * @dev Revokes `role` from the calling account. + * + * Roles are often managed via {grantRole} and {revokeRole}: this function's + * purpose is to provide a mechanism for accounts to lose their privileges + * if they are compromised (such as when a trusted device is misplaced). + * + * If the calling account had been revoked `role`, emits a {RoleRevoked} + * event. + * + * Requirements: + * + * - the caller must be `account`. + * + * May emit a {RoleRevoked} event. + */ + function renounceRole(bytes32 role, address account) public virtual override { + require(account == _msgSender(), "AccessControl: can only renounce roles for self"); + + _revokeRole(role, account); + } + + /** + * @dev Grants `role` to `account`. + * + * If `account` had not been already granted `role`, emits a {RoleGranted} + * event. Note that unlike {grantRole}, this function doesn't perform any + * checks on the calling account. + * + * May emit a {RoleGranted} event. + * + * [WARNING] + * ==== + * This function should only be called from the constructor when setting + * up the initial roles for the system. + * + * Using this function in any other way is effectively circumventing the admin + * system imposed by {AccessControl}. + * ==== + * + * NOTE: This function is deprecated in favor of {_grantRole}. + */ + function _setupRole(bytes32 role, address account) internal virtual { + _grantRole(role, account); + } + + /** + * @dev Sets `adminRole` as ``role``'s admin role. + * + * Emits a {RoleAdminChanged} event. + */ + function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual { + bytes32 previousAdminRole = getRoleAdmin(role); + _roles[role].adminRole = adminRole; + emit RoleAdminChanged(role, previousAdminRole, adminRole); + } + + /** + * @dev Grants `role` to `account`. + * + * Internal function without access restriction. + * + * May emit a {RoleGranted} event. + */ + function _grantRole(bytes32 role, address account) internal virtual { + if (!hasRole(role, account)) { + _roles[role].members[account] = true; + emit RoleGranted(role, account, _msgSender()); + } + } + + /** + * @dev Revokes `role` from `account`. + * + * Internal function without access restriction. + * + * May emit a {RoleRevoked} event. + */ + function _revokeRole(bytes32 role, address account) internal virtual { + if (hasRole(role, account)) { + _roles[role].members[account] = false; + emit RoleRevoked(role, account, _msgSender()); + } + } +} + +// lib/openzeppelin-contracts/contracts\access/AccessControlEnumerable.sol + +// OpenZeppelin Contracts (last updated v4.5.0) (access/AccessControlEnumerable.sol) + + + + + + + +/** + * @dev Extension of {AccessControl} that allows enumerating the members of each role. + */ +abstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl { + using EnumerableSet for EnumerableSet.AddressSet; + + mapping(bytes32 => EnumerableSet.AddressSet) private _roleMembers; + + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { + return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId); + } + + /** + * @dev Returns one of the accounts that have `role`. `index` must be a + * value between 0 and {getRoleMemberCount}, non-inclusive. + * + * Role bearers are not sorted in any particular way, and their ordering may + * change at any point. + * + * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure + * you perform all queries on the same block. See the following + * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] + * for more information. + */ + function getRoleMember(bytes32 role, uint256 index) public view virtual override returns (address) { + return _roleMembers[role].at(index); + } + + /** + * @dev Returns the number of accounts that have `role`. Can be used + * together with {getRoleMember} to enumerate all bearers of a role. + */ + function getRoleMemberCount(bytes32 role) public view virtual override returns (uint256) { + return _roleMembers[role].length(); + } + + /** + * @dev Overload {_grantRole} to track enumerable memberships + */ + function _grantRole(bytes32 role, address account) internal virtual override { + super._grantRole(role, account); + _roleMembers[role].add(account); + } + + /** + * @dev Overload {_revokeRole} to track enumerable memberships + */ + function _revokeRole(bytes32 role, address account) internal virtual override { + super._revokeRole(role, account); + _roleMembers[role].remove(account); + } +} + +// src\pookyball\RefillableSale.sol + + + + + + +struct Item { + /// Supply of the current sale + uint256 supply; + /// Total number of tokens minted during all the sales + uint256 minted; + /// Total supply of all the sales + uint256 totalSupply; + /// The token price in native currency wei + uint256 price; +} + +struct Refill { + /// The Pookyball rarity (0=COMMON, 1=RARE, 2=EPIC, 3=LEGENDARY) + PookyballRarity rarity; + /// The refill token quantity + uint256 quantity; + /// The token price in native currency wei + uint256 price; +} + +/// @title RefillableSale +/// @author Mathieu Bour for Pooky Labs Ltd. +/// +/// @notice Allow Pookyball players to mint one or multiple Pookyball tokens. +/// This contract is refillable, meaning that an authorized SELLER account is allowed to change the available +/// balls/rarities. +/// The sale might also be closed at some point, see `closedUntil` for the next mint window! +contract RefillableSale is AccessControlEnumerable { + bytes32 public constant SELLER = keccak256("SELLER"); + PookyballRarity[] public rarities = + [PookyballRarity.COMMON, PookyballRarity.RARE, PookyballRarity.EPIC, PookyballRarity.LEGENDARY]; + + /// The available mintable items mapped by rarity. + mapping(PookyballRarity => Item) public items; + + /// The Pookyball ERC721 token (cannot be changed). + IPookyball public immutable pookyball; + /// The address of Pooky's treasury (cannot be changed). + address public immutable treasury; + /// The date when next mint window will open (compared to block.timestamp). + uint256 public closedUntil; + + /// Fired when a sale is made + event Sale( + address indexed account, PookyballRarity indexed rarity, uint256 quantity, uint256 value + ); + + /// Thrown when a mint is attempt before the sale opens. + error Closed(uint256 closedUntil); + /// Thrown when a mint would exceed the template supply. + error InsufficientSupply(PookyballRarity rarity, uint256 remaining); + /// Thrown when the msg.value of the mint function does not cover the mint cost. + error InsufficientValue(uint256 expected, uint256 actual); + /// Thrown when the native transfer has failed. + error TransferFailed(address recipient, uint256 amount); + + /// @param _pookyball The Pookyball ERC721 token address. + /// @param _treasury The Pooky's treasury address. + /// @param admin The AccessControl admin address. + /// @param sellers The initial SELLER addresses. + constructor(IPookyball _pookyball, address _treasury, address admin, address[] memory sellers) { + pookyball = _pookyball; + treasury = _treasury; + _grantRole(DEFAULT_ADMIN_ROLE, admin); + + uint256 l = sellers.length; + for (uint256 i = 0; i < l; i++) { + _grantRole(SELLER, sellers[i]); + } + + // Default prices + items[PookyballRarity.COMMON] = Item(0, 0, 0, 20 ether); + items[PookyballRarity.RARE] = Item(0, 0, 0, 80 ether); + items[PookyballRarity.EPIC] = Item(0, 0, 0, 320 ether); + items[PookyballRarity.LEGENDARY] = Item(0, 0, 0, 1280 ether); + } + + function getTemplates() external view returns (Item[] memory) { + uint256 l = rarities.length; + Item[] memory output = new Item[](l); + + for (uint256 i = 0; i < l; i++) { + output[i] = items[rarities[i]]; + } + + return output; + } + + /// @notice Checks if the sale is open. + function isClosed() public view returns (bool) { + return closedUntil == 0 || block.timestamp < closedUntil; + } + + /// @notice return the ineligibility reason of a set of parameters. + /// Required for Paper.xyz custom contract integrations. + /// See https://docs.withpaper.com/reference/eligibilitymethod + /// @return The reason why the parameters are invalid; empty string if teh parameters are valid. + function eligible(PookyballRarity rarity, uint256 quantity) external view returns (string memory) { + if (isClosed()) { + return "sale is closed"; + } + + Item memory item = items[rarity]; + if (item.minted + quantity > item.totalSupply) { + return "insufficient supply"; + } + + return ""; + } + + /// @notice Mint one or more Pookyball token to a account. + /// @dev Requirements: + /// - sale must be open + /// - item should exists (check with the InsufficientSupply error) + /// - item should have enough supply + /// - enough native currency should be sent to cover the mint price + function mint(PookyballRarity rarity, address recipient, uint256 quantity) external payable { + if (isClosed()) { + revert Closed(closedUntil); + } + + Item memory item = items[rarity]; + + if (item.minted + quantity > item.totalSupply) { + revert InsufficientSupply(rarity, item.totalSupply - item.minted); + } + + if (msg.value < quantity * item.price) { + revert InsufficientValue(quantity * item.price, msg.value); + } + + // Build the arrays for the batched mint + address[] memory recipients = new address[](quantity); + PookyballRarity[] memory rarities_ = new PookyballRarity[](quantity); + + for (uint256 i = 0; i < quantity; i++) { + recipients[i] = recipient; + rarities_[i] = rarity; + } + + // Actual Pookyball token mint + pookyball.mint(recipients, rarities_); + items[rarity].minted += quantity; + + // Forward the funds to the treasury wallet + (bool sent,) = treasury.call{ value: msg.value }(""); + if (!sent) { + revert TransferFailed(treasury, msg.value); + } + + emit Sale(recipient, rarity, quantity, msg.value); + } + + /// @notice Restock the sale items. + /// @param refills Array of the modifications to apply. + /// @param _closedUntil Update the opening of the sale; a date in the past opens the sale immediately. + /// @dev Requirements: + /// - msg.sender must have the SELLER role + function restock(Refill[] memory refills, uint256 _closedUntil) external onlyRole(SELLER) { + uint256 len = refills.length; + for (uint256 i = 0; i < len; i++) { + PookyballRarity rarity = refills[i].rarity; + items[rarity].price = refills[i].price; + items[rarity].totalSupply = items[rarity].minted + refills[i].quantity; + items[rarity].supply = refills[i].quantity; + } + + closedUntil = _closedUntil; + } +} diff --git a/flattened/Rewards.sol b/flattened/Rewards.sol new file mode 100644 index 00000000..ef309b97 --- /dev/null +++ b/flattened/Rewards.sol @@ -0,0 +1,2275 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0 ^0.8.17 ^0.8.21 ^0.8.4; + +// lib/ERC721A/contracts\IERC721A.sol + +// ERC721A Contracts v4.2.3 +// Creator: Chiru Labs + + + +/** + * @dev Interface of ERC721A. + */ +interface IERC721A { + /** + * The caller must own the token or be an approved operator. + */ + error ApprovalCallerNotOwnerNorApproved(); + + /** + * The token does not exist. + */ + error ApprovalQueryForNonexistentToken(); + + /** + * Cannot query the balance for the zero address. + */ + error BalanceQueryForZeroAddress(); + + /** + * Cannot mint to the zero address. + */ + error MintToZeroAddress(); + + /** + * The quantity of tokens minted must be more than zero. + */ + error MintZeroQuantity(); + + /** + * The token does not exist. + */ + error OwnerQueryForNonexistentToken(); + + /** + * The caller must own the token or be an approved operator. + */ + error TransferCallerNotOwnerNorApproved(); + + /** + * The token must be owned by `from`. + */ + error TransferFromIncorrectOwner(); + + /** + * Cannot safely transfer to a contract that does not implement the + * ERC721Receiver interface. + */ + error TransferToNonERC721ReceiverImplementer(); + + /** + * Cannot transfer to the zero address. + */ + error TransferToZeroAddress(); + + /** + * The token does not exist. + */ + error URIQueryForNonexistentToken(); + + /** + * The `quantity` minted with ERC2309 exceeds the safety limit. + */ + error MintERC2309QuantityExceedsLimit(); + + /** + * The `extraData` cannot be set on an unintialized ownership slot. + */ + error OwnershipNotInitializedForExtraData(); + + // ============================================================= + // STRUCTS + // ============================================================= + + struct TokenOwnership { + // The address of the owner. + address addr; + // Stores the start time of ownership with minimal overhead for tokenomics. + uint64 startTimestamp; + // Whether the token has been burned. + bool burned; + // Arbitrary data similar to `startTimestamp` that can be set via {_extraData}. + uint24 extraData; + } + + // ============================================================= + // TOKEN COUNTERS + // ============================================================= + + /** + * @dev Returns the total number of tokens in existence. + * Burned tokens will reduce the count. + * To get the total number of tokens minted, please see {_totalMinted}. + */ + function totalSupply() external view returns (uint256); + + // ============================================================= + // 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 30000 gas. + */ + function supportsInterface(bytes4 interfaceId) external view returns (bool); + + // ============================================================= + // IERC721 + // ============================================================= + + /** + * @dev Emitted when `tokenId` token is transferred from `from` to `to`. + */ + event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); + + /** + * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token. + */ + event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); + + /** + * @dev Emitted when `owner` enables or disables + * (`approved`) `operator` to manage all of its assets. + */ + event ApprovalForAll(address indexed owner, address indexed operator, bool approved); + + /** + * @dev Returns the number of tokens in `owner`'s account. + */ + function balanceOf(address owner) external view returns (uint256 balance); + + /** + * @dev Returns the owner of the `tokenId` token. + * + * Requirements: + * + * - `tokenId` must exist. + */ + function ownerOf(uint256 tokenId) external view returns (address owner); + + /** + * @dev Safely transfers `tokenId` token from `from` to `to`, + * checking first that contract recipients are aware of the ERC721 protocol + * to prevent tokens from being forever locked. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must exist and be owned by `from`. + * - If the caller is not `from`, it must be have been allowed to move + * this token by either {approve} or {setApprovalForAll}. + * - If `to` refers to a smart contract, it must implement + * {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. + * + * Emits a {Transfer} event. + */ + function safeTransferFrom( + address from, + address to, + uint256 tokenId, + bytes calldata data + ) external payable; + + /** + * @dev Equivalent to `safeTransferFrom(from, to, tokenId, '')`. + */ + function safeTransferFrom( + address from, + address to, + uint256 tokenId + ) external payable; + + /** + * @dev Transfers `tokenId` from `from` to `to`. + * + * WARNING: Usage of this method is discouraged, use {safeTransferFrom} + * whenever possible. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must be owned by `from`. + * - If the caller is not `from`, it must be approved to move this token + * by either {approve} or {setApprovalForAll}. + * + * Emits a {Transfer} event. + */ + function transferFrom( + address from, + address to, + uint256 tokenId + ) external payable; + + /** + * @dev Gives permission to `to` to transfer `tokenId` token to another account. + * The approval is cleared when the token is transferred. + * + * Only a single account can be approved at a time, so approving the + * zero address clears previous approvals. + * + * Requirements: + * + * - The caller must own the token or be an approved operator. + * - `tokenId` must exist. + * + * Emits an {Approval} event. + */ + function approve(address to, uint256 tokenId) external payable; + + /** + * @dev Approve or remove `operator` as an operator for the caller. + * Operators can call {transferFrom} or {safeTransferFrom} + * for any token owned by the caller. + * + * Requirements: + * + * - The `operator` cannot be the caller. + * + * Emits an {ApprovalForAll} event. + */ + function setApprovalForAll(address operator, bool _approved) external; + + /** + * @dev Returns the account approved for `tokenId` token. + * + * Requirements: + * + * - `tokenId` must exist. + */ + function getApproved(uint256 tokenId) external view returns (address operator); + + /** + * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`. + * + * See {setApprovalForAll}. + */ + function isApprovedForAll(address owner, address operator) external view returns (bool); + + // ============================================================= + // IERC721Metadata + // ============================================================= + + /** + * @dev Returns the token collection name. + */ + function name() external view returns (string memory); + + /** + * @dev Returns the token collection symbol. + */ + function symbol() external view returns (string memory); + + /** + * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token. + */ + function tokenURI(uint256 tokenId) external view returns (string memory); + + // ============================================================= + // IERC2309 + // ============================================================= + + /** + * @dev Emitted when tokens in `fromTokenId` to `toTokenId` + * (inclusive) is transferred from `from` to `to`, as defined in the + * [ERC2309](https://eips.ethereum.org/EIPS/eip-2309) standard. + * + * See {_mintERC2309} for more details. + */ + event ConsecutiveTransfer(uint256 indexed fromTokenId, uint256 toTokenId, address indexed from, address indexed to); +} + +// lib/openzeppelin-contracts/contracts\access/IAccessControl.sol + +// OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol) + + + +/** + * @dev External interface of AccessControl declared to support ERC165 detection. + */ +interface IAccessControl { + /** + * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` + * + * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite + * {RoleAdminChanged} not being emitted signaling this. + * + * _Available since v3.1._ + */ + event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole); + + /** + * @dev Emitted when `account` is granted `role`. + * + * `sender` is the account that originated the contract call, an admin role + * bearer except when using {AccessControl-_setupRole}. + */ + event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender); + + /** + * @dev Emitted when `account` is revoked `role`. + * + * `sender` is the account that originated the contract call: + * - if using `revokeRole`, it is the admin role bearer + * - if using `renounceRole`, it is the role bearer (i.e. `account`) + */ + event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender); + + /** + * @dev Returns `true` if `account` has been granted `role`. + */ + function hasRole(bytes32 role, address account) external view returns (bool); + + /** + * @dev Returns the admin role that controls `role`. See {grantRole} and + * {revokeRole}. + * + * To change a role's admin, use {AccessControl-_setRoleAdmin}. + */ + function getRoleAdmin(bytes32 role) external view returns (bytes32); + + /** + * @dev Grants `role` to `account`. + * + * If `account` had not been already granted `role`, emits a {RoleGranted} + * event. + * + * Requirements: + * + * - the caller must have ``role``'s admin role. + */ + function grantRole(bytes32 role, address account) external; + + /** + * @dev Revokes `role` from `account`. + * + * If `account` had been granted `role`, emits a {RoleRevoked} event. + * + * Requirements: + * + * - the caller must have ``role``'s admin role. + */ + function revokeRole(bytes32 role, address account) external; + + /** + * @dev Revokes `role` from the calling account. + * + * Roles are often managed via {grantRole} and {revokeRole}: this function's + * purpose is to provide a mechanism for accounts to lose their privileges + * if they are compromised (such as when a trusted device is misplaced). + * + * If the calling account had been granted `role`, emits a {RoleRevoked} + * event. + * + * Requirements: + * + * - the caller must be `account`. + */ + function renounceRole(bytes32 role, address account) external; +} + +// lib/openzeppelin-contracts/contracts\token/ERC20/IERC20.sol + +// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol) + + + +/** + * @dev Interface of the ERC20 standard as defined in the EIP. + */ +interface IERC20 { + /** + * @dev Emitted when `value` tokens are moved from one account (`from`) to + * another (`to`). + * + * Note that `value` may be zero. + */ + event Transfer(address indexed from, address indexed to, uint256 value); + + /** + * @dev Emitted when the allowance of a `spender` for an `owner` is set by + * a call to {approve}. `value` is the new allowance. + */ + event Approval(address indexed owner, address indexed spender, uint256 value); + + /** + * @dev Returns the amount of tokens in existence. + */ + function totalSupply() external view returns (uint256); + + /** + * @dev Returns the amount of tokens owned by `account`. + */ + function balanceOf(address account) external view returns (uint256); + + /** + * @dev Moves `amount` tokens from the caller's account to `to`. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * Emits a {Transfer} event. + */ + function transfer(address to, uint256 amount) external returns (bool); + + /** + * @dev Returns the remaining number of tokens that `spender` will be + * allowed to spend on behalf of `owner` through {transferFrom}. This is + * zero by default. + * + * This value changes when {approve} or {transferFrom} are called. + */ + function allowance(address owner, address spender) external view returns (uint256); + + /** + * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * IMPORTANT: Beware that changing an allowance with this method brings the risk + * that someone may use both the old and the new allowance by unfortunate + * transaction ordering. One possible solution to mitigate this race + * condition is to first reduce the spender's allowance to 0 and set the + * desired value afterwards: + * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 + * + * Emits an {Approval} event. + */ + function approve(address spender, uint256 amount) external returns (bool); + + /** + * @dev Moves `amount` tokens from `from` to `to` using the + * allowance mechanism. `amount` is then deducted from the caller's + * allowance. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * Emits a {Transfer} event. + */ + function transferFrom(address from, address to, uint256 amount) external returns (bool); +} + +// lib/openzeppelin-contracts/contracts/utils/introspection/IERC165.sol + +// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol) + + + +/** + * @dev Interface of the ERC165 standard, as defined in the + * https://eips.ethereum.org/EIPS/eip-165[EIP]. + * + * Implementers can declare support of contract interfaces, which can then be + * queried by others ({ERC165Checker}). + * + * For an implementation, see {ERC165}. + */ +interface IERC165 { + /** + * @dev Returns true if this contract implements the interface defined by + * `interfaceId`. See the corresponding + * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] + * to learn more about how these ids are created. + * + * This function call must use less than 30 000 gas. + */ + function supportsInterface(bytes4 interfaceId) external view returns (bool); +} + +// lib/solady/src/auth/Ownable.sol + + + +/// @notice Simple single owner authorization mixin. +/// @author Solady (https://github.com/vectorized/solady/blob/main/src/auth/Ownable.sol) +/// @dev While the ownable portion follows +/// [EIP-173](https://eips.ethereum.org/EIPS/eip-173) for compatibility, +/// the nomenclature for the 2-step ownership handover may be unique to this codebase. +abstract contract Ownable { + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* CUSTOM ERRORS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev The caller is not authorized to call the function. + error Unauthorized(); + + /// @dev The `newOwner` cannot be the zero address. + error NewOwnerIsZeroAddress(); + + /// @dev The `pendingOwner` does not have a valid handover request. + error NoHandoverRequest(); + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* EVENTS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev The ownership is transferred from `oldOwner` to `newOwner`. + /// This event is intentionally kept the same as OpenZeppelin's Ownable to be + /// compatible with indexers and [EIP-173](https://eips.ethereum.org/EIPS/eip-173), + /// despite it not being as lightweight as a single argument event. + event OwnershipTransferred(address indexed oldOwner, address indexed newOwner); + + /// @dev An ownership handover to `pendingOwner` has been requested. + event OwnershipHandoverRequested(address indexed pendingOwner); + + /// @dev The ownership handover to `pendingOwner` has been canceled. + event OwnershipHandoverCanceled(address indexed pendingOwner); + + /// @dev `keccak256(bytes("OwnershipTransferred(address,address)"))`. + uint256 private constant _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE = + 0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0; + + /// @dev `keccak256(bytes("OwnershipHandoverRequested(address)"))`. + uint256 private constant _OWNERSHIP_HANDOVER_REQUESTED_EVENT_SIGNATURE = + 0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d; + + /// @dev `keccak256(bytes("OwnershipHandoverCanceled(address)"))`. + uint256 private constant _OWNERSHIP_HANDOVER_CANCELED_EVENT_SIGNATURE = + 0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92; + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* STORAGE */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev The owner slot is given by: `not(_OWNER_SLOT_NOT)`. + /// It is intentionally chosen to be a high value + /// to avoid collision with lower slots. + /// The choice of manual storage layout is to enable compatibility + /// with both regular and upgradeable contracts. + uint256 private constant _OWNER_SLOT_NOT = 0x8b78c6d8; + + /// The ownership handover slot of `newOwner` is given by: + /// ``` + /// mstore(0x00, or(shl(96, user), _HANDOVER_SLOT_SEED)) + /// let handoverSlot := keccak256(0x00, 0x20) + /// ``` + /// It stores the expiry timestamp of the two-step ownership handover. + uint256 private constant _HANDOVER_SLOT_SEED = 0x389a75e1; + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* INTERNAL FUNCTIONS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev Initializes the owner directly without authorization guard. + /// This function must be called upon initialization, + /// regardless of whether the contract is upgradeable or not. + /// This is to enable generalization to both regular and upgradeable contracts, + /// and to save gas in case the initial owner is not the caller. + /// For performance reasons, this function will not check if there + /// is an existing owner. + function _initializeOwner(address newOwner) internal virtual { + /// @solidity memory-safe-assembly + assembly { + // Clean the upper 96 bits. + newOwner := shr(96, shl(96, newOwner)) + // Store the new value. + sstore(not(_OWNER_SLOT_NOT), newOwner) + // Emit the {OwnershipTransferred} event. + log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, 0, newOwner) + } + } + + /// @dev Sets the owner directly without authorization guard. + function _setOwner(address newOwner) internal virtual { + /// @solidity memory-safe-assembly + assembly { + let ownerSlot := not(_OWNER_SLOT_NOT) + // Clean the upper 96 bits. + newOwner := shr(96, shl(96, newOwner)) + // Emit the {OwnershipTransferred} event. + log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, sload(ownerSlot), newOwner) + // Store the new value. + sstore(ownerSlot, newOwner) + } + } + + /// @dev Throws if the sender is not the owner. + function _checkOwner() internal view virtual { + /// @solidity memory-safe-assembly + assembly { + // If the caller is not the stored owner, revert. + if iszero(eq(caller(), sload(not(_OWNER_SLOT_NOT)))) { + mstore(0x00, 0x82b42900) // `Unauthorized()`. + revert(0x1c, 0x04) + } + } + } + + /// @dev Returns how long a two-step ownership handover is valid for in seconds. + /// Override to return a different value if needed. + /// Made internal to conserve bytecode. Wrap it in a public function if needed. + function _ownershipHandoverValidFor() internal view virtual returns (uint64) { + return 48 * 3600; + } + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* PUBLIC UPDATE FUNCTIONS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev Allows the owner to transfer the ownership to `newOwner`. + function transferOwnership(address newOwner) public payable virtual onlyOwner { + /// @solidity memory-safe-assembly + assembly { + if iszero(shl(96, newOwner)) { + mstore(0x00, 0x7448fbae) // `NewOwnerIsZeroAddress()`. + revert(0x1c, 0x04) + } + } + _setOwner(newOwner); + } + + /// @dev Allows the owner to renounce their ownership. + function renounceOwnership() public payable virtual onlyOwner { + _setOwner(address(0)); + } + + /// @dev Request a two-step ownership handover to the caller. + /// The request will automatically expire in 48 hours (172800 seconds) by default. + function requestOwnershipHandover() public payable virtual { + unchecked { + uint256 expires = block.timestamp + _ownershipHandoverValidFor(); + /// @solidity memory-safe-assembly + assembly { + // Compute and set the handover slot to `expires`. + mstore(0x0c, _HANDOVER_SLOT_SEED) + mstore(0x00, caller()) + sstore(keccak256(0x0c, 0x20), expires) + // Emit the {OwnershipHandoverRequested} event. + log2(0, 0, _OWNERSHIP_HANDOVER_REQUESTED_EVENT_SIGNATURE, caller()) + } + } + } + + /// @dev Cancels the two-step ownership handover to the caller, if any. + function cancelOwnershipHandover() public payable virtual { + /// @solidity memory-safe-assembly + assembly { + // Compute and set the handover slot to 0. + mstore(0x0c, _HANDOVER_SLOT_SEED) + mstore(0x00, caller()) + sstore(keccak256(0x0c, 0x20), 0) + // Emit the {OwnershipHandoverCanceled} event. + log2(0, 0, _OWNERSHIP_HANDOVER_CANCELED_EVENT_SIGNATURE, caller()) + } + } + + /// @dev Allows the owner to complete the two-step ownership handover to `pendingOwner`. + /// Reverts if there is no existing ownership handover requested by `pendingOwner`. + function completeOwnershipHandover(address pendingOwner) public payable virtual onlyOwner { + /// @solidity memory-safe-assembly + assembly { + // Compute and set the handover slot to 0. + mstore(0x0c, _HANDOVER_SLOT_SEED) + mstore(0x00, pendingOwner) + let handoverSlot := keccak256(0x0c, 0x20) + // If the handover does not exist, or has expired. + if gt(timestamp(), sload(handoverSlot)) { + mstore(0x00, 0x6f5e8818) // `NoHandoverRequest()`. + revert(0x1c, 0x04) + } + // Set the handover slot to 0. + sstore(handoverSlot, 0) + } + _setOwner(pendingOwner); + } + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* PUBLIC READ FUNCTIONS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev Returns the owner of the contract. + function owner() public view virtual returns (address result) { + /// @solidity memory-safe-assembly + assembly { + result := sload(not(_OWNER_SLOT_NOT)) + } + } + + /// @dev Returns the expiry timestamp for the two-step ownership handover to `pendingOwner`. + function ownershipHandoverExpiresAt(address pendingOwner) + public + view + virtual + returns (uint256 result) + { + /// @solidity memory-safe-assembly + assembly { + // Compute the handover slot. + mstore(0x0c, _HANDOVER_SLOT_SEED) + mstore(0x00, pendingOwner) + // Load the handover slot. + result := sload(keccak256(0x0c, 0x20)) + } + } + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* MODIFIERS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev Marks a function as only callable by the owner. + modifier onlyOwner() virtual { + _checkOwner(); + _; + } +} + +// lib/solady/src\utils/ECDSA.sol + + + +/// @notice Gas optimized ECDSA wrapper. +/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/ECDSA.sol) +/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/ECDSA.sol) +/// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/cryptography/ECDSA.sol) +library ECDSA { + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* CUSTOM ERRORS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev The signature is invalid. + error InvalidSignature(); + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* CONSTANTS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev The number which `s` must be less than in order for + /// the signature to be non-malleable. + bytes32 private constant _MALLEABILITY_THRESHOLD_PLUS_ONE = + 0x7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a1; + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* RECOVERY OPERATIONS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + // Note: as of Solady version 0.0.68, these functions will + // revert upon recovery failure for more safety by default. + + /// @dev Recovers the signer's address from a message digest `hash`, + /// and the `signature`. + /// + /// This function does NOT accept EIP-2098 short form signatures. + /// Use `recover(bytes32 hash, bytes32 r, bytes32 vs)` for EIP-2098 + /// short form signatures instead. + function recover(bytes32 hash, bytes memory signature) internal view returns (address result) { + /// @solidity memory-safe-assembly + assembly { + let m := mload(0x40) // Cache the free memory pointer. + mstore(0x00, hash) + mstore(0x20, byte(0, mload(add(signature, 0x60)))) // `v`. + mstore(0x40, mload(add(signature, 0x20))) // `r`. + mstore(0x60, mload(add(signature, 0x40))) // `s`. + pop( + staticcall( + gas(), // Amount of gas left for the transaction. + and( + // If the signature is exactly 65 bytes in length. + eq(mload(signature), 65), + // If `s` in lower half order, such that the signature is not malleable. + lt(mload(0x60), _MALLEABILITY_THRESHOLD_PLUS_ONE) + ), // Address of `ecrecover`. + 0x00, // Start of input. + 0x80, // Size of input. + 0x00, // Start of output. + 0x20 // Size of output. + ) + ) + result := mload(0x00) + // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise. + if iszero(returndatasize()) { + mstore(0x00, 0x8baa579f) // `InvalidSignature()`. + revert(0x1c, 0x04) + } + mstore(0x60, 0) // Restore the zero slot. + mstore(0x40, m) // Restore the free memory pointer. + } + } + + /// @dev Recovers the signer's address from a message digest `hash`, + /// and the `signature`. + /// + /// This function does NOT accept EIP-2098 short form signatures. + /// Use `recover(bytes32 hash, bytes32 r, bytes32 vs)` for EIP-2098 + /// short form signatures instead. + function recoverCalldata(bytes32 hash, bytes calldata signature) + internal + view + returns (address result) + { + /// @solidity memory-safe-assembly + assembly { + let m := mload(0x40) // Cache the free memory pointer. + mstore(0x00, hash) + mstore(0x20, byte(0, calldataload(add(signature.offset, 0x40)))) // `v`. + calldatacopy(0x40, signature.offset, 0x40) // Copy `r` and `s`. + pop( + staticcall( + gas(), // Amount of gas left for the transaction. + and( + // If the signature is exactly 65 bytes in length. + eq(signature.length, 65), + // If `s` in lower half order, such that the signature is not malleable. + lt(mload(0x60), _MALLEABILITY_THRESHOLD_PLUS_ONE) + ), // Address of `ecrecover`. + 0x00, // Start of input. + 0x80, // Size of input. + 0x00, // Start of output. + 0x20 // Size of output. + ) + ) + result := mload(0x00) + // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise. + if iszero(returndatasize()) { + mstore(0x00, 0x8baa579f) // `InvalidSignature()`. + revert(0x1c, 0x04) + } + mstore(0x60, 0) // Restore the zero slot. + mstore(0x40, m) // Restore the free memory pointer. + } + } + + /// @dev Recovers the signer's address from a message digest `hash`, + /// and the EIP-2098 short form signature defined by `r` and `vs`. + /// + /// This function only accepts EIP-2098 short form signatures. + /// See: https://eips.ethereum.org/EIPS/eip-2098 + function recover(bytes32 hash, bytes32 r, bytes32 vs) internal view returns (address result) { + /// @solidity memory-safe-assembly + assembly { + let m := mload(0x40) // Cache the free memory pointer. + mstore(0x00, hash) + mstore(0x20, add(shr(255, vs), 27)) // `v`. + mstore(0x40, r) + mstore(0x60, shr(1, shl(1, vs))) // `s`. + pop( + staticcall( + gas(), // Amount of gas left for the transaction. + // If `s` in lower half order, such that the signature is not malleable. + lt(mload(0x60), _MALLEABILITY_THRESHOLD_PLUS_ONE), // Address of `ecrecover`. + 0x00, // Start of input. + 0x80, // Size of input. + 0x00, // Start of output. + 0x20 // Size of output. + ) + ) + result := mload(0x00) + // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise. + if iszero(returndatasize()) { + mstore(0x00, 0x8baa579f) // `InvalidSignature()`. + revert(0x1c, 0x04) + } + mstore(0x60, 0) // Restore the zero slot. + mstore(0x40, m) // Restore the free memory pointer. + } + } + + /// @dev Recovers the signer's address from a message digest `hash`, + /// and the signature defined by `v`, `r`, `s`. + function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) + internal + view + returns (address result) + { + /// @solidity memory-safe-assembly + assembly { + let m := mload(0x40) // Cache the free memory pointer. + mstore(0x00, hash) + mstore(0x20, and(v, 0xff)) + mstore(0x40, r) + mstore(0x60, s) + pop( + staticcall( + gas(), // Amount of gas left for the transaction. + // If `s` in lower half order, such that the signature is not malleable. + lt(s, _MALLEABILITY_THRESHOLD_PLUS_ONE), // Address of `ecrecover`. + 0x00, // Start of input. + 0x80, // Size of input. + 0x00, // Start of output. + 0x20 // Size of output. + ) + ) + result := mload(0x00) + // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise. + if iszero(returndatasize()) { + mstore(0x00, 0x8baa579f) // `InvalidSignature()`. + revert(0x1c, 0x04) + } + mstore(0x60, 0) // Restore the zero slot. + mstore(0x40, m) // Restore the free memory pointer. + } + } + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* TRY-RECOVER OPERATIONS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + // WARNING! + // These functions will NOT revert upon recovery failure. + // Instead, they will return the zero address upon recovery failure. + // It is critical that the returned address is NEVER compared against + // a zero address (e.g. an uninitialized address variable). + + /// @dev Recovers the signer's address from a message digest `hash`, + /// and the `signature`. + /// + /// This function does NOT accept EIP-2098 short form signatures. + /// Use `recover(bytes32 hash, bytes32 r, bytes32 vs)` for EIP-2098 + /// short form signatures instead. + function tryRecover(bytes32 hash, bytes memory signature) + internal + view + returns (address result) + { + /// @solidity memory-safe-assembly + assembly { + let m := mload(0x40) // Cache the free memory pointer. + mstore(0x00, hash) + mstore(0x20, byte(0, mload(add(signature, 0x60)))) // `v`. + mstore(0x40, mload(add(signature, 0x20))) // `r`. + mstore(0x60, mload(add(signature, 0x40))) // `s`. + pop( + staticcall( + gas(), // Amount of gas left for the transaction. + and( + // If the signature is exactly 65 bytes in length. + eq(mload(signature), 65), + // If `s` in lower half order, such that the signature is not malleable. + lt(mload(0x60), _MALLEABILITY_THRESHOLD_PLUS_ONE) + ), // Address of `ecrecover`. + 0x00, // Start of input. + 0x80, // Size of input. + 0x40, // Start of output. + 0x20 // Size of output. + ) + ) + mstore(0x60, 0) // Restore the zero slot. + // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise. + result := mload(xor(0x60, returndatasize())) + mstore(0x40, m) // Restore the free memory pointer. + } + } + + /// @dev Recovers the signer's address from a message digest `hash`, + /// and the `signature`. + /// + /// This function does NOT accept EIP-2098 short form signatures. + /// Use `recover(bytes32 hash, bytes32 r, bytes32 vs)` for EIP-2098 + /// short form signatures instead. + function tryRecoverCalldata(bytes32 hash, bytes calldata signature) + internal + view + returns (address result) + { + /// @solidity memory-safe-assembly + assembly { + let m := mload(0x40) // Cache the free memory pointer. + mstore(0x00, hash) + mstore(0x20, byte(0, calldataload(add(signature.offset, 0x40)))) // `v`. + calldatacopy(0x40, signature.offset, 0x40) // Copy `r` and `s`. + pop( + staticcall( + gas(), // Amount of gas left for the transaction. + and( + // If the signature is exactly 65 bytes in length. + eq(signature.length, 65), + // If `s` in lower half order, such that the signature is not malleable. + lt(mload(0x60), _MALLEABILITY_THRESHOLD_PLUS_ONE) + ), // Address of `ecrecover`. + 0x00, // Start of input. + 0x80, // Size of input. + 0x40, // Start of output. + 0x20 // Size of output. + ) + ) + mstore(0x60, 0) // Restore the zero slot. + // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise. + result := mload(xor(0x60, returndatasize())) + mstore(0x40, m) // Restore the free memory pointer. + } + } + + /// @dev Recovers the signer's address from a message digest `hash`, + /// and the EIP-2098 short form signature defined by `r` and `vs`. + /// + /// This function only accepts EIP-2098 short form signatures. + /// See: https://eips.ethereum.org/EIPS/eip-2098 + function tryRecover(bytes32 hash, bytes32 r, bytes32 vs) + internal + view + returns (address result) + { + /// @solidity memory-safe-assembly + assembly { + let m := mload(0x40) // Cache the free memory pointer. + mstore(0x00, hash) + mstore(0x20, add(shr(255, vs), 27)) // `v`. + mstore(0x40, r) + mstore(0x60, shr(1, shl(1, vs))) // `s`. + pop( + staticcall( + gas(), // Amount of gas left for the transaction. + // If `s` in lower half order, such that the signature is not malleable. + lt(mload(0x60), _MALLEABILITY_THRESHOLD_PLUS_ONE), // Address of `ecrecover`. + 0x00, // Start of input. + 0x80, // Size of input. + 0x40, // Start of output. + 0x20 // Size of output. + ) + ) + mstore(0x60, 0) // Restore the zero slot. + // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise. + result := mload(xor(0x60, returndatasize())) + mstore(0x40, m) // Restore the free memory pointer. + } + } + + /// @dev Recovers the signer's address from a message digest `hash`, + /// and the signature defined by `v`, `r`, `s`. + function tryRecover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) + internal + view + returns (address result) + { + /// @solidity memory-safe-assembly + assembly { + let m := mload(0x40) // Cache the free memory pointer. + mstore(0x00, hash) + mstore(0x20, and(v, 0xff)) + mstore(0x40, r) + mstore(0x60, s) + pop( + staticcall( + gas(), // Amount of gas left for the transaction. + // If `s` in lower half order, such that the signature is not malleable. + lt(s, _MALLEABILITY_THRESHOLD_PLUS_ONE), // Address of `ecrecover`. + 0x00, // Start of input. + 0x80, // Size of input. + 0x40, // Start of output. + 0x20 // Size of output. + ) + ) + mstore(0x60, 0) // Restore the zero slot. + // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise. + result := mload(xor(0x60, returndatasize())) + mstore(0x40, m) // Restore the free memory pointer. + } + } + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* HASHING OPERATIONS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev Returns an Ethereum Signed Message, created from a `hash`. + /// This produces a hash corresponding to the one signed with the + /// [`eth_sign`](https://eth.wiki/json-rpc/API#eth_sign) + /// JSON-RPC method as part of EIP-191. + function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32 result) { + /// @solidity memory-safe-assembly + assembly { + mstore(0x20, hash) // Store into scratch space for keccak256. + mstore(0x00, "\x00\x00\x00\x00\x19Ethereum Signed Message:\n32") // 28 bytes. + result := keccak256(0x04, 0x3c) // `32 * 2 - (32 - 28) = 60 = 0x3c`. + } + } + + /// @dev Returns an Ethereum Signed Message, created from `s`. + /// This produces a hash corresponding to the one signed with the + /// [`eth_sign`](https://eth.wiki/json-rpc/API#eth_sign) + /// JSON-RPC method as part of EIP-191. + /// Note: Supports lengths of `s` up to 999999 bytes. + function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32 result) { + /// @solidity memory-safe-assembly + assembly { + let sLength := mload(s) + let o := 0x20 + mstore(o, "\x19Ethereum Signed Message:\n") // 26 bytes, zero-right-padded. + mstore(0x00, 0x00) + // Convert the `s.length` to ASCII decimal representation: `base10(s.length)`. + for { let temp := sLength } 1 {} { + o := sub(o, 1) + mstore8(o, add(48, mod(temp, 10))) + temp := div(temp, 10) + if iszero(temp) { break } + } + let n := sub(0x3a, o) // Header length: `26 + 32 - o`. + // Throw an out-of-offset error (consumes all gas) if the header exceeds 32 bytes. + returndatacopy(returndatasize(), returndatasize(), gt(n, 0x20)) + mstore(s, or(mload(0x00), mload(n))) // Temporarily store the header. + result := keccak256(add(s, sub(0x20, n)), add(n, sLength)) + mstore(s, sLength) // Restore the length. + } + } + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* EMPTY CALLDATA HELPERS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev Returns an empty calldata bytes. + function emptySignature() internal pure returns (bytes calldata signature) { + /// @solidity memory-safe-assembly + assembly { + signature.length := 0 + } + } +} + +// lib/ERC721A/contracts\extensions/IERC721ABurnable.sol + +// ERC721A Contracts v4.2.3 +// Creator: Chiru Labs + + + + + +/** + * @dev Interface of ERC721ABurnable. + */ +interface IERC721ABurnable is IERC721A { + /** + * @dev Burns `tokenId`. See {ERC721A-_burn}. + * + * Requirements: + * + * - The caller must own `tokenId` or be an approved operator. + */ + function burn(uint256 tokenId) external; +} + +// lib/ERC721A/contracts\extensions/IERC721AQueryable.sol + +// ERC721A Contracts v4.2.3 +// Creator: Chiru Labs + + + + + +/** + * @dev Interface of ERC721AQueryable. + */ +interface IERC721AQueryable is IERC721A { + /** + * Invalid query range (`start` >= `stop`). + */ + error InvalidQueryRange(); + + /** + * @dev Returns the `TokenOwnership` struct at `tokenId` without reverting. + * + * If the `tokenId` is out of bounds: + * + * - `addr = address(0)` + * - `startTimestamp = 0` + * - `burned = false` + * - `extraData = 0` + * + * If the `tokenId` is burned: + * + * - `addr =
` + * - `startTimestamp = ` + * - `burned = true` + * - `extraData = ` + * + * Otherwise: + * + * - `addr =
` + * - `startTimestamp = ` + * - `burned = false` + * - `extraData = ` + */ + function explicitOwnershipOf(uint256 tokenId) external view returns (TokenOwnership memory); + + /** + * @dev Returns an array of `TokenOwnership` structs at `tokenIds` in order. + * See {ERC721AQueryable-explicitOwnershipOf} + */ + function explicitOwnershipsOf(uint256[] memory tokenIds) external view returns (TokenOwnership[] memory); + + /** + * @dev Returns an array of token IDs owned by `owner`, + * in the range [`start`, `stop`) + * (i.e. `start <= tokenId < stop`). + * + * This function allows for tokens to be queried if the collection + * grows too big for a single call of {ERC721AQueryable-tokensOfOwner}. + * + * Requirements: + * + * - `start < stop` + */ + function tokensOfOwnerIn( + address owner, + uint256 start, + uint256 stop + ) external view returns (uint256[] memory); + + /** + * @dev Returns an array of token IDs owned by `owner`. + * + * This function scans the ownership mapping and is O(`totalSupply`) in complexity. + * It is meant to be called off-chain. + * + * See {ERC721AQueryable-tokensOfOwnerIn} for splitting the scan into + * multiple smaller scans if the collection is large enough to cause + * an out-of-gas error (10K collections should be fine). + */ + function tokensOfOwner(address owner) external view returns (uint256[] memory); +} + +// lib/openzeppelin-contracts/contracts\interfaces/IERC165.sol + +// OpenZeppelin Contracts v4.4.1 (interfaces/IERC165.sol) + + + + + +// lib/openzeppelin-contracts/contracts\interfaces/IERC2981.sol + +// OpenZeppelin Contracts (last updated v4.9.0) (interfaces/IERC2981.sol) + + + + + +/** + * @dev Interface for the NFT Royalty Standard. + * + * A standardized way to retrieve royalty payment information for non-fungible tokens (NFTs) to enable universal + * support for royalty payments across all NFT marketplaces and ecosystem participants. + * + * _Available since v4.5._ + */ +interface IERC2981 is IERC165 { + /** + * @dev Returns how much royalty is owed and to whom, based on a sale price that may be denominated in any unit of + * exchange. The royalty amount is denominated and should be paid in that same unit of exchange. + */ + function royaltyInfo( + uint256 tokenId, + uint256 salePrice + ) external view returns (address receiver, uint256 royaltyAmount); +} + +// lib/openzeppelin-contracts/contracts\token/ERC721/IERC721.sol + +// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC721/IERC721.sol) + + + + + +/** + * @dev Required interface of an ERC721 compliant contract. + */ +interface IERC721 is IERC165 { + /** + * @dev Emitted when `tokenId` token is transferred from `from` to `to`. + */ + event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); + + /** + * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token. + */ + event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); + + /** + * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets. + */ + event ApprovalForAll(address indexed owner, address indexed operator, bool approved); + + /** + * @dev Returns the number of tokens in ``owner``'s account. + */ + function balanceOf(address owner) external view returns (uint256 balance); + + /** + * @dev Returns the owner of the `tokenId` token. + * + * Requirements: + * + * - `tokenId` must exist. + */ + function ownerOf(uint256 tokenId) external view returns (address owner); + + /** + * @dev Safely transfers `tokenId` token from `from` to `to`. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must exist and be owned by `from`. + * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. + * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. + * + * Emits a {Transfer} event. + */ + function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external; + + /** + * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients + * are aware of the ERC721 protocol to prevent tokens from being forever locked. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must exist and be owned by `from`. + * - If the caller is not `from`, it must have been allowed to move this token by either {approve} or {setApprovalForAll}. + * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. + * + * Emits a {Transfer} event. + */ + function safeTransferFrom(address from, address to, uint256 tokenId) external; + + /** + * @dev Transfers `tokenId` token from `from` to `to`. + * + * WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721 + * or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must + * understand this adds an external call which potentially creates a reentrancy vulnerability. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must be owned by `from`. + * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. + * + * Emits a {Transfer} event. + */ + function transferFrom(address from, address to, uint256 tokenId) external; + + /** + * @dev Gives permission to `to` to transfer `tokenId` token to another account. + * The approval is cleared when the token is transferred. + * + * Only a single account can be approved at a time, so approving the zero address clears previous approvals. + * + * Requirements: + * + * - The caller must own the token or be an approved operator. + * - `tokenId` must exist. + * + * Emits an {Approval} event. + */ + function approve(address to, uint256 tokenId) external; + + /** + * @dev Approve or remove `operator` as an operator for the caller. + * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller. + * + * Requirements: + * + * - The `operator` cannot be the caller. + * + * Emits an {ApprovalForAll} event. + */ + function setApprovalForAll(address operator, bool approved) external; + + /** + * @dev Returns the account approved for `tokenId` token. + * + * Requirements: + * + * - `tokenId` must exist. + */ + function getApproved(uint256 tokenId) external view returns (address operator); + + /** + * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`. + * + * See {setApprovalForAll} + */ + function isApprovedForAll(address owner, address operator) external view returns (bool); +} + +// lib/solady/src\auth/OwnableRoles.sol + + + + + +/// @notice Simple single owner and multiroles authorization mixin. +/// @author Solady (https://github.com/vectorized/solady/blob/main/src/auth/Ownable.sol) +/// @dev While the ownable portion follows [EIP-173](https://eips.ethereum.org/EIPS/eip-173) +/// for compatibility, the nomenclature for the 2-step ownership handover and roles +/// may be unique to this codebase. +abstract contract OwnableRoles is Ownable { + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* EVENTS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev The `user`'s roles is updated to `roles`. + /// Each bit of `roles` represents whether the role is set. + event RolesUpdated(address indexed user, uint256 indexed roles); + + /// @dev `keccak256(bytes("RolesUpdated(address,uint256)"))`. + uint256 private constant _ROLES_UPDATED_EVENT_SIGNATURE = + 0x715ad5ce61fc9595c7b415289d59cf203f23a94fa06f04af7e489a0a76e1fe26; + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* STORAGE */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev The role slot of `user` is given by: + /// ``` + /// mstore(0x00, or(shl(96, user), _ROLE_SLOT_SEED)) + /// let roleSlot := keccak256(0x00, 0x20) + /// ``` + /// This automatically ignores the upper bits of the `user` in case + /// they are not clean, as well as keep the `keccak256` under 32-bytes. + /// + /// Note: This is equal to `_OWNER_SLOT_NOT` in for gas efficiency. + uint256 private constant _ROLE_SLOT_SEED = 0x8b78c6d8; + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* INTERNAL FUNCTIONS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev Overwrite the roles directly without authorization guard. + function _setRoles(address user, uint256 roles) internal virtual { + /// @solidity memory-safe-assembly + assembly { + mstore(0x0c, _ROLE_SLOT_SEED) + mstore(0x00, user) + // Store the new value. + sstore(keccak256(0x0c, 0x20), roles) + // Emit the {RolesUpdated} event. + log3(0, 0, _ROLES_UPDATED_EVENT_SIGNATURE, shr(96, mload(0x0c)), roles) + } + } + + /// @dev Updates the roles directly without authorization guard. + /// If `on` is true, each set bit of `roles` will be turned on, + /// otherwise, each set bit of `roles` will be turned off. + function _updateRoles(address user, uint256 roles, bool on) internal virtual { + /// @solidity memory-safe-assembly + assembly { + mstore(0x0c, _ROLE_SLOT_SEED) + mstore(0x00, user) + let roleSlot := keccak256(0x0c, 0x20) + // Load the current value. + let current := sload(roleSlot) + // Compute the updated roles if `on` is true. + let updated := or(current, roles) + // Compute the updated roles if `on` is false. + // Use `and` to compute the intersection of `current` and `roles`, + // `xor` it with `current` to flip the bits in the intersection. + if iszero(on) { updated := xor(current, and(current, roles)) } + // Then, store the new value. + sstore(roleSlot, updated) + // Emit the {RolesUpdated} event. + log3(0, 0, _ROLES_UPDATED_EVENT_SIGNATURE, shr(96, mload(0x0c)), updated) + } + } + + /// @dev Grants the roles directly without authorization guard. + /// Each bit of `roles` represents the role to turn on. + function _grantRoles(address user, uint256 roles) internal virtual { + _updateRoles(user, roles, true); + } + + /// @dev Removes the roles directly without authorization guard. + /// Each bit of `roles` represents the role to turn off. + function _removeRoles(address user, uint256 roles) internal virtual { + _updateRoles(user, roles, false); + } + + /// @dev Throws if the sender does not have any of the `roles`. + function _checkRoles(uint256 roles) internal view virtual { + /// @solidity memory-safe-assembly + assembly { + // Compute the role slot. + mstore(0x0c, _ROLE_SLOT_SEED) + mstore(0x00, caller()) + // Load the stored value, and if the `and` intersection + // of the value and `roles` is zero, revert. + if iszero(and(sload(keccak256(0x0c, 0x20)), roles)) { + mstore(0x00, 0x82b42900) // `Unauthorized()`. + revert(0x1c, 0x04) + } + } + } + + /// @dev Throws if the sender is not the owner, + /// and does not have any of the `roles`. + /// Checks for ownership first, then lazily checks for roles. + function _checkOwnerOrRoles(uint256 roles) internal view virtual { + /// @solidity memory-safe-assembly + assembly { + // If the caller is not the stored owner. + // Note: `_ROLE_SLOT_SEED` is equal to `_OWNER_SLOT_NOT`. + if iszero(eq(caller(), sload(not(_ROLE_SLOT_SEED)))) { + // Compute the role slot. + mstore(0x0c, _ROLE_SLOT_SEED) + mstore(0x00, caller()) + // Load the stored value, and if the `and` intersection + // of the value and `roles` is zero, revert. + if iszero(and(sload(keccak256(0x0c, 0x20)), roles)) { + mstore(0x00, 0x82b42900) // `Unauthorized()`. + revert(0x1c, 0x04) + } + } + } + } + + /// @dev Throws if the sender does not have any of the `roles`, + /// and is not the owner. + /// Checks for roles first, then lazily checks for ownership. + function _checkRolesOrOwner(uint256 roles) internal view virtual { + /// @solidity memory-safe-assembly + assembly { + // Compute the role slot. + mstore(0x0c, _ROLE_SLOT_SEED) + mstore(0x00, caller()) + // Load the stored value, and if the `and` intersection + // of the value and `roles` is zero, revert. + if iszero(and(sload(keccak256(0x0c, 0x20)), roles)) { + // If the caller is not the stored owner. + // Note: `_ROLE_SLOT_SEED` is equal to `_OWNER_SLOT_NOT`. + if iszero(eq(caller(), sload(not(_ROLE_SLOT_SEED)))) { + mstore(0x00, 0x82b42900) // `Unauthorized()`. + revert(0x1c, 0x04) + } + } + } + } + + /// @dev Convenience function to return a `roles` bitmap from an array of `ordinals`. + /// This is meant for frontends like Etherscan, and is therefore not fully optimized. + /// Not recommended to be called on-chain. + /// Made internal to conserve bytecode. Wrap it in a public function if needed. + function _rolesFromOrdinals(uint8[] memory ordinals) internal pure returns (uint256 roles) { + /// @solidity memory-safe-assembly + assembly { + for { let i := shl(5, mload(ordinals)) } i { i := sub(i, 0x20) } { + // We don't need to mask the values of `ordinals`, as Solidity + // cleans dirty upper bits when storing variables into memory. + roles := or(shl(mload(add(ordinals, i)), 1), roles) + } + } + } + + /// @dev Convenience function to return an array of `ordinals` from the `roles` bitmap. + /// This is meant for frontends like Etherscan, and is therefore not fully optimized. + /// Not recommended to be called on-chain. + /// Made internal to conserve bytecode. Wrap it in a public function if needed. + function _ordinalsFromRoles(uint256 roles) internal pure returns (uint8[] memory ordinals) { + /// @solidity memory-safe-assembly + assembly { + // Grab the pointer to the free memory. + ordinals := mload(0x40) + let ptr := add(ordinals, 0x20) + let o := 0 + // The absence of lookup tables, De Bruijn, etc., here is intentional for + // smaller bytecode, as this function is not meant to be called on-chain. + for { let t := roles } 1 {} { + mstore(ptr, o) + // `shr` 5 is equivalent to multiplying by 0x20. + // Push back into the ordinals array if the bit is set. + ptr := add(ptr, shl(5, and(t, 1))) + o := add(o, 1) + t := shr(o, roles) + if iszero(t) { break } + } + // Store the length of `ordinals`. + mstore(ordinals, shr(5, sub(ptr, add(ordinals, 0x20)))) + // Allocate the memory. + mstore(0x40, ptr) + } + } + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* PUBLIC UPDATE FUNCTIONS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev Allows the owner to grant `user` `roles`. + /// If the `user` already has a role, then it will be an no-op for the role. + function grantRoles(address user, uint256 roles) public payable virtual onlyOwner { + _grantRoles(user, roles); + } + + /// @dev Allows the owner to remove `user` `roles`. + /// If the `user` does not have a role, then it will be an no-op for the role. + function revokeRoles(address user, uint256 roles) public payable virtual onlyOwner { + _removeRoles(user, roles); + } + + /// @dev Allow the caller to remove their own roles. + /// If the caller does not have a role, then it will be an no-op for the role. + function renounceRoles(uint256 roles) public payable virtual { + _removeRoles(msg.sender, roles); + } + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* PUBLIC READ FUNCTIONS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev Returns the roles of `user`. + function rolesOf(address user) public view virtual returns (uint256 roles) { + /// @solidity memory-safe-assembly + assembly { + // Compute the role slot. + mstore(0x0c, _ROLE_SLOT_SEED) + mstore(0x00, user) + // Load the stored value. + roles := sload(keccak256(0x0c, 0x20)) + } + } + + /// @dev Returns whether `user` has any of `roles`. + function hasAnyRole(address user, uint256 roles) public view virtual returns (bool) { + return rolesOf(user) & roles != 0; + } + + /// @dev Returns whether `user` has all of `roles`. + function hasAllRoles(address user, uint256 roles) public view virtual returns (bool) { + return rolesOf(user) & roles == roles; + } + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* MODIFIERS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev Marks a function as only callable by an account with `roles`. + modifier onlyRoles(uint256 roles) virtual { + _checkRoles(roles); + _; + } + + /// @dev Marks a function as only callable by the owner or by an account + /// with `roles`. Checks for ownership first, then lazily checks for roles. + modifier onlyOwnerOrRoles(uint256 roles) virtual { + _checkOwnerOrRoles(roles); + _; + } + + /// @dev Marks a function as only callable by an account with `roles` + /// or the owner. Checks for roles first, then lazily checks for ownership. + modifier onlyRolesOrOwner(uint256 roles) virtual { + _checkRolesOrOwner(roles); + _; + } + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* ROLE CONSTANTS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + // IYKYK + + uint256 internal constant _ROLE_0 = 1 << 0; + uint256 internal constant _ROLE_1 = 1 << 1; + uint256 internal constant _ROLE_2 = 1 << 2; + uint256 internal constant _ROLE_3 = 1 << 3; + uint256 internal constant _ROLE_4 = 1 << 4; + uint256 internal constant _ROLE_5 = 1 << 5; + uint256 internal constant _ROLE_6 = 1 << 6; + uint256 internal constant _ROLE_7 = 1 << 7; + uint256 internal constant _ROLE_8 = 1 << 8; + uint256 internal constant _ROLE_9 = 1 << 9; + uint256 internal constant _ROLE_10 = 1 << 10; + uint256 internal constant _ROLE_11 = 1 << 11; + uint256 internal constant _ROLE_12 = 1 << 12; + uint256 internal constant _ROLE_13 = 1 << 13; + uint256 internal constant _ROLE_14 = 1 << 14; + uint256 internal constant _ROLE_15 = 1 << 15; + uint256 internal constant _ROLE_16 = 1 << 16; + uint256 internal constant _ROLE_17 = 1 << 17; + uint256 internal constant _ROLE_18 = 1 << 18; + uint256 internal constant _ROLE_19 = 1 << 19; + uint256 internal constant _ROLE_20 = 1 << 20; + uint256 internal constant _ROLE_21 = 1 << 21; + uint256 internal constant _ROLE_22 = 1 << 22; + uint256 internal constant _ROLE_23 = 1 << 23; + uint256 internal constant _ROLE_24 = 1 << 24; + uint256 internal constant _ROLE_25 = 1 << 25; + uint256 internal constant _ROLE_26 = 1 << 26; + uint256 internal constant _ROLE_27 = 1 << 27; + uint256 internal constant _ROLE_28 = 1 << 28; + uint256 internal constant _ROLE_29 = 1 << 29; + uint256 internal constant _ROLE_30 = 1 << 30; + uint256 internal constant _ROLE_31 = 1 << 31; + uint256 internal constant _ROLE_32 = 1 << 32; + uint256 internal constant _ROLE_33 = 1 << 33; + uint256 internal constant _ROLE_34 = 1 << 34; + uint256 internal constant _ROLE_35 = 1 << 35; + uint256 internal constant _ROLE_36 = 1 << 36; + uint256 internal constant _ROLE_37 = 1 << 37; + uint256 internal constant _ROLE_38 = 1 << 38; + uint256 internal constant _ROLE_39 = 1 << 39; + uint256 internal constant _ROLE_40 = 1 << 40; + uint256 internal constant _ROLE_41 = 1 << 41; + uint256 internal constant _ROLE_42 = 1 << 42; + uint256 internal constant _ROLE_43 = 1 << 43; + uint256 internal constant _ROLE_44 = 1 << 44; + uint256 internal constant _ROLE_45 = 1 << 45; + uint256 internal constant _ROLE_46 = 1 << 46; + uint256 internal constant _ROLE_47 = 1 << 47; + uint256 internal constant _ROLE_48 = 1 << 48; + uint256 internal constant _ROLE_49 = 1 << 49; + uint256 internal constant _ROLE_50 = 1 << 50; + uint256 internal constant _ROLE_51 = 1 << 51; + uint256 internal constant _ROLE_52 = 1 << 52; + uint256 internal constant _ROLE_53 = 1 << 53; + uint256 internal constant _ROLE_54 = 1 << 54; + uint256 internal constant _ROLE_55 = 1 << 55; + uint256 internal constant _ROLE_56 = 1 << 56; + uint256 internal constant _ROLE_57 = 1 << 57; + uint256 internal constant _ROLE_58 = 1 << 58; + uint256 internal constant _ROLE_59 = 1 << 59; + uint256 internal constant _ROLE_60 = 1 << 60; + uint256 internal constant _ROLE_61 = 1 << 61; + uint256 internal constant _ROLE_62 = 1 << 62; + uint256 internal constant _ROLE_63 = 1 << 63; + uint256 internal constant _ROLE_64 = 1 << 64; + uint256 internal constant _ROLE_65 = 1 << 65; + uint256 internal constant _ROLE_66 = 1 << 66; + uint256 internal constant _ROLE_67 = 1 << 67; + uint256 internal constant _ROLE_68 = 1 << 68; + uint256 internal constant _ROLE_69 = 1 << 69; + uint256 internal constant _ROLE_70 = 1 << 70; + uint256 internal constant _ROLE_71 = 1 << 71; + uint256 internal constant _ROLE_72 = 1 << 72; + uint256 internal constant _ROLE_73 = 1 << 73; + uint256 internal constant _ROLE_74 = 1 << 74; + uint256 internal constant _ROLE_75 = 1 << 75; + uint256 internal constant _ROLE_76 = 1 << 76; + uint256 internal constant _ROLE_77 = 1 << 77; + uint256 internal constant _ROLE_78 = 1 << 78; + uint256 internal constant _ROLE_79 = 1 << 79; + uint256 internal constant _ROLE_80 = 1 << 80; + uint256 internal constant _ROLE_81 = 1 << 81; + uint256 internal constant _ROLE_82 = 1 << 82; + uint256 internal constant _ROLE_83 = 1 << 83; + uint256 internal constant _ROLE_84 = 1 << 84; + uint256 internal constant _ROLE_85 = 1 << 85; + uint256 internal constant _ROLE_86 = 1 << 86; + uint256 internal constant _ROLE_87 = 1 << 87; + uint256 internal constant _ROLE_88 = 1 << 88; + uint256 internal constant _ROLE_89 = 1 << 89; + uint256 internal constant _ROLE_90 = 1 << 90; + uint256 internal constant _ROLE_91 = 1 << 91; + uint256 internal constant _ROLE_92 = 1 << 92; + uint256 internal constant _ROLE_93 = 1 << 93; + uint256 internal constant _ROLE_94 = 1 << 94; + uint256 internal constant _ROLE_95 = 1 << 95; + uint256 internal constant _ROLE_96 = 1 << 96; + uint256 internal constant _ROLE_97 = 1 << 97; + uint256 internal constant _ROLE_98 = 1 << 98; + uint256 internal constant _ROLE_99 = 1 << 99; + uint256 internal constant _ROLE_100 = 1 << 100; + uint256 internal constant _ROLE_101 = 1 << 101; + uint256 internal constant _ROLE_102 = 1 << 102; + uint256 internal constant _ROLE_103 = 1 << 103; + uint256 internal constant _ROLE_104 = 1 << 104; + uint256 internal constant _ROLE_105 = 1 << 105; + uint256 internal constant _ROLE_106 = 1 << 106; + uint256 internal constant _ROLE_107 = 1 << 107; + uint256 internal constant _ROLE_108 = 1 << 108; + uint256 internal constant _ROLE_109 = 1 << 109; + uint256 internal constant _ROLE_110 = 1 << 110; + uint256 internal constant _ROLE_111 = 1 << 111; + uint256 internal constant _ROLE_112 = 1 << 112; + uint256 internal constant _ROLE_113 = 1 << 113; + uint256 internal constant _ROLE_114 = 1 << 114; + uint256 internal constant _ROLE_115 = 1 << 115; + uint256 internal constant _ROLE_116 = 1 << 116; + uint256 internal constant _ROLE_117 = 1 << 117; + uint256 internal constant _ROLE_118 = 1 << 118; + uint256 internal constant _ROLE_119 = 1 << 119; + uint256 internal constant _ROLE_120 = 1 << 120; + uint256 internal constant _ROLE_121 = 1 << 121; + uint256 internal constant _ROLE_122 = 1 << 122; + uint256 internal constant _ROLE_123 = 1 << 123; + uint256 internal constant _ROLE_124 = 1 << 124; + uint256 internal constant _ROLE_125 = 1 << 125; + uint256 internal constant _ROLE_126 = 1 << 126; + uint256 internal constant _ROLE_127 = 1 << 127; + uint256 internal constant _ROLE_128 = 1 << 128; + uint256 internal constant _ROLE_129 = 1 << 129; + uint256 internal constant _ROLE_130 = 1 << 130; + uint256 internal constant _ROLE_131 = 1 << 131; + uint256 internal constant _ROLE_132 = 1 << 132; + uint256 internal constant _ROLE_133 = 1 << 133; + uint256 internal constant _ROLE_134 = 1 << 134; + uint256 internal constant _ROLE_135 = 1 << 135; + uint256 internal constant _ROLE_136 = 1 << 136; + uint256 internal constant _ROLE_137 = 1 << 137; + uint256 internal constant _ROLE_138 = 1 << 138; + uint256 internal constant _ROLE_139 = 1 << 139; + uint256 internal constant _ROLE_140 = 1 << 140; + uint256 internal constant _ROLE_141 = 1 << 141; + uint256 internal constant _ROLE_142 = 1 << 142; + uint256 internal constant _ROLE_143 = 1 << 143; + uint256 internal constant _ROLE_144 = 1 << 144; + uint256 internal constant _ROLE_145 = 1 << 145; + uint256 internal constant _ROLE_146 = 1 << 146; + uint256 internal constant _ROLE_147 = 1 << 147; + uint256 internal constant _ROLE_148 = 1 << 148; + uint256 internal constant _ROLE_149 = 1 << 149; + uint256 internal constant _ROLE_150 = 1 << 150; + uint256 internal constant _ROLE_151 = 1 << 151; + uint256 internal constant _ROLE_152 = 1 << 152; + uint256 internal constant _ROLE_153 = 1 << 153; + uint256 internal constant _ROLE_154 = 1 << 154; + uint256 internal constant _ROLE_155 = 1 << 155; + uint256 internal constant _ROLE_156 = 1 << 156; + uint256 internal constant _ROLE_157 = 1 << 157; + uint256 internal constant _ROLE_158 = 1 << 158; + uint256 internal constant _ROLE_159 = 1 << 159; + uint256 internal constant _ROLE_160 = 1 << 160; + uint256 internal constant _ROLE_161 = 1 << 161; + uint256 internal constant _ROLE_162 = 1 << 162; + uint256 internal constant _ROLE_163 = 1 << 163; + uint256 internal constant _ROLE_164 = 1 << 164; + uint256 internal constant _ROLE_165 = 1 << 165; + uint256 internal constant _ROLE_166 = 1 << 166; + uint256 internal constant _ROLE_167 = 1 << 167; + uint256 internal constant _ROLE_168 = 1 << 168; + uint256 internal constant _ROLE_169 = 1 << 169; + uint256 internal constant _ROLE_170 = 1 << 170; + uint256 internal constant _ROLE_171 = 1 << 171; + uint256 internal constant _ROLE_172 = 1 << 172; + uint256 internal constant _ROLE_173 = 1 << 173; + uint256 internal constant _ROLE_174 = 1 << 174; + uint256 internal constant _ROLE_175 = 1 << 175; + uint256 internal constant _ROLE_176 = 1 << 176; + uint256 internal constant _ROLE_177 = 1 << 177; + uint256 internal constant _ROLE_178 = 1 << 178; + uint256 internal constant _ROLE_179 = 1 << 179; + uint256 internal constant _ROLE_180 = 1 << 180; + uint256 internal constant _ROLE_181 = 1 << 181; + uint256 internal constant _ROLE_182 = 1 << 182; + uint256 internal constant _ROLE_183 = 1 << 183; + uint256 internal constant _ROLE_184 = 1 << 184; + uint256 internal constant _ROLE_185 = 1 << 185; + uint256 internal constant _ROLE_186 = 1 << 186; + uint256 internal constant _ROLE_187 = 1 << 187; + uint256 internal constant _ROLE_188 = 1 << 188; + uint256 internal constant _ROLE_189 = 1 << 189; + uint256 internal constant _ROLE_190 = 1 << 190; + uint256 internal constant _ROLE_191 = 1 << 191; + uint256 internal constant _ROLE_192 = 1 << 192; + uint256 internal constant _ROLE_193 = 1 << 193; + uint256 internal constant _ROLE_194 = 1 << 194; + uint256 internal constant _ROLE_195 = 1 << 195; + uint256 internal constant _ROLE_196 = 1 << 196; + uint256 internal constant _ROLE_197 = 1 << 197; + uint256 internal constant _ROLE_198 = 1 << 198; + uint256 internal constant _ROLE_199 = 1 << 199; + uint256 internal constant _ROLE_200 = 1 << 200; + uint256 internal constant _ROLE_201 = 1 << 201; + uint256 internal constant _ROLE_202 = 1 << 202; + uint256 internal constant _ROLE_203 = 1 << 203; + uint256 internal constant _ROLE_204 = 1 << 204; + uint256 internal constant _ROLE_205 = 1 << 205; + uint256 internal constant _ROLE_206 = 1 << 206; + uint256 internal constant _ROLE_207 = 1 << 207; + uint256 internal constant _ROLE_208 = 1 << 208; + uint256 internal constant _ROLE_209 = 1 << 209; + uint256 internal constant _ROLE_210 = 1 << 210; + uint256 internal constant _ROLE_211 = 1 << 211; + uint256 internal constant _ROLE_212 = 1 << 212; + uint256 internal constant _ROLE_213 = 1 << 213; + uint256 internal constant _ROLE_214 = 1 << 214; + uint256 internal constant _ROLE_215 = 1 << 215; + uint256 internal constant _ROLE_216 = 1 << 216; + uint256 internal constant _ROLE_217 = 1 << 217; + uint256 internal constant _ROLE_218 = 1 << 218; + uint256 internal constant _ROLE_219 = 1 << 219; + uint256 internal constant _ROLE_220 = 1 << 220; + uint256 internal constant _ROLE_221 = 1 << 221; + uint256 internal constant _ROLE_222 = 1 << 222; + uint256 internal constant _ROLE_223 = 1 << 223; + uint256 internal constant _ROLE_224 = 1 << 224; + uint256 internal constant _ROLE_225 = 1 << 225; + uint256 internal constant _ROLE_226 = 1 << 226; + uint256 internal constant _ROLE_227 = 1 << 227; + uint256 internal constant _ROLE_228 = 1 << 228; + uint256 internal constant _ROLE_229 = 1 << 229; + uint256 internal constant _ROLE_230 = 1 << 230; + uint256 internal constant _ROLE_231 = 1 << 231; + uint256 internal constant _ROLE_232 = 1 << 232; + uint256 internal constant _ROLE_233 = 1 << 233; + uint256 internal constant _ROLE_234 = 1 << 234; + uint256 internal constant _ROLE_235 = 1 << 235; + uint256 internal constant _ROLE_236 = 1 << 236; + uint256 internal constant _ROLE_237 = 1 << 237; + uint256 internal constant _ROLE_238 = 1 << 238; + uint256 internal constant _ROLE_239 = 1 << 239; + uint256 internal constant _ROLE_240 = 1 << 240; + uint256 internal constant _ROLE_241 = 1 << 241; + uint256 internal constant _ROLE_242 = 1 << 242; + uint256 internal constant _ROLE_243 = 1 << 243; + uint256 internal constant _ROLE_244 = 1 << 244; + uint256 internal constant _ROLE_245 = 1 << 245; + uint256 internal constant _ROLE_246 = 1 << 246; + uint256 internal constant _ROLE_247 = 1 << 247; + uint256 internal constant _ROLE_248 = 1 << 248; + uint256 internal constant _ROLE_249 = 1 << 249; + uint256 internal constant _ROLE_250 = 1 << 250; + uint256 internal constant _ROLE_251 = 1 << 251; + uint256 internal constant _ROLE_252 = 1 << 252; + uint256 internal constant _ROLE_253 = 1 << 253; + uint256 internal constant _ROLE_254 = 1 << 254; + uint256 internal constant _ROLE_255 = 1 << 255; +} + +// src\common/INonceRegistry.sol + + + + + +/// @title INoncesRegistry +/// @author Mathieu Bour for Pooky Labs Ltd. +/// +/// @notice Minimal NoncesRegistry interface. +interface INonceRegistry is IAccessControl { + /// @notice Get the value of a given nonce. + function has(bytes32 nonce) external view returns (bool); + + /// @notice Set the value of a given nonce. + function set(bytes32 nonce, bool value) external; + + /// @notice Set the value of a multiple nonces. + function setBatch(bytes32[] memory nonces, bool[] memory values) external; +} + +// src\tokens/IPOK.sol + + + + + + +/// @title IPOK +/// @author Mathieu Bour, Dusan Zdravkovic for Pooky Labs Ltd. +/// +/// @notice Minimal $POK ERC20 token interface. +interface IPOK is IAccessControl, IERC20 { + /// @notice Mint an arbitrary amount of $POK to an account. + /// @dev Requirements: + /// - only MINTER role can mint $POK tokens + function mint(address to, uint256 amount) external; + + /// @notice Burn an arbitrary amount of $POK of an sender account. + /// It is acknowledged that burning directly from the user wallet is anti-pattern + /// but since $POK is soulbounded, this allow to skip the ERC20 approve call. + /// @dev Requirements: + /// - only BURNER role can burn $POK tokens + function burn(address to, uint256 amount) external; +} + +// src\pookyball/IPookyball.sol + + + + + + + +/// @title PookyballMetadata +/// @notice The Pookyball rarities are represented on chain by this enum. +enum PookyballRarity { + COMMON, + RARE, + EPIC, + LEGENDARY, + MYTHIC +} + +/// @title PookyballMetadata +/// @notice Pookyballs NFT have the following features: +/// - rarity: integer enum. +/// - level: token level, can be increase by spending token experiences points (PXP). +/// - pxp: token experience points. +/// - seed: a random uint256 word provided by Chainlink VRF service that will be used by Pooky's NFT generator +/// back-end to generate the NFT visuals and in-game statistics\. +struct PookyballMetadata { + PookyballRarity rarity; + uint256 level; + uint256 pxp; + uint256 seed; +} + +/// @title IPookyball +/// @author Mathieu Bour for Pooky Labs Ltd. +/// @notice Minimal Pookyball interface. +interface IPookyball is IAccessControl, IERC2981, IERC721 { + /// Fired when the seed of a Pookyball token is set by the VRFCoordinator + event SeedSet(uint256 indexed tokenId, uint256 seed); + /// Fired when the level of a Pookyball token is changed + event LevelChanged(uint256 indexed tokenId, uint256 level); + /// Fired when the PXP of a Pookyball token is changed + event PXPChanged(uint256 indexed tokenId, uint256 amount); + + /// Thrown when the length of two parameters mismatch. Used in the mint batched function. + error ArgumentSizeMismatch(uint256 x, uint256 y); + + /// @notice PookyballMetadata of the token {tokenId}. + /// @dev Requirements: + /// - Pookyball {tokenId} should exist (minted and not burned). + function metadata(uint256 tokenId) external view returns (PookyballMetadata memory); + + /// @notice Change the secondary sale royalties receiver address. + function setERC2981Receiver(address newReceiver) external; + + /// @notice Mint a new Pookyball token with a given rarity. + function mint(address[] memory recipients, PookyballRarity[] memory rarities) + external + returns (uint256); + + /// @notice Change the level of a Pookyball token. + /// @dev Requirements: + /// - Pookyball {tokenId} should exist (minted and not burned). + function setLevel(uint256 tokenId, uint256 newLevel) external; + + /// @notice Change the PXP of a Pookyball token. + /// @dev Requirements: + /// - Pookyball {tokenId} should exist (minted and not burned). + function setPXP(uint256 tokenId, uint256 newPXP) external; +} + +// src\common/IBaseERC721A.sol + + + + + + + + + +/// @title IBaseERC721 +/// +/// @author Mathieu Bour for Pooky Labs Ltd. +interface IBaseERC721A is IERC165, IERC721A, IERC721ABurnable, IERC721AQueryable, IERC2981 { + /// Fired when the seed of a Pookyball token is set by the VRFCoordinator, + event SeedSet(uint256 indexed tokenId, uint256 seed); + + /// Thrown when the token {tokenId} does not exist. + error NonExistentToken(uint256 tokenId); + + // ----- ERC721A patches ----- + /// @dev This allow to iterate over the token ids. + function nextTokenId() external view returns (uint256); + + function supportsInterface(bytes4 interfaceId) + external + view + override(IERC165, IERC721A) + returns (bool); +} + +// src\stickers/IStickers.sol + + + + + +enum StickerRarity { + COMMON, + RARE, + EPIC, + LEGENDARY, + MYTHIC +} + +struct StickerMint { + address recipient; + StickerRarity rarity; +} + +struct StickerMetadata { + uint248 level; + StickerRarity rarity; +} + +/// @title IStickers +/// @author Mathieu Bour for Pooky Labs Ltd. +interface IStickers is IBaseERC721A { + /// Fired when the level of a Pookyball token is changed, + event LevelChanged(uint256 indexed tokenId, uint256 level); + + /// @notice StickerMetadata of the token {tokenId}. + /// @dev Requirements: + /// - Sticker {tokenId} should exist (minted and not burned). + function metadata(uint256 tokenId) external view returns (StickerMetadata memory); + + /// @notice Change the level of a Sticker token. + /// @dev Requirements: + /// - Sticker {tokenId} should exist (minted and not burned). + function setLevel(uint256 tokenId, uint248 newLevel) external; + + /// @notice Mint multiple Stickers at once. + /// @param recipient The mint recipient. + /// @param rarities The Sticker rarities. + function mint(address recipient, StickerRarity[] memory rarities) external; +} + +// src\common\Rewards.sol + + + + + + + + + + +/// @notice Input rewards data, signed by the Pooky back-end. +struct RewardsData { + /// @notice The amount of native currency. + uint256 amountNAT; + /// @notice The amount of $POK token. + uint256 amountPOK; + /// @notice The rarities of the minted Pookyballs. + PookyballRarity[] pookyballs; + /// @notice The rarities of the minted Stickers. + StickerRarity[] stickers; + /// @notice The nonces that represents the payload. This prevent accounts to claim the same reward twice. + bytes32[] nonces; +} + +/// @title Rewards +/// @author Mathieu Bour, Claudiu Micu for Pooky Labs Ltd. +/// +/// @notice Gameplay contract that allows to claim rewards native, $POK tokens and Pookyball PXP rewards. +/// @dev Only authorized REWARDER-role can sign the rewards payload. +contract Rewards is OwnableRoles { + using ECDSA for bytes32; + + // Roles + uint256 public constant REWARDER = _ROLE_0; + + // Contracts + IPOK public immutable pok; + IPookyball public immutable pookyball; + IStickers public immutable stickers; + + /// To prevent users to use the same signature multiple times, we mark the rewards as claimed. + INonceRegistry public nonces; + + /// Fired when rewards are claimed. + event RewardsClaimed(address indexed account, RewardsData rewards, string data); + + /// Thrown when an account submits an invalid signature. + error InvalidSignature(); + /// Thrown when an account tries to claim rewards twice. + error AlreadyClaimed(bytes32 nonce); + /// Thrown when the reward contract does not own enough native currency. + error InsufficientBalance(uint256 expected, uint256 actual); + /// Thrown when the native transfer has failed. + error TransferFailed(address recipient, uint256 amount); + + constructor( + IPOK _pok, + IPookyball _pookyball, + IStickers _stickers, + INonceRegistry _nonces, + address admin, + address[] memory rewarders + ) { + pok = _pok; + pookyball = _pookyball; + stickers = _stickers; + nonces = _nonces; + + // Set up the roles + _initializeOwner(admin); + uint256 length = rewarders.length; + for (uint256 i; i < length;) { + _grantRoles(rewarders[i], REWARDER); + unchecked { + i++; + } + } + } + + /// @notice Receive funds that will be used for native token reward. + receive() external payable { } + + /// @notice Recover all the funds on the contract. + function withdraw() external onlyOwner { + (bool sent,) = address(msg.sender).call{ value: address(this).balance }(""); + if (!sent) { + revert TransferFailed(msg.sender, address(this).balance); + } + } + + /// @notice Claim rewards using a signature generated from the Pooky game back-end. + /// Rewards include: native currency, $POK tokens, PXP for the Pookyball tokens and Pookyball tokens. + /// @dev Requirements: + /// - signature is valid + /// - tokenIds and tokenPXP have the same size + /// - contract has enough native currency to reward player + function claim(RewardsData memory rewards, bytes memory signature, string memory data) external { + // Generate the signed message from the sender, rewards and nonce + bytes32 hash = keccak256(abi.encode(msg.sender, rewards, data)).toEthSignedMessageHash(); + + // Ensure that all rewards are claimed only once + uint256 length = rewards.nonces.length; + for (uint256 i; i < length; i++) { + if (nonces.has(rewards.nonces[i])) { + revert AlreadyClaimed(rewards.nonces[i]); + } + + nonces.set(rewards.nonces[i], true); + } + + if (!hasAllRoles(hash.recover(signature), REWARDER)) { + revert InvalidSignature(); + } + + // Mint $POK token + if (rewards.amountPOK > 0) { + pok.mint(msg.sender, rewards.amountPOK); + } + + // Mint Pookyballs + if (rewards.pookyballs.length > 0) { + uint256 pookyballCount = rewards.pookyballs.length; + address[] memory addresses = new address[](pookyballCount); + + for (uint256 i; i < pookyballCount;) { + addresses[i] = msg.sender; + unchecked { + i++; + } + } + + pookyball.mint(addresses, rewards.pookyballs); + } + + // Mint Stickers + if (rewards.stickers.length > 0) { + stickers.mint(msg.sender, rewards.stickers); + } + + // Transfer native currency + if (rewards.amountNAT > 0) { + // Ensure that the contract has enough tokens to deliver + if (address(this).balance < rewards.amountNAT) { + revert InsufficientBalance(rewards.amountNAT, address(this).balance); + } + + (bool sent,) = address(msg.sender).call{ value: rewards.amountNAT }(""); + if (!sent) { + revert TransferFailed(msg.sender, rewards.amountNAT); + } + } + + emit RewardsClaimed(msg.sender, rewards, data); + } +} diff --git a/flattened/Stickers.sol b/flattened/Stickers.sol new file mode 100644 index 00000000..537e3d67 --- /dev/null +++ b/flattened/Stickers.sol @@ -0,0 +1,3741 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0 ^0.8.13 ^0.8.21 ^0.8.4; + +// lib/ERC721A/contracts/IERC721A.sol + +// ERC721A Contracts v4.2.3 +// Creator: Chiru Labs + + + +/** + * @dev Interface of ERC721A. + */ +interface IERC721A { + /** + * The caller must own the token or be an approved operator. + */ + error ApprovalCallerNotOwnerNorApproved(); + + /** + * The token does not exist. + */ + error ApprovalQueryForNonexistentToken(); + + /** + * Cannot query the balance for the zero address. + */ + error BalanceQueryForZeroAddress(); + + /** + * Cannot mint to the zero address. + */ + error MintToZeroAddress(); + + /** + * The quantity of tokens minted must be more than zero. + */ + error MintZeroQuantity(); + + /** + * The token does not exist. + */ + error OwnerQueryForNonexistentToken(); + + /** + * The caller must own the token or be an approved operator. + */ + error TransferCallerNotOwnerNorApproved(); + + /** + * The token must be owned by `from`. + */ + error TransferFromIncorrectOwner(); + + /** + * Cannot safely transfer to a contract that does not implement the + * ERC721Receiver interface. + */ + error TransferToNonERC721ReceiverImplementer(); + + /** + * Cannot transfer to the zero address. + */ + error TransferToZeroAddress(); + + /** + * The token does not exist. + */ + error URIQueryForNonexistentToken(); + + /** + * The `quantity` minted with ERC2309 exceeds the safety limit. + */ + error MintERC2309QuantityExceedsLimit(); + + /** + * The `extraData` cannot be set on an unintialized ownership slot. + */ + error OwnershipNotInitializedForExtraData(); + + // ============================================================= + // STRUCTS + // ============================================================= + + struct TokenOwnership { + // The address of the owner. + address addr; + // Stores the start time of ownership with minimal overhead for tokenomics. + uint64 startTimestamp; + // Whether the token has been burned. + bool burned; + // Arbitrary data similar to `startTimestamp` that can be set via {_extraData}. + uint24 extraData; + } + + // ============================================================= + // TOKEN COUNTERS + // ============================================================= + + /** + * @dev Returns the total number of tokens in existence. + * Burned tokens will reduce the count. + * To get the total number of tokens minted, please see {_totalMinted}. + */ + function totalSupply() external view returns (uint256); + + // ============================================================= + // 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 30000 gas. + */ + function supportsInterface(bytes4 interfaceId) external view returns (bool); + + // ============================================================= + // IERC721 + // ============================================================= + + /** + * @dev Emitted when `tokenId` token is transferred from `from` to `to`. + */ + event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); + + /** + * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token. + */ + event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); + + /** + * @dev Emitted when `owner` enables or disables + * (`approved`) `operator` to manage all of its assets. + */ + event ApprovalForAll(address indexed owner, address indexed operator, bool approved); + + /** + * @dev Returns the number of tokens in `owner`'s account. + */ + function balanceOf(address owner) external view returns (uint256 balance); + + /** + * @dev Returns the owner of the `tokenId` token. + * + * Requirements: + * + * - `tokenId` must exist. + */ + function ownerOf(uint256 tokenId) external view returns (address owner); + + /** + * @dev Safely transfers `tokenId` token from `from` to `to`, + * checking first that contract recipients are aware of the ERC721 protocol + * to prevent tokens from being forever locked. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must exist and be owned by `from`. + * - If the caller is not `from`, it must be have been allowed to move + * this token by either {approve} or {setApprovalForAll}. + * - If `to` refers to a smart contract, it must implement + * {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. + * + * Emits a {Transfer} event. + */ + function safeTransferFrom( + address from, + address to, + uint256 tokenId, + bytes calldata data + ) external payable; + + /** + * @dev Equivalent to `safeTransferFrom(from, to, tokenId, '')`. + */ + function safeTransferFrom( + address from, + address to, + uint256 tokenId + ) external payable; + + /** + * @dev Transfers `tokenId` from `from` to `to`. + * + * WARNING: Usage of this method is discouraged, use {safeTransferFrom} + * whenever possible. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must be owned by `from`. + * - If the caller is not `from`, it must be approved to move this token + * by either {approve} or {setApprovalForAll}. + * + * Emits a {Transfer} event. + */ + function transferFrom( + address from, + address to, + uint256 tokenId + ) external payable; + + /** + * @dev Gives permission to `to` to transfer `tokenId` token to another account. + * The approval is cleared when the token is transferred. + * + * Only a single account can be approved at a time, so approving the + * zero address clears previous approvals. + * + * Requirements: + * + * - The caller must own the token or be an approved operator. + * - `tokenId` must exist. + * + * Emits an {Approval} event. + */ + function approve(address to, uint256 tokenId) external payable; + + /** + * @dev Approve or remove `operator` as an operator for the caller. + * Operators can call {transferFrom} or {safeTransferFrom} + * for any token owned by the caller. + * + * Requirements: + * + * - The `operator` cannot be the caller. + * + * Emits an {ApprovalForAll} event. + */ + function setApprovalForAll(address operator, bool _approved) external; + + /** + * @dev Returns the account approved for `tokenId` token. + * + * Requirements: + * + * - `tokenId` must exist. + */ + function getApproved(uint256 tokenId) external view returns (address operator); + + /** + * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`. + * + * See {setApprovalForAll}. + */ + function isApprovedForAll(address owner, address operator) external view returns (bool); + + // ============================================================= + // IERC721Metadata + // ============================================================= + + /** + * @dev Returns the token collection name. + */ + function name() external view returns (string memory); + + /** + * @dev Returns the token collection symbol. + */ + function symbol() external view returns (string memory); + + /** + * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token. + */ + function tokenURI(uint256 tokenId) external view returns (string memory); + + // ============================================================= + // IERC2309 + // ============================================================= + + /** + * @dev Emitted when tokens in `fromTokenId` to `toTokenId` + * (inclusive) is transferred from `from` to `to`, as defined in the + * [ERC2309](https://eips.ethereum.org/EIPS/eip-2309) standard. + * + * See {_mintERC2309} for more details. + */ + event ConsecutiveTransfer(uint256 indexed fromTokenId, uint256 toTokenId, address indexed from, address indexed to); +} + +// lib/chainlink/contracts/src/v0.8\interfaces/VRFCoordinatorV2Interface.sol + + + +interface VRFCoordinatorV2Interface { + /** + * @notice Get configuration relevant for making requests + * @return minimumRequestConfirmations global min for request confirmations + * @return maxGasLimit global max for request gas limit + * @return s_provingKeyHashes list of registered key hashes + */ + function getRequestConfig() external view returns (uint16, uint32, bytes32[] memory); + + /** + * @notice Request a set of random words. + * @param keyHash - Corresponds to a particular oracle job which uses + * that key for generating the VRF proof. Different keyHash's have different gas price + * ceilings, so you can select a specific one to bound your maximum per request cost. + * @param subId - The ID of the VRF subscription. Must be funded + * with the minimum subscription balance required for the selected keyHash. + * @param minimumRequestConfirmations - How many blocks you'd like the + * oracle to wait before responding to the request. See SECURITY CONSIDERATIONS + * for why you may want to request more. The acceptable range is + * [minimumRequestBlockConfirmations, 200]. + * @param callbackGasLimit - How much gas you'd like to receive in your + * fulfillRandomWords callback. Note that gasleft() inside fulfillRandomWords + * may be slightly less than this amount because of gas used calling the function + * (argument decoding etc.), so you may need to request slightly more than you expect + * to have inside fulfillRandomWords. The acceptable range is + * [0, maxGasLimit] + * @param numWords - The number of uint256 random values you'd like to receive + * in your fulfillRandomWords callback. Note these numbers are expanded in a + * secure way by the VRFCoordinator from a single random value supplied by the oracle. + * @return requestId - A unique identifier of the request. Can be used to match + * a request to a response in fulfillRandomWords. + */ + function requestRandomWords( + bytes32 keyHash, + uint64 subId, + uint16 minimumRequestConfirmations, + uint32 callbackGasLimit, + uint32 numWords + ) external returns (uint256 requestId); + + /** + * @notice Create a VRF subscription. + * @return subId - A unique subscription id. + * @dev You can manage the consumer set dynamically with addConsumer/removeConsumer. + * @dev Note to fund the subscription, use transferAndCall. For example + * @dev LINKTOKEN.transferAndCall( + * @dev address(COORDINATOR), + * @dev amount, + * @dev abi.encode(subId)); + */ + function createSubscription() external returns (uint64 subId); + + /** + * @notice Get a VRF subscription. + * @param subId - ID of the subscription + * @return balance - LINK balance of the subscription in juels. + * @return reqCount - number of requests for this subscription, determines fee tier. + * @return owner - owner of the subscription. + * @return consumers - list of consumer address which are able to use this subscription. + */ + function getSubscription( + uint64 subId + ) external view returns (uint96 balance, uint64 reqCount, address owner, address[] memory consumers); + + /** + * @notice Request subscription owner transfer. + * @param subId - ID of the subscription + * @param newOwner - proposed new owner of the subscription + */ + function requestSubscriptionOwnerTransfer(uint64 subId, address newOwner) external; + + /** + * @notice Request subscription owner transfer. + * @param subId - ID of the subscription + * @dev will revert if original owner of subId has + * not requested that msg.sender become the new owner. + */ + function acceptSubscriptionOwnerTransfer(uint64 subId) external; + + /** + * @notice Add a consumer to a VRF subscription. + * @param subId - ID of the subscription + * @param consumer - New consumer which can use the subscription + */ + function addConsumer(uint64 subId, address consumer) external; + + /** + * @notice Remove a consumer from a VRF subscription. + * @param subId - ID of the subscription + * @param consumer - Consumer to remove from the subscription + */ + function removeConsumer(uint64 subId, address consumer) external; + + /** + * @notice Cancel a subscription + * @param subId - ID of the subscription + * @param to - Where to send the remaining LINK to + */ + function cancelSubscription(uint64 subId, address to) external; + + /* + * @notice Check to see if there exists a request commitment consumers + * for all consumers and keyhashes for a given sub. + * @param subId - ID of the subscription + * @return true if there exists at least one unfulfilled request for the subscription, false + * otherwise. + */ + function pendingRequestExists(uint64 subId) external view returns (bool); +} + +// lib/openzeppelin-contracts/contracts/utils/introspection/IERC165.sol + +// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol) + + + +/** + * @dev Interface of the ERC165 standard, as defined in the + * https://eips.ethereum.org/EIPS/eip-165[EIP]. + * + * Implementers can declare support of contract interfaces, which can then be + * queried by others ({ERC165Checker}). + * + * For an implementation, see {ERC165}. + */ +interface IERC165 { + /** + * @dev Returns true if this contract implements the interface defined by + * `interfaceId`. See the corresponding + * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] + * to learn more about how these ids are created. + * + * This function call must use less than 30 000 gas. + */ + function supportsInterface(bytes4 interfaceId) external view returns (bool); +} + +// lib/operator-filter-registry/src/IOperatorFilterRegistry.sol + + + +interface IOperatorFilterRegistry { + /** + * @notice Returns true if operator is not filtered for a given token, either by address or codeHash. Also returns + * true if supplied registrant address is not registered. + */ + function isOperatorAllowed(address registrant, address operator) external view returns (bool); + + /** + * @notice Registers an address with the registry. May be called by address itself or by EIP-173 owner. + */ + function register(address registrant) external; + + /** + * @notice Registers an address with the registry and "subscribes" to another address's filtered operators and codeHashes. + */ + function registerAndSubscribe(address registrant, address subscription) external; + + /** + * @notice Registers an address with the registry and copies the filtered operators and codeHashes from another + * address without subscribing. + */ + function registerAndCopyEntries(address registrant, address registrantToCopy) external; + + /** + * @notice Unregisters an address with the registry and removes its subscription. May be called by address itself or by EIP-173 owner. + * Note that this does not remove any filtered addresses or codeHashes. + * Also note that any subscriptions to this registrant will still be active and follow the existing filtered addresses and codehashes. + */ + function unregister(address addr) external; + + /** + * @notice Update an operator address for a registered address - when filtered is true, the operator is filtered. + */ + function updateOperator(address registrant, address operator, bool filtered) external; + + /** + * @notice Update multiple operators for a registered address - when filtered is true, the operators will be filtered. Reverts on duplicates. + */ + function updateOperators(address registrant, address[] calldata operators, bool filtered) external; + + /** + * @notice Update a codeHash for a registered address - when filtered is true, the codeHash is filtered. + */ + function updateCodeHash(address registrant, bytes32 codehash, bool filtered) external; + + /** + * @notice Update multiple codeHashes for a registered address - when filtered is true, the codeHashes will be filtered. Reverts on duplicates. + */ + function updateCodeHashes(address registrant, bytes32[] calldata codeHashes, bool filtered) external; + + /** + * @notice Subscribe an address to another registrant's filtered operators and codeHashes. Will remove previous + * subscription if present. + * Note that accounts with subscriptions may go on to subscribe to other accounts - in this case, + * subscriptions will not be forwarded. Instead the former subscription's existing entries will still be + * used. + */ + function subscribe(address registrant, address registrantToSubscribe) external; + + /** + * @notice Unsubscribe an address from its current subscribed registrant, and optionally copy its filtered operators and codeHashes. + */ + function unsubscribe(address registrant, bool copyExistingEntries) external; + + /** + * @notice Get the subscription address of a given registrant, if any. + */ + function subscriptionOf(address addr) external returns (address registrant); + + /** + * @notice Get the set of addresses subscribed to a given registrant. + * Note that order is not guaranteed as updates are made. + */ + function subscribers(address registrant) external returns (address[] memory); + + /** + * @notice Get the subscriber at a given index in the set of addresses subscribed to a given registrant. + * Note that order is not guaranteed as updates are made. + */ + function subscriberAt(address registrant, uint256 index) external returns (address); + + /** + * @notice Copy filtered operators and codeHashes from a different registrantToCopy to addr. + */ + function copyEntriesOf(address registrant, address registrantToCopy) external; + + /** + * @notice Returns true if operator is filtered by a given address or its subscription. + */ + function isOperatorFiltered(address registrant, address operator) external returns (bool); + + /** + * @notice Returns true if the hash of an address's code is filtered by a given address or its subscription. + */ + function isCodeHashOfFiltered(address registrant, address operatorWithCode) external returns (bool); + + /** + * @notice Returns true if a codeHash is filtered by a given address or its subscription. + */ + function isCodeHashFiltered(address registrant, bytes32 codeHash) external returns (bool); + + /** + * @notice Returns a list of filtered operators for a given address or its subscription. + */ + function filteredOperators(address addr) external returns (address[] memory); + + /** + * @notice Returns the set of filtered codeHashes for a given address or its subscription. + * Note that order is not guaranteed as updates are made. + */ + function filteredCodeHashes(address addr) external returns (bytes32[] memory); + + /** + * @notice Returns the filtered operator at the given index of the set of filtered operators for a given address or + * its subscription. + * Note that order is not guaranteed as updates are made. + */ + function filteredOperatorAt(address registrant, uint256 index) external returns (address); + + /** + * @notice Returns the filtered codeHash at the given index of the list of filtered codeHashes for a given address or + * its subscription. + * Note that order is not guaranteed as updates are made. + */ + function filteredCodeHashAt(address registrant, uint256 index) external returns (bytes32); + + /** + * @notice Returns true if an address has registered + */ + function isRegistered(address addr) external returns (bool); + + /** + * @dev Convenience method to compute the code hash of an arbitrary contract + */ + function codeHashOf(address addr) external returns (bytes32); +} + +// lib/operator-filter-registry/src/lib/Constants.sol + + + +address constant CANONICAL_OPERATOR_FILTER_REGISTRY_ADDRESS = 0x000000000000AAeB6D7670E522A718067333cd4E; +address constant CANONICAL_CORI_SUBSCRIPTION = 0x3cc6CddA760b79bAfa08dF41ECFA224f810dCeB6; + +// lib/solady/src/auth/Ownable.sol + + + +/// @notice Simple single owner authorization mixin. +/// @author Solady (https://github.com/vectorized/solady/blob/main/src/auth/Ownable.sol) +/// @dev While the ownable portion follows +/// [EIP-173](https://eips.ethereum.org/EIPS/eip-173) for compatibility, +/// the nomenclature for the 2-step ownership handover may be unique to this codebase. +abstract contract Ownable { + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* CUSTOM ERRORS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev The caller is not authorized to call the function. + error Unauthorized(); + + /// @dev The `newOwner` cannot be the zero address. + error NewOwnerIsZeroAddress(); + + /// @dev The `pendingOwner` does not have a valid handover request. + error NoHandoverRequest(); + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* EVENTS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev The ownership is transferred from `oldOwner` to `newOwner`. + /// This event is intentionally kept the same as OpenZeppelin's Ownable to be + /// compatible with indexers and [EIP-173](https://eips.ethereum.org/EIPS/eip-173), + /// despite it not being as lightweight as a single argument event. + event OwnershipTransferred(address indexed oldOwner, address indexed newOwner); + + /// @dev An ownership handover to `pendingOwner` has been requested. + event OwnershipHandoverRequested(address indexed pendingOwner); + + /// @dev The ownership handover to `pendingOwner` has been canceled. + event OwnershipHandoverCanceled(address indexed pendingOwner); + + /// @dev `keccak256(bytes("OwnershipTransferred(address,address)"))`. + uint256 private constant _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE = + 0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0; + + /// @dev `keccak256(bytes("OwnershipHandoverRequested(address)"))`. + uint256 private constant _OWNERSHIP_HANDOVER_REQUESTED_EVENT_SIGNATURE = + 0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d; + + /// @dev `keccak256(bytes("OwnershipHandoverCanceled(address)"))`. + uint256 private constant _OWNERSHIP_HANDOVER_CANCELED_EVENT_SIGNATURE = + 0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92; + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* STORAGE */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev The owner slot is given by: `not(_OWNER_SLOT_NOT)`. + /// It is intentionally chosen to be a high value + /// to avoid collision with lower slots. + /// The choice of manual storage layout is to enable compatibility + /// with both regular and upgradeable contracts. + uint256 private constant _OWNER_SLOT_NOT = 0x8b78c6d8; + + /// The ownership handover slot of `newOwner` is given by: + /// ``` + /// mstore(0x00, or(shl(96, user), _HANDOVER_SLOT_SEED)) + /// let handoverSlot := keccak256(0x00, 0x20) + /// ``` + /// It stores the expiry timestamp of the two-step ownership handover. + uint256 private constant _HANDOVER_SLOT_SEED = 0x389a75e1; + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* INTERNAL FUNCTIONS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev Initializes the owner directly without authorization guard. + /// This function must be called upon initialization, + /// regardless of whether the contract is upgradeable or not. + /// This is to enable generalization to both regular and upgradeable contracts, + /// and to save gas in case the initial owner is not the caller. + /// For performance reasons, this function will not check if there + /// is an existing owner. + function _initializeOwner(address newOwner) internal virtual { + /// @solidity memory-safe-assembly + assembly { + // Clean the upper 96 bits. + newOwner := shr(96, shl(96, newOwner)) + // Store the new value. + sstore(not(_OWNER_SLOT_NOT), newOwner) + // Emit the {OwnershipTransferred} event. + log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, 0, newOwner) + } + } + + /// @dev Sets the owner directly without authorization guard. + function _setOwner(address newOwner) internal virtual { + /// @solidity memory-safe-assembly + assembly { + let ownerSlot := not(_OWNER_SLOT_NOT) + // Clean the upper 96 bits. + newOwner := shr(96, shl(96, newOwner)) + // Emit the {OwnershipTransferred} event. + log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, sload(ownerSlot), newOwner) + // Store the new value. + sstore(ownerSlot, newOwner) + } + } + + /// @dev Throws if the sender is not the owner. + function _checkOwner() internal view virtual { + /// @solidity memory-safe-assembly + assembly { + // If the caller is not the stored owner, revert. + if iszero(eq(caller(), sload(not(_OWNER_SLOT_NOT)))) { + mstore(0x00, 0x82b42900) // `Unauthorized()`. + revert(0x1c, 0x04) + } + } + } + + /// @dev Returns how long a two-step ownership handover is valid for in seconds. + /// Override to return a different value if needed. + /// Made internal to conserve bytecode. Wrap it in a public function if needed. + function _ownershipHandoverValidFor() internal view virtual returns (uint64) { + return 48 * 3600; + } + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* PUBLIC UPDATE FUNCTIONS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev Allows the owner to transfer the ownership to `newOwner`. + function transferOwnership(address newOwner) public payable virtual onlyOwner { + /// @solidity memory-safe-assembly + assembly { + if iszero(shl(96, newOwner)) { + mstore(0x00, 0x7448fbae) // `NewOwnerIsZeroAddress()`. + revert(0x1c, 0x04) + } + } + _setOwner(newOwner); + } + + /// @dev Allows the owner to renounce their ownership. + function renounceOwnership() public payable virtual onlyOwner { + _setOwner(address(0)); + } + + /// @dev Request a two-step ownership handover to the caller. + /// The request will automatically expire in 48 hours (172800 seconds) by default. + function requestOwnershipHandover() public payable virtual { + unchecked { + uint256 expires = block.timestamp + _ownershipHandoverValidFor(); + /// @solidity memory-safe-assembly + assembly { + // Compute and set the handover slot to `expires`. + mstore(0x0c, _HANDOVER_SLOT_SEED) + mstore(0x00, caller()) + sstore(keccak256(0x0c, 0x20), expires) + // Emit the {OwnershipHandoverRequested} event. + log2(0, 0, _OWNERSHIP_HANDOVER_REQUESTED_EVENT_SIGNATURE, caller()) + } + } + } + + /// @dev Cancels the two-step ownership handover to the caller, if any. + function cancelOwnershipHandover() public payable virtual { + /// @solidity memory-safe-assembly + assembly { + // Compute and set the handover slot to 0. + mstore(0x0c, _HANDOVER_SLOT_SEED) + mstore(0x00, caller()) + sstore(keccak256(0x0c, 0x20), 0) + // Emit the {OwnershipHandoverCanceled} event. + log2(0, 0, _OWNERSHIP_HANDOVER_CANCELED_EVENT_SIGNATURE, caller()) + } + } + + /// @dev Allows the owner to complete the two-step ownership handover to `pendingOwner`. + /// Reverts if there is no existing ownership handover requested by `pendingOwner`. + function completeOwnershipHandover(address pendingOwner) public payable virtual onlyOwner { + /// @solidity memory-safe-assembly + assembly { + // Compute and set the handover slot to 0. + mstore(0x0c, _HANDOVER_SLOT_SEED) + mstore(0x00, pendingOwner) + let handoverSlot := keccak256(0x0c, 0x20) + // If the handover does not exist, or has expired. + if gt(timestamp(), sload(handoverSlot)) { + mstore(0x00, 0x6f5e8818) // `NoHandoverRequest()`. + revert(0x1c, 0x04) + } + // Set the handover slot to 0. + sstore(handoverSlot, 0) + } + _setOwner(pendingOwner); + } + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* PUBLIC READ FUNCTIONS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev Returns the owner of the contract. + function owner() public view virtual returns (address result) { + /// @solidity memory-safe-assembly + assembly { + result := sload(not(_OWNER_SLOT_NOT)) + } + } + + /// @dev Returns the expiry timestamp for the two-step ownership handover to `pendingOwner`. + function ownershipHandoverExpiresAt(address pendingOwner) + public + view + virtual + returns (uint256 result) + { + /// @solidity memory-safe-assembly + assembly { + // Compute the handover slot. + mstore(0x0c, _HANDOVER_SLOT_SEED) + mstore(0x00, pendingOwner) + // Load the handover slot. + result := sload(keccak256(0x0c, 0x20)) + } + } + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* MODIFIERS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev Marks a function as only callable by the owner. + modifier onlyOwner() virtual { + _checkOwner(); + _; + } +} + +// src\common/CustomVRFConsumerBaseV2.sol + + + +/** + * + * @notice Interface for contracts using VRF randomness + * ***************************************************************************** + * @dev PURPOSE + * + * @dev Reggie the Random Oracle (not his real job) wants to provide randomness + * @dev to Vera the verifier in such a way that Vera can be sure he's not + * @dev making his output up to suit himself. Reggie provides Vera a public key + * @dev to which he knows the secret key. Each time Vera provides a seed to + * @dev Reggie, he gives back a value which is computed completely + * @dev deterministically from the seed and the secret key. + * + * @dev Reggie provides a proof by which Vera can verify that the output was + * @dev correctly computed once Reggie tells it to her, but without that proof, + * @dev the output is indistinguishable to her from a uniform random sample + * @dev from the output space. + * + * @dev The purpose of this contract is to make it easy for unrelated contracts + * @dev to talk to Vera the verifier about the work Reggie is doing, to provide + * @dev simple access to a verifiable source of randomness. It ensures 2 things: + * @dev 1. The fulfillment came from the VRFCoordinator + * @dev 2. The consumer contract implements fulfillRandomWords. + * ***************************************************************************** + * @dev USAGE + * + * @dev Calling contracts must inherit from VRFConsumerBase, and can + * @dev initialize VRFConsumerBase's attributes in their constructor as + * @dev shown: + * + * @dev contract VRFConsumer { + * @dev constructor(, address _vrfCoordinator, address _link) + * @dev VRFConsumerBase(_vrfCoordinator) public { + * @dev + * @dev } + * @dev } + * + * @dev The oracle will have given you an ID for the VRF keypair they have + * @dev committed to (let's call it keyHash). Create subscription, fund it + * @dev and your consumer contract as a consumer of it (see VRFCoordinatorInterface + * @dev subscription management functions). + * @dev Call requestRandomWords(keyHash, subId, minimumRequestConfirmations, + * @dev callbackGasLimit, numWords), + * @dev see (VRFCoordinatorInterface for a description of the arguments). + * + * @dev Once the VRFCoordinator has received and validated the oracle's response + * @dev to your request, it will call your contract's fulfillRandomWords method. + * + * @dev The randomness argument to fulfillRandomWords is a set of random words + * @dev generated from your requestId and the blockHash of the request. + * + * @dev If your contract could have concurrent requests open, you can use the + * @dev requestId returned from requestRandomWords to track which response is associated + * @dev with which randomness request. + * @dev See "SECURITY CONSIDERATIONS" for principles to keep in mind, + * @dev if your contract could have multiple requests in flight simultaneously. + * + * @dev Colliding `requestId`s are cryptographically impossible as long as seeds + * @dev differ. + * + * ***************************************************************************** + * @dev SECURITY CONSIDERATIONS + * + * @dev A method with the ability to call your fulfillRandomness method directly + * @dev could spoof a VRF response with any random value, so it's critical that + * @dev it cannot be directly called by anything other than this base contract + * @dev (specifically, by the VRFConsumerBase.rawFulfillRandomness method). + * + * @dev For your users to trust that your contract's random behavior is free + * @dev from malicious interference, it's best if you can write it so that all + * @dev behaviors implied by a VRF response are executed *during* your + * @dev fulfillRandomness method. If your contract must store the response (or + * @dev anything derived from it) and use it later, you must ensure that any + * @dev user-significant behavior which depends on that stored value cannot be + * @dev manipulated by a subsequent VRF request. + * + * @dev Similarly, both miners and the VRF oracle itself have some influence + * @dev over the order in which VRF responses appear on the blockchain, so if + * @dev your contract could have multiple VRF requests in flight simultaneously, + * @dev you must ensure that the order in which the VRF responses arrive cannot + * @dev be used to manipulate your contract's user-significant behavior. + * + * @dev Since the block hash of the block which contains the requestRandomness + * @dev call is mixed into the input to the VRF *last*, a sufficiently powerful + * @dev miner could, in principle, fork the blockchain to evict the block + * @dev containing the request, forcing the request to be included in a + * @dev different block with a different hash, and therefore a different input + * @dev to the VRF. However, such an attack would incur a substantial economic + * @dev cost. This cost scales with the number of blocks the VRF oracle waits + * @dev until it calls responds to a request. It is for this reason that + * @dev that you can signal to an oracle you'd like them to wait longer before + * @dev responding to the request (however this is not enforced in the contract + * @dev and so remains effective only in the case of unmodified oracle software). + */ +abstract contract CustomVRFConsumerBaseV2 { + error OnlyCoordinatorCanFulfill(address have, address want); + + address internal vrfCoordinator; + + /** + * @param _vrfCoordinator address of VRFCoordinator contract + */ + constructor(address _vrfCoordinator) { + vrfCoordinator = _vrfCoordinator; + } + + /** + * @notice fulfillRandomness handles the VRF response. Your contract must + * @notice implement it. See "SECURITY CONSIDERATIONS" above for important + * @notice principles to keep in mind when implementing your fulfillRandomness + * @notice method. + * + * @dev CustomVRFConsumerBaseV2 expects its subcontracts to have a method with this + * @dev signature, and will call it once it has verified the proof + * @dev associated with the randomness. (It is triggered via a call to + * @dev rawFulfillRandomness, below.) + * + * @param requestId The Id initially returned by requestRandomness + * @param randomWords the VRF output expanded to the requested number of words + */ + function fulfillRandomWords(uint256 requestId, uint256[] memory randomWords) internal virtual; + + // rawFulfillRandomness is called by VRFCoordinator when it receives a valid VRF + // proof. rawFulfillRandomness then calls fulfillRandomness, after validating + // the origin of the call + function rawFulfillRandomWords(uint256 requestId, uint256[] memory randomWords) external { + if (msg.sender != vrfCoordinator) { + revert OnlyCoordinatorCanFulfill(msg.sender, vrfCoordinator); + } + fulfillRandomWords(requestId, randomWords); + } +} + +// lib/ERC721A/contracts\ERC721A.sol + +// ERC721A Contracts v4.2.3 +// Creator: Chiru Labs + + + + + +/** + * @dev Interface of ERC721 token receiver. + */ +interface ERC721A__IERC721Receiver { + function onERC721Received( + address operator, + address from, + uint256 tokenId, + bytes calldata data + ) external returns (bytes4); +} + +/** + * @title ERC721A + * + * @dev Implementation of the [ERC721](https://eips.ethereum.org/EIPS/eip-721) + * Non-Fungible Token Standard, including the Metadata extension. + * Optimized for lower gas during batch mints. + * + * Token IDs are minted in sequential order (e.g. 0, 1, 2, 3, ...) + * starting from `_startTokenId()`. + * + * Assumptions: + * + * - An owner cannot have more than 2**64 - 1 (max value of uint64) of supply. + * - The maximum token ID cannot exceed 2**256 - 1 (max value of uint256). + */ +contract ERC721A is IERC721A { + // Bypass for a `--via-ir` bug (https://github.com/chiru-labs/ERC721A/pull/364). + struct TokenApprovalRef { + address value; + } + + // ============================================================= + // CONSTANTS + // ============================================================= + + // Mask of an entry in packed address data. + uint256 private constant _BITMASK_ADDRESS_DATA_ENTRY = (1 << 64) - 1; + + // The bit position of `numberMinted` in packed address data. + uint256 private constant _BITPOS_NUMBER_MINTED = 64; + + // The bit position of `numberBurned` in packed address data. + uint256 private constant _BITPOS_NUMBER_BURNED = 128; + + // The bit position of `aux` in packed address data. + uint256 private constant _BITPOS_AUX = 192; + + // Mask of all 256 bits in packed address data except the 64 bits for `aux`. + uint256 private constant _BITMASK_AUX_COMPLEMENT = (1 << 192) - 1; + + // The bit position of `startTimestamp` in packed ownership. + uint256 private constant _BITPOS_START_TIMESTAMP = 160; + + // The bit mask of the `burned` bit in packed ownership. + uint256 private constant _BITMASK_BURNED = 1 << 224; + + // The bit position of the `nextInitialized` bit in packed ownership. + uint256 private constant _BITPOS_NEXT_INITIALIZED = 225; + + // The bit mask of the `nextInitialized` bit in packed ownership. + uint256 private constant _BITMASK_NEXT_INITIALIZED = 1 << 225; + + // The bit position of `extraData` in packed ownership. + uint256 private constant _BITPOS_EXTRA_DATA = 232; + + // Mask of all 256 bits in a packed ownership except the 24 bits for `extraData`. + uint256 private constant _BITMASK_EXTRA_DATA_COMPLEMENT = (1 << 232) - 1; + + // The mask of the lower 160 bits for addresses. + uint256 private constant _BITMASK_ADDRESS = (1 << 160) - 1; + + // The maximum `quantity` that can be minted with {_mintERC2309}. + // This limit is to prevent overflows on the address data entries. + // For a limit of 5000, a total of 3.689e15 calls to {_mintERC2309} + // is required to cause an overflow, which is unrealistic. + uint256 private constant _MAX_MINT_ERC2309_QUANTITY_LIMIT = 5000; + + // The `Transfer` event signature is given by: + // `keccak256(bytes("Transfer(address,address,uint256)"))`. + bytes32 private constant _TRANSFER_EVENT_SIGNATURE = + 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef; + + // ============================================================= + // STORAGE + // ============================================================= + + // The next token ID to be minted. + uint256 private _currentIndex; + + // The number of tokens burned. + uint256 private _burnCounter; + + // Token name + string private _name; + + // Token symbol + string private _symbol; + + // Mapping from token ID to ownership details + // An empty struct value does not necessarily mean the token is unowned. + // See {_packedOwnershipOf} implementation for details. + // + // Bits Layout: + // - [0..159] `addr` + // - [160..223] `startTimestamp` + // - [224] `burned` + // - [225] `nextInitialized` + // - [232..255] `extraData` + mapping(uint256 => uint256) private _packedOwnerships; + + // Mapping owner address to address data. + // + // Bits Layout: + // - [0..63] `balance` + // - [64..127] `numberMinted` + // - [128..191] `numberBurned` + // - [192..255] `aux` + mapping(address => uint256) private _packedAddressData; + + // Mapping from token ID to approved address. + mapping(uint256 => TokenApprovalRef) private _tokenApprovals; + + // Mapping from owner to operator approvals + mapping(address => mapping(address => bool)) private _operatorApprovals; + + // ============================================================= + // CONSTRUCTOR + // ============================================================= + + constructor(string memory name_, string memory symbol_) { + _name = name_; + _symbol = symbol_; + _currentIndex = _startTokenId(); + } + + // ============================================================= + // TOKEN COUNTING OPERATIONS + // ============================================================= + + /** + * @dev Returns the starting token ID. + * To change the starting token ID, please override this function. + */ + function _startTokenId() internal view virtual returns (uint256) { + return 0; + } + + /** + * @dev Returns the next token ID to be minted. + */ + function _nextTokenId() internal view virtual returns (uint256) { + return _currentIndex; + } + + /** + * @dev Returns the total number of tokens in existence. + * Burned tokens will reduce the count. + * To get the total number of tokens minted, please see {_totalMinted}. + */ + function totalSupply() public view virtual override returns (uint256) { + // Counter underflow is impossible as _burnCounter cannot be incremented + // more than `_currentIndex - _startTokenId()` times. + unchecked { + return _currentIndex - _burnCounter - _startTokenId(); + } + } + + /** + * @dev Returns the total amount of tokens minted in the contract. + */ + function _totalMinted() internal view virtual returns (uint256) { + // Counter underflow is impossible as `_currentIndex` does not decrement, + // and it is initialized to `_startTokenId()`. + unchecked { + return _currentIndex - _startTokenId(); + } + } + + /** + * @dev Returns the total number of tokens burned. + */ + function _totalBurned() internal view virtual returns (uint256) { + return _burnCounter; + } + + // ============================================================= + // ADDRESS DATA OPERATIONS + // ============================================================= + + /** + * @dev Returns the number of tokens in `owner`'s account. + */ + function balanceOf(address owner) public view virtual override returns (uint256) { + if (owner == address(0)) _revert(BalanceQueryForZeroAddress.selector); + return _packedAddressData[owner] & _BITMASK_ADDRESS_DATA_ENTRY; + } + + /** + * Returns the number of tokens minted by `owner`. + */ + function _numberMinted(address owner) internal view returns (uint256) { + return (_packedAddressData[owner] >> _BITPOS_NUMBER_MINTED) & _BITMASK_ADDRESS_DATA_ENTRY; + } + + /** + * Returns the number of tokens burned by or on behalf of `owner`. + */ + function _numberBurned(address owner) internal view returns (uint256) { + return (_packedAddressData[owner] >> _BITPOS_NUMBER_BURNED) & _BITMASK_ADDRESS_DATA_ENTRY; + } + + /** + * Returns the auxiliary data for `owner`. (e.g. number of whitelist mint slots used). + */ + function _getAux(address owner) internal view returns (uint64) { + return uint64(_packedAddressData[owner] >> _BITPOS_AUX); + } + + /** + * Sets the auxiliary data for `owner`. (e.g. number of whitelist mint slots used). + * If there are multiple variables, please pack them into a uint64. + */ + function _setAux(address owner, uint64 aux) internal virtual { + uint256 packed = _packedAddressData[owner]; + uint256 auxCasted; + // Cast `aux` with assembly to avoid redundant masking. + assembly { + auxCasted := aux + } + packed = (packed & _BITMASK_AUX_COMPLEMENT) | (auxCasted << _BITPOS_AUX); + _packedAddressData[owner] = packed; + } + + // ============================================================= + // 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 30000 gas. + */ + function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { + // The interface IDs are constants representing the first 4 bytes + // of the XOR of all function selectors in the interface. + // See: [ERC165](https://eips.ethereum.org/EIPS/eip-165) + // (e.g. `bytes4(i.functionA.selector ^ i.functionB.selector ^ ...)`) + return + interfaceId == 0x01ffc9a7 || // ERC165 interface ID for ERC165. + interfaceId == 0x80ac58cd || // ERC165 interface ID for ERC721. + interfaceId == 0x5b5e139f; // ERC165 interface ID for ERC721Metadata. + } + + // ============================================================= + // IERC721Metadata + // ============================================================= + + /** + * @dev Returns the token collection name. + */ + function name() public view virtual override returns (string memory) { + return _name; + } + + /** + * @dev Returns the token collection symbol. + */ + function symbol() public view virtual override returns (string memory) { + return _symbol; + } + + /** + * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token. + */ + function tokenURI(uint256 tokenId) public view virtual override returns (string memory) { + if (!_exists(tokenId)) _revert(URIQueryForNonexistentToken.selector); + + string memory baseURI = _baseURI(); + return bytes(baseURI).length != 0 ? string(abi.encodePacked(baseURI, _toString(tokenId))) : ''; + } + + /** + * @dev Base URI for computing {tokenURI}. If set, the resulting URI for each + * token will be the concatenation of the `baseURI` and the `tokenId`. Empty + * by default, it can be overridden in child contracts. + */ + function _baseURI() internal view virtual returns (string memory) { + return ''; + } + + // ============================================================= + // OWNERSHIPS OPERATIONS + // ============================================================= + + /** + * @dev Returns the owner of the `tokenId` token. + * + * Requirements: + * + * - `tokenId` must exist. + */ + function ownerOf(uint256 tokenId) public view virtual override returns (address) { + return address(uint160(_packedOwnershipOf(tokenId))); + } + + /** + * @dev Gas spent here starts off proportional to the maximum mint batch size. + * It gradually moves to O(1) as tokens get transferred around over time. + */ + function _ownershipOf(uint256 tokenId) internal view virtual returns (TokenOwnership memory) { + return _unpackedOwnership(_packedOwnershipOf(tokenId)); + } + + /** + * @dev Returns the unpacked `TokenOwnership` struct at `index`. + */ + function _ownershipAt(uint256 index) internal view virtual returns (TokenOwnership memory) { + return _unpackedOwnership(_packedOwnerships[index]); + } + + /** + * @dev Returns whether the ownership slot at `index` is initialized. + * An uninitialized slot does not necessarily mean that the slot has no owner. + */ + function _ownershipIsInitialized(uint256 index) internal view virtual returns (bool) { + return _packedOwnerships[index] != 0; + } + + /** + * @dev Initializes the ownership slot minted at `index` for efficiency purposes. + */ + function _initializeOwnershipAt(uint256 index) internal virtual { + if (_packedOwnerships[index] == 0) { + _packedOwnerships[index] = _packedOwnershipOf(index); + } + } + + /** + * Returns the packed ownership data of `tokenId`. + */ + function _packedOwnershipOf(uint256 tokenId) private view returns (uint256 packed) { + if (_startTokenId() <= tokenId) { + packed = _packedOwnerships[tokenId]; + // If the data at the starting slot does not exist, start the scan. + if (packed == 0) { + if (tokenId >= _currentIndex) _revert(OwnerQueryForNonexistentToken.selector); + // Invariant: + // There will always be an initialized ownership slot + // (i.e. `ownership.addr != address(0) && ownership.burned == false`) + // before an unintialized ownership slot + // (i.e. `ownership.addr == address(0) && ownership.burned == false`) + // Hence, `tokenId` will not underflow. + // + // We can directly compare the packed value. + // If the address is zero, packed will be zero. + for (;;) { + unchecked { + packed = _packedOwnerships[--tokenId]; + } + if (packed == 0) continue; + if (packed & _BITMASK_BURNED == 0) return packed; + // Otherwise, the token is burned, and we must revert. + // This handles the case of batch burned tokens, where only the burned bit + // of the starting slot is set, and remaining slots are left uninitialized. + _revert(OwnerQueryForNonexistentToken.selector); + } + } + // Otherwise, the data exists and we can skip the scan. + // This is possible because we have already achieved the target condition. + // This saves 2143 gas on transfers of initialized tokens. + // If the token is not burned, return `packed`. Otherwise, revert. + if (packed & _BITMASK_BURNED == 0) return packed; + } + _revert(OwnerQueryForNonexistentToken.selector); + } + + /** + * @dev Returns the unpacked `TokenOwnership` struct from `packed`. + */ + function _unpackedOwnership(uint256 packed) private pure returns (TokenOwnership memory ownership) { + ownership.addr = address(uint160(packed)); + ownership.startTimestamp = uint64(packed >> _BITPOS_START_TIMESTAMP); + ownership.burned = packed & _BITMASK_BURNED != 0; + ownership.extraData = uint24(packed >> _BITPOS_EXTRA_DATA); + } + + /** + * @dev Packs ownership data into a single uint256. + */ + function _packOwnershipData(address owner, uint256 flags) private view returns (uint256 result) { + assembly { + // Mask `owner` to the lower 160 bits, in case the upper bits somehow aren't clean. + owner := and(owner, _BITMASK_ADDRESS) + // `owner | (block.timestamp << _BITPOS_START_TIMESTAMP) | flags`. + result := or(owner, or(shl(_BITPOS_START_TIMESTAMP, timestamp()), flags)) + } + } + + /** + * @dev Returns the `nextInitialized` flag set if `quantity` equals 1. + */ + function _nextInitializedFlag(uint256 quantity) private pure returns (uint256 result) { + // For branchless setting of the `nextInitialized` flag. + assembly { + // `(quantity == 1) << _BITPOS_NEXT_INITIALIZED`. + result := shl(_BITPOS_NEXT_INITIALIZED, eq(quantity, 1)) + } + } + + // ============================================================= + // APPROVAL OPERATIONS + // ============================================================= + + /** + * @dev Gives permission to `to` to transfer `tokenId` token to another account. See {ERC721A-_approve}. + * + * Requirements: + * + * - The caller must own the token or be an approved operator. + */ + function approve(address to, uint256 tokenId) public payable virtual override { + _approve(to, tokenId, true); + } + + /** + * @dev Returns the account approved for `tokenId` token. + * + * Requirements: + * + * - `tokenId` must exist. + */ + function getApproved(uint256 tokenId) public view virtual override returns (address) { + if (!_exists(tokenId)) _revert(ApprovalQueryForNonexistentToken.selector); + + return _tokenApprovals[tokenId].value; + } + + /** + * @dev Approve or remove `operator` as an operator for the caller. + * Operators can call {transferFrom} or {safeTransferFrom} + * for any token owned by the caller. + * + * Requirements: + * + * - The `operator` cannot be the caller. + * + * Emits an {ApprovalForAll} event. + */ + function setApprovalForAll(address operator, bool approved) public virtual override { + _operatorApprovals[_msgSenderERC721A()][operator] = approved; + emit ApprovalForAll(_msgSenderERC721A(), operator, approved); + } + + /** + * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`. + * + * See {setApprovalForAll}. + */ + function isApprovedForAll(address owner, address operator) public view virtual override returns (bool) { + return _operatorApprovals[owner][operator]; + } + + /** + * @dev Returns whether `tokenId` exists. + * + * Tokens can be managed by their owner or approved accounts via {approve} or {setApprovalForAll}. + * + * Tokens start existing when they are minted. See {_mint}. + */ + function _exists(uint256 tokenId) internal view virtual returns (bool result) { + if (_startTokenId() <= tokenId) { + if (tokenId < _currentIndex) { + uint256 packed; + while ((packed = _packedOwnerships[tokenId]) == 0) --tokenId; + result = packed & _BITMASK_BURNED == 0; + } + } + } + + /** + * @dev Returns whether `msgSender` is equal to `approvedAddress` or `owner`. + */ + function _isSenderApprovedOrOwner( + address approvedAddress, + address owner, + address msgSender + ) private pure returns (bool result) { + assembly { + // Mask `owner` to the lower 160 bits, in case the upper bits somehow aren't clean. + owner := and(owner, _BITMASK_ADDRESS) + // Mask `msgSender` to the lower 160 bits, in case the upper bits somehow aren't clean. + msgSender := and(msgSender, _BITMASK_ADDRESS) + // `msgSender == owner || msgSender == approvedAddress`. + result := or(eq(msgSender, owner), eq(msgSender, approvedAddress)) + } + } + + /** + * @dev Returns the storage slot and value for the approved address of `tokenId`. + */ + function _getApprovedSlotAndAddress(uint256 tokenId) + private + view + returns (uint256 approvedAddressSlot, address approvedAddress) + { + TokenApprovalRef storage tokenApproval = _tokenApprovals[tokenId]; + // The following is equivalent to `approvedAddress = _tokenApprovals[tokenId].value`. + assembly { + approvedAddressSlot := tokenApproval.slot + approvedAddress := sload(approvedAddressSlot) + } + } + + // ============================================================= + // TRANSFER OPERATIONS + // ============================================================= + + /** + * @dev Transfers `tokenId` from `from` to `to`. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must be owned by `from`. + * - If the caller is not `from`, it must be approved to move this token + * by either {approve} or {setApprovalForAll}. + * + * Emits a {Transfer} event. + */ + function transferFrom( + address from, + address to, + uint256 tokenId + ) public payable virtual override { + uint256 prevOwnershipPacked = _packedOwnershipOf(tokenId); + + // Mask `from` to the lower 160 bits, in case the upper bits somehow aren't clean. + from = address(uint160(uint256(uint160(from)) & _BITMASK_ADDRESS)); + + if (address(uint160(prevOwnershipPacked)) != from) _revert(TransferFromIncorrectOwner.selector); + + (uint256 approvedAddressSlot, address approvedAddress) = _getApprovedSlotAndAddress(tokenId); + + // The nested ifs save around 20+ gas over a compound boolean condition. + if (!_isSenderApprovedOrOwner(approvedAddress, from, _msgSenderERC721A())) + if (!isApprovedForAll(from, _msgSenderERC721A())) _revert(TransferCallerNotOwnerNorApproved.selector); + + _beforeTokenTransfers(from, to, tokenId, 1); + + // Clear approvals from the previous owner. + assembly { + if approvedAddress { + // This is equivalent to `delete _tokenApprovals[tokenId]`. + sstore(approvedAddressSlot, 0) + } + } + + // Underflow of the sender's balance is impossible because we check for + // ownership above and the recipient's balance can't realistically overflow. + // Counter overflow is incredibly unrealistic as `tokenId` would have to be 2**256. + unchecked { + // We can directly increment and decrement the balances. + --_packedAddressData[from]; // Updates: `balance -= 1`. + ++_packedAddressData[to]; // Updates: `balance += 1`. + + // Updates: + // - `address` to the next owner. + // - `startTimestamp` to the timestamp of transfering. + // - `burned` to `false`. + // - `nextInitialized` to `true`. + _packedOwnerships[tokenId] = _packOwnershipData( + to, + _BITMASK_NEXT_INITIALIZED | _nextExtraData(from, to, prevOwnershipPacked) + ); + + // If the next slot may not have been initialized (i.e. `nextInitialized == false`) . + if (prevOwnershipPacked & _BITMASK_NEXT_INITIALIZED == 0) { + uint256 nextTokenId = tokenId + 1; + // If the next slot's address is zero and not burned (i.e. packed value is zero). + if (_packedOwnerships[nextTokenId] == 0) { + // If the next slot is within bounds. + if (nextTokenId != _currentIndex) { + // Initialize the next slot to maintain correctness for `ownerOf(tokenId + 1)`. + _packedOwnerships[nextTokenId] = prevOwnershipPacked; + } + } + } + } + + // Mask `to` to the lower 160 bits, in case the upper bits somehow aren't clean. + uint256 toMasked = uint256(uint160(to)) & _BITMASK_ADDRESS; + assembly { + // Emit the `Transfer` event. + log4( + 0, // Start of data (0, since no data). + 0, // End of data (0, since no data). + _TRANSFER_EVENT_SIGNATURE, // Signature. + from, // `from`. + toMasked, // `to`. + tokenId // `tokenId`. + ) + } + if (toMasked == 0) _revert(TransferToZeroAddress.selector); + + _afterTokenTransfers(from, to, tokenId, 1); + } + + /** + * @dev Equivalent to `safeTransferFrom(from, to, tokenId, '')`. + */ + function safeTransferFrom( + address from, + address to, + uint256 tokenId + ) public payable virtual override { + safeTransferFrom(from, to, tokenId, ''); + } + + /** + * @dev Safely transfers `tokenId` token from `from` to `to`. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must exist and be owned by `from`. + * - If the caller is not `from`, it must be approved to move this token + * by either {approve} or {setApprovalForAll}. + * - If `to` refers to a smart contract, it must implement + * {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. + * + * Emits a {Transfer} event. + */ + function safeTransferFrom( + address from, + address to, + uint256 tokenId, + bytes memory _data + ) public payable virtual override { + transferFrom(from, to, tokenId); + if (to.code.length != 0) + if (!_checkContractOnERC721Received(from, to, tokenId, _data)) { + _revert(TransferToNonERC721ReceiverImplementer.selector); + } + } + + /** + * @dev Hook that is called before a set of serially-ordered token IDs + * are about to be transferred. This includes minting. + * And also called before burning one token. + * + * `startTokenId` - the first token ID to be transferred. + * `quantity` - the amount to be transferred. + * + * Calling conditions: + * + * - When `from` and `to` are both non-zero, `from`'s `tokenId` will be + * transferred to `to`. + * - When `from` is zero, `tokenId` will be minted for `to`. + * - When `to` is zero, `tokenId` will be burned by `from`. + * - `from` and `to` are never both zero. + */ + function _beforeTokenTransfers( + address from, + address to, + uint256 startTokenId, + uint256 quantity + ) internal virtual {} + + /** + * @dev Hook that is called after a set of serially-ordered token IDs + * have been transferred. This includes minting. + * And also called after one token has been burned. + * + * `startTokenId` - the first token ID to be transferred. + * `quantity` - the amount to be transferred. + * + * Calling conditions: + * + * - When `from` and `to` are both non-zero, `from`'s `tokenId` has been + * transferred to `to`. + * - When `from` is zero, `tokenId` has been minted for `to`. + * - When `to` is zero, `tokenId` has been burned by `from`. + * - `from` and `to` are never both zero. + */ + function _afterTokenTransfers( + address from, + address to, + uint256 startTokenId, + uint256 quantity + ) internal virtual {} + + /** + * @dev Private function to invoke {IERC721Receiver-onERC721Received} on a target contract. + * + * `from` - Previous owner of the given token ID. + * `to` - Target address that will receive the token. + * `tokenId` - Token ID to be transferred. + * `_data` - Optional data to send along with the call. + * + * Returns whether the call correctly returned the expected magic value. + */ + function _checkContractOnERC721Received( + address from, + address to, + uint256 tokenId, + bytes memory _data + ) private returns (bool) { + try ERC721A__IERC721Receiver(to).onERC721Received(_msgSenderERC721A(), from, tokenId, _data) returns ( + bytes4 retval + ) { + return retval == ERC721A__IERC721Receiver(to).onERC721Received.selector; + } catch (bytes memory reason) { + if (reason.length == 0) { + _revert(TransferToNonERC721ReceiverImplementer.selector); + } + assembly { + revert(add(32, reason), mload(reason)) + } + } + } + + // ============================================================= + // MINT OPERATIONS + // ============================================================= + + /** + * @dev Mints `quantity` tokens and transfers them to `to`. + * + * Requirements: + * + * - `to` cannot be the zero address. + * - `quantity` must be greater than 0. + * + * Emits a {Transfer} event for each mint. + */ + function _mint(address to, uint256 quantity) internal virtual { + uint256 startTokenId = _currentIndex; + if (quantity == 0) _revert(MintZeroQuantity.selector); + + _beforeTokenTransfers(address(0), to, startTokenId, quantity); + + // Overflows are incredibly unrealistic. + // `balance` and `numberMinted` have a maximum limit of 2**64. + // `tokenId` has a maximum limit of 2**256. + unchecked { + // Updates: + // - `address` to the owner. + // - `startTimestamp` to the timestamp of minting. + // - `burned` to `false`. + // - `nextInitialized` to `quantity == 1`. + _packedOwnerships[startTokenId] = _packOwnershipData( + to, + _nextInitializedFlag(quantity) | _nextExtraData(address(0), to, 0) + ); + + // Updates: + // - `balance += quantity`. + // - `numberMinted += quantity`. + // + // We can directly add to the `balance` and `numberMinted`. + _packedAddressData[to] += quantity * ((1 << _BITPOS_NUMBER_MINTED) | 1); + + // Mask `to` to the lower 160 bits, in case the upper bits somehow aren't clean. + uint256 toMasked = uint256(uint160(to)) & _BITMASK_ADDRESS; + + if (toMasked == 0) _revert(MintToZeroAddress.selector); + + uint256 end = startTokenId + quantity; + uint256 tokenId = startTokenId; + + do { + assembly { + // Emit the `Transfer` event. + log4( + 0, // Start of data (0, since no data). + 0, // End of data (0, since no data). + _TRANSFER_EVENT_SIGNATURE, // Signature. + 0, // `address(0)`. + toMasked, // `to`. + tokenId // `tokenId`. + ) + } + // The `!=` check ensures that large values of `quantity` + // that overflows uint256 will make the loop run out of gas. + } while (++tokenId != end); + + _currentIndex = end; + } + _afterTokenTransfers(address(0), to, startTokenId, quantity); + } + + /** + * @dev Mints `quantity` tokens and transfers them to `to`. + * + * This function is intended for efficient minting only during contract creation. + * + * It emits only one {ConsecutiveTransfer} as defined in + * [ERC2309](https://eips.ethereum.org/EIPS/eip-2309), + * instead of a sequence of {Transfer} event(s). + * + * Calling this function outside of contract creation WILL make your contract + * non-compliant with the ERC721 standard. + * For full ERC721 compliance, substituting ERC721 {Transfer} event(s) with the ERC2309 + * {ConsecutiveTransfer} event is only permissible during contract creation. + * + * Requirements: + * + * - `to` cannot be the zero address. + * - `quantity` must be greater than 0. + * + * Emits a {ConsecutiveTransfer} event. + */ + function _mintERC2309(address to, uint256 quantity) internal virtual { + uint256 startTokenId = _currentIndex; + if (to == address(0)) _revert(MintToZeroAddress.selector); + if (quantity == 0) _revert(MintZeroQuantity.selector); + if (quantity > _MAX_MINT_ERC2309_QUANTITY_LIMIT) _revert(MintERC2309QuantityExceedsLimit.selector); + + _beforeTokenTransfers(address(0), to, startTokenId, quantity); + + // Overflows are unrealistic due to the above check for `quantity` to be below the limit. + unchecked { + // Updates: + // - `balance += quantity`. + // - `numberMinted += quantity`. + // + // We can directly add to the `balance` and `numberMinted`. + _packedAddressData[to] += quantity * ((1 << _BITPOS_NUMBER_MINTED) | 1); + + // Updates: + // - `address` to the owner. + // - `startTimestamp` to the timestamp of minting. + // - `burned` to `false`. + // - `nextInitialized` to `quantity == 1`. + _packedOwnerships[startTokenId] = _packOwnershipData( + to, + _nextInitializedFlag(quantity) | _nextExtraData(address(0), to, 0) + ); + + emit ConsecutiveTransfer(startTokenId, startTokenId + quantity - 1, address(0), to); + + _currentIndex = startTokenId + quantity; + } + _afterTokenTransfers(address(0), to, startTokenId, quantity); + } + + /** + * @dev Safely mints `quantity` tokens and transfers them to `to`. + * + * Requirements: + * + * - If `to` refers to a smart contract, it must implement + * {IERC721Receiver-onERC721Received}, which is called for each safe transfer. + * - `quantity` must be greater than 0. + * + * See {_mint}. + * + * Emits a {Transfer} event for each mint. + */ + function _safeMint( + address to, + uint256 quantity, + bytes memory _data + ) internal virtual { + _mint(to, quantity); + + unchecked { + if (to.code.length != 0) { + uint256 end = _currentIndex; + uint256 index = end - quantity; + do { + if (!_checkContractOnERC721Received(address(0), to, index++, _data)) { + _revert(TransferToNonERC721ReceiverImplementer.selector); + } + } while (index < end); + // Reentrancy protection. + if (_currentIndex != end) _revert(bytes4(0)); + } + } + } + + /** + * @dev Equivalent to `_safeMint(to, quantity, '')`. + */ + function _safeMint(address to, uint256 quantity) internal virtual { + _safeMint(to, quantity, ''); + } + + // ============================================================= + // APPROVAL OPERATIONS + // ============================================================= + + /** + * @dev Equivalent to `_approve(to, tokenId, false)`. + */ + function _approve(address to, uint256 tokenId) internal virtual { + _approve(to, tokenId, false); + } + + /** + * @dev Gives permission to `to` to transfer `tokenId` token to another account. + * The approval is cleared when the token is transferred. + * + * Only a single account can be approved at a time, so approving the + * zero address clears previous approvals. + * + * Requirements: + * + * - `tokenId` must exist. + * + * Emits an {Approval} event. + */ + function _approve( + address to, + uint256 tokenId, + bool approvalCheck + ) internal virtual { + address owner = ownerOf(tokenId); + + if (approvalCheck && _msgSenderERC721A() != owner) + if (!isApprovedForAll(owner, _msgSenderERC721A())) { + _revert(ApprovalCallerNotOwnerNorApproved.selector); + } + + _tokenApprovals[tokenId].value = to; + emit Approval(owner, to, tokenId); + } + + // ============================================================= + // BURN OPERATIONS + // ============================================================= + + /** + * @dev Equivalent to `_burn(tokenId, false)`. + */ + function _burn(uint256 tokenId) internal virtual { + _burn(tokenId, false); + } + + /** + * @dev Destroys `tokenId`. + * The approval is cleared when the token is burned. + * + * Requirements: + * + * - `tokenId` must exist. + * + * Emits a {Transfer} event. + */ + function _burn(uint256 tokenId, bool approvalCheck) internal virtual { + uint256 prevOwnershipPacked = _packedOwnershipOf(tokenId); + + address from = address(uint160(prevOwnershipPacked)); + + (uint256 approvedAddressSlot, address approvedAddress) = _getApprovedSlotAndAddress(tokenId); + + if (approvalCheck) { + // The nested ifs save around 20+ gas over a compound boolean condition. + if (!_isSenderApprovedOrOwner(approvedAddress, from, _msgSenderERC721A())) + if (!isApprovedForAll(from, _msgSenderERC721A())) _revert(TransferCallerNotOwnerNorApproved.selector); + } + + _beforeTokenTransfers(from, address(0), tokenId, 1); + + // Clear approvals from the previous owner. + assembly { + if approvedAddress { + // This is equivalent to `delete _tokenApprovals[tokenId]`. + sstore(approvedAddressSlot, 0) + } + } + + // Underflow of the sender's balance is impossible because we check for + // ownership above and the recipient's balance can't realistically overflow. + // Counter overflow is incredibly unrealistic as `tokenId` would have to be 2**256. + unchecked { + // Updates: + // - `balance -= 1`. + // - `numberBurned += 1`. + // + // We can directly decrement the balance, and increment the number burned. + // This is equivalent to `packed -= 1; packed += 1 << _BITPOS_NUMBER_BURNED;`. + _packedAddressData[from] += (1 << _BITPOS_NUMBER_BURNED) - 1; + + // Updates: + // - `address` to the last owner. + // - `startTimestamp` to the timestamp of burning. + // - `burned` to `true`. + // - `nextInitialized` to `true`. + _packedOwnerships[tokenId] = _packOwnershipData( + from, + (_BITMASK_BURNED | _BITMASK_NEXT_INITIALIZED) | _nextExtraData(from, address(0), prevOwnershipPacked) + ); + + // If the next slot may not have been initialized (i.e. `nextInitialized == false`) . + if (prevOwnershipPacked & _BITMASK_NEXT_INITIALIZED == 0) { + uint256 nextTokenId = tokenId + 1; + // If the next slot's address is zero and not burned (i.e. packed value is zero). + if (_packedOwnerships[nextTokenId] == 0) { + // If the next slot is within bounds. + if (nextTokenId != _currentIndex) { + // Initialize the next slot to maintain correctness for `ownerOf(tokenId + 1)`. + _packedOwnerships[nextTokenId] = prevOwnershipPacked; + } + } + } + } + + emit Transfer(from, address(0), tokenId); + _afterTokenTransfers(from, address(0), tokenId, 1); + + // Overflow not possible, as _burnCounter cannot be exceed _currentIndex times. + unchecked { + _burnCounter++; + } + } + + // ============================================================= + // EXTRA DATA OPERATIONS + // ============================================================= + + /** + * @dev Directly sets the extra data for the ownership data `index`. + */ + function _setExtraDataAt(uint256 index, uint24 extraData) internal virtual { + uint256 packed = _packedOwnerships[index]; + if (packed == 0) _revert(OwnershipNotInitializedForExtraData.selector); + uint256 extraDataCasted; + // Cast `extraData` with assembly to avoid redundant masking. + assembly { + extraDataCasted := extraData + } + packed = (packed & _BITMASK_EXTRA_DATA_COMPLEMENT) | (extraDataCasted << _BITPOS_EXTRA_DATA); + _packedOwnerships[index] = packed; + } + + /** + * @dev Called during each token transfer to set the 24bit `extraData` field. + * Intended to be overridden by the cosumer contract. + * + * `previousExtraData` - the value of `extraData` before transfer. + * + * Calling conditions: + * + * - When `from` and `to` are both non-zero, `from`'s `tokenId` will be + * transferred to `to`. + * - When `from` is zero, `tokenId` will be minted for `to`. + * - When `to` is zero, `tokenId` will be burned by `from`. + * - `from` and `to` are never both zero. + */ + function _extraData( + address from, + address to, + uint24 previousExtraData + ) internal view virtual returns (uint24) {} + + /** + * @dev Returns the next extra data for the packed ownership data. + * The returned result is shifted into position. + */ + function _nextExtraData( + address from, + address to, + uint256 prevOwnershipPacked + ) private view returns (uint256) { + uint24 extraData = uint24(prevOwnershipPacked >> _BITPOS_EXTRA_DATA); + return uint256(_extraData(from, to, extraData)) << _BITPOS_EXTRA_DATA; + } + + // ============================================================= + // OTHER OPERATIONS + // ============================================================= + + /** + * @dev Returns the message sender (defaults to `msg.sender`). + * + * If you are writing GSN compatible contracts, you need to override this function. + */ + function _msgSenderERC721A() internal view virtual returns (address) { + return msg.sender; + } + + /** + * @dev Converts a uint256 to its ASCII string decimal representation. + */ + function _toString(uint256 value) internal pure virtual returns (string memory str) { + assembly { + // The maximum value of a uint256 contains 78 digits (1 byte per digit), but + // we allocate 0xa0 bytes to keep the free memory pointer 32-byte word aligned. + // We will need 1 word for the trailing zeros padding, 1 word for the length, + // and 3 words for a maximum of 78 digits. Total: 5 * 0x20 = 0xa0. + let m := add(mload(0x40), 0xa0) + // Update the free memory pointer to allocate. + mstore(0x40, m) + // Assign the `str` to the end. + str := sub(m, 0x20) + // Zeroize the slot after the string. + mstore(str, 0) + + // Cache the end of the memory to calculate the length later. + let end := str + + // We write the string from rightmost digit to leftmost digit. + // The following is essentially a do-while loop that also handles the zero case. + // prettier-ignore + for { let temp := value } 1 {} { + str := sub(str, 1) + // Write the character to the pointer. + // The ASCII index of the '0' character is 48. + mstore8(str, add(48, mod(temp, 10))) + // Keep dividing `temp` until zero. + temp := div(temp, 10) + // prettier-ignore + if iszero(temp) { break } + } + + let length := sub(end, str) + // Move the pointer 32 bytes leftwards to make room for the length. + str := sub(str, 0x20) + // Store the length. + mstore(str, length) + } + } + + /** + * @dev For more efficient reverts. + */ + function _revert(bytes4 errorSelector) internal pure { + assembly { + mstore(0x00, errorSelector) + revert(0x00, 0x04) + } + } +} + +// lib/ERC721A/contracts/extensions/IERC721ABurnable.sol + +// ERC721A Contracts v4.2.3 +// Creator: Chiru Labs + + + + + +/** + * @dev Interface of ERC721ABurnable. + */ +interface IERC721ABurnable is IERC721A { + /** + * @dev Burns `tokenId`. See {ERC721A-_burn}. + * + * Requirements: + * + * - The caller must own `tokenId` or be an approved operator. + */ + function burn(uint256 tokenId) external; +} + +// lib/ERC721A/contracts/extensions/IERC721AQueryable.sol + +// ERC721A Contracts v4.2.3 +// Creator: Chiru Labs + + + + + +/** + * @dev Interface of ERC721AQueryable. + */ +interface IERC721AQueryable is IERC721A { + /** + * Invalid query range (`start` >= `stop`). + */ + error InvalidQueryRange(); + + /** + * @dev Returns the `TokenOwnership` struct at `tokenId` without reverting. + * + * If the `tokenId` is out of bounds: + * + * - `addr = address(0)` + * - `startTimestamp = 0` + * - `burned = false` + * - `extraData = 0` + * + * If the `tokenId` is burned: + * + * - `addr =
` + * - `startTimestamp = ` + * - `burned = true` + * - `extraData = ` + * + * Otherwise: + * + * - `addr =
` + * - `startTimestamp = ` + * - `burned = false` + * - `extraData = ` + */ + function explicitOwnershipOf(uint256 tokenId) external view returns (TokenOwnership memory); + + /** + * @dev Returns an array of `TokenOwnership` structs at `tokenIds` in order. + * See {ERC721AQueryable-explicitOwnershipOf} + */ + function explicitOwnershipsOf(uint256[] memory tokenIds) external view returns (TokenOwnership[] memory); + + /** + * @dev Returns an array of token IDs owned by `owner`, + * in the range [`start`, `stop`) + * (i.e. `start <= tokenId < stop`). + * + * This function allows for tokens to be queried if the collection + * grows too big for a single call of {ERC721AQueryable-tokensOfOwner}. + * + * Requirements: + * + * - `start < stop` + */ + function tokensOfOwnerIn( + address owner, + uint256 start, + uint256 stop + ) external view returns (uint256[] memory); + + /** + * @dev Returns an array of token IDs owned by `owner`. + * + * This function scans the ownership mapping and is O(`totalSupply`) in complexity. + * It is meant to be called off-chain. + * + * See {ERC721AQueryable-tokensOfOwnerIn} for splitting the scan into + * multiple smaller scans if the collection is large enough to cause + * an out-of-gas error (10K collections should be fine). + */ + function tokensOfOwner(address owner) external view returns (uint256[] memory); +} + +// lib/openzeppelin-contracts/contracts\interfaces/IERC165.sol + +// OpenZeppelin Contracts v4.4.1 (interfaces/IERC165.sol) + + + + + +// lib/openzeppelin-contracts/contracts/interfaces/IERC2981.sol + +// OpenZeppelin Contracts (last updated v4.9.0) (interfaces/IERC2981.sol) + + + + + +/** + * @dev Interface for the NFT Royalty Standard. + * + * A standardized way to retrieve royalty payment information for non-fungible tokens (NFTs) to enable universal + * support for royalty payments across all NFT marketplaces and ecosystem participants. + * + * _Available since v4.5._ + */ +interface IERC2981 is IERC165 { + /** + * @dev Returns how much royalty is owed and to whom, based on a sale price that may be denominated in any unit of + * exchange. The royalty amount is denominated and should be paid in that same unit of exchange. + */ + function royaltyInfo( + uint256 tokenId, + uint256 salePrice + ) external view returns (address receiver, uint256 royaltyAmount); +} + +// lib/openzeppelin-contracts/contracts/utils/introspection/ERC165.sol + +// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol) + + + + + +/** + * @dev Implementation of the {IERC165} interface. + * + * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check + * for the additional interface id that will be supported. For example: + * + * ```solidity + * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { + * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId); + * } + * ``` + * + * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation. + */ +abstract contract ERC165 is IERC165 { + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { + return interfaceId == type(IERC165).interfaceId; + } +} + +// lib/solady/src\auth/OwnableRoles.sol + + + + + +/// @notice Simple single owner and multiroles authorization mixin. +/// @author Solady (https://github.com/vectorized/solady/blob/main/src/auth/Ownable.sol) +/// @dev While the ownable portion follows [EIP-173](https://eips.ethereum.org/EIPS/eip-173) +/// for compatibility, the nomenclature for the 2-step ownership handover and roles +/// may be unique to this codebase. +abstract contract OwnableRoles is Ownable { + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* EVENTS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev The `user`'s roles is updated to `roles`. + /// Each bit of `roles` represents whether the role is set. + event RolesUpdated(address indexed user, uint256 indexed roles); + + /// @dev `keccak256(bytes("RolesUpdated(address,uint256)"))`. + uint256 private constant _ROLES_UPDATED_EVENT_SIGNATURE = + 0x715ad5ce61fc9595c7b415289d59cf203f23a94fa06f04af7e489a0a76e1fe26; + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* STORAGE */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev The role slot of `user` is given by: + /// ``` + /// mstore(0x00, or(shl(96, user), _ROLE_SLOT_SEED)) + /// let roleSlot := keccak256(0x00, 0x20) + /// ``` + /// This automatically ignores the upper bits of the `user` in case + /// they are not clean, as well as keep the `keccak256` under 32-bytes. + /// + /// Note: This is equal to `_OWNER_SLOT_NOT` in for gas efficiency. + uint256 private constant _ROLE_SLOT_SEED = 0x8b78c6d8; + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* INTERNAL FUNCTIONS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev Overwrite the roles directly without authorization guard. + function _setRoles(address user, uint256 roles) internal virtual { + /// @solidity memory-safe-assembly + assembly { + mstore(0x0c, _ROLE_SLOT_SEED) + mstore(0x00, user) + // Store the new value. + sstore(keccak256(0x0c, 0x20), roles) + // Emit the {RolesUpdated} event. + log3(0, 0, _ROLES_UPDATED_EVENT_SIGNATURE, shr(96, mload(0x0c)), roles) + } + } + + /// @dev Updates the roles directly without authorization guard. + /// If `on` is true, each set bit of `roles` will be turned on, + /// otherwise, each set bit of `roles` will be turned off. + function _updateRoles(address user, uint256 roles, bool on) internal virtual { + /// @solidity memory-safe-assembly + assembly { + mstore(0x0c, _ROLE_SLOT_SEED) + mstore(0x00, user) + let roleSlot := keccak256(0x0c, 0x20) + // Load the current value. + let current := sload(roleSlot) + // Compute the updated roles if `on` is true. + let updated := or(current, roles) + // Compute the updated roles if `on` is false. + // Use `and` to compute the intersection of `current` and `roles`, + // `xor` it with `current` to flip the bits in the intersection. + if iszero(on) { updated := xor(current, and(current, roles)) } + // Then, store the new value. + sstore(roleSlot, updated) + // Emit the {RolesUpdated} event. + log3(0, 0, _ROLES_UPDATED_EVENT_SIGNATURE, shr(96, mload(0x0c)), updated) + } + } + + /// @dev Grants the roles directly without authorization guard. + /// Each bit of `roles` represents the role to turn on. + function _grantRoles(address user, uint256 roles) internal virtual { + _updateRoles(user, roles, true); + } + + /// @dev Removes the roles directly without authorization guard. + /// Each bit of `roles` represents the role to turn off. + function _removeRoles(address user, uint256 roles) internal virtual { + _updateRoles(user, roles, false); + } + + /// @dev Throws if the sender does not have any of the `roles`. + function _checkRoles(uint256 roles) internal view virtual { + /// @solidity memory-safe-assembly + assembly { + // Compute the role slot. + mstore(0x0c, _ROLE_SLOT_SEED) + mstore(0x00, caller()) + // Load the stored value, and if the `and` intersection + // of the value and `roles` is zero, revert. + if iszero(and(sload(keccak256(0x0c, 0x20)), roles)) { + mstore(0x00, 0x82b42900) // `Unauthorized()`. + revert(0x1c, 0x04) + } + } + } + + /// @dev Throws if the sender is not the owner, + /// and does not have any of the `roles`. + /// Checks for ownership first, then lazily checks for roles. + function _checkOwnerOrRoles(uint256 roles) internal view virtual { + /// @solidity memory-safe-assembly + assembly { + // If the caller is not the stored owner. + // Note: `_ROLE_SLOT_SEED` is equal to `_OWNER_SLOT_NOT`. + if iszero(eq(caller(), sload(not(_ROLE_SLOT_SEED)))) { + // Compute the role slot. + mstore(0x0c, _ROLE_SLOT_SEED) + mstore(0x00, caller()) + // Load the stored value, and if the `and` intersection + // of the value and `roles` is zero, revert. + if iszero(and(sload(keccak256(0x0c, 0x20)), roles)) { + mstore(0x00, 0x82b42900) // `Unauthorized()`. + revert(0x1c, 0x04) + } + } + } + } + + /// @dev Throws if the sender does not have any of the `roles`, + /// and is not the owner. + /// Checks for roles first, then lazily checks for ownership. + function _checkRolesOrOwner(uint256 roles) internal view virtual { + /// @solidity memory-safe-assembly + assembly { + // Compute the role slot. + mstore(0x0c, _ROLE_SLOT_SEED) + mstore(0x00, caller()) + // Load the stored value, and if the `and` intersection + // of the value and `roles` is zero, revert. + if iszero(and(sload(keccak256(0x0c, 0x20)), roles)) { + // If the caller is not the stored owner. + // Note: `_ROLE_SLOT_SEED` is equal to `_OWNER_SLOT_NOT`. + if iszero(eq(caller(), sload(not(_ROLE_SLOT_SEED)))) { + mstore(0x00, 0x82b42900) // `Unauthorized()`. + revert(0x1c, 0x04) + } + } + } + } + + /// @dev Convenience function to return a `roles` bitmap from an array of `ordinals`. + /// This is meant for frontends like Etherscan, and is therefore not fully optimized. + /// Not recommended to be called on-chain. + /// Made internal to conserve bytecode. Wrap it in a public function if needed. + function _rolesFromOrdinals(uint8[] memory ordinals) internal pure returns (uint256 roles) { + /// @solidity memory-safe-assembly + assembly { + for { let i := shl(5, mload(ordinals)) } i { i := sub(i, 0x20) } { + // We don't need to mask the values of `ordinals`, as Solidity + // cleans dirty upper bits when storing variables into memory. + roles := or(shl(mload(add(ordinals, i)), 1), roles) + } + } + } + + /// @dev Convenience function to return an array of `ordinals` from the `roles` bitmap. + /// This is meant for frontends like Etherscan, and is therefore not fully optimized. + /// Not recommended to be called on-chain. + /// Made internal to conserve bytecode. Wrap it in a public function if needed. + function _ordinalsFromRoles(uint256 roles) internal pure returns (uint8[] memory ordinals) { + /// @solidity memory-safe-assembly + assembly { + // Grab the pointer to the free memory. + ordinals := mload(0x40) + let ptr := add(ordinals, 0x20) + let o := 0 + // The absence of lookup tables, De Bruijn, etc., here is intentional for + // smaller bytecode, as this function is not meant to be called on-chain. + for { let t := roles } 1 {} { + mstore(ptr, o) + // `shr` 5 is equivalent to multiplying by 0x20. + // Push back into the ordinals array if the bit is set. + ptr := add(ptr, shl(5, and(t, 1))) + o := add(o, 1) + t := shr(o, roles) + if iszero(t) { break } + } + // Store the length of `ordinals`. + mstore(ordinals, shr(5, sub(ptr, add(ordinals, 0x20)))) + // Allocate the memory. + mstore(0x40, ptr) + } + } + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* PUBLIC UPDATE FUNCTIONS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev Allows the owner to grant `user` `roles`. + /// If the `user` already has a role, then it will be an no-op for the role. + function grantRoles(address user, uint256 roles) public payable virtual onlyOwner { + _grantRoles(user, roles); + } + + /// @dev Allows the owner to remove `user` `roles`. + /// If the `user` does not have a role, then it will be an no-op for the role. + function revokeRoles(address user, uint256 roles) public payable virtual onlyOwner { + _removeRoles(user, roles); + } + + /// @dev Allow the caller to remove their own roles. + /// If the caller does not have a role, then it will be an no-op for the role. + function renounceRoles(uint256 roles) public payable virtual { + _removeRoles(msg.sender, roles); + } + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* PUBLIC READ FUNCTIONS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev Returns the roles of `user`. + function rolesOf(address user) public view virtual returns (uint256 roles) { + /// @solidity memory-safe-assembly + assembly { + // Compute the role slot. + mstore(0x0c, _ROLE_SLOT_SEED) + mstore(0x00, user) + // Load the stored value. + roles := sload(keccak256(0x0c, 0x20)) + } + } + + /// @dev Returns whether `user` has any of `roles`. + function hasAnyRole(address user, uint256 roles) public view virtual returns (bool) { + return rolesOf(user) & roles != 0; + } + + /// @dev Returns whether `user` has all of `roles`. + function hasAllRoles(address user, uint256 roles) public view virtual returns (bool) { + return rolesOf(user) & roles == roles; + } + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* MODIFIERS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev Marks a function as only callable by an account with `roles`. + modifier onlyRoles(uint256 roles) virtual { + _checkRoles(roles); + _; + } + + /// @dev Marks a function as only callable by the owner or by an account + /// with `roles`. Checks for ownership first, then lazily checks for roles. + modifier onlyOwnerOrRoles(uint256 roles) virtual { + _checkOwnerOrRoles(roles); + _; + } + + /// @dev Marks a function as only callable by an account with `roles` + /// or the owner. Checks for roles first, then lazily checks for ownership. + modifier onlyRolesOrOwner(uint256 roles) virtual { + _checkRolesOrOwner(roles); + _; + } + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* ROLE CONSTANTS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + // IYKYK + + uint256 internal constant _ROLE_0 = 1 << 0; + uint256 internal constant _ROLE_1 = 1 << 1; + uint256 internal constant _ROLE_2 = 1 << 2; + uint256 internal constant _ROLE_3 = 1 << 3; + uint256 internal constant _ROLE_4 = 1 << 4; + uint256 internal constant _ROLE_5 = 1 << 5; + uint256 internal constant _ROLE_6 = 1 << 6; + uint256 internal constant _ROLE_7 = 1 << 7; + uint256 internal constant _ROLE_8 = 1 << 8; + uint256 internal constant _ROLE_9 = 1 << 9; + uint256 internal constant _ROLE_10 = 1 << 10; + uint256 internal constant _ROLE_11 = 1 << 11; + uint256 internal constant _ROLE_12 = 1 << 12; + uint256 internal constant _ROLE_13 = 1 << 13; + uint256 internal constant _ROLE_14 = 1 << 14; + uint256 internal constant _ROLE_15 = 1 << 15; + uint256 internal constant _ROLE_16 = 1 << 16; + uint256 internal constant _ROLE_17 = 1 << 17; + uint256 internal constant _ROLE_18 = 1 << 18; + uint256 internal constant _ROLE_19 = 1 << 19; + uint256 internal constant _ROLE_20 = 1 << 20; + uint256 internal constant _ROLE_21 = 1 << 21; + uint256 internal constant _ROLE_22 = 1 << 22; + uint256 internal constant _ROLE_23 = 1 << 23; + uint256 internal constant _ROLE_24 = 1 << 24; + uint256 internal constant _ROLE_25 = 1 << 25; + uint256 internal constant _ROLE_26 = 1 << 26; + uint256 internal constant _ROLE_27 = 1 << 27; + uint256 internal constant _ROLE_28 = 1 << 28; + uint256 internal constant _ROLE_29 = 1 << 29; + uint256 internal constant _ROLE_30 = 1 << 30; + uint256 internal constant _ROLE_31 = 1 << 31; + uint256 internal constant _ROLE_32 = 1 << 32; + uint256 internal constant _ROLE_33 = 1 << 33; + uint256 internal constant _ROLE_34 = 1 << 34; + uint256 internal constant _ROLE_35 = 1 << 35; + uint256 internal constant _ROLE_36 = 1 << 36; + uint256 internal constant _ROLE_37 = 1 << 37; + uint256 internal constant _ROLE_38 = 1 << 38; + uint256 internal constant _ROLE_39 = 1 << 39; + uint256 internal constant _ROLE_40 = 1 << 40; + uint256 internal constant _ROLE_41 = 1 << 41; + uint256 internal constant _ROLE_42 = 1 << 42; + uint256 internal constant _ROLE_43 = 1 << 43; + uint256 internal constant _ROLE_44 = 1 << 44; + uint256 internal constant _ROLE_45 = 1 << 45; + uint256 internal constant _ROLE_46 = 1 << 46; + uint256 internal constant _ROLE_47 = 1 << 47; + uint256 internal constant _ROLE_48 = 1 << 48; + uint256 internal constant _ROLE_49 = 1 << 49; + uint256 internal constant _ROLE_50 = 1 << 50; + uint256 internal constant _ROLE_51 = 1 << 51; + uint256 internal constant _ROLE_52 = 1 << 52; + uint256 internal constant _ROLE_53 = 1 << 53; + uint256 internal constant _ROLE_54 = 1 << 54; + uint256 internal constant _ROLE_55 = 1 << 55; + uint256 internal constant _ROLE_56 = 1 << 56; + uint256 internal constant _ROLE_57 = 1 << 57; + uint256 internal constant _ROLE_58 = 1 << 58; + uint256 internal constant _ROLE_59 = 1 << 59; + uint256 internal constant _ROLE_60 = 1 << 60; + uint256 internal constant _ROLE_61 = 1 << 61; + uint256 internal constant _ROLE_62 = 1 << 62; + uint256 internal constant _ROLE_63 = 1 << 63; + uint256 internal constant _ROLE_64 = 1 << 64; + uint256 internal constant _ROLE_65 = 1 << 65; + uint256 internal constant _ROLE_66 = 1 << 66; + uint256 internal constant _ROLE_67 = 1 << 67; + uint256 internal constant _ROLE_68 = 1 << 68; + uint256 internal constant _ROLE_69 = 1 << 69; + uint256 internal constant _ROLE_70 = 1 << 70; + uint256 internal constant _ROLE_71 = 1 << 71; + uint256 internal constant _ROLE_72 = 1 << 72; + uint256 internal constant _ROLE_73 = 1 << 73; + uint256 internal constant _ROLE_74 = 1 << 74; + uint256 internal constant _ROLE_75 = 1 << 75; + uint256 internal constant _ROLE_76 = 1 << 76; + uint256 internal constant _ROLE_77 = 1 << 77; + uint256 internal constant _ROLE_78 = 1 << 78; + uint256 internal constant _ROLE_79 = 1 << 79; + uint256 internal constant _ROLE_80 = 1 << 80; + uint256 internal constant _ROLE_81 = 1 << 81; + uint256 internal constant _ROLE_82 = 1 << 82; + uint256 internal constant _ROLE_83 = 1 << 83; + uint256 internal constant _ROLE_84 = 1 << 84; + uint256 internal constant _ROLE_85 = 1 << 85; + uint256 internal constant _ROLE_86 = 1 << 86; + uint256 internal constant _ROLE_87 = 1 << 87; + uint256 internal constant _ROLE_88 = 1 << 88; + uint256 internal constant _ROLE_89 = 1 << 89; + uint256 internal constant _ROLE_90 = 1 << 90; + uint256 internal constant _ROLE_91 = 1 << 91; + uint256 internal constant _ROLE_92 = 1 << 92; + uint256 internal constant _ROLE_93 = 1 << 93; + uint256 internal constant _ROLE_94 = 1 << 94; + uint256 internal constant _ROLE_95 = 1 << 95; + uint256 internal constant _ROLE_96 = 1 << 96; + uint256 internal constant _ROLE_97 = 1 << 97; + uint256 internal constant _ROLE_98 = 1 << 98; + uint256 internal constant _ROLE_99 = 1 << 99; + uint256 internal constant _ROLE_100 = 1 << 100; + uint256 internal constant _ROLE_101 = 1 << 101; + uint256 internal constant _ROLE_102 = 1 << 102; + uint256 internal constant _ROLE_103 = 1 << 103; + uint256 internal constant _ROLE_104 = 1 << 104; + uint256 internal constant _ROLE_105 = 1 << 105; + uint256 internal constant _ROLE_106 = 1 << 106; + uint256 internal constant _ROLE_107 = 1 << 107; + uint256 internal constant _ROLE_108 = 1 << 108; + uint256 internal constant _ROLE_109 = 1 << 109; + uint256 internal constant _ROLE_110 = 1 << 110; + uint256 internal constant _ROLE_111 = 1 << 111; + uint256 internal constant _ROLE_112 = 1 << 112; + uint256 internal constant _ROLE_113 = 1 << 113; + uint256 internal constant _ROLE_114 = 1 << 114; + uint256 internal constant _ROLE_115 = 1 << 115; + uint256 internal constant _ROLE_116 = 1 << 116; + uint256 internal constant _ROLE_117 = 1 << 117; + uint256 internal constant _ROLE_118 = 1 << 118; + uint256 internal constant _ROLE_119 = 1 << 119; + uint256 internal constant _ROLE_120 = 1 << 120; + uint256 internal constant _ROLE_121 = 1 << 121; + uint256 internal constant _ROLE_122 = 1 << 122; + uint256 internal constant _ROLE_123 = 1 << 123; + uint256 internal constant _ROLE_124 = 1 << 124; + uint256 internal constant _ROLE_125 = 1 << 125; + uint256 internal constant _ROLE_126 = 1 << 126; + uint256 internal constant _ROLE_127 = 1 << 127; + uint256 internal constant _ROLE_128 = 1 << 128; + uint256 internal constant _ROLE_129 = 1 << 129; + uint256 internal constant _ROLE_130 = 1 << 130; + uint256 internal constant _ROLE_131 = 1 << 131; + uint256 internal constant _ROLE_132 = 1 << 132; + uint256 internal constant _ROLE_133 = 1 << 133; + uint256 internal constant _ROLE_134 = 1 << 134; + uint256 internal constant _ROLE_135 = 1 << 135; + uint256 internal constant _ROLE_136 = 1 << 136; + uint256 internal constant _ROLE_137 = 1 << 137; + uint256 internal constant _ROLE_138 = 1 << 138; + uint256 internal constant _ROLE_139 = 1 << 139; + uint256 internal constant _ROLE_140 = 1 << 140; + uint256 internal constant _ROLE_141 = 1 << 141; + uint256 internal constant _ROLE_142 = 1 << 142; + uint256 internal constant _ROLE_143 = 1 << 143; + uint256 internal constant _ROLE_144 = 1 << 144; + uint256 internal constant _ROLE_145 = 1 << 145; + uint256 internal constant _ROLE_146 = 1 << 146; + uint256 internal constant _ROLE_147 = 1 << 147; + uint256 internal constant _ROLE_148 = 1 << 148; + uint256 internal constant _ROLE_149 = 1 << 149; + uint256 internal constant _ROLE_150 = 1 << 150; + uint256 internal constant _ROLE_151 = 1 << 151; + uint256 internal constant _ROLE_152 = 1 << 152; + uint256 internal constant _ROLE_153 = 1 << 153; + uint256 internal constant _ROLE_154 = 1 << 154; + uint256 internal constant _ROLE_155 = 1 << 155; + uint256 internal constant _ROLE_156 = 1 << 156; + uint256 internal constant _ROLE_157 = 1 << 157; + uint256 internal constant _ROLE_158 = 1 << 158; + uint256 internal constant _ROLE_159 = 1 << 159; + uint256 internal constant _ROLE_160 = 1 << 160; + uint256 internal constant _ROLE_161 = 1 << 161; + uint256 internal constant _ROLE_162 = 1 << 162; + uint256 internal constant _ROLE_163 = 1 << 163; + uint256 internal constant _ROLE_164 = 1 << 164; + uint256 internal constant _ROLE_165 = 1 << 165; + uint256 internal constant _ROLE_166 = 1 << 166; + uint256 internal constant _ROLE_167 = 1 << 167; + uint256 internal constant _ROLE_168 = 1 << 168; + uint256 internal constant _ROLE_169 = 1 << 169; + uint256 internal constant _ROLE_170 = 1 << 170; + uint256 internal constant _ROLE_171 = 1 << 171; + uint256 internal constant _ROLE_172 = 1 << 172; + uint256 internal constant _ROLE_173 = 1 << 173; + uint256 internal constant _ROLE_174 = 1 << 174; + uint256 internal constant _ROLE_175 = 1 << 175; + uint256 internal constant _ROLE_176 = 1 << 176; + uint256 internal constant _ROLE_177 = 1 << 177; + uint256 internal constant _ROLE_178 = 1 << 178; + uint256 internal constant _ROLE_179 = 1 << 179; + uint256 internal constant _ROLE_180 = 1 << 180; + uint256 internal constant _ROLE_181 = 1 << 181; + uint256 internal constant _ROLE_182 = 1 << 182; + uint256 internal constant _ROLE_183 = 1 << 183; + uint256 internal constant _ROLE_184 = 1 << 184; + uint256 internal constant _ROLE_185 = 1 << 185; + uint256 internal constant _ROLE_186 = 1 << 186; + uint256 internal constant _ROLE_187 = 1 << 187; + uint256 internal constant _ROLE_188 = 1 << 188; + uint256 internal constant _ROLE_189 = 1 << 189; + uint256 internal constant _ROLE_190 = 1 << 190; + uint256 internal constant _ROLE_191 = 1 << 191; + uint256 internal constant _ROLE_192 = 1 << 192; + uint256 internal constant _ROLE_193 = 1 << 193; + uint256 internal constant _ROLE_194 = 1 << 194; + uint256 internal constant _ROLE_195 = 1 << 195; + uint256 internal constant _ROLE_196 = 1 << 196; + uint256 internal constant _ROLE_197 = 1 << 197; + uint256 internal constant _ROLE_198 = 1 << 198; + uint256 internal constant _ROLE_199 = 1 << 199; + uint256 internal constant _ROLE_200 = 1 << 200; + uint256 internal constant _ROLE_201 = 1 << 201; + uint256 internal constant _ROLE_202 = 1 << 202; + uint256 internal constant _ROLE_203 = 1 << 203; + uint256 internal constant _ROLE_204 = 1 << 204; + uint256 internal constant _ROLE_205 = 1 << 205; + uint256 internal constant _ROLE_206 = 1 << 206; + uint256 internal constant _ROLE_207 = 1 << 207; + uint256 internal constant _ROLE_208 = 1 << 208; + uint256 internal constant _ROLE_209 = 1 << 209; + uint256 internal constant _ROLE_210 = 1 << 210; + uint256 internal constant _ROLE_211 = 1 << 211; + uint256 internal constant _ROLE_212 = 1 << 212; + uint256 internal constant _ROLE_213 = 1 << 213; + uint256 internal constant _ROLE_214 = 1 << 214; + uint256 internal constant _ROLE_215 = 1 << 215; + uint256 internal constant _ROLE_216 = 1 << 216; + uint256 internal constant _ROLE_217 = 1 << 217; + uint256 internal constant _ROLE_218 = 1 << 218; + uint256 internal constant _ROLE_219 = 1 << 219; + uint256 internal constant _ROLE_220 = 1 << 220; + uint256 internal constant _ROLE_221 = 1 << 221; + uint256 internal constant _ROLE_222 = 1 << 222; + uint256 internal constant _ROLE_223 = 1 << 223; + uint256 internal constant _ROLE_224 = 1 << 224; + uint256 internal constant _ROLE_225 = 1 << 225; + uint256 internal constant _ROLE_226 = 1 << 226; + uint256 internal constant _ROLE_227 = 1 << 227; + uint256 internal constant _ROLE_228 = 1 << 228; + uint256 internal constant _ROLE_229 = 1 << 229; + uint256 internal constant _ROLE_230 = 1 << 230; + uint256 internal constant _ROLE_231 = 1 << 231; + uint256 internal constant _ROLE_232 = 1 << 232; + uint256 internal constant _ROLE_233 = 1 << 233; + uint256 internal constant _ROLE_234 = 1 << 234; + uint256 internal constant _ROLE_235 = 1 << 235; + uint256 internal constant _ROLE_236 = 1 << 236; + uint256 internal constant _ROLE_237 = 1 << 237; + uint256 internal constant _ROLE_238 = 1 << 238; + uint256 internal constant _ROLE_239 = 1 << 239; + uint256 internal constant _ROLE_240 = 1 << 240; + uint256 internal constant _ROLE_241 = 1 << 241; + uint256 internal constant _ROLE_242 = 1 << 242; + uint256 internal constant _ROLE_243 = 1 << 243; + uint256 internal constant _ROLE_244 = 1 << 244; + uint256 internal constant _ROLE_245 = 1 << 245; + uint256 internal constant _ROLE_246 = 1 << 246; + uint256 internal constant _ROLE_247 = 1 << 247; + uint256 internal constant _ROLE_248 = 1 << 248; + uint256 internal constant _ROLE_249 = 1 << 249; + uint256 internal constant _ROLE_250 = 1 << 250; + uint256 internal constant _ROLE_251 = 1 << 251; + uint256 internal constant _ROLE_252 = 1 << 252; + uint256 internal constant _ROLE_253 = 1 << 253; + uint256 internal constant _ROLE_254 = 1 << 254; + uint256 internal constant _ROLE_255 = 1 << 255; +} + +// src\types/VRFConfig.sol + + + + + +struct VRFConfig { + VRFCoordinatorV2Interface coordinator; + bytes32 keyHash; + uint64 subcriptionId; + uint16 minimumRequestConfirmations; + uint32 callbackGasLimit; +} + +// lib/operator-filter-registry/src/OperatorFilterer.sol + + + + + +/** + * @title OperatorFilterer + * @notice Abstract contract whose constructor automatically registers and optionally subscribes to or copies another + * registrant's entries in the OperatorFilterRegistry. + * @dev This smart contract is meant to be inherited by token contracts so they can use the following: + * - `onlyAllowedOperator` modifier for `transferFrom` and `safeTransferFrom` methods. + * - `onlyAllowedOperatorApproval` modifier for `approve` and `setApprovalForAll` methods. + * Please note that if your token contract does not provide an owner with EIP-173, it must provide + * administration methods on the contract itself to interact with the registry otherwise the subscription + * will be locked to the options set during construction. + */ + +abstract contract OperatorFilterer { + /// @dev Emitted when an operator is not allowed. + error OperatorNotAllowed(address operator); + + IOperatorFilterRegistry public constant OPERATOR_FILTER_REGISTRY = + IOperatorFilterRegistry(CANONICAL_OPERATOR_FILTER_REGISTRY_ADDRESS); + + /// @dev The constructor that is called when the contract is being deployed. + constructor(address subscriptionOrRegistrantToCopy, bool subscribe) { + // If an inheriting token contract is deployed to a network without the registry deployed, the modifier + // will not revert, but the contract will need to be registered with the registry once it is deployed in + // order for the modifier to filter addresses. + if (address(OPERATOR_FILTER_REGISTRY).code.length > 0) { + if (subscribe) { + OPERATOR_FILTER_REGISTRY.registerAndSubscribe(address(this), subscriptionOrRegistrantToCopy); + } else { + if (subscriptionOrRegistrantToCopy != address(0)) { + OPERATOR_FILTER_REGISTRY.registerAndCopyEntries(address(this), subscriptionOrRegistrantToCopy); + } else { + OPERATOR_FILTER_REGISTRY.register(address(this)); + } + } + } + } + + /** + * @dev A helper function to check if an operator is allowed. + */ + modifier onlyAllowedOperator(address from) virtual { + // Allow spending tokens from addresses with balance + // Note that this still allows listings and marketplaces with escrow to transfer tokens if transferred + // from an EOA. + if (from != msg.sender) { + _checkFilterOperator(msg.sender); + } + _; + } + + /** + * @dev A helper function to check if an operator approval is allowed. + */ + modifier onlyAllowedOperatorApproval(address operator) virtual { + _checkFilterOperator(operator); + _; + } + + /** + * @dev A helper function to check if an operator is allowed. + */ + function _checkFilterOperator(address operator) internal view virtual { + // Check registry code length to facilitate testing in environments without a deployed registry. + if (address(OPERATOR_FILTER_REGISTRY).code.length > 0) { + // under normal circumstances, this function will revert rather than return false, but inheriting contracts + // may specify their own OperatorFilterRegistry implementations, which may behave differently + if (!OPERATOR_FILTER_REGISTRY.isOperatorAllowed(address(this), operator)) { + revert OperatorNotAllowed(operator); + } + } + } +} + +// lib/ERC721A/contracts\extensions/ERC721ABurnable.sol + +// ERC721A Contracts v4.2.3 +// Creator: Chiru Labs + + + + + + +/** + * @title ERC721ABurnable. + * + * @dev ERC721A token that can be irreversibly burned (destroyed). + */ +abstract contract ERC721ABurnable is ERC721A, IERC721ABurnable { + /** + * @dev Burns `tokenId`. See {ERC721A-_burn}. + * + * Requirements: + * + * - The caller must own `tokenId` or be an approved operator. + */ + function burn(uint256 tokenId) public virtual override { + _burn(tokenId, true); + } +} + +// lib/ERC721A/contracts\extensions/ERC721AQueryable.sol + +// ERC721A Contracts v4.2.3 +// Creator: Chiru Labs + + + + + + +/** + * @title ERC721AQueryable. + * + * @dev ERC721A subclass with convenience query functions. + */ +abstract contract ERC721AQueryable is ERC721A, IERC721AQueryable { + /** + * @dev Returns the `TokenOwnership` struct at `tokenId` without reverting. + * + * If the `tokenId` is out of bounds: + * + * - `addr = address(0)` + * - `startTimestamp = 0` + * - `burned = false` + * - `extraData = 0` + * + * If the `tokenId` is burned: + * + * - `addr =
` + * - `startTimestamp = ` + * - `burned = true` + * - `extraData = ` + * + * Otherwise: + * + * - `addr =
` + * - `startTimestamp = ` + * - `burned = false` + * - `extraData = ` + */ + function explicitOwnershipOf(uint256 tokenId) + public + view + virtual + override + returns (TokenOwnership memory ownership) + { + unchecked { + if (tokenId >= _startTokenId()) { + if (tokenId < _nextTokenId()) { + // If the `tokenId` is within bounds, + // scan backwards for the initialized ownership slot. + while (!_ownershipIsInitialized(tokenId)) --tokenId; + return _ownershipAt(tokenId); + } + } + } + } + + /** + * @dev Returns an array of `TokenOwnership` structs at `tokenIds` in order. + * See {ERC721AQueryable-explicitOwnershipOf} + */ + function explicitOwnershipsOf(uint256[] calldata tokenIds) + external + view + virtual + override + returns (TokenOwnership[] memory) + { + TokenOwnership[] memory ownerships; + uint256 i = tokenIds.length; + assembly { + // Grab the free memory pointer. + ownerships := mload(0x40) + // Store the length. + mstore(ownerships, i) + // Allocate one word for the length, + // `tokenIds.length` words for the pointers. + i := shl(5, i) // Multiply `i` by 32. + mstore(0x40, add(add(ownerships, 0x20), i)) + } + while (i != 0) { + uint256 tokenId; + assembly { + i := sub(i, 0x20) + tokenId := calldataload(add(tokenIds.offset, i)) + } + TokenOwnership memory ownership = explicitOwnershipOf(tokenId); + assembly { + // Store the pointer of `ownership` in the `ownerships` array. + mstore(add(add(ownerships, 0x20), i), ownership) + } + } + return ownerships; + } + + /** + * @dev Returns an array of token IDs owned by `owner`, + * in the range [`start`, `stop`) + * (i.e. `start <= tokenId < stop`). + * + * This function allows for tokens to be queried if the collection + * grows too big for a single call of {ERC721AQueryable-tokensOfOwner}. + * + * Requirements: + * + * - `start < stop` + */ + function tokensOfOwnerIn( + address owner, + uint256 start, + uint256 stop + ) external view virtual override returns (uint256[] memory) { + return _tokensOfOwnerIn(owner, start, stop); + } + + /** + * @dev Returns an array of token IDs owned by `owner`. + * + * This function scans the ownership mapping and is O(`totalSupply`) in complexity. + * It is meant to be called off-chain. + * + * See {ERC721AQueryable-tokensOfOwnerIn} for splitting the scan into + * multiple smaller scans if the collection is large enough to cause + * an out-of-gas error (10K collections should be fine). + */ + function tokensOfOwner(address owner) external view virtual override returns (uint256[] memory) { + uint256 start = _startTokenId(); + uint256 stop = _nextTokenId(); + uint256[] memory tokenIds; + if (start != stop) tokenIds = _tokensOfOwnerIn(owner, start, stop); + return tokenIds; + } + + /** + * @dev Helper function for returning an array of token IDs owned by `owner`. + * + * Note that this function is optimized for smaller bytecode size over runtime gas, + * since it is meant to be called off-chain. + */ + function _tokensOfOwnerIn( + address owner, + uint256 start, + uint256 stop + ) private view returns (uint256[] memory) { + unchecked { + if (start >= stop) _revert(InvalidQueryRange.selector); + // Set `start = max(start, _startTokenId())`. + if (start < _startTokenId()) { + start = _startTokenId(); + } + uint256 stopLimit = _nextTokenId(); + // Set `stop = min(stop, stopLimit)`. + if (stop >= stopLimit) { + stop = stopLimit; + } + uint256[] memory tokenIds; + uint256 tokenIdsMaxLength = balanceOf(owner); + bool startLtStop = start < stop; + assembly { + // Set `tokenIdsMaxLength` to zero if `start` is less than `stop`. + tokenIdsMaxLength := mul(tokenIdsMaxLength, startLtStop) + } + if (tokenIdsMaxLength != 0) { + // Set `tokenIdsMaxLength = min(balanceOf(owner), stop - start)`, + // to cater for cases where `balanceOf(owner)` is too big. + if (stop - start <= tokenIdsMaxLength) { + tokenIdsMaxLength = stop - start; + } + assembly { + // Grab the free memory pointer. + tokenIds := mload(0x40) + // Allocate one word for the length, and `tokenIdsMaxLength` words + // for the data. `shl(5, x)` is equivalent to `mul(32, x)`. + mstore(0x40, add(tokenIds, shl(5, add(tokenIdsMaxLength, 1)))) + } + // We need to call `explicitOwnershipOf(start)`, + // because the slot at `start` may not be initialized. + TokenOwnership memory ownership = explicitOwnershipOf(start); + address currOwnershipAddr; + // If the starting slot exists (i.e. not burned), + // initialize `currOwnershipAddr`. + // `ownership.address` will not be zero, + // as `start` is clamped to the valid token ID range. + if (!ownership.burned) { + currOwnershipAddr = ownership.addr; + } + uint256 tokenIdsIdx; + // Use a do-while, which is slightly more efficient for this case, + // as the array will at least contain one element. + do { + ownership = _ownershipAt(start); + assembly { + switch mload(add(ownership, 0x40)) + // if `ownership.burned == false`. + case 0 { + // if `ownership.addr != address(0)`. + // The `addr` already has it's upper 96 bits clearned, + // since it is written to memory with regular Solidity. + if mload(ownership) { + currOwnershipAddr := mload(ownership) + } + // if `currOwnershipAddr == owner`. + // The `shl(96, x)` is to make the comparison agnostic to any + // dirty upper 96 bits in `owner`. + if iszero(shl(96, xor(currOwnershipAddr, owner))) { + tokenIdsIdx := add(tokenIdsIdx, 1) + mstore(add(tokenIds, shl(5, tokenIdsIdx)), start) + } + } + // Otherwise, reset `currOwnershipAddr`. + // This handles the case of batch burned tokens + // (burned bit of first slot set, remaining slots left uninitialized). + default { + currOwnershipAddr := 0 + } + start := add(start, 1) + } + } while (!(start == stop || tokenIdsIdx == tokenIdsMaxLength)); + // Store the length of the array. + assembly { + mstore(tokenIds, tokenIdsIdx) + } + } + return tokenIds; + } + } +} + +// lib/openzeppelin-contracts/contracts\token/common/ERC2981.sol + +// OpenZeppelin Contracts (last updated v4.9.0) (token/common/ERC2981.sol) + + + + + + +/** + * @dev Implementation of the NFT Royalty Standard, a standardized way to retrieve royalty payment information. + * + * Royalty information can be specified globally for all token ids via {_setDefaultRoyalty}, and/or individually for + * specific token ids via {_setTokenRoyalty}. The latter takes precedence over the first. + * + * Royalty is specified as a fraction of sale price. {_feeDenominator} is overridable but defaults to 10000, meaning the + * fee is specified in basis points by default. + * + * IMPORTANT: ERC-2981 only specifies a way to signal royalty information and does not enforce its payment. See + * https://eips.ethereum.org/EIPS/eip-2981#optional-royalty-payments[Rationale] in the EIP. Marketplaces are expected to + * voluntarily pay royalties together with sales, but note that this standard is not yet widely supported. + * + * _Available since v4.5._ + */ +abstract contract ERC2981 is IERC2981, ERC165 { + struct RoyaltyInfo { + address receiver; + uint96 royaltyFraction; + } + + RoyaltyInfo private _defaultRoyaltyInfo; + mapping(uint256 => RoyaltyInfo) private _tokenRoyaltyInfo; + + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface(bytes4 interfaceId) public view virtual override(IERC165, ERC165) returns (bool) { + return interfaceId == type(IERC2981).interfaceId || super.supportsInterface(interfaceId); + } + + /** + * + */ + function royaltyInfo(uint256 tokenId, uint256 salePrice) public view virtual override returns (address, uint256) { + RoyaltyInfo memory royalty = _tokenRoyaltyInfo[tokenId]; + + if (royalty.receiver == address(0)) { + royalty = _defaultRoyaltyInfo; + } + + uint256 royaltyAmount = (salePrice * royalty.royaltyFraction) / _feeDenominator(); + + return (royalty.receiver, royaltyAmount); + } + + /** + * @dev The denominator with which to interpret the fee set in {_setTokenRoyalty} and {_setDefaultRoyalty} as a + * fraction of the sale price. Defaults to 10000 so fees are expressed in basis points, but may be customized by an + * override. + */ + function _feeDenominator() internal pure virtual returns (uint96) { + return 10000; + } + + /** + * @dev Sets the royalty information that all ids in this contract will default to. + * + * Requirements: + * + * - `receiver` cannot be the zero address. + * - `feeNumerator` cannot be greater than the fee denominator. + */ + function _setDefaultRoyalty(address receiver, uint96 feeNumerator) internal virtual { + require(feeNumerator <= _feeDenominator(), "ERC2981: royalty fee will exceed salePrice"); + require(receiver != address(0), "ERC2981: invalid receiver"); + + _defaultRoyaltyInfo = RoyaltyInfo(receiver, feeNumerator); + } + + /** + * @dev Removes default royalty information. + */ + function _deleteDefaultRoyalty() internal virtual { + delete _defaultRoyaltyInfo; + } + + /** + * @dev Sets the royalty information for a specific token id, overriding the global default. + * + * Requirements: + * + * - `receiver` cannot be the zero address. + * - `feeNumerator` cannot be greater than the fee denominator. + */ + function _setTokenRoyalty(uint256 tokenId, address receiver, uint96 feeNumerator) internal virtual { + require(feeNumerator <= _feeDenominator(), "ERC2981: royalty fee will exceed salePrice"); + require(receiver != address(0), "ERC2981: Invalid parameters"); + + _tokenRoyaltyInfo[tokenId] = RoyaltyInfo(receiver, feeNumerator); + } + + /** + * @dev Resets royalty information for the token id back to the global default. + */ + function _resetTokenRoyalty(uint256 tokenId) internal virtual { + delete _tokenRoyaltyInfo[tokenId]; + } +} + +// lib/operator-filter-registry/src\DefaultOperatorFilterer.sol + + + + + +/** + * @title DefaultOperatorFilterer + * @notice Inherits from OperatorFilterer and automatically subscribes to the default OpenSea subscription. + * @dev Please note that if your token contract does not provide an owner with EIP-173, it must provide + * administration methods on the contract itself to interact with the registry otherwise the subscription + * will be locked to the options set during construction. + */ + +abstract contract DefaultOperatorFilterer is OperatorFilterer { + /// @dev The constructor that is called when the contract is being deployed. + constructor() OperatorFilterer(CANONICAL_CORI_SUBSCRIPTION, true) {} +} + +// src\common/IBaseERC721A.sol + + + + + + + + + +/// @title IBaseERC721 +/// +/// @author Mathieu Bour for Pooky Labs Ltd. +interface IBaseERC721A is IERC165, IERC721A, IERC721ABurnable, IERC721AQueryable, IERC2981 { + /// Fired when the seed of a Pookyball token is set by the VRFCoordinator, + event SeedSet(uint256 indexed tokenId, uint256 seed); + + /// Thrown when the token {tokenId} does not exist. + error NonExistentToken(uint256 tokenId); + + // ----- ERC721A patches ----- + /// @dev This allow to iterate over the token ids. + function nextTokenId() external view returns (uint256); + + function supportsInterface(bytes4 interfaceId) + external + view + override(IERC165, IERC721A) + returns (bool); +} + +// src\stickers/IStickers.sol + + + + + +enum StickerRarity { + COMMON, + RARE, + EPIC, + LEGENDARY, + MYTHIC +} + +struct StickerMint { + address recipient; + StickerRarity rarity; +} + +struct StickerMetadata { + uint248 level; + StickerRarity rarity; +} + +/// @title IStickers +/// @author Mathieu Bour for Pooky Labs Ltd. +interface IStickers is IBaseERC721A { + /// Fired when the level of a Pookyball token is changed, + event LevelChanged(uint256 indexed tokenId, uint256 level); + + /// @notice StickerMetadata of the token {tokenId}. + /// @dev Requirements: + /// - Sticker {tokenId} should exist (minted and not burned). + function metadata(uint256 tokenId) external view returns (StickerMetadata memory); + + /// @notice Change the level of a Sticker token. + /// @dev Requirements: + /// - Sticker {tokenId} should exist (minted and not burned). + function setLevel(uint256 tokenId, uint248 newLevel) external; + + /// @notice Mint multiple Stickers at once. + /// @param recipient The mint recipient. + /// @param rarities The Sticker rarities. + function mint(address recipient, StickerRarity[] memory rarities) external; +} + +// src\common/BaseERC721A.sol + + + + + + + + + + + + + + + +/// @title BaseERC721A +/// @author Mathieu Bour for Pooky Labs Ltd. +/// +/// @notice Opiniated ERC721 implementation base on ERC721A +/// Features: +/// - `Ownable` via Solady. +/// - Chainlink VRF v2 to assign a random seed to each token id. +/// - Burnable, queryable via the ERC721A extensions. +/// - Royalties enforced on OpenSea using the `DefaultOperatorFilterer`. +contract BaseERC721A is + ERC721A, + ERC721ABurnable, + ERC721AQueryable, + ERC2981, + DefaultOperatorFilterer, + Ownable, + CustomVRFConsumerBaseV2, + IBaseERC721A +{ + /// @notice The prefix URI of all the token metadata. + string public baseURI; + + /// @notice URI of the contract-level metadata. + /// Specified by OpenSea documentation (https://docs.opensea.io/docs/contract-level-metadata). + string public contractURI; + + // VRF parameters + VRFConfig public vrf; + mapping(uint256 => uint256) public vrfRequests; + bool public canUpdateVRF = true; + bool public canUseVRF = false; + + /// The random numbers associated with the tokens: tokenId => randomWord. + mapping(uint256 => uint256) public seeds; + + constructor( + address admin, + // ERC721 + string memory name_, + string memory symbol_, + string memory baseURI_, + string memory _contractURI, + // VRF + VRFConfig memory _vrf, + // ERC2981 + address _receiver, + uint96 royalty + ) ERC721A(name_, symbol_) CustomVRFConsumerBaseV2(address(_vrf.coordinator)) { + _initializeOwner(admin); + baseURI = baseURI_; + _contractURI = contractURI; + vrf = _vrf; + _setDefaultRoyalty(_receiver, royalty); + } + + modifier onlyExists(uint256 tokenId) { + if (!_exists(tokenId)) { + revert NonExistentToken(tokenId); + } + + _; + } + + // ----- ERC721A patches ----- + /// @dev Collection starts at token id 1. + function _startTokenId() internal view virtual override returns (uint256) { + return 1; + } + + /// @dev This allow to iterate over the token ids. + function nextTokenId() external view returns (uint256) { + return _nextTokenId(); + } + + // ----- Metadata ----- + /// @notice Change the base URI of the tokens URI. + /// @dev We keep this function as an escape hatch in case of a migration to another token metadata platform. + /// Requirements: + /// - Only owner can set can set base URI. + function setBaseURI(string memory newBaseURI) external onlyOwner { + baseURI = newBaseURI; + } + + /// @notice Set the URI of the contract-level metadata. + /// @dev We keep this function as an escape hatch in case of a migration to another token metadata platform. + /// Requirements: + /// - Only owner can set the contract URI. + + function setContractURI(string memory newContractURI) external onlyOwner { + contractURI = newContractURI; + } + + /// @notice Override the ERC721A _baseURI with a state variable. + function _baseURI() internal view override returns (string memory) { + return baseURI; + } + + // ---- Mint & VRF ---- + /// @notice Mint a new Pookyball token with a given rarity. Level, PXP and seed are set to zero, entropy is + /// requested to the VRF coordinator. + /// @dev Requirements: + /// - sender must have the MINTER role or be the owner. + function _mint(address to, uint256 quantity) internal virtual override { + super._mint(to, quantity); + + if (canUseVRF) { + // Request entropy from the VRF coordinator + uint256 requestId = vrf.coordinator.requestRandomWords( + vrf.keyHash, + vrf.subcriptionId, + vrf.minimumRequestConfirmations, + vrf.callbackGasLimit, + uint32(quantity) + ); + + vrfRequests[requestId] = _totalMinted(); + } else { + for (uint256 i = 0; i < quantity; i++) { + uint256 tokenId = _totalMinted() - i; + seeds[tokenId] = generateRandomSeed(tokenId); + emit SeedSet(tokenId, seeds[tokenId]); + } + } + } + + /// @notice Receive the entropy from the VRF coordinator. + /// @dev randomWords will only have one word as entropy is requested per token. + function fulfillRandomWords(uint256 requestId, uint256[] memory randomWords) internal override { + uint256 tokenId = vrfRequests[requestId]; + + // Apply the random words + for (uint256 i = 0; i < randomWords.length; i++) { + seeds[tokenId - i] = randomWords[i]; + emit SeedSet(tokenId - i, randomWords[i]); + } + } + + // ---- ERC2981 ---- + /// @notice Change the default royalties and/or the address that will receive them. + /// @param _receiver The new address that will receive the royalties. + /// @param royalty The new default royalty over 10000. + function setDefaultRoyalty(address _receiver, uint96 royalty) external onlyOwner { + _setDefaultRoyalty(_receiver, royalty); + } + + // ---- Operator Filter Registry ---- + /// Operator Filter Registry implementation. + /// @dev See {IERC721A-setApprovalForAll}. + function setApprovalForAll(address operator, bool approved) + public + override(ERC721A, IERC721A) + onlyAllowedOperatorApproval(operator) + { + super.setApprovalForAll(operator, approved); + } + + /// Operator Filter Registry implementation. + /// @dev See {IERC721A-approve}. + function approve(address operator, uint256 tokenId) + public + payable + override(ERC721A, IERC721A) + onlyAllowedOperatorApproval(operator) + { + super.approve(operator, tokenId); + } + + /// Operator Filter Registry implementation. + /// @dev See {IERC721A-transferFrom}. + function transferFrom(address from, address to, uint256 tokenId) + public + payable + override(ERC721A, IERC721A) + onlyAllowedOperator(from) + { + super.transferFrom(from, to, tokenId); + } + + /// Operator Filter Registry implementation. + /// @dev See {IERC721A-safeTransferFrom}. + function safeTransferFrom(address from, address to, uint256 tokenId) + public + payable + override(ERC721A, IERC721A) + onlyAllowedOperator(from) + { + super.safeTransferFrom(from, to, tokenId); + } + + /// Operator Filter Registry implementation. + /// @dev See {IERC721A-safeTransferFrom}. + function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory data) + public + payable + override(ERC721A, IERC721A) + onlyAllowedOperator(from) + { + super.safeTransferFrom(from, to, tokenId, data); + } + + // ----- ERC165 ----- + /// @notice IERC165 declaration. + /// @dev Supports the following `interfaceId`s: + /// - IERC165: 0x01ffc9a7 + /// - IERC721: 0x80ac58cd + /// - IERC721Metadata: 0x5b5e139f + /// - IERC2981: 0x2a55205a + function supportsInterface(bytes4 interfaceId) + public + view + virtual + override(IBaseERC721A, ERC721A, IERC721A, ERC2981) + returns (bool) + { + return super.supportsInterface(interfaceId) || ERC721A.supportsInterface(interfaceId); + } + + // disable update vrf + function disableUpdateVRF() external onlyOwner { + canUpdateVRF = false; + } + + // enable vrf usage + function enableVRF() external onlyOwner { + canUseVRF = true; + } + + // update vrf + function updateVRF( + address _vrfCoordinator, + bytes32 _vrfKeyHash, + uint64 _vrfSubId, + uint16 _vrfMinimumRequestConfirmations, + uint32 _vrfCallbackGasLimit + ) external onlyOwner { + require(canUpdateVRF, "VRF can't be updated"); + vrfCoordinator = _vrfCoordinator; + vrf = VRFConfig( + VRFCoordinatorV2Interface(_vrfCoordinator), + _vrfKeyHash, + _vrfSubId, + _vrfMinimumRequestConfirmations, + _vrfCallbackGasLimit + ); + } + + // generate pseudo random seed + function generateRandomSeed(uint256 tokenId) public view returns (uint256) { + // Hash the combination of block timestamp, sender's address, and token ID + bytes32 hash = keccak256(abi.encodePacked(block.timestamp, msg.sender, tokenId)); + + // Convert the hash to a uint256 + uint256 randomSeed = uint256(hash); + + return randomSeed; + } +} + +// src\stickers\Stickers.sol + + + + + + + + + + + +/// @title Stickers +/// @author Mathieu Bour for Pooky Labs Ltd. +/// @dev Implemented roles: +/// - Owner: allowed to change metadata of the Stickers +/// - `MINTER`: allowed to mint new Stickers +/// - `GAME`: allowed to change the game attributes of the Stickers +contract Stickers is IStickers, BaseERC721A, OwnableRoles { + uint248 constant DEFAULT_LEVEL = 0; + + // Roles + uint256 public constant MINTER = _ROLE_0; + uint256 public constant GAME = _ROLE_1; + + /// @notice Tokens gameplay metadata, see `StickerMetadata` + mapping(uint256 => StickerMetadata) _metadata; + + constructor(address admin, address _receiver, VRFConfig memory _vrf) + BaseERC721A( + admin, + "Pooky Stickers", + "STK", + "https://metadata.pooky.gg/stickers/", + "https://metadata.pooky.gg/contracts/Stickers.json", + _vrf, + _receiver, + 500 // 5% royalties by default + ) + { } + + /// @notice Get the StickerMetadata of the token `tokenId`. + /// @dev Requirements: + /// - Sticker `tokenId` should exist (minted and not burned). + function metadata(uint256 tokenId) + external + view + onlyExists(tokenId) + returns (StickerMetadata memory) + { + return _metadata[tokenId]; + } + + /// @notice Change the level of a Sticker token. + /// @dev Requirements: + /// - sender must have the `GAME` role or be the owner. + /// - Sticker `tokenId` should exist (minted and not burned). + function setLevel(uint256 tokenId, uint248 newLevel) + external + onlyExists(tokenId) + onlyRolesOrOwner(GAME) + { + _metadata[tokenId].level = newLevel; + emit LevelChanged(tokenId, newLevel); + } + + /// @notice Mint a new Sticker token with a given rarity. + /// Level and seed are set to zero, entropy is requested to the VRF coordinator. + /// @dev Requirements: + /// - sender must have the `MINTER` role or be the owner. + function mint(address recipient, StickerRarity[] memory rarities) + external + onlyRolesOrOwner(MINTER) + { + uint256 quantity = rarities.length; + uint256 start = _nextTokenId(); + + _mint(recipient, quantity); + + for (uint256 i = 0; i < quantity;) { + _metadata[start + i] = StickerMetadata( + DEFAULT_LEVEL, // Stickers are level 0 by default + rarities[i] + ); + + unchecked { + i++; + } + } + } + + // ----- ERC165 ----- + /// @notice IERC165 declaration. + /// @dev Supports the following `interfaceId`s: + /// - IERC165: 0x01ffc9a7 + /// - IERC721: 0x80ac58cd + /// - IERC721Metadata: 0x5b5e139f + /// - IERC2981: 0x2a55205a + function supportsInterface(bytes4 interfaceId) + public + view + virtual + override(BaseERC721A, IBaseERC721A) + returns (bool) + { + return super.supportsInterface(interfaceId); + } +} diff --git a/flattened/StickersAscension.sol b/flattened/StickersAscension.sol new file mode 100644 index 00000000..a136fad5 --- /dev/null +++ b/flattened/StickersAscension.sol @@ -0,0 +1,2470 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0 ^0.8.17 ^0.8.21 ^0.8.22 ^0.8.4; + +// lib/ERC721A/contracts\IERC721A.sol + +// ERC721A Contracts v4.2.3 +// Creator: Chiru Labs + + + +/** + * @dev Interface of ERC721A. + */ +interface IERC721A { + /** + * The caller must own the token or be an approved operator. + */ + error ApprovalCallerNotOwnerNorApproved(); + + /** + * The token does not exist. + */ + error ApprovalQueryForNonexistentToken(); + + /** + * Cannot query the balance for the zero address. + */ + error BalanceQueryForZeroAddress(); + + /** + * Cannot mint to the zero address. + */ + error MintToZeroAddress(); + + /** + * The quantity of tokens minted must be more than zero. + */ + error MintZeroQuantity(); + + /** + * The token does not exist. + */ + error OwnerQueryForNonexistentToken(); + + /** + * The caller must own the token or be an approved operator. + */ + error TransferCallerNotOwnerNorApproved(); + + /** + * The token must be owned by `from`. + */ + error TransferFromIncorrectOwner(); + + /** + * Cannot safely transfer to a contract that does not implement the + * ERC721Receiver interface. + */ + error TransferToNonERC721ReceiverImplementer(); + + /** + * Cannot transfer to the zero address. + */ + error TransferToZeroAddress(); + + /** + * The token does not exist. + */ + error URIQueryForNonexistentToken(); + + /** + * The `quantity` minted with ERC2309 exceeds the safety limit. + */ + error MintERC2309QuantityExceedsLimit(); + + /** + * The `extraData` cannot be set on an unintialized ownership slot. + */ + error OwnershipNotInitializedForExtraData(); + + // ============================================================= + // STRUCTS + // ============================================================= + + struct TokenOwnership { + // The address of the owner. + address addr; + // Stores the start time of ownership with minimal overhead for tokenomics. + uint64 startTimestamp; + // Whether the token has been burned. + bool burned; + // Arbitrary data similar to `startTimestamp` that can be set via {_extraData}. + uint24 extraData; + } + + // ============================================================= + // TOKEN COUNTERS + // ============================================================= + + /** + * @dev Returns the total number of tokens in existence. + * Burned tokens will reduce the count. + * To get the total number of tokens minted, please see {_totalMinted}. + */ + function totalSupply() external view returns (uint256); + + // ============================================================= + // 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 30000 gas. + */ + function supportsInterface(bytes4 interfaceId) external view returns (bool); + + // ============================================================= + // IERC721 + // ============================================================= + + /** + * @dev Emitted when `tokenId` token is transferred from `from` to `to`. + */ + event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); + + /** + * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token. + */ + event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); + + /** + * @dev Emitted when `owner` enables or disables + * (`approved`) `operator` to manage all of its assets. + */ + event ApprovalForAll(address indexed owner, address indexed operator, bool approved); + + /** + * @dev Returns the number of tokens in `owner`'s account. + */ + function balanceOf(address owner) external view returns (uint256 balance); + + /** + * @dev Returns the owner of the `tokenId` token. + * + * Requirements: + * + * - `tokenId` must exist. + */ + function ownerOf(uint256 tokenId) external view returns (address owner); + + /** + * @dev Safely transfers `tokenId` token from `from` to `to`, + * checking first that contract recipients are aware of the ERC721 protocol + * to prevent tokens from being forever locked. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must exist and be owned by `from`. + * - If the caller is not `from`, it must be have been allowed to move + * this token by either {approve} or {setApprovalForAll}. + * - If `to` refers to a smart contract, it must implement + * {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. + * + * Emits a {Transfer} event. + */ + function safeTransferFrom( + address from, + address to, + uint256 tokenId, + bytes calldata data + ) external payable; + + /** + * @dev Equivalent to `safeTransferFrom(from, to, tokenId, '')`. + */ + function safeTransferFrom( + address from, + address to, + uint256 tokenId + ) external payable; + + /** + * @dev Transfers `tokenId` from `from` to `to`. + * + * WARNING: Usage of this method is discouraged, use {safeTransferFrom} + * whenever possible. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must be owned by `from`. + * - If the caller is not `from`, it must be approved to move this token + * by either {approve} or {setApprovalForAll}. + * + * Emits a {Transfer} event. + */ + function transferFrom( + address from, + address to, + uint256 tokenId + ) external payable; + + /** + * @dev Gives permission to `to` to transfer `tokenId` token to another account. + * The approval is cleared when the token is transferred. + * + * Only a single account can be approved at a time, so approving the + * zero address clears previous approvals. + * + * Requirements: + * + * - The caller must own the token or be an approved operator. + * - `tokenId` must exist. + * + * Emits an {Approval} event. + */ + function approve(address to, uint256 tokenId) external payable; + + /** + * @dev Approve or remove `operator` as an operator for the caller. + * Operators can call {transferFrom} or {safeTransferFrom} + * for any token owned by the caller. + * + * Requirements: + * + * - The `operator` cannot be the caller. + * + * Emits an {ApprovalForAll} event. + */ + function setApprovalForAll(address operator, bool _approved) external; + + /** + * @dev Returns the account approved for `tokenId` token. + * + * Requirements: + * + * - `tokenId` must exist. + */ + function getApproved(uint256 tokenId) external view returns (address operator); + + /** + * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`. + * + * See {setApprovalForAll}. + */ + function isApprovedForAll(address owner, address operator) external view returns (bool); + + // ============================================================= + // IERC721Metadata + // ============================================================= + + /** + * @dev Returns the token collection name. + */ + function name() external view returns (string memory); + + /** + * @dev Returns the token collection symbol. + */ + function symbol() external view returns (string memory); + + /** + * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token. + */ + function tokenURI(uint256 tokenId) external view returns (string memory); + + // ============================================================= + // IERC2309 + // ============================================================= + + /** + * @dev Emitted when tokens in `fromTokenId` to `toTokenId` + * (inclusive) is transferred from `from` to `to`, as defined in the + * [ERC2309](https://eips.ethereum.org/EIPS/eip-2309) standard. + * + * See {_mintERC2309} for more details. + */ + event ConsecutiveTransfer(uint256 indexed fromTokenId, uint256 toTokenId, address indexed from, address indexed to); +} + +// lib/openzeppelin-contracts/contracts\access/IAccessControl.sol + +// OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol) + + + +/** + * @dev External interface of AccessControl declared to support ERC165 detection. + */ +interface IAccessControl { + /** + * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` + * + * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite + * {RoleAdminChanged} not being emitted signaling this. + * + * _Available since v3.1._ + */ + event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole); + + /** + * @dev Emitted when `account` is granted `role`. + * + * `sender` is the account that originated the contract call, an admin role + * bearer except when using {AccessControl-_setupRole}. + */ + event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender); + + /** + * @dev Emitted when `account` is revoked `role`. + * + * `sender` is the account that originated the contract call: + * - if using `revokeRole`, it is the admin role bearer + * - if using `renounceRole`, it is the role bearer (i.e. `account`) + */ + event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender); + + /** + * @dev Returns `true` if `account` has been granted `role`. + */ + function hasRole(bytes32 role, address account) external view returns (bool); + + /** + * @dev Returns the admin role that controls `role`. See {grantRole} and + * {revokeRole}. + * + * To change a role's admin, use {AccessControl-_setRoleAdmin}. + */ + function getRoleAdmin(bytes32 role) external view returns (bytes32); + + /** + * @dev Grants `role` to `account`. + * + * If `account` had not been already granted `role`, emits a {RoleGranted} + * event. + * + * Requirements: + * + * - the caller must have ``role``'s admin role. + */ + function grantRole(bytes32 role, address account) external; + + /** + * @dev Revokes `role` from `account`. + * + * If `account` had been granted `role`, emits a {RoleRevoked} event. + * + * Requirements: + * + * - the caller must have ``role``'s admin role. + */ + function revokeRole(bytes32 role, address account) external; + + /** + * @dev Revokes `role` from the calling account. + * + * Roles are often managed via {grantRole} and {revokeRole}: this function's + * purpose is to provide a mechanism for accounts to lose their privileges + * if they are compromised (such as when a trusted device is misplaced). + * + * If the calling account had been granted `role`, emits a {RoleRevoked} + * event. + * + * Requirements: + * + * - the caller must be `account`. + */ + function renounceRole(bytes32 role, address account) external; +} + +// lib/openzeppelin-contracts/contracts\token/ERC20/IERC20.sol + +// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol) + + + +/** + * @dev Interface of the ERC20 standard as defined in the EIP. + */ +interface IERC20 { + /** + * @dev Emitted when `value` tokens are moved from one account (`from`) to + * another (`to`). + * + * Note that `value` may be zero. + */ + event Transfer(address indexed from, address indexed to, uint256 value); + + /** + * @dev Emitted when the allowance of a `spender` for an `owner` is set by + * a call to {approve}. `value` is the new allowance. + */ + event Approval(address indexed owner, address indexed spender, uint256 value); + + /** + * @dev Returns the amount of tokens in existence. + */ + function totalSupply() external view returns (uint256); + + /** + * @dev Returns the amount of tokens owned by `account`. + */ + function balanceOf(address account) external view returns (uint256); + + /** + * @dev Moves `amount` tokens from the caller's account to `to`. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * Emits a {Transfer} event. + */ + function transfer(address to, uint256 amount) external returns (bool); + + /** + * @dev Returns the remaining number of tokens that `spender` will be + * allowed to spend on behalf of `owner` through {transferFrom}. This is + * zero by default. + * + * This value changes when {approve} or {transferFrom} are called. + */ + function allowance(address owner, address spender) external view returns (uint256); + + /** + * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * IMPORTANT: Beware that changing an allowance with this method brings the risk + * that someone may use both the old and the new allowance by unfortunate + * transaction ordering. One possible solution to mitigate this race + * condition is to first reduce the spender's allowance to 0 and set the + * desired value afterwards: + * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 + * + * Emits an {Approval} event. + */ + function approve(address spender, uint256 amount) external returns (bool); + + /** + * @dev Moves `amount` tokens from `from` to `to` using the + * allowance mechanism. `amount` is then deducted from the caller's + * allowance. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * Emits a {Transfer} event. + */ + function transferFrom(address from, address to, uint256 amount) external returns (bool); +} + +// lib/openzeppelin-contracts/contracts/utils/introspection/IERC165.sol + +// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol) + + + +/** + * @dev Interface of the ERC165 standard, as defined in the + * https://eips.ethereum.org/EIPS/eip-165[EIP]. + * + * Implementers can declare support of contract interfaces, which can then be + * queried by others ({ERC165Checker}). + * + * For an implementation, see {ERC165}. + */ +interface IERC165 { + /** + * @dev Returns true if this contract implements the interface defined by + * `interfaceId`. See the corresponding + * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] + * to learn more about how these ids are created. + * + * This function call must use less than 30 000 gas. + */ + function supportsInterface(bytes4 interfaceId) external view returns (bool); +} + +// lib/solady/src/auth/Ownable.sol + + + +/// @notice Simple single owner authorization mixin. +/// @author Solady (https://github.com/vectorized/solady/blob/main/src/auth/Ownable.sol) +/// @dev While the ownable portion follows +/// [EIP-173](https://eips.ethereum.org/EIPS/eip-173) for compatibility, +/// the nomenclature for the 2-step ownership handover may be unique to this codebase. +abstract contract Ownable { + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* CUSTOM ERRORS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev The caller is not authorized to call the function. + error Unauthorized(); + + /// @dev The `newOwner` cannot be the zero address. + error NewOwnerIsZeroAddress(); + + /// @dev The `pendingOwner` does not have a valid handover request. + error NoHandoverRequest(); + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* EVENTS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev The ownership is transferred from `oldOwner` to `newOwner`. + /// This event is intentionally kept the same as OpenZeppelin's Ownable to be + /// compatible with indexers and [EIP-173](https://eips.ethereum.org/EIPS/eip-173), + /// despite it not being as lightweight as a single argument event. + event OwnershipTransferred(address indexed oldOwner, address indexed newOwner); + + /// @dev An ownership handover to `pendingOwner` has been requested. + event OwnershipHandoverRequested(address indexed pendingOwner); + + /// @dev The ownership handover to `pendingOwner` has been canceled. + event OwnershipHandoverCanceled(address indexed pendingOwner); + + /// @dev `keccak256(bytes("OwnershipTransferred(address,address)"))`. + uint256 private constant _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE = + 0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0; + + /// @dev `keccak256(bytes("OwnershipHandoverRequested(address)"))`. + uint256 private constant _OWNERSHIP_HANDOVER_REQUESTED_EVENT_SIGNATURE = + 0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d; + + /// @dev `keccak256(bytes("OwnershipHandoverCanceled(address)"))`. + uint256 private constant _OWNERSHIP_HANDOVER_CANCELED_EVENT_SIGNATURE = + 0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92; + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* STORAGE */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev The owner slot is given by: `not(_OWNER_SLOT_NOT)`. + /// It is intentionally chosen to be a high value + /// to avoid collision with lower slots. + /// The choice of manual storage layout is to enable compatibility + /// with both regular and upgradeable contracts. + uint256 private constant _OWNER_SLOT_NOT = 0x8b78c6d8; + + /// The ownership handover slot of `newOwner` is given by: + /// ``` + /// mstore(0x00, or(shl(96, user), _HANDOVER_SLOT_SEED)) + /// let handoverSlot := keccak256(0x00, 0x20) + /// ``` + /// It stores the expiry timestamp of the two-step ownership handover. + uint256 private constant _HANDOVER_SLOT_SEED = 0x389a75e1; + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* INTERNAL FUNCTIONS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev Initializes the owner directly without authorization guard. + /// This function must be called upon initialization, + /// regardless of whether the contract is upgradeable or not. + /// This is to enable generalization to both regular and upgradeable contracts, + /// and to save gas in case the initial owner is not the caller. + /// For performance reasons, this function will not check if there + /// is an existing owner. + function _initializeOwner(address newOwner) internal virtual { + /// @solidity memory-safe-assembly + assembly { + // Clean the upper 96 bits. + newOwner := shr(96, shl(96, newOwner)) + // Store the new value. + sstore(not(_OWNER_SLOT_NOT), newOwner) + // Emit the {OwnershipTransferred} event. + log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, 0, newOwner) + } + } + + /// @dev Sets the owner directly without authorization guard. + function _setOwner(address newOwner) internal virtual { + /// @solidity memory-safe-assembly + assembly { + let ownerSlot := not(_OWNER_SLOT_NOT) + // Clean the upper 96 bits. + newOwner := shr(96, shl(96, newOwner)) + // Emit the {OwnershipTransferred} event. + log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, sload(ownerSlot), newOwner) + // Store the new value. + sstore(ownerSlot, newOwner) + } + } + + /// @dev Throws if the sender is not the owner. + function _checkOwner() internal view virtual { + /// @solidity memory-safe-assembly + assembly { + // If the caller is not the stored owner, revert. + if iszero(eq(caller(), sload(not(_OWNER_SLOT_NOT)))) { + mstore(0x00, 0x82b42900) // `Unauthorized()`. + revert(0x1c, 0x04) + } + } + } + + /// @dev Returns how long a two-step ownership handover is valid for in seconds. + /// Override to return a different value if needed. + /// Made internal to conserve bytecode. Wrap it in a public function if needed. + function _ownershipHandoverValidFor() internal view virtual returns (uint64) { + return 48 * 3600; + } + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* PUBLIC UPDATE FUNCTIONS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev Allows the owner to transfer the ownership to `newOwner`. + function transferOwnership(address newOwner) public payable virtual onlyOwner { + /// @solidity memory-safe-assembly + assembly { + if iszero(shl(96, newOwner)) { + mstore(0x00, 0x7448fbae) // `NewOwnerIsZeroAddress()`. + revert(0x1c, 0x04) + } + } + _setOwner(newOwner); + } + + /// @dev Allows the owner to renounce their ownership. + function renounceOwnership() public payable virtual onlyOwner { + _setOwner(address(0)); + } + + /// @dev Request a two-step ownership handover to the caller. + /// The request will automatically expire in 48 hours (172800 seconds) by default. + function requestOwnershipHandover() public payable virtual { + unchecked { + uint256 expires = block.timestamp + _ownershipHandoverValidFor(); + /// @solidity memory-safe-assembly + assembly { + // Compute and set the handover slot to `expires`. + mstore(0x0c, _HANDOVER_SLOT_SEED) + mstore(0x00, caller()) + sstore(keccak256(0x0c, 0x20), expires) + // Emit the {OwnershipHandoverRequested} event. + log2(0, 0, _OWNERSHIP_HANDOVER_REQUESTED_EVENT_SIGNATURE, caller()) + } + } + } + + /// @dev Cancels the two-step ownership handover to the caller, if any. + function cancelOwnershipHandover() public payable virtual { + /// @solidity memory-safe-assembly + assembly { + // Compute and set the handover slot to 0. + mstore(0x0c, _HANDOVER_SLOT_SEED) + mstore(0x00, caller()) + sstore(keccak256(0x0c, 0x20), 0) + // Emit the {OwnershipHandoverCanceled} event. + log2(0, 0, _OWNERSHIP_HANDOVER_CANCELED_EVENT_SIGNATURE, caller()) + } + } + + /// @dev Allows the owner to complete the two-step ownership handover to `pendingOwner`. + /// Reverts if there is no existing ownership handover requested by `pendingOwner`. + function completeOwnershipHandover(address pendingOwner) public payable virtual onlyOwner { + /// @solidity memory-safe-assembly + assembly { + // Compute and set the handover slot to 0. + mstore(0x0c, _HANDOVER_SLOT_SEED) + mstore(0x00, pendingOwner) + let handoverSlot := keccak256(0x0c, 0x20) + // If the handover does not exist, or has expired. + if gt(timestamp(), sload(handoverSlot)) { + mstore(0x00, 0x6f5e8818) // `NoHandoverRequest()`. + revert(0x1c, 0x04) + } + // Set the handover slot to 0. + sstore(handoverSlot, 0) + } + _setOwner(pendingOwner); + } + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* PUBLIC READ FUNCTIONS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev Returns the owner of the contract. + function owner() public view virtual returns (address result) { + /// @solidity memory-safe-assembly + assembly { + result := sload(not(_OWNER_SLOT_NOT)) + } + } + + /// @dev Returns the expiry timestamp for the two-step ownership handover to `pendingOwner`. + function ownershipHandoverExpiresAt(address pendingOwner) + public + view + virtual + returns (uint256 result) + { + /// @solidity memory-safe-assembly + assembly { + // Compute the handover slot. + mstore(0x0c, _HANDOVER_SLOT_SEED) + mstore(0x00, pendingOwner) + // Load the handover slot. + result := sload(keccak256(0x0c, 0x20)) + } + } + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* MODIFIERS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev Marks a function as only callable by the owner. + modifier onlyOwner() virtual { + _checkOwner(); + _; + } +} + +// lib/solady/src\utils/ECDSA.sol + + + +/// @notice Gas optimized ECDSA wrapper. +/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/ECDSA.sol) +/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/ECDSA.sol) +/// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/cryptography/ECDSA.sol) +library ECDSA { + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* CUSTOM ERRORS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev The signature is invalid. + error InvalidSignature(); + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* CONSTANTS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev The number which `s` must be less than in order for + /// the signature to be non-malleable. + bytes32 private constant _MALLEABILITY_THRESHOLD_PLUS_ONE = + 0x7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a1; + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* RECOVERY OPERATIONS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + // Note: as of Solady version 0.0.68, these functions will + // revert upon recovery failure for more safety by default. + + /// @dev Recovers the signer's address from a message digest `hash`, + /// and the `signature`. + /// + /// This function does NOT accept EIP-2098 short form signatures. + /// Use `recover(bytes32 hash, bytes32 r, bytes32 vs)` for EIP-2098 + /// short form signatures instead. + function recover(bytes32 hash, bytes memory signature) internal view returns (address result) { + /// @solidity memory-safe-assembly + assembly { + let m := mload(0x40) // Cache the free memory pointer. + mstore(0x00, hash) + mstore(0x20, byte(0, mload(add(signature, 0x60)))) // `v`. + mstore(0x40, mload(add(signature, 0x20))) // `r`. + mstore(0x60, mload(add(signature, 0x40))) // `s`. + pop( + staticcall( + gas(), // Amount of gas left for the transaction. + and( + // If the signature is exactly 65 bytes in length. + eq(mload(signature), 65), + // If `s` in lower half order, such that the signature is not malleable. + lt(mload(0x60), _MALLEABILITY_THRESHOLD_PLUS_ONE) + ), // Address of `ecrecover`. + 0x00, // Start of input. + 0x80, // Size of input. + 0x00, // Start of output. + 0x20 // Size of output. + ) + ) + result := mload(0x00) + // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise. + if iszero(returndatasize()) { + mstore(0x00, 0x8baa579f) // `InvalidSignature()`. + revert(0x1c, 0x04) + } + mstore(0x60, 0) // Restore the zero slot. + mstore(0x40, m) // Restore the free memory pointer. + } + } + + /// @dev Recovers the signer's address from a message digest `hash`, + /// and the `signature`. + /// + /// This function does NOT accept EIP-2098 short form signatures. + /// Use `recover(bytes32 hash, bytes32 r, bytes32 vs)` for EIP-2098 + /// short form signatures instead. + function recoverCalldata(bytes32 hash, bytes calldata signature) + internal + view + returns (address result) + { + /// @solidity memory-safe-assembly + assembly { + let m := mload(0x40) // Cache the free memory pointer. + mstore(0x00, hash) + mstore(0x20, byte(0, calldataload(add(signature.offset, 0x40)))) // `v`. + calldatacopy(0x40, signature.offset, 0x40) // Copy `r` and `s`. + pop( + staticcall( + gas(), // Amount of gas left for the transaction. + and( + // If the signature is exactly 65 bytes in length. + eq(signature.length, 65), + // If `s` in lower half order, such that the signature is not malleable. + lt(mload(0x60), _MALLEABILITY_THRESHOLD_PLUS_ONE) + ), // Address of `ecrecover`. + 0x00, // Start of input. + 0x80, // Size of input. + 0x00, // Start of output. + 0x20 // Size of output. + ) + ) + result := mload(0x00) + // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise. + if iszero(returndatasize()) { + mstore(0x00, 0x8baa579f) // `InvalidSignature()`. + revert(0x1c, 0x04) + } + mstore(0x60, 0) // Restore the zero slot. + mstore(0x40, m) // Restore the free memory pointer. + } + } + + /// @dev Recovers the signer's address from a message digest `hash`, + /// and the EIP-2098 short form signature defined by `r` and `vs`. + /// + /// This function only accepts EIP-2098 short form signatures. + /// See: https://eips.ethereum.org/EIPS/eip-2098 + function recover(bytes32 hash, bytes32 r, bytes32 vs) internal view returns (address result) { + /// @solidity memory-safe-assembly + assembly { + let m := mload(0x40) // Cache the free memory pointer. + mstore(0x00, hash) + mstore(0x20, add(shr(255, vs), 27)) // `v`. + mstore(0x40, r) + mstore(0x60, shr(1, shl(1, vs))) // `s`. + pop( + staticcall( + gas(), // Amount of gas left for the transaction. + // If `s` in lower half order, such that the signature is not malleable. + lt(mload(0x60), _MALLEABILITY_THRESHOLD_PLUS_ONE), // Address of `ecrecover`. + 0x00, // Start of input. + 0x80, // Size of input. + 0x00, // Start of output. + 0x20 // Size of output. + ) + ) + result := mload(0x00) + // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise. + if iszero(returndatasize()) { + mstore(0x00, 0x8baa579f) // `InvalidSignature()`. + revert(0x1c, 0x04) + } + mstore(0x60, 0) // Restore the zero slot. + mstore(0x40, m) // Restore the free memory pointer. + } + } + + /// @dev Recovers the signer's address from a message digest `hash`, + /// and the signature defined by `v`, `r`, `s`. + function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) + internal + view + returns (address result) + { + /// @solidity memory-safe-assembly + assembly { + let m := mload(0x40) // Cache the free memory pointer. + mstore(0x00, hash) + mstore(0x20, and(v, 0xff)) + mstore(0x40, r) + mstore(0x60, s) + pop( + staticcall( + gas(), // Amount of gas left for the transaction. + // If `s` in lower half order, such that the signature is not malleable. + lt(s, _MALLEABILITY_THRESHOLD_PLUS_ONE), // Address of `ecrecover`. + 0x00, // Start of input. + 0x80, // Size of input. + 0x00, // Start of output. + 0x20 // Size of output. + ) + ) + result := mload(0x00) + // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise. + if iszero(returndatasize()) { + mstore(0x00, 0x8baa579f) // `InvalidSignature()`. + revert(0x1c, 0x04) + } + mstore(0x60, 0) // Restore the zero slot. + mstore(0x40, m) // Restore the free memory pointer. + } + } + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* TRY-RECOVER OPERATIONS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + // WARNING! + // These functions will NOT revert upon recovery failure. + // Instead, they will return the zero address upon recovery failure. + // It is critical that the returned address is NEVER compared against + // a zero address (e.g. an uninitialized address variable). + + /// @dev Recovers the signer's address from a message digest `hash`, + /// and the `signature`. + /// + /// This function does NOT accept EIP-2098 short form signatures. + /// Use `recover(bytes32 hash, bytes32 r, bytes32 vs)` for EIP-2098 + /// short form signatures instead. + function tryRecover(bytes32 hash, bytes memory signature) + internal + view + returns (address result) + { + /// @solidity memory-safe-assembly + assembly { + let m := mload(0x40) // Cache the free memory pointer. + mstore(0x00, hash) + mstore(0x20, byte(0, mload(add(signature, 0x60)))) // `v`. + mstore(0x40, mload(add(signature, 0x20))) // `r`. + mstore(0x60, mload(add(signature, 0x40))) // `s`. + pop( + staticcall( + gas(), // Amount of gas left for the transaction. + and( + // If the signature is exactly 65 bytes in length. + eq(mload(signature), 65), + // If `s` in lower half order, such that the signature is not malleable. + lt(mload(0x60), _MALLEABILITY_THRESHOLD_PLUS_ONE) + ), // Address of `ecrecover`. + 0x00, // Start of input. + 0x80, // Size of input. + 0x40, // Start of output. + 0x20 // Size of output. + ) + ) + mstore(0x60, 0) // Restore the zero slot. + // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise. + result := mload(xor(0x60, returndatasize())) + mstore(0x40, m) // Restore the free memory pointer. + } + } + + /// @dev Recovers the signer's address from a message digest `hash`, + /// and the `signature`. + /// + /// This function does NOT accept EIP-2098 short form signatures. + /// Use `recover(bytes32 hash, bytes32 r, bytes32 vs)` for EIP-2098 + /// short form signatures instead. + function tryRecoverCalldata(bytes32 hash, bytes calldata signature) + internal + view + returns (address result) + { + /// @solidity memory-safe-assembly + assembly { + let m := mload(0x40) // Cache the free memory pointer. + mstore(0x00, hash) + mstore(0x20, byte(0, calldataload(add(signature.offset, 0x40)))) // `v`. + calldatacopy(0x40, signature.offset, 0x40) // Copy `r` and `s`. + pop( + staticcall( + gas(), // Amount of gas left for the transaction. + and( + // If the signature is exactly 65 bytes in length. + eq(signature.length, 65), + // If `s` in lower half order, such that the signature is not malleable. + lt(mload(0x60), _MALLEABILITY_THRESHOLD_PLUS_ONE) + ), // Address of `ecrecover`. + 0x00, // Start of input. + 0x80, // Size of input. + 0x40, // Start of output. + 0x20 // Size of output. + ) + ) + mstore(0x60, 0) // Restore the zero slot. + // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise. + result := mload(xor(0x60, returndatasize())) + mstore(0x40, m) // Restore the free memory pointer. + } + } + + /// @dev Recovers the signer's address from a message digest `hash`, + /// and the EIP-2098 short form signature defined by `r` and `vs`. + /// + /// This function only accepts EIP-2098 short form signatures. + /// See: https://eips.ethereum.org/EIPS/eip-2098 + function tryRecover(bytes32 hash, bytes32 r, bytes32 vs) + internal + view + returns (address result) + { + /// @solidity memory-safe-assembly + assembly { + let m := mload(0x40) // Cache the free memory pointer. + mstore(0x00, hash) + mstore(0x20, add(shr(255, vs), 27)) // `v`. + mstore(0x40, r) + mstore(0x60, shr(1, shl(1, vs))) // `s`. + pop( + staticcall( + gas(), // Amount of gas left for the transaction. + // If `s` in lower half order, such that the signature is not malleable. + lt(mload(0x60), _MALLEABILITY_THRESHOLD_PLUS_ONE), // Address of `ecrecover`. + 0x00, // Start of input. + 0x80, // Size of input. + 0x40, // Start of output. + 0x20 // Size of output. + ) + ) + mstore(0x60, 0) // Restore the zero slot. + // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise. + result := mload(xor(0x60, returndatasize())) + mstore(0x40, m) // Restore the free memory pointer. + } + } + + /// @dev Recovers the signer's address from a message digest `hash`, + /// and the signature defined by `v`, `r`, `s`. + function tryRecover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) + internal + view + returns (address result) + { + /// @solidity memory-safe-assembly + assembly { + let m := mload(0x40) // Cache the free memory pointer. + mstore(0x00, hash) + mstore(0x20, and(v, 0xff)) + mstore(0x40, r) + mstore(0x60, s) + pop( + staticcall( + gas(), // Amount of gas left for the transaction. + // If `s` in lower half order, such that the signature is not malleable. + lt(s, _MALLEABILITY_THRESHOLD_PLUS_ONE), // Address of `ecrecover`. + 0x00, // Start of input. + 0x80, // Size of input. + 0x40, // Start of output. + 0x20 // Size of output. + ) + ) + mstore(0x60, 0) // Restore the zero slot. + // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise. + result := mload(xor(0x60, returndatasize())) + mstore(0x40, m) // Restore the free memory pointer. + } + } + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* HASHING OPERATIONS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev Returns an Ethereum Signed Message, created from a `hash`. + /// This produces a hash corresponding to the one signed with the + /// [`eth_sign`](https://eth.wiki/json-rpc/API#eth_sign) + /// JSON-RPC method as part of EIP-191. + function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32 result) { + /// @solidity memory-safe-assembly + assembly { + mstore(0x20, hash) // Store into scratch space for keccak256. + mstore(0x00, "\x00\x00\x00\x00\x19Ethereum Signed Message:\n32") // 28 bytes. + result := keccak256(0x04, 0x3c) // `32 * 2 - (32 - 28) = 60 = 0x3c`. + } + } + + /// @dev Returns an Ethereum Signed Message, created from `s`. + /// This produces a hash corresponding to the one signed with the + /// [`eth_sign`](https://eth.wiki/json-rpc/API#eth_sign) + /// JSON-RPC method as part of EIP-191. + /// Note: Supports lengths of `s` up to 999999 bytes. + function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32 result) { + /// @solidity memory-safe-assembly + assembly { + let sLength := mload(s) + let o := 0x20 + mstore(o, "\x19Ethereum Signed Message:\n") // 26 bytes, zero-right-padded. + mstore(0x00, 0x00) + // Convert the `s.length` to ASCII decimal representation: `base10(s.length)`. + for { let temp := sLength } 1 {} { + o := sub(o, 1) + mstore8(o, add(48, mod(temp, 10))) + temp := div(temp, 10) + if iszero(temp) { break } + } + let n := sub(0x3a, o) // Header length: `26 + 32 - o`. + // Throw an out-of-offset error (consumes all gas) if the header exceeds 32 bytes. + returndatacopy(returndatasize(), returndatasize(), gt(n, 0x20)) + mstore(s, or(mload(0x00), mload(n))) // Temporarily store the header. + result := keccak256(add(s, sub(0x20, n)), add(n, sLength)) + mstore(s, sLength) // Restore the length. + } + } + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* EMPTY CALLDATA HELPERS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev Returns an empty calldata bytes. + function emptySignature() internal pure returns (bytes calldata signature) { + /// @solidity memory-safe-assembly + assembly { + signature.length := 0 + } + } +} + +// src\common/ITreasury.sol + + + +/// @title ITreasury +/// @author Mathieu Bour for Pooky Labs Ltd. +interface ITreasury { + /// Thrown when the msg.value of the mint function does not cover the mint cost. + error InsufficientValue(uint256 expected, uint256 actual); + /// Thrown when the native transfer has failed. + error TransferFailed(address recipient, uint256 amount); + + /// Change the native currency destination address. + /// @param _treasury The new treasury address. + function changeTreasury(address _treasury) external; +} + +// lib/ERC721A/contracts\extensions/IERC721ABurnable.sol + +// ERC721A Contracts v4.2.3 +// Creator: Chiru Labs + + + + + +/** + * @dev Interface of ERC721ABurnable. + */ +interface IERC721ABurnable is IERC721A { + /** + * @dev Burns `tokenId`. See {ERC721A-_burn}. + * + * Requirements: + * + * - The caller must own `tokenId` or be an approved operator. + */ + function burn(uint256 tokenId) external; +} + +// lib/ERC721A/contracts\extensions/IERC721AQueryable.sol + +// ERC721A Contracts v4.2.3 +// Creator: Chiru Labs + + + + + +/** + * @dev Interface of ERC721AQueryable. + */ +interface IERC721AQueryable is IERC721A { + /** + * Invalid query range (`start` >= `stop`). + */ + error InvalidQueryRange(); + + /** + * @dev Returns the `TokenOwnership` struct at `tokenId` without reverting. + * + * If the `tokenId` is out of bounds: + * + * - `addr = address(0)` + * - `startTimestamp = 0` + * - `burned = false` + * - `extraData = 0` + * + * If the `tokenId` is burned: + * + * - `addr =
` + * - `startTimestamp = ` + * - `burned = true` + * - `extraData = ` + * + * Otherwise: + * + * - `addr =
` + * - `startTimestamp = ` + * - `burned = false` + * - `extraData = ` + */ + function explicitOwnershipOf(uint256 tokenId) external view returns (TokenOwnership memory); + + /** + * @dev Returns an array of `TokenOwnership` structs at `tokenIds` in order. + * See {ERC721AQueryable-explicitOwnershipOf} + */ + function explicitOwnershipsOf(uint256[] memory tokenIds) external view returns (TokenOwnership[] memory); + + /** + * @dev Returns an array of token IDs owned by `owner`, + * in the range [`start`, `stop`) + * (i.e. `start <= tokenId < stop`). + * + * This function allows for tokens to be queried if the collection + * grows too big for a single call of {ERC721AQueryable-tokensOfOwner}. + * + * Requirements: + * + * - `start < stop` + */ + function tokensOfOwnerIn( + address owner, + uint256 start, + uint256 stop + ) external view returns (uint256[] memory); + + /** + * @dev Returns an array of token IDs owned by `owner`. + * + * This function scans the ownership mapping and is O(`totalSupply`) in complexity. + * It is meant to be called off-chain. + * + * See {ERC721AQueryable-tokensOfOwnerIn} for splitting the scan into + * multiple smaller scans if the collection is large enough to cause + * an out-of-gas error (10K collections should be fine). + */ + function tokensOfOwner(address owner) external view returns (uint256[] memory); +} + +// lib/openzeppelin-contracts/contracts\interfaces/IERC165.sol + +// OpenZeppelin Contracts v4.4.1 (interfaces/IERC165.sol) + + + + + +// lib/openzeppelin-contracts/contracts\interfaces/IERC2981.sol + +// OpenZeppelin Contracts (last updated v4.9.0) (interfaces/IERC2981.sol) + + + + + +/** + * @dev Interface for the NFT Royalty Standard. + * + * A standardized way to retrieve royalty payment information for non-fungible tokens (NFTs) to enable universal + * support for royalty payments across all NFT marketplaces and ecosystem participants. + * + * _Available since v4.5._ + */ +interface IERC2981 is IERC165 { + /** + * @dev Returns how much royalty is owed and to whom, based on a sale price that may be denominated in any unit of + * exchange. The royalty amount is denominated and should be paid in that same unit of exchange. + */ + function royaltyInfo( + uint256 tokenId, + uint256 salePrice + ) external view returns (address receiver, uint256 royaltyAmount); +} + +// lib/openzeppelin-contracts/contracts\token/ERC721/IERC721.sol + +// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC721/IERC721.sol) + + + + + +/** + * @dev Required interface of an ERC721 compliant contract. + */ +interface IERC721 is IERC165 { + /** + * @dev Emitted when `tokenId` token is transferred from `from` to `to`. + */ + event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); + + /** + * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token. + */ + event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); + + /** + * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets. + */ + event ApprovalForAll(address indexed owner, address indexed operator, bool approved); + + /** + * @dev Returns the number of tokens in ``owner``'s account. + */ + function balanceOf(address owner) external view returns (uint256 balance); + + /** + * @dev Returns the owner of the `tokenId` token. + * + * Requirements: + * + * - `tokenId` must exist. + */ + function ownerOf(uint256 tokenId) external view returns (address owner); + + /** + * @dev Safely transfers `tokenId` token from `from` to `to`. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must exist and be owned by `from`. + * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. + * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. + * + * Emits a {Transfer} event. + */ + function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external; + + /** + * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients + * are aware of the ERC721 protocol to prevent tokens from being forever locked. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must exist and be owned by `from`. + * - If the caller is not `from`, it must have been allowed to move this token by either {approve} or {setApprovalForAll}. + * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. + * + * Emits a {Transfer} event. + */ + function safeTransferFrom(address from, address to, uint256 tokenId) external; + + /** + * @dev Transfers `tokenId` token from `from` to `to`. + * + * WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721 + * or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must + * understand this adds an external call which potentially creates a reentrancy vulnerability. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must be owned by `from`. + * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. + * + * Emits a {Transfer} event. + */ + function transferFrom(address from, address to, uint256 tokenId) external; + + /** + * @dev Gives permission to `to` to transfer `tokenId` token to another account. + * The approval is cleared when the token is transferred. + * + * Only a single account can be approved at a time, so approving the zero address clears previous approvals. + * + * Requirements: + * + * - The caller must own the token or be an approved operator. + * - `tokenId` must exist. + * + * Emits an {Approval} event. + */ + function approve(address to, uint256 tokenId) external; + + /** + * @dev Approve or remove `operator` as an operator for the caller. + * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller. + * + * Requirements: + * + * - The `operator` cannot be the caller. + * + * Emits an {ApprovalForAll} event. + */ + function setApprovalForAll(address operator, bool approved) external; + + /** + * @dev Returns the account approved for `tokenId` token. + * + * Requirements: + * + * - `tokenId` must exist. + */ + function getApproved(uint256 tokenId) external view returns (address operator); + + /** + * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`. + * + * See {setApprovalForAll} + */ + function isApprovedForAll(address owner, address operator) external view returns (bool); +} + +// lib/solady/src\auth/OwnableRoles.sol + + + + + +/// @notice Simple single owner and multiroles authorization mixin. +/// @author Solady (https://github.com/vectorized/solady/blob/main/src/auth/Ownable.sol) +/// @dev While the ownable portion follows [EIP-173](https://eips.ethereum.org/EIPS/eip-173) +/// for compatibility, the nomenclature for the 2-step ownership handover and roles +/// may be unique to this codebase. +abstract contract OwnableRoles is Ownable { + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* EVENTS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev The `user`'s roles is updated to `roles`. + /// Each bit of `roles` represents whether the role is set. + event RolesUpdated(address indexed user, uint256 indexed roles); + + /// @dev `keccak256(bytes("RolesUpdated(address,uint256)"))`. + uint256 private constant _ROLES_UPDATED_EVENT_SIGNATURE = + 0x715ad5ce61fc9595c7b415289d59cf203f23a94fa06f04af7e489a0a76e1fe26; + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* STORAGE */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev The role slot of `user` is given by: + /// ``` + /// mstore(0x00, or(shl(96, user), _ROLE_SLOT_SEED)) + /// let roleSlot := keccak256(0x00, 0x20) + /// ``` + /// This automatically ignores the upper bits of the `user` in case + /// they are not clean, as well as keep the `keccak256` under 32-bytes. + /// + /// Note: This is equal to `_OWNER_SLOT_NOT` in for gas efficiency. + uint256 private constant _ROLE_SLOT_SEED = 0x8b78c6d8; + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* INTERNAL FUNCTIONS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev Overwrite the roles directly without authorization guard. + function _setRoles(address user, uint256 roles) internal virtual { + /// @solidity memory-safe-assembly + assembly { + mstore(0x0c, _ROLE_SLOT_SEED) + mstore(0x00, user) + // Store the new value. + sstore(keccak256(0x0c, 0x20), roles) + // Emit the {RolesUpdated} event. + log3(0, 0, _ROLES_UPDATED_EVENT_SIGNATURE, shr(96, mload(0x0c)), roles) + } + } + + /// @dev Updates the roles directly without authorization guard. + /// If `on` is true, each set bit of `roles` will be turned on, + /// otherwise, each set bit of `roles` will be turned off. + function _updateRoles(address user, uint256 roles, bool on) internal virtual { + /// @solidity memory-safe-assembly + assembly { + mstore(0x0c, _ROLE_SLOT_SEED) + mstore(0x00, user) + let roleSlot := keccak256(0x0c, 0x20) + // Load the current value. + let current := sload(roleSlot) + // Compute the updated roles if `on` is true. + let updated := or(current, roles) + // Compute the updated roles if `on` is false. + // Use `and` to compute the intersection of `current` and `roles`, + // `xor` it with `current` to flip the bits in the intersection. + if iszero(on) { updated := xor(current, and(current, roles)) } + // Then, store the new value. + sstore(roleSlot, updated) + // Emit the {RolesUpdated} event. + log3(0, 0, _ROLES_UPDATED_EVENT_SIGNATURE, shr(96, mload(0x0c)), updated) + } + } + + /// @dev Grants the roles directly without authorization guard. + /// Each bit of `roles` represents the role to turn on. + function _grantRoles(address user, uint256 roles) internal virtual { + _updateRoles(user, roles, true); + } + + /// @dev Removes the roles directly without authorization guard. + /// Each bit of `roles` represents the role to turn off. + function _removeRoles(address user, uint256 roles) internal virtual { + _updateRoles(user, roles, false); + } + + /// @dev Throws if the sender does not have any of the `roles`. + function _checkRoles(uint256 roles) internal view virtual { + /// @solidity memory-safe-assembly + assembly { + // Compute the role slot. + mstore(0x0c, _ROLE_SLOT_SEED) + mstore(0x00, caller()) + // Load the stored value, and if the `and` intersection + // of the value and `roles` is zero, revert. + if iszero(and(sload(keccak256(0x0c, 0x20)), roles)) { + mstore(0x00, 0x82b42900) // `Unauthorized()`. + revert(0x1c, 0x04) + } + } + } + + /// @dev Throws if the sender is not the owner, + /// and does not have any of the `roles`. + /// Checks for ownership first, then lazily checks for roles. + function _checkOwnerOrRoles(uint256 roles) internal view virtual { + /// @solidity memory-safe-assembly + assembly { + // If the caller is not the stored owner. + // Note: `_ROLE_SLOT_SEED` is equal to `_OWNER_SLOT_NOT`. + if iszero(eq(caller(), sload(not(_ROLE_SLOT_SEED)))) { + // Compute the role slot. + mstore(0x0c, _ROLE_SLOT_SEED) + mstore(0x00, caller()) + // Load the stored value, and if the `and` intersection + // of the value and `roles` is zero, revert. + if iszero(and(sload(keccak256(0x0c, 0x20)), roles)) { + mstore(0x00, 0x82b42900) // `Unauthorized()`. + revert(0x1c, 0x04) + } + } + } + } + + /// @dev Throws if the sender does not have any of the `roles`, + /// and is not the owner. + /// Checks for roles first, then lazily checks for ownership. + function _checkRolesOrOwner(uint256 roles) internal view virtual { + /// @solidity memory-safe-assembly + assembly { + // Compute the role slot. + mstore(0x0c, _ROLE_SLOT_SEED) + mstore(0x00, caller()) + // Load the stored value, and if the `and` intersection + // of the value and `roles` is zero, revert. + if iszero(and(sload(keccak256(0x0c, 0x20)), roles)) { + // If the caller is not the stored owner. + // Note: `_ROLE_SLOT_SEED` is equal to `_OWNER_SLOT_NOT`. + if iszero(eq(caller(), sload(not(_ROLE_SLOT_SEED)))) { + mstore(0x00, 0x82b42900) // `Unauthorized()`. + revert(0x1c, 0x04) + } + } + } + } + + /// @dev Convenience function to return a `roles` bitmap from an array of `ordinals`. + /// This is meant for frontends like Etherscan, and is therefore not fully optimized. + /// Not recommended to be called on-chain. + /// Made internal to conserve bytecode. Wrap it in a public function if needed. + function _rolesFromOrdinals(uint8[] memory ordinals) internal pure returns (uint256 roles) { + /// @solidity memory-safe-assembly + assembly { + for { let i := shl(5, mload(ordinals)) } i { i := sub(i, 0x20) } { + // We don't need to mask the values of `ordinals`, as Solidity + // cleans dirty upper bits when storing variables into memory. + roles := or(shl(mload(add(ordinals, i)), 1), roles) + } + } + } + + /// @dev Convenience function to return an array of `ordinals` from the `roles` bitmap. + /// This is meant for frontends like Etherscan, and is therefore not fully optimized. + /// Not recommended to be called on-chain. + /// Made internal to conserve bytecode. Wrap it in a public function if needed. + function _ordinalsFromRoles(uint256 roles) internal pure returns (uint8[] memory ordinals) { + /// @solidity memory-safe-assembly + assembly { + // Grab the pointer to the free memory. + ordinals := mload(0x40) + let ptr := add(ordinals, 0x20) + let o := 0 + // The absence of lookup tables, De Bruijn, etc., here is intentional for + // smaller bytecode, as this function is not meant to be called on-chain. + for { let t := roles } 1 {} { + mstore(ptr, o) + // `shr` 5 is equivalent to multiplying by 0x20. + // Push back into the ordinals array if the bit is set. + ptr := add(ptr, shl(5, and(t, 1))) + o := add(o, 1) + t := shr(o, roles) + if iszero(t) { break } + } + // Store the length of `ordinals`. + mstore(ordinals, shr(5, sub(ptr, add(ordinals, 0x20)))) + // Allocate the memory. + mstore(0x40, ptr) + } + } + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* PUBLIC UPDATE FUNCTIONS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev Allows the owner to grant `user` `roles`. + /// If the `user` already has a role, then it will be an no-op for the role. + function grantRoles(address user, uint256 roles) public payable virtual onlyOwner { + _grantRoles(user, roles); + } + + /// @dev Allows the owner to remove `user` `roles`. + /// If the `user` does not have a role, then it will be an no-op for the role. + function revokeRoles(address user, uint256 roles) public payable virtual onlyOwner { + _removeRoles(user, roles); + } + + /// @dev Allow the caller to remove their own roles. + /// If the caller does not have a role, then it will be an no-op for the role. + function renounceRoles(uint256 roles) public payable virtual { + _removeRoles(msg.sender, roles); + } + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* PUBLIC READ FUNCTIONS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev Returns the roles of `user`. + function rolesOf(address user) public view virtual returns (uint256 roles) { + /// @solidity memory-safe-assembly + assembly { + // Compute the role slot. + mstore(0x0c, _ROLE_SLOT_SEED) + mstore(0x00, user) + // Load the stored value. + roles := sload(keccak256(0x0c, 0x20)) + } + } + + /// @dev Returns whether `user` has any of `roles`. + function hasAnyRole(address user, uint256 roles) public view virtual returns (bool) { + return rolesOf(user) & roles != 0; + } + + /// @dev Returns whether `user` has all of `roles`. + function hasAllRoles(address user, uint256 roles) public view virtual returns (bool) { + return rolesOf(user) & roles == roles; + } + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* MODIFIERS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev Marks a function as only callable by an account with `roles`. + modifier onlyRoles(uint256 roles) virtual { + _checkRoles(roles); + _; + } + + /// @dev Marks a function as only callable by the owner or by an account + /// with `roles`. Checks for ownership first, then lazily checks for roles. + modifier onlyOwnerOrRoles(uint256 roles) virtual { + _checkOwnerOrRoles(roles); + _; + } + + /// @dev Marks a function as only callable by an account with `roles` + /// or the owner. Checks for roles first, then lazily checks for ownership. + modifier onlyRolesOrOwner(uint256 roles) virtual { + _checkRolesOrOwner(roles); + _; + } + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* ROLE CONSTANTS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + // IYKYK + + uint256 internal constant _ROLE_0 = 1 << 0; + uint256 internal constant _ROLE_1 = 1 << 1; + uint256 internal constant _ROLE_2 = 1 << 2; + uint256 internal constant _ROLE_3 = 1 << 3; + uint256 internal constant _ROLE_4 = 1 << 4; + uint256 internal constant _ROLE_5 = 1 << 5; + uint256 internal constant _ROLE_6 = 1 << 6; + uint256 internal constant _ROLE_7 = 1 << 7; + uint256 internal constant _ROLE_8 = 1 << 8; + uint256 internal constant _ROLE_9 = 1 << 9; + uint256 internal constant _ROLE_10 = 1 << 10; + uint256 internal constant _ROLE_11 = 1 << 11; + uint256 internal constant _ROLE_12 = 1 << 12; + uint256 internal constant _ROLE_13 = 1 << 13; + uint256 internal constant _ROLE_14 = 1 << 14; + uint256 internal constant _ROLE_15 = 1 << 15; + uint256 internal constant _ROLE_16 = 1 << 16; + uint256 internal constant _ROLE_17 = 1 << 17; + uint256 internal constant _ROLE_18 = 1 << 18; + uint256 internal constant _ROLE_19 = 1 << 19; + uint256 internal constant _ROLE_20 = 1 << 20; + uint256 internal constant _ROLE_21 = 1 << 21; + uint256 internal constant _ROLE_22 = 1 << 22; + uint256 internal constant _ROLE_23 = 1 << 23; + uint256 internal constant _ROLE_24 = 1 << 24; + uint256 internal constant _ROLE_25 = 1 << 25; + uint256 internal constant _ROLE_26 = 1 << 26; + uint256 internal constant _ROLE_27 = 1 << 27; + uint256 internal constant _ROLE_28 = 1 << 28; + uint256 internal constant _ROLE_29 = 1 << 29; + uint256 internal constant _ROLE_30 = 1 << 30; + uint256 internal constant _ROLE_31 = 1 << 31; + uint256 internal constant _ROLE_32 = 1 << 32; + uint256 internal constant _ROLE_33 = 1 << 33; + uint256 internal constant _ROLE_34 = 1 << 34; + uint256 internal constant _ROLE_35 = 1 << 35; + uint256 internal constant _ROLE_36 = 1 << 36; + uint256 internal constant _ROLE_37 = 1 << 37; + uint256 internal constant _ROLE_38 = 1 << 38; + uint256 internal constant _ROLE_39 = 1 << 39; + uint256 internal constant _ROLE_40 = 1 << 40; + uint256 internal constant _ROLE_41 = 1 << 41; + uint256 internal constant _ROLE_42 = 1 << 42; + uint256 internal constant _ROLE_43 = 1 << 43; + uint256 internal constant _ROLE_44 = 1 << 44; + uint256 internal constant _ROLE_45 = 1 << 45; + uint256 internal constant _ROLE_46 = 1 << 46; + uint256 internal constant _ROLE_47 = 1 << 47; + uint256 internal constant _ROLE_48 = 1 << 48; + uint256 internal constant _ROLE_49 = 1 << 49; + uint256 internal constant _ROLE_50 = 1 << 50; + uint256 internal constant _ROLE_51 = 1 << 51; + uint256 internal constant _ROLE_52 = 1 << 52; + uint256 internal constant _ROLE_53 = 1 << 53; + uint256 internal constant _ROLE_54 = 1 << 54; + uint256 internal constant _ROLE_55 = 1 << 55; + uint256 internal constant _ROLE_56 = 1 << 56; + uint256 internal constant _ROLE_57 = 1 << 57; + uint256 internal constant _ROLE_58 = 1 << 58; + uint256 internal constant _ROLE_59 = 1 << 59; + uint256 internal constant _ROLE_60 = 1 << 60; + uint256 internal constant _ROLE_61 = 1 << 61; + uint256 internal constant _ROLE_62 = 1 << 62; + uint256 internal constant _ROLE_63 = 1 << 63; + uint256 internal constant _ROLE_64 = 1 << 64; + uint256 internal constant _ROLE_65 = 1 << 65; + uint256 internal constant _ROLE_66 = 1 << 66; + uint256 internal constant _ROLE_67 = 1 << 67; + uint256 internal constant _ROLE_68 = 1 << 68; + uint256 internal constant _ROLE_69 = 1 << 69; + uint256 internal constant _ROLE_70 = 1 << 70; + uint256 internal constant _ROLE_71 = 1 << 71; + uint256 internal constant _ROLE_72 = 1 << 72; + uint256 internal constant _ROLE_73 = 1 << 73; + uint256 internal constant _ROLE_74 = 1 << 74; + uint256 internal constant _ROLE_75 = 1 << 75; + uint256 internal constant _ROLE_76 = 1 << 76; + uint256 internal constant _ROLE_77 = 1 << 77; + uint256 internal constant _ROLE_78 = 1 << 78; + uint256 internal constant _ROLE_79 = 1 << 79; + uint256 internal constant _ROLE_80 = 1 << 80; + uint256 internal constant _ROLE_81 = 1 << 81; + uint256 internal constant _ROLE_82 = 1 << 82; + uint256 internal constant _ROLE_83 = 1 << 83; + uint256 internal constant _ROLE_84 = 1 << 84; + uint256 internal constant _ROLE_85 = 1 << 85; + uint256 internal constant _ROLE_86 = 1 << 86; + uint256 internal constant _ROLE_87 = 1 << 87; + uint256 internal constant _ROLE_88 = 1 << 88; + uint256 internal constant _ROLE_89 = 1 << 89; + uint256 internal constant _ROLE_90 = 1 << 90; + uint256 internal constant _ROLE_91 = 1 << 91; + uint256 internal constant _ROLE_92 = 1 << 92; + uint256 internal constant _ROLE_93 = 1 << 93; + uint256 internal constant _ROLE_94 = 1 << 94; + uint256 internal constant _ROLE_95 = 1 << 95; + uint256 internal constant _ROLE_96 = 1 << 96; + uint256 internal constant _ROLE_97 = 1 << 97; + uint256 internal constant _ROLE_98 = 1 << 98; + uint256 internal constant _ROLE_99 = 1 << 99; + uint256 internal constant _ROLE_100 = 1 << 100; + uint256 internal constant _ROLE_101 = 1 << 101; + uint256 internal constant _ROLE_102 = 1 << 102; + uint256 internal constant _ROLE_103 = 1 << 103; + uint256 internal constant _ROLE_104 = 1 << 104; + uint256 internal constant _ROLE_105 = 1 << 105; + uint256 internal constant _ROLE_106 = 1 << 106; + uint256 internal constant _ROLE_107 = 1 << 107; + uint256 internal constant _ROLE_108 = 1 << 108; + uint256 internal constant _ROLE_109 = 1 << 109; + uint256 internal constant _ROLE_110 = 1 << 110; + uint256 internal constant _ROLE_111 = 1 << 111; + uint256 internal constant _ROLE_112 = 1 << 112; + uint256 internal constant _ROLE_113 = 1 << 113; + uint256 internal constant _ROLE_114 = 1 << 114; + uint256 internal constant _ROLE_115 = 1 << 115; + uint256 internal constant _ROLE_116 = 1 << 116; + uint256 internal constant _ROLE_117 = 1 << 117; + uint256 internal constant _ROLE_118 = 1 << 118; + uint256 internal constant _ROLE_119 = 1 << 119; + uint256 internal constant _ROLE_120 = 1 << 120; + uint256 internal constant _ROLE_121 = 1 << 121; + uint256 internal constant _ROLE_122 = 1 << 122; + uint256 internal constant _ROLE_123 = 1 << 123; + uint256 internal constant _ROLE_124 = 1 << 124; + uint256 internal constant _ROLE_125 = 1 << 125; + uint256 internal constant _ROLE_126 = 1 << 126; + uint256 internal constant _ROLE_127 = 1 << 127; + uint256 internal constant _ROLE_128 = 1 << 128; + uint256 internal constant _ROLE_129 = 1 << 129; + uint256 internal constant _ROLE_130 = 1 << 130; + uint256 internal constant _ROLE_131 = 1 << 131; + uint256 internal constant _ROLE_132 = 1 << 132; + uint256 internal constant _ROLE_133 = 1 << 133; + uint256 internal constant _ROLE_134 = 1 << 134; + uint256 internal constant _ROLE_135 = 1 << 135; + uint256 internal constant _ROLE_136 = 1 << 136; + uint256 internal constant _ROLE_137 = 1 << 137; + uint256 internal constant _ROLE_138 = 1 << 138; + uint256 internal constant _ROLE_139 = 1 << 139; + uint256 internal constant _ROLE_140 = 1 << 140; + uint256 internal constant _ROLE_141 = 1 << 141; + uint256 internal constant _ROLE_142 = 1 << 142; + uint256 internal constant _ROLE_143 = 1 << 143; + uint256 internal constant _ROLE_144 = 1 << 144; + uint256 internal constant _ROLE_145 = 1 << 145; + uint256 internal constant _ROLE_146 = 1 << 146; + uint256 internal constant _ROLE_147 = 1 << 147; + uint256 internal constant _ROLE_148 = 1 << 148; + uint256 internal constant _ROLE_149 = 1 << 149; + uint256 internal constant _ROLE_150 = 1 << 150; + uint256 internal constant _ROLE_151 = 1 << 151; + uint256 internal constant _ROLE_152 = 1 << 152; + uint256 internal constant _ROLE_153 = 1 << 153; + uint256 internal constant _ROLE_154 = 1 << 154; + uint256 internal constant _ROLE_155 = 1 << 155; + uint256 internal constant _ROLE_156 = 1 << 156; + uint256 internal constant _ROLE_157 = 1 << 157; + uint256 internal constant _ROLE_158 = 1 << 158; + uint256 internal constant _ROLE_159 = 1 << 159; + uint256 internal constant _ROLE_160 = 1 << 160; + uint256 internal constant _ROLE_161 = 1 << 161; + uint256 internal constant _ROLE_162 = 1 << 162; + uint256 internal constant _ROLE_163 = 1 << 163; + uint256 internal constant _ROLE_164 = 1 << 164; + uint256 internal constant _ROLE_165 = 1 << 165; + uint256 internal constant _ROLE_166 = 1 << 166; + uint256 internal constant _ROLE_167 = 1 << 167; + uint256 internal constant _ROLE_168 = 1 << 168; + uint256 internal constant _ROLE_169 = 1 << 169; + uint256 internal constant _ROLE_170 = 1 << 170; + uint256 internal constant _ROLE_171 = 1 << 171; + uint256 internal constant _ROLE_172 = 1 << 172; + uint256 internal constant _ROLE_173 = 1 << 173; + uint256 internal constant _ROLE_174 = 1 << 174; + uint256 internal constant _ROLE_175 = 1 << 175; + uint256 internal constant _ROLE_176 = 1 << 176; + uint256 internal constant _ROLE_177 = 1 << 177; + uint256 internal constant _ROLE_178 = 1 << 178; + uint256 internal constant _ROLE_179 = 1 << 179; + uint256 internal constant _ROLE_180 = 1 << 180; + uint256 internal constant _ROLE_181 = 1 << 181; + uint256 internal constant _ROLE_182 = 1 << 182; + uint256 internal constant _ROLE_183 = 1 << 183; + uint256 internal constant _ROLE_184 = 1 << 184; + uint256 internal constant _ROLE_185 = 1 << 185; + uint256 internal constant _ROLE_186 = 1 << 186; + uint256 internal constant _ROLE_187 = 1 << 187; + uint256 internal constant _ROLE_188 = 1 << 188; + uint256 internal constant _ROLE_189 = 1 << 189; + uint256 internal constant _ROLE_190 = 1 << 190; + uint256 internal constant _ROLE_191 = 1 << 191; + uint256 internal constant _ROLE_192 = 1 << 192; + uint256 internal constant _ROLE_193 = 1 << 193; + uint256 internal constant _ROLE_194 = 1 << 194; + uint256 internal constant _ROLE_195 = 1 << 195; + uint256 internal constant _ROLE_196 = 1 << 196; + uint256 internal constant _ROLE_197 = 1 << 197; + uint256 internal constant _ROLE_198 = 1 << 198; + uint256 internal constant _ROLE_199 = 1 << 199; + uint256 internal constant _ROLE_200 = 1 << 200; + uint256 internal constant _ROLE_201 = 1 << 201; + uint256 internal constant _ROLE_202 = 1 << 202; + uint256 internal constant _ROLE_203 = 1 << 203; + uint256 internal constant _ROLE_204 = 1 << 204; + uint256 internal constant _ROLE_205 = 1 << 205; + uint256 internal constant _ROLE_206 = 1 << 206; + uint256 internal constant _ROLE_207 = 1 << 207; + uint256 internal constant _ROLE_208 = 1 << 208; + uint256 internal constant _ROLE_209 = 1 << 209; + uint256 internal constant _ROLE_210 = 1 << 210; + uint256 internal constant _ROLE_211 = 1 << 211; + uint256 internal constant _ROLE_212 = 1 << 212; + uint256 internal constant _ROLE_213 = 1 << 213; + uint256 internal constant _ROLE_214 = 1 << 214; + uint256 internal constant _ROLE_215 = 1 << 215; + uint256 internal constant _ROLE_216 = 1 << 216; + uint256 internal constant _ROLE_217 = 1 << 217; + uint256 internal constant _ROLE_218 = 1 << 218; + uint256 internal constant _ROLE_219 = 1 << 219; + uint256 internal constant _ROLE_220 = 1 << 220; + uint256 internal constant _ROLE_221 = 1 << 221; + uint256 internal constant _ROLE_222 = 1 << 222; + uint256 internal constant _ROLE_223 = 1 << 223; + uint256 internal constant _ROLE_224 = 1 << 224; + uint256 internal constant _ROLE_225 = 1 << 225; + uint256 internal constant _ROLE_226 = 1 << 226; + uint256 internal constant _ROLE_227 = 1 << 227; + uint256 internal constant _ROLE_228 = 1 << 228; + uint256 internal constant _ROLE_229 = 1 << 229; + uint256 internal constant _ROLE_230 = 1 << 230; + uint256 internal constant _ROLE_231 = 1 << 231; + uint256 internal constant _ROLE_232 = 1 << 232; + uint256 internal constant _ROLE_233 = 1 << 233; + uint256 internal constant _ROLE_234 = 1 << 234; + uint256 internal constant _ROLE_235 = 1 << 235; + uint256 internal constant _ROLE_236 = 1 << 236; + uint256 internal constant _ROLE_237 = 1 << 237; + uint256 internal constant _ROLE_238 = 1 << 238; + uint256 internal constant _ROLE_239 = 1 << 239; + uint256 internal constant _ROLE_240 = 1 << 240; + uint256 internal constant _ROLE_241 = 1 << 241; + uint256 internal constant _ROLE_242 = 1 << 242; + uint256 internal constant _ROLE_243 = 1 << 243; + uint256 internal constant _ROLE_244 = 1 << 244; + uint256 internal constant _ROLE_245 = 1 << 245; + uint256 internal constant _ROLE_246 = 1 << 246; + uint256 internal constant _ROLE_247 = 1 << 247; + uint256 internal constant _ROLE_248 = 1 << 248; + uint256 internal constant _ROLE_249 = 1 << 249; + uint256 internal constant _ROLE_250 = 1 << 250; + uint256 internal constant _ROLE_251 = 1 << 251; + uint256 internal constant _ROLE_252 = 1 << 252; + uint256 internal constant _ROLE_253 = 1 << 253; + uint256 internal constant _ROLE_254 = 1 << 254; + uint256 internal constant _ROLE_255 = 1 << 255; +} + +// src\common/Treasury.sol + + + + + + +/// @title Treasury +/// @author Mathieu Bour for Pooky Labs Ltd. +/// +/// @notice Base class for contracts that are made to receive native currency. +/// The destination address is controller by the contract owner. +abstract contract Treasury is Ownable, ITreasury { + /// The native currency destination address. + address public treasury; + + constructor(address _treasury) { + treasury = _treasury; + } + + /// @notice Forward the funds to the treasury wallet at the end of the transaction. + /// Since `treasury` is a trusted address, this modifier should not lead to any re-entrancy issue. + modifier forwarder() { + _; + + uint256 value = address(this).balance; + (bool sent,) = treasury.call{ value: value }(""); + if (!sent) { + revert TransferFailed(treasury, value); + } + } + + /// Change the native currency destination address. + /// @param _treasury The new treasury address. + function changeTreasury(address _treasury) external onlyOwner { + treasury = _treasury; + } +} + +// src\tokens/IPOK.sol + + + + + + +/// @title IPOK +/// @author Mathieu Bour, Dusan Zdravkovic for Pooky Labs Ltd. +/// +/// @notice Minimal $POK ERC20 token interface. +interface IPOK is IAccessControl, IERC20 { + /// @notice Mint an arbitrary amount of $POK to an account. + /// @dev Requirements: + /// - only MINTER role can mint $POK tokens + function mint(address to, uint256 amount) external; + + /// @notice Burn an arbitrary amount of $POK of an sender account. + /// It is acknowledged that burning directly from the user wallet is anti-pattern + /// but since $POK is soulbounded, this allow to skip the ERC20 approve call. + /// @dev Requirements: + /// - only BURNER role can burn $POK tokens + function burn(address to, uint256 amount) external; +} + +// src\common/Signer.sol + + + + + + +/// @title Signer +/// @author Mathieu Bour for Pooky Labs Ltd. +/// +/// @dev Provide the `verify` function and the `onlyVerify` modifier to child contracts. +abstract contract Signer is OwnableRoles { + using ECDSA for bytes32; + + uint256 public constant SIGNER = _ROLE_42; + + /// Thrown when the signature is invalid. + error InvalidSignature(); + + constructor(address signer) { + _grantRoles(signer, SIGNER); + } + + /// @notice Ensure that `data` has been signed by a `SIGNER` using the `proof`. + function verify(bytes memory data, bytes calldata proof) internal view { + // Generate the signed message from the tokenId and currentPXP + bytes32 hash = keccak256(data).toEthSignedMessageHash(); + + if (!hasAllRoles(hash.recoverCalldata(proof), SIGNER)) { + revert InvalidSignature(); + } + } + + /// @notice Modifier version of the `verify` function. + modifier onlyVerify(bytes memory data, bytes calldata proof) { + verify(data, proof); + _; + } +} + +// src\pookyball/IPookyball.sol + + + + + + + +/// @title PookyballMetadata +/// @notice The Pookyball rarities are represented on chain by this enum. +enum PookyballRarity { + COMMON, + RARE, + EPIC, + LEGENDARY, + MYTHIC +} + +/// @title PookyballMetadata +/// @notice Pookyballs NFT have the following features: +/// - rarity: integer enum. +/// - level: token level, can be increase by spending token experiences points (PXP). +/// - pxp: token experience points. +/// - seed: a random uint256 word provided by Chainlink VRF service that will be used by Pooky's NFT generator +/// back-end to generate the NFT visuals and in-game statistics\. +struct PookyballMetadata { + PookyballRarity rarity; + uint256 level; + uint256 pxp; + uint256 seed; +} + +/// @title IPookyball +/// @author Mathieu Bour for Pooky Labs Ltd. +/// @notice Minimal Pookyball interface. +interface IPookyball is IAccessControl, IERC2981, IERC721 { + /// Fired when the seed of a Pookyball token is set by the VRFCoordinator + event SeedSet(uint256 indexed tokenId, uint256 seed); + /// Fired when the level of a Pookyball token is changed + event LevelChanged(uint256 indexed tokenId, uint256 level); + /// Fired when the PXP of a Pookyball token is changed + event PXPChanged(uint256 indexed tokenId, uint256 amount); + + /// Thrown when the length of two parameters mismatch. Used in the mint batched function. + error ArgumentSizeMismatch(uint256 x, uint256 y); + + /// @notice PookyballMetadata of the token {tokenId}. + /// @dev Requirements: + /// - Pookyball {tokenId} should exist (minted and not burned). + function metadata(uint256 tokenId) external view returns (PookyballMetadata memory); + + /// @notice Change the secondary sale royalties receiver address. + function setERC2981Receiver(address newReceiver) external; + + /// @notice Mint a new Pookyball token with a given rarity. + function mint(address[] memory recipients, PookyballRarity[] memory rarities) + external + returns (uint256); + + /// @notice Change the level of a Pookyball token. + /// @dev Requirements: + /// - Pookyball {tokenId} should exist (minted and not burned). + function setLevel(uint256 tokenId, uint256 newLevel) external; + + /// @notice Change the PXP of a Pookyball token. + /// @dev Requirements: + /// - Pookyball {tokenId} should exist (minted and not burned). + function setPXP(uint256 tokenId, uint256 newPXP) external; +} + +// src\common/IBaseERC721A.sol + + + + + + + + + +/// @title IBaseERC721 +/// +/// @author Mathieu Bour for Pooky Labs Ltd. +interface IBaseERC721A is IERC165, IERC721A, IERC721ABurnable, IERC721AQueryable, IERC2981 { + /// Fired when the seed of a Pookyball token is set by the VRFCoordinator, + event SeedSet(uint256 indexed tokenId, uint256 seed); + + /// Thrown when the token {tokenId} does not exist. + error NonExistentToken(uint256 tokenId); + + // ----- ERC721A patches ----- + /// @dev This allow to iterate over the token ids. + function nextTokenId() external view returns (uint256); + + function supportsInterface(bytes4 interfaceId) + external + view + override(IERC165, IERC721A) + returns (bool); +} + +// src\stickers/IStickers.sol + + + + + +enum StickerRarity { + COMMON, + RARE, + EPIC, + LEGENDARY, + MYTHIC +} + +struct StickerMint { + address recipient; + StickerRarity rarity; +} + +struct StickerMetadata { + uint248 level; + StickerRarity rarity; +} + +/// @title IStickers +/// @author Mathieu Bour for Pooky Labs Ltd. +interface IStickers is IBaseERC721A { + /// Fired when the level of a Pookyball token is changed, + event LevelChanged(uint256 indexed tokenId, uint256 level); + + /// @notice StickerMetadata of the token {tokenId}. + /// @dev Requirements: + /// - Sticker {tokenId} should exist (minted and not burned). + function metadata(uint256 tokenId) external view returns (StickerMetadata memory); + + /// @notice Change the level of a Sticker token. + /// @dev Requirements: + /// - Sticker {tokenId} should exist (minted and not burned). + function setLevel(uint256 tokenId, uint248 newLevel) external; + + /// @notice Mint multiple Stickers at once. + /// @param recipient The mint recipient. + /// @param rarities The Sticker rarities. + function mint(address recipient, StickerRarity[] memory rarities) external; +} + +// src\stickers/IStickersController.sol + + + + + + +/// @notice IStickersController +/// @author Mathieu Bour for Pooky Labs Ltd. +interface IStickersController { + /// @notice Fired when a sticker is attached to a Pookyball. + event StickerAttached(uint256 stickerId, uint256 pookyballId); + /// @notice Fired when a sticker is replace from a Pookyball. + event StickerReplaced(uint256 stickerId, uint256 previousStickerId, uint256 pookyballId); + /// @notice Fired when a sticker is detached from a Pookyball. + event StickerDetached(uint256 stickerId, uint256 pookyballId); + + /// @notice Thrown when a sticker is invalid. + error InvalidSticker(uint256 stickerId); + + /// @notice The Stickers ERC-721 contract. + function stickers() external view returns (IStickers); + + /// @notice The Pookyball ERC-721 contract. + function pookyball() external view returns (IPookyball); + + /// @notice Get the Pookyball token id linked to a Sticker. + /// @param stickerId The Sticker token id. + function attachedTo(uint256 stickerId) external view returns (uint256); + + /// @notice Get the Stickers token ids attached to a Pookyball. + /// @param pookyballId The Pookyball token id. + function slots(uint256 pookyballId) external view returns (uint256[] memory); + + /// @notice Attach a sticker to a Pookyball. + /// @param stickerId The sticker token id. + /// @param pookyballId The Pookyball token id. + /// @dev Caution: no ownership checks are run. + function attach(uint256 stickerId, uint256 pookyballId) external; + + /// @notice Replace a sticker from a Pookyball, burning the previous one. + /// @param stickerId The sticker token id. + /// @param previousStickerId The previous sticker token id that will be burned. + /// @param pookyballId The Pookyball token id. + /// @dev Caution: no ownership checks are run. + function replace(uint256 stickerId, uint256 previousStickerId, uint256 pookyballId) external; + + /// @notice Detach (remove) a sticker from a Pookyball. + /// @param stickerId The Sstickerticker token id. + /// @param recepient The address when to send the detached sticker. + function detach(uint256 stickerId, address recepient) external; +} + +// src\stickers\StickersAscension.sol + + + + + + + + + + + +/// @title StickersAscension +/// @author Mathieu Bour for Pooky Labs Ltd. +/// +/// @notice This contract allow Pooky players to upgrade their Stickers by merging Stickers into a better single Sticker. +contract StickersAscension is OwnableRoles, Signer { + /// @notice Fired when a Sticker is ascended. + /// @param tokenId The new ascended Sticker id. + /// @param rarity The rarity of the new ascended Sticker. + /// @param parts The Sticker that were used for the ascension. + /// @param data Abitrary data. + event Ascended(uint256 indexed tokenId, StickerRarity rarity, uint256[] parts, string data); + + /// @notice Thrown when the `tokenId` is not eligible for the ascension. + error Ineligible(uint256 tokenId); + + /// @notice Thrown when the rarity of the Sticker does not support Ascension. + error UnsupportedRarity(StickerRarity rarity); + + /// @notice Thrown when the rarities of the two source Stickers do not match. + error RarityMismatch(StickerRarity source, StickerRarity other); + + /// @notice The StickersController smart contract, used to detach stickers if necessary. + IStickersController public immutable controller; + + /// @notice The Stickers ERC-721 smart contract. + IStickers public immutable stickers; + + /// @notice The Pookyball ERC-721 smart contract. + IPookyball public immutable pookyball; + + /// @param _controller The StickersController smart contract, used to detach stickers if necessary. + constructor(IStickersController _controller, address admin, address _signer) Signer(_signer) { + _initializeOwner(admin); + controller = _controller; + stickers = _controller.stickers(); + pookyball = _controller.pookyball(); + } + + /// @notice Check if the provided metadata is at the maximum level, based on the rarity. + /// @param m The StickerMetadata to check. + function isLevelMax(StickerMetadata memory m) public pure returns (bool) { + if (m.rarity == StickerRarity.COMMON && m.level >= 40) { + return true; + } + if (m.rarity == StickerRarity.RARE && m.level >= 60) { + return true; + } + if (m.rarity == StickerRarity.EPIC && m.level >= 80) { + return true; + } + if (m.rarity == StickerRarity.LEGENDARY && m.level >= 100) { + return true; + } + + return false; + } + + /// @notice Get the next rarity after `rarity`. + function nextRarity(StickerRarity rarity) public pure returns (StickerRarity) { + if (rarity == StickerRarity.COMMON) { + return StickerRarity.RARE; + } else if (rarity == StickerRarity.RARE) { + return StickerRarity.EPIC; + } else if (rarity == StickerRarity.EPIC) { + return StickerRarity.LEGENDARY; + } else if (rarity == StickerRarity.LEGENDARY) { + return StickerRarity.MYTHIC; + } + + revert UnsupportedRarity(rarity); + } + + /// @notice Mint the new ascended Sticker. + /// @dev Unsupported rarities (legendary and mythical) will revert with `UnsupportedRarity`. + /// @param rarity The ascended Sticker rarity. + /// @param recipient The recipient of the Sticker. + /// @return The ascended Sticker token id. + function _mint(StickerRarity rarity, address recipient) internal returns (uint256) { + StickerRarity[] memory rarities = new StickerRarity[](1); + rarities[0] = rarity; + + stickers.mint(recipient, rarities); + return stickers.nextTokenId() - 1; + } + + /// @dev Burn a sticker, checking that + function _burn(uint256 stickerId, address sender, bool requireMax) + internal + returns (StickerMetadata memory metadata) + { + metadata = stickers.metadata(stickerId); + if (requireMax && !isLevelMax(metadata)) { + revert Ineligible(stickerId); + } + + if (stickers.ownerOf(stickerId) == sender) { + // pass + } else if ( + stickers + // Sticker is attached to a Pookyball, check the owner the Pookyball + .ownerOf(stickerId) == address(controller) + && pookyball.ownerOf(controller.attachedTo(stickerId)) == sender + ) { + controller.detach(stickerId, address(this)); + } else { + revert Ineligible(stickerId); + } + + stickers.burn(stickerId); + } + + /// @notice Ascend two maxed identical Stickers of the same rarity. + /// @dev Since the Stickers attributes are stored off-chain, calling this function requires a proof from the Pooky back-end. + /// @param source The first Sticker id. + /// @param other The second Sticker id. + /// @param data Abitrary data repeated in the `Ascended` event. + /// @param proof The proof from the back-end: `abi.encode(source, other, data, address(this))`. + /// @return ascendedId The ascended Sticker id. + function ascend2(uint256 source, uint256 other, string calldata data, bytes calldata proof) + external + onlyVerify(abi.encode(source, other, data, address(this)), proof) + returns (uint256 ascendedId) + { + StickerMetadata memory mSource = _burn(source, msg.sender, true); + StickerMetadata memory mOther = _burn(other, msg.sender, true); + if (mSource.rarity != mOther.rarity) { + revert RarityMismatch(mSource.rarity, mOther.rarity); + } + + uint256[] memory _parts = new uint[](2); + _parts[0] = source; + _parts[1] = other; + + StickerRarity rarity = nextRarity(mSource.rarity); + ascendedId = _mint(rarity, msg.sender); + emit Ascended(ascendedId, rarity, _parts, data); + } + + /// @notice Ascend three maxed Stickers of the same rarity. + /// @param source The reference Sticker to ascend. + /// @param parts An array of two other maxed Stickers of the same rarity. + /// @param data Abitrary data repeated in the `Ascended` event. + /// @param proof The proof from the back-end: `abi.encode(source, parts, data, address(this))`. + /// @return ascendedId The ascended Sticker id. + function ascend3( + uint256 source, + uint256[2] memory parts, + string calldata data, + bytes calldata proof + ) + external + onlyVerify(abi.encode(source, parts, data, address(this)), proof) + returns (uint256 ascendedId) + { + StickerMetadata memory mSource = _burn(source, msg.sender, true); + + uint256[] memory _parts = new uint[](parts.length + 1); + _parts[0] = source; + + for (uint256 i; i < parts.length; i++) { + _parts[i + 1] = parts[i]; + StickerMetadata memory m = _burn(parts[i], msg.sender, true); + + if (mSource.rarity != m.rarity) { + revert RarityMismatch(mSource.rarity, m.rarity); + } + } + + StickerRarity rarity = nextRarity(mSource.rarity); + ascendedId = _mint(rarity, msg.sender); + emit Ascended(ascendedId, rarity, _parts, data); + } + + /// @notice Ascend one maxed Sticker and five Stickers of the same rarity. + /// @param source The reference Sticker to ascend. + /// @param parts An array of five other Stickers of the same rarity. + /// @param data Abitrary data repeated in the `Ascended` event. + /// @param proof The proof from the back-end: `abi.encode(source, parts, data, address(this))`. + /// @return ascendedId The ascended Sticker id. + function ascend6( + uint256 source, + uint256[5] memory parts, + string calldata data, + bytes calldata proof + ) + external + onlyVerify(abi.encode(source, parts, data, address(this)), proof) + returns (uint256 ascendedId) + { + StickerMetadata memory mSource = _burn(source, msg.sender, true); + + uint256[] memory _parts = new uint[](parts.length + 1); + _parts[0] = source; + + // Burn parts + for (uint256 i; i < parts.length; i++) { + _parts[i + 1] = parts[i]; + + StickerMetadata memory m = _burn(parts[i], msg.sender, false); + + // Ensure that the part[i] has the same rarity as the source + if (mSource.rarity != m.rarity) { + revert RarityMismatch(mSource.rarity, m.rarity); + } + } + + StickerRarity rarity = nextRarity(mSource.rarity); + ascendedId = _mint(rarity, msg.sender); + emit Ascended(ascendedId, rarity, _parts, data); + } +} diff --git a/flattened/StickersController.sol b/flattened/StickersController.sol new file mode 100644 index 00000000..00404423 --- /dev/null +++ b/flattened/StickersController.sol @@ -0,0 +1,2128 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0 ^0.8.17 ^0.8.21 ^0.8.4; + +// lib/ERC721A/contracts\IERC721A.sol + +// ERC721A Contracts v4.2.3 +// Creator: Chiru Labs + + + +/** + * @dev Interface of ERC721A. + */ +interface IERC721A { + /** + * The caller must own the token or be an approved operator. + */ + error ApprovalCallerNotOwnerNorApproved(); + + /** + * The token does not exist. + */ + error ApprovalQueryForNonexistentToken(); + + /** + * Cannot query the balance for the zero address. + */ + error BalanceQueryForZeroAddress(); + + /** + * Cannot mint to the zero address. + */ + error MintToZeroAddress(); + + /** + * The quantity of tokens minted must be more than zero. + */ + error MintZeroQuantity(); + + /** + * The token does not exist. + */ + error OwnerQueryForNonexistentToken(); + + /** + * The caller must own the token or be an approved operator. + */ + error TransferCallerNotOwnerNorApproved(); + + /** + * The token must be owned by `from`. + */ + error TransferFromIncorrectOwner(); + + /** + * Cannot safely transfer to a contract that does not implement the + * ERC721Receiver interface. + */ + error TransferToNonERC721ReceiverImplementer(); + + /** + * Cannot transfer to the zero address. + */ + error TransferToZeroAddress(); + + /** + * The token does not exist. + */ + error URIQueryForNonexistentToken(); + + /** + * The `quantity` minted with ERC2309 exceeds the safety limit. + */ + error MintERC2309QuantityExceedsLimit(); + + /** + * The `extraData` cannot be set on an unintialized ownership slot. + */ + error OwnershipNotInitializedForExtraData(); + + // ============================================================= + // STRUCTS + // ============================================================= + + struct TokenOwnership { + // The address of the owner. + address addr; + // Stores the start time of ownership with minimal overhead for tokenomics. + uint64 startTimestamp; + // Whether the token has been burned. + bool burned; + // Arbitrary data similar to `startTimestamp` that can be set via {_extraData}. + uint24 extraData; + } + + // ============================================================= + // TOKEN COUNTERS + // ============================================================= + + /** + * @dev Returns the total number of tokens in existence. + * Burned tokens will reduce the count. + * To get the total number of tokens minted, please see {_totalMinted}. + */ + function totalSupply() external view returns (uint256); + + // ============================================================= + // 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 30000 gas. + */ + function supportsInterface(bytes4 interfaceId) external view returns (bool); + + // ============================================================= + // IERC721 + // ============================================================= + + /** + * @dev Emitted when `tokenId` token is transferred from `from` to `to`. + */ + event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); + + /** + * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token. + */ + event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); + + /** + * @dev Emitted when `owner` enables or disables + * (`approved`) `operator` to manage all of its assets. + */ + event ApprovalForAll(address indexed owner, address indexed operator, bool approved); + + /** + * @dev Returns the number of tokens in `owner`'s account. + */ + function balanceOf(address owner) external view returns (uint256 balance); + + /** + * @dev Returns the owner of the `tokenId` token. + * + * Requirements: + * + * - `tokenId` must exist. + */ + function ownerOf(uint256 tokenId) external view returns (address owner); + + /** + * @dev Safely transfers `tokenId` token from `from` to `to`, + * checking first that contract recipients are aware of the ERC721 protocol + * to prevent tokens from being forever locked. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must exist and be owned by `from`. + * - If the caller is not `from`, it must be have been allowed to move + * this token by either {approve} or {setApprovalForAll}. + * - If `to` refers to a smart contract, it must implement + * {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. + * + * Emits a {Transfer} event. + */ + function safeTransferFrom( + address from, + address to, + uint256 tokenId, + bytes calldata data + ) external payable; + + /** + * @dev Equivalent to `safeTransferFrom(from, to, tokenId, '')`. + */ + function safeTransferFrom( + address from, + address to, + uint256 tokenId + ) external payable; + + /** + * @dev Transfers `tokenId` from `from` to `to`. + * + * WARNING: Usage of this method is discouraged, use {safeTransferFrom} + * whenever possible. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must be owned by `from`. + * - If the caller is not `from`, it must be approved to move this token + * by either {approve} or {setApprovalForAll}. + * + * Emits a {Transfer} event. + */ + function transferFrom( + address from, + address to, + uint256 tokenId + ) external payable; + + /** + * @dev Gives permission to `to` to transfer `tokenId` token to another account. + * The approval is cleared when the token is transferred. + * + * Only a single account can be approved at a time, so approving the + * zero address clears previous approvals. + * + * Requirements: + * + * - The caller must own the token or be an approved operator. + * - `tokenId` must exist. + * + * Emits an {Approval} event. + */ + function approve(address to, uint256 tokenId) external payable; + + /** + * @dev Approve or remove `operator` as an operator for the caller. + * Operators can call {transferFrom} or {safeTransferFrom} + * for any token owned by the caller. + * + * Requirements: + * + * - The `operator` cannot be the caller. + * + * Emits an {ApprovalForAll} event. + */ + function setApprovalForAll(address operator, bool _approved) external; + + /** + * @dev Returns the account approved for `tokenId` token. + * + * Requirements: + * + * - `tokenId` must exist. + */ + function getApproved(uint256 tokenId) external view returns (address operator); + + /** + * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`. + * + * See {setApprovalForAll}. + */ + function isApprovedForAll(address owner, address operator) external view returns (bool); + + // ============================================================= + // IERC721Metadata + // ============================================================= + + /** + * @dev Returns the token collection name. + */ + function name() external view returns (string memory); + + /** + * @dev Returns the token collection symbol. + */ + function symbol() external view returns (string memory); + + /** + * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token. + */ + function tokenURI(uint256 tokenId) external view returns (string memory); + + // ============================================================= + // IERC2309 + // ============================================================= + + /** + * @dev Emitted when tokens in `fromTokenId` to `toTokenId` + * (inclusive) is transferred from `from` to `to`, as defined in the + * [ERC2309](https://eips.ethereum.org/EIPS/eip-2309) standard. + * + * See {_mintERC2309} for more details. + */ + event ConsecutiveTransfer(uint256 indexed fromTokenId, uint256 toTokenId, address indexed from, address indexed to); +} + +// lib/openzeppelin-contracts/contracts\access/IAccessControl.sol + +// OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol) + + + +/** + * @dev External interface of AccessControl declared to support ERC165 detection. + */ +interface IAccessControl { + /** + * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` + * + * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite + * {RoleAdminChanged} not being emitted signaling this. + * + * _Available since v3.1._ + */ + event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole); + + /** + * @dev Emitted when `account` is granted `role`. + * + * `sender` is the account that originated the contract call, an admin role + * bearer except when using {AccessControl-_setupRole}. + */ + event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender); + + /** + * @dev Emitted when `account` is revoked `role`. + * + * `sender` is the account that originated the contract call: + * - if using `revokeRole`, it is the admin role bearer + * - if using `renounceRole`, it is the role bearer (i.e. `account`) + */ + event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender); + + /** + * @dev Returns `true` if `account` has been granted `role`. + */ + function hasRole(bytes32 role, address account) external view returns (bool); + + /** + * @dev Returns the admin role that controls `role`. See {grantRole} and + * {revokeRole}. + * + * To change a role's admin, use {AccessControl-_setRoleAdmin}. + */ + function getRoleAdmin(bytes32 role) external view returns (bytes32); + + /** + * @dev Grants `role` to `account`. + * + * If `account` had not been already granted `role`, emits a {RoleGranted} + * event. + * + * Requirements: + * + * - the caller must have ``role``'s admin role. + */ + function grantRole(bytes32 role, address account) external; + + /** + * @dev Revokes `role` from `account`. + * + * If `account` had been granted `role`, emits a {RoleRevoked} event. + * + * Requirements: + * + * - the caller must have ``role``'s admin role. + */ + function revokeRole(bytes32 role, address account) external; + + /** + * @dev Revokes `role` from the calling account. + * + * Roles are often managed via {grantRole} and {revokeRole}: this function's + * purpose is to provide a mechanism for accounts to lose their privileges + * if they are compromised (such as when a trusted device is misplaced). + * + * If the calling account had been granted `role`, emits a {RoleRevoked} + * event. + * + * Requirements: + * + * - the caller must be `account`. + */ + function renounceRole(bytes32 role, address account) external; +} + +// lib/openzeppelin-contracts/contracts/utils/introspection/IERC165.sol + +// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol) + + + +/** + * @dev Interface of the ERC165 standard, as defined in the + * https://eips.ethereum.org/EIPS/eip-165[EIP]. + * + * Implementers can declare support of contract interfaces, which can then be + * queried by others ({ERC165Checker}). + * + * For an implementation, see {ERC165}. + */ +interface IERC165 { + /** + * @dev Returns true if this contract implements the interface defined by + * `interfaceId`. See the corresponding + * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] + * to learn more about how these ids are created. + * + * This function call must use less than 30 000 gas. + */ + function supportsInterface(bytes4 interfaceId) external view returns (bool); +} + +// lib/openzeppelin-contracts/contracts\utils/structs/EnumerableSet.sol + +// OpenZeppelin Contracts (last updated v4.9.0) (utils/structs/EnumerableSet.sol) +// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js. + + + +/** + * @dev Library for managing + * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive + * types. + * + * Sets have the following properties: + * + * - Elements are added, removed, and checked for existence in constant time + * (O(1)). + * - Elements are enumerated in O(n). No guarantees are made on the ordering. + * + * ```solidity + * contract Example { + * // Add the library methods + * using EnumerableSet for EnumerableSet.AddressSet; + * + * // Declare a set state variable + * EnumerableSet.AddressSet private mySet; + * } + * ``` + * + * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`) + * and `uint256` (`UintSet`) are supported. + * + * [WARNING] + * ==== + * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure + * unusable. + * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info. + * + * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an + * array of EnumerableSet. + * ==== + */ +library EnumerableSet { + // To implement this library for multiple types with as little code + // repetition as possible, we write it in terms of a generic Set type with + // bytes32 values. + // The Set implementation uses private functions, and user-facing + // implementations (such as AddressSet) are just wrappers around the + // underlying Set. + // This means that we can only create new EnumerableSets for types that fit + // in bytes32. + + struct Set { + // Storage of set values + bytes32[] _values; + // Position of the value in the `values` array, plus 1 because index 0 + // means a value is not in the set. + mapping(bytes32 => uint256) _indexes; + } + + /** + * @dev Add a value to a set. O(1). + * + * Returns true if the value was added to the set, that is if it was not + * already present. + */ + function _add(Set storage set, bytes32 value) private returns (bool) { + if (!_contains(set, value)) { + set._values.push(value); + // The value is stored at length-1, but we add 1 to all indexes + // and use 0 as a sentinel value + set._indexes[value] = set._values.length; + return true; + } else { + return false; + } + } + + /** + * @dev Removes a value from a set. O(1). + * + * Returns true if the value was removed from the set, that is if it was + * present. + */ + function _remove(Set storage set, bytes32 value) private returns (bool) { + // We read and store the value's index to prevent multiple reads from the same storage slot + uint256 valueIndex = set._indexes[value]; + + if (valueIndex != 0) { + // Equivalent to contains(set, value) + // To delete an element from the _values array in O(1), we swap the element to delete with the last one in + // the array, and then remove the last element (sometimes called as 'swap and pop'). + // This modifies the order of the array, as noted in {at}. + + uint256 toDeleteIndex = valueIndex - 1; + uint256 lastIndex = set._values.length - 1; + + if (lastIndex != toDeleteIndex) { + bytes32 lastValue = set._values[lastIndex]; + + // Move the last value to the index where the value to delete is + set._values[toDeleteIndex] = lastValue; + // Update the index for the moved value + set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex + } + + // Delete the slot where the moved value was stored + set._values.pop(); + + // Delete the index for the deleted slot + delete set._indexes[value]; + + return true; + } else { + return false; + } + } + + /** + * @dev Returns true if the value is in the set. O(1). + */ + function _contains(Set storage set, bytes32 value) private view returns (bool) { + return set._indexes[value] != 0; + } + + /** + * @dev Returns the number of values on the set. O(1). + */ + function _length(Set storage set) private view returns (uint256) { + return set._values.length; + } + + /** + * @dev Returns the value stored at position `index` in the set. O(1). + * + * Note that there are no guarantees on the ordering of values inside the + * array, and it may change when more values are added or removed. + * + * Requirements: + * + * - `index` must be strictly less than {length}. + */ + function _at(Set storage set, uint256 index) private view returns (bytes32) { + return set._values[index]; + } + + /** + * @dev Return the entire set in an array + * + * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed + * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that + * this function has an unbounded cost, and using it as part of a state-changing function may render the function + * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. + */ + function _values(Set storage set) private view returns (bytes32[] memory) { + return set._values; + } + + // Bytes32Set + + struct Bytes32Set { + Set _inner; + } + + /** + * @dev Add a value to a set. O(1). + * + * Returns true if the value was added to the set, that is if it was not + * already present. + */ + function add(Bytes32Set storage set, bytes32 value) internal returns (bool) { + return _add(set._inner, value); + } + + /** + * @dev Removes a value from a set. O(1). + * + * Returns true if the value was removed from the set, that is if it was + * present. + */ + function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) { + return _remove(set._inner, value); + } + + /** + * @dev Returns true if the value is in the set. O(1). + */ + function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) { + return _contains(set._inner, value); + } + + /** + * @dev Returns the number of values in the set. O(1). + */ + function length(Bytes32Set storage set) internal view returns (uint256) { + return _length(set._inner); + } + + /** + * @dev Returns the value stored at position `index` in the set. O(1). + * + * Note that there are no guarantees on the ordering of values inside the + * array, and it may change when more values are added or removed. + * + * Requirements: + * + * - `index` must be strictly less than {length}. + */ + function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) { + return _at(set._inner, index); + } + + /** + * @dev Return the entire set in an array + * + * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed + * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that + * this function has an unbounded cost, and using it as part of a state-changing function may render the function + * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. + */ + function values(Bytes32Set storage set) internal view returns (bytes32[] memory) { + bytes32[] memory store = _values(set._inner); + bytes32[] memory result; + + /// @solidity memory-safe-assembly + assembly { + result := store + } + + return result; + } + + // AddressSet + + struct AddressSet { + Set _inner; + } + + /** + * @dev Add a value to a set. O(1). + * + * Returns true if the value was added to the set, that is if it was not + * already present. + */ + function add(AddressSet storage set, address value) internal returns (bool) { + return _add(set._inner, bytes32(uint256(uint160(value)))); + } + + /** + * @dev Removes a value from a set. O(1). + * + * Returns true if the value was removed from the set, that is if it was + * present. + */ + function remove(AddressSet storage set, address value) internal returns (bool) { + return _remove(set._inner, bytes32(uint256(uint160(value)))); + } + + /** + * @dev Returns true if the value is in the set. O(1). + */ + function contains(AddressSet storage set, address value) internal view returns (bool) { + return _contains(set._inner, bytes32(uint256(uint160(value)))); + } + + /** + * @dev Returns the number of values in the set. O(1). + */ + function length(AddressSet storage set) internal view returns (uint256) { + return _length(set._inner); + } + + /** + * @dev Returns the value stored at position `index` in the set. O(1). + * + * Note that there are no guarantees on the ordering of values inside the + * array, and it may change when more values are added or removed. + * + * Requirements: + * + * - `index` must be strictly less than {length}. + */ + function at(AddressSet storage set, uint256 index) internal view returns (address) { + return address(uint160(uint256(_at(set._inner, index)))); + } + + /** + * @dev Return the entire set in an array + * + * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed + * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that + * this function has an unbounded cost, and using it as part of a state-changing function may render the function + * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. + */ + function values(AddressSet storage set) internal view returns (address[] memory) { + bytes32[] memory store = _values(set._inner); + address[] memory result; + + /// @solidity memory-safe-assembly + assembly { + result := store + } + + return result; + } + + // UintSet + + struct UintSet { + Set _inner; + } + + /** + * @dev Add a value to a set. O(1). + * + * Returns true if the value was added to the set, that is if it was not + * already present. + */ + function add(UintSet storage set, uint256 value) internal returns (bool) { + return _add(set._inner, bytes32(value)); + } + + /** + * @dev Removes a value from a set. O(1). + * + * Returns true if the value was removed from the set, that is if it was + * present. + */ + function remove(UintSet storage set, uint256 value) internal returns (bool) { + return _remove(set._inner, bytes32(value)); + } + + /** + * @dev Returns true if the value is in the set. O(1). + */ + function contains(UintSet storage set, uint256 value) internal view returns (bool) { + return _contains(set._inner, bytes32(value)); + } + + /** + * @dev Returns the number of values in the set. O(1). + */ + function length(UintSet storage set) internal view returns (uint256) { + return _length(set._inner); + } + + /** + * @dev Returns the value stored at position `index` in the set. O(1). + * + * Note that there are no guarantees on the ordering of values inside the + * array, and it may change when more values are added or removed. + * + * Requirements: + * + * - `index` must be strictly less than {length}. + */ + function at(UintSet storage set, uint256 index) internal view returns (uint256) { + return uint256(_at(set._inner, index)); + } + + /** + * @dev Return the entire set in an array + * + * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed + * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that + * this function has an unbounded cost, and using it as part of a state-changing function may render the function + * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. + */ + function values(UintSet storage set) internal view returns (uint256[] memory) { + bytes32[] memory store = _values(set._inner); + uint256[] memory result; + + /// @solidity memory-safe-assembly + assembly { + result := store + } + + return result; + } +} + +// lib/solady/src/auth/Ownable.sol + + + +/// @notice Simple single owner authorization mixin. +/// @author Solady (https://github.com/vectorized/solady/blob/main/src/auth/Ownable.sol) +/// @dev While the ownable portion follows +/// [EIP-173](https://eips.ethereum.org/EIPS/eip-173) for compatibility, +/// the nomenclature for the 2-step ownership handover may be unique to this codebase. +abstract contract Ownable { + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* CUSTOM ERRORS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev The caller is not authorized to call the function. + error Unauthorized(); + + /// @dev The `newOwner` cannot be the zero address. + error NewOwnerIsZeroAddress(); + + /// @dev The `pendingOwner` does not have a valid handover request. + error NoHandoverRequest(); + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* EVENTS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev The ownership is transferred from `oldOwner` to `newOwner`. + /// This event is intentionally kept the same as OpenZeppelin's Ownable to be + /// compatible with indexers and [EIP-173](https://eips.ethereum.org/EIPS/eip-173), + /// despite it not being as lightweight as a single argument event. + event OwnershipTransferred(address indexed oldOwner, address indexed newOwner); + + /// @dev An ownership handover to `pendingOwner` has been requested. + event OwnershipHandoverRequested(address indexed pendingOwner); + + /// @dev The ownership handover to `pendingOwner` has been canceled. + event OwnershipHandoverCanceled(address indexed pendingOwner); + + /// @dev `keccak256(bytes("OwnershipTransferred(address,address)"))`. + uint256 private constant _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE = + 0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0; + + /// @dev `keccak256(bytes("OwnershipHandoverRequested(address)"))`. + uint256 private constant _OWNERSHIP_HANDOVER_REQUESTED_EVENT_SIGNATURE = + 0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d; + + /// @dev `keccak256(bytes("OwnershipHandoverCanceled(address)"))`. + uint256 private constant _OWNERSHIP_HANDOVER_CANCELED_EVENT_SIGNATURE = + 0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92; + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* STORAGE */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev The owner slot is given by: `not(_OWNER_SLOT_NOT)`. + /// It is intentionally chosen to be a high value + /// to avoid collision with lower slots. + /// The choice of manual storage layout is to enable compatibility + /// with both regular and upgradeable contracts. + uint256 private constant _OWNER_SLOT_NOT = 0x8b78c6d8; + + /// The ownership handover slot of `newOwner` is given by: + /// ``` + /// mstore(0x00, or(shl(96, user), _HANDOVER_SLOT_SEED)) + /// let handoverSlot := keccak256(0x00, 0x20) + /// ``` + /// It stores the expiry timestamp of the two-step ownership handover. + uint256 private constant _HANDOVER_SLOT_SEED = 0x389a75e1; + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* INTERNAL FUNCTIONS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev Initializes the owner directly without authorization guard. + /// This function must be called upon initialization, + /// regardless of whether the contract is upgradeable or not. + /// This is to enable generalization to both regular and upgradeable contracts, + /// and to save gas in case the initial owner is not the caller. + /// For performance reasons, this function will not check if there + /// is an existing owner. + function _initializeOwner(address newOwner) internal virtual { + /// @solidity memory-safe-assembly + assembly { + // Clean the upper 96 bits. + newOwner := shr(96, shl(96, newOwner)) + // Store the new value. + sstore(not(_OWNER_SLOT_NOT), newOwner) + // Emit the {OwnershipTransferred} event. + log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, 0, newOwner) + } + } + + /// @dev Sets the owner directly without authorization guard. + function _setOwner(address newOwner) internal virtual { + /// @solidity memory-safe-assembly + assembly { + let ownerSlot := not(_OWNER_SLOT_NOT) + // Clean the upper 96 bits. + newOwner := shr(96, shl(96, newOwner)) + // Emit the {OwnershipTransferred} event. + log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, sload(ownerSlot), newOwner) + // Store the new value. + sstore(ownerSlot, newOwner) + } + } + + /// @dev Throws if the sender is not the owner. + function _checkOwner() internal view virtual { + /// @solidity memory-safe-assembly + assembly { + // If the caller is not the stored owner, revert. + if iszero(eq(caller(), sload(not(_OWNER_SLOT_NOT)))) { + mstore(0x00, 0x82b42900) // `Unauthorized()`. + revert(0x1c, 0x04) + } + } + } + + /// @dev Returns how long a two-step ownership handover is valid for in seconds. + /// Override to return a different value if needed. + /// Made internal to conserve bytecode. Wrap it in a public function if needed. + function _ownershipHandoverValidFor() internal view virtual returns (uint64) { + return 48 * 3600; + } + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* PUBLIC UPDATE FUNCTIONS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev Allows the owner to transfer the ownership to `newOwner`. + function transferOwnership(address newOwner) public payable virtual onlyOwner { + /// @solidity memory-safe-assembly + assembly { + if iszero(shl(96, newOwner)) { + mstore(0x00, 0x7448fbae) // `NewOwnerIsZeroAddress()`. + revert(0x1c, 0x04) + } + } + _setOwner(newOwner); + } + + /// @dev Allows the owner to renounce their ownership. + function renounceOwnership() public payable virtual onlyOwner { + _setOwner(address(0)); + } + + /// @dev Request a two-step ownership handover to the caller. + /// The request will automatically expire in 48 hours (172800 seconds) by default. + function requestOwnershipHandover() public payable virtual { + unchecked { + uint256 expires = block.timestamp + _ownershipHandoverValidFor(); + /// @solidity memory-safe-assembly + assembly { + // Compute and set the handover slot to `expires`. + mstore(0x0c, _HANDOVER_SLOT_SEED) + mstore(0x00, caller()) + sstore(keccak256(0x0c, 0x20), expires) + // Emit the {OwnershipHandoverRequested} event. + log2(0, 0, _OWNERSHIP_HANDOVER_REQUESTED_EVENT_SIGNATURE, caller()) + } + } + } + + /// @dev Cancels the two-step ownership handover to the caller, if any. + function cancelOwnershipHandover() public payable virtual { + /// @solidity memory-safe-assembly + assembly { + // Compute and set the handover slot to 0. + mstore(0x0c, _HANDOVER_SLOT_SEED) + mstore(0x00, caller()) + sstore(keccak256(0x0c, 0x20), 0) + // Emit the {OwnershipHandoverCanceled} event. + log2(0, 0, _OWNERSHIP_HANDOVER_CANCELED_EVENT_SIGNATURE, caller()) + } + } + + /// @dev Allows the owner to complete the two-step ownership handover to `pendingOwner`. + /// Reverts if there is no existing ownership handover requested by `pendingOwner`. + function completeOwnershipHandover(address pendingOwner) public payable virtual onlyOwner { + /// @solidity memory-safe-assembly + assembly { + // Compute and set the handover slot to 0. + mstore(0x0c, _HANDOVER_SLOT_SEED) + mstore(0x00, pendingOwner) + let handoverSlot := keccak256(0x0c, 0x20) + // If the handover does not exist, or has expired. + if gt(timestamp(), sload(handoverSlot)) { + mstore(0x00, 0x6f5e8818) // `NoHandoverRequest()`. + revert(0x1c, 0x04) + } + // Set the handover slot to 0. + sstore(handoverSlot, 0) + } + _setOwner(pendingOwner); + } + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* PUBLIC READ FUNCTIONS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev Returns the owner of the contract. + function owner() public view virtual returns (address result) { + /// @solidity memory-safe-assembly + assembly { + result := sload(not(_OWNER_SLOT_NOT)) + } + } + + /// @dev Returns the expiry timestamp for the two-step ownership handover to `pendingOwner`. + function ownershipHandoverExpiresAt(address pendingOwner) + public + view + virtual + returns (uint256 result) + { + /// @solidity memory-safe-assembly + assembly { + // Compute the handover slot. + mstore(0x0c, _HANDOVER_SLOT_SEED) + mstore(0x00, pendingOwner) + // Load the handover slot. + result := sload(keccak256(0x0c, 0x20)) + } + } + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* MODIFIERS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev Marks a function as only callable by the owner. + modifier onlyOwner() virtual { + _checkOwner(); + _; + } +} + +// lib/ERC721A/contracts\extensions/IERC721ABurnable.sol + +// ERC721A Contracts v4.2.3 +// Creator: Chiru Labs + + + + + +/** + * @dev Interface of ERC721ABurnable. + */ +interface IERC721ABurnable is IERC721A { + /** + * @dev Burns `tokenId`. See {ERC721A-_burn}. + * + * Requirements: + * + * - The caller must own `tokenId` or be an approved operator. + */ + function burn(uint256 tokenId) external; +} + +// lib/ERC721A/contracts\extensions/IERC721AQueryable.sol + +// ERC721A Contracts v4.2.3 +// Creator: Chiru Labs + + + + + +/** + * @dev Interface of ERC721AQueryable. + */ +interface IERC721AQueryable is IERC721A { + /** + * Invalid query range (`start` >= `stop`). + */ + error InvalidQueryRange(); + + /** + * @dev Returns the `TokenOwnership` struct at `tokenId` without reverting. + * + * If the `tokenId` is out of bounds: + * + * - `addr = address(0)` + * - `startTimestamp = 0` + * - `burned = false` + * - `extraData = 0` + * + * If the `tokenId` is burned: + * + * - `addr =
` + * - `startTimestamp = ` + * - `burned = true` + * - `extraData = ` + * + * Otherwise: + * + * - `addr =
` + * - `startTimestamp = ` + * - `burned = false` + * - `extraData = ` + */ + function explicitOwnershipOf(uint256 tokenId) external view returns (TokenOwnership memory); + + /** + * @dev Returns an array of `TokenOwnership` structs at `tokenIds` in order. + * See {ERC721AQueryable-explicitOwnershipOf} + */ + function explicitOwnershipsOf(uint256[] memory tokenIds) external view returns (TokenOwnership[] memory); + + /** + * @dev Returns an array of token IDs owned by `owner`, + * in the range [`start`, `stop`) + * (i.e. `start <= tokenId < stop`). + * + * This function allows for tokens to be queried if the collection + * grows too big for a single call of {ERC721AQueryable-tokensOfOwner}. + * + * Requirements: + * + * - `start < stop` + */ + function tokensOfOwnerIn( + address owner, + uint256 start, + uint256 stop + ) external view returns (uint256[] memory); + + /** + * @dev Returns an array of token IDs owned by `owner`. + * + * This function scans the ownership mapping and is O(`totalSupply`) in complexity. + * It is meant to be called off-chain. + * + * See {ERC721AQueryable-tokensOfOwnerIn} for splitting the scan into + * multiple smaller scans if the collection is large enough to cause + * an out-of-gas error (10K collections should be fine). + */ + function tokensOfOwner(address owner) external view returns (uint256[] memory); +} + +// lib/openzeppelin-contracts/contracts\interfaces/IERC165.sol + +// OpenZeppelin Contracts v4.4.1 (interfaces/IERC165.sol) + + + + + +// lib/openzeppelin-contracts/contracts\interfaces/IERC2981.sol + +// OpenZeppelin Contracts (last updated v4.9.0) (interfaces/IERC2981.sol) + + + + + +/** + * @dev Interface for the NFT Royalty Standard. + * + * A standardized way to retrieve royalty payment information for non-fungible tokens (NFTs) to enable universal + * support for royalty payments across all NFT marketplaces and ecosystem participants. + * + * _Available since v4.5._ + */ +interface IERC2981 is IERC165 { + /** + * @dev Returns how much royalty is owed and to whom, based on a sale price that may be denominated in any unit of + * exchange. The royalty amount is denominated and should be paid in that same unit of exchange. + */ + function royaltyInfo( + uint256 tokenId, + uint256 salePrice + ) external view returns (address receiver, uint256 royaltyAmount); +} + +// lib/openzeppelin-contracts/contracts\token/ERC721/IERC721.sol + +// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC721/IERC721.sol) + + + + + +/** + * @dev Required interface of an ERC721 compliant contract. + */ +interface IERC721 is IERC165 { + /** + * @dev Emitted when `tokenId` token is transferred from `from` to `to`. + */ + event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); + + /** + * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token. + */ + event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); + + /** + * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets. + */ + event ApprovalForAll(address indexed owner, address indexed operator, bool approved); + + /** + * @dev Returns the number of tokens in ``owner``'s account. + */ + function balanceOf(address owner) external view returns (uint256 balance); + + /** + * @dev Returns the owner of the `tokenId` token. + * + * Requirements: + * + * - `tokenId` must exist. + */ + function ownerOf(uint256 tokenId) external view returns (address owner); + + /** + * @dev Safely transfers `tokenId` token from `from` to `to`. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must exist and be owned by `from`. + * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. + * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. + * + * Emits a {Transfer} event. + */ + function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external; + + /** + * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients + * are aware of the ERC721 protocol to prevent tokens from being forever locked. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must exist and be owned by `from`. + * - If the caller is not `from`, it must have been allowed to move this token by either {approve} or {setApprovalForAll}. + * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. + * + * Emits a {Transfer} event. + */ + function safeTransferFrom(address from, address to, uint256 tokenId) external; + + /** + * @dev Transfers `tokenId` token from `from` to `to`. + * + * WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721 + * or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must + * understand this adds an external call which potentially creates a reentrancy vulnerability. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must be owned by `from`. + * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. + * + * Emits a {Transfer} event. + */ + function transferFrom(address from, address to, uint256 tokenId) external; + + /** + * @dev Gives permission to `to` to transfer `tokenId` token to another account. + * The approval is cleared when the token is transferred. + * + * Only a single account can be approved at a time, so approving the zero address clears previous approvals. + * + * Requirements: + * + * - The caller must own the token or be an approved operator. + * - `tokenId` must exist. + * + * Emits an {Approval} event. + */ + function approve(address to, uint256 tokenId) external; + + /** + * @dev Approve or remove `operator` as an operator for the caller. + * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller. + * + * Requirements: + * + * - The `operator` cannot be the caller. + * + * Emits an {ApprovalForAll} event. + */ + function setApprovalForAll(address operator, bool approved) external; + + /** + * @dev Returns the account approved for `tokenId` token. + * + * Requirements: + * + * - `tokenId` must exist. + */ + function getApproved(uint256 tokenId) external view returns (address operator); + + /** + * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`. + * + * See {setApprovalForAll} + */ + function isApprovedForAll(address owner, address operator) external view returns (bool); +} + +// lib/solady/src\auth/OwnableRoles.sol + + + + + +/// @notice Simple single owner and multiroles authorization mixin. +/// @author Solady (https://github.com/vectorized/solady/blob/main/src/auth/Ownable.sol) +/// @dev While the ownable portion follows [EIP-173](https://eips.ethereum.org/EIPS/eip-173) +/// for compatibility, the nomenclature for the 2-step ownership handover and roles +/// may be unique to this codebase. +abstract contract OwnableRoles is Ownable { + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* EVENTS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev The `user`'s roles is updated to `roles`. + /// Each bit of `roles` represents whether the role is set. + event RolesUpdated(address indexed user, uint256 indexed roles); + + /// @dev `keccak256(bytes("RolesUpdated(address,uint256)"))`. + uint256 private constant _ROLES_UPDATED_EVENT_SIGNATURE = + 0x715ad5ce61fc9595c7b415289d59cf203f23a94fa06f04af7e489a0a76e1fe26; + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* STORAGE */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev The role slot of `user` is given by: + /// ``` + /// mstore(0x00, or(shl(96, user), _ROLE_SLOT_SEED)) + /// let roleSlot := keccak256(0x00, 0x20) + /// ``` + /// This automatically ignores the upper bits of the `user` in case + /// they are not clean, as well as keep the `keccak256` under 32-bytes. + /// + /// Note: This is equal to `_OWNER_SLOT_NOT` in for gas efficiency. + uint256 private constant _ROLE_SLOT_SEED = 0x8b78c6d8; + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* INTERNAL FUNCTIONS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev Overwrite the roles directly without authorization guard. + function _setRoles(address user, uint256 roles) internal virtual { + /// @solidity memory-safe-assembly + assembly { + mstore(0x0c, _ROLE_SLOT_SEED) + mstore(0x00, user) + // Store the new value. + sstore(keccak256(0x0c, 0x20), roles) + // Emit the {RolesUpdated} event. + log3(0, 0, _ROLES_UPDATED_EVENT_SIGNATURE, shr(96, mload(0x0c)), roles) + } + } + + /// @dev Updates the roles directly without authorization guard. + /// If `on` is true, each set bit of `roles` will be turned on, + /// otherwise, each set bit of `roles` will be turned off. + function _updateRoles(address user, uint256 roles, bool on) internal virtual { + /// @solidity memory-safe-assembly + assembly { + mstore(0x0c, _ROLE_SLOT_SEED) + mstore(0x00, user) + let roleSlot := keccak256(0x0c, 0x20) + // Load the current value. + let current := sload(roleSlot) + // Compute the updated roles if `on` is true. + let updated := or(current, roles) + // Compute the updated roles if `on` is false. + // Use `and` to compute the intersection of `current` and `roles`, + // `xor` it with `current` to flip the bits in the intersection. + if iszero(on) { updated := xor(current, and(current, roles)) } + // Then, store the new value. + sstore(roleSlot, updated) + // Emit the {RolesUpdated} event. + log3(0, 0, _ROLES_UPDATED_EVENT_SIGNATURE, shr(96, mload(0x0c)), updated) + } + } + + /// @dev Grants the roles directly without authorization guard. + /// Each bit of `roles` represents the role to turn on. + function _grantRoles(address user, uint256 roles) internal virtual { + _updateRoles(user, roles, true); + } + + /// @dev Removes the roles directly without authorization guard. + /// Each bit of `roles` represents the role to turn off. + function _removeRoles(address user, uint256 roles) internal virtual { + _updateRoles(user, roles, false); + } + + /// @dev Throws if the sender does not have any of the `roles`. + function _checkRoles(uint256 roles) internal view virtual { + /// @solidity memory-safe-assembly + assembly { + // Compute the role slot. + mstore(0x0c, _ROLE_SLOT_SEED) + mstore(0x00, caller()) + // Load the stored value, and if the `and` intersection + // of the value and `roles` is zero, revert. + if iszero(and(sload(keccak256(0x0c, 0x20)), roles)) { + mstore(0x00, 0x82b42900) // `Unauthorized()`. + revert(0x1c, 0x04) + } + } + } + + /// @dev Throws if the sender is not the owner, + /// and does not have any of the `roles`. + /// Checks for ownership first, then lazily checks for roles. + function _checkOwnerOrRoles(uint256 roles) internal view virtual { + /// @solidity memory-safe-assembly + assembly { + // If the caller is not the stored owner. + // Note: `_ROLE_SLOT_SEED` is equal to `_OWNER_SLOT_NOT`. + if iszero(eq(caller(), sload(not(_ROLE_SLOT_SEED)))) { + // Compute the role slot. + mstore(0x0c, _ROLE_SLOT_SEED) + mstore(0x00, caller()) + // Load the stored value, and if the `and` intersection + // of the value and `roles` is zero, revert. + if iszero(and(sload(keccak256(0x0c, 0x20)), roles)) { + mstore(0x00, 0x82b42900) // `Unauthorized()`. + revert(0x1c, 0x04) + } + } + } + } + + /// @dev Throws if the sender does not have any of the `roles`, + /// and is not the owner. + /// Checks for roles first, then lazily checks for ownership. + function _checkRolesOrOwner(uint256 roles) internal view virtual { + /// @solidity memory-safe-assembly + assembly { + // Compute the role slot. + mstore(0x0c, _ROLE_SLOT_SEED) + mstore(0x00, caller()) + // Load the stored value, and if the `and` intersection + // of the value and `roles` is zero, revert. + if iszero(and(sload(keccak256(0x0c, 0x20)), roles)) { + // If the caller is not the stored owner. + // Note: `_ROLE_SLOT_SEED` is equal to `_OWNER_SLOT_NOT`. + if iszero(eq(caller(), sload(not(_ROLE_SLOT_SEED)))) { + mstore(0x00, 0x82b42900) // `Unauthorized()`. + revert(0x1c, 0x04) + } + } + } + } + + /// @dev Convenience function to return a `roles` bitmap from an array of `ordinals`. + /// This is meant for frontends like Etherscan, and is therefore not fully optimized. + /// Not recommended to be called on-chain. + /// Made internal to conserve bytecode. Wrap it in a public function if needed. + function _rolesFromOrdinals(uint8[] memory ordinals) internal pure returns (uint256 roles) { + /// @solidity memory-safe-assembly + assembly { + for { let i := shl(5, mload(ordinals)) } i { i := sub(i, 0x20) } { + // We don't need to mask the values of `ordinals`, as Solidity + // cleans dirty upper bits when storing variables into memory. + roles := or(shl(mload(add(ordinals, i)), 1), roles) + } + } + } + + /// @dev Convenience function to return an array of `ordinals` from the `roles` bitmap. + /// This is meant for frontends like Etherscan, and is therefore not fully optimized. + /// Not recommended to be called on-chain. + /// Made internal to conserve bytecode. Wrap it in a public function if needed. + function _ordinalsFromRoles(uint256 roles) internal pure returns (uint8[] memory ordinals) { + /// @solidity memory-safe-assembly + assembly { + // Grab the pointer to the free memory. + ordinals := mload(0x40) + let ptr := add(ordinals, 0x20) + let o := 0 + // The absence of lookup tables, De Bruijn, etc., here is intentional for + // smaller bytecode, as this function is not meant to be called on-chain. + for { let t := roles } 1 {} { + mstore(ptr, o) + // `shr` 5 is equivalent to multiplying by 0x20. + // Push back into the ordinals array if the bit is set. + ptr := add(ptr, shl(5, and(t, 1))) + o := add(o, 1) + t := shr(o, roles) + if iszero(t) { break } + } + // Store the length of `ordinals`. + mstore(ordinals, shr(5, sub(ptr, add(ordinals, 0x20)))) + // Allocate the memory. + mstore(0x40, ptr) + } + } + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* PUBLIC UPDATE FUNCTIONS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev Allows the owner to grant `user` `roles`. + /// If the `user` already has a role, then it will be an no-op for the role. + function grantRoles(address user, uint256 roles) public payable virtual onlyOwner { + _grantRoles(user, roles); + } + + /// @dev Allows the owner to remove `user` `roles`. + /// If the `user` does not have a role, then it will be an no-op for the role. + function revokeRoles(address user, uint256 roles) public payable virtual onlyOwner { + _removeRoles(user, roles); + } + + /// @dev Allow the caller to remove their own roles. + /// If the caller does not have a role, then it will be an no-op for the role. + function renounceRoles(uint256 roles) public payable virtual { + _removeRoles(msg.sender, roles); + } + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* PUBLIC READ FUNCTIONS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev Returns the roles of `user`. + function rolesOf(address user) public view virtual returns (uint256 roles) { + /// @solidity memory-safe-assembly + assembly { + // Compute the role slot. + mstore(0x0c, _ROLE_SLOT_SEED) + mstore(0x00, user) + // Load the stored value. + roles := sload(keccak256(0x0c, 0x20)) + } + } + + /// @dev Returns whether `user` has any of `roles`. + function hasAnyRole(address user, uint256 roles) public view virtual returns (bool) { + return rolesOf(user) & roles != 0; + } + + /// @dev Returns whether `user` has all of `roles`. + function hasAllRoles(address user, uint256 roles) public view virtual returns (bool) { + return rolesOf(user) & roles == roles; + } + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* MODIFIERS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev Marks a function as only callable by an account with `roles`. + modifier onlyRoles(uint256 roles) virtual { + _checkRoles(roles); + _; + } + + /// @dev Marks a function as only callable by the owner or by an account + /// with `roles`. Checks for ownership first, then lazily checks for roles. + modifier onlyOwnerOrRoles(uint256 roles) virtual { + _checkOwnerOrRoles(roles); + _; + } + + /// @dev Marks a function as only callable by an account with `roles` + /// or the owner. Checks for roles first, then lazily checks for ownership. + modifier onlyRolesOrOwner(uint256 roles) virtual { + _checkRolesOrOwner(roles); + _; + } + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* ROLE CONSTANTS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + // IYKYK + + uint256 internal constant _ROLE_0 = 1 << 0; + uint256 internal constant _ROLE_1 = 1 << 1; + uint256 internal constant _ROLE_2 = 1 << 2; + uint256 internal constant _ROLE_3 = 1 << 3; + uint256 internal constant _ROLE_4 = 1 << 4; + uint256 internal constant _ROLE_5 = 1 << 5; + uint256 internal constant _ROLE_6 = 1 << 6; + uint256 internal constant _ROLE_7 = 1 << 7; + uint256 internal constant _ROLE_8 = 1 << 8; + uint256 internal constant _ROLE_9 = 1 << 9; + uint256 internal constant _ROLE_10 = 1 << 10; + uint256 internal constant _ROLE_11 = 1 << 11; + uint256 internal constant _ROLE_12 = 1 << 12; + uint256 internal constant _ROLE_13 = 1 << 13; + uint256 internal constant _ROLE_14 = 1 << 14; + uint256 internal constant _ROLE_15 = 1 << 15; + uint256 internal constant _ROLE_16 = 1 << 16; + uint256 internal constant _ROLE_17 = 1 << 17; + uint256 internal constant _ROLE_18 = 1 << 18; + uint256 internal constant _ROLE_19 = 1 << 19; + uint256 internal constant _ROLE_20 = 1 << 20; + uint256 internal constant _ROLE_21 = 1 << 21; + uint256 internal constant _ROLE_22 = 1 << 22; + uint256 internal constant _ROLE_23 = 1 << 23; + uint256 internal constant _ROLE_24 = 1 << 24; + uint256 internal constant _ROLE_25 = 1 << 25; + uint256 internal constant _ROLE_26 = 1 << 26; + uint256 internal constant _ROLE_27 = 1 << 27; + uint256 internal constant _ROLE_28 = 1 << 28; + uint256 internal constant _ROLE_29 = 1 << 29; + uint256 internal constant _ROLE_30 = 1 << 30; + uint256 internal constant _ROLE_31 = 1 << 31; + uint256 internal constant _ROLE_32 = 1 << 32; + uint256 internal constant _ROLE_33 = 1 << 33; + uint256 internal constant _ROLE_34 = 1 << 34; + uint256 internal constant _ROLE_35 = 1 << 35; + uint256 internal constant _ROLE_36 = 1 << 36; + uint256 internal constant _ROLE_37 = 1 << 37; + uint256 internal constant _ROLE_38 = 1 << 38; + uint256 internal constant _ROLE_39 = 1 << 39; + uint256 internal constant _ROLE_40 = 1 << 40; + uint256 internal constant _ROLE_41 = 1 << 41; + uint256 internal constant _ROLE_42 = 1 << 42; + uint256 internal constant _ROLE_43 = 1 << 43; + uint256 internal constant _ROLE_44 = 1 << 44; + uint256 internal constant _ROLE_45 = 1 << 45; + uint256 internal constant _ROLE_46 = 1 << 46; + uint256 internal constant _ROLE_47 = 1 << 47; + uint256 internal constant _ROLE_48 = 1 << 48; + uint256 internal constant _ROLE_49 = 1 << 49; + uint256 internal constant _ROLE_50 = 1 << 50; + uint256 internal constant _ROLE_51 = 1 << 51; + uint256 internal constant _ROLE_52 = 1 << 52; + uint256 internal constant _ROLE_53 = 1 << 53; + uint256 internal constant _ROLE_54 = 1 << 54; + uint256 internal constant _ROLE_55 = 1 << 55; + uint256 internal constant _ROLE_56 = 1 << 56; + uint256 internal constant _ROLE_57 = 1 << 57; + uint256 internal constant _ROLE_58 = 1 << 58; + uint256 internal constant _ROLE_59 = 1 << 59; + uint256 internal constant _ROLE_60 = 1 << 60; + uint256 internal constant _ROLE_61 = 1 << 61; + uint256 internal constant _ROLE_62 = 1 << 62; + uint256 internal constant _ROLE_63 = 1 << 63; + uint256 internal constant _ROLE_64 = 1 << 64; + uint256 internal constant _ROLE_65 = 1 << 65; + uint256 internal constant _ROLE_66 = 1 << 66; + uint256 internal constant _ROLE_67 = 1 << 67; + uint256 internal constant _ROLE_68 = 1 << 68; + uint256 internal constant _ROLE_69 = 1 << 69; + uint256 internal constant _ROLE_70 = 1 << 70; + uint256 internal constant _ROLE_71 = 1 << 71; + uint256 internal constant _ROLE_72 = 1 << 72; + uint256 internal constant _ROLE_73 = 1 << 73; + uint256 internal constant _ROLE_74 = 1 << 74; + uint256 internal constant _ROLE_75 = 1 << 75; + uint256 internal constant _ROLE_76 = 1 << 76; + uint256 internal constant _ROLE_77 = 1 << 77; + uint256 internal constant _ROLE_78 = 1 << 78; + uint256 internal constant _ROLE_79 = 1 << 79; + uint256 internal constant _ROLE_80 = 1 << 80; + uint256 internal constant _ROLE_81 = 1 << 81; + uint256 internal constant _ROLE_82 = 1 << 82; + uint256 internal constant _ROLE_83 = 1 << 83; + uint256 internal constant _ROLE_84 = 1 << 84; + uint256 internal constant _ROLE_85 = 1 << 85; + uint256 internal constant _ROLE_86 = 1 << 86; + uint256 internal constant _ROLE_87 = 1 << 87; + uint256 internal constant _ROLE_88 = 1 << 88; + uint256 internal constant _ROLE_89 = 1 << 89; + uint256 internal constant _ROLE_90 = 1 << 90; + uint256 internal constant _ROLE_91 = 1 << 91; + uint256 internal constant _ROLE_92 = 1 << 92; + uint256 internal constant _ROLE_93 = 1 << 93; + uint256 internal constant _ROLE_94 = 1 << 94; + uint256 internal constant _ROLE_95 = 1 << 95; + uint256 internal constant _ROLE_96 = 1 << 96; + uint256 internal constant _ROLE_97 = 1 << 97; + uint256 internal constant _ROLE_98 = 1 << 98; + uint256 internal constant _ROLE_99 = 1 << 99; + uint256 internal constant _ROLE_100 = 1 << 100; + uint256 internal constant _ROLE_101 = 1 << 101; + uint256 internal constant _ROLE_102 = 1 << 102; + uint256 internal constant _ROLE_103 = 1 << 103; + uint256 internal constant _ROLE_104 = 1 << 104; + uint256 internal constant _ROLE_105 = 1 << 105; + uint256 internal constant _ROLE_106 = 1 << 106; + uint256 internal constant _ROLE_107 = 1 << 107; + uint256 internal constant _ROLE_108 = 1 << 108; + uint256 internal constant _ROLE_109 = 1 << 109; + uint256 internal constant _ROLE_110 = 1 << 110; + uint256 internal constant _ROLE_111 = 1 << 111; + uint256 internal constant _ROLE_112 = 1 << 112; + uint256 internal constant _ROLE_113 = 1 << 113; + uint256 internal constant _ROLE_114 = 1 << 114; + uint256 internal constant _ROLE_115 = 1 << 115; + uint256 internal constant _ROLE_116 = 1 << 116; + uint256 internal constant _ROLE_117 = 1 << 117; + uint256 internal constant _ROLE_118 = 1 << 118; + uint256 internal constant _ROLE_119 = 1 << 119; + uint256 internal constant _ROLE_120 = 1 << 120; + uint256 internal constant _ROLE_121 = 1 << 121; + uint256 internal constant _ROLE_122 = 1 << 122; + uint256 internal constant _ROLE_123 = 1 << 123; + uint256 internal constant _ROLE_124 = 1 << 124; + uint256 internal constant _ROLE_125 = 1 << 125; + uint256 internal constant _ROLE_126 = 1 << 126; + uint256 internal constant _ROLE_127 = 1 << 127; + uint256 internal constant _ROLE_128 = 1 << 128; + uint256 internal constant _ROLE_129 = 1 << 129; + uint256 internal constant _ROLE_130 = 1 << 130; + uint256 internal constant _ROLE_131 = 1 << 131; + uint256 internal constant _ROLE_132 = 1 << 132; + uint256 internal constant _ROLE_133 = 1 << 133; + uint256 internal constant _ROLE_134 = 1 << 134; + uint256 internal constant _ROLE_135 = 1 << 135; + uint256 internal constant _ROLE_136 = 1 << 136; + uint256 internal constant _ROLE_137 = 1 << 137; + uint256 internal constant _ROLE_138 = 1 << 138; + uint256 internal constant _ROLE_139 = 1 << 139; + uint256 internal constant _ROLE_140 = 1 << 140; + uint256 internal constant _ROLE_141 = 1 << 141; + uint256 internal constant _ROLE_142 = 1 << 142; + uint256 internal constant _ROLE_143 = 1 << 143; + uint256 internal constant _ROLE_144 = 1 << 144; + uint256 internal constant _ROLE_145 = 1 << 145; + uint256 internal constant _ROLE_146 = 1 << 146; + uint256 internal constant _ROLE_147 = 1 << 147; + uint256 internal constant _ROLE_148 = 1 << 148; + uint256 internal constant _ROLE_149 = 1 << 149; + uint256 internal constant _ROLE_150 = 1 << 150; + uint256 internal constant _ROLE_151 = 1 << 151; + uint256 internal constant _ROLE_152 = 1 << 152; + uint256 internal constant _ROLE_153 = 1 << 153; + uint256 internal constant _ROLE_154 = 1 << 154; + uint256 internal constant _ROLE_155 = 1 << 155; + uint256 internal constant _ROLE_156 = 1 << 156; + uint256 internal constant _ROLE_157 = 1 << 157; + uint256 internal constant _ROLE_158 = 1 << 158; + uint256 internal constant _ROLE_159 = 1 << 159; + uint256 internal constant _ROLE_160 = 1 << 160; + uint256 internal constant _ROLE_161 = 1 << 161; + uint256 internal constant _ROLE_162 = 1 << 162; + uint256 internal constant _ROLE_163 = 1 << 163; + uint256 internal constant _ROLE_164 = 1 << 164; + uint256 internal constant _ROLE_165 = 1 << 165; + uint256 internal constant _ROLE_166 = 1 << 166; + uint256 internal constant _ROLE_167 = 1 << 167; + uint256 internal constant _ROLE_168 = 1 << 168; + uint256 internal constant _ROLE_169 = 1 << 169; + uint256 internal constant _ROLE_170 = 1 << 170; + uint256 internal constant _ROLE_171 = 1 << 171; + uint256 internal constant _ROLE_172 = 1 << 172; + uint256 internal constant _ROLE_173 = 1 << 173; + uint256 internal constant _ROLE_174 = 1 << 174; + uint256 internal constant _ROLE_175 = 1 << 175; + uint256 internal constant _ROLE_176 = 1 << 176; + uint256 internal constant _ROLE_177 = 1 << 177; + uint256 internal constant _ROLE_178 = 1 << 178; + uint256 internal constant _ROLE_179 = 1 << 179; + uint256 internal constant _ROLE_180 = 1 << 180; + uint256 internal constant _ROLE_181 = 1 << 181; + uint256 internal constant _ROLE_182 = 1 << 182; + uint256 internal constant _ROLE_183 = 1 << 183; + uint256 internal constant _ROLE_184 = 1 << 184; + uint256 internal constant _ROLE_185 = 1 << 185; + uint256 internal constant _ROLE_186 = 1 << 186; + uint256 internal constant _ROLE_187 = 1 << 187; + uint256 internal constant _ROLE_188 = 1 << 188; + uint256 internal constant _ROLE_189 = 1 << 189; + uint256 internal constant _ROLE_190 = 1 << 190; + uint256 internal constant _ROLE_191 = 1 << 191; + uint256 internal constant _ROLE_192 = 1 << 192; + uint256 internal constant _ROLE_193 = 1 << 193; + uint256 internal constant _ROLE_194 = 1 << 194; + uint256 internal constant _ROLE_195 = 1 << 195; + uint256 internal constant _ROLE_196 = 1 << 196; + uint256 internal constant _ROLE_197 = 1 << 197; + uint256 internal constant _ROLE_198 = 1 << 198; + uint256 internal constant _ROLE_199 = 1 << 199; + uint256 internal constant _ROLE_200 = 1 << 200; + uint256 internal constant _ROLE_201 = 1 << 201; + uint256 internal constant _ROLE_202 = 1 << 202; + uint256 internal constant _ROLE_203 = 1 << 203; + uint256 internal constant _ROLE_204 = 1 << 204; + uint256 internal constant _ROLE_205 = 1 << 205; + uint256 internal constant _ROLE_206 = 1 << 206; + uint256 internal constant _ROLE_207 = 1 << 207; + uint256 internal constant _ROLE_208 = 1 << 208; + uint256 internal constant _ROLE_209 = 1 << 209; + uint256 internal constant _ROLE_210 = 1 << 210; + uint256 internal constant _ROLE_211 = 1 << 211; + uint256 internal constant _ROLE_212 = 1 << 212; + uint256 internal constant _ROLE_213 = 1 << 213; + uint256 internal constant _ROLE_214 = 1 << 214; + uint256 internal constant _ROLE_215 = 1 << 215; + uint256 internal constant _ROLE_216 = 1 << 216; + uint256 internal constant _ROLE_217 = 1 << 217; + uint256 internal constant _ROLE_218 = 1 << 218; + uint256 internal constant _ROLE_219 = 1 << 219; + uint256 internal constant _ROLE_220 = 1 << 220; + uint256 internal constant _ROLE_221 = 1 << 221; + uint256 internal constant _ROLE_222 = 1 << 222; + uint256 internal constant _ROLE_223 = 1 << 223; + uint256 internal constant _ROLE_224 = 1 << 224; + uint256 internal constant _ROLE_225 = 1 << 225; + uint256 internal constant _ROLE_226 = 1 << 226; + uint256 internal constant _ROLE_227 = 1 << 227; + uint256 internal constant _ROLE_228 = 1 << 228; + uint256 internal constant _ROLE_229 = 1 << 229; + uint256 internal constant _ROLE_230 = 1 << 230; + uint256 internal constant _ROLE_231 = 1 << 231; + uint256 internal constant _ROLE_232 = 1 << 232; + uint256 internal constant _ROLE_233 = 1 << 233; + uint256 internal constant _ROLE_234 = 1 << 234; + uint256 internal constant _ROLE_235 = 1 << 235; + uint256 internal constant _ROLE_236 = 1 << 236; + uint256 internal constant _ROLE_237 = 1 << 237; + uint256 internal constant _ROLE_238 = 1 << 238; + uint256 internal constant _ROLE_239 = 1 << 239; + uint256 internal constant _ROLE_240 = 1 << 240; + uint256 internal constant _ROLE_241 = 1 << 241; + uint256 internal constant _ROLE_242 = 1 << 242; + uint256 internal constant _ROLE_243 = 1 << 243; + uint256 internal constant _ROLE_244 = 1 << 244; + uint256 internal constant _ROLE_245 = 1 << 245; + uint256 internal constant _ROLE_246 = 1 << 246; + uint256 internal constant _ROLE_247 = 1 << 247; + uint256 internal constant _ROLE_248 = 1 << 248; + uint256 internal constant _ROLE_249 = 1 << 249; + uint256 internal constant _ROLE_250 = 1 << 250; + uint256 internal constant _ROLE_251 = 1 << 251; + uint256 internal constant _ROLE_252 = 1 << 252; + uint256 internal constant _ROLE_253 = 1 << 253; + uint256 internal constant _ROLE_254 = 1 << 254; + uint256 internal constant _ROLE_255 = 1 << 255; +} + +// src\pookyball/IPookyball.sol + + + + + + + +/// @title PookyballMetadata +/// @notice The Pookyball rarities are represented on chain by this enum. +enum PookyballRarity { + COMMON, + RARE, + EPIC, + LEGENDARY, + MYTHIC +} + +/// @title PookyballMetadata +/// @notice Pookyballs NFT have the following features: +/// - rarity: integer enum. +/// - level: token level, can be increase by spending token experiences points (PXP). +/// - pxp: token experience points. +/// - seed: a random uint256 word provided by Chainlink VRF service that will be used by Pooky's NFT generator +/// back-end to generate the NFT visuals and in-game statistics\. +struct PookyballMetadata { + PookyballRarity rarity; + uint256 level; + uint256 pxp; + uint256 seed; +} + +/// @title IPookyball +/// @author Mathieu Bour for Pooky Labs Ltd. +/// @notice Minimal Pookyball interface. +interface IPookyball is IAccessControl, IERC2981, IERC721 { + /// Fired when the seed of a Pookyball token is set by the VRFCoordinator + event SeedSet(uint256 indexed tokenId, uint256 seed); + /// Fired when the level of a Pookyball token is changed + event LevelChanged(uint256 indexed tokenId, uint256 level); + /// Fired when the PXP of a Pookyball token is changed + event PXPChanged(uint256 indexed tokenId, uint256 amount); + + /// Thrown when the length of two parameters mismatch. Used in the mint batched function. + error ArgumentSizeMismatch(uint256 x, uint256 y); + + /// @notice PookyballMetadata of the token {tokenId}. + /// @dev Requirements: + /// - Pookyball {tokenId} should exist (minted and not burned). + function metadata(uint256 tokenId) external view returns (PookyballMetadata memory); + + /// @notice Change the secondary sale royalties receiver address. + function setERC2981Receiver(address newReceiver) external; + + /// @notice Mint a new Pookyball token with a given rarity. + function mint(address[] memory recipients, PookyballRarity[] memory rarities) + external + returns (uint256); + + /// @notice Change the level of a Pookyball token. + /// @dev Requirements: + /// - Pookyball {tokenId} should exist (minted and not burned). + function setLevel(uint256 tokenId, uint256 newLevel) external; + + /// @notice Change the PXP of a Pookyball token. + /// @dev Requirements: + /// - Pookyball {tokenId} should exist (minted and not burned). + function setPXP(uint256 tokenId, uint256 newPXP) external; +} + +// src\common/IBaseERC721A.sol + + + + + + + + + +/// @title IBaseERC721 +/// +/// @author Mathieu Bour for Pooky Labs Ltd. +interface IBaseERC721A is IERC165, IERC721A, IERC721ABurnable, IERC721AQueryable, IERC2981 { + /// Fired when the seed of a Pookyball token is set by the VRFCoordinator, + event SeedSet(uint256 indexed tokenId, uint256 seed); + + /// Thrown when the token {tokenId} does not exist. + error NonExistentToken(uint256 tokenId); + + // ----- ERC721A patches ----- + /// @dev This allow to iterate over the token ids. + function nextTokenId() external view returns (uint256); + + function supportsInterface(bytes4 interfaceId) + external + view + override(IERC165, IERC721A) + returns (bool); +} + +// src\stickers/IStickers.sol + + + + + +enum StickerRarity { + COMMON, + RARE, + EPIC, + LEGENDARY, + MYTHIC +} + +struct StickerMint { + address recipient; + StickerRarity rarity; +} + +struct StickerMetadata { + uint248 level; + StickerRarity rarity; +} + +/// @title IStickers +/// @author Mathieu Bour for Pooky Labs Ltd. +interface IStickers is IBaseERC721A { + /// Fired when the level of a Pookyball token is changed, + event LevelChanged(uint256 indexed tokenId, uint256 level); + + /// @notice StickerMetadata of the token {tokenId}. + /// @dev Requirements: + /// - Sticker {tokenId} should exist (minted and not burned). + function metadata(uint256 tokenId) external view returns (StickerMetadata memory); + + /// @notice Change the level of a Sticker token. + /// @dev Requirements: + /// - Sticker {tokenId} should exist (minted and not burned). + function setLevel(uint256 tokenId, uint248 newLevel) external; + + /// @notice Mint multiple Stickers at once. + /// @param recipient The mint recipient. + /// @param rarities The Sticker rarities. + function mint(address recipient, StickerRarity[] memory rarities) external; +} + +// src\stickers/IStickersController.sol + + + + + + +/// @notice IStickersController +/// @author Mathieu Bour for Pooky Labs Ltd. +interface IStickersController { + /// @notice Fired when a sticker is attached to a Pookyball. + event StickerAttached(uint256 stickerId, uint256 pookyballId); + /// @notice Fired when a sticker is replace from a Pookyball. + event StickerReplaced(uint256 stickerId, uint256 previousStickerId, uint256 pookyballId); + /// @notice Fired when a sticker is detached from a Pookyball. + event StickerDetached(uint256 stickerId, uint256 pookyballId); + + /// @notice Thrown when a sticker is invalid. + error InvalidSticker(uint256 stickerId); + + /// @notice The Stickers ERC-721 contract. + function stickers() external view returns (IStickers); + + /// @notice The Pookyball ERC-721 contract. + function pookyball() external view returns (IPookyball); + + /// @notice Get the Pookyball token id linked to a Sticker. + /// @param stickerId The Sticker token id. + function attachedTo(uint256 stickerId) external view returns (uint256); + + /// @notice Get the Stickers token ids attached to a Pookyball. + /// @param pookyballId The Pookyball token id. + function slots(uint256 pookyballId) external view returns (uint256[] memory); + + /// @notice Attach a sticker to a Pookyball. + /// @param stickerId The sticker token id. + /// @param pookyballId The Pookyball token id. + /// @dev Caution: no ownership checks are run. + function attach(uint256 stickerId, uint256 pookyballId) external; + + /// @notice Replace a sticker from a Pookyball, burning the previous one. + /// @param stickerId The sticker token id. + /// @param previousStickerId The previous sticker token id that will be burned. + /// @param pookyballId The Pookyball token id. + /// @dev Caution: no ownership checks are run. + function replace(uint256 stickerId, uint256 previousStickerId, uint256 pookyballId) external; + + /// @notice Detach (remove) a sticker from a Pookyball. + /// @param stickerId The Sstickerticker token id. + /// @param recepient The address when to send the detached sticker. + function detach(uint256 stickerId, address recepient) external; +} + +// src\stickers\StickersController.sol + + + + + + + + + +/// @title StickersController +/// @author Mathieu Bour for Pooky Labs Ltd. +/// +/// @notice This contract contains the relationship data between the Pookyballs and the Stickers. +/// @dev This contract only handles the Pookyball <=> Sticker association and does not run any check. +/// It also have the {Stickers-OPERATOR} role, allowing to freely move the Stickers tokens. +/// When a Sticker is linked to a Pookyball, the Sticker is transfered to this contract so the original +/// owner cannot sell the token anymore on any platform. +contract StickersController is IStickersController, OwnableRoles { + using EnumerableSet for EnumerableSet.UintSet; + + // Roles + uint256 public constant LINKER = _ROLE_0; + uint256 public constant REPLACER = _ROLE_1; + uint256 public constant REMOVER = _ROLE_2; + + mapping(uint256 => uint256) private _links; + mapping(uint256 => EnumerableSet.UintSet) private _slots; + + IPookyball public immutable pookyball; + IStickers public immutable stickers; + + constructor(IPookyball _pookyball, IStickers _stickers, address admin) { + pookyball = _pookyball; + stickers = _stickers; + + _initializeOwner(admin); + } + + /// @notice Get the Pookyball token id linked to a Sticker. + /// @param stickerId The Sticker token id. + function attachedTo(uint256 stickerId) external view returns (uint256) { + return _links[stickerId]; + } + + /// @notice Get the Sticker token ids attached to a Pookyball. + /// @param pookyballId The Pookyball token id. + function slots(uint256 pookyballId) external view returns (uint256[] memory) { + return _slots[pookyballId].values(); + } + + /// @notice Attach a Sticker to a Pookyball (internal). + /// @param stickerId The Sticker token id. + /// @param pookyballId The Pookyball token id. + /// @dev Caution: no role/ownership checks are run. + function _attach(uint256 stickerId, uint256 pookyballId) internal { + _slots[pookyballId].add(stickerId); + _links[stickerId] = pookyballId; + stickers.transferFrom(stickers.ownerOf(stickerId), address(this), stickerId); + } + + /// @notice Attach a Sticker to a Pookyball. + /// @param stickerId The Sticker token id. + /// @param pookyballId The Pookyball token id. + /// @dev Caution: no token ownership checks are run. + function attach(uint256 stickerId, uint256 pookyballId) public onlyRolesOrOwner(LINKER) { + _attach(stickerId, pookyballId); + emit StickerAttached(stickerId, pookyballId); + } + + /// @notice Replace a sticker from a Pookyball, burning the previous one. + /// @param stickerId The Sticker token id. + /// @param previousStickerId The previous Sticker token id that will be burned. + /// @param pookyballId The Pookyball token id. + /// @dev Caution: no token ownership checks are run. + function replace(uint256 stickerId, uint256 previousStickerId, uint256 pookyballId) + public + onlyRolesOrOwner(REPLACER) + { + if (!_slots[pookyballId].contains(previousStickerId)) { + revert InvalidSticker(previousStickerId); + } + + _slots[pookyballId].remove(previousStickerId); + delete _links[previousStickerId]; + stickers.burn(previousStickerId); + _attach(stickerId, pookyballId); + emit StickerReplaced(stickerId, previousStickerId, pookyballId); + } + + /// @notice Detach (remove) a Sticker from a Pookyball. + /// @param stickerId The Sticker token id. + /// @param recepient The address when to send the detached Sticker. + /// @dev Caution: no token ownership checks are run. + function detach(uint256 stickerId, address recepient) external onlyRolesOrOwner(REMOVER) { + uint256 pookyballId = _links[stickerId]; + _slots[pookyballId].remove(stickerId); + delete _links[stickerId]; + stickers.transferFrom(address(this), recepient, stickerId); + emit StickerDetached(stickerId, pookyballId); + } +} diff --git a/flattened/StickersLevelUp.sol b/flattened/StickersLevelUp.sol new file mode 100644 index 00000000..cb282991 --- /dev/null +++ b/flattened/StickersLevelUp.sol @@ -0,0 +1,2432 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0 ^0.8.17 ^0.8.21 ^0.8.4; + +// lib/ERC721A/contracts\IERC721A.sol + +// ERC721A Contracts v4.2.3 +// Creator: Chiru Labs + + + +/** + * @dev Interface of ERC721A. + */ +interface IERC721A { + /** + * The caller must own the token or be an approved operator. + */ + error ApprovalCallerNotOwnerNorApproved(); + + /** + * The token does not exist. + */ + error ApprovalQueryForNonexistentToken(); + + /** + * Cannot query the balance for the zero address. + */ + error BalanceQueryForZeroAddress(); + + /** + * Cannot mint to the zero address. + */ + error MintToZeroAddress(); + + /** + * The quantity of tokens minted must be more than zero. + */ + error MintZeroQuantity(); + + /** + * The token does not exist. + */ + error OwnerQueryForNonexistentToken(); + + /** + * The caller must own the token or be an approved operator. + */ + error TransferCallerNotOwnerNorApproved(); + + /** + * The token must be owned by `from`. + */ + error TransferFromIncorrectOwner(); + + /** + * Cannot safely transfer to a contract that does not implement the + * ERC721Receiver interface. + */ + error TransferToNonERC721ReceiverImplementer(); + + /** + * Cannot transfer to the zero address. + */ + error TransferToZeroAddress(); + + /** + * The token does not exist. + */ + error URIQueryForNonexistentToken(); + + /** + * The `quantity` minted with ERC2309 exceeds the safety limit. + */ + error MintERC2309QuantityExceedsLimit(); + + /** + * The `extraData` cannot be set on an unintialized ownership slot. + */ + error OwnershipNotInitializedForExtraData(); + + // ============================================================= + // STRUCTS + // ============================================================= + + struct TokenOwnership { + // The address of the owner. + address addr; + // Stores the start time of ownership with minimal overhead for tokenomics. + uint64 startTimestamp; + // Whether the token has been burned. + bool burned; + // Arbitrary data similar to `startTimestamp` that can be set via {_extraData}. + uint24 extraData; + } + + // ============================================================= + // TOKEN COUNTERS + // ============================================================= + + /** + * @dev Returns the total number of tokens in existence. + * Burned tokens will reduce the count. + * To get the total number of tokens minted, please see {_totalMinted}. + */ + function totalSupply() external view returns (uint256); + + // ============================================================= + // 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 30000 gas. + */ + function supportsInterface(bytes4 interfaceId) external view returns (bool); + + // ============================================================= + // IERC721 + // ============================================================= + + /** + * @dev Emitted when `tokenId` token is transferred from `from` to `to`. + */ + event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); + + /** + * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token. + */ + event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); + + /** + * @dev Emitted when `owner` enables or disables + * (`approved`) `operator` to manage all of its assets. + */ + event ApprovalForAll(address indexed owner, address indexed operator, bool approved); + + /** + * @dev Returns the number of tokens in `owner`'s account. + */ + function balanceOf(address owner) external view returns (uint256 balance); + + /** + * @dev Returns the owner of the `tokenId` token. + * + * Requirements: + * + * - `tokenId` must exist. + */ + function ownerOf(uint256 tokenId) external view returns (address owner); + + /** + * @dev Safely transfers `tokenId` token from `from` to `to`, + * checking first that contract recipients are aware of the ERC721 protocol + * to prevent tokens from being forever locked. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must exist and be owned by `from`. + * - If the caller is not `from`, it must be have been allowed to move + * this token by either {approve} or {setApprovalForAll}. + * - If `to` refers to a smart contract, it must implement + * {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. + * + * Emits a {Transfer} event. + */ + function safeTransferFrom( + address from, + address to, + uint256 tokenId, + bytes calldata data + ) external payable; + + /** + * @dev Equivalent to `safeTransferFrom(from, to, tokenId, '')`. + */ + function safeTransferFrom( + address from, + address to, + uint256 tokenId + ) external payable; + + /** + * @dev Transfers `tokenId` from `from` to `to`. + * + * WARNING: Usage of this method is discouraged, use {safeTransferFrom} + * whenever possible. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must be owned by `from`. + * - If the caller is not `from`, it must be approved to move this token + * by either {approve} or {setApprovalForAll}. + * + * Emits a {Transfer} event. + */ + function transferFrom( + address from, + address to, + uint256 tokenId + ) external payable; + + /** + * @dev Gives permission to `to` to transfer `tokenId` token to another account. + * The approval is cleared when the token is transferred. + * + * Only a single account can be approved at a time, so approving the + * zero address clears previous approvals. + * + * Requirements: + * + * - The caller must own the token or be an approved operator. + * - `tokenId` must exist. + * + * Emits an {Approval} event. + */ + function approve(address to, uint256 tokenId) external payable; + + /** + * @dev Approve or remove `operator` as an operator for the caller. + * Operators can call {transferFrom} or {safeTransferFrom} + * for any token owned by the caller. + * + * Requirements: + * + * - The `operator` cannot be the caller. + * + * Emits an {ApprovalForAll} event. + */ + function setApprovalForAll(address operator, bool _approved) external; + + /** + * @dev Returns the account approved for `tokenId` token. + * + * Requirements: + * + * - `tokenId` must exist. + */ + function getApproved(uint256 tokenId) external view returns (address operator); + + /** + * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`. + * + * See {setApprovalForAll}. + */ + function isApprovedForAll(address owner, address operator) external view returns (bool); + + // ============================================================= + // IERC721Metadata + // ============================================================= + + /** + * @dev Returns the token collection name. + */ + function name() external view returns (string memory); + + /** + * @dev Returns the token collection symbol. + */ + function symbol() external view returns (string memory); + + /** + * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token. + */ + function tokenURI(uint256 tokenId) external view returns (string memory); + + // ============================================================= + // IERC2309 + // ============================================================= + + /** + * @dev Emitted when tokens in `fromTokenId` to `toTokenId` + * (inclusive) is transferred from `from` to `to`, as defined in the + * [ERC2309](https://eips.ethereum.org/EIPS/eip-2309) standard. + * + * See {_mintERC2309} for more details. + */ + event ConsecutiveTransfer(uint256 indexed fromTokenId, uint256 toTokenId, address indexed from, address indexed to); +} + +// lib/openzeppelin-contracts/contracts\access/IAccessControl.sol + +// OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol) + + + +/** + * @dev External interface of AccessControl declared to support ERC165 detection. + */ +interface IAccessControl { + /** + * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` + * + * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite + * {RoleAdminChanged} not being emitted signaling this. + * + * _Available since v3.1._ + */ + event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole); + + /** + * @dev Emitted when `account` is granted `role`. + * + * `sender` is the account that originated the contract call, an admin role + * bearer except when using {AccessControl-_setupRole}. + */ + event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender); + + /** + * @dev Emitted when `account` is revoked `role`. + * + * `sender` is the account that originated the contract call: + * - if using `revokeRole`, it is the admin role bearer + * - if using `renounceRole`, it is the role bearer (i.e. `account`) + */ + event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender); + + /** + * @dev Returns `true` if `account` has been granted `role`. + */ + function hasRole(bytes32 role, address account) external view returns (bool); + + /** + * @dev Returns the admin role that controls `role`. See {grantRole} and + * {revokeRole}. + * + * To change a role's admin, use {AccessControl-_setRoleAdmin}. + */ + function getRoleAdmin(bytes32 role) external view returns (bytes32); + + /** + * @dev Grants `role` to `account`. + * + * If `account` had not been already granted `role`, emits a {RoleGranted} + * event. + * + * Requirements: + * + * - the caller must have ``role``'s admin role. + */ + function grantRole(bytes32 role, address account) external; + + /** + * @dev Revokes `role` from `account`. + * + * If `account` had been granted `role`, emits a {RoleRevoked} event. + * + * Requirements: + * + * - the caller must have ``role``'s admin role. + */ + function revokeRole(bytes32 role, address account) external; + + /** + * @dev Revokes `role` from the calling account. + * + * Roles are often managed via {grantRole} and {revokeRole}: this function's + * purpose is to provide a mechanism for accounts to lose their privileges + * if they are compromised (such as when a trusted device is misplaced). + * + * If the calling account had been granted `role`, emits a {RoleRevoked} + * event. + * + * Requirements: + * + * - the caller must be `account`. + */ + function renounceRole(bytes32 role, address account) external; +} + +// lib/openzeppelin-contracts/contracts\token/ERC20/IERC20.sol + +// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol) + + + +/** + * @dev Interface of the ERC20 standard as defined in the EIP. + */ +interface IERC20 { + /** + * @dev Emitted when `value` tokens are moved from one account (`from`) to + * another (`to`). + * + * Note that `value` may be zero. + */ + event Transfer(address indexed from, address indexed to, uint256 value); + + /** + * @dev Emitted when the allowance of a `spender` for an `owner` is set by + * a call to {approve}. `value` is the new allowance. + */ + event Approval(address indexed owner, address indexed spender, uint256 value); + + /** + * @dev Returns the amount of tokens in existence. + */ + function totalSupply() external view returns (uint256); + + /** + * @dev Returns the amount of tokens owned by `account`. + */ + function balanceOf(address account) external view returns (uint256); + + /** + * @dev Moves `amount` tokens from the caller's account to `to`. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * Emits a {Transfer} event. + */ + function transfer(address to, uint256 amount) external returns (bool); + + /** + * @dev Returns the remaining number of tokens that `spender` will be + * allowed to spend on behalf of `owner` through {transferFrom}. This is + * zero by default. + * + * This value changes when {approve} or {transferFrom} are called. + */ + function allowance(address owner, address spender) external view returns (uint256); + + /** + * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * IMPORTANT: Beware that changing an allowance with this method brings the risk + * that someone may use both the old and the new allowance by unfortunate + * transaction ordering. One possible solution to mitigate this race + * condition is to first reduce the spender's allowance to 0 and set the + * desired value afterwards: + * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 + * + * Emits an {Approval} event. + */ + function approve(address spender, uint256 amount) external returns (bool); + + /** + * @dev Moves `amount` tokens from `from` to `to` using the + * allowance mechanism. `amount` is then deducted from the caller's + * allowance. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * Emits a {Transfer} event. + */ + function transferFrom(address from, address to, uint256 amount) external returns (bool); +} + +// lib/openzeppelin-contracts/contracts/utils/introspection/IERC165.sol + +// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol) + + + +/** + * @dev Interface of the ERC165 standard, as defined in the + * https://eips.ethereum.org/EIPS/eip-165[EIP]. + * + * Implementers can declare support of contract interfaces, which can then be + * queried by others ({ERC165Checker}). + * + * For an implementation, see {ERC165}. + */ +interface IERC165 { + /** + * @dev Returns true if this contract implements the interface defined by + * `interfaceId`. See the corresponding + * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] + * to learn more about how these ids are created. + * + * This function call must use less than 30 000 gas. + */ + function supportsInterface(bytes4 interfaceId) external view returns (bool); +} + +// lib/solady/src/auth/Ownable.sol + + + +/// @notice Simple single owner authorization mixin. +/// @author Solady (https://github.com/vectorized/solady/blob/main/src/auth/Ownable.sol) +/// @dev While the ownable portion follows +/// [EIP-173](https://eips.ethereum.org/EIPS/eip-173) for compatibility, +/// the nomenclature for the 2-step ownership handover may be unique to this codebase. +abstract contract Ownable { + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* CUSTOM ERRORS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev The caller is not authorized to call the function. + error Unauthorized(); + + /// @dev The `newOwner` cannot be the zero address. + error NewOwnerIsZeroAddress(); + + /// @dev The `pendingOwner` does not have a valid handover request. + error NoHandoverRequest(); + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* EVENTS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev The ownership is transferred from `oldOwner` to `newOwner`. + /// This event is intentionally kept the same as OpenZeppelin's Ownable to be + /// compatible with indexers and [EIP-173](https://eips.ethereum.org/EIPS/eip-173), + /// despite it not being as lightweight as a single argument event. + event OwnershipTransferred(address indexed oldOwner, address indexed newOwner); + + /// @dev An ownership handover to `pendingOwner` has been requested. + event OwnershipHandoverRequested(address indexed pendingOwner); + + /// @dev The ownership handover to `pendingOwner` has been canceled. + event OwnershipHandoverCanceled(address indexed pendingOwner); + + /// @dev `keccak256(bytes("OwnershipTransferred(address,address)"))`. + uint256 private constant _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE = + 0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0; + + /// @dev `keccak256(bytes("OwnershipHandoverRequested(address)"))`. + uint256 private constant _OWNERSHIP_HANDOVER_REQUESTED_EVENT_SIGNATURE = + 0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d; + + /// @dev `keccak256(bytes("OwnershipHandoverCanceled(address)"))`. + uint256 private constant _OWNERSHIP_HANDOVER_CANCELED_EVENT_SIGNATURE = + 0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92; + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* STORAGE */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev The owner slot is given by: `not(_OWNER_SLOT_NOT)`. + /// It is intentionally chosen to be a high value + /// to avoid collision with lower slots. + /// The choice of manual storage layout is to enable compatibility + /// with both regular and upgradeable contracts. + uint256 private constant _OWNER_SLOT_NOT = 0x8b78c6d8; + + /// The ownership handover slot of `newOwner` is given by: + /// ``` + /// mstore(0x00, or(shl(96, user), _HANDOVER_SLOT_SEED)) + /// let handoverSlot := keccak256(0x00, 0x20) + /// ``` + /// It stores the expiry timestamp of the two-step ownership handover. + uint256 private constant _HANDOVER_SLOT_SEED = 0x389a75e1; + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* INTERNAL FUNCTIONS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev Initializes the owner directly without authorization guard. + /// This function must be called upon initialization, + /// regardless of whether the contract is upgradeable or not. + /// This is to enable generalization to both regular and upgradeable contracts, + /// and to save gas in case the initial owner is not the caller. + /// For performance reasons, this function will not check if there + /// is an existing owner. + function _initializeOwner(address newOwner) internal virtual { + /// @solidity memory-safe-assembly + assembly { + // Clean the upper 96 bits. + newOwner := shr(96, shl(96, newOwner)) + // Store the new value. + sstore(not(_OWNER_SLOT_NOT), newOwner) + // Emit the {OwnershipTransferred} event. + log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, 0, newOwner) + } + } + + /// @dev Sets the owner directly without authorization guard. + function _setOwner(address newOwner) internal virtual { + /// @solidity memory-safe-assembly + assembly { + let ownerSlot := not(_OWNER_SLOT_NOT) + // Clean the upper 96 bits. + newOwner := shr(96, shl(96, newOwner)) + // Emit the {OwnershipTransferred} event. + log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, sload(ownerSlot), newOwner) + // Store the new value. + sstore(ownerSlot, newOwner) + } + } + + /// @dev Throws if the sender is not the owner. + function _checkOwner() internal view virtual { + /// @solidity memory-safe-assembly + assembly { + // If the caller is not the stored owner, revert. + if iszero(eq(caller(), sload(not(_OWNER_SLOT_NOT)))) { + mstore(0x00, 0x82b42900) // `Unauthorized()`. + revert(0x1c, 0x04) + } + } + } + + /// @dev Returns how long a two-step ownership handover is valid for in seconds. + /// Override to return a different value if needed. + /// Made internal to conserve bytecode. Wrap it in a public function if needed. + function _ownershipHandoverValidFor() internal view virtual returns (uint64) { + return 48 * 3600; + } + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* PUBLIC UPDATE FUNCTIONS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev Allows the owner to transfer the ownership to `newOwner`. + function transferOwnership(address newOwner) public payable virtual onlyOwner { + /// @solidity memory-safe-assembly + assembly { + if iszero(shl(96, newOwner)) { + mstore(0x00, 0x7448fbae) // `NewOwnerIsZeroAddress()`. + revert(0x1c, 0x04) + } + } + _setOwner(newOwner); + } + + /// @dev Allows the owner to renounce their ownership. + function renounceOwnership() public payable virtual onlyOwner { + _setOwner(address(0)); + } + + /// @dev Request a two-step ownership handover to the caller. + /// The request will automatically expire in 48 hours (172800 seconds) by default. + function requestOwnershipHandover() public payable virtual { + unchecked { + uint256 expires = block.timestamp + _ownershipHandoverValidFor(); + /// @solidity memory-safe-assembly + assembly { + // Compute and set the handover slot to `expires`. + mstore(0x0c, _HANDOVER_SLOT_SEED) + mstore(0x00, caller()) + sstore(keccak256(0x0c, 0x20), expires) + // Emit the {OwnershipHandoverRequested} event. + log2(0, 0, _OWNERSHIP_HANDOVER_REQUESTED_EVENT_SIGNATURE, caller()) + } + } + } + + /// @dev Cancels the two-step ownership handover to the caller, if any. + function cancelOwnershipHandover() public payable virtual { + /// @solidity memory-safe-assembly + assembly { + // Compute and set the handover slot to 0. + mstore(0x0c, _HANDOVER_SLOT_SEED) + mstore(0x00, caller()) + sstore(keccak256(0x0c, 0x20), 0) + // Emit the {OwnershipHandoverCanceled} event. + log2(0, 0, _OWNERSHIP_HANDOVER_CANCELED_EVENT_SIGNATURE, caller()) + } + } + + /// @dev Allows the owner to complete the two-step ownership handover to `pendingOwner`. + /// Reverts if there is no existing ownership handover requested by `pendingOwner`. + function completeOwnershipHandover(address pendingOwner) public payable virtual onlyOwner { + /// @solidity memory-safe-assembly + assembly { + // Compute and set the handover slot to 0. + mstore(0x0c, _HANDOVER_SLOT_SEED) + mstore(0x00, pendingOwner) + let handoverSlot := keccak256(0x0c, 0x20) + // If the handover does not exist, or has expired. + if gt(timestamp(), sload(handoverSlot)) { + mstore(0x00, 0x6f5e8818) // `NoHandoverRequest()`. + revert(0x1c, 0x04) + } + // Set the handover slot to 0. + sstore(handoverSlot, 0) + } + _setOwner(pendingOwner); + } + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* PUBLIC READ FUNCTIONS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev Returns the owner of the contract. + function owner() public view virtual returns (address result) { + /// @solidity memory-safe-assembly + assembly { + result := sload(not(_OWNER_SLOT_NOT)) + } + } + + /// @dev Returns the expiry timestamp for the two-step ownership handover to `pendingOwner`. + function ownershipHandoverExpiresAt(address pendingOwner) + public + view + virtual + returns (uint256 result) + { + /// @solidity memory-safe-assembly + assembly { + // Compute the handover slot. + mstore(0x0c, _HANDOVER_SLOT_SEED) + mstore(0x00, pendingOwner) + // Load the handover slot. + result := sload(keccak256(0x0c, 0x20)) + } + } + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* MODIFIERS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev Marks a function as only callable by the owner. + modifier onlyOwner() virtual { + _checkOwner(); + _; + } +} + +// lib/solady/src\utils/ECDSA.sol + + + +/// @notice Gas optimized ECDSA wrapper. +/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/ECDSA.sol) +/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/ECDSA.sol) +/// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/cryptography/ECDSA.sol) +library ECDSA { + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* CUSTOM ERRORS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev The signature is invalid. + error InvalidSignature(); + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* CONSTANTS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev The number which `s` must be less than in order for + /// the signature to be non-malleable. + bytes32 private constant _MALLEABILITY_THRESHOLD_PLUS_ONE = + 0x7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a1; + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* RECOVERY OPERATIONS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + // Note: as of Solady version 0.0.68, these functions will + // revert upon recovery failure for more safety by default. + + /// @dev Recovers the signer's address from a message digest `hash`, + /// and the `signature`. + /// + /// This function does NOT accept EIP-2098 short form signatures. + /// Use `recover(bytes32 hash, bytes32 r, bytes32 vs)` for EIP-2098 + /// short form signatures instead. + function recover(bytes32 hash, bytes memory signature) internal view returns (address result) { + /// @solidity memory-safe-assembly + assembly { + let m := mload(0x40) // Cache the free memory pointer. + mstore(0x00, hash) + mstore(0x20, byte(0, mload(add(signature, 0x60)))) // `v`. + mstore(0x40, mload(add(signature, 0x20))) // `r`. + mstore(0x60, mload(add(signature, 0x40))) // `s`. + pop( + staticcall( + gas(), // Amount of gas left for the transaction. + and( + // If the signature is exactly 65 bytes in length. + eq(mload(signature), 65), + // If `s` in lower half order, such that the signature is not malleable. + lt(mload(0x60), _MALLEABILITY_THRESHOLD_PLUS_ONE) + ), // Address of `ecrecover`. + 0x00, // Start of input. + 0x80, // Size of input. + 0x00, // Start of output. + 0x20 // Size of output. + ) + ) + result := mload(0x00) + // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise. + if iszero(returndatasize()) { + mstore(0x00, 0x8baa579f) // `InvalidSignature()`. + revert(0x1c, 0x04) + } + mstore(0x60, 0) // Restore the zero slot. + mstore(0x40, m) // Restore the free memory pointer. + } + } + + /// @dev Recovers the signer's address from a message digest `hash`, + /// and the `signature`. + /// + /// This function does NOT accept EIP-2098 short form signatures. + /// Use `recover(bytes32 hash, bytes32 r, bytes32 vs)` for EIP-2098 + /// short form signatures instead. + function recoverCalldata(bytes32 hash, bytes calldata signature) + internal + view + returns (address result) + { + /// @solidity memory-safe-assembly + assembly { + let m := mload(0x40) // Cache the free memory pointer. + mstore(0x00, hash) + mstore(0x20, byte(0, calldataload(add(signature.offset, 0x40)))) // `v`. + calldatacopy(0x40, signature.offset, 0x40) // Copy `r` and `s`. + pop( + staticcall( + gas(), // Amount of gas left for the transaction. + and( + // If the signature is exactly 65 bytes in length. + eq(signature.length, 65), + // If `s` in lower half order, such that the signature is not malleable. + lt(mload(0x60), _MALLEABILITY_THRESHOLD_PLUS_ONE) + ), // Address of `ecrecover`. + 0x00, // Start of input. + 0x80, // Size of input. + 0x00, // Start of output. + 0x20 // Size of output. + ) + ) + result := mload(0x00) + // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise. + if iszero(returndatasize()) { + mstore(0x00, 0x8baa579f) // `InvalidSignature()`. + revert(0x1c, 0x04) + } + mstore(0x60, 0) // Restore the zero slot. + mstore(0x40, m) // Restore the free memory pointer. + } + } + + /// @dev Recovers the signer's address from a message digest `hash`, + /// and the EIP-2098 short form signature defined by `r` and `vs`. + /// + /// This function only accepts EIP-2098 short form signatures. + /// See: https://eips.ethereum.org/EIPS/eip-2098 + function recover(bytes32 hash, bytes32 r, bytes32 vs) internal view returns (address result) { + /// @solidity memory-safe-assembly + assembly { + let m := mload(0x40) // Cache the free memory pointer. + mstore(0x00, hash) + mstore(0x20, add(shr(255, vs), 27)) // `v`. + mstore(0x40, r) + mstore(0x60, shr(1, shl(1, vs))) // `s`. + pop( + staticcall( + gas(), // Amount of gas left for the transaction. + // If `s` in lower half order, such that the signature is not malleable. + lt(mload(0x60), _MALLEABILITY_THRESHOLD_PLUS_ONE), // Address of `ecrecover`. + 0x00, // Start of input. + 0x80, // Size of input. + 0x00, // Start of output. + 0x20 // Size of output. + ) + ) + result := mload(0x00) + // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise. + if iszero(returndatasize()) { + mstore(0x00, 0x8baa579f) // `InvalidSignature()`. + revert(0x1c, 0x04) + } + mstore(0x60, 0) // Restore the zero slot. + mstore(0x40, m) // Restore the free memory pointer. + } + } + + /// @dev Recovers the signer's address from a message digest `hash`, + /// and the signature defined by `v`, `r`, `s`. + function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) + internal + view + returns (address result) + { + /// @solidity memory-safe-assembly + assembly { + let m := mload(0x40) // Cache the free memory pointer. + mstore(0x00, hash) + mstore(0x20, and(v, 0xff)) + mstore(0x40, r) + mstore(0x60, s) + pop( + staticcall( + gas(), // Amount of gas left for the transaction. + // If `s` in lower half order, such that the signature is not malleable. + lt(s, _MALLEABILITY_THRESHOLD_PLUS_ONE), // Address of `ecrecover`. + 0x00, // Start of input. + 0x80, // Size of input. + 0x00, // Start of output. + 0x20 // Size of output. + ) + ) + result := mload(0x00) + // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise. + if iszero(returndatasize()) { + mstore(0x00, 0x8baa579f) // `InvalidSignature()`. + revert(0x1c, 0x04) + } + mstore(0x60, 0) // Restore the zero slot. + mstore(0x40, m) // Restore the free memory pointer. + } + } + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* TRY-RECOVER OPERATIONS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + // WARNING! + // These functions will NOT revert upon recovery failure. + // Instead, they will return the zero address upon recovery failure. + // It is critical that the returned address is NEVER compared against + // a zero address (e.g. an uninitialized address variable). + + /// @dev Recovers the signer's address from a message digest `hash`, + /// and the `signature`. + /// + /// This function does NOT accept EIP-2098 short form signatures. + /// Use `recover(bytes32 hash, bytes32 r, bytes32 vs)` for EIP-2098 + /// short form signatures instead. + function tryRecover(bytes32 hash, bytes memory signature) + internal + view + returns (address result) + { + /// @solidity memory-safe-assembly + assembly { + let m := mload(0x40) // Cache the free memory pointer. + mstore(0x00, hash) + mstore(0x20, byte(0, mload(add(signature, 0x60)))) // `v`. + mstore(0x40, mload(add(signature, 0x20))) // `r`. + mstore(0x60, mload(add(signature, 0x40))) // `s`. + pop( + staticcall( + gas(), // Amount of gas left for the transaction. + and( + // If the signature is exactly 65 bytes in length. + eq(mload(signature), 65), + // If `s` in lower half order, such that the signature is not malleable. + lt(mload(0x60), _MALLEABILITY_THRESHOLD_PLUS_ONE) + ), // Address of `ecrecover`. + 0x00, // Start of input. + 0x80, // Size of input. + 0x40, // Start of output. + 0x20 // Size of output. + ) + ) + mstore(0x60, 0) // Restore the zero slot. + // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise. + result := mload(xor(0x60, returndatasize())) + mstore(0x40, m) // Restore the free memory pointer. + } + } + + /// @dev Recovers the signer's address from a message digest `hash`, + /// and the `signature`. + /// + /// This function does NOT accept EIP-2098 short form signatures. + /// Use `recover(bytes32 hash, bytes32 r, bytes32 vs)` for EIP-2098 + /// short form signatures instead. + function tryRecoverCalldata(bytes32 hash, bytes calldata signature) + internal + view + returns (address result) + { + /// @solidity memory-safe-assembly + assembly { + let m := mload(0x40) // Cache the free memory pointer. + mstore(0x00, hash) + mstore(0x20, byte(0, calldataload(add(signature.offset, 0x40)))) // `v`. + calldatacopy(0x40, signature.offset, 0x40) // Copy `r` and `s`. + pop( + staticcall( + gas(), // Amount of gas left for the transaction. + and( + // If the signature is exactly 65 bytes in length. + eq(signature.length, 65), + // If `s` in lower half order, such that the signature is not malleable. + lt(mload(0x60), _MALLEABILITY_THRESHOLD_PLUS_ONE) + ), // Address of `ecrecover`. + 0x00, // Start of input. + 0x80, // Size of input. + 0x40, // Start of output. + 0x20 // Size of output. + ) + ) + mstore(0x60, 0) // Restore the zero slot. + // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise. + result := mload(xor(0x60, returndatasize())) + mstore(0x40, m) // Restore the free memory pointer. + } + } + + /// @dev Recovers the signer's address from a message digest `hash`, + /// and the EIP-2098 short form signature defined by `r` and `vs`. + /// + /// This function only accepts EIP-2098 short form signatures. + /// See: https://eips.ethereum.org/EIPS/eip-2098 + function tryRecover(bytes32 hash, bytes32 r, bytes32 vs) + internal + view + returns (address result) + { + /// @solidity memory-safe-assembly + assembly { + let m := mload(0x40) // Cache the free memory pointer. + mstore(0x00, hash) + mstore(0x20, add(shr(255, vs), 27)) // `v`. + mstore(0x40, r) + mstore(0x60, shr(1, shl(1, vs))) // `s`. + pop( + staticcall( + gas(), // Amount of gas left for the transaction. + // If `s` in lower half order, such that the signature is not malleable. + lt(mload(0x60), _MALLEABILITY_THRESHOLD_PLUS_ONE), // Address of `ecrecover`. + 0x00, // Start of input. + 0x80, // Size of input. + 0x40, // Start of output. + 0x20 // Size of output. + ) + ) + mstore(0x60, 0) // Restore the zero slot. + // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise. + result := mload(xor(0x60, returndatasize())) + mstore(0x40, m) // Restore the free memory pointer. + } + } + + /// @dev Recovers the signer's address from a message digest `hash`, + /// and the signature defined by `v`, `r`, `s`. + function tryRecover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) + internal + view + returns (address result) + { + /// @solidity memory-safe-assembly + assembly { + let m := mload(0x40) // Cache the free memory pointer. + mstore(0x00, hash) + mstore(0x20, and(v, 0xff)) + mstore(0x40, r) + mstore(0x60, s) + pop( + staticcall( + gas(), // Amount of gas left for the transaction. + // If `s` in lower half order, such that the signature is not malleable. + lt(s, _MALLEABILITY_THRESHOLD_PLUS_ONE), // Address of `ecrecover`. + 0x00, // Start of input. + 0x80, // Size of input. + 0x40, // Start of output. + 0x20 // Size of output. + ) + ) + mstore(0x60, 0) // Restore the zero slot. + // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise. + result := mload(xor(0x60, returndatasize())) + mstore(0x40, m) // Restore the free memory pointer. + } + } + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* HASHING OPERATIONS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev Returns an Ethereum Signed Message, created from a `hash`. + /// This produces a hash corresponding to the one signed with the + /// [`eth_sign`](https://eth.wiki/json-rpc/API#eth_sign) + /// JSON-RPC method as part of EIP-191. + function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32 result) { + /// @solidity memory-safe-assembly + assembly { + mstore(0x20, hash) // Store into scratch space for keccak256. + mstore(0x00, "\x00\x00\x00\x00\x19Ethereum Signed Message:\n32") // 28 bytes. + result := keccak256(0x04, 0x3c) // `32 * 2 - (32 - 28) = 60 = 0x3c`. + } + } + + /// @dev Returns an Ethereum Signed Message, created from `s`. + /// This produces a hash corresponding to the one signed with the + /// [`eth_sign`](https://eth.wiki/json-rpc/API#eth_sign) + /// JSON-RPC method as part of EIP-191. + /// Note: Supports lengths of `s` up to 999999 bytes. + function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32 result) { + /// @solidity memory-safe-assembly + assembly { + let sLength := mload(s) + let o := 0x20 + mstore(o, "\x19Ethereum Signed Message:\n") // 26 bytes, zero-right-padded. + mstore(0x00, 0x00) + // Convert the `s.length` to ASCII decimal representation: `base10(s.length)`. + for { let temp := sLength } 1 {} { + o := sub(o, 1) + mstore8(o, add(48, mod(temp, 10))) + temp := div(temp, 10) + if iszero(temp) { break } + } + let n := sub(0x3a, o) // Header length: `26 + 32 - o`. + // Throw an out-of-offset error (consumes all gas) if the header exceeds 32 bytes. + returndatacopy(returndatasize(), returndatasize(), gt(n, 0x20)) + mstore(s, or(mload(0x00), mload(n))) // Temporarily store the header. + result := keccak256(add(s, sub(0x20, n)), add(n, sLength)) + mstore(s, sLength) // Restore the length. + } + } + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* EMPTY CALLDATA HELPERS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev Returns an empty calldata bytes. + function emptySignature() internal pure returns (bytes calldata signature) { + /// @solidity memory-safe-assembly + assembly { + signature.length := 0 + } + } +} + +// src\common/ITreasury.sol + + + +/// @title ITreasury +/// @author Mathieu Bour for Pooky Labs Ltd. +interface ITreasury { + /// Thrown when the msg.value of the mint function does not cover the mint cost. + error InsufficientValue(uint256 expected, uint256 actual); + /// Thrown when the native transfer has failed. + error TransferFailed(address recipient, uint256 amount); + + /// Change the native currency destination address. + /// @param _treasury The new treasury address. + function changeTreasury(address _treasury) external; +} + +// lib/ERC721A/contracts\extensions/IERC721ABurnable.sol + +// ERC721A Contracts v4.2.3 +// Creator: Chiru Labs + + + + + +/** + * @dev Interface of ERC721ABurnable. + */ +interface IERC721ABurnable is IERC721A { + /** + * @dev Burns `tokenId`. See {ERC721A-_burn}. + * + * Requirements: + * + * - The caller must own `tokenId` or be an approved operator. + */ + function burn(uint256 tokenId) external; +} + +// lib/ERC721A/contracts\extensions/IERC721AQueryable.sol + +// ERC721A Contracts v4.2.3 +// Creator: Chiru Labs + + + + + +/** + * @dev Interface of ERC721AQueryable. + */ +interface IERC721AQueryable is IERC721A { + /** + * Invalid query range (`start` >= `stop`). + */ + error InvalidQueryRange(); + + /** + * @dev Returns the `TokenOwnership` struct at `tokenId` without reverting. + * + * If the `tokenId` is out of bounds: + * + * - `addr = address(0)` + * - `startTimestamp = 0` + * - `burned = false` + * - `extraData = 0` + * + * If the `tokenId` is burned: + * + * - `addr =
` + * - `startTimestamp = ` + * - `burned = true` + * - `extraData = ` + * + * Otherwise: + * + * - `addr =
` + * - `startTimestamp = ` + * - `burned = false` + * - `extraData = ` + */ + function explicitOwnershipOf(uint256 tokenId) external view returns (TokenOwnership memory); + + /** + * @dev Returns an array of `TokenOwnership` structs at `tokenIds` in order. + * See {ERC721AQueryable-explicitOwnershipOf} + */ + function explicitOwnershipsOf(uint256[] memory tokenIds) external view returns (TokenOwnership[] memory); + + /** + * @dev Returns an array of token IDs owned by `owner`, + * in the range [`start`, `stop`) + * (i.e. `start <= tokenId < stop`). + * + * This function allows for tokens to be queried if the collection + * grows too big for a single call of {ERC721AQueryable-tokensOfOwner}. + * + * Requirements: + * + * - `start < stop` + */ + function tokensOfOwnerIn( + address owner, + uint256 start, + uint256 stop + ) external view returns (uint256[] memory); + + /** + * @dev Returns an array of token IDs owned by `owner`. + * + * This function scans the ownership mapping and is O(`totalSupply`) in complexity. + * It is meant to be called off-chain. + * + * See {ERC721AQueryable-tokensOfOwnerIn} for splitting the scan into + * multiple smaller scans if the collection is large enough to cause + * an out-of-gas error (10K collections should be fine). + */ + function tokensOfOwner(address owner) external view returns (uint256[] memory); +} + +// lib/openzeppelin-contracts/contracts\interfaces/IERC165.sol + +// OpenZeppelin Contracts v4.4.1 (interfaces/IERC165.sol) + + + + + +// lib/openzeppelin-contracts/contracts\interfaces/IERC2981.sol + +// OpenZeppelin Contracts (last updated v4.9.0) (interfaces/IERC2981.sol) + + + + + +/** + * @dev Interface for the NFT Royalty Standard. + * + * A standardized way to retrieve royalty payment information for non-fungible tokens (NFTs) to enable universal + * support for royalty payments across all NFT marketplaces and ecosystem participants. + * + * _Available since v4.5._ + */ +interface IERC2981 is IERC165 { + /** + * @dev Returns how much royalty is owed and to whom, based on a sale price that may be denominated in any unit of + * exchange. The royalty amount is denominated and should be paid in that same unit of exchange. + */ + function royaltyInfo( + uint256 tokenId, + uint256 salePrice + ) external view returns (address receiver, uint256 royaltyAmount); +} + +// lib/openzeppelin-contracts/contracts\token/ERC721/IERC721.sol + +// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC721/IERC721.sol) + + + + + +/** + * @dev Required interface of an ERC721 compliant contract. + */ +interface IERC721 is IERC165 { + /** + * @dev Emitted when `tokenId` token is transferred from `from` to `to`. + */ + event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); + + /** + * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token. + */ + event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); + + /** + * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets. + */ + event ApprovalForAll(address indexed owner, address indexed operator, bool approved); + + /** + * @dev Returns the number of tokens in ``owner``'s account. + */ + function balanceOf(address owner) external view returns (uint256 balance); + + /** + * @dev Returns the owner of the `tokenId` token. + * + * Requirements: + * + * - `tokenId` must exist. + */ + function ownerOf(uint256 tokenId) external view returns (address owner); + + /** + * @dev Safely transfers `tokenId` token from `from` to `to`. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must exist and be owned by `from`. + * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. + * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. + * + * Emits a {Transfer} event. + */ + function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external; + + /** + * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients + * are aware of the ERC721 protocol to prevent tokens from being forever locked. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must exist and be owned by `from`. + * - If the caller is not `from`, it must have been allowed to move this token by either {approve} or {setApprovalForAll}. + * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. + * + * Emits a {Transfer} event. + */ + function safeTransferFrom(address from, address to, uint256 tokenId) external; + + /** + * @dev Transfers `tokenId` token from `from` to `to`. + * + * WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721 + * or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must + * understand this adds an external call which potentially creates a reentrancy vulnerability. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must be owned by `from`. + * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. + * + * Emits a {Transfer} event. + */ + function transferFrom(address from, address to, uint256 tokenId) external; + + /** + * @dev Gives permission to `to` to transfer `tokenId` token to another account. + * The approval is cleared when the token is transferred. + * + * Only a single account can be approved at a time, so approving the zero address clears previous approvals. + * + * Requirements: + * + * - The caller must own the token or be an approved operator. + * - `tokenId` must exist. + * + * Emits an {Approval} event. + */ + function approve(address to, uint256 tokenId) external; + + /** + * @dev Approve or remove `operator` as an operator for the caller. + * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller. + * + * Requirements: + * + * - The `operator` cannot be the caller. + * + * Emits an {ApprovalForAll} event. + */ + function setApprovalForAll(address operator, bool approved) external; + + /** + * @dev Returns the account approved for `tokenId` token. + * + * Requirements: + * + * - `tokenId` must exist. + */ + function getApproved(uint256 tokenId) external view returns (address operator); + + /** + * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`. + * + * See {setApprovalForAll} + */ + function isApprovedForAll(address owner, address operator) external view returns (bool); +} + +// lib/solady/src\auth/OwnableRoles.sol + + + + + +/// @notice Simple single owner and multiroles authorization mixin. +/// @author Solady (https://github.com/vectorized/solady/blob/main/src/auth/Ownable.sol) +/// @dev While the ownable portion follows [EIP-173](https://eips.ethereum.org/EIPS/eip-173) +/// for compatibility, the nomenclature for the 2-step ownership handover and roles +/// may be unique to this codebase. +abstract contract OwnableRoles is Ownable { + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* EVENTS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev The `user`'s roles is updated to `roles`. + /// Each bit of `roles` represents whether the role is set. + event RolesUpdated(address indexed user, uint256 indexed roles); + + /// @dev `keccak256(bytes("RolesUpdated(address,uint256)"))`. + uint256 private constant _ROLES_UPDATED_EVENT_SIGNATURE = + 0x715ad5ce61fc9595c7b415289d59cf203f23a94fa06f04af7e489a0a76e1fe26; + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* STORAGE */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev The role slot of `user` is given by: + /// ``` + /// mstore(0x00, or(shl(96, user), _ROLE_SLOT_SEED)) + /// let roleSlot := keccak256(0x00, 0x20) + /// ``` + /// This automatically ignores the upper bits of the `user` in case + /// they are not clean, as well as keep the `keccak256` under 32-bytes. + /// + /// Note: This is equal to `_OWNER_SLOT_NOT` in for gas efficiency. + uint256 private constant _ROLE_SLOT_SEED = 0x8b78c6d8; + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* INTERNAL FUNCTIONS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev Overwrite the roles directly without authorization guard. + function _setRoles(address user, uint256 roles) internal virtual { + /// @solidity memory-safe-assembly + assembly { + mstore(0x0c, _ROLE_SLOT_SEED) + mstore(0x00, user) + // Store the new value. + sstore(keccak256(0x0c, 0x20), roles) + // Emit the {RolesUpdated} event. + log3(0, 0, _ROLES_UPDATED_EVENT_SIGNATURE, shr(96, mload(0x0c)), roles) + } + } + + /// @dev Updates the roles directly without authorization guard. + /// If `on` is true, each set bit of `roles` will be turned on, + /// otherwise, each set bit of `roles` will be turned off. + function _updateRoles(address user, uint256 roles, bool on) internal virtual { + /// @solidity memory-safe-assembly + assembly { + mstore(0x0c, _ROLE_SLOT_SEED) + mstore(0x00, user) + let roleSlot := keccak256(0x0c, 0x20) + // Load the current value. + let current := sload(roleSlot) + // Compute the updated roles if `on` is true. + let updated := or(current, roles) + // Compute the updated roles if `on` is false. + // Use `and` to compute the intersection of `current` and `roles`, + // `xor` it with `current` to flip the bits in the intersection. + if iszero(on) { updated := xor(current, and(current, roles)) } + // Then, store the new value. + sstore(roleSlot, updated) + // Emit the {RolesUpdated} event. + log3(0, 0, _ROLES_UPDATED_EVENT_SIGNATURE, shr(96, mload(0x0c)), updated) + } + } + + /// @dev Grants the roles directly without authorization guard. + /// Each bit of `roles` represents the role to turn on. + function _grantRoles(address user, uint256 roles) internal virtual { + _updateRoles(user, roles, true); + } + + /// @dev Removes the roles directly without authorization guard. + /// Each bit of `roles` represents the role to turn off. + function _removeRoles(address user, uint256 roles) internal virtual { + _updateRoles(user, roles, false); + } + + /// @dev Throws if the sender does not have any of the `roles`. + function _checkRoles(uint256 roles) internal view virtual { + /// @solidity memory-safe-assembly + assembly { + // Compute the role slot. + mstore(0x0c, _ROLE_SLOT_SEED) + mstore(0x00, caller()) + // Load the stored value, and if the `and` intersection + // of the value and `roles` is zero, revert. + if iszero(and(sload(keccak256(0x0c, 0x20)), roles)) { + mstore(0x00, 0x82b42900) // `Unauthorized()`. + revert(0x1c, 0x04) + } + } + } + + /// @dev Throws if the sender is not the owner, + /// and does not have any of the `roles`. + /// Checks for ownership first, then lazily checks for roles. + function _checkOwnerOrRoles(uint256 roles) internal view virtual { + /// @solidity memory-safe-assembly + assembly { + // If the caller is not the stored owner. + // Note: `_ROLE_SLOT_SEED` is equal to `_OWNER_SLOT_NOT`. + if iszero(eq(caller(), sload(not(_ROLE_SLOT_SEED)))) { + // Compute the role slot. + mstore(0x0c, _ROLE_SLOT_SEED) + mstore(0x00, caller()) + // Load the stored value, and if the `and` intersection + // of the value and `roles` is zero, revert. + if iszero(and(sload(keccak256(0x0c, 0x20)), roles)) { + mstore(0x00, 0x82b42900) // `Unauthorized()`. + revert(0x1c, 0x04) + } + } + } + } + + /// @dev Throws if the sender does not have any of the `roles`, + /// and is not the owner. + /// Checks for roles first, then lazily checks for ownership. + function _checkRolesOrOwner(uint256 roles) internal view virtual { + /// @solidity memory-safe-assembly + assembly { + // Compute the role slot. + mstore(0x0c, _ROLE_SLOT_SEED) + mstore(0x00, caller()) + // Load the stored value, and if the `and` intersection + // of the value and `roles` is zero, revert. + if iszero(and(sload(keccak256(0x0c, 0x20)), roles)) { + // If the caller is not the stored owner. + // Note: `_ROLE_SLOT_SEED` is equal to `_OWNER_SLOT_NOT`. + if iszero(eq(caller(), sload(not(_ROLE_SLOT_SEED)))) { + mstore(0x00, 0x82b42900) // `Unauthorized()`. + revert(0x1c, 0x04) + } + } + } + } + + /// @dev Convenience function to return a `roles` bitmap from an array of `ordinals`. + /// This is meant for frontends like Etherscan, and is therefore not fully optimized. + /// Not recommended to be called on-chain. + /// Made internal to conserve bytecode. Wrap it in a public function if needed. + function _rolesFromOrdinals(uint8[] memory ordinals) internal pure returns (uint256 roles) { + /// @solidity memory-safe-assembly + assembly { + for { let i := shl(5, mload(ordinals)) } i { i := sub(i, 0x20) } { + // We don't need to mask the values of `ordinals`, as Solidity + // cleans dirty upper bits when storing variables into memory. + roles := or(shl(mload(add(ordinals, i)), 1), roles) + } + } + } + + /// @dev Convenience function to return an array of `ordinals` from the `roles` bitmap. + /// This is meant for frontends like Etherscan, and is therefore not fully optimized. + /// Not recommended to be called on-chain. + /// Made internal to conserve bytecode. Wrap it in a public function if needed. + function _ordinalsFromRoles(uint256 roles) internal pure returns (uint8[] memory ordinals) { + /// @solidity memory-safe-assembly + assembly { + // Grab the pointer to the free memory. + ordinals := mload(0x40) + let ptr := add(ordinals, 0x20) + let o := 0 + // The absence of lookup tables, De Bruijn, etc., here is intentional for + // smaller bytecode, as this function is not meant to be called on-chain. + for { let t := roles } 1 {} { + mstore(ptr, o) + // `shr` 5 is equivalent to multiplying by 0x20. + // Push back into the ordinals array if the bit is set. + ptr := add(ptr, shl(5, and(t, 1))) + o := add(o, 1) + t := shr(o, roles) + if iszero(t) { break } + } + // Store the length of `ordinals`. + mstore(ordinals, shr(5, sub(ptr, add(ordinals, 0x20)))) + // Allocate the memory. + mstore(0x40, ptr) + } + } + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* PUBLIC UPDATE FUNCTIONS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev Allows the owner to grant `user` `roles`. + /// If the `user` already has a role, then it will be an no-op for the role. + function grantRoles(address user, uint256 roles) public payable virtual onlyOwner { + _grantRoles(user, roles); + } + + /// @dev Allows the owner to remove `user` `roles`. + /// If the `user` does not have a role, then it will be an no-op for the role. + function revokeRoles(address user, uint256 roles) public payable virtual onlyOwner { + _removeRoles(user, roles); + } + + /// @dev Allow the caller to remove their own roles. + /// If the caller does not have a role, then it will be an no-op for the role. + function renounceRoles(uint256 roles) public payable virtual { + _removeRoles(msg.sender, roles); + } + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* PUBLIC READ FUNCTIONS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev Returns the roles of `user`. + function rolesOf(address user) public view virtual returns (uint256 roles) { + /// @solidity memory-safe-assembly + assembly { + // Compute the role slot. + mstore(0x0c, _ROLE_SLOT_SEED) + mstore(0x00, user) + // Load the stored value. + roles := sload(keccak256(0x0c, 0x20)) + } + } + + /// @dev Returns whether `user` has any of `roles`. + function hasAnyRole(address user, uint256 roles) public view virtual returns (bool) { + return rolesOf(user) & roles != 0; + } + + /// @dev Returns whether `user` has all of `roles`. + function hasAllRoles(address user, uint256 roles) public view virtual returns (bool) { + return rolesOf(user) & roles == roles; + } + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* MODIFIERS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev Marks a function as only callable by an account with `roles`. + modifier onlyRoles(uint256 roles) virtual { + _checkRoles(roles); + _; + } + + /// @dev Marks a function as only callable by the owner or by an account + /// with `roles`. Checks for ownership first, then lazily checks for roles. + modifier onlyOwnerOrRoles(uint256 roles) virtual { + _checkOwnerOrRoles(roles); + _; + } + + /// @dev Marks a function as only callable by an account with `roles` + /// or the owner. Checks for roles first, then lazily checks for ownership. + modifier onlyRolesOrOwner(uint256 roles) virtual { + _checkRolesOrOwner(roles); + _; + } + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* ROLE CONSTANTS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + // IYKYK + + uint256 internal constant _ROLE_0 = 1 << 0; + uint256 internal constant _ROLE_1 = 1 << 1; + uint256 internal constant _ROLE_2 = 1 << 2; + uint256 internal constant _ROLE_3 = 1 << 3; + uint256 internal constant _ROLE_4 = 1 << 4; + uint256 internal constant _ROLE_5 = 1 << 5; + uint256 internal constant _ROLE_6 = 1 << 6; + uint256 internal constant _ROLE_7 = 1 << 7; + uint256 internal constant _ROLE_8 = 1 << 8; + uint256 internal constant _ROLE_9 = 1 << 9; + uint256 internal constant _ROLE_10 = 1 << 10; + uint256 internal constant _ROLE_11 = 1 << 11; + uint256 internal constant _ROLE_12 = 1 << 12; + uint256 internal constant _ROLE_13 = 1 << 13; + uint256 internal constant _ROLE_14 = 1 << 14; + uint256 internal constant _ROLE_15 = 1 << 15; + uint256 internal constant _ROLE_16 = 1 << 16; + uint256 internal constant _ROLE_17 = 1 << 17; + uint256 internal constant _ROLE_18 = 1 << 18; + uint256 internal constant _ROLE_19 = 1 << 19; + uint256 internal constant _ROLE_20 = 1 << 20; + uint256 internal constant _ROLE_21 = 1 << 21; + uint256 internal constant _ROLE_22 = 1 << 22; + uint256 internal constant _ROLE_23 = 1 << 23; + uint256 internal constant _ROLE_24 = 1 << 24; + uint256 internal constant _ROLE_25 = 1 << 25; + uint256 internal constant _ROLE_26 = 1 << 26; + uint256 internal constant _ROLE_27 = 1 << 27; + uint256 internal constant _ROLE_28 = 1 << 28; + uint256 internal constant _ROLE_29 = 1 << 29; + uint256 internal constant _ROLE_30 = 1 << 30; + uint256 internal constant _ROLE_31 = 1 << 31; + uint256 internal constant _ROLE_32 = 1 << 32; + uint256 internal constant _ROLE_33 = 1 << 33; + uint256 internal constant _ROLE_34 = 1 << 34; + uint256 internal constant _ROLE_35 = 1 << 35; + uint256 internal constant _ROLE_36 = 1 << 36; + uint256 internal constant _ROLE_37 = 1 << 37; + uint256 internal constant _ROLE_38 = 1 << 38; + uint256 internal constant _ROLE_39 = 1 << 39; + uint256 internal constant _ROLE_40 = 1 << 40; + uint256 internal constant _ROLE_41 = 1 << 41; + uint256 internal constant _ROLE_42 = 1 << 42; + uint256 internal constant _ROLE_43 = 1 << 43; + uint256 internal constant _ROLE_44 = 1 << 44; + uint256 internal constant _ROLE_45 = 1 << 45; + uint256 internal constant _ROLE_46 = 1 << 46; + uint256 internal constant _ROLE_47 = 1 << 47; + uint256 internal constant _ROLE_48 = 1 << 48; + uint256 internal constant _ROLE_49 = 1 << 49; + uint256 internal constant _ROLE_50 = 1 << 50; + uint256 internal constant _ROLE_51 = 1 << 51; + uint256 internal constant _ROLE_52 = 1 << 52; + uint256 internal constant _ROLE_53 = 1 << 53; + uint256 internal constant _ROLE_54 = 1 << 54; + uint256 internal constant _ROLE_55 = 1 << 55; + uint256 internal constant _ROLE_56 = 1 << 56; + uint256 internal constant _ROLE_57 = 1 << 57; + uint256 internal constant _ROLE_58 = 1 << 58; + uint256 internal constant _ROLE_59 = 1 << 59; + uint256 internal constant _ROLE_60 = 1 << 60; + uint256 internal constant _ROLE_61 = 1 << 61; + uint256 internal constant _ROLE_62 = 1 << 62; + uint256 internal constant _ROLE_63 = 1 << 63; + uint256 internal constant _ROLE_64 = 1 << 64; + uint256 internal constant _ROLE_65 = 1 << 65; + uint256 internal constant _ROLE_66 = 1 << 66; + uint256 internal constant _ROLE_67 = 1 << 67; + uint256 internal constant _ROLE_68 = 1 << 68; + uint256 internal constant _ROLE_69 = 1 << 69; + uint256 internal constant _ROLE_70 = 1 << 70; + uint256 internal constant _ROLE_71 = 1 << 71; + uint256 internal constant _ROLE_72 = 1 << 72; + uint256 internal constant _ROLE_73 = 1 << 73; + uint256 internal constant _ROLE_74 = 1 << 74; + uint256 internal constant _ROLE_75 = 1 << 75; + uint256 internal constant _ROLE_76 = 1 << 76; + uint256 internal constant _ROLE_77 = 1 << 77; + uint256 internal constant _ROLE_78 = 1 << 78; + uint256 internal constant _ROLE_79 = 1 << 79; + uint256 internal constant _ROLE_80 = 1 << 80; + uint256 internal constant _ROLE_81 = 1 << 81; + uint256 internal constant _ROLE_82 = 1 << 82; + uint256 internal constant _ROLE_83 = 1 << 83; + uint256 internal constant _ROLE_84 = 1 << 84; + uint256 internal constant _ROLE_85 = 1 << 85; + uint256 internal constant _ROLE_86 = 1 << 86; + uint256 internal constant _ROLE_87 = 1 << 87; + uint256 internal constant _ROLE_88 = 1 << 88; + uint256 internal constant _ROLE_89 = 1 << 89; + uint256 internal constant _ROLE_90 = 1 << 90; + uint256 internal constant _ROLE_91 = 1 << 91; + uint256 internal constant _ROLE_92 = 1 << 92; + uint256 internal constant _ROLE_93 = 1 << 93; + uint256 internal constant _ROLE_94 = 1 << 94; + uint256 internal constant _ROLE_95 = 1 << 95; + uint256 internal constant _ROLE_96 = 1 << 96; + uint256 internal constant _ROLE_97 = 1 << 97; + uint256 internal constant _ROLE_98 = 1 << 98; + uint256 internal constant _ROLE_99 = 1 << 99; + uint256 internal constant _ROLE_100 = 1 << 100; + uint256 internal constant _ROLE_101 = 1 << 101; + uint256 internal constant _ROLE_102 = 1 << 102; + uint256 internal constant _ROLE_103 = 1 << 103; + uint256 internal constant _ROLE_104 = 1 << 104; + uint256 internal constant _ROLE_105 = 1 << 105; + uint256 internal constant _ROLE_106 = 1 << 106; + uint256 internal constant _ROLE_107 = 1 << 107; + uint256 internal constant _ROLE_108 = 1 << 108; + uint256 internal constant _ROLE_109 = 1 << 109; + uint256 internal constant _ROLE_110 = 1 << 110; + uint256 internal constant _ROLE_111 = 1 << 111; + uint256 internal constant _ROLE_112 = 1 << 112; + uint256 internal constant _ROLE_113 = 1 << 113; + uint256 internal constant _ROLE_114 = 1 << 114; + uint256 internal constant _ROLE_115 = 1 << 115; + uint256 internal constant _ROLE_116 = 1 << 116; + uint256 internal constant _ROLE_117 = 1 << 117; + uint256 internal constant _ROLE_118 = 1 << 118; + uint256 internal constant _ROLE_119 = 1 << 119; + uint256 internal constant _ROLE_120 = 1 << 120; + uint256 internal constant _ROLE_121 = 1 << 121; + uint256 internal constant _ROLE_122 = 1 << 122; + uint256 internal constant _ROLE_123 = 1 << 123; + uint256 internal constant _ROLE_124 = 1 << 124; + uint256 internal constant _ROLE_125 = 1 << 125; + uint256 internal constant _ROLE_126 = 1 << 126; + uint256 internal constant _ROLE_127 = 1 << 127; + uint256 internal constant _ROLE_128 = 1 << 128; + uint256 internal constant _ROLE_129 = 1 << 129; + uint256 internal constant _ROLE_130 = 1 << 130; + uint256 internal constant _ROLE_131 = 1 << 131; + uint256 internal constant _ROLE_132 = 1 << 132; + uint256 internal constant _ROLE_133 = 1 << 133; + uint256 internal constant _ROLE_134 = 1 << 134; + uint256 internal constant _ROLE_135 = 1 << 135; + uint256 internal constant _ROLE_136 = 1 << 136; + uint256 internal constant _ROLE_137 = 1 << 137; + uint256 internal constant _ROLE_138 = 1 << 138; + uint256 internal constant _ROLE_139 = 1 << 139; + uint256 internal constant _ROLE_140 = 1 << 140; + uint256 internal constant _ROLE_141 = 1 << 141; + uint256 internal constant _ROLE_142 = 1 << 142; + uint256 internal constant _ROLE_143 = 1 << 143; + uint256 internal constant _ROLE_144 = 1 << 144; + uint256 internal constant _ROLE_145 = 1 << 145; + uint256 internal constant _ROLE_146 = 1 << 146; + uint256 internal constant _ROLE_147 = 1 << 147; + uint256 internal constant _ROLE_148 = 1 << 148; + uint256 internal constant _ROLE_149 = 1 << 149; + uint256 internal constant _ROLE_150 = 1 << 150; + uint256 internal constant _ROLE_151 = 1 << 151; + uint256 internal constant _ROLE_152 = 1 << 152; + uint256 internal constant _ROLE_153 = 1 << 153; + uint256 internal constant _ROLE_154 = 1 << 154; + uint256 internal constant _ROLE_155 = 1 << 155; + uint256 internal constant _ROLE_156 = 1 << 156; + uint256 internal constant _ROLE_157 = 1 << 157; + uint256 internal constant _ROLE_158 = 1 << 158; + uint256 internal constant _ROLE_159 = 1 << 159; + uint256 internal constant _ROLE_160 = 1 << 160; + uint256 internal constant _ROLE_161 = 1 << 161; + uint256 internal constant _ROLE_162 = 1 << 162; + uint256 internal constant _ROLE_163 = 1 << 163; + uint256 internal constant _ROLE_164 = 1 << 164; + uint256 internal constant _ROLE_165 = 1 << 165; + uint256 internal constant _ROLE_166 = 1 << 166; + uint256 internal constant _ROLE_167 = 1 << 167; + uint256 internal constant _ROLE_168 = 1 << 168; + uint256 internal constant _ROLE_169 = 1 << 169; + uint256 internal constant _ROLE_170 = 1 << 170; + uint256 internal constant _ROLE_171 = 1 << 171; + uint256 internal constant _ROLE_172 = 1 << 172; + uint256 internal constant _ROLE_173 = 1 << 173; + uint256 internal constant _ROLE_174 = 1 << 174; + uint256 internal constant _ROLE_175 = 1 << 175; + uint256 internal constant _ROLE_176 = 1 << 176; + uint256 internal constant _ROLE_177 = 1 << 177; + uint256 internal constant _ROLE_178 = 1 << 178; + uint256 internal constant _ROLE_179 = 1 << 179; + uint256 internal constant _ROLE_180 = 1 << 180; + uint256 internal constant _ROLE_181 = 1 << 181; + uint256 internal constant _ROLE_182 = 1 << 182; + uint256 internal constant _ROLE_183 = 1 << 183; + uint256 internal constant _ROLE_184 = 1 << 184; + uint256 internal constant _ROLE_185 = 1 << 185; + uint256 internal constant _ROLE_186 = 1 << 186; + uint256 internal constant _ROLE_187 = 1 << 187; + uint256 internal constant _ROLE_188 = 1 << 188; + uint256 internal constant _ROLE_189 = 1 << 189; + uint256 internal constant _ROLE_190 = 1 << 190; + uint256 internal constant _ROLE_191 = 1 << 191; + uint256 internal constant _ROLE_192 = 1 << 192; + uint256 internal constant _ROLE_193 = 1 << 193; + uint256 internal constant _ROLE_194 = 1 << 194; + uint256 internal constant _ROLE_195 = 1 << 195; + uint256 internal constant _ROLE_196 = 1 << 196; + uint256 internal constant _ROLE_197 = 1 << 197; + uint256 internal constant _ROLE_198 = 1 << 198; + uint256 internal constant _ROLE_199 = 1 << 199; + uint256 internal constant _ROLE_200 = 1 << 200; + uint256 internal constant _ROLE_201 = 1 << 201; + uint256 internal constant _ROLE_202 = 1 << 202; + uint256 internal constant _ROLE_203 = 1 << 203; + uint256 internal constant _ROLE_204 = 1 << 204; + uint256 internal constant _ROLE_205 = 1 << 205; + uint256 internal constant _ROLE_206 = 1 << 206; + uint256 internal constant _ROLE_207 = 1 << 207; + uint256 internal constant _ROLE_208 = 1 << 208; + uint256 internal constant _ROLE_209 = 1 << 209; + uint256 internal constant _ROLE_210 = 1 << 210; + uint256 internal constant _ROLE_211 = 1 << 211; + uint256 internal constant _ROLE_212 = 1 << 212; + uint256 internal constant _ROLE_213 = 1 << 213; + uint256 internal constant _ROLE_214 = 1 << 214; + uint256 internal constant _ROLE_215 = 1 << 215; + uint256 internal constant _ROLE_216 = 1 << 216; + uint256 internal constant _ROLE_217 = 1 << 217; + uint256 internal constant _ROLE_218 = 1 << 218; + uint256 internal constant _ROLE_219 = 1 << 219; + uint256 internal constant _ROLE_220 = 1 << 220; + uint256 internal constant _ROLE_221 = 1 << 221; + uint256 internal constant _ROLE_222 = 1 << 222; + uint256 internal constant _ROLE_223 = 1 << 223; + uint256 internal constant _ROLE_224 = 1 << 224; + uint256 internal constant _ROLE_225 = 1 << 225; + uint256 internal constant _ROLE_226 = 1 << 226; + uint256 internal constant _ROLE_227 = 1 << 227; + uint256 internal constant _ROLE_228 = 1 << 228; + uint256 internal constant _ROLE_229 = 1 << 229; + uint256 internal constant _ROLE_230 = 1 << 230; + uint256 internal constant _ROLE_231 = 1 << 231; + uint256 internal constant _ROLE_232 = 1 << 232; + uint256 internal constant _ROLE_233 = 1 << 233; + uint256 internal constant _ROLE_234 = 1 << 234; + uint256 internal constant _ROLE_235 = 1 << 235; + uint256 internal constant _ROLE_236 = 1 << 236; + uint256 internal constant _ROLE_237 = 1 << 237; + uint256 internal constant _ROLE_238 = 1 << 238; + uint256 internal constant _ROLE_239 = 1 << 239; + uint256 internal constant _ROLE_240 = 1 << 240; + uint256 internal constant _ROLE_241 = 1 << 241; + uint256 internal constant _ROLE_242 = 1 << 242; + uint256 internal constant _ROLE_243 = 1 << 243; + uint256 internal constant _ROLE_244 = 1 << 244; + uint256 internal constant _ROLE_245 = 1 << 245; + uint256 internal constant _ROLE_246 = 1 << 246; + uint256 internal constant _ROLE_247 = 1 << 247; + uint256 internal constant _ROLE_248 = 1 << 248; + uint256 internal constant _ROLE_249 = 1 << 249; + uint256 internal constant _ROLE_250 = 1 << 250; + uint256 internal constant _ROLE_251 = 1 << 251; + uint256 internal constant _ROLE_252 = 1 << 252; + uint256 internal constant _ROLE_253 = 1 << 253; + uint256 internal constant _ROLE_254 = 1 << 254; + uint256 internal constant _ROLE_255 = 1 << 255; +} + +// src\common/Treasury.sol + + + + + + +/// @title Treasury +/// @author Mathieu Bour for Pooky Labs Ltd. +/// +/// @notice Base class for contracts that are made to receive native currency. +/// The destination address is controller by the contract owner. +abstract contract Treasury is Ownable, ITreasury { + /// The native currency destination address. + address public treasury; + + constructor(address _treasury) { + treasury = _treasury; + } + + /// @notice Forward the funds to the treasury wallet at the end of the transaction. + /// Since `treasury` is a trusted address, this modifier should not lead to any re-entrancy issue. + modifier forwarder() { + _; + + uint256 value = address(this).balance; + (bool sent,) = treasury.call{ value: value }(""); + if (!sent) { + revert TransferFailed(treasury, value); + } + } + + /// Change the native currency destination address. + /// @param _treasury The new treasury address. + function changeTreasury(address _treasury) external onlyOwner { + treasury = _treasury; + } +} + +// src\tokens/IPOK.sol + + + + + + +/// @title IPOK +/// @author Mathieu Bour, Dusan Zdravkovic for Pooky Labs Ltd. +/// +/// @notice Minimal $POK ERC20 token interface. +interface IPOK is IAccessControl, IERC20 { + /// @notice Mint an arbitrary amount of $POK to an account. + /// @dev Requirements: + /// - only MINTER role can mint $POK tokens + function mint(address to, uint256 amount) external; + + /// @notice Burn an arbitrary amount of $POK of an sender account. + /// It is acknowledged that burning directly from the user wallet is anti-pattern + /// but since $POK is soulbounded, this allow to skip the ERC20 approve call. + /// @dev Requirements: + /// - only BURNER role can burn $POK tokens + function burn(address to, uint256 amount) external; +} + +// src\common/Signer.sol + + + + + + +/// @title Signer +/// @author Mathieu Bour for Pooky Labs Ltd. +/// +/// @dev Provide the `verify` function and the `onlyVerify` modifier to child contracts. +abstract contract Signer is OwnableRoles { + using ECDSA for bytes32; + + uint256 public constant SIGNER = _ROLE_42; + + /// Thrown when the signature is invalid. + error InvalidSignature(); + + constructor(address signer) { + _grantRoles(signer, SIGNER); + } + + /// @notice Ensure that `data` has been signed by a `SIGNER` using the `proof`. + function verify(bytes memory data, bytes calldata proof) internal view { + // Generate the signed message from the tokenId and currentPXP + bytes32 hash = keccak256(data).toEthSignedMessageHash(); + + if (!hasAllRoles(hash.recoverCalldata(proof), SIGNER)) { + revert InvalidSignature(); + } + } + + /// @notice Modifier version of the `verify` function. + modifier onlyVerify(bytes memory data, bytes calldata proof) { + verify(data, proof); + _; + } +} + +// src\pookyball/IPookyball.sol + + + + + + + +/// @title PookyballMetadata +/// @notice The Pookyball rarities are represented on chain by this enum. +enum PookyballRarity { + COMMON, + RARE, + EPIC, + LEGENDARY, + MYTHIC +} + +/// @title PookyballMetadata +/// @notice Pookyballs NFT have the following features: +/// - rarity: integer enum. +/// - level: token level, can be increase by spending token experiences points (PXP). +/// - pxp: token experience points. +/// - seed: a random uint256 word provided by Chainlink VRF service that will be used by Pooky's NFT generator +/// back-end to generate the NFT visuals and in-game statistics\. +struct PookyballMetadata { + PookyballRarity rarity; + uint256 level; + uint256 pxp; + uint256 seed; +} + +/// @title IPookyball +/// @author Mathieu Bour for Pooky Labs Ltd. +/// @notice Minimal Pookyball interface. +interface IPookyball is IAccessControl, IERC2981, IERC721 { + /// Fired when the seed of a Pookyball token is set by the VRFCoordinator + event SeedSet(uint256 indexed tokenId, uint256 seed); + /// Fired when the level of a Pookyball token is changed + event LevelChanged(uint256 indexed tokenId, uint256 level); + /// Fired when the PXP of a Pookyball token is changed + event PXPChanged(uint256 indexed tokenId, uint256 amount); + + /// Thrown when the length of two parameters mismatch. Used in the mint batched function. + error ArgumentSizeMismatch(uint256 x, uint256 y); + + /// @notice PookyballMetadata of the token {tokenId}. + /// @dev Requirements: + /// - Pookyball {tokenId} should exist (minted and not burned). + function metadata(uint256 tokenId) external view returns (PookyballMetadata memory); + + /// @notice Change the secondary sale royalties receiver address. + function setERC2981Receiver(address newReceiver) external; + + /// @notice Mint a new Pookyball token with a given rarity. + function mint(address[] memory recipients, PookyballRarity[] memory rarities) + external + returns (uint256); + + /// @notice Change the level of a Pookyball token. + /// @dev Requirements: + /// - Pookyball {tokenId} should exist (minted and not burned). + function setLevel(uint256 tokenId, uint256 newLevel) external; + + /// @notice Change the PXP of a Pookyball token. + /// @dev Requirements: + /// - Pookyball {tokenId} should exist (minted and not burned). + function setPXP(uint256 tokenId, uint256 newPXP) external; +} + +// src\common/IBaseERC721A.sol + + + + + + + + + +/// @title IBaseERC721 +/// +/// @author Mathieu Bour for Pooky Labs Ltd. +interface IBaseERC721A is IERC165, IERC721A, IERC721ABurnable, IERC721AQueryable, IERC2981 { + /// Fired when the seed of a Pookyball token is set by the VRFCoordinator, + event SeedSet(uint256 indexed tokenId, uint256 seed); + + /// Thrown when the token {tokenId} does not exist. + error NonExistentToken(uint256 tokenId); + + // ----- ERC721A patches ----- + /// @dev This allow to iterate over the token ids. + function nextTokenId() external view returns (uint256); + + function supportsInterface(bytes4 interfaceId) + external + view + override(IERC165, IERC721A) + returns (bool); +} + +// src\stickers/IStickers.sol + + + + + +enum StickerRarity { + COMMON, + RARE, + EPIC, + LEGENDARY, + MYTHIC +} + +struct StickerMint { + address recipient; + StickerRarity rarity; +} + +struct StickerMetadata { + uint248 level; + StickerRarity rarity; +} + +/// @title IStickers +/// @author Mathieu Bour for Pooky Labs Ltd. +interface IStickers is IBaseERC721A { + /// Fired when the level of a Pookyball token is changed, + event LevelChanged(uint256 indexed tokenId, uint256 level); + + /// @notice StickerMetadata of the token {tokenId}. + /// @dev Requirements: + /// - Sticker {tokenId} should exist (minted and not burned). + function metadata(uint256 tokenId) external view returns (StickerMetadata memory); + + /// @notice Change the level of a Sticker token. + /// @dev Requirements: + /// - Sticker {tokenId} should exist (minted and not burned). + function setLevel(uint256 tokenId, uint248 newLevel) external; + + /// @notice Mint multiple Stickers at once. + /// @param recipient The mint recipient. + /// @param rarities The Sticker rarities. + function mint(address recipient, StickerRarity[] memory rarities) external; +} + +// src\common/LevelUp.sol + + + + + + + + + + +struct Pricing { + uint256 requiredPXP; + uint256 remainingPXP; + uint256 newLevel; + uint256 gapPOK; + uint256 feePOK; +} + +/// @title LevelUp +/// @author Mathieu Bour for Pooky Labs Ltd. +/// +/// @notice Base level up contract for tokens using exponential level growth, POK/NAT integration and offchain PXP. +/// @dev Implemented roles: +/// - Owner: allowed to change the pricing +/// - `SIGNER`: allowed to sign the current PXP +abstract contract LevelUp is OwnableRoles, Signer, Treasury { + uint256 public constant PXP_DECIMALS = 18; + uint256 public constant BASE_RATIO = 10000; + + /// @notice How much PXP is necessary is required to pass to the level 0 => 1. + uint256 public basePXP; + + /// @notice How much POK is 1 PXP point (over 10000). + uint256 public ratePXP_POK = 1250; + + /// @notice How much POK is 1 native currency (over 10000). + uint256 public rateNAT_POK = 350; + + /// @notice Level PXP growth factor (over 10000). + /// Example: 10750 means that every level requires 7.5% more PXP that the previous one. + uint256 public growth = 10750; + + /// @notice The POK fee required to pass the level (over 10000). + /// Example: 800 means that every level requires 8% of the level PXP in POK. + uint256 public fee = 800; + + /// @notice The POK token destination address. + IPOK public immutable pok; + + mapping(uint256 => uint256) public slots; + + /// Thrown when an account tries to level a ball above its maximum level. + error MaximumLevelReached(uint256 tokenId, uint256 maxLevel); + /// Thrown when an account does own enough $POK token to pay the level up fee + error InsufficientPOK(uint256 expected, uint256 actual); + + constructor( + IPOK _pok, + address admin, + address _signer, + address _treasury, + uint256 _basePXP, + uint256 precompute + ) Signer(_signer) Treasury(_treasury) { + pok = _pok; + _initializeOwner(admin); + basePXP = _basePXP; + slots[1] = _basePXP; + compute(2, precompute); + } + + function compute(uint256 from, uint256 to) public { + for (uint256 i = from; i <= to;) { + slots[i] = slots[i - 1] * growth / 10000; + unchecked { + i++; + } + } + } + + /// Change how much PXP is necessary is required to pass to the level 0 => 1. + /// @param _basePXP The new base PXP value. + function changeBasePXP(uint256 _basePXP) external onlyOwner { + basePXP = _basePXP; + } + + /// Change how much POK is 1 PXP point (over 10000). + /// @param _ratePXP_POK The new PXP/POK rate value. + function changeRatePXP_POK(uint256 _ratePXP_POK) external onlyOwner { + ratePXP_POK = _ratePXP_POK; + } + + /// Change how much POK is 1 native currency (over 10000). + /// @param _rateNAT_POK The new NAT/POK rate value. + function changeRateNAT_POK(uint256 _rateNAT_POK) external onlyOwner { + rateNAT_POK = _rateNAT_POK; + } + + /// Change the level PXP growth factor. + /// @param _growth The new growth factor. + function changeGrowth(uint256 _growth) external onlyOwner { + growth = _growth; + } + + /// Change the POK fee required to pass the level. + /// @param _fee The new POK fee. + function changeFee(uint256 _fee) external onlyOwner { + fee = _fee; + } + + /// @notice Get the levelling parameters for a given token. + /// @param tokenId The token id. + /// @return currentLevel The current token level. + /// @return maxLevel The maximum allowed level. + function getParams(uint256 tokenId) + public + virtual + returns (uint256 currentLevel, uint256 maxLevel); + + /// Apply the new level and PXP change. + /// @param tokenId The token id. + /// @param newLevel The new level. + /// @param newPXP The new PXP amount. + function _apply(uint256 tokenId, uint256 newLevel, uint256 newPXP) internal virtual; + + /// Compute the level up pricing given the token parameters. + /// @param currentLevel The token current level. + /// @param currentPXP The token current PXP. + /// @param increase The number of level to increase. + /// @param value The transaction value in native currency. + function getPricing(uint256 currentLevel, uint256 currentPXP, uint256 increase, uint256 value) + public + view + returns (Pricing memory pricing) + { + for (uint256 i = 1; i <= increase; i++) { + pricing.requiredPXP += slots[currentLevel + i]; + } + + if (pricing.requiredPXP > currentPXP) { + pricing.gapPOK = (pricing.requiredPXP - currentPXP) * ratePXP_POK / BASE_RATIO; + } else { + pricing.remainingPXP = currentPXP - pricing.requiredPXP; + } + + pricing.feePOK = pricing.requiredPXP * fee / BASE_RATIO; + uint256 coverPOK = value * BASE_RATIO / rateNAT_POK; + + if (pricing.feePOK > coverPOK) { + pricing.feePOK -= coverPOK; + } else { + pricing.feePOK = 0; + } + + pricing.newLevel = currentLevel + increase; + } + + /// Level up a token with offchain PXP validation. + /// @param tokenId The token id. + /// @param increase The number of levels to increase. + /// @param currentPXP The token current PXP. + /// @param proof The signature of `abi.encode(tokenId, currentLevel, currentPXP, address(this))`. + function levelUp(uint256 tokenId, uint256 increase, uint256 currentPXP, bytes calldata proof) + external + payable + forwarder + { + (uint256 currentLevel, uint256 maxLevel) = getParams(tokenId); + if (currentLevel + increase > maxLevel) { + revert MaximumLevelReached(tokenId, maxLevel); + } + + verify(abi.encode(tokenId, currentLevel, currentPXP, address(this)), proof); + + Pricing memory pricing = getPricing(currentLevel, currentPXP, increase, msg.value); + uint256 requiredPOK = pricing.gapPOK + pricing.feePOK; + + uint256 balancePOK = pok.balanceOf(msg.sender); + if (requiredPOK > balancePOK) { + revert InsufficientPOK(requiredPOK, balancePOK); + } + + // Burn $POK tokens + pok.burn(msg.sender, requiredPOK); + + _apply(tokenId, pricing.newLevel, pricing.remainingPXP); + } +} + +// src\stickers\StickersLevelUp.sol + + + + + + + +/// @title StickersLevelUp +/// @author Mathieu Bour for Pooky Labs Ltd. +/// +/// @notice Allow to level up Pooky Stickers tokens. +contract StickersLevelUp is LevelUp { + /// The Stickers contract. + IStickers stickers; + + constructor(IStickers _stickers, IPOK _pok, address admin, address _signer, address _treasury) + LevelUp(_pok, admin, _signer, _treasury, 20e18, 120) + { + stickers = _stickers; + } + + /// @notice Get the levelling parameters for a given token. + /// @param tokenId The token id. + /// @return currentLevel The current token level. + /// @return maxLevel The maximum allowed level. + function getParams(uint256 tokenId) public view override returns (uint256, uint256 maxLevel) { + StickerMetadata memory metadata = stickers.metadata(tokenId); + + if (metadata.rarity == StickerRarity.COMMON) { + maxLevel = 40; + } else if (metadata.rarity == StickerRarity.RARE) { + maxLevel = 60; + } else if (metadata.rarity == StickerRarity.EPIC) { + maxLevel = 80; + } else if (metadata.rarity == StickerRarity.LEGENDARY) { + maxLevel = 100; + } else if (metadata.rarity == StickerRarity.MYTHIC) { + maxLevel = 120; + } + + return (uint256(metadata.level), maxLevel); + } + + function _apply(uint256 tokenId, uint256 newLevel, uint256) internal virtual override { + stickers.setLevel(tokenId, uint248(newLevel)); // Safe cast, restricted by maxLevel above + } +} diff --git a/flattened/StickersManager.sol b/flattened/StickersManager.sol new file mode 100644 index 00000000..65c305fe --- /dev/null +++ b/flattened/StickersManager.sol @@ -0,0 +1,965 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0 ^0.8.17 ^0.8.21 ^0.8.4; + +// lib/ERC721A/contracts\IERC721A.sol + +// ERC721A Contracts v4.2.3 +// Creator: Chiru Labs + + + +/** + * @dev Interface of ERC721A. + */ +interface IERC721A { + /** + * The caller must own the token or be an approved operator. + */ + error ApprovalCallerNotOwnerNorApproved(); + + /** + * The token does not exist. + */ + error ApprovalQueryForNonexistentToken(); + + /** + * Cannot query the balance for the zero address. + */ + error BalanceQueryForZeroAddress(); + + /** + * Cannot mint to the zero address. + */ + error MintToZeroAddress(); + + /** + * The quantity of tokens minted must be more than zero. + */ + error MintZeroQuantity(); + + /** + * The token does not exist. + */ + error OwnerQueryForNonexistentToken(); + + /** + * The caller must own the token or be an approved operator. + */ + error TransferCallerNotOwnerNorApproved(); + + /** + * The token must be owned by `from`. + */ + error TransferFromIncorrectOwner(); + + /** + * Cannot safely transfer to a contract that does not implement the + * ERC721Receiver interface. + */ + error TransferToNonERC721ReceiverImplementer(); + + /** + * Cannot transfer to the zero address. + */ + error TransferToZeroAddress(); + + /** + * The token does not exist. + */ + error URIQueryForNonexistentToken(); + + /** + * The `quantity` minted with ERC2309 exceeds the safety limit. + */ + error MintERC2309QuantityExceedsLimit(); + + /** + * The `extraData` cannot be set on an unintialized ownership slot. + */ + error OwnershipNotInitializedForExtraData(); + + // ============================================================= + // STRUCTS + // ============================================================= + + struct TokenOwnership { + // The address of the owner. + address addr; + // Stores the start time of ownership with minimal overhead for tokenomics. + uint64 startTimestamp; + // Whether the token has been burned. + bool burned; + // Arbitrary data similar to `startTimestamp` that can be set via {_extraData}. + uint24 extraData; + } + + // ============================================================= + // TOKEN COUNTERS + // ============================================================= + + /** + * @dev Returns the total number of tokens in existence. + * Burned tokens will reduce the count. + * To get the total number of tokens minted, please see {_totalMinted}. + */ + function totalSupply() external view returns (uint256); + + // ============================================================= + // 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 30000 gas. + */ + function supportsInterface(bytes4 interfaceId) external view returns (bool); + + // ============================================================= + // IERC721 + // ============================================================= + + /** + * @dev Emitted when `tokenId` token is transferred from `from` to `to`. + */ + event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); + + /** + * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token. + */ + event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); + + /** + * @dev Emitted when `owner` enables or disables + * (`approved`) `operator` to manage all of its assets. + */ + event ApprovalForAll(address indexed owner, address indexed operator, bool approved); + + /** + * @dev Returns the number of tokens in `owner`'s account. + */ + function balanceOf(address owner) external view returns (uint256 balance); + + /** + * @dev Returns the owner of the `tokenId` token. + * + * Requirements: + * + * - `tokenId` must exist. + */ + function ownerOf(uint256 tokenId) external view returns (address owner); + + /** + * @dev Safely transfers `tokenId` token from `from` to `to`, + * checking first that contract recipients are aware of the ERC721 protocol + * to prevent tokens from being forever locked. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must exist and be owned by `from`. + * - If the caller is not `from`, it must be have been allowed to move + * this token by either {approve} or {setApprovalForAll}. + * - If `to` refers to a smart contract, it must implement + * {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. + * + * Emits a {Transfer} event. + */ + function safeTransferFrom( + address from, + address to, + uint256 tokenId, + bytes calldata data + ) external payable; + + /** + * @dev Equivalent to `safeTransferFrom(from, to, tokenId, '')`. + */ + function safeTransferFrom( + address from, + address to, + uint256 tokenId + ) external payable; + + /** + * @dev Transfers `tokenId` from `from` to `to`. + * + * WARNING: Usage of this method is discouraged, use {safeTransferFrom} + * whenever possible. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must be owned by `from`. + * - If the caller is not `from`, it must be approved to move this token + * by either {approve} or {setApprovalForAll}. + * + * Emits a {Transfer} event. + */ + function transferFrom( + address from, + address to, + uint256 tokenId + ) external payable; + + /** + * @dev Gives permission to `to` to transfer `tokenId` token to another account. + * The approval is cleared when the token is transferred. + * + * Only a single account can be approved at a time, so approving the + * zero address clears previous approvals. + * + * Requirements: + * + * - The caller must own the token or be an approved operator. + * - `tokenId` must exist. + * + * Emits an {Approval} event. + */ + function approve(address to, uint256 tokenId) external payable; + + /** + * @dev Approve or remove `operator` as an operator for the caller. + * Operators can call {transferFrom} or {safeTransferFrom} + * for any token owned by the caller. + * + * Requirements: + * + * - The `operator` cannot be the caller. + * + * Emits an {ApprovalForAll} event. + */ + function setApprovalForAll(address operator, bool _approved) external; + + /** + * @dev Returns the account approved for `tokenId` token. + * + * Requirements: + * + * - `tokenId` must exist. + */ + function getApproved(uint256 tokenId) external view returns (address operator); + + /** + * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`. + * + * See {setApprovalForAll}. + */ + function isApprovedForAll(address owner, address operator) external view returns (bool); + + // ============================================================= + // IERC721Metadata + // ============================================================= + + /** + * @dev Returns the token collection name. + */ + function name() external view returns (string memory); + + /** + * @dev Returns the token collection symbol. + */ + function symbol() external view returns (string memory); + + /** + * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token. + */ + function tokenURI(uint256 tokenId) external view returns (string memory); + + // ============================================================= + // IERC2309 + // ============================================================= + + /** + * @dev Emitted when tokens in `fromTokenId` to `toTokenId` + * (inclusive) is transferred from `from` to `to`, as defined in the + * [ERC2309](https://eips.ethereum.org/EIPS/eip-2309) standard. + * + * See {_mintERC2309} for more details. + */ + event ConsecutiveTransfer(uint256 indexed fromTokenId, uint256 toTokenId, address indexed from, address indexed to); +} + +// lib/openzeppelin-contracts/contracts\access/IAccessControl.sol + +// OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol) + + + +/** + * @dev External interface of AccessControl declared to support ERC165 detection. + */ +interface IAccessControl { + /** + * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` + * + * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite + * {RoleAdminChanged} not being emitted signaling this. + * + * _Available since v3.1._ + */ + event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole); + + /** + * @dev Emitted when `account` is granted `role`. + * + * `sender` is the account that originated the contract call, an admin role + * bearer except when using {AccessControl-_setupRole}. + */ + event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender); + + /** + * @dev Emitted when `account` is revoked `role`. + * + * `sender` is the account that originated the contract call: + * - if using `revokeRole`, it is the admin role bearer + * - if using `renounceRole`, it is the role bearer (i.e. `account`) + */ + event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender); + + /** + * @dev Returns `true` if `account` has been granted `role`. + */ + function hasRole(bytes32 role, address account) external view returns (bool); + + /** + * @dev Returns the admin role that controls `role`. See {grantRole} and + * {revokeRole}. + * + * To change a role's admin, use {AccessControl-_setRoleAdmin}. + */ + function getRoleAdmin(bytes32 role) external view returns (bytes32); + + /** + * @dev Grants `role` to `account`. + * + * If `account` had not been already granted `role`, emits a {RoleGranted} + * event. + * + * Requirements: + * + * - the caller must have ``role``'s admin role. + */ + function grantRole(bytes32 role, address account) external; + + /** + * @dev Revokes `role` from `account`. + * + * If `account` had been granted `role`, emits a {RoleRevoked} event. + * + * Requirements: + * + * - the caller must have ``role``'s admin role. + */ + function revokeRole(bytes32 role, address account) external; + + /** + * @dev Revokes `role` from the calling account. + * + * Roles are often managed via {grantRole} and {revokeRole}: this function's + * purpose is to provide a mechanism for accounts to lose their privileges + * if they are compromised (such as when a trusted device is misplaced). + * + * If the calling account had been granted `role`, emits a {RoleRevoked} + * event. + * + * Requirements: + * + * - the caller must be `account`. + */ + function renounceRole(bytes32 role, address account) external; +} + +// lib/openzeppelin-contracts/contracts/utils/introspection/IERC165.sol + +// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol) + + + +/** + * @dev Interface of the ERC165 standard, as defined in the + * https://eips.ethereum.org/EIPS/eip-165[EIP]. + * + * Implementers can declare support of contract interfaces, which can then be + * queried by others ({ERC165Checker}). + * + * For an implementation, see {ERC165}. + */ +interface IERC165 { + /** + * @dev Returns true if this contract implements the interface defined by + * `interfaceId`. See the corresponding + * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] + * to learn more about how these ids are created. + * + * This function call must use less than 30 000 gas. + */ + function supportsInterface(bytes4 interfaceId) external view returns (bool); +} + +// lib/ERC721A/contracts\extensions/IERC721ABurnable.sol + +// ERC721A Contracts v4.2.3 +// Creator: Chiru Labs + + + + + +/** + * @dev Interface of ERC721ABurnable. + */ +interface IERC721ABurnable is IERC721A { + /** + * @dev Burns `tokenId`. See {ERC721A-_burn}. + * + * Requirements: + * + * - The caller must own `tokenId` or be an approved operator. + */ + function burn(uint256 tokenId) external; +} + +// lib/ERC721A/contracts\extensions/IERC721AQueryable.sol + +// ERC721A Contracts v4.2.3 +// Creator: Chiru Labs + + + + + +/** + * @dev Interface of ERC721AQueryable. + */ +interface IERC721AQueryable is IERC721A { + /** + * Invalid query range (`start` >= `stop`). + */ + error InvalidQueryRange(); + + /** + * @dev Returns the `TokenOwnership` struct at `tokenId` without reverting. + * + * If the `tokenId` is out of bounds: + * + * - `addr = address(0)` + * - `startTimestamp = 0` + * - `burned = false` + * - `extraData = 0` + * + * If the `tokenId` is burned: + * + * - `addr =
` + * - `startTimestamp = ` + * - `burned = true` + * - `extraData = ` + * + * Otherwise: + * + * - `addr =
` + * - `startTimestamp = ` + * - `burned = false` + * - `extraData = ` + */ + function explicitOwnershipOf(uint256 tokenId) external view returns (TokenOwnership memory); + + /** + * @dev Returns an array of `TokenOwnership` structs at `tokenIds` in order. + * See {ERC721AQueryable-explicitOwnershipOf} + */ + function explicitOwnershipsOf(uint256[] memory tokenIds) external view returns (TokenOwnership[] memory); + + /** + * @dev Returns an array of token IDs owned by `owner`, + * in the range [`start`, `stop`) + * (i.e. `start <= tokenId < stop`). + * + * This function allows for tokens to be queried if the collection + * grows too big for a single call of {ERC721AQueryable-tokensOfOwner}. + * + * Requirements: + * + * - `start < stop` + */ + function tokensOfOwnerIn( + address owner, + uint256 start, + uint256 stop + ) external view returns (uint256[] memory); + + /** + * @dev Returns an array of token IDs owned by `owner`. + * + * This function scans the ownership mapping and is O(`totalSupply`) in complexity. + * It is meant to be called off-chain. + * + * See {ERC721AQueryable-tokensOfOwnerIn} for splitting the scan into + * multiple smaller scans if the collection is large enough to cause + * an out-of-gas error (10K collections should be fine). + */ + function tokensOfOwner(address owner) external view returns (uint256[] memory); +} + +// lib/openzeppelin-contracts/contracts\interfaces/IERC165.sol + +// OpenZeppelin Contracts v4.4.1 (interfaces/IERC165.sol) + + + + + +// lib/openzeppelin-contracts/contracts\interfaces/IERC2981.sol + +// OpenZeppelin Contracts (last updated v4.9.0) (interfaces/IERC2981.sol) + + + + + +/** + * @dev Interface for the NFT Royalty Standard. + * + * A standardized way to retrieve royalty payment information for non-fungible tokens (NFTs) to enable universal + * support for royalty payments across all NFT marketplaces and ecosystem participants. + * + * _Available since v4.5._ + */ +interface IERC2981 is IERC165 { + /** + * @dev Returns how much royalty is owed and to whom, based on a sale price that may be denominated in any unit of + * exchange. The royalty amount is denominated and should be paid in that same unit of exchange. + */ + function royaltyInfo( + uint256 tokenId, + uint256 salePrice + ) external view returns (address receiver, uint256 royaltyAmount); +} + +// lib/openzeppelin-contracts/contracts\token/ERC721/IERC721.sol + +// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC721/IERC721.sol) + + + + + +/** + * @dev Required interface of an ERC721 compliant contract. + */ +interface IERC721 is IERC165 { + /** + * @dev Emitted when `tokenId` token is transferred from `from` to `to`. + */ + event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); + + /** + * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token. + */ + event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); + + /** + * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets. + */ + event ApprovalForAll(address indexed owner, address indexed operator, bool approved); + + /** + * @dev Returns the number of tokens in ``owner``'s account. + */ + function balanceOf(address owner) external view returns (uint256 balance); + + /** + * @dev Returns the owner of the `tokenId` token. + * + * Requirements: + * + * - `tokenId` must exist. + */ + function ownerOf(uint256 tokenId) external view returns (address owner); + + /** + * @dev Safely transfers `tokenId` token from `from` to `to`. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must exist and be owned by `from`. + * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. + * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. + * + * Emits a {Transfer} event. + */ + function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external; + + /** + * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients + * are aware of the ERC721 protocol to prevent tokens from being forever locked. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must exist and be owned by `from`. + * - If the caller is not `from`, it must have been allowed to move this token by either {approve} or {setApprovalForAll}. + * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. + * + * Emits a {Transfer} event. + */ + function safeTransferFrom(address from, address to, uint256 tokenId) external; + + /** + * @dev Transfers `tokenId` token from `from` to `to`. + * + * WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721 + * or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must + * understand this adds an external call which potentially creates a reentrancy vulnerability. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must be owned by `from`. + * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. + * + * Emits a {Transfer} event. + */ + function transferFrom(address from, address to, uint256 tokenId) external; + + /** + * @dev Gives permission to `to` to transfer `tokenId` token to another account. + * The approval is cleared when the token is transferred. + * + * Only a single account can be approved at a time, so approving the zero address clears previous approvals. + * + * Requirements: + * + * - The caller must own the token or be an approved operator. + * - `tokenId` must exist. + * + * Emits an {Approval} event. + */ + function approve(address to, uint256 tokenId) external; + + /** + * @dev Approve or remove `operator` as an operator for the caller. + * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller. + * + * Requirements: + * + * - The `operator` cannot be the caller. + * + * Emits an {ApprovalForAll} event. + */ + function setApprovalForAll(address operator, bool approved) external; + + /** + * @dev Returns the account approved for `tokenId` token. + * + * Requirements: + * + * - `tokenId` must exist. + */ + function getApproved(uint256 tokenId) external view returns (address operator); + + /** + * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`. + * + * See {setApprovalForAll} + */ + function isApprovedForAll(address owner, address operator) external view returns (bool); +} + +// src\pookyball/IPookyball.sol + + + + + + + +/// @title PookyballMetadata +/// @notice The Pookyball rarities are represented on chain by this enum. +enum PookyballRarity { + COMMON, + RARE, + EPIC, + LEGENDARY, + MYTHIC +} + +/// @title PookyballMetadata +/// @notice Pookyballs NFT have the following features: +/// - rarity: integer enum. +/// - level: token level, can be increase by spending token experiences points (PXP). +/// - pxp: token experience points. +/// - seed: a random uint256 word provided by Chainlink VRF service that will be used by Pooky's NFT generator +/// back-end to generate the NFT visuals and in-game statistics\. +struct PookyballMetadata { + PookyballRarity rarity; + uint256 level; + uint256 pxp; + uint256 seed; +} + +/// @title IPookyball +/// @author Mathieu Bour for Pooky Labs Ltd. +/// @notice Minimal Pookyball interface. +interface IPookyball is IAccessControl, IERC2981, IERC721 { + /// Fired when the seed of a Pookyball token is set by the VRFCoordinator + event SeedSet(uint256 indexed tokenId, uint256 seed); + /// Fired when the level of a Pookyball token is changed + event LevelChanged(uint256 indexed tokenId, uint256 level); + /// Fired when the PXP of a Pookyball token is changed + event PXPChanged(uint256 indexed tokenId, uint256 amount); + + /// Thrown when the length of two parameters mismatch. Used in the mint batched function. + error ArgumentSizeMismatch(uint256 x, uint256 y); + + /// @notice PookyballMetadata of the token {tokenId}. + /// @dev Requirements: + /// - Pookyball {tokenId} should exist (minted and not burned). + function metadata(uint256 tokenId) external view returns (PookyballMetadata memory); + + /// @notice Change the secondary sale royalties receiver address. + function setERC2981Receiver(address newReceiver) external; + + /// @notice Mint a new Pookyball token with a given rarity. + function mint(address[] memory recipients, PookyballRarity[] memory rarities) + external + returns (uint256); + + /// @notice Change the level of a Pookyball token. + /// @dev Requirements: + /// - Pookyball {tokenId} should exist (minted and not burned). + function setLevel(uint256 tokenId, uint256 newLevel) external; + + /// @notice Change the PXP of a Pookyball token. + /// @dev Requirements: + /// - Pookyball {tokenId} should exist (minted and not burned). + function setPXP(uint256 tokenId, uint256 newPXP) external; +} + +// src\common/IBaseERC721A.sol + + + + + + + + + +/// @title IBaseERC721 +/// +/// @author Mathieu Bour for Pooky Labs Ltd. +interface IBaseERC721A is IERC165, IERC721A, IERC721ABurnable, IERC721AQueryable, IERC2981 { + /// Fired when the seed of a Pookyball token is set by the VRFCoordinator, + event SeedSet(uint256 indexed tokenId, uint256 seed); + + /// Thrown when the token {tokenId} does not exist. + error NonExistentToken(uint256 tokenId); + + // ----- ERC721A patches ----- + /// @dev This allow to iterate over the token ids. + function nextTokenId() external view returns (uint256); + + function supportsInterface(bytes4 interfaceId) + external + view + override(IERC165, IERC721A) + returns (bool); +} + +// src\stickers/IStickers.sol + + + + + +enum StickerRarity { + COMMON, + RARE, + EPIC, + LEGENDARY, + MYTHIC +} + +struct StickerMint { + address recipient; + StickerRarity rarity; +} + +struct StickerMetadata { + uint248 level; + StickerRarity rarity; +} + +/// @title IStickers +/// @author Mathieu Bour for Pooky Labs Ltd. +interface IStickers is IBaseERC721A { + /// Fired when the level of a Pookyball token is changed, + event LevelChanged(uint256 indexed tokenId, uint256 level); + + /// @notice StickerMetadata of the token {tokenId}. + /// @dev Requirements: + /// - Sticker {tokenId} should exist (minted and not burned). + function metadata(uint256 tokenId) external view returns (StickerMetadata memory); + + /// @notice Change the level of a Sticker token. + /// @dev Requirements: + /// - Sticker {tokenId} should exist (minted and not burned). + function setLevel(uint256 tokenId, uint248 newLevel) external; + + /// @notice Mint multiple Stickers at once. + /// @param recipient The mint recipient. + /// @param rarities The Sticker rarities. + function mint(address recipient, StickerRarity[] memory rarities) external; +} + +// src\stickers/IStickersController.sol + + + + + + +/// @notice IStickersController +/// @author Mathieu Bour for Pooky Labs Ltd. +interface IStickersController { + /// @notice Fired when a sticker is attached to a Pookyball. + event StickerAttached(uint256 stickerId, uint256 pookyballId); + /// @notice Fired when a sticker is replace from a Pookyball. + event StickerReplaced(uint256 stickerId, uint256 previousStickerId, uint256 pookyballId); + /// @notice Fired when a sticker is detached from a Pookyball. + event StickerDetached(uint256 stickerId, uint256 pookyballId); + + /// @notice Thrown when a sticker is invalid. + error InvalidSticker(uint256 stickerId); + + /// @notice The Stickers ERC-721 contract. + function stickers() external view returns (IStickers); + + /// @notice The Pookyball ERC-721 contract. + function pookyball() external view returns (IPookyball); + + /// @notice Get the Pookyball token id linked to a Sticker. + /// @param stickerId The Sticker token id. + function attachedTo(uint256 stickerId) external view returns (uint256); + + /// @notice Get the Stickers token ids attached to a Pookyball. + /// @param pookyballId The Pookyball token id. + function slots(uint256 pookyballId) external view returns (uint256[] memory); + + /// @notice Attach a sticker to a Pookyball. + /// @param stickerId The sticker token id. + /// @param pookyballId The Pookyball token id. + /// @dev Caution: no ownership checks are run. + function attach(uint256 stickerId, uint256 pookyballId) external; + + /// @notice Replace a sticker from a Pookyball, burning the previous one. + /// @param stickerId The sticker token id. + /// @param previousStickerId The previous sticker token id that will be burned. + /// @param pookyballId The Pookyball token id. + /// @dev Caution: no ownership checks are run. + function replace(uint256 stickerId, uint256 previousStickerId, uint256 pookyballId) external; + + /// @notice Detach (remove) a sticker from a Pookyball. + /// @param stickerId The Sstickerticker token id. + /// @param recepient The address when to send the detached sticker. + function detach(uint256 stickerId, address recepient) external; +} + +// src\stickers\StickersManager.sol + + + + + + + +/// @title StickersManager +/// @author Mathieu Bour for Pooky Labs Ltd. +/// +/// @dev Implementation of the manager that allows end users to attach or replace stickers to Pookyballs. +contract StickersManager { + IStickers public immutable stickers; + IPookyball public immutable pookyball; + IStickersController public immutable controller; + + error OwnershipRequired(address token, uint256 tokenId); + error InsufficientFreeSlot(uint256 pookyballId); + + constructor(IStickersController _controller) { + controller = _controller; + stickers = _controller.stickers(); + pookyball = _controller.pookyball(); + } + + modifier checkOwnership(uint256 stickerId, uint256 pookyballId) { + if (stickers.ownerOf(stickerId) != msg.sender) { + revert OwnershipRequired(address(stickers), stickerId); + } + + if (pookyball.ownerOf(pookyballId) != msg.sender) { + revert OwnershipRequired(address(pookyball), pookyballId); + } + + _; + } + + function slots(uint256 pookyballId) + public + view + returns (uint256 total, uint256 unlocked, uint256 free) + { + PookyballMetadata memory metadata = pookyball.metadata(pookyballId); + + if (metadata.rarity == PookyballRarity.COMMON) { + total = 4; + } else if (metadata.rarity == PookyballRarity.RARE) { + total = 6; + } else if (metadata.rarity == PookyballRarity.EPIC) { + total = 8; + } else if (metadata.rarity == PookyballRarity.LEGENDARY) { + total = 10; + } else if (metadata.rarity == PookyballRarity.MYTHIC) { + total = 12; + } + + unlocked = (metadata.level + 5) / 10; + uint256 used = controller.slots(pookyballId).length; + + // We might have some promotional offers that allow to unlock the slots before the Pookyball has reached the required level + if (used > unlocked) { + unlocked = used; + } + + free = unlocked - used; + } + + function attach(uint256 stickerId, uint256 pookyballId) + external + checkOwnership(stickerId, pookyballId) + { + (,, uint256 free) = slots(pookyballId); + + if (free == 0) { + revert InsufficientFreeSlot(pookyballId); + } + + controller.attach(stickerId, pookyballId); + } + + function replace(uint256 stickerId, uint256 previousStickerId, uint256 pookyballId) + external + checkOwnership(stickerId, pookyballId) + { + controller.replace(stickerId, previousStickerId, pookyballId); + } +} diff --git a/flattened/StickersSale.sol b/flattened/StickersSale.sol new file mode 100644 index 00000000..8c095ec7 --- /dev/null +++ b/flattened/StickersSale.sol @@ -0,0 +1,1544 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0 ^0.8.21 ^0.8.4; + +// lib/ERC721A/contracts\IERC721A.sol + +// ERC721A Contracts v4.2.3 +// Creator: Chiru Labs + + + +/** + * @dev Interface of ERC721A. + */ +interface IERC721A { + /** + * The caller must own the token or be an approved operator. + */ + error ApprovalCallerNotOwnerNorApproved(); + + /** + * The token does not exist. + */ + error ApprovalQueryForNonexistentToken(); + + /** + * Cannot query the balance for the zero address. + */ + error BalanceQueryForZeroAddress(); + + /** + * Cannot mint to the zero address. + */ + error MintToZeroAddress(); + + /** + * The quantity of tokens minted must be more than zero. + */ + error MintZeroQuantity(); + + /** + * The token does not exist. + */ + error OwnerQueryForNonexistentToken(); + + /** + * The caller must own the token or be an approved operator. + */ + error TransferCallerNotOwnerNorApproved(); + + /** + * The token must be owned by `from`. + */ + error TransferFromIncorrectOwner(); + + /** + * Cannot safely transfer to a contract that does not implement the + * ERC721Receiver interface. + */ + error TransferToNonERC721ReceiverImplementer(); + + /** + * Cannot transfer to the zero address. + */ + error TransferToZeroAddress(); + + /** + * The token does not exist. + */ + error URIQueryForNonexistentToken(); + + /** + * The `quantity` minted with ERC2309 exceeds the safety limit. + */ + error MintERC2309QuantityExceedsLimit(); + + /** + * The `extraData` cannot be set on an unintialized ownership slot. + */ + error OwnershipNotInitializedForExtraData(); + + // ============================================================= + // STRUCTS + // ============================================================= + + struct TokenOwnership { + // The address of the owner. + address addr; + // Stores the start time of ownership with minimal overhead for tokenomics. + uint64 startTimestamp; + // Whether the token has been burned. + bool burned; + // Arbitrary data similar to `startTimestamp` that can be set via {_extraData}. + uint24 extraData; + } + + // ============================================================= + // TOKEN COUNTERS + // ============================================================= + + /** + * @dev Returns the total number of tokens in existence. + * Burned tokens will reduce the count. + * To get the total number of tokens minted, please see {_totalMinted}. + */ + function totalSupply() external view returns (uint256); + + // ============================================================= + // 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 30000 gas. + */ + function supportsInterface(bytes4 interfaceId) external view returns (bool); + + // ============================================================= + // IERC721 + // ============================================================= + + /** + * @dev Emitted when `tokenId` token is transferred from `from` to `to`. + */ + event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); + + /** + * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token. + */ + event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); + + /** + * @dev Emitted when `owner` enables or disables + * (`approved`) `operator` to manage all of its assets. + */ + event ApprovalForAll(address indexed owner, address indexed operator, bool approved); + + /** + * @dev Returns the number of tokens in `owner`'s account. + */ + function balanceOf(address owner) external view returns (uint256 balance); + + /** + * @dev Returns the owner of the `tokenId` token. + * + * Requirements: + * + * - `tokenId` must exist. + */ + function ownerOf(uint256 tokenId) external view returns (address owner); + + /** + * @dev Safely transfers `tokenId` token from `from` to `to`, + * checking first that contract recipients are aware of the ERC721 protocol + * to prevent tokens from being forever locked. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must exist and be owned by `from`. + * - If the caller is not `from`, it must be have been allowed to move + * this token by either {approve} or {setApprovalForAll}. + * - If `to` refers to a smart contract, it must implement + * {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. + * + * Emits a {Transfer} event. + */ + function safeTransferFrom( + address from, + address to, + uint256 tokenId, + bytes calldata data + ) external payable; + + /** + * @dev Equivalent to `safeTransferFrom(from, to, tokenId, '')`. + */ + function safeTransferFrom( + address from, + address to, + uint256 tokenId + ) external payable; + + /** + * @dev Transfers `tokenId` from `from` to `to`. + * + * WARNING: Usage of this method is discouraged, use {safeTransferFrom} + * whenever possible. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must be owned by `from`. + * - If the caller is not `from`, it must be approved to move this token + * by either {approve} or {setApprovalForAll}. + * + * Emits a {Transfer} event. + */ + function transferFrom( + address from, + address to, + uint256 tokenId + ) external payable; + + /** + * @dev Gives permission to `to` to transfer `tokenId` token to another account. + * The approval is cleared when the token is transferred. + * + * Only a single account can be approved at a time, so approving the + * zero address clears previous approvals. + * + * Requirements: + * + * - The caller must own the token or be an approved operator. + * - `tokenId` must exist. + * + * Emits an {Approval} event. + */ + function approve(address to, uint256 tokenId) external payable; + + /** + * @dev Approve or remove `operator` as an operator for the caller. + * Operators can call {transferFrom} or {safeTransferFrom} + * for any token owned by the caller. + * + * Requirements: + * + * - The `operator` cannot be the caller. + * + * Emits an {ApprovalForAll} event. + */ + function setApprovalForAll(address operator, bool _approved) external; + + /** + * @dev Returns the account approved for `tokenId` token. + * + * Requirements: + * + * - `tokenId` must exist. + */ + function getApproved(uint256 tokenId) external view returns (address operator); + + /** + * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`. + * + * See {setApprovalForAll}. + */ + function isApprovedForAll(address owner, address operator) external view returns (bool); + + // ============================================================= + // IERC721Metadata + // ============================================================= + + /** + * @dev Returns the token collection name. + */ + function name() external view returns (string memory); + + /** + * @dev Returns the token collection symbol. + */ + function symbol() external view returns (string memory); + + /** + * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token. + */ + function tokenURI(uint256 tokenId) external view returns (string memory); + + // ============================================================= + // IERC2309 + // ============================================================= + + /** + * @dev Emitted when tokens in `fromTokenId` to `toTokenId` + * (inclusive) is transferred from `from` to `to`, as defined in the + * [ERC2309](https://eips.ethereum.org/EIPS/eip-2309) standard. + * + * See {_mintERC2309} for more details. + */ + event ConsecutiveTransfer(uint256 indexed fromTokenId, uint256 toTokenId, address indexed from, address indexed to); +} + +// lib/openzeppelin-contracts/contracts/utils/introspection/IERC165.sol + +// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol) + + + +/** + * @dev Interface of the ERC165 standard, as defined in the + * https://eips.ethereum.org/EIPS/eip-165[EIP]. + * + * Implementers can declare support of contract interfaces, which can then be + * queried by others ({ERC165Checker}). + * + * For an implementation, see {ERC165}. + */ +interface IERC165 { + /** + * @dev Returns true if this contract implements the interface defined by + * `interfaceId`. See the corresponding + * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] + * to learn more about how these ids are created. + * + * This function call must use less than 30 000 gas. + */ + function supportsInterface(bytes4 interfaceId) external view returns (bool); +} + +// lib/solady/src/auth/Ownable.sol + + + +/// @notice Simple single owner authorization mixin. +/// @author Solady (https://github.com/vectorized/solady/blob/main/src/auth/Ownable.sol) +/// @dev While the ownable portion follows +/// [EIP-173](https://eips.ethereum.org/EIPS/eip-173) for compatibility, +/// the nomenclature for the 2-step ownership handover may be unique to this codebase. +abstract contract Ownable { + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* CUSTOM ERRORS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev The caller is not authorized to call the function. + error Unauthorized(); + + /// @dev The `newOwner` cannot be the zero address. + error NewOwnerIsZeroAddress(); + + /// @dev The `pendingOwner` does not have a valid handover request. + error NoHandoverRequest(); + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* EVENTS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev The ownership is transferred from `oldOwner` to `newOwner`. + /// This event is intentionally kept the same as OpenZeppelin's Ownable to be + /// compatible with indexers and [EIP-173](https://eips.ethereum.org/EIPS/eip-173), + /// despite it not being as lightweight as a single argument event. + event OwnershipTransferred(address indexed oldOwner, address indexed newOwner); + + /// @dev An ownership handover to `pendingOwner` has been requested. + event OwnershipHandoverRequested(address indexed pendingOwner); + + /// @dev The ownership handover to `pendingOwner` has been canceled. + event OwnershipHandoverCanceled(address indexed pendingOwner); + + /// @dev `keccak256(bytes("OwnershipTransferred(address,address)"))`. + uint256 private constant _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE = + 0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0; + + /// @dev `keccak256(bytes("OwnershipHandoverRequested(address)"))`. + uint256 private constant _OWNERSHIP_HANDOVER_REQUESTED_EVENT_SIGNATURE = + 0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d; + + /// @dev `keccak256(bytes("OwnershipHandoverCanceled(address)"))`. + uint256 private constant _OWNERSHIP_HANDOVER_CANCELED_EVENT_SIGNATURE = + 0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92; + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* STORAGE */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev The owner slot is given by: `not(_OWNER_SLOT_NOT)`. + /// It is intentionally chosen to be a high value + /// to avoid collision with lower slots. + /// The choice of manual storage layout is to enable compatibility + /// with both regular and upgradeable contracts. + uint256 private constant _OWNER_SLOT_NOT = 0x8b78c6d8; + + /// The ownership handover slot of `newOwner` is given by: + /// ``` + /// mstore(0x00, or(shl(96, user), _HANDOVER_SLOT_SEED)) + /// let handoverSlot := keccak256(0x00, 0x20) + /// ``` + /// It stores the expiry timestamp of the two-step ownership handover. + uint256 private constant _HANDOVER_SLOT_SEED = 0x389a75e1; + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* INTERNAL FUNCTIONS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev Initializes the owner directly without authorization guard. + /// This function must be called upon initialization, + /// regardless of whether the contract is upgradeable or not. + /// This is to enable generalization to both regular and upgradeable contracts, + /// and to save gas in case the initial owner is not the caller. + /// For performance reasons, this function will not check if there + /// is an existing owner. + function _initializeOwner(address newOwner) internal virtual { + /// @solidity memory-safe-assembly + assembly { + // Clean the upper 96 bits. + newOwner := shr(96, shl(96, newOwner)) + // Store the new value. + sstore(not(_OWNER_SLOT_NOT), newOwner) + // Emit the {OwnershipTransferred} event. + log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, 0, newOwner) + } + } + + /// @dev Sets the owner directly without authorization guard. + function _setOwner(address newOwner) internal virtual { + /// @solidity memory-safe-assembly + assembly { + let ownerSlot := not(_OWNER_SLOT_NOT) + // Clean the upper 96 bits. + newOwner := shr(96, shl(96, newOwner)) + // Emit the {OwnershipTransferred} event. + log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, sload(ownerSlot), newOwner) + // Store the new value. + sstore(ownerSlot, newOwner) + } + } + + /// @dev Throws if the sender is not the owner. + function _checkOwner() internal view virtual { + /// @solidity memory-safe-assembly + assembly { + // If the caller is not the stored owner, revert. + if iszero(eq(caller(), sload(not(_OWNER_SLOT_NOT)))) { + mstore(0x00, 0x82b42900) // `Unauthorized()`. + revert(0x1c, 0x04) + } + } + } + + /// @dev Returns how long a two-step ownership handover is valid for in seconds. + /// Override to return a different value if needed. + /// Made internal to conserve bytecode. Wrap it in a public function if needed. + function _ownershipHandoverValidFor() internal view virtual returns (uint64) { + return 48 * 3600; + } + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* PUBLIC UPDATE FUNCTIONS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev Allows the owner to transfer the ownership to `newOwner`. + function transferOwnership(address newOwner) public payable virtual onlyOwner { + /// @solidity memory-safe-assembly + assembly { + if iszero(shl(96, newOwner)) { + mstore(0x00, 0x7448fbae) // `NewOwnerIsZeroAddress()`. + revert(0x1c, 0x04) + } + } + _setOwner(newOwner); + } + + /// @dev Allows the owner to renounce their ownership. + function renounceOwnership() public payable virtual onlyOwner { + _setOwner(address(0)); + } + + /// @dev Request a two-step ownership handover to the caller. + /// The request will automatically expire in 48 hours (172800 seconds) by default. + function requestOwnershipHandover() public payable virtual { + unchecked { + uint256 expires = block.timestamp + _ownershipHandoverValidFor(); + /// @solidity memory-safe-assembly + assembly { + // Compute and set the handover slot to `expires`. + mstore(0x0c, _HANDOVER_SLOT_SEED) + mstore(0x00, caller()) + sstore(keccak256(0x0c, 0x20), expires) + // Emit the {OwnershipHandoverRequested} event. + log2(0, 0, _OWNERSHIP_HANDOVER_REQUESTED_EVENT_SIGNATURE, caller()) + } + } + } + + /// @dev Cancels the two-step ownership handover to the caller, if any. + function cancelOwnershipHandover() public payable virtual { + /// @solidity memory-safe-assembly + assembly { + // Compute and set the handover slot to 0. + mstore(0x0c, _HANDOVER_SLOT_SEED) + mstore(0x00, caller()) + sstore(keccak256(0x0c, 0x20), 0) + // Emit the {OwnershipHandoverCanceled} event. + log2(0, 0, _OWNERSHIP_HANDOVER_CANCELED_EVENT_SIGNATURE, caller()) + } + } + + /// @dev Allows the owner to complete the two-step ownership handover to `pendingOwner`. + /// Reverts if there is no existing ownership handover requested by `pendingOwner`. + function completeOwnershipHandover(address pendingOwner) public payable virtual onlyOwner { + /// @solidity memory-safe-assembly + assembly { + // Compute and set the handover slot to 0. + mstore(0x0c, _HANDOVER_SLOT_SEED) + mstore(0x00, pendingOwner) + let handoverSlot := keccak256(0x0c, 0x20) + // If the handover does not exist, or has expired. + if gt(timestamp(), sload(handoverSlot)) { + mstore(0x00, 0x6f5e8818) // `NoHandoverRequest()`. + revert(0x1c, 0x04) + } + // Set the handover slot to 0. + sstore(handoverSlot, 0) + } + _setOwner(pendingOwner); + } + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* PUBLIC READ FUNCTIONS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev Returns the owner of the contract. + function owner() public view virtual returns (address result) { + /// @solidity memory-safe-assembly + assembly { + result := sload(not(_OWNER_SLOT_NOT)) + } + } + + /// @dev Returns the expiry timestamp for the two-step ownership handover to `pendingOwner`. + function ownershipHandoverExpiresAt(address pendingOwner) + public + view + virtual + returns (uint256 result) + { + /// @solidity memory-safe-assembly + assembly { + // Compute the handover slot. + mstore(0x0c, _HANDOVER_SLOT_SEED) + mstore(0x00, pendingOwner) + // Load the handover slot. + result := sload(keccak256(0x0c, 0x20)) + } + } + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* MODIFIERS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev Marks a function as only callable by the owner. + modifier onlyOwner() virtual { + _checkOwner(); + _; + } +} + +// src\common/ITreasury.sol + + + +/// @title ITreasury +/// @author Mathieu Bour for Pooky Labs Ltd. +interface ITreasury { + /// Thrown when the msg.value of the mint function does not cover the mint cost. + error InsufficientValue(uint256 expected, uint256 actual); + /// Thrown when the native transfer has failed. + error TransferFailed(address recipient, uint256 amount); + + /// Change the native currency destination address. + /// @param _treasury The new treasury address. + function changeTreasury(address _treasury) external; +} + +// lib/ERC721A/contracts\extensions/IERC721ABurnable.sol + +// ERC721A Contracts v4.2.3 +// Creator: Chiru Labs + + + + + +/** + * @dev Interface of ERC721ABurnable. + */ +interface IERC721ABurnable is IERC721A { + /** + * @dev Burns `tokenId`. See {ERC721A-_burn}. + * + * Requirements: + * + * - The caller must own `tokenId` or be an approved operator. + */ + function burn(uint256 tokenId) external; +} + +// lib/ERC721A/contracts\extensions/IERC721AQueryable.sol + +// ERC721A Contracts v4.2.3 +// Creator: Chiru Labs + + + + + +/** + * @dev Interface of ERC721AQueryable. + */ +interface IERC721AQueryable is IERC721A { + /** + * Invalid query range (`start` >= `stop`). + */ + error InvalidQueryRange(); + + /** + * @dev Returns the `TokenOwnership` struct at `tokenId` without reverting. + * + * If the `tokenId` is out of bounds: + * + * - `addr = address(0)` + * - `startTimestamp = 0` + * - `burned = false` + * - `extraData = 0` + * + * If the `tokenId` is burned: + * + * - `addr =
` + * - `startTimestamp = ` + * - `burned = true` + * - `extraData = ` + * + * Otherwise: + * + * - `addr =
` + * - `startTimestamp = ` + * - `burned = false` + * - `extraData = ` + */ + function explicitOwnershipOf(uint256 tokenId) external view returns (TokenOwnership memory); + + /** + * @dev Returns an array of `TokenOwnership` structs at `tokenIds` in order. + * See {ERC721AQueryable-explicitOwnershipOf} + */ + function explicitOwnershipsOf(uint256[] memory tokenIds) external view returns (TokenOwnership[] memory); + + /** + * @dev Returns an array of token IDs owned by `owner`, + * in the range [`start`, `stop`) + * (i.e. `start <= tokenId < stop`). + * + * This function allows for tokens to be queried if the collection + * grows too big for a single call of {ERC721AQueryable-tokensOfOwner}. + * + * Requirements: + * + * - `start < stop` + */ + function tokensOfOwnerIn( + address owner, + uint256 start, + uint256 stop + ) external view returns (uint256[] memory); + + /** + * @dev Returns an array of token IDs owned by `owner`. + * + * This function scans the ownership mapping and is O(`totalSupply`) in complexity. + * It is meant to be called off-chain. + * + * See {ERC721AQueryable-tokensOfOwnerIn} for splitting the scan into + * multiple smaller scans if the collection is large enough to cause + * an out-of-gas error (10K collections should be fine). + */ + function tokensOfOwner(address owner) external view returns (uint256[] memory); +} + +// lib/openzeppelin-contracts/contracts\interfaces/IERC165.sol + +// OpenZeppelin Contracts v4.4.1 (interfaces/IERC165.sol) + + + + + +// lib/openzeppelin-contracts/contracts\interfaces/IERC2981.sol + +// OpenZeppelin Contracts (last updated v4.9.0) (interfaces/IERC2981.sol) + + + + + +/** + * @dev Interface for the NFT Royalty Standard. + * + * A standardized way to retrieve royalty payment information for non-fungible tokens (NFTs) to enable universal + * support for royalty payments across all NFT marketplaces and ecosystem participants. + * + * _Available since v4.5._ + */ +interface IERC2981 is IERC165 { + /** + * @dev Returns how much royalty is owed and to whom, based on a sale price that may be denominated in any unit of + * exchange. The royalty amount is denominated and should be paid in that same unit of exchange. + */ + function royaltyInfo( + uint256 tokenId, + uint256 salePrice + ) external view returns (address receiver, uint256 royaltyAmount); +} + +// lib/solady/src\auth/OwnableRoles.sol + + + + + +/// @notice Simple single owner and multiroles authorization mixin. +/// @author Solady (https://github.com/vectorized/solady/blob/main/src/auth/Ownable.sol) +/// @dev While the ownable portion follows [EIP-173](https://eips.ethereum.org/EIPS/eip-173) +/// for compatibility, the nomenclature for the 2-step ownership handover and roles +/// may be unique to this codebase. +abstract contract OwnableRoles is Ownable { + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* EVENTS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev The `user`'s roles is updated to `roles`. + /// Each bit of `roles` represents whether the role is set. + event RolesUpdated(address indexed user, uint256 indexed roles); + + /// @dev `keccak256(bytes("RolesUpdated(address,uint256)"))`. + uint256 private constant _ROLES_UPDATED_EVENT_SIGNATURE = + 0x715ad5ce61fc9595c7b415289d59cf203f23a94fa06f04af7e489a0a76e1fe26; + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* STORAGE */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev The role slot of `user` is given by: + /// ``` + /// mstore(0x00, or(shl(96, user), _ROLE_SLOT_SEED)) + /// let roleSlot := keccak256(0x00, 0x20) + /// ``` + /// This automatically ignores the upper bits of the `user` in case + /// they are not clean, as well as keep the `keccak256` under 32-bytes. + /// + /// Note: This is equal to `_OWNER_SLOT_NOT` in for gas efficiency. + uint256 private constant _ROLE_SLOT_SEED = 0x8b78c6d8; + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* INTERNAL FUNCTIONS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev Overwrite the roles directly without authorization guard. + function _setRoles(address user, uint256 roles) internal virtual { + /// @solidity memory-safe-assembly + assembly { + mstore(0x0c, _ROLE_SLOT_SEED) + mstore(0x00, user) + // Store the new value. + sstore(keccak256(0x0c, 0x20), roles) + // Emit the {RolesUpdated} event. + log3(0, 0, _ROLES_UPDATED_EVENT_SIGNATURE, shr(96, mload(0x0c)), roles) + } + } + + /// @dev Updates the roles directly without authorization guard. + /// If `on` is true, each set bit of `roles` will be turned on, + /// otherwise, each set bit of `roles` will be turned off. + function _updateRoles(address user, uint256 roles, bool on) internal virtual { + /// @solidity memory-safe-assembly + assembly { + mstore(0x0c, _ROLE_SLOT_SEED) + mstore(0x00, user) + let roleSlot := keccak256(0x0c, 0x20) + // Load the current value. + let current := sload(roleSlot) + // Compute the updated roles if `on` is true. + let updated := or(current, roles) + // Compute the updated roles if `on` is false. + // Use `and` to compute the intersection of `current` and `roles`, + // `xor` it with `current` to flip the bits in the intersection. + if iszero(on) { updated := xor(current, and(current, roles)) } + // Then, store the new value. + sstore(roleSlot, updated) + // Emit the {RolesUpdated} event. + log3(0, 0, _ROLES_UPDATED_EVENT_SIGNATURE, shr(96, mload(0x0c)), updated) + } + } + + /// @dev Grants the roles directly without authorization guard. + /// Each bit of `roles` represents the role to turn on. + function _grantRoles(address user, uint256 roles) internal virtual { + _updateRoles(user, roles, true); + } + + /// @dev Removes the roles directly without authorization guard. + /// Each bit of `roles` represents the role to turn off. + function _removeRoles(address user, uint256 roles) internal virtual { + _updateRoles(user, roles, false); + } + + /// @dev Throws if the sender does not have any of the `roles`. + function _checkRoles(uint256 roles) internal view virtual { + /// @solidity memory-safe-assembly + assembly { + // Compute the role slot. + mstore(0x0c, _ROLE_SLOT_SEED) + mstore(0x00, caller()) + // Load the stored value, and if the `and` intersection + // of the value and `roles` is zero, revert. + if iszero(and(sload(keccak256(0x0c, 0x20)), roles)) { + mstore(0x00, 0x82b42900) // `Unauthorized()`. + revert(0x1c, 0x04) + } + } + } + + /// @dev Throws if the sender is not the owner, + /// and does not have any of the `roles`. + /// Checks for ownership first, then lazily checks for roles. + function _checkOwnerOrRoles(uint256 roles) internal view virtual { + /// @solidity memory-safe-assembly + assembly { + // If the caller is not the stored owner. + // Note: `_ROLE_SLOT_SEED` is equal to `_OWNER_SLOT_NOT`. + if iszero(eq(caller(), sload(not(_ROLE_SLOT_SEED)))) { + // Compute the role slot. + mstore(0x0c, _ROLE_SLOT_SEED) + mstore(0x00, caller()) + // Load the stored value, and if the `and` intersection + // of the value and `roles` is zero, revert. + if iszero(and(sload(keccak256(0x0c, 0x20)), roles)) { + mstore(0x00, 0x82b42900) // `Unauthorized()`. + revert(0x1c, 0x04) + } + } + } + } + + /// @dev Throws if the sender does not have any of the `roles`, + /// and is not the owner. + /// Checks for roles first, then lazily checks for ownership. + function _checkRolesOrOwner(uint256 roles) internal view virtual { + /// @solidity memory-safe-assembly + assembly { + // Compute the role slot. + mstore(0x0c, _ROLE_SLOT_SEED) + mstore(0x00, caller()) + // Load the stored value, and if the `and` intersection + // of the value and `roles` is zero, revert. + if iszero(and(sload(keccak256(0x0c, 0x20)), roles)) { + // If the caller is not the stored owner. + // Note: `_ROLE_SLOT_SEED` is equal to `_OWNER_SLOT_NOT`. + if iszero(eq(caller(), sload(not(_ROLE_SLOT_SEED)))) { + mstore(0x00, 0x82b42900) // `Unauthorized()`. + revert(0x1c, 0x04) + } + } + } + } + + /// @dev Convenience function to return a `roles` bitmap from an array of `ordinals`. + /// This is meant for frontends like Etherscan, and is therefore not fully optimized. + /// Not recommended to be called on-chain. + /// Made internal to conserve bytecode. Wrap it in a public function if needed. + function _rolesFromOrdinals(uint8[] memory ordinals) internal pure returns (uint256 roles) { + /// @solidity memory-safe-assembly + assembly { + for { let i := shl(5, mload(ordinals)) } i { i := sub(i, 0x20) } { + // We don't need to mask the values of `ordinals`, as Solidity + // cleans dirty upper bits when storing variables into memory. + roles := or(shl(mload(add(ordinals, i)), 1), roles) + } + } + } + + /// @dev Convenience function to return an array of `ordinals` from the `roles` bitmap. + /// This is meant for frontends like Etherscan, and is therefore not fully optimized. + /// Not recommended to be called on-chain. + /// Made internal to conserve bytecode. Wrap it in a public function if needed. + function _ordinalsFromRoles(uint256 roles) internal pure returns (uint8[] memory ordinals) { + /// @solidity memory-safe-assembly + assembly { + // Grab the pointer to the free memory. + ordinals := mload(0x40) + let ptr := add(ordinals, 0x20) + let o := 0 + // The absence of lookup tables, De Bruijn, etc., here is intentional for + // smaller bytecode, as this function is not meant to be called on-chain. + for { let t := roles } 1 {} { + mstore(ptr, o) + // `shr` 5 is equivalent to multiplying by 0x20. + // Push back into the ordinals array if the bit is set. + ptr := add(ptr, shl(5, and(t, 1))) + o := add(o, 1) + t := shr(o, roles) + if iszero(t) { break } + } + // Store the length of `ordinals`. + mstore(ordinals, shr(5, sub(ptr, add(ordinals, 0x20)))) + // Allocate the memory. + mstore(0x40, ptr) + } + } + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* PUBLIC UPDATE FUNCTIONS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev Allows the owner to grant `user` `roles`. + /// If the `user` already has a role, then it will be an no-op for the role. + function grantRoles(address user, uint256 roles) public payable virtual onlyOwner { + _grantRoles(user, roles); + } + + /// @dev Allows the owner to remove `user` `roles`. + /// If the `user` does not have a role, then it will be an no-op for the role. + function revokeRoles(address user, uint256 roles) public payable virtual onlyOwner { + _removeRoles(user, roles); + } + + /// @dev Allow the caller to remove their own roles. + /// If the caller does not have a role, then it will be an no-op for the role. + function renounceRoles(uint256 roles) public payable virtual { + _removeRoles(msg.sender, roles); + } + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* PUBLIC READ FUNCTIONS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev Returns the roles of `user`. + function rolesOf(address user) public view virtual returns (uint256 roles) { + /// @solidity memory-safe-assembly + assembly { + // Compute the role slot. + mstore(0x0c, _ROLE_SLOT_SEED) + mstore(0x00, user) + // Load the stored value. + roles := sload(keccak256(0x0c, 0x20)) + } + } + + /// @dev Returns whether `user` has any of `roles`. + function hasAnyRole(address user, uint256 roles) public view virtual returns (bool) { + return rolesOf(user) & roles != 0; + } + + /// @dev Returns whether `user` has all of `roles`. + function hasAllRoles(address user, uint256 roles) public view virtual returns (bool) { + return rolesOf(user) & roles == roles; + } + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* MODIFIERS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev Marks a function as only callable by an account with `roles`. + modifier onlyRoles(uint256 roles) virtual { + _checkRoles(roles); + _; + } + + /// @dev Marks a function as only callable by the owner or by an account + /// with `roles`. Checks for ownership first, then lazily checks for roles. + modifier onlyOwnerOrRoles(uint256 roles) virtual { + _checkOwnerOrRoles(roles); + _; + } + + /// @dev Marks a function as only callable by an account with `roles` + /// or the owner. Checks for roles first, then lazily checks for ownership. + modifier onlyRolesOrOwner(uint256 roles) virtual { + _checkRolesOrOwner(roles); + _; + } + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* ROLE CONSTANTS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + // IYKYK + + uint256 internal constant _ROLE_0 = 1 << 0; + uint256 internal constant _ROLE_1 = 1 << 1; + uint256 internal constant _ROLE_2 = 1 << 2; + uint256 internal constant _ROLE_3 = 1 << 3; + uint256 internal constant _ROLE_4 = 1 << 4; + uint256 internal constant _ROLE_5 = 1 << 5; + uint256 internal constant _ROLE_6 = 1 << 6; + uint256 internal constant _ROLE_7 = 1 << 7; + uint256 internal constant _ROLE_8 = 1 << 8; + uint256 internal constant _ROLE_9 = 1 << 9; + uint256 internal constant _ROLE_10 = 1 << 10; + uint256 internal constant _ROLE_11 = 1 << 11; + uint256 internal constant _ROLE_12 = 1 << 12; + uint256 internal constant _ROLE_13 = 1 << 13; + uint256 internal constant _ROLE_14 = 1 << 14; + uint256 internal constant _ROLE_15 = 1 << 15; + uint256 internal constant _ROLE_16 = 1 << 16; + uint256 internal constant _ROLE_17 = 1 << 17; + uint256 internal constant _ROLE_18 = 1 << 18; + uint256 internal constant _ROLE_19 = 1 << 19; + uint256 internal constant _ROLE_20 = 1 << 20; + uint256 internal constant _ROLE_21 = 1 << 21; + uint256 internal constant _ROLE_22 = 1 << 22; + uint256 internal constant _ROLE_23 = 1 << 23; + uint256 internal constant _ROLE_24 = 1 << 24; + uint256 internal constant _ROLE_25 = 1 << 25; + uint256 internal constant _ROLE_26 = 1 << 26; + uint256 internal constant _ROLE_27 = 1 << 27; + uint256 internal constant _ROLE_28 = 1 << 28; + uint256 internal constant _ROLE_29 = 1 << 29; + uint256 internal constant _ROLE_30 = 1 << 30; + uint256 internal constant _ROLE_31 = 1 << 31; + uint256 internal constant _ROLE_32 = 1 << 32; + uint256 internal constant _ROLE_33 = 1 << 33; + uint256 internal constant _ROLE_34 = 1 << 34; + uint256 internal constant _ROLE_35 = 1 << 35; + uint256 internal constant _ROLE_36 = 1 << 36; + uint256 internal constant _ROLE_37 = 1 << 37; + uint256 internal constant _ROLE_38 = 1 << 38; + uint256 internal constant _ROLE_39 = 1 << 39; + uint256 internal constant _ROLE_40 = 1 << 40; + uint256 internal constant _ROLE_41 = 1 << 41; + uint256 internal constant _ROLE_42 = 1 << 42; + uint256 internal constant _ROLE_43 = 1 << 43; + uint256 internal constant _ROLE_44 = 1 << 44; + uint256 internal constant _ROLE_45 = 1 << 45; + uint256 internal constant _ROLE_46 = 1 << 46; + uint256 internal constant _ROLE_47 = 1 << 47; + uint256 internal constant _ROLE_48 = 1 << 48; + uint256 internal constant _ROLE_49 = 1 << 49; + uint256 internal constant _ROLE_50 = 1 << 50; + uint256 internal constant _ROLE_51 = 1 << 51; + uint256 internal constant _ROLE_52 = 1 << 52; + uint256 internal constant _ROLE_53 = 1 << 53; + uint256 internal constant _ROLE_54 = 1 << 54; + uint256 internal constant _ROLE_55 = 1 << 55; + uint256 internal constant _ROLE_56 = 1 << 56; + uint256 internal constant _ROLE_57 = 1 << 57; + uint256 internal constant _ROLE_58 = 1 << 58; + uint256 internal constant _ROLE_59 = 1 << 59; + uint256 internal constant _ROLE_60 = 1 << 60; + uint256 internal constant _ROLE_61 = 1 << 61; + uint256 internal constant _ROLE_62 = 1 << 62; + uint256 internal constant _ROLE_63 = 1 << 63; + uint256 internal constant _ROLE_64 = 1 << 64; + uint256 internal constant _ROLE_65 = 1 << 65; + uint256 internal constant _ROLE_66 = 1 << 66; + uint256 internal constant _ROLE_67 = 1 << 67; + uint256 internal constant _ROLE_68 = 1 << 68; + uint256 internal constant _ROLE_69 = 1 << 69; + uint256 internal constant _ROLE_70 = 1 << 70; + uint256 internal constant _ROLE_71 = 1 << 71; + uint256 internal constant _ROLE_72 = 1 << 72; + uint256 internal constant _ROLE_73 = 1 << 73; + uint256 internal constant _ROLE_74 = 1 << 74; + uint256 internal constant _ROLE_75 = 1 << 75; + uint256 internal constant _ROLE_76 = 1 << 76; + uint256 internal constant _ROLE_77 = 1 << 77; + uint256 internal constant _ROLE_78 = 1 << 78; + uint256 internal constant _ROLE_79 = 1 << 79; + uint256 internal constant _ROLE_80 = 1 << 80; + uint256 internal constant _ROLE_81 = 1 << 81; + uint256 internal constant _ROLE_82 = 1 << 82; + uint256 internal constant _ROLE_83 = 1 << 83; + uint256 internal constant _ROLE_84 = 1 << 84; + uint256 internal constant _ROLE_85 = 1 << 85; + uint256 internal constant _ROLE_86 = 1 << 86; + uint256 internal constant _ROLE_87 = 1 << 87; + uint256 internal constant _ROLE_88 = 1 << 88; + uint256 internal constant _ROLE_89 = 1 << 89; + uint256 internal constant _ROLE_90 = 1 << 90; + uint256 internal constant _ROLE_91 = 1 << 91; + uint256 internal constant _ROLE_92 = 1 << 92; + uint256 internal constant _ROLE_93 = 1 << 93; + uint256 internal constant _ROLE_94 = 1 << 94; + uint256 internal constant _ROLE_95 = 1 << 95; + uint256 internal constant _ROLE_96 = 1 << 96; + uint256 internal constant _ROLE_97 = 1 << 97; + uint256 internal constant _ROLE_98 = 1 << 98; + uint256 internal constant _ROLE_99 = 1 << 99; + uint256 internal constant _ROLE_100 = 1 << 100; + uint256 internal constant _ROLE_101 = 1 << 101; + uint256 internal constant _ROLE_102 = 1 << 102; + uint256 internal constant _ROLE_103 = 1 << 103; + uint256 internal constant _ROLE_104 = 1 << 104; + uint256 internal constant _ROLE_105 = 1 << 105; + uint256 internal constant _ROLE_106 = 1 << 106; + uint256 internal constant _ROLE_107 = 1 << 107; + uint256 internal constant _ROLE_108 = 1 << 108; + uint256 internal constant _ROLE_109 = 1 << 109; + uint256 internal constant _ROLE_110 = 1 << 110; + uint256 internal constant _ROLE_111 = 1 << 111; + uint256 internal constant _ROLE_112 = 1 << 112; + uint256 internal constant _ROLE_113 = 1 << 113; + uint256 internal constant _ROLE_114 = 1 << 114; + uint256 internal constant _ROLE_115 = 1 << 115; + uint256 internal constant _ROLE_116 = 1 << 116; + uint256 internal constant _ROLE_117 = 1 << 117; + uint256 internal constant _ROLE_118 = 1 << 118; + uint256 internal constant _ROLE_119 = 1 << 119; + uint256 internal constant _ROLE_120 = 1 << 120; + uint256 internal constant _ROLE_121 = 1 << 121; + uint256 internal constant _ROLE_122 = 1 << 122; + uint256 internal constant _ROLE_123 = 1 << 123; + uint256 internal constant _ROLE_124 = 1 << 124; + uint256 internal constant _ROLE_125 = 1 << 125; + uint256 internal constant _ROLE_126 = 1 << 126; + uint256 internal constant _ROLE_127 = 1 << 127; + uint256 internal constant _ROLE_128 = 1 << 128; + uint256 internal constant _ROLE_129 = 1 << 129; + uint256 internal constant _ROLE_130 = 1 << 130; + uint256 internal constant _ROLE_131 = 1 << 131; + uint256 internal constant _ROLE_132 = 1 << 132; + uint256 internal constant _ROLE_133 = 1 << 133; + uint256 internal constant _ROLE_134 = 1 << 134; + uint256 internal constant _ROLE_135 = 1 << 135; + uint256 internal constant _ROLE_136 = 1 << 136; + uint256 internal constant _ROLE_137 = 1 << 137; + uint256 internal constant _ROLE_138 = 1 << 138; + uint256 internal constant _ROLE_139 = 1 << 139; + uint256 internal constant _ROLE_140 = 1 << 140; + uint256 internal constant _ROLE_141 = 1 << 141; + uint256 internal constant _ROLE_142 = 1 << 142; + uint256 internal constant _ROLE_143 = 1 << 143; + uint256 internal constant _ROLE_144 = 1 << 144; + uint256 internal constant _ROLE_145 = 1 << 145; + uint256 internal constant _ROLE_146 = 1 << 146; + uint256 internal constant _ROLE_147 = 1 << 147; + uint256 internal constant _ROLE_148 = 1 << 148; + uint256 internal constant _ROLE_149 = 1 << 149; + uint256 internal constant _ROLE_150 = 1 << 150; + uint256 internal constant _ROLE_151 = 1 << 151; + uint256 internal constant _ROLE_152 = 1 << 152; + uint256 internal constant _ROLE_153 = 1 << 153; + uint256 internal constant _ROLE_154 = 1 << 154; + uint256 internal constant _ROLE_155 = 1 << 155; + uint256 internal constant _ROLE_156 = 1 << 156; + uint256 internal constant _ROLE_157 = 1 << 157; + uint256 internal constant _ROLE_158 = 1 << 158; + uint256 internal constant _ROLE_159 = 1 << 159; + uint256 internal constant _ROLE_160 = 1 << 160; + uint256 internal constant _ROLE_161 = 1 << 161; + uint256 internal constant _ROLE_162 = 1 << 162; + uint256 internal constant _ROLE_163 = 1 << 163; + uint256 internal constant _ROLE_164 = 1 << 164; + uint256 internal constant _ROLE_165 = 1 << 165; + uint256 internal constant _ROLE_166 = 1 << 166; + uint256 internal constant _ROLE_167 = 1 << 167; + uint256 internal constant _ROLE_168 = 1 << 168; + uint256 internal constant _ROLE_169 = 1 << 169; + uint256 internal constant _ROLE_170 = 1 << 170; + uint256 internal constant _ROLE_171 = 1 << 171; + uint256 internal constant _ROLE_172 = 1 << 172; + uint256 internal constant _ROLE_173 = 1 << 173; + uint256 internal constant _ROLE_174 = 1 << 174; + uint256 internal constant _ROLE_175 = 1 << 175; + uint256 internal constant _ROLE_176 = 1 << 176; + uint256 internal constant _ROLE_177 = 1 << 177; + uint256 internal constant _ROLE_178 = 1 << 178; + uint256 internal constant _ROLE_179 = 1 << 179; + uint256 internal constant _ROLE_180 = 1 << 180; + uint256 internal constant _ROLE_181 = 1 << 181; + uint256 internal constant _ROLE_182 = 1 << 182; + uint256 internal constant _ROLE_183 = 1 << 183; + uint256 internal constant _ROLE_184 = 1 << 184; + uint256 internal constant _ROLE_185 = 1 << 185; + uint256 internal constant _ROLE_186 = 1 << 186; + uint256 internal constant _ROLE_187 = 1 << 187; + uint256 internal constant _ROLE_188 = 1 << 188; + uint256 internal constant _ROLE_189 = 1 << 189; + uint256 internal constant _ROLE_190 = 1 << 190; + uint256 internal constant _ROLE_191 = 1 << 191; + uint256 internal constant _ROLE_192 = 1 << 192; + uint256 internal constant _ROLE_193 = 1 << 193; + uint256 internal constant _ROLE_194 = 1 << 194; + uint256 internal constant _ROLE_195 = 1 << 195; + uint256 internal constant _ROLE_196 = 1 << 196; + uint256 internal constant _ROLE_197 = 1 << 197; + uint256 internal constant _ROLE_198 = 1 << 198; + uint256 internal constant _ROLE_199 = 1 << 199; + uint256 internal constant _ROLE_200 = 1 << 200; + uint256 internal constant _ROLE_201 = 1 << 201; + uint256 internal constant _ROLE_202 = 1 << 202; + uint256 internal constant _ROLE_203 = 1 << 203; + uint256 internal constant _ROLE_204 = 1 << 204; + uint256 internal constant _ROLE_205 = 1 << 205; + uint256 internal constant _ROLE_206 = 1 << 206; + uint256 internal constant _ROLE_207 = 1 << 207; + uint256 internal constant _ROLE_208 = 1 << 208; + uint256 internal constant _ROLE_209 = 1 << 209; + uint256 internal constant _ROLE_210 = 1 << 210; + uint256 internal constant _ROLE_211 = 1 << 211; + uint256 internal constant _ROLE_212 = 1 << 212; + uint256 internal constant _ROLE_213 = 1 << 213; + uint256 internal constant _ROLE_214 = 1 << 214; + uint256 internal constant _ROLE_215 = 1 << 215; + uint256 internal constant _ROLE_216 = 1 << 216; + uint256 internal constant _ROLE_217 = 1 << 217; + uint256 internal constant _ROLE_218 = 1 << 218; + uint256 internal constant _ROLE_219 = 1 << 219; + uint256 internal constant _ROLE_220 = 1 << 220; + uint256 internal constant _ROLE_221 = 1 << 221; + uint256 internal constant _ROLE_222 = 1 << 222; + uint256 internal constant _ROLE_223 = 1 << 223; + uint256 internal constant _ROLE_224 = 1 << 224; + uint256 internal constant _ROLE_225 = 1 << 225; + uint256 internal constant _ROLE_226 = 1 << 226; + uint256 internal constant _ROLE_227 = 1 << 227; + uint256 internal constant _ROLE_228 = 1 << 228; + uint256 internal constant _ROLE_229 = 1 << 229; + uint256 internal constant _ROLE_230 = 1 << 230; + uint256 internal constant _ROLE_231 = 1 << 231; + uint256 internal constant _ROLE_232 = 1 << 232; + uint256 internal constant _ROLE_233 = 1 << 233; + uint256 internal constant _ROLE_234 = 1 << 234; + uint256 internal constant _ROLE_235 = 1 << 235; + uint256 internal constant _ROLE_236 = 1 << 236; + uint256 internal constant _ROLE_237 = 1 << 237; + uint256 internal constant _ROLE_238 = 1 << 238; + uint256 internal constant _ROLE_239 = 1 << 239; + uint256 internal constant _ROLE_240 = 1 << 240; + uint256 internal constant _ROLE_241 = 1 << 241; + uint256 internal constant _ROLE_242 = 1 << 242; + uint256 internal constant _ROLE_243 = 1 << 243; + uint256 internal constant _ROLE_244 = 1 << 244; + uint256 internal constant _ROLE_245 = 1 << 245; + uint256 internal constant _ROLE_246 = 1 << 246; + uint256 internal constant _ROLE_247 = 1 << 247; + uint256 internal constant _ROLE_248 = 1 << 248; + uint256 internal constant _ROLE_249 = 1 << 249; + uint256 internal constant _ROLE_250 = 1 << 250; + uint256 internal constant _ROLE_251 = 1 << 251; + uint256 internal constant _ROLE_252 = 1 << 252; + uint256 internal constant _ROLE_253 = 1 << 253; + uint256 internal constant _ROLE_254 = 1 << 254; + uint256 internal constant _ROLE_255 = 1 << 255; +} + +// src\common/Treasury.sol + + + + + + +/// @title Treasury +/// @author Mathieu Bour for Pooky Labs Ltd. +/// +/// @notice Base class for contracts that are made to receive native currency. +/// The destination address is controller by the contract owner. +abstract contract Treasury is Ownable, ITreasury { + /// The native currency destination address. + address public treasury; + + constructor(address _treasury) { + treasury = _treasury; + } + + /// @notice Forward the funds to the treasury wallet at the end of the transaction. + /// Since `treasury` is a trusted address, this modifier should not lead to any re-entrancy issue. + modifier forwarder() { + _; + + uint256 value = address(this).balance; + (bool sent,) = treasury.call{ value: value }(""); + if (!sent) { + revert TransferFailed(treasury, value); + } + } + + /// Change the native currency destination address. + /// @param _treasury The new treasury address. + function changeTreasury(address _treasury) external onlyOwner { + treasury = _treasury; + } +} + +// src\common/IBaseERC721A.sol + + + + + + + + + +/// @title IBaseERC721 +/// +/// @author Mathieu Bour for Pooky Labs Ltd. +interface IBaseERC721A is IERC165, IERC721A, IERC721ABurnable, IERC721AQueryable, IERC2981 { + /// Fired when the seed of a Pookyball token is set by the VRFCoordinator, + event SeedSet(uint256 indexed tokenId, uint256 seed); + + /// Thrown when the token {tokenId} does not exist. + error NonExistentToken(uint256 tokenId); + + // ----- ERC721A patches ----- + /// @dev This allow to iterate over the token ids. + function nextTokenId() external view returns (uint256); + + function supportsInterface(bytes4 interfaceId) + external + view + override(IERC165, IERC721A) + returns (bool); +} + +// src\stickers/IStickers.sol + + + + + +enum StickerRarity { + COMMON, + RARE, + EPIC, + LEGENDARY, + MYTHIC +} + +struct StickerMint { + address recipient; + StickerRarity rarity; +} + +struct StickerMetadata { + uint248 level; + StickerRarity rarity; +} + +/// @title IStickers +/// @author Mathieu Bour for Pooky Labs Ltd. +interface IStickers is IBaseERC721A { + /// Fired when the level of a Pookyball token is changed, + event LevelChanged(uint256 indexed tokenId, uint256 level); + + /// @notice StickerMetadata of the token {tokenId}. + /// @dev Requirements: + /// - Sticker {tokenId} should exist (minted and not burned). + function metadata(uint256 tokenId) external view returns (StickerMetadata memory); + + /// @notice Change the level of a Sticker token. + /// @dev Requirements: + /// - Sticker {tokenId} should exist (minted and not burned). + function setLevel(uint256 tokenId, uint248 newLevel) external; + + /// @notice Mint multiple Stickers at once. + /// @param recipient The mint recipient. + /// @param rarities The Sticker rarities. + function mint(address recipient, StickerRarity[] memory rarities) external; +} + +// src\stickers\StickersSale.sol + + + + + + + +struct Pack { + uint256 price; + /// Supply of the current sale + uint256 supply; + /// Total number of tokens minted during all the sales + uint256 minted; + /// Total supply of all the sales + uint256 totalSupply; + PackContent content; +} + +struct PackContent { + /// How many common stickers are in the pack. + uint256 common; + /// How many rare stickers are in the pack. + uint256 rare; + /// How many epic stickers are in the pack. + uint256 epic; + /// How many legendary stickers are in the pack. + uint256 legendary; +} + +struct Refill { + uint256 packId; + /// The token price in native currency wei. + uint256 price; + /// The refill token quantity. + uint256 quantity; +} + +/// @title StickersSale +/// @author Mathieu Bour for Pooky Labs Ltd. +/// @notice Sticker Sale contract that can be refilled by an admin. +/// @dev Roles: +/// - Owner: allowd to create new packs +/// - Seller: allowed to refill the sale +contract StickersSale is OwnableRoles, Treasury { + uint256 public constant SELLER = _ROLE_0; + + /// The Stickers contract address. + IStickers public immutable stickers; + + /// The date when next mint window will open (compared to block.timestamp). + uint256 public closedUntil; + + mapping(uint256 => Pack) public packs; + /// The number of created packs. + uint256 size; + + /// Thrown when a mint is attempt before the sale opens. + error Closed(uint256 closedUntil); + /// Thrown when the passed pack id is invalid (greater or equal than `size`). + error InvalidPack(); + /// Thrown when a mint would exceed the pack supply. + error InsufficientSupply(uint256 packId); + + constructor(IStickers _stickers, address admin, address _treasury, Pack[] memory _packs) + Treasury(_treasury) + { + stickers = _stickers; + _initializeOwner(admin); + + uint256 length = _packs.length; + for (uint256 i; i < length;) { + _create(_packs[i]); + unchecked { + i++; + } + } + } + + /// @notice List available packs. + function getPacks() external view returns (Pack[] memory) { + Pack[] memory output = new Pack[](size); + for (uint256 i; i < size;) { + output[i] = packs[i]; + unchecked { + i++; + } + } + + return output; + } + + /// @notice Checks if the sale is open. + function isClosed() public view returns (bool) { + return closedUntil == 0 || block.timestamp < closedUntil; + } + + /// @dev Internal unprotected pack creation. + function _create(Pack memory _pack) internal { + packs[size++] = _pack; + } + + /// @notice Create a new pack. + /// @dev Requirements: + /// - Only owner can create new packs. + function create(Pack memory _pack) external onlyOwner { + _create(_pack); + } + + /// @notice Purchase a Stickers pack. + /// @dev Requirements: + /// - Sale must be open. + /// - Pack ID must exist. + /// - Transaction value must be greater or equal than the pack price. + function purchase(uint256 packId, address recipient) external payable forwarder { + if (isClosed()) { + revert Closed(closedUntil); + } + + if (packId >= size) { + revert InvalidPack(); + } + + Pack memory pack = packs[packId]; + + if (pack.minted + 1 > pack.totalSupply) { + revert InsufficientSupply(packId); + } + + if (msg.value < pack.price) { + revert InsufficientValue(msg.value, pack.price); + } + + uint256 quantity = + pack.content.common + pack.content.rare + pack.content.epic + pack.content.legendary; + + StickerRarity[] memory rarities = new StickerRarity[](quantity); + + uint256 requestId; + for (uint256 i; i < pack.content.common;) { + rarities[requestId++] = StickerRarity.COMMON; + unchecked { + i++; + } + } + for (uint256 i; i < pack.content.rare;) { + rarities[requestId++] = StickerRarity.RARE; + unchecked { + i++; + } + } + for (uint256 i; i < pack.content.epic;) { + rarities[requestId++] = StickerRarity.EPIC; + unchecked { + i++; + } + } + for (uint256 i; i < pack.content.legendary;) { + rarities[requestId++] = StickerRarity.LEGENDARY; + unchecked { + i++; + } + } + + stickers.mint(recipient, rarities); + packs[packId].minted++; + } + + /// @notice Restock the sale items. + /// @param refills Array of the modifications to apply. + /// @param _closedUntil Update the opening of the sale; a date in the past opens the sale immediately. + /// @dev Requirements: + /// - msg.sender must have the `SELLER` role or be the owner + function restock(Refill[] memory refills, uint256 _closedUntil) external onlyRolesOrOwner(SELLER) { + uint256 length = refills.length; + for (uint256 i; i < length;) { + Pack memory current = packs[refills[i].packId]; + current.price = refills[i].price; + current.totalSupply = current.minted + refills[i].quantity; + current.supply = refills[i].quantity; + packs[refills[i].packId] = current; + unchecked { + i++; + } + } + + closedUntil = _closedUntil; + } +} From 30e65bb80b07a909c186b0931b2a0a755ebc4ab6 Mon Sep 17 00:00:00 2001 From: Claudiu Date: Mon, 1 Apr 2024 20:10:22 +0300 Subject: [PATCH 06/10] feat(scripts): Add missing scripts --- script/amoy/04_BoostPXP.s.sol | 2 + script/amoy/05_Pookyball.s.sol | 2 - script/amoy/07_RefillableSale.s.sol | 43 ++++++++++++++++ script/amoy/08_Pressure.s.sol | 35 +++++++++++++ ...lReroll.s.sol => 09_PookyballReroll.s.sol} | 0 script/amoy/09_Stickers.s.sol | 13 +++-- ...LevelUp.s.sol => 12_StickersLevelUp.s.sol} | 0 ...ickersSale.s.sol => 13_StickersSale.s.sol} | 0 ...ller.s.sol => 14_StickersController.s.sol} | 2 + ...Manager.s.sol => 15_StickersManager.s.sol} | 0 ...nsion.s.sol => 16_StickersAscension.s.sol} | 0 ...sion.s.sol => 17_PookyballAscension.s.sol} | 0 script/amoy/18_Rewards.s.sol | 51 +++++++++++++++++++ 13 files changed, 141 insertions(+), 7 deletions(-) create mode 100644 script/amoy/07_RefillableSale.s.sol create mode 100644 script/amoy/08_Pressure.s.sol rename script/amoy/{07_PookyballReroll.s.sol => 09_PookyballReroll.s.sol} (100%) rename script/amoy/{10_StickersLevelUp.s.sol => 12_StickersLevelUp.s.sol} (100%) rename script/amoy/{11_StickersSale.s.sol => 13_StickersSale.s.sol} (100%) rename script/amoy/{12_StickersController.s.sol => 14_StickersController.s.sol} (97%) rename script/amoy/{13_StickersManager.s.sol => 15_StickersManager.s.sol} (100%) rename script/amoy/{14_StickersAscension.s.sol => 16_StickersAscension.s.sol} (100%) rename script/amoy/{08_PookyballAscension.s.sol => 17_PookyballAscension.s.sol} (100%) create mode 100644 script/amoy/18_Rewards.s.sol diff --git a/script/amoy/04_BoostPXP.s.sol b/script/amoy/04_BoostPXP.s.sol index e5a7f8ac..52f2bc78 100644 --- a/script/amoy/04_BoostPXP.s.sol +++ b/script/amoy/04_BoostPXP.s.sol @@ -29,7 +29,9 @@ contract DeployBoostPXP is Script { // ================ Admin grant roles ================ vm.startBroadcast(adminPK); + nonces.grantRole(nonces.OPERATOR(), address(boostPXP)); + vm.stopBroadcast(); } } diff --git a/script/amoy/05_Pookyball.s.sol b/script/amoy/05_Pookyball.s.sol index 39cd6a30..25eae19f 100644 --- a/script/amoy/05_Pookyball.s.sol +++ b/script/amoy/05_Pookyball.s.sol @@ -3,8 +3,6 @@ pragma solidity ^0.8.21; import "forge-std/console.sol"; import { Script } from "forge-std/Script.sol"; -import { BoostPXP } from "@/common/BoostPXP.sol"; -import { NonceRegistry } from "@/common/NonceRegistry.sol"; import { Pookyball } from "@/pookyball/Pookyball.sol"; contract DeployPookyball is Script { diff --git a/script/amoy/07_RefillableSale.s.sol b/script/amoy/07_RefillableSale.s.sol new file mode 100644 index 00000000..c2a4a6d2 --- /dev/null +++ b/script/amoy/07_RefillableSale.s.sol @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.22; + +import "forge-std/console.sol"; +import { Script } from "forge-std/Script.sol"; +import { NonceRegistry } from "@/common/NonceRegistry.sol"; +import { Pookyball } from "@/pookyball/Pookyball.sol"; +import { RefillableSale } from "@/pookyball/RefillableSale.sol"; + +contract DeployRefillableSale is Script { + bytes32 salt = keccak256(bytes(vm.envString("SALT"))); + uint256 deployerPK = vm.envUint("DEPLOYER_PK"); + uint256 adminPK = vm.envUint("ADMIN_PK"); + address adminAddress = vm.envAddress("ADMIN_ADDRESS"); + address signerAddress = vm.envAddress("BACKEND_ADDRESS"); + address treasuryAddress = vm.envAddress("TREASURY_ADDRESS"); + address operatorAddress = vm.envAddress("OPERATOR_ADDRESS"); + + Pookyball pookyball = Pookyball(vm.envAddress("CONTRACT_POOKYBALL_ADDRESS")); + + function run() public { + // ================ Deploy RefillableSale ================ + vm.startBroadcast(deployerPK); + + address[] memory sellers = new address[](1); + sellers[0] = operatorAddress; + + RefillableSale refillableSale = + new RefillableSale{ salt: salt }(pookyball, treasuryAddress, adminAddress, sellers); + + console.log("RefillableSale deployed at:", address(refillableSale)); + + vm.stopBroadcast(); + + // ================ Admin grant roles ================ + vm.startBroadcast(adminPK); + + console.log("Pookyball grant roles for RefillableSale to mint"); + pookyball.grantRole(pookyball.MINTER(), address(refillableSale)); + + vm.stopBroadcast(); + } +} diff --git a/script/amoy/08_Pressure.s.sol b/script/amoy/08_Pressure.s.sol new file mode 100644 index 00000000..925071e6 --- /dev/null +++ b/script/amoy/08_Pressure.s.sol @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.22; + +import "forge-std/console.sol"; +import { Script } from "forge-std/Script.sol"; +import { Pressure } from "@/pookyball/Pressure.sol"; +import { POK } from "@/tokens/POK.sol"; + +contract DeployPressure is Script { + bytes32 salt = keccak256(bytes(vm.envString("SALT"))); + uint256 deployerPK = vm.envUint("DEPLOYER_PK"); + uint256 adminPK = vm.envUint("ADMIN_PK"); + address treasuryAddress = vm.envAddress("TREASURY_ADDRESS"); + + POK pok = POK(vm.envAddress("CONTRACT_POK_ADDRESS")); + + function run() public { + // ================ Deploy Pressure ================ + vm.startBroadcast(deployerPK); + + Pressure pressure = new Pressure{ salt: salt }(pok, treasuryAddress); + + console.log("Pressure deployed at:", address(pressure)); + + vm.stopBroadcast(); + + // ================ Admin grant roles ================ + vm.startBroadcast(adminPK); + + console.log("Pookyball grant roles for Pressure to burn POK"); + pok.grantRole(pok.BURNER(), address(pressure)); + + vm.stopBroadcast(); + } +} diff --git a/script/amoy/07_PookyballReroll.s.sol b/script/amoy/09_PookyballReroll.s.sol similarity index 100% rename from script/amoy/07_PookyballReroll.s.sol rename to script/amoy/09_PookyballReroll.s.sol diff --git a/script/amoy/09_Stickers.s.sol b/script/amoy/09_Stickers.s.sol index 20546634..49df8fa5 100644 --- a/script/amoy/09_Stickers.s.sol +++ b/script/amoy/09_Stickers.s.sol @@ -38,12 +38,15 @@ contract DeployStickers is Script { vm.stopBroadcast(); - // ================ Admin grant roles ================ - vm.startBroadcast(adminPK); + uint256 chainID = vm.envUint("CHAIN_ID"); + if (chainID != 31337 && chainID != 80002) { + // ================ Admin grant roles ================ + vm.startBroadcast(adminPK); - console.log("Add the Stickers consumer to VRF Coordinator"); - vrf.coordinator.addConsumer(vrf.subcriptionId, address(stickers)); + console.log("Add the Stickers consumer to VRF Coordinator"); + vrf.coordinator.addConsumer(vrf.subcriptionId, address(stickers)); - vm.stopBroadcast(); + vm.stopBroadcast(); + } } } diff --git a/script/amoy/10_StickersLevelUp.s.sol b/script/amoy/12_StickersLevelUp.s.sol similarity index 100% rename from script/amoy/10_StickersLevelUp.s.sol rename to script/amoy/12_StickersLevelUp.s.sol diff --git a/script/amoy/11_StickersSale.s.sol b/script/amoy/13_StickersSale.s.sol similarity index 100% rename from script/amoy/11_StickersSale.s.sol rename to script/amoy/13_StickersSale.s.sol diff --git a/script/amoy/12_StickersController.s.sol b/script/amoy/14_StickersController.s.sol similarity index 97% rename from script/amoy/12_StickersController.s.sol rename to script/amoy/14_StickersController.s.sol index 1bb54ad8..45b33cff 100644 --- a/script/amoy/12_StickersController.s.sol +++ b/script/amoy/14_StickersController.s.sol @@ -24,5 +24,7 @@ contract DeployStickersController is Script { ); console.log("StickersController deployed at:", address(controller)); + + vm.stopBroadcast(); } } diff --git a/script/amoy/13_StickersManager.s.sol b/script/amoy/15_StickersManager.s.sol similarity index 100% rename from script/amoy/13_StickersManager.s.sol rename to script/amoy/15_StickersManager.s.sol diff --git a/script/amoy/14_StickersAscension.s.sol b/script/amoy/16_StickersAscension.s.sol similarity index 100% rename from script/amoy/14_StickersAscension.s.sol rename to script/amoy/16_StickersAscension.s.sol diff --git a/script/amoy/08_PookyballAscension.s.sol b/script/amoy/17_PookyballAscension.s.sol similarity index 100% rename from script/amoy/08_PookyballAscension.s.sol rename to script/amoy/17_PookyballAscension.s.sol diff --git a/script/amoy/18_Rewards.s.sol b/script/amoy/18_Rewards.s.sol new file mode 100644 index 00000000..e44b059d --- /dev/null +++ b/script/amoy/18_Rewards.s.sol @@ -0,0 +1,51 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.22; + +import "forge-std/console.sol"; +import { NonceRegistry } from "@/common/NonceRegistry.sol"; +import { POK } from "@/tokens/POK.sol"; +import { Pookyball } from "@/pookyball/Pookyball.sol"; +import { Rewards } from "@/common/Rewards.sol"; +import { Script } from "forge-std/Script.sol"; +import { Stickers } from "@/stickers/Stickers.sol"; + +contract DeployRewards is Script { + bytes32 salt = keccak256(bytes(vm.envString("SALT"))); + uint256 deployerPK = vm.envUint("DEPLOYER_PK"); + uint256 adminPK = vm.envUint("ADMIN_PK"); + address adminAddress = vm.envAddress("ADMIN_ADDRESS"); + address operatorAddress = vm.envAddress("OPERATOR_ADDRESS"); + + Pookyball pookyball = Pookyball(vm.envAddress("CONTRACT_POOKYBALL_ADDRESS")); + Stickers stickers = Stickers(vm.envAddress("CONTRACT_STICKERS_ADDRESS")); + POK pok = POK(vm.envAddress("CONTRACT_POK_ADDRESS")); + NonceRegistry nonces = NonceRegistry(vm.envAddress("CONTRACT_NONCE_REGISTRY_ADDRESS")); + + function run() external { + // ================ Deploy Rewards ================ + vm.startBroadcast(deployerPK); + + address[] memory rewarders = new address[](1); + rewarders[0] = operatorAddress; + + Rewards rewards = + new Rewards{ salt: salt }(pok, pookyball, stickers, nonces, adminAddress, rewarders); + + console.log("Rewards deployed at:", address(rewards)); + + vm.stopBroadcast(); + + // ================ Admin grant roles ================ + vm.startBroadcast(adminPK); + + nonces.grantRole(nonces.OPERATOR(), address(rewards)); + + pookyball.grantRole(pookyball.MINTER(), address(rewards)); + + stickers.grantRoles(address(rewards), stickers.MINTER()); + + pok.grantRole(pok.MINTER(), address(rewards)); + + vm.stopBroadcast(); + } +} From 358d61cfee82ebf8bc6f9c665d31f3aff38be32d Mon Sep 17 00:00:00 2001 From: Claudiu Date: Mon, 1 Apr 2024 20:11:11 +0300 Subject: [PATCH 07/10] fix(doc): Relocate chain docs --- docs/chains.md | 19 +++++++++++++++++++ docs/chains/amoy.md | 8 -------- docs/chains/mainnet.md | 8 -------- 3 files changed, 19 insertions(+), 16 deletions(-) create mode 100644 docs/chains.md delete mode 100644 docs/chains/amoy.md delete mode 100644 docs/chains/mainnet.md diff --git a/docs/chains.md b/docs/chains.md new file mode 100644 index 00000000..e86058e4 --- /dev/null +++ b/docs/chains.md @@ -0,0 +1,19 @@ +# Chains on which contracts are deployed + +## Chain info: + +- Network Name: `Polygon Mainnet` +- New RPC URL: [`https://polygon-rpc.com`](https://polygon-rpc.com) +- Chain ID: `137` +- Currency Symbol: `MATIC` +- Block Explorer URL: [`https://polygonscan.com`](https://polygonscan.com) +- Faucet: [`https://faucet.polygon.technology/`](https://faucet.polygon.technology/) + +## Chain info: + +- Network Name: `Polygon Amoy Testnet` +- New RPC URL: [`https://rpc-amoy.polygon.technology/`](https://rpc-amoy.polygon.technology/) +- Chain ID: `80002` +- Currency Symbol: `MATIC` +- Block Explorer URL: [`https://www.oklink.com/amoy`](https://www.oklink.com/amoy) +- Faucet: [`https://faucet.polygon.technology/`](https://faucet.polygon.technology/) diff --git a/docs/chains/amoy.md b/docs/chains/amoy.md deleted file mode 100644 index 93e40379..00000000 --- a/docs/chains/amoy.md +++ /dev/null @@ -1,8 +0,0 @@ -## Chain info: - -- Network Name: `Polygon Amoy Testnet` -- New RPC URL: [`https://80002.rpc.thirdweb.com`](https://80002.rpc.thirdweb.com) -- Chain ID: `80002` -- Currency Symbol: `MATIC` -- Block Explorer URL: [`https://www.oklink.com/amoy`](https://www.oklink.com/amoy) -- Faucet: [`https://faucet.polygon.technology/`](https://faucet.polygon.technology/) diff --git a/docs/chains/mainnet.md b/docs/chains/mainnet.md deleted file mode 100644 index d56e9777..00000000 --- a/docs/chains/mainnet.md +++ /dev/null @@ -1,8 +0,0 @@ -## Chain info: - -- Network Name: `Polygon Mainnet` -- New RPC URL: [`https://polygon-rpc.com`](https://polygon-rpc.com) -- Chain ID: `137` -- Currency Symbol: `MATIC` -- Block Explorer URL: [`https://polygonscan.com`](https://polygonscan.com) -- Faucet: [`https://faucet.polygon.technology/`](https://faucet.polygon.technology/) From d543dce402b927d94ce039f20ab1a005b4af529b Mon Sep 17 00:00:00 2001 From: Claudiu Date: Mon, 1 Apr 2024 20:11:36 +0300 Subject: [PATCH 08/10] feat(docs): Add alchemy webhook docs --- docs/alchemy_webhooks/energy.md | 44 +++++++++++++++++ docs/alchemy_webhooks/pookyball.md | 50 ++++++++++++++++++++ docs/alchemy_webhooks/pookyball_ascension.md | 44 +++++++++++++++++ docs/alchemy_webhooks/pookyball_pressure.md | 44 +++++++++++++++++ docs/alchemy_webhooks/pookyball_reroll.md | 44 +++++++++++++++++ docs/alchemy_webhooks/rewards.md | 44 +++++++++++++++++ docs/alchemy_webhooks/stickers.md | 48 +++++++++++++++++++ docs/alchemy_webhooks/stickers_ascension.md | 44 +++++++++++++++++ docs/alchemy_webhooks/stickers_controller.md | 48 +++++++++++++++++++ 9 files changed, 410 insertions(+) create mode 100644 docs/alchemy_webhooks/energy.md create mode 100644 docs/alchemy_webhooks/pookyball.md create mode 100644 docs/alchemy_webhooks/pookyball_ascension.md create mode 100644 docs/alchemy_webhooks/pookyball_pressure.md create mode 100644 docs/alchemy_webhooks/pookyball_reroll.md create mode 100644 docs/alchemy_webhooks/rewards.md create mode 100644 docs/alchemy_webhooks/stickers.md create mode 100644 docs/alchemy_webhooks/stickers_ascension.md create mode 100644 docs/alchemy_webhooks/stickers_controller.md diff --git a/docs/alchemy_webhooks/energy.md b/docs/alchemy_webhooks/energy.md new file mode 100644 index 00000000..d453f4e6 --- /dev/null +++ b/docs/alchemy_webhooks/energy.md @@ -0,0 +1,44 @@ +# Energy Alchemy Webhook + +## URL + +https://blockchain-events-service-t57fod3riq-oa.a.run.app/api/webhook/energy + +## Graphql Query + +``` +{ + block(hash: "0xcd823713b39008f1f6e909103157de6b78d51e22c923bfcd1cab2fa8b5df3092") { + hash + number + timestamp + logs( + filter: { + addresses: [ + # Energy + "0xcE3bAF0c9989beC8e39B0D063Ffdf5C09373a510" + ] + topics: [[ + # Transfer(address,address,uint256) + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef" + ]] + } + ) { + topics + data + index + account { + address + } + transaction { + hash + from { + address + } + value + status + } + } + } +} +``` diff --git a/docs/alchemy_webhooks/pookyball.md b/docs/alchemy_webhooks/pookyball.md new file mode 100644 index 00000000..2f980242 --- /dev/null +++ b/docs/alchemy_webhooks/pookyball.md @@ -0,0 +1,50 @@ +# Pookyball Alchemy Webhook + +## URL + +https://blockchain-events-service-t57fod3riq-oa.a.run.app/api/webhook/pookyball + +## Graphql Query + +``` +{ + block(hash: "0x6361d2726ffc5b7ab49a006782513ce2358ab06e4bfd35c9ca1080fa86b2fc00") { + hash + number + timestamp + logs( + filter: { + addresses: [ + # Pookyball + "0x91290239CD991eB8B748FaFe3fb2401C5ec3c988" + ] + topics: [[ + # Seedset(uint256,uint256) + "0x14296754697e325872a9c14eb682f467bc46b15a78ae9420d7a13a7cd3833b2c" + # Transfer(uint256,address,address) + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef" + # LevelChanged(uint256,uint256) + "0x8bdaee675270281b7bc2d5b9ced20517ecf5ce96158973ef78072a7bc1491b44" + # PXPChanged(uint256,uint256) + "0x334246ed50b046a9933ddd38bbb387c51e3709753687788af1c5207d3689761b" + ]] + } + ) { + topics + data + index + account { + address + } + transaction { + hash + from { + address + } + value + status + } + } + } +} +``` diff --git a/docs/alchemy_webhooks/pookyball_ascension.md b/docs/alchemy_webhooks/pookyball_ascension.md new file mode 100644 index 00000000..36130975 --- /dev/null +++ b/docs/alchemy_webhooks/pookyball_ascension.md @@ -0,0 +1,44 @@ +# Pookyball Ascension Alchemy Webhook + +## URL + +https://blockchain-events-service-t57fod3riq-oa.a.run.app/api/webhook/pookyball/ascension + +## Graphql Query + +``` +{ + block(hash: "0xc0d32f45c8db019a877f8cfe4b021f3adcdb4d9d90dc2942f716155b4e9bbe9d") { + hash + number + timestamp + logs( + filter: { + addresses: [ + # Ascension + "0x1369B4e6B4B1A8f1a6C3c79dCB5DbB251EdC0D30" + ] + topics: [[ + # Ascended(uint256,uint8,uint256,uint256,string) + "0x82c463f27adb1a5c8e7d0209eb97c6dcec687c389dfc71b7c0a6216a128571db" + ]] + } + ) { + topics + data + index + account { + address + } + transaction { + hash + from { + address + } + value + status + } + } + } +} +``` diff --git a/docs/alchemy_webhooks/pookyball_pressure.md b/docs/alchemy_webhooks/pookyball_pressure.md new file mode 100644 index 00000000..e3b47a23 --- /dev/null +++ b/docs/alchemy_webhooks/pookyball_pressure.md @@ -0,0 +1,44 @@ +# Pookyball Pressure Alchemy Webhook + +## URL + +https://blockchain-events-service-t57fod3riq-oa.a.run.app/api/webhook/pookyball/pressure + +## Graphql Query + +``` +{ + block(hash: "0xae3c3dabd292cbb43c40afc615d5563a1dfa5f1a92d801a239f361570a519ca5") { + hash + number + timestamp + logs( + filter: { + addresses: [ + # Pressure + "0x3876E098488092af30aFACBF4e99553372CaAedD" + ] + topics: [[ + # Inflated(uint256,uint8,uint8) + "0xae8e536e52847e375aeccd7c0fe477cd7394d10e10101278e98d83ad0633b3da" + ]] + } + ) { + topics + data + index + account { + address + } + transaction { + hash + from { + address + } + value + status + } + } + } +} +``` diff --git a/docs/alchemy_webhooks/pookyball_reroll.md b/docs/alchemy_webhooks/pookyball_reroll.md new file mode 100644 index 00000000..8e4756f0 --- /dev/null +++ b/docs/alchemy_webhooks/pookyball_reroll.md @@ -0,0 +1,44 @@ +# Pookyball Reroll Alchemy Webhook + +## URL + +https://blockchain-events-service-t57fod3riq-oa.a.run.app/api/webhook/pookyball/reroll + +## Graphql Query + +``` +{ + block(hash: "0xa9cb852339ea8ac81780d8fd07ab893f4abf88531b182270b232d9062c4bebfe") { + hash + number + timestamp + logs( + filter: { + addresses: [ + # Reroll + "0x5c2E6a21813751411c4d445F9DFa2638c8271f61" + ] + topics: [[ + # Reroll(uint256,uint256) + "0xd49929b567bcaca6fae0329912961a4872c232438a2d478bb94c0775ff1e1f62" + ]] + } + ) { + topics + data + index + account { + address + } + transaction { + hash + from { + address + } + value + status + } + } + } +} +``` diff --git a/docs/alchemy_webhooks/rewards.md b/docs/alchemy_webhooks/rewards.md new file mode 100644 index 00000000..09a9e79c --- /dev/null +++ b/docs/alchemy_webhooks/rewards.md @@ -0,0 +1,44 @@ +# Rewards Alchemy Webhook + +## URL + +https://blockchain-events-service-t57fod3riq-oa.a.run.app/api/webhook/reward + +## Graphql Query + +``` +{ + block(hash: "0x53484e705a10026632c689a082b0723b50c79150acbf634656698a24d2c8c0a7") { + hash + number + timestamp + logs( + filter: { + addresses: [ + # Reward + "0xBa609c15697617f9a243A5E0A609371044497719" + ] + topics: [[ + # RewardsClaimed(address,(uint256,uint256,(uint256,uint256)[],uint8[],bytes32[]),string) + "0x333a6859dbd4f68eb6492cd6f8ad2b4ae4ae870747adebb44935fb4a2603cedf" + ]] + } + ) { + topics + data + index + account { + address + } + transaction { + hash + from { + address + } + value + status + } + } + } +} +``` diff --git a/docs/alchemy_webhooks/stickers.md b/docs/alchemy_webhooks/stickers.md new file mode 100644 index 00000000..14eaa2df --- /dev/null +++ b/docs/alchemy_webhooks/stickers.md @@ -0,0 +1,48 @@ +# Stickers Alchemy Webhook + +## URL + +https://blockchain-events-service-t57fod3riq-oa.a.run.app/api/webhook/sticker + +## Graphql Query + +``` +{ + block(hash: "0x7a71beba18bbcf6c9a057964d613c66c7fd7579a0ebae931b7ce66f80836e478") { + hash + number + timestamp + logs( + filter: { + addresses: [ + # Sticker + "0x975d59D5ff4c1D4ED908892377E23Bf00c40f7aD" + ] + topics: [[ + # SeedSet(uint256,uint256) + "0x14296754697e325872a9c14eb682f467bc46b15a78ae9420d7a13a7cd3833b2c" + # Transfer(uint256,address,address) + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef" + # LevelChanged(uint256,uint256) + "0x8bdaee675270281b7bc2d5b9ced20517ecf5ce96158973ef78072a7bc1491b44" + ]] + } + ) { + topics + data + index + account { + address + } + transaction { + hash + from { + address + } + value + status + } + } + } +} +``` diff --git a/docs/alchemy_webhooks/stickers_ascension.md b/docs/alchemy_webhooks/stickers_ascension.md new file mode 100644 index 00000000..27684065 --- /dev/null +++ b/docs/alchemy_webhooks/stickers_ascension.md @@ -0,0 +1,44 @@ +# Stickers Ascension Alchemy Webhook + +## URL + +https://blockchain-events-service-t57fod3riq-oa.a.run.app/api/webhook/sticker/ascension + +## Graphql Query + +``` +{ + block(hash: "0xdf758a3c5698d68094e113f25a9ca1a2f7a8d102e9351dea92afbeffc36b7e94") { + hash + number + timestamp + logs( + filter: { + addresses: [ + # Ascension Stickers + "0xCb20FEe5113F10fE06BD9452d2E5cD1972161006" + ] + topics: [[ + # Ascended(uint256 indexed tokenId, uint8 rarity, uint256[] parts, string data) + "0x11869a71baced1026064951c3a99898feaafa2a01af499fe82eb2396891db7ef" + ]] + } + ) { + topics + data + index + account { + address + } + transaction { + hash + from { + address + } + value + status + } + } + } +} +``` diff --git a/docs/alchemy_webhooks/stickers_controller.md b/docs/alchemy_webhooks/stickers_controller.md new file mode 100644 index 00000000..372ddb6c --- /dev/null +++ b/docs/alchemy_webhooks/stickers_controller.md @@ -0,0 +1,48 @@ +# Stickers Controller Alchemy Webhook + +## URL + +https://blockchain-events-service-t57fod3riq-oa.a.run.app/api/webhook/sticker/controller + +## Graphql Query + +``` +{ + block(hash: "0x40bb2ace6b4d4301747320b9107183def831554b018e0a2a4cdde7199bb8bc6f") { + hash + number + timestamp + logs( + filter: { + addresses: [ + # StickerController + "0xB9b85d3DCF4bB8c064D9F594354F07F5DCE12daF" + ] + topics: [[ + # StickerAttached(uint256,uint256) + "0xa0caedfb09abf5bb3acfa131de435a0b7aa4884a8b70d261e35fd563f843e1ac" + # StickerReplaced(uint256,uint256,uint256) + "0xf22098f7acee83ee20f4856c625c4321d76cb426bcb4e2ae67d7b3eccf00bd85" + # StickerDetached(uint256,uint256) + "0x47d2a53d2ac8e763206badd9286235cacd85eb4d108ee384e77c6fedbc4f0f02" + ]] + } + ) { + topics + data + index + account { + address + } + transaction { + hash + from { + address + } + value + status + } + } + } +} +``` From 4301d6e03aea727fc308dc9d367c5ee39f6a11fa Mon Sep 17 00:00:00 2001 From: Claudiu Date: Mon, 1 Apr 2024 20:12:21 +0300 Subject: [PATCH 09/10] feat(docs): Add amoy testnet contract addresses --- CONTRIBUTING.md | 2 +- README.md | 63 +++++++++++++++++++++++++++++++++---------------- 2 files changed, 44 insertions(+), 21 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 5b87165a..6475fd5c 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -42,4 +42,4 @@ etc. - [Foundry Book](https://book.getfoundry.sh/) - [OpenZeppelin Contracts 4.x](https://docs.openzeppelin.com/contracts/4.x/) -- [Polygon Mumbai Testnet Faucet](https://mumbaifaucet.com/) +- [Polygon Amoy Testnet Faucet](https://faucet.polygon.technology/) diff --git a/README.md b/README.md index a1daab4c..38608efa 100644 --- a/README.md +++ b/README.md @@ -7,26 +7,49 @@ For more details about the internal architecture of the repository, see [CONTRIBUTING.md](CONTRIBUTING.md). -## Contracts - -| Contract | Address on Polygon | -| -------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------- | -| [`Energy`](https://github.com/pooky-labs/smart-contracts/blob/a9cb86055339ccb3b313b35ffbca7ecdf12358f6/src/common/Energy.sol) | [`0x356fB0fE98023239b240795003595dbCb63c57cd`](https://polygonscan.com/address/0x356fB0fE98023239b240795003595dbCb63c57cd#code) | -| [`NonceRegistry`](https://github.com/pooky-labs/smart-contracts/blob/f15873dd3cffa045fd0029763c50fa00ab8c2134/src/common/NonceRegistry.sol) | [`0xB08Ee469Dcf9c40B77261d8665A8BbdFad22B818`](https://polygonscan.com/address/0xB08Ee469Dcf9c40B77261d8665A8BbdFad22B818#code) | -| [`Rewards`](https://github.com/pooky-labs/smart-contracts/blob/5f4932e4525771953b91d349a3a615b338f02d43/src/game/Rewards.sol) | [`0x64A85fb2Ca5ebdC70cBa233a7Ea94672BeF5B372`](https://polygonscan.com/address/0x64A85fb2Ca5ebdC70cBa233a7Ea94672BeF5B372#code) | -| [`Pookyball`](https://github.com/pooky-labs/smart-contracts/blob/9f11c880e8bd31c9a266b3738c8b17463cf77cfa/src/tokens/Pookyball.sol) | [`0xb4859acd9B0A65CA4897c31e5cb5160D9Ff32C0A`](https://polygonscan.com/address/0xb4859acd9B0A65CA4897c31e5cb5160D9Ff32C0A#code) | -| [`PookyballAscension`](https://github.com/pooky-labs/smart-contracts/blob/fba76ea65e3b99b425b473bf5d689837ebedeb18/src/pookyball/PookyballAscension.sol) | [`0x2a3b939f2deaf2bd16806b7f4b48af23f1bcc515`](https://polygonscan.com/address/0x2a3b939f2deaf2bd16806b7f4b48af23f1bcc515#code) | -| [`PookyballLevelUp`](https://github.com/pooky-labs/smart-contracts/blob/fba76ea65e3b99b425b473bf5d689837ebedeb18/src/pookyball/PookyballLevelUp.sol) | [`0x13e887fca91d6f9ff5d44dcf44f9b9074b314aab`](https://polygonscan.com/address/0x13e887fca91d6f9ff5d44dcf44f9b9074b314aab#code) | -| [`PookyballReroll`](https://github.com/pooky-labs/smart-contracts/blob/1c40639834a1f5f7bafb191c2cc7c94a8a2be92f/src/pookyball/PookyballReroll.sol) | [`0x336033401230245EA9BD940Cb1b4cA91AF16415f`](https://polygonscan.com/address/0x336033401230245EA9BD940Cb1b4cA91AF16415f#code) | -| [`Pressure`](https://github.com/pooky-labs/smart-contracts/blob/fba76ea65e3b99b425b473bf5d689837ebedeb18/src/pookyball/Pressure.sol) | [`0xa34223AD4d42CB041056287784FE1F91a7e5b21A`](https://polygonscan.com/address/0xa34223AD4d42CB041056287784FE1F91a7e5b21A#code) | -| [`RefillableSale`](https://github.com/pooky-labs/smart-contracts/blob/fba76ea65e3b99b425b473bf5d689837ebedeb18/src/pookyball/RefillableSale.sol) | [`0x57f48000b7573dd55963f15a1bf2490e43fee41c`](https://polygonscan.com/address/0x57f48000b7573dd55963f15a1bf2490e43fee41c#code) | -| [`Stickers`](https://github.com/pooky-labs/smart-contracts/blob/f15873dd3cffa045fd0029763c50fa00ab8c2134/src/stickers/Stickers.sol) | [`0x440D4955a914D5e29F861aC024A608aE41c56cB6`](https://polygonscan.com/address/0x440D4955a914D5e29F861aC024A608aE41c56cB6#code) | -| [`StickerAscension`](https://github.com/pooky-labs/smart-contracts/blob/fba76ea65e3b99b425b473bf5d689837ebedeb18/src/stickers/StickersAscension.sol) | [`0x49d0e15af6c939670c628cea99512ae22c79fa7c`](https://polygonscan.com/address/0x49d0e15af6c939670c628cea99512ae22c79fa7c#code) | -| [`StickersController`](https://github.com/pooky-labs/smart-contracts/blob/f15873dd3cffa045fd0029763c50fa00ab8c2134/src/stickers/StickersController.sol) | [`0x75cc3c6329930758659eD87338B926c90e16d05F`](https://polygonscan.com/address/0x75cc3c6329930758659eD87338B926c90e16d05F#code) | -| [`StickersManager`](https://github.com/pooky-labs/smart-contracts/blob/f15873dd3cffa045fd0029763c50fa00ab8c2134/src/stickers/StickersManager.sol) | [`0x534Fda3d9C8A08FD0E57DE8c1Af9B32987614bA1`](https://polygonscan.com/address/0x534Fda3d9C8A08FD0E57DE8c1Af9B32987614bA1#code) | -| [`StickersLevelUp`](https://github.com/pooky-labs/smart-contracts/blob/f15873dd3cffa045fd0029763c50fa00ab8c2134/src/stickers/StickersLevelUp.sol) | [`0x766e81AF624Cd6D2615EF675bDca2aB1ffBCBCbE`](https://polygonscan.com/address/0x766e81AF624Cd6D2615EF675bDca2aB1ffBCBCbE#code) | -| [`StickersSale`](https://github.com/pooky-labs/smart-contracts/blob/fba76ea65e3b99b425b473bf5d689837ebedeb18/src/stickers/StickersSale.sol) | [`0x5d10f5685271b4dc21943438eac77ca549ac3d36`](https://polygonscan.com/address/0x5d10f5685271b4dc21943438eac77ca549ac3d36#code) | -| [`POK`](https://github.com/pooky-labs/smart-contracts/blob/fba76ea65e3b99b425b473bf5d689837ebedeb18/src/tokens/POK.sol) | [`0x7b7E3B03f34b17d70C276C4886467D58867Bbc94`](https://polygonscan.com/address/0x7b7E3B03f34b17d70C276C4886467D58867Bbc94#code) | +## Contracts Polygon Mainnet + +| Contract | Address on Polygon | +| ------------------ | ------------------------------------------------------------------------------------------------------------------------------- | +| POK | [`0x7b7E3B03f34b17d70C276C4886467D58867Bbc94`](https://polygonscan.com/address/0x7b7E3B03f34b17d70C276C4886467D58867Bbc94#code) | +| Energy | [`0x356fB0fE98023239b240795003595dbCb63c57cd`](https://polygonscan.com/address/0x356fB0fE98023239b240795003595dbCb63c57cd#code) | +| NonceRegistry | [`0xB08Ee469Dcf9c40B77261d8665A8BbdFad22B818`](https://polygonscan.com/address/0xB08Ee469Dcf9c40B77261d8665A8BbdFad22B818#code) | +| BoostPXP | [`0xB08Ee469Dcf9c40B77261d8665A8BbdFad22B818`](https://polygonscan.com/address/0xB08Ee469Dcf9c40B77261d8665A8BbdFad22B818#code) | +| Pookyball | [`0xb4859acd9B0A65CA4897c31e5cb5160D9Ff32C0A`](https://polygonscan.com/address/0xb4859acd9B0A65CA4897c31e5cb5160D9Ff32C0A#code) | +| PookyballLevelUp | [`0x13e887fca91d6f9ff5d44dcf44f9b9074b314aab`](https://polygonscan.com/address/0x13e887fca91d6f9ff5d44dcf44f9b9074b314aab#code) | +| RefillableSale | [`0x57f48000b7573dd55963f15a1bf2490e43fee41c`](https://polygonscan.com/address/0x57f48000b7573dd55963f15a1bf2490e43fee41c#code) | +| Pressure | [`0xa34223AD4d42CB041056287784FE1F91a7e5b21A`](https://polygonscan.com/address/0xa34223AD4d42CB041056287784FE1F91a7e5b21A#code) | +| PookyballReroll | [`0x336033401230245EA9BD940Cb1b4cA91AF16415f`](https://polygonscan.com/address/0x336033401230245EA9BD940Cb1b4cA91AF16415f#code) | +| Stickers | [`0x440D4955a914D5e29F861aC024A608aE41c56cB6`](https://polygonscan.com/address/0x440D4955a914D5e29F861aC024A608aE41c56cB6#code) | +| StickersLevelUp | [`0x766e81AF624Cd6D2615EF675bDca2aB1ffBCBCbE`](https://polygonscan.com/address/0x766e81AF624Cd6D2615EF675bDca2aB1ffBCBCbE#code) | +| StickersSale | [`0x5d10f5685271b4dc21943438eac77ca549ac3d36`](https://polygonscan.com/address/0x5d10f5685271b4dc21943438eac77ca549ac3d36#code) | +| StickersController | [`0x75cc3c6329930758659eD87338B926c90e16d05F`](https://polygonscan.com/address/0x75cc3c6329930758659eD87338B926c90e16d05F#code) | +| StickersManager | [`0x534Fda3d9C8A08FD0E57DE8c1Af9B32987614bA1`](https://polygonscan.com/address/0x534Fda3d9C8A08FD0E57DE8c1Af9B32987614bA1#code) | +| StickerAscension | [`0x49d0e15af6c939670c628cea99512ae22c79fa7c`](https://polygonscan.com/address/0x49d0e15af6c939670c628cea99512ae22c79fa7c#code) | +| PookyballAscension | [`0x2a3b939f2deaf2bd16806b7f4b48af23f1bcc515`](https://polygonscan.com/address/0x2a3b939f2deaf2bd16806b7f4b48af23f1bcc515#code) | +| Rewards | [`0x64A85fb2Ca5ebdC70cBa233a7Ea94672BeF5B372`](https://polygonscan.com/address/0x64A85fb2Ca5ebdC70cBa233a7Ea94672BeF5B372#code) | + +## Contracts Polygon Amoy Testnet + +| Contract | Address on Polygon | +| ------------------ | --------------------------------------------------------------------------------------------------------------------------------------- | +| POK | [`0x66e4E3d15F14DEEE674e44666A60aC9D43CF3D1A`](https://www.oklink.com/amoy/address/0x66e4E3d15F14DEEE674e44666A60aC9D43CF3D1A/contract) | +| Energy | [`0xcE3bAF0c9989beC8e39B0D063Ffdf5C09373a510`](https://www.oklink.com/amoy/address/0xcE3bAF0c9989beC8e39B0D063Ffdf5C09373a510/contract) | +| NonceRegistry | [`0x2787DA764ebfaB0766f8737CA2Ce849Ea1c6fD88`](https://www.oklink.com/amoy/address/0x2787DA764ebfaB0766f8737CA2Ce849Ea1c6fD88/contract) | +| BoostPXP | [`0xd2141454Ba77aEf88FF7dD865334abaf8eFa83C3`](https://www.oklink.com/amoy/address/0xd2141454Ba77aEf88FF7dD865334abaf8eFa83C3/contract) | +| Pookyball | [`0x91290239CD991eB8B748FaFe3fb2401C5ec3c988`](https://www.oklink.com/amoy/address/0x91290239CD991eB8B748FaFe3fb2401C5ec3c988/contract) | +| PookyballLevelUp | [`0xEd78B7932d7fb92b28436de95B64C5C12DdD23a7`](https://www.oklink.com/amoy/address/0xEd78B7932d7fb92b28436de95B64C5C12DdD23a7/contract) | +| RefillableSale | [`0xee62bA98Deee1cFfa61F1AA07329c2d5fcC8ea17`](https://www.oklink.com/amoy/address/0xee62bA98Deee1cFfa61F1AA07329c2d5fcC8ea17/contract) | +| Pressure | [`0x3876E098488092af30aFACBF4e99553372CaAedD`](https://www.oklink.com/amoy/address/0x3876E098488092af30aFACBF4e99553372CaAedD/contract) | +| PookyballReroll | [`0x5c2E6a21813751411c4d445F9DFa2638c8271f61`](https://www.oklink.com/amoy/address/0x5c2E6a21813751411c4d445F9DFa2638c8271f61/contract) | +| Stickers | [`0x975d59D5ff4c1D4ED908892377E23Bf00c40f7aD`](https://www.oklink.com/amoy/address/0x975d59D5ff4c1D4ED908892377E23Bf00c40f7aD/contract) | +| StickersLevelUp | [`0x92ddB44c3D33Ef49F0f8EeE3ca6F1bD07e4188C4`](https://www.oklink.com/amoy/address/0x92ddB44c3D33Ef49F0f8EeE3ca6F1bD07e4188C4/contract) | +| StickersSale | [`0xa3C4BD44E80cD3E83BCBB33EB6C3B3Eb24286073`](https://www.oklink.com/amoy/address/0xa3C4BD44E80cD3E83BCBB33EB6C3B3Eb24286073/contract) | +| StickersController | [`0xB9b85d3DCF4bB8c064D9F594354F07F5DCE12daF`](https://www.oklink.com/amoy/address/0xB9b85d3DCF4bB8c064D9F594354F07F5DCE12daF/contract) | +| StickersManager | [`0x17FBe0246aC8F13D457dDcc2b46FBCD6E80eA675`](https://www.oklink.com/amoy/address/0x17FBe0246aC8F13D457dDcc2b46FBCD6E80eA675/contract) | +| StickerAscension | [`0xCb20FEe5113F10fE06BD9452d2E5cD1972161006`](https://www.oklink.com/amoy/address/0xCb20FEe5113F10fE06BD9452d2E5cD1972161006/contract) | +| PookyballAscension | [`0x1369B4e6B4B1A8f1a6C3c79dCB5DbB251EdC0D30`](https://www.oklink.com/amoy/address/0x1369B4e6B4B1A8f1a6C3c79dCB5DbB251EdC0D30/contract) | +| Rewards | [`0xBa609c15697617f9a243A5E0A609371044497719`](https://www.oklink.com/amoy/address/0xBa609c15697617f9a243A5E0A609371044497719/contract) | ## Governance From 9fa3fa23322e5fd96a7632e2709ecaf654328dab Mon Sep 17 00:00:00 2001 From: Claudiu Date: Mon, 1 Apr 2024 20:12:47 +0300 Subject: [PATCH 10/10] feat(env): Add example of env file --- .env_example | 47 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 .env_example diff --git a/.env_example b/.env_example new file mode 100644 index 00000000..0ee134be --- /dev/null +++ b/.env_example @@ -0,0 +1,47 @@ +RPC_URL=https://rpc-amoy.polygon.technology/ +CHAIN_ID=80002 + +SALT=0x1234567890abcdef + +DEPLOYER_ADDRESS=0xC0DE54132cA2B4BAce7C02AF31Aa9d3c1905f379 +DEPLOYER_PK= + +ADMIN_ADDRESS=0xF00Db2f08D1F6b3f6089573085B5826Bb358e319 +ADMIN_PK= + +OPERATOR_ADDRESS=0x481074326aC46C7BC52f0b25D2F7Aaf40f586472 + +BACKEND_ADDRESS=0xCAFE3e690bf74Ec274210E1c448130c1f8228513 + +TREASURY_ADDRESS=0xBABA035d2e22073C3a2AadA404dae4f6A9D57BD7 + +ROYALTY_RECEIVER_ADDRESS=0x2dfCa6e357a73D180B8e6aa8f7690A315a4395F7 + +VRF_COORDINATOR_ADDRESS=0x7a1BaC17Ccc5b313516C5E16fb24f7659aA5ebed +VRF_KEY_HASH=0x4b09e658ed251bcafeebbc69400383d49f344ace09b9576fe248bb02c003fe9f +VRF_SUB_ID=2307 +VRF_MINIMUM_REQUEST_CONFIRMATIONS=10 +VRF_CALLBACK_GAS_LIMIT=2500000 + +POLYGONSCAN_API_KEY= + +POOKYBALL_BASE_URI=https://tokens.pooky.tech/ +POOKYBALL_CONTRACT_URI=https://static.pooky.tech/contracts/Pookyball.json + +CONTRACT_POK_ADDRESS=0x66e4E3d15F14DEEE674e44666A60aC9D43CF3D1A +CONTRACT_ENERGY_ADDRESS=0xcE3bAF0c9989beC8e39B0D063Ffdf5C09373a510 +CONTRACT_NONCE_REGISTRY_ADDRESS=0x2787DA764ebfaB0766f8737CA2Ce849Ea1c6fD88 +CONTRACT_BOOST_PXP_ADDRESS=0xd2141454Ba77aEf88FF7dD865334abaf8eFa83C3 +CONTRACT_POOKYBALL_ADDRESS=0x91290239CD991eB8B748FaFe3fb2401C5ec3c988 +CONTRACT_POOKYBALL_LEVEL_UP_ADDRESS=0xEd78B7932d7fb92b28436de95B64C5C12DdD23a7 +CONTRACT_POOKYBALL_REFIILABLE_SALE_ADDRESS=0xee62bA98Deee1cFfa61F1AA07329c2d5fcC8ea17 +CONTRACT_PRESSURE_ADDRESS=0x3876E098488092af30aFACBF4e99553372CaAedD +CONTRACT_POOKYBALL_REROLL_ADDRESS=0x5c2E6a21813751411c4d445F9DFa2638c8271f61 +CONTRACT_STICKERS_ADDRESS=0x975d59D5ff4c1D4ED908892377E23Bf00c40f7aD +CONTRACT_STICKERS_LEVEL_UP_ADDRESS=0x92ddB44c3D33Ef49F0f8EeE3ca6F1bD07e4188C4 +CONTRACT_STICKERS_SALE_ADDRESS=0xa3C4BD44E80cD3E83BCBB33EB6C3B3Eb24286073 +CONTRACT_STICKERS_CONTROLLER_ADDRESS=0xB9b85d3DCF4bB8c064D9F594354F07F5DCE12daF +CONTRACT_STICKERS_MANAGER_ADDRESS=0x17FBe0246aC8F13D457dDcc2b46FBCD6E80eA675 +CONTRACT_STICKERS_ASCENSION=0xCb20FEe5113F10fE06BD9452d2E5cD1972161006 +CONTRACT_POOKYBALL_ASCENSION_ADDRESS=0x1369B4e6B4B1A8f1a6C3c79dCB5DbB251EdC0D30 +CONTRACT_REWARDS=0xBa609c15697617f9a243A5E0A609371044497719