additive fees; burnSwapAmounts fix

This commit is contained in:
tim
2025-11-04 16:58:16 -04:00
parent 590acdd4dc
commit dc2e186331
10 changed files with 103 additions and 100 deletions

24
doc/launch_list.md Normal file
View File

@@ -0,0 +1,24 @@
| Symbol | Address |
|-----------------|----------------------------------------------|
| **Stablecoins** | |
| USDT | `0xdAC17F958D2ee523a2206206994597C13D831ec7` |
| USDC | `0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48` |
| USDe | `0x4c9EDD5852cd905f086C759E8383e09bff1E68B3` |
| DAI | `0x6B175474E89094C44Da98b954EedeAC495271d0F` |
| **Chain Coins** | |
| WETH | `0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2` |
| WBTC | `0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599` |
| WSOL | `0xd1D82d3Ab815E0B47e38EC2d666c5b8AA05Ae501` |
| BNB | `0xB8c77482e45F1F44dE1745F52C74426C631bDD52` |
| TRX | `0x50327c6c5a14DCaDE707ABad2E27eB517df87AB5` |
| POL | `0x455e53CBB86018Ac2B8092FdCd39d8444aFFC3F6` |
| DOT | `0x21c2c96Dbfa137E23946143c71AC8330F9B44001` |
| NEAR | `0x85F17Cf997934a597031b2E18a9aB6ebD4B9f6a4` |
| **Others** | |
| WBETH | `0xa2E3356610840701BDf5611a53974510Ae27E2e1` |
| ARB | `0xB50721BCf8d664c30412Cfbc6cf7a15145234ad1` |
| UNI | `0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984` |
| LINK | `0x514910771AF9Ca656af840dff83E8264EcF986CA` |
| AAVE | `0x7Fc66500c84A76Ad7e9c93437bFc5Ac33E2DDaE9` |
| PEPE | `0x6982508145454Ce325dDbE47a25d4ec3d2311933` |
| SHIB | `0x95aD61b0a150d79219dCF64E1E6Cc01f0B64C4cE` |

View File

@@ -117,20 +117,19 @@ if __name__ == "__main__":
if alerts:
log.warning("Some fee configuration may produce large values (bps): %s", alerts)
print("\nPair fees [per-asset fee -> total]:")
# Per-asset diagnostic: show per-asset fee (interpreted vs USDC)
for n, w in weights.items():
f_token = per_asset_fee(w)
print(f"{n:>12} {bps(f_token):>12}")
print()
for (name_a, w_a), (name_b, w_b) in combinations(weights.items(), 2):
f_eff_ab, f_i_ab, f_j_ab = fee_for_pair(w_a, w_b)
print(
f"{name_a}/{name_b}: per-asset_in={bps(f_i_ab)}, per-asset_out={bps(f_j_ab)}, total={bps(f_eff_ab)}"
f"{name_a+'-'+name_b:>12} {bps(f_eff_ab):>12}"
)
# Per-asset diagnostic: show per-asset fee (interpreted vs USDC)
print("\nPer-asset diagnostics (fees interpreted vs USDC):")
for n, w in weights.items():
f_token = per_asset_fee(w)
print(f"{n}: target_vs_USDC={w:.6f} bps, per_asset_fee={bps(f_token)}")
# -- Solidity (ABDK Q64.64) output --
# Print derived per-asset fees and cap as Solidity int128 Q64.64 constants that can be pasted
# into a Solidity file using ABDK's 64.64 fixed-point representation (int128 constants).

View File

@@ -240,7 +240,8 @@ interface IPartyPool is IERC20Metadata, IOwnable {
/// @param lpAmount amount of LP tokens to burn
/// @param outputTokenIndex index of target asset to receive
/// @param deadline optional deadline
/// @return amountOutUint uint amount of asset outputTokenIndex sent to receiver
/// @return amountOut uint amount of asset outputTokenIndex sent to receiver
/// @return outFee uint amount of output asset kept by the LP's and protocol as a fee
function burnSwap(
address payer,
address receiver,
@@ -248,7 +249,7 @@ interface IPartyPool is IERC20Metadata, IOwnable {
uint256 outputTokenIndex,
uint256 deadline,
bool unwrap
) external returns (uint256 amountOutUint);
) external returns (uint256 amountOut, uint256 outFee);
/// @dev Initiate a flash loan.
/// @param receiver The receiver of the tokens in the loan, and the receiver of the callback.

View File

@@ -519,7 +519,7 @@ library LMSRStabilized {
State storage s,
uint256 i,
int128 alpha
) internal view returns (int128 amountOut, int128 amountIn) {
) internal view returns (int128 amountIn, int128 amountOut) {
return swapAmountsForBurn(s.kappa, s.qInternal, i, alpha);
}
@@ -536,14 +536,14 @@ library LMSRStabilized {
/// @param qInternal Cached internal balances in 64.64 fixed-point format
/// @param i Index of output asset
/// @param alpha Proportional share to burn (0 < alpha <= 1)
/// @return amountOut Amount of asset i received (in 64.64 fixed-point)
/// @return amountIn LP size-metric redeemed (alpha * S)
/// @return amountOut Amount of asset i received (in 64.64 fixed-point)
function swapAmountsForBurn(
int128 kappa,
int128[] memory qInternal,
uint256 i,
int128 alpha
) internal pure returns (int128 amountOut, int128 amountIn) {
) internal pure returns (int128 amountIn, int128 amountOut) {
require(alpha > int128(0) && alpha <= ONE, "LMSR: alpha");
int128 sizeMetric = _computeSizeMetric(qInternal);
@@ -566,10 +566,10 @@ library LMSRStabilized {
}
// Start totalOut with direct portion of asset i redeemed
int128 totalOut = alpha.mul(qInternal[i]);
amountOut = alpha.mul(qInternal[i]);
// Track whether any non-zero contribution was produced
bool anyNonZero = (totalOut > int128(0));
bool anyNonZero = (amountOut > int128(0));
// For each asset j != i, swap the withdrawn a_j := alpha * q_j into i
for (uint256 j = 0; j < n; ) {
@@ -621,7 +621,7 @@ library LMSRStabilized {
// Update q_local: pool receives amountInUsed on asset j, and loses qLocal[i]
qLocal[j] = qLocal[j].add(amountInUsed);
// subtract capped output from qLocal[i] (becomes zero)
totalOut = totalOut.add(qLocal[i]);
amountOut = amountOut.add(qLocal[i]);
qLocal[i] = int128(0);
anyNonZero = true;
unchecked { j++; }
@@ -632,7 +632,7 @@ library LMSRStabilized {
// Update q_local accordingly: pool receives aj on j, and loses y on i
qLocal[j] = qLocal[j].add(aj);
qLocal[i] = qLocal[i].sub(y);
totalOut = totalOut.add(y);
amountOut = amountOut.add(y);
anyNonZero = true;
}
}
@@ -640,12 +640,9 @@ library LMSRStabilized {
}
// If no asset contributed (totalOut == 0) treat as no-trade and revert
if (!anyNonZero || totalOut <= int128(0)) {
if (!anyNonZero || amountOut <= int128(0)) {
revert("LMSR: zero output");
}
amountOut = totalOut;
return (amountOut, amountIn);
}

View File

@@ -408,14 +408,7 @@ contract PartyPool is PartyPoolBase, OwnableExternal, ERC20External, IPartyPool
return abi.decode(result, (uint256, uint256, uint256));
}
/// @notice Burn LP _tokens then swap the redeemed proportional basket into a single asset `inputTokenIndex` and send to receiver.
/// @dev This function forwards the call to the burnSwap implementation via delegatecall
/// @param payer who burns LP _tokens
/// @param receiver who receives the single asset
/// @param lpAmount amount of LP _tokens to burn
/// @param outputTokenIndex index of target asset to receive
/// @param deadline optional deadline
/// @return amountOutUint uint amount of asset i sent to receiver
/// @inheritdoc IPartyPool
function burnSwap(
address payer,
address receiver,
@@ -423,7 +416,7 @@ contract PartyPool is PartyPoolBase, OwnableExternal, ERC20External, IPartyPool
uint256 outputTokenIndex,
uint256 deadline,
bool unwrap
) external returns (uint256 amountOutUint) {
) external returns (uint256 amountOut, uint256 outFee) {
bytes memory data = abi.encodeWithSelector(
PartyPoolMintImpl.burnSwap.selector,
payer,
@@ -437,7 +430,7 @@ contract PartyPool is PartyPoolBase, OwnableExternal, ERC20External, IPartyPool
);
bytes memory result = Address.functionDelegateCall(address(MINT_IMPL), data);
return abi.decode(result, (uint256));
return abi.decode(result, (uint256,uint256 ));
}

View File

@@ -96,7 +96,10 @@ abstract contract PartyPoolBase is OwnableInternal, ERC20Internal, ReentrancyGua
function _pairFeePpmView(uint256 i, uint256 j) internal view returns (uint256) {
uint256 fi = _fees[i];
uint256 fj = _fees[j];
return fi + fj - fi * fj / 1_000_000;
// multiplicative combination, while mathematically correct, is more confusing to users
// return fi + fj - fi * fj / 1_000_000;
// additive fees are easy to understand and very very close to the multiplicative combination.
return fi + fj;
}
function _pairFeePpm(uint256 i, uint256 j) internal returns (uint256 fee) {

View File

@@ -269,7 +269,7 @@ contract PartyPoolMintImpl is PartyPoolBase {
/// @param lmsrState current LMSR state
/// @param bases_ scaling _bases for each token
/// @param totalSupply_ current total LP token supply
/// @return amountInUsed actual input amount used (excluding fee)
/// @return amountIn actual input amount used (excluding fee)
/// @return lpMinted LP tokens that would be minted
/// @return inFee fee amount charged
function swapMintAmounts(
@@ -279,7 +279,7 @@ contract PartyPoolMintImpl is PartyPoolBase {
LMSRStabilized.State memory lmsrState,
uint256[] memory bases_,
uint256 totalSupply_
) public pure returns (uint256 amountInUsed, uint256 lpMinted, uint256 inFee) {
) public pure returns (uint256 amountIn, uint256 lpMinted, uint256 inFee) {
require(inputTokenIndex < bases_.length, "swapMintAmounts: idx");
require(maxAmountIn > 0, "swapMintAmounts: input zero");
require(lmsrState.qInternal.length > 0, "swapMintAmounts: uninit pool");
@@ -302,7 +302,7 @@ contract PartyPoolMintImpl is PartyPoolBase {
inputTokenIndex, netInternalGuess);
// amountInInternalUsed may be <= netInternalGuess. Convert to uint (ceil) to determine actual transfer
amountInUsed = _internalToUintCeilPure(amountInInternalUsed, bases_[inputTokenIndex]);
uint256 amountInUsed = _internalToUintCeilPure(amountInInternalUsed, bases_[inputTokenIndex]);
require(amountInUsed > 0, "swapMintAmounts: input zero after internal conversion");
// Compute fee on the actual used input (ceiling)
@@ -310,8 +310,8 @@ contract PartyPoolMintImpl is PartyPoolBase {
if (swapFeePpm > 0) {
inFee = (amountInUsed * swapFeePpm + 999999) / 1000000; // ceil fee
}
uint256 totalTransfer = amountInUsed + inFee;
require(totalTransfer > 0 && totalTransfer <= maxAmountIn, "swapMintAmounts: transfer exceeds max");
amountIn = amountInUsed + inFee;
require(amountIn > 0 && amountIn <= maxAmountIn, "swapMintAmounts: transfer exceeds max");
// Compute old and new scaled size metrics to determine LP minted
int128 oldTotal = _computeSizeMetricPure(lmsrState.qInternal);
@@ -347,7 +347,7 @@ contract PartyPoolMintImpl is PartyPoolBase {
/// @param maxAmountIn maximum uint token input (inclusive of fee)
/// @param deadline optional deadline
/// @param swapFeePpm fee in parts-per-million for this pool
/// @return amountInUsed actual input used (uint256), lpMinted actual LP minted (uint256), inFee fee taken from the input (uint256)
/// @return amountIn actual input used (uint256), lpMinted actual LP minted (uint256), inFee fee taken from the input (uint256)
function swapMint(
address payer,
address receiver,
@@ -356,7 +356,7 @@ contract PartyPoolMintImpl is PartyPoolBase {
uint256 deadline,
uint256 swapFeePpm,
uint256 protocolFeePpm
) external payable native killable nonReentrant returns (uint256 amountInUsed, uint256 lpMinted, uint256 inFee) {
) external payable native killable nonReentrant returns (uint256 amountIn, uint256 lpMinted, uint256 inFee) {
uint256 n = _tokens.length;
require(inputTokenIndex < n, "swapMint: idx");
require(maxAmountIn > 0, "swapMint: input zero");
@@ -374,27 +374,27 @@ contract PartyPoolMintImpl is PartyPoolBase {
(int128 amountInInternalUsed, int128 sizeIncreaseInternal) = _lmsr.swapAmountsForMint(inputTokenIndex, netInternalGuess);
// amountInInternalUsed may be <= netInternalGuess. Convert to uint (ceil) to determine actual transfer
uint256 amountInUint = _internalToUintCeil(amountInInternalUsed, _bases[inputTokenIndex]);
require(amountInUint > 0, "swapMint: input zero after internal conversion");
uint256 amountInUsed = _internalToUintCeil(amountInInternalUsed, _bases[inputTokenIndex]);
require(amountInUsed > 0, "swapMint: input zero after internal conversion");
// Compute fee on the actual used input and total transfer amount (ceiling)
uint256 feeUintActual = _ceilFee(amountInUint, swapFeePpm);
uint256 totalTransfer = amountInUint + feeUintActual;
require(totalTransfer > 0 && totalTransfer <= maxAmountIn, "swapMint: transfer exceeds max");
inFee = _ceilFee(amountInUsed, swapFeePpm);
amountIn = amountInUsed + inFee;
require(amountIn > 0 && amountIn <= maxAmountIn, "swapMint: transfer exceeds max");
// Transfer _tokens from payer (assume standard ERC20 without transfer fees) via helper
_receiveTokenFrom(payer, _tokens[inputTokenIndex], totalTransfer);
_receiveTokenFrom(payer, _tokens[inputTokenIndex], amountIn);
// Accrue protocol share (floor) from the fee on the input token
uint256 protoShare = 0;
if (protocolFeePpm > 0 && feeUintActual > 0) {
protoShare = (feeUintActual * protocolFeePpm) / 1_000_000;
if (protocolFeePpm > 0 && inFee > 0) {
protoShare = (inFee * protocolFeePpm) / 1_000_000;
if (protoShare > 0) {
_protocolFeesOwed[inputTokenIndex] += protoShare;
}
}
// Update cached effective balance directly: add totalTransfer minus protocol share
_cachedUintBalances[inputTokenIndex] += (totalTransfer - protoShare);
_cachedUintBalances[inputTokenIndex] += (amountIn - protoShare);
// Compute old and new scaled size metrics to determine LP minted
int128 oldTotal = _computeSizeMetric(_lmsr.qInternal);
@@ -403,23 +403,22 @@ contract PartyPoolMintImpl is PartyPoolBase {
int128 newTotal = oldTotal.add(sizeIncreaseInternal);
uint256 newScaled = ABDKMath64x64.mulu(newTotal, LP_SCALE);
uint256 actualLpToMint;
// Use natural ERC20 function since base contract inherits from ERC20
uint256 currentSupply = _totalSupply;
if (currentSupply == 0) {
// If somehow supply zero (shouldn't happen as _lmsr.nAssets>0), mint newScaled
actualLpToMint = newScaled;
lpMinted = newScaled;
} else {
uint256 delta = (newScaled > oldScaled) ? (newScaled - oldScaled) : 0;
if (delta > 0) {
// floor truncation rounds in favor of pool
actualLpToMint = (currentSupply * delta) / oldScaled;
lpMinted = (currentSupply * delta) / oldScaled;
} else {
actualLpToMint = 0;
lpMinted = 0;
}
}
require(actualLpToMint > 0, "swapMint: zero LP minted");
require(lpMinted > 0, "swapMint: zero LP minted");
// Update LMSR internal state: scale qInternal proportionally by newTotal/oldTotal
int128[] memory newQInternal = new int128[](n);
@@ -432,14 +431,11 @@ contract PartyPoolMintImpl is PartyPoolBase {
_lmsr.updateForProportionalChange(newQInternal);
// Use natural ERC20 function since base contract inherits from ERC20
_mint(receiver, actualLpToMint);
_mint(receiver, lpMinted);
emit IPartyPool.SwapMint(payer, receiver, _tokens[inputTokenIndex],
totalTransfer, actualLpToMint, feeUintActual-protoShare, protoShare);
amountIn, lpMinted, inFee -protoShare, protoShare);
amountInUsed = amountInUint;
lpMinted = actualLpToMint;
inFee = feeUintActual;
return (amountInUsed, lpMinted, inFee);
}
@@ -465,23 +461,17 @@ contract PartyPoolMintImpl is PartyPoolBase {
require(totalSupply_ > 0, "burnSwapAmounts: empty supply");
// alpha = lpAmount / supply as Q64.64
int128 alpha = ABDKMath64x64.divu(lpAmount, totalSupply_) // fraction of total supply to burn
.mul(ABDKMath64x64.divu(1000000-swapFeePpm, 1000000)); // adjusted for fee
int128 alpha = ABDKMath64x64.divu(lpAmount, totalSupply_);
// Use LMSR view to compute single-asset payout and burned size-metric
(int128 payoutInternal, ) = LMSRStabilized.swapAmountsForBurn(lmsrState.kappa, lmsrState.qInternal,
(, int128 payoutInternal) = LMSRStabilized.swapAmountsForBurn(lmsrState.kappa, lmsrState.qInternal,
outputTokenIndex, alpha);
// Convert payoutInternal -> uint (floor) to favor pool
amountOut = _internalToUintFloorPure(payoutInternal, bases_[outputTokenIndex]);
require(amountOut > 0, "burnSwapAmounts: output zero");
// 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.kappa, lmsrState.qInternal,
outputTokenIndex, alphaGross);
uint256 payoutGrossUint = _internalToUintFloorPure(payoutGrossInternal, bases_[outputTokenIndex]);
outFee = (payoutGrossUint > amountOut) ? (payoutGrossUint - amountOut) : 0;
uint256 grossAmountOut = _internalToUintFloorPure(payoutInternal, bases_[outputTokenIndex]);
(outFee,) = _computeFee(grossAmountOut, swapFeePpm);
require(grossAmountOut > outFee, "burnSwapAmounts: output zero");
amountOut = grossAmountOut - outFee;
}
/// @notice Burn LP _tokens then swap the redeemed proportional basket into a single asset `outputTokenIndex` and send to receiver.
@@ -494,7 +484,8 @@ contract PartyPoolMintImpl is PartyPoolBase {
/// @param outputTokenIndex index of target asset to receive
/// @param deadline optional deadline
/// @param swapFeePpm fee in parts-per-million for this pool (may be used for future fee logic)
/// @return amountOutUint uint amount of asset i sent to receiver
/// @return amountOut uint amount of asset i sent to receiver
/// @return outFee uint amount of asset i kept as an LP and protocol fee
function burnSwap(
address payer,
address receiver,
@@ -504,7 +495,7 @@ contract PartyPoolMintImpl is PartyPoolBase {
bool unwrap,
uint256 swapFeePpm,
uint256 protocolFeePpm
) external nonReentrant killable returns (uint256 amountOutUint) {
) external nonReentrant killable returns (uint256 amountOut, uint256 outFee) {
uint256 n = _tokens.length;
require(outputTokenIndex < n, "burnSwap: idx");
require(lpAmount > 0, "burnSwap: zero lp");
@@ -514,35 +505,26 @@ contract PartyPoolMintImpl is PartyPoolBase {
require(supply > 0, "burnSwap: empty supply");
// alpha = lpAmount / supply as Q64.64 (adjusted for fee)
int128 alpha = ABDKMath64x64.divu(lpAmount, supply) // fraction of total supply to burn
.mul(ABDKMath64x64.divu(1000000-swapFeePpm, 1000000)); // adjusted for fee
int128 alpha = ABDKMath64x64.divu(lpAmount, supply); // fraction of total supply to burn
// Use LMSR view to compute single-asset payout and burned size-metric
(int128 payoutInternal, ) = _lmsr.swapAmountsForBurn(outputTokenIndex, alpha);
(, int128 payoutInternal) = _lmsr.swapAmountsForBurn(outputTokenIndex, alpha);
// Convert payoutInternal -> uint (floor) to favor pool
amountOutUint = _internalToUintFloor(payoutInternal, _bases[outputTokenIndex]);
require(amountOutUint > 0, "burnSwap: output zero");
// Compute gross payout (no swap fee) so we can determine token-side fee = gross - net
int128 alphaGross = ABDKMath64x64.divu(lpAmount, supply); // gross fraction (no swap fee)
(int128 payoutGrossInternal, ) = _lmsr.swapAmountsForBurn(outputTokenIndex, alphaGross);
uint256 payoutGrossUint = _internalToUintFloor(payoutGrossInternal, _bases[outputTokenIndex]);
uint256 feeTokenUint = (payoutGrossUint > amountOutUint) ? (payoutGrossUint - amountOutUint) : 0;
uint256 payoutGrossUint = _internalToUintFloorPure(payoutInternal, _bases[outputTokenIndex]);
(outFee,) = _computeFee(payoutGrossUint, swapFeePpm);
require(payoutGrossUint > outFee, "burnSwapAmounts: output zero");
amountOut = payoutGrossUint - outFee;
// Accrue protocol share (floor) from the token-side fee
uint256 protoShare = 0;
if (protocolFeePpm > 0 && feeTokenUint > 0) {
protoShare = (feeTokenUint * protocolFeePpm) / 1_000_000;
if (protocolFeePpm > 0 && outFee > 0) {
protoShare = (outFee * protocolFeePpm) / 1_000_000;
if (protoShare > 0) {
_protocolFeesOwed[outputTokenIndex] += protoShare;
}
}
// Transfer the payout to receiver via centralized helper
IERC20 outputToken = _tokens[outputTokenIndex];
_sendTokenTo(outputToken, receiver, amountOutUint, unwrap);
// Burn LP _tokens from payer (authorization via allowance)
if (msg.sender != payer) {
uint256 allowed = _allowances[payer][msg.sender];
@@ -550,13 +532,19 @@ contract PartyPoolMintImpl is PartyPoolBase {
}
_burn(payer, lpAmount);
// Transfer the payout to receiver via centralized helper
IERC20 outputToken = _tokens[outputTokenIndex];
_sendTokenTo(outputToken, receiver, amountOut, unwrap);
// Update cached balances using computed payout and protocol fee; no on-chain reads
int128[] memory newQInternal = new int128[](n);
for (uint256 idx = 0; idx < n; idx++) {
uint256 newBal = _cachedUintBalances[idx];
if (idx == outputTokenIndex) {
// Effective LP balance decreases by net payout and increased protocol owed
newBal = newBal - amountOutUint - protoShare;
newBal = newBal - amountOut - protoShare;
}
_cachedUintBalances[idx] = newBal;
newQInternal[idx] = _uintToInternalFloor(newBal, _bases[idx]);
@@ -573,10 +561,8 @@ contract PartyPoolMintImpl is PartyPoolBase {
_lmsr.updateForProportionalChange(newQInternal);
}
emit IPartyPool.BurnSwap(payer, receiver, outputToken, lpAmount, amountOutUint,
feeTokenUint-protoShare, protoShare);
return amountOutUint;
emit IPartyPool.BurnSwap(payer, receiver, outputToken, lpAmount, amountOut,
outFee-protoShare, protoShare);
}
/// @notice Pure version of _uintToInternalFloor for use in view functions

View File

@@ -900,7 +900,7 @@ contract LMSRStabilizedTest is Test {
int128 alpha = ABDKMath64x64.divu(1, 100); // 1%
int128 S = _computeSizeMetric(s.qInternal);
(int128 payout, int128 burned) = s.swapAmountsForBurn(0, alpha);
(int128 burned, int128 payout) = s.swapAmountsForBurn(0, alpha);
// burned should equal alpha * S
assertEq(burned, alpha.mul(S), "burned size-metric mismatch");
@@ -921,7 +921,7 @@ contract LMSRStabilizedTest is Test {
_updateCachedQInternal(mockQInternal);
int128 alpha = ABDKMath64x64.divu(1, 100); // 1%
(int128 payout, int128 burned) = s.swapAmountsForBurn(0, alpha);
(int128 burned, int128 payout) = s.swapAmountsForBurn(0, alpha);
// Should still burn the size metric
int128 S = _computeSizeMetric(mockQInternal);

View File

@@ -484,7 +484,7 @@ contract NativeTest is Test {
uint256 thisEthBefore = address(this).balance;
// Burn LP and receive all proceeds as native currency (WETH unwrapped)
uint256 payout = pool.burnSwap(
(uint256 payout, ) = pool.burnSwap(
address(this), // payer (holds LP)
address(this), // receiver
lpToBurn, // lpAmount
@@ -506,7 +506,7 @@ contract NativeTest is Test {
uint256 bobEthBefore = bob.balance;
// Burn LP and send native currency to bob
uint256 payout = pool.burnSwap(
(uint256 payout, ) = pool.burnSwap(
address(this), // payer
bob, // receiver
lpToBurn,
@@ -555,7 +555,7 @@ contract NativeTest is Test {
// 4. Burn LP to native currency
uint256 lpToBurn = lpMinted / 2;
uint256 payout = pool.burnSwap(alice, alice, lpToBurn, 2, 0, true);
(uint256 payout, ) = pool.burnSwap(alice, alice, lpToBurn, 2, 0, true);
assertTrue(payout > 0, "Should receive payout in native");
// Alice should have some ETH back (maybe more or less depending on slippage)

View File

@@ -784,7 +784,7 @@ contract PartyPoolTest is Test {
uint256 bobBefore = token0.balanceOf(bob);
// Call burnSwap where this contract is the payer (it holds initial LP from setUp)
uint256 payout = pool.burnSwap(address(this), bob, lpToBurn, target, 0, false);
(uint256 payout, ) = pool.burnSwap(address(this), bob, lpToBurn, target, 0, false);
// Payout must be > 0
assertTrue(payout > 0, "burnSwap should produce a payout");