From cb55d05e886dde153ffad2996edd7168a0529c86 Mon Sep 17 00:00:00 2001 From: wojciech-turek Date: Thu, 8 Aug 2024 20:32:09 +0200 Subject: [PATCH] Add batch transfer deployment and add setup script --- .../800_deploy_batch_transfer.ts | 4 +- .../900_batch_transfer/801_add_operators.ts | 42 ++ .../deployments/polygon/BatchTransfer.json | 473 ++++++++++++++++++ .../a25c1b72c17f3b4f6df2f7f6fa6e6be7.json | 57 +++ 4 files changed, 574 insertions(+), 2 deletions(-) rename packages/deploy/deploy/{800_batch_transfer => 900_batch_transfer}/800_deploy_batch_transfer.ts (87%) create mode 100644 packages/deploy/deploy/900_batch_transfer/801_add_operators.ts create mode 100644 packages/deploy/deployments/polygon/BatchTransfer.json create mode 100644 packages/deploy/deployments/polygon/solcInputs/a25c1b72c17f3b4f6df2f7f6fa6e6be7.json diff --git a/packages/deploy/deploy/800_batch_transfer/800_deploy_batch_transfer.ts b/packages/deploy/deploy/900_batch_transfer/800_deploy_batch_transfer.ts similarity index 87% rename from packages/deploy/deploy/800_batch_transfer/800_deploy_batch_transfer.ts rename to packages/deploy/deploy/900_batch_transfer/800_deploy_batch_transfer.ts index 3bd867fe7f..4b84901518 100644 --- a/packages/deploy/deploy/800_batch_transfer/800_deploy_batch_transfer.ts +++ b/packages/deploy/deploy/900_batch_transfer/800_deploy_batch_transfer.ts @@ -4,14 +4,14 @@ import {HardhatRuntimeEnvironment} from 'hardhat/types'; const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { const {deployments, getNamedAccounts} = hre; const {deploy} = deployments; - const {deployer, sandAdmin} = await getNamedAccounts(); + const {deployer} = await getNamedAccounts(); + await deploy('BatchTransfer', { from: deployer, contract: '@sandbox-smart-contracts/batch-transfers/contracts/BatchTransfer.sol:BatchTransfer', log: true, skipIfAlreadyDeployed: true, - args: [sandAdmin], }); }; diff --git a/packages/deploy/deploy/900_batch_transfer/801_add_operators.ts b/packages/deploy/deploy/900_batch_transfer/801_add_operators.ts new file mode 100644 index 0000000000..8774cfe59a --- /dev/null +++ b/packages/deploy/deploy/900_batch_transfer/801_add_operators.ts @@ -0,0 +1,42 @@ +import {DeployFunction} from 'hardhat-deploy/types'; +import {HardhatRuntimeEnvironment} from 'hardhat/types'; + +const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { + const {deployments, getNamedAccounts} = hre; + const {execute, log, read, catchUnknownSigner} = deployments; + const {deployer} = await getNamedAccounts(); + + const operatorRole = await read('BatchTransfer', 'OPERATOR_ROLE'); + + const operators = [ + '0x782788bB333feB56bbC426588263Db9671F074c1', // (NFT Vault for DAO) + '0x7A9fe22691c811ea339D9B73150e6911a5343DcA', // (Seb) + '0x51b66b4cb9053726442752f1a722ce5438553a88', // (QA PROD Account) + ]; + + for (const operator of operators) { + const isOperator = await read( + 'BatchTransfer', + 'hasRole', + operatorRole, + operator + ); + if (!isOperator) { + await catchUnknownSigner( + execute( + 'BatchTransfer', + {from: deployer, log: true}, + 'grantRole', + operatorRole, + operator + ) + ); + log(`[BatchTransfer] Operator role granted to ${operator}`); + } + } +}; + +export default func; + +func.tags = ['BatchTransfer', 'BatchTransfer_setup']; +func.dependencies = ['BatchTransfer_deploy']; diff --git a/packages/deploy/deployments/polygon/BatchTransfer.json b/packages/deploy/deployments/polygon/BatchTransfer.json new file mode 100644 index 0000000000..9e966d89db --- /dev/null +++ b/packages/deploy/deployments/polygon/BatchTransfer.json @@ -0,0 +1,473 @@ +{ + "address": "0x676Dcf917981D73ce80A2D4F6A9b47dDeEc8021b", + "abi": [ + { + "inputs": [], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [], + "name": "AccessControlBadConfirmation", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "neededRole", + "type": "bytes32" + } + ], + "name": "AccessControlUnauthorizedAccount", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "bytes32", + "name": "previousAdminRole", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "bytes32", + "name": "newAdminRole", + "type": "bytes32" + } + ], + "name": "RoleAdminChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "sender", + "type": "address" + } + ], + "name": "RoleGranted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "sender", + "type": "address" + } + ], + "name": "RoleRevoked", + "type": "event" + }, + { + "inputs": [], + "name": "DEFAULT_ADMIN_ROLE", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "OPERATOR_ROLE", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address[]", + "name": "contracts", + "type": "address[]" + }, + { + "internalType": "address[][]", + "name": "recipients", + "type": "address[][]" + }, + { + "internalType": "uint256[][]", + "name": "tokenIds", + "type": "uint256[][]" + }, + { + "internalType": "uint256[][]", + "name": "amounts", + "type": "uint256[][]" + }, + { + "internalType": "bool[]", + "name": "isERC1155", + "type": "bool[]" + } + ], + "name": "batchTransfer", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + } + ], + "name": "getRoleAdmin", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "grantRole", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "hasRole", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "callerConfirmation", + "type": "address" + } + ], + "name": "renounceRole", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "revokeRole", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "interfaceId", + "type": "bytes4" + } + ], + "name": "supportsInterface", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + } + ], + "transactionHash": "0x90131cc010286638511f870dd64eb09c6790c9d757c784656307740e6b6a987d", + "receipt": { + "to": null, + "from": "0x46fDE94FAb22CfdAD71e37fe78F6b1611A52a11e", + "contractAddress": "0x676Dcf917981D73ce80A2D4F6A9b47dDeEc8021b", + "transactionIndex": 12, + "gasUsed": "779928", + "logsBloom": "0x00000004000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000008000000000001000000000000000000000000000200000000000000040800000000000000000000100000000000000000000020400000000000000000800000001000000000080000000000000000000000000000000000000000000080000000000000000000001000000000000200000000000000000000000000000000000000000000000001000000000004000000000000000000001000000000000000000000000000100100000000020000000000000000000000000000000000000000000100000000000000000100000", + "blockHash": "0xc88d5fc053ebab88398fbe0c080e7dad61cab50345affe78177462e7989205a1", + "transactionHash": "0x90131cc010286638511f870dd64eb09c6790c9d757c784656307740e6b6a987d", + "logs": [ + { + "transactionIndex": 12, + "blockNumber": 60349679, + "transactionHash": "0x90131cc010286638511f870dd64eb09c6790c9d757c784656307740e6b6a987d", + "address": "0x676Dcf917981D73ce80A2D4F6A9b47dDeEc8021b", + "topics": [ + "0x2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x00000000000000000000000046fde94fab22cfdad71e37fe78f6b1611a52a11e", + "0x00000000000000000000000046fde94fab22cfdad71e37fe78f6b1611a52a11e" + ], + "data": "0x", + "logIndex": 59, + "blockHash": "0xc88d5fc053ebab88398fbe0c080e7dad61cab50345affe78177462e7989205a1" + }, + { + "transactionIndex": 12, + "blockNumber": 60349679, + "transactionHash": "0x90131cc010286638511f870dd64eb09c6790c9d757c784656307740e6b6a987d", + "address": "0x0000000000000000000000000000000000001010", + "topics": [ + "0x4dfe1bbbcf077ddc3e01291eea2d5c70c2b422b415d95645b9adcfd678cb1d63", + "0x0000000000000000000000000000000000000000000000000000000000001010", + "0x00000000000000000000000046fde94fab22cfdad71e37fe78f6b1611a52a11e", + "0x000000000000000000000000dfe6ad10265afc05831b332fda6f5bc1ad9d79ce" + ], + "data": "0x0000000000000000000000000000000000000000000000000067e843afa6908800000000000000000000000000000000000000000000000003782dace9d9000000000000000000000000000000000000000000000000019e1f92c414db076acc000000000000000000000000000000000000000000000000031045693a326f7800000000000000000000000000000000000000000000019e1ffaac588aadfb54", + "logIndex": 60, + "blockHash": "0xc88d5fc053ebab88398fbe0c080e7dad61cab50345affe78177462e7989205a1" + } + ], + "blockNumber": 60349679, + "cumulativeGasUsed": "2570426", + "status": 1, + "byzantium": true + }, + "args": [], + "numDeployments": 1, + "solcInputHash": "a25c1b72c17f3b4f6df2f7f6fa6e6be7", + "metadata": "{\"compiler\":{\"version\":\"0.8.23+commit.f704f362\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"AccessControlBadConfirmation\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"neededRole\",\"type\":\"bytes32\"}],\"name\":\"AccessControlUnauthorizedAccount\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"DEFAULT_ADMIN_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"OPERATOR_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"contracts\",\"type\":\"address[]\"},{\"internalType\":\"address[][]\",\"name\":\"recipients\",\"type\":\"address[][]\"},{\"internalType\":\"uint256[][]\",\"name\":\"tokenIds\",\"type\":\"uint256[][]\"},{\"internalType\":\"uint256[][]\",\"name\":\"amounts\",\"type\":\"uint256[][]\"},{\"internalType\":\"bool[]\",\"name\":\"isERC1155\",\"type\":\"bool[]\"}],\"name\":\"batchTransfer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"callerConfirmation\",\"type\":\"address\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"custom:security-contact\":\"contact-blockchain@sandbox.game\",\"errors\":{\"AccessControlBadConfirmation()\":[{\"details\":\"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\"}],\"AccessControlUnauthorizedAccount(address,bytes32)\":[{\"details\":\"The `account` is missing a role.\"}]},\"events\":{\"RoleAdminChanged(bytes32,bytes32,bytes32)\":{\"details\":\"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.\"},\"RoleGranted(bytes32,address,address)\":{\"details\":\"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}.\"},\"RoleRevoked(bytes32,address,address)\":{\"details\":\"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`)\"}},\"kind\":\"dev\",\"methods\":{\"batchTransfer(address[],address[][],uint256[][],uint256[][],bool[])\":{\"details\":\"The arrays must have the same length\",\"params\":{\"amounts\":\"The amounts of tokens\",\"contracts\":\"The addresses of the contracts\",\"isERC1155\":\"Whether the token is ERC1155 or not\",\"recipients\":\"The addresses of the recipients\",\"tokenIds\":\"The token IDs\"}},\"getRoleAdmin(bytes32)\":{\"details\":\"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}.\"},\"grantRole(bytes32,address)\":{\"details\":\"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.\"},\"hasRole(bytes32,address)\":{\"details\":\"Returns `true` if `account` has been granted `role`.\"},\"renounceRole(bytes32,address)\":{\"details\":\"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 `callerConfirmation`. May emit a {RoleRevoked} event.\"},\"revokeRole(bytes32,address)\":{\"details\":\"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.\"},\"supportsInterface(bytes4)\":{\"details\":\"See {IERC165-supportsInterface}.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"OPERATOR_ROLE()\":{\"notice\":\"The role that allows an address to use the contract\"},\"batchTransfer(address[],address[][],uint256[][],uint256[][],bool[])\":{\"notice\":\"Batch transfer ERC721 and ERC1155 tokens\"},\"constructor\":{\"notice\":\"Grant the contract deployer the default admin role\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"@sandbox-smart-contracts/batch-transfers/contracts/BatchTransfer.sol\":\"BatchTransfer\"},\"evmVersion\":\"paris\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":2000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/access/AccessControl.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\\n\\npragma solidity ^0.8.20;\\n\\nimport {IAccessControl} from \\\"./IAccessControl.sol\\\";\\nimport {Context} from \\\"../utils/Context.sol\\\";\\nimport {ERC165} from \\\"../utils/introspection/ERC165.sol\\\";\\n\\n/**\\n * @dev Contract module that allows children to implement role-based access\\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\\n * members except through off-chain means by accessing the contract event logs. Some\\n * applications may benefit from on-chain enumerability, for those cases see\\n * {AccessControlEnumerable}.\\n *\\n * Roles are referred to by their `bytes32` identifier. These should be exposed\\n * in the external API and be unique. The best way to achieve this is by\\n * using `public constant` hash digests:\\n *\\n * ```solidity\\n * bytes32 public constant MY_ROLE = keccak256(\\\"MY_ROLE\\\");\\n * ```\\n *\\n * Roles can be used to represent a set of permissions. To restrict access to a\\n * function call, use {hasRole}:\\n *\\n * ```solidity\\n * function foo() public {\\n * require(hasRole(MY_ROLE, msg.sender));\\n * ...\\n * }\\n * ```\\n *\\n * Roles can be granted and revoked dynamically via the {grantRole} and\\n * {revokeRole} functions. Each role has an associated admin role, and only\\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\\n *\\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\\n * that only accounts with this role will be able to grant or revoke other\\n * roles. More complex role relationships can be created by using\\n * {_setRoleAdmin}.\\n *\\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\\n * grant and revoke this role. Extra precautions should be taken to secure\\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\\n * to enforce additional security measures for this role.\\n */\\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\\n struct RoleData {\\n mapping(address account => bool) hasRole;\\n bytes32 adminRole;\\n }\\n\\n mapping(bytes32 role => RoleData) private _roles;\\n\\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\\n\\n /**\\n * @dev Modifier that checks that an account has a specific role. Reverts\\n * with an {AccessControlUnauthorizedAccount} error including the required role.\\n */\\n modifier onlyRole(bytes32 role) {\\n _checkRole(role);\\n _;\\n }\\n\\n /**\\n * @dev See {IERC165-supportsInterface}.\\n */\\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\\n }\\n\\n /**\\n * @dev Returns `true` if `account` has been granted `role`.\\n */\\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\\n return _roles[role].hasRole[account];\\n }\\n\\n /**\\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\\n */\\n function _checkRole(bytes32 role) internal view virtual {\\n _checkRole(role, _msgSender());\\n }\\n\\n /**\\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\\n * is missing `role`.\\n */\\n function _checkRole(bytes32 role, address account) internal view virtual {\\n if (!hasRole(role, account)) {\\n revert AccessControlUnauthorizedAccount(account, role);\\n }\\n }\\n\\n /**\\n * @dev Returns the admin role that controls `role`. See {grantRole} and\\n * {revokeRole}.\\n *\\n * To change a role's admin, use {_setRoleAdmin}.\\n */\\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\\n return _roles[role].adminRole;\\n }\\n\\n /**\\n * @dev Grants `role` to `account`.\\n *\\n * If `account` had not been already granted `role`, emits a {RoleGranted}\\n * event.\\n *\\n * Requirements:\\n *\\n * - the caller must have ``role``'s admin role.\\n *\\n * May emit a {RoleGranted} event.\\n */\\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\\n _grantRole(role, account);\\n }\\n\\n /**\\n * @dev Revokes `role` from `account`.\\n *\\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\\n *\\n * Requirements:\\n *\\n * - the caller must have ``role``'s admin role.\\n *\\n * May emit a {RoleRevoked} event.\\n */\\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\\n _revokeRole(role, account);\\n }\\n\\n /**\\n * @dev Revokes `role` from the calling account.\\n *\\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\\n * purpose is to provide a mechanism for accounts to lose their privileges\\n * if they are compromised (such as when a trusted device is misplaced).\\n *\\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\\n * event.\\n *\\n * Requirements:\\n *\\n * - the caller must be `callerConfirmation`.\\n *\\n * May emit a {RoleRevoked} event.\\n */\\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\\n if (callerConfirmation != _msgSender()) {\\n revert AccessControlBadConfirmation();\\n }\\n\\n _revokeRole(role, callerConfirmation);\\n }\\n\\n /**\\n * @dev Sets `adminRole` as ``role``'s admin role.\\n *\\n * Emits a {RoleAdminChanged} event.\\n */\\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\\n bytes32 previousAdminRole = getRoleAdmin(role);\\n _roles[role].adminRole = adminRole;\\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\\n }\\n\\n /**\\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\\n *\\n * Internal function without access restriction.\\n *\\n * May emit a {RoleGranted} event.\\n */\\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\\n if (!hasRole(role, account)) {\\n _roles[role].hasRole[account] = true;\\n emit RoleGranted(role, account, _msgSender());\\n return true;\\n } else {\\n return false;\\n }\\n }\\n\\n /**\\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\\n *\\n * Internal function without access restriction.\\n *\\n * May emit a {RoleRevoked} event.\\n */\\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\\n if (hasRole(role, account)) {\\n _roles[role].hasRole[account] = false;\\n emit RoleRevoked(role, account, _msgSender());\\n return true;\\n } else {\\n return false;\\n }\\n }\\n}\\n\",\"keccak256\":\"0xa0e92d42942f4f57c5be50568dac11e9d00c93efcb458026e18d2d9b9b2e7308\",\"license\":\"MIT\"},\"@openzeppelin/contracts/access/IAccessControl.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\\n\\npragma solidity ^0.8.20;\\n\\n/**\\n * @dev External interface of AccessControl declared to support ERC165 detection.\\n */\\ninterface IAccessControl {\\n /**\\n * @dev The `account` is missing a role.\\n */\\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\\n\\n /**\\n * @dev The caller of a function is not the expected one.\\n *\\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\\n */\\n error AccessControlBadConfirmation();\\n\\n /**\\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\\n *\\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\\n * {RoleAdminChanged} not being emitted signaling this.\\n */\\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\\n\\n /**\\n * @dev Emitted when `account` is granted `role`.\\n *\\n * `sender` is the account that originated the contract call, an admin role\\n * bearer except when using {AccessControl-_setupRole}.\\n */\\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\\n\\n /**\\n * @dev Emitted when `account` is revoked `role`.\\n *\\n * `sender` is the account that originated the contract call:\\n * - if using `revokeRole`, it is the admin role bearer\\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\\n */\\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\\n\\n /**\\n * @dev Returns `true` if `account` has been granted `role`.\\n */\\n function hasRole(bytes32 role, address account) external view returns (bool);\\n\\n /**\\n * @dev Returns the admin role that controls `role`. See {grantRole} and\\n * {revokeRole}.\\n *\\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\\n */\\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\\n\\n /**\\n * @dev Grants `role` to `account`.\\n *\\n * If `account` had not been already granted `role`, emits a {RoleGranted}\\n * event.\\n *\\n * Requirements:\\n *\\n * - the caller must have ``role``'s admin role.\\n */\\n function grantRole(bytes32 role, address account) external;\\n\\n /**\\n * @dev Revokes `role` from `account`.\\n *\\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\\n *\\n * Requirements:\\n *\\n * - the caller must have ``role``'s admin role.\\n */\\n function revokeRole(bytes32 role, address account) external;\\n\\n /**\\n * @dev Revokes `role` from the calling account.\\n *\\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\\n * purpose is to provide a mechanism for accounts to lose their privileges\\n * if they are compromised (such as when a trusted device is misplaced).\\n *\\n * If the calling account had been granted `role`, emits a {RoleRevoked}\\n * event.\\n *\\n * Requirements:\\n *\\n * - the caller must be `callerConfirmation`.\\n */\\n function renounceRole(bytes32 role, address callerConfirmation) external;\\n}\\n\",\"keccak256\":\"0xb6b36edd6a2999fd243ff226d6cbf84bd71af2432bbd0dfe19392996a1d9cb41\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC1155/IERC1155.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v5.0.1) (token/ERC1155/IERC1155.sol)\\n\\npragma solidity ^0.8.20;\\n\\nimport {IERC165} from \\\"../../utils/introspection/IERC165.sol\\\";\\n\\n/**\\n * @dev Required interface of an ERC1155 compliant contract, as defined in the\\n * https://eips.ethereum.org/EIPS/eip-1155[EIP].\\n */\\ninterface IERC1155 is IERC165 {\\n /**\\n * @dev Emitted when `value` amount of tokens of type `id` are transferred from `from` to `to` by `operator`.\\n */\\n event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value);\\n\\n /**\\n * @dev Equivalent to multiple {TransferSingle} events, where `operator`, `from` and `to` are the same for all\\n * transfers.\\n */\\n event TransferBatch(\\n address indexed operator,\\n address indexed from,\\n address indexed to,\\n uint256[] ids,\\n uint256[] values\\n );\\n\\n /**\\n * @dev Emitted when `account` grants or revokes permission to `operator` to transfer their tokens, according to\\n * `approved`.\\n */\\n event ApprovalForAll(address indexed account, address indexed operator, bool approved);\\n\\n /**\\n * @dev Emitted when the URI for token type `id` changes to `value`, if it is a non-programmatic URI.\\n *\\n * If an {URI} event was emitted for `id`, the standard\\n * https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[guarantees] that `value` will equal the value\\n * returned by {IERC1155MetadataURI-uri}.\\n */\\n event URI(string value, uint256 indexed id);\\n\\n /**\\n * @dev Returns the value of tokens of token type `id` owned by `account`.\\n *\\n * Requirements:\\n *\\n * - `account` cannot be the zero address.\\n */\\n function balanceOf(address account, uint256 id) external view returns (uint256);\\n\\n /**\\n * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {balanceOf}.\\n *\\n * Requirements:\\n *\\n * - `accounts` and `ids` must have the same length.\\n */\\n function balanceOfBatch(\\n address[] calldata accounts,\\n uint256[] calldata ids\\n ) external view returns (uint256[] memory);\\n\\n /**\\n * @dev Grants or revokes permission to `operator` to transfer the caller's tokens, according to `approved`,\\n *\\n * Emits an {ApprovalForAll} event.\\n *\\n * Requirements:\\n *\\n * - `operator` cannot be the caller.\\n */\\n function setApprovalForAll(address operator, bool approved) external;\\n\\n /**\\n * @dev Returns true if `operator` is approved to transfer ``account``'s tokens.\\n *\\n * See {setApprovalForAll}.\\n */\\n function isApprovedForAll(address account, address operator) external view returns (bool);\\n\\n /**\\n * @dev Transfers a `value` amount of tokens of type `id` from `from` to `to`.\\n *\\n * WARNING: This function can potentially allow a reentrancy attack when transferring tokens\\n * to an untrusted contract, when invoking {onERC1155Received} on the receiver.\\n * Ensure to follow the checks-effects-interactions pattern and consider employing\\n * reentrancy guards when interacting with untrusted contracts.\\n *\\n * Emits a {TransferSingle} event.\\n *\\n * Requirements:\\n *\\n * - `to` cannot be the zero address.\\n * - If the caller is not `from`, it must have been approved to spend ``from``'s tokens via {setApprovalForAll}.\\n * - `from` must have a balance of tokens of type `id` of at least `value` amount.\\n * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the\\n * acceptance magic value.\\n */\\n function safeTransferFrom(address from, address to, uint256 id, uint256 value, bytes calldata data) external;\\n\\n /**\\n * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {safeTransferFrom}.\\n *\\n * WARNING: This function can potentially allow a reentrancy attack when transferring tokens\\n * to an untrusted contract, when invoking {onERC1155BatchReceived} on the receiver.\\n * Ensure to follow the checks-effects-interactions pattern and consider employing\\n * reentrancy guards when interacting with untrusted contracts.\\n *\\n * Emits either a {TransferSingle} or a {TransferBatch} event, depending on the length of the array arguments.\\n *\\n * Requirements:\\n *\\n * - `ids` and `values` must have the same length.\\n * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the\\n * acceptance magic value.\\n */\\n function safeBatchTransferFrom(\\n address from,\\n address to,\\n uint256[] calldata ids,\\n uint256[] calldata values,\\n bytes calldata data\\n ) external;\\n}\\n\",\"keccak256\":\"0x6caffc9cfdc623eca9f87a686071708af5d5c17454d65022843fdddbc53c0cce\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC721/IERC721.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/IERC721.sol)\\n\\npragma solidity ^0.8.20;\\n\\nimport {IERC165} from \\\"../../utils/introspection/IERC165.sol\\\";\\n\\n/**\\n * @dev Required interface of an ERC721 compliant contract.\\n */\\ninterface IERC721 is IERC165 {\\n /**\\n * @dev Emitted when `tokenId` token is transferred from `from` to `to`.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);\\n\\n /**\\n * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.\\n */\\n event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);\\n\\n /**\\n * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.\\n */\\n event ApprovalForAll(address indexed owner, address indexed operator, bool approved);\\n\\n /**\\n * @dev Returns the number of tokens in ``owner``'s account.\\n */\\n function balanceOf(address owner) external view returns (uint256 balance);\\n\\n /**\\n * @dev Returns the owner of the `tokenId` token.\\n *\\n * Requirements:\\n *\\n * - `tokenId` must exist.\\n */\\n function ownerOf(uint256 tokenId) external view returns (address owner);\\n\\n /**\\n * @dev Safely transfers `tokenId` token from `from` to `to`.\\n *\\n * Requirements:\\n *\\n * - `from` cannot be the zero address.\\n * - `to` cannot be the zero address.\\n * - `tokenId` token must exist and be owned by `from`.\\n * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.\\n * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon\\n * a safe transfer.\\n *\\n * Emits a {Transfer} event.\\n */\\n function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external;\\n\\n /**\\n * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients\\n * are aware of the ERC721 protocol to prevent tokens from being forever locked.\\n *\\n * Requirements:\\n *\\n * - `from` cannot be the zero address.\\n * - `to` cannot be the zero address.\\n * - `tokenId` token must exist and be owned by `from`.\\n * - If the caller is not `from`, it must have been allowed to move this token by either {approve} or\\n * {setApprovalForAll}.\\n * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon\\n * a safe transfer.\\n *\\n * Emits a {Transfer} event.\\n */\\n function safeTransferFrom(address from, address to, uint256 tokenId) external;\\n\\n /**\\n * @dev Transfers `tokenId` token from `from` to `to`.\\n *\\n * WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721\\n * or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must\\n * understand this adds an external call which potentially creates a reentrancy vulnerability.\\n *\\n * Requirements:\\n *\\n * - `from` cannot be the zero address.\\n * - `to` cannot be the zero address.\\n * - `tokenId` token must be owned by `from`.\\n * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(address from, address to, uint256 tokenId) external;\\n\\n /**\\n * @dev Gives permission to `to` to transfer `tokenId` token to another account.\\n * The approval is cleared when the token is transferred.\\n *\\n * Only a single account can be approved at a time, so approving the zero address clears previous approvals.\\n *\\n * Requirements:\\n *\\n * - The caller must own the token or be an approved operator.\\n * - `tokenId` must exist.\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address to, uint256 tokenId) external;\\n\\n /**\\n * @dev Approve or remove `operator` as an operator for the caller.\\n * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.\\n *\\n * Requirements:\\n *\\n * - The `operator` cannot be the address zero.\\n *\\n * Emits an {ApprovalForAll} event.\\n */\\n function setApprovalForAll(address operator, bool approved) external;\\n\\n /**\\n * @dev Returns the account approved for `tokenId` token.\\n *\\n * Requirements:\\n *\\n * - `tokenId` must exist.\\n */\\n function getApproved(uint256 tokenId) external view returns (address operator);\\n\\n /**\\n * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.\\n *\\n * See {setApprovalForAll}\\n */\\n function isApprovedForAll(address owner, address operator) external view returns (bool);\\n}\\n\",\"keccak256\":\"0x5ef46daa3b58ef2702279d514780316efaa952915ee1aa3396f041ee2982b0b4\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Context.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\\n\\npragma solidity ^0.8.20;\\n\\n/**\\n * @dev Provides information about the current execution context, including the\\n * sender of the transaction and its data. While these are generally available\\n * via msg.sender and msg.data, they should not be accessed in such a direct\\n * manner, since when dealing with meta-transactions the account sending and\\n * paying for execution may not be the actual sender (as far as an application\\n * is concerned).\\n *\\n * This contract is only required for intermediate, library-like contracts.\\n */\\nabstract contract Context {\\n function _msgSender() internal view virtual returns (address) {\\n return msg.sender;\\n }\\n\\n function _msgData() internal view virtual returns (bytes calldata) {\\n return msg.data;\\n }\\n\\n function _contextSuffixLength() internal view virtual returns (uint256) {\\n return 0;\\n }\\n}\\n\",\"keccak256\":\"0x493033a8d1b176a037b2cc6a04dad01a5c157722049bbecf632ca876224dd4b2\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/introspection/ERC165.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\\n\\npragma solidity ^0.8.20;\\n\\nimport {IERC165} from \\\"./IERC165.sol\\\";\\n\\n/**\\n * @dev Implementation of the {IERC165} interface.\\n *\\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\\n * for the additional interface id that will be supported. For example:\\n *\\n * ```solidity\\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\\n * }\\n * ```\\n */\\nabstract contract ERC165 is IERC165 {\\n /**\\n * @dev See {IERC165-supportsInterface}.\\n */\\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\\n return interfaceId == type(IERC165).interfaceId;\\n }\\n}\\n\",\"keccak256\":\"0x9e8778b14317ba9e256c30a76fd6c32b960af621987f56069e1e819c77c6a133\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/introspection/IERC165.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\\n\\npragma solidity ^0.8.20;\\n\\n/**\\n * @dev Interface of the ERC165 standard, as defined in the\\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\\n *\\n * Implementers can declare support of contract interfaces, which can then be\\n * queried by others ({ERC165Checker}).\\n *\\n * For an implementation, see {ERC165}.\\n */\\ninterface IERC165 {\\n /**\\n * @dev Returns true if this contract implements the interface defined by\\n * `interfaceId`. See the corresponding\\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\\n * to learn more about how these ids are created.\\n *\\n * This function call must use less than 30 000 gas.\\n */\\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\\n}\\n\",\"keccak256\":\"0x4296879f55019b23e135000eb36896057e7101fb7fb859c5ef690cf14643757b\",\"license\":\"MIT\"},\"@sandbox-smart-contracts/batch-transfers/contracts/BatchTransfer.sol\":{\"content\":\"//SPDX-License-Identifier: MIT\\npragma solidity ^0.8.20;\\n\\nimport \\\"@openzeppelin/contracts/access/AccessControl.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC721/IERC721.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC1155/IERC1155.sol\\\";\\n\\n/// @custom:security-contact contact-blockchain@sandbox.game\\ncontract BatchTransfer is AccessControl {\\n /// @notice The role that allows an address to use the contract\\n bytes32 public constant OPERATOR_ROLE = keccak256(\\\"OPERATOR_ROLE\\\");\\n\\n /// Grant the contract deployer the default admin role\\n constructor() {\\n _grantRole(DEFAULT_ADMIN_ROLE, _msgSender());\\n }\\n\\n /// @notice Batch transfer ERC721 and ERC1155 tokens\\n /// @param contracts The addresses of the contracts\\n /// @param recipients The addresses of the recipients\\n /// @param tokenIds The token IDs\\n /// @param amounts The amounts of tokens\\n /// @param isERC1155 Whether the token is ERC1155 or not\\n /// @dev The arrays must have the same length\\n function batchTransfer(\\n address[] calldata contracts,\\n address[][] calldata recipients,\\n uint256[][] calldata tokenIds,\\n uint256[][] calldata amounts,\\n bool[] calldata isERC1155\\n ) external onlyRole(OPERATOR_ROLE) {\\n require(\\n contracts.length == recipients.length &&\\n recipients.length == tokenIds.length &&\\n tokenIds.length == amounts.length &&\\n amounts.length == isERC1155.length,\\n \\\"Arrays must have the same length\\\"\\n );\\n for (uint256 i = 0; i < contracts.length; i++) {\\n if (isERC1155[i]) {\\n for (uint256 j = 0; j < recipients[i].length; j++) {\\n IERC1155(contracts[i]).safeTransferFrom(\\n _msgSender(),\\n recipients[i][j],\\n tokenIds[i][j],\\n amounts[i][j],\\n \\\"\\\"\\n );\\n }\\n } else {\\n require(tokenIds[i].length == 1, \\\"ERC721: Only one token can be transferred at a time\\\");\\n require(recipients[i].length == 1, \\\"ERC721: Only one recipient can be specified\\\");\\n IERC721(contracts[i]).safeTransferFrom(_msgSender(), recipients[i][0], tokenIds[i][0]);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x356d5e4cc0bade363664e383fa35b43b7350432049a28f0f3fa160872953f824\",\"license\":\"MIT\"}},\"version\":1}", + "bytecode": "0x608060405234801561001057600080fd5b5061001c600033610022565b506100ce565b6000828152602081815260408083206001600160a01b038516845290915281205460ff166100c4576000838152602081815260408083206001600160a01b03861684529091529020805460ff1916600117905561007c3390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45060016100c8565b5060005b92915050565b610cb6806100dd6000396000f3fe608060405234801561001057600080fd5b50600436106100a35760003560e01c80638045893911610076578063a217fddf1161005b578063a217fddf14610173578063d547741f1461017b578063f5b541a61461018e57600080fd5b8063804589391461012957806391d148541461013c57600080fd5b806301ffc9a7146100a8578063248a9ca3146100d05780632f2ff15d1461010157806336568abe14610116575b600080fd5b6100bb6100b63660046109c5565b6101b5565b60405190151581526020015b60405180910390f35b6100f36100de366004610a0e565b60009081526020819052604090206001015490565b6040519081526020016100c7565b61011461010f366004610a43565b61024e565b005b610114610124366004610a43565b610279565b610114610137366004610abb565b6102ca565b6100bb61014a366004610a43565b6000918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b6100f3600081565b610114610189366004610a43565b6107f6565b6100f37f97667070c54ef182b0f5858b034beac1b6f3089aa2d3188bb1e8929f4fa9b92981565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b00000000000000000000000000000000000000000000000000000000148061024857507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316145b92915050565b6000828152602081905260409020600101546102698161081b565b6102738383610828565b50505050565b6001600160a01b03811633146102bb576040517f6697b23200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6102c582826108d2565b505050565b7f97667070c54ef182b0f5858b034beac1b6f3089aa2d3188bb1e8929f4fa9b9296102f48161081b565b898814801561030257508786145b801561030d57508584145b801561031857508382145b6103695760405162461bcd60e51b815260206004820181905260248201527f417272617973206d7573742068617665207468652073616d65206c656e67746860448201526064015b60405180910390fd5b60005b8a8110156107e85783838281811061038657610386610bac565b905060200201602081019061039b9190610bdb565b1561056d5760005b8a8a838181106103b5576103b5610bac565b90506020028101906103c79190610bfd565b9050811015610567578c8c838181106103e2576103e2610bac565b90506020020160208101906103f79190610c65565b6001600160a01b031663f242432a338d8d8681811061041857610418610bac565b905060200281019061042a9190610bfd565b8581811061043a5761043a610bac565b905060200201602081019061044f9190610c65565b8c8c8781811061046157610461610bac565b90506020028101906104739190610bfd565b8681811061048357610483610bac565b905060200201358b8b8881811061049c5761049c610bac565b90506020028101906104ae9190610bfd565b878181106104be576104be610bac565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e089901b1681526001600160a01b03968716600482015295909416602486015250604484019190915260209091020135606482015260a06084820152600060a482015260c401600060405180830381600087803b15801561054357600080fd5b505af1158015610557573d6000803e3d6000fd5b5050600190920191506103a39050565b506107e0565b87878281811061057f5761057f610bac565b90506020028101906105919190610bfd565b90506001146106085760405162461bcd60e51b815260206004820152603360248201527f4552433732313a204f6e6c79206f6e6520746f6b656e2063616e20626520747260448201527f616e7366657272656420617420612074696d65000000000000000000000000006064820152608401610360565b89898281811061061a5761061a610bac565b905060200281019061062c9190610bfd565b90506001146106a35760405162461bcd60e51b815260206004820152602b60248201527f4552433732313a204f6e6c79206f6e6520726563697069656e742063616e206260448201527f65207370656369666965640000000000000000000000000000000000000000006064820152608401610360565b8b8b828181106106b5576106b5610bac565b90506020020160208101906106ca9190610c65565b6001600160a01b03166342842e0e338c8c858181106106eb576106eb610bac565b90506020028101906106fd9190610bfd565b600081811061070e5761070e610bac565b90506020020160208101906107239190610c65565b8b8b8681811061073557610735610bac565b90506020028101906107479190610bfd565b600081811061075857610758610bac565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e088901b1681526001600160a01b03958616600482015294909316602485015250602090910201356044820152606401600060405180830381600087803b1580156107c757600080fd5b505af11580156107db573d6000803e3d6000fd5b505050505b60010161036c565b505050505050505050505050565b6000828152602081905260409020600101546108118161081b565b61027383836108d2565b6108258133610955565b50565b6000828152602081815260408083206001600160a01b038516845290915281205460ff166108ca576000838152602081815260408083206001600160a01b03861684529091529020805460ff191660011790556108823390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a4506001610248565b506000610248565b6000828152602081815260408083206001600160a01b038516845290915281205460ff16156108ca576000838152602081815260408083206001600160a01b0386168085529252808320805460ff1916905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a4506001610248565b6000828152602081815260408083206001600160a01b038516845290915290205460ff166109c1576040517fe2517d3f0000000000000000000000000000000000000000000000000000000081526001600160a01b038216600482015260248101839052604401610360565b5050565b6000602082840312156109d757600080fd5b81357fffffffff0000000000000000000000000000000000000000000000000000000081168114610a0757600080fd5b9392505050565b600060208284031215610a2057600080fd5b5035919050565b80356001600160a01b0381168114610a3e57600080fd5b919050565b60008060408385031215610a5657600080fd5b82359150610a6660208401610a27565b90509250929050565b60008083601f840112610a8157600080fd5b50813567ffffffffffffffff811115610a9957600080fd5b6020830191508360208260051b8501011115610ab457600080fd5b9250929050565b60008060008060008060008060008060a08b8d031215610ada57600080fd5b8a3567ffffffffffffffff80821115610af257600080fd5b610afe8e838f01610a6f565b909c509a5060208d0135915080821115610b1757600080fd5b610b238e838f01610a6f565b909a50985060408d0135915080821115610b3c57600080fd5b610b488e838f01610a6f565b909850965060608d0135915080821115610b6157600080fd5b610b6d8e838f01610a6f565b909650945060808d0135915080821115610b8657600080fd5b50610b938d828e01610a6f565b915080935050809150509295989b9194979a5092959850565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600060208284031215610bed57600080fd5b81358015158114610a0757600080fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112610c3257600080fd5b83018035915067ffffffffffffffff821115610c4d57600080fd5b6020019150600581901b3603821315610ab457600080fd5b600060208284031215610c7757600080fd5b610a0782610a2756fea26469706673582212201c3bcd6946d7cea884ff992fdce331753e2c002b97cc8abd738ee5872e7c157964736f6c63430008170033", + "deployedBytecode": "0x608060405234801561001057600080fd5b50600436106100a35760003560e01c80638045893911610076578063a217fddf1161005b578063a217fddf14610173578063d547741f1461017b578063f5b541a61461018e57600080fd5b8063804589391461012957806391d148541461013c57600080fd5b806301ffc9a7146100a8578063248a9ca3146100d05780632f2ff15d1461010157806336568abe14610116575b600080fd5b6100bb6100b63660046109c5565b6101b5565b60405190151581526020015b60405180910390f35b6100f36100de366004610a0e565b60009081526020819052604090206001015490565b6040519081526020016100c7565b61011461010f366004610a43565b61024e565b005b610114610124366004610a43565b610279565b610114610137366004610abb565b6102ca565b6100bb61014a366004610a43565b6000918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b6100f3600081565b610114610189366004610a43565b6107f6565b6100f37f97667070c54ef182b0f5858b034beac1b6f3089aa2d3188bb1e8929f4fa9b92981565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b00000000000000000000000000000000000000000000000000000000148061024857507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316145b92915050565b6000828152602081905260409020600101546102698161081b565b6102738383610828565b50505050565b6001600160a01b03811633146102bb576040517f6697b23200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6102c582826108d2565b505050565b7f97667070c54ef182b0f5858b034beac1b6f3089aa2d3188bb1e8929f4fa9b9296102f48161081b565b898814801561030257508786145b801561030d57508584145b801561031857508382145b6103695760405162461bcd60e51b815260206004820181905260248201527f417272617973206d7573742068617665207468652073616d65206c656e67746860448201526064015b60405180910390fd5b60005b8a8110156107e85783838281811061038657610386610bac565b905060200201602081019061039b9190610bdb565b1561056d5760005b8a8a838181106103b5576103b5610bac565b90506020028101906103c79190610bfd565b9050811015610567578c8c838181106103e2576103e2610bac565b90506020020160208101906103f79190610c65565b6001600160a01b031663f242432a338d8d8681811061041857610418610bac565b905060200281019061042a9190610bfd565b8581811061043a5761043a610bac565b905060200201602081019061044f9190610c65565b8c8c8781811061046157610461610bac565b90506020028101906104739190610bfd565b8681811061048357610483610bac565b905060200201358b8b8881811061049c5761049c610bac565b90506020028101906104ae9190610bfd565b878181106104be576104be610bac565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e089901b1681526001600160a01b03968716600482015295909416602486015250604484019190915260209091020135606482015260a06084820152600060a482015260c401600060405180830381600087803b15801561054357600080fd5b505af1158015610557573d6000803e3d6000fd5b5050600190920191506103a39050565b506107e0565b87878281811061057f5761057f610bac565b90506020028101906105919190610bfd565b90506001146106085760405162461bcd60e51b815260206004820152603360248201527f4552433732313a204f6e6c79206f6e6520746f6b656e2063616e20626520747260448201527f616e7366657272656420617420612074696d65000000000000000000000000006064820152608401610360565b89898281811061061a5761061a610bac565b905060200281019061062c9190610bfd565b90506001146106a35760405162461bcd60e51b815260206004820152602b60248201527f4552433732313a204f6e6c79206f6e6520726563697069656e742063616e206260448201527f65207370656369666965640000000000000000000000000000000000000000006064820152608401610360565b8b8b828181106106b5576106b5610bac565b90506020020160208101906106ca9190610c65565b6001600160a01b03166342842e0e338c8c858181106106eb576106eb610bac565b90506020028101906106fd9190610bfd565b600081811061070e5761070e610bac565b90506020020160208101906107239190610c65565b8b8b8681811061073557610735610bac565b90506020028101906107479190610bfd565b600081811061075857610758610bac565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e088901b1681526001600160a01b03958616600482015294909316602485015250602090910201356044820152606401600060405180830381600087803b1580156107c757600080fd5b505af11580156107db573d6000803e3d6000fd5b505050505b60010161036c565b505050505050505050505050565b6000828152602081905260409020600101546108118161081b565b61027383836108d2565b6108258133610955565b50565b6000828152602081815260408083206001600160a01b038516845290915281205460ff166108ca576000838152602081815260408083206001600160a01b03861684529091529020805460ff191660011790556108823390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a4506001610248565b506000610248565b6000828152602081815260408083206001600160a01b038516845290915281205460ff16156108ca576000838152602081815260408083206001600160a01b0386168085529252808320805460ff1916905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a4506001610248565b6000828152602081815260408083206001600160a01b038516845290915290205460ff166109c1576040517fe2517d3f0000000000000000000000000000000000000000000000000000000081526001600160a01b038216600482015260248101839052604401610360565b5050565b6000602082840312156109d757600080fd5b81357fffffffff0000000000000000000000000000000000000000000000000000000081168114610a0757600080fd5b9392505050565b600060208284031215610a2057600080fd5b5035919050565b80356001600160a01b0381168114610a3e57600080fd5b919050565b60008060408385031215610a5657600080fd5b82359150610a6660208401610a27565b90509250929050565b60008083601f840112610a8157600080fd5b50813567ffffffffffffffff811115610a9957600080fd5b6020830191508360208260051b8501011115610ab457600080fd5b9250929050565b60008060008060008060008060008060a08b8d031215610ada57600080fd5b8a3567ffffffffffffffff80821115610af257600080fd5b610afe8e838f01610a6f565b909c509a5060208d0135915080821115610b1757600080fd5b610b238e838f01610a6f565b909a50985060408d0135915080821115610b3c57600080fd5b610b488e838f01610a6f565b909850965060608d0135915080821115610b6157600080fd5b610b6d8e838f01610a6f565b909650945060808d0135915080821115610b8657600080fd5b50610b938d828e01610a6f565b915080935050809150509295989b9194979a5092959850565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600060208284031215610bed57600080fd5b81358015158114610a0757600080fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112610c3257600080fd5b83018035915067ffffffffffffffff821115610c4d57600080fd5b6020019150600581901b3603821315610ab457600080fd5b600060208284031215610c7757600080fd5b610a0782610a2756fea26469706673582212201c3bcd6946d7cea884ff992fdce331753e2c002b97cc8abd738ee5872e7c157964736f6c63430008170033", + "devdoc": { + "custom:security-contact": "contact-blockchain@sandbox.game", + "errors": { + "AccessControlBadConfirmation()": [ + { + "details": "The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}." + } + ], + "AccessControlUnauthorizedAccount(address,bytes32)": [ + { + "details": "The `account` is missing a role." + } + ] + }, + "events": { + "RoleAdminChanged(bytes32,bytes32,bytes32)": { + "details": "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." + }, + "RoleGranted(bytes32,address,address)": { + "details": "Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}." + }, + "RoleRevoked(bytes32,address,address)": { + "details": "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`)" + } + }, + "kind": "dev", + "methods": { + "batchTransfer(address[],address[][],uint256[][],uint256[][],bool[])": { + "details": "The arrays must have the same length", + "params": { + "amounts": "The amounts of tokens", + "contracts": "The addresses of the contracts", + "isERC1155": "Whether the token is ERC1155 or not", + "recipients": "The addresses of the recipients", + "tokenIds": "The token IDs" + } + }, + "getRoleAdmin(bytes32)": { + "details": "Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}." + }, + "grantRole(bytes32,address)": { + "details": "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." + }, + "hasRole(bytes32,address)": { + "details": "Returns `true` if `account` has been granted `role`." + }, + "renounceRole(bytes32,address)": { + "details": "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 `callerConfirmation`. May emit a {RoleRevoked} event." + }, + "revokeRole(bytes32,address)": { + "details": "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." + }, + "supportsInterface(bytes4)": { + "details": "See {IERC165-supportsInterface}." + } + }, + "version": 1 + }, + "userdoc": { + "kind": "user", + "methods": { + "OPERATOR_ROLE()": { + "notice": "The role that allows an address to use the contract" + }, + "batchTransfer(address[],address[][],uint256[][],uint256[][],bool[])": { + "notice": "Batch transfer ERC721 and ERC1155 tokens" + }, + "constructor": { + "notice": "Grant the contract deployer the default admin role" + } + }, + "version": 1 + }, + "storageLayout": { + "storage": [ + { + "astId": 26, + "contract": "@sandbox-smart-contracts/batch-transfers/contracts/BatchTransfer.sol:BatchTransfer", + "label": "_roles", + "offset": 0, + "slot": "0", + "type": "t_mapping(t_bytes32,t_struct(RoleData)21_storage)" + } + ], + "types": { + "t_address": { + "encoding": "inplace", + "label": "address", + "numberOfBytes": "20" + }, + "t_bool": { + "encoding": "inplace", + "label": "bool", + "numberOfBytes": "1" + }, + "t_bytes32": { + "encoding": "inplace", + "label": "bytes32", + "numberOfBytes": "32" + }, + "t_mapping(t_address,t_bool)": { + "encoding": "mapping", + "key": "t_address", + "label": "mapping(address => bool)", + "numberOfBytes": "32", + "value": "t_bool" + }, + "t_mapping(t_bytes32,t_struct(RoleData)21_storage)": { + "encoding": "mapping", + "key": "t_bytes32", + "label": "mapping(bytes32 => struct AccessControl.RoleData)", + "numberOfBytes": "32", + "value": "t_struct(RoleData)21_storage" + }, + "t_struct(RoleData)21_storage": { + "encoding": "inplace", + "label": "struct AccessControl.RoleData", + "members": [ + { + "astId": 18, + "contract": "@sandbox-smart-contracts/batch-transfers/contracts/BatchTransfer.sol:BatchTransfer", + "label": "hasRole", + "offset": 0, + "slot": "0", + "type": "t_mapping(t_address,t_bool)" + }, + { + "astId": 20, + "contract": "@sandbox-smart-contracts/batch-transfers/contracts/BatchTransfer.sol:BatchTransfer", + "label": "adminRole", + "offset": 0, + "slot": "1", + "type": "t_bytes32" + } + ], + "numberOfBytes": "64" + } + } + } +} \ No newline at end of file diff --git a/packages/deploy/deployments/polygon/solcInputs/a25c1b72c17f3b4f6df2f7f6fa6e6be7.json b/packages/deploy/deployments/polygon/solcInputs/a25c1b72c17f3b4f6df2f7f6fa6e6be7.json new file mode 100644 index 0000000000..a90e307353 --- /dev/null +++ b/packages/deploy/deployments/polygon/solcInputs/a25c1b72c17f3b4f6df2f7f6fa6e6be7.json @@ -0,0 +1,57 @@ +{ + "language": "Solidity", + "sources": { + "@openzeppelin/contracts/access/AccessControl.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\npragma solidity ^0.8.20;\n\nimport {IAccessControl} from \"./IAccessControl.sol\";\nimport {Context} from \"../utils/Context.sol\";\nimport {ERC165} from \"../utils/introspection/ERC165.sol\";\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account => bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role => RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n" + }, + "@openzeppelin/contracts/access/IAccessControl.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n" + }, + "@openzeppelin/contracts/token/ERC1155/IERC1155.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.1) (token/ERC1155/IERC1155.sol)\n\npragma solidity ^0.8.20;\n\nimport {IERC165} from \"../../utils/introspection/IERC165.sol\";\n\n/**\n * @dev Required interface of an ERC1155 compliant contract, as defined in the\n * https://eips.ethereum.org/EIPS/eip-1155[EIP].\n */\ninterface IERC1155 is IERC165 {\n /**\n * @dev Emitted when `value` amount of tokens of type `id` are transferred from `from` to `to` by `operator`.\n */\n event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value);\n\n /**\n * @dev Equivalent to multiple {TransferSingle} events, where `operator`, `from` and `to` are the same for all\n * transfers.\n */\n event TransferBatch(\n address indexed operator,\n address indexed from,\n address indexed to,\n uint256[] ids,\n uint256[] values\n );\n\n /**\n * @dev Emitted when `account` grants or revokes permission to `operator` to transfer their tokens, according to\n * `approved`.\n */\n event ApprovalForAll(address indexed account, address indexed operator, bool approved);\n\n /**\n * @dev Emitted when the URI for token type `id` changes to `value`, if it is a non-programmatic URI.\n *\n * If an {URI} event was emitted for `id`, the standard\n * https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[guarantees] that `value` will equal the value\n * returned by {IERC1155MetadataURI-uri}.\n */\n event URI(string value, uint256 indexed id);\n\n /**\n * @dev Returns the value of tokens of token type `id` owned by `account`.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n */\n function balanceOf(address account, uint256 id) external view returns (uint256);\n\n /**\n * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {balanceOf}.\n *\n * Requirements:\n *\n * - `accounts` and `ids` must have the same length.\n */\n function balanceOfBatch(\n address[] calldata accounts,\n uint256[] calldata ids\n ) external view returns (uint256[] memory);\n\n /**\n * @dev Grants or revokes permission to `operator` to transfer the caller's tokens, according to `approved`,\n *\n * Emits an {ApprovalForAll} event.\n *\n * Requirements:\n *\n * - `operator` cannot be the caller.\n */\n function setApprovalForAll(address operator, bool approved) external;\n\n /**\n * @dev Returns true if `operator` is approved to transfer ``account``'s tokens.\n *\n * See {setApprovalForAll}.\n */\n function isApprovedForAll(address account, address operator) external view returns (bool);\n\n /**\n * @dev Transfers a `value` amount of tokens of type `id` from `from` to `to`.\n *\n * WARNING: This function can potentially allow a reentrancy attack when transferring tokens\n * to an untrusted contract, when invoking {onERC1155Received} on the receiver.\n * Ensure to follow the checks-effects-interactions pattern and consider employing\n * reentrancy guards when interacting with untrusted contracts.\n *\n * Emits a {TransferSingle} event.\n *\n * Requirements:\n *\n * - `to` cannot be the zero address.\n * - If the caller is not `from`, it must have been approved to spend ``from``'s tokens via {setApprovalForAll}.\n * - `from` must have a balance of tokens of type `id` of at least `value` amount.\n * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the\n * acceptance magic value.\n */\n function safeTransferFrom(address from, address to, uint256 id, uint256 value, bytes calldata data) external;\n\n /**\n * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {safeTransferFrom}.\n *\n * WARNING: This function can potentially allow a reentrancy attack when transferring tokens\n * to an untrusted contract, when invoking {onERC1155BatchReceived} on the receiver.\n * Ensure to follow the checks-effects-interactions pattern and consider employing\n * reentrancy guards when interacting with untrusted contracts.\n *\n * Emits either a {TransferSingle} or a {TransferBatch} event, depending on the length of the array arguments.\n *\n * Requirements:\n *\n * - `ids` and `values` must have the same length.\n * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the\n * acceptance magic value.\n */\n function safeBatchTransferFrom(\n address from,\n address to,\n uint256[] calldata ids,\n uint256[] calldata values,\n bytes calldata data\n ) external;\n}\n" + }, + "@openzeppelin/contracts/token/ERC721/IERC721.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/IERC721.sol)\n\npragma solidity ^0.8.20;\n\nimport {IERC165} from \"../../utils/introspection/IERC165.sol\";\n\n/**\n * @dev Required interface of an ERC721 compliant contract.\n */\ninterface IERC721 is IERC165 {\n /**\n * @dev Emitted when `tokenId` token is transferred from `from` to `to`.\n */\n event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);\n\n /**\n * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.\n */\n event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);\n\n /**\n * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.\n */\n event ApprovalForAll(address indexed owner, address indexed operator, bool approved);\n\n /**\n * @dev Returns the number of tokens in ``owner``'s account.\n */\n function balanceOf(address owner) external view returns (uint256 balance);\n\n /**\n * @dev Returns the owner of the `tokenId` token.\n *\n * Requirements:\n *\n * - `tokenId` must exist.\n */\n function ownerOf(uint256 tokenId) external view returns (address owner);\n\n /**\n * @dev Safely transfers `tokenId` token from `from` to `to`.\n *\n * Requirements:\n *\n * - `from` cannot be the zero address.\n * - `to` cannot be the zero address.\n * - `tokenId` token must exist and be owned by `from`.\n * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.\n * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon\n * a safe transfer.\n *\n * Emits a {Transfer} event.\n */\n function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external;\n\n /**\n * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients\n * are aware of the ERC721 protocol to prevent tokens from being forever locked.\n *\n * Requirements:\n *\n * - `from` cannot be the zero address.\n * - `to` cannot be the zero address.\n * - `tokenId` token must exist and be owned by `from`.\n * - If the caller is not `from`, it must have been allowed to move this token by either {approve} or\n * {setApprovalForAll}.\n * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon\n * a safe transfer.\n *\n * Emits a {Transfer} event.\n */\n function safeTransferFrom(address from, address to, uint256 tokenId) external;\n\n /**\n * @dev Transfers `tokenId` token from `from` to `to`.\n *\n * WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721\n * or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must\n * understand this adds an external call which potentially creates a reentrancy vulnerability.\n *\n * Requirements:\n *\n * - `from` cannot be the zero address.\n * - `to` cannot be the zero address.\n * - `tokenId` token must be owned by `from`.\n * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 tokenId) external;\n\n /**\n * @dev Gives permission to `to` to transfer `tokenId` token to another account.\n * The approval is cleared when the token is transferred.\n *\n * Only a single account can be approved at a time, so approving the zero address clears previous approvals.\n *\n * Requirements:\n *\n * - The caller must own the token or be an approved operator.\n * - `tokenId` must exist.\n *\n * Emits an {Approval} event.\n */\n function approve(address to, uint256 tokenId) external;\n\n /**\n * @dev Approve or remove `operator` as an operator for the caller.\n * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.\n *\n * Requirements:\n *\n * - The `operator` cannot be the address zero.\n *\n * Emits an {ApprovalForAll} event.\n */\n function setApprovalForAll(address operator, bool approved) external;\n\n /**\n * @dev Returns the account approved for `tokenId` token.\n *\n * Requirements:\n *\n * - `tokenId` must exist.\n */\n function getApproved(uint256 tokenId) external view returns (address operator);\n\n /**\n * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.\n *\n * See {setApprovalForAll}\n */\n function isApprovedForAll(address owner, address operator) external view returns (bool);\n}\n" + }, + "@openzeppelin/contracts/utils/Context.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n" + }, + "@openzeppelin/contracts/utils/introspection/ERC165.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\npragma solidity ^0.8.20;\n\nimport {IERC165} from \"./IERC165.sol\";\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n" + }, + "@openzeppelin/contracts/utils/introspection/IERC165.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n" + }, + "@sandbox-smart-contracts/batch-transfers/contracts/BatchTransfer.sol": { + "content": "//SPDX-License-Identifier: MIT\npragma solidity ^0.8.20;\n\nimport \"@openzeppelin/contracts/access/AccessControl.sol\";\nimport \"@openzeppelin/contracts/token/ERC721/IERC721.sol\";\nimport \"@openzeppelin/contracts/token/ERC1155/IERC1155.sol\";\n\n/// @custom:security-contact contact-blockchain@sandbox.game\ncontract BatchTransfer is AccessControl {\n /// @notice The role that allows an address to use the contract\n bytes32 public constant OPERATOR_ROLE = keccak256(\"OPERATOR_ROLE\");\n\n /// Grant the contract deployer the default admin role\n constructor() {\n _grantRole(DEFAULT_ADMIN_ROLE, _msgSender());\n }\n\n /// @notice Batch transfer ERC721 and ERC1155 tokens\n /// @param contracts The addresses of the contracts\n /// @param recipients The addresses of the recipients\n /// @param tokenIds The token IDs\n /// @param amounts The amounts of tokens\n /// @param isERC1155 Whether the token is ERC1155 or not\n /// @dev The arrays must have the same length\n function batchTransfer(\n address[] calldata contracts,\n address[][] calldata recipients,\n uint256[][] calldata tokenIds,\n uint256[][] calldata amounts,\n bool[] calldata isERC1155\n ) external onlyRole(OPERATOR_ROLE) {\n require(\n contracts.length == recipients.length &&\n recipients.length == tokenIds.length &&\n tokenIds.length == amounts.length &&\n amounts.length == isERC1155.length,\n \"Arrays must have the same length\"\n );\n for (uint256 i = 0; i < contracts.length; i++) {\n if (isERC1155[i]) {\n for (uint256 j = 0; j < recipients[i].length; j++) {\n IERC1155(contracts[i]).safeTransferFrom(\n _msgSender(),\n recipients[i][j],\n tokenIds[i][j],\n amounts[i][j],\n \"\"\n );\n }\n } else {\n require(tokenIds[i].length == 1, \"ERC721: Only one token can be transferred at a time\");\n require(recipients[i].length == 1, \"ERC721: Only one recipient can be specified\");\n IERC721(contracts[i]).safeTransferFrom(_msgSender(), recipients[i][0], tokenIds[i][0]);\n }\n }\n }\n}\n" + } + }, + "settings": { + "optimizer": { + "enabled": true, + "runs": 2000 + }, + "evmVersion": "paris", + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata", + "devdoc", + "userdoc", + "storageLayout", + "evm.gasEstimates" + ], + "": [ + "ast" + ] + } + }, + "metadata": { + "useLiteralContent": true + } + } +} \ No newline at end of file