From ea32b38c9f6faf45b792f2331e9d49ff668953a7 Mon Sep 17 00:00:00 2001 From: Stanley Date: Tue, 10 Sep 2024 15:17:18 -0400 Subject: [PATCH] ERC1155 tests pass --- remappings.txt | 1 - .../immutable/ImmutableAllowlistERC1155.sol | 2 +- .../immutable/ImmutableAllowlistERC1155.t.sol | 320 ++++++++++++++++++ .../immutable/ImmutableAllowlistERC721.t.sol | 6 - test/module/minting/ClaimableERC1155.t.sol | 2 - 5 files changed, 321 insertions(+), 10 deletions(-) create mode 100644 test/module/immutable/ImmutableAllowlistERC1155.t.sol diff --git a/remappings.txt b/remappings.txt index 86346b81..413cecc2 100644 --- a/remappings.txt +++ b/remappings.txt @@ -5,4 +5,3 @@ forge-std/=lib/forge-std/src/ @erc721a-upgradeable/=lib/ERC721A-Upgradeable/contracts/ @limitbreak/creator-token-standards/=lib/creator-token-standards/src/ @limitbreak/permit-c/=lib/PermitC/src/ -@imtbl/contracts/=lib/contracts.git/contracts/ diff --git a/src/module/token/immutable/ImmutableAllowlistERC1155.sol b/src/module/token/immutable/ImmutableAllowlistERC1155.sol index 75137596..1fcffaa4 100644 --- a/src/module/token/immutable/ImmutableAllowlistERC1155.sol +++ b/src/module/token/immutable/ImmutableAllowlistERC1155.sol @@ -51,7 +51,7 @@ contract ImmutableAllowlistERC1155 is config.fallbackFunctions[1] = FallbackFunction({selector: this.operatorAllowlist.selector, permissionBits: 0}); config.requiredInterfaces = new bytes4[](1); - config.requiredInterfaces[0] = 0x80ac58cd; // ERC1155 + config.requiredInterfaces[0] = 0xd9b67a26; // ERC1155 config.registerInstallationCallback = true; } diff --git a/test/module/immutable/ImmutableAllowlistERC1155.t.sol b/test/module/immutable/ImmutableAllowlistERC1155.t.sol new file mode 100644 index 00000000..b229d1d3 --- /dev/null +++ b/test/module/immutable/ImmutableAllowlistERC1155.t.sol @@ -0,0 +1,320 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.20; + +import "lib/forge-std/src/console.sol"; + +import {Test} from "forge-std/Test.sol"; +import {Role} from "src/Role.sol"; + +// Target contract + +import {Module} from "src/Module.sol"; +import {ERC1155Core} from "src/core/token/ERC1155Core.sol"; + +import {ICore} from "src/interface/ICore.sol"; +import {IModuleConfig} from "src/interface/IModuleConfig.sol"; +import {ImmutableAllowlistERC1155} from "src/module/token/immutable/ImmutableAllowlistERC1155.sol"; + +import {OperatorAllowlistEnforced} from "dependecies/immutable/allowlist/OperatorAllowlistEnforced.sol"; +import {OperatorAllowlistEnforcementErrors} from "dependecies/immutable/errors/Errors.sol"; +import {OperatorAllowlist} from "dependecies/immutable/test/allowlist/OperatorAllowlist.sol"; + +contract Core is ERC1155Core { + + constructor( + string memory name, + string memory symbol, + string memory contractURI, + address owner, + address[] memory modules, + bytes[] memory moduleInstallData + ) ERC1155Core(name, symbol, contractURI, owner, modules, moduleInstallData) {} + + // disable mint, approve and tokenId callbacks for these tests + function _beforeMint(address to, uint256 tokenId, uint256 value, bytes memory data) internal override {} + + function _updateTokenId(uint256 tokenId) internal override returns (uint256) { + return tokenId; + } + +} + +contract DummyContract { + + ERC1155Core public immutable erc1155Core; + + constructor(address payable _erc1155Core) { + erc1155Core = ERC1155Core(_erc1155Core); + } + + // Implement the IERC1155Receiver functions to accept ERC1155 tokens + + function onERC1155Received(address operator, address from, uint256 id, uint256 value, bytes calldata data) + external + returns (bytes4) + { + return this.onERC1155Received.selector; + } + + function onERC1155BatchReceived( + address operator, + address from, + uint256[] calldata ids, + uint256[] calldata values, + bytes calldata data + ) external returns (bytes4) { + return this.onERC1155BatchReceived.selector; + } + + // Required to declare support for the ERC1155Receiver interface + function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) { + return interfaceId == 0x4e2312e0; + } + + // Set approval for the operator to manage tokens + function setApprovalForAll(address _operator) external { + erc1155Core.setApprovalForAll(_operator, true); + } + + // Transfer a single token + function transfer(address _to, uint256 _tokenId) external { + erc1155Core.safeTransferFrom(address(this), _to, _tokenId, 1, ""); + } + + // Batch transfer multiple tokens + function batchTransfer(address _to, uint256[] calldata tokenIds, uint256[] calldata amounts) external { + erc1155Core.safeBatchTransferFrom(address(this), _to, tokenIds, amounts, ""); + } + +} + +contract ImmutableAllowlistERC1155Test is Test { + + Core public core; + + ImmutableAllowlistERC1155 public immutableAllowlistModule; + OperatorAllowlist public operatorAllowlist; + DummyContract public dummyContract1; + DummyContract public dummyContract2; + + address public owner = address(0x1); + address public actorOne = address(0x2); + address public actorTwo = address(0x3); + address public actorThree = address(0x4); + + event OperatorAllowlistRegistryUpdated(address oldRegistry, address newRegistry); + + function setUp() public { + address[] memory modules; + bytes[] memory moduleData; + + core = new Core("test", "TEST", "", owner, modules, moduleData); + immutableAllowlistModule = new ImmutableAllowlistERC1155(); + + vm.prank(owner); + operatorAllowlist = new OperatorAllowlist(owner); + + // install module + vm.startPrank(owner); + bytes memory encodedOperatorAllowlist = + immutableAllowlistModule.encodeBytesOnInstall(address(operatorAllowlist)); + core.installModule(address(immutableAllowlistModule), encodedOperatorAllowlist); + vm.stopPrank(); + + // set registrar role for owner + vm.prank(owner); + operatorAllowlist.grantRegistrarRole(owner); + + // deploy dummy contract + dummyContract1 = new DummyContract(payable(address(core))); + dummyContract2 = new DummyContract(payable(address(core))); + + // mint tokens + core.mint(actorOne, 0, 1, string(""), ""); // tokenId 0 + core.mint(actorTwo, 1, 1, string(""), ""); // tokenId 1 + core.mint(actorThree, 3, 1, string(""), ""); // tokenId 2 + + vm.prank(owner); + core.grantRoles(owner, Role._MANAGER_ROLE); + } + + function allowlist(address _target) internal { + address[] memory allowlist = new address[](1); + allowlist[0] = _target; + vm.prank(owner); + operatorAllowlist.addAddressToAllowlist(allowlist); + } + + /*/////////////////////////////////////////////////////////////// + Unit tests: `setOperatorAllowlistRegistry` + //////////////////////////////////////////////////////////////*/ + + function test_state_setOperatorAllowlistRegistry() public { + OperatorAllowlist operatorAllowlist2 = new OperatorAllowlist(owner); + + vm.prank(owner); + vm.expectEmit(true, true, true, true); + emit OperatorAllowlistRegistryUpdated(address(operatorAllowlist), address(operatorAllowlist2)); + ImmutableAllowlistERC1155(address(core)).setOperatorAllowlistRegistry(address(operatorAllowlist2)); + + assertEq(ImmutableAllowlistERC1155(address(core)).operatorAllowlist(), address(operatorAllowlist2)); + } + + function test_revert_setOperatorAllowlistRegistry() public { + vm.prank(owner); + // should revert since the allowlist does not implement the IOperatorAllowlist interface + // and that it doesn't implement supportsInterface + vm.expectRevert(); + ImmutableAllowlistERC1155(address(core)).setOperatorAllowlistRegistry(address(0x123)); + } + + /*/////////////////////////////////////////////////////////////// + Unit tests: `beforeApproveForAll` + //////////////////////////////////////////////////////////////*/ + + function test_state_beforeApproveForAllERC1155() public { + // passes when msg.sender is an EOA and targetApproval is an EOA + vm.prank(actorOne); + core.setApprovalForAll(actorTwo, true); + + // set allowlist for dummy contract + address[] memory allowlist = new address[](3); + allowlist[0] = address(dummyContract1); + allowlist[1] = address(dummyContract2); + allowlist[2] = address(actorThree); + vm.prank(owner); + operatorAllowlist.addAddressToAllowlist(allowlist); + + vm.startPrank(actorThree); + core.mint(actorThree, 3, 1, string(""), ""); // tokenId 3 + core.safeTransferFrom(actorThree, address(dummyContract1), 3, 1, ""); + vm.stopPrank(); + + // passes when msg.sender is a contract and is allowlisted + // and when targetApproval is a contract and is allowlisted + dummyContract1.setApprovalForAll(address(dummyContract2)); + } + + function test_revert_beforeApproveForAllERC1155() public { + vm.prank(actorOne); + vm.expectRevert( + abi.encodeWithSelector( + OperatorAllowlistEnforcementErrors.ApproveTargetNotInAllowlist.selector, address(dummyContract1) + ) + ); + core.setApprovalForAll(address(dummyContract1), true); + } + + /*/////////////////////////////////////////////////////////////// + Unit tests: `beforeTransferERC1155` + //////////////////////////////////////////////////////////////*/ + + function test_state_beforeTransferERC1155() public { + // set allowlist + address[] memory allowlist = new address[](5); + allowlist[0] = address(dummyContract1); + allowlist[1] = address(dummyContract2); + allowlist[2] = address(actorOne); + allowlist[3] = address(actorTwo); + allowlist[4] = address(actorThree); + vm.prank(owner); + operatorAllowlist.addAddressToAllowlist(allowlist); + + vm.prank(actorOne); + core.safeTransferFrom(actorOne, actorTwo, 0, 1, ""); + + // passes when msg.sender is an EOA and targetApproval is a contract and is allowlisted + core.mint(actorThree, 3, 1, string(""), ""); // tokenId 3 + vm.startPrank(actorThree); + core.safeTransferFrom(actorThree, address(dummyContract1), 3, 1, ""); + vm.stopPrank(); + + // passes when msg.sender is a contract and is allowlisted + // and when targetApproval is a contract and is allowlisted + dummyContract1.transfer(address(dummyContract2), 3); + } + + function test_revert_beforeTransferERC1155() public { + // fails when msg.sender is not allowlisted + vm.prank(actorOne); + vm.expectRevert( + abi.encodeWithSelector(OperatorAllowlistEnforcementErrors.CallerNotInAllowlist.selector, actorOne) + ); + core.safeTransferFrom(actorOne, actorTwo, 0, 1, ""); + + // fails when target is not allowlisted + allowlist(actorOne); + vm.prank(actorOne); + vm.expectRevert( + abi.encodeWithSelector( + OperatorAllowlistEnforcementErrors.TransferToNotInAllowlist.selector, address(dummyContract1) + ) + ); + core.safeTransferFrom(actorOne, address(dummyContract1), 0, 1, ""); + } + + /*/////////////////////////////////////////////////////////////// + Unit tests: `beforeTransferERC1155` + //////////////////////////////////////////////////////////////*/ + + function test_state_beforeBatchTransferERC1155() public { + // set allowlist + address[] memory allowlist = new address[](5); + allowlist[0] = address(dummyContract1); + allowlist[1] = address(dummyContract2); + allowlist[2] = address(actorOne); + allowlist[3] = address(actorTwo); + allowlist[4] = address(actorThree); + vm.prank(owner); + operatorAllowlist.addAddressToAllowlist(allowlist); + + uint256[] memory tokenIds = new uint256[](1); + tokenIds[0] = 0; + uint256[] memory amounts = new uint256[](1); + amounts[0] = 1; + vm.prank(actorOne); + core.safeBatchTransferFrom(actorOne, actorTwo, tokenIds, amounts, ""); + + // passes when msg.sender is an EOA and targetApproval is a contract and is allowlisted + core.mint(actorThree, 3, 1, string(""), ""); // tokenId 3 + vm.startPrank(actorThree); + core.safeTransferFrom(actorThree, address(dummyContract1), 3, 1, ""); + vm.stopPrank(); + + // passes when msg.sender is a contract and is allowlisted + // and when targetApproval is a contract and is allowlisted + uint256[] memory _tokenIds = new uint256[](1); + tokenIds[0] = 3; + uint256[] memory _amounts = new uint256[](1); + amounts[0] = 1; + dummyContract1.batchTransfer(address(dummyContract2), _tokenIds, _amounts); + } + + function test_revert_beforeBatchTransferERC1155() public { + // fails when msg.sender is not allowlisted + uint256[] memory tokenIds = new uint256[](1); + tokenIds[0] = 0; + uint256[] memory amounts = new uint256[](1); + amounts[0] = 1; + vm.prank(actorOne); + vm.expectRevert( + abi.encodeWithSelector(OperatorAllowlistEnforcementErrors.CallerNotInAllowlist.selector, actorOne) + ); + core.safeBatchTransferFrom(actorOne, actorTwo, tokenIds, amounts, ""); + + // fails when target is not allowlisted + uint256[] memory _tokenIds = new uint256[](1); + tokenIds[0] = 3; + uint256[] memory _amounts = new uint256[](1); + amounts[0] = 1; + allowlist(actorOne); + vm.prank(actorOne); + vm.expectRevert( + abi.encodeWithSelector( + OperatorAllowlistEnforcementErrors.TransferToNotInAllowlist.selector, address(dummyContract1) + ) + ); + core.safeBatchTransferFrom(actorOne, address(dummyContract1), _tokenIds, _amounts, ""); + } + +} diff --git a/test/module/immutable/ImmutableAllowlistERC721.t.sol b/test/module/immutable/ImmutableAllowlistERC721.t.sol index 3f09b74f..1750299c 100644 --- a/test/module/immutable/ImmutableAllowlistERC721.t.sol +++ b/test/module/immutable/ImmutableAllowlistERC721.t.sol @@ -259,10 +259,4 @@ contract ImmutableAllowlistERC721Test is Test { core.transferFrom(actorOne, address(dummyContract1), 0); } - /// @notice Callback function for ERC721.setApprovalForAll - function beforeApproveForAll(address _from, address _to, bool _approved) external returns (bytes memory) {} - - /// @notice Callback function for ERC721.transferFrom/safeTransferFrom - function beforeTransferERC721(address _from, address _to, uint256 _tokenId) external returns (bytes memory) {} - } diff --git a/test/module/minting/ClaimableERC1155.t.sol b/test/module/minting/ClaimableERC1155.t.sol index c8107c0f..620cdfd9 100644 --- a/test/module/minting/ClaimableERC1155.t.sol +++ b/test/module/minting/ClaimableERC1155.t.sol @@ -293,8 +293,6 @@ contract ClaimableERC1155Test is Test { uid: bytes32("1") }); bytes memory sig = signMintRequest(claimRequest, permissionedActorPrivateKey); - console.log("permissoned actor address"); - console.logAddress(permissionedActor); uint256 balBefore = tokenRecipient.balance; assertEq(balBefore, 100 ether);