Skip to main content

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 deadline
  • mintParams: Specific minting parameters
  • collateralAmount: Amount of collateral to deposit
  • numTokens: Expected synthetic tokens to receive
  • feePercentage: Current fee percentage
  • recipient: Address to receive synthetic tokens

Returns:

  • syntheticTokensMinted: Actual synthetic tokens minted
  • feePaid: Fee paid for the operation

Process:

  1. Validates pool state and parameters
  2. Calculates required collateral and fees
  3. Transfers collateral from user
  4. Updates pool accounting
  5. 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 deadline
  • redeemParams: Specific redemption parameters
  • numTokens: Synthetic tokens to burn
  • collateralAmount: Expected collateral to receive
  • feePercentage: Current fee percentage
  • recipient: Address to receive collateral

Returns:

  • collateralRedeemed: Actual collateral received
  • feePaid: 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 deadline
  • destPool: Destination pool for the target synthetic asset
  • numTokens: Source synthetic tokens to exchange
  • destNumTokens: Expected destination tokens
  • feePercentage: Current fee percentage
  • recipient: 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 deadline
  • collateralAmount: Collateral to contribute
  • numTokens: Tokens to contribute (if any)
  • feePercentage: Current fee percentage

Access Control: Only whitelisted LPs Returns:

  • collateralUsed: Actual collateral utilized
  • tokensAdded: 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 withdrawn
  • tokensRemoved: 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 liquidate
  • collateralAmount: Maximum collateral to liquidate
  • numTokens: Tokens provided for liquidation
  • expiration: Transaction deadline

Returns:

  • liquidatedCollateral: Collateral obtained from liquidation
  • liquidatedTokens: 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.