event changes: SwapMint/BurnSwap replace rather than augment the regular Mint/Burn events; All swapping events have lpFee and protocolFee

This commit is contained in:
tim
2025-10-21 14:42:40 -04:00
parent 11ae6f2a4b
commit 538f778f51
4 changed files with 54 additions and 31 deletions

View File

@@ -38,29 +38,45 @@ interface IPartyPool is IERC20Metadata, IOwnable {
IERC20 indexed tokenIn, IERC20 indexed tokenIn,
IERC20 indexed tokenOut, IERC20 indexed tokenOut,
uint256 amountIn, uint256 amountIn,
uint256 amountOut uint256 amountOut,
uint256 lpFee,
uint256 protocolFee
); );
/// @notice Emitted when a single-token swapMint is executed. /// @notice Emitted instead of Swap when a single-token swapMint is executed.
/// Records payer/receiver, input token index, gross transfer (net+fee), net input and fee taken.
event SwapMint( event SwapMint(
address indexed payer, address indexed payer,
address indexed receiver, address indexed receiver,
uint256 indexed inputTokenIndex, IERC20 indexed tokenIn,
uint256 grossTransfer, // total _tokens transferred (net + fee) uint256 amountIn,
uint256 netInput, // net input credited to swaps (after fee) uint256 amountOut,
uint256 feeTaken // fee taken (ceil) uint256 lpFee, // taken from the input token
uint256 protocolFee // taken from the input token
); );
/// @notice Emitted when a burnSwap is executed. /// @notice Emitted instead of Burn when a burnSwap is executed.
/// Records payer/receiver, target token index and the uint payout sent to the receiver.
event BurnSwap( event BurnSwap(
address indexed payer, address indexed payer,
address indexed receiver, address indexed receiver,
uint256 indexed targetTokenIndex, IERC20 indexed tokenOut,
uint256 payoutUint 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); function LMSR() external view returns (LMSRStabilized.State memory);

View File

@@ -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 {IERC3156FlashLender} from "../lib/openzeppelin-contracts/contracts/interfaces/IERC3156FlashLender.sol";
import {NativeWrapper} from "./NativeWrapper.sol"; import {NativeWrapper} from "./NativeWrapper.sol";
import {OwnableExternal} from "./OwnableExternal.sol"; import {OwnableExternal} from "./OwnableExternal.sol";
import {IPartyPoolViewer} from "./IPartyPoolViewer.sol";
/// @title PartyPool - LMSR-backed multi-asset pool with LP ERC20 token /// @title PartyPool - LMSR-backed multi-asset pool with LP ERC20 token
/// @notice A multi-asset liquidity pool backed by the LMSRStabilized pricing model. /// @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; uint256 balJAfter = _cachedUintBalances[outputTokenIndex] + _protocolFeesOwed[outputTokenIndex] - amountOutUint;
// Accrue protocol share (floor) from the fee on input token // Accrue protocol share (floor) from the fee on input token
uint256 protoShare = 0;
if (PROTOCOL_FEE_PPM > 0 && feeUint > 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) { if (protoShare > 0) {
_protocolFeesOwed[inputTokenIndex] += protoShare; _protocolFeesOwed[inputTokenIndex] += protoShare;
} }
@@ -279,7 +281,8 @@ contract PartyPool is PartyPoolBase, OwnableExternal, ERC20External, IPartyPool
// Transfer output to receiver near the end // Transfer output to receiver near the end
_sendTokenTo(tokenOut, receiver, amountOutUint, unwrap); _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); return (totalTransferAmount, amountOutUint, feeUint);
} }
@@ -450,8 +453,9 @@ contract PartyPool is PartyPoolBase, OwnableExternal, ERC20External, IPartyPool
(uint256 fee, ) = _computeFee(amount, FLASH_FEE_PPM); (uint256 fee, ) = _computeFee(amount, FLASH_FEE_PPM);
// Compute protocol share of flash fee // Compute protocol share of flash fee
uint256 protoShare = 0;
if (PROTOCOL_FEE_PPM > 0 && fee > 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) { if (protoShare > 0) {
_protocolFeesOwed[tokenIndex] += protoShare; _protocolFeesOwed[tokenIndex] += protoShare;
} }
@@ -467,6 +471,8 @@ contract PartyPool is PartyPoolBase, OwnableExternal, ERC20External, IPartyPool
require(balAfter >= _protocolFeesOwed[tokenIndex], "balance < protocol owed"); require(balAfter >= _protocolFeesOwed[tokenIndex], "balance < protocol owed");
_cachedUintBalances[tokenIndex] = balAfter - _protocolFeesOwed[tokenIndex]; _cachedUintBalances[tokenIndex] = balAfter - _protocolFeesOwed[tokenIndex];
emit Flash(msg.sender, receiver, token, amount, fee-protoShare, protoShare);
return true; return true;
} }

View File

@@ -424,12 +424,8 @@ contract PartyPoolMintImpl is PartyPoolBase {
// Use natural ERC20 function since base contract inherits from ERC20 // Use natural ERC20 function since base contract inherits from ERC20
_mint(receiver, actualLpToMint); _mint(receiver, actualLpToMint);
// Emit SwapMint event with gross transfer, net input and fee (planned exact-in) emit IPartyPool.SwapMint(payer, receiver, _tokens[inputTokenIndex],
emit IPartyPool.SwapMint(payer, receiver, inputTokenIndex, totalTransfer, amountInUint, feeUintActual); totalTransfer, actualLpToMint, feeUintActual-protoShare, protoShare);
// 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
return actualLpToMint; return actualLpToMint;
} }
@@ -524,7 +520,8 @@ contract PartyPoolMintImpl is PartyPoolBase {
} }
// Transfer the payout to receiver via centralized helper // 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) // Burn LP _tokens from payer (authorization via allowance)
if (msg.sender != payer) { if (msg.sender != payer) {
@@ -545,9 +542,6 @@ contract PartyPoolMintImpl is PartyPoolBase {
newQInternal[idx] = _uintToInternalFloor(newBal, _bases[idx]); 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 // If entire pool drained, deinit; else update proportionally
bool allZero = true; bool allZero = true;
for (uint256 idx = 0; idx < n; idx++) { for (uint256 idx = 0; idx < n; idx++) {
@@ -559,7 +553,9 @@ contract PartyPoolMintImpl is PartyPoolBase {
_lmsr.updateForProportionalChange(newQInternal); _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; return amountOutUint;
} }

View File

@@ -74,18 +74,21 @@ contract PartyPoolSwapImpl is PartyPoolBase {
_quoteSwapToLimit(inputTokenIndex, outputTokenIndex, limitPrice, swapFeePpm); _quoteSwapToLimit(inputTokenIndex, outputTokenIndex, limitPrice, swapFeePpm);
// Transfer the exact amount needed from payer and require exact receipt (revert on fee-on-transfer) // Transfer the exact amount needed from payer and require exact receipt (revert on fee-on-transfer)
_receiveTokenFrom(payer, _tokens[inputTokenIndex], totalTransferAmount); IERC20 tokenIn = _tokens[inputTokenIndex];
uint256 balIAfter = IERC20(_tokens[inputTokenIndex]).balanceOf(address(this)); _receiveTokenFrom(payer, tokenIn, totalTransferAmount);
uint256 balIAfter = tokenIn.balanceOf(address(this));
require(balIAfter == prevBalI + totalTransferAmount, "swapToLimit: non-standard tokenIn"); require(balIAfter == prevBalI + totalTransferAmount, "swapToLimit: non-standard tokenIn");
// Transfer output to receiver and verify exact decrease // Transfer output to receiver and verify exact decrease
_sendTokenTo(_tokens[outputTokenIndex], receiver, amountOutUint, unwrap); IERC20 tokenOut = _tokens[outputTokenIndex];
uint256 balJAfter = IERC20(_tokens[outputTokenIndex]).balanceOf(address(this)); _sendTokenTo(tokenOut, receiver, amountOutUint, unwrap);
uint256 balJAfter = IERC20(tokenOut).balanceOf(address(this));
require(balJAfter == prevBalJ - amountOutUint, "swapToLimit: non-standard tokenOut"); require(balJAfter == prevBalJ - amountOutUint, "swapToLimit: non-standard tokenOut");
// Accrue protocol share (floor) from the fee on input token // Accrue protocol share (floor) from the fee on input token
uint256 protoShare = 0;
if (protocolFeePpm > 0 && feeUint > 0 ) { if (protocolFeePpm > 0 && feeUint > 0 ) {
uint256 protoShare = (feeUint * protocolFeePpm) / 1_000_000; // floor protoShare = (feeUint * protocolFeePpm) / 1_000_000; // floor
if (protoShare > 0) { if (protoShare > 0) {
_protocolFeesOwed[inputTokenIndex] += protoShare; _protocolFeesOwed[inputTokenIndex] += protoShare;
} }
@@ -102,7 +105,8 @@ contract PartyPoolSwapImpl is PartyPoolBase {
_lmsr.applySwap(inputTokenIndex, outputTokenIndex, amountInInternalMax, amountOutInternal); _lmsr.applySwap(inputTokenIndex, outputTokenIndex, amountInInternalMax, amountOutInternal);
// Maintain original event semantics (logs input without fee) // 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); return (amountInUsedUint, amountOutUint, feeUint);
} }
@@ -164,6 +168,7 @@ contract PartyPoolSwapImpl is PartyPoolBase {
// transfer owed _tokens to protocol destination via centralized helper // transfer owed _tokens to protocol destination via centralized helper
_sendTokenTo(_tokens[i], dest, owed, false); _sendTokenTo(_tokens[i], dest, owed, false);
} }
emit IPartyPool.ProtocolFeesCollected();
} }
} }