Skip to content
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

BTT Split #559

Merged
merged 8 commits into from
Nov 20, 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
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
Loading