// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.30; import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"; /// @title PartyPool - LMSR-backed multi-asset pool with LP ERC20 token /// @notice A multi-asset liquidity pool backed by the LMSRStabilized pricing model. /// The pool issues an ERC20 LP token representing proportional ownership. /// It supports: /// - Proportional minting and burning of LP tokens, /// - Single-token mint (swapMint) and single-asset withdrawal (burnSwap), /// - Exact-input swaps and swaps-to-price-limits, /// - Flash loans via a callback interface. /// /// @dev The contract stores per-token uint "bases" used to scale token units into the internal Q64.64 /// representation used by the LMSR library. Cached on-chain uint balances are kept to reduce balanceOf calls. /// The contract uses ceiling/floor rules described in function comments to bias rounding in favor of the pool /// (i.e., floor outputs to users, ceil inputs/fees where appropriate). interface IPartyPool is IERC20Metadata { // All int128's are ABDKMath64x64 format // Events event Mint(address payer, address indexed receiver, uint256[] amounts, uint256 lpMinted); event Burn(address payer, address indexed receiver, uint256[] amounts, uint256 lpBurned); event Swap( address payer, address indexed receiver, IERC20 indexed tokenIn, IERC20 indexed tokenOut, uint256 amountIn, uint256 amountOut ); /// @notice Emitted when a single-token swapMint is executed. /// Records payer/receiver, input token index, gross transfer (net+fee), net input and fee taken. 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) ); /// @notice Emitted when a burnSwap is executed. /// Records payer/receiver, target token index and the uint payout sent to the receiver. event BurnSwap( address indexed payer, address indexed receiver, uint256 indexed targetTokenIndex, uint256 payoutUint ); /// @notice Token addresses comprising the pool. Effectively immutable after construction. /// @dev tokens[i] corresponds to the i-th asset and maps to index i in the internal LMSR arrays. function getToken(uint256) external view returns (IERC20); // get single token /// @notice Returns the number of tokens (n) in the pool. function numTokens() external view returns (uint256); /// @notice Returns the list of all token addresses in the pool (copy). function allTokens() external view returns (IERC20[] memory); /// @notice Per-token uint base denominators used to convert uint token amounts <-> internal Q64.64 representation. /// @dev denominators()[i] is the base for tokens[i]. These bases are chosen by deployer and must match token decimals. function denominators() external view returns (uint256[] memory); /// @notice Per-swap fee in parts-per-million (ppm). Fee is taken from input amounts before LMSR computations. function swapFeePpm() external view returns (uint256); /// @notice Flash-loan fee in parts-per-million (ppm) applied to flash borrow amounts. function flashFeePpm() external view returns (uint256); /// @notice Protocol fee share (ppm) applied to fees collected by the pool (floored when accrued) /// @dev This is the fraction (in ppm) of the pool-collected fees that are owed to the protocol. function protocolFeePpm() external view returns (uint256); /// @notice Address that will receive collected protocol tokens when collectProtocolFees() is called. function protocolFeeAddress() external view returns (address); /// @notice Per-token protocol fee ledger accessor. Returns tokens owed (raw uint token units) for token index i. function protocolFeesOwed(uint256) external view returns (uint256); /// @notice Liquidity parameter κ (Q64.64) used by the LMSR kernel: b = κ * S(q) /// @dev Pools are constructed with a κ value; this getter exposes the κ used by the pool. function kappa() external view returns (int128); // Initialization / Mint / Burn (LP token managed) /// @notice Initial mint to set up pool for the first time. /// @dev Assumes tokens have already been transferred to the pool prior to calling. /// Can only be called when the pool is uninitialized (totalSupply() == 0 or lmsr.nAssets == 0). /// @param receiver address that receives the LP tokens /// @param lpTokens The number of LP tokens to issue for this mint. If 0, then the number of tokens returned will equal the LMSR internal q total function initialMint(address receiver, uint256 lpTokens) external returns (uint256 lpMinted); /// @notice Calculate the proportional deposit amounts required for a given LP token amount /// @dev Returns the minimum token amounts (rounded up) that must be supplied to receive lpTokenAmount /// LP tokens at current pool proportions. If the pool is empty (initial deposit) returns zeros /// because the initial deposit is handled by transferring tokens then calling mint(). /// @param lpTokenAmount The amount of LP tokens desired /// @return depositAmounts Array of token amounts to deposit (rounded up) function mintAmounts(uint256 lpTokenAmount) external view returns (uint256[] memory depositAmounts); /// @notice Proportional mint (or initial supply if first call). /// @dev - For initial supply: assumes tokens have already been transferred to the pool prior to calling. /// - For subsequent mints: payer must approve the required token amounts before calling. /// Rounds follow the pool-favorable conventions documented in helpers (ceil inputs, floor outputs). /// @param payer address that provides the input tokens (ignored for initial deposit) /// @param receiver address that receives the LP tokens /// @param lpTokenAmount desired amount of LP tokens to mint (ignored for initial deposit) /// @param deadline timestamp after which the transaction will revert. Pass 0 to ignore. /// @return lpMinted the actual amount of lpToken minted function mint(address payer, address receiver, uint256 lpTokenAmount, uint256 deadline) external returns (uint256 lpMinted); /// @notice Calculate the proportional withdrawal amounts for a given LP token amount /// @dev Returns the maximum token amounts (rounded down) that will be withdrawn when burning lpTokenAmount. /// If the pool is uninitialized or supply is zero, returns zeros. /// @param lpTokenAmount The amount of LP tokens to burn /// @return withdrawAmounts Array of token amounts to withdraw (rounded down) function burnAmounts(uint256 lpTokenAmount) external view returns (uint256[] memory withdrawAmounts); /// @notice Burn LP tokens and withdraw the proportional basket to receiver. /// @dev Payer must own or approve the LP tokens being burned. The function updates LMSR state /// proportionally to reflect the reduced pool size after the withdrawal. /// @param payer address that provides the LP tokens to burn /// @param receiver address that receives the withdrawn tokens /// @param lpAmount amount of LP tokens to burn (proportional withdrawal) /// @param deadline timestamp after which the transaction will revert. Pass 0 to ignore. function burn(address payer, address receiver, uint256 lpAmount, uint256 deadline) external returns (uint256[] memory withdrawAmounts); // Swaps /// @notice External view to quote exact-in swap amounts (gross input incl. fee and output), matching swap() computations /// @param inputTokenIndex index of input token /// @param outputTokenIndex index of output token /// @param maxAmountIn maximum gross input allowed (inclusive of fee) /// @param limitPrice maximum acceptable marginal price (pass 0 to ignore) /// @return amountIn gross input amount to transfer (includes fee), amountOut output amount user would receive, fee fee amount taken function swapAmounts( uint256 inputTokenIndex, uint256 outputTokenIndex, uint256 maxAmountIn, int128 limitPrice ) external view returns (uint256 amountIn, uint256 amountOut, uint256 fee); /// @notice Swap input token inputTokenIndex -> token outputTokenIndex. Payer must approve token inputTokenIndex. /// @dev This function transfers the exact gross input (including fee) from payer and sends the computed output to receiver. /// Non-standard tokens (fee-on-transfer, rebasers) are rejected via balance checks. /// @param payer address of the account that pays for the swap /// @param receiver address that will receive the output tokens /// @param inputTokenIndex index of input asset /// @param outputTokenIndex index of output asset /// @param maxAmountIn maximum amount of token inputTokenIndex (uint256) to transfer in (inclusive of fees) /// @param limitPrice maximum acceptable marginal price (64.64 fixed point). Pass 0 to ignore. /// @param deadline timestamp after which the transaction will revert. Pass 0 to ignore. /// @return amountIn actual input used (uint256), amountOut actual output sent (uint256), fee fee taken from the input (uint256) function swap( address payer, address receiver, uint256 inputTokenIndex, uint256 outputTokenIndex, uint256 maxAmountIn, int128 limitPrice, uint256 deadline ) external returns (uint256 amountIn, uint256 amountOut, uint256 fee); /// @notice External view to quote swap-to-limit amounts (gross input incl. fee and output), matching swapToLimit() computations /// @param inputTokenIndex index of input token /// @param outputTokenIndex index of output token /// @param limitPrice target marginal price to reach (must be > 0) /// @return amountIn gross input amount to transfer (includes fee), amountOut output amount user would receive, fee fee amount taken function swapToLimitAmounts( uint256 inputTokenIndex, uint256 outputTokenIndex, int128 limitPrice ) external view returns (uint256 amountIn, uint256 amountOut, uint256 fee); /// @notice Swap up to the price limit; computes max input to reach limit then performs swap. /// @dev If balances prevent fully reaching the limit, the function caps and returns actuals. /// The payer must transfer the exact gross input computed by the view. /// @param payer address of the account that pays for the swap /// @param receiver address that will receive the output tokens /// @param inputTokenIndex index of input asset /// @param outputTokenIndex index of output asset /// @param limitPrice target marginal price to reach (must be > 0) /// @param deadline timestamp after which the transaction will revert. Pass 0 to ignore. /// @return amountInUsed actual input used excluding fee (uint256), amountOut actual output sent (uint256), fee fee taken from the input (uint256) function swapToLimit( address payer, address receiver, uint256 inputTokenIndex, uint256 outputTokenIndex, int128 limitPrice, uint256 deadline ) external returns (uint256 amountInUsed, uint256 amountOut, uint256 fee); /// @notice Single-token mint: deposit a single token, charge swap-LMSR cost, and mint LP. /// @dev swapMint executes as an exact-in planned swap followed by proportional scaling of qInternal. /// The function emits SwapMint (gross, net, fee) and also emits Mint for LP issuance. /// @param payer who transfers the input token /// @param receiver who receives the minted LP tokens /// @param inputTokenIndex index of the input token /// @param maxAmountIn maximum uint token input (inclusive of fee) /// @param deadline optional deadline /// @return lpMinted actual LP minted (uint) function swapMint( address payer, address receiver, uint256 inputTokenIndex, uint256 maxAmountIn, uint256 deadline ) external returns (uint256 lpMinted); /// @notice Burn LP tokens then swap the redeemed proportional basket into a single asset `inputTokenIndex` and send to receiver. /// @dev The function burns LP tokens (authorization via allowance if needed), sends the single-asset payout and updates LMSR state. /// @param payer who burns LP tokens /// @param receiver who receives the single asset /// @param lpAmount amount of LP tokens to burn /// @param inputTokenIndex index of target asset to receive /// @param deadline optional deadline /// @return amountOutUint uint amount of asset inputTokenIndex sent to receiver function burnSwap( address payer, address receiver, uint256 lpAmount, uint256 inputTokenIndex, uint256 deadline ) external returns (uint256 amountOutUint); /// @notice Marginal price of `base` denominated in `quote` as Q64.64. /// @dev Returns the LMSR marginal price p_quote / p_base in ABDK 64.64 fixed-point format. /// Useful for off-chain quoting; raw 64.64 value is returned (no scaling to token units). /// @param baseTokenIndex index of the base asset (e.g., ETH) /// @param quoteTokenIndex index of the quote asset (e.g., USD) /// @return price Q64.64 value equal to quote per base (p_quote / p_base) function price(uint256 baseTokenIndex, uint256 quoteTokenIndex) external view returns (int128); /// @notice Price of one LP token denominated in `quote` as Q64.64. /// @dev Computes LMSR poolPrice (quote per unit internal qTotal) and scales it to LP units: /// returns price_per_LP = poolPrice_quote * (totalSupply() / qTotal) in ABDK 64.64 format. /// The returned value is raw Q64.64 and represents quote units per one LP token unit. /// @param quoteTokenIndex index of the quote asset in which to denominate the LP price /// @return price Q64.64 value equal to quote per LP token unit function poolPrice(uint256 quoteTokenIndex) external view returns (int128); /// @notice Compute repayment amounts (principal + flash fee) for a proposed flash loan. /// @param loanAmounts array of per-token loan amounts; must match the pool's token ordering. /// @return repaymentAmounts array where repaymentAmounts[i] = loanAmounts[i] + ceil(loanAmounts[i] * flashFeePpm) function flashRepaymentAmounts(uint256[] memory loanAmounts) external view returns (uint256[] memory repaymentAmounts); /// @notice Receive token amounts and require them to be repaid plus a fee inside a callback. /// @dev The caller must implement IPartyFlashCallback#partyFlashCallback which receives (amounts, repaymentAmounts, data). /// This function verifies that, after the callback returns, the pool's balances have increased by at least the fees /// for each borrowed token. Reverts if repayment (including fee) did not occur. /// @param recipient The address which will receive the token amounts /// @param amounts The amount of each token to send (array length must equal pool size) /// @param data Any data to be passed through to the callback function flash( address recipient, uint256[] memory amounts, bytes calldata data ) external; }