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:
@@ -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);
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user