diff --git a/contracts/utils/ERC721BatchTransfer.sol b/contracts/utils/ERC721BatchTransfer.sol index 9e0de923..5681bdda 100644 --- a/contracts/utils/ERC721BatchTransfer.sol +++ b/contracts/utils/ERC721BatchTransfer.sol @@ -12,7 +12,6 @@ import {IERC721} from "@openzeppelin/contracts/token/ERC721/IERC721.sol"; */ contract ERC721BatchTransfer { error InvalidArguments(); - error NotOwnerOfToken(); event BatchTransferToSingle( address indexed contractAddress, @@ -37,19 +36,17 @@ contract ERC721BatchTransfer { address to, uint256[] calldata tokenIds ) external { - uint256 length = tokenIds.length; - for (uint256 i; i < length; ) { - uint256 tokenId = tokenIds[i]; - address owner = erc721Contract.ownerOf(tokenId); - if (msg.sender != owner) { - revert NotOwnerOfToken(); - } - erc721Contract.transferFrom(owner, to, tokenId); + for (uint256 i; i < tokenIds.length; ) { + erc721Contract.transferFrom(msg.sender, to, tokenIds[i]); unchecked { ++i; } } - emit BatchTransferToSingle(address(erc721Contract), to, length); + emit BatchTransferToSingle( + address(erc721Contract), + to, + tokenIds.length + ); } /** @@ -63,19 +60,17 @@ contract ERC721BatchTransfer { address to, uint256[] calldata tokenIds ) external { - uint256 length = tokenIds.length; - for (uint256 i; i < length; ) { - uint256 tokenId = tokenIds[i]; - address owner = erc721Contract.ownerOf(tokenId); - if (msg.sender != owner) { - revert NotOwnerOfToken(); - } - erc721Contract.safeTransferFrom(owner, to, tokenId); + for (uint256 i; i < tokenIds.length; ) { + erc721Contract.safeTransferFrom(msg.sender, to, tokenIds[i]); unchecked { ++i; } } - emit BatchTransferToSingle(address(erc721Contract), to, length); + emit BatchTransferToSingle( + address(erc721Contract), + to, + tokenIds.length + ); } /** @@ -95,23 +90,16 @@ contract ERC721BatchTransfer { address[] calldata tos, uint256[] calldata tokenIds ) external { - uint256 length = tokenIds.length; - if (tos.length != length) revert InvalidArguments(); + if (tos.length != tokenIds.length) revert InvalidArguments(); - for (uint256 i; i < length; ) { - uint256 tokenId = tokenIds[i]; - address owner = erc721Contract.ownerOf(tokenId); - address to = tos[i]; - if (msg.sender != owner) { - revert NotOwnerOfToken(); - } - erc721Contract.transferFrom(owner, to, tokenId); + for (uint256 i; i < tokenIds.length; ) { + erc721Contract.transferFrom(msg.sender, tos[i], tokenIds[i]); unchecked { ++i; } } - emit BatchTransferToMultiple(address(erc721Contract), length); + emit BatchTransferToMultiple(address(erc721Contract), tokenIds.length); } /** @@ -130,22 +118,15 @@ contract ERC721BatchTransfer { address[] calldata tos, uint256[] calldata tokenIds ) external { - uint256 length = tokenIds.length; - if (tos.length != length) revert InvalidArguments(); + if (tos.length != tokenIds.length) revert InvalidArguments(); - for (uint256 i; i < length; ) { - uint256 tokenId = tokenIds[i]; - address owner = erc721Contract.ownerOf(tokenId); - address to = tos[i]; - if (msg.sender != owner) { - revert NotOwnerOfToken(); - } - erc721Contract.safeTransferFrom(owner, to, tokenId); + for (uint256 i; i < tokenIds.length; ) { + erc721Contract.safeTransferFrom(msg.sender, tos[i], tokenIds[i]); unchecked { ++i; } } - emit BatchTransferToMultiple(address(erc721Contract), length); + emit BatchTransferToMultiple(address(erc721Contract), tokenIds.length); } } diff --git a/hardhat.config.ts b/hardhat.config.ts index 922dc43a..e40f36a0 100644 --- a/hardhat.config.ts +++ b/hardhat.config.ts @@ -1,6 +1,6 @@ import 'dotenv/config'; -import "@nomicfoundation/hardhat-verify"; +import '@nomicfoundation/hardhat-verify'; import '@nomiclabs/hardhat-waffle'; import '@typechain/hardhat'; import 'hardhat-contract-sizer'; @@ -56,7 +56,7 @@ const config: HardhatUserConfig = { runs: 20, details: { yulDetails: { - optimizerSteps: "dhfoD[xarrscLMcCTU]uljmul", + optimizerSteps: 'dhfoD[xarrscLMcCTU]uljmul', }, }, }, @@ -77,8 +77,8 @@ const config: HardhatUserConfig = { networks: { hardhat: { accounts: { - accountsBalance: '1000000000000000000000' - } + accountsBalance: '1000000000000000000000', + }, }, base: { url: process.env.BASE_URL || '', @@ -130,8 +130,8 @@ const config: HardhatUserConfig = { apiKey: process.env.ETHERSCAN_API_KEY, }, sourcify: { - enabled: true - } + enabled: true, + }, }; task('setStages', 'Set stages for ERC721M') @@ -146,7 +146,6 @@ task('setStages', 'Set stages for ERC721M') ) .setAction(setStages); - task('set1155Stages', 'Set stages for ERC721M') .addParam('contract', 'contract address') .addParam('stages', 'stages json file') @@ -181,10 +180,7 @@ task('deploy', 'Deploy ERC721M') 'ERC-20 contract address (if minting with ERC-20)', '0x0000000000000000000000000000000000000000', ) - .addOptionalParam( - 'fundreceiver', - 'The treasury wallet to receive mint fund', - ) + .addOptionalParam('fundreceiver', 'The treasury wallet to receive mint fund') .addParam( 'useoperatorfilterer', 'whether or not to use operator filterer, used with legacy 721M contract', @@ -228,7 +224,6 @@ task('deploy', 'Deploy ERC721M') await deploy(tasksArgs, hre); }); - task('deploy1155', 'Deploy ERC1155M') .addParam('name', 'name') .addParam('symbol', 'symbol') @@ -240,10 +235,7 @@ task('deploy1155', 'Deploy ERC1155M') 'ERC-20 contract address (if minting with ERC-20)', '0x0000000000000000000000000000000000000000', ) - .addOptionalParam( - 'fundreceiver', - 'The treasury wallet to receive mint fund', - ) + .addOptionalParam('fundreceiver', 'The treasury wallet to receive mint fund') .addParam( 'openedition', 'whether or not a open edition mint (unlimited supply, 999,999,999)', @@ -267,7 +259,7 @@ task('deploy1155', 'Deploy ERC1155M') await hre.run('compile'); console.log('Deploying...'); await deploy1155(tasksArgs, hre); -}); + }); task('setBaseURI', 'Set the base uri') .addParam('uri', 'uri') @@ -309,7 +301,6 @@ task('ownerMint1155', 'Mint token(s) as owner for ERC1155M') .addOptionalParam('gaslimit', 'Set maximum gas units to spend on transaction') .setAction(ownerMint1155); - task('setGlobalWalletLimit', 'Set the global wallet limit') .addParam('contract', 'contract address') .addParam('limit', 'global wallet limit (0 for no global limit)') @@ -459,13 +450,16 @@ task('thawTrading', 'Thaw trading for 721Cv2') task('cleanWhitelist', 'Clean up whitelist') .addOptionalParam('whitelistpath', 'plain whitelist path') - .addOptionalParam('variablewalletlimitpath', 'variable wallet limit whitelist path') - .setAction(cleanWhitelist) + .addOptionalParam( + 'variablewalletlimitpath', + 'variable wallet limit whitelist path', + ) + .setAction(cleanWhitelist); task('deployCloneFactory', 'Deploy 721CMRoyalties clone factory') .addOptionalParam('gaspricegwei', 'Set gas price in Gwei') .addOptionalParam('gaslimit', 'Set maximum gas units to spend on transaction') - .setAction(deployCloneFactory) + .setAction(deployCloneFactory); task('deployClone', 'Create 721CMRoyalties cline') .addParam('name', 'name') @@ -474,7 +468,11 @@ task('deployClone', 'Create 721CMRoyalties cline') .addParam('tokenurisuffix', 'token uri suffix', '.json') .addParam('globalwalletlimit', 'global wallet limit', '0') .addParam('timestampexpiryseconds', 'timestamp expiry in seconds', '300') - .addParam('mintcurrency','ERC-20 contract address. 0x0 if using native token','0x0000000000000000000000000000000000000000') + .addParam( + 'mintcurrency', + 'ERC-20 contract address. 0x0 if using native token', + '0x0000000000000000000000000000000000000000', + ) .addParam('fundreceiver', 'The treasury wallet to receive mint fund') .addParam('royaltyreceiver', 'erc2198 royalty receiver address') .addParam('royaltyfeenumerator', 'erc2198 royalty fee numerator') diff --git a/scripts/common/constants.ts b/scripts/common/constants.ts index 9a8c1909..b0c9bc5a 100644 --- a/scripts/common/constants.ts +++ b/scripts/common/constants.ts @@ -13,7 +13,7 @@ export const ContractDetails = { } as const; export const ERC721BatchTransferContract = - '0x38F7ba911f7efc434D29D6E39c814E9d4De3FEef'; + '0x2d9082592Db4A7C2536A1cEDc33Cc2a53a75Bf27'; export const ERC721CV2_VALIDATOR = '0x721C00182a990771244d7A71B9FA2ea789A3b433'; export const ERC721CV2_FREEZE_LEVEL = 4; @@ -22,4 +22,5 @@ export const ERC721CV2_EMPTY_LIST = 4; // Mainnet, Polygon, Base export const ERC721CMRoyaltiesCloneFactoryContract = '0x7cEEd7215D71393d56966dA48C5727851326e101'; -export const RESERVOIR_RELAYER_EOA = '0xf70da97812CB96acDF810712Aa562db8dfA3dbEF'; \ No newline at end of file +export const RESERVOIR_RELAYER_EOA = '0xf70da97812CB96acDF810712Aa562db8dfA3dbEF'; + diff --git a/test/ERC721BatchTransfer.test.ts b/test/ERC721BatchTransfer.test.ts index b78b3187..d88743c1 100644 --- a/test/ERC721BatchTransfer.test.ts +++ b/test/ERC721BatchTransfer.test.ts @@ -36,7 +36,7 @@ describe('ERC721BatchTransfer', function () { await nftContract.setApprovalForAll(transferContract.address, true); - await nftContract.mintBatch(owner.address, 5); + await nftContract.mintBatch(owner.address, 1000); for (let i = 0; i < 5; i++) { const tokenOwner = await nftContract.ownerOf(i); @@ -56,6 +56,24 @@ describe('ERC721BatchTransfer', function () { } }); + it.skip('batchTransferToSingleWallet max Batch', async () => { + // old cap was 777 + const batchAmount = 834; + const tx = await transferContract.batchTransferToSingleWallet( + nftContract.address, + addresses.addr1, + Array.from({ length: batchAmount }, (_, i) => i), + ); + const receipt = await tx.wait(); + + console.log(receipt.gasUsed); + + for (let i = 0; i < batchAmount; i++) { + const tokenOwner = await nftContract.ownerOf(i); + expect(tokenOwner).to.equal(addresses.addr1); + } + }); + it('safeBatchTransferToSingleWallet', async () => { const tokenIds = [0, 1, 2, 3, 4]; await transferContract.safeBatchTransferToSingleWallet( @@ -130,7 +148,7 @@ describe('ERC721BatchTransfer', function () { tos, tokenIds, ), - ).to.be.revertedWith('NotOwnerOfToken'); + ).to.be.revertedWith('TransferFromIncorrectOwner()'); }); it('revert if invalid arguments', async () => {