From 538f778f516c1908d1f0207149787d758dd57e44 Mon Sep 17 00:00:00 2001 From: tim Date: Tue, 21 Oct 2025 14:42:40 -0400 Subject: [PATCH] event changes: SwapMint/BurnSwap replace rather than augment the regular Mint/Burn events; All swapping events have lpFee and protocolFee --- src/IPartyPool.sol | 38 +++++++++++++++++++++++++++----------- src/PartyPool.sol | 12 +++++++++--- src/PartyPoolMintImpl.sol | 18 +++++++----------- src/PartyPoolSwapImpl.sol | 17 +++++++++++------ 4 files changed, 54 insertions(+), 31 deletions(-) diff --git a/src/IPartyPool.sol b/src/IPartyPool.sol index a8bc3f1..29ea18d 100644 --- a/src/IPartyPool.sol +++ b/src/IPartyPool.sol @@ -38,29 +38,45 @@ interface IPartyPool is IERC20Metadata, IOwnable { IERC20 indexed tokenIn, IERC20 indexed tokenOut, uint256 amountIn, - uint256 amountOut + uint256 amountOut, + uint256 lpFee, + uint256 protocolFee ); - /// @notice Emitted when a single-token swapMint is executed. - /// Records payer/receiver, input token index, gross transfer (net+fee), net input and fee taken. + /// @notice Emitted instead of Swap when a single-token swapMint is executed. event SwapMint( address indexed payer, address indexed receiver, - uint256 indexed inputTokenIndex, - uint256 grossTransfer, // total _tokens transferred (net + fee) - uint256 netInput, // net input credited to swaps (after fee) - uint256 feeTaken // fee taken (ceil) + IERC20 indexed tokenIn, + uint256 amountIn, + uint256 amountOut, + uint256 lpFee, // taken from the input token + uint256 protocolFee // taken from the input token ); - /// @notice Emitted when a burnSwap is executed. - /// Records payer/receiver, target token index and the uint payout sent to the receiver. + /// @notice Emitted instead of Burn when a burnSwap is executed. event BurnSwap( address indexed payer, address indexed receiver, - uint256 indexed targetTokenIndex, - uint256 payoutUint + IERC20 indexed tokenOut, + uint256 amountIn, + uint256 amountOut, + uint256 lpFee, + uint256 protocolFee ); + event Flash( + address indexed initiator, + IERC3156FlashBorrower indexed receiver, + IERC20 indexed token, + uint256 amount, + uint256 lpFee, + uint256 protocolFee + ); + + /// @notice Emitted when protocol fees are collected from this pool. + /// @dev After collection, the protocolFee accounting array will be zeroed out. + event ProtocolFeesCollected(); function LMSR() external view returns (LMSRStabilized.State memory); diff --git a/src/PartyPool.sol b/src/PartyPool.sol index 81cf726..75c389c 100644 --- a/src/PartyPool.sol +++ b/src/PartyPool.sol @@ -19,6 +19,7 @@ import {SafeERC20} from "../lib/openzeppelin-contracts/contracts/token/ERC20/uti import {IERC3156FlashLender} from "../lib/openzeppelin-contracts/contracts/interfaces/IERC3156FlashLender.sol"; import {NativeWrapper} from "./NativeWrapper.sol"; import {OwnableExternal} from "./OwnableExternal.sol"; +import {IPartyPoolViewer} from "./IPartyPoolViewer.sol"; /// @title PartyPool - LMSR-backed multi-asset pool with LP ERC20 token /// @notice A multi-asset liquidity pool backed by the LMSRStabilized pricing model. @@ -259,8 +260,9 @@ contract PartyPool is PartyPoolBase, OwnableExternal, ERC20External, IPartyPool uint256 balJAfter = _cachedUintBalances[outputTokenIndex] + _protocolFeesOwed[outputTokenIndex] - amountOutUint; // Accrue protocol share (floor) from the fee on input token + uint256 protoShare = 0; if (PROTOCOL_FEE_PPM > 0 && feeUint > 0) { - uint256 protoShare = (feeUint * PROTOCOL_FEE_PPM) / 1_000_000; // floor + protoShare = (feeUint * PROTOCOL_FEE_PPM) / 1_000_000; // floor if (protoShare > 0) { _protocolFeesOwed[inputTokenIndex] += protoShare; } @@ -279,7 +281,8 @@ contract PartyPool is PartyPoolBase, OwnableExternal, ERC20External, IPartyPool // Transfer output to receiver near the end _sendTokenTo(tokenOut, receiver, amountOutUint, unwrap); - emit Swap(payer, receiver, tokenIn, tokenOut, totalTransferAmount, amountOutUint); + emit Swap(payer, receiver, tokenIn, tokenOut, totalTransferAmount, + amountOutUint, feeUint - protoShare, protoShare); return (totalTransferAmount, amountOutUint, feeUint); } @@ -450,8 +453,9 @@ contract PartyPool is PartyPoolBase, OwnableExternal, ERC20External, IPartyPool (uint256 fee, ) = _computeFee(amount, FLASH_FEE_PPM); // Compute protocol share of flash fee + uint256 protoShare = 0; if (PROTOCOL_FEE_PPM > 0 && fee > 0) { - uint256 protoShare = (fee * PROTOCOL_FEE_PPM) / 1_000_000; // floor + protoShare = (fee * PROTOCOL_FEE_PPM) / 1_000_000; // floor if (protoShare > 0) { _protocolFeesOwed[tokenIndex] += protoShare; } @@ -467,6 +471,8 @@ contract PartyPool is PartyPoolBase, OwnableExternal, ERC20External, IPartyPool require(balAfter >= _protocolFeesOwed[tokenIndex], "balance < protocol owed"); _cachedUintBalances[tokenIndex] = balAfter - _protocolFeesOwed[tokenIndex]; + emit Flash(msg.sender, receiver, token, amount, fee-protoShare, protoShare); + return true; } diff --git a/src/PartyPoolMintImpl.sol b/src/PartyPoolMintImpl.sol index 49ff74c..121432e 100644 --- a/src/PartyPoolMintImpl.sol +++ b/src/PartyPoolMintImpl.sol @@ -424,12 +424,8 @@ contract PartyPoolMintImpl is PartyPoolBase { // Use natural ERC20 function since base contract inherits from ERC20 _mint(receiver, actualLpToMint); - // Emit SwapMint event with gross transfer, net input and fee (planned exact-in) - emit IPartyPool.SwapMint(payer, receiver, inputTokenIndex, totalTransfer, amountInUint, feeUintActual); - - // Emit standard Mint event which records deposit amounts and LP minted - emit IPartyPool.Mint(payer, receiver, new uint256[](n), actualLpToMint); - // Note: depositAmounts array omitted (empty) since swapMint uses single-token input + emit IPartyPool.SwapMint(payer, receiver, _tokens[inputTokenIndex], + totalTransfer, actualLpToMint, feeUintActual-protoShare, protoShare); return actualLpToMint; } @@ -524,7 +520,8 @@ contract PartyPoolMintImpl is PartyPoolBase { } // Transfer the payout to receiver via centralized helper - _sendTokenTo(_tokens[inputTokenIndex], receiver, amountOutUint, unwrap); + IERC20 inputToken = _tokens[inputTokenIndex]; + _sendTokenTo(inputToken, receiver, amountOutUint, unwrap); // Burn LP _tokens from payer (authorization via allowance) if (msg.sender != payer) { @@ -545,9 +542,6 @@ contract PartyPoolMintImpl is PartyPoolBase { newQInternal[idx] = _uintToInternalFloor(newBal, _bases[idx]); } - // Emit BurnSwap with public-facing info only (do not expose ΔS or LP burned) - emit IPartyPool.BurnSwap(payer, receiver, inputTokenIndex, amountOutUint); - // If entire pool drained, deinit; else update proportionally bool allZero = true; for (uint256 idx = 0; idx < n; idx++) { @@ -559,7 +553,9 @@ contract PartyPoolMintImpl is PartyPoolBase { _lmsr.updateForProportionalChange(newQInternal); } - emit IPartyPool.Burn(payer, receiver, new uint256[](n), lpAmount); + emit IPartyPool.BurnSwap(payer, receiver, inputToken, lpAmount, amountOutUint, + feeTokenUint-protoShare, protoShare); + return amountOutUint; } diff --git a/src/PartyPoolSwapImpl.sol b/src/PartyPoolSwapImpl.sol index 6cc9eff..cddbeb6 100644 --- a/src/PartyPoolSwapImpl.sol +++ b/src/PartyPoolSwapImpl.sol @@ -74,18 +74,21 @@ contract PartyPoolSwapImpl is PartyPoolBase { _quoteSwapToLimit(inputTokenIndex, outputTokenIndex, limitPrice, swapFeePpm); // Transfer the exact amount needed from payer and require exact receipt (revert on fee-on-transfer) - _receiveTokenFrom(payer, _tokens[inputTokenIndex], totalTransferAmount); - uint256 balIAfter = IERC20(_tokens[inputTokenIndex]).balanceOf(address(this)); + IERC20 tokenIn = _tokens[inputTokenIndex]; + _receiveTokenFrom(payer, tokenIn, totalTransferAmount); + uint256 balIAfter = tokenIn.balanceOf(address(this)); require(balIAfter == prevBalI + totalTransferAmount, "swapToLimit: non-standard tokenIn"); // Transfer output to receiver and verify exact decrease - _sendTokenTo(_tokens[outputTokenIndex], receiver, amountOutUint, unwrap); - uint256 balJAfter = IERC20(_tokens[outputTokenIndex]).balanceOf(address(this)); + IERC20 tokenOut = _tokens[outputTokenIndex]; + _sendTokenTo(tokenOut, receiver, amountOutUint, unwrap); + uint256 balJAfter = IERC20(tokenOut).balanceOf(address(this)); require(balJAfter == prevBalJ - amountOutUint, "swapToLimit: non-standard tokenOut"); // Accrue protocol share (floor) from the fee on input token + uint256 protoShare = 0; if (protocolFeePpm > 0 && feeUint > 0 ) { - uint256 protoShare = (feeUint * protocolFeePpm) / 1_000_000; // floor + protoShare = (feeUint * protocolFeePpm) / 1_000_000; // floor if (protoShare > 0) { _protocolFeesOwed[inputTokenIndex] += protoShare; } @@ -102,7 +105,8 @@ contract PartyPoolSwapImpl is PartyPoolBase { _lmsr.applySwap(inputTokenIndex, outputTokenIndex, amountInInternalMax, amountOutInternal); // Maintain original event semantics (logs input without fee) - emit IPartyPool.Swap(payer, receiver, _tokens[inputTokenIndex], _tokens[outputTokenIndex], amountInUsedUint, amountOutUint); + emit IPartyPool.Swap(payer, receiver, tokenIn, tokenOut, + amountInUsedUint, amountOutUint, feeUint-protoShare, protoShare); return (amountInUsedUint, amountOutUint, feeUint); } @@ -164,6 +168,7 @@ contract PartyPoolSwapImpl is PartyPoolBase { // transfer owed _tokens to protocol destination via centralized helper _sendTokenTo(_tokens[i], dest, owed, false); } + emit IPartyPool.ProtocolFeesCollected(); } }