Skip to content

Commit

Permalink
BTT TokenERC20 (#553)
Browse files Browse the repository at this point in the history
* test initialize

* test mintTo

* test setContractURI

* test setPlatformFeeInfo

* test setPrimarySaleRecipient

* test verify

* test mintWithSignature

* test other functions
  • Loading branch information
kumaryash90 authored Oct 24, 2023
1 parent e06a324 commit 1ad2caa
Show file tree
Hide file tree
Showing 16 changed files with 1,435 additions and 0 deletions.
233 changes: 233 additions & 0 deletions src/test/tokenerc20-BTT/initialize/initialize.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,233 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;

import "../../utils/BaseTest.sol";

import { TWProxy } from "contracts/infra/TWProxy.sol";

contract MyTokenERC20 is TokenERC20 {
function eip712NameHash() external view returns (bytes32) {
return _EIP712NameHash();
}

function eip712VersionHash() external view returns (bytes32) {
return _EIP712VersionHash();
}
}

contract TokenERC20Test_Initialize is BaseTest {
address public implementation;
address public proxy;

event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);

function setUp() public override {
super.setUp();

// Deploy implementation.
implementation = address(new MyTokenERC20());

// Deploy proxy pointing to implementaion.
vm.prank(deployer);
proxy = address(
new TWProxy(
implementation,
abi.encodeCall(
TokenERC20.initialize,
(
deployer,
NAME,
SYMBOL,
CONTRACT_URI,
forwarders(),
saleRecipient,
platformFeeRecipient,
platformFeeBps
)
)
)
);
}

function test_initialize_initializingImplementation() public {
vm.expectRevert("Initializable: contract is already initialized");
TokenERC20(implementation).initialize(
deployer,
NAME,
SYMBOL,
CONTRACT_URI,
forwarders(),
saleRecipient,
platformFeeRecipient,
platformFeeBps
);
}

modifier whenNotImplementation() {
_;
}

function test_initialize_proxyAlreadyInitialized() public whenNotImplementation {
vm.expectRevert("Initializable: contract is already initialized");
MyTokenERC20(proxy).initialize(
deployer,
NAME,
SYMBOL,
CONTRACT_URI,
forwarders(),
saleRecipient,
platformFeeRecipient,
platformFeeBps
);
}

modifier whenProxyNotInitialized() {
proxy = address(new TWProxy(implementation, ""));
_;
}

function test_initialize_exceedsMaxBps() public whenNotImplementation whenProxyNotInitialized {
vm.expectRevert("exceeds MAX_BPS");
MyTokenERC20(proxy).initialize(
deployer,
NAME,
SYMBOL,
CONTRACT_URI,
forwarders(),
saleRecipient,
platformFeeRecipient,
uint128(MAX_BPS) + 1 // platformFeeBps greater than MAX_BPS
);
}

modifier whenPlatformFeeBpsWithinMaxBps() {
_;
}

function test_initialize() public whenNotImplementation whenProxyNotInitialized whenPlatformFeeBpsWithinMaxBps {
MyTokenERC20(proxy).initialize(
deployer,
NAME,
SYMBOL,
CONTRACT_URI,
forwarders(),
saleRecipient,
platformFeeRecipient,
platformFeeBps
);

// check state
MyTokenERC20 tokenContract = MyTokenERC20(proxy);

assertEq(tokenContract.eip712NameHash(), keccak256(bytes(NAME)));
assertEq(tokenContract.eip712VersionHash(), keccak256(bytes("1")));

address[] memory _trustedForwarders = forwarders();
for (uint256 i = 0; i < _trustedForwarders.length; i++) {
assertTrue(tokenContract.isTrustedForwarder(_trustedForwarders[i]));
}

assertEq(tokenContract.name(), NAME);
assertEq(tokenContract.symbol(), SYMBOL);
assertEq(tokenContract.contractURI(), CONTRACT_URI);

(address _platformFeeRecipient, uint16 _platformFeeBps) = tokenContract.getPlatformFeeInfo();
assertEq(_platformFeeBps, platformFeeBps);
assertEq(_platformFeeRecipient, platformFeeRecipient);

assertEq(tokenContract.primarySaleRecipient(), saleRecipient);

assertTrue(tokenContract.hasRole(bytes32(0x00), deployer));
assertTrue(tokenContract.hasRole(keccak256("TRANSFER_ROLE"), deployer));
assertTrue(tokenContract.hasRole(keccak256("TRANSFER_ROLE"), address(0)));
assertTrue(tokenContract.hasRole(keccak256("MINTER_ROLE"), deployer));
}

function test_initialize_event_RoleGranted_DefaultAdmin()
public
whenNotImplementation
whenProxyNotInitialized
whenPlatformFeeBpsWithinMaxBps
{
bytes32 _defaultAdminRole = bytes32(0x00);
vm.prank(deployer);
vm.expectEmit(true, true, true, false);
emit RoleGranted(_defaultAdminRole, deployer, deployer);
MyTokenERC20(proxy).initialize(
deployer,
NAME,
SYMBOL,
CONTRACT_URI,
forwarders(),
saleRecipient,
platformFeeRecipient,
platformFeeBps
);
}

function test_initialize_event_RoleGranted_MinterRole()
public
whenNotImplementation
whenProxyNotInitialized
whenPlatformFeeBpsWithinMaxBps
{
bytes32 _minterRole = keccak256("MINTER_ROLE");
vm.prank(deployer);
vm.expectEmit(true, true, true, false);
emit RoleGranted(_minterRole, deployer, deployer);
MyTokenERC20(proxy).initialize(
deployer,
NAME,
SYMBOL,
CONTRACT_URI,
forwarders(),
saleRecipient,
platformFeeRecipient,
platformFeeBps
);
}

function test_initialize_event_RoleGranted_TransferRole()
public
whenNotImplementation
whenProxyNotInitialized
whenPlatformFeeBpsWithinMaxBps
{
bytes32 _transferRole = keccak256("TRANSFER_ROLE");
vm.prank(deployer);
vm.expectEmit(true, true, true, false);
emit RoleGranted(_transferRole, deployer, deployer);
MyTokenERC20(proxy).initialize(
deployer,
NAME,
SYMBOL,
CONTRACT_URI,
forwarders(),
saleRecipient,
platformFeeRecipient,
platformFeeBps
);
}

function test_initialize_event_RoleGranted_TransferRole_AddressZero()
public
whenNotImplementation
whenProxyNotInitialized
whenPlatformFeeBpsWithinMaxBps
{
bytes32 _transferRole = keccak256("TRANSFER_ROLE");
vm.prank(deployer);
vm.expectEmit(true, true, true, false);
emit RoleGranted(_transferRole, address(0), deployer);
MyTokenERC20(proxy).initialize(
deployer,
NAME,
SYMBOL,
CONTRACT_URI,
forwarders(),
saleRecipient,
platformFeeRecipient,
platformFeeBps
);
}
}
34 changes: 34 additions & 0 deletions src/test/tokenerc20-BTT/initialize/initialize.tree
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
initialize(
address _defaultAdmin,
string memory _name,
string memory _symbol,
string memory _contractURI,
address[] memory _trustedForwarders,
address _primarySaleRecipient,
address _platformFeeRecipient
uint256 _platformFeeBps,
)
├── when initializing the implementation contract (not proxy)
│ └── it should revert ✅
└── when it is a proxy to the implementation
└── when it is already initialized
│ └── it should revert ✅
└── when it is not initialized
└── when platformFeeBps is greater than MAX_BPS
│ └── it should revert ✅
└── when platformFeeBps is less than or equal to MAX_BPS
└── it should correctly set EIP712 name hash and version hash ✅
└── it should set trustedForwarder mapping to true for all addresses in `_trustedForwarders` ✅
└── it should set _name and _symbol to `_name` and `_symbol` param values respectively ✅
└── it should set contractURI to `_contractURI` param value ✅
└── it should set platformFeeRecipient and platformFeeBps as `_platformFeeRecipient` and `_platformFeeBps` respectively ✅
└── it should set primary sale recipient as `_saleRecipient` param value ✅
└── it should grant 0x00 (DEFAULT_ADMIN_ROLE) to `_defaultAdmin` address ✅
└── it should emit RoleGranted event ✅
└── it should grant MINTER_ROLE to `_defaultAdmin` address ✅
└── it should emit RoleGranted event ✅
└── it should grant TRANSFER_ROLE to `_defaultAdmin` address ✅
└── it should emit RoleGranted event ✅
└── it should grant TRANSFER_ROLE to address(0) ✅
└── it should emit RoleGranted event ✅

81 changes: 81 additions & 0 deletions src/test/tokenerc20-BTT/mint-to/mintTo.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;

import "../../utils/BaseTest.sol";

import { TWProxy } from "contracts/infra/TWProxy.sol";

contract MyTokenERC20 is TokenERC20 {}

contract TokenERC20Test_MintTo is BaseTest {
address public implementation;
address public proxy;
address public caller;
address public recipient;
uint256 public amount;

MyTokenERC20 internal tokenContract;

event TokensMinted(address indexed mintedTo, uint256 quantityMinted);

function setUp() public override {
super.setUp();

// Deploy implementation.
implementation = address(new MyTokenERC20());
caller = getActor(1);
recipient = getActor(2);

// Deploy proxy pointing to implementaion.
vm.prank(deployer);
proxy = address(
new TWProxy(
implementation,
abi.encodeCall(
TokenERC20.initialize,
(
deployer,
NAME,
SYMBOL,
CONTRACT_URI,
forwarders(),
saleRecipient,
platformFeeRecipient,
platformFeeBps
)
)
)
);

tokenContract = MyTokenERC20(proxy);
amount = 100;
}

function test_mintTo_notMinterRole() public {
vm.prank(caller);
vm.expectRevert("not minter.");
tokenContract.mintTo(recipient, amount);
}

modifier whenMinterRole() {
vm.prank(deployer);
tokenContract.grantRole(keccak256("MINTER_ROLE"), caller);
_;
}

function test_mintTo() public whenMinterRole {
// mint
vm.prank(caller);
tokenContract.mintTo(recipient, amount);

// check state after
assertEq(tokenContract.balanceOf(recipient), amount);
}

function test_mintTo_TokensMintedEvent() public whenMinterRole {
vm.prank(caller);
vm.expectEmit(true, false, false, true);
emit TokensMinted(recipient, amount);
tokenContract.mintTo(recipient, amount);
}
}
7 changes: 7 additions & 0 deletions src/test/tokenerc20-BTT/mint-to/mintTo.tree
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
mintTo(address to, uint256 amount)
├── when caller doesn't have MINTER_ROLE
│ └── it should revert ✅
└── when caller has MINTER_ROLE
└── it should mint `amount` to `to` ✅
└── it should emit TokensMinted event ✅

Loading

0 comments on commit 1ad2caa

Please sign in to comment.