styling consistency
This commit is contained in:
@@ -19,7 +19,7 @@ contract DeployMock is Script {
|
|||||||
function run() public {
|
function run() public {
|
||||||
vm.startBroadcast();
|
vm.startBroadcast();
|
||||||
|
|
||||||
// create mock tokens
|
// create mock _tokens
|
||||||
usxd = new MockERC20('Joke Currency', 'USXD', 6);
|
usxd = new MockERC20('Joke Currency', 'USXD', 6);
|
||||||
fusd = new MockERC20('Fake USD', 'FUSD', 6);
|
fusd = new MockERC20('Fake USD', 'FUSD', 6);
|
||||||
dive = new MockERC20('DAI Virtually Equal', 'DIVE', 18);
|
dive = new MockERC20('DAI Virtually Equal', 'DIVE', 18);
|
||||||
@@ -41,7 +41,7 @@ contract DeployMock is Script {
|
|||||||
// deploy a PartyPlanner factory and create the pool via factory
|
// deploy a PartyPlanner factory and create the pool via factory
|
||||||
PartyPlanner planner = Deploy.newPartyPlanner();
|
PartyPlanner planner = Deploy.newPartyPlanner();
|
||||||
|
|
||||||
// prepare initial deposits (10_000 units of each token, scaled by bases)
|
// prepare initial deposits (10_000 units of each token, scaled by _bases)
|
||||||
uint256[] memory initialDeposits = new uint256[](3);
|
uint256[] memory initialDeposits = new uint256[](3);
|
||||||
initialDeposits[0] = _bases[0] * 10_000;
|
initialDeposits[0] = _bases[0] * 10_000;
|
||||||
initialDeposits[1] = _bases[1] * 10_000;
|
initialDeposits[1] = _bases[1] * 10_000;
|
||||||
@@ -49,7 +49,7 @@ contract DeployMock is Script {
|
|||||||
uint256 initialLpAmount = 0;
|
uint256 initialLpAmount = 0;
|
||||||
uint256 deadline = 0;
|
uint256 deadline = 0;
|
||||||
|
|
||||||
// mint tokens to the deployer so it can fund the initial deposits and approve the factory
|
// mint _tokens to the deployer so it can fund the initial deposits and approve the factory
|
||||||
mintAll(msg.sender, 10_000);
|
mintAll(msg.sender, 10_000);
|
||||||
|
|
||||||
// approve factory to move initial deposits
|
// approve factory to move initial deposits
|
||||||
@@ -75,7 +75,7 @@ contract DeployMock is Script {
|
|||||||
deadline
|
deadline
|
||||||
);
|
);
|
||||||
|
|
||||||
// give tokens to dev7 for later use
|
// give _tokens to dev7 for later use
|
||||||
mintAll(DEV_ACCOUNT_7, 1_000_000);
|
mintAll(DEV_ACCOUNT_7, 1_000_000);
|
||||||
|
|
||||||
vm.stopBroadcast();
|
vm.stopBroadcast();
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ contract ERC20External is ERC20Internal, IERC20Metadata {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @dev Returns the number of decimals used to get its user representation.
|
* @dev Returns the number of decimals used to get its user representation.
|
||||||
* For example, if `decimals` equals `2`, a balance of `505` tokens should
|
* For example, if `decimals` equals `2`, a balance of `505` _tokens should
|
||||||
* be displayed to a user as `5.05` (`505 / 10 ** 2`).
|
* be displayed to a user as `5.05` (`505 / 10 ** 2`).
|
||||||
*
|
*
|
||||||
* Tokens usually opt for a value of 18, imitating the relationship between
|
* Tokens usually opt for a value of 18, imitating the relationship between
|
||||||
@@ -111,7 +111,7 @@ contract ERC20External is ERC20Internal, IERC20Metadata {
|
|||||||
*
|
*
|
||||||
* - `from` and `to` cannot be the zero address.
|
* - `from` and `to` cannot be the zero address.
|
||||||
* - `from` must have a balance of at least `value`.
|
* - `from` must have a balance of at least `value`.
|
||||||
* - the caller must have allowance for ``from``'s tokens of at least
|
* - the caller must have allowance for ``from``'s _tokens of at least
|
||||||
* `value`.
|
* `value`.
|
||||||
*/
|
*/
|
||||||
function transferFrom(address from, address to, uint256 value) public virtual returns (bool) {
|
function transferFrom(address from, address to, uint256 value) public virtual returns (bool) {
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ abstract contract ERC20Internal is Context, IERC20Errors {
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @dev Moves a `value` amount of tokens from `from` to `to`.
|
* @dev Moves a `value` amount of _tokens from `from` to `to`.
|
||||||
*
|
*
|
||||||
* This internal function is equivalent to {transfer}, and can be used to
|
* This internal function is equivalent to {transfer}, and can be used to
|
||||||
* e.g. implement automatic token fees, slashing mechanisms, etc.
|
* e.g. implement automatic token fees, slashing mechanisms, etc.
|
||||||
@@ -36,7 +36,7 @@ abstract contract ERC20Internal is Context, IERC20Errors {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @dev Transfers a `value` amount of tokens from `from` to `to`, or alternatively mints (or burns) if `from`
|
* @dev Transfers a `value` amount of _tokens from `from` to `to`, or alternatively mints (or burns) if `from`
|
||||||
* (or `to`) is the zero address. All customizations to transfers, mints, and burns should be done by overriding
|
* (or `to`) is the zero address. All customizations to transfers, mints, and burns should be done by overriding
|
||||||
* this function.
|
* this function.
|
||||||
*
|
*
|
||||||
@@ -73,7 +73,7 @@ abstract contract ERC20Internal is Context, IERC20Errors {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @dev Creates a `value` amount of tokens and assigns them to `account`, by transferring it from address(0).
|
* @dev Creates a `value` amount of _tokens and assigns them to `account`, by transferring it from address(0).
|
||||||
* Relies on the `_update` mechanism
|
* Relies on the `_update` mechanism
|
||||||
*
|
*
|
||||||
* Emits a {Transfer} event with `from` set to the zero address.
|
* Emits a {Transfer} event with `from` set to the zero address.
|
||||||
@@ -88,7 +88,7 @@ abstract contract ERC20Internal is Context, IERC20Errors {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @dev Destroys a `value` amount of tokens from `account`, lowering the total supply.
|
* @dev Destroys a `value` amount of _tokens from `account`, lowering the total supply.
|
||||||
* Relies on the `_update` mechanism.
|
* Relies on the `_update` mechanism.
|
||||||
*
|
*
|
||||||
* Emits a {Transfer} event with `to` set to the zero address.
|
* Emits a {Transfer} event with `to` set to the zero address.
|
||||||
@@ -103,7 +103,7 @@ abstract contract ERC20Internal is Context, IERC20Errors {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @dev Sets `value` as the allowance of `spender` over the `owner`'s tokens.
|
* @dev Sets `value` as the allowance of `spender` over the `owner`'s _tokens.
|
||||||
*
|
*
|
||||||
* This internal function is equivalent to `approve`, and can be used to
|
* This internal function is equivalent to `approve`, and can be used to
|
||||||
* e.g. set automatic allowances for certain subsystems, etc.
|
* e.g. set automatic allowances for certain subsystems, etc.
|
||||||
|
|||||||
@@ -17,18 +17,18 @@ interface IPartyPlanner {
|
|||||||
/// @param name_ LP token name
|
/// @param name_ LP token name
|
||||||
/// @param symbol_ LP token symbol
|
/// @param symbol_ LP token symbol
|
||||||
/// @param _tokens token addresses (n)
|
/// @param _tokens token addresses (n)
|
||||||
/// @param _bases scaling bases for each token (n) - used when converting to/from internal 64.64 amounts
|
/// @param _bases scaling _bases for each token (n) - used when converting to/from internal 64.64 amounts
|
||||||
/// @param _tradeFrac trade fraction in 64.64 fixed-point (as used by LMSR)
|
/// @param _tradeFrac trade fraction in 64.64 fixed-point (as used by LMSR)
|
||||||
/// @param _targetSlippage target slippage in 64.64 fixed-point (as used by LMSR)
|
/// @param _targetSlippage target slippage in 64.64 fixed-point (as used by LMSR)
|
||||||
/// @param _swapFeePpm fee in parts-per-million, taken from swap input amounts before LMSR calculations
|
/// @param _swapFeePpm fee in parts-per-million, taken from swap input amounts before LMSR calculations
|
||||||
/// @param _flashFeePpm fee in parts-per-million, taken for flash loans
|
/// @param _flashFeePpm fee in parts-per-million, taken for flash loans
|
||||||
/// @param _stable if true and assets.length==2, then the optimization for 2-asset stablecoin pools is activated
|
/// @param _stable if true and assets.length==2, then the optimization for 2-asset stablecoin pools is activated
|
||||||
/// @param payer address that provides the initial token deposits
|
/// @param payer address that provides the initial token deposits
|
||||||
/// @param receiver address that receives the minted LP tokens
|
/// @param receiver address that receives the minted LP _tokens
|
||||||
/// @param initialDeposits amounts of each token to deposit initially
|
/// @param initialDeposits amounts of each token to deposit initially
|
||||||
/// @param deadline Reverts if nonzero and the current blocktime is later than the deadline
|
/// @param deadline Reverts if nonzero and the current blocktime is later than the deadline
|
||||||
/// @return pool Address of the newly created and initialized PartyPool
|
/// @return pool Address of the newly created and initialized PartyPool
|
||||||
/// @return lpAmount Amount of LP tokens minted to the receiver
|
/// @return lpAmount Amount of LP _tokens minted to the receiver
|
||||||
function newPool(
|
function newPool(
|
||||||
// Pool constructor args (legacy)
|
// Pool constructor args (legacy)
|
||||||
string memory name_,
|
string memory name_,
|
||||||
@@ -52,17 +52,17 @@ interface IPartyPlanner {
|
|||||||
/// @param name_ LP token name
|
/// @param name_ LP token name
|
||||||
/// @param symbol_ LP token symbol
|
/// @param symbol_ LP token symbol
|
||||||
/// @param _tokens token addresses (n)
|
/// @param _tokens token addresses (n)
|
||||||
/// @param _bases scaling bases for each token (n) - used when converting to/from internal 64.64 amounts
|
/// @param _bases scaling _bases for each token (n) - used when converting to/from internal 64.64 amounts
|
||||||
/// @param _kappa liquidity parameter κ in 64.64 fixed-point used to derive b = κ * S(q)
|
/// @param _kappa liquidity parameter κ in 64.64 fixed-point used to derive b = κ * S(q)
|
||||||
/// @param _swapFeePpm fee in parts-per-million, taken from swap input amounts before LMSR calculations
|
/// @param _swapFeePpm fee in parts-per-million, taken from swap input amounts before LMSR calculations
|
||||||
/// @param _flashFeePpm fee in parts-per-million, taken for flash loans
|
/// @param _flashFeePpm fee in parts-per-million, taken for flash loans
|
||||||
/// @param _stable if true and assets.length==2, then the optimization for 2-asset stablecoin pools is activated
|
/// @param _stable if true and assets.length==2, then the optimization for 2-asset stablecoin pools is activated
|
||||||
/// @param payer address that provides the initial token deposits
|
/// @param payer address that provides the initial token deposits
|
||||||
/// @param receiver address that receives the minted LP tokens
|
/// @param receiver address that receives the minted LP _tokens
|
||||||
/// @param initialDeposits amounts of each token to deposit initially
|
/// @param initialDeposits amounts of each token to deposit initially
|
||||||
/// @param deadline Reverts if nonzero and the current blocktime is later than the deadline
|
/// @param deadline Reverts if nonzero and the current blocktime is later than the deadline
|
||||||
/// @return pool Address of the newly created and initialized PartyPool
|
/// @return pool Address of the newly created and initialized PartyPool
|
||||||
/// @return lpAmount Amount of LP tokens minted to the receiver
|
/// @return lpAmount Amount of LP _tokens minted to the receiver
|
||||||
function newPool(
|
function newPool(
|
||||||
// Pool constructor args (kappa-based)
|
// Pool constructor args (kappa-based)
|
||||||
string memory name_,
|
string memory name_,
|
||||||
@@ -96,8 +96,8 @@ interface IPartyPlanner {
|
|||||||
/// @return pools Array of pool addresses for the requested page
|
/// @return pools Array of pool addresses for the requested page
|
||||||
function getAllPools(uint256 offset, uint256 limit) external view returns (IPartyPool[] memory pools);
|
function getAllPools(uint256 offset, uint256 limit) external view returns (IPartyPool[] memory pools);
|
||||||
|
|
||||||
/// @notice Returns the total number of unique tokens
|
/// @notice Returns the total number of unique _tokens
|
||||||
/// @return The total count of unique tokens
|
/// @return The total count of unique _tokens
|
||||||
function tokenCount() external view returns (uint256);
|
function tokenCount() external view returns (uint256);
|
||||||
|
|
||||||
/// @notice Retrieves a page of token addresses
|
/// @notice Retrieves a page of token addresses
|
||||||
|
|||||||
@@ -11,12 +11,12 @@ import {IERC20} from "../lib/openzeppelin-contracts/contracts/token/ERC20/IERC20
|
|||||||
/// @notice A multi-asset liquidity pool backed by the LMSRStabilized pricing model.
|
/// @notice A multi-asset liquidity pool backed by the LMSRStabilized pricing model.
|
||||||
/// The pool issues an ERC20 LP token representing proportional ownership.
|
/// The pool issues an ERC20 LP token representing proportional ownership.
|
||||||
/// It supports:
|
/// It supports:
|
||||||
/// - Proportional minting and burning of LP tokens,
|
/// - Proportional minting and burning of LP _tokens,
|
||||||
/// - Single-token mint (swapMint) and single-asset withdrawal (burnSwap),
|
/// - Single-token mint (swapMint) and single-asset withdrawal (burnSwap),
|
||||||
/// - Exact-input swaps and swaps-to-price-limits,
|
/// - Exact-input swaps and swaps-to-price-limits,
|
||||||
/// - Flash loans via a callback interface.
|
/// - Flash loans via a callback interface.
|
||||||
///
|
///
|
||||||
/// @dev The contract stores per-token uint "bases" used to scale token units into the internal Q64.64
|
/// @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.
|
/// 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
|
/// 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).
|
/// (i.e., floor outputs to users, ceil inputs/fees where appropriate).
|
||||||
@@ -44,7 +44,7 @@ interface IPartyPool is IERC20Metadata {
|
|||||||
address indexed payer,
|
address indexed payer,
|
||||||
address indexed receiver,
|
address indexed receiver,
|
||||||
uint256 indexed inputTokenIndex,
|
uint256 indexed inputTokenIndex,
|
||||||
uint256 grossTransfer, // total tokens transferred (net + fee)
|
uint256 grossTransfer, // total _tokens transferred (net + fee)
|
||||||
uint256 netInput, // net input credited to swaps (after fee)
|
uint256 netInput, // net input credited to swaps (after fee)
|
||||||
uint256 feeTaken // fee taken (ceil)
|
uint256 feeTaken // fee taken (ceil)
|
||||||
);
|
);
|
||||||
@@ -62,10 +62,10 @@ interface IPartyPool is IERC20Metadata {
|
|||||||
function LMSR() external view returns (LMSRStabilized.State memory);
|
function LMSR() external view returns (LMSRStabilized.State memory);
|
||||||
|
|
||||||
/// @notice Token addresses comprising the pool. Effectively immutable after construction.
|
/// @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.
|
/// @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
|
function getToken(uint256) external view returns (IERC20); // get single token
|
||||||
|
|
||||||
/// @notice Returns the number of tokens (n) in the pool.
|
/// @notice Returns the number of _tokens (n) in the pool.
|
||||||
function numTokens() external view returns (uint256);
|
function numTokens() external view returns (uint256);
|
||||||
|
|
||||||
/// @notice Returns the list of all token addresses in the pool (copy).
|
/// @notice Returns the list of all token addresses in the pool (copy).
|
||||||
@@ -75,7 +75,7 @@ interface IPartyPool is IERC20Metadata {
|
|||||||
function wrapperToken() external view returns (IWETH9);
|
function wrapperToken() external view returns (IWETH9);
|
||||||
|
|
||||||
/// @notice Per-token uint base denominators used to convert uint token amounts <-> internal Q64.64 representation.
|
/// @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.
|
/// @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);
|
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.
|
/// @notice Per-swap fee in parts-per-million (ppm). Fee is taken from input amounts before LMSR computations.
|
||||||
@@ -88,10 +88,10 @@ interface IPartyPool is IERC20Metadata {
|
|||||||
/// @dev This is the fraction (in ppm) of the pool-collected fees that are owed to the protocol.
|
/// @dev This is the fraction (in ppm) of the pool-collected fees that are owed to the protocol.
|
||||||
function protocolFeePpm() external view returns (uint256);
|
function protocolFeePpm() external view returns (uint256);
|
||||||
|
|
||||||
/// @notice Address that will receive collected protocol tokens when collectProtocolFees() is called.
|
/// @notice Address that will receive collected protocol _tokens when collectProtocolFees() is called.
|
||||||
function protocolFeeAddress() external view returns (address);
|
function protocolFeeAddress() external view returns (address);
|
||||||
|
|
||||||
/// @notice Protocol fee ledger accessor. Returns tokens owed (raw uint token units) from this pool as protocol fees
|
/// @notice Protocol fee ledger accessor. Returns _tokens owed (raw uint token units) from this pool as protocol fees
|
||||||
/// that have not yet been transferred out.
|
/// that have not yet been transferred out.
|
||||||
function allProtocolFeesOwed() external view returns (uint256[] memory);
|
function allProtocolFeesOwed() external view returns (uint256[] memory);
|
||||||
|
|
||||||
@@ -105,28 +105,28 @@ interface IPartyPool is IERC20Metadata {
|
|||||||
// Initialization / Mint / Burn (LP token managed)
|
// Initialization / Mint / Burn (LP token managed)
|
||||||
|
|
||||||
/// @notice Initial mint to set up pool for the first time.
|
/// @notice Initial mint to set up pool for the first time.
|
||||||
/// @dev Assumes tokens have already been transferred to the pool prior to calling.
|
/// @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).
|
/// Can only be called when the pool is uninitialized (totalSupply() == 0 or _lmsr.nAssets == 0).
|
||||||
/// @param receiver address that receives the LP tokens
|
/// @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
|
/// @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 payable returns (uint256 lpMinted);
|
function initialMint(address receiver, uint256 lpTokens) external payable returns (uint256 lpMinted);
|
||||||
|
|
||||||
/// @notice Proportional mint (or initial supply if first call).
|
/// @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.
|
/// @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.
|
/// - 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).
|
/// 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 payer address that provides the input _tokens (ignored for initial deposit)
|
||||||
/// @param receiver address that receives the LP tokens
|
/// @param receiver address that receives the LP _tokens
|
||||||
/// @param lpTokenAmount desired amount of LP tokens to mint (ignored for initial deposit)
|
/// @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.
|
/// @param deadline timestamp after which the transaction will revert. Pass 0 to ignore.
|
||||||
/// @return lpMinted the actual amount of lpToken minted
|
/// @return lpMinted the actual amount of lpToken minted
|
||||||
function mint(address payer, address receiver, uint256 lpTokenAmount, uint256 deadline) external payable returns (uint256 lpMinted);
|
function mint(address payer, address receiver, uint256 lpTokenAmount, uint256 deadline) external payable returns (uint256 lpMinted);
|
||||||
|
|
||||||
/// @notice Burn LP tokens and withdraw the proportional basket to receiver.
|
/// @notice Burn LP _tokens and withdraw the proportional basket to receiver.
|
||||||
/// @dev This function forwards the call to the burn implementation via delegatecall
|
/// @dev This function forwards the call to the burn implementation via delegatecall
|
||||||
/// @param payer address that provides the LP tokens to burn
|
/// @param payer address that provides the LP _tokens to burn
|
||||||
/// @param receiver address that receives the withdrawn tokens
|
/// @param receiver address that receives the withdrawn _tokens
|
||||||
/// @param lpAmount amount of LP tokens to burn (proportional withdrawal)
|
/// @param lpAmount amount of LP _tokens to burn (proportional withdrawal)
|
||||||
/// @param deadline timestamp after which the transaction will revert. Pass 0 to ignore.
|
/// @param deadline timestamp after which the transaction will revert. Pass 0 to ignore.
|
||||||
/// @param unwrap if true and the native token is being withdrawn, it is unwraped and sent as native currency
|
/// @param unwrap if true and the native token is being withdrawn, it is unwraped and sent as native currency
|
||||||
function burn(address payer, address receiver, uint256 lpAmount, uint256 deadline, bool unwrap) external returns (uint256[] memory withdrawAmounts);
|
function burn(address payer, address receiver, uint256 lpAmount, uint256 deadline, bool unwrap) external returns (uint256[] memory withdrawAmounts);
|
||||||
@@ -149,9 +149,9 @@ interface IPartyPool is IERC20Metadata {
|
|||||||
|
|
||||||
/// @notice Swap input token inputTokenIndex -> token outputTokenIndex. Payer must approve token inputTokenIndex.
|
/// @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.
|
/// @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.
|
/// Non-standard _tokens (fee-on-transfer, rebasers) are rejected via balance checks.
|
||||||
/// @param payer address of the account that pays for the swap
|
/// @param payer address of the account that pays for the swap
|
||||||
/// @param receiver address that will receive the output tokens
|
/// @param receiver address that will receive the output _tokens
|
||||||
/// @param inputTokenIndex index of input asset
|
/// @param inputTokenIndex index of input asset
|
||||||
/// @param outputTokenIndex index of output asset
|
/// @param outputTokenIndex index of output asset
|
||||||
/// @param maxAmountIn maximum amount of token inputTokenIndex (uint256) to transfer in (inclusive of fees)
|
/// @param maxAmountIn maximum amount of token inputTokenIndex (uint256) to transfer in (inclusive of fees)
|
||||||
@@ -173,7 +173,7 @@ interface IPartyPool is IERC20Metadata {
|
|||||||
/// @dev If balances prevent fully reaching the limit, the function caps and returns actuals.
|
/// @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.
|
/// The payer must transfer the exact gross input computed by the view.
|
||||||
/// @param payer address of the account that pays for the swap
|
/// @param payer address of the account that pays for the swap
|
||||||
/// @param receiver address that will receive the output tokens
|
/// @param receiver address that will receive the output _tokens
|
||||||
/// @param inputTokenIndex index of input asset
|
/// @param inputTokenIndex index of input asset
|
||||||
/// @param outputTokenIndex index of output asset
|
/// @param outputTokenIndex index of output asset
|
||||||
/// @param limitPrice target marginal price to reach (must be > 0)
|
/// @param limitPrice target marginal price to reach (must be > 0)
|
||||||
@@ -193,7 +193,7 @@ interface IPartyPool is IERC20Metadata {
|
|||||||
/// @dev swapMint executes as an exact-in planned swap followed by proportional scaling of qInternal.
|
/// @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.
|
/// The function emits SwapMint (gross, net, fee) and also emits Mint for LP issuance.
|
||||||
/// @param payer who transfers the input token
|
/// @param payer who transfers the input token
|
||||||
/// @param receiver who receives the minted LP tokens
|
/// @param receiver who receives the minted LP _tokens
|
||||||
/// @param inputTokenIndex index of the input token
|
/// @param inputTokenIndex index of the input token
|
||||||
/// @param maxAmountIn maximum uint token input (inclusive of fee)
|
/// @param maxAmountIn maximum uint token input (inclusive of fee)
|
||||||
/// @param deadline optional deadline
|
/// @param deadline optional deadline
|
||||||
@@ -206,11 +206,11 @@ interface IPartyPool is IERC20Metadata {
|
|||||||
uint256 deadline
|
uint256 deadline
|
||||||
) external payable returns (uint256 lpMinted);
|
) external payable returns (uint256 lpMinted);
|
||||||
|
|
||||||
/// @notice Burn LP tokens then swap the redeemed proportional basket into a single asset `inputTokenIndex` and send to receiver.
|
/// @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.
|
/// @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 payer who burns LP _tokens
|
||||||
/// @param receiver who receives the single asset
|
/// @param receiver who receives the single asset
|
||||||
/// @param lpAmount amount of LP tokens to burn
|
/// @param lpAmount amount of LP _tokens to burn
|
||||||
/// @param inputTokenIndex index of target asset to receive
|
/// @param inputTokenIndex index of target asset to receive
|
||||||
/// @param deadline optional deadline
|
/// @param deadline optional deadline
|
||||||
/// @return amountOutUint uint amount of asset inputTokenIndex sent to receiver
|
/// @return amountOutUint uint amount of asset inputTokenIndex sent to receiver
|
||||||
@@ -225,9 +225,9 @@ interface IPartyPool is IERC20Metadata {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @dev Initiate a flash loan.
|
* @dev Initiate a flash loan.
|
||||||
* @param receiver The receiver of the tokens in the loan, and the receiver of the callback.
|
* @param receiver The receiver of the _tokens in the loan, and the receiver of the callback.
|
||||||
* @param token The loan currency.
|
* @param token The loan currency.
|
||||||
* @param amount The amount of tokens lent.
|
* @param amount The amount of _tokens lent.
|
||||||
* @param data Arbitrary data structure, intended to contain user-defined parameters.
|
* @param data Arbitrary data structure, intended to contain user-defined parameters.
|
||||||
*/
|
*/
|
||||||
function flashLoan(
|
function flashLoan(
|
||||||
|
|||||||
@@ -22,9 +22,9 @@ interface IPartyPoolViewer {
|
|||||||
|
|
||||||
/// @notice Calculate the proportional deposit amounts required for a given LP token amount
|
/// @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
|
/// @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
|
/// 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().
|
/// because the initial deposit is handled by transferring _tokens then calling mint().
|
||||||
/// @param lpTokenAmount The amount of LP tokens desired
|
/// @param lpTokenAmount The amount of LP _tokens desired
|
||||||
/// @return depositAmounts Array of token amounts to deposit (rounded up)
|
/// @return depositAmounts Array of token amounts to deposit (rounded up)
|
||||||
function mintAmounts(IPartyPool pool, uint256 lpTokenAmount) external view returns (uint256[] memory depositAmounts);
|
function mintAmounts(IPartyPool pool, uint256 lpTokenAmount) external view returns (uint256[] memory depositAmounts);
|
||||||
|
|
||||||
@@ -51,7 +51,7 @@ interface IPartyPoolViewer {
|
|||||||
|
|
||||||
/// @notice Calculate the amounts for a burn swap operation
|
/// @notice Calculate the amounts for a burn swap operation
|
||||||
/// @dev This is a pure view function that computes burn swap amounts from provided state
|
/// @dev This is a pure view function that computes burn swap amounts from provided state
|
||||||
/// @param lpAmount amount of LP tokens to burn
|
/// @param lpAmount amount of LP _tokens to burn
|
||||||
/// @param inputTokenIndex index of target asset to receive
|
/// @param inputTokenIndex index of target asset to receive
|
||||||
function burnSwapAmounts(IPartyPool pool, uint256 lpAmount, uint256 inputTokenIndex) external view
|
function burnSwapAmounts(IPartyPool pool, uint256 lpAmount, uint256 inputTokenIndex) external view
|
||||||
returns (uint256 amountOut);
|
returns (uint256 amountOut);
|
||||||
@@ -71,7 +71,7 @@ interface IPartyPoolViewer {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @dev The fee to be charged for a given loan.
|
* @dev The fee to be charged for a given loan.
|
||||||
* @param amount The amount of tokens lent.
|
* @param amount The amount of _tokens lent.
|
||||||
* @return fee The amount of `token` to be charged for the loan, on top of the returned principal.
|
* @return fee The amount of `token` to be charged for the loan, on top of the returned principal.
|
||||||
*/
|
*/
|
||||||
function flashFee(IPartyPool pool, address token, uint256 amount) external view returns (uint256 fee);
|
function flashFee(IPartyPool pool, address token, uint256 amount) external view returns (uint256 fee);
|
||||||
|
|||||||
@@ -119,7 +119,7 @@ contract PartyPlanner is IPartyPlanner {
|
|||||||
_allPools.push(pool);
|
_allPools.push(pool);
|
||||||
_poolSupported[pool] = true;
|
_poolSupported[pool] = true;
|
||||||
|
|
||||||
// Track tokens and populate mappings
|
// Track _tokens and populate mappings
|
||||||
for (uint256 i = 0; i < _tokens.length; i++) {
|
for (uint256 i = 0; i < _tokens.length; i++) {
|
||||||
IERC20 token = _tokens[i];
|
IERC20 token = _tokens[i];
|
||||||
|
|
||||||
@@ -135,7 +135,7 @@ contract PartyPlanner is IPartyPlanner {
|
|||||||
|
|
||||||
emit PartyStarted(pool, name_, symbol_, _tokens);
|
emit PartyStarted(pool, name_, symbol_, _tokens);
|
||||||
|
|
||||||
// Transfer initial tokens from payer to the pool
|
// Transfer initial _tokens from payer to the pool
|
||||||
for (uint256 i = 0; i < _tokens.length; i++) {
|
for (uint256 i = 0; i < _tokens.length; i++) {
|
||||||
if (initialDeposits[i] > 0) {
|
if (initialDeposits[i] > 0) {
|
||||||
IERC20(_tokens[i]).safeTransferFrom(payer, address(pool), initialDeposits[i]);
|
IERC20(_tokens[i]).safeTransferFrom(payer, address(pool), initialDeposits[i]);
|
||||||
@@ -143,7 +143,7 @@ contract PartyPlanner is IPartyPlanner {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Call mint on the new pool to initialize it with the transferred tokens
|
// Call mint on the new pool to initialize it with the transferred _tokens
|
||||||
lpAmount = pool.initialMint(receiver, initialLpAmount);
|
lpAmount = pool.initialMint(receiver, initialLpAmount);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -240,7 +240,7 @@ contract PartyPlanner is IPartyPlanner {
|
|||||||
return new address[](0);
|
return new address[](0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate actual number of tokens to return (respecting bounds)
|
// Calculate actual number of _tokens to return (respecting bounds)
|
||||||
uint256 itemsToReturn = (offset + limit > totalTokens) ? (totalTokens - offset) : limit;
|
uint256 itemsToReturn = (offset + limit > totalTokens) ? (totalTokens - offset) : limit;
|
||||||
|
|
||||||
// Create result array of appropriate size
|
// Create result array of appropriate size
|
||||||
|
|||||||
@@ -23,12 +23,12 @@ import {IWETH9} from "./IWETH9.sol";
|
|||||||
/// @notice A multi-asset liquidity pool backed by the LMSRStabilized pricing model.
|
/// @notice A multi-asset liquidity pool backed by the LMSRStabilized pricing model.
|
||||||
/// The pool issues an ERC20 LP token representing proportional ownership.
|
/// The pool issues an ERC20 LP token representing proportional ownership.
|
||||||
/// It supports:
|
/// It supports:
|
||||||
/// - Proportional minting and burning of LP tokens,
|
/// - Proportional minting and burning of LP _tokens,
|
||||||
/// - Single-token mint (swapMint) and single-asset withdrawal (burnSwap),
|
/// - Single-token mint (swapMint) and single-asset withdrawal (burnSwap),
|
||||||
/// - Exact-input swaps and swaps-to-price-limits,
|
/// - Exact-input swaps and swaps-to-price-limits,
|
||||||
/// - Flash loans via a callback interface.
|
/// - Flash loans via a callback interface.
|
||||||
///
|
///
|
||||||
/// @dev The contract stores per-token uint "bases" used to scale token units into the internal Q64.64
|
/// @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.
|
/// 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
|
/// 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).
|
/// (i.e., floor outputs to users, ceil inputs/fees where appropriate).
|
||||||
@@ -59,12 +59,12 @@ contract PartyPool is PartyPoolBase, ERC20External, IPartyPool {
|
|||||||
uint256 private immutable PROTOCOL_FEE_PPM;
|
uint256 private immutable PROTOCOL_FEE_PPM;
|
||||||
function protocolFeePpm() external view returns (uint256) { return PROTOCOL_FEE_PPM; }
|
function protocolFeePpm() external view returns (uint256) { return PROTOCOL_FEE_PPM; }
|
||||||
|
|
||||||
/// @notice Address to which collected protocol tokens will be sent on collectProtocolFees()
|
/// @notice Address to which collected protocol _tokens will be sent on collectProtocolFees()
|
||||||
address private immutable PROTOCOL_FEE_ADDRESS;
|
address private immutable PROTOCOL_FEE_ADDRESS;
|
||||||
function protocolFeeAddress() external view returns (address) { return PROTOCOL_FEE_ADDRESS; }
|
function protocolFeeAddress() external view returns (address) { return PROTOCOL_FEE_ADDRESS; }
|
||||||
|
|
||||||
// @inheritdoc IPartyPool
|
// @inheritdoc IPartyPool
|
||||||
function allProtocolFeesOwed() external view returns (uint256[] memory) { return protocolFeesOwed; }
|
function allProtocolFeesOwed() external view returns (uint256[] memory) { return _protocolFeesOwed; }
|
||||||
|
|
||||||
/// @notice Address of the Mint implementation contract for delegatecall
|
/// @notice Address of the Mint implementation contract for delegatecall
|
||||||
PartyPoolMintImpl private immutable MINT_IMPL;
|
PartyPoolMintImpl private immutable MINT_IMPL;
|
||||||
@@ -76,24 +76,24 @@ contract PartyPool is PartyPoolBase, ERC20External, IPartyPool {
|
|||||||
|
|
||||||
|
|
||||||
/// @inheritdoc IPartyPool
|
/// @inheritdoc IPartyPool
|
||||||
function getToken(uint256 i) external view returns (IERC20) { return tokens[i]; }
|
function getToken(uint256 i) external view returns (IERC20) { return _tokens[i]; }
|
||||||
|
|
||||||
/// @inheritdoc IPartyPool
|
/// @inheritdoc IPartyPool
|
||||||
function numTokens() external view returns (uint256) { return tokens.length; }
|
function numTokens() external view returns (uint256) { return _tokens.length; }
|
||||||
|
|
||||||
/// @inheritdoc IPartyPool
|
/// @inheritdoc IPartyPool
|
||||||
function allTokens() external view returns (IERC20[] memory) { return tokens; }
|
function allTokens() external view returns (IERC20[] memory) { return _tokens; }
|
||||||
|
|
||||||
/// @inheritdoc IPartyPool
|
/// @inheritdoc IPartyPool
|
||||||
function denominators() external view returns (uint256[] memory) { return bases; }
|
function denominators() external view returns (uint256[] memory) { return _bases; }
|
||||||
|
|
||||||
function LMSR() external view returns (LMSRStabilized.State memory) { return lmsr; }
|
function LMSR() external view returns (LMSRStabilized.State memory) { return _lmsr; }
|
||||||
|
|
||||||
|
|
||||||
/// @param name_ LP token name
|
/// @param name_ LP token name
|
||||||
/// @param symbol_ LP token symbol
|
/// @param symbol_ LP token symbol
|
||||||
/// @param tokens_ token addresses (n)
|
/// @param tokens_ token addresses (n)
|
||||||
/// @param bases_ scaling bases for each token (n) - used when converting to/from internal 64.64 amounts
|
/// @param bases_ scaling _bases for each token (n) - used when converting to/from internal 64.64 amounts
|
||||||
/// @param kappa_ liquidity parameter κ (Q64.64) used to derive b = κ * S(q)
|
/// @param kappa_ liquidity parameter κ (Q64.64) used to derive b = κ * S(q)
|
||||||
/// @param swapFeePpm_ fee in parts-per-million, taken from swap input amounts before LMSR calculations
|
/// @param swapFeePpm_ fee in parts-per-million, taken from swap input amounts before LMSR calculations
|
||||||
/// @param flashFeePpm_ fee in parts-per-million, taken for flash loans
|
/// @param flashFeePpm_ fee in parts-per-million, taken for flash loans
|
||||||
@@ -107,8 +107,8 @@ contract PartyPool is PartyPoolBase, ERC20External, IPartyPool {
|
|||||||
int128 kappa_,
|
int128 kappa_,
|
||||||
uint256 swapFeePpm_,
|
uint256 swapFeePpm_,
|
||||||
uint256 flashFeePpm_,
|
uint256 flashFeePpm_,
|
||||||
uint256 protocolFeePpm_, // NEW: protocol share of fees (ppm)
|
uint256 protocolFeePpm_,
|
||||||
address protocolFeeAddress_, // NEW: recipient for collected protocol tokens
|
address protocolFeeAddress_,
|
||||||
IWETH9 wrapperToken_,
|
IWETH9 wrapperToken_,
|
||||||
PartyPoolSwapImpl swapImpl_,
|
PartyPoolSwapImpl swapImpl_,
|
||||||
PartyPoolMintImpl mintImpl_
|
PartyPoolMintImpl mintImpl_
|
||||||
@@ -118,14 +118,16 @@ contract PartyPool is PartyPoolBase, ERC20External, IPartyPool {
|
|||||||
{
|
{
|
||||||
require(tokens_.length > 1, "Pool: need >1 asset");
|
require(tokens_.length > 1, "Pool: need >1 asset");
|
||||||
require(tokens_.length == bases_.length, "Pool: lengths mismatch");
|
require(tokens_.length == bases_.length, "Pool: lengths mismatch");
|
||||||
tokens = tokens_;
|
_tokens = tokens_;
|
||||||
bases = bases_;
|
_bases = bases_;
|
||||||
KAPPA = kappa_;
|
KAPPA = kappa_;
|
||||||
require(swapFeePpm_ < 1_000_000, "Pool: fee >= ppm");
|
require(swapFeePpm_ < 1_000_000, "Pool: fee >= ppm");
|
||||||
SWAP_FEE_PPM = swapFeePpm_;
|
SWAP_FEE_PPM = swapFeePpm_;
|
||||||
require(flashFeePpm_ < 1_000_000, "Pool: flash fee >= ppm");
|
require(flashFeePpm_ < 1_000_000, "Pool: flash fee >= ppm");
|
||||||
FLASH_FEE_PPM = flashFeePpm_;
|
FLASH_FEE_PPM = flashFeePpm_;
|
||||||
require(protocolFeePpm_ < 1_000_000, "Pool: protocol fee >= ppm");
|
require(protocolFeePpm_ < 1_000_000, "Pool: protocol fee >= ppm");
|
||||||
|
// If the protocolFeePpm_ is set, then also require the fee address to be nonzero
|
||||||
|
require(protocolFeePpm_ == 0 || protocolFeeAddress_ != address(0));
|
||||||
PROTOCOL_FEE_PPM = protocolFeePpm_;
|
PROTOCOL_FEE_PPM = protocolFeePpm_;
|
||||||
PROTOCOL_FEE_ADDRESS = protocolFeeAddress_;
|
PROTOCOL_FEE_ADDRESS = protocolFeeAddress_;
|
||||||
SWAP_IMPL = swapImpl_;
|
SWAP_IMPL = swapImpl_;
|
||||||
@@ -134,17 +136,17 @@ contract PartyPool is PartyPoolBase, ERC20External, IPartyPool {
|
|||||||
uint256 n = tokens_.length;
|
uint256 n = tokens_.length;
|
||||||
|
|
||||||
// Initialize LMSR state nAssets; full init occurs on first mint when quantities are known.
|
// Initialize LMSR state nAssets; full init occurs on first mint when quantities are known.
|
||||||
lmsr.nAssets = n;
|
_lmsr.nAssets = n;
|
||||||
|
|
||||||
// Initialize token address to index mapping
|
// Initialize token address to index mapping
|
||||||
for (uint i = 0; i < n;) {
|
for (uint i = 0; i < n;) {
|
||||||
tokenAddressToIndexPlusOne[tokens_[i]] = i + 1;
|
_tokenAddressToIndexPlusOne[tokens_[i]] = i + 1;
|
||||||
unchecked {i++;}
|
unchecked {i++;}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize caches to zero and protocol ledger
|
// Initialize caches to zero and protocol ledger
|
||||||
cachedUintBalances = new uint256[](n);
|
_cachedUintBalances = new uint256[](n);
|
||||||
protocolFeesOwed = new uint256[](n);
|
_protocolFeesOwed = new uint256[](n);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -167,9 +169,9 @@ contract PartyPool is PartyPoolBase, ERC20External, IPartyPool {
|
|||||||
|
|
||||||
/// @notice Proportional mint for existing pool.
|
/// @notice Proportional mint for existing pool.
|
||||||
/// @dev This function forwards the call to the mint implementation via delegatecall
|
/// @dev This function forwards the call to the mint implementation via delegatecall
|
||||||
/// @param payer address that provides the input tokens
|
/// @param payer address that provides the input _tokens
|
||||||
/// @param receiver address that receives the LP tokens
|
/// @param receiver address that receives the LP _tokens
|
||||||
/// @param lpTokenAmount desired amount of LP tokens to mint
|
/// @param lpTokenAmount desired amount of LP _tokens to mint
|
||||||
/// @param deadline timestamp after which the transaction will revert. Pass 0 to ignore.
|
/// @param deadline timestamp after which the transaction will revert. Pass 0 to ignore.
|
||||||
function mint(address payer, address receiver, uint256 lpTokenAmount, uint256 deadline) external payable
|
function mint(address payer, address receiver, uint256 lpTokenAmount, uint256 deadline) external payable
|
||||||
returns (uint256 lpMinted) {
|
returns (uint256 lpMinted) {
|
||||||
@@ -231,36 +233,36 @@ contract PartyPool is PartyPoolBase, ERC20External, IPartyPool {
|
|||||||
_quoteSwapExactIn(inputTokenIndex, outputTokenIndex, maxAmountIn, limitPrice);
|
_quoteSwapExactIn(inputTokenIndex, outputTokenIndex, maxAmountIn, limitPrice);
|
||||||
|
|
||||||
// Cache token references for fewer SLOADs
|
// Cache token references for fewer SLOADs
|
||||||
IERC20 tokenIn = tokens[inputTokenIndex];
|
IERC20 tokenIn = _tokens[inputTokenIndex];
|
||||||
IERC20 tokenOut = tokens[outputTokenIndex];
|
IERC20 tokenOut = _tokens[outputTokenIndex];
|
||||||
|
|
||||||
// Transfer tokens in via centralized helper
|
// Transfer _tokens in via centralized helper
|
||||||
_receiveTokenFrom(payer, tokenIn, totalTransferAmount);
|
_receiveTokenFrom(payer, tokenIn, totalTransferAmount);
|
||||||
|
|
||||||
// Compute on-chain balances as: onchain = cached + owed (+/- transfer)
|
// Compute on-chain balances as: onchain = cached + owed (+/- transfer)
|
||||||
uint256 balIAfter = cachedUintBalances[inputTokenIndex] + protocolFeesOwed[inputTokenIndex] + totalTransferAmount;
|
uint256 balIAfter = _cachedUintBalances[inputTokenIndex] + _protocolFeesOwed[inputTokenIndex] + totalTransferAmount;
|
||||||
uint256 balJAfter = cachedUintBalances[outputTokenIndex] + protocolFeesOwed[outputTokenIndex] - amountOutUint;
|
uint256 balJAfter = _cachedUintBalances[outputTokenIndex] + _protocolFeesOwed[outputTokenIndex] - amountOutUint;
|
||||||
|
|
||||||
// Transfer output to receiver via centralized helper
|
|
||||||
_sendTokenTo(tokenOut, receiver, amountOutUint, unwrap);
|
|
||||||
|
|
||||||
// Accrue protocol share (floor) from the fee on input token
|
// Accrue protocol share (floor) from the fee on input token
|
||||||
if (PROTOCOL_FEE_PPM > 0 && feeUint > 0) {
|
if (PROTOCOL_FEE_PPM > 0 && feeUint > 0) {
|
||||||
uint256 protoShare = (feeUint * PROTOCOL_FEE_PPM) / 1_000_000; // floor
|
uint256 protoShare = (feeUint * PROTOCOL_FEE_PPM) / 1_000_000; // floor
|
||||||
if (protoShare > 0) {
|
if (protoShare > 0) {
|
||||||
protocolFeesOwed[inputTokenIndex] += protoShare;
|
_protocolFeesOwed[inputTokenIndex] += protoShare;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Inline _recordCachedBalance: ensure onchain >= owed then set cached = onchain - owed
|
// Inline _recordCachedBalance: ensure onchain >= owed then set cached = onchain - owed
|
||||||
require(balIAfter >= protocolFeesOwed[inputTokenIndex], "balance < protocol owed");
|
require(balIAfter >= _protocolFeesOwed[inputTokenIndex], "balance < protocol owed");
|
||||||
cachedUintBalances[inputTokenIndex] = balIAfter - protocolFeesOwed[inputTokenIndex];
|
_cachedUintBalances[inputTokenIndex] = balIAfter - _protocolFeesOwed[inputTokenIndex];
|
||||||
|
|
||||||
require(balJAfter >= protocolFeesOwed[outputTokenIndex], "balance < protocol owed");
|
require(balJAfter >= _protocolFeesOwed[outputTokenIndex], "balance < protocol owed");
|
||||||
cachedUintBalances[outputTokenIndex] = balJAfter - protocolFeesOwed[outputTokenIndex];
|
_cachedUintBalances[outputTokenIndex] = balJAfter - _protocolFeesOwed[outputTokenIndex];
|
||||||
|
|
||||||
// Apply swap to LMSR state with the internal amounts actually used
|
// Apply swap to LMSR state with the internal amounts actually used
|
||||||
lmsr.applySwap(inputTokenIndex, outputTokenIndex, amountInInternalUsed, amountOutInternal);
|
_lmsr.applySwap(inputTokenIndex, outputTokenIndex, amountInInternalUsed, amountOutInternal);
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
|
||||||
@@ -289,13 +291,13 @@ contract PartyPool is PartyPoolBase, ERC20External, IPartyPool {
|
|||||||
uint256 feeUint
|
uint256 feeUint
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
uint256 n = tokens.length;
|
uint256 n = _tokens.length;
|
||||||
|
|
||||||
// Estimate max net input (fee on gross rounded up, then subtract)
|
// Estimate max net input (fee on gross rounded up, then subtract)
|
||||||
(, uint256 netUintForSwap) = _computeFee(maxAmountIn, SWAP_FEE_PPM);
|
(, uint256 netUintForSwap) = _computeFee(maxAmountIn, SWAP_FEE_PPM);
|
||||||
|
|
||||||
// Convert to internal (floor)
|
// Convert to internal (floor)
|
||||||
int128 deltaInternalI = _uintToInternalFloor(netUintForSwap, bases[inputTokenIndex]);
|
int128 deltaInternalI = _uintToInternalFloor(netUintForSwap, _bases[inputTokenIndex]);
|
||||||
require(deltaInternalI > int128(0), "swap: input too small after fee");
|
require(deltaInternalI > int128(0), "swap: input too small after fee");
|
||||||
|
|
||||||
// Compute internal amounts using LMSR (exact-input with price limit)
|
// Compute internal amounts using LMSR (exact-input with price limit)
|
||||||
@@ -303,7 +305,7 @@ contract PartyPool is PartyPoolBase, ERC20External, IPartyPool {
|
|||||||
(amountInInternalUsed, amountOutInternal) = _swapAmountsForExactInput(inputTokenIndex, outputTokenIndex, deltaInternalI, limitPrice);
|
(amountInInternalUsed, amountOutInternal) = _swapAmountsForExactInput(inputTokenIndex, outputTokenIndex, deltaInternalI, limitPrice);
|
||||||
|
|
||||||
// Convert actual used input internal -> uint (ceil)
|
// Convert actual used input internal -> uint (ceil)
|
||||||
amountInUintNoFee = _internalToUintCeil(amountInInternalUsed, bases[inputTokenIndex]);
|
amountInUintNoFee = _internalToUintCeil(amountInInternalUsed, _bases[inputTokenIndex]);
|
||||||
|
|
||||||
// Compute gross transfer including fee on the used input (ceil)
|
// Compute gross transfer including fee on the used input (ceil)
|
||||||
feeUint = 0;
|
feeUint = 0;
|
||||||
@@ -317,7 +319,7 @@ contract PartyPool is PartyPoolBase, ERC20External, IPartyPool {
|
|||||||
require(grossIn <= maxAmountIn, "swap: transfer exceeds max");
|
require(grossIn <= maxAmountIn, "swap: transfer exceeds max");
|
||||||
|
|
||||||
// Compute output (floor)
|
// Compute output (floor)
|
||||||
amountOutUint = _internalToUintFloor(amountOutInternal, bases[outputTokenIndex]);
|
amountOutUint = _internalToUintFloor(amountOutInternal, _bases[outputTokenIndex]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -351,7 +353,7 @@ contract PartyPool is PartyPoolBase, ERC20External, IPartyPool {
|
|||||||
/// @notice Single-token mint: deposit a single token, charge swap-LMSR cost, and mint LP.
|
/// @notice Single-token mint: deposit a single token, charge swap-LMSR cost, and mint LP.
|
||||||
/// @dev This function forwards the call to the swapMint implementation via delegatecall
|
/// @dev This function forwards the call to the swapMint implementation via delegatecall
|
||||||
/// @param payer who transfers the input token
|
/// @param payer who transfers the input token
|
||||||
/// @param receiver who receives the minted LP tokens
|
/// @param receiver who receives the minted LP _tokens
|
||||||
/// @param inputTokenIndex index of the input token
|
/// @param inputTokenIndex index of the input token
|
||||||
/// @param maxAmountIn maximum uint token input (inclusive of fee)
|
/// @param maxAmountIn maximum uint token input (inclusive of fee)
|
||||||
/// @param deadline optional deadline
|
/// @param deadline optional deadline
|
||||||
@@ -378,11 +380,11 @@ contract PartyPool is PartyPoolBase, ERC20External, IPartyPool {
|
|||||||
return abi.decode(result, (uint256));
|
return abi.decode(result, (uint256));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @notice Burn LP tokens then swap the redeemed proportional basket into a single asset `inputTokenIndex` and send to receiver.
|
/// @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
|
/// @dev This function forwards the call to the burnSwap implementation via delegatecall
|
||||||
/// @param payer who burns LP tokens
|
/// @param payer who burns LP _tokens
|
||||||
/// @param receiver who receives the single asset
|
/// @param receiver who receives the single asset
|
||||||
/// @param lpAmount amount of LP tokens to burn
|
/// @param lpAmount amount of LP _tokens to burn
|
||||||
/// @param inputTokenIndex index of target asset to receive
|
/// @param inputTokenIndex index of target asset to receive
|
||||||
/// @param deadline optional deadline
|
/// @param deadline optional deadline
|
||||||
/// @return amountOutUint uint amount of asset i sent to receiver
|
/// @return amountOutUint uint amount of asset i sent to receiver
|
||||||
@@ -414,10 +416,10 @@ contract PartyPool is PartyPoolBase, ERC20External, IPartyPool {
|
|||||||
bytes32 internal constant FLASH_CALLBACK_SUCCESS = keccak256("ERC3156FlashBorrower.onFlashLoan");
|
bytes32 internal constant FLASH_CALLBACK_SUCCESS = keccak256("ERC3156FlashBorrower.onFlashLoan");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @dev Loan `amount` tokens to `receiver`, and takes it back plus a `flashFee` after the callback.
|
* @dev Loan `amount` _tokens to `receiver`, and takes it back plus a `flashFee` after the callback.
|
||||||
* @param receiver The contract receiving the tokens, needs to implement the `onFlashLoan(address user, uint256 amount, uint256 fee, bytes calldata)` interface.
|
* @param receiver The contract receiving the _tokens, needs to implement the `onFlashLoan(address user, uint256 amount, uint256 fee, bytes calldata)` interface.
|
||||||
* @param tokenAddr The loan currency.
|
* @param tokenAddr The loan currency.
|
||||||
* @param amount The amount of tokens lent.
|
* @param amount The amount of _tokens lent.
|
||||||
* @param data A data parameter to be passed on to the `receiver` for any custom use.
|
* @param data A data parameter to be passed on to the `receiver` for any custom use.
|
||||||
*/
|
*/
|
||||||
function flashLoan(
|
function flashLoan(
|
||||||
@@ -429,26 +431,28 @@ contract PartyPool is PartyPoolBase, ERC20External, IPartyPool {
|
|||||||
{
|
{
|
||||||
IERC20 token = IERC20(tokenAddr);
|
IERC20 token = IERC20(tokenAddr);
|
||||||
require(amount <= token.balanceOf(address(this)));
|
require(amount <= token.balanceOf(address(this)));
|
||||||
uint256 tokenIndex = tokenAddressToIndexPlusOne[token] - 1;
|
uint256 tokenIndex = _tokenAddressToIndexPlusOne[token];
|
||||||
|
require(tokenIndex != 0, 'flash: token not in pool');
|
||||||
|
tokenIndex -= 1;
|
||||||
(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
|
||||||
if (PROTOCOL_FEE_PPM > 0 && fee > 0) {
|
if (PROTOCOL_FEE_PPM > 0 && fee > 0) {
|
||||||
uint256 protoShare = (fee * PROTOCOL_FEE_PPM) / 1_000_000; // floor
|
uint256 protoShare = (fee * PROTOCOL_FEE_PPM) / 1_000_000; // floor
|
||||||
if (protoShare > 0) {
|
if (protoShare > 0) {
|
||||||
protocolFeesOwed[tokenIndex] += protoShare;
|
_protocolFeesOwed[tokenIndex] += protoShare;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_sendTokenTo(token, address(receiver), amount, false);
|
_sendTokenTo(token, address(receiver), amount, false);
|
||||||
require(receiver.onFlashLoan(msg.sender, address(token), amount, fee, data) == FLASH_CALLBACK_SUCCESS);
|
require(receiver.onFlashLoan(address(receiver), address(token), amount, fee, data) == FLASH_CALLBACK_SUCCESS);
|
||||||
_receiveTokenFrom(address(receiver), token, amount + fee);
|
_receiveTokenFrom(address(receiver), token, amount + fee);
|
||||||
|
|
||||||
// Update cached balance for the borrowed token
|
// Update cached balance for the borrowed token
|
||||||
uint256 balAfter = token.balanceOf(address(this));
|
uint256 balAfter = token.balanceOf(address(this));
|
||||||
// Inline _recordCachedBalance logic
|
// Inline _recordCachedBalance logic
|
||||||
require(balAfter >= protocolFeesOwed[tokenIndex], "balance < protocol owed");
|
require(balAfter >= _protocolFeesOwed[tokenIndex], "balance < protocol owed");
|
||||||
cachedUintBalances[tokenIndex] = balAfter - protocolFeesOwed[tokenIndex];
|
_cachedUintBalances[tokenIndex] = balAfter - _protocolFeesOwed[tokenIndex];
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -460,23 +464,23 @@ contract PartyPool is PartyPoolBase, ERC20External, IPartyPool {
|
|||||||
address dest = PROTOCOL_FEE_ADDRESS;
|
address dest = PROTOCOL_FEE_ADDRESS;
|
||||||
require(dest != address(0), "collect: zero addr");
|
require(dest != address(0), "collect: zero addr");
|
||||||
|
|
||||||
uint256 n = tokens.length;
|
uint256 n = _tokens.length;
|
||||||
for (uint256 i = 0; i < n; i++) {
|
for (uint256 i = 0; i < n; i++) {
|
||||||
uint256 owed = protocolFeesOwed[i];
|
uint256 owed = _protocolFeesOwed[i];
|
||||||
if (owed == 0) continue;
|
if (owed == 0) continue;
|
||||||
uint256 bal = IERC20(tokens[i]).balanceOf(address(this));
|
uint256 bal = IERC20(_tokens[i]).balanceOf(address(this));
|
||||||
require(bal >= owed, "collect: fee > bal");
|
require(bal >= owed, "collect: fee > bal");
|
||||||
protocolFeesOwed[i] = 0;
|
_protocolFeesOwed[i] = 0;
|
||||||
// transfer owed tokens to protocol destination via centralized helper
|
|
||||||
_sendTokenTo(tokens[i], dest, owed, false);
|
|
||||||
// update cached to effective onchain minus owed
|
// update cached to effective onchain minus owed
|
||||||
cachedUintBalances[i] = bal - owed;
|
_cachedUintBalances[i] = bal - owed;
|
||||||
|
// transfer owed _tokens to protocol destination via centralized helper
|
||||||
|
_sendTokenTo(_tokens[i], dest, owed, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function _swapAmountsForExactInput(uint256 i, uint256 j, int128 a, int128 limitPrice) internal virtual view
|
function _swapAmountsForExactInput(uint256 i, uint256 j, int128 a, int128 limitPrice) internal virtual view
|
||||||
returns (int128 amountIn, int128 amountOut) {
|
returns (int128 amountIn, int128 amountOut) {
|
||||||
return lmsr.swapAmountsForExactInput(i, j, a, limitPrice);
|
return _lmsr.swapAmountsForExactInput(i, j, a, limitPrice);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,6 +28,6 @@ contract PartyPoolBalancedPair is PartyPool {
|
|||||||
|
|
||||||
function _swapAmountsForExactInput(uint256 i, uint256 j, int128 a, int128 limitPrice) internal virtual override view
|
function _swapAmountsForExactInput(uint256 i, uint256 j, int128 a, int128 limitPrice) internal virtual override view
|
||||||
returns (int128 amountIn, int128 amountOut) {
|
returns (int128 amountIn, int128 amountOut) {
|
||||||
return LMSRStabilizedBalancedPair.swapAmountsForExactInput(lmsr, i, j, a, limitPrice);
|
return LMSRStabilizedBalancedPair.swapAmountsForExactInput(_lmsr, i, j, a, limitPrice);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,31 +37,31 @@ abstract contract PartyPoolBase is ERC20Internal, ReentrancyGuard, PartyPoolHelp
|
|||||||
//
|
//
|
||||||
|
|
||||||
// LMSR internal state
|
// LMSR internal state
|
||||||
LMSRStabilized.State internal lmsr;
|
LMSRStabilized.State internal _lmsr;
|
||||||
|
|
||||||
/// @notice Scale factor used when converting LMSR Q64.64 totals to LP token units (uint).
|
/// @notice Scale factor used when converting LMSR Q64.64 totals to LP token units (uint).
|
||||||
/// @dev LP tokens are minted in units equal to ABDK.mulu(lastTotalQ64x64, LP_SCALE).
|
/// @dev LP _tokens are minted in units equal to ABDK.mulu(lastTotalQ64x64, LP_SCALE).
|
||||||
uint256 internal constant LP_SCALE = 1e18; // Scale used to convert LMSR lastTotal (Q64.64) into LP token units (uint)
|
uint256 internal constant LP_SCALE = 1e18; // Scale used to convert LMSR lastTotal (Q64.64) into LP token units (uint)
|
||||||
|
|
||||||
/// @notice Token addresses comprising the pool. Effectively immutable after construction.
|
/// @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.
|
/// @dev _tokens[i] corresponds to the i-th asset and maps to index i in the internal LMSR arrays.
|
||||||
IERC20[] internal tokens; // effectively immutable since there is no interface to change the tokens
|
IERC20[] internal _tokens; // effectively immutable since there is no interface to change the _tokens
|
||||||
|
|
||||||
/// @notice Amounts of token owed as protocol fees but not yet collected. Subtract this amount from the pool's token
|
/// @notice Amounts of token owed as protocol fees but not yet collected. Subtract this amount from the pool's token
|
||||||
/// balances to compute the tokens owned by LP's.
|
/// balances to compute the _tokens owned by LP's.
|
||||||
uint256[] internal protocolFeesOwed;
|
uint256[] internal _protocolFeesOwed;
|
||||||
|
|
||||||
/// @notice Per-token uint base denominators used to convert uint token amounts <-> internal Q64.64 representation.
|
/// @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.
|
/// @dev denominators()[i] is the base for _tokens[i]. These _bases are chosen by deployer and must match token decimals.
|
||||||
uint256[] internal bases; // per-token uint base used to scale token amounts <-> internal
|
uint256[] internal _bases; // per-token uint base used to scale token amounts <-> internal
|
||||||
|
|
||||||
/// @notice Mapping from token address => (index+1). A zero value indicates the token is not in the pool.
|
/// @notice Mapping from token address => (index+1). A zero value indicates the token is not in the pool.
|
||||||
/// @dev Use index = tokenAddressToIndexPlusOne[token] - 1 when non-zero.
|
/// @dev Use index = _tokenAddressToIndexPlusOne[token] - 1 when non-zero.
|
||||||
mapping(IERC20=>uint) internal tokenAddressToIndexPlusOne; // Uses index+1 so a result of 0 indicates a failed lookup
|
mapping(IERC20=>uint) internal _tokenAddressToIndexPlusOne; // Uses index+1 so a result of 0 indicates a failed lookup
|
||||||
|
|
||||||
// Cached on-chain balances (uint) and internal 64.64 representation
|
// Cached on-chain balances (uint) and internal 64.64 representation
|
||||||
// balance / base = internal
|
// balance / base = internal
|
||||||
uint256[] internal cachedUintBalances;
|
uint256[] internal _cachedUintBalances;
|
||||||
|
|
||||||
|
|
||||||
/* ----------------------
|
/* ----------------------
|
||||||
@@ -100,9 +100,9 @@ abstract contract PartyPoolBase is ERC20Internal, ReentrancyGuard, PartyPoolHelp
|
|||||||
Token transfer helpers (includes autowrap)
|
Token transfer helpers (includes autowrap)
|
||||||
---------------------- */
|
---------------------- */
|
||||||
|
|
||||||
/// @notice Receive tokens from `payer` into the pool (address(this)) using SafeERC20 semantics.
|
/// @notice Receive _tokens from `payer` into the pool (address(this)) using SafeERC20 semantics.
|
||||||
/// @dev Note: this helper does NOT query the on-chain balance after transfer to save gas.
|
/// @dev Note: this helper does NOT query the on-chain balance after transfer to save gas.
|
||||||
/// Callers should query the balance themselves when they need it (e.g., to detect fee-on-transfer tokens).
|
/// Callers should query the balance themselves when they need it (e.g., to detect fee-on-transfer _tokens).
|
||||||
function _receiveTokenFrom(address payer, IERC20 token, uint256 amount) internal {
|
function _receiveTokenFrom(address payer, IERC20 token, uint256 amount) internal {
|
||||||
if( token == WRAPPER_TOKEN && msg.value >= amount )
|
if( token == WRAPPER_TOKEN && msg.value >= amount )
|
||||||
WRAPPER_TOKEN.deposit{value:amount}();
|
WRAPPER_TOKEN.deposit{value:amount}();
|
||||||
@@ -110,9 +110,9 @@ abstract contract PartyPoolBase is ERC20Internal, ReentrancyGuard, PartyPoolHelp
|
|||||||
token.safeTransferFrom(payer, address(this), amount);
|
token.safeTransferFrom(payer, address(this), amount);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @notice Send tokens from the pool to `receiver` using SafeERC20 semantics.
|
/// @notice Send _tokens from the pool to `receiver` using SafeERC20 semantics.
|
||||||
/// @dev Note: this helper does NOT query the on-chain balance after transfer to save gas.
|
/// @dev Note: this helper does NOT query the on-chain balance after transfer to save gas.
|
||||||
/// Callers should query the balance themselves when they need it (e.g., to detect fee-on-transfer tokens).
|
/// Callers should query the balance themselves when they need it (e.g., to detect fee-on-transfer _tokens).
|
||||||
function _sendTokenTo(IERC20 token, address receiver, uint256 amount, bool unwrap) internal {
|
function _sendTokenTo(IERC20 token, address receiver, uint256 amount, bool unwrap) internal {
|
||||||
if( unwrap && token == WRAPPER_TOKEN ) {
|
if( unwrap && token == WRAPPER_TOKEN ) {
|
||||||
WRAPPER_TOKEN.withdraw(amount);
|
WRAPPER_TOKEN.withdraw(amount);
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ pragma solidity ^0.8.30;
|
|||||||
|
|
||||||
import {ABDKMath64x64} from "../lib/abdk-libraries-solidity/ABDKMath64x64.sol";
|
import {ABDKMath64x64} from "../lib/abdk-libraries-solidity/ABDKMath64x64.sol";
|
||||||
|
|
||||||
|
|
||||||
abstract contract PartyPoolHelpers {
|
abstract contract PartyPoolHelpers {
|
||||||
using ABDKMath64x64 for int128;
|
using ABDKMath64x64 for int128;
|
||||||
|
|
||||||
@@ -27,21 +26,12 @@ abstract contract PartyPoolHelpers {
|
|||||||
netUint = gross - feeUint;
|
netUint = gross - feeUint;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @notice Convenience: return gross = net + fee(net) using ceiling for fee.
|
|
||||||
/// @param netUint net amount
|
|
||||||
/// @param feePpm fee in ppm to apply
|
|
||||||
function _addFee(uint256 netUint, uint256 feePpm) internal pure returns (uint256 gross) {
|
|
||||||
if (feePpm == 0) return netUint;
|
|
||||||
uint256 fee = _ceilFee(netUint, feePpm);
|
|
||||||
return netUint + fee;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @notice Helper to compute size metric (sum of all asset quantities) from internal balances
|
/// @notice Helper to compute size metric (sum of all asset quantities) from internal balances
|
||||||
/// @dev Returns the sum of all provided qInternal_ entries as a Q64.64 value.
|
/// @dev Returns the sum of all provided qInternal entries as a Q64.64 value.
|
||||||
function _computeSizeMetric(int128[] memory qInternal_) internal pure returns (int128) {
|
function _computeSizeMetric(int128[] memory qInternal) internal pure returns (int128) {
|
||||||
int128 total = int128(0);
|
int128 total = int128(0);
|
||||||
for (uint i = 0; i < qInternal_.length; ) {
|
for (uint i = 0; i < qInternal.length; ) {
|
||||||
total = total.add(qInternal_[i]);
|
total = total.add(qInternal[i]);
|
||||||
unchecked { i++; }
|
unchecked { i++; }
|
||||||
}
|
}
|
||||||
return total;
|
return total;
|
||||||
|
|||||||
@@ -27,27 +27,27 @@ contract PartyPoolMintImpl is PartyPoolBase {
|
|||||||
|
|
||||||
function initialMint(address receiver, uint256 lpTokens, int128 KAPPA) external payable native nonReentrant
|
function initialMint(address receiver, uint256 lpTokens, int128 KAPPA) external payable native nonReentrant
|
||||||
returns (uint256 lpMinted) {
|
returns (uint256 lpMinted) {
|
||||||
uint256 n = tokens.length;
|
uint256 n = _tokens.length;
|
||||||
|
|
||||||
// Check if this is initial deposit - revert if not
|
// Check if this is initial deposit - revert if not
|
||||||
bool isInitialDeposit = _totalSupply == 0 || lmsr.nAssets == 0;
|
bool isInitialDeposit = _totalSupply == 0 || _lmsr.nAssets == 0;
|
||||||
require(isInitialDeposit, "initialMint: pool already initialized");
|
require(isInitialDeposit, "initialMint: pool already initialized");
|
||||||
|
|
||||||
// Update cached balances for all assets
|
// Update cached balances for all assets
|
||||||
int128[] memory newQInternal = new int128[](n);
|
int128[] memory newQInternal = new int128[](n);
|
||||||
uint256[] memory depositAmounts = new uint256[](n);
|
uint256[] memory depositAmounts = new uint256[](n);
|
||||||
for (uint i = 0; i < n; ) {
|
for (uint i = 0; i < n; ) {
|
||||||
uint256 bal = IERC20(tokens[i]).balanceOf(address(this));
|
uint256 bal = IERC20(_tokens[i]).balanceOf(address(this));
|
||||||
cachedUintBalances[i] = bal;
|
_cachedUintBalances[i] = bal;
|
||||||
newQInternal[i] = _uintToInternalFloor(bal, bases[i]);
|
newQInternal[i] = _uintToInternalFloor(bal, _bases[i]);
|
||||||
depositAmounts[i] = bal;
|
depositAmounts[i] = bal;
|
||||||
unchecked { i++; }
|
unchecked { i++; }
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize the stabilized LMSR state with provided kappa
|
// Initialize the stabilized LMSR state with provided kappa
|
||||||
lmsr.init(newQInternal, KAPPA);
|
_lmsr.init(newQInternal, KAPPA);
|
||||||
|
|
||||||
// Compute actual LP tokens to mint based on size metric (scaled)
|
// Compute actual LP _tokens to mint based on size metric (scaled)
|
||||||
if( lpTokens != 0 )
|
if( lpTokens != 0 )
|
||||||
lpMinted = lpTokens;
|
lpMinted = lpTokens;
|
||||||
else {
|
else {
|
||||||
@@ -68,24 +68,24 @@ contract PartyPoolMintImpl is PartyPoolBase {
|
|||||||
function mint(address payer, address receiver, uint256 lpTokenAmount, uint256 deadline) external payable native nonReentrant
|
function mint(address payer, address receiver, uint256 lpTokenAmount, uint256 deadline) external payable native nonReentrant
|
||||||
returns (uint256 lpMinted) {
|
returns (uint256 lpMinted) {
|
||||||
require(deadline == 0 || block.timestamp <= deadline, "mint: deadline exceeded");
|
require(deadline == 0 || block.timestamp <= deadline, "mint: deadline exceeded");
|
||||||
uint256 n = tokens.length;
|
uint256 n = _tokens.length;
|
||||||
|
|
||||||
// Check if this is NOT initial deposit - revert if it is
|
// Check if this is NOT initial deposit - revert if it is
|
||||||
bool isInitialDeposit = _totalSupply == 0 || lmsr.nAssets == 0;
|
bool isInitialDeposit = _totalSupply == 0 || _lmsr.nAssets == 0;
|
||||||
require(!isInitialDeposit, "mint: use initialMint for pool initialization");
|
require(!isInitialDeposit, "mint: use initialMint for pool initialization");
|
||||||
require(lpTokenAmount > 0, "mint: zero LP amount");
|
require(lpTokenAmount > 0, "mint: zero LP amount");
|
||||||
|
|
||||||
// Capture old pool size metric (scaled) by computing from current balances
|
// Capture old pool size metric (scaled) by computing from current balances
|
||||||
int128 oldTotal = _computeSizeMetric(lmsr.qInternal);
|
int128 oldTotal = _computeSizeMetric(_lmsr.qInternal);
|
||||||
uint256 oldScaled = ABDKMath64x64.mulu(oldTotal, LP_SCALE);
|
uint256 oldScaled = ABDKMath64x64.mulu(oldTotal, LP_SCALE);
|
||||||
|
|
||||||
// Calculate required deposit amounts for the desired LP tokens
|
// Calculate required deposit amounts for the desired LP _tokens
|
||||||
uint256[] memory depositAmounts = mintAmounts(lpTokenAmount, lmsr.nAssets, _totalSupply, cachedUintBalances);
|
uint256[] memory depositAmounts = mintAmounts(lpTokenAmount, _lmsr.nAssets, _totalSupply, _cachedUintBalances);
|
||||||
|
|
||||||
// Transfer in all token amounts
|
// Transfer in all token amounts
|
||||||
for (uint i = 0; i < n; ) {
|
for (uint i = 0; i < n; ) {
|
||||||
if (depositAmounts[i] > 0) {
|
if (depositAmounts[i] > 0) {
|
||||||
_receiveTokenFrom(payer, tokens[i], depositAmounts[i]);
|
_receiveTokenFrom(payer, _tokens[i], depositAmounts[i]);
|
||||||
}
|
}
|
||||||
unchecked { i++; }
|
unchecked { i++; }
|
||||||
}
|
}
|
||||||
@@ -93,16 +93,16 @@ contract PartyPoolMintImpl is PartyPoolBase {
|
|||||||
// Update cached balances and internal q for all assets using depositAmounts
|
// Update cached balances and internal q for all assets using depositAmounts
|
||||||
int128[] memory newQInternal = new int128[](n);
|
int128[] memory newQInternal = new int128[](n);
|
||||||
for (uint i = 0; i < n; ) {
|
for (uint i = 0; i < n; ) {
|
||||||
uint256 newBal = cachedUintBalances[i] + depositAmounts[i];
|
uint256 newBal = _cachedUintBalances[i] + depositAmounts[i];
|
||||||
cachedUintBalances[i] = newBal;
|
_cachedUintBalances[i] = newBal;
|
||||||
newQInternal[i] = _uintToInternalFloor(newBal, bases[i]);
|
newQInternal[i] = _uintToInternalFloor(newBal, _bases[i]);
|
||||||
unchecked { i++; }
|
unchecked { i++; }
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update for proportional change
|
// Update for proportional change
|
||||||
lmsr.updateForProportionalChange(newQInternal);
|
_lmsr.updateForProportionalChange(newQInternal);
|
||||||
|
|
||||||
// Compute actual LP tokens to mint based on change in size metric (scaled)
|
// Compute actual LP _tokens to mint based on change in size metric (scaled)
|
||||||
// floor truncation rounds in favor of the pool
|
// floor truncation rounds in favor of the pool
|
||||||
int128 newTotal = _computeSizeMetric(newQInternal);
|
int128 newTotal = _computeSizeMetric(newQInternal);
|
||||||
uint256 newScaled = ABDKMath64x64.mulu(newTotal, LP_SCALE);
|
uint256 newScaled = ABDKMath64x64.mulu(newTotal, LP_SCALE);
|
||||||
@@ -131,18 +131,18 @@ contract PartyPoolMintImpl is PartyPoolBase {
|
|||||||
return actualLpToMint;
|
return actualLpToMint;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @notice Burn LP tokens and withdraw the proportional basket to receiver.
|
/// @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
|
/// @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.
|
/// proportionally to reflect the reduced pool size after the withdrawal.
|
||||||
/// @param payer address that provides the LP tokens to burn
|
/// @param payer address that provides the LP _tokens to burn
|
||||||
/// @param receiver address that receives the withdrawn tokens
|
/// @param receiver address that receives the withdrawn _tokens
|
||||||
/// @param lpAmount amount of LP tokens to burn (proportional withdrawal)
|
/// @param lpAmount amount of LP _tokens to burn (proportional withdrawal)
|
||||||
/// @param deadline timestamp after which the transaction will revert. Pass 0 to ignore.
|
/// @param deadline timestamp after which the transaction will revert. Pass 0 to ignore.
|
||||||
/// @param unwrap if true and the native token is being withdrawn, it is unwraped and sent as native currency
|
/// @param unwrap if true and the native token is being withdrawn, it is unwraped and sent as native currency
|
||||||
function burn(address payer, address receiver, uint256 lpAmount, uint256 deadline, bool unwrap) external nonReentrant
|
function burn(address payer, address receiver, uint256 lpAmount, uint256 deadline, bool unwrap) external nonReentrant
|
||||||
returns (uint256[] memory withdrawAmounts) {
|
returns (uint256[] memory withdrawAmounts) {
|
||||||
require(deadline == 0 || block.timestamp <= deadline, "burn: deadline exceeded");
|
require(deadline == 0 || block.timestamp <= deadline, "burn: deadline exceeded");
|
||||||
uint256 n = tokens.length;
|
uint256 n = _tokens.length;
|
||||||
require(lpAmount > 0, "burn: zero lp");
|
require(lpAmount > 0, "burn: zero lp");
|
||||||
|
|
||||||
uint256 supply = _totalSupply;
|
uint256 supply = _totalSupply;
|
||||||
@@ -151,12 +151,12 @@ contract PartyPoolMintImpl is PartyPoolBase {
|
|||||||
// Use cached balances; assume standard ERC20 transfers without external interference
|
// Use cached balances; assume standard ERC20 transfers without external interference
|
||||||
|
|
||||||
// Compute proportional withdrawal amounts for the requested LP amount (rounded down)
|
// Compute proportional withdrawal amounts for the requested LP amount (rounded down)
|
||||||
withdrawAmounts = burnAmounts(lpAmount, lmsr.nAssets, _totalSupply, cachedUintBalances);
|
withdrawAmounts = burnAmounts(lpAmount, _lmsr.nAssets, _totalSupply, _cachedUintBalances);
|
||||||
|
|
||||||
// Transfer underlying tokens out to receiver according to computed proportions
|
// Transfer underlying _tokens out to receiver according to computed proportions
|
||||||
for (uint i = 0; i < n; ) {
|
for (uint i = 0; i < n; ) {
|
||||||
if (withdrawAmounts[i] > 0) {
|
if (withdrawAmounts[i] > 0) {
|
||||||
_sendTokenTo(tokens[i], receiver, withdrawAmounts[i], unwrap);
|
_sendTokenTo(_tokens[i], receiver, withdrawAmounts[i], unwrap);
|
||||||
}
|
}
|
||||||
unchecked { i++; }
|
unchecked { i++; }
|
||||||
}
|
}
|
||||||
@@ -164,9 +164,9 @@ contract PartyPoolMintImpl is PartyPoolBase {
|
|||||||
// Update cached balances and internal q for all assets using computed withdrawals
|
// Update cached balances and internal q for all assets using computed withdrawals
|
||||||
int128[] memory newQInternal = new int128[](n);
|
int128[] memory newQInternal = new int128[](n);
|
||||||
for (uint i = 0; i < n; ) {
|
for (uint i = 0; i < n; ) {
|
||||||
uint256 newBal = cachedUintBalances[i] - withdrawAmounts[i];
|
uint256 newBal = _cachedUintBalances[i] - withdrawAmounts[i];
|
||||||
cachedUintBalances[i] = newBal;
|
_cachedUintBalances[i] = newBal;
|
||||||
newQInternal[i] = _uintToInternalFloor(newBal, bases[i]);
|
newQInternal[i] = _uintToInternalFloor(newBal, _bases[i]);
|
||||||
unchecked { i++; }
|
unchecked { i++; }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -181,9 +181,9 @@ contract PartyPoolMintImpl is PartyPoolBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (allZero) {
|
if (allZero) {
|
||||||
lmsr.deinit();
|
_lmsr.deinit();
|
||||||
} else {
|
} else {
|
||||||
lmsr.updateForProportionalChange(newQInternal);
|
_lmsr.updateForProportionalChange(newQInternal);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Burn exactly the requested LP amount from payer (authorization via allowance)
|
// Burn exactly the requested LP amount from payer (authorization via allowance)
|
||||||
@@ -199,9 +199,9 @@ contract PartyPoolMintImpl is PartyPoolBase {
|
|||||||
|
|
||||||
/// @notice Calculate the proportional deposit amounts required for a given LP token amount
|
/// @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
|
/// @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
|
/// 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().
|
/// because the initial deposit is handled by transferring _tokens then calling mint().
|
||||||
/// @param lpTokenAmount The amount of LP tokens desired
|
/// @param lpTokenAmount The amount of LP _tokens desired
|
||||||
/// @return depositAmounts Array of token amounts to deposit (rounded up)
|
/// @return depositAmounts Array of token amounts to deposit (rounded up)
|
||||||
function mintAmounts(uint256 lpTokenAmount,
|
function mintAmounts(uint256 lpTokenAmount,
|
||||||
uint256 numAssets, uint256 totalSupply, uint256[] memory cachedUintBalances) public pure
|
uint256 numAssets, uint256 totalSupply, uint256[] memory cachedUintBalances) public pure
|
||||||
@@ -209,7 +209,7 @@ contract PartyPoolMintImpl is PartyPoolBase {
|
|||||||
depositAmounts = new uint256[](numAssets);
|
depositAmounts = new uint256[](numAssets);
|
||||||
|
|
||||||
// If this is the first mint or pool is empty, return zeros
|
// If this is the first mint or pool is empty, return zeros
|
||||||
// For first mint, tokens should already be transferred to the pool
|
// For first mint, _tokens should already be transferred to the pool
|
||||||
if (totalSupply == 0 || numAssets == 0) {
|
if (totalSupply == 0 || numAssets == 0) {
|
||||||
return depositAmounts; // Return zeros, initial deposit handled differently
|
return depositAmounts; // Return zeros, initial deposit handled differently
|
||||||
}
|
}
|
||||||
@@ -256,11 +256,11 @@ contract PartyPoolMintImpl is PartyPoolBase {
|
|||||||
/// @param maxAmountIn maximum amount of token to deposit (inclusive of fee)
|
/// @param maxAmountIn maximum amount of token to deposit (inclusive of fee)
|
||||||
/// @param swapFeePpm fee in parts-per-million
|
/// @param swapFeePpm fee in parts-per-million
|
||||||
/// @param lmsrState current LMSR state
|
/// @param lmsrState current LMSR state
|
||||||
/// @param bases_ scaling bases for each token
|
/// @param bases_ scaling _bases for each token
|
||||||
/// @param totalSupply_ current total LP token supply
|
/// @param totalSupply_ current total LP token supply
|
||||||
/// @return amountInUsed actual input amount used (excluding fee)
|
/// @return amountInUsed actual input amount used (excluding fee)
|
||||||
/// @return fee fee amount charged
|
/// @return fee fee amount charged
|
||||||
/// @return lpMinted LP tokens that would be minted
|
/// @return lpMinted LP _tokens that would be minted
|
||||||
function swapMintAmounts(
|
function swapMintAmounts(
|
||||||
uint256 inputTokenIndex,
|
uint256 inputTokenIndex,
|
||||||
uint256 maxAmountIn,
|
uint256 maxAmountIn,
|
||||||
@@ -311,7 +311,7 @@ contract PartyPoolMintImpl is PartyPoolBase {
|
|||||||
uint256 newScaled = ABDKMath64x64.mulu(newTotal, LP_SCALE);
|
uint256 newScaled = ABDKMath64x64.mulu(newTotal, LP_SCALE);
|
||||||
|
|
||||||
if (totalSupply_ == 0) {
|
if (totalSupply_ == 0) {
|
||||||
// If somehow supply zero (shouldn't happen as lmsr.nAssets>0), mint newScaled
|
// If somehow supply zero (shouldn't happen as _lmsr.nAssets>0), mint newScaled
|
||||||
lpMinted = newScaled;
|
lpMinted = newScaled;
|
||||||
} else {
|
} else {
|
||||||
require(oldScaled > 0, "swapMintAmounts: oldScaled zero");
|
require(oldScaled > 0, "swapMintAmounts: oldScaled zero");
|
||||||
@@ -331,7 +331,7 @@ contract PartyPoolMintImpl is PartyPoolBase {
|
|||||||
/// @dev swapMint executes as an exact-in planned swap followed by proportional scaling of qInternal.
|
/// @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.
|
/// The function emits SwapMint (gross, net, fee) and also emits Mint for LP issuance.
|
||||||
/// @param payer who transfers the input token
|
/// @param payer who transfers the input token
|
||||||
/// @param receiver who receives the minted LP tokens
|
/// @param receiver who receives the minted LP _tokens
|
||||||
/// @param inputTokenIndex index of the input token
|
/// @param inputTokenIndex index of the input token
|
||||||
/// @param maxAmountIn maximum uint token input (inclusive of fee)
|
/// @param maxAmountIn maximum uint token input (inclusive of fee)
|
||||||
/// @param deadline optional deadline
|
/// @param deadline optional deadline
|
||||||
@@ -346,24 +346,24 @@ contract PartyPoolMintImpl is PartyPoolBase {
|
|||||||
uint256 swapFeePpm,
|
uint256 swapFeePpm,
|
||||||
uint256 protocolFeePpm
|
uint256 protocolFeePpm
|
||||||
) external payable native nonReentrant returns (uint256 lpMinted) {
|
) external payable native nonReentrant returns (uint256 lpMinted) {
|
||||||
uint256 n = tokens.length;
|
uint256 n = _tokens.length;
|
||||||
require(inputTokenIndex < n, "swapMint: idx");
|
require(inputTokenIndex < n, "swapMint: idx");
|
||||||
require(maxAmountIn > 0, "swapMint: input zero");
|
require(maxAmountIn > 0, "swapMint: input zero");
|
||||||
require(deadline == 0 || block.timestamp <= deadline, "swapMint: deadline");
|
require(deadline == 0 || block.timestamp <= deadline, "swapMint: deadline");
|
||||||
require(lmsr.nAssets > 0, "swapMint: uninit pool");
|
require(_lmsr.nAssets > 0, "swapMint: uninit pool");
|
||||||
|
|
||||||
// compute fee on gross maxAmountIn to get an initial net estimate (we'll recompute based on actual used)
|
// compute fee on gross maxAmountIn to get an initial net estimate (we'll recompute based on actual used)
|
||||||
(, uint256 netUintGuess) = _computeFee(maxAmountIn, swapFeePpm);
|
(, uint256 netUintGuess) = _computeFee(maxAmountIn, swapFeePpm);
|
||||||
|
|
||||||
// Convert the net guess to internal (floor)
|
// Convert the net guess to internal (floor)
|
||||||
int128 netInternalGuess = _uintToInternalFloor(netUintGuess, bases[inputTokenIndex]);
|
int128 netInternalGuess = _uintToInternalFloor(netUintGuess, _bases[inputTokenIndex]);
|
||||||
require(netInternalGuess > int128(0), "swapMint: input too small after fee");
|
require(netInternalGuess > int128(0), "swapMint: input too small after fee");
|
||||||
|
|
||||||
// Use LMSR view to determine actual internal consumed and size-increase (ΔS) for mint
|
// Use LMSR view to determine actual internal consumed and size-increase (ΔS) for mint
|
||||||
(int128 amountInInternalUsed, int128 sizeIncreaseInternal) = lmsr.swapAmountsForMint(inputTokenIndex, netInternalGuess);
|
(int128 amountInInternalUsed, int128 sizeIncreaseInternal) = _lmsr.swapAmountsForMint(inputTokenIndex, netInternalGuess);
|
||||||
|
|
||||||
// amountInInternalUsed may be <= netInternalGuess. Convert to uint (ceil) to determine actual transfer
|
// amountInInternalUsed may be <= netInternalGuess. Convert to uint (ceil) to determine actual transfer
|
||||||
uint256 amountInUint = _internalToUintCeil(amountInInternalUsed, bases[inputTokenIndex]);
|
uint256 amountInUint = _internalToUintCeil(amountInInternalUsed, _bases[inputTokenIndex]);
|
||||||
require(amountInUint > 0, "swapMint: input zero after internal conversion");
|
require(amountInUint > 0, "swapMint: input zero after internal conversion");
|
||||||
|
|
||||||
// Compute fee on the actual used input and total transfer amount (ceiling)
|
// Compute fee on the actual used input and total transfer amount (ceiling)
|
||||||
@@ -371,22 +371,22 @@ contract PartyPoolMintImpl is PartyPoolBase {
|
|||||||
uint256 totalTransfer = amountInUint + feeUintActual;
|
uint256 totalTransfer = amountInUint + feeUintActual;
|
||||||
require(totalTransfer > 0 && totalTransfer <= maxAmountIn, "swapMint: transfer exceeds max");
|
require(totalTransfer > 0 && totalTransfer <= maxAmountIn, "swapMint: transfer exceeds max");
|
||||||
|
|
||||||
// Transfer tokens from payer (assume standard ERC20 without transfer fees) via helper
|
// Transfer _tokens from payer (assume standard ERC20 without transfer fees) via helper
|
||||||
_receiveTokenFrom(payer, tokens[inputTokenIndex], totalTransfer);
|
_receiveTokenFrom(payer, _tokens[inputTokenIndex], totalTransfer);
|
||||||
|
|
||||||
// Accrue protocol share (floor) from the fee on the input token
|
// Accrue protocol share (floor) from the fee on the input token
|
||||||
uint256 protoShare = 0;
|
uint256 protoShare = 0;
|
||||||
if (protocolFeePpm > 0 && feeUintActual > 0) {
|
if (protocolFeePpm > 0 && feeUintActual > 0) {
|
||||||
protoShare = (feeUintActual * protocolFeePpm) / 1_000_000;
|
protoShare = (feeUintActual * protocolFeePpm) / 1_000_000;
|
||||||
if (protoShare > 0) {
|
if (protoShare > 0) {
|
||||||
protocolFeesOwed[inputTokenIndex] += protoShare;
|
_protocolFeesOwed[inputTokenIndex] += protoShare;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Update cached effective balance directly: add totalTransfer minus protocol share
|
// Update cached effective balance directly: add totalTransfer minus protocol share
|
||||||
cachedUintBalances[inputTokenIndex] += (totalTransfer - protoShare);
|
_cachedUintBalances[inputTokenIndex] += (totalTransfer - protoShare);
|
||||||
|
|
||||||
// Compute old and new scaled size metrics to determine LP minted
|
// Compute old and new scaled size metrics to determine LP minted
|
||||||
int128 oldTotal = _computeSizeMetric(lmsr.qInternal);
|
int128 oldTotal = _computeSizeMetric(_lmsr.qInternal);
|
||||||
uint256 oldScaled = ABDKMath64x64.mulu(oldTotal, LP_SCALE);
|
uint256 oldScaled = ABDKMath64x64.mulu(oldTotal, LP_SCALE);
|
||||||
|
|
||||||
int128 newTotal = oldTotal.add(sizeIncreaseInternal);
|
int128 newTotal = oldTotal.add(sizeIncreaseInternal);
|
||||||
@@ -396,7 +396,7 @@ contract PartyPoolMintImpl is PartyPoolBase {
|
|||||||
// Use natural ERC20 function since base contract inherits from ERC20
|
// Use natural ERC20 function since base contract inherits from ERC20
|
||||||
uint256 currentSupply = _totalSupply;
|
uint256 currentSupply = _totalSupply;
|
||||||
if (currentSupply == 0) {
|
if (currentSupply == 0) {
|
||||||
// If somehow supply zero (shouldn't happen as lmsr.nAssets>0), mint newScaled
|
// If somehow supply zero (shouldn't happen as _lmsr.nAssets>0), mint newScaled
|
||||||
actualLpToMint = newScaled;
|
actualLpToMint = newScaled;
|
||||||
} else {
|
} else {
|
||||||
uint256 delta = (newScaled > oldScaled) ? (newScaled - oldScaled) : 0;
|
uint256 delta = (newScaled > oldScaled) ? (newScaled - oldScaled) : 0;
|
||||||
@@ -414,11 +414,11 @@ contract PartyPoolMintImpl is PartyPoolBase {
|
|||||||
int128[] memory newQInternal = new int128[](n);
|
int128[] memory newQInternal = new int128[](n);
|
||||||
for (uint256 idx = 0; idx < n; idx++) {
|
for (uint256 idx = 0; idx < n; idx++) {
|
||||||
// newQInternal[idx] = qInternal[idx] * (newTotal / oldTotal)
|
// newQInternal[idx] = qInternal[idx] * (newTotal / oldTotal)
|
||||||
newQInternal[idx] = lmsr.qInternal[idx].mul(newTotal).div(oldTotal);
|
newQInternal[idx] = _lmsr.qInternal[idx].mul(newTotal).div(oldTotal);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update cached internal and kappa via updateForProportionalChange
|
// Update cached internal and kappa via updateForProportionalChange
|
||||||
lmsr.updateForProportionalChange(newQInternal);
|
_lmsr.updateForProportionalChange(newQInternal);
|
||||||
|
|
||||||
// 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);
|
||||||
@@ -435,11 +435,11 @@ contract PartyPoolMintImpl is PartyPoolBase {
|
|||||||
|
|
||||||
/// @notice Calculate the amounts for a burn swap operation
|
/// @notice Calculate the amounts for a burn swap operation
|
||||||
/// @dev This is a pure view function that computes burn swap amounts from provided state
|
/// @dev This is a pure view function that computes burn swap amounts from provided state
|
||||||
/// @param lpAmount amount of LP tokens to burn
|
/// @param lpAmount amount of LP _tokens to burn
|
||||||
/// @param inputTokenIndex index of target asset to receive
|
/// @param inputTokenIndex index of target asset to receive
|
||||||
/// @param swapFeePpm fee in parts-per-million
|
/// @param swapFeePpm fee in parts-per-million
|
||||||
/// @param lmsrState current LMSR state
|
/// @param lmsrState current LMSR state
|
||||||
/// @param bases_ scaling bases for each token
|
/// @param bases_ scaling _bases for each token
|
||||||
/// @param totalSupply_ current total LP token supply
|
/// @param totalSupply_ current total LP token supply
|
||||||
/// @return amountOut amount of target asset that would be received
|
/// @return amountOut amount of target asset that would be received
|
||||||
function burnSwapAmounts(
|
function burnSwapAmounts(
|
||||||
@@ -467,11 +467,11 @@ contract PartyPoolMintImpl is PartyPoolBase {
|
|||||||
require(amountOut > 0, "burnSwapAmounts: output zero");
|
require(amountOut > 0, "burnSwapAmounts: output zero");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @notice Burn LP tokens then swap the redeemed proportional basket into a single asset `inputTokenIndex` and send to receiver.
|
/// @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.
|
/// @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 payer who burns LP _tokens
|
||||||
/// @param receiver who receives the single asset
|
/// @param receiver who receives the single asset
|
||||||
/// @param lpAmount amount of LP tokens to burn
|
/// @param lpAmount amount of LP _tokens to burn
|
||||||
/// @param inputTokenIndex index of target asset to receive
|
/// @param inputTokenIndex index of target asset to receive
|
||||||
/// @param deadline optional deadline
|
/// @param deadline optional deadline
|
||||||
/// @param swapFeePpm fee in parts-per-million for this pool (may be used for future fee logic)
|
/// @param swapFeePpm fee in parts-per-million for this pool (may be used for future fee logic)
|
||||||
@@ -486,7 +486,7 @@ contract PartyPoolMintImpl is PartyPoolBase {
|
|||||||
uint256 swapFeePpm,
|
uint256 swapFeePpm,
|
||||||
uint256 protocolFeePpm
|
uint256 protocolFeePpm
|
||||||
) external nonReentrant returns (uint256 amountOutUint) {
|
) external nonReentrant returns (uint256 amountOutUint) {
|
||||||
uint256 n = tokens.length;
|
uint256 n = _tokens.length;
|
||||||
require(inputTokenIndex < n, "burnSwap: idx");
|
require(inputTokenIndex < n, "burnSwap: idx");
|
||||||
require(lpAmount > 0, "burnSwap: zero lp");
|
require(lpAmount > 0, "burnSwap: zero lp");
|
||||||
require(deadline == 0 || block.timestamp <= deadline, "burnSwap: deadline");
|
require(deadline == 0 || block.timestamp <= deadline, "burnSwap: deadline");
|
||||||
@@ -499,16 +499,16 @@ contract PartyPoolMintImpl is PartyPoolBase {
|
|||||||
.mul(ABDKMath64x64.divu(1000000-swapFeePpm, 1000000)); // adjusted for fee
|
.mul(ABDKMath64x64.divu(1000000-swapFeePpm, 1000000)); // adjusted for fee
|
||||||
|
|
||||||
// Use LMSR view to compute single-asset payout and burned size-metric
|
// Use LMSR view to compute single-asset payout and burned size-metric
|
||||||
(int128 payoutInternal, ) = lmsr.swapAmountsForBurn(inputTokenIndex, alpha);
|
(int128 payoutInternal, ) = _lmsr.swapAmountsForBurn(inputTokenIndex, alpha);
|
||||||
|
|
||||||
// Convert payoutInternal -> uint (floor) to favor pool
|
// Convert payoutInternal -> uint (floor) to favor pool
|
||||||
amountOutUint = _internalToUintFloor(payoutInternal, bases[inputTokenIndex]);
|
amountOutUint = _internalToUintFloor(payoutInternal, _bases[inputTokenIndex]);
|
||||||
require(amountOutUint > 0, "burnSwap: output zero");
|
require(amountOutUint > 0, "burnSwap: output zero");
|
||||||
|
|
||||||
// Compute gross payout (no swap fee) so we can determine token-side fee = gross - net
|
// 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 alphaGross = ABDKMath64x64.divu(lpAmount, supply); // gross fraction (no swap fee)
|
||||||
(int128 payoutGrossInternal, ) = lmsr.swapAmountsForBurn(inputTokenIndex, alphaGross);
|
(int128 payoutGrossInternal, ) = _lmsr.swapAmountsForBurn(inputTokenIndex, alphaGross);
|
||||||
uint256 payoutGrossUint = _internalToUintFloor(payoutGrossInternal, bases[inputTokenIndex]);
|
uint256 payoutGrossUint = _internalToUintFloor(payoutGrossInternal, _bases[inputTokenIndex]);
|
||||||
uint256 feeTokenUint = (payoutGrossUint > amountOutUint) ? (payoutGrossUint - amountOutUint) : 0;
|
uint256 feeTokenUint = (payoutGrossUint > amountOutUint) ? (payoutGrossUint - amountOutUint) : 0;
|
||||||
|
|
||||||
// Accrue protocol share (floor) from the token-side fee
|
// Accrue protocol share (floor) from the token-side fee
|
||||||
@@ -516,14 +516,14 @@ contract PartyPoolMintImpl is PartyPoolBase {
|
|||||||
if (protocolFeePpm > 0 && feeTokenUint > 0) {
|
if (protocolFeePpm > 0 && feeTokenUint > 0) {
|
||||||
protoShare = (feeTokenUint * protocolFeePpm) / 1_000_000;
|
protoShare = (feeTokenUint * protocolFeePpm) / 1_000_000;
|
||||||
if (protoShare > 0) {
|
if (protoShare > 0) {
|
||||||
protocolFeesOwed[inputTokenIndex] += protoShare;
|
_protocolFeesOwed[inputTokenIndex] += protoShare;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Transfer the payout to receiver via centralized helper
|
// Transfer the payout to receiver via centralized helper
|
||||||
_sendTokenTo(tokens[inputTokenIndex], receiver, amountOutUint, unwrap);
|
_sendTokenTo(_tokens[inputTokenIndex], 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) {
|
||||||
uint256 allowed = _allowances[payer][msg.sender];
|
uint256 allowed = _allowances[payer][msg.sender];
|
||||||
_approve(payer, msg.sender, allowed - lpAmount);
|
_approve(payer, msg.sender, allowed - lpAmount);
|
||||||
@@ -533,13 +533,13 @@ contract PartyPoolMintImpl is PartyPoolBase {
|
|||||||
// Update cached balances using computed payout and protocol fee; no on-chain reads
|
// Update cached balances using computed payout and protocol fee; no on-chain reads
|
||||||
int128[] memory newQInternal = new int128[](n);
|
int128[] memory newQInternal = new int128[](n);
|
||||||
for (uint256 idx = 0; idx < n; idx++) {
|
for (uint256 idx = 0; idx < n; idx++) {
|
||||||
uint256 newBal = cachedUintBalances[idx];
|
uint256 newBal = _cachedUintBalances[idx];
|
||||||
if (idx == inputTokenIndex) {
|
if (idx == inputTokenIndex) {
|
||||||
// Effective LP balance decreases by net payout and increased protocol owed
|
// Effective LP balance decreases by net payout and increased protocol owed
|
||||||
newBal = newBal - amountOutUint - protoShare;
|
newBal = newBal - amountOutUint - protoShare;
|
||||||
}
|
}
|
||||||
cachedUintBalances[idx] = newBal;
|
_cachedUintBalances[idx] = newBal;
|
||||||
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 BurnSwap with public-facing info only (do not expose ΔS or LP burned)
|
||||||
@@ -551,9 +551,9 @@ contract PartyPoolMintImpl is PartyPoolBase {
|
|||||||
if (newQInternal[idx] != int128(0)) { allZero = false; break; }
|
if (newQInternal[idx] != int128(0)) { allZero = false; break; }
|
||||||
}
|
}
|
||||||
if (allZero) {
|
if (allZero) {
|
||||||
lmsr.deinit();
|
_lmsr.deinit();
|
||||||
} else {
|
} else {
|
||||||
lmsr.updateForProportionalChange(newQInternal);
|
_lmsr.updateForProportionalChange(newQInternal);
|
||||||
}
|
}
|
||||||
|
|
||||||
emit IPartyPool.Burn(payer, receiver, new uint256[](n), lpAmount);
|
emit IPartyPool.Burn(payer, receiver, new uint256[](n), lpAmount);
|
||||||
|
|||||||
@@ -60,49 +60,49 @@ contract PartyPoolSwapImpl is PartyPoolBase {
|
|||||||
uint256 swapFeePpm,
|
uint256 swapFeePpm,
|
||||||
uint256 protocolFeePpm
|
uint256 protocolFeePpm
|
||||||
) external payable native returns (uint256 amountInUsed, uint256 amountOut, uint256 fee) {
|
) external payable native returns (uint256 amountInUsed, uint256 amountOut, uint256 fee) {
|
||||||
uint256 n = tokens.length;
|
uint256 n = _tokens.length;
|
||||||
require(inputTokenIndex < n && outputTokenIndex < n, "swapToLimit: idx");
|
require(inputTokenIndex < n && outputTokenIndex < n, "swapToLimit: idx");
|
||||||
require(limitPrice > int128(0), "swapToLimit: limit <= 0");
|
require(limitPrice > int128(0), "swapToLimit: limit <= 0");
|
||||||
require(deadline == 0 || block.timestamp <= deadline, "swapToLimit: deadline exceeded");
|
require(deadline == 0 || block.timestamp <= deadline, "swapToLimit: deadline exceeded");
|
||||||
|
|
||||||
// Read previous balances for affected assets
|
// Read previous balances for affected assets
|
||||||
uint256 prevBalI = IERC20(tokens[inputTokenIndex]).balanceOf(address(this));
|
uint256 prevBalI = IERC20(_tokens[inputTokenIndex]).balanceOf(address(this));
|
||||||
uint256 prevBalJ = IERC20(tokens[outputTokenIndex]).balanceOf(address(this));
|
uint256 prevBalJ = IERC20(_tokens[outputTokenIndex]).balanceOf(address(this));
|
||||||
|
|
||||||
// Compute amounts using the same path as views
|
// Compute amounts using the same path as views
|
||||||
(uint256 totalTransferAmount, uint256 amountOutUint, int128 amountInInternalMax, int128 amountOutInternal, uint256 amountInUsedUint, uint256 feeUint) =
|
(uint256 totalTransferAmount, uint256 amountOutUint, int128 amountInInternalMax, int128 amountOutInternal, uint256 amountInUsedUint, uint256 feeUint) =
|
||||||
_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);
|
_receiveTokenFrom(payer, _tokens[inputTokenIndex], totalTransferAmount);
|
||||||
uint256 balIAfter = IERC20(tokens[inputTokenIndex]).balanceOf(address(this));
|
uint256 balIAfter = IERC20(_tokens[inputTokenIndex]).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);
|
_sendTokenTo(_tokens[outputTokenIndex], receiver, amountOutUint, unwrap);
|
||||||
uint256 balJAfter = IERC20(tokens[outputTokenIndex]).balanceOf(address(this));
|
uint256 balJAfter = IERC20(_tokens[outputTokenIndex]).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
|
||||||
if (protocolFeePpm > 0 && feeUint > 0 ) {
|
if (protocolFeePpm > 0 && feeUint > 0 ) {
|
||||||
uint256 protoShare = (feeUint * protocolFeePpm) / 1_000_000; // floor
|
uint256 protoShare = (feeUint * protocolFeePpm) / 1_000_000; // floor
|
||||||
if (protoShare > 0) {
|
if (protoShare > 0) {
|
||||||
protocolFeesOwed[inputTokenIndex] += protoShare;
|
_protocolFeesOwed[inputTokenIndex] += protoShare;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update caches to effective balances (inline _recordCachedBalance)
|
// Update caches to effective balances (inline _recordCachedBalance)
|
||||||
require(balIAfter >= protocolFeesOwed[inputTokenIndex], "balance < protocol owed");
|
require(balIAfter >= _protocolFeesOwed[inputTokenIndex], "balance < protocol owed");
|
||||||
cachedUintBalances[inputTokenIndex] = balIAfter - protocolFeesOwed[inputTokenIndex];
|
_cachedUintBalances[inputTokenIndex] = balIAfter - _protocolFeesOwed[inputTokenIndex];
|
||||||
|
|
||||||
require(balJAfter >= protocolFeesOwed[outputTokenIndex], "balance < protocol owed");
|
require(balJAfter >= _protocolFeesOwed[outputTokenIndex], "balance < protocol owed");
|
||||||
cachedUintBalances[outputTokenIndex] = balJAfter - protocolFeesOwed[outputTokenIndex];
|
_cachedUintBalances[outputTokenIndex] = balJAfter - _protocolFeesOwed[outputTokenIndex];
|
||||||
|
|
||||||
// Apply swap to LMSR state with the internal amounts
|
// Apply swap to LMSR state with the internal amounts
|
||||||
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, _tokens[inputTokenIndex], _tokens[outputTokenIndex], amountInUsedUint, amountOutUint);
|
||||||
|
|
||||||
return (amountInUsedUint, amountOutUint, feeUint);
|
return (amountInUsedUint, amountOutUint, feeUint);
|
||||||
}
|
}
|
||||||
@@ -129,10 +129,10 @@ contract PartyPoolSwapImpl is PartyPoolBase {
|
|||||||
)
|
)
|
||||||
{
|
{
|
||||||
// Compute internal maxima at the price limit
|
// Compute internal maxima at the price limit
|
||||||
(amountInInternal, amountOutInternal) = lmsr.swapAmountsForPriceLimit(inputTokenIndex, outputTokenIndex, limitPrice);
|
(amountInInternal, amountOutInternal) = _lmsr.swapAmountsForPriceLimit(inputTokenIndex, outputTokenIndex, limitPrice);
|
||||||
|
|
||||||
// Convert input to uint (ceil) and output to uint (floor)
|
// Convert input to uint (ceil) and output to uint (floor)
|
||||||
amountInUintNoFee = _internalToUintCeil(amountInInternal, bases[inputTokenIndex]);
|
amountInUintNoFee = _internalToUintCeil(amountInInternal, _bases[inputTokenIndex]);
|
||||||
require(amountInUintNoFee > 0, "swapToLimit: input zero");
|
require(amountInUintNoFee > 0, "swapToLimit: input zero");
|
||||||
|
|
||||||
feeUint = 0;
|
feeUint = 0;
|
||||||
@@ -142,7 +142,7 @@ contract PartyPoolSwapImpl is PartyPoolBase {
|
|||||||
grossIn += feeUint;
|
grossIn += feeUint;
|
||||||
}
|
}
|
||||||
|
|
||||||
amountOutUint = _internalToUintFloor(amountOutInternal, bases[outputTokenIndex]);
|
amountOutUint = _internalToUintFloor(amountOutInternal, _bases[outputTokenIndex]);
|
||||||
require(amountOutUint > 0, "swapToLimit: output zero");
|
require(amountOutUint > 0, "swapToLimit: output zero");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -167,7 +167,7 @@ contract PartyPoolViewer is PartyPoolHelpers, IPartyPoolViewer {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @dev The fee to be charged for a given loan.
|
* @dev The fee to be charged for a given loan.
|
||||||
* @param amount The amount of tokens lent.
|
* @param amount The amount of _tokens lent.
|
||||||
* @return fee The amount of `token` to be charged for the loan, on top of the returned principal.
|
* @return fee The amount of `token` to be charged for the loan, on top of the returned principal.
|
||||||
*/
|
*/
|
||||||
function flashFee(
|
function flashFee(
|
||||||
|
|||||||
@@ -114,9 +114,9 @@ contract GasTest is Test {
|
|||||||
uint256 constant internal INIT_BAL = 1_000_000; // initial token units for each token (internal==amount when base==1)
|
uint256 constant internal INIT_BAL = 1_000_000; // initial token units for each token (internal==amount when base==1)
|
||||||
uint256 constant internal BASE = 1; // use base=1 so internal amounts correspond to raw integers (Q64.64 units)
|
uint256 constant internal BASE = 1; // use base=1 so internal amounts correspond to raw integers (Q64.64 units)
|
||||||
|
|
||||||
/// @notice Helper function to create a pool with the specified number of tokens
|
/// @notice Helper function to create a pool with the specified number of _tokens
|
||||||
function createPool(uint256 numTokens) internal returns (PartyPool) {
|
function createPool(uint256 numTokens) internal returns (PartyPool) {
|
||||||
// Deploy tokens dynamically
|
// Deploy _tokens dynamically
|
||||||
address[] memory tokens = new address[](numTokens);
|
address[] memory tokens = new address[](numTokens);
|
||||||
uint256[] memory bases = new uint256[](numTokens);
|
uint256[] memory bases = new uint256[](numTokens);
|
||||||
|
|
||||||
@@ -139,7 +139,7 @@ contract GasTest is Test {
|
|||||||
for (uint i = 0; i < tokens.length; i++) {
|
for (uint i = 0; i < tokens.length; i++) {
|
||||||
ierc20Tokens[i] = IERC20(tokens[i]);
|
ierc20Tokens[i] = IERC20(tokens[i]);
|
||||||
}
|
}
|
||||||
// Compute kappa from slippage params and number of tokens, then construct pool with kappa
|
// Compute kappa from slippage params and number of _tokens, then construct pool with kappa
|
||||||
int128 computedKappa = LMSRStabilized.computeKappaFromSlippage(ierc20Tokens.length, tradeFrac, targetSlippage);
|
int128 computedKappa = LMSRStabilized.computeKappaFromSlippage(ierc20Tokens.length, tradeFrac, targetSlippage);
|
||||||
PartyPool newPool = Deploy.newPartyPool(poolName, poolName, ierc20Tokens, bases, computedKappa, feePpm, feePpm, false);
|
PartyPool newPool = Deploy.newPartyPool(poolName, poolName, ierc20Tokens, bases, computedKappa, feePpm, feePpm, false);
|
||||||
|
|
||||||
@@ -156,7 +156,7 @@ contract GasTest is Test {
|
|||||||
|
|
||||||
/// @notice Helper to create a pool with the stable-pair optimization enabled
|
/// @notice Helper to create a pool with the stable-pair optimization enabled
|
||||||
function createPoolStable(uint256 numTokens) internal returns (PartyPool) {
|
function createPoolStable(uint256 numTokens) internal returns (PartyPool) {
|
||||||
// Deploy tokens dynamically
|
// Deploy _tokens dynamically
|
||||||
address[] memory tokens = new address[](numTokens);
|
address[] memory tokens = new address[](numTokens);
|
||||||
uint256[] memory bases = new uint256[](numTokens);
|
uint256[] memory bases = new uint256[](numTokens);
|
||||||
|
|
||||||
@@ -216,7 +216,7 @@ contract GasTest is Test {
|
|||||||
// Deploy the borrower contract
|
// Deploy the borrower contract
|
||||||
borrower = new FlashBorrower(address(pool2));
|
borrower = new FlashBorrower(address(pool2));
|
||||||
|
|
||||||
// Mint tokens to alice to be used for repayments and approve borrower
|
// Mint _tokens to alice to be used for repayments and approve borrower
|
||||||
IERC20[] memory tokenAddresses = pool2.allTokens();
|
IERC20[] memory tokenAddresses = pool2.allTokens();
|
||||||
vm.startPrank(alice);
|
vm.startPrank(alice);
|
||||||
for (uint256 i = 0; i < tokenAddresses.length; i++) {
|
for (uint256 i = 0; i < tokenAddresses.length; i++) {
|
||||||
@@ -226,12 +226,12 @@ contract GasTest is Test {
|
|||||||
vm.stopPrank();
|
vm.stopPrank();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @notice Helper function: perform 10 swaps back-and-forth between the first two tokens.
|
/// @notice Helper function: perform 10 swaps back-and-forth between the first two _tokens.
|
||||||
function _performSwapGasTest(PartyPool testPool) internal {
|
function _performSwapGasTest(PartyPool testPool) internal {
|
||||||
IERC20[] memory tokens = testPool.allTokens();
|
IERC20[] memory tokens = testPool.allTokens();
|
||||||
require(tokens.length >= 2, "Pool must have at least 2 tokens");
|
require(tokens.length >= 2, "Pool must have at least 2 tokens");
|
||||||
|
|
||||||
// Ensure alice approves pool for both tokens
|
// Ensure alice approves pool for both _tokens
|
||||||
vm.prank(alice);
|
vm.prank(alice);
|
||||||
TestERC20(address(tokens[0])).approve(address(testPool), type(uint256).max);
|
TestERC20(address(tokens[0])).approve(address(testPool), type(uint256).max);
|
||||||
vm.prank(alice);
|
vm.prank(alice);
|
||||||
@@ -252,22 +252,22 @@ contract GasTest is Test {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @notice Gas measurement: perform 10 swaps back-and-forth between first two tokens in the 2-token pool.
|
/// @notice Gas measurement: perform 10 swaps back-and-forth between first two _tokens in the 2-token pool.
|
||||||
function testSwapGasPair() public {
|
function testSwapGasPair() public {
|
||||||
_performSwapGasTest(pool2);
|
_performSwapGasTest(pool2);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @notice Gas measurement: perform 10 swaps back-and-forth between first two tokens in the 10-token pool.
|
/// @notice Gas measurement: perform 10 swaps back-and-forth between first two _tokens in the 10-token pool.
|
||||||
function testSwapGasTen() public {
|
function testSwapGasTen() public {
|
||||||
_performSwapGasTest(pool10);
|
_performSwapGasTest(pool10);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @notice Gas measurement: perform 10 swaps back-and-forth between first two tokens in the 20-token pool.
|
/// @notice Gas measurement: perform 10 swaps back-and-forth between first two _tokens in the 20-token pool.
|
||||||
function testSwapGasTwenty() public {
|
function testSwapGasTwenty() public {
|
||||||
_performSwapGasTest(pool20);
|
_performSwapGasTest(pool20);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @notice Gas measurement: perform 10 swaps back-and-forth between first two tokens in the 100-token pool.
|
/// @notice Gas measurement: perform 10 swaps back-and-forth between first two _tokens in the 100-token pool.
|
||||||
function testSwapGasFifty() public {
|
function testSwapGasFifty() public {
|
||||||
_performSwapGasTest(pool50);
|
_performSwapGasTest(pool50);
|
||||||
}
|
}
|
||||||
@@ -307,7 +307,7 @@ contract GasTest is Test {
|
|||||||
uint256 minted = testPool.swapMint(alice, alice, 0, input, 0);
|
uint256 minted = testPool.swapMint(alice, alice, 0, input, 0);
|
||||||
// If nothing minted (numerical edge), skip burn step
|
// If nothing minted (numerical edge), skip burn step
|
||||||
if (minted == 0) continue;
|
if (minted == 0) continue;
|
||||||
// Immediately burn the minted LP back to tokens, targeting the same token index
|
// Immediately burn the minted LP back to _tokens, targeting the same token index
|
||||||
testPool.burnSwap(alice, alice, minted, 0, 0, false);
|
testPool.burnSwap(alice, alice, minted, 0, 0, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -343,7 +343,7 @@ contract GasTest is Test {
|
|||||||
|
|
||||||
vm.startPrank(alice);
|
vm.startPrank(alice);
|
||||||
|
|
||||||
// Mint additional tokens to alice and approve pool to transfer tokens for proportional mint
|
// Mint additional _tokens to alice and approve pool to transfer _tokens for proportional mint
|
||||||
for (uint256 i = 0; i < poolTokens.length; i++) {
|
for (uint256 i = 0; i < poolTokens.length; i++) {
|
||||||
TestERC20(address(poolTokens[i])).mint(alice, iterations * input * 2);
|
TestERC20(address(poolTokens[i])).mint(alice, iterations * input * 2);
|
||||||
TestERC20(address(poolTokens[i])).approve(address(testPool), type(uint256).max);
|
TestERC20(address(poolTokens[i])).approve(address(testPool), type(uint256).max);
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ contract NativeTest is Test {
|
|||||||
vm.deal(alice, 100 ether);
|
vm.deal(alice, 100 ether);
|
||||||
vm.deal(bob, 100 ether);
|
vm.deal(bob, 100 ether);
|
||||||
|
|
||||||
// Deploy two regular ERC20 tokens
|
// Deploy two regular ERC20 _tokens
|
||||||
token0 = new TestERC20Native("T0", "T0", 0);
|
token0 = new TestERC20Native("T0", "T0", 0);
|
||||||
token1 = new TestERC20Native("T1", "T1", 0);
|
token1 = new TestERC20Native("T1", "T1", 0);
|
||||||
|
|
||||||
@@ -72,7 +72,7 @@ contract NativeTest is Test {
|
|||||||
token0.mint(address(this), INIT_BAL);
|
token0.mint(address(this), INIT_BAL);
|
||||||
token1.mint(address(this), INIT_BAL);
|
token1.mint(address(this), INIT_BAL);
|
||||||
|
|
||||||
// For WETH, we deposit native currency to get wrapped tokens
|
// For WETH, we deposit native currency to get wrapped _tokens
|
||||||
weth.deposit{value: INIT_BAL}();
|
weth.deposit{value: INIT_BAL}();
|
||||||
|
|
||||||
// Configure LMSR parameters
|
// Configure LMSR parameters
|
||||||
@@ -104,7 +104,7 @@ contract NativeTest is Test {
|
|||||||
// Perform initial mint
|
// Perform initial mint
|
||||||
pool.initialMint(address(this), 0);
|
pool.initialMint(address(this), 0);
|
||||||
|
|
||||||
// Mint tokens to alice and bob for testing
|
// Mint _tokens to alice and bob for testing
|
||||||
token0.mint(alice, INIT_BAL);
|
token0.mint(alice, INIT_BAL);
|
||||||
token1.mint(alice, INIT_BAL);
|
token1.mint(alice, INIT_BAL);
|
||||||
|
|
||||||
@@ -407,7 +407,7 @@ contract NativeTest is Test {
|
|||||||
true // unwrap
|
true // unwrap
|
||||||
);
|
);
|
||||||
|
|
||||||
// Bob should receive tokens and native currency
|
// Bob should receive _tokens and native currency
|
||||||
assertEq(token0.balanceOf(bob), bobToken0Before + withdraws[0], "Bob token0");
|
assertEq(token0.balanceOf(bob), bobToken0Before + withdraws[0], "Bob token0");
|
||||||
assertEq(token1.balanceOf(bob), bobToken1Before + withdraws[1], "Bob token1");
|
assertEq(token1.balanceOf(bob), bobToken1Before + withdraws[1], "Bob token1");
|
||||||
assertEq(bob.balance, bobEthBefore + withdraws[2], "Bob should receive ETH");
|
assertEq(bob.balance, bobEthBefore + withdraws[2], "Bob should receive ETH");
|
||||||
@@ -441,7 +441,7 @@ contract NativeTest is Test {
|
|||||||
assertTrue(alice.balance <= aliceEthBefore, "Alice ETH should decrease");
|
assertTrue(alice.balance <= aliceEthBefore, "Alice ETH should decrease");
|
||||||
assertTrue(aliceEthBefore - alice.balance <= maxIn, "Alice spent at most maxIn");
|
assertTrue(aliceEthBefore - alice.balance <= maxIn, "Alice spent at most maxIn");
|
||||||
|
|
||||||
// Alice should receive LP tokens
|
// Alice should receive LP _tokens
|
||||||
assertTrue(pool.balanceOf(alice) >= aliceLpBefore + lpMinted, "Alice should receive LP");
|
assertTrue(pool.balanceOf(alice) >= aliceLpBefore + lpMinted, "Alice should receive LP");
|
||||||
|
|
||||||
vm.stopPrank();
|
vm.stopPrank();
|
||||||
@@ -567,7 +567,7 @@ contract NativeTest is Test {
|
|||||||
vm.stopPrank();
|
vm.stopPrank();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @notice Test that unwrap=false with WETH actually transfers WETH tokens (not native)
|
/// @notice Test that unwrap=false with WETH actually transfers WETH _tokens (not native)
|
||||||
function testSwapWithWethNoUnwrap() public {
|
function testSwapWithWethNoUnwrap() public {
|
||||||
uint256 maxIn = 10_000;
|
uint256 maxIn = 10_000;
|
||||||
|
|
||||||
|
|||||||
@@ -49,17 +49,17 @@ contract PartyPlannerTest is Test {
|
|||||||
// Deploy PartyPlanner
|
// Deploy PartyPlanner
|
||||||
planner = Deploy.newPartyPlanner();
|
planner = Deploy.newPartyPlanner();
|
||||||
|
|
||||||
// Deploy mock tokens
|
// Deploy mock _tokens
|
||||||
tokenA = new MockERC20("Token A", "TKNA", 18);
|
tokenA = new MockERC20("Token A", "TKNA", 18);
|
||||||
tokenB = new MockERC20("Token B", "TKNB", 18);
|
tokenB = new MockERC20("Token B", "TKNB", 18);
|
||||||
tokenC = new MockERC20("Token C", "TKNC", 6);
|
tokenC = new MockERC20("Token C", "TKNC", 6);
|
||||||
|
|
||||||
// Mint tokens to payer
|
// Mint _tokens to payer
|
||||||
tokenA.mint(payer, INITIAL_MINT_AMOUNT);
|
tokenA.mint(payer, INITIAL_MINT_AMOUNT);
|
||||||
tokenB.mint(payer, INITIAL_MINT_AMOUNT);
|
tokenB.mint(payer, INITIAL_MINT_AMOUNT);
|
||||||
tokenC.mint(payer, INITIAL_MINT_AMOUNT);
|
tokenC.mint(payer, INITIAL_MINT_AMOUNT);
|
||||||
|
|
||||||
// Approve tokens for PartyPlanner
|
// Approve _tokens for PartyPlanner
|
||||||
vm.startPrank(payer);
|
vm.startPrank(payer);
|
||||||
tokenA.approve(address(planner), type(uint256).max);
|
tokenA.approve(address(planner), type(uint256).max);
|
||||||
tokenB.approve(address(planner), type(uint256).max);
|
tokenB.approve(address(planner), type(uint256).max);
|
||||||
@@ -156,7 +156,7 @@ contract PartyPlannerTest is Test {
|
|||||||
}
|
}
|
||||||
assertTrue(poolInTokenB, "Pool should be indexed under tokenB");
|
assertTrue(poolInTokenB, "Pool should be indexed under tokenB");
|
||||||
|
|
||||||
// Verify LP tokens were minted to receiver
|
// Verify LP _tokens were minted to receiver
|
||||||
assertEq(pool.balanceOf(receiver), lpAmount, "Receiver should have LP tokens");
|
assertEq(pool.balanceOf(receiver), lpAmount, "Receiver should have LP tokens");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -130,7 +130,7 @@ contract PartyPoolTest is Test {
|
|||||||
alice = address(0xA11ce);
|
alice = address(0xA11ce);
|
||||||
bob = address(0xB0b);
|
bob = address(0xB0b);
|
||||||
|
|
||||||
// Deploy three ERC20 test tokens and mint initial supplies to this test contract for initial deposit
|
// Deploy three ERC20 test _tokens and mint initial supplies to this test contract for initial deposit
|
||||||
token0 = new TestERC20("T0", "T0", 0);
|
token0 = new TestERC20("T0", "T0", 0);
|
||||||
token1 = new TestERC20("T1", "T1", 0);
|
token1 = new TestERC20("T1", "T1", 0);
|
||||||
token2 = new TestERC20("T2", "T2", 0);
|
token2 = new TestERC20("T2", "T2", 0);
|
||||||
@@ -175,7 +175,7 @@ contract PartyPoolTest is Test {
|
|||||||
int128 kappa3 = LMSRStabilized.computeKappaFromSlippage(tokens.length, tradeFrac, targetSlippage);
|
int128 kappa3 = LMSRStabilized.computeKappaFromSlippage(tokens.length, tradeFrac, targetSlippage);
|
||||||
pool = Deploy.newPartyPool("LP", "LP", tokens, bases, kappa3, feePpm, feePpm, false);
|
pool = Deploy.newPartyPool("LP", "LP", tokens, bases, kappa3, feePpm, feePpm, false);
|
||||||
|
|
||||||
// Transfer initial deposit amounts into pool before initial mint (pool expects tokens already in contract)
|
// Transfer initial deposit amounts into pool before initial mint (pool expects _tokens already in contract)
|
||||||
// We deposit equal amounts INIT_BAL for each token
|
// We deposit equal amounts INIT_BAL for each token
|
||||||
token0.transfer(address(pool), INIT_BAL);
|
token0.transfer(address(pool), INIT_BAL);
|
||||||
token1.transfer(address(pool), INIT_BAL);
|
token1.transfer(address(pool), INIT_BAL);
|
||||||
@@ -184,7 +184,7 @@ contract PartyPoolTest is Test {
|
|||||||
// Perform initial mint (initial deposit); receiver is this contract
|
// Perform initial mint (initial deposit); receiver is this contract
|
||||||
pool.initialMint(address(this), 0);
|
pool.initialMint(address(this), 0);
|
||||||
|
|
||||||
// Set up pool10 with 10 tokens
|
// Set up pool10 with 10 _tokens
|
||||||
IERC20[] memory tokens10 = new IERC20[](10);
|
IERC20[] memory tokens10 = new IERC20[](10);
|
||||||
tokens10[0] = IERC20(address(token0));
|
tokens10[0] = IERC20(address(token0));
|
||||||
tokens10[1] = IERC20(address(token1));
|
tokens10[1] = IERC20(address(token1));
|
||||||
@@ -205,7 +205,7 @@ contract PartyPoolTest is Test {
|
|||||||
int128 kappa10 = LMSRStabilized.computeKappaFromSlippage(tokens10.length, tradeFrac, targetSlippage);
|
int128 kappa10 = LMSRStabilized.computeKappaFromSlippage(tokens10.length, tradeFrac, targetSlippage);
|
||||||
pool10 = Deploy.newPartyPool("LP10", "LP10", tokens10, bases10, kappa10, feePpm, feePpm, false);
|
pool10 = Deploy.newPartyPool("LP10", "LP10", tokens10, bases10, kappa10, feePpm, feePpm, false);
|
||||||
|
|
||||||
// Mint additional tokens for pool10 initial deposit
|
// Mint additional _tokens for pool10 initial deposit
|
||||||
token0.mint(address(this), INIT_BAL);
|
token0.mint(address(this), INIT_BAL);
|
||||||
token1.mint(address(this), INIT_BAL);
|
token1.mint(address(this), INIT_BAL);
|
||||||
token2.mint(address(this), INIT_BAL);
|
token2.mint(address(this), INIT_BAL);
|
||||||
@@ -232,7 +232,7 @@ contract PartyPoolTest is Test {
|
|||||||
// Perform initial mint for pool10
|
// Perform initial mint for pool10
|
||||||
pool10.initialMint(address(this), 0);
|
pool10.initialMint(address(this), 0);
|
||||||
|
|
||||||
// For later tests we will mint tokens to alice/bob as needed
|
// For later tests we will mint _tokens to alice/bob as needed
|
||||||
token0.mint(alice, INIT_BAL);
|
token0.mint(alice, INIT_BAL);
|
||||||
token1.mint(alice, INIT_BAL);
|
token1.mint(alice, INIT_BAL);
|
||||||
token2.mint(alice, INIT_BAL);
|
token2.mint(alice, INIT_BAL);
|
||||||
@@ -258,7 +258,7 @@ contract PartyPoolTest is Test {
|
|||||||
viewer = Deploy.newViewer();
|
viewer = Deploy.newViewer();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @notice Basic sanity: initial mint should have produced LP tokens for this contract and the pool holds tokens.
|
/// @notice Basic sanity: initial mint should have produced LP _tokens for this contract and the pool holds _tokens.
|
||||||
function testInitialMintAndLP() public view {
|
function testInitialMintAndLP() public view {
|
||||||
uint256 totalLp = pool.totalSupply();
|
uint256 totalLp = pool.totalSupply();
|
||||||
assertTrue(totalLp > 0, "Initial LP supply should be > 0");
|
assertTrue(totalLp > 0, "Initial LP supply should be > 0");
|
||||||
@@ -274,7 +274,7 @@ contract PartyPoolTest is Test {
|
|||||||
function testProportionalMintZeroLpReverts() public {
|
function testProportionalMintZeroLpReverts() public {
|
||||||
// Attempt to request a tiny LP amount (1) and expect revert because calculated actualLpToMint will be zero
|
// Attempt to request a tiny LP amount (1) and expect revert because calculated actualLpToMint will be zero
|
||||||
|
|
||||||
// Approve pool to transfer tokens on alice's behalf
|
// Approve pool to transfer _tokens on alice's behalf
|
||||||
vm.startPrank(alice);
|
vm.startPrank(alice);
|
||||||
token0.approve(address(pool), type(uint256).max);
|
token0.approve(address(pool), type(uint256).max);
|
||||||
token1.approve(address(pool), type(uint256).max);
|
token1.approve(address(pool), type(uint256).max);
|
||||||
@@ -290,7 +290,7 @@ contract PartyPoolTest is Test {
|
|||||||
/// does not undercharge (no value extraction). This test verifies the request succeeds
|
/// does not undercharge (no value extraction). This test verifies the request succeeds
|
||||||
/// and that computed deposits are at least the proportional floor (ceil >= floor).
|
/// and that computed deposits are at least the proportional floor (ceil >= floor).
|
||||||
function testProportionalMintOneWeiSucceedsAndProtectsPool() public {
|
function testProportionalMintOneWeiSucceedsAndProtectsPool() public {
|
||||||
// Request a tiny LP amount (1 wei). Approve pool to transfer tokens on alice's behalf.
|
// Request a tiny LP amount (1 wei). Approve pool to transfer _tokens on alice's behalf.
|
||||||
vm.startPrank(alice);
|
vm.startPrank(alice);
|
||||||
token0.approve(address(pool), type(uint256).max);
|
token0.approve(address(pool), type(uint256).max);
|
||||||
token1.approve(address(pool), type(uint256).max);
|
token1.approve(address(pool), type(uint256).max);
|
||||||
@@ -406,14 +406,14 @@ contract PartyPoolTest is Test {
|
|||||||
assertTrue(withdrawAmounts[i] <= poolBal, "withdraw amount cannot exceed pool balance");
|
assertTrue(withdrawAmounts[i] <= poolBal, "withdraw amount cannot exceed pool balance");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Burn by sending LP tokens from this contract (which holds initial LP from setUp)
|
// Burn by sending LP _tokens from this contract (which holds initial LP from setUp)
|
||||||
// Call burn(payer=this, receiver=bob, lpAmount=totalLp)
|
// Call burn(payer=this, receiver=bob, lpAmount=totalLp)
|
||||||
pool.burn(address(this), bob, totalLp, 0, false);
|
pool.burn(address(this), bob, totalLp, 0, false);
|
||||||
|
|
||||||
// After burning entire pool, totalSupply should be zero or very small (we expect zero since we withdrew all)
|
// After burning entire pool, totalSupply should be zero or very small (we expect zero since we withdrew all)
|
||||||
assertEq(pool.totalSupply(), 0);
|
assertEq(pool.totalSupply(), 0);
|
||||||
|
|
||||||
// Bob should have received the withdrawn tokens
|
// Bob should have received the withdrawn _tokens
|
||||||
for (uint i = 0; i < withdrawAmounts.length; i++) {
|
for (uint i = 0; i < withdrawAmounts.length; i++) {
|
||||||
assertTrue(IERC20(pool.allTokens()[i]).balanceOf(bob) >= withdrawAmounts[i], "Bob should receive withdrawn tokens");
|
assertTrue(IERC20(pool.allTokens()[i]).balanceOf(bob) >= withdrawAmounts[i], "Bob should receive withdrawn tokens");
|
||||||
}
|
}
|
||||||
@@ -424,7 +424,7 @@ contract PartyPoolTest is Test {
|
|||||||
// Use alice as payer and bob as receiver
|
// Use alice as payer and bob as receiver
|
||||||
uint256 maxIn = 10_000;
|
uint256 maxIn = 10_000;
|
||||||
|
|
||||||
// Ensure alice has tokens and approves pool
|
// Ensure alice has _tokens and approves pool
|
||||||
vm.prank(alice);
|
vm.prank(alice);
|
||||||
token0.approve(address(pool), type(uint256).max);
|
token0.approve(address(pool), type(uint256).max);
|
||||||
|
|
||||||
@@ -503,7 +503,7 @@ contract PartyPoolTest is Test {
|
|||||||
// Compute expected deposit amounts via view
|
// Compute expected deposit amounts via view
|
||||||
uint256[] memory expected = viewer.mintAmounts(pool, req);
|
uint256[] memory expected = viewer.mintAmounts(pool, req);
|
||||||
|
|
||||||
// Ensure alice has tokens and approve pool
|
// Ensure alice has _tokens and approve pool
|
||||||
vm.startPrank(alice);
|
vm.startPrank(alice);
|
||||||
token0.approve(address(pool), type(uint256).max);
|
token0.approve(address(pool), type(uint256).max);
|
||||||
token1.approve(address(pool), type(uint256).max);
|
token1.approve(address(pool), type(uint256).max);
|
||||||
@@ -548,7 +548,7 @@ contract PartyPoolTest is Test {
|
|||||||
|
|
||||||
uint256[] memory expected = viewer.mintAmounts(pool10, req);
|
uint256[] memory expected = viewer.mintAmounts(pool10, req);
|
||||||
|
|
||||||
// Approve all tokens from alice
|
// Approve all _tokens from alice
|
||||||
vm.startPrank(alice);
|
vm.startPrank(alice);
|
||||||
token0.approve(address(pool10), type(uint256).max);
|
token0.approve(address(pool10), type(uint256).max);
|
||||||
token1.approve(address(pool10), type(uint256).max);
|
token1.approve(address(pool10), type(uint256).max);
|
||||||
@@ -614,7 +614,7 @@ contract PartyPoolTest is Test {
|
|||||||
uint256 myLp = pool.balanceOf(address(this));
|
uint256 myLp = pool.balanceOf(address(this));
|
||||||
if (myLp < req) {
|
if (myLp < req) {
|
||||||
uint256 topUp = req - myLp;
|
uint256 topUp = req - myLp;
|
||||||
// Have alice supply tokens to mint LP into this contract
|
// Have alice supply _tokens to mint LP into this contract
|
||||||
vm.startPrank(alice);
|
vm.startPrank(alice);
|
||||||
token0.approve(address(pool), type(uint256).max);
|
token0.approve(address(pool), type(uint256).max);
|
||||||
token1.approve(address(pool), type(uint256).max);
|
token1.approve(address(pool), type(uint256).max);
|
||||||
@@ -754,7 +754,7 @@ contract PartyPoolTest is Test {
|
|||||||
// Very large input relative to pool
|
// Very large input relative to pool
|
||||||
uint256 largeInput = 10_000_000_000; // intentionally large
|
uint256 largeInput = 10_000_000_000; // intentionally large
|
||||||
|
|
||||||
// Ensure alice has sufficient tokens for this large test input (mint top-up)
|
// Ensure alice has sufficient _tokens for this large test input (mint top-up)
|
||||||
token0.mint(alice, largeInput);
|
token0.mint(alice, largeInput);
|
||||||
|
|
||||||
vm.startPrank(alice);
|
vm.startPrank(alice);
|
||||||
@@ -818,12 +818,12 @@ contract PartyPoolTest is Test {
|
|||||||
// Deploy the borrower contract
|
// Deploy the borrower contract
|
||||||
borrower = new FlashBorrower(address(pool));
|
borrower = new FlashBorrower(address(pool));
|
||||||
|
|
||||||
// Mint tokens to alice to be used for repayments
|
// Mint _tokens to alice to be used for repayments
|
||||||
token0.mint(alice, INIT_BAL * 2);
|
token0.mint(alice, INIT_BAL * 2);
|
||||||
token1.mint(alice, INIT_BAL * 2);
|
token1.mint(alice, INIT_BAL * 2);
|
||||||
token2.mint(alice, INIT_BAL * 2);
|
token2.mint(alice, INIT_BAL * 2);
|
||||||
|
|
||||||
// Alice approves borrower to transfer tokens on their behalf for repayment
|
// Alice approves borrower to transfer _tokens on their behalf for repayment
|
||||||
vm.startPrank(alice);
|
vm.startPrank(alice);
|
||||||
token0.approve(address(borrower), type(uint256).max);
|
token0.approve(address(borrower), type(uint256).max);
|
||||||
token1.approve(address(borrower), type(uint256).max);
|
token1.approve(address(borrower), type(uint256).max);
|
||||||
@@ -998,7 +998,7 @@ contract PartyPoolTest is Test {
|
|||||||
int128 kappaCustom = LMSRStabilized.computeKappaFromSlippage(tokens.length, tradeFrac, targetSlippage);
|
int128 kappaCustom = LMSRStabilized.computeKappaFromSlippage(tokens.length, tradeFrac, targetSlippage);
|
||||||
PartyPool poolCustom = Deploy.newPartyPool("LP_CUSTOM", "LP_CUSTOM", tokens, bases, kappaCustom, feePpm, feePpm, false);
|
PartyPool poolCustom = Deploy.newPartyPool("LP_CUSTOM", "LP_CUSTOM", tokens, bases, kappaCustom, feePpm, feePpm, false);
|
||||||
|
|
||||||
// Mint additional tokens for both pools
|
// Mint additional _tokens for both pools
|
||||||
token0.mint(address(this), INIT_BAL * 2);
|
token0.mint(address(this), INIT_BAL * 2);
|
||||||
token1.mint(address(this), INIT_BAL * 2);
|
token1.mint(address(this), INIT_BAL * 2);
|
||||||
token2.mint(address(this), INIT_BAL * 2);
|
token2.mint(address(this), INIT_BAL * 2);
|
||||||
@@ -1052,7 +1052,7 @@ contract PartyPoolTest is Test {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// @notice Test that minting the same proportion in pools with different initial LP amounts
|
/// @notice Test that minting the same proportion in pools with different initial LP amounts
|
||||||
/// returns correctly scaled LP tokens
|
/// returns correctly scaled LP _tokens
|
||||||
function testProportionalMintingScaledByInitialAmount() public {
|
function testProportionalMintingScaledByInitialAmount() public {
|
||||||
// Create two identical pools with different initial LP amounts
|
// Create two identical pools with different initial LP amounts
|
||||||
IERC20[] memory tokens = new IERC20[](3);
|
IERC20[] memory tokens = new IERC20[](3);
|
||||||
@@ -1072,7 +1072,7 @@ contract PartyPoolTest is Test {
|
|||||||
int128 kappaCustom2 = LMSRStabilized.computeKappaFromSlippage(tokens.length, tradeFrac, targetSlippage);
|
int128 kappaCustom2 = LMSRStabilized.computeKappaFromSlippage(tokens.length, tradeFrac, targetSlippage);
|
||||||
PartyPool poolCustom = Deploy.newPartyPool("LP_CUSTOM", "LP_CUSTOM", tokens, bases, kappaCustom2, feePpm, feePpm, false);
|
PartyPool poolCustom = Deploy.newPartyPool("LP_CUSTOM", "LP_CUSTOM", tokens, bases, kappaCustom2, feePpm, feePpm, false);
|
||||||
|
|
||||||
// Mint additional tokens
|
// Mint additional _tokens
|
||||||
token0.mint(address(this), INIT_BAL * 4);
|
token0.mint(address(this), INIT_BAL * 4);
|
||||||
token1.mint(address(this), INIT_BAL * 4);
|
token1.mint(address(this), INIT_BAL * 4);
|
||||||
token2.mint(address(this), INIT_BAL * 4);
|
token2.mint(address(this), INIT_BAL * 4);
|
||||||
@@ -1108,7 +1108,7 @@ contract PartyPoolTest is Test {
|
|||||||
|
|
||||||
vm.startPrank(alice);
|
vm.startPrank(alice);
|
||||||
|
|
||||||
// Approve tokens for both pools
|
// Approve _tokens for both pools
|
||||||
token0.approve(address(poolDefault), type(uint256).max);
|
token0.approve(address(poolDefault), type(uint256).max);
|
||||||
token1.approve(address(poolDefault), type(uint256).max);
|
token1.approve(address(poolDefault), type(uint256).max);
|
||||||
token2.approve(address(poolDefault), type(uint256).max);
|
token2.approve(address(poolDefault), type(uint256).max);
|
||||||
|
|||||||
Reference in New Issue
Block a user