Skip to content

Commit

Permalink
test: add 'withdrawERC1155' unit concrete tests
Browse files Browse the repository at this point in the history
  • Loading branch information
gabrielstoica committed Sep 3, 2024
1 parent 574c10d commit bfe8461
Show file tree
Hide file tree
Showing 6 changed files with 176 additions and 3 deletions.
3 changes: 3 additions & 0 deletions test/Base.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { ModuleKeeper } from "./../src/ModuleKeeper.sol";
import { DockRegistry } from "./../src/DockRegistry.sol";
import { ERC1967Proxy } from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol";
import { MockERC721Collection } from "./mocks/MockERC721Collection.sol";
import { MockERC1155Collection } from "./mocks/MockERC1155Collection.sol";

abstract contract Base_Test is Test, Events {
/*//////////////////////////////////////////////////////////////////////////
Expand All @@ -33,6 +34,7 @@ abstract contract Base_Test is Test, Events {
MockNonCompliantContainer internal mockNonCompliantContainer;
MockBadReceiver internal mockBadReceiver;
MockERC721Collection internal mockERC721;
MockERC1155Collection internal mockERC1155;

/*//////////////////////////////////////////////////////////////////////////
TEST STORAGE
Expand Down Expand Up @@ -62,6 +64,7 @@ abstract contract Base_Test is Test, Events {
mockNonCompliantContainer = new MockNonCompliantContainer({ _owner: users.admin });
mockBadReceiver = new MockBadReceiver();
mockERC721 = new MockERC721Collection("MockERC721Collection", "MC");
mockERC1155 = new MockERC1155Collection("https://nft.com/0x1.json");

// Create a mock modules array
mockModules.push(address(mockModule));
Expand Down
60 changes: 60 additions & 0 deletions test/mocks/MockERC1155Collection.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.26;

import { ERC1155 } from "@openzeppelin/contracts/token/ERC1155/ERC1155.sol";

/// @notice A mock implementation of ERC-1155 that implements the {IERC1155} interface
contract MockERC1155Collection is ERC1155 {
uint256 private _tokenTypeIdCounter;

constructor(string memory uri) ERC1155(uri) {
// Start the token type ID counter at 1
_tokenTypeIdCounter = 1;
}

function mint(address to, uint256 amount) public returns (uint256) {
// Generate a new token ID
uint256 tokenId = _tokenTypeIdCounter;

// Mint the token to the specified address
_mint(to, tokenId, amount, "");

// Increment the token ID counter
unchecked {
_tokenTypeIdCounter++;
}

// Return the token ID
return tokenId;
}

function mintBatch(address to, uint256[] memory amounts) public returns (uint256[] memory) {
// Create a new array to store the token IDs
uint256 cachedAmount = amounts.length;
uint256[] memory tokenIds = new uint256[](cachedAmount);

for (uint256 i; i < cachedAmount; ++i) {
// Generate a new token ID for each amount
tokenIds[i] = _tokenTypeIdCounter;

// Increment the token ID counter
unchecked {
++_tokenTypeIdCounter;
}
}

// Mint the tokens to the specified address
_mintBatch(to, tokenIds, amounts, "");

// Return the token IDs
return tokenIds;
}

function burn(uint256 tokenId, uint256 amount) public {
_burn(msg.sender, tokenId, amount);
}

function burnBatch(uint256[] memory tokenIds, uint256[] memory amounts) public {
_burnBatch(msg.sender, tokenIds, amounts);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.26;

import { Container_Unit_Concrete_Test } from "../Container.t.sol";
import { Errors } from "../../../../utils/Errors.sol";
import { Events } from "../../../../utils/Events.sol";
import { IERC1155 } from "@openzeppelin/contracts/interfaces/IERC1155.sol";

contract WithdrawERC1155_Unit_Concrete_Test is Container_Unit_Concrete_Test {
uint256[] ids;
uint256[] amounts;

function setUp() public virtual override {
Container_Unit_Concrete_Test.setUp();

ids = new uint256[](2);
amounts = new uint256[](2);

ids[0] = 1;
ids[1] = 2;
amounts[0] = 100;
amounts[1] = 200;
}

function test_RevertWhen_CallerNotOwner() external {
// Make Bob the caller for this test suite who is not the owner of the container
vm.startPrank({ msgSender: users.bob });

// Expect the next call to revert with the {CallerNotContainerOwner} error
vm.expectRevert(Errors.CallerNotContainerOwner.selector);

// Run the test
container.withdrawERC1155({ collection: IERC1155(address(0x0)), ids: ids, amounts: amounts });
}

modifier whenCallerOwner() {
// Make Eve the caller for the next test suite as she's the owner of the container
vm.startPrank({ msgSender: users.eve });
_;
}

function test_RevertWhen_InsufficientERC1155Balance() external whenCallerOwner {
// Expect the next call to revert with the {ERC1155InsufficientBalance} error
vm.expectRevert(
abi.encodeWithSelector(
Errors.ERC1155InsufficientBalance.selector, address(container), 0, amounts[0], ids[0]
)
);

// Run the test by attempting to withdraw a nonexistent ERC1155 token
container.withdrawERC1155({ collection: mockERC1155, ids: ids, amounts: amounts });
}

modifier whenExistingERC1155Token() {
// Mint 100 ERC1155 tokens to the container contract
mockERC1155.mintBatch({ to: address(container), amounts: amounts });
_;
}

function test_WithdrawERC1155() external whenCallerOwner whenExistingERC1155Token {
uint256[] memory idsToWithdraw = new uint256[](1);
uint256[] memory amountsToWithdraw = new uint256[](1);
idsToWithdraw[0] = 1;
amountsToWithdraw[0] = 100;

// Expect the {ERC721Withdrawn} event to be emitted
vm.expectEmit();
emit Events.ERC1155Withdrawn({
to: users.eve,
collection: address(mockERC1155),
ids: idsToWithdraw,
amounts: amountsToWithdraw
});

// Run the test
container.withdrawERC1155({ collection: mockERC1155, ids: idsToWithdraw, amounts: amountsToWithdraw });

// Assert the actual and expected token type 1 ERC1155 balance of Eve
uint256 actualBalanceOfEve = mockERC1155.balanceOf(users.eve, idsToWithdraw[0]);
assertEq(actualBalanceOfEve, amountsToWithdraw[0]);
}

function test_WithdrawERC1155_Batch() external whenCallerOwner whenExistingERC1155Token {
// Expect the {ERC721Withdrawn} event to be emitted
vm.expectEmit();
emit Events.ERC1155Withdrawn({ to: users.eve, collection: address(mockERC1155), ids: ids, amounts: amounts });

// Run the test
container.withdrawERC1155({ collection: mockERC1155, ids: ids, amounts: amounts });

// Assert the actual and expected balance of any ERC1155 tokens
uint256 numberOfTokens = ids.length;
for (uint256 i; i < numberOfTokens; ++i) {
uint256 actualBalanceOfEve = mockERC1155.balanceOf(users.eve, ids[i]);
assertEq(actualBalanceOfEve, amounts[i]);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
withdrawERC1155.t.sol
├── when the caller IS NOT the container owner
│ └── it should revert with the {CallerNotContainerOwner} error
└── when the caller IS the container owner
├── when there the ERC-1155 balance IS NOT sufficient
│ └── it should revert with the {ERC1155InsufficientBalance} error
└── when there the ERC-1155 balance IS sufficient
├── it should transfer the token(s) to the caller
└── it should emit an {ERC1155Withdrawn} event
3 changes: 3 additions & 0 deletions test/utils/Errors.sol
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ library Errors {
/// @notice Thrown when the ERC-721 token ID does not exist
error ERC721NonexistentToken(uint256 tokenId);

/// @notice Thrown when the balance of the sender is insufficient to perform an ERC-1155 transfer
error ERC1155InsufficientBalance(address sender, uint256 balance, uint256 needed, uint256 tokenId);

/*//////////////////////////////////////////////////////////////////////////
MODULE-MANAGER
//////////////////////////////////////////////////////////////////////////*/
Expand Down
6 changes: 3 additions & 3 deletions test/utils/Events.sol
Original file line number Diff line number Diff line change
Expand Up @@ -77,9 +77,9 @@ abstract contract Events {

/// @notice Emitted when an ERC-1155 token is withdrawn from the container
/// @param to The address to which the tokens were transferred
/// @param id The ID of the token
/// @param value The amount of the tokens withdrawn
event ERC1155Withdrawn(address indexed to, address indexed collection, uint256 id, uint256 value);
/// @param ids The IDs of the tokens
/// @param amounts The amounts of the tokens
event ERC1155Withdrawn(address indexed to, address indexed collection, uint256[] ids, uint256[] amounts);

/// @notice Emitted when a module execution is successful
/// @param module The address of the module
Expand Down

0 comments on commit bfe8461

Please sign in to comment.