Made-with: Cursor
15 KiB
Chain 138 PMM Redeploy and Pool Funding Runbook
Purpose: Execute the live on-chain PMM remediation and funding sequence on Chain 138 in the correct order:
- deploy live Chain 138 quote-side
USDTandUSDCERC-20 mirror tokens - redeploy
DODOPMMIntegrationwith those live Chain 138 official stable addresses - recreate the usable public stable pools on the new integration
- create public XAU pools using
cXAUCorcXAUTas the Chain 138 XAU anchor - deploy the
PrivatePoolRegistryand register the XAU private stabilization pools - fund the pools in the correct order
Primary chain: Chain 138
Operator requirement: deployer EOA with PRIVATE_KEY, gas, and the required token balances / mint authority.
0. Preconditions
0.1 Required environment
From smom-dbis-138/.env:
PRIVATE_KEY=0x...
RPC_URL_138=http://...
DODO_VENDING_MACHINE_ADDRESS=0x...
COMPLIANT_USDT_ADDRESS=0x93E66202A11B1772E55407B32B44e5Cd8eda7f22
COMPLIANT_USDC_ADDRESS=0xf22258f57794CC8E06237084b353Ab30fFfa640b
OFFICIAL_USDT_ADDRESS=0x...
OFFICIAL_USDC_ADDRESS=0x...
0.2 XAU anchor selection
Choose one Chain 138 XAU anchor for the PMM and private stabilization pools:
# Preferred default
XAU_ADDRESS_138=0x290E52a8819A4fbD0714E517225429aA2B70EC6b # cXAUC
# Optional alternate
CXAUT_ADDRESS_138=0x94e408E26c6FD8F4ee00b54dF19082FDA07dC96E # cXAUT
If XAU_ADDRESS_138 is unset, the scripts default to cXAUC on Chain 138.
0.3 Stop conditions
Stop immediately if any of these checks fail:
cd /home/intlc/projects/proxmox/smom-dbis-138
source .env
cast wallet address "$PRIVATE_KEY"
cast code "$DODO_VENDING_MACHINE_ADDRESS" --rpc-url "$RPC_URL_138"
cast code "$COMPLIANT_USDT_ADDRESS" --rpc-url "$RPC_URL_138"
cast code "$COMPLIANT_USDC_ADDRESS" --rpc-url "$RPC_URL_138"
cast code "$OFFICIAL_USDT_ADDRESS" --rpc-url "$RPC_URL_138"
cast code "$OFFICIAL_USDC_ADDRESS" --rpc-url "$RPC_URL_138"
cast code "${XAU_ADDRESS_138:-0x290E52a8819A4fbD0714E517225429aA2B70EC6b}" --rpc-url "$RPC_URL_138"
Expected result: each cast code returns non-empty bytecode.
0.4 Important blocker note
Do not use the historical placeholder addresses 0x15DF... or 0xA0b8... on Chain 138 unless cast code proves they are live ERC-20 contracts on Chain 138.
The local PMM integration requires live quote-side ERC-20s on Chain 138. If OFFICIAL_USDT_ADDRESS and OFFICIAL_USDC_ADDRESS have no bytecode, deploy the local mirror tokens first.
1. Snapshot the current state
Record the current integration and pool state before redeploying:
cd /home/intlc/projects/proxmox/smom-dbis-138
source .env
echo "Current integration: ${DODO_PMM_INTEGRATION_ADDRESS:-${DODO_PMM_INTEGRATION:-unset}}"
echo "Current cUSDT/cUSDC pool: ${POOL_CUSDTCUSDC:-unset}"
echo "Current cUSDT/USDT pool: ${POOL_CUSDTUSDT:-unset}"
echo "Current cUSDC/USDC pool: ${POOL_CUSDCUSDC:-unset}"
If the current integration exists, record its immutable token addresses:
INT="${DODO_PMM_INTEGRATION_ADDRESS:-${DODO_PMM_INTEGRATION:-}}"
[ -n "$INT" ] && cast call "$INT" "officialUSDT()(address)" --rpc-url "$RPC_URL_138"
[ -n "$INT" ] && cast call "$INT" "officialUSDC()(address)" --rpc-url "$RPC_URL_138"
1. Deploy the Chain 138 official stable mirrors
Deploy the local quote-side assets first. These are lightweight ERC-20 mirrors used only to unblock local PMM pools on Chain 138.
cd /home/intlc/projects/proxmox/smom-dbis-138
source .env
forge script script/DeployOfficialUSDT138.s.sol:DeployOfficialUSDT138 \
--rpc-url "$RPC_URL_138" \
--broadcast \
--private-key "$PRIVATE_KEY" \
--with-gas-price "${GAS_PRICE_138:-1000000000}" \
--legacy \
-vv
forge script script/DeployOfficialUSDC138.s.sol:DeployOfficialUSDC138 \
--rpc-url "$RPC_URL_138" \
--broadcast \
--private-key "$PRIVATE_KEY" \
--with-gas-price "${GAS_PRICE_138:-1000000000}" \
--legacy \
-vv
Persist the deployed addresses into .env:
OFFICIAL_USDT_ADDRESS=0x...
OFFICIAL_USDC_ADDRESS=0x...
Verify both:
cast code "$OFFICIAL_USDT_ADDRESS" --rpc-url "$RPC_URL_138"
cast code "$OFFICIAL_USDC_ADDRESS" --rpc-url "$RPC_URL_138"
cast call "$OFFICIAL_USDT_ADDRESS" "symbol()(string)" --rpc-url "$RPC_URL_138"
cast call "$OFFICIAL_USDC_ADDRESS" "symbol()(string)" --rpc-url "$RPC_URL_138"
Expected result:
- both return non-empty bytecode
- symbols return
USDTandUSDC
2. Redeploy PMM integration on Chain 138
This step creates a fresh DODOPMMIntegration using the corrected Chain 138 official stable addresses.
cd /home/intlc/projects/proxmox/smom-dbis-138
source .env
forge script script/dex/DeployDODOPMMIntegration.s.sol:DeployDODOPMMIntegration \
--rpc-url "$RPC_URL_138" \
--broadcast \
--private-key "$PRIVATE_KEY" \
--with-gas-price "${GAS_PRICE_138:-1000000000}" \
--legacy \
-vv
After deployment, update .env with the new integration address:
DODO_PMM_INTEGRATION_ADDRESS=0x...
DODO_PMM_INTEGRATION=0x...
Verify the new immutables:
INT="${DODO_PMM_INTEGRATION_ADDRESS:-${DODO_PMM_INTEGRATION:-}}"
cast call "$INT" "officialUSDT()(address)" --rpc-url "$RPC_URL_138"
cast call "$INT" "officialUSDC()(address)" --rpc-url "$RPC_URL_138"
cast call "$INT" "compliantUSDT()(address)" --rpc-url "$RPC_URL_138"
cast call "$INT" "compliantUSDC()(address)" --rpc-url "$RPC_URL_138"
Expected result:
officialUSDT= the liveOFFICIAL_USDT_ADDRESSyou just deployed or verifiedofficialUSDC= the liveOFFICIAL_USDC_ADDRESSyou just deployed or verified
3. Create the corrected public stable pools
Create the three public PMM pools on the new integration:
cd /home/intlc/projects/proxmox/smom-dbis-138
source .env
forge script script/dex/CreateCUSDTCUSDCPool.s.sol:CreateCUSDTCUSDCPool \
--rpc-url "$RPC_URL_138" --broadcast --private-key "$PRIVATE_KEY" --with-gas-price "${GAS_PRICE_138:-1000000000}" -vv
forge script script/dex/CreateCUSDTUSDTPool.s.sol:CreateCUSDTUSDTPool \
--rpc-url "$RPC_URL_138" --broadcast --private-key "$PRIVATE_KEY" --with-gas-price "${GAS_PRICE_138:-1000000000}" -vv
forge script script/dex/CreateCUSDCUSDCPool.s.sol:CreateCUSDCUSDCPool \
--rpc-url "$RPC_URL_138" --broadcast --private-key "$PRIVATE_KEY" --with-gas-price "${GAS_PRICE_138:-1000000000}" -vv
Record the new pool addresses:
INT="${DODO_PMM_INTEGRATION_ADDRESS:-${DODO_PMM_INTEGRATION:-}}"
POOL_CUSDTCUSDC=$(cast call "$INT" "pools(address,address)(address)" \
"$COMPLIANT_USDT_ADDRESS" "$COMPLIANT_USDC_ADDRESS" --rpc-url "$RPC_URL_138" | cast --to-addr)
POOL_CUSDTUSDT=$(cast call "$INT" "pools(address,address)(address)" \
"$COMPLIANT_USDT_ADDRESS" "$OFFICIAL_USDT_ADDRESS" --rpc-url "$RPC_URL_138" | cast --to-addr)
POOL_CUSDCUSDC=$(cast call "$INT" "pools(address,address)(address)" \
"$COMPLIANT_USDC_ADDRESS" "$OFFICIAL_USDC_ADDRESS" --rpc-url "$RPC_URL_138" | cast --to-addr)
echo "$POOL_CUSDTCUSDC"
echo "$POOL_CUSDTUSDT"
echo "$POOL_CUSDCUSDC"
Persist them into .env.
4. Create the public XAU pools
Use the new public XAU script so the XAU side is explicit as cXAUC or cXAUT.
cd /home/intlc/projects/proxmox/smom-dbis-138
source .env
forge script script/dex/CreatePublicXAUPoolsChain138.s.sol:CreatePublicXAUPoolsChain138 \
--rpc-url "$RPC_URL_138" \
--broadcast \
--private-key "$PRIVATE_KEY" \
--with-gas-price "${GAS_PRICE_138:-1000000000}" \
--legacy \
-vv
Optional controls:
CREATE_CUSDT_XAU=true
CREATE_CUSDC_XAU=true
CREATE_CEURT_XAU=true
Verify the created public XAU pools:
INT="${DODO_PMM_INTEGRATION_ADDRESS:-${DODO_PMM_INTEGRATION:-}}"
XAU="${XAU_ADDRESS_138:-0x290E52a8819A4fbD0714E517225429aA2B70EC6b}"
cast call "$INT" "pools(address,address)(address)" "$COMPLIANT_USDT_ADDRESS" "$XAU" --rpc-url "$RPC_URL_138"
cast call "$INT" "pools(address,address)(address)" "$COMPLIANT_USDC_ADDRESS" "$XAU" --rpc-url "$RPC_URL_138"
cast call "$INT" "pools(address,address)(address)" "0xdf4b71c61E5912712C1Bdd451416B9aC26949d72" "$XAU" --rpc-url "$RPC_URL_138"
Persist the returned pool addresses if they are non-zero.
5. Deploy PrivatePoolRegistry and register private XAU pools
cd /home/intlc/projects/proxmox/smom-dbis-138
source .env
forge script script/dex/DeployPrivatePoolRegistryAndPools.s.sol:DeployPrivatePoolRegistryAndPools \
--rpc-url "$RPC_URL_138" \
--broadcast \
--private-key "$PRIVATE_KEY" \
--with-gas-price "${GAS_PRICE_138:-1000000000}" \
--legacy \
-vv
Record:
PRIVATE_POOL_REGISTRY=0x...
Verify registrations:
REG="$PRIVATE_POOL_REGISTRY"
XAU="${XAU_ADDRESS_138:-0x290E52a8819A4fbD0714E517225429aA2B70EC6b}"
cast call "$REG" "getPool(address,address)(address)" "$COMPLIANT_USDT_ADDRESS" "$XAU" --rpc-url "$RPC_URL_138"
cast call "$REG" "getPool(address,address)(address)" "$COMPLIANT_USDC_ADDRESS" "$XAU" --rpc-url "$RPC_URL_138"
cast call "$REG" "getPool(address,address)(address)" "0xdf4b71c61E5912712C1Bdd451416B9aC26949d72" "$XAU" --rpc-url "$RPC_URL_138"
6. Fund the pools in the correct order
6.1 Funding order
Fund in this order:
cUSDT / cUSDCcUSDT / USDTcUSDC / USDC- public XAU pools:
cUSDT / XAUcUSDC / XAUcEURT / XAU
- private stabilization pools last
Reason:
cUSDT/cUSDCestablishes the base compliant market first- official stable pools come next after the corrected addresses are live
- XAU public pools should discover price before private stabilization paths are seeded
6.2 Mint compliant balances
Mint the compliant side first:
cd /home/intlc/projects/proxmox/smom-dbis-138
source .env
MINT_CUSDT_AMOUNT=2000000 \
MINT_CUSDC_AMOUNT=2000000 \
./scripts/mint-for-liquidity.sh
Mint additional compliant assets as needed:
DEPLOYER=$(cast wallet address "$PRIVATE_KEY")
cast send 0xdf4b71c61E5912712C1Bdd451416B9aC26949d72 \
"mint(address,uint256)" "$DEPLOYER" 1000000000000 \
--rpc-url "$RPC_URL_138" --private-key "$PRIVATE_KEY"
6.3 Acquire / verify non-mintable sides
Before adding liquidity, confirm balances of:
OFFICIAL_USDT_ADDRESSOFFICIAL_USDC_ADDRESSXAU_ADDRESS_138(cXAUCorcXAUT)
DEPLOYER=$(cast wallet address "$PRIVATE_KEY")
cast call "$OFFICIAL_USDT_ADDRESS" "balanceOf(address)(uint256)" "$DEPLOYER" --rpc-url "$RPC_URL_138"
cast call "$OFFICIAL_USDC_ADDRESS" "balanceOf(address)(uint256)" "$DEPLOYER" --rpc-url "$RPC_URL_138"
cast call "${XAU_ADDRESS_138:-0x290E52a8819A4fbD0714E517225429aA2B70EC6b}" "balanceOf(address)(uint256)" "$DEPLOYER" --rpc-url "$RPC_URL_138"
Do not proceed on a pool until both sides have sufficient balance.
6.4 Fund cUSDT / cUSDC
Use the existing add-liquidity script first:
export ADD_LIQUIDITY_CUSDTCUSDC_BASE=1000000000000
export ADD_LIQUIDITY_CUSDTCUSDC_QUOTE=1000000000000
forge script script/dex/AddLiquidityPMMPoolsChain138.s.sol:AddLiquidityPMMPoolsChain138 \
--rpc-url "$RPC_URL_138" \
--broadcast \
--private-key "$PRIVATE_KEY" \
--with-gas-price "${GAS_PRICE_138:-1000000000}" \
-vv
6.5 Fund cUSDT / USDT and cUSDC / USDC
Set per-pool liquidity amounts:
export ADD_LIQUIDITY_CUSDTUSDT_BASE=1000000000000
export ADD_LIQUIDITY_CUSDTUSDT_QUOTE=1000000000000
export ADD_LIQUIDITY_CUSDCUSDC_BASE=1000000000000
export ADD_LIQUIDITY_CUSDCUSDC_QUOTE=1000000000000
Then run the same liquidity script:
forge script script/dex/AddLiquidityPMMPoolsChain138.s.sol:AddLiquidityPMMPoolsChain138 \
--rpc-url "$RPC_URL_138" \
--broadcast \
--private-key "$PRIVATE_KEY" \
--with-gas-price "${GAS_PRICE_138:-1000000000}" \
-vv
6.6 Fund public XAU pools
For each public XAU pool:
- approve both tokens to the integration
- call
addLiquidity(pool, baseAmount, quoteAmount)
Example for cUSDT / XAU:
INT="${DODO_PMM_INTEGRATION_ADDRESS:-${DODO_PMM_INTEGRATION:-}}"
XAU="${XAU_ADDRESS_138:-0x290E52a8819A4fbD0714E517225429aA2B70EC6b}"
POOL=$(cast call "$INT" "pools(address,address)(address)" "$COMPLIANT_USDT_ADDRESS" "$XAU" --rpc-url "$RPC_URL_138" | cast --to-addr)
cast send "$COMPLIANT_USDT_ADDRESS" "approve(address,uint256)" "$INT" 1000000000000 --rpc-url "$RPC_URL_138" --private-key "$PRIVATE_KEY"
cast send "$XAU" "approve(address,uint256)" "$INT" 1000000000000 --rpc-url "$RPC_URL_138" --private-key "$PRIVATE_KEY"
cast send "$INT" "addLiquidity(address,uint256,uint256)" "$POOL" 1000000000000 1000000000000 --rpc-url "$RPC_URL_138" --private-key "$PRIVATE_KEY"
Repeat for:
cUSDC / XAUcEURT / XAU
6.7 Seed private stabilization pools last
Only after the public pools have been created and seeded:
- verify private registry entries exist
- approve both sides
- fund the corresponding private pool addresses with smaller initial depth than the public pools
Use the same addLiquidity(address,uint256,uint256) pattern against the registered pool addresses.
7. Post-funding verification
7.1 Pool reserves
cast call "$POOL_CUSDTCUSDC" "getVaultReserve()(uint256,uint256)" --rpc-url "$RPC_URL_138"
cast call "$POOL_CUSDTUSDT" "getVaultReserve()(uint256,uint256)" --rpc-url "$RPC_URL_138"
cast call "$POOL_CUSDCUSDC" "getVaultReserve()(uint256,uint256)" --rpc-url "$RPC_URL_138"
Repeat for each XAU pool address.
7.2 Explorer alignment
After successful execution, update:
Also update the explorer pool inventory if new pool addresses were created.
8. Rollback / abort guidance
Abort if any of the following occurs:
- official token bytecode missing on 138
- integration deployed with wrong immutables
- pool creation returns zero or reverts unexpectedly
- deployer lacks balance for either side of a target pool
If the new integration is deployed but pool creation fails, stop there and do not fund the old incorrect pools.