forked from balancer/balancer-core
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add btt tests for exitswap pool amount in (#169)
* refactor: explicitly set weights in every scenario, remove it from base contract * test: btt tests for joinswapExternAmountIn * chore: remove preexisting unit tests replaced by ones in this pr * test: query tokenIn balance * test: btt tests for exitswapPoolAmountIn * chore: remove preexisting unit tests replaced by ones in this pr * fix: feedback from review
- Loading branch information
1 parent
dfbed26
commit cb92f9d
Showing
3 changed files
with
132 additions
and
249 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity 0.8.25; | ||
|
||
import {BPoolBase} from './BPoolBase.sol'; | ||
|
||
import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol'; | ||
|
||
import {BMath} from 'contracts/BMath.sol'; | ||
import {BNum} from 'contracts/BNum.sol'; | ||
import {IBPool} from 'interfaces/IBPool.sol'; | ||
|
||
contract BPoolExitSwapPoolAmountIn is BPoolBase, BMath { | ||
// Valid scenario: | ||
address public tokenOut; | ||
uint256 public tokenOutWeight = 3e18; | ||
uint256 public tokenOutBalance = 400e18; | ||
uint256 public totalWeight = 9e18; | ||
uint256 public poolAmountIn = 1e18; | ||
// calcSingleOutGivenPoolIn(400, 3, 100, 9, 1, 10^(-6)) | ||
uint256 public expectedAmountOut = 11.880392079733333329e18; | ||
|
||
function setUp() public virtual override { | ||
super.setUp(); | ||
tokenOut = tokens[1]; | ||
_setRecord(tokenOut, IBPool.Record({bound: true, index: 0, denorm: tokenOutWeight})); | ||
bPool.set__tokens(tokens); | ||
bPool.set__totalWeight(totalWeight); | ||
bPool.set__finalized(true); | ||
bPool.call__mintPoolShare(INIT_POOL_SUPPLY); | ||
|
||
vm.mockCall(tokenOut, abi.encodePacked(IERC20.balanceOf.selector), abi.encode(uint256(tokenOutBalance))); | ||
|
||
bPool.mock_call__pullPoolShare(address(this), poolAmountIn); | ||
bPool.mock_call__burnPoolShare(poolAmountIn); | ||
bPool.mock_call__pushPoolShare(deployer, 0); | ||
bPool.mock_call__pushUnderlying(tokenOut, address(this), expectedAmountOut); | ||
} | ||
|
||
function test_RevertWhen_ReentrancyLockIsSet() external { | ||
bPool.call__setLock(_MUTEX_TAKEN); | ||
// it should revert | ||
vm.expectRevert(IBPool.BPool_Reentrancy.selector); | ||
bPool.exitswapPoolAmountIn(tokenOut, poolAmountIn, expectedAmountOut); | ||
} | ||
|
||
function test_RevertWhen_PoolIsNotFinalized() external { | ||
bPool.set__finalized(false); | ||
// it should revert | ||
vm.expectRevert(IBPool.BPool_PoolNotFinalized.selector); | ||
bPool.exitswapPoolAmountIn(tokenOut, poolAmountIn, expectedAmountOut); | ||
} | ||
|
||
function test_RevertWhen_TokenIsNotBound() external { | ||
// it should revert | ||
vm.expectRevert(IBPool.BPool_TokenNotBound.selector); | ||
bPool.exitswapPoolAmountIn(makeAddr('unknown token'), poolAmountIn, expectedAmountOut); | ||
} | ||
|
||
function test_RevertWhen_TotalSupplyIsZero() external { | ||
bPool.call__burnPoolShare(INIT_POOL_SUPPLY); | ||
// it should revert | ||
vm.expectRevert(BNum.BNum_SubUnderflow.selector); | ||
bPool.exitswapPoolAmountIn(tokenOut, poolAmountIn, expectedAmountOut); | ||
} | ||
|
||
function test_RevertWhen_ComputedTokenAmountOutIsLessThanMinAmountOut() external { | ||
// it should revert | ||
vm.expectRevert(IBPool.BPool_TokenAmountOutBelowMinAmountOut.selector); | ||
bPool.exitswapPoolAmountIn(tokenOut, poolAmountIn, expectedAmountOut + 1); | ||
} | ||
|
||
function test_RevertWhen_ComputedTokenAmountOutExceedsMaxAllowedRatio() external { | ||
// trying to burn ~20 pool tokens would result in half of the tokenOut | ||
// under management being sent to the caller: | ||
// calcPoolInGivenSingleOut(tokenOutBalance, tokenOutWeight, INIT_POOL_SUPPLY, totalWeight, tokenOutBalance / 2, MIN_FEE); | ||
// and MAX_OUT_RATIO is ~0.3 | ||
uint256 poolAmountIn_ = 20e18; | ||
// it should revert | ||
vm.expectRevert(IBPool.BPool_TokenAmountOutAboveMaxOut.selector); | ||
bPool.exitswapPoolAmountIn(tokenOut, poolAmountIn_, expectedAmountOut); | ||
} | ||
|
||
function test_WhenPreconditionsAreMet() external { | ||
// it sets the reentrancy lock | ||
bPool.expectCall__setLock(_MUTEX_TAKEN); | ||
// it queries token out balance | ||
vm.expectCall(tokenOut, abi.encodeCall(IERC20.balanceOf, (address(bPool)))); | ||
// it pulls poolAmountIn shares | ||
bPool.expectCall__pullPoolShare(address(this), poolAmountIn); | ||
// it burns poolAmountIn - exitFee shares | ||
bPool.expectCall__burnPoolShare(poolAmountIn); | ||
// it sends exitFee to factory | ||
bPool.expectCall__pushPoolShare(deployer, 0); | ||
// it calls _pushUnderlying for token out | ||
bPool.expectCall__pushUnderlying(tokenOut, address(this), expectedAmountOut); | ||
// it emits LOG_CALL event | ||
bytes memory _data = abi.encodeCall(IBPool.exitswapPoolAmountIn, (tokenOut, poolAmountIn, expectedAmountOut)); | ||
vm.expectEmit(); | ||
emit IBPool.LOG_CALL(IBPool.exitswapPoolAmountIn.selector, address(this), _data); | ||
// it emits LOG_EXIT event for token out | ||
emit IBPool.LOG_EXIT(address(this), tokenOut, expectedAmountOut); | ||
// it returns token out amount | ||
uint256 out = bPool.exitswapPoolAmountIn(tokenOut, poolAmountIn, expectedAmountOut); | ||
assertEq(out, expectedAmountOut); | ||
// it clears the reentrancy lock | ||
assertEq(bPool.call__getLock(), _MUTEX_FREE); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
BPool::ExitSwapPoolAmountIn | ||
├── when reentrancy lock is set | ||
│ └── it should revert | ||
├── when pool is not finalized | ||
│ └── it should revert | ||
├── when token is not bound | ||
│ └── it should revert | ||
├── when total supply is zero | ||
│ └── it should revert // subtraction underflow | ||
├── when computed token amount out is less than minAmountOut | ||
│ └── it should revert | ||
├── when computed token amount out exceeds max allowed ratio | ||
│ └── it should revert | ||
└── when preconditions are met | ||
├── it emits LOG_CALL event | ||
├── it sets the reentrancy lock | ||
├── it queries token out balance | ||
├── it emits LOG_EXIT event for token out | ||
├── it pulls poolAmountIn shares | ||
├── it burns poolAmountIn - exitFee shares | ||
├── it sends exitFee to factory | ||
├── it calls _pushUnderlying for token out | ||
├── it returns token out amount | ||
└── it clears the reentrancy lock |