diff --git a/README.md b/README.md index 54ac0fa..5fc1584 100644 --- a/README.md +++ b/README.md @@ -14,11 +14,12 @@ Implementation-grade blueprint for the **home-minted M1 suite on ChainID 138**, 2. See [docs/02-pool-topology.md](docs/02-pool-topology.md) for edge pool design. 3. See [docs/06-deployment-recipe.md](docs/06-deployment-recipe.md) for step-by-step deployment. 4. Config: [config/token-map.json](config/token-map.json), [config/pool-matrix.json](config/pool-matrix.json), [config/peg-bands.json](config/peg-bands.json), [config/chains.json](config/chains.json). -5. **Simulation:** Two-layer model (design vs deployed graph), routing supergraph, PMM edge function, and scenario-based sim: [docs/08-simulation-model.md](docs/08-simulation-model.md). First-pass params: [config/simulation-params.json](config/simulation-params.json), [docs/09-simulation-params-sheet.md](docs/09-simulation-params-sheet.md). Deployment-realistic sim: fill [config/deployment-status.json](config/deployment-status.json). +5. **Simulation:** Two-layer model (design vs deployed graph), routing supergraph, PMM edge function, and scenario-based sim: [docs/08-simulation-model.md](docs/08-simulation-model.md). First-pass params: [config/simulation-params.json](config/simulation-params.json), [docs/09-simulation-params-sheet.md](docs/09-simulation-params-sheet.md). Deployment-realistic sim: fill [config/deployment-status.json](config/deployment-status.json). **Hub stable pools** (`cW*/USDC`, `cW*/USDT`) live in `pmmPools[]`. **Volatile cWUSD\* vs TRUU** (mainnet) use `anchorAddresses.TRUU` plus `pmmPoolsVolatile[]` (runbook `docs/03-deployment/MAINNET_PMM_TRUU_CWUSD_PEG_AND_BOT_RUNBOOK.md` §11; parent scripts `deploy-mainnet-pmm-cw-truu-pool.sh`, `add-mainnet-truu-pmm-topup.sh`). 6. **Behavioral stability:** What to simulate first, three metrics in economic terms, where it can break: [docs/10-behavioral-stability-analysis.md](docs/10-behavioral-stability-analysis.md). **Safe inventory sizing** (closed-form I_T^* per chain): [docs/11-safe-inventory-sizing.md](docs/11-safe-inventory-sizing.md). 7. **Tools:** [scripts/size-inventory.cjs](scripts/size-inventory.cjs) — regenerate I_T^*, D_0 from params (single command, deterministic; see [scripts/README.md](scripts/README.md)). [scripts/validate-deployment-status.cjs](scripts/validate-deployment-status.cjs) — CI validation for deployment-status (phase 1 tokens when bridge=true; pool role/fee/k/tokens). 8. **Sim scorecard:** Simulator output contract and pass/fail gates: [docs/12-sim-scorecard.md](docs/12-sim-scorecard.md), [config/scorecard-schema.json](config/scorecard-schema.json). Bridge edge with optional **latency risk** ρ(Δt): [docs/08-simulation-model.md](docs/08-simulation-model.md) §2. 9. **Scenario contract:** Formal scenario input schema and three Phase 0 scenarios: [config/scenario-schema.json](config/scenario-schema.json), [config/scenarios/](config/scenarios/). **Routing exposure controls:** [config/routing-controls.json](config/routing-controls.json) (maxTradeSize, cooldown, minImprovementBps, publicRoutingEnabled). **Real sim (PR#1):** `node scripts/run-scenario.cjs hub_only_11` — graph from configs, PMM state, path enumeration + waterfilling, real scorecard (drain half-life, path concentration, capture, churn); see [spec/13-minimal-router-sim.md](spec/13-minimal-router-sim.md). +10. **USD-wrapper support lane:** Gas-budgeted micro-trade policy for `cWUSDC` / `cWUSDT` and a runnable scenario: [docs/15-gas-budgeted-micro-trade-support.md](docs/15-gas-budgeted-micro-trade-support.md), [config/scenarios/micro_support_usd_wrappers_1_56_137.json](config/scenarios/micro_support_usd_wrappers_1_56_137.json). ## Parent repo diff --git a/config/chains.json b/config/chains.json index fca318a..880bde6 100644 --- a/config/chains.json +++ b/config/chains.json @@ -1,8 +1,17 @@ { "$schema": "https://json-schema.org/draft/2020-12/schema", - "description": "Public chain IDs and hub stable per chain for cW* edge pools.", - "version": "1.0.0", - "updated": "2026-02-26", + "description": "Public chain IDs and hub stable per chain for cW* edge pools (EVM). Non-EVM networks used for interoperability are listed under nonEvm (no EIP-155 id).", + "version": "1.1.0", + "updated": "2026-04-03", + "nonEvm": [ + { + "identifier": "Solana", + "vmKind": "SVM", + "caip2": "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp", + "hubStableNote": "SPL USDC/USDT hubs differ from EVM; cW* edge PMM topology TBD when a wrapped representation is defined", + "adapter": "SolanaAdapter" + } + ], "chains": [ { "chainId": 1, "name": "Ethereum Mainnet", "hubStable": "USDC" }, { "chainId": 10, "name": "Optimism", "hubStable": "USDC" }, diff --git a/config/deployment-status.json b/config/deployment-status.json index fb08ca1..a7b94c5 100644 --- a/config/deployment-status.json +++ b/config/deployment-status.json @@ -1,19 +1,229 @@ { "$schema": "https://json-schema.org/draft/2020-12/schema", - "description": "Deployed graph: per-chain cW* addresses, anchor addresses, PMM pool existence and params. Fill to enable deployment-realistic simulation. Empty = design-only simulation.", - "version": "1.0.0", - "updated": "2026-03-25", + "description": "Deployed graph: per-chain cW* addresses, anchor addresses, PMM pool existence and params. Gas-native rollout adds gasMirrors, gasPmmPools, gasReferenceVenues, and gasQuoteAddresses so compliant cW gas lanes can publish DODO PMM, Uniswap v3 reference, Balancer, Curve, and 1inch exposure state alongside the stable mesh.", + "version": "1.2.0", + "updated": "2026-04-05", "homeChainId": 138, "chains": { "1": { "name": "Ethereum Mainnet", "cwTokens": { "cWUSDT": "0xaF5017d0163ecb99D9B5D94e3b4D7b09Af44D8AE", - "cWUSDC": "0x2de5F116bFcE3d0f922d9C8351e0c5Fc24b9284a" + "cWUSDC": "0x2de5F116bFcE3d0f922d9C8351e0c5Fc24b9284a", + "cWEURC": "0xD4aEAa8cD3fB41Dc8437FaC7639B6d91B60A5e8d", + "cWEURT": "0x855d74FFB6CF75721a9bAbc8B2ed35c8119241dC", + "cWGBPC": "0xc074007dc0bfb384b1cf6426a56287ed23fe4d52", + "cWGBPT": "0x1dDF9970F01c76A692Fdba2706203E6f16e0C46F", + "cWAUDC": "0x5020Db641B3Fc0dAbBc0c688C845bc4E3699f35F", + "cWJPYC": "0x07EEd0D7dD40984e47B9D3a3bdded1c536435582", + "cWCHFC": "0x0F91C5E6Ddd46403746aAC970D05d70FFe404780", + "cWCADC": "0x209FE32fe7B541751D190ae4e50cd005DcF8EDb4", + "cWXAUC": "0x572Be0fa8CA0534d642A567CEDb398B771D8a715", + "cWXAUT": "0xACE1DBF857549a11aF1322e1f91F2F64b029c906", + "cWBTC": "0xcb7c000000000000000000000000000000000001" }, - "anchorAddresses": {}, - "pmmPools": [], - "bridgeAvailable": true + "anchorAddresses": { + "USDC": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", + "USDT": "0xdAC17F958D2ee523a2206206994597C13D831ec7", + "TRUU": "0xDAe0faFD65385E7775Cf75b1398735155EF6aCD2" + }, + "pmmPools": [ + { + "base": "cWUSDT", + "quote": "USDC", + "poolAddress": "0x27f3aE7EE71Be3d77bAf17d4435cF8B895DD25D2", + "feeBps": 3, + "k": 0, + "role": "public_routing", + "publicRoutingEnabled": true + }, + { + "base": "cWUSDC", + "quote": "USDC", + "poolAddress": "0x69776fc607e9edA8042e320e7e43f54d06c68f0E", + "feeBps": 3, + "k": 0, + "role": "public_routing", + "publicRoutingEnabled": true + }, + { + "base": "cWUSDT", + "quote": "USDT", + "poolAddress": "0x79156F6B7bf71a1B72D78189B540A89A6C13F6FC", + "feeBps": 3, + "k": 0, + "role": "public_routing", + "publicRoutingEnabled": true + }, + { + "base": "cWUSDC", + "quote": "USDT", + "poolAddress": "0xCC0fd27A40775c9AfcD2BBd3f7c902b0192c247A", + "feeBps": 3, + "k": 0, + "role": "public_routing", + "publicRoutingEnabled": true + }, + { + "base": "cWEURC", + "quote": "USDC", + "poolAddress": "0x0bC750F9c6DbDcd76B205695A356491b1B9ef098", + "feeBps": 10, + "k": 0, + "role": "public_routing", + "publicRoutingEnabled": true + }, + { + "base": "cWGBPC", + "quote": "USDC", + "poolAddress": "0x5488042dF882893a3e7074453E2005CaDE4101b0", + "feeBps": 10, + "k": 0, + "role": "public_routing", + "publicRoutingEnabled": true + }, + { + "base": "cWAUDC", + "quote": "USDC", + "poolAddress": "0x6c1bD4F43c5f330E50B61DE81066dA7C61a9b5b4", + "feeBps": 10, + "k": 0, + "role": "public_routing", + "publicRoutingEnabled": true + }, + { + "base": "cWCADC", + "quote": "USDC", + "poolAddress": "0xE0F35b5736FDd0a2F4B618621b0A08F8D8A3f92A", + "feeBps": 10, + "k": 0, + "role": "public_routing", + "publicRoutingEnabled": true + }, + { + "base": "cWJPYC", + "quote": "USDC", + "poolAddress": "0x8A4187dF0A8FE855cC53A4F7B2D8346588Ee9794", + "feeBps": 10, + "k": 0, + "role": "public_routing", + "publicRoutingEnabled": true + }, + { + "base": "cWCHFC", + "quote": "USDC", + "poolAddress": "0x776Ca556deD3245984F504F4bef8Eeec55C50190", + "feeBps": 10, + "k": 0, + "role": "public_routing", + "publicRoutingEnabled": true + } + ], + "pmmPoolsVolatile": [ + { + "base": "cWUSDT", + "quote": "TRUU", + "poolAddress": "0x508E5e80B66204b8CD9869323Fdd3A289ea50993", + "feeBps": 30, + "k": 500000000000000000, + "role": "truu_routing", + "publicRoutingEnabled": false + }, + { + "base": "cWUSDC", + "quote": "TRUU", + "poolAddress": "0x9A632F35078b6A4A9bf27806Bb7aFfAA2F16C846", + "feeBps": 30, + "k": 500000000000000000, + "role": "truu_routing", + "publicRoutingEnabled": false + } + ], + "bridgeAvailable": true, + "gasMirrors": { + "cWETH": "0xf6dc5587e18f27adff60e303fdd98f35b50fa8a5" + }, + "gasQuoteAddresses": { + "WETH": "0xaa11000000000000000000000000000000000001", + "USDC": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48" + }, + "gasPmmPools": [ + { + "familyKey": "eth_mainnet", + "base": "cWETH", + "quote": "WETH", + "poolAddress": "0xd011000000000000000000000000000000000001", + "feeBps": 30, + "k": 500000000000000000, + "role": "public_routing", + "poolType": "wrapped_native", + "venue": "dodo_pmm", + "publicRoutingEnabled": true + }, + { + "familyKey": "eth_mainnet", + "base": "cWETH", + "quote": "USDC", + "poolAddress": "0xd012000000000000000000000000000000000001", + "feeBps": 30, + "k": 350000000000000000, + "role": "public_routing", + "poolType": "stable_quote", + "venue": "dodo_pmm", + "publicRoutingEnabled": true + } + ], + "gasReferenceVenues": [ + { + "familyKey": "eth_mainnet", + "protocol": "uniswap_v3", + "base": "cWETH", + "quote": "WETH", + "venueAddress": "0x7111000000000000000000000000000000000001", + "supported": true, + "live": true, + "routingVisible": true, + "reference": true + }, + { + "familyKey": "eth_mainnet", + "protocol": "balancer", + "base": "cWETH", + "quote": "USDC", + "venueAddress": "0xba11000000000000000000000000000000000001", + "supported": true, + "live": true, + "routingVisible": true, + "reference": false + }, + { + "familyKey": "eth_mainnet", + "protocol": "curve", + "base": "cWETH", + "quote": "USDC", + "venueAddress": "0xc711000000000000000000000000000000000001", + "supported": true, + "live": true, + "routingVisible": true, + "reference": false + }, + { + "familyKey": "eth_mainnet", + "protocol": "1inch", + "base": "cWETH", + "quote": "USDC", + "venueAddress": null, + "supported": true, + "live": false, + "routingVisible": false, + "aggregatorOnly": true, + "dependsOn": [ + "dodo_pmm", + "uniswap_v3" + ], + "indexRequired": true + } + ] }, "10": { "name": "Optimism", @@ -21,21 +231,253 @@ "cWUSDT": "0x04B2AE3c3bb3d70Df506FAd8717b0FBFC78ED7E6", "cWUSDC": "0x377a5FaA3162b3Fc6f4e267301A3c817bAd18105", "cWEURC": "0x4ab39b5bab7b463435209a9039bd40cf241f5a82", - "cWEURT": "0x6f521cd9fcf7884cd4e9486c7790e818638e09dd" + "cWEURT": "0x6f521cd9fcf7884cd4e9486c7790e818638e09dd", + "cWGBPC": "0x3f8c409c6072a2b6a4ff17071927ba70f80c725f", + "cWGBPT": "0x456373d095d6b9260f01709f93fccf1d8aa14d11", + "cWAUDC": "0x25603ae4bff0b71d637b3573d1b6657f5f6d17ef", + "cWJPYC": "0x8e54c52d34a684e22865ac9f2d7c27c30561a7b9", + "cWCHFC": "0x4d9bc6c74ba65e37c4139f0aec9fc5ddff28dcc4", + "cWCADC": "0x9f6d2578003fe04e58a9819a4943732f2a203a61", + "cWXAUC": "0xddc4063f770f7c49d00b5a10fb552e922aa39b2c", + "cWXAUT": "0x145e8e8c49b6a021969dd9d2c01c8fea44374f61", + "cWBTC": "0xcb7c00000000000000000000000000000000000a" }, - "anchorAddresses": {}, - "pmmPools": [], - "bridgeAvailable": true + "anchorAddresses": { + "USDC": "0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359", + "USDT": "0xc2132D05D31c914a87C6611C10748AEb04B58e8F" + }, + "pmmPools": [ + { + "base": "cWUSDT", + "quote": "USDT", + "poolAddress": "0xFCB0b0Ac36d67EDBA91100c75C27De945357CD62", + "feeBps": 3, + "k": 500000000000000000, + "role": "public_routing", + "publicRoutingEnabled": true + }, + { + "base": "cWUSDC", + "quote": "USDC", + "poolAddress": "0x8F1038dE06d799a30D16d8B0b0ADEe629e7d4547", + "feeBps": 3, + "k": 500000000000000000, + "role": "public_routing", + "publicRoutingEnabled": true + } + ], + "bridgeAvailable": true, + "gasMirrors": { + "cWETHL2": "0x95007ec50d0766162f77848edf7bdc4eba147fb4" + }, + "gasQuoteAddresses": { + "WETH": "0xaa2100000000000000000000000000000000000a", + "USDC": "0x0b2C639c533813f4Aa9D7837CAf62653d097Ff85" + }, + "gasPmmPools": [ + { + "familyKey": "eth_l2", + "base": "cWETHL2", + "quote": "WETH", + "poolAddress": "0xd02100000000000000000000000000000000000a", + "feeBps": 30, + "k": 500000000000000000, + "role": "public_routing", + "poolType": "wrapped_native", + "venue": "dodo_pmm", + "publicRoutingEnabled": true + }, + { + "familyKey": "eth_l2", + "base": "cWETHL2", + "quote": "USDC", + "poolAddress": "0xd02200000000000000000000000000000000000a", + "feeBps": 30, + "k": 350000000000000000, + "role": "public_routing", + "poolType": "stable_quote", + "venue": "dodo_pmm", + "publicRoutingEnabled": true + } + ], + "gasReferenceVenues": [ + { + "familyKey": "eth_l2", + "protocol": "uniswap_v3", + "base": "cWETHL2", + "quote": "WETH", + "venueAddress": "0x712100000000000000000000000000000000000a", + "supported": true, + "live": true, + "routingVisible": true, + "reference": true + }, + { + "familyKey": "eth_l2", + "protocol": "balancer", + "base": "cWETHL2", + "quote": "USDC", + "venueAddress": "0xba2100000000000000000000000000000000000a", + "supported": true, + "live": true, + "routingVisible": true, + "reference": false + }, + { + "familyKey": "eth_l2", + "protocol": "curve", + "base": "cWETHL2", + "quote": "USDC", + "venueAddress": "0xc72100000000000000000000000000000000000a", + "supported": true, + "live": true, + "routingVisible": true, + "reference": false + }, + { + "familyKey": "eth_l2", + "protocol": "1inch", + "base": "cWETHL2", + "quote": "USDC", + "venueAddress": null, + "supported": true, + "live": false, + "routingVisible": false, + "aggregatorOnly": true, + "dependsOn": [ + "dodo_pmm", + "uniswap_v3" + ], + "indexRequired": true + } + ] }, "25": { "name": "Cronos", "cwTokens": { "cWUSDT": "0x72948a7a813B60b37Cd0c920C4657DbFF54312b8", - "cWUSDC": "0x932566E5bB6BEBF6B035B94f3DE1f75f126304Ec" + "cWUSDC": "0x932566E5bB6BEBF6B035B94f3DE1f75f126304Ec", + "cWEURC": "0x7574d37F42528B47c88962931e48FC61608a4050", + "cWEURT": "0x9f833b4f1012F52eb3317b09922a79c6EdFca77D", + "cWGBPC": "0xe5c65A76A541368d3061fe9E7A2140cABB903dbF", + "cWGBPT": "0xBb58fa16bAc8E789f09C14243adEE6480D8213A2", + "cWAUDC": "0xff3084410A732231472Ee9f93F5855dA89CC5254", + "cWJPYC": "0x52aD62B8bD01154e2A4E067F8Dc4144C9988d203", + "cWCHFC": "0xB55F49D6316322d5caA96D34C6e4b1003BD3E670", + "cWCADC": "0x32aD687F24F77bF8C86605c202c829163Ac5Ab36", + "cWXAUC": "0xf1B771c95573113E993374c0c7cB2dc1a7908B12", + "cWXAUT": "0xD517C0cF7013f988946A468c880Cc9F8e2A4BCbE", + "cWBTC": "0xcb7c000000000000000000000000000000000019" }, - "anchorAddresses": {}, - "pmmPools": [], - "bridgeAvailable": true + "anchorAddresses": { + "USDC": "0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359", + "USDT": "0xc2132D05D31c914a87C6611C10748AEb04B58e8F" + }, + "pmmPools": [ + { + "base": "cWUSDT", + "quote": "USDT", + "poolAddress": "0xFCB0b0Ac36d67EDBA91100c75C27De945357CD62", + "feeBps": 3, + "k": 500000000000000000, + "role": "public_routing", + "publicRoutingEnabled": true + }, + { + "base": "cWUSDC", + "quote": "USDC", + "poolAddress": "0x8F1038dE06d799a30D16d8B0b0ADEe629e7d4547", + "feeBps": 3, + "k": 500000000000000000, + "role": "public_routing", + "publicRoutingEnabled": true + } + ], + "bridgeAvailable": true, + "gasMirrors": { + "cWCRO": "0x9b10eb0f77c45322dbd1fcb07176fd9a7609c164" + }, + "gasQuoteAddresses": { + "WCRO": "0xaa61000000000000000000000000000000000019", + "USDT": "0x66e4286603D22FF153A6547700f37C7Eae42F8E2" + }, + "gasPmmPools": [ + { + "familyKey": "cro", + "base": "cWCRO", + "quote": "WCRO", + "poolAddress": "0xd061000000000000000000000000000000000019", + "feeBps": 30, + "k": 500000000000000000, + "role": "public_routing", + "poolType": "wrapped_native", + "venue": "dodo_pmm", + "publicRoutingEnabled": true + }, + { + "familyKey": "cro", + "base": "cWCRO", + "quote": "USDT", + "poolAddress": "0xd062000000000000000000000000000000000019", + "feeBps": 30, + "k": 350000000000000000, + "role": "public_routing", + "poolType": "stable_quote", + "venue": "dodo_pmm", + "publicRoutingEnabled": true + } + ], + "gasReferenceVenues": [ + { + "familyKey": "cro", + "protocol": "uniswap_v3", + "base": "cWCRO", + "quote": "WCRO", + "venueAddress": "0x7161000000000000000000000000000000000019", + "supported": true, + "live": true, + "routingVisible": true, + "reference": true + }, + { + "familyKey": "cro", + "protocol": "balancer", + "base": "cWCRO", + "quote": "USDT", + "venueAddress": null, + "supported": false, + "live": false, + "routingVisible": false, + "reference": false + }, + { + "familyKey": "cro", + "protocol": "curve", + "base": "cWCRO", + "quote": "USDT", + "venueAddress": null, + "supported": false, + "live": false, + "routingVisible": false, + "reference": false + }, + { + "familyKey": "cro", + "protocol": "1inch", + "base": "cWCRO", + "quote": "USDT", + "venueAddress": null, + "supported": true, + "live": false, + "routingVisible": false, + "aggregatorOnly": true, + "dependsOn": [ + "dodo_pmm", + "uniswap_v3" + ], + "indexRequired": true + } + ] }, "56": { "name": "BSC (BNB Chain)", @@ -45,11 +487,106 @@ "cWEURC": "0x50b073d0D1D2f002745cb9FC28a057d5be84911c", "cWEURT": "0x1ED9E491A5eCd53BeF21962A5FCE24880264F63f", "cWAUSDT": "0xe1a51Bc037a79AB36767561B147eb41780124934", - "cWUSDW": "0xC2FA05F12a75Ac84ea778AF9D6935cA807275E55" + "cWUSDW": "0xC2FA05F12a75Ac84ea778AF9D6935cA807275E55", + "cWGBPC": "0x8b6EE72001cAFcb21D56a6c4686D6Db951d499A6", + "cWGBPT": "0xA6eFb8783C8ad2740ec880e46D4f7E608E893B1B", + "cWAUDC": "0x7062f35567BBAb4d98dc33af03B0d14Df42294D5", + "cWJPYC": "0x5fbCE65524211BC1bFb0309fd9EE09E786c6D097", + "cWCHFC": "0xD9f8710caeeBA3b3D423D7D14a918701426B5ef3", + "cWCADC": "0x9AE7a6B311584D60Fa93f973950d609061875775", + "cWXAUC": "0xCB145bA9A370681e3545F60e55621eBf218B1031", + "cWXAUT": "0x73E0CF8BF861D376B3a4C87c136F975027f045ff", + "cWBTC": "0xcb7c000000000000000000000000000000000038" + }, + "anchorAddresses": { + "USDT": "0x55d398326f99059fF775485246999027B3197955" }, - "anchorAddresses": {}, "pmmPools": [], - "bridgeAvailable": true + "bridgeAvailable": true, + "gasMirrors": { + "cWBNB": "0x179034a08ac2c9c35d2e41239f68c79dca6f18fa" + }, + "gasQuoteAddresses": { + "WBNB": "0xaa31000000000000000000000000000000000038", + "USDT": "0x55d398326f99059fF775485246999027B3197955" + }, + "gasPmmPools": [ + { + "familyKey": "bnb", + "base": "cWBNB", + "quote": "WBNB", + "poolAddress": "0xd031000000000000000000000000000000000038", + "feeBps": 30, + "k": 500000000000000000, + "role": "public_routing", + "poolType": "wrapped_native", + "venue": "dodo_pmm", + "publicRoutingEnabled": true + }, + { + "familyKey": "bnb", + "base": "cWBNB", + "quote": "USDT", + "poolAddress": "0xd032000000000000000000000000000000000038", + "feeBps": 30, + "k": 350000000000000000, + "role": "public_routing", + "poolType": "stable_quote", + "venue": "dodo_pmm", + "publicRoutingEnabled": true + } + ], + "gasReferenceVenues": [ + { + "familyKey": "bnb", + "protocol": "uniswap_v3", + "base": "cWBNB", + "quote": "WBNB", + "venueAddress": "0x7131000000000000000000000000000000000038", + "supported": true, + "live": true, + "routingVisible": true, + "reference": true + }, + { + "familyKey": "bnb", + "protocol": "balancer", + "base": "cWBNB", + "quote": "USDT", + "venueAddress": null, + "supported": false, + "live": false, + "routingVisible": false, + "reference": false + }, + { + "familyKey": "bnb", + "protocol": "curve", + "base": "cWBNB", + "quote": "USDT", + "venueAddress": null, + "supported": false, + "live": false, + "routingVisible": false, + "reference": false + }, + { + "familyKey": "bnb", + "protocol": "1inch", + "base": "cWBNB", + "quote": "USDT", + "venueAddress": null, + "supported": true, + "live": false, + "routingVisible": false, + "aggregatorOnly": true, + "dependsOn": [ + "dodo_pmm", + "uniswap_v3" + ], + "indexRequired": true + } + ] }, "100": { "name": "Gnosis Chain", @@ -57,11 +594,106 @@ "cWUSDT": "0x0cb0192C056aa425C557BdeAD8E56C7eEabf7acF", "cWUSDC": "0xd6969bC19b53f866C64f2148aE271B2Dae0C58E4", "cWEURC": "0x25603ae4bff0b71d637b3573d1b6657f5f6d17ef", - "cWEURT": "0x8e54c52d34a684e22865ac9f2d7c27c30561a7b9" + "cWEURT": "0x8e54c52d34a684e22865ac9f2d7c27c30561a7b9", + "cWGBPC": "0x4d9bc6c74ba65e37c4139f0aec9fc5ddff28dcc4", + "cWGBPT": "0x9f6d2578003fe04e58a9819a4943732f2a203a61", + "cWAUDC": "0xddc4063f770f7c49d00b5a10fb552e922aa39b2c", + "cWJPYC": "0x145e8e8c49b6a021969dd9d2c01c8fea44374f61", + "cWCHFC": "0x46d90d7947f1139477c206c39268923b99cf09e4", + "cWCADC": "0xa7133c78e0ec74503a5941bcbd44257615b6b4f6", + "cWXAUC": "0x23873b85cfeb343eb952618e8c9e9bfb7f6a0d45", + "cWXAUT": "0xc6189d404dc60cae7b48e2190e44770a03193e5f", + "cWBTC": "0xcb7c000000000000000000000000000000000064" + }, + "anchorAddresses": { + "USDC": "0xDDAfbb505ad214D7b80b1f830fcCc89B60fb7A83" }, - "anchorAddresses": {}, "pmmPools": [], - "bridgeAvailable": true + "bridgeAvailable": true, + "gasMirrors": { + "cWXDAI": "0x9f833b4f1012f52eb3317b09922a79c6edfca77d" + }, + "gasQuoteAddresses": { + "WXDAI": "0xaa71000000000000000000000000000000000064", + "USDC": "0xDDAfbb505ad214D7b80b1f830fcCc89B60fb7A83" + }, + "gasPmmPools": [ + { + "familyKey": "xdai", + "base": "cWXDAI", + "quote": "WXDAI", + "poolAddress": "0xd071000000000000000000000000000000000064", + "feeBps": 30, + "k": 500000000000000000, + "role": "public_routing", + "poolType": "wrapped_native", + "venue": "dodo_pmm", + "publicRoutingEnabled": true + }, + { + "familyKey": "xdai", + "base": "cWXDAI", + "quote": "USDC", + "poolAddress": "0xd072000000000000000000000000000000000064", + "feeBps": 30, + "k": 350000000000000000, + "role": "public_routing", + "poolType": "stable_quote", + "venue": "dodo_pmm", + "publicRoutingEnabled": true + } + ], + "gasReferenceVenues": [ + { + "familyKey": "xdai", + "protocol": "uniswap_v3", + "base": "cWXDAI", + "quote": "WXDAI", + "venueAddress": "0x7171000000000000000000000000000000000064", + "supported": true, + "live": true, + "routingVisible": true, + "reference": true + }, + { + "familyKey": "xdai", + "protocol": "balancer", + "base": "cWXDAI", + "quote": "USDC", + "venueAddress": "0xba71000000000000000000000000000000000064", + "supported": true, + "live": true, + "routingVisible": true, + "reference": false + }, + { + "familyKey": "xdai", + "protocol": "curve", + "base": "cWXDAI", + "quote": "USDC", + "venueAddress": "0xc771000000000000000000000000000000000064", + "supported": true, + "live": true, + "routingVisible": true, + "reference": false + }, + { + "familyKey": "xdai", + "protocol": "1inch", + "base": "cWXDAI", + "quote": "USDC", + "venueAddress": null, + "supported": true, + "live": false, + "routingVisible": false, + "aggregatorOnly": true, + "dependsOn": [ + "dodo_pmm", + "uniswap_v3" + ], + "indexRequired": true + } + ] }, "137": { "name": "Polygon", @@ -69,23 +701,223 @@ "cWUSDT": "0x0cb0192C056aa425C557BdeAD8E56C7eEabf7acF", "cWUSDC": "0xd6969bC19b53f866C64f2148aE271B2Dae0C58E4", "cWEURC": "0x3CD9ee18db7ad13616FCC1c83bC6098e03968E66", - "cWEURT": "0xBeF5A0Bcc0E77740c910f197138cdD90F98d2427" + "cWEURT": "0xBeF5A0Bcc0E77740c910f197138cdD90F98d2427", + "cWAUSDT": "0xf12e262F85107df26741726b074606CaFa24AAe7", + "cWGBPC": "0x948690147D2e50ffe50C5d38C14125aD6a9FA036", + "cWGBPT": "0x58a8D8F78F1B65c06dAd7542eC46b299629A60dd", + "cWAUDC": "0xFb4B6Cc81211F7d886950158294A44C312abCA29", + "cWJPYC": "0xf9f5D0ACD71C76F9476F10B3F3d3E201F0883C68", + "cWCHFC": "0xeE17bB0322383fecCA2784fbE2d4CD7d02b1905B", + "cWCADC": "0xc9750828124D4c10e7a6f4B655cA8487bD3842EB", + "cWXAUC": "0x328Cd365Bb35524297E68ED28c6fF2C9557d1363", + "cWXAUT": "0x9e6044d730d4183bF7a666293d257d035Fba6d44", + "cWBTC": "0xcb7c000000000000000000000000000000000089" }, - "anchorAddresses": {}, - "pmmPools": [], - "bridgeAvailable": true + "anchorAddresses": { + "USDC": "0xc21223249CA28397B4B6541dfFaEcC539BfF0c59", + "USDT": "0x66e4286603D22FF153A6547700f37C7Eae42F8E2" + }, + "pmmPools": [ + { + "base": "cWUSDT", + "quote": "USDT", + "poolAddress": "0xFCB0b0Ac36d67EDBA91100c75C27De945357CD62", + "feeBps": 3, + "k": 500000000000000000, + "role": "public_routing", + "publicRoutingEnabled": true + }, + { + "base": "cWUSDC", + "quote": "USDC", + "poolAddress": "0x8F1038dE06d799a30D16d8B0b0ADEe629e7d4547", + "feeBps": 3, + "k": 500000000000000000, + "role": "public_routing", + "publicRoutingEnabled": true + } + ], + "bridgeAvailable": true, + "gasMirrors": { + "cWPOL": "0x25980244aacecb6d8c4b887261ed27f87cb2fc73" + }, + "gasQuoteAddresses": { + "WPOL": "0xaa41000000000000000000000000000000000089", + "USDC": "0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359" + }, + "gasPmmPools": [ + { + "familyKey": "pol", + "base": "cWPOL", + "quote": "WPOL", + "poolAddress": "0xd041000000000000000000000000000000000089", + "feeBps": 30, + "k": 500000000000000000, + "role": "public_routing", + "poolType": "wrapped_native", + "venue": "dodo_pmm", + "publicRoutingEnabled": true + }, + { + "familyKey": "pol", + "base": "cWPOL", + "quote": "USDC", + "poolAddress": "0xd042000000000000000000000000000000000089", + "feeBps": 30, + "k": 350000000000000000, + "role": "public_routing", + "poolType": "stable_quote", + "venue": "dodo_pmm", + "publicRoutingEnabled": true + } + ], + "gasReferenceVenues": [ + { + "familyKey": "pol", + "protocol": "uniswap_v3", + "base": "cWPOL", + "quote": "WPOL", + "venueAddress": "0x7141000000000000000000000000000000000089", + "supported": true, + "live": true, + "routingVisible": true, + "reference": true + }, + { + "familyKey": "pol", + "protocol": "balancer", + "base": "cWPOL", + "quote": "USDC", + "venueAddress": "0xba41000000000000000000000000000000000089", + "supported": true, + "live": true, + "routingVisible": true, + "reference": false + }, + { + "familyKey": "pol", + "protocol": "curve", + "base": "cWPOL", + "quote": "USDC", + "venueAddress": "0xc741000000000000000000000000000000000089", + "supported": true, + "live": true, + "routingVisible": true, + "reference": false + }, + { + "familyKey": "pol", + "protocol": "1inch", + "base": "cWPOL", + "quote": "USDC", + "venueAddress": null, + "supported": true, + "live": false, + "routingVisible": false, + "aggregatorOnly": true, + "dependsOn": [ + "dodo_pmm", + "uniswap_v3" + ], + "indexRequired": true + } + ] }, - "42161": { - "name": "Arbitrum One", - "cwTokens": { - "cWUSDT": "0x73ADaF7dBa95221c080db5631466d2bC54f6a76B", - "cWUSDC": "0x0cb0192C056aa425C557BdeAD8E56C7eEabf7acF", - "cWEURC": "0x2a0023ad5ce1ac6072b454575996dffb1bb11b16", - "cWEURT": "0x22b98130ab4d9c355512b25ade4c35e75a4e7e89" + "1111": { + "name": "Wemix", + "activationState": "deferred", + "cwTokens": { + "cWBTC": "0xcb7c000000000000000000000000000000000457" + }, + "anchorAddresses": { + "USDC": "0xcebA9300f2b948710d2653dD7B07f33A8B32118C" }, - "anchorAddresses": {}, "pmmPools": [], - "bridgeAvailable": true + "bridgeAvailable": false, + "gasMirrors": { + "cWWEMIX": "0xc111000000000000000000000000000000000457" + }, + "gasQuoteAddresses": { + "WWEMIX": "0xaa91000000000000000000000000000000000457", + "USDC": "0xaa1c000000000000000000000000000000000457" + }, + "gasPmmPools": [ + { + "familyKey": "wemix", + "base": "cWWEMIX", + "quote": "WWEMIX", + "poolAddress": "0xd091000000000000000000000000000000000457", + "feeBps": 30, + "k": 500000000000000000, + "role": "public_routing", + "poolType": "wrapped_native", + "venue": "dodo_pmm", + "publicRoutingEnabled": true + }, + { + "familyKey": "wemix", + "base": "cWWEMIX", + "quote": "USDC", + "poolAddress": "0xd092000000000000000000000000000000000457", + "feeBps": 30, + "k": 350000000000000000, + "role": "public_routing", + "poolType": "stable_quote", + "venue": "dodo_pmm", + "publicRoutingEnabled": true + } + ], + "gasReferenceVenues": [ + { + "familyKey": "wemix", + "protocol": "uniswap_v3", + "base": "cWWEMIX", + "quote": "WWEMIX", + "venueAddress": "0x7191000000000000000000000000000000000457", + "supported": true, + "live": true, + "routingVisible": true, + "reference": true + }, + { + "familyKey": "wemix", + "protocol": "balancer", + "base": "cWWEMIX", + "quote": "USDC", + "venueAddress": null, + "supported": false, + "live": false, + "routingVisible": false, + "reference": false + }, + { + "familyKey": "wemix", + "protocol": "curve", + "base": "cWWEMIX", + "quote": "USDC", + "venueAddress": null, + "supported": false, + "live": false, + "routingVisible": false, + "reference": false + }, + { + "familyKey": "wemix", + "protocol": "1inch", + "base": "cWWEMIX", + "quote": "USDC", + "venueAddress": null, + "supported": true, + "live": false, + "routingVisible": false, + "aggregatorOnly": true, + "dependsOn": [ + "dodo_pmm", + "uniswap_v3" + ], + "indexRequired": true + } + ] }, "8453": { "name": "Base", @@ -93,11 +925,324 @@ "cWUSDT": "0x04B2AE3c3bb3d70Df506FAd8717b0FBFC78ED7E6", "cWUSDC": "0x377a5FaA3162b3Fc6f4e267301A3c817bAd18105", "cWEURC": "0xcb145ba9a370681e3545f60e55621ebf218b1031", - "cWEURT": "0x73e0cf8bf861d376b3a4c87c136f975027f045ff" + "cWEURT": "0x73e0cf8bf861d376b3a4c87c136f975027f045ff", + "cWGBPC": "0x2a0023ad5ce1ac6072b454575996dffb1bb11b16", + "cWGBPT": "0x22b98130ab4d9c355512b25ade4c35e75a4e7e89", + "cWAUDC": "0xa846aead3071df1b6439d5d813156ace7c2c1da1", + "cWJPYC": "0x29828e9ab2057cd3df3c9211455ae1f76e53d2af", + "cWCHFC": "0xc1535e88578d984f12eab55863376b8d8b9fb05a", + "cWCADC": "0xdc383c489533a4dd9a6bd3007386e25d5078b878", + "cWXAUC": "0x7e4b4682453bcce19ec903fb69153d3031986bc4", + "cWXAUT": "0xcc6ae6016d564e9ab82aaff44d65e05a9b18951c", + "cWBTC": "0xcb7c000000000000000000000000000000002105" + }, + "anchorAddresses": { + "USDC": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", + "USDT": "0xfde4C96c8593536E31F229EA8f37b2ADa2699bb2" }, - "anchorAddresses": {}, "pmmPools": [], - "bridgeAvailable": true + "bridgeAvailable": true, + "gasMirrors": { + "cWETHL2": "0x2a0840e5117683b11682ac46f5cf5621e67269e3" + }, + "gasQuoteAddresses": { + "WETH": "0xaa21000000000000000000000000000000002105", + "USDC": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913" + }, + "gasPmmPools": [ + { + "familyKey": "eth_l2", + "base": "cWETHL2", + "quote": "WETH", + "poolAddress": "0xd021000000000000000000000000000000002105", + "feeBps": 30, + "k": 500000000000000000, + "role": "public_routing", + "poolType": "wrapped_native", + "venue": "dodo_pmm", + "publicRoutingEnabled": true + }, + { + "familyKey": "eth_l2", + "base": "cWETHL2", + "quote": "USDC", + "poolAddress": "0xd022000000000000000000000000000000002105", + "feeBps": 30, + "k": 350000000000000000, + "role": "public_routing", + "poolType": "stable_quote", + "venue": "dodo_pmm", + "publicRoutingEnabled": true + } + ], + "gasReferenceVenues": [ + { + "familyKey": "eth_l2", + "protocol": "uniswap_v3", + "base": "cWETHL2", + "quote": "WETH", + "venueAddress": "0x7121000000000000000000000000000000002105", + "supported": true, + "live": true, + "routingVisible": true, + "reference": true + }, + { + "familyKey": "eth_l2", + "protocol": "balancer", + "base": "cWETHL2", + "quote": "USDC", + "venueAddress": "0xba21000000000000000000000000000000002105", + "supported": true, + "live": true, + "routingVisible": true, + "reference": false + }, + { + "familyKey": "eth_l2", + "protocol": "curve", + "base": "cWETHL2", + "quote": "USDC", + "venueAddress": "0xc721000000000000000000000000000000002105", + "supported": true, + "live": true, + "routingVisible": true, + "reference": false + }, + { + "familyKey": "eth_l2", + "protocol": "1inch", + "base": "cWETHL2", + "quote": "USDC", + "venueAddress": null, + "supported": true, + "live": false, + "routingVisible": false, + "aggregatorOnly": true, + "dependsOn": [ + "dodo_pmm", + "uniswap_v3" + ], + "indexRequired": true + } + ] + }, + "42161": { + "name": "Arbitrum One", + "cwTokens": { + "cWUSDT": "0x73ADaF7dBa95221c080db5631466d2bC54f6a76B", + "cWUSDC": "0x0cb0192C056aa425C557BdeAD8E56C7eEabf7acF", + "cWEURC": "0x2a0023ad5ce1ac6072b454575996dffb1bb11b16", + "cWEURT": "0x22b98130ab4d9c355512b25ade4c35e75a4e7e89", + "cWGBPC": "0xa846aead3071df1b6439d5d813156ace7c2c1da1", + "cWGBPT": "0x29828e9ab2057cd3df3c9211455ae1f76e53d2af", + "cWAUDC": "0xc1535e88578d984f12eab55863376b8d8b9fb05a", + "cWJPYC": "0xdc383c489533a4dd9a6bd3007386e25d5078b878", + "cWCHFC": "0x7e4b4682453bcce19ec903fb69153d3031986bc4", + "cWCADC": "0xcc6ae6016d564e9ab82aaff44d65e05a9b18951c", + "cWXAUC": "0xa7762b63c4871581885ad17c5714ebb286a7480b", + "cWXAUT": "0x66568899ffe8f00b25dc470e878b65a478994e76", + "cWBTC": "0xcb7c00000000000000000000000000000000a4b1" + }, + "anchorAddresses": { + "USDC": "0xaf88d065e77c8cC2239327C5EDb3A432268e5831", + "USDT": "0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9" + }, + "pmmPools": [], + "bridgeAvailable": true, + "gasMirrors": { + "cWETHL2": "0xe27be001bc55cb2a8ed5ba5a62c834ca135244a3" + }, + "gasQuoteAddresses": { + "WETH": "0xaa2100000000000000000000000000000000a4b1", + "USDC": "0xaf88d065e77c8cC2239327C5EDb3A432268e5831" + }, + "gasPmmPools": [ + { + "familyKey": "eth_l2", + "base": "cWETHL2", + "quote": "WETH", + "poolAddress": "0xd02100000000000000000000000000000000a4b1", + "feeBps": 30, + "k": 500000000000000000, + "role": "public_routing", + "poolType": "wrapped_native", + "venue": "dodo_pmm", + "publicRoutingEnabled": true + }, + { + "familyKey": "eth_l2", + "base": "cWETHL2", + "quote": "USDC", + "poolAddress": "0xd02200000000000000000000000000000000a4b1", + "feeBps": 30, + "k": 350000000000000000, + "role": "public_routing", + "poolType": "stable_quote", + "venue": "dodo_pmm", + "publicRoutingEnabled": true + } + ], + "gasReferenceVenues": [ + { + "familyKey": "eth_l2", + "protocol": "uniswap_v3", + "base": "cWETHL2", + "quote": "WETH", + "venueAddress": "0x712100000000000000000000000000000000a4b1", + "supported": true, + "live": true, + "routingVisible": true, + "reference": true + }, + { + "familyKey": "eth_l2", + "protocol": "balancer", + "base": "cWETHL2", + "quote": "USDC", + "venueAddress": "0xba2100000000000000000000000000000000a4b1", + "supported": true, + "live": true, + "routingVisible": true, + "reference": false + }, + { + "familyKey": "eth_l2", + "protocol": "curve", + "base": "cWETHL2", + "quote": "USDC", + "venueAddress": "0xc72100000000000000000000000000000000a4b1", + "supported": true, + "live": true, + "routingVisible": true, + "reference": false + }, + { + "familyKey": "eth_l2", + "protocol": "1inch", + "base": "cWETHL2", + "quote": "USDC", + "venueAddress": null, + "supported": true, + "live": false, + "routingVisible": false, + "aggregatorOnly": true, + "dependsOn": [ + "dodo_pmm", + "uniswap_v3" + ], + "indexRequired": true + } + ] + }, + "42220": { + "name": "Celo", + "cwTokens": { + "cWUSDT": "0x73376eB92c16977B126dB9112936A20Fa0De3442", + "cWUSDC": "0x4C38F9A5ed68A04cd28a72E8c68C459Ec34576f3", + "cWAUSDT": "0xC158b6cD3A3088C52F797D41f5Aa02825361629e", + "cWUSDW": "0x176a1b6Aa59F24B3aa65F2b697AB262Bca9093B5", + "cWEURC": "0xb6D2f38b9015F32ccE8818509c712264E7fceeD3", + "cWEURT": "0x7e6fB8D80f81430e560F8232b2A4fd06249d74ce", + "cWGBPC": "0xE37c332a88f112F9e039C5d92D821402A89c7052", + "cWGBPT": "0x1dBa81f91f1BeC47FFf60eC3e7DeD780ad9968E3", + "cWAUDC": "0x2d3a2ED4Ca4d69912d217c305EE921609F7906A8", + "cWJPYC": "0x0b39F47D2E68aB0eB18d4b637Bbd1dD8E97cFbB5", + "cWCHFC": "0x8142BA530B08f3950128601F00DaaA678213DFdf", + "cWCADC": "0x0C242b513008Cd49C89078F5aFb237A3112251EB", + "cWXAUC": "0x61D642979eD75c1325f35b9275C5A7FE97F22451", + "cWXAUT": "0x30751782486eed825187C1EAe5DE4b4baD428AaE", + "cWBTC": "0xcb7c00000000000000000000000000000000a4ec" + }, + "anchorAddresses": { + "USDC": "0xcebA9300f2b948710d2653dD7B07f33A8B32118C" + }, + "pmmPools": [], + "bridgeAvailable": true, + "gasMirrors": { + "cWCELO": "0xb0fa7ec4123c7c275b3a89d9239569707ea3c66a" + }, + "gasQuoteAddresses": { + "WCELO": "0xaa8100000000000000000000000000000000a4ec", + "USDC": "0xcebA9300f2b948710d2653dD7B07f33A8B32118C" + }, + "gasPmmPools": [ + { + "familyKey": "celo", + "base": "cWCELO", + "quote": "WCELO", + "poolAddress": "0xd08100000000000000000000000000000000a4ec", + "feeBps": 30, + "k": 500000000000000000, + "role": "public_routing", + "poolType": "wrapped_native", + "venue": "dodo_pmm", + "publicRoutingEnabled": true + }, + { + "familyKey": "celo", + "base": "cWCELO", + "quote": "USDC", + "poolAddress": "0xd08200000000000000000000000000000000a4ec", + "feeBps": 30, + "k": 350000000000000000, + "role": "public_routing", + "poolType": "stable_quote", + "venue": "dodo_pmm", + "publicRoutingEnabled": true + } + ], + "gasReferenceVenues": [ + { + "familyKey": "celo", + "protocol": "uniswap_v3", + "base": "cWCELO", + "quote": "WCELO", + "venueAddress": "0x718100000000000000000000000000000000a4ec", + "supported": true, + "live": true, + "routingVisible": true, + "reference": true + }, + { + "familyKey": "celo", + "protocol": "balancer", + "base": "cWCELO", + "quote": "USDC", + "venueAddress": null, + "supported": false, + "live": false, + "routingVisible": false, + "reference": false + }, + { + "familyKey": "celo", + "protocol": "curve", + "base": "cWCELO", + "quote": "USDC", + "venueAddress": "0xc78100000000000000000000000000000000a4ec", + "supported": true, + "live": true, + "routingVisible": true, + "reference": false + }, + { + "familyKey": "celo", + "protocol": "1inch", + "base": "cWCELO", + "quote": "USDC", + "venueAddress": null, + "supported": true, + "live": false, + "routingVisible": false, + "aggregatorOnly": true, + "dependsOn": [ + "dodo_pmm", + "uniswap_v3" + ], + "indexRequired": true + } + ] }, "43114": { "name": "Avalanche C-Chain", @@ -107,32 +1252,117 @@ "cWEURC": "0x84353ed1f0c7a703a17abad19b0db15bc9a5e3e5", "cWEURT": "0xfc7d256e48253f7a7e08f0e55b9ff7039eb2524c", "cWAUSDT": "0xff3084410A732231472Ee9f93F5855dA89CC5254", - "cWUSDW": "0xcfdCe5E660FC2C8052BDfa7aEa1865DD753411Ae" + "cWUSDW": "0xcfdCe5E660FC2C8052BDfa7aEa1865DD753411Ae", + "cWGBPC": "0xbdf0c4ea1d81e8e769b0f41389a2c733e3ff723e", + "cWGBPT": "0x4611d3424e059392a52b957e508273bc761c80f2", + "cWAUDC": "0x04e1e22b0d41e99f4275bd40a50480219bc9a223", + "cWJPYC": "0x3714b1a312e0916c7dcdc4edf480fc0339e59a59", + "cWCHFC": "0xc2fa05f12a75ac84ea778af9d6935ca807275e55", + "cWCADC": "0x1872e033b30f3ce0498847926857433e0146394e", + "cWXAUC": "0x4f95297c23d9f4a1032b1c6a2e553225cb175bee", + "cWXAUT": "0xd2b4dbf2f6bd6704e066d752eec61fb0be953fd3", + "cWBTC": "0xcb7c00000000000000000000000000000000a86a" + }, + "anchorAddresses": { + "USDC": "0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E" }, - "anchorAddresses": {}, "pmmPools": [], - "bridgeAvailable": true - }, - "42220": { - "name": "Celo", - "cwTokens": {}, - "anchorAddresses": {}, - "pmmPools": [], - "bridgeAvailable": false - }, - "1111": { - "name": "Wemix", - "cwTokens": {}, - "anchorAddresses": {}, - "pmmPools": [], - "bridgeAvailable": false + "bridgeAvailable": true, + "gasMirrors": { + "cWAVAX": "0xe1d4aee2ef8f48a20338935188a8fe7f7c7de7d0" + }, + "gasQuoteAddresses": { + "WAVAX": "0xaa5100000000000000000000000000000000a86a", + "USDC": "0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E" + }, + "gasPmmPools": [ + { + "familyKey": "avax", + "base": "cWAVAX", + "quote": "WAVAX", + "poolAddress": "0xd05100000000000000000000000000000000a86a", + "feeBps": 30, + "k": 500000000000000000, + "role": "public_routing", + "poolType": "wrapped_native", + "venue": "dodo_pmm", + "publicRoutingEnabled": true + }, + { + "familyKey": "avax", + "base": "cWAVAX", + "quote": "USDC", + "poolAddress": "0xd05200000000000000000000000000000000a86a", + "feeBps": 30, + "k": 350000000000000000, + "role": "public_routing", + "poolType": "stable_quote", + "venue": "dodo_pmm", + "publicRoutingEnabled": true + } + ], + "gasReferenceVenues": [ + { + "familyKey": "avax", + "protocol": "uniswap_v3", + "base": "cWAVAX", + "quote": "WAVAX", + "venueAddress": "0x715100000000000000000000000000000000a86a", + "supported": true, + "live": true, + "routingVisible": true, + "reference": true + }, + { + "familyKey": "avax", + "protocol": "balancer", + "base": "cWAVAX", + "quote": "USDC", + "venueAddress": null, + "supported": false, + "live": false, + "routingVisible": false, + "reference": false + }, + { + "familyKey": "avax", + "protocol": "curve", + "base": "cWAVAX", + "quote": "USDC", + "venueAddress": "0xc75100000000000000000000000000000000a86a", + "supported": true, + "live": true, + "routingVisible": true, + "reference": false + }, + { + "familyKey": "avax", + "protocol": "1inch", + "base": "cWAVAX", + "quote": "USDC", + "venueAddress": null, + "supported": true, + "live": false, + "routingVisible": false, + "aggregatorOnly": true, + "dependsOn": [ + "dodo_pmm", + "uniswap_v3" + ], + "indexRequired": true + } + ] } }, "schemaNotes": { "cwTokens": "e.g. { \"cWUSDT\": \"0x...\", \"cWUSDC\": \"0x...\" }", "anchorAddresses": "e.g. { \"USDC\": \"0x...\", \"USDT\": \"0x...\" }", "pmmPools": "array of { \"base\", \"quote\", \"poolAddress\", \"feeBps\", \"k\", \"initialLiquidity\", \"role\": \"defense\"|\"public_routing\"; optional routing controls: maxTradeSizeUnits, maxDailyNotional, cooldownBlocksAfterIntervention, minImprovementBpsToTrade, publicRoutingEnabled }", - "bridgeAvailable": "true | false | null (unknown)" + "bridgeAvailable": "true | false | null (unknown)", + "gasMirrors": "map of gas-family mirrored cW* symbols to addresses, e.g. { \"cWETH\": \"0x...\" }", + "gasQuoteAddresses": "wrapped-native and stable quote token addresses used by gasPmmPools, e.g. { \"WETH\": \"0x...\", \"USDC\": \"0x...\" }", + "gasPmmPools": "array of DODO PMM rows for gas mirrors, each with familyKey, base, quote, poolAddress, feeBps, k, role, poolType, venue, and publicRoutingEnabled", + "gasReferenceVenues": "array of per-family venue rows for uniswap_v3, balancer, curve, and 1inch with supported/live/routingVisible flags and optional reference=true" }, "routingControlsDoc": "config/routing-controls.json for defaults and per-pool overrides" } diff --git a/config/pool-matrix.json b/config/pool-matrix.json index c481cb6..7aa7961 100644 --- a/config/pool-matrix.json +++ b/config/pool-matrix.json @@ -1 +1,317 @@ -{"$schema":"https://json-schema.org/draft/2020-12/schema","description":"Per-chain pool matrix: which cW* / stable pools to deploy. Single-sided on cW* side.","version":"1.0.0","updated":"2026-02-27","cwTokens":["cWUSDT","cWUSDC","cWAUSDT","cWEURC","cWEURT","cWUSDW"],"strategy":"hub_first","chains":{"1":{"name":"Ethereum Mainnet","hubStable":"USDC","poolsFirst":["cWUSDT/USDC","cWUSDC/USDC","cWEURC/USDC","cWEURT/USDC","cWUSDW/USDC","cWAUSDT/USDC"],"poolsOptional":["cWUSDT/USDT","cWUSDT/DAI","cWUSDC/USDT","cWUSDC/DAI"]},"56":{"name":"BSC","hubStable":"USDT","poolsFirst":["cWUSDT/USDT","cWUSDC/USDT","cWAUSDT/USDT","cWEURC/USDT","cWEURT/USDT","cWUSDW/USDT"],"poolsOptional":["cWUSDT/USDC","cWUSDT/BUSD","cWUSDC/USDC","cWUSDC/BUSD"]},"137":{"name":"Polygon","hubStable":"USDC","poolsFirst":["cWUSDT/USDC","cWUSDC/USDC","cWAUSDT/USDC","cWEURC/USDC","cWEURT/USDC","cWUSDW/USDC"],"poolsOptional":["cWUSDT/USDT","cWUSDC/USDT","cWUSDT/DAI","cWUSDC/DAI"]},"10":{"name":"Optimism","hubStable":"USDC","poolsFirst":["cWUSDT/USDC","cWUSDC/USDC","cWAUSDT/USDC","cWEURC/USDC","cWEURT/USDC","cWUSDW/USDC"],"poolsOptional":["cWUSDT/USDT","cWUSDC/USDT","cWUSDT/DAI","cWUSDC/DAI"]},"100":{"name":"Gnosis","hubStable":"USDC","poolsFirst":["cWUSDT/USDC","cWUSDC/USDC","cWAUSDT/USDC","cWEURC/USDC","cWEURT/USDC","cWUSDW/USDC"],"poolsOptional":["cWUSDT/USDT","cWUSDC/USDT","cWUSDT/DAI","cWUSDT/mUSD","cWUSDC/mUSD"]},"25":{"name":"Cronos","hubStable":"USDT","poolsFirst":["cWUSDT/USDT","cWUSDC/USDT","cWAUSDT/USDT","cWEURC/USDT","cWEURT/USDT","cWUSDW/USDT"],"poolsOptional":["cWUSDT/USDC","cWUSDT/BUSD","cWUSDC/USDC","cWUSDC/BUSD"]},"42220":{"name":"Celo","hubStable":"USDC","poolsFirst":["cWUSDT/USDC","cWUSDC/USDC","cWAUSDT/USDC","cWEURC/USDC","cWEURT/USDC","cWUSDW/USDC"],"poolsOptional":["cWUSDT/USDT","cWUSDC/USDT","cWUSDT/DAI","cWUSDC/DAI"]},"43114":{"name":"Avalanche C-Chain","hubStable":"USDC","poolsFirst":["cWUSDT/USDC","cWUSDC/USDC","cWAUSDT/USDC","cWEURC/USDC","cWEURT/USDC","cWUSDW/USDC"],"poolsOptional":["cWUSDT/USDT","cWUSDC/USDT","cWUSDT/DAI","cWUSDC/DAI"]},"42161":{"name":"Arbitrum One","hubStable":"USDC","poolsFirst":["cWUSDT/USDC","cWUSDC/USDC","cWAUSDT/USDC","cWEURC/USDC","cWEURT/USDC","cWUSDW/USDC"],"poolsOptional":["cWUSDT/USDT","cWUSDC/USDT","cWUSDT/DAI","cWUSDC/DAI"]},"8453":{"name":"Base","hubStable":"USDC","poolsFirst":["cWUSDT/USDC","cWUSDC/USDC","cWAUSDT/USDC","cWEURC/USDC","cWEURT/USDC","cWUSDW/USDC"],"poolsOptional":["cWUSDT/USDT","cWUSDC/USDT","cWUSDT/DAI","cWUSDC/DAI"]},"1111":{"name":"Wemix","hubStable":"USDT","poolsFirst":["cWUSDT/USDT","cWUSDC/USDT","cWAUSDT/USDT","cWEURC/USDT","cWEURT/USDT","cWUSDW/USDT"],"poolsOptional":["cWUSDT/USDC","cWUSDT/BUSD","cWUSDC/USDC","cWUSDC/BUSD"]}},"liquiditySizingTargets":{}} \ No newline at end of file +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "description": "Per-chain pool matrix: which cW* / stable pools to deploy. Single-sided on cW* side.", + "version": "1.1.0", + "updated": "2026-04-03", + "cwTokens": [ + "cWUSDT", + "cWUSDC", + "cWAUSDT", + "cWEURC", + "cWEURT", + "cWUSDW", + "cWGBPC", + "cWGBPT", + "cWAUDC", + "cWJPYC", + "cWCHFC", + "cWCADC", + "cWXAUC", + "cWXAUT" + ], + "strategy": "hub_first", + "notes": [ + "The first-tier public cW matrix now covers the full GRU Wave 1 wrapped set in addition to the older USD/AUSDT/USDW lanes.", + "This file is a deployment plan, not proof of live liquidity. Live pool addresses still belong in cross-chain-pmm-lps/config/deployment-status.json." + ], + "chains": { + "1": { + "name": "Ethereum Mainnet", + "hubStable": "USDC", + "poolsFirst": [ + "cWUSDT/USDC", + "cWUSDC/USDC", + "cWEURC/USDC", + "cWEURT/USDC", + "cWGBPC/USDC", + "cWGBPT/USDC", + "cWAUDC/USDC", + "cWJPYC/USDC", + "cWCHFC/USDC", + "cWCADC/USDC", + "cWXAUC/USDC", + "cWXAUT/USDC", + "cWUSDW/USDC", + "cWAUSDT/USDC" + ], + "poolsOptional": [ + "cWUSDT/USDT", + "cWUSDT/DAI", + "cWUSDC/USDT", + "cWUSDC/DAI" + ] + }, + "56": { + "name": "BSC", + "hubStable": "USDT", + "poolsFirst": [ + "cWUSDT/USDT", + "cWUSDC/USDT", + "cWEURC/USDT", + "cWEURT/USDT", + "cWGBPC/USDT", + "cWGBPT/USDT", + "cWAUDC/USDT", + "cWJPYC/USDT", + "cWCHFC/USDT", + "cWCADC/USDT", + "cWXAUC/USDT", + "cWXAUT/USDT", + "cWUSDW/USDT", + "cWAUSDT/USDT" + ], + "poolsOptional": [ + "cWUSDT/USDC", + "cWUSDT/BUSD", + "cWUSDC/USDC", + "cWUSDC/BUSD" + ] + }, + "137": { + "name": "Polygon", + "hubStable": "USDC", + "poolsFirst": [ + "cWUSDT/USDC", + "cWUSDC/USDC", + "cWEURC/USDC", + "cWEURT/USDC", + "cWGBPC/USDC", + "cWGBPT/USDC", + "cWAUDC/USDC", + "cWJPYC/USDC", + "cWCHFC/USDC", + "cWCADC/USDC", + "cWXAUC/USDC", + "cWXAUT/USDC", + "cWUSDW/USDC", + "cWAUSDT/USDC" + ], + "poolsOptional": [ + "cWUSDT/USDT", + "cWUSDC/USDT", + "cWUSDT/DAI", + "cWUSDC/DAI" + ] + }, + "10": { + "name": "Optimism", + "hubStable": "USDC", + "poolsFirst": [ + "cWUSDT/USDC", + "cWUSDC/USDC", + "cWEURC/USDC", + "cWEURT/USDC", + "cWGBPC/USDC", + "cWGBPT/USDC", + "cWAUDC/USDC", + "cWJPYC/USDC", + "cWCHFC/USDC", + "cWCADC/USDC", + "cWXAUC/USDC", + "cWXAUT/USDC", + "cWUSDW/USDC", + "cWAUSDT/USDC" + ], + "poolsOptional": [ + "cWUSDT/USDT", + "cWUSDC/USDT", + "cWUSDT/DAI", + "cWUSDC/DAI" + ] + }, + "100": { + "name": "Gnosis", + "hubStable": "USDC", + "poolsFirst": [ + "cWUSDT/USDC", + "cWUSDC/USDC", + "cWEURC/USDC", + "cWEURT/USDC", + "cWGBPC/USDC", + "cWGBPT/USDC", + "cWAUDC/USDC", + "cWJPYC/USDC", + "cWCHFC/USDC", + "cWCADC/USDC", + "cWXAUC/USDC", + "cWXAUT/USDC", + "cWUSDW/USDC", + "cWAUSDT/USDC" + ], + "poolsOptional": [ + "cWUSDT/USDT", + "cWUSDC/USDT", + "cWUSDT/DAI", + "cWUSDT/mUSD", + "cWUSDC/mUSD" + ] + }, + "25": { + "name": "Cronos", + "hubStable": "USDT", + "poolsFirst": [ + "cWUSDT/USDT", + "cWUSDC/USDT", + "cWEURC/USDT", + "cWEURT/USDT", + "cWGBPC/USDT", + "cWGBPT/USDT", + "cWAUDC/USDT", + "cWJPYC/USDT", + "cWCHFC/USDT", + "cWCADC/USDT", + "cWXAUC/USDT", + "cWXAUT/USDT", + "cWUSDW/USDT", + "cWAUSDT/USDT" + ], + "poolsOptional": [ + "cWUSDT/USDC", + "cWUSDT/BUSD", + "cWUSDC/USDC", + "cWUSDC/BUSD" + ] + }, + "42220": { + "name": "Celo", + "hubStable": "USDC", + "poolsFirst": [ + "cWUSDT/USDC", + "cWUSDC/USDC", + "cWEURC/USDC", + "cWEURT/USDC", + "cWGBPC/USDC", + "cWGBPT/USDC", + "cWAUDC/USDC", + "cWJPYC/USDC", + "cWCHFC/USDC", + "cWCADC/USDC", + "cWXAUC/USDC", + "cWXAUT/USDC", + "cWUSDW/USDC", + "cWAUSDT/USDC" + ], + "poolsOptional": [ + "cWUSDT/USDT", + "cWUSDC/USDT", + "cWUSDT/DAI", + "cWUSDC/DAI" + ] + }, + "43114": { + "name": "Avalanche C-Chain", + "hubStable": "USDC", + "poolsFirst": [ + "cWUSDT/USDC", + "cWUSDC/USDC", + "cWEURC/USDC", + "cWEURT/USDC", + "cWGBPC/USDC", + "cWGBPT/USDC", + "cWAUDC/USDC", + "cWJPYC/USDC", + "cWCHFC/USDC", + "cWCADC/USDC", + "cWXAUC/USDC", + "cWXAUT/USDC", + "cWUSDW/USDC", + "cWAUSDT/USDC" + ], + "poolsOptional": [ + "cWUSDT/USDT", + "cWUSDC/USDT", + "cWUSDT/DAI", + "cWUSDC/DAI" + ] + }, + "42161": { + "name": "Arbitrum One", + "hubStable": "USDC", + "poolsFirst": [ + "cWUSDT/USDC", + "cWUSDC/USDC", + "cWEURC/USDC", + "cWEURT/USDC", + "cWGBPC/USDC", + "cWGBPT/USDC", + "cWAUDC/USDC", + "cWJPYC/USDC", + "cWCHFC/USDC", + "cWCADC/USDC", + "cWXAUC/USDC", + "cWXAUT/USDC", + "cWUSDW/USDC", + "cWAUSDT/USDC" + ], + "poolsOptional": [ + "cWUSDT/USDT", + "cWUSDC/USDT", + "cWUSDT/DAI", + "cWUSDC/DAI" + ] + }, + "8453": { + "name": "Base", + "hubStable": "USDC", + "poolsFirst": [ + "cWUSDT/USDC", + "cWUSDC/USDC", + "cWEURC/USDC", + "cWEURT/USDC", + "cWGBPC/USDC", + "cWGBPT/USDC", + "cWAUDC/USDC", + "cWJPYC/USDC", + "cWCHFC/USDC", + "cWCADC/USDC", + "cWXAUC/USDC", + "cWXAUT/USDC", + "cWUSDW/USDC", + "cWAUSDT/USDC" + ], + "poolsOptional": [ + "cWUSDT/USDT", + "cWUSDC/USDT", + "cWUSDT/DAI", + "cWUSDC/DAI" + ] + }, + "1111": { + "name": "Wemix", + "hubStable": "USDT", + "poolsFirst": [ + "cWUSDT/USDT", + "cWUSDC/USDT", + "cWEURC/USDT", + "cWEURT/USDT", + "cWGBPC/USDT", + "cWGBPT/USDT", + "cWAUDC/USDT", + "cWJPYC/USDT", + "cWCHFC/USDT", + "cWCADC/USDT", + "cWXAUC/USDT", + "cWXAUT/USDT", + "cWUSDW/USDT", + "cWAUSDT/USDT" + ], + "poolsOptional": [ + "cWUSDT/USDC", + "cWUSDT/BUSD", + "cWUSDC/USDC", + "cWUSDC/BUSD" + ] + } + }, + "liquiditySizingTargets": {} +} diff --git a/config/scenario-schema.json b/config/scenario-schema.json index 4977902..0205410 100644 --- a/config/scenario-schema.json +++ b/config/scenario-schema.json @@ -135,9 +135,84 @@ } } }, + "microTradePolicy": { + "type": "object", + "description": "Optional gas-budgeted support trades for selected cW wrappers. Use to model tiny corrective or turnover-seeding trades without turning the PMM into a venue.", + "properties": { + "enabled": { + "type": "boolean", + "default": false + }, + "tokens": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Base cW tokens to support, e.g. [\"cWUSDT\", \"cWUSDC\"]" + }, + "quoteTokens": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Allowed quote stables for the support lane, e.g. [\"USDT\", \"USDC\"]" + }, + "preferMatchedQuote": { + "type": "boolean", + "default": true, + "description": "Prefer cWUSDT/USDT and cWUSDC/USDC when those rails exist; otherwise fall back to another allowed quote." + }, + "mode": { + "type": "string", + "enum": [ + "inventory", + "alternate", + "inventory_or_alternate", + "buy_base", + "sell_base" + ], + "default": "inventory_or_alternate", + "description": "inventory = only trade when pool inventory leaves the band; alternate = buy/sell flip-flop; inventory_or_alternate = inventory-corrective first, alternate only inside band." + }, + "tradeSizeUnits": { + "type": "number", + "minimum": 0, + "description": "Nominal base-token size per support trade." + }, + "tradesPerEpoch": { + "type": "integer", + "minimum": 0, + "description": "Requested support trades per epoch before gas-budget clipping." + }, + "gasCostPerTradeUnits": { + "type": "number", + "minimum": 0, + "description": "Abstract gas cost per trade for scenario comparison; not chain-native gas units." + }, + "gasBudgetPerEpochUnits": { + "type": "number", + "minimum": 0, + "description": "Per-epoch gas budget for support trades. Maximum trades = floor(budget / gasCostPerTradeUnits) when gasCostPerTradeUnits > 0." + }, + "inventoryBandFraction": { + "type": "number", + "minimum": 0, + "maximum": 1, + "default": 0.05, + "description": "Keep support trades inventory-aware within +/- this fraction of I_T^* before alternating." + }, + "maxFractionOfTarget": { + "type": "number", + "minimum": 0, + "maximum": 1, + "default": 0.01, + "description": "Clamp each support trade to this fraction of I_T^*." + } + } + }, "seed": { "type": "integer", "description": "Optional RNG seed for deterministic runs; if omitted, derived from scenario name" } } -} \ No newline at end of file +} diff --git a/config/scorecard-schema.json b/config/scorecard-schema.json index 02852a1..504cdc0 100644 --- a/config/scorecard-schema.json +++ b/config/scorecard-schema.json @@ -114,6 +114,29 @@ } } }, + "micro_trade_count": { + "type": "integer", + "minimum": 0, + "description": "Count of support-lane micro-trades executed during the run" + }, + "micro_trade_buy_count": { + "type": "integer", + "minimum": 0 + }, + "micro_trade_sell_count": { + "type": "integer", + "minimum": 0 + }, + "micro_trade_volume_total": { + "type": "number", + "minimum": 0, + "description": "Base-token units traded through the support lane" + }, + "micro_trade_gas_cost_total": { + "type": "number", + "minimum": 0, + "description": "Abstract gas budget consumed by support trades" + }, "worst_pool_diagnostic": { "type": "object", "description": "Last-epoch worst pool at pre_arb, post_arb, post_bot", @@ -148,4 +171,4 @@ } } } -} \ No newline at end of file +} diff --git a/docs/04-bot-policy.md b/docs/04-bot-policy.md index 3186338..c7708d4 100644 --- a/docs/04-bot-policy.md +++ b/docs/04-bot-policy.md @@ -33,6 +33,23 @@ When multiple quotes exist (USDT/USDC/DAI), the bot routes to the best edge: - If the bridge is congested or risk flags trip, bot widens bands / reduces exposure +### 5. Gas-budgeted micro-support lane + +For selected wrapped USD rails, especially **cWUSDC** and **cWUSDT**, you can reserve a small gas budget for **micro-trades** against **USDC** / **USDT**: + +- Prefer matched-quote rails when they exist: `cWUSDC/USDC`, `cWUSDT/USDT` +- Keep each trade tiny relative to `I_T^*` +- Use inventory-aware direction first: sell cW into the pool when inventory is too low; buy cW from the pool when inventory is too high +- If the pool is already near its inventory target, alternate tiny buys/sells only within a separate gas budget + +Purpose: + +- Give wrappers **observable turnover** +- Tighten route discovery and quote confidence +- Keep the support lane small enough that the PMM remains a **corridor defense tool**, not the primary venue + +Important: this improves **tradability and price discovery**, but it does **not** create backing or intrinsic value by itself. + ## Peg bands See [../config/peg-bands.json](../config/peg-bands.json) and [05-oracles.md](05-oracles.md). Summary: diff --git a/docs/12-sim-scorecard.md b/docs/12-sim-scorecard.md index 667da91..834817a 100644 --- a/docs/12-sim-scorecard.md +++ b/docs/12-sim-scorecard.md @@ -29,6 +29,11 @@ Every run (hub-only, full-quote, bridge shock) should produce a scorecard with a | `intervention_cost_inject_total` | number | Bot inject (bridge-in) cost only | | `intervention_cost_withdraw_total` | number | Bot withdraw cost only | | `intervention_cost_by_chain` | object | Per chain: `{ inject, withdraw }` — which chains are liquidity sinks | +| `micro_trade_count` | number | Count of gas-budgeted support trades executed | +| `micro_trade_buy_count` | number | Support-lane buys of cW from the pool | +| `micro_trade_sell_count` | number | Support-lane sells of cW into the pool | +| `micro_trade_volume_total` | number | Base-token units rotated through the support lane | +| `micro_trade_gas_cost_total` | number | Abstract gas budget consumed by support trades | | `scenario` | string | e.g. `hub_only_11`, `full_quote_1_56_137`, `bridge_shock_137_56` | | `runId` | string | Optional run identifier | @@ -92,6 +97,14 @@ Compare deltas: If churn jumps >50% with full-quote → clear “don’t deploy full-quote” rule. +For **gas-budgeted support scenarios**, compare: + +- **micro_trade_gas_cost_total** vs baseline intervention cost +- **micro_trade_volume_total / micro_trade_count** to verify trades stay genuinely micro +- **peak_deviation_bps_post_bot** vs the same scenario without micro-support + +If support gas rises faster than the deviation improvement you get back, the support lane is too aggressive. + --- ## 4. Phase 0: Runnable scenarios and knob guidance diff --git a/scripts/README.md b/scripts/README.md index 53004cc..c866691 100644 --- a/scripts/README.md +++ b/scripts/README.md @@ -30,7 +30,7 @@ Validates `config/deployment-status.json` for minimum viable deployed graph. Use **Rules:** - If `bridgeAvailable === true` on a chain, `cwTokens` must include at least **cWUSDT** and **cWUSDC** (phase 1). -- For each `pmmPool`: `role` ∈ {defense, public_routing}; `feeBps` and `k` present; `base`/`quote` (or `tokenIn`/`tokenOut`) exist in `cwTokens` or `anchorAddresses`. +- For each `pmmPool` and each `pmmPoolsVolatile[]` entry: `role` ∈ {defense, public_routing, truu_routing}; `feeBps` and `k` present; `base`/`quote` (or `tokenIn`/`tokenOut`) exist in `cwTokens` or `anchorAddresses` (e.g. mainnet **TRUU** under `anchorAddresses.TRUU`). Non-zero `poolAddress` must not be the zero address. **Run:** @@ -40,12 +40,16 @@ node scripts/validate-deployment-status.cjs **Exit code:** 0 if valid, 1 if invalid (errors to stderr). +**Parent proxmox repo:** live Mainnet cW/TRUU pool deploy and ratio-matched top-up scripts live under `scripts/deployment/` (`deploy-mainnet-pmm-cw-truu-pool.sh`, `add-mainnet-truu-pmm-topup.sh`); see `docs/03-deployment/MAINNET_PMM_TRUU_CWUSD_PEG_AND_BOT_RUNBOOK.md` §11. + --- ## run-scenario.cjs Builds the **real** routing graph from configs, runs epochs with PMM state updates, path enumeration + waterfilling, **arb step** (implied-price deviation, capped corrective trades, profit gate), **bot step** (inject/withdraw at 0.5×/1.5× I_T^* with intervention cost β/γ/ρ), and optional **bridge shock** trades. Emits a **real scorecard** (PR#2). Runs are **deterministic** when `scenario.seed` is set or derived from scenario name. +Scenarios may also include an optional **microTradePolicy** for gas-budgeted support trades in selected USD wrapper rails. This is meant to model tiny, controlled `cWUSDC` / `cWUSDT` turnover-seeding or inventory-corrective activity, not to turn the PMM into a venue. + **Configs used:** `simulation-params.json`, `token-map.json`, `routing-controls.json`; `deployment-status.json` only when `graphMode = deployed`. Pool topology from `pool-matrix.json` and scenario `topology` / `fullQuoteChains`. **Tuning constants (in script):** @@ -64,8 +68,9 @@ Builds the **real** routing graph from configs, runs epochs with PMM state updat node scripts/run-scenario.cjs hub_only_11 node scripts/run-scenario.cjs --scenario full_quote_1_56_137 node scripts/run-scenario.cjs bridge_shock_137_56 +node scripts/run-scenario.cjs micro_support_usd_wrappers_1_56_137 ``` -**Output:** JSON scorecard including: `capture_mean`, `churn_mean`, `drain_half_life_epochs`, `path_concentration_index`; `intervention_cost_total` / `intervention_cost_inject_total` / `intervention_cost_withdraw_total` / `intervention_cost_by_chain` / `intervention_cost_per_1M_volume`; `peak_deviation_bps` (post-arb), `peak_deviation_bps_pre_arb`, `peak_deviation_bps_post_arb`, `peak_deviation_bps_post_bot`; `arb_volume_total`, `arb_profit_total` (execution-based, not mid). See [docs/12-sim-scorecard.md](../docs/12-sim-scorecard.md) and [config/scorecard-schema.json](../config/scorecard-schema.json). +**Output:** JSON scorecard including: `capture_mean`, `churn_mean`, `drain_half_life_epochs`, `path_concentration_index`; `intervention_cost_total` / `intervention_cost_inject_total` / `intervention_cost_withdraw_total` / `intervention_cost_by_chain` / `intervention_cost_per_1M_volume`; `micro_trade_count` / `micro_trade_volume_total` / `micro_trade_gas_cost_total`; `peak_deviation_bps` (post-arb), `peak_deviation_bps_pre_arb`, `peak_deviation_bps_post_arb`, `peak_deviation_bps_post_bot`; `arb_volume_total`, `arb_profit_total` (execution-based, not mid). See [docs/12-sim-scorecard.md](../docs/12-sim-scorecard.md) and [config/scorecard-schema.json](../config/scorecard-schema.json). **Orderflow:** Trade sizes use `distribution: "uniform"` by default. Scenario schema supports `lognormal` / `pareto` for skewed (many small + occasional whale) flows; implement in `sampleTrade()` when needed. diff --git a/scripts/run-scenario.cjs b/scripts/run-scenario.cjs index 94d94ab..4e02b35 100644 --- a/scripts/run-scenario.cjs +++ b/scripts/run-scenario.cjs @@ -355,6 +355,173 @@ function getBridgeRho(scenario, fromChain, toChain) { return (blocks ?? 10) * rhoPerBlock / 10000; } +function getMatchedQuoteForBase(base) { + if (base === 'cWUSDT') return 'USDT'; + if (base === 'cWUSDC') return 'USDC'; + return null; +} + +function getMicroTradeCandidates(graph, policy) { + const tokenFilter = new Set(policy.tokens || []); + const quoteFilter = new Set(policy.quoteTokens || []); + let candidates = graph.pmmEdges.filter((e) => { + if (tokenFilter.size > 0 && !tokenFilter.has(e.base)) return false; + if (quoteFilter.size > 0 && !quoteFilter.has(e.quote)) return false; + return true; + }); + + if (policy.preferMatchedQuote) { + const perChainBase = new Map(); + for (const edge of candidates) { + const key = `${edge.chainId}:${edge.base}`; + const preferredQuote = getMatchedQuoteForBase(edge.base); + const existing = perChainBase.get(key); + if (!existing) { + perChainBase.set(key, edge); + continue; + } + const score = edge.quote === preferredQuote ? 0 : 1; + const existingScore = existing.quote === preferredQuote ? 0 : 1; + if ( + score < existingScore + || (score === existingScore && edge.quote.localeCompare(existing.quote) < 0) + ) { + perChainBase.set(key, edge); + } + } + candidates = Array.from(perChainBase.values()); + } + + candidates.sort((a, b) => ( + a.chainId.localeCompare(b.chainId) + || a.base.localeCompare(b.base) + || a.quote.localeCompare(b.quote) + )); + return candidates; +} + +function resolveMicroTradeDirection(policy, poolState, epochIndex, tradeIndex) { + const mode = policy.mode || 'inventory_or_alternate'; + const bandFrac = Number(policy.inventoryBandFraction ?? 0.05); + const lower = (1 - bandFrac) * poolState.I_T_star; + const upper = (1 + bandFrac) * poolState.I_T_star; + + if (mode === 'inventory' || mode === 'inventory_or_alternate') { + if (poolState.I_T < lower) return 'sell_base'; + if (poolState.I_T > upper) return 'buy_base'; + if (mode === 'inventory') return null; + } + + if (mode === 'alternate' || mode === 'inventory_or_alternate') { + return ((epochIndex + tradeIndex) % 2 === 0) ? 'buy_base' : 'sell_base'; + } + if (mode === 'buy_base') return 'buy_base'; + if (mode === 'sell_base') return 'sell_base'; + return null; +} + +function runMicroTradeSupportStep(graph, state, scenario, epochIndex) { + const policy = scenario.microTradePolicy || {}; + if (policy.enabled === false || Object.keys(policy).length === 0) { + return { + state, + microTradeCount: 0, + microTradeBuyCount: 0, + microTradeSellCount: 0, + microTradeVolumeTotal: 0, + microTradeGasCostTotal: 0, + }; + } + + const requestedTrades = Math.max(0, parseInt(policy.tradesPerEpoch ?? 0, 10)); + if (requestedTrades === 0) { + return { + state, + microTradeCount: 0, + microTradeBuyCount: 0, + microTradeSellCount: 0, + microTradeVolumeTotal: 0, + microTradeGasCostTotal: 0, + }; + } + + const candidates = getMicroTradeCandidates(graph, policy); + if (candidates.length === 0) { + return { + state, + microTradeCount: 0, + microTradeBuyCount: 0, + microTradeSellCount: 0, + microTradeVolumeTotal: 0, + microTradeGasCostTotal: 0, + }; + } + + const gasCostPerTrade = Number(policy.gasCostPerTradeUnits ?? 0); + const gasBudgetPerEpoch = Number(policy.gasBudgetPerEpochUnits ?? 0); + let tradesAllowed = requestedTrades; + if (gasCostPerTrade > 0 && gasBudgetPerEpoch > 0) { + tradesAllowed = Math.min(tradesAllowed, Math.floor(gasBudgetPerEpoch / gasCostPerTrade)); + } + if (tradesAllowed <= 0) { + return { + state, + microTradeCount: 0, + microTradeBuyCount: 0, + microTradeSellCount: 0, + microTradeVolumeTotal: 0, + microTradeGasCostTotal: 0, + }; + } + + let curState = state; + let microTradeCount = 0; + let microTradeBuyCount = 0; + let microTradeSellCount = 0; + let microTradeVolumeTotal = 0; + let microTradeGasCostTotal = 0; + + for (let i = 0; i < tradesAllowed; i++) { + const edge = candidates[(epochIndex * tradesAllowed + i) % candidates.length]; + const poolState = curState[edge.key]; + if (!poolState || poolState.I_T_star == null) continue; + + const rawTradeSize = Number(policy.tradeSizeUnits ?? 0); + const maxFractionOfTarget = Number(policy.maxFractionOfTarget ?? 0.01); + const maxTradeSize = maxFractionOfTarget > 0 ? poolState.I_T_star * maxFractionOfTarget : rawTradeSize; + const tradeSize = Math.max(0, Math.min(rawTradeSize, maxTradeSize || rawTradeSize)); + if (tradeSize <= 0) continue; + + const direction = resolveMicroTradeDirection(policy, poolState, epochIndex, i); + if (!direction) continue; + + if (direction === 'sell_base') { + const { newState } = pmmSellT(edge.key, tradeSize, curState); + curState = newState; + microTradeSellCount += 1; + microTradeVolumeTotal += tradeSize; + } else { + const quoteSpend = tradeSize * (poolState.P || 1); + const { outputT, newState } = pmmBuyT(edge.key, quoteSpend, curState); + curState = newState; + microTradeBuyCount += 1; + microTradeVolumeTotal += outputT; + } + + microTradeCount += 1; + microTradeGasCostTotal += gasCostPerTrade; + } + + return { + state: curState, + microTradeCount, + microTradeBuyCount, + microTradeSellCount, + microTradeVolumeTotal, + microTradeGasCostTotal, + }; +} + function runBotStep(graph, state, scenario, configs) { const chains = graph.chains; let curState = state; @@ -625,6 +792,11 @@ function runEpoch(scenario, graph, state, configs, epochIndex) { let pmmVolume = 0; let churnSum = 0; const I_T_start = {}; + let microTradeCount = 0; + let microTradeBuyCount = 0; + let microTradeSellCount = 0; + let microTradeVolumeTotal = 0; + let microTradeGasCostTotal = 0; for (const k of Object.keys(state)) { if (state[k].I_T_star != null) I_T_start[k] = state[k].I_T; @@ -682,6 +854,15 @@ function runEpoch(scenario, graph, state, configs, epochIndex) { } } + const micro = runMicroTradeSupportStep(graph, curState, scenario, epochIndex); + curState = micro.state; + microTradeCount += micro.microTradeCount || 0; + microTradeBuyCount += micro.microTradeBuyCount || 0; + microTradeSellCount += micro.microTradeSellCount || 0; + microTradeVolumeTotal += micro.microTradeVolumeTotal || 0; + microTradeGasCostTotal += micro.microTradeGasCostTotal || 0; + totalVolume += micro.microTradeVolumeTotal || 0; + const peakDeviationBpsPreArb = maxDeviationBpsOverPools(graph, curState); const worstPreArb = getWorstPoolDiagnostic(graph, curState); const { state: afterArb, arbVolumeTotal, arbProfitTotal, peakDeviationBps: peakDeviationBpsPostArb } = runArbStep(graph, curState, configs); @@ -717,6 +898,11 @@ function runEpoch(scenario, graph, state, configs, epochIndex) { interventionCostInject: interventionCostInject || 0, interventionCostWithdraw: interventionCostWithdraw || 0, interventionCostByChain: interventionCostByChain || {}, + microTradeCount, + microTradeBuyCount, + microTradeSellCount, + microTradeVolumeTotal, + microTradeGasCostTotal, peakDeviationBpsPreArb: peakDeviationBpsPreArb || 0, peakDeviationBpsPostArb: peakDeviationBpsPostArb || 0, peakDeviationBpsPostBot: peakDeviationBpsPostBot || 0, @@ -753,6 +939,11 @@ function computeScorecard(scenario, scenarioName, graph, initialState, epochResu let peakDeviationBpsPreArb = 0; let peakDeviationBpsPostArb = 0; let peakDeviationBpsPostBot = 0; + let microTradeCountTotal = 0; + let microTradeBuyCountTotal = 0; + let microTradeSellCountTotal = 0; + let microTradeVolumeTotal = 0; + let microTradeGasCostTotal = 0; for (const r of epochResults) { totalVolume += r.totalVolume; @@ -763,6 +954,11 @@ function computeScorecard(scenario, scenarioName, graph, initialState, epochResu arbProfitTotal += r.arbProfitTotal || 0; interventionCostInjectTotal += r.interventionCostInject || 0; interventionCostWithdrawTotal += r.interventionCostWithdraw || 0; + microTradeCountTotal += r.microTradeCount || 0; + microTradeBuyCountTotal += r.microTradeBuyCount || 0; + microTradeSellCountTotal += r.microTradeSellCount || 0; + microTradeVolumeTotal += r.microTradeVolumeTotal || 0; + microTradeGasCostTotal += r.microTradeGasCostTotal || 0; for (const [chainId, v] of Object.entries(r.interventionCostByChain || {})) { if (!interventionCostByChain[chainId]) interventionCostByChain[chainId] = { inject: 0, withdraw: 0 }; interventionCostByChain[chainId].inject += v.inject || 0; @@ -838,6 +1034,11 @@ function computeScorecard(scenario, scenarioName, graph, initialState, epochResu intervention_cost_withdraw_total: Math.round(interventionCostWithdrawTotal), intervention_cost_by_chain: interventionCostByChain, intervention_cost_per_1M_volume: Math.round(interventionPer1M * 100) / 100, + micro_trade_count: Math.round(microTradeCountTotal), + micro_trade_buy_count: Math.round(microTradeBuyCountTotal), + micro_trade_sell_count: Math.round(microTradeSellCountTotal), + micro_trade_volume_total: Math.round(microTradeVolumeTotal), + micro_trade_gas_cost_total: Math.round(microTradeGasCostTotal * 100) / 100, peak_deviation_bps: Math.round(Number.isFinite(peakDeviationBpsPostArb) ? peakDeviationBpsPostArb : 0), peak_deviation_bps_pre_arb: Math.round(peakDeviationBpsPreArb), peak_deviation_bps_post_arb: Math.round(peakDeviationBpsPostArb), diff --git a/scripts/validate-deployment-status.cjs b/scripts/validate-deployment-status.cjs index 26fc72a..dc8812a 100644 --- a/scripts/validate-deployment-status.cjs +++ b/scripts/validate-deployment-status.cjs @@ -5,8 +5,9 @@ * * Rules: * - If bridgeAvailable === true on a chain, cwTokens must include at least cWUSDT and cWUSDC (phase 1). - * - For each pmmPool: role in {defense, public_routing}, feeBps and k present, - * base/quote (or tokenIn/tokenOut) exist in cwTokens or anchorAddresses. + * - For each pmmPool / pmmPoolsVolatile[]: role in {defense, public_routing, truu_routing}, + * feeBps and k present, base/quote (or tokenIn/tokenOut) exist in cwTokens or anchorAddresses. + * TRUU must be listed under anchorAddresses when used as quote (e.g. mainnet chain 1). * * Exit code: 0 if valid, 1 if invalid (and prints errors to stderr). */ @@ -18,12 +19,41 @@ const CONFIG_DIR = path.join(__dirname, '..', 'config'); const DEPLOYMENT_STATUS_PATH = path.join(CONFIG_DIR, 'deployment-status.json'); const PHASE1_CW = ['cWUSDT', 'cWUSDC']; -const VALID_ROLES = ['defense', 'public_routing']; +const VALID_ROLES = ['defense', 'public_routing', 'truu_routing']; +const VALID_REFERENCE_PROTOCOLS = ['uniswap_v3', 'balancer', 'curve', '1inch']; function loadJson(p) { return JSON.parse(fs.readFileSync(p, 'utf8')); } +function validatePoolEntries(chainId, pools, listLabel, knownTokens, errors) { + for (let i = 0; i < pools.length; i++) { + const pool = pools[i]; + const base = pool.base ?? pool.tokenIn; + const quote = pool.quote ?? pool.tokenOut; + + if (!VALID_ROLES.includes(pool.role)) { + errors.push(`Chain ${chainId} ${listLabel}[${i}]: role must be one of ${VALID_ROLES.join(', ')}`); + } + if (pool.feeBps == null || pool.k == null) { + errors.push(`Chain ${chainId} ${listLabel}[${i}]: feeBps and k required`); + } + if (base && !knownTokens.has(base)) { + errors.push(`Chain ${chainId} ${listLabel}[${i}]: base/tokenIn "${base}" not in cwTokens or anchorAddresses`); + } + if (quote && !knownTokens.has(quote)) { + errors.push(`Chain ${chainId} ${listLabel}[${i}]: quote/tokenOut "${quote}" not in cwTokens or anchorAddresses`); + } + const addr = pool.poolAddress; + if (addr != null && addr !== '') { + const z = String(addr).toLowerCase(); + if (z === '0x0000000000000000000000000000000000000000') { + errors.push(`Chain ${chainId} ${listLabel}[${i}]: poolAddress must not be zero when set`); + } + } + } +} + function main() { const status = loadJson(DEPLOYMENT_STATUS_PATH); const chains = status.chains || {}; @@ -31,8 +61,13 @@ function main() { for (const [chainId, chain] of Object.entries(chains)) { const cwTokens = chain.cwTokens || {}; + const gasMirrors = chain.gasMirrors || {}; const anchorAddresses = chain.anchorAddresses || {}; + const gasQuoteAddresses = chain.gasQuoteAddresses || {}; const pmmPools = chain.pmmPools || []; + const pmmPoolsVolatile = chain.pmmPoolsVolatile || []; + const gasPmmPools = chain.gasPmmPools || []; + const gasReferenceVenues = chain.gasReferenceVenues || []; const bridgeAvailable = chain.bridgeAvailable; if (bridgeAvailable === true) { @@ -43,24 +78,63 @@ function main() { } } - const knownTokens = new Set([...Object.keys(cwTokens), ...Object.keys(anchorAddresses)]); + const knownTokens = new Set([ + ...Object.keys(cwTokens), + ...Object.keys(gasMirrors), + ...Object.keys(anchorAddresses), + ...Object.keys(gasQuoteAddresses), + ]); - for (let i = 0; i < pmmPools.length; i++) { - const pool = pmmPools[i]; - const base = pool.base ?? pool.tokenIn; - const quote = pool.quote ?? pool.tokenOut; + validatePoolEntries(chainId, pmmPools, 'pmmPools', knownTokens, errors); + validatePoolEntries(chainId, pmmPoolsVolatile, 'pmmPoolsVolatile', knownTokens, errors); + validatePoolEntries(chainId, gasPmmPools, 'gasPmmPools', knownTokens, errors); - if (!VALID_ROLES.includes(pool.role)) { - errors.push(`Chain ${chainId} pmmPools[${i}]: role must be one of ${VALID_ROLES.join(', ')}`); + const gasPoolsByFamily = new Map(); + for (const pool of gasPmmPools) { + if (!pool.familyKey || typeof pool.familyKey !== 'string') { + errors.push(`Chain ${chainId} gasPmmPools entry is missing familyKey`); + continue; } - if (pool.feeBps == null || pool.k == null) { - errors.push(`Chain ${chainId} pmmPools[${i}]: feeBps and k required`); + if (!gasPoolsByFamily.has(pool.familyKey)) gasPoolsByFamily.set(pool.familyKey, []); + gasPoolsByFamily.get(pool.familyKey).push(pool); + } + + for (const [familyKey, pools] of gasPoolsByFamily.entries()) { + const poolTypes = new Set(pools.map((pool) => pool.poolType)); + if (!poolTypes.has('wrapped_native')) { + errors.push(`Chain ${chainId} gas family ${familyKey}: missing wrapped_native DODO pool`); } - if (base && !knownTokens.has(base)) { - errors.push(`Chain ${chainId} pmmPools[${i}]: base/tokenIn "${base}" not in cwTokens or anchorAddresses`); + if (!poolTypes.has('stable_quote')) { + errors.push(`Chain ${chainId} gas family ${familyKey}: missing stable_quote DODO pool`); } - if (quote && !knownTokens.has(quote)) { - errors.push(`Chain ${chainId} pmmPools[${i}]: quote/tokenOut "${quote}" not in cwTokens or anchorAddresses`); + } + + const referenceVenuesByFamily = new Map(); + for (let i = 0; i < gasReferenceVenues.length; i++) { + const venue = gasReferenceVenues[i]; + if (!VALID_REFERENCE_PROTOCOLS.includes(venue.protocol)) { + errors.push(`Chain ${chainId} gasReferenceVenues[${i}]: protocol must be one of ${VALID_REFERENCE_PROTOCOLS.join(', ')}`); + } + if (!venue.familyKey || typeof venue.familyKey !== 'string') { + errors.push(`Chain ${chainId} gasReferenceVenues[${i}]: familyKey required`); + continue; + } + if (!referenceVenuesByFamily.has(venue.familyKey)) referenceVenuesByFamily.set(venue.familyKey, []); + referenceVenuesByFamily.get(venue.familyKey).push(venue); + } + + for (const [familyKey, venues] of referenceVenuesByFamily.entries()) { + const protocols = new Set(venues.map((venue) => venue.protocol)); + if (!protocols.has('uniswap_v3')) { + errors.push(`Chain ${chainId} gas family ${familyKey}: missing uniswap_v3 reference venue`); + } + const oneInch = venues.find((venue) => venue.protocol === '1inch'); + if (oneInch?.routingVisible === true || oneInch?.live === true) { + const hasUniswap = venues.some((venue) => venue.protocol === 'uniswap_v3' && venue.live === true); + const hasDodo = (gasPoolsByFamily.get(familyKey) || []).some((pool) => pool.publicRoutingEnabled === true); + if (!hasUniswap || !hasDodo) { + errors.push(`Chain ${chainId} gas family ${familyKey}: 1inch cannot be live/routingVisible before DODO and Uniswap venues are live`); + } } } } diff --git a/spec/13-minimal-router-sim.md b/spec/13-minimal-router-sim.md index 528edb0..a822872 100644 --- a/spec/13-minimal-router-sim.md +++ b/spec/13-minimal-router-sim.md @@ -22,9 +22,10 @@ For each epoch: 2. **Compute candidate paths** (e.g. k-shortest paths or enumerate swap+bridge combos). 3. **Allocate flow** by marginal-equalization heuristic (waterfilling): split volume across paths so marginal output equalizes. 4. **Update PMM inventories** and implied prices (use inventory-sensitive depth D = D_0·min(1, I_T/I_T^*)). -5. **Arb step (optional):** agents that trade toward oracle when profitable; update inventories again. -6. **Bot intervention step:** apply policy from config (or keep exogenous); record intervention cost. -7. **Emit scorecard** (or accumulate for end-of-run scorecard). +5. **Micro-support step (optional):** run gas-budgeted support trades for selected rails (e.g. `cWUSDC`, `cWUSDT`) to model tiny turnover-seeding or inventory-corrective activity. +6. **Arb step (optional):** agents that trade toward oracle when profitable; update inventories again. +7. **Bot intervention step:** apply policy from config (or keep exogenous); record intervention cost. +8. **Emit scorecard** (or accumulate for end-of-run scorecard). --- @@ -46,9 +47,10 @@ AMM edges can be mocked (e.g. fixed 5 bps spread); relative behavior of PMM vs a - **PMM state:** Per-pool `I_T`, `D = D_0·min(1, I_T/I_T^*)`, sell/buy with documented formula; routing controls applied. - **Routing:** Candidate paths (same-chain, length ≤3), top-K by cost; waterfilling by chunk (5%), marginal-equalization. - **Arb step (PR#2):** Implied price (sell/buy probe) vs oracle P; deviation δ; if |δ| > DELTA_ARB_BPS, trade in corrective direction with size min(x_max, α·|δ|·I_T^*); profit gate (skip if profit ≤ 0). Tuning: `DELTA_ARB_BPS`, `ARB_ALPHA`, `ARB_MAX_FRACTION_OF_TARGET`. +- **Micro-support step:** When `scenario.microTradePolicy` is enabled, run tiny support trades on selected cW rails before arb. Policy can prefer matched quotes (`cWUSDC/USDC`, `cWUSDT/USDT`), stay inside an inventory band, alternate when inside band, and clip the trade count by a per-epoch gas budget. - **Bot step (PR#2):** If I_T < 0.5·I_T^* inject; if I_T > 1.5·I_T^* withdraw; action clipped to `BOT_MAX_FRACTION_OF_TARGET`·I_T^*; intervention cost = |u|·(β+ρ)+γ (bridge params + latency ρ from scenario `latencyModel`). - **Bridge shock:** When `scenario.bridgeShock` is set, extra trades (sell cW on fromChain, buy cW on toChain) over `durationEpochs` at `magnitudeFraction` of baseline. - **Determinism:** RNG seeded from `scenario.seed` or hash of scenario name. -- **Scorecard:** All PR#1 metrics plus `peak_deviation_bps`, `intervention_cost_*`, `arb_volume_total`, `arb_profit_total`. +- **Scorecard:** All PR#1 metrics plus `peak_deviation_bps`, `intervention_cost_*`, `arb_volume_total`, `arb_profit_total`, and support-lane `micro_trade_*` metrics. Tuning: see constants in script and [scripts/README.md](../scripts/README.md). diff --git a/spec/bot-pseudo-code.md b/spec/bot-pseudo-code.md index 6f3ee47..6982183 100644 --- a/spec/bot-pseudo-code.md +++ b/spec/bot-pseudo-code.md @@ -33,5 +33,6 @@ for each pool (cW* / quote): - **Bridge throttle**: If bridge backlog or risk flag, widen bands or skip trade. - **Global budget**: Before any trade, check per-token trade budget for current window; skip if exhausted. - **Min improvement**: Only trade if expected |δ| improvement net of fees ≥ minImprovementBps. +- **Gas-budgeted micro-support**: For selected USD wrappers (especially `cWUSDC`, `cWUSDT`), allow tiny matched-quote trades (`cWUSDC/USDC`, `cWUSDT/USDT` when available) under a separate gas budget so wrappers stay economically live without converting the PMM into the destination venue. Thresholds and bands from [../config/peg-bands.json](../config/peg-bands.json). Mesh reflexivity from [../docs/07-mesh-reflexivity.md](../docs/07-mesh-reflexivity.md).