Skip to content

Commit

Permalink
Phantom: Test swaps (balancer#864)
Browse files Browse the repository at this point in the history
* phantom: test swaps

* phantom: fix linter

* remove hardhat console import

Co-authored-by: dmf7z <[email protected]>
  • Loading branch information
facuspagnuolo and dmf7z authored Sep 24, 2021
1 parent 6bbf721 commit 215ee8c
Show file tree
Hide file tree
Showing 7 changed files with 434 additions and 123 deletions.
86 changes: 44 additions & 42 deletions pkg/pool-stable-phantom/contracts/StablePhantomPool.sol
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ contract StablePhantomPool is StablePool {
uint256 indexIn,
uint256 indexOut
) public virtual override onlyVault(request.poolId) returns (uint256) {
_require(totalSupply() > 0, Errors.UNINITIALIZED);
_cachePriceRatesIfNecessary();
return super.onSwap(request, balances, indexIn, indexOut);
}
Expand All @@ -139,11 +140,13 @@ contract StablePhantomPool is StablePool {
uint256 indexIn,
uint256 indexOut
) internal virtual override returns (uint256) {
uint256[] memory balances = _dropBptItem(balancesIncludingBpt); // Avoid BPT balance for stable pool math
// Avoid BPT balance for stable pool math
(uint256 virtualSupply, uint256[] memory balances) = _dropBptItem(balancesIncludingBpt);

if (request.tokenIn == IERC20(this)) {
return _onSwapTokenGivenBptIn(request.amount, _skipBptIndex(indexOut), balances);
return _onSwapTokenGivenBptIn(request.amount, _skipBptIndex(indexOut), virtualSupply, balances);
} else if (request.tokenOut == IERC20(this)) {
return _onSwapBptGivenTokenIn(request.amount, _skipBptIndex(indexIn), balances);
return _onSwapBptGivenTokenIn(request.amount, _skipBptIndex(indexIn), virtualSupply, balances);
} else {
return super._onSwapGivenIn(request, balances, _skipBptIndex(indexIn), _skipBptIndex(indexOut));
}
Expand All @@ -158,11 +161,13 @@ contract StablePhantomPool is StablePool {
uint256 indexIn,
uint256 indexOut
) internal virtual override returns (uint256) {
uint256[] memory balances = _dropBptItem(balancesIncludingBpt); // Avoid BPT balance for stable pool math
// Avoid BPT balance for stable pool math
(uint256 virtualSupply, uint256[] memory balances) = _dropBptItem(balancesIncludingBpt);

if (request.tokenIn == IERC20(this)) {
return _onSwapBptGivenTokenOut(request.amount, _skipBptIndex(indexOut), balances);
return _onSwapBptGivenTokenOut(request.amount, _skipBptIndex(indexOut), virtualSupply, balances);
} else if (request.tokenOut == IERC20(this)) {
return _onSwapTokenGivenBptOut(request.amount, _skipBptIndex(indexIn), balances);
return _onSwapTokenGivenBptOut(request.amount, _skipBptIndex(indexIn), virtualSupply, balances);
} else {
return super._onSwapGivenOut(request, balances, _skipBptIndex(indexIn), _skipBptIndex(indexOut));
}
Expand All @@ -174,12 +179,13 @@ contract StablePhantomPool is StablePool {
function _onSwapTokenGivenBptIn(
uint256 bptIn,
uint256 tokenIndex,
uint256 virtualSupply,
uint256[] memory balances
) internal view returns (uint256) {
// TODO: calc due protocol fees
uint256 swapFee = getSwapFeePercentage();
(uint256 currentAmp, ) = _getAmplificationParameter();
return StableMath._calcTokenOutGivenExactBptIn(currentAmp, balances, tokenIndex, bptIn, totalSupply(), swapFee);
// Use virtual total supply and zero swap fees for joins.
(uint256 amp, ) = _getAmplificationParameter();
return StableMath._calcTokenOutGivenExactBptIn(amp, balances, tokenIndex, bptIn, virtualSupply, 0);
}

/**
Expand All @@ -188,13 +194,13 @@ contract StablePhantomPool is StablePool {
function _onSwapTokenGivenBptOut(
uint256 bptOut,
uint256 tokenIndex,
uint256 virtualSupply,
uint256[] memory balances
) internal view returns (uint256) {
// TODO: calc due protocol fees
uint256 swapFee = getSwapFeePercentage();
(uint256 currentAmp, ) = _getAmplificationParameter();
return
StableMath._calcTokenInGivenExactBptOut(currentAmp, balances, tokenIndex, bptOut, totalSupply(), swapFee);
// Use virtual total supply and zero swap fees for joins
(uint256 amp, ) = _getAmplificationParameter();
return StableMath._calcTokenInGivenExactBptOut(amp, balances, tokenIndex, bptOut, virtualSupply, 0);
}

/**
Expand All @@ -203,20 +209,15 @@ contract StablePhantomPool is StablePool {
function _onSwapBptGivenTokenOut(
uint256 amountOut,
uint256 tokenIndex,
uint256 virtualSupply,
uint256[] memory balances
) internal view returns (uint256) {
// TODO: calc due protocol fees
(uint256 currentAmp, ) = _getAmplificationParameter();
uint256[] memory amountsOut = new uint256[](_getTotalTokens() - 1); // Avoid BPT balance for stable pool math
// Avoid BPT balance for stable pool math. Use virtual total supply and zero swap fees for exits.
(uint256 amp, ) = _getAmplificationParameter();
uint256[] memory amountsOut = new uint256[](_getTotalTokens() - 1);
amountsOut[tokenIndex] = amountOut;
return
StableMath._calcBptInGivenExactTokensOut(
currentAmp,
balances,
amountsOut,
totalSupply(),
getSwapFeePercentage()
);
return StableMath._calcBptInGivenExactTokensOut(amp, balances, amountsOut, virtualSupply, 0);
}

/**
Expand All @@ -225,20 +226,15 @@ contract StablePhantomPool is StablePool {
function _onSwapBptGivenTokenIn(
uint256 amountIn,
uint256 tokenIndex,
uint256 virtualSupply,
uint256[] memory balances
) internal view returns (uint256) {
// TODO: calc due protocol fees
uint256[] memory amountsIn = new uint256[](_getTotalTokens() - 1); // Avoid BPT balance for stable pool math
// Avoid BPT balance for stable pool math. Use virtual total supply and zero swap fees for exits.
uint256[] memory amountsIn = new uint256[](_getTotalTokens() - 1);
amountsIn[tokenIndex] = amountIn;
(uint256 currentAmp, ) = _getAmplificationParameter();
return
StableMath._calcBptOutGivenExactTokensIn(
currentAmp,
balances,
amountsIn,
totalSupply(),
getSwapFeePercentage()
);
(uint256 amp, ) = _getAmplificationParameter();
return StableMath._calcBptOutGivenExactTokensIn(amp, balances, amountsIn, virtualSupply, 0);
}

/**
Expand All @@ -258,23 +254,24 @@ contract StablePhantomPool is StablePool {
StablePool.JoinKind kind = userData.joinKind();
_require(kind == StablePool.JoinKind.INIT, Errors.UNINITIALIZED);

uint256[] memory amountsIn = userData.initialAmountsIn();
InputHelpers.ensureInputLengthMatch(amountsIn.length, _getTotalTokens());
_upscaleArray(amountsIn, scalingFactors);
uint256[] memory amountsInIncludingBpt = userData.initialAmountsIn();
InputHelpers.ensureInputLengthMatch(amountsInIncludingBpt.length, _getTotalTokens());
_upscaleArray(amountsInIncludingBpt, scalingFactors);

(uint256 currentAmp, ) = _getAmplificationParameter();
uint256 invariantAfterJoin = StableMath._calculateInvariant(currentAmp, _dropBptItem(amountsIn), true);
(uint256 amp, ) = _getAmplificationParameter();
(, uint256[] memory amountsIn) = _dropBptItem(amountsInIncludingBpt);
uint256 invariantAfterJoin = StableMath._calculateInvariant(amp, amountsIn, true);

// Set the initial BPT to the value of the invariant
uint256 bptAmountOut = invariantAfterJoin;
_updateLastInvariant(invariantAfterJoin, currentAmp);
_updateLastInvariant(invariantAfterJoin, amp);

// Mint the total amount of BPT to the sender forcing the Vault to pull it
uint256 initialBpt = _MAX_TOKEN_BALANCE.sub(bptAmountOut);
_mintPoolTokens(sender, initialBpt);
_approve(sender, address(getVault()), initialBpt);
amountsIn[_bptIndex] = initialBpt;
return (bptAmountOut, amountsIn);
amountsInIncludingBpt[_bptIndex] = initialBpt;
return (bptAmountOut, amountsInIncludingBpt);
}

/**
Expand Down Expand Up @@ -486,7 +483,12 @@ contract StablePhantomPool is StablePool {
return index < _bptIndex ? index : index.sub(1);
}

function _dropBptItem(uint256[] memory _balances) internal view returns (uint256[] memory balances) {
function _dropBptItem(uint256[] memory _balances)
internal
view
returns (uint256 virtualSupply, uint256[] memory balances)
{
virtualSupply = _MAX_TOKEN_BALANCE - _balances[_bptIndex];
balances = new uint256[](_balances.length - 1);
for (uint256 i = 0; i < balances.length; i++) {
balances[i] = _balances[i < _bptIndex ? i : i + 1];
Expand Down
Loading

0 comments on commit 215ee8c

Please sign in to comment.