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

feat: adding btt tests for bToken #167

Merged
merged 3 commits into from
Jul 23, 2024
Merged
Show file tree
Hide file tree
Changes from 2 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
190 changes: 65 additions & 125 deletions test/unit/BToken.t.sol
Original file line number Diff line number Diff line change
@@ -1,154 +1,94 @@
// SPDX-License-Identifier: GPL-3
pragma solidity ^0.8.25;
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.25;

import {IERC20Errors} from '@openzeppelin/contracts/interfaces/draft-IERC6093.sol';
import {Test} from 'forge-std/Test.sol';
import {MockBToken} from 'test/smock/MockBToken.sol';

contract BToken_Unit_Constructor is Test {
function test_ConstructorParams() public {
MockBToken btoken = new MockBToken();
assertEq(btoken.name(), 'Balancer Pool Token');
assertEq(btoken.symbol(), 'BPT');
assertEq(btoken.decimals(), 18);
}
}
contract BToken is Test {
MockBToken public bToken;
uint256 public initialApproval = 100e18;
uint256 public initialBalance = 100e18;
address public caller = makeAddr('caller');
address public spender = makeAddr('spender');
address public target = makeAddr('target');

abstract contract BToken_Unit_base is Test {
MockBToken internal bToken;
function setUp() external {
bToken = new MockBToken();

modifier assumeNonZeroAddresses(address addr1, address addr2) {
vm.assume(addr1 != address(0));
vm.assume(addr2 != address(0));
_;
vm.startPrank(caller);
// sets initial approval (cannot be mocked)
bToken.approve(spender, initialApproval);
}

modifier assumeNonZeroAddress(address addr) {
vm.assume(addr != address(0));
_;
function test_ConstructorWhenCalled() external {
MockBToken _bToken = new MockBToken();
// it sets token name
assertEq(_bToken.name(), 'Balancer Pool Token');
// it sets token symbol
assertEq(_bToken.symbol(), 'BPT');
}

function setUp() public virtual {
bToken = new MockBToken();
function test_IncreaseApprovalRevertWhen_SenderIsAddressZero() external {
vm.startPrank(address(0));
// it should revert
vm.expectRevert(abi.encodeWithSelector(IERC20Errors.ERC20InvalidApprover.selector, address(0)));

bToken.increaseApproval(spender, 100e18);
}
}

contract BToken_Unit_IncreaseApproval is BToken_Unit_base {
function test_increasesApprovalFromZero(
address sender,
address spender,
uint256 amount
) public assumeNonZeroAddresses(sender, spender) {
vm.prank(sender);
bToken.increaseApproval(spender, amount);
assertEq(bToken.allowance(sender, spender), amount);
function test_IncreaseApprovalRevertWhen_SpenderIsAddressZero() external {
// it should revert
vm.expectRevert(abi.encodeWithSelector(IERC20Errors.ERC20InvalidSpender.selector, address(0)));
bToken.increaseApproval(address(0), 100e18);
}

function test_increasesApprovalFromNonZero(
address sender,
address spender,
uint128 existingAllowance,
uint128 amount
) public assumeNonZeroAddresses(sender, spender) {
vm.assume(existingAllowance > 0);
vm.startPrank(sender);
bToken.approve(spender, existingAllowance);
bToken.increaseApproval(spender, amount);
vm.stopPrank();
assertEq(bToken.allowance(sender, spender), uint256(amount) + existingAllowance);
function test_IncreaseApprovalWhenCalled() external {
bToken.increaseApproval(spender, 100e18);
// it increases spender approval
assertEq(bToken.allowance(caller, spender), 200e18);
}
}

contract BToken_Unit_DecreaseApproval is BToken_Unit_base {
function test_decreaseApprovalToNonZero(
address sender,
address spender,
uint256 existingAllowance,
uint256 amount
) public assumeNonZeroAddresses(sender, spender) {
existingAllowance = bound(existingAllowance, 1, type(uint256).max);
amount = bound(amount, 0, existingAllowance - 1);
vm.startPrank(sender);
bToken.approve(spender, existingAllowance);
bToken.decreaseApproval(spender, amount);
vm.stopPrank();
assertEq(bToken.allowance(sender, spender), existingAllowance - amount);
function test_DecreaseApprovalRevertWhen_SenderIsAddressZero() external {
vm.startPrank(address(0));
// it should revert
vm.expectRevert(abi.encodeWithSelector(IERC20Errors.ERC20InvalidApprover.selector, address(0)));
bToken.decreaseApproval(spender, 50e18);
}

function test_decreaseApprovalToZero(
address sender,
address spender,
uint256 existingAllowance,
uint256 amount
) public assumeNonZeroAddresses(sender, spender) {
amount = bound(amount, existingAllowance, type(uint256).max);
vm.startPrank(sender);
bToken.approve(spender, existingAllowance);
bToken.decreaseApproval(spender, amount);
vm.stopPrank();
assertEq(bToken.allowance(sender, spender), 0);
function test_DecreaseApprovalRevertWhen_SpenderIsAddressZero() external {
// it should revert
vm.expectRevert(abi.encodeWithSelector(IERC20Errors.ERC20InvalidSpender.selector, address(0)));
bToken.decreaseApproval(address(0), 50e18);
}
}

contract BToken_Unit__push is BToken_Unit_base {
function test_revertsOnInsufficientSelfBalance(
address to,
uint128 existingBalance,
uint128 offset
) public assumeNonZeroAddress(to) {
vm.assume(offset > 1);
deal(address(bToken), address(bToken), existingBalance);
vm.expectRevert(
abi.encodeWithSelector(
IERC20Errors.ERC20InsufficientBalance.selector,
address(bToken),
existingBalance,
uint256(existingBalance) + offset
)
);
bToken.call__push(to, uint256(existingBalance) + offset);
function test_DecreaseApprovalWhenDecrementIsBiggerThanCurrentApproval() external {
bToken.decreaseApproval(spender, 200e18);
// it decreases spender approval to 0
assertEq(bToken.allowance(caller, spender), 0);
}

function test_sendsTokens(
address to,
uint128 existingBalance,
uint256 transferAmount
) public assumeNonZeroAddress(to) {
vm.assume(to != address(bToken));
transferAmount = bound(transferAmount, 0, existingBalance);
deal(address(bToken), address(bToken), existingBalance);
bToken.call__push(to, transferAmount);
assertEq(bToken.balanceOf(to), transferAmount);
assertEq(bToken.balanceOf(address(bToken)), existingBalance - transferAmount);
function test_DecreaseApprovalWhenCalled() external {
bToken.decreaseApproval(spender, 50e18);
// it decreases spender approval
assertEq(bToken.allowance(caller, spender), 50e18);
}
}

contract BToken_Unit__pull is BToken_Unit_base {
function test_revertsOnInsufficientFromBalance(
address from,
uint128 existingBalance,
uint128 offset
) public assumeNonZeroAddress(from) {
vm.assume(offset > 1);
deal(address(bToken), from, existingBalance);
vm.expectRevert(
abi.encodeWithSelector(
IERC20Errors.ERC20InsufficientBalance.selector, from, existingBalance, uint256(existingBalance) + offset
)
);
bToken.call__pull(from, uint256(existingBalance) + offset);
function test__pushWhenCalled() external {
deal(address(bToken), address(bToken), initialBalance);
bToken.call__push(target, 50e18);

// it transfers tokens to recipient
assertEq(bToken.balanceOf(address(bToken)), 50e18);
assertEq(bToken.balanceOf(target), 50e18);
}

function test_getsTokens(
address from,
uint128 existingBalance,
uint256 transferAmount
) public assumeNonZeroAddress(from) {
vm.assume(from != address(bToken));
transferAmount = bound(transferAmount, 0, existingBalance);
deal(address(bToken), address(from), existingBalance);
bToken.call__pull(from, transferAmount);
assertEq(bToken.balanceOf(address(bToken)), transferAmount);
assertEq(bToken.balanceOf(from), existingBalance - transferAmount);
function test__pullWhenCalled() external {
deal(address(bToken), address(target), initialBalance);
bToken.call__pull(target, 50e18);

// it transfers tokens from sender
assertEq(bToken.balanceOf(target), 50e18);
assertEq(bToken.balanceOf(address(bToken)), 50e18);
}
}
30 changes: 30 additions & 0 deletions test/unit/BToken.tree
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
BToken::constructor
└── when called
├── it sets token name
└── it sets token symbol

BToken::increaseApproval
├── when sender is address zero
│ └── it should revert
├── when spender is address zero

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how could we get to this? I imagine the assertion was added to OZ to avoid programeer errors when calling the internal method, but is there any context in where an external caller could beaddress(0)?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmmm is not, but is an actual possible branch, it actually happens inside _approve so tbh i wouldn't care so much for it

│ └── it should revert
└── when called
└── it increases spender approval
0xteddybear marked this conversation as resolved.
Show resolved Hide resolved

BToken::decreaseApproval
├── when sender is address zero
│ └── it should revert
├── when spender is address zero
│ └── it should revert
├── when decrement is bigger than current approval
│ └── it decreases spender approval to 0
└── when called
└── it decreases spender approval

BToken::_push
└── when called
└── it transfers tokens to recipient

BToken::_pull
└── when called
└── it transfers tokens from sender
Loading