Skip to content

Commit

Permalink
Merge pull request #53 from primitivefinance/experimental/n-token-pools
Browse files Browse the repository at this point in the history
Experimental/n token pools
  • Loading branch information
clemlak authored Mar 13, 2024
2 parents 5a9295a + af6d0ac commit 704df34
Show file tree
Hide file tree
Showing 101 changed files with 7,728 additions and 4,288 deletions.
2 changes: 0 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@ optimized-out
kit/target
target

# VSCode
.vscode
.env
report/main.aux
report/main.pyg
Expand Down
6 changes: 6 additions & 0 deletions .vscode/extensions.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"recommendations": [
"remisa.mathover",
"nomicfoundation.hardhat-solidity"
]
}
10 changes: 10 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"editor.formatOnSave": true,
"solidity.formatter": "forge",
"[solidity]": {
"editor.defaultFormatter": "NomicFoundation.hardhat-solidity"
},
"mathover.matchRegex": "\\$\\$(.*?)\\$\\$",
"mathover.forwardSkip": 2,
"mathover.backwardSkip": 2
}
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@ A few rules:

## Style Guide


### Imports

1. Use named imports as much as possible.
2. Import external dependencies first (libs, etc).
3. Import from root `src/DFMM.sol` instead of `../DFMM.sol`.

### Tests

Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,8 @@ To run all the tests, simply run the following command:
forge t
```

Learn more about our testing suite [here](./test/README.md).

### Deployment

You can deploy the contracts with the following command:
Expand Down
File renamed without changes.
244 changes: 73 additions & 171 deletions src/ConstantSum/ConstantSum.sol
Original file line number Diff line number Diff line change
@@ -1,228 +1,130 @@
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.8.13;

import "./ConstantSumLib.sol";
import "src/interfaces/IDFMM.sol";
import "src/interfaces/IStrategy.sol";
import "forge-std/Test.sol";

contract ConstantSum is IStrategy {
using FixedPointMathLib for uint256;
import "./ConstantSumMath.sol";
import "./ConstantSumUtils.sol";
import { PairStrategy, IStrategy, Pool } from "src/PairStrategy.sol";

struct InternalParams {
uint256 price;
uint256 swapFee;
address controller;
}

struct InternalParams {
uint256 price;
uint256 swapFee;
address controller;
}
struct ConstantSumParams {
uint256 price;
uint256 swapFee;
address controller;
}

struct ConstantSumParams {
uint256 price;
uint256 swapFee;
address controller;
}
enum UpdateCode {
Invalid,
SwapFee,
Price,
Controller
}

/// @inheritdoc IStrategy
address public dfmm;
contract ConstantSum is PairStrategy {
using FixedPointMathLib for uint256;

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

mapping(uint256 => InternalParams) public internalParams;

constructor(address dfmm_) {
dfmm = dfmm_;
}

modifier onlyDFMM() {
if (msg.sender != dfmm) revert NotDFMM();
_;
}
constructor(address dfmm_) PairStrategy(dfmm_) { }

function init(
address,
uint256 poolId,
IDFMM.Pool calldata pool,
Pool calldata,
bytes calldata data
)
public
onlyDFMM
returns (
bool valid,
int256 invariant,
uint256 reserveX,
uint256 reserveY,
uint256[] memory reserves,
uint256 totalLiquidity
)
{
ConstantSumParams memory params;
(reserveX, reserveY, totalLiquidity, params) =
abi.decode(data, (uint256, uint256, uint256, ConstantSumParams));
(reserves, totalLiquidity, params) =
abi.decode(data, (uint256[], uint256, ConstantSumParams));

internalParams[poolId].price = params.price;
internalParams[poolId].swapFee = params.swapFee;

// Get the trading function and check this is valid
invariant = ConstantSumLib.tradingFunction(
reserveX, reserveY, totalLiquidity, params.price
);

valid = -EPSILON < invariant && invariant < EPSILON;

return (valid, invariant, reserveX, reserveY, totalLiquidity);
}

function validateSwap(
address,
uint256 poolId,
IDFMM.Pool calldata pool,
bytes calldata data
)
external
view
returns (
bool valid,
int256 invariant,
int256 liquidityDelta,
uint256 nextRx,
uint256 nextRy,
uint256 nextL
)
{
ConstantSumParams memory params =
abi.decode(getPoolParams(poolId), (ConstantSumParams));

(nextRx, nextRy, nextL) = abi.decode(data, (uint256, uint256, uint256));

uint256 minLiquidityDelta;
uint256 amountIn;
uint256 fees;
if (nextRx > pool.reserveX) {
amountIn = nextRx - pool.reserveX;
fees = amountIn.mulWadUp(params.swapFee);
minLiquidityDelta += fees;
} else if (nextRy > pool.reserveY) {
amountIn = nextRy - pool.reserveY;
fees = amountIn.mulWadUp(params.swapFee);
minLiquidityDelta += fees.divWadUp(params.price);
} else {
revert("invalid swap: inputs x and y have the same sign!");
}

liquidityDelta = int256(nextL) - int256(pool.totalLiquidity);
assert(liquidityDelta >= int256(minLiquidityDelta));

invariant =
ConstantSumLib.tradingFunction(nextRx, nextRy, nextL, params.price);

valid = -EPSILON < invariant && invariant < EPSILON;
}

function computeSwapConstant(
uint256 poolId,
bytes memory data
) external view returns (int256) {
(uint256 reserveX, uint256 reserveY, uint256 totalLiquidity) =
abi.decode(data, (uint256, uint256, uint256));
return ConstantSumLib.tradingFunction(
reserveX,
reserveY,
totalLiquidity,
abi.decode(getPoolParams(poolId), (ConstantSumParams)).price
);
}

// This should literally always work lol
function validateAllocate(
address,
uint256 poolId,
IDFMM.Pool calldata pool,
bytes calldata data
)
external
view
returns (
bool valid,
int256 invariant,
uint256 deltaX,
uint256 deltaY,
uint256 deltaLiquidity
)
{
(deltaX, deltaY, deltaLiquidity) =
abi.decode(data, (uint256, uint256, uint256));

invariant = ConstantSumLib.tradingFunction(
pool.reserveX + deltaX,
pool.reserveX + deltaY,
pool.totalLiquidity + deltaLiquidity,
abi.decode(getPoolParams(poolId), (ConstantSumParams)).price
);
tradingFunction(reserves, totalLiquidity, abi.encode(params));

valid = -EPSILON < invariant && invariant < EPSILON;
}

// This should literally always work lol
function validateDeallocate(
address,
uint256 poolId,
IDFMM.Pool calldata pool,
bytes calldata data
)
external
view
returns (
bool valid,
int256 invariant,
uint256 deltaX,
uint256 deltaY,
uint256 deltaLiquidity
)
{
(deltaX, deltaY, deltaLiquidity) =
abi.decode(data, (uint256, uint256, uint256));

invariant = ConstantSumLib.tradingFunction(
pool.reserveX - deltaX,
pool.reserveY - deltaY,
pool.totalLiquidity - deltaLiquidity,
abi.decode(getPoolParams(poolId), (ConstantSumParams)).price
);

valid = -EPSILON < invariant && invariant < EPSILON;
return (valid, invariant, reserves, totalLiquidity);
}

/// @inheritdoc IStrategy
function update(
address sender,
uint256 poolId,
IDFMM.Pool calldata pool,
Pool calldata,
bytes calldata data
) external onlyDFMM {
if (sender != internalParams[poolId].controller) revert InvalidSender();
ConstantSumLib.ConstantSumUpdateCode updateCode =
abi.decode(data, (ConstantSumLib.ConstantSumUpdateCode));

if (updateCode == ConstantSumLib.ConstantSumUpdateCode.Price) {
internalParams[poolId].price =
ConstantSumLib.decodePriceUpdate(data);
} else if (updateCode == ConstantSumLib.ConstantSumUpdateCode.SwapFee) {
internalParams[poolId].swapFee =
ConstantSumLib.decodeFeeUpdate(data);
} else if (
updateCode == ConstantSumLib.ConstantSumUpdateCode.Controller
) {
internalParams[poolId].controller =
ConstantSumLib.decodeControllerUpdate(data);
UpdateCode updateCode = abi.decode(data, (UpdateCode));

if (updateCode == UpdateCode.Price) {
(internalParams[poolId].price,) = decodePriceUpdate(data);
} else if (updateCode == UpdateCode.SwapFee) {
internalParams[poolId].swapFee = decodeFeeUpdate(data);
} else if (updateCode == UpdateCode.Controller) {
internalParams[poolId].controller = decodeControllerUpdate(data);
} else {
revert InvalidUpdateCode();
}
}

function getPoolParams(uint256 poolId) public view returns (bytes memory) {
function getPoolParams(uint256 poolId)
public
view
override
returns (bytes memory)
{
ConstantSumParams memory params;

params.price = internalParams[poolId].price;
params.swapFee = internalParams[poolId].swapFee;

return abi.encode(params);
}

function tradingFunction(
uint256[] memory reserves,
uint256 totalLiquidity,
bytes memory params
) public pure override returns (int256) {
return computeTradingFunction(
reserves,
totalLiquidity,
abi.decode(params, (ConstantSumParams)).price
);
}

function _computeAllocateDeltasGivenDeltaL(
uint256,
Pool memory,
bytes memory
) internal pure override returns (uint256[] memory) {
return new uint256[](0);
}

function _computeDeallocateDeltasGivenDeltaL(
uint256,
Pool memory,
bytes memory
) internal pure override returns (uint256[] memory) {
return new uint256[](0);
}
}
Loading

0 comments on commit 704df34

Please sign in to comment.