Skip to content

Commit 1ad2caa

Browse files
authored
BTT TokenERC20 (#553)
* test initialize * test mintTo * test setContractURI * test setPlatformFeeInfo * test setPrimarySaleRecipient * test verify * test mintWithSignature * test other functions
1 parent e06a324 commit 1ad2caa

File tree

16 files changed

+1435
-0
lines changed

16 files changed

+1435
-0
lines changed
Lines changed: 233 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,233 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
pragma solidity ^0.8.0;
3+
4+
import "../../utils/BaseTest.sol";
5+
6+
import { TWProxy } from "contracts/infra/TWProxy.sol";
7+
8+
contract MyTokenERC20 is TokenERC20 {
9+
function eip712NameHash() external view returns (bytes32) {
10+
return _EIP712NameHash();
11+
}
12+
13+
function eip712VersionHash() external view returns (bytes32) {
14+
return _EIP712VersionHash();
15+
}
16+
}
17+
18+
contract TokenERC20Test_Initialize is BaseTest {
19+
address public implementation;
20+
address public proxy;
21+
22+
event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);
23+
24+
function setUp() public override {
25+
super.setUp();
26+
27+
// Deploy implementation.
28+
implementation = address(new MyTokenERC20());
29+
30+
// Deploy proxy pointing to implementaion.
31+
vm.prank(deployer);
32+
proxy = address(
33+
new TWProxy(
34+
implementation,
35+
abi.encodeCall(
36+
TokenERC20.initialize,
37+
(
38+
deployer,
39+
NAME,
40+
SYMBOL,
41+
CONTRACT_URI,
42+
forwarders(),
43+
saleRecipient,
44+
platformFeeRecipient,
45+
platformFeeBps
46+
)
47+
)
48+
)
49+
);
50+
}
51+
52+
function test_initialize_initializingImplementation() public {
53+
vm.expectRevert("Initializable: contract is already initialized");
54+
TokenERC20(implementation).initialize(
55+
deployer,
56+
NAME,
57+
SYMBOL,
58+
CONTRACT_URI,
59+
forwarders(),
60+
saleRecipient,
61+
platformFeeRecipient,
62+
platformFeeBps
63+
);
64+
}
65+
66+
modifier whenNotImplementation() {
67+
_;
68+
}
69+
70+
function test_initialize_proxyAlreadyInitialized() public whenNotImplementation {
71+
vm.expectRevert("Initializable: contract is already initialized");
72+
MyTokenERC20(proxy).initialize(
73+
deployer,
74+
NAME,
75+
SYMBOL,
76+
CONTRACT_URI,
77+
forwarders(),
78+
saleRecipient,
79+
platformFeeRecipient,
80+
platformFeeBps
81+
);
82+
}
83+
84+
modifier whenProxyNotInitialized() {
85+
proxy = address(new TWProxy(implementation, ""));
86+
_;
87+
}
88+
89+
function test_initialize_exceedsMaxBps() public whenNotImplementation whenProxyNotInitialized {
90+
vm.expectRevert("exceeds MAX_BPS");
91+
MyTokenERC20(proxy).initialize(
92+
deployer,
93+
NAME,
94+
SYMBOL,
95+
CONTRACT_URI,
96+
forwarders(),
97+
saleRecipient,
98+
platformFeeRecipient,
99+
uint128(MAX_BPS) + 1 // platformFeeBps greater than MAX_BPS
100+
);
101+
}
102+
103+
modifier whenPlatformFeeBpsWithinMaxBps() {
104+
_;
105+
}
106+
107+
function test_initialize() public whenNotImplementation whenProxyNotInitialized whenPlatformFeeBpsWithinMaxBps {
108+
MyTokenERC20(proxy).initialize(
109+
deployer,
110+
NAME,
111+
SYMBOL,
112+
CONTRACT_URI,
113+
forwarders(),
114+
saleRecipient,
115+
platformFeeRecipient,
116+
platformFeeBps
117+
);
118+
119+
// check state
120+
MyTokenERC20 tokenContract = MyTokenERC20(proxy);
121+
122+
assertEq(tokenContract.eip712NameHash(), keccak256(bytes(NAME)));
123+
assertEq(tokenContract.eip712VersionHash(), keccak256(bytes("1")));
124+
125+
address[] memory _trustedForwarders = forwarders();
126+
for (uint256 i = 0; i < _trustedForwarders.length; i++) {
127+
assertTrue(tokenContract.isTrustedForwarder(_trustedForwarders[i]));
128+
}
129+
130+
assertEq(tokenContract.name(), NAME);
131+
assertEq(tokenContract.symbol(), SYMBOL);
132+
assertEq(tokenContract.contractURI(), CONTRACT_URI);
133+
134+
(address _platformFeeRecipient, uint16 _platformFeeBps) = tokenContract.getPlatformFeeInfo();
135+
assertEq(_platformFeeBps, platformFeeBps);
136+
assertEq(_platformFeeRecipient, platformFeeRecipient);
137+
138+
assertEq(tokenContract.primarySaleRecipient(), saleRecipient);
139+
140+
assertTrue(tokenContract.hasRole(bytes32(0x00), deployer));
141+
assertTrue(tokenContract.hasRole(keccak256("TRANSFER_ROLE"), deployer));
142+
assertTrue(tokenContract.hasRole(keccak256("TRANSFER_ROLE"), address(0)));
143+
assertTrue(tokenContract.hasRole(keccak256("MINTER_ROLE"), deployer));
144+
}
145+
146+
function test_initialize_event_RoleGranted_DefaultAdmin()
147+
public
148+
whenNotImplementation
149+
whenProxyNotInitialized
150+
whenPlatformFeeBpsWithinMaxBps
151+
{
152+
bytes32 _defaultAdminRole = bytes32(0x00);
153+
vm.prank(deployer);
154+
vm.expectEmit(true, true, true, false);
155+
emit RoleGranted(_defaultAdminRole, deployer, deployer);
156+
MyTokenERC20(proxy).initialize(
157+
deployer,
158+
NAME,
159+
SYMBOL,
160+
CONTRACT_URI,
161+
forwarders(),
162+
saleRecipient,
163+
platformFeeRecipient,
164+
platformFeeBps
165+
);
166+
}
167+
168+
function test_initialize_event_RoleGranted_MinterRole()
169+
public
170+
whenNotImplementation
171+
whenProxyNotInitialized
172+
whenPlatformFeeBpsWithinMaxBps
173+
{
174+
bytes32 _minterRole = keccak256("MINTER_ROLE");
175+
vm.prank(deployer);
176+
vm.expectEmit(true, true, true, false);
177+
emit RoleGranted(_minterRole, deployer, deployer);
178+
MyTokenERC20(proxy).initialize(
179+
deployer,
180+
NAME,
181+
SYMBOL,
182+
CONTRACT_URI,
183+
forwarders(),
184+
saleRecipient,
185+
platformFeeRecipient,
186+
platformFeeBps
187+
);
188+
}
189+
190+
function test_initialize_event_RoleGranted_TransferRole()
191+
public
192+
whenNotImplementation
193+
whenProxyNotInitialized
194+
whenPlatformFeeBpsWithinMaxBps
195+
{
196+
bytes32 _transferRole = keccak256("TRANSFER_ROLE");
197+
vm.prank(deployer);
198+
vm.expectEmit(true, true, true, false);
199+
emit RoleGranted(_transferRole, deployer, deployer);
200+
MyTokenERC20(proxy).initialize(
201+
deployer,
202+
NAME,
203+
SYMBOL,
204+
CONTRACT_URI,
205+
forwarders(),
206+
saleRecipient,
207+
platformFeeRecipient,
208+
platformFeeBps
209+
);
210+
}
211+
212+
function test_initialize_event_RoleGranted_TransferRole_AddressZero()
213+
public
214+
whenNotImplementation
215+
whenProxyNotInitialized
216+
whenPlatformFeeBpsWithinMaxBps
217+
{
218+
bytes32 _transferRole = keccak256("TRANSFER_ROLE");
219+
vm.prank(deployer);
220+
vm.expectEmit(true, true, true, false);
221+
emit RoleGranted(_transferRole, address(0), deployer);
222+
MyTokenERC20(proxy).initialize(
223+
deployer,
224+
NAME,
225+
SYMBOL,
226+
CONTRACT_URI,
227+
forwarders(),
228+
saleRecipient,
229+
platformFeeRecipient,
230+
platformFeeBps
231+
);
232+
}
233+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
initialize(
2+
address _defaultAdmin,
3+
string memory _name,
4+
string memory _symbol,
5+
string memory _contractURI,
6+
address[] memory _trustedForwarders,
7+
address _primarySaleRecipient,
8+
address _platformFeeRecipient
9+
uint256 _platformFeeBps,
10+
)
11+
├── when initializing the implementation contract (not proxy)
12+
│ └── it should revert ✅
13+
└── when it is a proxy to the implementation
14+
└── when it is already initialized
15+
│ └── it should revert ✅
16+
└── when it is not initialized
17+
└── when platformFeeBps is greater than MAX_BPS
18+
│ └── it should revert ✅
19+
└── when platformFeeBps is less than or equal to MAX_BPS
20+
└── it should correctly set EIP712 name hash and version hash ✅
21+
└── it should set trustedForwarder mapping to true for all addresses in `_trustedForwarders` ✅
22+
└── it should set _name and _symbol to `_name` and `_symbol` param values respectively ✅
23+
└── it should set contractURI to `_contractURI` param value ✅
24+
└── it should set platformFeeRecipient and platformFeeBps as `_platformFeeRecipient` and `_platformFeeBps` respectively ✅
25+
└── it should set primary sale recipient as `_saleRecipient` param value ✅
26+
└── it should grant 0x00 (DEFAULT_ADMIN_ROLE) to `_defaultAdmin` address ✅
27+
└── it should emit RoleGranted event ✅
28+
└── it should grant MINTER_ROLE to `_defaultAdmin` address ✅
29+
└── it should emit RoleGranted event ✅
30+
└── it should grant TRANSFER_ROLE to `_defaultAdmin` address ✅
31+
└── it should emit RoleGranted event ✅
32+
└── it should grant TRANSFER_ROLE to address(0) ✅
33+
└── it should emit RoleGranted event ✅
34+
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
pragma solidity ^0.8.0;
3+
4+
import "../../utils/BaseTest.sol";
5+
6+
import { TWProxy } from "contracts/infra/TWProxy.sol";
7+
8+
contract MyTokenERC20 is TokenERC20 {}
9+
10+
contract TokenERC20Test_MintTo is BaseTest {
11+
address public implementation;
12+
address public proxy;
13+
address public caller;
14+
address public recipient;
15+
uint256 public amount;
16+
17+
MyTokenERC20 internal tokenContract;
18+
19+
event TokensMinted(address indexed mintedTo, uint256 quantityMinted);
20+
21+
function setUp() public override {
22+
super.setUp();
23+
24+
// Deploy implementation.
25+
implementation = address(new MyTokenERC20());
26+
caller = getActor(1);
27+
recipient = getActor(2);
28+
29+
// Deploy proxy pointing to implementaion.
30+
vm.prank(deployer);
31+
proxy = address(
32+
new TWProxy(
33+
implementation,
34+
abi.encodeCall(
35+
TokenERC20.initialize,
36+
(
37+
deployer,
38+
NAME,
39+
SYMBOL,
40+
CONTRACT_URI,
41+
forwarders(),
42+
saleRecipient,
43+
platformFeeRecipient,
44+
platformFeeBps
45+
)
46+
)
47+
)
48+
);
49+
50+
tokenContract = MyTokenERC20(proxy);
51+
amount = 100;
52+
}
53+
54+
function test_mintTo_notMinterRole() public {
55+
vm.prank(caller);
56+
vm.expectRevert("not minter.");
57+
tokenContract.mintTo(recipient, amount);
58+
}
59+
60+
modifier whenMinterRole() {
61+
vm.prank(deployer);
62+
tokenContract.grantRole(keccak256("MINTER_ROLE"), caller);
63+
_;
64+
}
65+
66+
function test_mintTo() public whenMinterRole {
67+
// mint
68+
vm.prank(caller);
69+
tokenContract.mintTo(recipient, amount);
70+
71+
// check state after
72+
assertEq(tokenContract.balanceOf(recipient), amount);
73+
}
74+
75+
function test_mintTo_TokensMintedEvent() public whenMinterRole {
76+
vm.prank(caller);
77+
vm.expectEmit(true, false, false, true);
78+
emit TokensMinted(recipient, amount);
79+
tokenContract.mintTo(recipient, amount);
80+
}
81+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
mintTo(address to, uint256 amount)
2+
├── when caller doesn't have MINTER_ROLE
3+
│ └── it should revert ✅
4+
└── when caller has MINTER_ROLE
5+
└── it should mint `amount` to `to` ✅
6+
└── it should emit TokensMinted event ✅
7+

0 commit comments

Comments
 (0)