Skip to content

BTT TokenERC20 #553

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Oct 24, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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