# DODO PMM Integration Documentation **Date**: 2025-01-12 **Status**: Implementation Guide **Purpose**: Integration with DODO Proactive Market Maker (PMM) for liquidity pools --- ## Overview DODO PMM Integration enables liquidity pools between CompliantUSDT (cUSDT)/CompliantUSDC (cUSDC) and official USDT/USDC tokens. This provides: - **Exchangeability**: Users can swap between compliant and official tokens - **Price Stability**: PMM algorithm maintains 1:1 peg - **Liquidity**: Efficient capital utilization - **Arbitrage Opportunities**: Market-driven peg maintenance --- ## Architecture ### Contract: DODOPMMIntegration **Location**: `contracts/dex/DODOPMMIntegration.sol` **Purpose**: - Create and manage DODO PMM pools - Facilitate swaps between compliant and official tokens - Manage liquidity provision **Key Features**: - Pool creation (cUSDT/USDT, cUSDC/USDC, cUSDT/cUSDC, and generic pairs) - Liquidity management - Swap execution - Price discovery via PMM algorithm ### Public Pool Pairs (VAULT_SYSTEM_MASTER_TECHNICAL_PLAN §4) The Master Plan specifies four **public** liquidity pool types for user routing and price discovery (not primary stabilization): | Pair | Creation method | Notes | |------|-----------------|--------| | **cUSDT / cUSDC** | `createCUSDTCUSDCPool(lpFeeRate, initialPrice, k, isOpenTWAP)` | Dedicated function; swap via `swapCUSDTForUSDC` / `swapUSDCForCUSDT`. Register in DODOPMMProvider for getQuote/executeSwap. | | **cUSDT / XAU** | `createPool(cUSDT, xauTokenAddress, ...)` | Use the Chain 138 XAU anchor token address (`cXAUC` or `cXAUT`) and the generic `createPool`. | | **cUSDC / XAU** | `createPool(cUSDC, xauTokenAddress, ...)` | Same as above. | | **cEURT / XAU** | `createPool(cEURTAddress, xauTokenAddress, ...)` | Requires `cEURT` and a Chain 138 XAU anchor token (`cXAUC` or `cXAUT`). | For cUSDT/XAU, cUSDC/XAU, and cEURT/XAU: use the deployed Chain 138 XAU anchor token (`cXAUC` at `0x290E52a8819A4fbD0714E517225429aA2B70EC6b` or `cXAUT` at `0x94e408E26c6FD8F4ee00b54dF19082FDA07dC96E`), then call `createPool(baseToken, quoteToken, lpFeeRate, initialPrice, k, isOpenTWAP)` with `POOL_MANAGER_ROLE`. **Unit:** 1 full XAU token = **1 troy ounce** of gold (`10^6` base units with 6 decimals). Public pools serve user routing, price discovery, and flash loan access; they do not serve as the primary stabilization engine (see Master Plan private mesh). --- ## DODO PMM Overview ### Proactive Market Maker (PMM) DODO's PMM algorithm: - Uses external price oracles (TWAP) - Maintains price stability through automated market making - More capital efficient than traditional AMMs - Lower slippage for stablecoin pairs ### Pool Types **DODO Vending Machine (DVM)**: - Most common for custom pairs - Supports single-sided liquidity provision - Better for stablecoin pairs **Key Parameters**: - `i`: Initial price (1e18 = $1 for stablecoins) - `k`: Slippage factor (lower = less slippage, 0.5e18 recommended) - `lpFeeRate`: LP fee in basis points (3 = 0.03%) - `isOpenTWAP`: Enable time-weighted average price oracle --- ## Deployment ### Prerequisites 1. **DODO Contracts** (check DODO docs for chain-specific addresses): - DODO Vending Machine Factory - DODO Approve (optional, for gas optimization) 2. **Token Addresses**: - Official USDT/USDC (on target chain) - Compliant cUSDT/cUSDC (on Chain 138) 3. **Network**: Deploy on chain where official tokens exist ### Deployment Steps #### Step 1: Set Environment Variables ```bash # In .env file PRIVATE_KEY=0x... RPC_URL=https://... # DODO contracts (example for Ethereum Mainnet - check DODO docs) DODO_VENDING_MACHINE_ADDRESS=0x... # DODO Vending Machine Factory DODO_APPROVE_ADDRESS=0x... # Optional # Official tokens on Chain 138 (local quote-side mirror stables) OFFICIAL_USDT_ADDRESS=0x004b63A7B5b0E06f6bB6adb4a5F9f590BF3182D1 OFFICIAL_USDC_ADDRESS=0x71D6687F38b93CCad569Fa6352c876eea967201b # Compliant tokens COMPLIANT_USDT_ADDRESS=0x93E66202A11B1772E55407B32B44e5Cd8eda7f22 COMPLIANT_USDC_ADDRESS=0xf22258f57794CC8E06237084b353Ab30fFfa640b # Admin DODO_INTEGRATION_ADMIN=0x... ``` #### Step 2: Deploy Contract ```bash cd smom-dbis-138 forge script script/dex/DeployDODOPMMIntegration.s.sol:DeployDODOPMMIntegration \ --rpc-url $RPC_URL \ --broadcast \ --legacy \ --gas-price 30000000000 \ --via-ir \ -vv # Save deployed address export DODO_PMM_INTEGRATION_ADDRESS= ``` --- ## Pool Creation ### Create cUSDT/USDT Pool ```bash # Pool parameters LP_FEE_RATE=3 # 0.03% = 3 basis points INITIAL_PRICE=1000000000000000000 # 1e18 = $1 K_FACTOR=500000000000000000 # 0.5e18 = 50% slippage factor ENABLE_TWAP=true # Enable TWAP oracle cast send $DODO_PMM_INTEGRATION_ADDRESS \ "createCUSDTUSDTPool(uint256,uint256,uint256,bool)" \ $LP_FEE_RATE \ $INITIAL_PRICE \ $K_FACTOR \ $ENABLE_TWAP \ --rpc-url $RPC_URL \ --private-key $PRIVATE_KEY \ --gas-price 30000000000 \ --legacy \ -vv # Get pool address POOL_ADDRESS=$(cast call $DODO_PMM_INTEGRATION_ADDRESS \ "pools(address,address)" \ $COMPLIANT_USDT_ADDRESS \ $OFFICIAL_USDT_ADDRESS \ --rpc-url $RPC_URL | cast --to-addr) ``` ### Create cUSDC/USDC Pool ```bash cast send $DODO_PMM_INTEGRATION_ADDRESS \ "createCUSDCUSDCPool(uint256,uint256,uint256,bool)" \ $LP_FEE_RATE \ $INITIAL_PRICE \ $K_FACTOR \ $ENABLE_TWAP \ --rpc-url $RPC_URL \ --private-key $PRIVATE_KEY \ --gas-price 30000000000 \ --legacy \ -vv ``` --- ## Liquidity Provision ### Add Liquidity to Pool ```bash # Parameters POOL_ADDRESS=0x... # Pool address from creation BASE_AMOUNT=1000000000000 # Amount of base token (cUSDT/cUSDC) QUOTE_AMOUNT=1000000000000 # Amount of quote token (USDT/USDC) # 1. Approve tokens to integration contract cast send $COMPLIANT_USDT_ADDRESS \ "approve(address,uint256)" \ $DODO_PMM_INTEGRATION_ADDRESS \ $BASE_AMOUNT \ --rpc-url $RPC_URL \ --private-key $PRIVATE_KEY \ --gas-price 30000000000 \ --legacy cast send $OFFICIAL_USDT_ADDRESS \ "approve(address,uint256)" \ $DODO_PMM_INTEGRATION_ADDRESS \ $QUOTE_AMOUNT \ --rpc-url $RPC_URL \ --private-key $PRIVATE_KEY \ --gas-price 30000000000 \ --legacy # 2. Add liquidity cast send $DODO_PMM_INTEGRATION_ADDRESS \ "addLiquidity(address,uint256,uint256)" \ $POOL_ADDRESS \ $BASE_AMOUNT \ $QUOTE_AMOUNT \ --rpc-url $RPC_URL \ --private-key $PRIVATE_KEY \ --gas-price 30000000000 \ --legacy \ -vv ``` --- ## Swapping ### Swap cUSDT → USDT ```bash AMOUNT_IN=1000000000000 # 1,000,000 cUSDT (6 decimals) MIN_AMOUNT_OUT=999000000000 # Minimum USDT to receive (slippage protection) # 1. Approve cUSDT cast send $COMPLIANT_USDT_ADDRESS \ "approve(address,uint256)" \ $DODO_PMM_INTEGRATION_ADDRESS \ $AMOUNT_IN \ --rpc-url $RPC_URL \ --private-key $PRIVATE_KEY \ --gas-price 30000000000 \ --legacy # 2. Execute swap cast send $DODO_PMM_INTEGRATION_ADDRESS \ "swapCUSDTForUSDT(address,uint256,uint256)" \ $POOL_ADDRESS \ $AMOUNT_IN \ $MIN_AMOUNT_OUT \ --rpc-url $RPC_URL \ --private-key $PRIVATE_KEY \ --gas-price 30000000000 \ --legacy \ -vv ``` ### Swap USDT → cUSDT ```bash # Similar process, using swapUSDTForCUSDT() cast send $DODO_PMM_INTEGRATION_ADDRESS \ "swapUSDTForCUSDT(address,uint256,uint256)" \ $POOL_ADDRESS \ $AMOUNT_IN \ $MIN_AMOUNT_OUT \ --rpc-url $RPC_URL \ --private-key $PRIVATE_KEY \ --gas-price 30000000000 \ --legacy \ -vv ``` --- ## Oracle and Reporting ### Optional ReserveSystem (oracle-backed mid price) PMM pool price can be driven by the **ReserveSystem** when base/quote tokens are registered there. This gives reporting and off-chain services an oracle-backed price when available. 1. **Set ReserveSystem** (admin only): ```bash cast send $DODO_PMM_INTEGRATION_ADDRESS \ "setReserveSystem(address)" \ $RESERVE_SYSTEM_ADDRESS \ --rpc-url $RPC_URL --private-key $PRIVATE_KEY ``` Use `address(0)` to disable and fall back to pool `getMidPrice()` only. 2. **getPoolPriceOrOracle(pool)** returns: oracle price (via `reserveSystem.getConversionPrice(baseToken, quoteToken)`) if ReserveSystem is set and returns a valid price; otherwise pool `getMidPrice()`. 3. **DODOPMMProvider** uses `getPoolPriceOrOracle` for quotes, so liquidity provider quotes prefer the oracle when configured. ### Reporting API and pool indexer The **token-aggregation** service indexes PMM pools for `/report/all`, `/report/coingecko`, and `/report/cross-chain` when **CHAIN_138_DODO_PMM_INTEGRATION** is set. - Set in token-aggregation `.env`: `CHAIN_138_DODO_PMM_INTEGRATION=`. - The pool indexer calls `getAllPools()`, then for each pool `getPoolConfig`, `getPoolReserves`, and `getPoolPriceOrOracle` to compute TVL and persist pools to the DB. - Ensure the indexer runs for Chain 138 (cron or on-demand) so report endpoints include PMM pools. See also: [PRICE_FEED_SETUP.md](PRICE_FEED_SETUP.md) for ReserveSystem/OraclePriceFeed setup; [ORACLE_AND_KEEPER_CHAIN138.md](ORACLE_AND_KEEPER_CHAIN138.md) for ORACLE_AGGREGATOR/ORACLE_PROXY and keeper flows on Chain 138. ### PMM price for vault / reporting **PMMPriceProvider** (`contracts/vault/adapters/PMMPriceProvider.sol`) exposes `getPrice(asset, quoteToken)` using DODOPMMIntegration’s `getPoolPriceOrOracle`. Use it for vault collateral valuation (e.g. cUSDT/cUSDC in USD terms) or off-chain reporting when the asset is a PMM pair token. Deploy with the DODOPMMIntegration address; see [Vault IMPLEMENTATION_SUMMARY](../vault/IMPLEMENTATION_SUMMARY.md#gru-smart-vault-and-pmm-integration). --- ## Query Functions ### Get Pool Price (oracle if configured) ```bash # Prefer oracle when ReserveSystem is set cast call $DODO_PMM_INTEGRATION_ADDRESS \ "getPoolPriceOrOracle(address)" \ $POOL_ADDRESS \ --rpc-url $RPC_URL # Pool mid only (no oracle) cast call $DODO_PMM_INTEGRATION_ADDRESS \ "getPoolPrice(address)" \ $POOL_ADDRESS \ --rpc-url $RPC_URL # Returns: price in 1e18 format (1000000000000000000 = $1) ``` ### Get Pool Reserves ```bash cast call $DODO_PMM_INTEGRATION_ADDRESS \ "getPoolReserves(address)" \ $POOL_ADDRESS \ --rpc-url $RPC_URL # Returns: (baseReserve, quoteReserve) ``` ### Get Pool Configuration ```bash cast call $DODO_PMM_INTEGRATION_ADDRESS \ "getPoolConfig(address)" \ $POOL_ADDRESS \ --rpc-url $RPC_URL # Returns: PoolConfig struct with all parameters ``` ### Get All Pools ```bash cast call $DODO_PMM_INTEGRATION_ADDRESS \ "getAllPools()" \ --rpc-url $RPC_URL # Returns: Array of all pool addresses ``` --- ## Pool Parameters Guide ### Initial Price (`i`) - **Value**: `1000000000000000000` (1e18) - **Meaning**: $1 for stablecoin pairs - **Adjustment**: Can set different initial price if needed ### K Factor (`k`) - **Range**: 0 to 1e18 - **Recommended**: `500000000000000000` (0.5e18 = 50%) - **Lower k**: Less slippage, more capital intensive - **Higher k**: More slippage, less capital intensive - **For stablecoins**: Lower k (0.3-0.5) recommended ### LP Fee Rate - **Unit**: Basis points (100 = 1%) - **Recommended**: 3-10 basis points (0.03% - 0.1%) - **Lower fee**: More attractive for traders - **Higher fee**: More revenue for LPs ### TWAP Oracle - **Purpose**: Price discovery and stability - **Recommended**: Enable for stablecoin pairs - **Benefit**: Reduces price manipulation --- ## Integration Workflow ### Phase 1: Setup 1. Deploy DODOPMMIntegration contract 2. Create pools (cUSDT/USDT, cUSDC/USDC) 3. Configure pool parameters ### Phase 2: Seed Liquidity 1. Approve tokens to integration contract 2. Add initial liquidity to pools 3. Monitor pool reserves and prices ### Phase 3: Enable Trading 1. Open pools for public trading 2. Monitor swap volumes 3. Adjust parameters if needed ### Phase 4: Maintenance 1. Monitor pool health 2. Add/remove liquidity as needed 3. Update parameters for optimization --- ## Best Practices 1. **Liquidity Depth**: Maintain sufficient liquidity for expected volume 2. **Price Monitoring**: Monitor pool prices vs. 1:1 peg 3. **Arbitrage**: Allow arbitrageurs to maintain peg 4. **Slippage Protection**: Use appropriate slippage tolerances 5. **Gas Optimization**: Use DODO Approve for batch operations 6. **Security**: Audit contracts before mainnet deployment --- ## Troubleshooting ### Pool Creation Fails - Check DODO Vending Machine address is correct - Verify token addresses are valid - Ensure sufficient gas ### Swaps Failing - Check pool has sufficient liquidity - Verify slippage tolerance is appropriate - Check token approvals ### Price Deviation - Check pool reserves are balanced - Monitor for large trades - Consider adding/removing liquidity --- ## Example Setup Script See `scripts/setup-dodo-pools.sh` for automated pool creation and configuration. --- ## Next Steps 1. Deploy integration contract 2. Create pools with optimal parameters 3. Seed initial liquidity 4. Enable trading 5. Monitor and optimize