Liquid staking pool system built on Lido V3 vaults with support for minting and external yield strategies.
# Build
forge build
# Run tests
just test-unit # Unit tests (no env needed)
just -E .env.hoodi.local test-integration # Integration tests (requires env)
# Format code
forge fmtNote: Integration tests and deployment scripts require environment variables. Use .env.* files with just -E:
just -E .env.hoodi.local <command> # Hoodi testnet
just -E .env.local <command> # Local developmentThe system consists of:
- Pool (ERC20) - User-facing liquid staking token
- Vault - Lido V3 staking vault with validators
- Dashboard - Vault role management and operations interface
- Withdrawal Queue - Handles unstaking requests
- Distributor - Fee distribution to node operators
- Timelock - Admin for all components with execution delay
- Strategy (optional) - External yield optimization
| Type | Minting | Strategy | Allowlist | Use Case |
|---|---|---|---|---|
| StvPool | ❌ | ❌ | Optional | Basic staking pool |
| StvStETHPool | ✅ | ❌ | Optional | Pool with stETH liquidity management |
| StvStrategyPool | ✅ | ✅ | Required | Pool with external strategy (e.g., GGV) |
- Minting: Pool can mint/burn stETH for advanced liquidity operations
- Strategy: Pool integrates with external yield optimizer
- Allowlist: Restricts deposits to approved addresses
All deployments use a two-phase pattern for security:
- Start - Deploys components, emits
PoolCreationStartedwith cryptographic commitment - Finish - Initializes contracts, wires roles, validates integrity (must complete within 24h)
# Deploy factory (one-time)
just -E .env.hoodi.local deploy-factory
# Deploy all pool types
just deploy-all .env.hoodi.local
# Deploy single pool (two-phase)
just deploy-pool-start $FACTORY_ADDRESS config/hoodi-stv.json
just deploy-pool-finish $FACTORY_ADDRESS deployments/intermediate-<timestamp>.json
# Deploy Mellow strategy factory + Mellow strategy pool on local Hoodi fork
just -E .env.hoodi.local deploy-mellow-strategy-factory
just -E .env.hoodi.local deploy-mellow-pool $FACTORY_ADDRESS config/hoodi-mellow.jsonEach pool type requires a JSON config. See config/ directory for examples.
Required fields:
vaultConfig- Node operator, manager, fees, confirmation expirytimelockConfig- Minimum delay, proposer, executor addressescommonPoolConfig- Token name/symbol, withdrawal delay, emergency committeeauxiliaryPoolConfig- Minting, allowlist, reserve ratio gap settingsstrategyFactory- Address of strategy factory (or zero address)mellow- For Mellow strategy pools only:vault,syncDepositQueue,asyncDepositQueue,asyncRedeemQueue
Constructor:
new Factory(locatorAddress, SubFactories({
stvPoolFactory,
stvStETHPoolFactory,
withdrawalQueueFactory,
distributorFactory,
timelockFactory
}))Deployment Functions:
// Simplified wrappers
createPoolStvStart(vaultConfig, timelockConfig, commonPoolConfig, allowlistEnabled)
createPoolStvStETHStart(vaultConfig, timelockConfig, commonPoolConfig, allowlistEnabled, reserveRatioGapBP)
// Generic (used by wrappers above)
createPoolStart(vaultConfig, timelockConfig, commonPoolConfig, auxiliaryConfig, strategyFactory, strategyDeployBytes)
// Finalization (for all pool types)
createPoolFinish(vaultConfig, timelockConfig, commonPoolConfig, auxiliaryConfig, strategyFactory, strategyDeployBytes, intermediate)- Timelock controller
- Pool proxy (uninitialized with DummyImplementation)
- Withdrawal queue proxy (uninitialized)
- Vault + Dashboard (not connected to VaultHub yet)
- Withdrawal queue implementation
- Distributor
- Pool implementation (StvPool or StvStETHPool based on config)
- Stores deployment hash with 24h deadline
- Validates deployment hash, deadline, and sender
- Connects vault to VaultHub (requires ETH =
VAULT_HUB.CONNECT_DEPOSIT()) - Upgrades pool proxy to real implementation and initializes
- Upgrades withdrawal queue proxy and initializes
- Deploys strategy (if specified) and adds to allowlist
- Grants emergency committee roles (pause deposits/minting)
- Grants operational roles (fund, rebalance, withdraw, mint, burn)
- Transfers admin to timelock
- Emits
PoolCreatedevent
Pool:
DEFAULT_ADMIN_ROLE→ TimelockDEPOSITS_PAUSE_ROLE→ Emergency CommitteeMINTING_PAUSE_ROLE→ Emergency Committee (if minting enabled)
Dashboard:
DEFAULT_ADMIN_ROLE→ TimelockFUND_ROLE→ PoolREBALANCE_ROLE→ PoolWITHDRAW_ROLE→ Withdrawal QueueMINT_ROLE,BURN_ROLE→ Pool (if minting enabled)PAUSE_BEACON_CHAIN_DEPOSITS_ROLE→ Emergency Committee
Distributor:
MANAGER_ROLE→ Node Operator Manager
- Circular dependencies (Pool ↔ Withdrawal Queue, Pool ↔ Strategy) resolved by deploying proxies first with DummyImplementation, then upgrading
- All cross-contract references stored as
immutableto save gas on operations - Separate factories keep main Factory under 24KB bytecode limit
# Clone and install dependencies
just core-init feat/vaults
# Deploy to local Anvil
just core-deploy lido-core 9123# Start local node
anvil --chain-id 1 --auto-impersonate --port 9123
# In another terminal
export CORE_LOCATOR_ADDRESS=$(jq -r '.lidoLocator.proxy.address' lido-core/deployed-local.json)
export RPC_URL=http://localhost:9123
# Deploy factory
just deploy-factory
# Deploy pools
just deploy-all .env.local# Unit tests (no env required)
just test-unit
# Integration tests (requires env with RPC_URL and CORE_LOCATOR_ADDRESS)
just -E .env.hoodi.local test-integration
# Specific test file
just -E .env.hoodi.local test-integration "stv-pool.test.sol"Required environment variables:
RPC_URL- RPC endpoint with deployed Lido coreCORE_LOCATOR_ADDRESS- Address of Lido Locator contractDEPLOYER- Deployer address (for deployments)PRIVATE_KEY- Private key (for deployments)
deployments/pool-factory-latest.json- Factory and sub-factory addressesdeployments/intermediate-<timestamp>-<config>.json- Intermediate state for finish phasedeployments/pool-instance-<config>-<chainId>-<timestamp>.json- Final deployment with all addresses
just --list # Show all available commands
# Deployment (requires -E .env.xxx)
just -E .env.xxx deploy-factory # Deploy factory
just -E .env.xxx deploy-pool-start ... # Start pool deployment
just -E .env.xxx deploy-pool-finish ... # Finish pool deployment
just -E .env.xxx deploy-all <env> # Deploy factory + all pool types
just -E .env.xxx deploy-mellow-strategy-factory
just -E .env.xxx deploy-mellow-pool ...
# Testing
just test-unit # Run unit tests (no env needed)
just -E .env.xxx test-integration [path] # Run integration tests (requires env)
# Local core setup
just core-init [branch] # Clone and setup Lido core
just core-deploy [subdir] [port] # Deploy Lido core locally