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

Fix rounding of 2CLP pools #1193

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 3 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
25 changes: 17 additions & 8 deletions pkg/pool-gyro/contracts/Gyro2CLPPool.sol
Original file line number Diff line number Diff line change
Expand Up @@ -90,16 +90,24 @@ contract Gyro2CLPPool is IGyro2CLPPool, BalancerPoolToken {
// New invariant
invariant = invariant.mulUp(invariantRatio);
uint256 squareNewInv = invariant * invariant;
// L / sqrt(beta)
uint256 a = invariant.divDown(sqrtBeta);
// L * sqrt(alpha)
uint256 b = invariant.mulDown(sqrtAlpha);

if (tokenInIndex == 0) {
// if newBalance = newX

// L / sqrt(beta), rounded down to minimize newBalance.
uint256 a = invariant.divDown(sqrtBeta);
// L * sqrt(alpha), rounded up to minimize newBalance (b is in the denominator).
uint256 b = invariant.mulUp(sqrtAlpha);

newBalance = squareNewInv.divUpRaw(b + balancesLiveScaled18[1]) - a;
joaobrunoah marked this conversation as resolved.
Show resolved Hide resolved
} else {
// if newBalance = newY

// L / sqrt(beta), rounded up to minimize newBalance (a is in the denominator).
uint256 a = invariant.divUp(sqrtBeta);
// L * sqrt(alpha), rounded down to minimize newBalance.
uint256 b = invariant.mulDown(sqrtAlpha);
joaobrunoah marked this conversation as resolved.
Show resolved Hide resolved

newBalance = squareNewInv.divUpRaw(a + balancesLiveScaled18[0]) - b;
}
}
Expand Down Expand Up @@ -167,7 +175,7 @@ contract Gyro2CLPPool is IGyro2CLPPool, BalancerPoolToken {

uint256 currentInvariant = Gyro2CLPMath.calculateInvariant(balances, sqrtAlpha, sqrtBeta, rounding);

uint256[2] memory virtualOffsets = _calculateVirtualOffsets(currentInvariant, sqrtAlpha, sqrtBeta);
uint256[2] memory virtualOffsets = _calculateVirtualOffsets(currentInvariant, sqrtAlpha, sqrtBeta, rounding);
joaobrunoah marked this conversation as resolved.
Show resolved Hide resolved

virtualBalanceIn = tokenInIsToken0 ? virtualOffsets[0] : virtualOffsets[1];
virtualBalanceOut = tokenInIsToken0 ? virtualOffsets[1] : virtualOffsets[0];
Expand All @@ -177,10 +185,11 @@ contract Gyro2CLPPool is IGyro2CLPPool, BalancerPoolToken {
function _calculateVirtualOffsets(
uint256 invariant,
uint256 sqrtAlpha,
uint256 sqrtBeta
uint256 sqrtBeta,
Rounding rounding
) internal view virtual returns (uint256[2] memory virtualOffsets) {
virtualOffsets[0] = Gyro2CLPMath.calculateVirtualParameter0(invariant, sqrtBeta);
virtualOffsets[1] = Gyro2CLPMath.calculateVirtualParameter1(invariant, sqrtAlpha);
virtualOffsets[0] = Gyro2CLPMath.calculateVirtualParameter0(invariant, sqrtBeta, rounding);
virtualOffsets[1] = Gyro2CLPMath.calculateVirtualParameter1(invariant, sqrtAlpha, rounding);
return virtualOffsets;
}

Expand Down
35 changes: 26 additions & 9 deletions pkg/pool-gyro/contracts/lib/Gyro2CLPMath.sol
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ library Gyro2CLPMath {
rounding
);

return calculateQuadratic(a, mb, bSquare, mc);
return calculateQuadratic(a, mb, bSquare, mc, rounding);
}

/**
Expand Down Expand Up @@ -116,17 +116,26 @@ library Gyro2CLPMath {
uint256 a,
uint256 mb,
uint256 bSquare, // b^2 can be calculated separately with more precision
uint256 mc
uint256 mc,
Rounding rounding
) internal pure returns (uint256 invariant) {
uint256 denominator = a.mulUp(2 * FixedPoint.ONE);
function(uint256, uint256) pure returns (uint256) _mulUpOrDown = rounding == Rounding.ROUND_DOWN
? FixedPoint.mulDown
: FixedPoint.mulUp;

function(uint256, uint256) pure returns (uint256) _divUpOrDown = rounding == Rounding.ROUND_DOWN
? FixedPoint.divDown
: FixedPoint.divUp;

uint256 denominator = 2 * a;
joaobrunoah marked this conversation as resolved.
Show resolved Hide resolved
// Order multiplications for fixed point precision.
uint256 addTerm = (mc.mulDown(4 * FixedPoint.ONE)).mulDown(a);
uint256 addTerm = _mulUpOrDown(4 * mc, a);
joaobrunoah marked this conversation as resolved.
Show resolved Hide resolved
// The minus sign in the radicand cancels out in this special case.
uint256 radicand = bSquare + addTerm;
uint256 sqrResult = GyroPoolMath.sqrt(radicand, 5);
// The minus sign in the numerator cancels out in this special case.
uint256 numerator = mb + sqrResult;
invariant = numerator.divDown(denominator);
invariant = _divUpOrDown(numerator, denominator);
}

/**
Expand Down Expand Up @@ -224,13 +233,21 @@ library Gyro2CLPMath {
}

/// @dev Calculate the virtual offset `a` for reserves `x`, as in (x+a)*(y+b)=L^2.
function calculateVirtualParameter0(uint256 invariant, uint256 _sqrtBeta) internal pure returns (uint256) {
return invariant.divDown(_sqrtBeta);
function calculateVirtualParameter0(
uint256 invariant,
uint256 _sqrtBeta,
Rounding rounding
) internal pure returns (uint256) {
return rounding == Rounding.ROUND_DOWN ? invariant.divDown(_sqrtBeta) : invariant.divUp(_sqrtBeta);
}

/// @dev Calculate the virtual offset `b` for reserves `y`, as in (x+a)*(y+b)=L^2.
function calculateVirtualParameter1(uint256 invariant, uint256 _sqrtAlpha) internal pure returns (uint256) {
return invariant.mulDown(_sqrtAlpha);
function calculateVirtualParameter1(
uint256 invariant,
uint256 _sqrtAlpha,
Rounding rounding
) internal pure returns (uint256) {
return rounding == Rounding.ROUND_DOWN ? invariant.mulDown(_sqrtAlpha) : invariant.mulUp(_sqrtAlpha);
}

/**
Expand Down
Loading