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

test: btt tests for joinswapPoolAmountOut #170

Merged
merged 4 commits into from
Jul 22, 2024
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
95 changes: 95 additions & 0 deletions test/unit/BPool/BPool_JoinswapPoolAmountOut.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.25;

import {BPoolBase} from './BPoolBase.sol';
import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol';

import {BNum} from 'contracts/BNum.sol';
import {IBPool} from 'interfaces/IBPool.sol';

contract BPoolJoinswapPoolAmountOut is BPoolBase, BNum {
address public tokenIn;

// Valid scenario
uint256 public poolAmountOut = 1e18;
uint256 public tokenInWeight = 8e18;
uint256 public totalWeight = 10e18;
uint256 public tokenInBalance = 300e18;
// ((((INIT_POOL_SUPPLY+poolAmountOut)/INIT_POOL_SUPPLY)^(1/(tokenInWeight/totalWeight)))*tokenInBalance-tokenInBalance)/(1-((1-(tokenInWeight/totalWeight))*MIN_FEE))
// ((((100+1)/100)^(1/(8/10)))*300-300)/(1-((1-(8/10))*(10^-6)))
// 3.754676583174615979425132956656691
uint256 public maxTokenIn = 3.754676583181324836e18;

function setUp() public virtual override {
super.setUp();
tokenIn = tokens[0];
bPool.set__finalized(true);
// mint an initial amount of pool shares (expected to happen at _finalize)
bPool.call__mintPoolShare(INIT_POOL_SUPPLY);
bPool.set__tokens(_tokensToMemory());
bPool.set__totalWeight(totalWeight);
bPool.set__records(tokenIn, IBPool.Record({bound: true, index: 0, denorm: tokenInWeight}));
vm.mockCall(tokenIn, abi.encodePacked(IERC20.balanceOf.selector), abi.encode(uint256(tokenInBalance)));
}

function test_RevertWhen_ReentrancyLockIsSet() external {
bPool.call__setLock(_MUTEX_TAKEN);
// it should revert
vm.expectRevert(IBPool.BPool_Reentrancy.selector);
bPool.joinswapPoolAmountOut(tokenIn, poolAmountOut, maxTokenIn);
}

function test_RevertWhen_PoolIsNotFinalized() external {
bPool.call__setLock(_MUTEX_TAKEN);
// it should revert
vm.expectRevert(IBPool.BPool_Reentrancy.selector);
bPool.joinswapPoolAmountOut(tokenIn, poolAmountOut, maxTokenIn);
}

function test_RevertWhen_TokenInIsNotBound() external {
// it should revert
vm.expectRevert(IBPool.BPool_TokenNotBound.selector);
bPool.joinswapPoolAmountOut(makeAddr('unknown token'), poolAmountOut, maxTokenIn);
}

function test_RevertWhen_TokenAmountInExceedsMaxRatio() external {
// it should revert
vm.expectRevert(IBPool.BPool_TokenAmountInAboveMaxRatio.selector);
// growing pool supply by 50% -> user has to provide over half of the
// pool's tokenIn (198 in this case, consistent with weight=0.8), while
// MAX_IN_RATIO=0.5
bPool.joinswapPoolAmountOut(tokenIn, 50e18, type(uint256).max);
}

function test_RevertWhen_CalculatedTokenAmountInIsMoreThanExpected() external {
// it should revert
vm.expectRevert(IBPool.BPool_TokenAmountInAboveMaxAmountIn.selector);
bPool.joinswapPoolAmountOut(tokenIn, poolAmountOut, maxTokenIn - 1);
}

function test_WhenPreconditionsAreMet() external {
// it sets reentrancy lock
bPool.expectCall__setLock(_MUTEX_TAKEN);
// it queries token in balance
vm.expectCall(tokenIn, abi.encodeCall(IERC20.balanceOf, (address(bPool))));
// it calls _pullUnderlying for token in
bPool.mock_call__pullUnderlying(tokenIn, address(this), maxTokenIn);
bPool.expectCall__pullUnderlying(tokenIn, address(this), maxTokenIn);
// it mints the pool shares
bPool.expectCall__mintPoolShare(poolAmountOut);
// it sends pool shares to caller
bPool.expectCall__pushPoolShare(address(this), poolAmountOut);
// it emits LOG_CALL event
bytes memory _data =
abi.encodeWithSelector(IBPool.joinswapPoolAmountOut.selector, tokenIn, poolAmountOut, maxTokenIn);
vm.expectEmit();
emit IBPool.LOG_CALL(IBPool.joinswapPoolAmountOut.selector, address(this), _data);
// it emits LOG_JOIN event for token in
vm.expectEmit();
emit IBPool.LOG_JOIN(address(this), tokenIn, maxTokenIn);
bPool.joinswapPoolAmountOut(tokenIn, poolAmountOut, maxTokenIn);

// it clears the reentrancy lock
assertEq(_MUTEX_FREE, bPool.call__getLock());
}
}
20 changes: 20 additions & 0 deletions test/unit/BPool/BPool_JoinswapPoolAmountOut.tree
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
BPool::JoinswapPoolAmountOut
├── when reentrancy lock is set
│ └── it should revert
├── when pool is not finalized
│ └── it should revert
├── when token in is not bound
│ └── it should revert
├── when token amount in exceeds max ratio
│ └── it should revert
├── when calculated token amount in is more than expected
│ └── it should revert
└── when preconditions are met
├── it emits LOG_CALL event
├── it sets the reentrancy lock
├── it queries token in balance
├── it emits LOG_JOIN event for token in
├── it mints the pool shares
├── it sends pool shares to caller
├── it calls _pullUnderlying for token in
└── it clears the reentrancy lock
Loading