removed state.nAssets

This commit is contained in:
tim
2025-10-29 19:35:41 -04:00
parent 20758cfb35
commit dd9b7474a6
9 changed files with 76 additions and 113 deletions

View File

@@ -250,13 +250,11 @@ interface IPartyPool is IERC20Metadata, IOwnable {
bool unwrap
) external returns (uint256 amountOutUint);
/**
* @dev Initiate a flash loan.
* @param receiver The receiver of the tokens in the loan, and the receiver of the callback.
* @param token The loan currency.
* @param amount The amount of tokens lent.
* @param data Arbitrary data structure, intended to contain user-defined parameters.
*/
/// @dev Initiate a flash loan.
/// @param receiver The receiver of the tokens in the loan, and the receiver of the callback.
/// @param token The loan currency.
/// @param amount The amount of tokens lent.
/// @param data Arbitrary data structure, intended to contain user-defined parameters.
function flashLoan(
IERC3156FlashBorrower receiver,
address token,

View File

@@ -12,7 +12,6 @@ library LMSRStabilized {
using ABDKMath64x64 for int128;
struct State {
uint256 nAssets;
int128 kappa; // liquidity parameter κ (64.64 fixed point)
int128[] qInternal; // cached internal balances in 64.64 fixed-point format
}
@@ -28,8 +27,6 @@ library LMSRStabilized {
int128[] memory initialQInternal,
int128 kappa
) internal {
s.nAssets = initialQInternal.length;
// Initialize qInternal cache
if (s.qInternal.length != initialQInternal.length) {
s.qInternal = new int128[](initialQInternal.length);
@@ -98,7 +95,7 @@ library LMSRStabilized {
int128 a,
int128 limitPrice
) internal view returns (int128 amountIn, int128 amountOut) {
return swapAmountsForExactInput(s.nAssets, s.kappa, s.qInternal, i, j, a, limitPrice);
return swapAmountsForExactInput(s.kappa, s.qInternal, i, j, a, limitPrice);
}
/// @notice Pure version: Closed-form asset-i -> asset-j amountOut in 64.64 fixed-point format (fee-free kernel)
@@ -113,7 +110,6 @@ library LMSRStabilized {
///
/// NOTE: Kernel is fee-free; fees should be handled by the wrapper/token layer.
///
/// @param nAssets Number of assets in the pool
/// @param kappa Liquidity parameter κ (64.64 fixed point)
/// @param qInternal Cached internal balances in 64.64 fixed-point format
/// @param i Index of input asset
@@ -123,7 +119,6 @@ library LMSRStabilized {
/// @return amountIn Actual amount of input asset used (may be less than `a` if limited by price)
/// @return amountOut Amount of output asset j in 64.64 fixed-point format
function swapAmountsForExactInput(
uint256 nAssets,
int128 kappa,
int128[] memory qInternal,
uint256 i,
@@ -217,7 +212,7 @@ library LMSRStabilized {
uint256 j,
int128 limitPrice
) internal view returns (int128 amountIn, int128 amountOut) {
return swapAmountsForPriceLimit(s.nAssets, s.kappa, s.qInternal, i, j, limitPrice);
return swapAmountsForPriceLimit(s.kappa, s.qInternal, i, j, limitPrice);
}
/// @notice Pure version: Maximum input/output pair possible when swapping from asset i to asset j
@@ -226,7 +221,6 @@ library LMSRStabilized {
/// and the corresponding output amount (amountOut). If the output would exceed the
/// j-balance, amountOut is capped and amountIn is solved for the capped output.
///
/// @param nAssets Number of assets in the pool
/// @param kappa Liquidity parameter κ (64.64 fixed point)
/// @param qInternal Cached internal balances in 64.64 fixed-point format
/// @param i Index of input asset
@@ -235,7 +229,6 @@ library LMSRStabilized {
/// @return amountIn Maximum input amount in 64.64 fixed-point format that reaches the price limit
/// @return amountOut Corresponding maximum output amount in 64.64 fixed-point format
function swapAmountsForPriceLimit(
uint256 nAssets,
int128 kappa,
int128[] memory qInternal,
uint256 i,
@@ -318,7 +311,7 @@ library LMSRStabilized {
uint256 i,
int128 a
) internal view returns (int128 amountIn, int128 amountOut) {
return swapAmountsForMint(s.nAssets, s.kappa, s.qInternal, i, a);
return swapAmountsForMint(s.kappa, s.qInternal, i, a);
}
/// @notice Pure version: Compute LP-size increase when minting from a single-token input using bisection only.
@@ -327,7 +320,6 @@ library LMSRStabilized {
/// where x_j(α) is the input to swap i->j that yields y_j = α*q_j and
/// x_j = b * ln( r0_j / (r0_j + 1 - exp(y_j / b)) ), r0_j = exp((q_i - q_j)/b).
/// Bisection is used (no Newton) to keep implementation compact and gas-friendly.
/// @param nAssets Number of assets in the pool
/// @param kappa Liquidity parameter κ (64.64 fixed point)
/// @param qInternal Cached internal balances in 64.64 fixed-point format
/// @param i Index of input asset
@@ -335,13 +327,13 @@ library LMSRStabilized {
/// @return amountIn Actual amount of input consumed
/// @return amountOut LP size-metric increase (alpha * S)
function swapAmountsForMint(
uint256 nAssets,
int128 kappa,
int128[] memory qInternal,
uint256 i,
int128 a
) internal pure returns (int128 amountIn, int128 amountOut) {
require(i < nAssets, "LMSR: idx");
uint256 n = qInternal.length;
require(i < n, "LMSR: idx");
require(a > int128(0), "LMSR: amount <= 0");
int128 sizeMetric = _computeSizeMetric(qInternal);
@@ -351,8 +343,6 @@ library LMSRStabilized {
int128 invB = ABDKMath64x64.div(ONE, b);
int128 S = sizeMetric;
uint256 n = nAssets;
// Precompute r0_j = exp((q_i - q_j) / b) for all j to avoid recomputing during search.
int128[] memory r0 = new int128[](n);
for (uint256 j = 0; j < n; ) {
@@ -530,7 +520,7 @@ library LMSRStabilized {
uint256 i,
int128 alpha
) internal view returns (int128 amountOut, int128 amountIn) {
return swapAmountsForBurn(s.nAssets, s.kappa, s.qInternal, i, alpha);
return swapAmountsForBurn(s.kappa, s.qInternal, i, alpha);
}
/// @notice Pure version: Compute single-asset payout when burning a proportional share alpha of the pool.
@@ -542,7 +532,6 @@ library LMSRStabilized {
/// - cap output to q_local[i] when necessary (solve inverse for input used)
/// Treat any per-asset rhs<=0 as "this asset contributes zero" (do not revert).
/// Revert only if the final single-asset payout is zero.
/// @param nAssets Number of assets in the pool
/// @param kappa Liquidity parameter κ (64.64 fixed point)
/// @param qInternal Cached internal balances in 64.64 fixed-point format
/// @param i Index of output asset
@@ -550,13 +539,11 @@ library LMSRStabilized {
/// @return amountOut Amount of asset i received (in 64.64 fixed-point)
/// @return amountIn LP size-metric redeemed (alpha * S)
function swapAmountsForBurn(
uint256 nAssets,
int128 kappa,
int128[] memory qInternal,
uint256 i,
int128 alpha
) internal pure returns (int128 amountOut, int128 amountIn) {
require(i < nAssets, "LMSR: idx");
require(alpha > int128(0) && alpha <= ONE, "LMSR: alpha");
int128 sizeMetric = _computeSizeMetric(qInternal);
@@ -565,7 +552,7 @@ library LMSRStabilized {
require(b > int128(0), "LMSR: b<=0");
int128 invB = ABDKMath64x64.div(ONE, b);
uint256 n = nAssets;
uint256 n = qInternal.length;
// Size metric and burned size (amountIn returned)
int128 S = sizeMetric;
@@ -675,7 +662,6 @@ library LMSRStabilized {
int128 amountIn,
int128 amountOut
) internal {
require(i < s.nAssets && j < s.nAssets, "LMSR: idx");
require(amountIn > int128(0), "LMSR: amountIn <= 0");
require(amountOut > int128(0), "LMSR: amountOut <= 0");
@@ -690,15 +676,14 @@ library LMSRStabilized {
/// Updates the internal qInternal cache with the new balances
/// @param newQInternal New asset quantities after mint/redeem (64.64 format)
function updateForProportionalChange(State storage s, int128[] memory newQInternal) internal {
require(newQInternal.length == s.nAssets, "LMSR: length mismatch");
// Compute new total for validation
int128 newTotal = _computeSizeMetric(newQInternal);
require(newTotal > int128(0), "LMSR: new total zero");
// Update the cached qInternal with new values
for (uint i = 0; i < s.nAssets; ) {
uint256 n = newQInternal.length;
for (uint i = 0; i < n; ) {
s.qInternal[i] = newQInternal[i];
unchecked { i++; }
}
@@ -775,19 +760,17 @@ library LMSRStabilized {
/// @notice Marginal price of `base` in terms of `quote` (p_quote / p_base) as Q64.64
/// @dev Returns exp((q_quote - q_base) / b). Indices must be valid and b > 0.
function price(State storage s, uint256 baseTokenIndex, uint256 quoteTokenIndex) internal view returns (int128) {
return price(s.nAssets, s.kappa, s.qInternal, baseTokenIndex, quoteTokenIndex);
return price(s.kappa, s.qInternal, baseTokenIndex, quoteTokenIndex);
}
/// @notice Pure version: Marginal price of `base` in terms of `quote` (p_quote / p_base) as Q64.64
/// @dev Returns exp((q_quote - q_base) / b). Indices must be valid and b > 0.
/// @param nAssets Number of assets in the pool
/// @param kappa Liquidity parameter κ (64.64 fixed point)
/// @param qInternal Cached internal balances in 64.64 fixed-point format
/// @param baseTokenIndex Index of base token
/// @param quoteTokenIndex Index of quote token
/// @return Price in 64.64 fixed-point format
function price(uint256 nAssets, int128 kappa, int128[] memory qInternal, uint256 baseTokenIndex, uint256 quoteTokenIndex) internal pure returns (int128) {
require(baseTokenIndex < nAssets && quoteTokenIndex < nAssets, "LMSR: idx");
function price(int128 kappa, int128[] memory qInternal, uint256 baseTokenIndex, uint256 quoteTokenIndex) internal pure returns (int128) {
int128 sizeMetric = _computeSizeMetric(qInternal);
require(sizeMetric > int128(0), "LMSR: size metric zero");
int128 b = kappa.mul(sizeMetric);
@@ -803,18 +786,16 @@ library LMSRStabilized {
/// @notice Price of one unit of the LP size-metric (S = sum q_i) denominated in `quote` asset (Q64.64)
/// @dev Computes: poolPrice_quote = (1 / S) * sum_j q_j * exp((q_j - q_quote) / b)
function poolPrice(State storage s, uint256 quoteTokenIndex) internal view returns (int128) {
return poolPrice(s.nAssets, s.kappa, s.qInternal, quoteTokenIndex);
return poolPrice(s.kappa, s.qInternal, quoteTokenIndex);
}
/// @notice Pure version: Price of one unit of the LP size-metric (S = sum q_i) denominated in `quote` asset (Q64.64)
/// @dev Computes: poolPrice_quote = (1 / S) * sum_j q_j * exp((q_j - q_quote) / b)
/// @param nAssets Number of assets in the pool
/// @param kappa Liquidity parameter κ (64.64 fixed point)
/// @param qInternal Cached internal balances in 64.64 fixed-point format
/// @param quoteTokenIndex Index of quote token
/// @return Pool price in 64.64 fixed-point format
function poolPrice(uint256 nAssets, int128 kappa, int128[] memory qInternal, uint256 quoteTokenIndex) internal pure returns (int128) {
require(quoteTokenIndex < nAssets, "LMSR: idx");
function poolPrice(int128 kappa, int128[] memory qInternal, uint256 quoteTokenIndex) internal pure returns (int128) {
// Compute b and ensure positivity
int128 sizeMetric = _computeSizeMetric(qInternal);
require(sizeMetric > int128(0), "LMSR: size metric zero");
@@ -830,7 +811,7 @@ library LMSRStabilized {
// Accumulate weighted exponentials: sum_j q_j * exp((q_j - q_quote) / b)
int128 acc = int128(0);
uint256 n = nAssets;
uint256 n = qInternal.length;
for (uint256 j = 0; j < n; ) {
// factor = exp((q_j - q_quote) / b)
int128 factor = _exp(qInternal[j].sub(qInternal[quoteTokenIndex]).mul(invB));
@@ -917,7 +898,6 @@ library LMSRStabilized {
/// This resets the state so the pool can be re-initialized by init(...) on next mint.
function deinit(State storage s) internal {
// Reset core state
s.nAssets = 0;
s.kappa = int128(0);
// Clear qInternal array

View File

@@ -35,10 +35,11 @@ library LMSRStabilizedBalancedPair {
int128 limitPrice
) internal view returns (int128 amountIn, int128 amountOut) {
// Quick index check
require(i < s.nAssets && j < s.nAssets, "LMSR: idx");
uint256 nAssets = s.qInternal.length;
require(i < nAssets && j < nAssets, "LMSR: idx");
// If not exactly a two-asset pool, fall back to the general routine.
if (s.nAssets != 2) {
if (nAssets != 2) {
return LMSRStabilized.swapAmountsForExactInput(s, i, j, a, limitPrice);
}

View File

@@ -148,9 +148,6 @@ contract PartyPool is PartyPoolBase, OwnableExternal, ERC20External, IPartyPool
uint256 n = tokens_.length;
// Initialize LMSR state nAssets; full init occurs on first mint when quantities are known.
_lmsr.nAssets = n;
// Initialize token address to index mapping
for (uint i = 0; i < n;) {
_tokenAddressToIndexPlusOne[tokens_[i]] = i + 1;
@@ -444,13 +441,7 @@ contract PartyPool is PartyPoolBase, OwnableExternal, ERC20External, IPartyPool
}
/**
* @dev Loan `amount` tokens to `receiver`, and takes it back plus a `flashFee` after the callback.
* @param receiver The contract receiving the tokens, needs to implement the `onFlashLoan(address user, uint256 amount, uint256 fee, bytes calldata)` interface.
* @param tokenAddr The loan currency.
* @param amount The amount of tokens lent.
* @param data A data parameter to be passed on to the `receiver` for any custom use.
*/
/// @inheritdoc IPartyPool
function flashLoan(
IERC3156FlashBorrower receiver,
address tokenAddr,

View File

@@ -30,7 +30,7 @@ contract PartyPoolMintImpl is PartyPoolBase {
uint256 n = _tokens.length;
// Check if this is initial deposit - revert if not
bool isInitialDeposit = _totalSupply == 0 || _lmsr.nAssets == 0;
bool isInitialDeposit = _totalSupply == 0 || _lmsr.qInternal.length == 0;
require(isInitialDeposit, "initialMint: pool already initialized");
// Read initial on-chain balances, require all > 0, and compute denominators (bases) from deposits.
@@ -79,7 +79,7 @@ contract PartyPoolMintImpl is PartyPoolBase {
uint256 n = _tokens.length;
// Check if this is NOT initial deposit - revert if it is
bool isInitialDeposit = _totalSupply == 0 || _lmsr.nAssets == 0;
bool isInitialDeposit = _totalSupply == 0 || _lmsr.qInternal.length == 0;
require(!isInitialDeposit, "mint: use initialMint for pool initialization");
require(lpTokenAmount > 0, "mint: zero LP amount");
@@ -88,7 +88,7 @@ contract PartyPoolMintImpl is PartyPoolBase {
uint256 oldScaled = ABDKMath64x64.mulu(oldTotal, LP_SCALE);
// Calculate required deposit amounts for the desired LP _tokens
uint256[] memory depositAmounts = mintAmounts(lpTokenAmount, _lmsr.nAssets, _totalSupply, _cachedUintBalances);
uint256[] memory depositAmounts = mintAmounts(lpTokenAmount, _totalSupply, _cachedUintBalances);
// Transfer in all token amounts
for (uint i = 0; i < n; ) {
@@ -160,7 +160,7 @@ contract PartyPoolMintImpl is PartyPoolBase {
// Use cached balances; assume standard ERC20 transfers without external interference
// Compute proportional withdrawal amounts for the requested LP amount (rounded down)
withdrawAmounts = burnAmounts(lpAmount, _lmsr.nAssets, _totalSupply, _cachedUintBalances);
withdrawAmounts = burnAmounts(lpAmount, _totalSupply, _cachedUintBalances);
// Transfer underlying _tokens out to receiver according to computed proportions
for (uint i = 0; i < n; ) {
@@ -213,8 +213,9 @@ contract PartyPoolMintImpl is PartyPoolBase {
/// @param lpTokenAmount The amount of LP _tokens desired
/// @return depositAmounts Array of token amounts to deposit (rounded up)
function mintAmounts(uint256 lpTokenAmount,
uint256 numAssets, uint256 totalSupply, uint256[] memory cachedUintBalances) public pure
uint256 totalSupply, uint256[] memory cachedUintBalances) public pure
returns (uint256[] memory depositAmounts) {
uint256 numAssets = cachedUintBalances.length;
depositAmounts = new uint256[](numAssets);
// If this is the first mint or pool is empty, return zeros
@@ -236,8 +237,9 @@ contract PartyPoolMintImpl is PartyPoolBase {
}
function burnAmounts(uint256 lpTokenAmount,
uint256 numAssets, uint256 totalSupply, uint256[] memory cachedUintBalances) public pure
uint256 totalSupply, uint256[] memory cachedUintBalances) public pure
returns (uint256[] memory withdrawAmounts) {
uint256 numAssets = cachedUintBalances.length;
withdrawAmounts = new uint256[](numAssets);
// If supply is zero or pool uninitialized, return zeros
@@ -280,7 +282,7 @@ contract PartyPoolMintImpl is PartyPoolBase {
) public pure returns (uint256 amountInUsed, uint256 lpMinted, uint256 inFee) {
require(inputTokenIndex < bases_.length, "swapMintAmounts: idx");
require(maxAmountIn > 0, "swapMintAmounts: input zero");
require(lmsrState.nAssets > 0, "swapMintAmounts: uninit pool");
require(lmsrState.qInternal.length > 0, "swapMintAmounts: uninit pool");
// Compute fee on gross maxAmountIn to get an initial net estimate
uint256 feeGuess = 0;
@@ -296,7 +298,7 @@ contract PartyPoolMintImpl is PartyPoolBase {
// Use LMSR view to determine actual internal consumed and size-increase (ΔS) for mint
(int128 amountInInternalUsed, int128 sizeIncreaseInternal) =
LMSRStabilized.swapAmountsForMint(lmsrState.nAssets, lmsrState.kappa, lmsrState.qInternal,
LMSRStabilized.swapAmountsForMint(lmsrState.kappa, lmsrState.qInternal,
inputTokenIndex, netInternalGuess);
// amountInInternalUsed may be <= netInternalGuess. Convert to uint (ceil) to determine actual transfer
@@ -359,7 +361,7 @@ contract PartyPoolMintImpl is PartyPoolBase {
require(inputTokenIndex < n, "swapMint: idx");
require(maxAmountIn > 0, "swapMint: input zero");
require(deadline == 0 || block.timestamp <= deadline, "swapMint: deadline");
require(_lmsr.nAssets > 0, "swapMint: uninit pool");
require(_lmsr.qInternal.length > 0, "swapMint: uninit pool");
// compute fee on gross maxAmountIn to get an initial net estimate (we'll recompute based on actual used)
(, uint256 netUintGuess) = _computeFee(maxAmountIn, swapFeePpm);
@@ -467,7 +469,7 @@ contract PartyPoolMintImpl is PartyPoolBase {
.mul(ABDKMath64x64.divu(1000000-swapFeePpm, 1000000)); // adjusted for fee
// Use LMSR view to compute single-asset payout and burned size-metric
(int128 payoutInternal, ) = LMSRStabilized.swapAmountsForBurn(lmsrState.nAssets, lmsrState.kappa, lmsrState.qInternal,
(int128 payoutInternal, ) = LMSRStabilized.swapAmountsForBurn(lmsrState.kappa, lmsrState.qInternal,
outputTokenIndex, alpha);
// Convert payoutInternal -> uint (floor) to favor pool
@@ -476,7 +478,7 @@ contract PartyPoolMintImpl is PartyPoolBase {
// Compute gross payout (no swap fee) to derive token-side fee = gross - net
int128 alphaGross = ABDKMath64x64.divu(lpAmount, totalSupply_); // gross fraction (no swap fee)
(int128 payoutGrossInternal, ) = LMSRStabilized.swapAmountsForBurn(lmsrState.nAssets, lmsrState.kappa, lmsrState.qInternal,
(int128 payoutGrossInternal, ) = LMSRStabilized.swapAmountsForBurn(lmsrState.kappa, lmsrState.qInternal,
outputTokenIndex, alphaGross);
uint256 payoutGrossUint = _internalToUintFloorPure(payoutGrossInternal, bases_[outputTokenIndex]);
outFee = (payoutGrossUint > amountOut) ? (payoutGrossUint - amountOut) : 0;

View File

@@ -73,7 +73,7 @@ contract PartyPoolSwapImpl is PartyPoolBase {
) external pure returns (uint256 amountIn, uint256 amountOut, uint256 inFee) {
// Compute internal maxima at the price limit
(int128 amountInInternal, int128 amountOutInternal) = LMSRStabilized.swapAmountsForPriceLimit(
bases.length, kappa, qInternal,
kappa, qInternal,
inputTokenIndex, outputTokenIndex, limitPrice);
// Convert input to uint (ceil) and output to uint (floor)

View File

@@ -33,9 +33,10 @@ contract PartyPoolViewer is PartyPoolHelpers, IPartyPoolViewer {
/// @return price Q64.64 value equal to quote per base (p_quote / p_base)
function price(IPartyPool pool, uint256 baseTokenIndex, uint256 quoteTokenIndex) external view returns (int128) {
LMSRStabilized.State memory lmsr = pool.LMSR();
require(baseTokenIndex < lmsr.nAssets && quoteTokenIndex < lmsr.nAssets, "price: idx");
require(lmsr.nAssets > 0, "price: uninit");
return LMSRStabilized.price(lmsr.nAssets, pool.kappa(), lmsr.qInternal, baseTokenIndex, quoteTokenIndex);
uint256 nAssets = lmsr.qInternal.length;
require(nAssets > 0, "price: uninit");
require(baseTokenIndex < nAssets && quoteTokenIndex < nAssets, "price: idx");
return LMSRStabilized.price(pool.kappa(), lmsr.qInternal, baseTokenIndex, quoteTokenIndex);
}
/// @notice Price of one LP token denominated in `quote` as Q64.64.
@@ -46,11 +47,12 @@ contract PartyPoolViewer is PartyPoolHelpers, IPartyPoolViewer {
/// @return price Q64.64 value equal to quote per LP token unit
function poolPrice(IPartyPool pool, uint256 quoteTokenIndex) external view returns (int128) {
LMSRStabilized.State memory lmsr = pool.LMSR();
require(lmsr.nAssets > 0, "poolPrice: uninit");
require(quoteTokenIndex < lmsr.nAssets, "poolPrice: idx");
uint256 nAssets = lmsr.qInternal.length;
require(nAssets > 0, "poolPrice: uninit");
require(quoteTokenIndex < nAssets, "poolPrice: idx");
// price per unit of qTotal (Q64.64) from LMSR
int128 pricePerQ = LMSRStabilized.poolPrice(lmsr.nAssets, pool.kappa(), lmsr.qInternal, quoteTokenIndex);
int128 pricePerQ = LMSRStabilized.poolPrice( pool.kappa(), lmsr.qInternal, quoteTokenIndex);
// total internal q (qTotal) as Q64.64
int128 qTotal = LMSRStabilized._computeSizeMetric(lmsr.qInternal);
@@ -71,19 +73,21 @@ contract PartyPoolViewer is PartyPoolHelpers, IPartyPoolViewer {
function mintAmounts(IPartyPool pool, uint256 lpTokenAmount) public view returns (uint256[] memory depositAmounts) {
LMSRStabilized.State memory lmsr = pool.LMSR();
uint256[] memory cachedUintBalances = new uint256[](lmsr.nAssets);
for( uint256 i=0; i<lmsr.nAssets; i++ )
uint256 nAssets = lmsr.qInternal.length;
uint256[] memory cachedUintBalances = new uint256[](nAssets);
for( uint256 i=0; i<nAssets; i++ )
cachedUintBalances[i] = pool.getToken(i).balanceOf(address(pool));
return MINT_IMPL.mintAmounts(lpTokenAmount, lmsr.nAssets, pool.totalSupply(), cachedUintBalances);
return MINT_IMPL.mintAmounts(lpTokenAmount, pool.totalSupply(), cachedUintBalances);
}
function burnAmounts(IPartyPool pool, uint256 lpTokenAmount) external view returns (uint256[] memory withdrawAmounts) {
LMSRStabilized.State memory lmsr = pool.LMSR();
uint256[] memory cachedUintBalances = new uint256[](lmsr.nAssets);
for( uint256 i=0; i<lmsr.nAssets; i++ )
uint256 nAssets = lmsr.qInternal.length;
uint256[] memory cachedUintBalances = new uint256[](nAssets);
for( uint256 i=0; i<nAssets; i++ )
cachedUintBalances[i] = pool.getToken(i).balanceOf(address(pool));
return MINT_IMPL.burnAmounts(lpTokenAmount, lmsr.nAssets, pool.totalSupply(), cachedUintBalances);
return MINT_IMPL.burnAmounts(lpTokenAmount, pool.totalSupply(), cachedUintBalances);
}
@@ -99,9 +103,10 @@ contract PartyPoolViewer is PartyPoolHelpers, IPartyPoolViewer {
int128 limitPrice
) external view returns (uint256 amountIn, uint256 amountOut, uint256 inFee) {
LMSRStabilized.State memory lmsr = pool.LMSR();
require(inputTokenIndex < lmsr.nAssets && outputTokenIndex < lmsr.nAssets, "swapToLimit: idx");
uint256 nAssets = lmsr.qInternal.length;
require(inputTokenIndex < nAssets && outputTokenIndex < nAssets, "swapToLimit: idx");
require(limitPrice > int128(0), "swapToLimit: limit <= 0");
require(lmsr.nAssets > 0, "swapToLimit: pool uninitialized");
require(nAssets > 0, "swapToLimit: pool uninitialized");
return SWAP_IMPL.swapToLimitAmounts(
inputTokenIndex, outputTokenIndex, limitPrice,
@@ -143,8 +148,9 @@ contract PartyPoolViewer is PartyPoolHelpers, IPartyPoolViewer {
function flashRepaymentAmounts(IPartyPool pool, uint256[] memory loanAmounts) external view
returns (uint256[] memory repaymentAmounts) {
LMSRStabilized.State memory lmsr = pool.LMSR();
repaymentAmounts = new uint256[](lmsr.nAssets);
for (uint256 i = 0; i < lmsr.nAssets; i++) {
uint256 nAssets = lmsr.qInternal.length;
repaymentAmounts = new uint256[](nAssets);
for (uint256 i = 0; i < nAssets; i++) {
uint256 amount = loanAmounts[i];
if (amount > 0) {
repaymentAmounts[i] = amount + _ceilFee(amount, pool.flashFeePpm());

View File

@@ -192,7 +192,7 @@ contract LMSRStabilizedTest is Test {
initAlmostBalanced();
// Verify basic state is still functional
assertTrue(s.nAssets > 0, "State should still be initialized");
assertTrue(s.qInternal.length > 0, "State should still be initialized");
assertTrue(s.kappa > int128(0), "Kappa should still be positive");
}
@@ -213,9 +213,10 @@ contract LMSRStabilizedTest is Test {
int128 initialB = _computeB(initialQ);
int128 initialKappa = s.kappa;
uint256 nAssets = s.qInternal.length;
// Simulate a deposit by increasing all asset quantities by 50%
int128[] memory newQ = new int128[](s.nAssets);
for (uint i = 0; i < s.nAssets; i++) {
int128[] memory newQ = new int128[](nAssets);
for (uint i = 0; i < nAssets; i++) {
// Increase by 50%
newQ[i] = initialQ[i].mul(ABDKMath64x64.fromUInt(3).div(ABDKMath64x64.fromUInt(2))); // 1.5x
}
@@ -362,8 +363,9 @@ contract LMSRStabilizedTest is Test {
int128 initialKappa = s.kappa;
// Simulate a withdrawal by decreasing all asset quantities by 30%
int128[] memory newQ = new int128[](s.nAssets);
for (uint i = 0; i < s.nAssets; i++) {
uint256 nAssets = s.qInternal.length;
int128[] memory newQ = new int128[](nAssets);
for (uint i = 0; i < nAssets; i++) {
// Decrease by 30%
newQ[i] = initialQ[i].mul(ABDKMath64x64.fromUInt(7).div(ABDKMath64x64.fromUInt(10))); // 0.7x
}
@@ -408,7 +410,7 @@ contract LMSRStabilizedTest is Test {
function testRecenterShiftTooLargeReverts() public {
initAlmostBalanced();
// Recentering has been removed, so this test now just verifies basic functionality
assertTrue(s.nAssets > 0, "State should still be initialized");
assertTrue(s.qInternal.length > 0, "State should still be initialized");
}
/// @notice limitPrice <= current price should revert (no partial fill)
@@ -431,25 +433,6 @@ contract LMSRStabilizedTest is Test {
this.externalSwapAmountsForExactInput(0, 1, tradeAmount, ABDKMath64x64.fromInt(1));
}
/// @notice If e_j == 0 we should revert early to avoid div-by-zero
function testEJZeroReverts() public {
initBalanced();
// Create mock qInternal where asset 1 has zero quantity
int128[] memory mockQInternal = new int128[](3);
mockQInternal[0] = ABDKMath64x64.fromUInt(1_000_000);
mockQInternal[1] = int128(0); // Zero quantity for asset 1
mockQInternal[2] = ABDKMath64x64.fromUInt(1_000_000);
// Update the state's cached qInternal
_updateCachedQInternal(mockQInternal);
int128 tradeAmount = mockQInternal[0].mul(stdTradeSize);
vm.expectRevert(bytes("LMSR: e_j==0"));
this.externalSwapAmountsForExactInput(0, 1, tradeAmount, 0);
}
/// @notice swapAmountsForPriceLimit returns zero if limit equals current price
function testSwapAmountsForPriceLimitZeroWhenLimitEqualsPrice() public {
initBalanced();
@@ -693,7 +676,8 @@ contract LMSRStabilizedTest is Test {
initBalanced();
// Create initial quantities
int128[] memory initialQValues = new int128[](s.nAssets);
uint256 nAssets = s.qInternal.length;
int128[] memory initialQValues = new int128[](nAssets);
initialQValues[0] = ABDKMath64x64.fromUInt(1_000_000);
initialQValues[1] = ABDKMath64x64.fromUInt(1_000_000);
initialQValues[2] = ABDKMath64x64.fromUInt(1_000_000);
@@ -705,8 +689,8 @@ contract LMSRStabilizedTest is Test {
int128 directSwapAmount = initialQValues[0].mul(stdTradeSize);
// Store a backup of the original values to restore between swaps
int128[] memory backupQ = new int128[](s.nAssets);
for (uint i = 0; i < s.nAssets; i++) {
int128[] memory backupQ = new int128[](nAssets);
for (uint i = 0; i < nAssets; i++) {
backupQ[i] = s.qInternal[i];
}
@@ -798,8 +782,9 @@ contract LMSRStabilizedTest is Test {
int128 tradeAmount1 = s.qInternal[1].mul(tradeSize);
// Store original state to restore between tests
int128[] memory backupQ = new int128[](s.nAssets);
for (uint i = 0; i < s.nAssets; i++) {
uint256 nAssets = s.qInternal.length;
int128[] memory backupQ = new int128[](nAssets);
for (uint i = 0; i < nAssets; i++) {
backupQ[i] = s.qInternal[i];
}