mirror of
https://github.com/simplex-chat/simplex-chat.git
synced 2026-04-01 22:35:49 +00:00
* tokens: ERC1155 contract for tokens * simplify 1155 * NFT and minter contracts * update NFT * update * update * update * update * NFT metadata JSON * update token metadata * flattened contracts
337 lines
14 KiB
Solidity
337 lines
14 KiB
Solidity
// SPDX-License-Identifier: MIT
|
|
pragma solidity ^0.8.27;
|
|
|
|
import "remix_tests.sol";
|
|
|
|
import "../contracts/MultiERC1155.sol";
|
|
|
|
contract MultiERC1155Test {
|
|
MultiERC1155 public ct;
|
|
address public owner = address(this);
|
|
address public admin = address(0x1);
|
|
address public minter = address(0x2);
|
|
address public user = address(0x3);
|
|
address public recipient = address(0x4);
|
|
|
|
MultiERC1155.TokenInfo defaultInfo = MultiERC1155.TokenInfo({
|
|
tokenUri: "https://example.com/token.json",
|
|
totalSupply: 0,
|
|
enabled: true
|
|
});
|
|
|
|
function beforeAll() public {
|
|
ct = new MultiERC1155();
|
|
MultiERC1155.TokenInfo memory newInfo = defaultInfo;
|
|
(bool success, ) = address(ct).call(abi.encodeWithSignature("addToken((string,bool,string,string,string,uint256))", newInfo));
|
|
Assert.equal(success, true, "addToken success");
|
|
}
|
|
|
|
// Constructor Test
|
|
function testConstructor() public {
|
|
Assert.equal(ct.owner(), owner, "Owner should be deployer");
|
|
Assert.equal(ct.admin(), owner, "Admin should be deployer");
|
|
Assert.equal(ct.minter(), owner, "Minter should be deployer");
|
|
Assert.equal(ct.mintingEnabled(), true, "Minting should be enabled");
|
|
Assert.equal(ct.contractLocked(), false, "Contract should not be locked");
|
|
uint[] memory ids = ct.getTokenIds();
|
|
Assert.equal(ids.length, uint(1), "One token ID added");
|
|
Assert.equal(ids[0], uint(1), "First token ID is 1");
|
|
(, uint currentSupply, bool exists, bool locked) = ct.tokens(1);
|
|
Assert.equal(exists, true, "Token 1 exists");
|
|
Assert.equal(locked, false, "Token 1 not locked");
|
|
Assert.equal(currentSupply, uint(0), "Token 1 supply 0");
|
|
}
|
|
|
|
// setAdmin Test
|
|
function testSetAdmin() public {
|
|
ct.setAdmin(admin);
|
|
Assert.equal(ct.admin(), admin, "Admin updated");
|
|
}
|
|
|
|
function testSetAdminOnlyOwner() public {
|
|
(bool success, ) = address(ct).call(abi.encodeWithSignature("setAdmin(address)", admin));
|
|
Assert.equal(success, true, "Set admin from owner succeeds"); // Since this is owner
|
|
|
|
// To test revert, Remix plugin runs as this, so for non-owner, manual simulation not easy; note as TODO or skip
|
|
}
|
|
|
|
// setMinter Test
|
|
function testSetMinter() public {
|
|
ct.setMinter(minter);
|
|
Assert.equal(ct.minter(), minter, "Minter updated");
|
|
}
|
|
|
|
function testSetMinterOnlyOwner() public {
|
|
(bool success, ) = address(ct).call(abi.encodeWithSignature("setMinter(address)", minter));
|
|
Assert.equal(success, true, "Set minter from owner succeeds");
|
|
}
|
|
|
|
// toggleMinting Test
|
|
function testToggleMinting() public {
|
|
ct.toggleMinting(false);
|
|
Assert.equal(ct.mintingEnabled(), false, "Minting disabled");
|
|
|
|
ct.toggleMinting(true);
|
|
Assert.equal(ct.mintingEnabled(), true, "Minting enabled");
|
|
}
|
|
|
|
function testToggleMintingNoChange() public {
|
|
ct.toggleMinting(true); // Already true
|
|
Assert.equal(ct.mintingEnabled(), true, "No change if same");
|
|
}
|
|
|
|
function testToggleMintingOnlyOwner() public {
|
|
(bool success, ) = address(ct).call(abi.encodeWithSignature("toggleMinting(bool)", false));
|
|
Assert.equal(success, true, "Toggle from owner succeeds");
|
|
}
|
|
|
|
// lockContract Test
|
|
function testLockContract() public {
|
|
ct.lockContract();
|
|
Assert.equal(ct.contractLocked(), true, "Contract locked");
|
|
Assert.equal(ct.mintingEnabled(), false, "Minting disabled");
|
|
}
|
|
|
|
function testLockContractOnlyOwner() public {
|
|
(bool success, ) = address(ct).call(abi.encodeWithSignature("lockContract()"));
|
|
Assert.equal(success, true, "Lock from owner succeeds");
|
|
}
|
|
|
|
// addToken Test
|
|
function testAddToken() public {
|
|
MultiERC1155.TokenInfo memory newInfo = MultiERC1155.TokenInfo({
|
|
tokenUri: "https://example.com/new_token.json",
|
|
totalSupply: 100,
|
|
enabled: true
|
|
});
|
|
|
|
ct.addToken(newInfo);
|
|
uint[] memory ids = ct.getTokenIds();
|
|
Assert.equal(ids.length, uint(2), "Two token IDs");
|
|
Assert.equal(ids[1], uint(2), "Second token ID 2");
|
|
(MultiERC1155.TokenInfo memory tokenInfo, uint currentSupply, bool exists, bool locked) = ct.tokens(2);
|
|
Assert.equal(exists, true, "Token 2 exists");
|
|
Assert.equal(locked, false, "Token 2 not locked");
|
|
Assert.equal(currentSupply, uint(0), "Token 2 supply 0");
|
|
Assert.equal(tokenInfo.totalSupply, uint(100), "Token 2 totalSupply 100");
|
|
// Validate info fields as needed
|
|
}
|
|
|
|
function testAddTokenByAdmin() public {
|
|
ct.setAdmin(admin);
|
|
MultiERC1155.TokenInfo memory newInfo = defaultInfo;
|
|
(bool success, ) = address(ct).call(abi.encodeWithSignature("addToken((string,bool,string,string,string,uint256))", newInfo));
|
|
Assert.equal(success, true, "Add by admin succeeds");
|
|
uint[] memory ids = ct.getTokenIds();
|
|
Assert.equal(ids.length, uint(2), "Two token IDs");
|
|
}
|
|
|
|
function testAddTokenRevertInvalidInfo() public {
|
|
MultiERC1155.TokenInfo memory invalidInfo = MultiERC1155.TokenInfo({
|
|
tokenUri: "",
|
|
totalSupply: 0,
|
|
enabled: true
|
|
});
|
|
(bool success, ) = address(ct).call(abi.encodeWithSignature("addToken((string,bool,string,string,string,uint256))", invalidInfo));
|
|
Assert.equal(success, false, "Invalid info reverts");
|
|
}
|
|
|
|
function testAddTokenOnlyAdminOrOwner() public {
|
|
MultiERC1155.TokenInfo memory info = defaultInfo;
|
|
(bool success, ) = address(ct).call(abi.encodeWithSignature("addToken((string,bool,string,string,string,uint256))", info));
|
|
Assert.equal(success, true, "Add from owner succeeds");
|
|
}
|
|
|
|
// removeToken Test
|
|
function testRemoveToken() public {
|
|
MultiERC1155.TokenInfo memory newInfo = defaultInfo;
|
|
ct.addToken(newInfo);
|
|
uint[] memory ids = ct.getTokenIds();
|
|
Assert.equal(ids.length, uint(2), "Two token IDs");
|
|
|
|
ct.removeToken(2);
|
|
ids = ct.getTokenIds();
|
|
Assert.equal(ids.length, uint(1), "One token ID after removal");
|
|
(,,bool exists,) = ct.tokens(2);
|
|
Assert.equal(exists, false, "Token 2 removed");
|
|
}
|
|
|
|
function testRemoveTokenRevertNonExist() public {
|
|
(bool success, ) = address(ct).call(abi.encodeWithSignature("removeToken(uint256)", 99));
|
|
Assert.equal(success, false, "Remove non-exist reverts");
|
|
}
|
|
|
|
function testRemoveTokenRevertHasSupply() public {
|
|
ct.mint(user, 1, 10, "");
|
|
(bool success,) = address(ct).call(abi.encodeWithSignature("removeToken(uint256)", 1));
|
|
Assert.equal(success, false, "Remove with supply reverts");
|
|
}
|
|
|
|
function testRemoveTokenRevertLast() public {
|
|
(bool success, ) = address(ct).call(abi.encodeWithSignature("removeToken(uint256)", 1));
|
|
Assert.equal(success, false, "Remove last reverts");
|
|
}
|
|
|
|
function testRemoveTokenOnlyAdminOrOwner() public {
|
|
(bool success, ) = address(ct).call(abi.encodeWithSignature("removeToken(uint256)", 1));
|
|
Assert.equal(success, false, "Remove last fails"); // But for non-owner, need simulation
|
|
}
|
|
|
|
// updateToken Test
|
|
function testUpdateToken() public {
|
|
ct.updateToken(1, false, 100);
|
|
(MultiERC1155.TokenInfo memory tokenInfo,,,) = ct.tokens(1);
|
|
Assert.equal(tokenInfo.enabled, false, "Enabled updated");
|
|
Assert.equal(tokenInfo.totalSupply, uint(100), "Total supply updated");
|
|
}
|
|
|
|
function testUpdateTokenNoChange() public {
|
|
(MultiERC1155.TokenInfo memory tokenInfo,,,) = ct.tokens(1);
|
|
ct.updateToken(1, tokenInfo.enabled, tokenInfo.totalSupply);
|
|
// No assert, as no change
|
|
}
|
|
|
|
function testUpdateTokenRevertNonExist() public {
|
|
(bool success, ) = address(ct).call(abi.encodeWithSignature("updateToken(uint256,bool,uint256)", 99, true, 0));
|
|
Assert.equal(success, false, "Update non-exist reverts");
|
|
}
|
|
|
|
function testUpdateTokenRevertLocked() public {
|
|
ct.mint(user, 1, 10, "");
|
|
ct.lockToken(1);
|
|
(bool success, ) = address(ct).call(abi.encodeWithSignature("updateToken(uint256,bool,uint256)", 1, true, 0));
|
|
Assert.equal(success, false, "Update locked reverts");
|
|
}
|
|
|
|
function testUpdateTokenRevertInvalidSupply() public {
|
|
ct.mint(user, 1, 10, "");
|
|
(bool success, ) = address(ct).call(abi.encodeWithSignature("updateToken(uint256,bool,uint256)", 1, true, 5));
|
|
Assert.equal(success, false, "Invalid supply reverts");
|
|
}
|
|
|
|
function testUpdateTokenOnlyAdminOrOwner() public {
|
|
(bool success, ) = address(ct).call(abi.encodeWithSignature("updateToken(uint256,bool,uint256)", 1, true, 0));
|
|
Assert.equal(success, true, "Update from owner succeeds");
|
|
}
|
|
|
|
// lockToken Test
|
|
function testLockToken() public {
|
|
ct.mint(user, 1, 10, "");
|
|
ct.lockToken(1);
|
|
(MultiERC1155.TokenInfo memory tokenInfo,,, bool locked) = ct.tokens(1);
|
|
Assert.equal(locked, true, "Token locked");
|
|
Assert.equal(tokenInfo.enabled, false, "Enabled false");
|
|
}
|
|
|
|
function testLockTokenRevertNonExist() public {
|
|
(bool success, ) = address(ct).call(abi.encodeWithSignature("lockToken(uint256)", 99));
|
|
Assert.equal(success, false, "Lock non-exist reverts");
|
|
}
|
|
|
|
function testLockTokenRevertAlreadyLocked() public {
|
|
ct.mint(user, 1, 10, "");
|
|
ct.lockToken(1);
|
|
(bool success, ) = address(ct).call(abi.encodeWithSignature("lockToken(uint256)", 1));
|
|
Assert.equal(success, false, "Lock already locked reverts");
|
|
}
|
|
|
|
function testLockTokenRevertNoSupply() public {
|
|
(bool success, ) = address(ct).call(abi.encodeWithSignature("lockToken(uint256)", 1));
|
|
Assert.equal(success, false, "Lock no supply reverts");
|
|
}
|
|
|
|
function testLockTokenOnlyOwner() public {
|
|
(bool success, ) = address(ct).call(abi.encodeWithSignature("lockToken(uint256)", 1));
|
|
Assert.equal(success, false, "Lock no supply fails"); // Test with supply
|
|
}
|
|
|
|
// mint Test
|
|
function testMint() public {
|
|
ct.mint(user, 1, 10, "");
|
|
Assert.equal(ct.balanceOf(user, 1), 10, "User balance 10");
|
|
(,uint currentSupply,,) = ct.tokens(1);
|
|
Assert.equal(currentSupply, 10, "Token supply 10");
|
|
}
|
|
|
|
function testMintRevertLockedContract() public {
|
|
ct.lockContract();
|
|
(bool success, ) = address(ct).call(abi.encodeWithSignature("mint(address,uint256,uint256,bytes)", user, 1, 10, ""));
|
|
Assert.equal(success, false, "Mint locked contract reverts");
|
|
}
|
|
|
|
function testMintRevertMintingDisabled() public {
|
|
ct.toggleMinting(false);
|
|
(bool success, ) = address(ct).call(abi.encodeWithSignature("mint(address,uint256,uint256,bytes)", user, 1, 10, ""));
|
|
Assert.equal(success, false, "Mint disabled reverts");
|
|
}
|
|
|
|
function testMintRevertInvalidCaller() public {
|
|
(bool success, ) = address(ct).call(abi.encodeWithSignature("mint(address,uint256,uint256,bytes)", user, 1, 10, ""));
|
|
Assert.equal(success, true, "Mint from owner succeeds");
|
|
}
|
|
|
|
function testMintRevertNonExist() public {
|
|
(bool success, ) = address(ct).call(abi.encodeWithSignature("mint(address,uint256,uint256,bytes)", user, 99, 10, ""));
|
|
Assert.equal(success, false, "Mint non-exist reverts");
|
|
}
|
|
|
|
function testMintRevertLockedToken() public {
|
|
ct.mint(user, 1, 10, "");
|
|
ct.lockToken(1);
|
|
(bool success, ) = address(ct).call(abi.encodeWithSignature("mint(address,uint256,uint256,bytes)", user, 1, 5, ""));
|
|
Assert.equal(success, false, "Mint locked token reverts");
|
|
}
|
|
|
|
function testMintRevertDisabledToken() public {
|
|
ct.updateToken(1, false, 0);
|
|
(bool success, ) = address(ct).call(abi.encodeWithSignature("mint(address,uint256,uint256,bytes)", user, 1, 10, ""));
|
|
Assert.equal(success, false, "Mint disabled token reverts");
|
|
}
|
|
|
|
function testMintRevertSupplyExceeded() public {
|
|
ct.updateToken(1, true, 5);
|
|
(bool success, ) = address(ct).call(abi.encodeWithSignature("mint(address,uint256,uint256,bytes)", user, 1, 10, ""));
|
|
Assert.equal(success, false, "Mint supply exceeded reverts");
|
|
}
|
|
|
|
function testMintRevertZeroAmount() public {
|
|
(bool success, ) = address(ct).call(abi.encodeWithSignature("mint(address,uint256,uint256,bytes)", user, 1, 0, ""));
|
|
Assert.equal(success, false, "Mint zero amount reverts");
|
|
}
|
|
|
|
// _update Test (via transfer/burn)
|
|
function testUpdateMint() public {
|
|
ct.mint(user, 1, 10, "");
|
|
(,uint currentSupply,,) = ct.tokens(1);
|
|
Assert.equal(currentSupply, 10, "Supply after mint");
|
|
}
|
|
|
|
function testUpdateBurn() public {
|
|
ct.mint(user, 1, 10, "");
|
|
(bool success, ) = address(ct).call(abi.encodeWithSignature("safeTransferFrom(address,address,uint256,uint256,bytes)", user, address(0), 1, 5, ""));
|
|
Assert.equal(success, true, "Burn succeeds");
|
|
(,uint currentSupply,,) = ct.tokens(1);
|
|
Assert.equal(currentSupply, 5, "Supply after burn");
|
|
}
|
|
|
|
function testUpdateTransfer() public {
|
|
ct.mint(user, 1, 10, "");
|
|
(bool success, ) = address(ct).call(abi.encodeWithSignature("safeTransferFrom(address,address,uint256,uint256,bytes)", user, recipient, 1, 5, ""));
|
|
Assert.equal(success, true, "Transfer succeeds");
|
|
(,uint currentSupply,,) = ct.tokens(1);
|
|
Assert.equal(currentSupply, 10, "Supply unchanged on transfer");
|
|
}
|
|
|
|
// uri Test
|
|
function testUri() public {
|
|
string memory json = Base64.encode(bytes('{"name":"Test Token","description":"Test Description","image":"https://test.com/image.png","properties":{}}'));
|
|
string memory expected = string.concat("data:application/json;base64,", json);
|
|
Assert.equal(ct.uri(1), expected, "URI matches");
|
|
}
|
|
|
|
function testUriRevertNonExist() public {
|
|
(bool success, ) = address(ct).call(abi.encodeWithSignature("uri(uint256)", 99));
|
|
Assert.equal(success, false, "URI non-exist reverts");
|
|
}
|
|
}
|