Pool
Overview
The MultiLpLiquidityPool contract (src/pool/MultiLpLiquidityPool.sol) is the core component of the Citadel Finance protocol. It implements a sophisticated liquidity pool that enables synthetic asset minting/burning with multiple liquidity providers, yield generation through lending protocols, and comprehensive risk management.
Purpose
- Synthetic Asset Creation: Mint/burn synthetic EUR and other assets
- Multi-LP Support: Multiple liquidity providers backing the same pool
- Yield Generation: Integration with lending protocols for idle collateral
- Risk Management: Liquidation mechanisms and overcollateralization
- Capital Efficiency: Optimized collateral utilization
Contract Details
- File:
src/pool/MultiLpLiquidityPool.sol - Inheritance: Multiple interfaces and security contracts
- License: AGPL-3.0-only
Key Functions
User Operations
mint
function mint(MintParams calldata _params)
external
override
nonReentrant
isNotExpired(_params.expiration)
returns (uint256 syntheticTokensMinted, uint256 feePaid)
Purpose: Mints synthetic tokens by depositing collateral.
Parameters (MintParams struct):
expiration: Transaction deadlinemintParams: Specific minting parameterscollateralAmount: Amount of collateral to depositnumTokens: Expected synthetic tokens to receivefeePercentage: Current fee percentagerecipient: Address to receive synthetic tokens
Returns:
syntheticTokensMinted: Actual synthetic tokens mintedfeePaid: Fee paid for the operation
Process:
- Validates pool state and parameters
- Calculates required collateral and fees
- Transfers collateral from user
- Updates pool accounting
- Mints synthetic tokens to recipient
redeem
function redeem(RedeemParams calldata _params)
external
override
nonReentrant
isNotExpired(_params.expiration)
returns (uint256 collateralRedeemed, uint256 feePaid)
Purpose: Burns synthetic tokens to retrieve collateral.
Parameters (RedeemParams struct):
expiration: Transaction deadlineredeemParams: Specific redemption parametersnumTokens: Synthetic tokens to burncollateralAmount: Expected collateral to receivefeePercentage: Current fee percentagerecipient: Address to receive collateral
Returns:
collateralRedeemed: Actual collateral receivedfeePaid: Fee paid for the operation
exchange
function exchange(ExchangeParams calldata _params)
external
override
nonReentrant
isNotExpired(_params.expiration)
returns (
uint256 destNumTokens,
uint256 feePaid
)
Purpose: Exchanges one synthetic asset for another through the pool.
Parameters (ExchangeParams struct):
expiration: Transaction deadlinedestPool: Destination pool for the target synthetic assetnumTokens: Source synthetic tokens to exchangedestNumTokens: Expected destination tokensfeePercentage: Current fee percentagerecipient: Address to receive destination tokens
Liquidity Provider Operations
addLiquidity
function addLiquidity(LiquidityParams calldata _params)
external
override
nonReentrant
isNotExpired(_params.expiration)
returns (uint256 collateralUsed, uint256 tokensAdded)
Purpose: Adds liquidity to the pool as a liquidity provider.
Parameters (LiquidityParams struct):
expiration: Transaction deadlinecollateralAmount: Collateral to contributenumTokens: Tokens to contribute (if any)feePercentage: Current fee percentage
Access Control: Only whitelisted LPs Returns:
collateralUsed: Actual collateral utilizedtokensAdded: Synthetic tokens added to position
removeLiquidity
function removeLiquidity(LiquidityParams calldata _params)
external
override
nonReentrant
isNotExpired(_params.expiration)
returns (uint256 collateralRemoved, uint256 tokensRemoved)
Purpose: Removes liquidity from the pool.
Parameters: Same structure as addLiquidity
Access Control: Only existing LPs
Returns:
collateralRemoved: Collateral withdrawntokensRemoved: Synthetic tokens withdrawn
Administrative Functions
registerLP
function registerLP(address _liquidityProvider)
external
override
onlyMaintainer
nonReentrant
Purpose: Adds a new liquidity provider to the whitelist.
Parameters:
_liquidityProvider: Address to whitelist as LP
Access Control: Only maintainer
activateLP
function activateLP() external override nonReentrant
Purpose: Allows a registered LP to activate their account.
Requirements: Must be registered but not yet active
Liquidation
liquidate
function liquidate(LiquidateParams calldata _params)
external
override
nonReentrant
isNotExpired(_params.expiration)
returns (uint256 liquidatedCollateral, uint256 liquidatedTokens)
Purpose: Liquidates undercollateralized LP positions.
Parameters (LiquidateParams struct):
liquidityProvider: LP to liquidatecollateralAmount: Maximum collateral to liquidatenumTokens: Tokens provided for liquidationexpiration: Transaction deadline
Returns:
liquidatedCollateral: Collateral obtained from liquidationliquidatedTokens: Tokens used in liquidation
Storage Structure
Pool Configuration
struct PoolData {
IStandardERC20 collateralToken; // Collateral ERC20 token
ISynthereumMultiLpLiquidityPool syntheticToken; // Synthetic token
address finder; // Finder contract
uint8 version; // Pool version
FixedPoint.Unsigned startingCollateralization; // Initial collateral ratio
Fee fee; // Fee structure
}
LP Positions
struct LPPosition {
FixedPoint.Unsigned tokensHeld; // Synthetic tokens held
FixedPoint.Unsigned collateralDeposited; // Collateral deposited
uint64 overCollateralization; // Overcollateralization ratio
}
Fee Structure
struct Fee {
FixedPoint.Unsigned feePercentage; // Base fee percentage
address[] feeRecipients; // Fee recipient addresses
uint32[] feeProportions; // Proportional fee distribution
}
Access Control
Roles
- DEFAULT_ADMIN_ROLE: Protocol administration
- MAINTAINER_ROLE: Operational maintenance
LP Whitelist
- LPs must be registered by maintainer
- LPs must activate their accounts
- Only active LPs can provide liquidity
Modifiers
modifier onlyMaintainer() {
require(hasRole(MAINTAINER_ROLE, msg.sender), 'Sender must be the maintainer');
_;
}
modifier isNotExpired(uint256 expirationTime) {
require(block.timestamp <= expirationTime, 'Transaction expired');
_;
}
Price Integration
Oracle System
- Integrates with PriceFeed contract for real-time pricing
- Supports multiple oracle implementations
- Price validation and staleness checks
Collateralization Ratios
- Over-collateralization: LPs must maintain ratios above minimum
- Global Collateralization: Pool-wide collateral backing
- Liquidation Threshold: Automatic liquidation triggers
Lending Integration
Yield Generation
- Idle collateral deployed to lending protocols
- Interest accrual tracked per operation
- Automatic compounding of earned interest
Supported Protocols
- Compound Protocol integration
- Extensible to other lending protocols
- Modular lending module architecture
Events
Core Operations
Mint(address indexed user, uint256 collateralUsed, uint256 numTokens, uint256 feePaid)Redeem(address indexed user, uint256 collateralRedeemed, uint256 numTokens, uint256 feePaid)Exchange(address indexed user, address indexed destPool, uint256 numTokens, uint256 destNumTokens, uint256 feePaid)
LP Management
AddLiquidity(address indexed liquidityProvider, uint256 collateralAdded, uint256 tokensAdded)RemoveLiquidity(address indexed liquidityProvider, uint256 collateralRemoved, uint256 tokensRemoved)RegisteredLp(address indexed liquidityProvider)ActivatedLP(address indexed liquidityProvider)
Liquidations
Liquidation(address indexed liquidator, address indexed liquidityProvider, uint256 collateralLiquidated, uint256 tokensLiquidated)
Usage Examples
Minting Synthetic EUR
// User wants to mint 1000 cEUR with USDC collateral
MintParams memory params = MintParams({
expiration: block.timestamp + 3600, // 1 hour expiration
mintParams: /* specific mint parameters */,
collateralAmount: 1100e6, // 1100 USDC (10% buffer)
numTokens: 1000e18, // 1000 cEUR expected
feePercentage: FixedPoint.Unsigned(2e15), // 0.2% fee
recipient: msg.sender
});
(uint256 minted, uint256 fee) = pool.mint(params);
LP Adding Liquidity
// LP adds 10,000 USDC liquidity
LiquidityParams memory params = LiquidityParams({
expiration: block.timestamp + 3600,
collateralAmount: 10000e6, // 10,000 USDC
numTokens: 0, // No synthetic tokens
feePercentage: FixedPoint.Unsigned(2e15)
});
(uint256 collateralUsed, uint256 tokensAdded) = pool.addLiquidity(params);
Redeeming Synthetic Tokens
// User burns 500 cEUR to get USDC back
RedeemParams memory params = RedeemParams({
expiration: block.timestamp + 3600,
redeemParams: /* specific redeem parameters */,
numTokens: 500e18, // 500 cEUR to burn
collateralAmount: 550e6, // Expected ~550 USDC
feePercentage: FixedPoint.Unsigned(2e15),
recipient: msg.sender
});
(uint256 collateralReceived, uint256 fee) = pool.redeem(params);
Security Features
Reentrancy Protection
All external functions use nonReentrant modifier.
Expiration Checks
All user operations include expiration timestamps to prevent stale transactions.
Collateralization Monitoring
- Real-time collateral ratio calculations
- Automatic liquidation triggers
- Overcollateralization requirements
Access Controls
- Role-based permissions
- LP whitelist management
- Administrative function restrictions
Risk Management
Liquidation System
- LPs below collateralization threshold can be liquidated
- Liquidators receive collateral at discount
- Protects pool solvency
Fee Structure
- Dynamic fee calculation
- Multiple fee recipients
- Proportional fee distribution
Emergency Features
- Emergency shutdown capability
- Pause mechanisms for operations
- Administrative override functions
The MultiLpLiquidityPool contract is the heart of Citadel Finance, enabling sophisticated synthetic asset creation with robust risk management and capital efficiency.