Skip to content

Commit 9e5d693

Browse files
WhiteOakKongkumaryash90joaquim-verges
authored
BTT Testing for DropERC20 (#532)
* create file structure * tree: initialize * tree: _beforeClaim * tree: _collectPriceOnClaim * tree: setMaxTotalSupply * clean * tree: _beforeClaim * test: initialize * test: _beforeClaim * test: collectPriceOnClaim * test: canSetFunctions * test: misc * test: setMaxTotalSupply * test: misc * test: misc * clean/lint * remove initialize harness and use TWProxy * clean/lint tests --------- Co-authored-by: Yash <72552910+kumaryash90@users.noreply.github.com> Co-authored-by: Joaquim Verges <joaquim.verges@gmail.com>
1 parent a64ca6b commit 9e5d693

File tree

12 files changed

+906
-0
lines changed

12 files changed

+906
-0
lines changed
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
pragma solidity ^0.8.0;
3+
4+
import { DropERC20 } from "contracts/prebuilts/drop/DropERC20.sol";
5+
import { TWProxy } from "contracts/infra/TWProxy.sol";
6+
7+
// Test imports
8+
import "../../../utils/BaseTest.sol";
9+
10+
contract HarnessDropERC20BeforeClaim is DropERC20 {
11+
bytes private emptyBytes = bytes("");
12+
13+
function harness_beforeClaim(uint256 quantity, AllowlistProof calldata _proof) public view {
14+
_beforeClaim(address(0), quantity, address(0), 0, _proof, emptyBytes);
15+
}
16+
}
17+
18+
contract DropERC20Test_beforeClaim is BaseTest {
19+
address public dropImp;
20+
HarnessDropERC20BeforeClaim public proxy;
21+
22+
uint256 private mintQty;
23+
24+
function setUp() public override {
25+
super.setUp();
26+
27+
bytes memory initializeData = abi.encodeCall(
28+
DropERC20.initialize,
29+
(deployer, NAME, SYMBOL, CONTRACT_URI, forwarders(), saleRecipient, platformFeeRecipient, platformFeeBps)
30+
);
31+
32+
dropImp = address(new HarnessDropERC20BeforeClaim());
33+
proxy = HarnessDropERC20BeforeClaim(address(new TWProxy(dropImp, initializeData)));
34+
}
35+
36+
modifier setMaxTotalSupply() {
37+
vm.prank(deployer);
38+
proxy.setMaxTotalSupply(100);
39+
_;
40+
}
41+
42+
modifier qtyExceedMaxTotalSupply() {
43+
mintQty = 101;
44+
_;
45+
}
46+
47+
function test_revert_MaxSupplyExceeded() public setMaxTotalSupply qtyExceedMaxTotalSupply {
48+
DropERC20.AllowlistProof memory proof;
49+
vm.expectRevert("exceed max total supply.");
50+
proxy.harness_beforeClaim(mintQty, proof);
51+
}
52+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
function _beforeClaim(
2+
address,
3+
uint256 _quantity,
4+
address,
5+
uint256,
6+
AllowlistProof calldata,
7+
bytes memory
8+
)
9+
└── when maxTotalSupply does not equal to 0 and totalSupply() + _quantity is greater than _maxTotalSupply
10+
└── it should revert ✅
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
pragma solidity ^0.8.0;
3+
4+
import { DropERC20 } from "contracts/prebuilts/drop/DropERC20.sol";
5+
import { TWProxy } from "contracts/infra/TWProxy.sol";
6+
7+
// Test imports
8+
import "../../../utils/BaseTest.sol";
9+
10+
contract HarnessDropERC20CanSet is DropERC20 {
11+
function canSetPlatformFeeInfo() external view returns (bool) {
12+
return _canSetPlatformFeeInfo();
13+
}
14+
15+
function canSetPrimarySaleRecipient() external view returns (bool) {
16+
return _canSetPrimarySaleRecipient();
17+
}
18+
19+
function canSetContractURI() external view returns (bool) {
20+
return _canSetContractURI();
21+
}
22+
23+
function canSetClaimConditions() external view returns (bool) {
24+
return _canSetClaimConditions();
25+
}
26+
}
27+
28+
contract DropERC20Test_canSet is BaseTest {
29+
address public dropImp;
30+
31+
HarnessDropERC20CanSet public proxy;
32+
33+
function setUp() public override {
34+
super.setUp();
35+
36+
bytes memory initializeData = abi.encodeCall(
37+
DropERC20.initialize,
38+
(deployer, NAME, SYMBOL, CONTRACT_URI, forwarders(), saleRecipient, platformFeeRecipient, platformFeeBps)
39+
);
40+
41+
dropImp = address(new HarnessDropERC20CanSet());
42+
proxy = HarnessDropERC20CanSet(address(new TWProxy(dropImp, initializeData)));
43+
}
44+
45+
modifier callerHasDefaultAdminRole() {
46+
vm.startPrank(deployer);
47+
_;
48+
}
49+
50+
modifier callerDoesNotHaveDefaultAdminRole() {
51+
_;
52+
}
53+
54+
function test_canSetPlatformFee_returnTrue() public callerHasDefaultAdminRole {
55+
bool status = proxy.canSetPlatformFeeInfo();
56+
assertEq(status, true);
57+
}
58+
59+
function test_canSetPlatformFee_returnFalse() public callerDoesNotHaveDefaultAdminRole {
60+
bool status = proxy.canSetPlatformFeeInfo();
61+
assertEq(status, false);
62+
}
63+
64+
function test_canSetPrimarySaleRecipient_returnTrue() public callerHasDefaultAdminRole {
65+
bool status = proxy.canSetPrimarySaleRecipient();
66+
assertEq(status, true);
67+
}
68+
69+
function test_canSetPrimarySaleRecipient_returnFalse() public callerDoesNotHaveDefaultAdminRole {
70+
bool status = proxy.canSetPrimarySaleRecipient();
71+
assertEq(status, false);
72+
}
73+
74+
function test_canSetContractURI_returnTrue() public callerHasDefaultAdminRole {
75+
bool status = proxy.canSetContractURI();
76+
assertEq(status, true);
77+
}
78+
79+
function test_canSetContractURI_returnFalse() public callerDoesNotHaveDefaultAdminRole {
80+
bool status = proxy.canSetContractURI();
81+
assertEq(status, false);
82+
}
83+
84+
function test_canSetClaimConditions_returnTrue() public callerHasDefaultAdminRole {
85+
bool status = proxy.canSetClaimConditions();
86+
assertEq(status, true);
87+
}
88+
89+
function test_canSetClaimConditions_returnFalse() public callerDoesNotHaveDefaultAdminRole {
90+
bool status = proxy.canSetClaimConditions();
91+
assertEq(status, false);
92+
}
93+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
function _canSetPlatformFeeInfo()
2+
├── when caller has DEFAULT_ADMIN_ROLE
3+
│ └── it should return true ✅
4+
└── when caller does not have DEFAULT_ADMIN_ROLE
5+
└── it should return false ✅
6+
7+
function _canSetPrimarySaleRecipient()
8+
├── when caller has DEFAULT_ADMIN_ROLE
9+
│ └── it should return true ✅
10+
└── when caller does not have DEFAULT_ADMIN_ROLE
11+
└── it should return false ✅
12+
13+
function _canSetContractURI()
14+
├── when caller has DEFAULT_ADMIN_ROLE
15+
│ └── it should return true ✅
16+
└── when caller does not have DEFAULT_ADMIN_ROLE
17+
└── it should return false ✅
18+
19+
function _canSetClaimConditions()
20+
├── when caller has DEFAULT_ADMIN_ROLE
21+
│ └── it should return true ✅
22+
└── when caller does not have DEFAULT_ADMIN_ROLE
23+
└── it should return false ✅
Lines changed: 209 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,209 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
pragma solidity ^0.8.0;
3+
4+
import { DropERC20 } from "contracts/prebuilts/drop/DropERC20.sol";
5+
import { TWProxy } from "contracts/infra/TWProxy.sol";
6+
7+
// Test imports
8+
import "../../../utils/BaseTest.sol";
9+
10+
contract HarnessDropERC20CollectPriceOnClaim is DropERC20 {
11+
function harness_collectPrice(
12+
address _primarySaleRecipient,
13+
uint256 _quantityToClaim,
14+
address _currency,
15+
uint256 _pricePerToken
16+
) public payable {
17+
_collectPriceOnClaim(_primarySaleRecipient, _quantityToClaim, _currency, _pricePerToken);
18+
}
19+
}
20+
21+
contract DropERC20Test_collectPrice is BaseTest {
22+
address public dropImp;
23+
HarnessDropERC20CollectPriceOnClaim public proxy;
24+
25+
address private currency;
26+
address private primarySaleRecipient;
27+
uint256 private msgValue;
28+
uint256 private pricePerToken;
29+
30+
function setUp() public override {
31+
super.setUp();
32+
33+
bytes memory initializeData = abi.encodeCall(
34+
DropERC20.initialize,
35+
(deployer, NAME, SYMBOL, CONTRACT_URI, forwarders(), saleRecipient, platformFeeRecipient, platformFeeBps)
36+
);
37+
38+
dropImp = address(new HarnessDropERC20CollectPriceOnClaim());
39+
proxy = HarnessDropERC20CollectPriceOnClaim(address(new TWProxy(dropImp, initializeData)));
40+
}
41+
42+
modifier pricePerTokenZero() {
43+
_;
44+
}
45+
46+
modifier pricePerTokenNotZero() {
47+
pricePerToken = 1 ether;
48+
_;
49+
}
50+
51+
modifier msgValueZero() {
52+
_;
53+
}
54+
55+
modifier msgValueNotZero() {
56+
msgValue = 1 ether;
57+
_;
58+
}
59+
60+
modifier valuePriceMismatch() {
61+
msgValue = 1 ether;
62+
pricePerToken = 2 ether;
63+
_;
64+
}
65+
66+
modifier primarySaleRecipientZeroAddress() {
67+
primarySaleRecipient = address(0);
68+
_;
69+
}
70+
71+
modifier primarySaleRecipientNotZeroAddress() {
72+
primarySaleRecipient = address(0x0999);
73+
_;
74+
}
75+
76+
modifier currencyNativeToken() {
77+
currency = NATIVE_TOKEN;
78+
_;
79+
}
80+
81+
modifier currencyNotNativeToken() {
82+
currency = address(erc20);
83+
_;
84+
}
85+
86+
function test_revert_pricePerTokenZeroMsgValueNotZero() public pricePerTokenZero msgValueNotZero {
87+
vm.expectRevert("!Value");
88+
proxy.harness_collectPrice{ value: msgValue }(primarySaleRecipient, 1 ether, currency, pricePerToken);
89+
}
90+
91+
function test_revert_nativeCurrencyTotalPriceZero() public pricePerTokenNotZero msgValueZero currencyNativeToken {
92+
vm.expectRevert("quantity too low");
93+
proxy.harness_collectPrice{ value: msgValue }(primarySaleRecipient, 0, currency, pricePerToken);
94+
}
95+
96+
function test_revert_nativeCurrencyValuePriceMismatch() public currencyNativeToken valuePriceMismatch {
97+
vm.expectRevert("Invalid msg value");
98+
proxy.harness_collectPrice{ value: msgValue }(primarySaleRecipient, 1 ether, currency, pricePerToken);
99+
}
100+
101+
function test_revert_erc20ValuePriceMismatch() public currencyNotNativeToken valuePriceMismatch {
102+
vm.expectRevert("Invalid msg value");
103+
proxy.harness_collectPrice{ value: msgValue }(primarySaleRecipient, 1 ether, currency, pricePerToken);
104+
}
105+
106+
function test_state_nativeCurrency()
107+
public
108+
currencyNativeToken
109+
pricePerTokenNotZero
110+
msgValueNotZero
111+
primarySaleRecipientNotZeroAddress
112+
{
113+
(address platformFeeRecipient, uint16 platformFeeBps) = proxy.getPlatformFeeInfo();
114+
uint256 beforeBalancePrimarySaleRecipient = address(primarySaleRecipient).balance;
115+
uint256 beforeBalancePlatformFeeRecipient = address(platformFeeRecipient).balance;
116+
117+
proxy.harness_collectPrice{ value: msgValue }(primarySaleRecipient, 1 ether, currency, pricePerToken);
118+
119+
uint256 afterBalancePrimarySaleRecipient = address(primarySaleRecipient).balance;
120+
uint256 afterBalancePlatformFeeRecipient = address(platformFeeRecipient).balance;
121+
122+
uint256 platformFeeVal = (msgValue * platformFeeBps) / MAX_BPS;
123+
uint256 primarySaleRecipientVal = msgValue - platformFeeVal;
124+
125+
assertEq(beforeBalancePrimarySaleRecipient + primarySaleRecipientVal, afterBalancePrimarySaleRecipient);
126+
assertEq(beforeBalancePlatformFeeRecipient + platformFeeVal, afterBalancePlatformFeeRecipient);
127+
}
128+
129+
function test_revert_erc20_msgValueNotZero()
130+
public
131+
currencyNotNativeToken
132+
msgValueNotZero
133+
primarySaleRecipientNotZeroAddress
134+
{
135+
vm.expectRevert("!Value");
136+
proxy.harness_collectPrice{ value: msgValue }(primarySaleRecipient, msgValue, currency, pricePerToken);
137+
}
138+
139+
function test_state_erc20() public currencyNotNativeToken pricePerTokenNotZero primarySaleRecipientNotZeroAddress {
140+
(address platformFeeRecipient, uint16 platformFeeBps) = proxy.getPlatformFeeInfo();
141+
142+
erc20.mint(address(this), pricePerToken);
143+
ERC20(erc20).approve(address(proxy), pricePerToken);
144+
uint256 beforeBalancePrimarySaleRecipient = erc20.balanceOf(primarySaleRecipient);
145+
uint256 beforeBalancePlatformFeeRecipient = erc20.balanceOf(platformFeeRecipient);
146+
147+
proxy.harness_collectPrice(primarySaleRecipient, pricePerToken, currency, pricePerToken);
148+
149+
uint256 afterBalancePrimarySaleRecipient = erc20.balanceOf(primarySaleRecipient);
150+
uint256 afterBalancePlatformFeeRecipient = erc20.balanceOf(platformFeeRecipient);
151+
152+
uint256 platformFeeVal = (pricePerToken * platformFeeBps) / MAX_BPS;
153+
uint256 primarySaleRecipientVal = 1 ether - platformFeeVal;
154+
155+
assertEq(beforeBalancePrimarySaleRecipient + primarySaleRecipientVal, afterBalancePrimarySaleRecipient);
156+
assertEq(beforeBalancePlatformFeeRecipient + platformFeeVal, afterBalancePlatformFeeRecipient);
157+
}
158+
159+
function test_state_erc20StoredPrimarySaleRecipient()
160+
public
161+
currencyNotNativeToken
162+
pricePerTokenNotZero
163+
primarySaleRecipientZeroAddress
164+
{
165+
(address platformFeeRecipient, uint16 platformFeeBps) = proxy.getPlatformFeeInfo();
166+
address storedPrimarySaleRecipient = proxy.primarySaleRecipient();
167+
168+
erc20.mint(address(this), pricePerToken);
169+
ERC20(erc20).approve(address(proxy), pricePerToken);
170+
uint256 beforeBalancePrimarySaleRecipient = erc20.balanceOf(storedPrimarySaleRecipient);
171+
uint256 beforeBalancePlatformFeeRecipient = erc20.balanceOf(platformFeeRecipient);
172+
173+
proxy.harness_collectPrice(primarySaleRecipient, pricePerToken, currency, pricePerToken);
174+
175+
uint256 afterBalancePrimarySaleRecipient = erc20.balanceOf(storedPrimarySaleRecipient);
176+
uint256 afterBalancePlatformFeeRecipient = erc20.balanceOf(platformFeeRecipient);
177+
178+
uint256 platformFeeVal = (pricePerToken * platformFeeBps) / MAX_BPS;
179+
uint256 primarySaleRecipientVal = 1 ether - platformFeeVal;
180+
181+
assertEq(beforeBalancePrimarySaleRecipient + primarySaleRecipientVal, afterBalancePrimarySaleRecipient);
182+
assertEq(beforeBalancePlatformFeeRecipient + platformFeeVal, afterBalancePlatformFeeRecipient);
183+
}
184+
185+
function test_state_nativeCurrencyStoredPrimarySaleRecipient()
186+
public
187+
currencyNativeToken
188+
pricePerTokenNotZero
189+
primarySaleRecipientZeroAddress
190+
msgValueNotZero
191+
{
192+
(address platformFeeRecipient, uint16 platformFeeBps) = proxy.getPlatformFeeInfo();
193+
address storedPrimarySaleRecipient = proxy.primarySaleRecipient();
194+
195+
uint256 beforeBalancePrimarySaleRecipient = address(storedPrimarySaleRecipient).balance;
196+
uint256 beforeBalancePlatformFeeRecipient = address(platformFeeRecipient).balance;
197+
198+
proxy.harness_collectPrice{ value: msgValue }(primarySaleRecipient, 1 ether, currency, pricePerToken);
199+
200+
uint256 afterBalancePrimarySaleRecipient = address(storedPrimarySaleRecipient).balance;
201+
uint256 afterBalancePlatformFeeRecipient = address(platformFeeRecipient).balance;
202+
203+
uint256 platformFeeVal = (msgValue * platformFeeBps) / MAX_BPS;
204+
uint256 primarySaleRecipientVal = msgValue - platformFeeVal;
205+
206+
assertEq(beforeBalancePrimarySaleRecipient + primarySaleRecipientVal, afterBalancePrimarySaleRecipient);
207+
assertEq(beforeBalancePlatformFeeRecipient + platformFeeVal, afterBalancePlatformFeeRecipient);
208+
}
209+
}

0 commit comments

Comments
 (0)