- Update dbis_core, cross-chain-pmm-lps, explorer-monorepo, metamask-integration, pr-workspace/chains - Omit embedded publish git dirs and empty placeholders from index Made-with: Cursor
29 KiB
Contract Deployment Runbook
Last Updated: 2026-04-03
Full deployment order: For the canonical sequence (prerequisites → core → PMM/pools → provider → optional → cW* → verification) and remaining recommendations, see DEPLOYMENT_ORDER_OF_OPERATIONS.md.
Deployment safety: Use RPC_URL_138 (Core only, from smom-dbis-138/.env) for all deployments; never use Public RPC. All secrets from smom-dbis-138/.env only. Run a gas/cost estimate before deploy (e.g. cd smom-dbis-138 && ./scripts/deployment/calculate-costs-consolidated.sh). Do not deploy when transactions are stuck — clear tx pool (./scripts/clear-all-transaction-pools.sh), wait ~60s, then retry; use scripts that check nonce when available.
Chain 138 deployment requirements (learned 2026-02-12)
- Gas price: Chain 138 enforces a minimum gas price. Always use
--with-gas-price 1000000000(1 gwei) forforge scriptandforge createwhen deploying to Chain 138; otherwise transactions fail with "Gas price below configured minimum gas price". - Gas 32xxx when deploying: If you see gas-related RPC errors (e.g. -32000, execution reverted, or out of gas), add
--gas-estimate-multiplier 150(or 200) toforge script ... --broadcastso the broadcast uses a higher gas limit. See RPC_ERRORS_32001_32602.md. - On-chain check: After deployments, run
./scripts/verify/check-contracts-on-chain-138.sh(usesRPC_URL_138; optional URL arg). Address list comes fromconfig/smart-contracts-master.jsonwhen available. See CONTRACT_ADDRESSES_REFERENCE, ADDRESS_MATRIX_AND_STATUS. - TransactionMirror: The deploy script can hit a Forge broadcast constructor-args decode error. If so, deploy manually:
forge create contracts/mirror/TransactionMirror.sol:TransactionMirror --constructor-args <ADMIN_ADDRESS> --rpc-url $RPC_URL_138 --private-key $PRIVATE_KEY --gas-price 1000000000.
RPC Routing Summary
Chain 138 uses two standard env vars: RPC_URL_138 (Core, admin/deploy) and RPC_URL_138_PUBLIC (Public, bridge/frontend). See RPC_ENDPOINTS_MASTER.
| Use Case | VMID | IP | Ports | Variable |
|---|---|---|---|---|
| Admin / contract deployment | 2101 | 192.168.11.211 | 8545, 8546 | RPC_URL_138 (Core) |
| Bridge, monitoring, public-facing | 2201 | 192.168.11.221 (FIXED) | 8545, 8546 | RPC_URL_138_PUBLIC (Public) |
Prerequisites
-
.env check (keys only, no secrets printed): From repo root:
./scripts/deployment/preflight-chain138-deploy.sh(RPC, dotenv, nonce). Or from smom-dbis-138:./scripts/deployment/check-env-required.sh— verifiesPRIVATE_KEY,RPC_URL,RPC_URL_138and optional PMM/mainnet/CCIP vars. Usesmom-dbis-138/.envonly for deploy secrets. -
Network access to Chain 138 RPC (set
RPC_URL_138in .env, e.g. http://192.168.11.211:8545 for Core)- Run from a host on the same LAN as Proxmox, or via VPN
- WSL/remote dev environments may get "No route to host" if not on network
-
PRIVATE_KEY in
smom-dbis-138/.env(deployer wallet with gas; same wallet holds LINK for bridge fees) -
Foundry (
forge) installed -
Test all contracts before deploy (Phase 0.8): Run
./scripts/deployment/test-all-contracts-before-deploy.shfrom repo root. This runsforge buildandforge testin smom-dbis-138. Use--dry-runto print commands only;--alltrato include alltra-lifi-settlement;--no-match "Fork|Mainnet|Integration|e2e"for unit tests only. See DEPLOYMENT_ORDER_OF_OPERATIONS § Phase 0.8.
Deprecated bridge (R4)
Do not use CCIPWETH9Bridge at 0x89dd.... Use only the canonical bridge at 0x971c... and set CCIPWETH9_BRIDGE_CHAIN138 in env. See docs/00-meta/RECOMMENDATIONS_OPERATOR_CHECKLIST.md R4.
Env required per deploy script
| Script / phase | Required env | Notes |
|---|---|---|
| DeployMulticall, DeployOracle, DeployMultiSig | PRIVATE_KEY, RPC_URL_138 (Chain 138 Core) |
deploy-all-contracts.sh |
| 01_DeployCore, 02_DeployBridges | PRIVATE_KEY, RPC; 02 needs UNIVERSAL_ASSET_REGISTRY, GOVERNANCE_CONTROLLER |
Phased core |
| DeployCCIPReceiver, DeployCCIPSender | PRIVATE_KEY, CCIP_ROUTER_ADDRESS, ORACLE_AGGREGATOR_ADDRESS; Sender optional: LINK_TOKEN_ADDRESS |
Set in .env; see .env.example |
| DeployWETHBridges (mainnet receiver) | MAINNET_WETH9_BRIDGE_ADDRESS, MAINNET_WETH10_BRIDGE_ADDRESS when configuring cross-chain |
.env.example |
| DeploySmartAccountsKit | PRIVATE_KEY, RPC_URL_138; optional ENTRY_POINT, SMART_ACCOUNT_FACTORY, PAYMASTER if pre-deployed |
Script does not deploy contracts; obtain EntryPoint/Factory from MetaMask kit or ERC-4337 impl and set in env |
| DeployTransactionMirror | PRIVATE_KEY, MIRROR_ADMIN (optional, default deployer) |
If forge script fails with constructor-args decode, use forge create — see § TransactionMirror below |
| DeployReserveSystem | TOKEN_FACTORY in .env |
Phase 6 |
Deploy Core Contracts (Chain 138)
cd smom-dbis-138
source .env
# Verify RPC: curl -s -X POST "$RPC_URL" -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}'
bash scripts/deployment/deploy-all-contracts.sh
Deploys: Multicall, Oracle, MultiSig (WETH9/10 pre-deployed in genesis).
Deploy Unified (Ordered or Parallel)
cd smom-dbis-138
./scripts/deployment/deploy-contracts-unified.sh --mode ordered
# or
./scripts/deployment/deploy-contracts-unified.sh --mode parallel
Deploy WETH Bridges (CCIP)
# From project root (use GAS_PRICE=1000000000 if min-gas-price error)
GAS_PRICE=1000000000 ./scripts/deploy-and-configure-weth9-bridge-chain138.sh
# Then set CCIPWETH9_BRIDGE_CHAIN138 in smom-dbis-138/.env
Smart accounts (ERC-4337)
Script: smom-dbis-138/script/smart-accounts/DeploySmartAccountsKit.s.sol (and DeployAccountWalletRegistryExtended.s.sol for registry).
Required env (in smom-dbis-138/.env): PRIVATE_KEY, RPC_URL_138 (Chain 138 Core). Optional: set ENTRY_POINT, SMART_ACCOUNT_FACTORY, PAYMASTER if already deployed; otherwise the script will deploy and log addresses to set in .env.
Deploy (Chain 138):
cd smom-dbis-138
source .env
forge script script/smart-accounts/DeploySmartAccountsKit.s.sol --rpc-url $RPC_URL_138 --broadcast --with-gas-price 1000000000
# Set ENTRY_POINT, SMART_ACCOUNT_FACTORY, PAYMASTER from output
Verification: Run script; confirm logged addresses match env. See PLACEHOLDERS_AND_TBD Smart Accounts Kit.
TransactionMirror (Chain 138)
Script: script/DeployTransactionMirror.s.sol. Deployed address: Set in smom-dbis-138/.env as TRANSACTION_MIRROR_ADDRESS from the script output (e.g. past deploys: 0xE362aa10D3Af1A16880A799b78D18F923403B55a, 0x4eeF36BBaf706C6da5859cF9B34E9934fEC3E006).
Recommended: Use the combined script; it always checks nonce, validates RPC is active (chainId 138), uses proper gas (1 gwei min), and loads the correct dotenv (smom-dbis-138/.env + config/ip-addresses.conf for RPC fallbacks).
Required in smom-dbis-138/.env: PRIVATE_KEY, RPC_URL_138 (Core RPC, 192.168.11.211:8545). No Public fallback for deployments. Optional: GAS_PRICE or GAS_PRICE_138 (default 1000000000). Before deploying: if Core was read-only, run ./scripts/maintenance/make-rpc-vmids-writable-via-ssh.sh then ./scripts/maintenance/health-check-rpc-2101.sh. See RPC_2101_READONLY_FIX.md.
If you see "Known transaction" or "Replacement transaction underpriced": Clear the tx pool then retry: ./scripts/clear-all-transaction-pools.sh (or RPC-only; see script). Run from a host that can reach RPC_URL_138 (same LAN/VPN):
./scripts/deployment/deploy-transaction-mirror-and-pmm-pool-after-txpool-clear.sh
This deploys TransactionMirror and creates the DODO cUSDT/cUSDC PMM pool, then runs on-chain verification. Core RPC only (no Public fallback). If Core is unreachable, fix read-only and health first (see RPC_2101_READONLY_FIX.md). Options: --dry-run (env, RPC, nonce only); --force (skip RPC check).
Skip stuck nonce manually: Set NEXT_NONCE to the next nonce (e.g. 13370) so the script uses vm.setNonce and deploys at a new address; then set TRANSACTION_MIRROR_ADDRESS in .env to the logged address. The combined script already sets NEXT_NONCE from pending nonce.
Or run the two forge commands manually (ensure RPC is Chain 138 and nonce is correct):
cd smom-dbis-138 && source .env
# Optional: export NEXT_NONCE=<pending nonce> if avoiding a stuck tx
forge script script/DeployTransactionMirror.s.sol:DeployTransactionMirror --rpc-url "$RPC_URL_138" --broadcast --private-key "$PRIVATE_KEY" --with-gas-price 1000000000
forge script script/dex/CreateCUSDTCUSDCPool.s.sol:CreateCUSDTCUSDCPool --rpc-url "$RPC_URL_138" --broadcast --private-key "$PRIVATE_KEY" --with-gas-price 1000000000
If forge script fails with "Failed to decode constructor arguments", deploy via forge create:
cd smom-dbis-138
source .env
ADMIN="${MIRROR_ADMIN:-$(cast wallet address --private-key $PRIVATE_KEY)}"
forge create contracts/mirror/TransactionMirror.sol:TransactionMirror \
--constructor-args "$ADMIN" \
--rpc-url "$RPC_URL_138" \
--private-key "$PRIVATE_KEY" \
--legacy \
--gas-price 1000000000
Or run the helper script (from repo root, from a host on LAN that can reach RPC_URL_138 e.g. 192.168.11.211:8545): ./scripts/deployment/deploy-transaction-mirror-chain138.sh. The script exports ETH_RPC_URL so Forge uses the correct RPC and, on success, updates or appends TRANSACTION_MIRROR_ADDRESS in smom-dbis-138/.env.
Cross-chain flash borrow / bridge / repay helpers (Chain 138)
For the cross-chain flash path, the repo now has a dedicated deploy script for:
UniversalCCIPFlashBridgeAdapterCrossChainFlashRepayReceiverCrossChainFlashVaultCreditReceiver
Foundry deploy script: smom-dbis-138/script/deploy/DeployCrossChainFlashInfrastructure.s.sol
Operator wrapper (recommended):
source scripts/lib/load-project-env.sh
./scripts/deployment/deploy-cross-chain-flash-infra-chain138.sh --dry-run
./scripts/deployment/deploy-cross-chain-flash-infra-chain138.sh
Required env:
PRIVATE_KEYRPC_URL_138UNIVERSAL_CCIP_BRIDGEorFLASH_UNIVERSAL_CCIP_BRIDGECCIP_ROUTERorCCIP_ROUTER_ADDRESSorCCIP_ROUTER_CHAIN138orFLASH_CCIP_ROUTER
Optional env overrides:
FLASH_REPAY_RECEIVER_ROUTERFLASH_VAULT_CREDIT_ROUTER
The deploy script logs and exports:
CROSS_CHAIN_FLASH_BRIDGE_ADAPTERCROSS_CHAIN_FLASH_REPAY_RECEIVERCROSS_CHAIN_FLASH_VAULT_CREDIT_RECEIVER
Live deployment (2026-04-03):
CROSS_CHAIN_FLASH_BRIDGE_ADAPTER=0xBe9e0B2d4cF6A3b2994d6f2f0904D2B165eB8ffCCROSS_CHAIN_FLASH_REPAY_RECEIVER=0xD084b68cB4B1ef2cBA09CF99FB1B6552fd9b4859CROSS_CHAIN_FLASH_VAULT_CREDIT_RECEIVER=0x89F7a1fcbBe104BeE96Da4b4b6b7d3AF85f7E661
Blockscout verification (2026-04-03):
UniversalCCIPFlashBridgeAdapterverified at2026-04-03T03:15:53ZCrossChainFlashRepayReceiververified at2026-04-03T03:11:16ZCrossChainFlashVaultCreditReceiververified at2026-04-03T03:15:34Z
Post-deploy verification:
bash scripts/verify/check-cross-chain-flash-infra-chain138.sh
Design reminder:
CrossChainFlashBorrowerstill handles the same-tx ERC-3156 borrow/repay path on the borrow chain.CrossChainFlashRepayReceiveris the destination-side CCIP delivery leg.CrossChainFlashVaultCreditReceiveris the source-side or same-chain CCIP vault refill leg after async settlement.
DODO v3 / D3MM pilot verification (Chain 138 private venue)
The private Chain 138 DODO v3 pilot is tracked separately from the public canonical DODO V2 stable-routing stack.
Current pilot addresses:
D3Oracle=0xD7459aEa8bB53C83a1e90262777D730539A326F0D3Vault=0x42b6867260Fb9eE6d09B7E0233A1fAD65D0133D1D3MMFactory=0x78470C7d2925B6738544E2DD4FE7c07CcA21AC31D3Proxy=0xc9a11abB7C63d88546Be24D58a6d95e3762cB843WETH10 / ETH-USD oracle source=0x99b3511a2d315a497c8112c1fdd8d508d4b1e506USDT/USD managed feed=0x7c2Cb2667f0f97f4004aae04B67d94A085E6f0f1USDC/USD managed feed=0xf072Ac13D45e6c83296ca18F3E04185B747DD6aacUSDT/USD managed feed=0x7c96E66F4a0713e327F9e73Cf2721f13DB29036CcUSDC/USD managed feed=0x291694095232CA80077125F64f6f73076e7910C1- Canonical
WETH10pilot poolD3MM=0x6550A3a59070061a262a893A1D6F3F490afFDBDA
Health check:
bash scripts/verify/check-dodo-v3-chain138.sh
Blockscout source-verification workflow:
bash scripts/verify/verify-dodo-v3-chain138-blockscout.sh
This verifies:
- the canonical D3MM pool returns
D3MM 1.0.0 D3Vaultstill recognizes the canonical poolD3Oraclehas a non-zero, whitelistedWETH10source and it no longer points at the bootstrapWETH10mockD3Oracleno longer points the stable assets at the older bootstrap mock feedsquerySellTokens(WETH10 -> USDT, 0.1)returns a healthy non-zero quoteD3Oracle,D3Vault,DODOApprove, andDODOApproveProxyare source-verified on BlockscoutD3MMFactoryandD3Proxyverification submissions have been sent through the saved standard-input path; Blockscout currently returns bytecode-only metadata for those two addresses rather than the full source-verification metadata
Current posture: the DODO v3 pilot oracle stack is now promoted onto the live Chain 138 oracle surfaces. Planner-v2 capability, generated route-matrix visibility, public /token-aggregation/api/v2 publication, and EnhancedSwapRouterV2 execution are now in place for the canonical WETH10 <-> USDT pilot lane. The public canonical stable execution stack for Chain 138 remains the DODO V2 DVM-backed PMM set, while DODO v3 stays a private pilot venue with a live execution path.
Live router-v2 execution stack (2026-04-03):
ENHANCED_SWAP_ROUTER_V2_ADDRESS=0xF1c93F54A5C2fc0d7766Ccb0Ad8f157DFB4C99CeINTENT_BRIDGE_COORDINATOR_V2_ADDRESS=0x7D0022B7e8360172fd9C0bB6778113b7Ea3674E7DODO_ROUTE_EXECUTOR_ADAPTER=0x88495B3dccEA93b0633390fDE71992683121Fa62DODO_V3_ROUTE_EXECUTOR_ADAPTER=0x9Cb97adD29c52e3B81989BcA2E33D46074B530eFUNISWAP_V3_ROUTE_EXECUTOR_ADAPTER=0x960D6db4E78705f82995690548556fb2266308EABALANCER_ROUTE_EXECUTOR_ADAPTER=0x4E1B71B69188Ab45021c797039b4887a4924157ACURVE_ROUTE_EXECUTOR_ADAPTER=0x5f0E07071c41ACcD2A1b1032D3bd49b323b9ADE6ONEINCH_ROUTE_EXECUTOR_ADAPTER=0x8168083d29b3293F215392A49D16e7FeF4a02600
Proof swap (2026-04-03):
- approval tx:
0xac36fc7c1f8b50a847101276c33404bfa6e4a53ddfc13f7296fbddedd87a5277 - router-v2 execution tx:
0x14cd60a226dbab0c96765fff23171569e5a2fc0e35bded03f92668951ced4b57 - result:
100 USDT -> 0.047130507214977987 WETH10
AlltraAdapter — setBridgeFee after deploy
After deploying or using AlltraAdapter (138 ↔ ALL Mainnet 651940), set the bridge fee to match ALL Mainnet fee structure.
Required: ALLTRA_ADAPTER_CHAIN138 in smom-dbis-138/.env (adapter address; see config/smart-contracts-master.json). Optional: ALLTRA_BRIDGE_FEE (wei) to pass to setBridgeFee. Deployer must have DEFAULT_ADMIN_ROLE.
cd smom-dbis-138 && source .env
# Use ALLTRA_BRIDGE_FEE from .env if set, else 0.001 ALL (1000000000000000 wei)
FEE="${ALLTRA_BRIDGE_FEE:-1000000000000000}"
cast send "$ALLTRA_ADAPTER_CHAIN138" "setBridgeFee(uint256)" "$FEE" \
--rpc-url "$RPC_URL_138" --private-key "$PRIVATE_KEY" --gas-price 1000000000
Document the final fee in PLACEHOLDERS_AND_TBD § AlltraAdapter when known.
Vault ac* / vdc* / sdc* (Chain 138)
After deploying the Vault System (DeployVaultSystem.s.sol), run the single script that creates all asset/deposit (ac*) and debt (vdc*) tokens via VaultFactory.createVaultWithDecimals.
Required env: VAULT_FACTORY_ADDRESS, PRIVATE_KEY, RPC_URL_138. Optional: OWNER, ENTITY (default deployer); CUSDC_ADDRESS_138, CUSDT_ADDRESS_138 or COMPLIANT_USDC_ADDRESS, COMPLIANT_USDT_ADDRESS (skip currency if unset).
Option A — deploy Vault System then ac/vdc/sdc in one go: run ./scripts/deployment/deploy-vault-system-and-ac-vdc-sdc.sh from smom-dbis-138 (uses PRIVATE_KEY, RPC_URL_138; parses VaultFactory from broadcast and runs ac/vdc/sdc step).
Option B — run steps separately:
cd smom-dbis-138
source .env
forge script script/deploy/vault/DeployVaultSystem.s.sol:DeployVaultSystem \
--rpc-url "$RPC_URL_138" --broadcast --with-gas-price 1000000000
# From output, set VAULT_FACTORY_ADDRESS=0x... then:
forge script script/deploy/vault/DeployAcVdcSdcVaults.s.sol:DeployAcVdcSdcVaults \
--rpc-url "$RPC_URL_138" --broadcast --with-gas-price 1000000000
Deployer must have VAULT_DEPLOYER_ROLE on VaultFactory. Each configured base token gets one vault with deposit token (ac*) and debt token (vdc*), 6 decimals, transferable debt. See MULTI_CHAIN_EXECUTION_DETERMINISTIC_DEPLOYMENT. Full architecture and phased roadmap: see VAULT_SYSTEM_MASTER_TECHNICAL_PLAN.
EnhancedSwapRouter & DODOPMMProvider (post-deploy configuration)
When Uniswap V3, Balancer, or DODO PMM pools exist on Chain 138 / 651940, configure the router and provider so on-chain quotes and swaps work.
Chain 138 dry-run helper (safe preflight):
cd smom-dbis-138
bash scripts/deployment/dry-run-enhanced-swap-router-chain138.sh
This helper loads smom-dbis-138/.env, verifies the minimum required env (PRIVATE_KEY, RPC_URL_138), prints the exact token/provider vars the deploy script will use, and shows the sourced non-broadcast forge script command for a safe Chain 138 dry-run. It also distinguishes "env preflight passed" from "router would actually be usable after deploy". The updated deploy script now preloads the live 2026-03-26 DODO pair map on Chain 138:
cUSDT ↔ cUSDCcUSDT ↔ USDTcUSDC ↔ USDCcUSDT ↔ cXAUCcUSDC ↔ cXAUCcEURT ↔ cXAUC
If provider env vars like DODOEX_ROUTER, DODO_PMM_PROVIDER_ADDRESS, UNISWAP_V3_ROUTER, BALANCER_VAULT, CURVE_3POOL, or ONEINCH_ROUTER are unset, the deploy path now falls back to the live Chain 138 pilot-compatible venue addresses for Uniswap_v3, Balancer, Curve_3, and 1inch. This keeps the Chain 138 deployment honest: the venues are funded and router-v2 wired on-chain, but they remain explicitly documented as pilot-compatible surfaces rather than upstream canonical protocol deployments.
For current Chain 138, prefer DODO_PMM_PROVIDER_ADDRESS when the deployed DODOPMMProvider is available. The router now supports that provider as its DODO backend on Chain 138. If neither DODO_PMM_PROVIDER_ADDRESS nor DODOEX_ROUTER is set, the router can still deploy and register the live pair map, but the DODO provider will be disabled and no DODO execution path will remain enabled.
The dry-run helper also probes the live DODOPMMProvider over RPC_URL_138 for WETH -> stable support. This is important because the current public/private PMM set is stable/stable and stable/XAU; swapToStablecoin() is still only operational when at least one live WETH -> stable route exists.
To run the sourced non-broadcast Forge simulation directly from the helper:
cd smom-dbis-138
bash scripts/deployment/dry-run-enhanced-swap-router-chain138.sh --run
You can increase visibility or the timeout if compilation/simulation is slow:
cd smom-dbis-138
bash scripts/deployment/dry-run-enhanced-swap-router-chain138.sh --run --timeout-seconds 180 --verbosity -vvv
EnhancedSwapRouter (set by address with ROUTING_MANAGER_ROLE):
| Config | Method | Env (optional) | When |
|---|---|---|---|
| Uniswap V3 Quoter | setUniswapQuoter(address) |
ENHANCED_SWAP_ROUTER_UNISWAP_QUOTER |
After Uniswap Quoter is deployed on chain |
| Balancer pool (WETH↔stable) | setBalancerPoolId(tokenIn, tokenOut, poolId) |
BALANCER_WETH_USDC_POOL_ID, BALANCER_WETH_USDT_POOL_ID |
After Balancer pool exists |
| Dodoex pool | setDodoPoolAddress(tokenIn, tokenOut, pool) |
Set via cast or script when DODO pool is known | After DODO PMM pool deployed |
Example (Chain 138, after setting env):
cd smom-dbis-138 && source .env
# Uniswap Quoter
[ -n "$ENHANCED_SWAP_ROUTER_UNISWAP_QUOTER" ] && cast send "$ENHANCED_SWAP_ROUTER" "setUniswapQuoter(address)" "$ENHANCED_SWAP_ROUTER_UNISWAP_QUOTER" --rpc-url "$RPC_URL_138" --private-key "$PRIVATE_KEY" --gas-price 1000000000
# Balancer (bytes32 pool IDs; use cast send with 0x-prefixed hex)
# cast send "$ENHANCED_SWAP_ROUTER" "setBalancerPoolId(address,address,bytes32)" <WETH> <USDC> "$BALANCER_WETH_USDC_POOL_ID" ...
DODOPMMProvider: Register existing DODO PMM pools so getQuote / executeSwap work. Address with POOL_MANAGER_ROLE calls registerPool(tokenIn, tokenOut, pool).
The corrected RegisterDODOPools.s.sol now reads DODOPMMIntegration.getAllPools() and getPoolConfig(pool) on-chain, then registers both directions for every discovered pool. That means it covers the current 2026-03-26 public live set and any future c* full-mesh pools already created in the integration. This is required because DODOPMMProvider stores routes as pools[tokenIn][tokenOut]. If the dry-run helper shows a documented live pair as missing, rerun this script before treating the provider as fully reconciled.
# After DODO pool is deployed (e.g. cUSDT↔USDT)
cast send "$DODO_PMM_PROVIDER_ADDRESS" "registerPool(address,address,address)" "<CUSDT>" "<USDT>" "<POOL_ADDRESS>" --rpc-url "$RPC_URL_138" --private-key "$PRIVATE_KEY" --gas-price 1000000000
Optional .env placeholders (see smom-dbis-138/.env.example): ENHANCED_SWAP_ROUTER_UNISWAP_QUOTER, BALANCER_WETH_USDC_POOL_ID, BALANCER_WETH_USDT_POOL_ID, DODO_PMM_PROVIDER_ADDRESS. Until set, router returns 0 for Uniswap/Balancer quotes and DODO provider returns no pool.
Private stabilization pools (Master Plan Phase 2)
XAU-anchored private pools (cUSDT↔XAU, cUSDC↔XAU, cEURT↔XAU) for the Stabilizer; only the Stabilizer or whitelisted keeper should execute swaps. See VAULT_SYSTEM_MASTER_TECHNICAL_PLAN §5.
Script: smom-dbis-138/script/dex/DeployPrivatePoolRegistryAndPools.s.sol — deploys PrivatePoolRegistry and optionally creates pools via DODOPMMIntegration createPool, then registers them in the registry.
Env (in smom-dbis-138/.env):
| Variable | Description |
|---|---|
PRIVATE_KEY |
Deployer (must have POOL_MANAGER_ROLE on DODOPMMIntegration to create pools) |
PRIVATE_POOL_REGISTRY_ADMIN |
Admin for PrivatePoolRegistry (default: deployer) |
DODOPMM_INTEGRATION_ADDRESS |
Deployed DODOPMMIntegration (set to create XAU pools in same run) |
XAU_ADDRESS_138 |
XAU token address on Chain 138 (required to create XAU-anchored pools) |
COMPLIANT_USDT_ADDRESS |
cUSDT on Chain 138 |
COMPLIANT_USDC_ADDRESS |
cUSDC on Chain 138 |
cEURT_ADDRESS_138 |
cEURT on Chain 138 (optional; omit to skip cEURT↔XAU pool) |
Deploy:
cd smom-dbis-138 && source .env
forge script script/dex/DeployPrivatePoolRegistryAndPools.s.sol:DeployPrivatePoolRegistryAndPools \
--rpc-url "$RPC_URL_138" --broadcast --with-gas-price 1000000000
If only the registry is needed (pools created later), leave DODOPMM_INTEGRATION_ADDRESS or XAU_ADDRESS_138 unset. To register existing pools manually: cast send "$PRIVATE_POOL_REGISTRY" "register(address,address,address)" <TOKEN_A> <TOKEN_B> <POOL_ADDRESS> .... Grant STABILIZER_LP_ROLE to allowed LPs when using a wrapper that checks it.
Stabilizer deployment and configuration (Phase 3 + 6)
Deploy the Stabilizer (Master Plan Phase 3) after PrivatePoolRegistry and private XAU-anchored pools exist. The Stabilizer calls checkDeviation() (peg manager or TWAP) and executePrivateSwap(tradeSize, tokenIn, tokenOut) via the private pool registry. Phase 6: TWAP/sustained N-block deviation, per-block volume cap, flash drain recovery target <3 blocks (see OPERATIONS_RUNBOOK Flash Loan Containment).
Deploy (e.g. via forge create or a small script):
- Constructor:
(admin, privatePoolRegistryAddress). - Set in
.env:STABILIZER_ADDRESS,PRIVATE_POOL_REGISTRY_ADDRESS,STABLECOIN_PEG_MANAGER_ADDRESS(or commodity peg), peg asset address.
Configuration (admin):
| Parameter | Method | Typical / notes |
|---|---|---|
| Peg source | setStablecoinPegSource(manager, asset) or setCommodityPegSource(manager, asset) |
One of them; deviation from peg used for checkDeviation() |
| thresholdBps | setThresholdBps(uint256) |
e.g. 50 (0.5%) |
| minBlocksBetweenExecution | setMinBlocksBetweenExecution(uint256) |
e.g. 3–5 (block delay) |
| maxStabilizationVolumePerBlock | setMaxStabilizationVolumePerBlock(uint256) |
Cap per block |
| maxSlippageBps | setMaxSlippageBps(uint256) |
e.g. 100 (1%) |
| maxGasPriceForStabilizer | setMaxGasPriceForStabilizer(uint256) |
MEV resistance; 0 = disabled |
| sustainedDeviationBlocks | setSustainedDeviationBlocks(uint256) |
N blocks over threshold before rebalance (Phase 6) |
Keeper: Grant STABILIZER_KEEPER_ROLE to the keeper EOA or bot:
cast send "$STABILIZER_ADDRESS" "grantRole(bytes32,address)" $(cast keccak "STABILIZER_KEEPER_ROLE()") "$KEEPER_ADDRESS" --rpc-url "$RPC_URL_138" --private-key "$PRIVATE_KEY" --gas-price 1000000000
Operational target (Phase 6): Flash drain recovery <3 blocks. The contract enforces sustained deviation over N blocks, per-block volume cap, and block delay; document in OPERATIONS_RUNBOOK and VAULT_SYSTEM_MASTER_TECHNICAL_PLAN §8/§16.
Contract Verification (Blockscout)
Use the Forge Verification Proxy for forge verify-contract (Blockscout expects module/action in query; Forge sends JSON only). The verification script uses canonical addresses from smom-dbis-138/.env and config/ip-addresses.conf (ORACLE_PROXY, AGGREGATOR_ADDRESS, CCIP_SENDER, CCIPWETH9_BRIDGE_CHAIN138, etc.); run from a host on LAN that can reach Blockscout (192.168.11.140:4000).
Preferred: orchestrated script (starts proxy if needed, timeout 900s default):
source smom-dbis-138/.env 2>/dev/null
./scripts/verify/run-contract-verification-with-proxy.sh
Manual (proxy + verify):
# 1. Start proxy (in separate terminal)
BLOCKSCOUT_URL=http://192.168.11.140:4000 node forge-verification-proxy/server.js
# 2. Run verification
./scripts/verify-contracts-blockscout.sh
See: forge-verification-proxy/README.md, BLOCKSCOUT_FORGE_VERIFICATION_EVALUATION.md. Fallback: manual verification at https://explorer.d-bis.org/address/#verify-contract
Runbooks in sync (R12): BLOCKSCOUT_FIX_RUNBOOK, BLOCKSCOUT_FORGE_VERIFICATION_EVALUATION, this runbook. Full recommendations (R1–R24): RECOMMENDATIONS_OPERATOR_CHECKLIST.
Troubleshooting
| Error | Cause | Fix |
|---|---|---|
No route to host |
Dev machine cannot reach RPC (RPC_URL_138, e.g. 192.168.11.211:8545) | Run from machine on LAN or VPN; or set RPC_URL_138=https://rpc-core.d-bis.org |
PRIVATE_KEY not set |
Missing in .env | Add deployer key to smom-dbis-138/.env |
Gas price below configured minimum gas price |
Chain 138 minimum gas not met | Use --with-gas-price 1000000000 for all forge script / forge create on Chain 138 |
| RPC -32xxx / out of gas when deploying | Gas estimate too low or estimation failed | Use --gas-estimate-multiplier 150 (or 200) with forge script ... --broadcast; ensure deployer has enough ETH. See RPC_ERRORS_32001_32602.md. |
Failed to decode constructor arguments (TransactionMirror) |
Forge broadcast decode bug | Deploy via forge create ... --constructor-args <ADMIN> --gas-price 1000000000 |
pam_chauthtok failed (Blockscout) |
Container PAM restriction | Use Proxmox Web UI: Container 5000 → Options → Password |
pvesm not found (verify-storage) |
Script must run ON Proxmox host | ssh root@r630-01 then run script |