diff --git a/foundry.toml b/foundry.toml index 9ce8e42..3990ef7 100644 --- a/foundry.toml +++ b/foundry.toml @@ -9,7 +9,7 @@ remappings = [ optimizer=true optimizer_runs=999999999 viaIR=true -gas_reports = ['PartyPool', 'PartyPlanner'] +gas_reports = ['PartyPlanner', 'PartyPoolBalancedPair', 'PartyPool', ] fs_permissions = [{ access = "write", path = "chain.json"}] [lint] diff --git a/src/Deploy.sol b/src/Deploy.sol new file mode 100644 index 0000000..b23e710 --- /dev/null +++ b/src/Deploy.sol @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.30; + +import "./PartyPoolBalancedPair.sol"; +import {PartyPlanner} from "./PartyPlanner.sol"; +import {PartyPool} from "./PartyPool.sol"; + + +library Deploy { + + function newPartyPlanner() internal returns (PartyPlanner) { + return new PartyPlanner(); + } + + function newPartyPool( + string memory name_, + string memory symbol_, + IERC20[] memory tokens_, + uint256[] memory bases_, + int128 kappa_, + uint256 swapFeePpm_, + uint256 flashFeePpm_, + bool stablePair_ + ) internal returns (PartyPool) { + return stablePair_ ? + new PartyPoolBalancedPair(name_, symbol_, tokens_, bases_, kappa_, swapFeePpm_, flashFeePpm_) : + new PartyPool(name_, symbol_, tokens_, bases_, kappa_, swapFeePpm_, flashFeePpm_); + } + +} diff --git a/src/PartyPlanner.sol b/src/PartyPlanner.sol index 80f5fff..2063a11 100644 --- a/src/PartyPlanner.sol +++ b/src/PartyPlanner.sol @@ -2,8 +2,9 @@ pragma solidity ^0.8.30; import "./IPartyPlanner.sol"; -import "./PartyPool.sol"; import "./LMSRStabilized.sol"; +import "./PartyPool.sol"; +import "./PartyPoolBalancedPair.sol"; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; @@ -48,16 +49,9 @@ contract PartyPlanner is IPartyPlanner { require(_kappa > int128(0), "Planner: kappa must be > 0"); // Create a new PartyPool instance (kappa-based constructor) - pool = new PartyPool( - name_, - symbol_, - _tokens, - _bases, - _kappa, - _swapFeePpm, - _flashFeePpm, - _stable - ); + pool = _stable && _tokens.length == 2 ? + new PartyPoolBalancedPair(name_, symbol_, _tokens, _bases, _kappa, _swapFeePpm, _flashFeePpm) : + new PartyPool(name_, symbol_, _tokens, _bases, _kappa, _swapFeePpm, _flashFeePpm); _allPools.push(pool); _poolSupported[pool] = true; diff --git a/src/PartyPool.sol b/src/PartyPool.sol index 1bdfb7e..50be3e6 100644 --- a/src/PartyPool.sol +++ b/src/PartyPool.sol @@ -32,9 +32,6 @@ contract PartyPool is PoolBase, IPartyPool { /// @notice Flash-loan fee in parts-per-million (ppm) applied to flash borrow amounts. uint256 public immutable flashFeePpm; - /// @notice If true and there are exactly two assets, an optimized 2-asset stable-pair path is used for some computations. - bool private immutable _stablePair; // if true, the optimized LMSRStabilizedBalancedPair optimization path is enabled - /// @inheritdoc IPartyPool function tokens(uint256 i) external view returns (IERC20) { return s.tokens[i]; } @@ -65,7 +62,6 @@ contract PartyPool is PoolBase, IPartyPool { /// @param kappa_ liquidity parameter κ (Q64.64) used to derive b = κ * S(q) /// @param swapFeePpm_ fee in parts-per-million, taken from swap input amounts before LMSR calculations /// @param flashFeePpm_ fee in parts-per-million, taken for flash loans - /// @param stable_ if true and assets.length==2, then the optimization for 2-asset stablecoin pools is activated. constructor( string memory name_, string memory symbol_, @@ -73,15 +69,13 @@ contract PartyPool is PoolBase, IPartyPool { uint256[] memory bases_, int128 kappa_, uint256 swapFeePpm_, - uint256 flashFeePpm_, - bool stable_ + uint256 flashFeePpm_ ) ERC20(name_, symbol_) { kappa = kappa_; require(swapFeePpm_ < 1_000_000, "Pool: fee >= ppm"); swapFeePpm = swapFeePpm_; require(flashFeePpm_ < 1_000_000, "Pool: flash fee >= ppm"); flashFeePpm = flashFeePpm_; - _stablePair = stable_ && tokens_.length == 2; // Initialize state using library s.initialize(tokens_, bases_); @@ -155,8 +149,8 @@ contract PartyPool is PoolBase, IPartyPool { uint256 outputTokenIndex, uint256 maxAmountIn, int128 limitPrice - ) external view returns (uint256 amountIn, uint256 amountOut, uint256 fee) { - return s.swapAmounts(inputTokenIndex, outputTokenIndex, maxAmountIn, limitPrice, swapFeePpm, _stablePair); + ) virtual external view returns (uint256 amountIn, uint256 amountOut, uint256 fee) { + return s.swapAmounts(inputTokenIndex, outputTokenIndex, maxAmountIn, limitPrice, swapFeePpm); } /// @inheritdoc IPartyPool @@ -176,17 +170,7 @@ contract PartyPool is PoolBase, IPartyPool { return s.swapMintAmounts(inputTokenIndex, maxAmountIn, swapFeePpm, totalSupply()); } - /// @notice Swap input token i -> token j. Payer must approve token i. - /// @dev This function transfers the exact gross input (including fee) from payer and sends the computed output to receiver. - /// Non-standard tokens (fee-on-transfer, rebasers) are rejected via balance checks. - /// @param payer address of the account that pays for the swap - /// @param receiver address that will receive the output tokens - /// @param inputTokenIndex index of input asset - /// @param outputTokenIndex index of output asset - /// @param maxAmountIn maximum amount of token i (uint256) to transfer in (inclusive of fees) - /// @param limitPrice maximum acceptable marginal price (64.64 fixed point). Pass 0 to ignore. - /// @param deadline timestamp after which the transaction will revert. Pass 0 to ignore. - /// @return amountIn actual input used (uint256), amountOut actual output sent (uint256), fee fee taken from the input (uint256) + /// @inheritdoc IPartyPool function swap( address payer, address receiver, @@ -195,8 +179,8 @@ contract PartyPool is PoolBase, IPartyPool { uint256 maxAmountIn, int128 limitPrice, uint256 deadline - ) external nonReentrant returns (uint256 amountIn, uint256 amountOut, uint256 fee) { - return s.swap(payer, receiver, inputTokenIndex, outputTokenIndex, maxAmountIn, limitPrice, deadline, swapFeePpm, _stablePair); + ) virtual external nonReentrant returns (uint256 amountIn, uint256 amountOut, uint256 fee) { + return s.swap(payer, receiver, inputTokenIndex, outputTokenIndex, maxAmountIn, limitPrice, deadline, swapFeePpm); } /// @notice Swap up to the price limit; computes max input to reach limit then performs swap. diff --git a/src/PartyPoolBalancedPair.sol b/src/PartyPoolBalancedPair.sol new file mode 100644 index 0000000..46c28ee --- /dev/null +++ b/src/PartyPoolBalancedPair.sol @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.30; + +import "./PartyPool.sol"; +import {PoolLibBalancedPair} from "./PoolLibBalancedPair.sol"; + +contract PartyPoolBalancedPair is PartyPool { + constructor( + string memory name_, + string memory symbol_, + IERC20[] memory tokens_, + uint256[] memory bases_, + int128 kappa_, + uint256 swapFeePpm_, + uint256 flashFeePpm_ + ) PartyPool(name_, symbol_, tokens_, bases_, kappa_, swapFeePpm_, flashFeePpm_) { + } + + function swapAmounts( + uint256 inputTokenIndex, + uint256 outputTokenIndex, + uint256 maxAmountIn, + int128 limitPrice + ) virtual override external view returns (uint256 amountIn, uint256 amountOut, uint256 fee) { + return PoolLibBalancedPair.swapAmounts( + s, inputTokenIndex, outputTokenIndex, + maxAmountIn, limitPrice, swapFeePpm); + } + + function swap( + address payer, + address receiver, + uint256 inputTokenIndex, + uint256 outputTokenIndex, + uint256 maxAmountIn, + int128 limitPrice, + uint256 deadline + ) virtual override external nonReentrant returns (uint256 amountIn, uint256 amountOut, uint256 fee) { + return PoolLibBalancedPair.swap(s, payer, receiver, inputTokenIndex, outputTokenIndex, maxAmountIn, limitPrice, deadline, swapFeePpm); + } + +} diff --git a/src/PoolLib.sol b/src/PoolLib.sol index b41d28c..a2a2031 100644 --- a/src/PoolLib.sol +++ b/src/PoolLib.sol @@ -51,7 +51,7 @@ library PoolLib { /// @param tokens_ Array of token addresses /// @param bases_ Array of base denominators for each token function initialize( - State storage state, + PoolLib.State storage state, IERC20[] memory tokens_, uint256[] memory bases_ ) internal { @@ -78,7 +78,7 @@ library PoolLib { /// @notice Get deposit amounts needed for minting LP tokens function mintDepositAmounts( - State storage state, + PoolLib.State storage state, uint256 lpTokenAmount, uint256 totalSupply ) internal view returns (uint256[] memory depositAmounts) { @@ -102,7 +102,7 @@ library PoolLib { /// @notice Initial mint to set up pool for the first time function initialMint( - State storage state, + PoolLib.State storage state, address receiver, uint256 lpTokens, int128 kappa, @@ -142,7 +142,7 @@ library PoolLib { /// @notice Proportional mint for existing pool function mint( - State storage state, + PoolLib.State storage state, address payer, address receiver, uint256 lpTokenAmount, @@ -209,7 +209,7 @@ library PoolLib { /// @notice Get withdrawal amounts for burning LP tokens function burnReceiveAmounts( - State storage state, + PoolLib.State storage state, uint256 lpTokenAmount, uint256 totalSupply ) internal view returns (uint256[] memory withdrawAmounts) { @@ -230,7 +230,7 @@ library PoolLib { /// @notice Burn LP tokens and withdraw proportional basket function burn( - State storage state, + PoolLib.State storage state, address payer, address receiver, uint256 lpAmount, @@ -293,23 +293,22 @@ library PoolLib { /// @notice Get swap amounts for exact input swap function swapAmounts( - State storage state, + PoolLib.State storage state, uint256 inputTokenIndex, uint256 outputTokenIndex, uint256 maxAmountIn, int128 limitPrice, - uint256 swapFeePpm, - bool stablePair + uint256 swapFeePpm ) internal view returns (uint256 amountIn, uint256 amountOut, uint256 fee) { (uint256 grossIn, uint256 outUint,,,, uint256 feeUint) = _quoteSwapExactIn( - state, inputTokenIndex, outputTokenIndex, maxAmountIn, limitPrice, swapFeePpm, stablePair + state, inputTokenIndex, outputTokenIndex, maxAmountIn, limitPrice, swapFeePpm ); return (grossIn, outUint, feeUint); } /// @notice Get swap amounts for swap to price limit function swapToLimitAmounts( - State storage state, + PoolLib.State storage state, uint256 inputTokenIndex, uint256 outputTokenIndex, int128 limitPrice, @@ -323,7 +322,7 @@ library PoolLib { /// @notice Get amounts for swapMint operation function swapMintAmounts( - State storage state, + PoolLib.State storage state, uint256 inputTokenIndex, uint256 maxAmountIn, uint256 swapFeePpm, @@ -381,7 +380,7 @@ library PoolLib { /// @notice Execute exact input swap function swap( - State storage state, + PoolLib.State storage state, address payer, address receiver, uint256 inputTokenIndex, @@ -389,8 +388,7 @@ library PoolLib { uint256 maxAmountIn, int128 limitPrice, uint256 deadline, - uint256 swapFeePpm, - bool stablePair + uint256 swapFeePpm ) internal returns (uint256 amountIn, uint256 amountOut, uint256 fee) { uint256 n = state.tokens.length; require(inputTokenIndex < n && outputTokenIndex < n, "swap: idx"); @@ -403,7 +401,7 @@ library PoolLib { // Compute amounts (uint256 totalTransferAmount, uint256 amountOutUint, int128 amountInInternalUsed, int128 amountOutInternal, , uint256 feeUint) = - _quoteSwapExactIn(state, inputTokenIndex, outputTokenIndex, maxAmountIn, limitPrice, swapFeePpm, stablePair); + _quoteSwapExactIn(state, inputTokenIndex, outputTokenIndex, maxAmountIn, limitPrice, swapFeePpm); // Transfer exact amount from payer state.tokens[inputTokenIndex].safeTransferFrom(payer, address(this), totalTransferAmount); @@ -429,7 +427,7 @@ library PoolLib { /// @notice Execute swap to price limit function swapToLimit( - State storage state, + PoolLib.State storage state, address payer, address receiver, uint256 inputTokenIndex, @@ -475,7 +473,7 @@ library PoolLib { /// @notice Get amounts for burnSwap operation function burnSwapAmounts( - State storage state, + PoolLib.State storage state, uint256 lpAmount, uint256 inputTokenIndex, uint256 swapFeePpm, @@ -508,7 +506,7 @@ library PoolLib { /// @notice Single-token mint (swapMint) function swapMint( - State storage state, + PoolLib.State storage state, address payer, address receiver, uint256 inputTokenIndex, @@ -557,7 +555,7 @@ library PoolLib { /// @notice Burn LP tokens and swap to single asset (burnSwap) function burnSwap( - State storage state, + PoolLib.State storage state, address payer, address receiver, uint256 lpAmount, @@ -607,7 +605,7 @@ library PoolLib { /// @notice Calculate flash loan repayment amounts function flashRepaymentAmounts( - State storage state, + PoolLib.State storage state, uint256[] memory loanAmounts, uint256 flashFeePpm ) internal view returns (uint256[] memory repaymentAmounts) { @@ -622,7 +620,7 @@ library PoolLib { /// @notice Execute flash loan function flash( - State storage state, + PoolLib.State storage state, address recipient, uint256[] memory amounts, bytes calldata data, @@ -683,7 +681,7 @@ library PoolLib { /// @notice Get marginal price between two tokens function price( - State storage state, + PoolLib.State storage state, uint256 baseTokenIndex, uint256 quoteTokenIndex ) internal view returns (int128) { @@ -695,7 +693,7 @@ library PoolLib { /// @notice Get price of one LP token in quote asset function poolPrice( - State storage state, + PoolLib.State storage state, uint256 quoteTokenIndex, uint256 totalSupply ) internal view returns (int128) { @@ -747,13 +745,12 @@ library PoolLib { /// @notice Internal quote for exact-input swap function _quoteSwapExactIn( - State storage state, + PoolLib.State storage state, uint256 inputTokenIndex, uint256 outputTokenIndex, uint256 maxAmountIn, int128 limitPrice, - uint256 swapFeePpm, - bool stablePair + uint256 swapFeePpm ) internal view @@ -779,9 +776,64 @@ library PoolLib { require(deltaInternalI > int128(0), "swap: input too small after fee"); // Compute internal amounts using LMSR - (amountInInternalUsed, amountOutInternal) = - stablePair ? LMSRStabilizedBalancedPair.swapAmountsForExactInput(state.lmsr, inputTokenIndex, outputTokenIndex, deltaInternalI, limitPrice) - : state.lmsr.swapAmountsForExactInput(inputTokenIndex, outputTokenIndex, deltaInternalI, limitPrice); + (amountInInternalUsed, amountOutInternal) = state.lmsr.swapAmountsForExactInput( + inputTokenIndex, outputTokenIndex, deltaInternalI, limitPrice); + + // Convert actual used input internal -> uint (ceil) + amountInUintNoFee = _internalToUintCeil(amountInInternalUsed, state.bases[inputTokenIndex]); + require(amountInUintNoFee > 0, "swap: input zero"); + + // Compute gross transfer including fee + feeUint = 0; + grossIn = amountInUintNoFee; + if (swapFeePpm > 0) { + feeUint = _ceilFee(amountInUintNoFee, swapFeePpm); + grossIn += feeUint; + } + + // Ensure within user max + require(grossIn <= maxAmountIn, "swap: transfer exceeds max"); + + // Compute output (floor) + amountOutUint = _internalToUintFloor(amountOutInternal, state.bases[outputTokenIndex]); + require(amountOutUint > 0, "swap: output zero"); + } + + /// @notice Internal quote for exact-input swap + function _quoteSwapExactIn_BalancedPair( + PoolLib.State storage state, + uint256 inputTokenIndex, + uint256 outputTokenIndex, + uint256 maxAmountIn, + int128 limitPrice, + uint256 swapFeePpm + ) + internal + view + returns ( + uint256 grossIn, + uint256 amountOutUint, + int128 amountInInternalUsed, + int128 amountOutInternal, + uint256 amountInUintNoFee, + uint256 feeUint + ) + { + uint256 n = state.tokens.length; + require(inputTokenIndex < n && outputTokenIndex < n, "swap: idx"); + require(maxAmountIn > 0, "swap: input zero"); + require(state.lmsr.nAssets > 0, "swap: empty pool"); + + // Estimate max net input + (, uint256 netUintForSwap) = _computeFee(maxAmountIn, swapFeePpm); + + // Convert to internal (floor) + int128 deltaInternalI = _uintToInternalFloor(netUintForSwap, state.bases[inputTokenIndex]); + require(deltaInternalI > int128(0), "swap: input too small after fee"); + + // Compute internal amounts using LMSR + (amountInInternalUsed, amountOutInternal) = LMSRStabilizedBalancedPair.swapAmountsForExactInput( + state.lmsr, inputTokenIndex, outputTokenIndex, deltaInternalI, limitPrice); // Convert actual used input internal -> uint (ceil) amountInUintNoFee = _internalToUintCeil(amountInInternalUsed, state.bases[inputTokenIndex]); @@ -805,7 +857,7 @@ library PoolLib { /// @notice Internal quote for swap-to-limit function _quoteSwapToLimit( - State storage state, + PoolLib.State storage state, uint256 inputTokenIndex, uint256 outputTokenIndex, int128 limitPrice, diff --git a/src/PoolLibBalancedPair.sol b/src/PoolLibBalancedPair.sol new file mode 100644 index 0000000..7c0693f --- /dev/null +++ b/src/PoolLibBalancedPair.sol @@ -0,0 +1,139 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.30; + +import "@abdk/ABDKMath64x64.sol"; +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; +import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; +import "./LMSRStabilized.sol"; +import "./LMSRStabilizedBalancedPair.sol"; +import "./IPartyFlashCallback.sol"; +import {PoolLib} from "./PoolLib.sol"; + +/// @title PoolLibBalancedPair - Library with optimized functions for stablecoin pair pools +/// @dev All functions are internal and accept State as the first parameter +library PoolLibBalancedPair { + using ABDKMath64x64 for int128; + using LMSRStabilized for LMSRStabilized.State; + using PoolLib for PoolLib.State; + using SafeERC20 for IERC20; + + /// @notice Get swap amounts for exact input swap + function swapAmounts( + PoolLib.State storage state, + uint256 inputTokenIndex, + uint256 outputTokenIndex, + uint256 maxAmountIn, + int128 limitPrice, + uint256 swapFeePpm + ) internal view returns (uint256 amountIn, uint256 amountOut, uint256 fee) { + (uint256 grossIn, uint256 outUint,,,, uint256 feeUint) = _quoteSwapExactIn( + state, inputTokenIndex, outputTokenIndex, maxAmountIn, limitPrice, swapFeePpm + ); + return (grossIn, outUint, feeUint); + } + + /// @notice Internal quote for exact-input swap + function _quoteSwapExactIn( + PoolLib.State storage state, + uint256 inputTokenIndex, + uint256 outputTokenIndex, + uint256 maxAmountIn, + int128 limitPrice, + uint256 swapFeePpm + ) + internal + view + returns ( + uint256 grossIn, + uint256 amountOutUint, + int128 amountInInternalUsed, + int128 amountOutInternal, + uint256 amountInUintNoFee, + uint256 feeUint + ) + { + uint256 n = state.tokens.length; + require(inputTokenIndex < n && outputTokenIndex < n, "swap: idx"); + require(maxAmountIn > 0, "swap: input zero"); + require(state.lmsr.nAssets > 0, "swap: empty pool"); + + // Estimate max net input + (, uint256 netUintForSwap) = PoolLib._computeFee(maxAmountIn, swapFeePpm); + + // Convert to internal (floor) + int128 deltaInternalI = PoolLib._uintToInternalFloor(netUintForSwap, state.bases[inputTokenIndex]); + require(deltaInternalI > int128(0), "swap: input too small after fee"); + + // Compute internal amounts using LMSR + (amountInInternalUsed, amountOutInternal) = LMSRStabilizedBalancedPair.swapAmountsForExactInput(state.lmsr, + inputTokenIndex, outputTokenIndex, deltaInternalI, limitPrice); + + // Convert actual used input internal -> uint (ceil) + amountInUintNoFee = PoolLib._internalToUintCeil(amountInInternalUsed, state.bases[inputTokenIndex]); + require(amountInUintNoFee > 0, "swap: input zero"); + + // Compute gross transfer including fee + feeUint = 0; + grossIn = amountInUintNoFee; + if (swapFeePpm > 0) { + feeUint = PoolLib._ceilFee(amountInUintNoFee, swapFeePpm); + grossIn += feeUint; + } + + // Ensure within user max + require(grossIn <= maxAmountIn, "swap: transfer exceeds max"); + + // Compute output (floor) + amountOutUint = PoolLib._internalToUintFloor(amountOutInternal, state.bases[outputTokenIndex]); + require(amountOutUint > 0, "swap: output zero"); + } + + /// @notice Execute exact input swap + function swap( + PoolLib.State storage state, + address payer, + address receiver, + uint256 inputTokenIndex, + uint256 outputTokenIndex, + uint256 maxAmountIn, + int128 limitPrice, + uint256 deadline, + uint256 swapFeePpm + ) internal returns (uint256 amountIn, uint256 amountOut, uint256 fee) { + uint256 n = state.tokens.length; + require(inputTokenIndex < n && outputTokenIndex < n, "swap: idx"); + require(maxAmountIn > 0, "swap: input zero"); + require(deadline == 0 || block.timestamp <= deadline, "swap: deadline exceeded"); + + // Read previous balances + uint256 prevBalI = IERC20(state.tokens[inputTokenIndex]).balanceOf(address(this)); + uint256 prevBalJ = IERC20(state.tokens[outputTokenIndex]).balanceOf(address(this)); + + // Compute amounts + (uint256 totalTransferAmount, uint256 amountOutUint, int128 amountInInternalUsed, int128 amountOutInternal, , uint256 feeUint) = + _quoteSwapExactIn(state, inputTokenIndex, outputTokenIndex, maxAmountIn, limitPrice, swapFeePpm); + + // Transfer exact amount from payer + state.tokens[inputTokenIndex].safeTransferFrom(payer, address(this), totalTransferAmount); + uint256 balIAfter = IERC20(state.tokens[inputTokenIndex]).balanceOf(address(this)); + require(balIAfter == prevBalI + totalTransferAmount, "swap: non-standard tokenIn"); + + // Transfer output to receiver + state.tokens[outputTokenIndex].safeTransfer(receiver, amountOutUint); + uint256 balJAfter = IERC20(state.tokens[outputTokenIndex]).balanceOf(address(this)); + require(balJAfter == prevBalJ - amountOutUint, "swap: non-standard tokenOut"); + + // Update cached balances + state.cachedUintBalances[inputTokenIndex] = balIAfter; + state.cachedUintBalances[outputTokenIndex] = balJAfter; + + // Apply swap to LMSR state + state.lmsr.applySwap(inputTokenIndex, outputTokenIndex, amountInInternalUsed, amountOutInternal); + + emit PoolLib.Swap(payer, receiver, state.tokens[inputTokenIndex], state.tokens[outputTokenIndex], totalTransferAmount, amountOutUint); + + return (totalTransferAmount, amountOutUint, feeUint); + } + +} diff --git a/test/GasTest.sol b/test/GasTest.sol index 8cd4ea4..fc3ef27 100644 --- a/test/GasTest.sol +++ b/test/GasTest.sol @@ -1,14 +1,15 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.30; -import "forge-std/Test.sol"; -import "@abdk/ABDKMath64x64.sol"; -import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; +import "../src/Deploy.sol"; +import "../src/IPartyFlashCallback.sol"; import "../src/LMSRStabilized.sol"; import "../src/PartyPool.sol"; +import "@abdk/ABDKMath64x64.sol"; // Import the flash callback interface -import "../src/IPartyFlashCallback.sol"; +import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; +import "forge-std/Test.sol"; /// @notice Test contract that implements the flash callback for testing flash loans contract FlashBorrower is IPartyFlashCallback { @@ -172,7 +173,7 @@ contract GasTest is Test { } // Compute kappa from slippage params and number of tokens, then construct pool with kappa int128 computedKappa = LMSRStabilized.computeKappaFromSlippage(ierc20Tokens.length, tradeFrac, targetSlippage); - PartyPool newPool = new PartyPool(poolName, poolName, ierc20Tokens, bases, computedKappa, feePpm, feePpm, false); + PartyPool newPool = Deploy.newPartyPool(poolName, poolName, ierc20Tokens, bases, computedKappa, feePpm, feePpm, false); // Transfer initial deposit amounts into pool before initial mint for (uint256 i = 0; i < numTokens; i++) { @@ -212,7 +213,7 @@ contract GasTest is Test { ierc20Tokens[i] = IERC20(tokens[i]); } int128 computedKappa = LMSRStabilized.computeKappaFromSlippage(ierc20Tokens.length, tradeFrac, targetSlippage); - PartyPool newPool = new PartyPool(poolName, poolName, ierc20Tokens, bases, computedKappa, feePpm, feePpm, true); + PartyPool newPool = Deploy.newPartyPool(poolName, poolName, ierc20Tokens, bases, computedKappa, feePpm, feePpm, true); // Transfer initial deposit amounts into pool before initial mint for (uint256 i = 0; i < numTokens; i++) { diff --git a/test/PartyPool.t.sol b/test/PartyPool.t.sol index 3f60345..53def46 100644 --- a/test/PartyPool.t.sol +++ b/test/PartyPool.t.sol @@ -1,14 +1,15 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.30; -import "forge-std/Test.sol"; -import "@abdk/ABDKMath64x64.sol"; -import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; +import "../src/Deploy.sol"; +import "../src/IPartyFlashCallback.sol"; import "../src/LMSRStabilized.sol"; import "../src/PartyPool.sol"; +import "@abdk/ABDKMath64x64.sol"; // Import the flash callback interface -import "../src/IPartyFlashCallback.sol"; +import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; +import "forge-std/Test.sol"; /// @notice Test contract that implements the flash callback for testing flash loans contract FlashBorrower is IPartyFlashCallback { @@ -197,7 +198,7 @@ contract PartyPoolTest is Test { uint256 feePpm = 1000; int128 kappa3 = LMSRStabilized.computeKappaFromSlippage(tokens.length, tradeFrac, targetSlippage); - pool = new PartyPool("LP", "LP", tokens, bases, kappa3, feePpm, feePpm, false); + pool = Deploy.newPartyPool("LP", "LP", tokens, bases, kappa3, feePpm, feePpm, false); // Transfer initial deposit amounts into pool before initial mint (pool expects tokens already in contract) // We deposit equal amounts INIT_BAL for each token @@ -227,7 +228,7 @@ contract PartyPoolTest is Test { } int128 kappa10 = LMSRStabilized.computeKappaFromSlippage(tokens10.length, tradeFrac, targetSlippage); - pool10 = new PartyPool("LP10", "LP10", tokens10, bases10, kappa10, feePpm, feePpm, false); + pool10 = Deploy.newPartyPool("LP10", "LP10", tokens10, bases10, kappa10, feePpm, feePpm, false); // Mint additional tokens for pool10 initial deposit token0.mint(address(this), INIT_BAL); @@ -1231,11 +1232,11 @@ contract PartyPoolTest is Test { // Pool with default initialization (lpTokens = 0) int128 kappaDefault = LMSRStabilized.computeKappaFromSlippage(tokens.length, tradeFrac, targetSlippage); - PartyPool poolDefault = new PartyPool("LP_DEFAULT", "LP_DEFAULT", tokens, bases, kappaDefault, feePpm, feePpm, false); + PartyPool poolDefault = Deploy.newPartyPool("LP_DEFAULT", "LP_DEFAULT", tokens, bases, kappaDefault, feePpm, feePpm, false); // Pool with custom initialization (lpTokens = custom amount) int128 kappaCustom = LMSRStabilized.computeKappaFromSlippage(tokens.length, tradeFrac, targetSlippage); - PartyPool poolCustom = new PartyPool("LP_CUSTOM", "LP_CUSTOM", tokens, bases, kappaCustom, feePpm, feePpm, false); + PartyPool poolCustom = Deploy.newPartyPool("LP_CUSTOM", "LP_CUSTOM", tokens, bases, kappaCustom, feePpm, feePpm, false); // Mint additional tokens for both pools token0.mint(address(this), INIT_BAL * 2); @@ -1307,9 +1308,9 @@ contract PartyPoolTest is Test { uint256 feePpm = 1000; int128 kappaDefault2 = LMSRStabilized.computeKappaFromSlippage(tokens.length, tradeFrac, targetSlippage); - PartyPool poolDefault = new PartyPool("LP_DEFAULT", "LP_DEFAULT", tokens, bases, kappaDefault2, feePpm, feePpm, false); + PartyPool poolDefault = Deploy.newPartyPool("LP_DEFAULT", "LP_DEFAULT", tokens, bases, kappaDefault2, feePpm, feePpm, false); int128 kappaCustom2 = LMSRStabilized.computeKappaFromSlippage(tokens.length, tradeFrac, targetSlippage); - PartyPool poolCustom = new PartyPool("LP_CUSTOM", "LP_CUSTOM", tokens, bases, kappaCustom2, feePpm, feePpm, false); + PartyPool poolCustom = Deploy.newPartyPool("LP_CUSTOM", "LP_CUSTOM", tokens, bases, kappaCustom2, feePpm, feePpm, false); // Mint additional tokens token0.mint(address(this), INIT_BAL * 4);