Skip to content

Commit 85874e3

Browse files
authored
BTT Split (#559)
* test initialize * test setContractURI * test other functions * test release * test distribute * test distribute
1 parent 0dbbeef commit 85874e3

File tree

14 files changed

+715
-0
lines changed

14 files changed

+715
-0
lines changed
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
pragma solidity ^0.8.11;
3+
4+
import "../../utils/BaseTest.sol";
5+
import "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol";
6+
7+
import { TWProxy } from "contracts/infra/TWProxy.sol";
8+
9+
contract MySplit is Split {}
10+
11+
contract SplitTest_DistributeERC20 is BaseTest {
12+
address payable public implementation;
13+
address payable public proxy;
14+
15+
address[] public payees;
16+
uint256[] public shares;
17+
18+
address internal caller;
19+
string internal _contractURI;
20+
21+
MySplit internal splitContract;
22+
23+
event PaymentReleased(address to, uint256 amount);
24+
25+
function setUp() public override {
26+
super.setUp();
27+
28+
// Deploy implementation.
29+
implementation = payable(address(new MySplit()));
30+
31+
// create 5 payees and shares
32+
for (uint160 i = 0; i < 5; i++) {
33+
payees.push(getActor(i + 100));
34+
shares.push(i + 100);
35+
}
36+
37+
caller = getActor(1);
38+
39+
// Deploy proxy pointing to implementaion.
40+
vm.prank(deployer);
41+
proxy = payable(
42+
address(
43+
new TWProxy(
44+
implementation,
45+
abi.encodeCall(Split.initialize, (deployer, CONTRACT_URI, forwarders(), payees, shares))
46+
)
47+
)
48+
);
49+
50+
splitContract = MySplit(proxy);
51+
_contractURI = "ipfs://contracturi";
52+
53+
erc20.mint(address(splitContract), 100 ether);
54+
}
55+
56+
function test_distribute() public {
57+
uint256[] memory pendingAmounts = new uint256[](payees.length);
58+
59+
// get pending payments
60+
for (uint256 i = 0; i < 5; i++) {
61+
pendingAmounts[i] = splitContract.releasable(IERC20Upgradeable(address(erc20)), payees[i]);
62+
}
63+
64+
// distribute
65+
splitContract.distribute(IERC20Upgradeable(address(erc20)));
66+
67+
uint256 totalPaid;
68+
for (uint256 i = 0; i < 5; i++) {
69+
totalPaid += pendingAmounts[i];
70+
71+
assertEq(splitContract.released(IERC20Upgradeable(address(erc20)), payees[i]), pendingAmounts[i]);
72+
assertEq(erc20.balanceOf(payees[i]), pendingAmounts[i]);
73+
}
74+
assertEq(splitContract.totalReleased(IERC20Upgradeable(address(erc20))), totalPaid);
75+
76+
assertEq(erc20.balanceOf(address(splitContract)), 100 ether - totalPaid);
77+
}
78+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
distribute()
2+
├── it should update released mapping for all payees account by respective pending payments ✅
3+
├── it should update total released by total pending payments ✅
4+
├── it should send correct pending payment amounts of erc20 tokens to each account ✅
5+
├── it should reduce balance of contract by total paid in this call ✅
6+
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
pragma solidity ^0.8.11;
3+
4+
import "../../utils/BaseTest.sol";
5+
6+
import { TWProxy } from "contracts/infra/TWProxy.sol";
7+
8+
contract MySplit is Split {}
9+
10+
contract SplitTest_DistributeNativeToken is BaseTest {
11+
address payable public implementation;
12+
address payable public proxy;
13+
14+
address[] public payees;
15+
uint256[] public shares;
16+
17+
address internal caller;
18+
string internal _contractURI;
19+
20+
MySplit internal splitContract;
21+
22+
event PaymentReleased(address to, uint256 amount);
23+
24+
function setUp() public override {
25+
super.setUp();
26+
27+
// Deploy implementation.
28+
implementation = payable(address(new MySplit()));
29+
30+
// create 5 payees and shares
31+
for (uint160 i = 0; i < 5; i++) {
32+
payees.push(getActor(i + 100));
33+
shares.push(i + 100);
34+
}
35+
36+
caller = getActor(1);
37+
38+
// Deploy proxy pointing to implementaion.
39+
vm.prank(deployer);
40+
proxy = payable(
41+
address(
42+
new TWProxy(
43+
implementation,
44+
abi.encodeCall(Split.initialize, (deployer, CONTRACT_URI, forwarders(), payees, shares))
45+
)
46+
)
47+
);
48+
49+
splitContract = MySplit(proxy);
50+
_contractURI = "ipfs://contracturi";
51+
52+
vm.deal(address(splitContract), 100 ether);
53+
}
54+
55+
function test_distribute() public {
56+
uint256[] memory pendingAmounts = new uint256[](payees.length);
57+
58+
// get pending payments
59+
for (uint256 i = 0; i < 5; i++) {
60+
pendingAmounts[i] = splitContract.releasable(payees[i]);
61+
}
62+
63+
// distribute
64+
splitContract.distribute();
65+
66+
uint256 totalPaid;
67+
for (uint256 i = 0; i < 5; i++) {
68+
totalPaid += pendingAmounts[i];
69+
70+
assertEq(splitContract.released(payees[i]), pendingAmounts[i]);
71+
assertEq(payees[i].balance, pendingAmounts[i]);
72+
}
73+
assertEq(splitContract.totalReleased(), totalPaid);
74+
75+
assertEq(address(splitContract).balance, 100 ether - totalPaid);
76+
}
77+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
distribute()
2+
├── it should update released mapping for all payees account by respective pending payments ✅
3+
├── it should update total released by total pending payments ✅
4+
├── it should send correct pending payment amounts of native tokens to each account ✅
5+
├── it should reduce balance of contract by total paid in this call ✅
6+
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
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 MySplit is Split {}
9+
10+
contract SplitTest_Initialize is BaseTest {
11+
address payable public implementation;
12+
address payable public proxy;
13+
14+
address[] public payees;
15+
uint256[] public shares;
16+
17+
event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);
18+
19+
function setUp() public override {
20+
super.setUp();
21+
22+
// create 5 payees and shares
23+
for (uint160 i = 0; i < 5; i++) {
24+
payees.push(getActor(i + 100));
25+
shares.push(i + 100);
26+
}
27+
28+
// Deploy implementation.
29+
implementation = payable(address(new MySplit()));
30+
31+
// Deploy proxy pointing to implementaion.
32+
vm.prank(deployer);
33+
proxy = payable(
34+
address(
35+
new TWProxy(
36+
implementation,
37+
abi.encodeCall(Split.initialize, (deployer, CONTRACT_URI, forwarders(), payees, shares))
38+
)
39+
)
40+
);
41+
}
42+
43+
function test_initialize_initializingImplementation() public {
44+
vm.expectRevert("Initializable: contract is already initialized");
45+
Split(implementation).initialize(deployer, CONTRACT_URI, forwarders(), payees, shares);
46+
}
47+
48+
modifier whenNotImplementation() {
49+
_;
50+
}
51+
52+
function test_initialize_proxyAlreadyInitialized() public whenNotImplementation {
53+
vm.expectRevert("Initializable: contract is already initialized");
54+
MySplit(proxy).initialize(deployer, CONTRACT_URI, forwarders(), payees, shares);
55+
}
56+
57+
modifier whenProxyNotInitialized() {
58+
proxy = payable(address(new TWProxy(implementation, "")));
59+
_;
60+
}
61+
62+
function test_initialize_payeeLengthZero() public whenNotImplementation whenProxyNotInitialized {
63+
address[] memory _payees;
64+
uint256[] memory _shares;
65+
vm.expectRevert("PaymentSplitter: no payees");
66+
MySplit(proxy).initialize(deployer, CONTRACT_URI, forwarders(), _payees, _shares);
67+
}
68+
69+
modifier whenPayeeLengthNotZero() {
70+
_;
71+
}
72+
73+
function test_initialize_payeesSharesUnequalLength()
74+
public
75+
whenNotImplementation
76+
whenProxyNotInitialized
77+
whenPayeeLengthNotZero
78+
{
79+
uint256[] memory _shares;
80+
vm.expectRevert("PaymentSplitter: payees and shares length mismatch");
81+
MySplit(proxy).initialize(deployer, CONTRACT_URI, forwarders(), payees, _shares);
82+
}
83+
84+
modifier whenEqualLengths() {
85+
_;
86+
}
87+
88+
function test_initialize()
89+
public
90+
whenNotImplementation
91+
whenProxyNotInitialized
92+
whenPayeeLengthNotZero
93+
whenEqualLengths
94+
{
95+
MySplit(proxy).initialize(deployer, CONTRACT_URI, forwarders(), payees, shares);
96+
97+
// check state
98+
MySplit splitContract = MySplit(proxy);
99+
100+
address[] memory _trustedForwarders = forwarders();
101+
for (uint256 i = 0; i < _trustedForwarders.length; i++) {
102+
assertTrue(splitContract.isTrustedForwarder(_trustedForwarders[i]));
103+
}
104+
105+
uint256 totalShares;
106+
for (uint160 i = 0; i < 5; i++) {
107+
uint256 _shares = splitContract.shares(payees[i]);
108+
assertEq(_shares, shares[i]);
109+
110+
totalShares += _shares;
111+
}
112+
assertEq(totalShares, splitContract.totalShares());
113+
assertEq(splitContract.payeeCount(), payees.length);
114+
assertEq(splitContract.contractURI(), CONTRACT_URI);
115+
assertTrue(splitContract.hasRole(bytes32(0x00), deployer));
116+
}
117+
118+
function test_initialize_event_RoleGranted_DefaultAdmin()
119+
public
120+
whenNotImplementation
121+
whenProxyNotInitialized
122+
whenPayeeLengthNotZero
123+
whenEqualLengths
124+
{
125+
bytes32 _defaultAdminRole = bytes32(0x00);
126+
vm.prank(deployer);
127+
vm.expectEmit(true, true, true, false);
128+
emit RoleGranted(_defaultAdminRole, deployer, deployer);
129+
MySplit(proxy).initialize(deployer, CONTRACT_URI, forwarders(), payees, shares);
130+
}
131+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
initialize(
2+
address _defaultAdmin,
3+
string memory _contractURI,
4+
address[] memory _trustedForwarders,
5+
address[] memory _payees,
6+
uint256[] memory _shares
7+
)
8+
├── when initializing the implementation contract (not proxy)
9+
│ └── it should revert ✅
10+
└── when it is a proxy to the implementation
11+
└── when it is already initialized
12+
│ └── it should revert ✅
13+
└── when it is not initialized
14+
└── when `_payees` length is zero
15+
│ └── it should revert ✅
16+
└── `_payees` length is not zero
17+
└── when `_payees` length not equal to `_shares` length
18+
│ └── it should revert ✅
19+
└── when `_payees` length equal to `_shares` length
20+
└── it should set trustedForwarder mapping to true for all addresses in `_trustedForwarders` ✅
21+
└── it should correctly save `_payees` and `_shares` in state ✅
22+
└── it should set contractURI to `_contractURI` param value ✅
23+
└── it should grant 0x00 (DEFAULT_ADMIN_ROLE) to `_defaultAdmin` address ✅
24+
└── it should emit RoleGranted event ✅
25+
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
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 MySplit is Split {}
9+
10+
contract SplitTest_OtherFunctions is BaseTest {
11+
address payable public implementation;
12+
address payable public proxy;
13+
14+
address[] public payees;
15+
uint256[] public shares;
16+
17+
address internal caller;
18+
string internal _contractURI;
19+
20+
MySplit internal splitContract;
21+
22+
function setUp() public override {
23+
super.setUp();
24+
25+
// Deploy implementation.
26+
implementation = payable(address(new MySplit()));
27+
28+
// create 5 payees and shares
29+
for (uint160 i = 0; i < 5; i++) {
30+
payees.push(getActor(i + 100));
31+
shares.push(i + 100);
32+
}
33+
34+
caller = getActor(1);
35+
36+
// Deploy proxy pointing to implementaion.
37+
vm.prank(deployer);
38+
proxy = payable(
39+
address(
40+
new TWProxy(
41+
implementation,
42+
abi.encodeCall(Split.initialize, (deployer, CONTRACT_URI, forwarders(), payees, shares))
43+
)
44+
)
45+
);
46+
47+
splitContract = MySplit(proxy);
48+
_contractURI = "ipfs://contracturi";
49+
}
50+
51+
function test_contractType() public {
52+
assertEq(splitContract.contractType(), bytes32("Split"));
53+
}
54+
55+
function test_contractVersion() public {
56+
assertEq(splitContract.contractVersion(), uint8(1));
57+
}
58+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
contractType()
2+
├── it should return bytes32("TokenERC721") ✅
3+
4+
contractVersion()
5+
├── it should return uint8(1) ✅

0 commit comments

Comments
 (0)