// SPDX-License-Identifier: AGPL-3.0-only pragma solidity 0.8.15; import {DSTestPlus} from "./utils/DSTestPlus.sol"; import {DSInvariantTest} from "./utils/DSInvariantTest.sol"; import {MockERC1155} from "./utils/mocks/MockERC1155.sol"; import {ERC1155TokenReceiver} from "../tokens/ERC1155.sol"; contract ERC1155Recipient is ERC1155TokenReceiver { address public operator; address public from; uint256 public id; uint256 public amount; bytes public mintData; function onERC1155Received( address _operator, address _from, uint256 _id, uint256 _amount, bytes calldata _data ) public override returns (bytes4) { operator = _operator; from = _from; id = _id; amount = _amount; mintData = _data; return ERC1155TokenReceiver.onERC1155Received.selector; } address public batchOperator; address public batchFrom; uint256[] internal _batchIds; uint256[] internal _batchAmounts; bytes public batchData; function batchIds() external view returns (uint256[] memory) { return _batchIds; } function batchAmounts() external view returns (uint256[] memory) { return _batchAmounts; } function onERC1155BatchReceived( address _operator, address _from, uint256[] calldata _ids, uint256[] calldata _amounts, bytes calldata _data ) external override returns (bytes4) { batchOperator = _operator; batchFrom = _from; _batchIds = _ids; _batchAmounts = _amounts; batchData = _data; return ERC1155TokenReceiver.onERC1155BatchReceived.selector; } } contract RevertingERC1155Recipient is ERC1155TokenReceiver { function onERC1155Received( address, address, uint256, uint256, bytes calldata ) public pure override returns (bytes4) { revert(string(abi.encodePacked(ERC1155TokenReceiver.onERC1155Received.selector))); } function onERC1155BatchReceived( address, address, uint256[] calldata, uint256[] calldata, bytes calldata ) external pure override returns (bytes4) { revert(string(abi.encodePacked(ERC1155TokenReceiver.onERC1155BatchReceived.selector))); } } contract WrongReturnDataERC1155Recipient is ERC1155TokenReceiver { function onERC1155Received( address, address, uint256, uint256, bytes calldata ) public pure override returns (bytes4) { return 0xCAFEBEEF; } function onERC1155BatchReceived( address, address, uint256[] calldata, uint256[] calldata, bytes calldata ) external pure override returns (bytes4) { return 0xCAFEBEEF; } } contract NonERC1155Recipient {} contract ERC1155Test is DSTestPlus, ERC1155TokenReceiver { MockERC1155 token; mapping(address => mapping(uint256 => uint256)) public userMintAmounts; mapping(address => mapping(uint256 => uint256)) public userTransferOrBurnAmounts; function setUp() public { token = new MockERC1155(); } function testMintToEOA() public { token.mint(address(0xBEEF), 1337, 1, ""); assertEq(token.balanceOf(address(0xBEEF), 1337), 1); } function testMintToERC1155Recipient() public { ERC1155Recipient to = new ERC1155Recipient(); token.mint(address(to), 1337, 1, "testing 123"); assertEq(token.balanceOf(address(to), 1337), 1); assertEq(to.operator(), address(this)); assertEq(to.from(), address(0)); assertEq(to.id(), 1337); assertBytesEq(to.mintData(), "testing 123"); } function testBatchMintToEOA() public { uint256[] memory ids = new uint256[](5); ids[0] = 1337; ids[1] = 1338; ids[2] = 1339; ids[3] = 1340; ids[4] = 1341; uint256[] memory amounts = new uint256[](5); amounts[0] = 100; amounts[1] = 200; amounts[2] = 300; amounts[3] = 400; amounts[4] = 500; token.batchMint(address(0xBEEF), ids, amounts, ""); assertEq(token.balanceOf(address(0xBEEF), 1337), 100); assertEq(token.balanceOf(address(0xBEEF), 1338), 200); assertEq(token.balanceOf(address(0xBEEF), 1339), 300); assertEq(token.balanceOf(address(0xBEEF), 1340), 400); assertEq(token.balanceOf(address(0xBEEF), 1341), 500); } function testBatchMintToERC1155Recipient() public { ERC1155Recipient to = new ERC1155Recipient(); uint256[] memory ids = new uint256[](5); ids[0] = 1337; ids[1] = 1338; ids[2] = 1339; ids[3] = 1340; ids[4] = 1341; uint256[] memory amounts = new uint256[](5); amounts[0] = 100; amounts[1] = 200; amounts[2] = 300; amounts[3] = 400; amounts[4] = 500; token.batchMint(address(to), ids, amounts, "testing 123"); assertEq(to.batchOperator(), address(this)); assertEq(to.batchFrom(), address(0)); assertUintArrayEq(to.batchIds(), ids); assertUintArrayEq(to.batchAmounts(), amounts); assertBytesEq(to.batchData(), "testing 123"); assertEq(token.balanceOf(address(to), 1337), 100); assertEq(token.balanceOf(address(to), 1338), 200); assertEq(token.balanceOf(address(to), 1339), 300); assertEq(token.balanceOf(address(to), 1340), 400); assertEq(token.balanceOf(address(to), 1341), 500); } function testBurn() public { token.mint(address(0xBEEF), 1337, 100, ""); token.burn(address(0xBEEF), 1337, 70); assertEq(token.balanceOf(address(0xBEEF), 1337), 30); } function testBatchBurn() public { uint256[] memory ids = new uint256[](5); ids[0] = 1337; ids[1] = 1338; ids[2] = 1339; ids[3] = 1340; ids[4] = 1341; uint256[] memory mintAmounts = new uint256[](5); mintAmounts[0] = 100; mintAmounts[1] = 200; mintAmounts[2] = 300; mintAmounts[3] = 400; mintAmounts[4] = 500; uint256[] memory burnAmounts = new uint256[](5); burnAmounts[0] = 50; burnAmounts[1] = 100; burnAmounts[2] = 150; burnAmounts[3] = 200; burnAmounts[4] = 250; token.batchMint(address(0xBEEF), ids, mintAmounts, ""); token.batchBurn(address(0xBEEF), ids, burnAmounts); assertEq(token.balanceOf(address(0xBEEF), 1337), 50); assertEq(token.balanceOf(address(0xBEEF), 1338), 100); assertEq(token.balanceOf(address(0xBEEF), 1339), 150); assertEq(token.balanceOf(address(0xBEEF), 1340), 200); assertEq(token.balanceOf(address(0xBEEF), 1341), 250); } function testApproveAll() public { token.setApprovalForAll(address(0xBEEF), true); assertTrue(token.isApprovedForAll(address(this), address(0xBEEF))); } function testSafeTransferFromToEOA() public { address from = address(0xABCD); token.mint(from, 1337, 100, ""); hevm.prank(from); token.setApprovalForAll(address(this), true); token.safeTransferFrom(from, address(0xBEEF), 1337, 70, ""); assertEq(token.balanceOf(address(0xBEEF), 1337), 70); assertEq(token.balanceOf(from, 1337), 30); } function testSafeTransferFromToERC1155Recipient() public { ERC1155Recipient to = new ERC1155Recipient(); address from = address(0xABCD); token.mint(from, 1337, 100, ""); hevm.prank(from); token.setApprovalForAll(address(this), true); token.safeTransferFrom(from, address(to), 1337, 70, "testing 123"); assertEq(to.operator(), address(this)); assertEq(to.from(), from); assertEq(to.id(), 1337); assertBytesEq(to.mintData(), "testing 123"); assertEq(token.balanceOf(address(to), 1337), 70); assertEq(token.balanceOf(from, 1337), 30); } function testSafeTransferFromSelf() public { token.mint(address(this), 1337, 100, ""); token.safeTransferFrom(address(this), address(0xBEEF), 1337, 70, ""); assertEq(token.balanceOf(address(0xBEEF), 1337), 70); assertEq(token.balanceOf(address(this), 1337), 30); } function testSafeBatchTransferFromToEOA() public { address from = address(0xABCD); uint256[] memory ids = new uint256[](5); ids[0] = 1337; ids[1] = 1338; ids[2] = 1339; ids[3] = 1340; ids[4] = 1341; uint256[] memory mintAmounts = new uint256[](5); mintAmounts[0] = 100; mintAmounts[1] = 200; mintAmounts[2] = 300; mintAmounts[3] = 400; mintAmounts[4] = 500; uint256[] memory transferAmounts = new uint256[](5); transferAmounts[0] = 50; transferAmounts[1] = 100; transferAmounts[2] = 150; transferAmounts[3] = 200; transferAmounts[4] = 250; token.batchMint(from, ids, mintAmounts, ""); hevm.prank(from); token.setApprovalForAll(address(this), true); token.safeBatchTransferFrom(from, address(0xBEEF), ids, transferAmounts, ""); assertEq(token.balanceOf(from, 1337), 50); assertEq(token.balanceOf(address(0xBEEF), 1337), 50); assertEq(token.balanceOf(from, 1338), 100); assertEq(token.balanceOf(address(0xBEEF), 1338), 100); assertEq(token.balanceOf(from, 1339), 150); assertEq(token.balanceOf(address(0xBEEF), 1339), 150); assertEq(token.balanceOf(from, 1340), 200); assertEq(token.balanceOf(address(0xBEEF), 1340), 200); assertEq(token.balanceOf(from, 1341), 250); assertEq(token.balanceOf(address(0xBEEF), 1341), 250); } function testSafeBatchTransferFromToERC1155Recipient() public { address from = address(0xABCD); ERC1155Recipient to = new ERC1155Recipient(); uint256[] memory ids = new uint256[](5); ids[0] = 1337; ids[1] = 1338; ids[2] = 1339; ids[3] = 1340; ids[4] = 1341; uint256[] memory mintAmounts = new uint256[](5); mintAmounts[0] = 100; mintAmounts[1] = 200; mintAmounts[2] = 300; mintAmounts[3] = 400; mintAmounts[4] = 500; uint256[] memory transferAmounts = new uint256[](5); transferAmounts[0] = 50; transferAmounts[1] = 100; transferAmounts[2] = 150; transferAmounts[3] = 200; transferAmounts[4] = 250; token.batchMint(from, ids, mintAmounts, ""); hevm.prank(from); token.setApprovalForAll(address(this), true); token.safeBatchTransferFrom(from, address(to), ids, transferAmounts, "testing 123"); assertEq(to.batchOperator(), address(this)); assertEq(to.batchFrom(), from); assertUintArrayEq(to.batchIds(), ids); assertUintArrayEq(to.batchAmounts(), transferAmounts); assertBytesEq(to.batchData(), "testing 123"); assertEq(token.balanceOf(from, 1337), 50); assertEq(token.balanceOf(address(to), 1337), 50); assertEq(token.balanceOf(from, 1338), 100); assertEq(token.balanceOf(address(to), 1338), 100); assertEq(token.balanceOf(from, 1339), 150); assertEq(token.balanceOf(address(to), 1339), 150); assertEq(token.balanceOf(from, 1340), 200); assertEq(token.balanceOf(address(to), 1340), 200); assertEq(token.balanceOf(from, 1341), 250); assertEq(token.balanceOf(address(to), 1341), 250); } function testBatchBalanceOf() public { address[] memory tos = new address[](5); tos[0] = address(0xBEEF); tos[1] = address(0xCAFE); tos[2] = address(0xFACE); tos[3] = address(0xDEAD); tos[4] = address(0xFEED); uint256[] memory ids = new uint256[](5); ids[0] = 1337; ids[1] = 1338; ids[2] = 1339; ids[3] = 1340; ids[4] = 1341; token.mint(address(0xBEEF), 1337, 100, ""); token.mint(address(0xCAFE), 1338, 200, ""); token.mint(address(0xFACE), 1339, 300, ""); token.mint(address(0xDEAD), 1340, 400, ""); token.mint(address(0xFEED), 1341, 500, ""); uint256[] memory balances = token.balanceOfBatch(tos, ids); assertEq(balances[0], 100); assertEq(balances[1], 200); assertEq(balances[2], 300); assertEq(balances[3], 400); assertEq(balances[4], 500); } function testFailMintToZero() public { token.mint(address(0), 1337, 1, ""); } function testFailMintToNonERC155Recipient() public { token.mint(address(new NonERC1155Recipient()), 1337, 1, ""); } function testFailMintToRevertingERC155Recipient() public { token.mint(address(new RevertingERC1155Recipient()), 1337, 1, ""); } function testFailMintToWrongReturnDataERC155Recipient() public { token.mint(address(new RevertingERC1155Recipient()), 1337, 1, ""); } function testFailBurnInsufficientBalance() public { token.mint(address(0xBEEF), 1337, 70, ""); token.burn(address(0xBEEF), 1337, 100); } function testFailSafeTransferFromInsufficientBalance() public { address from = address(0xABCD); token.mint(from, 1337, 70, ""); hevm.prank(from); token.setApprovalForAll(address(this), true); token.safeTransferFrom(from, address(0xBEEF), 1337, 100, ""); } function testFailSafeTransferFromSelfInsufficientBalance() public { token.mint(address(this), 1337, 70, ""); token.safeTransferFrom(address(this), address(0xBEEF), 1337, 100, ""); } function testFailSafeTransferFromToZero() public { token.mint(address(this), 1337, 100, ""); token.safeTransferFrom(address(this), address(0), 1337, 70, ""); } function testFailSafeTransferFromToNonERC155Recipient() public { token.mint(address(this), 1337, 100, ""); token.safeTransferFrom(address(this), address(new NonERC1155Recipient()), 1337, 70, ""); } function testFailSafeTransferFromToRevertingERC1155Recipient() public { token.mint(address(this), 1337, 100, ""); token.safeTransferFrom(address(this), address(new RevertingERC1155Recipient()), 1337, 70, ""); } function testFailSafeTransferFromToWrongReturnDataERC1155Recipient() public { token.mint(address(this), 1337, 100, ""); token.safeTransferFrom(address(this), address(new WrongReturnDataERC1155Recipient()), 1337, 70, ""); } function testFailSafeBatchTransferInsufficientBalance() public { address from = address(0xABCD); uint256[] memory ids = new uint256[](5); ids[0] = 1337; ids[1] = 1338; ids[2] = 1339; ids[3] = 1340; ids[4] = 1341; uint256[] memory mintAmounts = new uint256[](5); mintAmounts[0] = 50; mintAmounts[1] = 100; mintAmounts[2] = 150; mintAmounts[3] = 200; mintAmounts[4] = 250; uint256[] memory transferAmounts = new uint256[](5); transferAmounts[0] = 100; transferAmounts[1] = 200; transferAmounts[2] = 300; transferAmounts[3] = 400; transferAmounts[4] = 500; token.batchMint(from, ids, mintAmounts, ""); hevm.prank(from); token.setApprovalForAll(address(this), true); token.safeBatchTransferFrom(from, address(0xBEEF), ids, transferAmounts, ""); } function testFailSafeBatchTransferFromToZero() public { address from = address(0xABCD); uint256[] memory ids = new uint256[](5); ids[0] = 1337; ids[1] = 1338; ids[2] = 1339; ids[3] = 1340; ids[4] = 1341; uint256[] memory mintAmounts = new uint256[](5); mintAmounts[0] = 100; mintAmounts[1] = 200; mintAmounts[2] = 300; mintAmounts[3] = 400; mintAmounts[4] = 500; uint256[] memory transferAmounts = new uint256[](5); transferAmounts[0] = 50; transferAmounts[1] = 100; transferAmounts[2] = 150; transferAmounts[3] = 200; transferAmounts[4] = 250; token.batchMint(from, ids, mintAmounts, ""); hevm.prank(from); token.setApprovalForAll(address(this), true); token.safeBatchTransferFrom(from, address(0), ids, transferAmounts, ""); } function testFailSafeBatchTransferFromToNonERC1155Recipient() public { address from = address(0xABCD); uint256[] memory ids = new uint256[](5); ids[0] = 1337; ids[1] = 1338; ids[2] = 1339; ids[3] = 1340; ids[4] = 1341; uint256[] memory mintAmounts = new uint256[](5); mintAmounts[0] = 100; mintAmounts[1] = 200; mintAmounts[2] = 300; mintAmounts[3] = 400; mintAmounts[4] = 500; uint256[] memory transferAmounts = new uint256[](5); transferAmounts[0] = 50; transferAmounts[1] = 100; transferAmounts[2] = 150; transferAmounts[3] = 200; transferAmounts[4] = 250; token.batchMint(from, ids, mintAmounts, ""); hevm.prank(from); token.setApprovalForAll(address(this), true); token.safeBatchTransferFrom(from, address(new NonERC1155Recipient()), ids, transferAmounts, ""); } function testFailSafeBatchTransferFromToRevertingERC1155Recipient() public { address from = address(0xABCD); uint256[] memory ids = new uint256[](5); ids[0] = 1337; ids[1] = 1338; ids[2] = 1339; ids[3] = 1340; ids[4] = 1341; uint256[] memory mintAmounts = new uint256[](5); mintAmounts[0] = 100; mintAmounts[1] = 200; mintAmounts[2] = 300; mintAmounts[3] = 400; mintAmounts[4] = 500; uint256[] memory transferAmounts = new uint256[](5); transferAmounts[0] = 50; transferAmounts[1] = 100; transferAmounts[2] = 150; transferAmounts[3] = 200; transferAmounts[4] = 250; token.batchMint(from, ids, mintAmounts, ""); hevm.prank(from); token.setApprovalForAll(address(this), true); token.safeBatchTransferFrom(from, address(new RevertingERC1155Recipient()), ids, transferAmounts, ""); } function testFailSafeBatchTransferFromToWrongReturnDataERC1155Recipient() public { address from = address(0xABCD); uint256[] memory ids = new uint256[](5); ids[0] = 1337; ids[1] = 1338; ids[2] = 1339; ids[3] = 1340; ids[4] = 1341; uint256[] memory mintAmounts = new uint256[](5); mintAmounts[0] = 100; mintAmounts[1] = 200; mintAmounts[2] = 300; mintAmounts[3] = 400; mintAmounts[4] = 500; uint256[] memory transferAmounts = new uint256[](5); transferAmounts[0] = 50; transferAmounts[1] = 100; transferAmounts[2] = 150; transferAmounts[3] = 200; transferAmounts[4] = 250; token.batchMint(from, ids, mintAmounts, ""); hevm.prank(from); token.setApprovalForAll(address(this), true); token.safeBatchTransferFrom(from, address(new WrongReturnDataERC1155Recipient()), ids, transferAmounts, ""); } function testFailSafeBatchTransferFromWithArrayLengthMismatch() public { address from = address(0xABCD); uint256[] memory ids = new uint256[](5); ids[0] = 1337; ids[1] = 1338; ids[2] = 1339; ids[3] = 1340; ids[4] = 1341; uint256[] memory mintAmounts = new uint256[](5); mintAmounts[0] = 100; mintAmounts[1] = 200; mintAmounts[2] = 300; mintAmounts[3] = 400; mintAmounts[4] = 500; uint256[] memory transferAmounts = new uint256[](4); transferAmounts[0] = 50; transferAmounts[1] = 100; transferAmounts[2] = 150; transferAmounts[3] = 200; token.batchMint(from, ids, mintAmounts, ""); hevm.prank(from); token.setApprovalForAll(address(this), true); token.safeBatchTransferFrom(from, address(0xBEEF), ids, transferAmounts, ""); } function testFailBatchMintToZero() public { uint256[] memory ids = new uint256[](5); ids[0] = 1337; ids[1] = 1338; ids[2] = 1339; ids[3] = 1340; ids[4] = 1341; uint256[] memory mintAmounts = new uint256[](5); mintAmounts[0] = 100; mintAmounts[1] = 200; mintAmounts[2] = 300; mintAmounts[3] = 400; mintAmounts[4] = 500; token.batchMint(address(0), ids, mintAmounts, ""); } function testFailBatchMintToNonERC1155Recipient() public { NonERC1155Recipient to = new NonERC1155Recipient(); uint256[] memory ids = new uint256[](5); ids[0] = 1337; ids[1] = 1338; ids[2] = 1339; ids[3] = 1340; ids[4] = 1341; uint256[] memory mintAmounts = new uint256[](5); mintAmounts[0] = 100; mintAmounts[1] = 200; mintAmounts[2] = 300; mintAmounts[3] = 400; mintAmounts[4] = 500; token.batchMint(address(to), ids, mintAmounts, ""); } function testFailBatchMintToRevertingERC1155Recipient() public { RevertingERC1155Recipient to = new RevertingERC1155Recipient(); uint256[] memory ids = new uint256[](5); ids[0] = 1337; ids[1] = 1338; ids[2] = 1339; ids[3] = 1340; ids[4] = 1341; uint256[] memory mintAmounts = new uint256[](5); mintAmounts[0] = 100; mintAmounts[1] = 200; mintAmounts[2] = 300; mintAmounts[3] = 400; mintAmounts[4] = 500; token.batchMint(address(to), ids, mintAmounts, ""); } function testFailBatchMintToWrongReturnDataERC1155Recipient() public { WrongReturnDataERC1155Recipient to = new WrongReturnDataERC1155Recipient(); uint256[] memory ids = new uint256[](5); ids[0] = 1337; ids[1] = 1338; ids[2] = 1339; ids[3] = 1340; ids[4] = 1341; uint256[] memory mintAmounts = new uint256[](5); mintAmounts[0] = 100; mintAmounts[1] = 200; mintAmounts[2] = 300; mintAmounts[3] = 400; mintAmounts[4] = 500; token.batchMint(address(to), ids, mintAmounts, ""); } function testFailBatchMintWithArrayMismatch() public { uint256[] memory ids = new uint256[](5); ids[0] = 1337; ids[1] = 1338; ids[2] = 1339; ids[3] = 1340; ids[4] = 1341; uint256[] memory amounts = new uint256[](4); amounts[0] = 100; amounts[1] = 200; amounts[2] = 300; amounts[3] = 400; token.batchMint(address(0xBEEF), ids, amounts, ""); } function testFailBatchBurnInsufficientBalance() public { uint256[] memory ids = new uint256[](5); ids[0] = 1337; ids[1] = 1338; ids[2] = 1339; ids[3] = 1340; ids[4] = 1341; uint256[] memory mintAmounts = new uint256[](5); mintAmounts[0] = 50; mintAmounts[1] = 100; mintAmounts[2] = 150; mintAmounts[3] = 200; mintAmounts[4] = 250; uint256[] memory burnAmounts = new uint256[](5); burnAmounts[0] = 100; burnAmounts[1] = 200; burnAmounts[2] = 300; burnAmounts[3] = 400; burnAmounts[4] = 500; token.batchMint(address(0xBEEF), ids, mintAmounts, ""); token.batchBurn(address(0xBEEF), ids, burnAmounts); } function testFailBatchBurnWithArrayLengthMismatch() public { uint256[] memory ids = new uint256[](5); ids[0] = 1337; ids[1] = 1338; ids[2] = 1339; ids[3] = 1340; ids[4] = 1341; uint256[] memory mintAmounts = new uint256[](5); mintAmounts[0] = 100; mintAmounts[1] = 200; mintAmounts[2] = 300; mintAmounts[3] = 400; mintAmounts[4] = 500; uint256[] memory burnAmounts = new uint256[](4); burnAmounts[0] = 50; burnAmounts[1] = 100; burnAmounts[2] = 150; burnAmounts[3] = 200; token.batchMint(address(0xBEEF), ids, mintAmounts, ""); token.batchBurn(address(0xBEEF), ids, burnAmounts); } function testFailBalanceOfBatchWithArrayMismatch() public view { address[] memory tos = new address[](5); tos[0] = address(0xBEEF); tos[1] = address(0xCAFE); tos[2] = address(0xFACE); tos[3] = address(0xDEAD); tos[4] = address(0xFEED); uint256[] memory ids = new uint256[](4); ids[0] = 1337; ids[1] = 1338; ids[2] = 1339; ids[3] = 1340; token.balanceOfBatch(tos, ids); } function testMintToEOA( address to, uint256 id, uint256 amount, bytes memory mintData ) public { if (to == address(0)) to = address(0xBEEF); if (uint256(uint160(to)) <= 18 || to.code.length > 0) return; token.mint(to, id, amount, mintData); assertEq(token.balanceOf(to, id), amount); } function testMintToERC1155Recipient( uint256 id, uint256 amount, bytes memory mintData ) public { ERC1155Recipient to = new ERC1155Recipient(); token.mint(address(to), id, amount, mintData); assertEq(token.balanceOf(address(to), id), amount); assertEq(to.operator(), address(this)); assertEq(to.from(), address(0)); assertEq(to.id(), id); assertBytesEq(to.mintData(), mintData); } function testBatchMintToEOA( address to, uint256[] memory ids, uint256[] memory amounts, bytes memory mintData ) public { if (to == address(0)) to = address(0xBEEF); if (uint256(uint160(to)) <= 18 || to.code.length > 0) return; uint256 minLength = min2(ids.length, amounts.length); uint256[] memory normalizedIds = new uint256[](minLength); uint256[] memory normalizedAmounts = new uint256[](minLength); for (uint256 i = 0; i < minLength; i++) { uint256 id = ids[i]; uint256 remainingMintAmountForId = type(uint256).max - userMintAmounts[to][id]; uint256 mintAmount = bound(amounts[i], 0, remainingMintAmountForId); normalizedIds[i] = id; normalizedAmounts[i] = mintAmount; userMintAmounts[to][id] += mintAmount; } token.batchMint(to, normalizedIds, normalizedAmounts, mintData); for (uint256 i = 0; i < normalizedIds.length; i++) { uint256 id = normalizedIds[i]; assertEq(token.balanceOf(to, id), userMintAmounts[to][id]); } } function testBatchMintToERC1155Recipient( uint256[] memory ids, uint256[] memory amounts, bytes memory mintData ) public { ERC1155Recipient to = new ERC1155Recipient(); uint256 minLength = min2(ids.length, amounts.length); uint256[] memory normalizedIds = new uint256[](minLength); uint256[] memory normalizedAmounts = new uint256[](minLength); for (uint256 i = 0; i < minLength; i++) { uint256 id = ids[i]; uint256 remainingMintAmountForId = type(uint256).max - userMintAmounts[address(to)][id]; uint256 mintAmount = bound(amounts[i], 0, remainingMintAmountForId); normalizedIds[i] = id; normalizedAmounts[i] = mintAmount; userMintAmounts[address(to)][id] += mintAmount; } token.batchMint(address(to), normalizedIds, normalizedAmounts, mintData); assertEq(to.batchOperator(), address(this)); assertEq(to.batchFrom(), address(0)); assertUintArrayEq(to.batchIds(), normalizedIds); assertUintArrayEq(to.batchAmounts(), normalizedAmounts); assertBytesEq(to.batchData(), mintData); for (uint256 i = 0; i < normalizedIds.length; i++) { uint256 id = normalizedIds[i]; assertEq(token.balanceOf(address(to), id), userMintAmounts[address(to)][id]); } } function testBurn( address to, uint256 id, uint256 mintAmount, bytes memory mintData, uint256 burnAmount ) public { if (to == address(0)) to = address(0xBEEF); if (uint256(uint160(to)) <= 18 || to.code.length > 0) return; burnAmount = bound(burnAmount, 0, mintAmount); token.mint(to, id, mintAmount, mintData); token.burn(to, id, burnAmount); assertEq(token.balanceOf(address(to), id), mintAmount - burnAmount); } function testBatchBurn( address to, uint256[] memory ids, uint256[] memory mintAmounts, uint256[] memory burnAmounts, bytes memory mintData ) public { if (to == address(0)) to = address(0xBEEF); if (uint256(uint160(to)) <= 18 || to.code.length > 0) return; uint256 minLength = min3(ids.length, mintAmounts.length, burnAmounts.length); uint256[] memory normalizedIds = new uint256[](minLength); uint256[] memory normalizedMintAmounts = new uint256[](minLength); uint256[] memory normalizedBurnAmounts = new uint256[](minLength); for (uint256 i = 0; i < minLength; i++) { uint256 id = ids[i]; uint256 remainingMintAmountForId = type(uint256).max - userMintAmounts[address(to)][id]; normalizedIds[i] = id; normalizedMintAmounts[i] = bound(mintAmounts[i], 0, remainingMintAmountForId); normalizedBurnAmounts[i] = bound(burnAmounts[i], 0, normalizedMintAmounts[i]); userMintAmounts[address(to)][id] += normalizedMintAmounts[i]; userTransferOrBurnAmounts[address(to)][id] += normalizedBurnAmounts[i]; } token.batchMint(to, normalizedIds, normalizedMintAmounts, mintData); token.batchBurn(to, normalizedIds, normalizedBurnAmounts); for (uint256 i = 0; i < normalizedIds.length; i++) { uint256 id = normalizedIds[i]; assertEq(token.balanceOf(to, id), userMintAmounts[to][id] - userTransferOrBurnAmounts[to][id]); } } function testApproveAll(address to, bool approved) public { token.setApprovalForAll(to, approved); assertBoolEq(token.isApprovedForAll(address(this), to), approved); } function testSafeTransferFromToEOA( uint256 id, uint256 mintAmount, bytes memory mintData, uint256 transferAmount, address to, bytes memory transferData ) public { if (to == address(0)) to = address(0xBEEF); if (uint256(uint160(to)) <= 18 || to.code.length > 0) return; transferAmount = bound(transferAmount, 0, mintAmount); address from = address(0xABCD); token.mint(from, id, mintAmount, mintData); hevm.prank(from); token.setApprovalForAll(address(this), true); token.safeTransferFrom(from, to, id, transferAmount, transferData); if (to == from) { assertEq(token.balanceOf(to, id), mintAmount); } else { assertEq(token.balanceOf(to, id), transferAmount); assertEq(token.balanceOf(from, id), mintAmount - transferAmount); } } function testSafeTransferFromToERC1155Recipient( uint256 id, uint256 mintAmount, bytes memory mintData, uint256 transferAmount, bytes memory transferData ) public { ERC1155Recipient to = new ERC1155Recipient(); address from = address(0xABCD); transferAmount = bound(transferAmount, 0, mintAmount); token.mint(from, id, mintAmount, mintData); hevm.prank(from); token.setApprovalForAll(address(this), true); token.safeTransferFrom(from, address(to), id, transferAmount, transferData); assertEq(to.operator(), address(this)); assertEq(to.from(), from); assertEq(to.id(), id); assertBytesEq(to.mintData(), transferData); assertEq(token.balanceOf(address(to), id), transferAmount); assertEq(token.balanceOf(from, id), mintAmount - transferAmount); } function testSafeTransferFromSelf( uint256 id, uint256 mintAmount, bytes memory mintData, uint256 transferAmount, address to, bytes memory transferData ) public { if (to == address(0)) to = address(0xBEEF); if (uint256(uint160(to)) <= 18 || to.code.length > 0) return; transferAmount = bound(transferAmount, 0, mintAmount); token.mint(address(this), id, mintAmount, mintData); token.safeTransferFrom(address(this), to, id, transferAmount, transferData); assertEq(token.balanceOf(to, id), transferAmount); assertEq(token.balanceOf(address(this), id), mintAmount - transferAmount); } function testSafeBatchTransferFromToEOA( address to, uint256[] memory ids, uint256[] memory mintAmounts, uint256[] memory transferAmounts, bytes memory mintData, bytes memory transferData ) public { if (to == address(0)) to = address(0xBEEF); if (uint256(uint160(to)) <= 18 || to.code.length > 0) return; address from = address(0xABCD); uint256 minLength = min3(ids.length, mintAmounts.length, transferAmounts.length); uint256[] memory normalizedIds = new uint256[](minLength); uint256[] memory normalizedMintAmounts = new uint256[](minLength); uint256[] memory normalizedTransferAmounts = new uint256[](minLength); for (uint256 i = 0; i < minLength; i++) { uint256 id = ids[i]; uint256 remainingMintAmountForId = type(uint256).max - userMintAmounts[from][id]; uint256 mintAmount = bound(mintAmounts[i], 0, remainingMintAmountForId); uint256 transferAmount = bound(transferAmounts[i], 0, mintAmount); normalizedIds[i] = id; normalizedMintAmounts[i] = mintAmount; normalizedTransferAmounts[i] = transferAmount; userMintAmounts[from][id] += mintAmount; userTransferOrBurnAmounts[from][id] += transferAmount; } token.batchMint(from, normalizedIds, normalizedMintAmounts, mintData); hevm.prank(from); token.setApprovalForAll(address(this), true); token.safeBatchTransferFrom(from, to, normalizedIds, normalizedTransferAmounts, transferData); for (uint256 i = 0; i < normalizedIds.length; i++) { uint256 id = normalizedIds[i]; assertEq(token.balanceOf(address(to), id), userTransferOrBurnAmounts[from][id]); assertEq(token.balanceOf(from, id), userMintAmounts[from][id] - userTransferOrBurnAmounts[from][id]); } } function testSafeBatchTransferFromToERC1155Recipient( uint256[] memory ids, uint256[] memory mintAmounts, uint256[] memory transferAmounts, bytes memory mintData, bytes memory transferData ) public { address from = address(0xABCD); ERC1155Recipient to = new ERC1155Recipient(); uint256 minLength = min3(ids.length, mintAmounts.length, transferAmounts.length); uint256[] memory normalizedIds = new uint256[](minLength); uint256[] memory normalizedMintAmounts = new uint256[](minLength); uint256[] memory normalizedTransferAmounts = new uint256[](minLength); for (uint256 i = 0; i < minLength; i++) { uint256 id = ids[i]; uint256 remainingMintAmountForId = type(uint256).max - userMintAmounts[from][id]; uint256 mintAmount = bound(mintAmounts[i], 0, remainingMintAmountForId); uint256 transferAmount = bound(transferAmounts[i], 0, mintAmount); normalizedIds[i] = id; normalizedMintAmounts[i] = mintAmount; normalizedTransferAmounts[i] = transferAmount; userMintAmounts[from][id] += mintAmount; userTransferOrBurnAmounts[from][id] += transferAmount; } token.batchMint(from, normalizedIds, normalizedMintAmounts, mintData); hevm.prank(from); token.setApprovalForAll(address(this), true); token.safeBatchTransferFrom(from, address(to), normalizedIds, normalizedTransferAmounts, transferData); assertEq(to.batchOperator(), address(this)); assertEq(to.batchFrom(), from); assertUintArrayEq(to.batchIds(), normalizedIds); assertUintArrayEq(to.batchAmounts(), normalizedTransferAmounts); assertBytesEq(to.batchData(), transferData); for (uint256 i = 0; i < normalizedIds.length; i++) { uint256 id = normalizedIds[i]; uint256 transferAmount = userTransferOrBurnAmounts[from][id]; assertEq(token.balanceOf(address(to), id), transferAmount); assertEq(token.balanceOf(from, id), userMintAmounts[from][id] - transferAmount); } } function testBatchBalanceOf( address[] memory tos, uint256[] memory ids, uint256[] memory amounts, bytes memory mintData ) public { uint256 minLength = min3(tos.length, ids.length, amounts.length); address[] memory normalizedTos = new address[](minLength); uint256[] memory normalizedIds = new uint256[](minLength); for (uint256 i = 0; i < minLength; i++) { uint256 id = ids[i]; address to = tos[i] == address(0) || tos[i].code.length > 0 ? address(0xBEEF) : tos[i]; uint256 remainingMintAmountForId = type(uint256).max - userMintAmounts[to][id]; normalizedTos[i] = to; normalizedIds[i] = id; uint256 mintAmount = bound(amounts[i], 0, remainingMintAmountForId); token.mint(to, id, mintAmount, mintData); userMintAmounts[to][id] += mintAmount; } uint256[] memory balances = token.balanceOfBatch(normalizedTos, normalizedIds); for (uint256 i = 0; i < normalizedTos.length; i++) { assertEq(balances[i], token.balanceOf(normalizedTos[i], normalizedIds[i])); } } function testFailMintToZero( uint256 id, uint256 amount, bytes memory data ) public { token.mint(address(0), id, amount, data); } function testFailMintToNonERC155Recipient( uint256 id, uint256 mintAmount, bytes memory mintData ) public { token.mint(address(new NonERC1155Recipient()), id, mintAmount, mintData); } function testFailMintToRevertingERC155Recipient( uint256 id, uint256 mintAmount, bytes memory mintData ) public { token.mint(address(new RevertingERC1155Recipient()), id, mintAmount, mintData); } function testFailMintToWrongReturnDataERC155Recipient( uint256 id, uint256 mintAmount, bytes memory mintData ) public { token.mint(address(new RevertingERC1155Recipient()), id, mintAmount, mintData); } function testFailBurnInsufficientBalance( address to, uint256 id, uint256 mintAmount, uint256 burnAmount, bytes memory mintData ) public { burnAmount = bound(burnAmount, mintAmount + 1, type(uint256).max); token.mint(to, id, mintAmount, mintData); token.burn(to, id, burnAmount); } function testFailSafeTransferFromInsufficientBalance( address to, uint256 id, uint256 mintAmount, uint256 transferAmount, bytes memory mintData, bytes memory transferData ) public { address from = address(0xABCD); transferAmount = bound(transferAmount, mintAmount + 1, type(uint256).max); token.mint(from, id, mintAmount, mintData); hevm.prank(from); token.setApprovalForAll(address(this), true); token.safeTransferFrom(from, to, id, transferAmount, transferData); } function testFailSafeTransferFromSelfInsufficientBalance( address to, uint256 id, uint256 mintAmount, uint256 transferAmount, bytes memory mintData, bytes memory transferData ) public { transferAmount = bound(transferAmount, mintAmount + 1, type(uint256).max); token.mint(address(this), id, mintAmount, mintData); token.safeTransferFrom(address(this), to, id, transferAmount, transferData); } function testFailSafeTransferFromToZero( uint256 id, uint256 mintAmount, uint256 transferAmount, bytes memory mintData, bytes memory transferData ) public { transferAmount = bound(transferAmount, 0, mintAmount); token.mint(address(this), id, mintAmount, mintData); token.safeTransferFrom(address(this), address(0), id, transferAmount, transferData); } function testFailSafeTransferFromToNonERC155Recipient( uint256 id, uint256 mintAmount, uint256 transferAmount, bytes memory mintData, bytes memory transferData ) public { transferAmount = bound(transferAmount, 0, mintAmount); token.mint(address(this), id, mintAmount, mintData); token.safeTransferFrom(address(this), address(new NonERC1155Recipient()), id, transferAmount, transferData); } function testFailSafeTransferFromToRevertingERC1155Recipient( uint256 id, uint256 mintAmount, uint256 transferAmount, bytes memory mintData, bytes memory transferData ) public { transferAmount = bound(transferAmount, 0, mintAmount); token.mint(address(this), id, mintAmount, mintData); token.safeTransferFrom( address(this), address(new RevertingERC1155Recipient()), id, transferAmount, transferData ); } function testFailSafeTransferFromToWrongReturnDataERC1155Recipient( uint256 id, uint256 mintAmount, uint256 transferAmount, bytes memory mintData, bytes memory transferData ) public { transferAmount = bound(transferAmount, 0, mintAmount); token.mint(address(this), id, mintAmount, mintData); token.safeTransferFrom( address(this), address(new WrongReturnDataERC1155Recipient()), id, transferAmount, transferData ); } function testFailSafeBatchTransferInsufficientBalance( address to, uint256[] memory ids, uint256[] memory mintAmounts, uint256[] memory transferAmounts, bytes memory mintData, bytes memory transferData ) public { address from = address(0xABCD); uint256 minLength = min3(ids.length, mintAmounts.length, transferAmounts.length); if (minLength == 0) revert(); uint256[] memory normalizedIds = new uint256[](minLength); uint256[] memory normalizedMintAmounts = new uint256[](minLength); uint256[] memory normalizedTransferAmounts = new uint256[](minLength); for (uint256 i = 0; i < minLength; i++) { uint256 id = ids[i]; uint256 remainingMintAmountForId = type(uint256).max - userMintAmounts[from][id]; uint256 mintAmount = bound(mintAmounts[i], 0, remainingMintAmountForId); uint256 transferAmount = bound(transferAmounts[i], mintAmount + 1, type(uint256).max); normalizedIds[i] = id; normalizedMintAmounts[i] = mintAmount; normalizedTransferAmounts[i] = transferAmount; userMintAmounts[from][id] += mintAmount; } token.batchMint(from, normalizedIds, normalizedMintAmounts, mintData); hevm.prank(from); token.setApprovalForAll(address(this), true); token.safeBatchTransferFrom(from, to, normalizedIds, normalizedTransferAmounts, transferData); } function testFailSafeBatchTransferFromToZero( uint256[] memory ids, uint256[] memory mintAmounts, uint256[] memory transferAmounts, bytes memory mintData, bytes memory transferData ) public { address from = address(0xABCD); uint256 minLength = min3(ids.length, mintAmounts.length, transferAmounts.length); uint256[] memory normalizedIds = new uint256[](minLength); uint256[] memory normalizedMintAmounts = new uint256[](minLength); uint256[] memory normalizedTransferAmounts = new uint256[](minLength); for (uint256 i = 0; i < minLength; i++) { uint256 id = ids[i]; uint256 remainingMintAmountForId = type(uint256).max - userMintAmounts[from][id]; uint256 mintAmount = bound(mintAmounts[i], 0, remainingMintAmountForId); uint256 transferAmount = bound(transferAmounts[i], 0, mintAmount); normalizedIds[i] = id; normalizedMintAmounts[i] = mintAmount; normalizedTransferAmounts[i] = transferAmount; userMintAmounts[from][id] += mintAmount; } token.batchMint(from, normalizedIds, normalizedMintAmounts, mintData); hevm.prank(from); token.setApprovalForAll(address(this), true); token.safeBatchTransferFrom(from, address(0), normalizedIds, normalizedTransferAmounts, transferData); } function testFailSafeBatchTransferFromToNonERC1155Recipient( uint256[] memory ids, uint256[] memory mintAmounts, uint256[] memory transferAmounts, bytes memory mintData, bytes memory transferData ) public { address from = address(0xABCD); uint256 minLength = min3(ids.length, mintAmounts.length, transferAmounts.length); uint256[] memory normalizedIds = new uint256[](minLength); uint256[] memory normalizedMintAmounts = new uint256[](minLength); uint256[] memory normalizedTransferAmounts = new uint256[](minLength); for (uint256 i = 0; i < minLength; i++) { uint256 id = ids[i]; uint256 remainingMintAmountForId = type(uint256).max - userMintAmounts[from][id]; uint256 mintAmount = bound(mintAmounts[i], 0, remainingMintAmountForId); uint256 transferAmount = bound(transferAmounts[i], 0, mintAmount); normalizedIds[i] = id; normalizedMintAmounts[i] = mintAmount; normalizedTransferAmounts[i] = transferAmount; userMintAmounts[from][id] += mintAmount; } token.batchMint(from, normalizedIds, normalizedMintAmounts, mintData); hevm.prank(from); token.setApprovalForAll(address(this), true); token.safeBatchTransferFrom( from, address(new NonERC1155Recipient()), normalizedIds, normalizedTransferAmounts, transferData ); } function testFailSafeBatchTransferFromToRevertingERC1155Recipient( uint256[] memory ids, uint256[] memory mintAmounts, uint256[] memory transferAmounts, bytes memory mintData, bytes memory transferData ) public { address from = address(0xABCD); uint256 minLength = min3(ids.length, mintAmounts.length, transferAmounts.length); uint256[] memory normalizedIds = new uint256[](minLength); uint256[] memory normalizedMintAmounts = new uint256[](minLength); uint256[] memory normalizedTransferAmounts = new uint256[](minLength); for (uint256 i = 0; i < minLength; i++) { uint256 id = ids[i]; uint256 remainingMintAmountForId = type(uint256).max - userMintAmounts[from][id]; uint256 mintAmount = bound(mintAmounts[i], 0, remainingMintAmountForId); uint256 transferAmount = bound(transferAmounts[i], 0, mintAmount); normalizedIds[i] = id; normalizedMintAmounts[i] = mintAmount; normalizedTransferAmounts[i] = transferAmount; userMintAmounts[from][id] += mintAmount; } token.batchMint(from, normalizedIds, normalizedMintAmounts, mintData); hevm.prank(from); token.setApprovalForAll(address(this), true); token.safeBatchTransferFrom( from, address(new RevertingERC1155Recipient()), normalizedIds, normalizedTransferAmounts, transferData ); } function testFailSafeBatchTransferFromToWrongReturnDataERC1155Recipient( uint256[] memory ids, uint256[] memory mintAmounts, uint256[] memory transferAmounts, bytes memory mintData, bytes memory transferData ) public { address from = address(0xABCD); uint256 minLength = min3(ids.length, mintAmounts.length, transferAmounts.length); uint256[] memory normalizedIds = new uint256[](minLength); uint256[] memory normalizedMintAmounts = new uint256[](minLength); uint256[] memory normalizedTransferAmounts = new uint256[](minLength); for (uint256 i = 0; i < minLength; i++) { uint256 id = ids[i]; uint256 remainingMintAmountForId = type(uint256).max - userMintAmounts[from][id]; uint256 mintAmount = bound(mintAmounts[i], 0, remainingMintAmountForId); uint256 transferAmount = bound(transferAmounts[i], 0, mintAmount); normalizedIds[i] = id; normalizedMintAmounts[i] = mintAmount; normalizedTransferAmounts[i] = transferAmount; userMintAmounts[from][id] += mintAmount; } token.batchMint(from, normalizedIds, normalizedMintAmounts, mintData); hevm.prank(from); token.setApprovalForAll(address(this), true); token.safeBatchTransferFrom( from, address(new WrongReturnDataERC1155Recipient()), normalizedIds, normalizedTransferAmounts, transferData ); } function testFailSafeBatchTransferFromWithArrayLengthMismatch( address to, uint256[] memory ids, uint256[] memory mintAmounts, uint256[] memory transferAmounts, bytes memory mintData, bytes memory transferData ) public { address from = address(0xABCD); if (ids.length == transferAmounts.length) revert(); token.batchMint(from, ids, mintAmounts, mintData); hevm.prank(from); token.setApprovalForAll(address(this), true); token.safeBatchTransferFrom(from, to, ids, transferAmounts, transferData); } function testFailBatchMintToZero( uint256[] memory ids, uint256[] memory amounts, bytes memory mintData ) public { uint256 minLength = min2(ids.length, amounts.length); uint256[] memory normalizedIds = new uint256[](minLength); uint256[] memory normalizedAmounts = new uint256[](minLength); for (uint256 i = 0; i < minLength; i++) { uint256 id = ids[i]; uint256 remainingMintAmountForId = type(uint256).max - userMintAmounts[address(0)][id]; uint256 mintAmount = bound(amounts[i], 0, remainingMintAmountForId); normalizedIds[i] = id; normalizedAmounts[i] = mintAmount; userMintAmounts[address(0)][id] += mintAmount; } token.batchMint(address(0), normalizedIds, normalizedAmounts, mintData); } function testFailBatchMintToNonERC1155Recipient( uint256[] memory ids, uint256[] memory amounts, bytes memory mintData ) public { NonERC1155Recipient to = new NonERC1155Recipient(); uint256 minLength = min2(ids.length, amounts.length); uint256[] memory normalizedIds = new uint256[](minLength); uint256[] memory normalizedAmounts = new uint256[](minLength); for (uint256 i = 0; i < minLength; i++) { uint256 id = ids[i]; uint256 remainingMintAmountForId = type(uint256).max - userMintAmounts[address(to)][id]; uint256 mintAmount = bound(amounts[i], 0, remainingMintAmountForId); normalizedIds[i] = id; normalizedAmounts[i] = mintAmount; userMintAmounts[address(to)][id] += mintAmount; } token.batchMint(address(to), normalizedIds, normalizedAmounts, mintData); } function testFailBatchMintToRevertingERC1155Recipient( uint256[] memory ids, uint256[] memory amounts, bytes memory mintData ) public { RevertingERC1155Recipient to = new RevertingERC1155Recipient(); uint256 minLength = min2(ids.length, amounts.length); uint256[] memory normalizedIds = new uint256[](minLength); uint256[] memory normalizedAmounts = new uint256[](minLength); for (uint256 i = 0; i < minLength; i++) { uint256 id = ids[i]; uint256 remainingMintAmountForId = type(uint256).max - userMintAmounts[address(to)][id]; uint256 mintAmount = bound(amounts[i], 0, remainingMintAmountForId); normalizedIds[i] = id; normalizedAmounts[i] = mintAmount; userMintAmounts[address(to)][id] += mintAmount; } token.batchMint(address(to), normalizedIds, normalizedAmounts, mintData); } function testFailBatchMintToWrongReturnDataERC1155Recipient( uint256[] memory ids, uint256[] memory amounts, bytes memory mintData ) public { WrongReturnDataERC1155Recipient to = new WrongReturnDataERC1155Recipient(); uint256 minLength = min2(ids.length, amounts.length); uint256[] memory normalizedIds = new uint256[](minLength); uint256[] memory normalizedAmounts = new uint256[](minLength); for (uint256 i = 0; i < minLength; i++) { uint256 id = ids[i]; uint256 remainingMintAmountForId = type(uint256).max - userMintAmounts[address(to)][id]; uint256 mintAmount = bound(amounts[i], 0, remainingMintAmountForId); normalizedIds[i] = id; normalizedAmounts[i] = mintAmount; userMintAmounts[address(to)][id] += mintAmount; } token.batchMint(address(to), normalizedIds, normalizedAmounts, mintData); } function testFailBatchMintWithArrayMismatch( address to, uint256[] memory ids, uint256[] memory amounts, bytes memory mintData ) public { if (ids.length == amounts.length) revert(); token.batchMint(address(to), ids, amounts, mintData); } function testFailBatchBurnInsufficientBalance( address to, uint256[] memory ids, uint256[] memory mintAmounts, uint256[] memory burnAmounts, bytes memory mintData ) public { uint256 minLength = min3(ids.length, mintAmounts.length, burnAmounts.length); if (minLength == 0) revert(); uint256[] memory normalizedIds = new uint256[](minLength); uint256[] memory normalizedMintAmounts = new uint256[](minLength); uint256[] memory normalizedBurnAmounts = new uint256[](minLength); for (uint256 i = 0; i < minLength; i++) { uint256 id = ids[i]; uint256 remainingMintAmountForId = type(uint256).max - userMintAmounts[to][id]; normalizedIds[i] = id; normalizedMintAmounts[i] = bound(mintAmounts[i], 0, remainingMintAmountForId); normalizedBurnAmounts[i] = bound(burnAmounts[i], normalizedMintAmounts[i] + 1, type(uint256).max); userMintAmounts[to][id] += normalizedMintAmounts[i]; } token.batchMint(to, normalizedIds, normalizedMintAmounts, mintData); token.batchBurn(to, normalizedIds, normalizedBurnAmounts); } function testFailBatchBurnWithArrayLengthMismatch( address to, uint256[] memory ids, uint256[] memory mintAmounts, uint256[] memory burnAmounts, bytes memory mintData ) public { if (ids.length == burnAmounts.length) revert(); token.batchMint(to, ids, mintAmounts, mintData); token.batchBurn(to, ids, burnAmounts); } function testFailBalanceOfBatchWithArrayMismatch(address[] memory tos, uint256[] memory ids) public view { if (tos.length == ids.length) revert(); token.balanceOfBatch(tos, ids); } }