Skip to content

Commit

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

* test setContractURI

* test other functions

* test release

* test distribute

* test distribute
  • Loading branch information
kumaryash90 authored Nov 20, 2023
1 parent 0dbbeef commit 85874e3
Show file tree
Hide file tree
Showing 14 changed files with 715 additions and 0 deletions.
78 changes: 78 additions & 0 deletions src/test/split-BTT/distribute-erc20/distribute.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.11;

import "../../utils/BaseTest.sol";
import "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol";

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

contract MySplit is Split {}

contract SplitTest_DistributeERC20 is BaseTest {
address payable public implementation;
address payable public proxy;

address[] public payees;
uint256[] public shares;

address internal caller;
string internal _contractURI;

MySplit internal splitContract;

event PaymentReleased(address to, uint256 amount);

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

// Deploy implementation.
implementation = payable(address(new MySplit()));

// create 5 payees and shares
for (uint160 i = 0; i < 5; i++) {
payees.push(getActor(i + 100));
shares.push(i + 100);
}

caller = getActor(1);

// Deploy proxy pointing to implementaion.
vm.prank(deployer);
proxy = payable(
address(
new TWProxy(
implementation,
abi.encodeCall(Split.initialize, (deployer, CONTRACT_URI, forwarders(), payees, shares))
)
)
);

splitContract = MySplit(proxy);
_contractURI = "ipfs://contracturi";

erc20.mint(address(splitContract), 100 ether);
}

function test_distribute() public {
uint256[] memory pendingAmounts = new uint256[](payees.length);

// get pending payments
for (uint256 i = 0; i < 5; i++) {
pendingAmounts[i] = splitContract.releasable(IERC20Upgradeable(address(erc20)), payees[i]);
}

// distribute
splitContract.distribute(IERC20Upgradeable(address(erc20)));

uint256 totalPaid;
for (uint256 i = 0; i < 5; i++) {
totalPaid += pendingAmounts[i];

assertEq(splitContract.released(IERC20Upgradeable(address(erc20)), payees[i]), pendingAmounts[i]);
assertEq(erc20.balanceOf(payees[i]), pendingAmounts[i]);
}
assertEq(splitContract.totalReleased(IERC20Upgradeable(address(erc20))), totalPaid);

assertEq(erc20.balanceOf(address(splitContract)), 100 ether - totalPaid);
}
}
6 changes: 6 additions & 0 deletions src/test/split-BTT/distribute-erc20/distribute.tree
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
distribute()
├── it should update released mapping for all payees account by respective pending payments ✅
├── it should update total released by total pending payments ✅
├── it should send correct pending payment amounts of erc20 tokens to each account ✅
├── it should reduce balance of contract by total paid in this call ✅

77 changes: 77 additions & 0 deletions src/test/split-BTT/distribute-native-token/distribute.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.11;

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

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

contract MySplit is Split {}

contract SplitTest_DistributeNativeToken is BaseTest {
address payable public implementation;
address payable public proxy;

address[] public payees;
uint256[] public shares;

address internal caller;
string internal _contractURI;

MySplit internal splitContract;

event PaymentReleased(address to, uint256 amount);

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

// Deploy implementation.
implementation = payable(address(new MySplit()));

// create 5 payees and shares
for (uint160 i = 0; i < 5; i++) {
payees.push(getActor(i + 100));
shares.push(i + 100);
}

caller = getActor(1);

// Deploy proxy pointing to implementaion.
vm.prank(deployer);
proxy = payable(
address(
new TWProxy(
implementation,
abi.encodeCall(Split.initialize, (deployer, CONTRACT_URI, forwarders(), payees, shares))
)
)
);

splitContract = MySplit(proxy);
_contractURI = "ipfs://contracturi";

vm.deal(address(splitContract), 100 ether);
}

function test_distribute() public {
uint256[] memory pendingAmounts = new uint256[](payees.length);

// get pending payments
for (uint256 i = 0; i < 5; i++) {
pendingAmounts[i] = splitContract.releasable(payees[i]);
}

// distribute
splitContract.distribute();

uint256 totalPaid;
for (uint256 i = 0; i < 5; i++) {
totalPaid += pendingAmounts[i];

assertEq(splitContract.released(payees[i]), pendingAmounts[i]);
assertEq(payees[i].balance, pendingAmounts[i]);
}
assertEq(splitContract.totalReleased(), totalPaid);

assertEq(address(splitContract).balance, 100 ether - totalPaid);
}
}
6 changes: 6 additions & 0 deletions src/test/split-BTT/distribute-native-token/distribute.tree
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
distribute()
├── it should update released mapping for all payees account by respective pending payments ✅
├── it should update total released by total pending payments ✅
├── it should send correct pending payment amounts of native tokens to each account ✅
├── it should reduce balance of contract by total paid in this call ✅

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

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

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

contract MySplit is Split {}

contract SplitTest_Initialize is BaseTest {
address payable public implementation;
address payable public proxy;

address[] public payees;
uint256[] public shares;

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

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

// create 5 payees and shares
for (uint160 i = 0; i < 5; i++) {
payees.push(getActor(i + 100));
shares.push(i + 100);
}

// Deploy implementation.
implementation = payable(address(new MySplit()));

// Deploy proxy pointing to implementaion.
vm.prank(deployer);
proxy = payable(
address(
new TWProxy(
implementation,
abi.encodeCall(Split.initialize, (deployer, CONTRACT_URI, forwarders(), payees, shares))
)
)
);
}

function test_initialize_initializingImplementation() public {
vm.expectRevert("Initializable: contract is already initialized");
Split(implementation).initialize(deployer, CONTRACT_URI, forwarders(), payees, shares);
}

modifier whenNotImplementation() {
_;
}

function test_initialize_proxyAlreadyInitialized() public whenNotImplementation {
vm.expectRevert("Initializable: contract is already initialized");
MySplit(proxy).initialize(deployer, CONTRACT_URI, forwarders(), payees, shares);
}

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

function test_initialize_payeeLengthZero() public whenNotImplementation whenProxyNotInitialized {
address[] memory _payees;
uint256[] memory _shares;
vm.expectRevert("PaymentSplitter: no payees");
MySplit(proxy).initialize(deployer, CONTRACT_URI, forwarders(), _payees, _shares);
}

modifier whenPayeeLengthNotZero() {
_;
}

function test_initialize_payeesSharesUnequalLength()
public
whenNotImplementation
whenProxyNotInitialized
whenPayeeLengthNotZero
{
uint256[] memory _shares;
vm.expectRevert("PaymentSplitter: payees and shares length mismatch");
MySplit(proxy).initialize(deployer, CONTRACT_URI, forwarders(), payees, _shares);
}

modifier whenEqualLengths() {
_;
}

function test_initialize()
public
whenNotImplementation
whenProxyNotInitialized
whenPayeeLengthNotZero
whenEqualLengths
{
MySplit(proxy).initialize(deployer, CONTRACT_URI, forwarders(), payees, shares);

// check state
MySplit splitContract = MySplit(proxy);

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

uint256 totalShares;
for (uint160 i = 0; i < 5; i++) {
uint256 _shares = splitContract.shares(payees[i]);
assertEq(_shares, shares[i]);

totalShares += _shares;
}
assertEq(totalShares, splitContract.totalShares());
assertEq(splitContract.payeeCount(), payees.length);
assertEq(splitContract.contractURI(), CONTRACT_URI);
assertTrue(splitContract.hasRole(bytes32(0x00), deployer));
}

function test_initialize_event_RoleGranted_DefaultAdmin()
public
whenNotImplementation
whenProxyNotInitialized
whenPayeeLengthNotZero
whenEqualLengths
{
bytes32 _defaultAdminRole = bytes32(0x00);
vm.prank(deployer);
vm.expectEmit(true, true, true, false);
emit RoleGranted(_defaultAdminRole, deployer, deployer);
MySplit(proxy).initialize(deployer, CONTRACT_URI, forwarders(), payees, shares);
}
}
25 changes: 25 additions & 0 deletions src/test/split-BTT/initialize/initialize.tree
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
initialize(
address _defaultAdmin,
string memory _contractURI,
address[] memory _trustedForwarders,
address[] memory _payees,
uint256[] memory _shares
)
├── 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 `_payees` length is zero
│ └── it should revert ✅
└── `_payees` length is not zero
└── when `_payees` length not equal to `_shares` length
│ └── it should revert ✅
└── when `_payees` length equal to `_shares` length
└── it should set trustedForwarder mapping to true for all addresses in `_trustedForwarders` ✅
└── it should correctly save `_payees` and `_shares` in state ✅
└── it should set contractURI to `_contractURI` param value ✅
└── it should grant 0x00 (DEFAULT_ADMIN_ROLE) to `_defaultAdmin` address ✅
└── it should emit RoleGranted event ✅

58 changes: 58 additions & 0 deletions src/test/split-BTT/other-functions/other.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;

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

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

contract MySplit is Split {}

contract SplitTest_OtherFunctions is BaseTest {
address payable public implementation;
address payable public proxy;

address[] public payees;
uint256[] public shares;

address internal caller;
string internal _contractURI;

MySplit internal splitContract;

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

// Deploy implementation.
implementation = payable(address(new MySplit()));

// create 5 payees and shares
for (uint160 i = 0; i < 5; i++) {
payees.push(getActor(i + 100));
shares.push(i + 100);
}

caller = getActor(1);

// Deploy proxy pointing to implementaion.
vm.prank(deployer);
proxy = payable(
address(
new TWProxy(
implementation,
abi.encodeCall(Split.initialize, (deployer, CONTRACT_URI, forwarders(), payees, shares))
)
)
);

splitContract = MySplit(proxy);
_contractURI = "ipfs://contracturi";
}

function test_contractType() public {
assertEq(splitContract.contractType(), bytes32("Split"));
}

function test_contractVersion() public {
assertEq(splitContract.contractVersion(), uint8(1));
}
}
5 changes: 5 additions & 0 deletions src/test/split-BTT/other-functions/other.tree
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
contractType()
├── it should return bytes32("TokenERC721") ✅

contractVersion()
├── it should return uint8(1) ✅
Loading

0 comments on commit 85874e3

Please sign in to comment.