Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

test: swapExactAmountOut happyPath #19

Merged
merged 3 commits into from
May 15, 2024
Merged
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
142 changes: 140 additions & 2 deletions test/unit/BPool.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import {Utils} from 'test/unit/Utils.sol';
// TODO: remove once `private` keyword is removed in all test cases
/* solhint-disable */

abstract contract BasePoolTest is Test, BConst, Utils {
abstract contract BasePoolTest is Test, BConst, Utils, BMath {
using LibString for *;

uint256 public constant TOKENS_AMOUNT = 3;
Expand Down Expand Up @@ -81,6 +81,20 @@ abstract contract BasePoolTest is Test, BConst, Utils {
function _setTotalSupply(uint256 _totalSupply) internal {
_setPoolBalance(address(0), _totalSupply);
}

function _assumeCalcSpotPrice(
uint256 _tokenInBalance,
uint256 _tokenInDenorm,
uint256 _tokenOutBalance,
uint256 _tokenOutDenorm,
uint256 _swapFee
) internal view {
uint256 _numer = bdiv(_tokenInBalance, _tokenInDenorm);
uint256 _denom = bdiv(_tokenOutBalance, _tokenOutDenorm);
uint256 _ratio = bdiv(_numer, _denom);
uint256 _scale = bdiv(BONE, bsub(BONE, _swapFee));
vm.assume(_ratio < type(uint256).max / _scale);
}
}

contract BPool_Unit_Constructor is BasePoolTest {
Expand Down Expand Up @@ -505,7 +519,7 @@ contract BPool_Unit_ExitPool is BasePoolTest {
function test_Emit_LogCall() private view {}
}

contract BPool_Unit_SwapExactAmountIn is BasePoolTest, BMath {
contract BPool_Unit_SwapExactAmountIn is BasePoolTest {
address tokenIn;
address tokenOut;

Expand Down Expand Up @@ -646,6 +660,130 @@ contract BPool_Unit_SwapExactAmountIn is BasePoolTest, BMath {
}

contract BPool_Unit_SwapExactAmountOut is BasePoolTest {
address tokenIn;
address tokenOut;

struct SwapExactAmountOut_FuzzScenario {
uint256 tokenAmountOut;
uint256 tokenInBalance;
uint256 tokenInDenorm;
uint256 tokenOutBalance;
uint256 tokenOutDenorm;
uint256 swapFee;
}

function _setValues(SwapExactAmountOut_FuzzScenario memory _fuzz) internal {
tokenIn = tokens[0];
tokenOut = tokens[1];

// Create mocks for tokenIn and tokenOut (only use the first 2 tokens)
_mockTransferFrom(tokenIn);
_mockTransfer(tokenOut);

// Set balances
_setRecord(
tokenIn,
BPool.Record({
bound: true,
index: 0, // NOTE: irrelevant for this method
denorm: _fuzz.tokenInDenorm,
balance: _fuzz.tokenInBalance
})
);
_setRecord(
tokenOut,
BPool.Record({
bound: true,
index: 0, // NOTE: irrelevant for this method
denorm: _fuzz.tokenOutDenorm,
balance: _fuzz.tokenOutBalance
})
);

// Set swapFee
_setSwapFee(_fuzz.swapFee);
// Set public swap
_setPublicSwap(true);
// Set finalize
_setFinalize(true);
}

function _assumeHappyPath(SwapExactAmountOut_FuzzScenario memory _fuzz) internal view {
// safe bound assumptions
_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);

// 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);

// max - calcSpotPrice (spotPriceAfter)
vm.assume(_fuzz.tokenAmountOut < type(uint256).max - _fuzz.tokenOutBalance);
vm.assume(_fuzz.tokenOutBalance + _fuzz.tokenAmountOut < type(uint256).max / _fuzz.tokenOutDenorm);

// internal calculation for calcSpotPrice (spotPriceBefore)
_assumeCalcSpotPrice(
_fuzz.tokenInBalance, _fuzz.tokenInDenorm, _fuzz.tokenOutBalance, _fuzz.tokenOutDenorm, _fuzz.swapFee
);
wei3erHase marked this conversation as resolved.
Show resolved Hide resolved

// MAX_OUT_RATIO
vm.assume(_fuzz.tokenAmountOut <= bmul(_fuzz.tokenOutBalance, MAX_OUT_RATIO));

// L364 BPool.sol
uint256 _spotPriceBefore = calcSpotPrice(
_fuzz.tokenInBalance, _fuzz.tokenInDenorm, _fuzz.tokenOutBalance, _fuzz.tokenOutDenorm, _fuzz.swapFee
);

// internal calculation for calcInGivenOut
uint256 _weightRatio = bdiv(_fuzz.tokenOutDenorm, _fuzz.tokenInDenorm);
uint256 _diff = bsub(_fuzz.tokenOutBalance, _fuzz.tokenAmountOut);
uint256 _y = bdiv(_fuzz.tokenOutBalance, _diff);
uint256 _foo = bpow(_y, _weightRatio);
vm.assume(bsub(_foo, BONE) < type(uint256).max / _fuzz.tokenInBalance);
Copy link
Member

Choose a reason for hiding this comment

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

why create _assumeCalcSpotPrice but not a method for this?


uint256 _tokenAmountIn = calcInGivenOut(
_fuzz.tokenInBalance,
_fuzz.tokenInDenorm,
_fuzz.tokenOutBalance,
_fuzz.tokenOutDenorm,
_fuzz.tokenAmountOut,
_fuzz.swapFee
);

vm.assume(_tokenAmountIn > BONE);
vm.assume(bmul(_spotPriceBefore, _fuzz.tokenAmountOut) <= _tokenAmountIn);

// max - calcSpotPrice (spotPriceAfter)
vm.assume(_tokenAmountIn < type(uint256).max - _fuzz.tokenInBalance);
vm.assume(_fuzz.tokenInBalance + _tokenAmountIn < type(uint256).max / _fuzz.tokenInDenorm);

// internal calculation for calcSpotPrice (spotPriceAfter)
_assumeCalcSpotPrice(
_fuzz.tokenInBalance + _tokenAmountIn,
_fuzz.tokenInDenorm,
_fuzz.tokenOutBalance - _fuzz.tokenAmountOut,
_fuzz.tokenOutDenorm,
_fuzz.swapFee
);
}

modifier happyPath(SwapExactAmountOut_FuzzScenario memory _fuzz) {
_assumeHappyPath(_fuzz);
_setValues(_fuzz);
_;
}

function test_HappyPath(SwapExactAmountOut_FuzzScenario memory _fuzz) public happyPath(_fuzz) {
uint256 _maxPrice = type(uint256).max;
uint256 _maxAmountIn = type(uint256).max;
bPool.swapExactAmountOut(tokenIn, _maxAmountIn, tokenOut, _fuzz.tokenAmountOut, _maxPrice);
}

function test_Revert_NotBoundTokenIn() private view {}

function test_Revert_NotBoundTokenOut() private view {}
Expand Down
Loading