ownership & killable
This commit is contained in:
@@ -35,6 +35,7 @@ contract DeploySepolia is Script {
|
|||||||
|
|
||||||
// deploy a PartyPlanner factory and create the pool via factory
|
// deploy a PartyPlanner factory and create the pool via factory
|
||||||
PartyPlanner planner = new PartyPlanner(
|
PartyPlanner planner = new PartyPlanner(
|
||||||
|
msg.sender, // admin address is the same as the deployer
|
||||||
WETH,
|
WETH,
|
||||||
swapImpl,
|
swapImpl,
|
||||||
mintImpl,
|
mintImpl,
|
||||||
|
|||||||
25
src/IOwnable.sol
Normal file
25
src/IOwnable.sol
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)
|
||||||
|
|
||||||
|
pragma solidity ^0.8.20;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dev OpenZeppelin's Ownable contract, split into internal and external parts.
|
||||||
|
*/
|
||||||
|
interface IOwnable {
|
||||||
|
/**
|
||||||
|
* @dev The caller account is not authorized to perform an operation.
|
||||||
|
*/
|
||||||
|
error OwnableUnauthorizedAccount(address account);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dev The owner is not a valid owner account. (eg. `address(0)`)
|
||||||
|
*/
|
||||||
|
error OwnableInvalidOwner(address owner);
|
||||||
|
|
||||||
|
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
|
||||||
|
|
||||||
|
function owner() external view returns (address);
|
||||||
|
function renounceOwnership() external;
|
||||||
|
function transferOwnership(address newOwner) external;
|
||||||
|
}
|
||||||
@@ -8,38 +8,38 @@ import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
|
|||||||
|
|
||||||
/// @title IPartyPlanner
|
/// @title IPartyPlanner
|
||||||
/// @notice Interface for factory contract for creating and tracking PartyPool instances
|
/// @notice Interface for factory contract for creating and tracking PartyPool instances
|
||||||
interface IPartyPlanner {
|
interface IPartyPlanner is IOwnable {
|
||||||
// Event emitted when a new pool is created
|
// Event emitted when a new pool is created
|
||||||
event PartyStarted(IPartyPool indexed pool, string name, string symbol, IERC20[] tokens);
|
event PartyStarted(IPartyPool indexed pool, string name, string symbol, IERC20[] tokens);
|
||||||
|
|
||||||
/// @notice Creates a new PartyPool instance and initializes it with initial deposits (legacy signature).
|
/// @notice Creates a new PartyPool instance and initializes it with initial deposits (legacy signature).
|
||||||
/// @dev Deprecated in favour of the kappa-based overload below; kept for backwards compatibility.
|
/// @dev Deprecated in favour of the kappa-based overload below; kept for backwards compatibility.
|
||||||
/// @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,
|
||||||
string memory symbol_,
|
string memory symbol,
|
||||||
IERC20[] memory _tokens,
|
IERC20[] memory tokens,
|
||||||
uint256[] memory _bases,
|
uint256[] memory bases,
|
||||||
int128 _tradeFrac,
|
int128 tradeFrac,
|
||||||
int128 _targetSlippage,
|
int128 targetSlippage,
|
||||||
uint256 _swapFeePpm,
|
uint256 swapFeePpm,
|
||||||
uint256 _flashFeePpm,
|
uint256 flashFeePpm,
|
||||||
bool _stable,
|
bool stable,
|
||||||
// Initial deposit information
|
// Initial deposit information
|
||||||
address payer,
|
address payer,
|
||||||
address receiver,
|
address receiver,
|
||||||
@@ -49,30 +49,30 @@ interface IPartyPlanner {
|
|||||||
) external returns (IPartyPool pool, uint256 lpAmount);
|
) external returns (IPartyPool pool, uint256 lpAmount);
|
||||||
|
|
||||||
/// @notice Creates a new PartyPool instance and initializes it with initial deposits (kappa-based).
|
/// @notice Creates a new PartyPool instance and initializes it with initial deposits (kappa-based).
|
||||||
/// @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,
|
||||||
string memory symbol_,
|
string memory symbol,
|
||||||
IERC20[] memory _tokens,
|
IERC20[] memory tokens,
|
||||||
uint256[] memory _bases,
|
uint256[] memory bases,
|
||||||
int128 _kappa,
|
int128 kappa,
|
||||||
uint256 _swapFeePpm,
|
uint256 swapFeePpm,
|
||||||
uint256 _flashFeePpm,
|
uint256 flashFeePpm,
|
||||||
bool _stable,
|
bool stable,
|
||||||
// Initial deposit information
|
// Initial deposit information
|
||||||
address payer,
|
address payer,
|
||||||
address receiver,
|
address receiver,
|
||||||
@@ -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
|
||||||
|
|||||||
@@ -2,8 +2,9 @@
|
|||||||
pragma solidity ^0.8.30;
|
pragma solidity ^0.8.30;
|
||||||
|
|
||||||
import "../lib/openzeppelin-contracts/contracts/interfaces/IERC3156FlashBorrower.sol";
|
import "../lib/openzeppelin-contracts/contracts/interfaces/IERC3156FlashBorrower.sol";
|
||||||
import "./NativeWrapper.sol";
|
import "./IOwnable.sol";
|
||||||
import "./LMSRStabilized.sol";
|
import "./LMSRStabilized.sol";
|
||||||
|
import "./NativeWrapper.sol";
|
||||||
import {IERC20Metadata} from "../lib/openzeppelin-contracts/contracts/token/ERC20/extensions/IERC20Metadata.sol";
|
import {IERC20Metadata} from "../lib/openzeppelin-contracts/contracts/token/ERC20/extensions/IERC20Metadata.sol";
|
||||||
import {IERC20} from "../lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol";
|
import {IERC20} from "../lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol";
|
||||||
|
|
||||||
@@ -20,7 +21,7 @@ import {IERC20} from "../lib/openzeppelin-contracts/contracts/token/ERC20/IERC20
|
|||||||
/// 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).
|
||||||
interface IPartyPool is IERC20Metadata {
|
interface IPartyPool is IERC20Metadata, IOwnable {
|
||||||
// All int128's are ABDKMath64x64 format
|
// All int128's are ABDKMath64x64 format
|
||||||
|
|
||||||
// Events
|
// Events
|
||||||
@@ -62,10 +63,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 +76,7 @@ interface IPartyPool is IERC20Metadata {
|
|||||||
function wrapperToken() external view returns (NativeWrapper);
|
function wrapperToken() external view returns (NativeWrapper);
|
||||||
|
|
||||||
/// @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 +89,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);
|
||||||
|
|
||||||
@@ -102,31 +103,36 @@ interface IPartyPool is IERC20Metadata {
|
|||||||
/// @dev Pools are constructed with a κ value; this getter exposes the κ used by the pool.
|
/// @dev Pools are constructed with a κ value; this getter exposes the κ used by the pool.
|
||||||
function kappa() external view returns (int128);
|
function kappa() external view returns (int128);
|
||||||
|
|
||||||
|
/// @notice If a security problem is found, the vault owner may call this function to permanently disable swap and
|
||||||
|
/// mint functionality, leaving only burns (withdrawals) working.
|
||||||
|
function kill() external;
|
||||||
|
function killed() external view returns (bool);
|
||||||
|
|
||||||
// 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 +155,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 +179,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 +199,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 +212,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 +231,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(
|
||||||
|
|||||||
62
src/OwnableExternal.sol
Normal file
62
src/OwnableExternal.sol
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)
|
||||||
|
|
||||||
|
pragma solidity ^0.8.20;
|
||||||
|
|
||||||
|
import "../lib/openzeppelin-contracts/contracts/utils/Context.sol";
|
||||||
|
import {OwnableInternal} from "./OwnableInternal.sol";
|
||||||
|
import {IOwnable} from "./IOwnable.sol";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dev Contract module which provides a basic access control mechanism, where
|
||||||
|
* there is an account (an owner) that can be granted exclusive access to
|
||||||
|
* specific functions.
|
||||||
|
*
|
||||||
|
* The initial owner is set to the address provided by the deployer. This can
|
||||||
|
* later be changed with {transferOwnership}.
|
||||||
|
*
|
||||||
|
* This module is used through inheritance. It will make available the modifier
|
||||||
|
* `onlyOwner`, which can be applied to your functions to restrict their use to
|
||||||
|
* the owner.
|
||||||
|
*/
|
||||||
|
abstract contract OwnableExternal is OwnableInternal, IOwnable {
|
||||||
|
/**
|
||||||
|
* @dev Initializes the contract setting the address provided by the deployer as the initial owner.
|
||||||
|
*/
|
||||||
|
constructor(address initialOwner) {
|
||||||
|
if (initialOwner == address(0)) {
|
||||||
|
revert OwnableInvalidOwner(address(0));
|
||||||
|
}
|
||||||
|
_transferOwnership(initialOwner);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dev Returns the address of the current owner.
|
||||||
|
*/
|
||||||
|
function owner() external view virtual returns (address) {
|
||||||
|
return _owner;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dev Leaves the contract without owner. It will not be possible to call
|
||||||
|
* `onlyOwner` functions. Can only be called by the current owner.
|
||||||
|
*
|
||||||
|
* NOTE: Renouncing ownership will leave the contract without an owner,
|
||||||
|
* thereby disabling any functionality that is only available to the owner.
|
||||||
|
*/
|
||||||
|
function renounceOwnership() external virtual onlyOwner {
|
||||||
|
_transferOwnership(address(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dev Transfers ownership of the contract to a new account (`newOwner`).
|
||||||
|
* Can only be called by the current owner.
|
||||||
|
*/
|
||||||
|
function transferOwnership(address newOwner) external virtual onlyOwner {
|
||||||
|
if (newOwner == address(0)) {
|
||||||
|
revert OwnableInvalidOwner(address(0));
|
||||||
|
}
|
||||||
|
_transferOwnership(newOwner);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
41
src/OwnableInternal.sol
Normal file
41
src/OwnableInternal.sol
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)
|
||||||
|
|
||||||
|
pragma solidity ^0.8.20;
|
||||||
|
|
||||||
|
import {Context} from "../lib/openzeppelin-contracts/contracts/utils/Context.sol";
|
||||||
|
import {IOwnable} from "./IOwnable.sol";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dev OpenZeppelin's Ownable contract, split into internal and external parts.
|
||||||
|
*/
|
||||||
|
abstract contract OwnableInternal is Context {
|
||||||
|
address internal _owner;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dev Throws if called by any account other than the owner.
|
||||||
|
*/
|
||||||
|
modifier onlyOwner() {
|
||||||
|
_checkOwner();
|
||||||
|
_;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dev Throws if the sender is not the owner.
|
||||||
|
*/
|
||||||
|
function _checkOwner() internal view virtual {
|
||||||
|
if (_owner != _msgSender()) {
|
||||||
|
revert IOwnable.OwnableUnauthorizedAccount(_msgSender());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dev Transfers ownership of the contract to a new account (`newOwner`).
|
||||||
|
* Internal function without access restriction.
|
||||||
|
*/
|
||||||
|
function _transferOwnership(address newOwner) internal virtual {
|
||||||
|
address oldOwner = _owner;
|
||||||
|
_owner = newOwner;
|
||||||
|
emit IOwnable.OwnershipTransferred(oldOwner, newOwner);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,15 +5,17 @@ import {IERC20} from "../lib/openzeppelin-contracts/contracts/token/ERC20/IERC20
|
|||||||
import {SafeERC20} from "../lib/openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.sol";
|
import {SafeERC20} from "../lib/openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.sol";
|
||||||
import {IPartyPlanner} from "./IPartyPlanner.sol";
|
import {IPartyPlanner} from "./IPartyPlanner.sol";
|
||||||
import {IPartyPool} from "./IPartyPool.sol";
|
import {IPartyPool} from "./IPartyPool.sol";
|
||||||
import {NativeWrapper} from "./NativeWrapper.sol";
|
|
||||||
import {LMSRStabilized} from "./LMSRStabilized.sol";
|
import {LMSRStabilized} from "./LMSRStabilized.sol";
|
||||||
|
import {NativeWrapper} from "./NativeWrapper.sol";
|
||||||
|
import {OwnableExternal} from "./OwnableExternal.sol";
|
||||||
|
import {OwnableInternal} from "./OwnableInternal.sol";
|
||||||
import {IPartyPoolDeployer} from "./PartyPoolDeployer.sol";
|
import {IPartyPoolDeployer} from "./PartyPoolDeployer.sol";
|
||||||
import {PartyPoolMintImpl} from "./PartyPoolMintImpl.sol";
|
import {PartyPoolMintImpl} from "./PartyPoolMintImpl.sol";
|
||||||
import {PartyPoolSwapImpl} from "./PartyPoolSwapImpl.sol";
|
import {PartyPoolSwapImpl} from "./PartyPoolSwapImpl.sol";
|
||||||
|
|
||||||
/// @title PartyPlanner
|
/// @title PartyPlanner
|
||||||
/// @notice Factory contract for creating and tracking PartyPool instances
|
/// @notice Factory contract for creating and tracking PartyPool instances
|
||||||
contract PartyPlanner is IPartyPlanner {
|
contract PartyPlanner is OwnableExternal, IPartyPlanner {
|
||||||
using SafeERC20 for IERC20;
|
using SafeERC20 for IERC20;
|
||||||
int128 private constant ONE = int128(1) << 64;
|
int128 private constant ONE = int128(1) << 64;
|
||||||
|
|
||||||
@@ -46,32 +48,37 @@ contract PartyPlanner is IPartyPlanner {
|
|||||||
mapping(IERC20 => bool) private _tokenSupported;
|
mapping(IERC20 => bool) private _tokenSupported;
|
||||||
mapping(IERC20 => IPartyPool[]) private _poolsByToken;
|
mapping(IERC20 => IPartyPool[]) private _poolsByToken;
|
||||||
|
|
||||||
/// @param _swapImpl address of the Swap implementation contract to be used by all pools
|
/// @param owner_ Initial administrator who is allowed to create new pools and kill() old ones
|
||||||
/// @param _mintImpl address of the Mint implementation contract to be used by all pools
|
/// @param wrapper_ The WETH9 implementation address used for this chain
|
||||||
/// @param _protocolFeePpm protocol fee share (ppm) to be used for pools created by this planner
|
/// @param swapImpl_ address of the Swap implementation contract to be used by all pools
|
||||||
/// @param _protocolFeeAddress recipient address for protocol fees for pools created by this planner (may be address(0))
|
/// @param mintImpl_ address of the Mint implementation contract to be used by all pools
|
||||||
|
/// @param protocolFeePpm_ protocol fee share (ppm) to be used for pools created by this planner
|
||||||
|
/// @param protocolFeeAddress_ recipient address for protocol fees for pools created by this planner (may be address(0))
|
||||||
constructor(
|
constructor(
|
||||||
NativeWrapper _wrapper,
|
address owner_,
|
||||||
PartyPoolSwapImpl _swapImpl,
|
NativeWrapper wrapper_,
|
||||||
PartyPoolMintImpl _mintImpl,
|
PartyPoolSwapImpl swapImpl_,
|
||||||
IPartyPoolDeployer _deployer,
|
PartyPoolMintImpl mintImpl_,
|
||||||
IPartyPoolDeployer _balancedPairDeployer,
|
IPartyPoolDeployer deployer_,
|
||||||
uint256 _protocolFeePpm,
|
IPartyPoolDeployer balancedPairDeployer_,
|
||||||
address _protocolFeeAddress
|
uint256 protocolFeePpm_,
|
||||||
) {
|
address protocolFeeAddress_
|
||||||
WRAPPER = _wrapper;
|
)
|
||||||
require(address(_swapImpl) != address(0), "Planner: swapImpl address cannot be zero");
|
OwnableExternal(owner_)
|
||||||
SWAP_IMPL = _swapImpl;
|
{
|
||||||
require(address(_mintImpl) != address(0), "Planner: mintImpl address cannot be zero");
|
WRAPPER = wrapper_;
|
||||||
MINT_IMPL = _mintImpl;
|
require(address(swapImpl_) != address(0), "Planner: swapImpl address cannot be zero");
|
||||||
require(address(_deployer) != address(0), "Planner: deployer address cannot be zero");
|
SWAP_IMPL = swapImpl_;
|
||||||
NORMAL_POOL_DEPLOYER = _deployer;
|
require(address(mintImpl_) != address(0), "Planner: mintImpl address cannot be zero");
|
||||||
require(address(_balancedPairDeployer) != address(0), "Planner: balanced pair deployer address cannot be zero");
|
MINT_IMPL = mintImpl_;
|
||||||
BALANCED_PAIR_DEPLOYER = _balancedPairDeployer;
|
require(address(deployer_) != address(0), "Planner: deployer address cannot be zero");
|
||||||
|
NORMAL_POOL_DEPLOYER = deployer_;
|
||||||
|
require(address(balancedPairDeployer_) != address(0), "Planner: balanced pair deployer address cannot be zero");
|
||||||
|
BALANCED_PAIR_DEPLOYER = balancedPairDeployer_;
|
||||||
|
|
||||||
require(_protocolFeePpm < 1_000_000, "Planner: protocol fee >= ppm");
|
require(protocolFeePpm_ < 1_000_000, "Planner: protocol fee >= ppm");
|
||||||
PROTOCOL_FEE_PPM = _protocolFeePpm;
|
PROTOCOL_FEE_PPM = protocolFeePpm_;
|
||||||
PROTOCOL_FEE_ADDRESS = _protocolFeeAddress;
|
PROTOCOL_FEE_ADDRESS = protocolFeeAddress_;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Main newPool variant: accepts kappa directly (preferred).
|
/// Main newPool variant: accepts kappa directly (preferred).
|
||||||
@@ -79,38 +86,39 @@ contract PartyPlanner is IPartyPlanner {
|
|||||||
// Pool constructor args
|
// Pool constructor args
|
||||||
string memory name_,
|
string memory name_,
|
||||||
string memory symbol_,
|
string memory symbol_,
|
||||||
IERC20[] memory _tokens,
|
IERC20[] memory tokens_,
|
||||||
uint256[] memory _bases,
|
uint256[] memory bases_,
|
||||||
int128 _kappa,
|
int128 kappa_,
|
||||||
uint256 _swapFeePpm,
|
uint256 swapFeePpm_,
|
||||||
uint256 _flashFeePpm,
|
uint256 flashFeePpm_,
|
||||||
bool _stable,
|
bool stable_,
|
||||||
// Initial deposit information
|
// Initial deposit information
|
||||||
address payer,
|
address payer,
|
||||||
address receiver,
|
address receiver,
|
||||||
uint256[] memory initialDeposits,
|
uint256[] memory initialDeposits,
|
||||||
uint256 initialLpAmount,
|
uint256 initialLpAmount,
|
||||||
uint256 deadline
|
uint256 deadline
|
||||||
) public returns (IPartyPool pool, uint256 lpAmount) {
|
) public onlyOwner returns (IPartyPool pool, uint256 lpAmount) {
|
||||||
// Validate inputs
|
// Validate inputs
|
||||||
require(deadline == 0 || block.timestamp <= deadline, "Planner: deadline exceeded");
|
require(deadline == 0 || block.timestamp <= deadline, "Planner: deadline exceeded");
|
||||||
require(_tokens.length == initialDeposits.length, "Planner: tokens and deposits length mismatch");
|
require(tokens_.length == initialDeposits.length, "Planner: tokens and deposits length mismatch");
|
||||||
require(payer != address(0), "Planner: payer cannot be zero address");
|
require(payer != address(0), "Planner: payer cannot be zero address");
|
||||||
require(receiver != address(0), "Planner: receiver cannot be zero address");
|
require(receiver != address(0), "Planner: receiver cannot be zero address");
|
||||||
|
|
||||||
// Validate kappa > 0 (Q64.64)
|
// Validate kappa > 0 (Q64.64)
|
||||||
require(_kappa > int128(0), "Planner: kappa must be > 0");
|
require(kappa_ > int128(0), "Planner: kappa must be > 0");
|
||||||
|
|
||||||
// Create a new PartyPool instance (kappa-based constructor)
|
// Create a new PartyPool instance (kappa-based constructor)
|
||||||
IPartyPoolDeployer deployer = _stable && _tokens.length == 2 ? BALANCED_PAIR_DEPLOYER : NORMAL_POOL_DEPLOYER;
|
IPartyPoolDeployer deployer = stable_ && tokens_.length == 2 ? BALANCED_PAIR_DEPLOYER : NORMAL_POOL_DEPLOYER;
|
||||||
pool = deployer.deploy(
|
pool = deployer.deploy(
|
||||||
|
_owner, // Same owner as this PartyPlanner
|
||||||
name_,
|
name_,
|
||||||
symbol_,
|
symbol_,
|
||||||
_tokens,
|
tokens_,
|
||||||
_bases,
|
bases_,
|
||||||
_kappa,
|
kappa_,
|
||||||
_swapFeePpm,
|
swapFeePpm_,
|
||||||
_flashFeePpm,
|
flashFeePpm_,
|
||||||
PROTOCOL_FEE_PPM,
|
PROTOCOL_FEE_PPM,
|
||||||
PROTOCOL_FEE_ADDRESS,
|
PROTOCOL_FEE_ADDRESS,
|
||||||
WRAPPER,
|
WRAPPER,
|
||||||
@@ -122,8 +130,8 @@ contract PartyPlanner is IPartyPlanner {
|
|||||||
_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];
|
||||||
|
|
||||||
// Add token to _allTokens if not already present
|
// Add token to _allTokens if not already present
|
||||||
if (!_tokenSupported[token]) {
|
if (!_tokenSupported[token]) {
|
||||||
@@ -135,17 +143,17 @@ contract PartyPlanner is IPartyPlanner {
|
|||||||
_poolsByToken[token].push(pool);
|
_poolsByToken[token].push(pool);
|
||||||
}
|
}
|
||||||
|
|
||||||
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]);
|
||||||
require(IERC20(_tokens[i]).balanceOf(address(pool)) == initialDeposits[i], 'fee-on-transfer tokens not supported');
|
require(IERC20(tokens_[i]).balanceOf(address(pool)) == initialDeposits[i], 'fee-on-transfer tokens not supported');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -156,37 +164,37 @@ contract PartyPlanner is IPartyPlanner {
|
|||||||
// Pool constructor args (old signature)
|
// Pool constructor args (old signature)
|
||||||
string memory name_,
|
string memory name_,
|
||||||
string memory symbol_,
|
string memory symbol_,
|
||||||
IERC20[] memory _tokens,
|
IERC20[] memory tokens_,
|
||||||
uint256[] memory _bases,
|
uint256[] memory bases_,
|
||||||
int128 _tradeFrac,
|
int128 tradeFrac_,
|
||||||
int128 _targetSlippage,
|
int128 targetSlippage_,
|
||||||
uint256 _swapFeePpm,
|
uint256 swapFeePpm_,
|
||||||
uint256 _flashFeePpm,
|
uint256 flashFeePpm_,
|
||||||
bool _stable,
|
bool stable_,
|
||||||
// Initial deposit information
|
// Initial deposit information
|
||||||
address payer,
|
address payer,
|
||||||
address receiver,
|
address receiver,
|
||||||
uint256[] memory initialDeposits,
|
uint256[] memory initialDeposits,
|
||||||
uint256 initialLpAmount,
|
uint256 initialLpAmount,
|
||||||
uint256 deadline
|
uint256 deadline
|
||||||
) external returns (IPartyPool pool, uint256 lpAmount) {
|
) external onlyOwner returns (IPartyPool pool, uint256 lpAmount) {
|
||||||
// Validate fixed-point fractions: must be less than 1.0 in 64.64 fixed-point
|
// Validate fixed-point fractions: must be less than 1.0 in 64.64 fixed-point
|
||||||
require(_tradeFrac < ONE, "Planner: tradeFrac must be < 1 (64.64)");
|
require(tradeFrac_ < ONE, "Planner: tradeFrac must be < 1 (64.64)");
|
||||||
require(_targetSlippage < ONE, "Planner: targetSlippage must be < 1 (64.64)");
|
require(targetSlippage_ < ONE, "Planner: targetSlippage must be < 1 (64.64)");
|
||||||
|
|
||||||
// Compute kappa from slippage params using LMSR helper (kappa depends only on n, f and s)
|
// Compute kappa from slippage params using LMSR helper (kappa depends only on n, f and s)
|
||||||
int128 computedKappa = LMSRStabilized.computeKappaFromSlippage(_tokens.length, _tradeFrac, _targetSlippage);
|
int128 computedKappa = LMSRStabilized.computeKappaFromSlippage(tokens_.length, tradeFrac_, targetSlippage_);
|
||||||
|
|
||||||
// Delegate to the kappa-based newPool variant
|
// Delegate to the kappa-based newPool variant
|
||||||
return newPool(
|
return newPool(
|
||||||
name_,
|
name_,
|
||||||
symbol_,
|
symbol_,
|
||||||
_tokens,
|
tokens_,
|
||||||
_bases,
|
bases_,
|
||||||
computedKappa,
|
computedKappa,
|
||||||
_swapFeePpm,
|
swapFeePpm_,
|
||||||
_flashFeePpm,
|
flashFeePpm_,
|
||||||
_stable,
|
stable_,
|
||||||
payer,
|
payer,
|
||||||
receiver,
|
receiver,
|
||||||
initialDeposits,
|
initialDeposits,
|
||||||
|
|||||||
@@ -18,27 +18,33 @@ import {ReentrancyGuard} from "../lib/openzeppelin-contracts/contracts/utils/Ree
|
|||||||
import {SafeERC20} from "../lib/openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.sol";
|
import {SafeERC20} from "../lib/openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.sol";
|
||||||
import {IERC3156FlashLender} from "../lib/openzeppelin-contracts/contracts/interfaces/IERC3156FlashLender.sol";
|
import {IERC3156FlashLender} from "../lib/openzeppelin-contracts/contracts/interfaces/IERC3156FlashLender.sol";
|
||||||
import {NativeWrapper} from "./NativeWrapper.sol";
|
import {NativeWrapper} from "./NativeWrapper.sol";
|
||||||
|
import {OwnableExternal} from "./OwnableExternal.sol";
|
||||||
|
|
||||||
/// @title PartyPool - LMSR-backed multi-asset pool with LP ERC20 token
|
/// @title PartyPool - LMSR-backed multi-asset pool with LP ERC20 token
|
||||||
/// @notice A multi-asset liquidity pool backed by the LMSRStabilized pricing model.
|
/// @notice A multi-asset liquidity pool backed by the LMSRStabilized pricing model.
|
||||||
/// 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),
|
|
||||||
/// - Exact-input swaps and swaps-to-price-limits,
|
/// - Exact-input swaps and swaps-to-price-limits,
|
||||||
/// - Flash loans via a callback interface.
|
/// - Single-token mint (swapMint) and single-asset withdrawal (burnSwap),
|
||||||
|
/// - ERC-3156 flash loans
|
||||||
///
|
///
|
||||||
/// @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). Mutating methods have re-entrancy locks.
|
||||||
contract PartyPool is PartyPoolBase, ERC20External, IPartyPool {
|
/// The contract may be "killed" by the admin in case any security issue is discovered, in which case all swaps and
|
||||||
|
/// mints are disabled, and only the burn() method remains functional to allow LP's to withdraw their assets.
|
||||||
|
contract PartyPool is PartyPoolBase, OwnableExternal, ERC20External, IPartyPool {
|
||||||
using ABDKMath64x64 for int128;
|
using ABDKMath64x64 for int128;
|
||||||
using LMSRStabilized for LMSRStabilized.State;
|
using LMSRStabilized for LMSRStabilized.State;
|
||||||
using SafeERC20 for IERC20;
|
using SafeERC20 for IERC20;
|
||||||
|
|
||||||
receive() external payable {}
|
receive() external payable {}
|
||||||
|
|
||||||
|
/// @notice If true, the vault has been disabled by the owner and only burns (withdrawals) are allowed.
|
||||||
|
function killed() external view returns (bool) { return _killed; }
|
||||||
|
|
||||||
function wrapperToken() external view returns (NativeWrapper) { return WRAPPER_TOKEN; }
|
function wrapperToken() external view returns (NativeWrapper) { return WRAPPER_TOKEN; }
|
||||||
|
|
||||||
/// @notice Liquidity parameter κ (Q64.64) used by the LMSR kernel: b = κ * S(q)
|
/// @notice Liquidity parameter κ (Q64.64) used by the LMSR kernel: b = κ * S(q)
|
||||||
@@ -90,6 +96,7 @@ contract PartyPool is PartyPoolBase, ERC20External, IPartyPool {
|
|||||||
function LMSR() external view returns (LMSRStabilized.State memory) { return _lmsr; }
|
function LMSR() external view returns (LMSRStabilized.State memory) { return _lmsr; }
|
||||||
|
|
||||||
|
|
||||||
|
/// @param owner_ Admin account that can disable the vault using kill()
|
||||||
/// @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)
|
||||||
@@ -100,6 +107,7 @@ contract PartyPool is PartyPoolBase, ERC20External, IPartyPool {
|
|||||||
/// @param swapImpl_ address of the SwapMint implementation contract
|
/// @param swapImpl_ address of the SwapMint implementation contract
|
||||||
/// @param mintImpl_ address of the Mint implementation contract
|
/// @param mintImpl_ address of the Mint implementation contract
|
||||||
constructor(
|
constructor(
|
||||||
|
address owner_,
|
||||||
string memory name_,
|
string memory name_,
|
||||||
string memory symbol_,
|
string memory symbol_,
|
||||||
IERC20[] memory tokens_,
|
IERC20[] memory tokens_,
|
||||||
@@ -114,8 +122,10 @@ contract PartyPool is PartyPoolBase, ERC20External, IPartyPool {
|
|||||||
PartyPoolMintImpl mintImpl_
|
PartyPoolMintImpl mintImpl_
|
||||||
)
|
)
|
||||||
PartyPoolBase(wrapperToken_)
|
PartyPoolBase(wrapperToken_)
|
||||||
|
OwnableExternal(owner_)
|
||||||
ERC20External(name_, symbol_)
|
ERC20External(name_, symbol_)
|
||||||
{
|
{
|
||||||
|
require(owner_ != address(0));
|
||||||
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_;
|
||||||
@@ -149,6 +159,11 @@ contract PartyPool is PartyPoolBase, ERC20External, IPartyPool {
|
|||||||
_protocolFeesOwed = new uint256[](n);
|
_protocolFeesOwed = new uint256[](n);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @notice If a security problem is found, the vault owner may call this function to permanently disable swap and
|
||||||
|
/// mint functionality, leaving only burns (withdrawals) working.
|
||||||
|
function kill() external onlyOwner {
|
||||||
|
_killed = true;
|
||||||
|
}
|
||||||
|
|
||||||
/* ----------------------
|
/* ----------------------
|
||||||
Initialization / Mint / Burn (LP token managed)
|
Initialization / Mint / Burn (LP token managed)
|
||||||
@@ -225,7 +240,7 @@ contract PartyPool is PartyPoolBase, ERC20External, IPartyPool {
|
|||||||
int128 limitPrice,
|
int128 limitPrice,
|
||||||
uint256 deadline,
|
uint256 deadline,
|
||||||
bool unwrap
|
bool unwrap
|
||||||
) external payable native nonReentrant returns (uint256 amountIn, uint256 amountOut, uint256 fee) {
|
) external payable native nonReentrant killable returns (uint256 amountIn, uint256 amountOut, uint256 fee) {
|
||||||
require(deadline == 0 || block.timestamp <= deadline, "swap: deadline exceeded");
|
require(deadline == 0 || block.timestamp <= deadline, "swap: deadline exceeded");
|
||||||
|
|
||||||
// Compute amounts using the same path as views
|
// Compute amounts using the same path as views
|
||||||
@@ -425,7 +440,7 @@ contract PartyPool is PartyPoolBase, ERC20External, IPartyPool {
|
|||||||
address tokenAddr,
|
address tokenAddr,
|
||||||
uint256 amount,
|
uint256 amount,
|
||||||
bytes calldata data
|
bytes calldata data
|
||||||
) external nonReentrant returns (bool)
|
) external nonReentrant killable returns (bool)
|
||||||
{
|
{
|
||||||
IERC20 token = IERC20(tokenAddr);
|
IERC20 token = IERC20(tokenAddr);
|
||||||
require(amount <= token.balanceOf(address(this)));
|
require(amount <= token.balanceOf(address(this)));
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import {PartyPoolSwapImpl} from "./PartyPoolSwapImpl.sol";
|
|||||||
|
|
||||||
contract PartyPoolBalancedPair is PartyPool {
|
contract PartyPoolBalancedPair is PartyPool {
|
||||||
constructor(
|
constructor(
|
||||||
|
address owner_,
|
||||||
string memory name_,
|
string memory name_,
|
||||||
string memory symbol_,
|
string memory symbol_,
|
||||||
IERC20[] memory tokens_,
|
IERC20[] memory tokens_,
|
||||||
@@ -23,7 +24,8 @@ contract PartyPoolBalancedPair is PartyPool {
|
|||||||
NativeWrapper wrapperToken_,
|
NativeWrapper wrapperToken_,
|
||||||
PartyPoolSwapImpl swapMintImpl_,
|
PartyPoolSwapImpl swapMintImpl_,
|
||||||
PartyPoolMintImpl mintImpl_
|
PartyPoolMintImpl mintImpl_
|
||||||
) PartyPool(name_, symbol_, tokens_, bases_, kappa_, swapFeePpm_, flashFeePpm_, protocolFeePpm_, protocolFeeAddress_, wrapperToken_, swapMintImpl_, mintImpl_)
|
)
|
||||||
|
PartyPool(owner_, name_, symbol_, tokens_, bases_, kappa_, swapFeePpm_, flashFeePpm_, protocolFeePpm_, protocolFeeAddress_, wrapperToken_, swapMintImpl_, mintImpl_)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
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
|
||||||
|
|||||||
@@ -9,10 +9,11 @@ import {LMSRStabilized} from "./LMSRStabilized.sol";
|
|||||||
import {PartyPoolHelpers} from "./PartyPoolHelpers.sol";
|
import {PartyPoolHelpers} from "./PartyPoolHelpers.sol";
|
||||||
import {ReentrancyGuard} from "../lib/openzeppelin-contracts/contracts/utils/ReentrancyGuard.sol";
|
import {ReentrancyGuard} from "../lib/openzeppelin-contracts/contracts/utils/ReentrancyGuard.sol";
|
||||||
import {SafeERC20} from "../lib/openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.sol";
|
import {SafeERC20} from "../lib/openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.sol";
|
||||||
|
import {OwnableInternal} from "./OwnableInternal.sol";
|
||||||
|
|
||||||
/// @notice Abstract base contract that contains storage and internal helpers only.
|
/// @notice Abstract base contract that contains storage and internal helpers only.
|
||||||
/// No external/public functions or constructor here — derived implementations own immutables and constructors.
|
/// No external/public functions here.
|
||||||
abstract contract PartyPoolBase is ERC20Internal, ReentrancyGuard, PartyPoolHelpers {
|
abstract contract PartyPoolBase is OwnableInternal, ERC20Internal, ReentrancyGuard, PartyPoolHelpers {
|
||||||
using ABDKMath64x64 for int128;
|
using ABDKMath64x64 for int128;
|
||||||
using LMSRStabilized for LMSRStabilized.State;
|
using LMSRStabilized for LMSRStabilized.State;
|
||||||
using SafeERC20 for IERC20;
|
using SafeERC20 for IERC20;
|
||||||
@@ -23,18 +24,13 @@ abstract contract PartyPoolBase is ERC20Internal, ReentrancyGuard, PartyPoolHelp
|
|||||||
WRAPPER_TOKEN = wrapper_;
|
WRAPPER_TOKEN = wrapper_;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @notice Designates methods that can receive native currency.
|
//
|
||||||
/// @dev If the pool has any balance of native currency at the end of the method, it is refunded to msg.sender
|
// Internal state
|
||||||
modifier native() {
|
//
|
||||||
_;
|
|
||||||
uint256 bal = address(this).balance;
|
|
||||||
if(bal > 0)
|
|
||||||
payable(msg.sender).transfer(bal);
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
/// @notice If _killed is set, then all `killable` methods are permanently disabled, leaving only burns
|
||||||
// Internal state (no immutables here; immutables belong to derived contracts)
|
/// (withdrawals) working
|
||||||
//
|
bool internal _killed;
|
||||||
|
|
||||||
// LMSR internal state
|
// LMSR internal state
|
||||||
LMSRStabilized.State internal _lmsr;
|
LMSRStabilized.State internal _lmsr;
|
||||||
@@ -64,6 +60,20 @@ abstract contract PartyPoolBase is ERC20Internal, ReentrancyGuard, PartyPoolHelp
|
|||||||
uint256[] internal _cachedUintBalances;
|
uint256[] internal _cachedUintBalances;
|
||||||
|
|
||||||
|
|
||||||
|
/// @notice Designates methods that can receive native currency.
|
||||||
|
/// @dev If the pool has any balance of native currency at the end of the method, it is refunded to msg.sender
|
||||||
|
modifier native() {
|
||||||
|
_;
|
||||||
|
uint256 bal = address(this).balance;
|
||||||
|
if(bal > 0)
|
||||||
|
payable(msg.sender).transfer(bal);
|
||||||
|
}
|
||||||
|
|
||||||
|
modifier killable() {
|
||||||
|
require(!_killed, 'killed');
|
||||||
|
_;
|
||||||
|
}
|
||||||
|
|
||||||
/* ----------------------
|
/* ----------------------
|
||||||
Conversion & fee helpers (internal)
|
Conversion & fee helpers (internal)
|
||||||
---------------------- */
|
---------------------- */
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import {PartyPoolBalancedPair} from "./PartyPoolBalancedPair.sol";
|
|||||||
|
|
||||||
interface IPartyPoolDeployer {
|
interface IPartyPoolDeployer {
|
||||||
function deploy(
|
function deploy(
|
||||||
|
address owner_,
|
||||||
string memory name_,
|
string memory name_,
|
||||||
string memory symbol_,
|
string memory symbol_,
|
||||||
IERC20[] memory tokens_,
|
IERC20[] memory tokens_,
|
||||||
@@ -28,6 +29,7 @@ interface IPartyPoolDeployer {
|
|||||||
|
|
||||||
contract PartyPoolDeployer is IPartyPoolDeployer {
|
contract PartyPoolDeployer is IPartyPoolDeployer {
|
||||||
function deploy(
|
function deploy(
|
||||||
|
address owner_,
|
||||||
string memory name_,
|
string memory name_,
|
||||||
string memory symbol_,
|
string memory symbol_,
|
||||||
IERC20[] memory tokens_,
|
IERC20[] memory tokens_,
|
||||||
@@ -42,6 +44,7 @@ contract PartyPoolDeployer is IPartyPoolDeployer {
|
|||||||
PartyPoolMintImpl mintImpl_
|
PartyPoolMintImpl mintImpl_
|
||||||
) external returns (IPartyPool) {
|
) external returns (IPartyPool) {
|
||||||
return new PartyPool(
|
return new PartyPool(
|
||||||
|
owner_,
|
||||||
name_,
|
name_,
|
||||||
symbol_,
|
symbol_,
|
||||||
tokens_,
|
tokens_,
|
||||||
@@ -60,6 +63,7 @@ contract PartyPoolDeployer is IPartyPoolDeployer {
|
|||||||
|
|
||||||
contract PartyPoolBalancedPairDeployer is IPartyPoolDeployer {
|
contract PartyPoolBalancedPairDeployer is IPartyPoolDeployer {
|
||||||
function deploy(
|
function deploy(
|
||||||
|
address owner_,
|
||||||
string memory name_,
|
string memory name_,
|
||||||
string memory symbol_,
|
string memory symbol_,
|
||||||
IERC20[] memory tokens_,
|
IERC20[] memory tokens_,
|
||||||
@@ -74,6 +78,7 @@ contract PartyPoolBalancedPairDeployer is IPartyPoolDeployer {
|
|||||||
PartyPoolMintImpl mintImpl_
|
PartyPoolMintImpl mintImpl_
|
||||||
) external returns (IPartyPool) {
|
) external returns (IPartyPool) {
|
||||||
return new PartyPoolBalancedPair(
|
return new PartyPoolBalancedPair(
|
||||||
|
owner_,
|
||||||
name_,
|
name_,
|
||||||
symbol_,
|
symbol_,
|
||||||
tokens_,
|
tokens_,
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ contract PartyPoolMintImpl is PartyPoolBase {
|
|||||||
// Initialization Mint
|
// Initialization Mint
|
||||||
//
|
//
|
||||||
|
|
||||||
function initialMint(address receiver, uint256 lpTokens, int128 KAPPA) external payable native nonReentrant
|
function initialMint(address receiver, uint256 lpTokens, int128 KAPPA) external payable native killable nonReentrant
|
||||||
returns (uint256 lpMinted) {
|
returns (uint256 lpMinted) {
|
||||||
uint256 n = _tokens.length;
|
uint256 n = _tokens.length;
|
||||||
|
|
||||||
@@ -65,7 +65,7 @@ contract PartyPoolMintImpl is PartyPoolBase {
|
|||||||
// Regular Mint and Burn
|
// Regular Mint and Burn
|
||||||
//
|
//
|
||||||
|
|
||||||
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 killable 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;
|
||||||
@@ -131,7 +131,8 @@ 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. Functional even if the pool has been
|
||||||
|
/// killed.
|
||||||
/// @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
|
||||||
@@ -345,7 +346,7 @@ contract PartyPoolMintImpl is PartyPoolBase {
|
|||||||
uint256 deadline,
|
uint256 deadline,
|
||||||
uint256 swapFeePpm,
|
uint256 swapFeePpm,
|
||||||
uint256 protocolFeePpm
|
uint256 protocolFeePpm
|
||||||
) external payable native nonReentrant returns (uint256 lpMinted) {
|
) external payable native killable 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");
|
||||||
@@ -468,6 +469,8 @@ contract PartyPoolMintImpl is PartyPoolBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// @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.
|
||||||
|
/// This version of burn does not work if the vault has been killed, because it involves a swap. Use regular burn()
|
||||||
|
/// to recover funds if the pool has been killed.
|
||||||
/// @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
|
||||||
@@ -485,7 +488,7 @@ contract PartyPoolMintImpl is PartyPoolBase {
|
|||||||
bool unwrap,
|
bool unwrap,
|
||||||
uint256 swapFeePpm,
|
uint256 swapFeePpm,
|
||||||
uint256 protocolFeePpm
|
uint256 protocolFeePpm
|
||||||
) external nonReentrant returns (uint256 amountOutUint) {
|
) external nonReentrant killable 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");
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ contract PartyPoolSwapImpl is PartyPoolBase {
|
|||||||
bool unwrap,
|
bool unwrap,
|
||||||
uint256 swapFeePpm,
|
uint256 swapFeePpm,
|
||||||
uint256 protocolFeePpm
|
uint256 protocolFeePpm
|
||||||
) external payable native returns (uint256 amountInUsed, uint256 amountOut, uint256 fee) {
|
) external payable native killable nonReentrant 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");
|
||||||
|
|||||||
@@ -18,11 +18,17 @@ library Deploy {
|
|||||||
|
|
||||||
function newPartyPlanner() internal returns (PartyPlanner) {
|
function newPartyPlanner() internal returns (PartyPlanner) {
|
||||||
NativeWrapper wrapper = new WETH9();
|
NativeWrapper wrapper = new WETH9();
|
||||||
return newPartyPlanner(wrapper);
|
return newPartyPlanner(msg.sender, wrapper);
|
||||||
}
|
}
|
||||||
|
|
||||||
function newPartyPlanner(NativeWrapper wrapper) internal returns (PartyPlanner) {
|
function newPartyPlanner(address owner) internal returns (PartyPlanner) {
|
||||||
|
NativeWrapper wrapper = new WETH9();
|
||||||
|
return newPartyPlanner(owner, wrapper);
|
||||||
|
}
|
||||||
|
|
||||||
|
function newPartyPlanner(address owner, NativeWrapper wrapper) internal returns (PartyPlanner) {
|
||||||
return new PartyPlanner(
|
return new PartyPlanner(
|
||||||
|
owner,
|
||||||
wrapper,
|
wrapper,
|
||||||
new PartyPoolSwapImpl(wrapper),
|
new PartyPoolSwapImpl(wrapper),
|
||||||
new PartyPoolMintImpl(wrapper),
|
new PartyPoolMintImpl(wrapper),
|
||||||
@@ -34,6 +40,7 @@ library Deploy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function newPartyPool(
|
function newPartyPool(
|
||||||
|
address owner_,
|
||||||
string memory name_,
|
string memory name_,
|
||||||
string memory symbol_,
|
string memory symbol_,
|
||||||
IERC20[] memory tokens_,
|
IERC20[] memory tokens_,
|
||||||
@@ -44,10 +51,11 @@ library Deploy {
|
|||||||
bool _stable
|
bool _stable
|
||||||
) internal returns (PartyPool) {
|
) internal returns (PartyPool) {
|
||||||
NativeWrapper wrapper = new WETH9();
|
NativeWrapper wrapper = new WETH9();
|
||||||
return newPartyPool(name_, symbol_, tokens_, bases_, _kappa, _swapFeePpm, _flashFeePpm, wrapper, _stable);
|
return newPartyPool(owner_, name_, symbol_, tokens_, bases_, _kappa, _swapFeePpm, _flashFeePpm, wrapper, _stable);
|
||||||
}
|
}
|
||||||
|
|
||||||
function newPartyPool(
|
function newPartyPool(
|
||||||
|
address owner_,
|
||||||
string memory name_,
|
string memory name_,
|
||||||
string memory symbol_,
|
string memory symbol_,
|
||||||
IERC20[] memory tokens_,
|
IERC20[] memory tokens_,
|
||||||
@@ -60,6 +68,7 @@ library Deploy {
|
|||||||
) internal returns (PartyPool) {
|
) internal returns (PartyPool) {
|
||||||
return _stable && tokens_.length == 2 ?
|
return _stable && tokens_.length == 2 ?
|
||||||
new PartyPoolBalancedPair(
|
new PartyPoolBalancedPair(
|
||||||
|
owner_,
|
||||||
name_,
|
name_,
|
||||||
symbol_,
|
symbol_,
|
||||||
tokens_,
|
tokens_,
|
||||||
@@ -74,6 +83,7 @@ library Deploy {
|
|||||||
new PartyPoolMintImpl(wrapper)
|
new PartyPoolMintImpl(wrapper)
|
||||||
) :
|
) :
|
||||||
new PartyPool(
|
new PartyPool(
|
||||||
|
owner_,
|
||||||
name_,
|
name_,
|
||||||
symbol_,
|
symbol_,
|
||||||
tokens_,
|
tokens_,
|
||||||
|
|||||||
@@ -141,7 +141,7 @@ contract GasTest is Test {
|
|||||||
}
|
}
|
||||||
// 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(address(this), poolName, poolName, ierc20Tokens, bases, computedKappa, feePpm, feePpm, false);
|
||||||
|
|
||||||
// Transfer initial deposit amounts into pool before initial mint
|
// Transfer initial deposit amounts into pool before initial mint
|
||||||
for (uint256 i = 0; i < numTokens; i++) {
|
for (uint256 i = 0; i < numTokens; i++) {
|
||||||
@@ -181,7 +181,7 @@ contract GasTest is Test {
|
|||||||
ierc20Tokens[i] = IERC20(tokens[i]);
|
ierc20Tokens[i] = IERC20(tokens[i]);
|
||||||
}
|
}
|
||||||
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, true);
|
PartyPool newPool = Deploy.newPartyPool(address(this), poolName, poolName, ierc20Tokens, bases, computedKappa, feePpm, feePpm, true);
|
||||||
|
|
||||||
// Transfer initial deposit amounts into pool before initial mint
|
// Transfer initial deposit amounts into pool before initial mint
|
||||||
for (uint256 i = 0; i < numTokens; i++) {
|
for (uint256 i = 0; i < numTokens; i++) {
|
||||||
|
|||||||
@@ -94,7 +94,7 @@ contract NativeTest is Test {
|
|||||||
uint256 feePpm = 1000;
|
uint256 feePpm = 1000;
|
||||||
|
|
||||||
int128 kappa = LMSRStabilized.computeKappaFromSlippage(tokens.length, tradeFrac, targetSlippage);
|
int128 kappa = LMSRStabilized.computeKappaFromSlippage(tokens.length, tradeFrac, targetSlippage);
|
||||||
pool = Deploy.newPartyPool("LP", "LP", tokens, bases, kappa, feePpm, feePpm, weth, false);
|
pool = Deploy.newPartyPool(address(this), "LP", "LP", tokens, bases, kappa, feePpm, feePpm, weth, false);
|
||||||
|
|
||||||
// Transfer initial deposit amounts into pool
|
// Transfer initial deposit amounts into pool
|
||||||
token0.transfer(address(pool), INIT_BAL);
|
token0.transfer(address(pool), INIT_BAL);
|
||||||
|
|||||||
@@ -46,8 +46,8 @@ contract PartyPlannerTest is Test {
|
|||||||
uint256 constant INITIAL_DEPOSIT_AMOUNT = 1000e18;
|
uint256 constant INITIAL_DEPOSIT_AMOUNT = 1000e18;
|
||||||
|
|
||||||
function setUp() public {
|
function setUp() public {
|
||||||
// Deploy PartyPlanner
|
// Deploy PartyPlanner owned by this test contract
|
||||||
planner = Deploy.newPartyPlanner();
|
planner = Deploy.newPartyPlanner(address(this));
|
||||||
|
|
||||||
// Deploy mock _tokens
|
// Deploy mock _tokens
|
||||||
tokenA = new MockERC20("Token A", "TKNA", 18);
|
tokenA = new MockERC20("Token A", "TKNA", 18);
|
||||||
|
|||||||
@@ -173,7 +173,7 @@ contract PartyPoolTest is Test {
|
|||||||
uint256 feePpm = 1000;
|
uint256 feePpm = 1000;
|
||||||
|
|
||||||
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(address(this), "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
|
||||||
@@ -203,7 +203,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(address(this), "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);
|
||||||
@@ -992,11 +992,11 @@ contract PartyPoolTest is Test {
|
|||||||
|
|
||||||
// Pool with default initialization (lpTokens = 0)
|
// Pool with default initialization (lpTokens = 0)
|
||||||
int128 kappaDefault = LMSRStabilized.computeKappaFromSlippage(tokens.length, tradeFrac, targetSlippage);
|
int128 kappaDefault = LMSRStabilized.computeKappaFromSlippage(tokens.length, tradeFrac, targetSlippage);
|
||||||
PartyPool poolDefault = Deploy.newPartyPool("LP_DEFAULT", "LP_DEFAULT", tokens, bases, kappaDefault, feePpm, feePpm, false);
|
PartyPool poolDefault = Deploy.newPartyPool(address(this), "LP_DEFAULT", "LP_DEFAULT", tokens, bases, kappaDefault, feePpm, feePpm, false);
|
||||||
|
|
||||||
// Pool with custom initialization (lpTokens = custom amount)
|
// Pool with custom initialization (lpTokens = custom amount)
|
||||||
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(address(this), "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);
|
||||||
@@ -1068,9 +1068,9 @@ contract PartyPoolTest is Test {
|
|||||||
uint256 feePpm = 1000;
|
uint256 feePpm = 1000;
|
||||||
|
|
||||||
int128 kappaDefault2 = LMSRStabilized.computeKappaFromSlippage(tokens.length, tradeFrac, targetSlippage);
|
int128 kappaDefault2 = LMSRStabilized.computeKappaFromSlippage(tokens.length, tradeFrac, targetSlippage);
|
||||||
PartyPool poolDefault = Deploy.newPartyPool("LP_DEFAULT", "LP_DEFAULT", tokens, bases, kappaDefault2, feePpm, feePpm, false);
|
PartyPool poolDefault = Deploy.newPartyPool(address(this), "LP_DEFAULT", "LP_DEFAULT", tokens, bases, kappaDefault2, feePpm, feePpm, false);
|
||||||
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(address(this), "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);
|
||||||
|
|||||||
Reference in New Issue
Block a user