Skip to content

Commit

Permalink
test: add sablier fees tests
Browse files Browse the repository at this point in the history
  • Loading branch information
andreivladbrg committed Jan 10, 2025
1 parent e2c1af4 commit 612bb77
Show file tree
Hide file tree
Showing 6 changed files with 135 additions and 0 deletions.
2 changes: 2 additions & 0 deletions src/SablierFees.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import { Adminable } from "./Adminable.sol";
/// @title SablierFees
/// @notice See the documentation in {ISablierFees}.
abstract contract SablierFees is Adminable, ISablierFees {
constructor(address initialAdmin) Adminable(initialAdmin) { }

/// @inheritdoc ISablierFees
function collectFees() external override {
uint256 feeAmount = address(this).balance;
Expand Down
8 changes: 8 additions & 0 deletions tests/mocks/Receive.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity >=0.8.22 <0.9.0;

contract ContractWithoutReceive { }

contract ContractWithReceive {
receive() external payable { }
}
8 changes: 8 additions & 0 deletions tests/mocks/SablierFeesMock.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity >=0.8.22;

import { SablierFees } from "src/SablierFees.sol";

contract SablierFeesMock is SablierFees {
constructor(address initialAdmin) SablierFees(initialAdmin) { }
}
24 changes: 24 additions & 0 deletions tests/unit/Unit.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity >=0.8.22 <0.9.0;

import { CommonBase } from "../Base.t.sol";
import { ContractWithoutReceive, ContractWithReceive } from "../mocks/Receive.sol";

abstract contract Unit_Test is CommonBase {
address internal admin;
address internal eve;

ContractWithoutReceive internal contractWithoutReceive;
ContractWithReceive internal contractWithReceive;

function setUp() public virtual override {
CommonBase.setUp();

admin = createUser("admin");
eve = createUser("eve");
contractWithoutReceive = new ContractWithoutReceive();
contractWithReceive = new ContractWithReceive();

resetPrank(admin);
}
}
81 changes: 81 additions & 0 deletions tests/unit/sablier-fees/collectFees.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity >=0.8.22 <0.9.0;

import { ISablierFees } from "src/interfaces/ISablierFees.sol";
import { Errors } from "src/libraries/Errors.sol";

import { Unit_Test } from "../Unit.t.sol";
import { SablierFeesMock } from "../../mocks/SablierFeesMock.sol";

contract CollectFees_Unit_Concrete_Test is Unit_Test {
SablierFeesMock internal sablierFeesMock;

function setUp() public virtual override {
Unit_Test.setUp();

sablierFeesMock = new SablierFeesMock(admin);
}

function test_GivenAdminIsNotContract() external {
_test_CollectFees(admin);
}

modifier givenAdminIsContract() {
_;
}

function test_RevertGiven_AdminDoesNotImplementReceiveFunction() external givenAdminIsContract {
// Transfer the admin to a contract that does not implement the receive function.
resetPrank({ msgSender: admin });
sablierFeesMock.transferAdmin(address(contractWithoutReceive));

// Make the contract the caller.
resetPrank({ msgSender: address(contractWithoutReceive) });

// Expect a revert.
vm.expectRevert(
abi.encodeWithSelector(
Errors.SablierFees_FeeTransferFail.selector,
address(contractWithoutReceive),
address(sablierFeesMock).balance
)
);

// Collect the fees.
sablierFeesMock.collectFees();
}

function test_GivenAdminImplementsReceiveFunction() external givenAdminIsContract {
// Transfer the admin to a contract that implements the receive function.
resetPrank({ msgSender: admin });
sablierFeesMock.transferAdmin(address(contractWithReceive));

// Make the contract the caller.
resetPrank({ msgSender: address(contractWithReceive) });

// Run the tests.
_test_CollectFees(address(contractWithReceive));
}

function _test_CollectFees(address admin) private {
uint256 fee = 1 ether;

// Set the contract balance to 1 ETH.
vm.deal({ account: address(sablierFeesMock), newBalance: 1 ether });

// Load the initial ETH balance of the admin.
uint256 initialAdminBalance = admin.balance;

// It should emit a {CollectFees} event.
vm.expectEmit({ emitter: address(sablierFeesMock) });
emit ISablierFees.CollectFees({ admin: admin, feeAmount: fee });

sablierFeesMock.collectFees();

// It should transfer the fee.
assertEq(admin.balance, initialAdminBalance + fee, "admin ETH balance");

// It should decrease contract balance to zero.
assertEq(address(sablierFeesMock).balance, 0, "sablierFeesMock ETH balance");
}
}
12 changes: 12 additions & 0 deletions tests/unit/sablier-fees/collectFees.tree
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
CollectFees_Unit_Concrete_Test
β”œβ”€β”€ given admin is not contract
β”‚ β”œβ”€β”€ it should transfer fee
β”‚ β”œβ”€β”€ it should decrease contract balance to zero
β”‚ └── it should emit a {CollectFees} event
└── given admin is contract
β”œβ”€β”€ given admin does not implement receive function
β”‚ └── it should revert
└── given admin implements receive function
β”œβ”€β”€ it should transfer fee
β”œβ”€β”€ it should decrease contract balance to zero
└── it should emit a {CollectFees} event

0 comments on commit 612bb77

Please sign in to comment.