ownership & killable

This commit is contained in:
tim
2025-10-19 13:35:33 -04:00
parent 5aa0032be0
commit d55be28cba
18 changed files with 364 additions and 176 deletions

View File

@@ -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 {IPartyPlanner} from "./IPartyPlanner.sol";
import {IPartyPool} from "./IPartyPool.sol";
import {NativeWrapper} from "./NativeWrapper.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 {PartyPoolMintImpl} from "./PartyPoolMintImpl.sol";
import {PartyPoolSwapImpl} from "./PartyPoolSwapImpl.sol";
/// @title PartyPlanner
/// @notice Factory contract for creating and tracking PartyPool instances
contract PartyPlanner is IPartyPlanner {
contract PartyPlanner is OwnableExternal, IPartyPlanner {
using SafeERC20 for IERC20;
int128 private constant ONE = int128(1) << 64;
@@ -46,32 +48,37 @@ contract PartyPlanner is IPartyPlanner {
mapping(IERC20 => bool) private _tokenSupported;
mapping(IERC20 => IPartyPool[]) private _poolsByToken;
/// @param _swapImpl address of the Swap implementation contract to be used by all pools
/// @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))
/// @param owner_ Initial administrator who is allowed to create new pools and kill() old ones
/// @param wrapper_ The WETH9 implementation address used for this chain
/// @param swapImpl_ address of the Swap implementation contract to be used by all pools
/// @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(
NativeWrapper _wrapper,
PartyPoolSwapImpl _swapImpl,
PartyPoolMintImpl _mintImpl,
IPartyPoolDeployer _deployer,
IPartyPoolDeployer _balancedPairDeployer,
uint256 _protocolFeePpm,
address _protocolFeeAddress
) {
WRAPPER = _wrapper;
require(address(_swapImpl) != address(0), "Planner: swapImpl address cannot be zero");
SWAP_IMPL = _swapImpl;
require(address(_mintImpl) != address(0), "Planner: mintImpl address cannot be zero");
MINT_IMPL = _mintImpl;
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;
address owner_,
NativeWrapper wrapper_,
PartyPoolSwapImpl swapImpl_,
PartyPoolMintImpl mintImpl_,
IPartyPoolDeployer deployer_,
IPartyPoolDeployer balancedPairDeployer_,
uint256 protocolFeePpm_,
address protocolFeeAddress_
)
OwnableExternal(owner_)
{
WRAPPER = wrapper_;
require(address(swapImpl_) != address(0), "Planner: swapImpl address cannot be zero");
SWAP_IMPL = swapImpl_;
require(address(mintImpl_) != address(0), "Planner: mintImpl address cannot be zero");
MINT_IMPL = mintImpl_;
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");
PROTOCOL_FEE_PPM = _protocolFeePpm;
PROTOCOL_FEE_ADDRESS = _protocolFeeAddress;
require(protocolFeePpm_ < 1_000_000, "Planner: protocol fee >= ppm");
PROTOCOL_FEE_PPM = protocolFeePpm_;
PROTOCOL_FEE_ADDRESS = protocolFeeAddress_;
}
/// Main newPool variant: accepts kappa directly (preferred).
@@ -79,38 +86,39 @@ contract PartyPlanner is IPartyPlanner {
// Pool constructor args
string memory name_,
string memory symbol_,
IERC20[] memory _tokens,
uint256[] memory _bases,
int128 _kappa,
uint256 _swapFeePpm,
uint256 _flashFeePpm,
bool _stable,
IERC20[] memory tokens_,
uint256[] memory bases_,
int128 kappa_,
uint256 swapFeePpm_,
uint256 flashFeePpm_,
bool stable_,
// Initial deposit information
address payer,
address receiver,
uint256[] memory initialDeposits,
uint256 initialLpAmount,
uint256 deadline
) public returns (IPartyPool pool, uint256 lpAmount) {
) public onlyOwner returns (IPartyPool pool, uint256 lpAmount) {
// Validate inputs
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(receiver != address(0), "Planner: receiver cannot be zero address");
// 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)
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(
_owner, // Same owner as this PartyPlanner
name_,
symbol_,
_tokens,
_bases,
_kappa,
_swapFeePpm,
_flashFeePpm,
tokens_,
bases_,
kappa_,
swapFeePpm_,
flashFeePpm_,
PROTOCOL_FEE_PPM,
PROTOCOL_FEE_ADDRESS,
WRAPPER,
@@ -122,8 +130,8 @@ contract PartyPlanner is IPartyPlanner {
_poolSupported[pool] = true;
// Track _tokens and populate mappings
for (uint256 i = 0; i < _tokens.length; i++) {
IERC20 token = _tokens[i];
for (uint256 i = 0; i < tokens_.length; i++) {
IERC20 token = tokens_[i];
// Add token to _allTokens if not already present
if (!_tokenSupported[token]) {
@@ -135,17 +143,17 @@ contract PartyPlanner is IPartyPlanner {
_poolsByToken[token].push(pool);
}
emit PartyStarted(pool, name_, symbol_, _tokens);
emit PartyStarted(pool, name_, symbol_, tokens_);
// 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) {
IERC20(_tokens[i]).safeTransferFrom(payer, address(pool), initialDeposits[i]);
require(IERC20(_tokens[i]).balanceOf(address(pool)) == initialDeposits[i], 'fee-on-transfer tokens not supported');
IERC20(tokens_[i]).safeTransferFrom(payer, address(pool), initialDeposits[i]);
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);
}
@@ -156,37 +164,37 @@ contract PartyPlanner is IPartyPlanner {
// Pool constructor args (old signature)
string memory name_,
string memory symbol_,
IERC20[] memory _tokens,
uint256[] memory _bases,
int128 _tradeFrac,
int128 _targetSlippage,
uint256 _swapFeePpm,
uint256 _flashFeePpm,
bool _stable,
IERC20[] memory tokens_,
uint256[] memory bases_,
int128 tradeFrac_,
int128 targetSlippage_,
uint256 swapFeePpm_,
uint256 flashFeePpm_,
bool stable_,
// Initial deposit information
address payer,
address receiver,
uint256[] memory initialDeposits,
uint256 initialLpAmount,
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
require(_tradeFrac < ONE, "Planner: tradeFrac must be < 1 (64.64)");
require(_targetSlippage < ONE, "Planner: targetSlippage 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)");
// 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
return newPool(
name_,
symbol_,
_tokens,
_bases,
tokens_,
bases_,
computedKappa,
_swapFeePpm,
_flashFeePpm,
_stable,
swapFeePpm_,
flashFeePpm_,
stable_,
payer,
receiver,
initialDeposits,