Skip to content

Commit

Permalink
Merge pull request #84 from primitivefinance/test/constant-sum-tests
Browse files Browse the repository at this point in the history
Fix ConstantSum strategy
  • Loading branch information
clemlak authored Mar 25, 2024
2 parents 7e930dc + 22967e4 commit c2fdd68
Show file tree
Hide file tree
Showing 11 changed files with 392 additions and 373 deletions.
89 changes: 86 additions & 3 deletions src/ConstantSum/ConstantSum.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@
pragma solidity 0.8.22;

import {
FixedPointMathLib, computeTradingFunction
FixedPointMathLib,
computeTradingFunction,
computeDeltaLiquidity
} from "./ConstantSumMath.sol";
import {
decodePriceUpdate,
Expand Down Expand Up @@ -33,6 +35,9 @@ enum UpdateCode {
contract ConstantSum is PairStrategy {
using FixedPointMathLib for uint256;

/// @notice Thrown when the expected liquidity is not met.
error InvalidDeltaLiquidity();

/// @inheritdoc IStrategy
string public constant name = "ConstantSum";

Expand Down Expand Up @@ -74,6 +79,84 @@ contract ConstantSum is PairStrategy {
return (valid, invariant, reserves, totalLiquidity);
}

function validateAllocate(
address,
uint256 poolId,
Pool memory pool,
bytes calldata data
)
external
view
override
returns (
bool valid,
int256 invariant,
uint256[] memory deltas,
uint256 deltaLiquidity
)
{
(uint256 deltaX, uint256 deltaY, uint256 minDeltaL) =
abi.decode(data, (uint256, uint256, uint256));

deltaLiquidity =
computeDeltaLiquidity(deltaX, deltaY, internalParams[poolId].price);
if (deltaLiquidity < minDeltaL) revert InvalidDeltaLiquidity();

deltas = new uint256[](2);
deltas[0] = deltaX;
deltas[1] = deltaY;

pool.reserves[0] += deltaX;
pool.reserves[1] += deltaY;

invariant = tradingFunction(
pool.reserves,
pool.totalLiquidity + deltaLiquidity,
getPoolParams(poolId)
);

valid = invariant >= 0;
}

function validateDeallocate(
address,
uint256 poolId,
Pool memory pool,
bytes calldata data
)
external
view
override
returns (
bool valid,
int256 invariant,
uint256[] memory deltas,
uint256 deltaLiquidity
)
{
(uint256 deltaX, uint256 deltaY, uint256 maxDeltaL) =
abi.decode(data, (uint256, uint256, uint256));

deltaLiquidity =
computeDeltaLiquidity(deltaX, deltaY, internalParams[poolId].price);
if (maxDeltaL > deltaLiquidity) revert InvalidDeltaLiquidity();

deltas = new uint256[](2);
deltas[0] = deltaX;
deltas[1] = deltaY;

pool.reserves[0] -= deltaX;
pool.reserves[1] -= deltaY;

invariant = tradingFunction(
pool.reserves,
pool.totalLiquidity - deltaLiquidity,
getPoolParams(poolId)
);

valid = invariant >= 0;
}

/// @inheritdoc IStrategy
function update(
address sender,
Expand Down Expand Up @@ -130,7 +213,7 @@ contract ConstantSum is PairStrategy {
Pool memory,
bytes memory
) internal pure override returns (uint256[] memory) {
return new uint256[](0);
return new uint256[](2);
}

/// @inheritdoc PairStrategy
Expand All @@ -139,6 +222,6 @@ contract ConstantSum is PairStrategy {
Pool memory,
bytes memory
) internal pure override returns (uint256[] memory) {
return new uint256[](0);
return new uint256[](2);
}
}
74 changes: 8 additions & 66 deletions src/ConstantSum/ConstantSumMath.sol
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,10 @@ function computeTradingFunction(
uint256 totalLiquidity,
uint256 price
) pure returns (int256) {
return int256(reserves[0].divWadUp(totalLiquidity))
+ int256(reserves[1].divWadUp(totalLiquidity.mulWadUp(price))) - int256(ONE);
return int256(
price.mulWadUp(reserves[0].divWadUp(totalLiquidity))
+ reserves[1].divWadUp(totalLiquidity)
) - int256(ONE);
}

function computeInitialPoolData(
Expand All @@ -24,77 +26,17 @@ function computeInitialPoolData(
) pure returns (bytes memory) {
// The pool can be initialized with any non-negative amount of rx, and ry.
// so we have to allow a user to pass an amount of both even if one is zero.
uint256 L = rx + ry.divWadUp(params.price);
uint256 L = rx.mulWadDown(params.price) + ry;
uint256[] memory reserves = new uint256[](2);
reserves[0] = rx;
reserves[1] = ry;
return abi.encode(reserves, L, params);
}

function computeDeallocateGivenDeltaX(
function computeDeltaLiquidity(
uint256 deltaX,
uint256 rX,
uint256 rY,
uint256 totalLiquidity
) pure returns (uint256 deltaY, uint256 deltaL) {
uint256 a = deltaX.divWadDown(rX);
if (rY > 0) {
deltaY = a.mulWadDown(rY);
}
deltaL = a.mulWadDown(totalLiquidity);
}

function computeDeallocateGivenDeltaY(
uint256 deltaY,
uint256 rX,
uint256 rY,
uint256 totalLiquidity
) pure returns (uint256 deltaX, uint256 deltaL) {
uint256 a = deltaY.divWadDown(rY);
if (rX > 0) {
deltaX = a.mulWadDown(rX);
}
deltaL = a.mulWadDown(totalLiquidity);
}

function computeAllocateGivenDeltaX(
uint256 deltaX,
uint256 rX,
uint256 rY,
uint256 totalLiquidity
) pure returns (uint256 deltaY, uint256 deltaL) {
uint256 a = deltaX.divWadUp(rX);
if (rY > 0) {
deltaY = a.mulWadUp(rY);
}
deltaL = a.mulWadUp(totalLiquidity);
}

function computeAllocateGivenDeltaY(
uint256 deltaY,
uint256 rX,
uint256 rY,
uint256 totalLiquidity
) pure returns (uint256 deltaX, uint256 deltaL) {
uint256 a = deltaY.divWadUp(rY);
if (rX > 0) {
deltaX = a.mulWadUp(rX);
}
deltaL = a.mulWadUp(totalLiquidity);
}

function computeDeltaGivenDeltaLRoundUp(
uint256 reserve,
uint256 deltaLiquidity,
uint256 totalLiquidity
) pure returns (uint256) {
return reserve.mulWadUp(deltaLiquidity.divWadUp(totalLiquidity));
}

function computeDeltaGivenDeltaLRoundDown(
uint256 reserve,
uint256 deltaLiquidity,
uint256 totalLiquidity
uint256 price
) pure returns (uint256) {
return reserve.mulWadDown(deltaLiquidity.divWadDown(totalLiquidity));
return price.mulWadUp(deltaX) + deltaY;
}
Loading

0 comments on commit c2fdd68

Please sign in to comment.