diff --git a/test/unit/BFactory.t.sol b/test/unit/BFactory.t.sol index 86b51348..3ee3e4fc 100644 --- a/test/unit/BFactory.t.sol +++ b/test/unit/BFactory.t.sol @@ -57,7 +57,8 @@ contract BFactory_Unit_NewBPool is Base { * @notice Test that event is emitted */ function test_Emit_Log(address _randomCaller) public { - vm.assume(_randomCaller != VM_ADDRESS); + assumeNotForgeAddress(_randomCaller); + vm.expectEmit(); address _expectedPoolAddress = vm.computeCreateAddress(address(bFactory), 1); emit BFactory.LOG_NEW_POOL(_randomCaller, _expectedPoolAddress); @@ -69,7 +70,8 @@ contract BFactory_Unit_NewBPool is Base { * @notice Test that msg.sender is set as the controller */ function test_Set_Controller(address _randomCaller) public { - vm.assume(_randomCaller != VM_ADDRESS); + assumeNotForgeAddress(_randomCaller); + vm.prank(_randomCaller); BPool _pool = bFactory.newBPool(); assertEq(_randomCaller, _pool.getController()); @@ -142,7 +144,8 @@ contract BFactory_Unit_Collect is Base { * @notice Test that LP token `balanceOf` function is called */ function test_Call_BalanceOf(address _lpToken, uint256 _toCollect) public { - vm.assume(_lpToken != address(VM_ADDRESS)); + assumeNotForgeAddress(_lpToken); + vm.mockCall(_lpToken, abi.encodeWithSelector(IERC20.balanceOf.selector, address(bFactory)), abi.encode(_toCollect)); vm.mockCall(_lpToken, abi.encodeWithSelector(IERC20.transfer.selector, owner, _toCollect), abi.encode(true)); @@ -155,7 +158,8 @@ contract BFactory_Unit_Collect is Base { * @notice Test that LP token `transfer` function is called */ function test_Call_Transfer(address _lpToken, uint256 _toCollect) public { - vm.assume(_lpToken != address(VM_ADDRESS)); + assumeNotForgeAddress(_lpToken); + vm.mockCall(_lpToken, abi.encodeWithSelector(IERC20.balanceOf.selector, address(bFactory)), abi.encode(_toCollect)); vm.mockCall(_lpToken, abi.encodeWithSelector(IERC20.transfer.selector, owner, _toCollect), abi.encode(true)); @@ -168,7 +172,8 @@ contract BFactory_Unit_Collect is Base { * @notice Test that the function fail if the transfer failed */ function test_Revert_TransferFailed(address _lpToken, uint256 _toCollect) public { - vm.assume(_lpToken != address(VM_ADDRESS)); + assumeNotForgeAddress(_lpToken); + vm.mockCall(_lpToken, abi.encodeWithSelector(IERC20.balanceOf.selector, address(bFactory)), abi.encode(_toCollect)); vm.mockCall(_lpToken, abi.encodeWithSelector(IERC20.transfer.selector, owner, _toCollect), abi.encode(false)); diff --git a/test/unit/BPool.t.sol b/test/unit/BPool.t.sol index 009342f6..91657644 100644 --- a/test/unit/BPool.t.sol +++ b/test/unit/BPool.t.sol @@ -13,12 +13,9 @@ import {Pow} from 'test/utils/Pow.sol'; import {Utils} from 'test/utils/Utils.sol'; abstract contract BasePoolTest is Test, BConst, Utils, BMath { - using LibString for *; - - uint256 public constant TOKENS_AMOUNT = 3; + using LibString for uint256; MockBPool public bPool; - address[TOKENS_AMOUNT] public tokens; // Deploy this external contract to perform a try-catch when calling bpow. // If the call fails, it means that the function overflowed, then we reject the fuzzed inputs @@ -42,36 +39,6 @@ abstract contract BasePoolTest is Test, BConst, Utils, BMath { _setTokens(_tokensToAdd); } - // TODO: move tokens and this method to Utils.sol - function _tokensToMemory() internal view returns (address[] memory _tokens) { - _tokens = new address[](tokens.length); - for (uint256 i = 0; i < tokens.length; i++) { - _tokens[i] = tokens[i]; - } - } - - function _staticToDynamicUintArray(uint256[TOKENS_AMOUNT] memory _fixedUintArray) - internal - pure - returns (uint256[] memory _memoryUintArray) - { - _memoryUintArray = new uint256[](_fixedUintArray.length); - for (uint256 i = 0; i < _fixedUintArray.length; i++) { - _memoryUintArray[i] = _fixedUintArray[i]; - } - } - - function _maxAmountsArray() internal pure returns (uint256[] memory _maxAmounts) { - _maxAmounts = new uint256[](TOKENS_AMOUNT); - for (uint256 i = 0; i < TOKENS_AMOUNT; i++) { - _maxAmounts[i] = type(uint256).max; - } - } - - function _zeroAmountsArray() internal view returns (uint256[] memory _zeroAmounts) { - _zeroAmounts = new uint256[](tokens.length); - } - function _mockTransfer(address _token) internal { // TODO: add amount to transfer to check that it's called with the right amount vm.mockCall(_token, abi.encodeWithSelector(IERC20(_token).transfer.selector), abi.encode(true)); @@ -120,6 +87,16 @@ abstract contract BasePoolTest is Test, BConst, Utils, BMath { bPool.set__totalWeight(_totalWeight); } + function _expectRevertByReentrancy() internal { + // Assert that the contract is accessible + assertEq(bPool.call__mutex(), false); + + // Simulate ongoing call to the contract + bPool.set__mutex(true); + + vm.expectRevert('ERR_REENTRY'); + } + function _assumeCalcSpotPrice( uint256 _tokenInBalance, uint256 _tokenInDenorm, @@ -331,13 +308,7 @@ contract BPool_Unit_GetCurrentTokens is BasePoolTest { } function test_Revert_Reentrancy() public { - // Assert that the contract is accessible - assertEq(bPool.call__mutex(), false); - - // Simulate ongoing call to the contract - bPool.set__mutex(true); - - vm.expectRevert('ERR_REENTRY'); + _expectRevertByReentrancy(); bPool.getCurrentTokens(); } } @@ -353,13 +324,7 @@ contract BPool_Unit_GetFinalTokens is BasePoolTest { } function test_Revert_Reentrancy() public { - // Assert that the contract is accessible - assertEq(bPool.call__mutex(), false); - - // Simulate ongoing call to the contract - bPool.set__mutex(true); - - vm.expectRevert('ERR_REENTRY'); + _expectRevertByReentrancy(); bPool.getFinalTokens(); } @@ -382,13 +347,7 @@ contract BPool_Unit_GetDenormalizedWeight is BasePoolTest { } function test_Revert_Reentrancy() public { - // Assert that the contract is accessible - assertEq(bPool.call__mutex(), false); - - // Simulate ongoing call to the contract - bPool.set__mutex(true); - - vm.expectRevert('ERR_REENTRY'); + _expectRevertByReentrancy(); bPool.getDenormalizedWeight(address(0)); } @@ -406,13 +365,7 @@ contract BPool_Unit_GetTotalDenormalizedWeight is BasePoolTest { } function test_Revert_Reentrancy() public { - // Assert that the contract is accessible - assertEq(bPool.call__mutex(), false); - - // Simulate ongoing call to the contract - bPool.set__mutex(true); - - vm.expectRevert('ERR_REENTRY'); + _expectRevertByReentrancy(); bPool.getTotalDenormalizedWeight(); } } @@ -429,13 +382,7 @@ contract BPool_Unit_GetNormalizedWeight is BasePoolTest { } function test_Revert_Reentrancy() public { - // Assert that the contract is accessible - assertEq(bPool.call__mutex(), false); - - // Simulate ongoing call to the contract - bPool.set__mutex(true); - - vm.expectRevert('ERR_REENTRY'); + _expectRevertByReentrancy(); bPool.getNormalizedWeight(address(0)); } @@ -453,13 +400,7 @@ contract BPool_Unit_GetBalance is BasePoolTest { } function test_Revert_Reentrancy() public { - // Assert that the contract is accessible - assertEq(bPool.call__mutex(), false); - - // Simulate ongoing call to the contract - bPool.set__mutex(true); - - vm.expectRevert('ERR_REENTRY'); + _expectRevertByReentrancy(); bPool.getBalance(address(0)); } @@ -477,13 +418,7 @@ contract BPool_Unit_GetSwapFee is BasePoolTest { } function test_Revert_Reentrancy() public { - // Assert that the contract is accessible - assertEq(bPool.call__mutex(), false); - - // Simulate ongoing call to the contract - bPool.set__mutex(true); - - vm.expectRevert('ERR_REENTRY'); + _expectRevertByReentrancy(); bPool.getSwapFee(); } } @@ -496,13 +431,7 @@ contract BPool_Unit_GetController is BasePoolTest { } function test_Revert_Reentrancy() public { - // Assert that the contract is accessible - assertEq(bPool.call__mutex(), false); - - // Simulate ongoing call to the contract - bPool.set__mutex(true); - - vm.expectRevert('ERR_REENTRY'); + _expectRevertByReentrancy(); bPool.getController(); } } @@ -545,13 +474,7 @@ contract BPool_Unit_SetSwapFee is BasePoolTest { } function test_Revert_Reentrancy(uint256 _fee) public happyPath(_fee) { - // Assert that the contract is accessible - assertEq(bPool.call__mutex(), false); - - // Simulate ongoing call to the contract - bPool.set__mutex(true); - - vm.expectRevert('ERR_REENTRY'); + _expectRevertByReentrancy(); bPool.setSwapFee(_fee); } @@ -584,13 +507,7 @@ contract BPool_Unit_SetController is BasePoolTest { } function test_Revert_Reentrancy(address _controller) public { - // Assert that the contract is accessible - assertEq(bPool.call__mutex(), false); - - // Simulate ongoing call to the contract - bPool.set__mutex(true); - - vm.expectRevert('ERR_REENTRY'); + _expectRevertByReentrancy(); bPool.setController(_controller); } @@ -627,13 +544,7 @@ contract BPool_Unit_SetPublicSwap is BasePoolTest { } function test_Revert_Reentrancy(bool _isPublicSwap) public { - // Assert that the contract is accessible - assertEq(bPool.call__mutex(), false); - - // Simulate ongoing call to the contract - bPool.set__mutex(true); - - vm.expectRevert('ERR_REENTRY'); + _expectRevertByReentrancy(); bPool.setPublicSwap(_isPublicSwap); } @@ -688,13 +599,7 @@ contract BPool_Unit_Finalize is BasePoolTest { } function test_Revert_Reentrancy(uint256 _tokensLength) public happyPath(_tokensLength) { - // Assert that the contract is accessible - assertEq(bPool.call__mutex(), false); - - // Simulate ongoing call to the contract - bPool.set__mutex(true); - - vm.expectRevert('ERR_REENTRY'); + _expectRevertByReentrancy(); bPool.finalize(); } @@ -757,18 +662,18 @@ contract BPool_Unit_Bind is BasePoolTest { } function _assumeHappyPath(Bind_FuzzScenario memory _fuzz) internal { - vm.assume(_fuzz.token != VM_ADDRESS); - vm.assume(_fuzz.token != 0x000000000000000000636F6e736F6c652e6c6f67); - vm.assume(_fuzz.balance >= MIN_BALANCE); - vm.assume(_fuzz.totalWeight >= MIN_WEIGHT); - vm.assume(_fuzz.totalWeight <= MAX_TOTAL_WEIGHT - MIN_WEIGHT); + assumeNotForgeAddress(_fuzz.token); + _fuzz.previousTokensAmount = bound(_fuzz.previousTokensAmount, 0, MAX_BOUND_TOKENS - 1); - _fuzz.denorm = bound(_fuzz.denorm, MIN_WEIGHT, MAX_TOTAL_WEIGHT - _fuzz.totalWeight); _fuzz.previousTokens = new address[](_fuzz.previousTokensAmount); for (uint256 i = 0; i < _fuzz.previousTokensAmount; i++) { _fuzz.previousTokens[i] = makeAddr(i.toString()); vm.assume(_fuzz.token != _fuzz.previousTokens[i]); } + + _fuzz.balance = bound(_fuzz.balance, MIN_BALANCE, type(uint256).max); + _fuzz.totalWeight = bound(_fuzz.totalWeight, MIN_WEIGHT, MAX_TOTAL_WEIGHT - MIN_WEIGHT); + _fuzz.denorm = bound(_fuzz.denorm, MIN_WEIGHT, MAX_TOTAL_WEIGHT - _fuzz.totalWeight); } modifier happyPath(Bind_FuzzScenario memory _fuzz) { @@ -778,9 +683,9 @@ contract BPool_Unit_Bind is BasePoolTest { } function test_Revert_NotController( + Bind_FuzzScenario memory _fuzz, address _controller, - address _caller, - Bind_FuzzScenario memory _fuzz + address _caller ) public happyPath(_fuzz) { vm.assume(_controller != _caller); bPool.set__controller(_controller); @@ -790,7 +695,7 @@ contract BPool_Unit_Bind is BasePoolTest { bPool.bind(_fuzz.token, _fuzz.balance, _fuzz.denorm); } - function test_Revert_IsBound(uint256 _tokenIndex, Bind_FuzzScenario memory _fuzz) public happyPath(_fuzz) { + function test_Revert_IsBound(Bind_FuzzScenario memory _fuzz, uint256 _tokenIndex) public happyPath(_fuzz) { vm.assume(_fuzz.previousTokensAmount > 0); _tokenIndex = bound(_tokenIndex, 0, _fuzz.previousTokens.length - 1); @@ -838,7 +743,7 @@ contract BPool_Unit_Bind is BasePoolTest { } function test_Call_Rebind(Bind_FuzzScenario memory _fuzz) public happyPath(_fuzz) { - // TODO: fix + // TODO: this behaviour is not possible to test in current environment. vm.skip(true); vm.expectCall( address(bPool), abi.encodeWithSelector(BPool.rebind.selector, _fuzz.token, _fuzz.balance, _fuzz.denorm) @@ -877,12 +782,10 @@ contract BPool_Unit_Rebind is BasePoolTest { } function _assumeHappyPath(Rebind_FuzzScenario memory _fuzz) internal pure { - vm.assume(_fuzz.token != VM_ADDRESS); - vm.assume(_fuzz.token != 0x000000000000000000636F6e736F6c652e6c6f67); - vm.assume(_fuzz.balance >= MIN_BALANCE); - vm.assume(_fuzz.previousBalance >= MIN_BALANCE); - vm.assume(_fuzz.totalWeight >= MIN_WEIGHT); - vm.assume(_fuzz.totalWeight <= MAX_TOTAL_WEIGHT - MIN_WEIGHT); + assumeNotForgeAddress(_fuzz.token); + _fuzz.balance = bound(_fuzz.balance, MIN_BALANCE, type(uint256).max); + _fuzz.previousBalance = bound(_fuzz.previousBalance, MIN_BALANCE, type(uint256).max); + _fuzz.totalWeight = bound(_fuzz.totalWeight, MIN_WEIGHT, MAX_TOTAL_WEIGHT - MIN_WEIGHT); _fuzz.previousDenorm = bound(_fuzz.previousDenorm, MIN_WEIGHT, _fuzz.totalWeight); _fuzz.denorm = bound(_fuzz.denorm, MIN_WEIGHT, MAX_TOTAL_WEIGHT - _fuzz.totalWeight); } @@ -894,9 +797,9 @@ contract BPool_Unit_Rebind is BasePoolTest { } function test_Revert_NotController( + Rebind_FuzzScenario memory _fuzz, address _controller, - address _caller, - Rebind_FuzzScenario memory _fuzz + address _caller ) public happyPath(_fuzz) { vm.assume(_controller != _caller); bPool.set__controller(_controller); @@ -906,7 +809,7 @@ contract BPool_Unit_Rebind is BasePoolTest { bPool.rebind(_fuzz.token, _fuzz.balance, _fuzz.denorm); } - function test_Revert_NotBound(address _token, Rebind_FuzzScenario memory _fuzz) public happyPath(_fuzz) { + function test_Revert_NotBound(Rebind_FuzzScenario memory _fuzz, address _token) public happyPath(_fuzz) { vm.assume(_token != _fuzz.token); vm.expectRevert('ERR_NOT_BOUND'); @@ -920,21 +823,21 @@ contract BPool_Unit_Rebind is BasePoolTest { bPool.rebind(_fuzz.token, _fuzz.balance, _fuzz.denorm); } - function test_Revert_MinWeight(uint256 _denorm, Rebind_FuzzScenario memory _fuzz) public happyPath(_fuzz) { + function test_Revert_MinWeight(Rebind_FuzzScenario memory _fuzz, uint256 _denorm) public happyPath(_fuzz) { vm.assume(_denorm < MIN_WEIGHT); vm.expectRevert('ERR_MIN_WEIGHT'); bPool.rebind(_fuzz.token, _fuzz.balance, _denorm); } - function test_Revert_MaxWeight(uint256 _denorm, Rebind_FuzzScenario memory _fuzz) public happyPath(_fuzz) { + function test_Revert_MaxWeight(Rebind_FuzzScenario memory _fuzz, uint256 _denorm) public happyPath(_fuzz) { vm.assume(_denorm > MAX_WEIGHT); vm.expectRevert('ERR_MAX_WEIGHT'); bPool.rebind(_fuzz.token, _fuzz.balance, _denorm); } - function test_Revert_MinBalance(uint256 _balance, Rebind_FuzzScenario memory _fuzz) public happyPath(_fuzz) { + function test_Revert_MinBalance(Rebind_FuzzScenario memory _fuzz, uint256 _balance) public happyPath(_fuzz) { vm.assume(_balance < MIN_BALANCE); vm.expectRevert('ERR_MIN_BALANCE'); @@ -942,13 +845,7 @@ contract BPool_Unit_Rebind is BasePoolTest { } function test_Revert_Reentrancy(Rebind_FuzzScenario memory _fuzz) public happyPath(_fuzz) { - // Assert that the contract is accessible - assertEq(bPool.call__mutex(), false); - - // Simulate ongoing call to the contract - bPool.set__mutex(true); - - vm.expectRevert('ERR_REENTRY'); + _expectRevertByReentrancy(); bPool.rebind(_fuzz.token, _fuzz.balance, _fuzz.denorm); } @@ -966,7 +863,7 @@ contract BPool_Unit_Rebind is BasePoolTest { assertEq(bPool.call__totalWeight(), _fuzz.totalWeight - (_fuzz.previousDenorm - _fuzz.denorm)); } - function test_Revert_MaxTotalWeight(uint256 _denorm, Rebind_FuzzScenario memory _fuzz) public happyPath(_fuzz) { + function test_Revert_MaxTotalWeight(Rebind_FuzzScenario memory _fuzz, uint256 _denorm) public happyPath(_fuzz) { _denorm = bound(_denorm, _fuzz.previousDenorm + 1, MAX_WEIGHT); _setTotalWeight(MAX_TOTAL_WEIGHT); @@ -1065,9 +962,8 @@ contract BPool_Unit_Unbind is BasePoolTest { } function _assumeHappyPath(Unbind_FuzzScenario memory _fuzz) internal { - vm.assume(_fuzz.balance >= MIN_BALANCE); - vm.assume(_fuzz.totalWeight >= MIN_WEIGHT); - vm.assume(_fuzz.totalWeight <= MAX_TOTAL_WEIGHT - MIN_WEIGHT); + _fuzz.balance = bound(_fuzz.balance, MIN_BALANCE, type(uint256).max); + _fuzz.totalWeight = bound(_fuzz.totalWeight, MIN_WEIGHT, MAX_TOTAL_WEIGHT - MIN_WEIGHT); // The token to unbind will be included inside the array _fuzz.previousTokensAmount = bound(_fuzz.previousTokensAmount, 1, MAX_BOUND_TOKENS); _fuzz.tokenIndex = bound(_fuzz.tokenIndex, 0, _fuzz.previousTokensAmount - 1); @@ -1085,9 +981,9 @@ contract BPool_Unit_Unbind is BasePoolTest { } function test_Revert_NotController( + Unbind_FuzzScenario memory _fuzz, address _controller, - address _caller, - Unbind_FuzzScenario memory _fuzz + address _caller ) public happyPath(_fuzz) { vm.assume(_controller != _caller); bPool.set__controller(_controller); @@ -1097,7 +993,7 @@ contract BPool_Unit_Unbind is BasePoolTest { bPool.unbind(_fuzz.previousTokens[_fuzz.tokenIndex]); } - function test_Revert_NotBound(address _token, Unbind_FuzzScenario memory _fuzz) public happyPath(_fuzz) { + function test_Revert_NotBound(Unbind_FuzzScenario memory _fuzz, address _token) public happyPath(_fuzz) { for (uint256 i = 0; i < _fuzz.previousTokensAmount; i++) { vm.assume(_token != _fuzz.previousTokens[i]); } @@ -1114,13 +1010,7 @@ contract BPool_Unit_Unbind is BasePoolTest { } function test_Revert_Reentrancy(Unbind_FuzzScenario memory _fuzz) public happyPath(_fuzz) { - // Assert that the contract is accessible - assertEq(bPool.call__mutex(), false); - - // Simulate ongoing call to the contract - bPool.set__mutex(true); - - vm.expectRevert('ERR_REENTRY'); + _expectRevertByReentrancy(); bPool.unbind(_fuzz.previousTokens[_fuzz.tokenIndex]); } @@ -1204,14 +1094,13 @@ contract BPool_Unit_Gulp is BasePoolTest { } modifier happyPath(Gulp_FuzzScenario memory _fuzz) { - vm.assume(_fuzz.token != VM_ADDRESS); - vm.assume(_fuzz.token != 0x000000000000000000636F6e736F6c652e6c6f67); + assumeNotForgeAddress(_fuzz.token); _mockBalanceOf(_fuzz.token, address(bPool), _fuzz.balance); _setRecord(_fuzz.token, BPool.Record({bound: true, index: 0, denorm: 0, balance: _fuzz.balance})); _; } - function test_Revert_NotBound(address _token, Gulp_FuzzScenario memory _fuzz) public happyPath(_fuzz) { + function test_Revert_NotBound(Gulp_FuzzScenario memory _fuzz, address _token) public happyPath(_fuzz) { vm.assume(_token != _fuzz.token); vm.expectRevert('ERR_NOT_BOUND'); @@ -1219,13 +1108,7 @@ contract BPool_Unit_Gulp is BasePoolTest { } function test_Revert_Reentrancy(Gulp_FuzzScenario memory _fuzz) public happyPath(_fuzz) { - // Assert that the contract is accessible - assertEq(bPool.call__mutex(), false); - - // Simulate ongoing call to the contract - bPool.set__mutex(true); - - vm.expectRevert('ERR_REENTRY'); + _expectRevertByReentrancy(); bPool.gulp(_fuzz.token); } @@ -1280,8 +1163,8 @@ contract BPool_Unit_GetSpotPrice is BasePoolTest { } function test_Revert_NotBoundTokenIn( - address _tokenIn, - GetSpotPrice_FuzzScenario memory _fuzz + GetSpotPrice_FuzzScenario memory _fuzz, + address _tokenIn ) public happyPath(_fuzz) { vm.assume(_tokenIn != _fuzz.tokenIn); vm.assume(_tokenIn != _fuzz.tokenOut); @@ -1291,8 +1174,8 @@ contract BPool_Unit_GetSpotPrice is BasePoolTest { } function test_Revert_NotBoundTokenOut( - address _tokenOut, - GetSpotPrice_FuzzScenario memory _fuzz + GetSpotPrice_FuzzScenario memory _fuzz, + address _tokenOut ) public happyPath(_fuzz) { vm.assume(_tokenOut != _fuzz.tokenIn); vm.assume(_tokenOut != _fuzz.tokenOut); @@ -1310,13 +1193,7 @@ contract BPool_Unit_GetSpotPrice is BasePoolTest { } function test_Revert_Reentrancy(GetSpotPrice_FuzzScenario memory _fuzz) public happyPath(_fuzz) { - // Assert that the contract is accessible - assertEq(bPool.call__mutex(), false); - - // Simulate ongoing call to the contract - bPool.set__mutex(true); - - vm.expectRevert('ERR_REENTRY'); + _expectRevertByReentrancy(); bPool.getSpotPrice(_fuzz.tokenIn, _fuzz.tokenOut); } } @@ -1354,8 +1231,8 @@ contract BPool_Unit_GetSpotPriceSansFee is BasePoolTest { } function test_Revert_NotBoundTokenIn( - address _tokenIn, - GetSpotPriceSansFee_FuzzScenario memory _fuzz + GetSpotPriceSansFee_FuzzScenario memory _fuzz, + address _tokenIn ) public happyPath(_fuzz) { vm.assume(_tokenIn != _fuzz.tokenIn); vm.assume(_tokenIn != _fuzz.tokenOut); @@ -1365,8 +1242,8 @@ contract BPool_Unit_GetSpotPriceSansFee is BasePoolTest { } function test_Revert_NotBoundTokenOut( - address _tokenOut, - GetSpotPriceSansFee_FuzzScenario memory _fuzz + GetSpotPriceSansFee_FuzzScenario memory _fuzz, + address _tokenOut ) public happyPath(_fuzz) { vm.assume(_tokenOut != _fuzz.tokenIn); vm.assume(_tokenOut != _fuzz.tokenOut); @@ -1383,13 +1260,7 @@ contract BPool_Unit_GetSpotPriceSansFee is BasePoolTest { } function test_Revert_Reentrancy(GetSpotPriceSansFee_FuzzScenario memory _fuzz) public happyPath(_fuzz) { - // Assert that the contract is accessible - assertEq(bPool.call__mutex(), false); - - // Simulate ongoing call to the contract - bPool.set__mutex(true); - - vm.expectRevert('ERR_REENTRY'); + _expectRevertByReentrancy(); bPool.getSpotPriceSansFee(_fuzz.tokenIn, _fuzz.tokenOut); } } @@ -1399,7 +1270,6 @@ contract BPool_Unit_JoinPool is BasePoolTest { uint256 poolAmountOut; uint256 initPoolSupply; uint256[TOKENS_AMOUNT] balance; - uint256[TOKENS_AMOUNT] maxAmountsIn; } function _setValues(JoinPool_FuzzScenario memory _fuzz) internal { @@ -1434,9 +1304,8 @@ contract BPool_Unit_JoinPool is BasePoolTest { } function _assumeHappyPath(JoinPool_FuzzScenario memory _fuzz) internal pure { - vm.assume(_fuzz.initPoolSupply >= INIT_POOL_SUPPLY); - vm.assume(_fuzz.poolAmountOut >= _fuzz.initPoolSupply); - vm.assume(_fuzz.poolAmountOut < type(uint256).max / BONE); + _fuzz.initPoolSupply = bound(_fuzz.initPoolSupply, INIT_POOL_SUPPLY, type(uint256).max / BONE); + _fuzz.poolAmountOut = bound(_fuzz.poolAmountOut, _fuzz.initPoolSupply, type(uint256).max / BONE); vm.assume(_fuzz.poolAmountOut * BONE < type(uint256).max - (_fuzz.initPoolSupply / 2)); uint256 _ratio = bdiv(_fuzz.poolAmountOut, _fuzz.initPoolSupply); @@ -1444,8 +1313,6 @@ contract BPool_Unit_JoinPool is BasePoolTest { for (uint256 i = 0; i < _fuzz.balance.length; i++) { _fuzz.balance[i] = bound(_fuzz.balance[i], MIN_BALANCE, _maxTokenAmountIn); - uint256 _tokenAmountIn = bmul(_ratio, _fuzz.balance[i]); - _fuzz.maxAmountsIn[i] = bound(_fuzz.maxAmountsIn[i], _tokenAmountIn, type(uint256).max); } } @@ -1459,14 +1326,14 @@ contract BPool_Unit_JoinPool is BasePoolTest { _setFinalize(false); vm.expectRevert('ERR_NOT_FINALIZED'); - bPool.joinPool(_fuzz.poolAmountOut, _staticToDynamicUintArray(_fuzz.maxAmountsIn)); + bPool.joinPool(_fuzz.poolAmountOut, _maxArray(tokens.length)); } function test_Revert_MathApprox(JoinPool_FuzzScenario memory _fuzz, uint256 _poolAmountOut) public happyPath(_fuzz) { _poolAmountOut = bound(_poolAmountOut, 0, (INIT_POOL_SUPPLY / 2 / BONE) - 1); // bdiv rounds up vm.expectRevert('ERR_MATH_APPROX'); - bPool.joinPool(_poolAmountOut, _staticToDynamicUintArray(_fuzz.maxAmountsIn)); + bPool.joinPool(_poolAmountOut, _maxArray(tokens.length)); } function test_Revert_TokenArrayMathApprox(JoinPool_FuzzScenario memory _fuzz, uint256 _tokenIndex) public { @@ -1476,33 +1343,33 @@ contract BPool_Unit_JoinPool is BasePoolTest { _setValues(_fuzz); vm.expectRevert('ERR_MATH_APPROX'); - bPool.joinPool(_fuzz.poolAmountOut, _staticToDynamicUintArray(_fuzz.maxAmountsIn)); + bPool.joinPool(_fuzz.poolAmountOut, _maxArray(tokens.length)); } - function test_Revert_TokenArrayLimitIn(JoinPool_FuzzScenario memory _fuzz) public happyPath(_fuzz) { + function test_Revert_TokenArrayLimitIn( + JoinPool_FuzzScenario memory _fuzz, + uint256 _tokenIndex, + uint256[TOKENS_AMOUNT] memory _maxAmountsIn + ) public happyPath(_fuzz) { + _tokenIndex = bound(_tokenIndex, 0, TOKENS_AMOUNT - 1); + uint256 _ratio = bdiv(_fuzz.poolAmountOut, _fuzz.initPoolSupply); for (uint256 i = 0; i < _fuzz.balance.length; i++) { uint256 _tokenAmountIn = bmul(_ratio, _fuzz.balance[i]); - _fuzz.maxAmountsIn[i] = _tokenAmountIn - 1; + _maxAmountsIn[i] = _tokenIndex == i ? _tokenAmountIn - 1 : _tokenAmountIn; } vm.expectRevert('ERR_LIMIT_IN'); - bPool.joinPool(_fuzz.poolAmountOut, _staticToDynamicUintArray(_fuzz.maxAmountsIn)); + bPool.joinPool(_fuzz.poolAmountOut, _staticToDynamicUintArray(_maxAmountsIn)); } function test_Revert_Reentrancy(JoinPool_FuzzScenario memory _fuzz) public happyPath(_fuzz) { - // Assert that the contract is accessible - assertEq(bPool.call__mutex(), false); - - // Simulate ongoing call to the contract - bPool.set__mutex(true); - - vm.expectRevert('ERR_REENTRY'); - bPool.joinPool(_fuzz.poolAmountOut, _staticToDynamicUintArray(_fuzz.maxAmountsIn)); + _expectRevertByReentrancy(); + bPool.joinPool(_fuzz.poolAmountOut, _maxArray(tokens.length)); } function test_Set_TokenArrayBalance(JoinPool_FuzzScenario memory _fuzz) public happyPath(_fuzz) { - bPool.joinPool(_fuzz.poolAmountOut, _staticToDynamicUintArray(_fuzz.maxAmountsIn)); + bPool.joinPool(_fuzz.poolAmountOut, _maxArray(tokens.length)); uint256 _poolTotal = _fuzz.initPoolSupply; uint256 _ratio = bdiv(_fuzz.poolAmountOut, _poolTotal); @@ -1524,7 +1391,7 @@ contract BPool_Unit_JoinPool is BasePoolTest { vm.expectEmit(); emit BPool.LOG_JOIN(address(this), tokens[i], _tokenAmountIn); } - bPool.joinPool(_fuzz.poolAmountOut, _staticToDynamicUintArray(_fuzz.maxAmountsIn)); + bPool.joinPool(_fuzz.poolAmountOut, _maxArray(tokens.length)); } function test_Pull_TokenArrayTokenAmountIn(JoinPool_FuzzScenario memory _fuzz) public happyPath(_fuzz) { @@ -1539,33 +1406,31 @@ contract BPool_Unit_JoinPool is BasePoolTest { abi.encodeWithSelector(IERC20.transferFrom.selector, address(this), address(bPool), _tokenAmountIn) ); } - bPool.joinPool(_fuzz.poolAmountOut, _staticToDynamicUintArray(_fuzz.maxAmountsIn)); + bPool.joinPool(_fuzz.poolAmountOut, _maxArray(tokens.length)); } function test_Mint_PoolShare(JoinPool_FuzzScenario memory _fuzz) public happyPath(_fuzz) { - bPool.joinPool(_fuzz.poolAmountOut, _staticToDynamicUintArray(_fuzz.maxAmountsIn)); + bPool.joinPool(_fuzz.poolAmountOut, _maxArray(tokens.length)); assertEq(bPool.totalSupply(), _fuzz.initPoolSupply + _fuzz.poolAmountOut); } function test_Push_PoolShare(JoinPool_FuzzScenario memory _fuzz, address _caller) public happyPath(_fuzz) { - vm.assume(_caller != address(VM_ADDRESS)); + assumeNotForgeAddress(_caller); vm.assume(_caller != address(0)); vm.prank(_caller); - bPool.joinPool(_fuzz.poolAmountOut, _staticToDynamicUintArray(_fuzz.maxAmountsIn)); + bPool.joinPool(_fuzz.poolAmountOut, _maxArray(tokens.length)); assertEq(bPool.balanceOf(_caller), _fuzz.poolAmountOut); } function test_Emit_LogCall(JoinPool_FuzzScenario memory _fuzz) public happyPath(_fuzz) { vm.expectEmit(); - bytes memory _data = abi.encodeWithSelector( - BPool.joinPool.selector, _fuzz.poolAmountOut, _staticToDynamicUintArray(_fuzz.maxAmountsIn) - ); + bytes memory _data = abi.encodeWithSelector(BPool.joinPool.selector, _fuzz.poolAmountOut, _maxArray(tokens.length)); emit BPool.LOG_CALL(BPool.joinPool.selector, address(this), _data); - bPool.joinPool(_fuzz.poolAmountOut, _staticToDynamicUintArray(_fuzz.maxAmountsIn)); + bPool.joinPool(_fuzz.poolAmountOut, _maxArray(tokens.length)); } } @@ -1574,7 +1439,6 @@ contract BPool_Unit_ExitPool is BasePoolTest { uint256 poolAmountIn; uint256 initPoolSupply; uint256[TOKENS_AMOUNT] balance; - uint256[TOKENS_AMOUNT] minAmountsOut; } function _setValues(ExitPool_FuzzScenario memory _fuzz) internal { @@ -1619,11 +1483,10 @@ contract BPool_Unit_ExitPool is BasePoolTest { vm.assume(_poolAmountInAfterFee * BONE < type(uint256).max - (_fuzz.initPoolSupply / 2)); uint256 _ratio = bdiv(_poolAmountInAfterFee, _fuzz.initPoolSupply); + uint256 _maxBalance = type(uint256).max / (_ratio * BONE); for (uint256 i = 0; i < _fuzz.balance.length; i++) { - _fuzz.balance[i] = bound(_fuzz.balance[i], BONE, type(uint256).max / (_ratio * BONE)); - uint256 _tokenAmountOut = bmul(_ratio, _fuzz.balance[i]); - _fuzz.minAmountsOut[i] = bound(_fuzz.minAmountsOut[i], 0, _tokenAmountOut); + _fuzz.balance[i] = bound(_fuzz.balance[i], BONE, _maxBalance); } } @@ -1637,20 +1500,20 @@ contract BPool_Unit_ExitPool is BasePoolTest { _setFinalize(false); vm.expectRevert('ERR_NOT_FINALIZED'); - bPool.exitPool(_fuzz.poolAmountIn, _staticToDynamicUintArray(_fuzz.minAmountsOut)); + bPool.exitPool(_fuzz.poolAmountIn, _zeroArray(tokens.length)); } function test_Revert_MathApprox(ExitPool_FuzzScenario memory _fuzz, uint256 _poolAmountIn) public happyPath(_fuzz) { _poolAmountIn = bound(_poolAmountIn, 0, (INIT_POOL_SUPPLY / 2 / BONE) - 1); // bdiv rounds up vm.expectRevert('ERR_MATH_APPROX'); - bPool.exitPool(_poolAmountIn, _staticToDynamicUintArray(_fuzz.minAmountsOut)); + bPool.exitPool(_poolAmountIn, _zeroArray(tokens.length)); } function test_Pull_PoolShare(ExitPool_FuzzScenario memory _fuzz) public happyPath(_fuzz) { assertEq(bPool.balanceOf(address(this)), _fuzz.poolAmountIn); - bPool.exitPool(_fuzz.poolAmountIn, _staticToDynamicUintArray(_fuzz.minAmountsOut)); + bPool.exitPool(_fuzz.poolAmountIn, _zeroArray(tokens.length)); assertEq(bPool.balanceOf(address(this)), 0); } @@ -1660,7 +1523,7 @@ contract BPool_Unit_ExitPool is BasePoolTest { uint256 _exitFee = bmul(_fuzz.poolAmountIn, EXIT_FEE); uint256 _balanceBefore = bPool.balanceOf(_factoryAddress); - bPool.exitPool(_fuzz.poolAmountIn, _staticToDynamicUintArray(_fuzz.minAmountsOut)); + bPool.exitPool(_fuzz.poolAmountIn, _zeroArray(tokens.length)); assertEq(bPool.balanceOf(_factoryAddress), _balanceBefore - _fuzz.poolAmountIn + _exitFee); } @@ -1670,7 +1533,7 @@ contract BPool_Unit_ExitPool is BasePoolTest { uint256 _pAiAfterExitFee = bsub(_fuzz.poolAmountIn, _exitFee); uint256 _totalSupplyBefore = bPool.totalSupply(); - bPool.exitPool(_fuzz.poolAmountIn, _staticToDynamicUintArray(_fuzz.minAmountsOut)); + bPool.exitPool(_fuzz.poolAmountIn, _zeroArray(tokens.length)); assertEq(bPool.totalSupply(), _totalSupplyBefore - _pAiAfterExitFee); } @@ -1685,12 +1548,13 @@ contract BPool_Unit_ExitPool is BasePoolTest { _setValues(_fuzz); vm.expectRevert('ERR_MATH_APPROX'); - bPool.exitPool(_fuzz.poolAmountIn, _staticToDynamicUintArray(_fuzz.minAmountsOut)); + bPool.exitPool(_fuzz.poolAmountIn, _zeroArray(tokens.length)); } function test_Revert_TokenArrayLimitOut( ExitPool_FuzzScenario memory _fuzz, - uint256 _tokenIndex + uint256 _tokenIndex, + uint256[TOKENS_AMOUNT] memory _minAmountsOut ) public happyPath(_fuzz) { _tokenIndex = bound(_tokenIndex, 0, TOKENS_AMOUNT - 1); @@ -1699,27 +1563,20 @@ contract BPool_Unit_ExitPool is BasePoolTest { uint256 _pAiAfterExitFee = bsub(_fuzz.poolAmountIn, _exitFee); uint256 _ratio = bdiv(_pAiAfterExitFee, _poolTotal); - uint256[] memory _minAmounts = new uint256[](tokens.length); for (uint256 i = 0; i < tokens.length; i++) { uint256 _bal = _fuzz.balance[i]; uint256 _tokenAmountOut = bmul(_ratio, _bal); - _minAmounts[i] = _tokenIndex == i ? _tokenAmountOut + 1 : _tokenAmountOut; + _minAmountsOut[i] = _tokenIndex == i ? _tokenAmountOut + 1 : _tokenAmountOut; } vm.expectRevert('ERR_LIMIT_OUT'); - bPool.exitPool(_fuzz.poolAmountIn, _minAmounts); + bPool.exitPool(_fuzz.poolAmountIn, _staticToDynamicUintArray(_minAmountsOut)); } function test_Revert_Reentrancy(ExitPool_FuzzScenario memory _fuzz) public happyPath(_fuzz) { - // Assert that the contract is accessible - assertEq(bPool.call__mutex(), false); - - // Simulate ongoing call to the contract - bPool.set__mutex(true); - - vm.expectRevert('ERR_REENTRY'); - bPool.exitPool(_fuzz.poolAmountIn, _staticToDynamicUintArray(_fuzz.minAmountsOut)); + _expectRevertByReentrancy(); + bPool.exitPool(_fuzz.poolAmountIn, _zeroArray(tokens.length)); } function test_Set_TokenArrayBalance(ExitPool_FuzzScenario memory _fuzz) public happyPath(_fuzz) { @@ -1728,7 +1585,7 @@ contract BPool_Unit_ExitPool is BasePoolTest { _balanceBefore[i] = bPool.getBalance(tokens[i]); } - bPool.exitPool(_fuzz.poolAmountIn, _staticToDynamicUintArray(_fuzz.minAmountsOut)); + bPool.exitPool(_fuzz.poolAmountIn, _zeroArray(tokens.length)); uint256 _exitFee = bmul(_fuzz.poolAmountIn, EXIT_FEE); uint256 _pAiAfterExitFee = bsub(_fuzz.poolAmountIn, _exitFee); @@ -1752,7 +1609,7 @@ contract BPool_Unit_ExitPool is BasePoolTest { vm.expectEmit(); emit BPool.LOG_EXIT(address(this), tokens[i], _tokenAmountOut); } - bPool.exitPool(_fuzz.poolAmountIn, _staticToDynamicUintArray(_fuzz.minAmountsOut)); + bPool.exitPool(_fuzz.poolAmountIn, _zeroArray(tokens.length)); } function test_Push_TokenArrayTokenAmountOut(ExitPool_FuzzScenario memory _fuzz) public happyPath(_fuzz) { @@ -1767,17 +1624,15 @@ contract BPool_Unit_ExitPool is BasePoolTest { address(tokens[i]), abi.encodeWithSelector(IERC20.transfer.selector, address(this), _tokenAmountOut) ); } - bPool.exitPool(_fuzz.poolAmountIn, _staticToDynamicUintArray(_fuzz.minAmountsOut)); + bPool.exitPool(_fuzz.poolAmountIn, _zeroArray(tokens.length)); } function test_Emit_LogCall(ExitPool_FuzzScenario memory _fuzz) public happyPath(_fuzz) { vm.expectEmit(); - bytes memory _data = abi.encodeWithSelector( - BPool.exitPool.selector, _fuzz.poolAmountIn, _staticToDynamicUintArray(_fuzz.minAmountsOut) - ); + bytes memory _data = abi.encodeWithSelector(BPool.exitPool.selector, _fuzz.poolAmountIn, _zeroArray(tokens.length)); emit BPool.LOG_CALL(BPool.exitPool.selector, address(this), _data); - bPool.exitPool(_fuzz.poolAmountIn, _staticToDynamicUintArray(_fuzz.minAmountsOut)); + bPool.exitPool(_fuzz.poolAmountIn, _zeroArray(tokens.length)); } } @@ -1792,8 +1647,6 @@ contract BPool_Unit_SwapExactAmountIn is BasePoolTest { uint256 tokenOutBalance; uint256 tokenOutDenorm; uint256 swapFee; - uint256 minAmountOut; - uint256 maxPrice; } function _setValues(SwapExactAmountIn_FuzzScenario memory _fuzz) internal { @@ -1838,13 +1691,9 @@ contract BPool_Unit_SwapExactAmountIn is BasePoolTest { _fuzz.tokenOutDenorm = bound(_fuzz.tokenOutDenorm, MIN_WEIGHT, MAX_WEIGHT); _fuzz.swapFee = bound(_fuzz.swapFee, MIN_FEE, MAX_FEE); - // min - vm.assume(_fuzz.tokenInBalance >= MIN_BALANCE); - vm.assume(_fuzz.tokenOutBalance >= MIN_BALANCE); - - // max - calcSpotPrice (spotPriceBefore) - vm.assume(_fuzz.tokenInBalance < type(uint256).max / _fuzz.tokenInDenorm); - vm.assume(_fuzz.tokenOutBalance < type(uint256).max / _fuzz.tokenOutDenorm); + // min - max - calcSpotPrice (spotPriceBefore) + _fuzz.tokenInBalance = bound(_fuzz.tokenInBalance, MIN_BALANCE, type(uint256).max / _fuzz.tokenInDenorm); + _fuzz.tokenOutBalance = bound(_fuzz.tokenOutBalance, MIN_BALANCE, type(uint256).max / _fuzz.tokenOutDenorm); // max - calcSpotPrice (spotPriceAfter) vm.assume(_fuzz.tokenAmountIn < type(uint256).max - _fuzz.tokenInBalance); @@ -1883,18 +1732,7 @@ contract BPool_Unit_SwapExactAmountIn is BasePoolTest { _fuzz.swapFee ); - uint256 _spotPriceAfter = calcSpotPrice( - _fuzz.tokenInBalance + _fuzz.tokenAmountIn, - _fuzz.tokenInDenorm, - _fuzz.tokenOutBalance - _tokenAmountOut, - _fuzz.tokenOutDenorm, - _fuzz.swapFee - ); - vm.assume(bmul(_spotPriceBefore, _tokenAmountOut) <= _fuzz.tokenAmountIn); - - _fuzz.minAmountOut = bound(_fuzz.minAmountOut, 0, _tokenAmountOut); - _fuzz.maxPrice = bound(_fuzz.maxPrice, _spotPriceAfter, type(uint256).max); } modifier happyPath(SwapExactAmountIn_FuzzScenario memory _fuzz) { @@ -1904,50 +1742,61 @@ contract BPool_Unit_SwapExactAmountIn is BasePoolTest { } function test_Revert_NotBoundTokenIn( - address _tokenIn, - SwapExactAmountIn_FuzzScenario memory _fuzz + SwapExactAmountIn_FuzzScenario memory _fuzz, + address _tokenIn ) public happyPath(_fuzz) { - vm.assume(_tokenIn != VM_ADDRESS); + assumeNotForgeAddress(_tokenIn); + vm.assume(_tokenIn != tokenIn); + vm.assume(_tokenIn != tokenOut); vm.expectRevert('ERR_NOT_BOUND'); - bPool.swapExactAmountIn(_tokenIn, _fuzz.tokenAmountIn, tokenOut, _fuzz.minAmountOut, _fuzz.maxPrice); + bPool.swapExactAmountIn(_tokenIn, _fuzz.tokenAmountIn, tokenOut, 0, type(uint256).max); } function test_Revert_NotBoundTokenOut( - address _tokenOut, - SwapExactAmountIn_FuzzScenario memory _fuzz + SwapExactAmountIn_FuzzScenario memory _fuzz, + address _tokenOut ) public happyPath(_fuzz) { - vm.assume(_tokenOut != VM_ADDRESS); + assumeNotForgeAddress(_tokenOut); + vm.assume(_tokenOut != tokenIn); + vm.assume(_tokenOut != tokenOut); vm.expectRevert('ERR_NOT_BOUND'); - bPool.swapExactAmountIn(tokenIn, _fuzz.tokenAmountIn, _tokenOut, _fuzz.minAmountOut, _fuzz.maxPrice); + bPool.swapExactAmountIn(tokenIn, _fuzz.tokenAmountIn, _tokenOut, 0, type(uint256).max); } function test_Revert_NotPublic(SwapExactAmountIn_FuzzScenario memory _fuzz) public happyPath(_fuzz) { _setPublicSwap(false); vm.expectRevert('ERR_SWAP_NOT_PUBLIC'); - bPool.swapExactAmountIn(tokenIn, _fuzz.tokenAmountIn, tokenOut, _fuzz.minAmountOut, _fuzz.maxPrice); + bPool.swapExactAmountIn(tokenIn, _fuzz.tokenAmountIn, tokenOut, 0, type(uint256).max); } function test_Revert_MaxInRatio(SwapExactAmountIn_FuzzScenario memory _fuzz) public happyPath(_fuzz) { uint256 _tokenAmountIn = bmul(_fuzz.tokenInBalance, MAX_IN_RATIO) + 1; vm.expectRevert('ERR_MAX_IN_RATIO'); - bPool.swapExactAmountIn(tokenIn, _tokenAmountIn, tokenOut, _fuzz.minAmountOut, _fuzz.maxPrice); + bPool.swapExactAmountIn(tokenIn, _tokenAmountIn, tokenOut, 0, type(uint256).max); } - function test_Revert_BadLimitPrice(SwapExactAmountIn_FuzzScenario memory _fuzz) public happyPath(_fuzz) { + function test_Revert_BadLimitPrice( + SwapExactAmountIn_FuzzScenario memory _fuzz, + uint256 _maxPrice + ) public happyPath(_fuzz) { uint256 _spotPriceBefore = calcSpotPrice( _fuzz.tokenInBalance, _fuzz.tokenInDenorm, _fuzz.tokenOutBalance, _fuzz.tokenOutDenorm, _fuzz.swapFee ); vm.assume(_spotPriceBefore > 0); + _maxPrice = bound(_maxPrice, 0, _spotPriceBefore - 1); vm.expectRevert('ERR_BAD_LIMIT_PRICE'); - bPool.swapExactAmountIn(tokenIn, _fuzz.tokenAmountIn, tokenOut, _fuzz.minAmountOut, _spotPriceBefore - 1); + bPool.swapExactAmountIn(tokenIn, _fuzz.tokenAmountIn, tokenOut, 0, _maxPrice); } - function test_Revert_LimitOut(SwapExactAmountIn_FuzzScenario memory _fuzz) public happyPath(_fuzz) { + function test_Revert_LimitOut( + SwapExactAmountIn_FuzzScenario memory _fuzz, + uint256 _minAmountOut + ) public happyPath(_fuzz) { uint256 _tokenAmountOut = calcOutGivenIn( _fuzz.tokenInBalance, _fuzz.tokenInDenorm, @@ -1956,31 +1805,25 @@ contract BPool_Unit_SwapExactAmountIn is BasePoolTest { _fuzz.tokenAmountIn, _fuzz.swapFee ); + _minAmountOut = bound(_minAmountOut, _tokenAmountOut + 1, type(uint256).max); vm.expectRevert('ERR_LIMIT_OUT'); - bPool.swapExactAmountIn(tokenIn, _fuzz.tokenAmountIn, tokenOut, _tokenAmountOut + 1, _fuzz.maxPrice); + bPool.swapExactAmountIn(tokenIn, _fuzz.tokenAmountIn, tokenOut, _minAmountOut, type(uint256).max); } function test_Revert_Reentrancy(SwapExactAmountIn_FuzzScenario memory _fuzz) public happyPath(_fuzz) { - // Assert that the contract is accessible - assertEq(bPool.call__mutex(), false); - - // Simulate ongoing call to the contract - bPool.set__mutex(true); - - vm.expectRevert('ERR_REENTRY'); - bPool.swapExactAmountIn(tokenIn, _fuzz.tokenAmountIn, tokenOut, _fuzz.minAmountOut, _fuzz.maxPrice); + _expectRevertByReentrancy(); + bPool.swapExactAmountIn(tokenIn, _fuzz.tokenAmountIn, tokenOut, 0, type(uint256).max); } function test_Set_InRecord(SwapExactAmountIn_FuzzScenario memory _fuzz) public happyPath(_fuzz) { - bPool.swapExactAmountIn(tokenIn, _fuzz.tokenAmountIn, tokenOut, _fuzz.minAmountOut, _fuzz.maxPrice); + bPool.swapExactAmountIn(tokenIn, _fuzz.tokenAmountIn, tokenOut, 0, type(uint256).max); assertEq(bPool.getBalance(tokenIn), _fuzz.tokenInBalance + _fuzz.tokenAmountIn); } function test_Set_OutRecord(SwapExactAmountIn_FuzzScenario memory _fuzz) public happyPath(_fuzz) { - (uint256 _tokenAmountOut,) = - bPool.swapExactAmountIn(tokenIn, _fuzz.tokenAmountIn, tokenOut, _fuzz.minAmountOut, _fuzz.maxPrice); + (uint256 _tokenAmountOut,) = bPool.swapExactAmountIn(tokenIn, _fuzz.tokenAmountIn, tokenOut, 0, type(uint256).max); assertEq(bPool.getBalance(tokenOut), _fuzz.tokenOutBalance - _tokenAmountOut); } @@ -2012,7 +1855,7 @@ contract BPool_Unit_SwapExactAmountIn is BasePoolTest { vm.assume(_spotPriceAfter > _spotPriceBefore); vm.expectRevert('ERR_LIMIT_PRICE'); - bPool.swapExactAmountIn(tokenIn, _fuzz.tokenAmountIn, tokenOut, _fuzz.minAmountOut, _spotPriceBefore); + bPool.swapExactAmountIn(tokenIn, _fuzz.tokenAmountIn, tokenOut, 0, _spotPriceBefore); } function test_Revert_MathApprox2(SwapExactAmountIn_FuzzScenario memory _fuzz) public { @@ -2020,10 +1863,8 @@ contract BPool_Unit_SwapExactAmountIn is BasePoolTest { _fuzz.tokenInDenorm = bound(_fuzz.tokenInDenorm, MIN_WEIGHT, MAX_WEIGHT); _fuzz.tokenOutDenorm = bound(_fuzz.tokenOutDenorm, MIN_WEIGHT, MAX_WEIGHT); _fuzz.swapFee = bound(_fuzz.swapFee, MIN_FEE, MAX_FEE); - vm.assume(_fuzz.tokenInBalance >= MIN_BALANCE); - vm.assume(_fuzz.tokenOutBalance >= MIN_BALANCE); - vm.assume(_fuzz.tokenInBalance < type(uint256).max / _fuzz.tokenInDenorm); - vm.assume(_fuzz.tokenOutBalance < type(uint256).max / _fuzz.tokenOutDenorm); + _fuzz.tokenInBalance = bound(_fuzz.tokenInBalance, MIN_BALANCE, type(uint256).max / _fuzz.tokenInDenorm); + _fuzz.tokenOutBalance = bound(_fuzz.tokenOutBalance, MIN_BALANCE, type(uint256).max / _fuzz.tokenOutDenorm); vm.assume(_fuzz.tokenAmountIn < type(uint256).max - _fuzz.tokenInBalance); vm.assume(_fuzz.tokenInBalance + _fuzz.tokenAmountIn < type(uint256).max / _fuzz.tokenInDenorm); _assumeCalcSpotPrice( @@ -2033,6 +1874,7 @@ contract BPool_Unit_SwapExactAmountIn is BasePoolTest { uint256 _spotPriceBefore = calcSpotPrice( _fuzz.tokenInBalance, _fuzz.tokenInDenorm, _fuzz.tokenOutBalance, _fuzz.tokenOutDenorm, _fuzz.swapFee ); + _assumeCalcOutGivenIn(_fuzz.tokenInBalance, _fuzz.tokenAmountIn, _fuzz.swapFee); uint256 _tokenAmountOut = calcOutGivenIn( _fuzz.tokenInBalance, _fuzz.tokenInDenorm, @@ -2051,21 +1893,10 @@ contract BPool_Unit_SwapExactAmountIn is BasePoolTest { ); vm.assume(_spotPriceBefore > bdiv(_fuzz.tokenAmountIn, _tokenAmountOut)); - uint256 _spotPriceAfter = calcSpotPrice( - _fuzz.tokenInBalance + _fuzz.tokenAmountIn, - _fuzz.tokenInDenorm, - _fuzz.tokenOutBalance - _tokenAmountOut, - _fuzz.tokenOutDenorm, - _fuzz.swapFee - ); - - _fuzz.minAmountOut = bound(_fuzz.minAmountOut, 0, _tokenAmountOut); - _fuzz.maxPrice = bound(_fuzz.maxPrice, _spotPriceAfter, type(uint256).max); - _setValues(_fuzz); vm.expectRevert('ERR_MATH_APPROX'); - bPool.swapExactAmountIn(tokenIn, _fuzz.tokenAmountIn, tokenOut, _fuzz.minAmountOut, _fuzz.maxPrice); + bPool.swapExactAmountIn(tokenIn, _fuzz.tokenAmountIn, tokenOut, 0, type(uint256).max); } function test_Emit_LogSwap(SwapExactAmountIn_FuzzScenario memory _fuzz) public happyPath(_fuzz) { @@ -2080,7 +1911,7 @@ contract BPool_Unit_SwapExactAmountIn is BasePoolTest { vm.expectEmit(); emit BPool.LOG_SWAP(address(this), tokenIn, tokenOut, _fuzz.tokenAmountIn, _tokenAmountOut); - bPool.swapExactAmountIn(tokenIn, _fuzz.tokenAmountIn, tokenOut, _fuzz.minAmountOut, _fuzz.maxPrice); + bPool.swapExactAmountIn(tokenIn, _fuzz.tokenAmountIn, tokenOut, 0, type(uint256).max); } function test_Pull_TokenAmountIn(SwapExactAmountIn_FuzzScenario memory _fuzz) public happyPath(_fuzz) { @@ -2088,7 +1919,7 @@ contract BPool_Unit_SwapExactAmountIn is BasePoolTest { address(tokenIn), abi.encodeWithSelector(IERC20.transferFrom.selector, address(this), address(bPool), _fuzz.tokenAmountIn) ); - bPool.swapExactAmountIn(tokenIn, _fuzz.tokenAmountIn, tokenOut, _fuzz.minAmountOut, _fuzz.maxPrice); + bPool.swapExactAmountIn(tokenIn, _fuzz.tokenAmountIn, tokenOut, 0, type(uint256).max); } function test_Push_TokenAmountOut(SwapExactAmountIn_FuzzScenario memory _fuzz) public happyPath(_fuzz) { @@ -2102,7 +1933,7 @@ contract BPool_Unit_SwapExactAmountIn is BasePoolTest { ); vm.expectCall(address(tokenOut), abi.encodeWithSelector(IERC20.transfer.selector, address(this), _tokenAmountOut)); - bPool.swapExactAmountIn(tokenIn, _fuzz.tokenAmountIn, tokenOut, _fuzz.minAmountOut, _fuzz.maxPrice); + bPool.swapExactAmountIn(tokenIn, _fuzz.tokenAmountIn, tokenOut, 0, type(uint256).max); } function test_Returns_AmountAndPrice(SwapExactAmountIn_FuzzScenario memory _fuzz) public happyPath(_fuzz) { @@ -2123,7 +1954,7 @@ contract BPool_Unit_SwapExactAmountIn is BasePoolTest { ); (uint256 _tokenAmountOut, uint256 _spotPriceAfter) = - bPool.swapExactAmountIn(tokenIn, _fuzz.tokenAmountIn, tokenOut, _fuzz.minAmountOut, _fuzz.maxPrice); + bPool.swapExactAmountIn(tokenIn, _fuzz.tokenAmountIn, tokenOut, 0, type(uint256).max); assertEq(_tokenAmountOut, _expectedTokenAmountOut); assertEq(_spotPriceAfter, _expectedSpotPriceAfter); @@ -2132,11 +1963,11 @@ contract BPool_Unit_SwapExactAmountIn is BasePoolTest { function test_Emit_LogCall(SwapExactAmountIn_FuzzScenario memory _fuzz) public happyPath(_fuzz) { vm.expectEmit(); bytes memory _data = abi.encodeWithSelector( - BPool.swapExactAmountIn.selector, tokenIn, _fuzz.tokenAmountIn, tokenOut, _fuzz.minAmountOut, _fuzz.maxPrice + BPool.swapExactAmountIn.selector, tokenIn, _fuzz.tokenAmountIn, tokenOut, 0, type(uint256).max ); emit BPool.LOG_CALL(BPool.swapExactAmountIn.selector, address(this), _data); - bPool.swapExactAmountIn(tokenIn, _fuzz.tokenAmountIn, tokenOut, _fuzz.minAmountOut, _fuzz.maxPrice); + bPool.swapExactAmountIn(tokenIn, _fuzz.tokenAmountIn, tokenOut, 0, type(uint256).max); } } @@ -2151,8 +1982,6 @@ contract BPool_Unit_SwapExactAmountOut is BasePoolTest { uint256 tokenOutBalance; uint256 tokenOutDenorm; uint256 swapFee; - uint256 maxAmountIn; - uint256 maxPrice; } function _setValues(SwapExactAmountOut_FuzzScenario memory _fuzz) internal { @@ -2197,9 +2026,8 @@ contract BPool_Unit_SwapExactAmountOut is BasePoolTest { _fuzz.tokenOutDenorm = bound(_fuzz.tokenOutDenorm, MIN_WEIGHT, MAX_WEIGHT); _fuzz.swapFee = bound(_fuzz.swapFee, MIN_FEE, MAX_FEE); - // min - vm.assume(_fuzz.tokenInBalance >= MIN_BALANCE); - vm.assume(_fuzz.tokenOutBalance >= MIN_BALANCE); + _fuzz.tokenInBalance = bound(_fuzz.tokenInBalance, MIN_BALANCE, type(uint256).max); + _fuzz.tokenOutBalance = bound(_fuzz.tokenOutBalance, MIN_BALANCE, type(uint256).max); // max - calcSpotPrice (spotPriceBefore) vm.assume(_fuzz.tokenInBalance < type(uint256).max / _fuzz.tokenInDenorm); @@ -2237,7 +2065,7 @@ contract BPool_Unit_SwapExactAmountOut is BasePoolTest { ); vm.assume(_tokenAmountIn > BONE); - vm.assume(bmul(_spotPriceBefore, _fuzz.tokenAmountOut) <= _tokenAmountIn); + vm.assume(_spotPriceBefore <= bdiv(_tokenAmountIn, _fuzz.tokenAmountOut)); // max - calcSpotPrice (spotPriceAfter) vm.assume(_tokenAmountIn < type(uint256).max - _fuzz.tokenInBalance); @@ -2251,17 +2079,6 @@ contract BPool_Unit_SwapExactAmountOut is BasePoolTest { _fuzz.tokenOutDenorm, _fuzz.swapFee ); - - uint256 _spotPriceAfter = calcSpotPrice( - _fuzz.tokenInBalance + _tokenAmountIn, - _fuzz.tokenInDenorm, - _fuzz.tokenOutBalance - _fuzz.tokenAmountOut, - _fuzz.tokenOutDenorm, - _fuzz.swapFee - ); - - _fuzz.maxAmountIn = bound(_fuzz.maxAmountIn, _tokenAmountIn, type(uint256).max); - _fuzz.maxPrice = bound(_fuzz.maxPrice, _spotPriceAfter, type(uint256).max); } modifier happyPath(SwapExactAmountOut_FuzzScenario memory _fuzz) { @@ -2271,50 +2088,61 @@ contract BPool_Unit_SwapExactAmountOut is BasePoolTest { } function test_Revert_NotBoundTokenIn( - address _tokenIn, - SwapExactAmountOut_FuzzScenario memory _fuzz + SwapExactAmountOut_FuzzScenario memory _fuzz, + address _tokenIn ) public happyPath(_fuzz) { - vm.assume(_tokenIn != VM_ADDRESS); + assumeNotForgeAddress(_tokenIn); + vm.assume(_tokenIn != tokenIn); + vm.assume(_tokenIn != tokenOut); vm.expectRevert('ERR_NOT_BOUND'); - bPool.swapExactAmountOut(_tokenIn, _fuzz.maxAmountIn, tokenOut, _fuzz.tokenAmountOut, _fuzz.maxPrice); + bPool.swapExactAmountOut(_tokenIn, type(uint256).max, tokenOut, _fuzz.tokenAmountOut, type(uint256).max); } function test_Revert_NotBoundTokenOut( - address _tokenOut, - SwapExactAmountOut_FuzzScenario memory _fuzz + SwapExactAmountOut_FuzzScenario memory _fuzz, + address _tokenOut ) public happyPath(_fuzz) { - vm.assume(_tokenOut != VM_ADDRESS); + assumeNotForgeAddress(_tokenOut); + vm.assume(_tokenOut != tokenIn); + vm.assume(_tokenOut != tokenOut); vm.expectRevert('ERR_NOT_BOUND'); - bPool.swapExactAmountOut(tokenIn, _fuzz.maxAmountIn, _tokenOut, _fuzz.tokenAmountOut, _fuzz.maxPrice); + bPool.swapExactAmountOut(tokenIn, type(uint256).max, _tokenOut, _fuzz.tokenAmountOut, type(uint256).max); } function test_Revert_NotPublic(SwapExactAmountOut_FuzzScenario memory _fuzz) public happyPath(_fuzz) { _setPublicSwap(false); vm.expectRevert('ERR_SWAP_NOT_PUBLIC'); - bPool.swapExactAmountOut(tokenIn, _fuzz.maxAmountIn, tokenOut, _fuzz.tokenAmountOut, _fuzz.maxPrice); + bPool.swapExactAmountOut(tokenIn, type(uint256).max, tokenOut, _fuzz.tokenAmountOut, type(uint256).max); } function test_Revert_MaxOutRatio(SwapExactAmountOut_FuzzScenario memory _fuzz) public happyPath(_fuzz) { uint256 _tokenAmountOut = bmul(_fuzz.tokenOutBalance, MAX_OUT_RATIO) + 1; vm.expectRevert('ERR_MAX_OUT_RATIO'); - bPool.swapExactAmountOut(tokenIn, _fuzz.maxAmountIn, tokenOut, _tokenAmountOut, _fuzz.maxPrice); + bPool.swapExactAmountOut(tokenIn, type(uint256).max, tokenOut, _tokenAmountOut, type(uint256).max); } - function test_Revert_BadLimitPrice(SwapExactAmountOut_FuzzScenario memory _fuzz) public happyPath(_fuzz) { + function test_Revert_BadLimitPrice( + SwapExactAmountOut_FuzzScenario memory _fuzz, + uint256 _maxPrice + ) public happyPath(_fuzz) { uint256 _spotPriceBefore = calcSpotPrice( _fuzz.tokenInBalance, _fuzz.tokenInDenorm, _fuzz.tokenOutBalance, _fuzz.tokenOutDenorm, _fuzz.swapFee ); vm.assume(_spotPriceBefore > 0); + _maxPrice = bound(_maxPrice, 0, _spotPriceBefore - 1); vm.expectRevert('ERR_BAD_LIMIT_PRICE'); - bPool.swapExactAmountOut(tokenIn, _fuzz.maxAmountIn, tokenOut, _fuzz.tokenAmountOut, _spotPriceBefore - 1); + bPool.swapExactAmountOut(tokenIn, type(uint256).max, tokenOut, _fuzz.tokenAmountOut, _maxPrice); } - function test_Revert_LimitIn(SwapExactAmountOut_FuzzScenario memory _fuzz) public happyPath(_fuzz) { + function test_Revert_LimitIn( + SwapExactAmountOut_FuzzScenario memory _fuzz, + uint256 _maxAmountIn + ) public happyPath(_fuzz) { uint256 _tokenAmountIn = calcInGivenOut( _fuzz.tokenInBalance, _fuzz.tokenInDenorm, @@ -2323,31 +2151,26 @@ contract BPool_Unit_SwapExactAmountOut is BasePoolTest { _fuzz.tokenAmountOut, _fuzz.swapFee ); + _maxAmountIn = bound(_maxAmountIn, 0, _tokenAmountIn - 1); vm.expectRevert('ERR_LIMIT_IN'); - bPool.swapExactAmountOut(tokenIn, _tokenAmountIn - 1, tokenOut, _fuzz.tokenAmountOut, _fuzz.maxPrice); + bPool.swapExactAmountOut(tokenIn, _maxAmountIn, tokenOut, _fuzz.tokenAmountOut, type(uint256).max); } function test_Revert_Reentrancy(SwapExactAmountOut_FuzzScenario memory _fuzz) public happyPath(_fuzz) { - // Assert that the contract is accessible - assertEq(bPool.call__mutex(), false); - - // Simulate ongoing call to the contract - bPool.set__mutex(true); - - vm.expectRevert('ERR_REENTRY'); - bPool.swapExactAmountOut(tokenIn, _fuzz.maxAmountIn, tokenOut, _fuzz.tokenAmountOut, _fuzz.maxPrice); + _expectRevertByReentrancy(); + bPool.swapExactAmountOut(tokenIn, type(uint256).max, tokenOut, _fuzz.tokenAmountOut, type(uint256).max); } function test_Set_InRecord(SwapExactAmountOut_FuzzScenario memory _fuzz) public happyPath(_fuzz) { (uint256 _tokenAmountIn,) = - bPool.swapExactAmountOut(tokenIn, _fuzz.maxAmountIn, tokenOut, _fuzz.tokenAmountOut, _fuzz.maxPrice); + bPool.swapExactAmountOut(tokenIn, type(uint256).max, tokenOut, _fuzz.tokenAmountOut, type(uint256).max); assertEq(bPool.getBalance(tokenIn), _fuzz.tokenInBalance + _tokenAmountIn); } function test_Set_OutRecord(SwapExactAmountOut_FuzzScenario memory _fuzz) public happyPath(_fuzz) { - bPool.swapExactAmountOut(tokenIn, _fuzz.maxAmountIn, tokenOut, _fuzz.tokenAmountOut, _fuzz.maxPrice); + bPool.swapExactAmountOut(tokenIn, type(uint256).max, tokenOut, _fuzz.tokenAmountOut, type(uint256).max); assertEq(bPool.getBalance(tokenOut), _fuzz.tokenOutBalance - _fuzz.tokenAmountOut); } @@ -2379,7 +2202,7 @@ contract BPool_Unit_SwapExactAmountOut is BasePoolTest { vm.assume(_spotPriceAfter > _spotPriceBefore); vm.expectRevert('ERR_LIMIT_PRICE'); - bPool.swapExactAmountOut(tokenIn, _fuzz.maxAmountIn, tokenOut, _fuzz.tokenAmountOut, _spotPriceBefore); + bPool.swapExactAmountOut(tokenIn, type(uint256).max, tokenOut, _fuzz.tokenAmountOut, _spotPriceBefore); } function test_Revert_MathApprox2(SwapExactAmountOut_FuzzScenario memory _fuzz) public { @@ -2387,8 +2210,8 @@ contract BPool_Unit_SwapExactAmountOut is BasePoolTest { _fuzz.tokenInDenorm = bound(_fuzz.tokenInDenorm, MIN_WEIGHT, MAX_WEIGHT); _fuzz.tokenOutDenorm = bound(_fuzz.tokenOutDenorm, MIN_WEIGHT, MAX_WEIGHT); _fuzz.swapFee = bound(_fuzz.swapFee, MIN_FEE, MAX_FEE); - vm.assume(_fuzz.tokenInBalance >= MIN_BALANCE); - vm.assume(_fuzz.tokenOutBalance >= MIN_BALANCE); + _fuzz.tokenInBalance = bound(_fuzz.tokenInBalance, MIN_BALANCE, type(uint256).max); + _fuzz.tokenOutBalance = bound(_fuzz.tokenOutBalance, MIN_BALANCE, type(uint256).max); vm.assume(_fuzz.tokenInBalance < type(uint256).max / _fuzz.tokenInDenorm); vm.assume(_fuzz.tokenOutBalance < type(uint256).max / _fuzz.tokenOutDenorm); vm.assume(_fuzz.tokenAmountOut < type(uint256).max - _fuzz.tokenOutBalance); @@ -2423,21 +2246,10 @@ contract BPool_Unit_SwapExactAmountOut is BasePoolTest { ); vm.assume(_spotPriceBefore > bdiv(_tokenAmountIn, _fuzz.tokenAmountOut)); - uint256 _spotPriceAfter = calcSpotPrice( - _fuzz.tokenInBalance + _tokenAmountIn, - _fuzz.tokenInDenorm, - _fuzz.tokenOutBalance - _fuzz.tokenAmountOut, - _fuzz.tokenOutDenorm, - _fuzz.swapFee - ); - - _fuzz.maxAmountIn = bound(_fuzz.maxAmountIn, _tokenAmountIn, type(uint256).max); - _fuzz.maxPrice = bound(_fuzz.maxPrice, _spotPriceAfter, type(uint256).max); - _setValues(_fuzz); vm.expectRevert('ERR_MATH_APPROX'); - bPool.swapExactAmountOut(tokenIn, _fuzz.maxAmountIn, tokenOut, _fuzz.tokenAmountOut, _fuzz.maxPrice); + bPool.swapExactAmountOut(tokenIn, type(uint256).max, tokenOut, _fuzz.tokenAmountOut, type(uint256).max); } function test_Emit_LogSwap(SwapExactAmountOut_FuzzScenario memory _fuzz) public happyPath(_fuzz) { @@ -2452,7 +2264,7 @@ contract BPool_Unit_SwapExactAmountOut is BasePoolTest { vm.expectEmit(); emit BPool.LOG_SWAP(address(this), tokenIn, tokenOut, _tokenAmountIn, _fuzz.tokenAmountOut); - bPool.swapExactAmountOut(tokenIn, _fuzz.maxAmountIn, tokenOut, _fuzz.tokenAmountOut, _fuzz.maxPrice); + bPool.swapExactAmountOut(tokenIn, type(uint256).max, tokenOut, _fuzz.tokenAmountOut, type(uint256).max); } function test_Pull_TokenAmountIn(SwapExactAmountOut_FuzzScenario memory _fuzz) public happyPath(_fuzz) { @@ -2469,14 +2281,14 @@ contract BPool_Unit_SwapExactAmountOut is BasePoolTest { address(tokenIn), abi.encodeWithSelector(IERC20.transferFrom.selector, address(this), address(bPool), _tokenAmountIn) ); - bPool.swapExactAmountOut(tokenIn, _fuzz.maxAmountIn, tokenOut, _fuzz.tokenAmountOut, _fuzz.maxPrice); + bPool.swapExactAmountOut(tokenIn, type(uint256).max, tokenOut, _fuzz.tokenAmountOut, type(uint256).max); } function test_Push_TokenAmountOut(SwapExactAmountOut_FuzzScenario memory _fuzz) public happyPath(_fuzz) { vm.expectCall( address(tokenOut), abi.encodeWithSelector(IERC20.transfer.selector, address(this), _fuzz.tokenAmountOut) ); - bPool.swapExactAmountOut(tokenIn, _fuzz.maxAmountIn, tokenOut, _fuzz.tokenAmountOut, _fuzz.maxPrice); + bPool.swapExactAmountOut(tokenIn, type(uint256).max, tokenOut, _fuzz.tokenAmountOut, type(uint256).max); } function test_Returns_AmountAndPrice(SwapExactAmountOut_FuzzScenario memory _fuzz) public happyPath(_fuzz) { @@ -2497,7 +2309,7 @@ contract BPool_Unit_SwapExactAmountOut is BasePoolTest { ); (uint256 _tokenAmountIn, uint256 _spotPriceAfter) = - bPool.swapExactAmountOut(tokenIn, _fuzz.maxAmountIn, tokenOut, _fuzz.tokenAmountOut, _fuzz.maxPrice); + bPool.swapExactAmountOut(tokenIn, type(uint256).max, tokenOut, _fuzz.tokenAmountOut, type(uint256).max); assertEq(_expectedTokenAmountIn, _tokenAmountIn); assertEq(_expectedSpotPriceAfter, _spotPriceAfter); @@ -2506,11 +2318,11 @@ contract BPool_Unit_SwapExactAmountOut is BasePoolTest { function test_Emit_LogCall(SwapExactAmountOut_FuzzScenario memory _fuzz) public happyPath(_fuzz) { vm.expectEmit(); bytes memory _data = abi.encodeWithSelector( - BPool.swapExactAmountOut.selector, tokenIn, _fuzz.maxAmountIn, tokenOut, _fuzz.tokenAmountOut, _fuzz.maxPrice + BPool.swapExactAmountOut.selector, tokenIn, type(uint256).max, tokenOut, _fuzz.tokenAmountOut, type(uint256).max ); emit BPool.LOG_CALL(BPool.swapExactAmountOut.selector, address(this), _data); - bPool.swapExactAmountOut(tokenIn, _fuzz.maxAmountIn, tokenOut, _fuzz.tokenAmountOut, _fuzz.maxPrice); + bPool.swapExactAmountOut(tokenIn, type(uint256).max, tokenOut, _fuzz.tokenAmountOut, type(uint256).max); } } @@ -2524,7 +2336,6 @@ contract BPool_Unit_JoinswapExternAmountIn is BasePoolTest { uint256 totalSupply; uint256 totalWeight; uint256 swapFee; - uint256 minPoolAmountOut; } function _setValues(JoinswapExternAmountIn_FuzzScenario memory _fuzz) internal { @@ -2562,10 +2373,8 @@ contract BPool_Unit_JoinswapExternAmountIn is BasePoolTest { _fuzz.swapFee = bound(_fuzz.swapFee, MIN_FEE, MAX_FEE); _fuzz.totalWeight = bound(_fuzz.totalWeight, MIN_WEIGHT * MAX_BOUND_TOKENS, MAX_WEIGHT * MAX_BOUND_TOKENS); - vm.assume(_fuzz.totalSupply >= INIT_POOL_SUPPLY); - - // min - vm.assume(_fuzz.tokenInBalance >= MIN_BALANCE); + _fuzz.totalSupply = bound(_fuzz.totalSupply, INIT_POOL_SUPPLY, type(uint256).max); + _fuzz.tokenInBalance = bound(_fuzz.tokenInBalance, MIN_BALANCE, type(uint256).max); // max vm.assume(_fuzz.tokenInBalance < type(uint256).max - _fuzz.tokenAmountIn); @@ -2583,17 +2392,6 @@ contract BPool_Unit_JoinswapExternAmountIn is BasePoolTest { _fuzz.totalWeight, _fuzz.totalSupply ); - - uint256 _poolAmountOut = calcPoolOutGivenSingleIn( - _fuzz.tokenInBalance, - _fuzz.tokenInDenorm, - _fuzz.totalSupply, - _fuzz.totalWeight, - _fuzz.tokenAmountIn, - _fuzz.swapFee - ); - - _fuzz.minPoolAmountOut = bound(_fuzz.minPoolAmountOut, 0, _poolAmountOut); } modifier happyPath(JoinswapExternAmountIn_FuzzScenario memory _fuzz) { @@ -2606,27 +2404,30 @@ contract BPool_Unit_JoinswapExternAmountIn is BasePoolTest { _setFinalize(false); vm.expectRevert('ERR_NOT_FINALIZED'); - bPool.joinswapExternAmountIn(tokenIn, _fuzz.tokenAmountIn, _fuzz.minPoolAmountOut); + bPool.joinswapExternAmountIn(tokenIn, _fuzz.tokenAmountIn, 0); } function test_Revert_NotBound( JoinswapExternAmountIn_FuzzScenario memory _fuzz, address _tokenIn ) public happyPath(_fuzz) { - vm.assume(_tokenIn != VM_ADDRESS); + assumeNotForgeAddress(_tokenIn); vm.expectRevert('ERR_NOT_BOUND'); - bPool.joinswapExternAmountIn(_tokenIn, _fuzz.tokenAmountIn, _fuzz.minPoolAmountOut); + bPool.joinswapExternAmountIn(_tokenIn, _fuzz.tokenAmountIn, 0); } function test_Revert_MaxInRatio(JoinswapExternAmountIn_FuzzScenario memory _fuzz) public happyPath(_fuzz) { uint256 _tokenAmountIn = bmul(_fuzz.tokenInBalance, MAX_IN_RATIO); vm.expectRevert('ERR_MAX_IN_RATIO'); - bPool.joinswapExternAmountIn(tokenIn, _tokenAmountIn + 1, _fuzz.minPoolAmountOut); + bPool.joinswapExternAmountIn(tokenIn, _tokenAmountIn + 1, 0); } - function test_Revert_LimitOut(JoinswapExternAmountIn_FuzzScenario memory _fuzz) public happyPath(_fuzz) { + function test_Revert_LimitOut( + JoinswapExternAmountIn_FuzzScenario memory _fuzz, + uint256 _minPoolAmountOut + ) public happyPath(_fuzz) { uint256 _poolAmountIn = calcPoolOutGivenSingleIn( _fuzz.tokenInBalance, _fuzz.tokenInDenorm, @@ -2635,24 +2436,19 @@ contract BPool_Unit_JoinswapExternAmountIn is BasePoolTest { _fuzz.tokenAmountIn, _fuzz.swapFee ); + _minPoolAmountOut = bound(_minPoolAmountOut, _poolAmountIn + 1, type(uint256).max); vm.expectRevert('ERR_LIMIT_OUT'); - bPool.joinswapExternAmountIn(tokenIn, _fuzz.tokenAmountIn, _poolAmountIn + 1); + bPool.joinswapExternAmountIn(tokenIn, _fuzz.tokenAmountIn, _minPoolAmountOut); } function test_Revert_Reentrancy(JoinswapExternAmountIn_FuzzScenario memory _fuzz) public { - // Assert that the contract is accessible - assertEq(bPool.call__mutex(), false); - - // Simulate ongoing call to the contract - bPool.set__mutex(true); - - vm.expectRevert('ERR_REENTRY'); - bPool.joinswapExternAmountIn(tokenIn, _fuzz.tokenAmountIn, _fuzz.minPoolAmountOut); + _expectRevertByReentrancy(); + bPool.joinswapExternAmountIn(tokenIn, _fuzz.tokenAmountIn, 0); } function test_Set_Balance(JoinswapExternAmountIn_FuzzScenario memory _fuzz) public happyPath(_fuzz) { - bPool.joinswapExternAmountIn(tokenIn, _fuzz.tokenAmountIn, _fuzz.minPoolAmountOut); + bPool.joinswapExternAmountIn(tokenIn, _fuzz.tokenAmountIn, 0); assertEq(bPool.getBalance(tokenIn), _fuzz.tokenInBalance + _fuzz.tokenAmountIn); } @@ -2661,11 +2457,11 @@ contract BPool_Unit_JoinswapExternAmountIn is BasePoolTest { vm.expectEmit(); emit BPool.LOG_JOIN(address(this), tokenIn, _fuzz.tokenAmountIn); - bPool.joinswapExternAmountIn(tokenIn, _fuzz.tokenAmountIn, _fuzz.minPoolAmountOut); + bPool.joinswapExternAmountIn(tokenIn, _fuzz.tokenAmountIn, 0); } function test_Mint_PoolShare(JoinswapExternAmountIn_FuzzScenario memory _fuzz) public happyPath(_fuzz) { - (uint256 _poolAmountOut) = bPool.joinswapExternAmountIn(tokenIn, _fuzz.tokenAmountIn, _fuzz.minPoolAmountOut); + (uint256 _poolAmountOut) = bPool.joinswapExternAmountIn(tokenIn, _fuzz.tokenAmountIn, 0); assertEq(bPool.totalSupply(), _fuzz.totalSupply + _poolAmountOut); } @@ -2673,7 +2469,7 @@ contract BPool_Unit_JoinswapExternAmountIn is BasePoolTest { function test_Push_PoolShare(JoinswapExternAmountIn_FuzzScenario memory _fuzz) public happyPath(_fuzz) { uint256 _balanceBefore = bPool.balanceOf(address(this)); - (uint256 _poolAmountOut) = bPool.joinswapExternAmountIn(tokenIn, _fuzz.tokenAmountIn, _fuzz.minPoolAmountOut); + (uint256 _poolAmountOut) = bPool.joinswapExternAmountIn(tokenIn, _fuzz.tokenAmountIn, 0); assertEq(bPool.balanceOf(address(this)), _balanceBefore + _poolAmountOut); } @@ -2683,7 +2479,7 @@ contract BPool_Unit_JoinswapExternAmountIn is BasePoolTest { address(tokenIn), abi.encodeWithSelector(IERC20.transferFrom.selector, address(this), address(bPool), _fuzz.tokenAmountIn) ); - bPool.joinswapExternAmountIn(tokenIn, _fuzz.tokenAmountIn, _fuzz.minPoolAmountOut); + bPool.joinswapExternAmountIn(tokenIn, _fuzz.tokenAmountIn, 0); } function test_Returns_PoolAmountOut(JoinswapExternAmountIn_FuzzScenario memory _fuzz) public happyPath(_fuzz) { @@ -2696,19 +2492,17 @@ contract BPool_Unit_JoinswapExternAmountIn is BasePoolTest { _fuzz.swapFee ); - (uint256 _poolAmountOut) = bPool.joinswapExternAmountIn(tokenIn, _fuzz.tokenAmountIn, _fuzz.minPoolAmountOut); + (uint256 _poolAmountOut) = bPool.joinswapExternAmountIn(tokenIn, _fuzz.tokenAmountIn, 0); assertEq(_poolAmountOut, _expectedPoolAmountOut); } function test_Emit_LogCall(JoinswapExternAmountIn_FuzzScenario memory _fuzz) public happyPath(_fuzz) { vm.expectEmit(); - bytes memory _data = abi.encodeWithSelector( - BPool.joinswapExternAmountIn.selector, tokenIn, _fuzz.tokenAmountIn, _fuzz.minPoolAmountOut - ); + bytes memory _data = abi.encodeWithSelector(BPool.joinswapExternAmountIn.selector, tokenIn, _fuzz.tokenAmountIn, 0); emit BPool.LOG_CALL(BPool.joinswapExternAmountIn.selector, address(this), _data); - bPool.joinswapExternAmountIn(tokenIn, _fuzz.tokenAmountIn, _fuzz.minPoolAmountOut); + bPool.joinswapExternAmountIn(tokenIn, _fuzz.tokenAmountIn, 0); } } @@ -2722,7 +2516,6 @@ contract BPool_Unit_JoinswapPoolAmountOut is BasePoolTest { uint256 totalSupply; uint256 totalWeight; uint256 swapFee; - uint256 maxAmountIn; } function _setValues(JoinswapPoolAmountOut_FuzzScenario memory _fuzz) internal { @@ -2760,11 +2553,8 @@ contract BPool_Unit_JoinswapPoolAmountOut is BasePoolTest { _fuzz.swapFee = bound(_fuzz.swapFee, MIN_FEE, MAX_FEE); _fuzz.totalWeight = bound(_fuzz.totalWeight, MIN_WEIGHT * MAX_BOUND_TOKENS, MAX_WEIGHT * MAX_BOUND_TOKENS); - // min - vm.assume(_fuzz.totalSupply >= INIT_POOL_SUPPLY); - - // max - vm.assume(_fuzz.totalSupply < type(uint256).max - _fuzz.poolAmountOut); + _fuzz.poolAmountOut = bound(_fuzz.poolAmountOut, INIT_POOL_SUPPLY, type(uint256).max - INIT_POOL_SUPPLY); + _fuzz.totalSupply = bound(_fuzz.totalSupply, INIT_POOL_SUPPLY, type(uint256).max - _fuzz.poolAmountOut); // min vm.assume(_fuzz.tokenInBalance >= MIN_BALANCE); @@ -2792,8 +2582,6 @@ contract BPool_Unit_JoinswapPoolAmountOut is BasePoolTest { // MAX_IN_RATIO vm.assume(_fuzz.tokenInBalance < type(uint256).max / MAX_IN_RATIO); vm.assume(_tokenAmountIn <= bmul(_fuzz.tokenInBalance, MAX_IN_RATIO)); - - _fuzz.maxAmountIn = bound(_fuzz.maxAmountIn, _tokenAmountIn, type(uint256).max); } modifier happyPath(JoinswapPoolAmountOut_FuzzScenario memory _fuzz) { @@ -2806,27 +2594,30 @@ contract BPool_Unit_JoinswapPoolAmountOut is BasePoolTest { _setFinalize(false); vm.expectRevert('ERR_NOT_FINALIZED'); - bPool.joinswapPoolAmountOut(tokenIn, _fuzz.poolAmountOut, _fuzz.maxAmountIn); + bPool.joinswapPoolAmountOut(tokenIn, _fuzz.poolAmountOut, type(uint256).max); } function test_Revert_NotBound( JoinswapPoolAmountOut_FuzzScenario memory _fuzz, address _tokenIn ) public happyPath(_fuzz) { - vm.assume(_tokenIn != VM_ADDRESS); + assumeNotForgeAddress(_tokenIn); vm.expectRevert('ERR_NOT_BOUND'); - bPool.joinswapPoolAmountOut(_tokenIn, _fuzz.poolAmountOut, _fuzz.maxAmountIn); + bPool.joinswapPoolAmountOut(_tokenIn, _fuzz.poolAmountOut, type(uint256).max); } function test_Revert_MathApprox(JoinswapPoolAmountOut_FuzzScenario memory _fuzz) public happyPath(_fuzz) { _fuzz.poolAmountOut = 0; vm.expectRevert('ERR_MATH_APPROX'); - bPool.joinswapPoolAmountOut(tokenIn, _fuzz.poolAmountOut, _fuzz.maxAmountIn); + bPool.joinswapPoolAmountOut(tokenIn, _fuzz.poolAmountOut, type(uint256).max); } - function test_Revert_LimitIn(JoinswapPoolAmountOut_FuzzScenario memory _fuzz) public happyPath(_fuzz) { + function test_Revert_LimitIn( + JoinswapPoolAmountOut_FuzzScenario memory _fuzz, + uint256 _maxAmountIn + ) public happyPath(_fuzz) { uint256 _tokenAmountIn = calcSingleInGivenPoolOut( _fuzz.tokenInBalance, _fuzz.tokenInDenorm, @@ -2835,9 +2626,10 @@ contract BPool_Unit_JoinswapPoolAmountOut is BasePoolTest { _fuzz.poolAmountOut, _fuzz.swapFee ); + _maxAmountIn = bound(_maxAmountIn, 0, _tokenAmountIn - 1); vm.expectRevert('ERR_LIMIT_IN'); - bPool.joinswapPoolAmountOut(tokenIn, _fuzz.poolAmountOut, _tokenAmountIn - 1); + bPool.joinswapPoolAmountOut(tokenIn, _fuzz.poolAmountOut, _maxAmountIn); } function test_Revert_MaxInRatio(JoinswapPoolAmountOut_FuzzScenario memory _fuzz) public { @@ -2846,8 +2638,8 @@ contract BPool_Unit_JoinswapPoolAmountOut is BasePoolTest { _fuzz.swapFee = bound(_fuzz.swapFee, MIN_FEE, MAX_FEE); _fuzz.totalWeight = bound(_fuzz.totalWeight, MIN_WEIGHT * MAX_BOUND_TOKENS, MAX_WEIGHT * MAX_BOUND_TOKENS); _fuzz.tokenInBalance = bound(_fuzz.tokenInBalance, MIN_BALANCE, type(uint256).max / MAX_IN_RATIO); - vm.assume(_fuzz.totalSupply >= INIT_POOL_SUPPLY); - vm.assume(_fuzz.totalSupply < type(uint256).max - _fuzz.poolAmountOut); + _fuzz.poolAmountOut = bound(_fuzz.poolAmountOut, INIT_POOL_SUPPLY, type(uint256).max - INIT_POOL_SUPPLY); + _fuzz.totalSupply = bound(_fuzz.totalSupply, INIT_POOL_SUPPLY, type(uint256).max - _fuzz.poolAmountOut); _assumeCalcSingleInGivenPoolOut( _fuzz.tokenInBalance, _fuzz.tokenInDenorm, _fuzz.totalSupply, _fuzz.totalWeight, _fuzz.poolAmountOut ); @@ -2861,29 +2653,21 @@ contract BPool_Unit_JoinswapPoolAmountOut is BasePoolTest { ); vm.assume(_tokenAmountIn > bmul(_fuzz.tokenInBalance, MAX_IN_RATIO)); - _fuzz.maxAmountIn = bound(_fuzz.maxAmountIn, _tokenAmountIn, type(uint256).max); - _setValues(_fuzz); vm.expectRevert('ERR_MAX_IN_RATIO'); - bPool.joinswapPoolAmountOut(tokenIn, _fuzz.poolAmountOut, _fuzz.maxAmountIn); + bPool.joinswapPoolAmountOut(tokenIn, _fuzz.poolAmountOut, type(uint256).max); } function test_Revert_Reentrancy(JoinswapPoolAmountOut_FuzzScenario memory _fuzz) public { - // Assert that the contract is accessible - assertEq(bPool.call__mutex(), false); - - // Simulate ongoing call to the contract - bPool.set__mutex(true); - - vm.expectRevert('ERR_REENTRY'); - bPool.joinswapPoolAmountOut(tokenIn, _fuzz.poolAmountOut, _fuzz.maxAmountIn); + _expectRevertByReentrancy(); + bPool.joinswapPoolAmountOut(tokenIn, _fuzz.poolAmountOut, type(uint256).max); } function test_Set_Balance(JoinswapPoolAmountOut_FuzzScenario memory _fuzz) public happyPath(_fuzz) { uint256 _balanceBefore = bPool.getBalance(tokenIn); - bPool.joinswapPoolAmountOut(tokenIn, _fuzz.poolAmountOut, _fuzz.maxAmountIn); + bPool.joinswapPoolAmountOut(tokenIn, _fuzz.poolAmountOut, type(uint256).max); uint256 _tokenAmountIn = calcSingleInGivenPoolOut( _fuzz.tokenInBalance, @@ -2909,11 +2693,11 @@ contract BPool_Unit_JoinswapPoolAmountOut is BasePoolTest { vm.expectEmit(); emit BPool.LOG_JOIN(address(this), tokenIn, _tokenAmountIn); - bPool.joinswapPoolAmountOut(tokenIn, _fuzz.poolAmountOut, _fuzz.maxAmountIn); + bPool.joinswapPoolAmountOut(tokenIn, _fuzz.poolAmountOut, type(uint256).max); } function test_Mint_PoolShare(JoinswapPoolAmountOut_FuzzScenario memory _fuzz) public happyPath(_fuzz) { - bPool.joinswapPoolAmountOut(tokenIn, _fuzz.poolAmountOut, _fuzz.maxAmountIn); + bPool.joinswapPoolAmountOut(tokenIn, _fuzz.poolAmountOut, type(uint256).max); assertEq(bPool.totalSupply(), _fuzz.totalSupply + _fuzz.poolAmountOut); } @@ -2921,7 +2705,7 @@ contract BPool_Unit_JoinswapPoolAmountOut is BasePoolTest { function test_Push_PoolShare(JoinswapPoolAmountOut_FuzzScenario memory _fuzz) public happyPath(_fuzz) { uint256 _balanceBefore = bPool.balanceOf(address(this)); - bPool.joinswapPoolAmountOut(tokenIn, _fuzz.poolAmountOut, _fuzz.maxAmountIn); + bPool.joinswapPoolAmountOut(tokenIn, _fuzz.poolAmountOut, type(uint256).max); assertEq(bPool.balanceOf(address(this)), _balanceBefore + _fuzz.poolAmountOut); } @@ -2940,7 +2724,7 @@ contract BPool_Unit_JoinswapPoolAmountOut is BasePoolTest { address(tokenIn), abi.encodeWithSelector(IERC20.transferFrom.selector, address(this), address(bPool), _tokenAmountIn) ); - bPool.joinswapPoolAmountOut(tokenIn, _fuzz.poolAmountOut, _fuzz.maxAmountIn); + bPool.joinswapPoolAmountOut(tokenIn, _fuzz.poolAmountOut, type(uint256).max); } function test_Returns_TokenAmountIn(JoinswapPoolAmountOut_FuzzScenario memory _fuzz) public happyPath(_fuzz) { @@ -2953,7 +2737,7 @@ contract BPool_Unit_JoinswapPoolAmountOut is BasePoolTest { _fuzz.swapFee ); - (uint256 _tokenAmountIn) = bPool.joinswapPoolAmountOut(tokenIn, _fuzz.poolAmountOut, _fuzz.maxAmountIn); + (uint256 _tokenAmountIn) = bPool.joinswapPoolAmountOut(tokenIn, _fuzz.poolAmountOut, type(uint256).max); assertEq(_expectedTokenAmountIn, _tokenAmountIn); } @@ -2961,10 +2745,10 @@ contract BPool_Unit_JoinswapPoolAmountOut is BasePoolTest { function test_Emit_LogCall(JoinswapPoolAmountOut_FuzzScenario memory _fuzz) public happyPath(_fuzz) { vm.expectEmit(); bytes memory _data = - abi.encodeWithSelector(BPool.joinswapPoolAmountOut.selector, tokenIn, _fuzz.poolAmountOut, _fuzz.maxAmountIn); + abi.encodeWithSelector(BPool.joinswapPoolAmountOut.selector, tokenIn, _fuzz.poolAmountOut, type(uint256).max); emit BPool.LOG_CALL(BPool.joinswapPoolAmountOut.selector, address(this), _data); - bPool.joinswapPoolAmountOut(tokenIn, _fuzz.poolAmountOut, _fuzz.maxAmountIn); + bPool.joinswapPoolAmountOut(tokenIn, _fuzz.poolAmountOut, type(uint256).max); } } @@ -2978,7 +2762,6 @@ contract BPool_Unit_ExitswapPoolAmountIn is BasePoolTest { uint256 totalSupply; uint256 totalWeight; uint256 swapFee; - uint256 minAmountOut; } function _setValues(ExitswapPoolAmountIn_FuzzScenario memory _fuzz) internal { @@ -3017,9 +2800,7 @@ contract BPool_Unit_ExitswapPoolAmountIn is BasePoolTest { _fuzz.tokenOutDenorm = bound(_fuzz.tokenOutDenorm, MIN_WEIGHT, MAX_WEIGHT); _fuzz.swapFee = bound(_fuzz.swapFee, MIN_FEE, MAX_FEE); _fuzz.totalWeight = bound(_fuzz.totalWeight, MIN_WEIGHT * MAX_BOUND_TOKENS, MAX_WEIGHT * MAX_BOUND_TOKENS); - - // min - vm.assume(_fuzz.totalSupply >= INIT_POOL_SUPPLY); + _fuzz.totalSupply = bound(_fuzz.totalSupply, INIT_POOL_SUPPLY, type(uint256).max); // max vm.assume(_fuzz.poolAmountIn < _fuzz.totalSupply); @@ -3053,8 +2834,6 @@ contract BPool_Unit_ExitswapPoolAmountIn is BasePoolTest { // MAX_OUT_RATIO vm.assume(_fuzz.tokenOutBalance < type(uint256).max / MAX_OUT_RATIO); vm.assume(_tokenAmountOut <= bmul(_fuzz.tokenOutBalance, MAX_OUT_RATIO)); - - _fuzz.minAmountOut = bound(_fuzz.minAmountOut, 0, _tokenAmountOut); } modifier happyPath(ExitswapPoolAmountIn_FuzzScenario memory _fuzz) { @@ -3067,20 +2846,23 @@ contract BPool_Unit_ExitswapPoolAmountIn is BasePoolTest { _setFinalize(false); vm.expectRevert('ERR_NOT_FINALIZED'); - bPool.exitswapPoolAmountIn(tokenOut, _fuzz.poolAmountIn, _fuzz.minAmountOut); + bPool.exitswapPoolAmountIn(tokenOut, _fuzz.poolAmountIn, 0); } function test_Revert_NotBound( ExitswapPoolAmountIn_FuzzScenario memory _fuzz, address _tokenIn ) public happyPath(_fuzz) { - vm.assume(_tokenIn != VM_ADDRESS); + assumeNotForgeAddress(_tokenIn); vm.expectRevert('ERR_NOT_BOUND'); - bPool.exitswapPoolAmountIn(_tokenIn, _fuzz.poolAmountIn, _fuzz.minAmountOut); + bPool.exitswapPoolAmountIn(_tokenIn, _fuzz.poolAmountIn, 0); } - function test_Revert_LimitOut(ExitswapPoolAmountIn_FuzzScenario memory _fuzz) public happyPath(_fuzz) { + function test_Revert_LimitOut( + ExitswapPoolAmountIn_FuzzScenario memory _fuzz, + uint256 _minAmountOut + ) public happyPath(_fuzz) { uint256 _tokenAmountOut = calcSingleOutGivenPoolIn( _fuzz.tokenOutBalance, _fuzz.tokenOutDenorm, @@ -3089,9 +2871,10 @@ contract BPool_Unit_ExitswapPoolAmountIn is BasePoolTest { _fuzz.poolAmountIn, _fuzz.swapFee ); + _minAmountOut = bound(_minAmountOut, _tokenAmountOut + 1, type(uint256).max); vm.expectRevert('ERR_LIMIT_OUT'); - bPool.exitswapPoolAmountIn(tokenOut, _fuzz.poolAmountIn, _tokenAmountOut + 1); + bPool.exitswapPoolAmountIn(tokenOut, _fuzz.poolAmountIn, _minAmountOut); } function test_Revert_MaxOutRatio(ExitswapPoolAmountIn_FuzzScenario memory _fuzz) public { @@ -3100,7 +2883,7 @@ contract BPool_Unit_ExitswapPoolAmountIn is BasePoolTest { _fuzz.swapFee = bound(_fuzz.swapFee, MIN_FEE, MAX_FEE); _fuzz.totalWeight = bound(_fuzz.totalWeight, MIN_WEIGHT * MAX_BOUND_TOKENS, MAX_WEIGHT * MAX_BOUND_TOKENS); _fuzz.tokenOutBalance = bound(_fuzz.tokenOutBalance, MIN_BALANCE, type(uint256).max / MAX_OUT_RATIO); - vm.assume(_fuzz.totalSupply >= INIT_POOL_SUPPLY); + _fuzz.totalSupply = bound(_fuzz.totalSupply, INIT_POOL_SUPPLY, type(uint256).max); vm.assume(_fuzz.totalSupply < type(uint256).max - _fuzz.poolAmountIn); vm.assume(_fuzz.poolAmountIn < _fuzz.totalSupply); _assumeCalcSingleOutGivenPoolIn( @@ -3121,23 +2904,15 @@ contract BPool_Unit_ExitswapPoolAmountIn is BasePoolTest { ); vm.assume(_tokenAmountOut > bmul(_fuzz.tokenOutBalance, MAX_OUT_RATIO)); - _fuzz.minAmountOut = bound(_fuzz.minAmountOut, 0, _tokenAmountOut); - _setValues(_fuzz); vm.expectRevert('ERR_MAX_OUT_RATIO'); - bPool.exitswapPoolAmountIn(tokenOut, _fuzz.poolAmountIn, _fuzz.minAmountOut); + bPool.exitswapPoolAmountIn(tokenOut, _fuzz.poolAmountIn, 0); } function test_Revert_Reentrancy(ExitswapPoolAmountIn_FuzzScenario memory _fuzz) public happyPath(_fuzz) { - // Assert that the contract is accessible - assertEq(bPool.call__mutex(), false); - - // Simulate ongoing call to the contract - bPool.set__mutex(true); - - vm.expectRevert('ERR_REENTRY'); - bPool.exitswapPoolAmountIn(tokenOut, _fuzz.poolAmountIn, _fuzz.minAmountOut); + _expectRevertByReentrancy(); + bPool.exitswapPoolAmountIn(tokenOut, _fuzz.poolAmountIn, 0); } function test_Set_Balance(ExitswapPoolAmountIn_FuzzScenario memory _fuzz) public happyPath(_fuzz) { @@ -3151,7 +2926,7 @@ contract BPool_Unit_ExitswapPoolAmountIn is BasePoolTest { _fuzz.swapFee ); - bPool.exitswapPoolAmountIn(tokenOut, _fuzz.poolAmountIn, _fuzz.minAmountOut); + bPool.exitswapPoolAmountIn(tokenOut, _fuzz.poolAmountIn, 0); assertEq(bPool.getBalance(tokenOut), _balanceBefore - _tokenAmountOut); } @@ -3169,13 +2944,13 @@ contract BPool_Unit_ExitswapPoolAmountIn is BasePoolTest { vm.expectEmit(); emit BPool.LOG_EXIT(address(this), tokenOut, _tokenAmountOut); - bPool.exitswapPoolAmountIn(tokenOut, _fuzz.poolAmountIn, _fuzz.minAmountOut); + bPool.exitswapPoolAmountIn(tokenOut, _fuzz.poolAmountIn, 0); } function test_Pull_PoolShare(ExitswapPoolAmountIn_FuzzScenario memory _fuzz) public happyPath(_fuzz) { uint256 _balanceBefore = bPool.balanceOf(address(this)); - bPool.exitswapPoolAmountIn(tokenOut, _fuzz.poolAmountIn, _fuzz.minAmountOut); + bPool.exitswapPoolAmountIn(tokenOut, _fuzz.poolAmountIn, 0); assertEq(bPool.balanceOf(address(this)), _balanceBefore - _fuzz.poolAmountIn); } @@ -3184,7 +2959,7 @@ contract BPool_Unit_ExitswapPoolAmountIn is BasePoolTest { uint256 _totalSupplyBefore = bPool.totalSupply(); uint256 _exitFee = bmul(_fuzz.poolAmountIn, EXIT_FEE); - bPool.exitswapPoolAmountIn(tokenOut, _fuzz.poolAmountIn, _fuzz.minAmountOut); + bPool.exitswapPoolAmountIn(tokenOut, _fuzz.poolAmountIn, 0); assertEq(bPool.totalSupply(), _totalSupplyBefore - bsub(_fuzz.poolAmountIn, _exitFee)); } @@ -3194,7 +2969,7 @@ contract BPool_Unit_ExitswapPoolAmountIn is BasePoolTest { uint256 _balanceBefore = bPool.balanceOf(_factoryAddress); uint256 _exitFee = bmul(_fuzz.poolAmountIn, EXIT_FEE); - bPool.exitswapPoolAmountIn(tokenOut, _fuzz.poolAmountIn, _fuzz.minAmountOut); + bPool.exitswapPoolAmountIn(tokenOut, _fuzz.poolAmountIn, 0); assertEq(bPool.balanceOf(_factoryAddress), _balanceBefore - _fuzz.poolAmountIn + _exitFee); } @@ -3210,7 +2985,7 @@ contract BPool_Unit_ExitswapPoolAmountIn is BasePoolTest { ); vm.expectCall(address(tokenOut), abi.encodeWithSelector(IERC20.transfer.selector, address(this), _tokenAmountOut)); - bPool.exitswapPoolAmountIn(tokenOut, _fuzz.poolAmountIn, _fuzz.minAmountOut); + bPool.exitswapPoolAmountIn(tokenOut, _fuzz.poolAmountIn, 0); } function test_Returns_TokenAmountOut(ExitswapPoolAmountIn_FuzzScenario memory _fuzz) public happyPath(_fuzz) { @@ -3223,18 +2998,17 @@ contract BPool_Unit_ExitswapPoolAmountIn is BasePoolTest { _fuzz.swapFee ); - (uint256 _tokenAmountOut) = bPool.exitswapPoolAmountIn(tokenOut, _fuzz.poolAmountIn, _fuzz.minAmountOut); + (uint256 _tokenAmountOut) = bPool.exitswapPoolAmountIn(tokenOut, _fuzz.poolAmountIn, 0); assertEq(_tokenAmountOut, _expectedTokenAmountOut); } function test_Emit_LogCall(ExitswapPoolAmountIn_FuzzScenario memory _fuzz) public happyPath(_fuzz) { vm.expectEmit(); - bytes memory _data = - abi.encodeWithSelector(BPool.exitswapPoolAmountIn.selector, tokenOut, _fuzz.poolAmountIn, _fuzz.minAmountOut); + bytes memory _data = abi.encodeWithSelector(BPool.exitswapPoolAmountIn.selector, tokenOut, _fuzz.poolAmountIn, 0); emit BPool.LOG_CALL(BPool.exitswapPoolAmountIn.selector, address(this), _data); - bPool.exitswapPoolAmountIn(tokenOut, _fuzz.poolAmountIn, _fuzz.minAmountOut); + bPool.exitswapPoolAmountIn(tokenOut, _fuzz.poolAmountIn, 0); } } @@ -3248,7 +3022,6 @@ contract BPool_Unit_ExitswapExternAmountOut is BasePoolTest { uint256 totalSupply; uint256 totalWeight; uint256 swapFee; - uint256 maxPoolAmountIn; } function _setValues(ExitswapExternAmountOut_FuzzScenario memory _fuzz, uint256 _poolAmountIn) internal { @@ -3290,10 +3063,10 @@ contract BPool_Unit_ExitswapExternAmountOut is BasePoolTest { // safe bound assumptions _fuzz.tokenOutDenorm = bound(_fuzz.tokenOutDenorm, MIN_WEIGHT, MAX_WEIGHT); _fuzz.swapFee = bound(_fuzz.swapFee, MIN_FEE, MAX_FEE); - _fuzz.totalWeight = bound(_fuzz.totalWeight, MIN_WEIGHT * MAX_BOUND_TOKENS, MAX_WEIGHT * MAX_BOUND_TOKENS); + _fuzz.totalWeight = bound(_fuzz.totalWeight, MIN_WEIGHT * MAX_BOUND_TOKENS, MAX_TOTAL_WEIGHT); // min - vm.assume(_fuzz.totalSupply >= INIT_POOL_SUPPLY); + _fuzz.totalSupply = bound(_fuzz.totalSupply, INIT_POOL_SUPPLY, type(uint256).max); // MAX_OUT_RATIO vm.assume(_fuzz.tokenOutBalance < type(uint256).max / MAX_OUT_RATIO); @@ -3330,8 +3103,6 @@ contract BPool_Unit_ExitswapExternAmountOut is BasePoolTest { // max vm.assume(_poolAmountIn < _fuzz.totalSupply); vm.assume(_fuzz.totalSupply < type(uint256).max - _poolAmountIn); - - _fuzz.maxPoolAmountIn = bound(_fuzz.maxPoolAmountIn, _poolAmountIn, type(uint256).max); } modifier happyPath(ExitswapExternAmountOut_FuzzScenario memory _fuzz) { @@ -3344,34 +3115,37 @@ contract BPool_Unit_ExitswapExternAmountOut is BasePoolTest { _setFinalize(false); vm.expectRevert('ERR_NOT_FINALIZED'); - bPool.exitswapExternAmountOut(tokenOut, _fuzz.tokenAmountOut, _fuzz.maxPoolAmountIn); + bPool.exitswapExternAmountOut(tokenOut, _fuzz.tokenAmountOut, type(uint256).max); } function test_Revert_NotBound( ExitswapExternAmountOut_FuzzScenario memory _fuzz, address _tokenOut ) public happyPath(_fuzz) { - vm.assume(_tokenOut != VM_ADDRESS); + assumeNotForgeAddress(_tokenOut); vm.expectRevert('ERR_NOT_BOUND'); - bPool.exitswapExternAmountOut(_tokenOut, _fuzz.tokenAmountOut, _fuzz.maxPoolAmountIn); + bPool.exitswapExternAmountOut(_tokenOut, _fuzz.tokenAmountOut, type(uint256).max); } function test_Revert_MaxOutRatio(ExitswapExternAmountOut_FuzzScenario memory _fuzz) public happyPath(_fuzz) { uint256 _maxTokenAmountOut = bmul(_fuzz.tokenOutBalance, MAX_OUT_RATIO); vm.expectRevert('ERR_MAX_OUT_RATIO'); - bPool.exitswapExternAmountOut(tokenOut, _maxTokenAmountOut + 1, _fuzz.maxPoolAmountIn); + bPool.exitswapExternAmountOut(tokenOut, _maxTokenAmountOut + 1, type(uint256).max); } function test_Revert_MathApprox(ExitswapExternAmountOut_FuzzScenario memory _fuzz) public happyPath(_fuzz) { _fuzz.tokenAmountOut = 0; vm.expectRevert('ERR_MATH_APPROX'); - bPool.exitswapExternAmountOut(tokenOut, _fuzz.tokenAmountOut, _fuzz.maxPoolAmountIn); + bPool.exitswapExternAmountOut(tokenOut, _fuzz.tokenAmountOut, type(uint256).max); } - function test_Revert_LimitIn(ExitswapExternAmountOut_FuzzScenario memory _fuzz) public happyPath(_fuzz) { + function test_Revert_LimitIn( + ExitswapExternAmountOut_FuzzScenario memory _fuzz, + uint256 _maxPoolAmountIn + ) public happyPath(_fuzz) { uint256 _poolAmountIn = calcPoolInGivenSingleOut( _fuzz.tokenOutBalance, _fuzz.tokenOutDenorm, @@ -3380,24 +3154,19 @@ contract BPool_Unit_ExitswapExternAmountOut is BasePoolTest { _fuzz.tokenAmountOut, _fuzz.swapFee ); + _maxPoolAmountIn = bound(_maxPoolAmountIn, 0, _poolAmountIn - 1); vm.expectRevert('ERR_LIMIT_IN'); - bPool.exitswapExternAmountOut(tokenOut, _fuzz.tokenAmountOut, _poolAmountIn - 1); + bPool.exitswapExternAmountOut(tokenOut, _fuzz.tokenAmountOut, _maxPoolAmountIn); } function test_Revert_Reentrancy(ExitswapExternAmountOut_FuzzScenario memory _fuzz) public { - // Assert that the contract is accessible - assertEq(bPool.call__mutex(), false); - - // Simulate ongoing call to the contract - bPool.set__mutex(true); - - vm.expectRevert('ERR_REENTRY'); - bPool.exitswapExternAmountOut(tokenOut, _fuzz.tokenAmountOut, _fuzz.maxPoolAmountIn); + _expectRevertByReentrancy(); + bPool.exitswapExternAmountOut(tokenOut, _fuzz.tokenAmountOut, type(uint256).max); } function test_Set_Balance(ExitswapExternAmountOut_FuzzScenario memory _fuzz) public happyPath(_fuzz) { - bPool.exitswapExternAmountOut(tokenOut, _fuzz.tokenAmountOut, _fuzz.maxPoolAmountIn); + bPool.exitswapExternAmountOut(tokenOut, _fuzz.tokenAmountOut, type(uint256).max); assertEq(bPool.getBalance(tokenOut), _fuzz.tokenOutBalance - _fuzz.tokenAmountOut); } @@ -3406,7 +3175,7 @@ contract BPool_Unit_ExitswapExternAmountOut is BasePoolTest { vm.expectEmit(); emit BPool.LOG_EXIT(address(this), tokenOut, _fuzz.tokenAmountOut); - bPool.exitswapExternAmountOut(tokenOut, _fuzz.tokenAmountOut, _fuzz.maxPoolAmountIn); + bPool.exitswapExternAmountOut(tokenOut, _fuzz.tokenAmountOut, type(uint256).max); } function test_Pull_PoolShare(ExitswapExternAmountOut_FuzzScenario memory _fuzz) public happyPath(_fuzz) { @@ -3421,7 +3190,7 @@ contract BPool_Unit_ExitswapExternAmountOut is BasePoolTest { ); uint256 _exitFee = bmul(_poolAmountIn, EXIT_FEE); - bPool.exitswapExternAmountOut(tokenOut, _fuzz.tokenAmountOut, _fuzz.maxPoolAmountIn); + bPool.exitswapExternAmountOut(tokenOut, _fuzz.tokenAmountOut, type(uint256).max); assertEq(bPool.balanceOf(address(this)), _balanceBefore - bsub(_poolAmountIn, _exitFee)); } @@ -3438,7 +3207,7 @@ contract BPool_Unit_ExitswapExternAmountOut is BasePoolTest { ); uint256 _exitFee = bmul(_poolAmountIn, EXIT_FEE); - bPool.exitswapExternAmountOut(tokenOut, _fuzz.tokenAmountOut, _fuzz.maxPoolAmountIn); + bPool.exitswapExternAmountOut(tokenOut, _fuzz.tokenAmountOut, type(uint256).max); assertEq(bPool.totalSupply(), _totalSupplyBefore - bsub(_poolAmountIn, _exitFee)); } @@ -3456,7 +3225,7 @@ contract BPool_Unit_ExitswapExternAmountOut is BasePoolTest { ); uint256 _exitFee = bmul(_poolAmountIn, EXIT_FEE); - bPool.exitswapExternAmountOut(tokenOut, _fuzz.tokenAmountOut, _fuzz.maxPoolAmountIn); + bPool.exitswapExternAmountOut(tokenOut, _fuzz.tokenAmountOut, type(uint256).max); assertEq(bPool.balanceOf(_factoryAddress), _balanceBefore - _poolAmountIn + _exitFee); } @@ -3465,7 +3234,7 @@ contract BPool_Unit_ExitswapExternAmountOut is BasePoolTest { vm.expectCall( address(tokenOut), abi.encodeWithSelector(IERC20.transfer.selector, address(this), _fuzz.tokenAmountOut) ); - bPool.exitswapExternAmountOut(tokenOut, _fuzz.tokenAmountOut, _fuzz.maxPoolAmountIn); + bPool.exitswapExternAmountOut(tokenOut, _fuzz.tokenAmountOut, type(uint256).max); } function test_Returns_PoolAmountIn(ExitswapExternAmountOut_FuzzScenario memory _fuzz) public happyPath(_fuzz) { @@ -3478,25 +3247,24 @@ contract BPool_Unit_ExitswapExternAmountOut is BasePoolTest { _fuzz.swapFee ); - (uint256 _poolAmountIn) = bPool.exitswapExternAmountOut(tokenOut, _fuzz.tokenAmountOut, _fuzz.maxPoolAmountIn); + (uint256 _poolAmountIn) = bPool.exitswapExternAmountOut(tokenOut, _fuzz.tokenAmountOut, type(uint256).max); assertEq(_expectedPoolAmountIn, _poolAmountIn); } function test_Emit_LogCall(ExitswapExternAmountOut_FuzzScenario memory _fuzz) public happyPath(_fuzz) { vm.expectEmit(); - bytes memory _data = abi.encodeWithSelector( - BPool.exitswapExternAmountOut.selector, tokenOut, _fuzz.tokenAmountOut, _fuzz.maxPoolAmountIn - ); + bytes memory _data = + abi.encodeWithSelector(BPool.exitswapExternAmountOut.selector, tokenOut, _fuzz.tokenAmountOut, type(uint256).max); emit BPool.LOG_CALL(BPool.exitswapExternAmountOut.selector, address(this), _data); - bPool.exitswapExternAmountOut(tokenOut, _fuzz.tokenAmountOut, _fuzz.maxPoolAmountIn); + bPool.exitswapExternAmountOut(tokenOut, _fuzz.tokenAmountOut, type(uint256).max); } } contract BPool_Unit__PullUnderlying is BasePoolTest { function test_Call_TransferFrom(address _erc20, address _from, uint256 _amount) public { - vm.assume(_erc20 != VM_ADDRESS); + assumeNotForgeAddress(_erc20); vm.mockCall( _erc20, abi.encodeWithSelector(IERC20.transferFrom.selector, _from, address(bPool), _amount), abi.encode(true) @@ -3507,7 +3275,7 @@ contract BPool_Unit__PullUnderlying is BasePoolTest { } function test_Revert_ERC20False(address _erc20, address _from, uint256 _amount) public { - vm.assume(_erc20 != VM_ADDRESS); + assumeNotForgeAddress(_erc20); vm.mockCall( _erc20, abi.encodeWithSelector(IERC20.transferFrom.selector, _from, address(bPool), _amount), abi.encode(false) @@ -3520,7 +3288,7 @@ contract BPool_Unit__PullUnderlying is BasePoolTest { contract BPool_Unit__PushUnderlying is BasePoolTest { function test_Call_Transfer(address _erc20, address _to, uint256 _amount) public { - vm.assume(_erc20 != VM_ADDRESS); + assumeNotForgeAddress(_erc20); vm.mockCall(_erc20, abi.encodeWithSelector(IERC20.transfer.selector, _to, _amount), abi.encode(true)); @@ -3529,7 +3297,7 @@ contract BPool_Unit__PushUnderlying is BasePoolTest { } function test_Revert_ERC20False(address _erc20, address _to, uint256 _amount) public { - vm.assume(_erc20 != VM_ADDRESS); + assumeNotForgeAddress(_erc20); vm.mockCall(_erc20, abi.encodeWithSelector(IERC20.transfer.selector, _to, _amount), abi.encode(false)); diff --git a/test/utils/Utils.sol b/test/utils/Utils.sol index 4206a956..a4134359 100644 --- a/test/utils/Utils.sol +++ b/test/utils/Utils.sol @@ -4,6 +4,28 @@ pragma solidity 0.8.23; import {Test} from 'forge-std/Test.sol'; contract Utils is Test { + uint256 public constant TOKENS_AMOUNT = 3; + + address[TOKENS_AMOUNT] public tokens; + + function _tokensToMemory() internal view returns (address[] memory _tokens) { + _tokens = new address[](tokens.length); + for (uint256 i = 0; i < tokens.length; i++) { + _tokens[i] = tokens[i]; + } + } + + function _staticToDynamicUintArray(uint256[TOKENS_AMOUNT] memory _fixedUintArray) + internal + pure + returns (uint256[] memory _memoryUintArray) + { + _memoryUintArray = new uint256[](_fixedUintArray.length); + for (uint256 i = 0; i < _fixedUintArray.length; i++) { + _memoryUintArray[i] = _fixedUintArray[i]; + } + } + /** * @dev Write a uint256 value to a storage slot. * @param _target The address of the contract. @@ -78,4 +100,23 @@ contract Utils is Test { bytes32 _slot = keccak256(abi.encode(_mappingKey, _mappingSlotNumber)); _writeUintToStorage(_target, uint256(_slot), _value); } + + /** + * @dev Load an array of type(uint256).max values into memory. + * @param _length The length of the array. + */ + function _maxArray(uint256 _length) internal pure returns (uint256[] memory _maxUintArray) { + _maxUintArray = new uint256[](_length); + for (uint256 i = 0; i < TOKENS_AMOUNT; i++) { + _maxUintArray[i] = type(uint256).max; + } + } + + /** + * @dev Load an array of 0 values into memory. + * @param _length The length of the array. + */ + function _zeroArray(uint256 _length) internal pure returns (uint256[] memory _zeroUintArray) { + _zeroUintArray = new uint256[](_length); + } }