Add ALL Mainnet completion planning evidence
This commit is contained in:
@@ -37,6 +37,24 @@
|
||||
"Tiny live canary swap executed on ALL Mainnet Uniswap V2 WALL/AUSDC."
|
||||
]
|
||||
},
|
||||
{
|
||||
"poolId": "651940-dodo_pmm-wall-ausdt",
|
||||
"generatedAt": "2026-04-30T06:58:00Z",
|
||||
"canaryTransactions": [
|
||||
{
|
||||
"direction": "base_to_quote",
|
||||
"txHash": "0x6b74c3b6816eb67409268a6e3b108fd631d278baf0fd57524a63c60c995bded3",
|
||||
"fundingTransferTxHash": "0x2e1540c484abac9049e383a16fc35a5b6b81a33bd70183b80b20f94533dbe141",
|
||||
"amountInRaw": "1000000",
|
||||
"tokenIn": "WALL",
|
||||
"tokenOut": "AUSDT",
|
||||
"executor": "DODO_DVM.transfer_then_sellBase"
|
||||
}
|
||||
],
|
||||
"notes": [
|
||||
"Tiny live canary swap executed on ALL Mainnet DODO PMM WALL/AUSDT."
|
||||
]
|
||||
},
|
||||
{
|
||||
"poolId": "137-dodo_pmm-cwusdc-usdc",
|
||||
"generatedAt": "2026-04-29T04:41:13.993Z",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"version": "1.0.0",
|
||||
"generatedAt": "2026-04-29T06:18:00Z",
|
||||
"generatedAt": "2026-04-30T06:51:46.495Z",
|
||||
"description": "Canonical pool-creation matrix for ALL Mainnet public spend readiness. Pools must exist here before funding.",
|
||||
"lifecycle": [
|
||||
"planned",
|
||||
@@ -23,9 +23,9 @@
|
||||
],
|
||||
"statusCounts": {
|
||||
"planned": 83,
|
||||
"canary_passed": 5,
|
||||
"canary_passed": 6,
|
||||
"created": 17,
|
||||
"live_read": 8
|
||||
"live_read": 7
|
||||
},
|
||||
"protocolCounts": {
|
||||
"dodo_pmm": 49,
|
||||
@@ -292,7 +292,7 @@
|
||||
"verification": "DODOPMMIntegration pools(base,quote) resolves to pool address; DVM clone has bytecode; initial reserves are zero until funding."
|
||||
},
|
||||
"reserveEvidence": {
|
||||
"generatedAt": "2026-04-29T04:41:20.353Z",
|
||||
"generatedAt": "2026-04-30T06:51:46.495Z",
|
||||
"evidenceRef": "reports/status/all-mainnet-required-pool-balances-latest.json#651940-dodo_pmm-wall-ausdc",
|
||||
"baseBalanceRaw": "1000000000001000000",
|
||||
"quoteBalanceRaw": "999999999998000001",
|
||||
@@ -444,10 +444,27 @@
|
||||
"k": null,
|
||||
"singleSided": false,
|
||||
"publicRoutingEnabled": true,
|
||||
"reserveSource": "all-mainnet-canonical-ausdt-correction",
|
||||
"status": "live_read",
|
||||
"reserveSource": "all-mainnet-required-pool-balance-check",
|
||||
"status": "canary_passed",
|
||||
"requiredForSpend": true,
|
||||
"canaryEvidence": null,
|
||||
"canaryEvidence": {
|
||||
"generatedAt": "2026-04-30T06:58:00Z",
|
||||
"sourceFile": "config/all-mainnet-canary-evidence.json",
|
||||
"canaryTransactions": [
|
||||
{
|
||||
"direction": "base_to_quote",
|
||||
"txHash": "0x6b74c3b6816eb67409268a6e3b108fd631d278baf0fd57524a63c60c995bded3",
|
||||
"fundingTransferTxHash": "0x2e1540c484abac9049e383a16fc35a5b6b81a33bd70183b80b20f94533dbe141",
|
||||
"amountInRaw": "1000000",
|
||||
"tokenIn": "WALL",
|
||||
"tokenOut": "AUSDT",
|
||||
"executor": "DODO_DVM.transfer_then_sellBase"
|
||||
}
|
||||
],
|
||||
"notes": [
|
||||
"Tiny live canary swap executed on ALL Mainnet DODO PMM WALL/AUSDT."
|
||||
]
|
||||
},
|
||||
"fundingTiersUsd": {
|
||||
"seed": 10,
|
||||
"smoke": 100,
|
||||
@@ -464,7 +481,9 @@
|
||||
"Canonical WALL/AUSDT DODO V2 DVM-backed pool created after quote asset correction from USDT to AUSDT.",
|
||||
"Vault assignments applied from explicit All Mainnet vault assignment map.",
|
||||
"Seeded with 1 WALL and 1 AUSDT from deployer wallet.",
|
||||
"EnhancedSwapRouterV2 DODO route registered and quoteable."
|
||||
"EnhancedSwapRouterV2 DODO route registered and quoteable.",
|
||||
"Live reserve read recorded from required-pool balance checker.",
|
||||
"Canary evidence recorded from explicit All Mainnet canary evidence file."
|
||||
],
|
||||
"infrastructure": {
|
||||
"dvmFactory": "0x8a3403aef8d40c0F4AfaF6Dc2000A537EbC863c2",
|
||||
@@ -477,16 +496,12 @@
|
||||
"verification": "DODOPMMIntegration pools(WALL,AUSDT) resolves to pool address; DVM clone has bytecode."
|
||||
},
|
||||
"reserveEvidence": {
|
||||
"generatedAt": "2026-04-29T05:48:00Z",
|
||||
"baseBalanceRaw": "1000000000000000000",
|
||||
"quoteBalanceRaw": "1000000000000000000",
|
||||
"generatedAt": "2026-04-30T06:51:46.495Z",
|
||||
"evidenceRef": "reports/status/all-mainnet-required-pool-balances-latest.json#651940-dodo_pmm-wall-ausdt",
|
||||
"baseBalanceRaw": "1000000000001000000",
|
||||
"quoteBalanceRaw": "999999999998000001",
|
||||
"poolHasCode": true,
|
||||
"liveReadStatus": "nonzero_base_and_quote",
|
||||
"fundingTransactions": [
|
||||
"0x2aa8835e2506e1d8802f9d14c570abdad7e14e9dfe0d0261f7e19da019215f25",
|
||||
"0xc3a6a7edb6d9e9422a78fafae53bab9b96746a6fff83ca607edff7793286f294",
|
||||
"0xf9344211547bccadc1b433cf31f6f953f15b915b7d031c03411a114e180cf399"
|
||||
]
|
||||
"liveReadStatus": "nonzero_base_and_quote"
|
||||
},
|
||||
"routerRouteEvidence": {
|
||||
"routerAddress": "0xb905fEfA56b028221E2Bc248Bbcd41141dc7aeD3",
|
||||
@@ -815,10 +830,10 @@
|
||||
"Canary evidence recorded from explicit All Mainnet canary evidence file."
|
||||
],
|
||||
"reserveEvidence": {
|
||||
"generatedAt": "2026-04-29T04:41:20.353Z",
|
||||
"generatedAt": "2026-04-30T06:51:46.495Z",
|
||||
"evidenceRef": "reports/status/all-mainnet-required-pool-balances-latest.json#651940-uniswap_v2-wall-ausdc",
|
||||
"baseBalanceRaw": "222025888680628319105322384",
|
||||
"quoteBalanceRaw": "130598623255778071651280",
|
||||
"baseBalanceRaw": "224445209871270534969174163",
|
||||
"quoteBalanceRaw": "129194376317333448505973",
|
||||
"poolHasCode": true,
|
||||
"liveReadStatus": "nonzero_base_and_quote"
|
||||
}
|
||||
@@ -895,10 +910,10 @@
|
||||
"Vault assignments applied from explicit All Mainnet vault assignment map."
|
||||
],
|
||||
"reserveEvidence": {
|
||||
"generatedAt": "2026-04-29T04:41:20.353Z",
|
||||
"generatedAt": "2026-04-30T06:51:46.495Z",
|
||||
"evidenceRef": "reports/status/all-mainnet-required-pool-balances-latest.json#651940-uniswap_v2-wall-usdt",
|
||||
"baseBalanceRaw": "119579763278558287348114878",
|
||||
"quoteBalanceRaw": "96183323535791914791099",
|
||||
"baseBalanceRaw": "116762468938410673082689864",
|
||||
"quoteBalanceRaw": "98510599724849461923660",
|
||||
"poolHasCode": true,
|
||||
"liveReadStatus": "nonzero_base_and_quote"
|
||||
}
|
||||
@@ -975,10 +990,10 @@
|
||||
"Vault assignments applied from explicit All Mainnet vault assignment map."
|
||||
],
|
||||
"reserveEvidence": {
|
||||
"generatedAt": "2026-04-29T04:41:20.353Z",
|
||||
"generatedAt": "2026-04-30T06:51:46.495Z",
|
||||
"evidenceRef": "reports/status/all-mainnet-required-pool-balances-latest.json#651940-uniswap_v2-usdt-ausdc",
|
||||
"baseBalanceRaw": "128823453150848278870209",
|
||||
"quoteBalanceRaw": "77642915975212836473965",
|
||||
"baseBalanceRaw": "126950810303091320030551",
|
||||
"quoteBalanceRaw": "78791103453769787415423",
|
||||
"poolHasCode": true,
|
||||
"liveReadStatus": "nonzero_base_and_quote"
|
||||
}
|
||||
@@ -1205,7 +1220,7 @@
|
||||
"Vault assignments applied from explicit All Mainnet vault assignment map."
|
||||
],
|
||||
"reserveEvidence": {
|
||||
"generatedAt": "2026-04-29T04:41:20.353Z",
|
||||
"generatedAt": "2026-04-30T06:51:46.495Z",
|
||||
"evidenceRef": "reports/status/all-mainnet-required-pool-balances-latest.json#1-dodo_pmm-cwusdc-usdc",
|
||||
"baseBalanceRaw": "818811480",
|
||||
"quoteBalanceRaw": "233144600",
|
||||
@@ -1285,7 +1300,7 @@
|
||||
"Vault assignments applied from explicit All Mainnet vault assignment map."
|
||||
],
|
||||
"reserveEvidence": {
|
||||
"generatedAt": "2026-04-29T04:41:20.353Z",
|
||||
"generatedAt": "2026-04-30T06:51:46.495Z",
|
||||
"evidenceRef": "reports/status/all-mainnet-required-pool-balances-latest.json#1-dodo_pmm-cwusdt-usdt",
|
||||
"baseBalanceRaw": "9845664",
|
||||
"quoteBalanceRaw": "2160199",
|
||||
@@ -2583,7 +2598,7 @@
|
||||
"Canary evidence recorded from explicit All Mainnet canary evidence file."
|
||||
],
|
||||
"reserveEvidence": {
|
||||
"generatedAt": "2026-04-29T04:41:20.353Z",
|
||||
"generatedAt": "2026-04-30T06:51:46.495Z",
|
||||
"evidenceRef": "reports/status/all-mainnet-required-pool-balances-latest.json#137-dodo_pmm-cwusdc-usdc",
|
||||
"baseBalanceRaw": "39885",
|
||||
"quoteBalanceRaw": "39883",
|
||||
@@ -2681,7 +2696,7 @@
|
||||
"Canary evidence recorded from explicit All Mainnet canary evidence file."
|
||||
],
|
||||
"reserveEvidence": {
|
||||
"generatedAt": "2026-04-29T04:41:20.353Z",
|
||||
"generatedAt": "2026-04-30T06:51:46.495Z",
|
||||
"evidenceRef": "reports/status/all-mainnet-required-pool-balances-latest.json#137-dodo_pmm-cwusdt-usdt",
|
||||
"baseBalanceRaw": "2605",
|
||||
"quoteBalanceRaw": "2603",
|
||||
@@ -3291,7 +3306,7 @@
|
||||
"transactionHash": "0x6a63466a12d2ee71201be232db0af6d5f40f8d829dbe453c9f00abbe6df6fbb9"
|
||||
},
|
||||
"reserveEvidence": {
|
||||
"generatedAt": "2026-04-29T04:41:20.353Z",
|
||||
"generatedAt": "2026-04-30T06:51:46.495Z",
|
||||
"evidenceRef": "reports/status/all-mainnet-required-pool-balances-latest.json#8453-dodo_pmm-cwusdc-usdc",
|
||||
"baseBalanceRaw": "1000000",
|
||||
"quoteBalanceRaw": "1000000",
|
||||
@@ -3977,7 +3992,7 @@
|
||||
"transactionHash": "0x4385161e41e88a560cc5107020d6099c540428c4e39f2415e238a37de16f4d31"
|
||||
},
|
||||
"reserveEvidence": {
|
||||
"generatedAt": "2026-04-29T04:41:20.353Z",
|
||||
"generatedAt": "2026-04-30T06:51:46.495Z",
|
||||
"evidenceRef": "reports/status/all-mainnet-required-pool-balances-latest.json#42161-dodo_pmm-cwusdc-usdc",
|
||||
"baseBalanceRaw": "100000",
|
||||
"quoteBalanceRaw": "100000",
|
||||
@@ -8677,7 +8692,7 @@
|
||||
"k": null,
|
||||
"singleSided": false,
|
||||
"publicRoutingEnabled": true,
|
||||
"reserveSource": "uniswap_v3_position_manager_seed",
|
||||
"reserveSource": "all-mainnet-required-pool-balance-check",
|
||||
"status": "canary_passed",
|
||||
"requiredForSpend": true,
|
||||
"canaryEvidence": {
|
||||
@@ -8712,7 +8727,8 @@
|
||||
"notes": [
|
||||
"ALL Mainnet official Uniswap V3 pool stack deployed from upstream Uniswap V3 artifacts.",
|
||||
"AUSDT/WALL 0.30% pool initialized at 1:1 sqrtPriceX96 and seeded through NonfungiblePositionManager.",
|
||||
"Standalone SwapRouter and Quoter are live and tested; EnhancedSwapRouterV2 V3 provider remains disabled until adapter quote compatibility is fixed."
|
||||
"Standalone SwapRouter and Quoter are live and tested; EnhancedSwapRouterV2 V3 provider remains disabled until adapter quote compatibility is fixed.",
|
||||
"Live reserve read recorded from required-pool balance checker."
|
||||
],
|
||||
"infrastructure": {
|
||||
"nftDescriptorLibrary": "0xb53E8A0A19fB381537c6f28D37b7C2f7DC29EF02",
|
||||
@@ -8731,12 +8747,12 @@
|
||||
"verification": "UniswapV3Factory.getPool(AUSDT,WALL,3000) resolves to pool address; pool has code and liquidity."
|
||||
},
|
||||
"reserveEvidence": {
|
||||
"generatedAt": "2026-04-29T06:14:00Z",
|
||||
"liquidityRaw": "1000000000000000000",
|
||||
"sqrtPriceX96": "79228162514264337593543950336",
|
||||
"tick": 0,
|
||||
"mintTxHash": "0x64660f089eac210ff94a1a01ffcdc1e3d9dc82739589b781d9ef18d8247a4754",
|
||||
"liveReadStatus": "nonzero_liquidity"
|
||||
"generatedAt": "2026-04-30T06:51:46.495Z",
|
||||
"evidenceRef": "reports/status/all-mainnet-required-pool-balances-latest.json#651940-uniswap_v3-wall-ausdt",
|
||||
"baseBalanceRaw": "1000000000001000000",
|
||||
"quoteBalanceRaw": "999999999999003001",
|
||||
"poolHasCode": true,
|
||||
"liveReadStatus": "nonzero_base_and_quote"
|
||||
},
|
||||
"routerRouteEvidence": {
|
||||
"routerAddress": "0xb905fEfA56b028221E2Bc248Bbcd41141dc7aeD3",
|
||||
|
||||
188
docs/03-deployment/ALL_MAINNET_PROTOCOL_COMPLETION_RUNBOOK.md
Normal file
188
docs/03-deployment/ALL_MAINNET_PROTOCOL_COMPLETION_RUNBOOK.md
Normal file
@@ -0,0 +1,188 @@
|
||||
# ALL Mainnet Protocol Completion Runbook
|
||||
|
||||
**Status:** Operator runbook
|
||||
**Scope:** ALL Mainnet `651940` pool inventory, auto-rebalancing, and protocol support gates.
|
||||
**Canonical inputs:** `config/all-mainnet-pool-creation-matrix.json`, `config/allmainnet-non-dodo-protocol-surface.json`
|
||||
|
||||
## Current State
|
||||
|
||||
The pool matrix already contains the intended inventory surface. Treat it as the source of truth for what must be created, funded, canaried, and eventually promoted.
|
||||
|
||||
As of the current matrix:
|
||||
|
||||
| Protocol | Rows | Required for spend | Main blocker |
|
||||
|---|---:|---:|---|
|
||||
| `dodo_pmm` | 49 | 24 | Remaining planned pools and non-production rows |
|
||||
| `single_sided_pmm` | 3 | 3 | Pool creation and funding |
|
||||
| `uniswap_v2` | 5 | 3 | One planned pool plus promotion evidence |
|
||||
| `uniswap_v3` | 1 | 1 | Canary passed; keep adapter compatibility gated |
|
||||
| `balancer_weighted` | 11 | 0 | Optional protocol inventory not deployed/imported |
|
||||
| `curve_stable` | 11 | 0 | Optional protocol inventory not deployed/imported |
|
||||
| `sushiswap_v2` | 11 | 0 | Optional protocol inventory not deployed/imported |
|
||||
| `oneinch_aggregator` | 11 | 0 | Optional aggregator routes depend on live native liquidity first |
|
||||
| `aave_backstop` | 11 | 0 | Optional backstop market not deployed/imported |
|
||||
|
||||
`config/allmainnet-non-dodo-protocol-surface.json` currently publishes partial same-chain inventory and keeps only DODO enabled through `EnhancedSwapRouterV2`. Do not enable optional providers until their pool rows have real addresses, reserve reads, canary evidence, and route quotes.
|
||||
|
||||
## Phase 1: Close Required Inventory
|
||||
|
||||
Work required rows first. Optional protocols should not distract from getting the spend mesh healthy.
|
||||
|
||||
1. Generate the live worklist:
|
||||
|
||||
```bash
|
||||
node scripts/status/generate-all-mainnet-readiness.mjs
|
||||
```
|
||||
|
||||
Read:
|
||||
|
||||
- `reports/status/all-mainnet-deployment-readiness-worklist-latest.json`
|
||||
- `reports/status/all-mainnet-production-gate-latest.json`
|
||||
- `reports/status/all-mainnet-spend-readiness-latest.json`
|
||||
|
||||
2. For every required row with `status: planned`, create or import the pool address.
|
||||
|
||||
Required blockers are usually one of:
|
||||
|
||||
- `pool_not_created`
|
||||
- `missing_base_address:*`
|
||||
- `missing_quote_address:*`
|
||||
- `missing_pool_address`
|
||||
|
||||
For DODO rows, use the committed DODO infrastructure from the row:
|
||||
|
||||
- `infrastructure.dvmFactory`
|
||||
- `infrastructure.dvmFactoryAdapter`
|
||||
- `infrastructure.dodoPmmIntegration`
|
||||
|
||||
For Uniswap V2/V3 rows, use the committed factory/router/quoter or import the canonical address from verified on-chain deployment evidence. Do not invent placeholder pool addresses.
|
||||
|
||||
3. After creating or importing pools, run reserve reads:
|
||||
|
||||
```bash
|
||||
node scripts/status/check-all-mainnet-required-pool-balances.mjs
|
||||
node scripts/status/check-all-mainnet-required-pool-balances.mjs --update-matrix
|
||||
```
|
||||
|
||||
Only use `--update-matrix` after reviewing the report. It promotes rows with live code and non-zero base/quote balances to `live_read`; it does not create, fund, or canary pools.
|
||||
|
||||
## Phase 2: Fund and Canary
|
||||
|
||||
Funding should move in tiers, not straight to production.
|
||||
|
||||
Use each row's `fundingTiersUsd`:
|
||||
|
||||
- `seed`: proves transferability and reserve reads
|
||||
- `smoke`: proves route quoteability and tiny swaps
|
||||
- `productionMinimum`: minimum operating reserve before promotion
|
||||
|
||||
After funding, run:
|
||||
|
||||
```bash
|
||||
node scripts/status/check-all-mainnet-required-pool-balances.mjs
|
||||
node scripts/status/preflight-all-mainnet-canaries.mjs
|
||||
```
|
||||
|
||||
Record successful canaries with:
|
||||
|
||||
```bash
|
||||
node scripts/status/record-all-mainnet-canary-evidence.mjs
|
||||
```
|
||||
|
||||
Promotion rule:
|
||||
|
||||
- `planned` -> create/import pool
|
||||
- `created` -> fund both sides
|
||||
- `live_read` -> canary both directions where applicable
|
||||
- `canary_passed` -> operator review
|
||||
- `production` -> public route eligible
|
||||
|
||||
## Phase 3: Auto-Rebalancing
|
||||
|
||||
Auto-rebalancing should be conservative and evidence driven. It should not be allowed to create new exposure on rows that have not passed the production gate.
|
||||
|
||||
Minimum policy per row:
|
||||
|
||||
```json
|
||||
{
|
||||
"maxPriceImpactBps": 100,
|
||||
"minReserveUsd": 1000,
|
||||
"refillTriggerBps": 200,
|
||||
"pauseOnReserveReadFailure": true
|
||||
}
|
||||
```
|
||||
|
||||
Implementation shape:
|
||||
|
||||
1. Watch only rows with `requiredForSpend: true` and status `live_read`, `canary_passed`, or `production`.
|
||||
2. Read live base/quote balances using `check-all-mainnet-required-pool-balances.mjs`.
|
||||
3. Convert reserves to oracle ISO value using the same ISO peg rules used by `scripts/verify/build-cw-public-price-table.py`.
|
||||
4. If either side is below `minReserveUsd` or outside `refillTriggerBps`, generate a rebalance intent.
|
||||
5. Execute only after dry-run quote checks pass and `maxPriceImpactBps` is respected.
|
||||
6. Record every action back into a report before changing matrix status.
|
||||
|
||||
Recommended first automation artifact:
|
||||
|
||||
```text
|
||||
scripts/status/plan-all-mainnet-rebalance.mjs
|
||||
```
|
||||
|
||||
It should be read-only by default and write:
|
||||
|
||||
```text
|
||||
reports/status/all-mainnet-rebalance-plan-latest.json
|
||||
```
|
||||
|
||||
The read-only planner is available now:
|
||||
|
||||
```bash
|
||||
node scripts/status/plan-all-mainnet-rebalance.mjs
|
||||
```
|
||||
|
||||
Only after that report is stable should an execution wrapper be added, for example:
|
||||
|
||||
```text
|
||||
scripts/deployment/execute-all-mainnet-rebalance.mjs
|
||||
```
|
||||
|
||||
The execution wrapper must require an explicit `--execute` flag.
|
||||
|
||||
## Phase 4: Enable All Protocols
|
||||
|
||||
Protocol enablement must follow native-liquidity order. Aggregators come last.
|
||||
|
||||
1. **DODO PMM:** Finish required DODO and single-sided PMM rows first. Keep DODO as the default router provider until other providers pass canaries.
|
||||
2. **Uniswap V2:** Promote committed V2 rows with live reserve reads and canaries. Add the remaining planned V2 pool address or mark it explicitly deferred.
|
||||
3. **Uniswap V3:** Keep the standalone V3 route recorded, but do not enable the enhanced-router V3 provider until the adapter quote incompatibility is fixed and canary evidence exists through the enhanced router path.
|
||||
4. **Balancer / Curve / Sushi:** Import or deploy canonical factories, routers/vaults, pools, and pool IDs. Add addresses to the pool matrix before funding. No route generation from config-only rows.
|
||||
5. **1inch:** Enable only after DODO plus at least one native venue for the same pair is live. 1inch rows are aggregator-only and must not be the first source of liquidity truth.
|
||||
6. **Aave backstop:** Treat as a reserve/backstop surface, not a swap venue. Enable after token markets, oracle config, caps, and pause controls are committed.
|
||||
|
||||
After each protocol wave:
|
||||
|
||||
```bash
|
||||
bash scripts/verify/check-allmainnet-protocol-surface.sh
|
||||
node scripts/status/generate-all-mainnet-readiness.mjs
|
||||
bash scripts/validation/validate-config-files.sh
|
||||
```
|
||||
|
||||
## Production Gate
|
||||
|
||||
A row can become public-route eligible only when all of these are true:
|
||||
|
||||
- Real token addresses
|
||||
- Real pool address with bytecode
|
||||
- Required vault assignments complete
|
||||
- Non-zero base and quote reserves
|
||||
- Canary evidence recorded
|
||||
- Route quote check passes
|
||||
- Protocol surface has the provider enabled
|
||||
- Status is `production`
|
||||
|
||||
The whole ALL Mainnet same-chain surface is production-ready only when:
|
||||
|
||||
```bash
|
||||
jq -e '.status == "production_ready"' reports/status/all-mainnet-production-gate-latest.json
|
||||
```
|
||||
|
||||
Until then, keep public routing constrained to canary-passed rows and explicitly disabled historical rows out of route generation.
|
||||
164
scripts/status/build-all-mainnet-deployment-funding-packet.mjs
Normal file
164
scripts/status/build-all-mainnet-deployment-funding-packet.mjs
Normal file
@@ -0,0 +1,164 @@
|
||||
#!/usr/bin/env node
|
||||
/**
|
||||
* Build the strict deployment/funding packet for ALL Mainnet completion.
|
||||
*
|
||||
* This is intentionally read-only. It converts the matrix, reserve report,
|
||||
* canary preflight, and rebalance plan into an operator packet that separates
|
||||
* executable work from rows that are blocked by missing addresses/evidence.
|
||||
*/
|
||||
|
||||
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
||||
import { resolve } from "node:path";
|
||||
|
||||
const repoRoot = resolve(new URL("../..", import.meta.url).pathname);
|
||||
const matrixPath = resolve(repoRoot, "config/all-mainnet-pool-creation-matrix.json");
|
||||
const readinessPath = resolve(repoRoot, "reports/status/all-mainnet-deployment-readiness-worklist-latest.json");
|
||||
const reservePath = resolve(repoRoot, "reports/status/all-mainnet-required-pool-balances-latest.json");
|
||||
const canaryPath = resolve(repoRoot, "reports/status/all-mainnet-canary-preflight-latest.json");
|
||||
const rebalancePath = resolve(repoRoot, "reports/status/all-mainnet-rebalance-plan-latest.json");
|
||||
const jsonOut = resolve(repoRoot, "reports/status/all-mainnet-full-deployment-funding-packet-latest.json");
|
||||
const mdOut = resolve(repoRoot, "reports/status/all-mainnet-full-deployment-funding-packet-latest.md");
|
||||
|
||||
function readJson(path, fallback = null) {
|
||||
return existsSync(path) ? JSON.parse(readFileSync(path, "utf8")) : fallback;
|
||||
}
|
||||
|
||||
function table(headers, rows) {
|
||||
return [
|
||||
`| ${headers.join(" | ")} |`,
|
||||
`| ${headers.map(() => "---").join(" | ")} |`,
|
||||
...rows.map((row) => `| ${row.map((cell) => String(cell ?? "").replace(/\|/g, "\\|")).join(" | ")} |`),
|
||||
].join("\n");
|
||||
}
|
||||
|
||||
function tokenPair(row) {
|
||||
return `${row.baseToken?.symbol || "?"}/${row.quoteToken?.symbol || "?"}`;
|
||||
}
|
||||
|
||||
function poolBlockers(row) {
|
||||
const blockers = [];
|
||||
if (!row.baseToken?.address) blockers.push(`missing_base_address:${row.baseToken?.symbol || "unknown"}`);
|
||||
if (!row.quoteToken?.address) blockers.push(`missing_quote_address:${row.quoteToken?.symbol || "unknown"}`);
|
||||
if (!row.poolAddress) blockers.push("missing_pool_address");
|
||||
if ((row.missingRequiredVaultRoles || []).length) blockers.push("missing_required_vault_assignments");
|
||||
return blockers;
|
||||
}
|
||||
|
||||
const matrix = readJson(matrixPath);
|
||||
const readiness = readJson(readinessPath, { blockers: [] });
|
||||
const reserve = readJson(reservePath, { results: [] });
|
||||
const canary = readJson(canaryPath, { results: [] });
|
||||
const rebalance = readJson(rebalancePath, { intents: [] });
|
||||
const generatedAt = new Date().toISOString();
|
||||
|
||||
const reserveByPoolId = new Map(reserve.results.map((row) => [row.poolId, row]));
|
||||
const canaryByPoolId = new Map(canary.results.map((row) => [row.poolId, row]));
|
||||
const rebalanceByPoolId = new Map(rebalance.intents.map((row) => [row.poolId, row]));
|
||||
const requiredRows = matrix.rows.filter((row) => row.requiredForSpend === true);
|
||||
|
||||
const rows = requiredRows.map((row) => {
|
||||
const reserveRow = reserveByPoolId.get(row.poolId);
|
||||
const canaryRow = canaryByPoolId.get(row.poolId);
|
||||
const rebalanceRow = rebalanceByPoolId.get(row.poolId);
|
||||
const blockers = new Set(poolBlockers(row));
|
||||
const productionBlockers = new Set();
|
||||
const actions = [];
|
||||
|
||||
if (row.status === "planned") {
|
||||
actions.push(row.protocol === "dodo_pmm" ? "create_or_import_dodo_pool" : "create_or_import_pool");
|
||||
}
|
||||
if (reserveRow?.liveReadStatus === "zero_balances") actions.push("fund_base_and_quote");
|
||||
if (reserveRow?.liveReadStatus === "partial_balance") actions.push("fund_low_side");
|
||||
if (["live_read"].includes(row.status)) actions.push("run_canary");
|
||||
if (canaryRow?.canaryPreflight === "ready") actions.push("execute_canary_swap");
|
||||
if (rebalanceRow?.executionStatus === "operator_review_required") actions.push(...(rebalanceRow.actions || []));
|
||||
|
||||
for (const blocker of canaryRow?.blockers || []) blockers.add(blocker);
|
||||
if (["live_read", "canary_passed", "production"].includes(row.status)) {
|
||||
for (const blocker of rebalanceRow?.blockers || []) blockers.add(blocker);
|
||||
}
|
||||
if (row.status !== "production") productionBlockers.add("not_production_status");
|
||||
|
||||
return {
|
||||
poolId: row.poolId,
|
||||
chainId: row.chainId,
|
||||
network: row.network,
|
||||
protocol: row.protocol,
|
||||
pair: tokenPair(row),
|
||||
status: row.status,
|
||||
poolAddress: row.poolAddress,
|
||||
publicRoutingEnabled: Boolean(row.publicRoutingEnabled),
|
||||
reserveStatus: reserveRow?.liveReadStatus || "not_checked",
|
||||
canaryPreflight: canaryRow?.canaryPreflight || "not_checked",
|
||||
rebalanceStatus: rebalanceRow?.executionStatus || "not_planned",
|
||||
actions: [...new Set(actions)],
|
||||
blockers: [...blockers],
|
||||
productionBlockers: [...productionBlockers],
|
||||
};
|
||||
});
|
||||
|
||||
const blocked = rows.filter((row) => row.blockers.length > 0);
|
||||
const executable = rows.filter((row) => row.blockers.length === 0 && row.actions.length > 0);
|
||||
const readyNoop = rows.filter((row) => row.blockers.length === 0 && row.actions.length === 0);
|
||||
const hardConfigBlockers = rows.filter((row) =>
|
||||
row.blockers.some((blocker) => blocker.startsWith("missing_") || blocker === "missing_pool_address"),
|
||||
);
|
||||
|
||||
const packet = {
|
||||
generatedAt,
|
||||
mode: "read_only_operator_packet",
|
||||
summary: {
|
||||
requiredRows: rows.length,
|
||||
executableRows: executable.length,
|
||||
blockedRows: blocked.length,
|
||||
readyNoopRows: readyNoop.length,
|
||||
hardConfigBlockers: hardConfigBlockers.length,
|
||||
},
|
||||
operatorOrder: [
|
||||
"resolve_hard_config_blockers",
|
||||
"create_or_import_missing_pools",
|
||||
"fund_zero_balance_pools",
|
||||
"run_reserve_reads",
|
||||
"execute_canary_swaps_for_ready_rows",
|
||||
"record_canary_evidence",
|
||||
"promote_reviewed_rows_to_production",
|
||||
"enable_optional_protocol_providers_after_native_pool_canaries",
|
||||
],
|
||||
rows,
|
||||
};
|
||||
|
||||
const md = [
|
||||
"# ALL Mainnet Full Deployment + Funding Packet",
|
||||
"",
|
||||
`- Generated: \`${generatedAt}\``,
|
||||
"- Mode: read-only operator packet; no transactions were executed.",
|
||||
"",
|
||||
table(
|
||||
["Metric", "Count"],
|
||||
Object.entries(packet.summary).map(([key, value]) => [key, value]),
|
||||
),
|
||||
"",
|
||||
"## Executable Rows",
|
||||
"",
|
||||
executable.length
|
||||
? table(["Pool", "Chain", "Protocol", "Pair", "Status", "Actions"], executable.map((row) => [row.poolId, row.chainId, row.protocol, row.pair, row.status, row.actions.join(", ")]))
|
||||
: "_No rows are fully executable without first clearing blockers._",
|
||||
"",
|
||||
"## Hard Config Blockers",
|
||||
"",
|
||||
hardConfigBlockers.length
|
||||
? table(["Pool", "Chain", "Protocol", "Pair", "Status", "Blockers"], hardConfigBlockers.map((row) => [row.poolId, row.chainId, row.protocol, row.pair, row.status, row.blockers.join(", ")]))
|
||||
: "_No hard config blockers._",
|
||||
"",
|
||||
"## Blocked Rows",
|
||||
"",
|
||||
blocked.length
|
||||
? table(["Pool", "Chain", "Protocol", "Pair", "Status", "Reserve", "Canary", "Blockers"], blocked.map((row) => [row.poolId, row.chainId, row.protocol, row.pair, row.status, row.reserveStatus, row.canaryPreflight, row.blockers.join(", ")]))
|
||||
: "_No blocked rows._",
|
||||
"",
|
||||
].join("\n");
|
||||
|
||||
mkdirSync(resolve(repoRoot, "reports/status"), { recursive: true });
|
||||
writeFileSync(jsonOut, `${JSON.stringify(packet, null, 2)}\n`);
|
||||
writeFileSync(mdOut, `${md}\n`);
|
||||
console.log(`[OK] ALL Mainnet deployment/funding packet written: ${jsonOut}`);
|
||||
155
scripts/status/plan-all-mainnet-rebalance.mjs
Normal file
155
scripts/status/plan-all-mainnet-rebalance.mjs
Normal file
@@ -0,0 +1,155 @@
|
||||
#!/usr/bin/env node
|
||||
/**
|
||||
* Build a read-only ALL Mainnet rebalance plan.
|
||||
*
|
||||
* This intentionally does not execute transfers or swaps. It consumes the
|
||||
* canonical pool matrix plus the latest reserve-read report, then emits
|
||||
* operator-reviewable intents for rows that are eligible for rebalancing.
|
||||
*/
|
||||
|
||||
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
||||
import { resolve } from "node:path";
|
||||
|
||||
const repoRoot = resolve(new URL("../..", import.meta.url).pathname);
|
||||
const matrixPath = resolve(repoRoot, "config/all-mainnet-pool-creation-matrix.json");
|
||||
const reserveReportPath = resolve(repoRoot, "reports/status/all-mainnet-required-pool-balances-latest.json");
|
||||
const outPath = resolve(repoRoot, "reports/status/all-mainnet-rebalance-plan-latest.json");
|
||||
|
||||
const eligibleStatuses = new Set(["live_read", "canary_passed", "production"]);
|
||||
const productionStatuses = new Set(["canary_passed", "production"]);
|
||||
|
||||
function readJson(path) {
|
||||
return JSON.parse(readFileSync(path, "utf8"));
|
||||
}
|
||||
|
||||
function asBigInt(value) {
|
||||
try {
|
||||
return BigInt(value || "0");
|
||||
} catch {
|
||||
return 0n;
|
||||
}
|
||||
}
|
||||
|
||||
function ratioBps(a, b) {
|
||||
if (a === 0n && b === 0n) return null;
|
||||
const high = a > b ? a : b;
|
||||
const low = a > b ? b : a;
|
||||
if (high === 0n) return null;
|
||||
return Number(((high - low) * 10_000n) / high);
|
||||
}
|
||||
|
||||
function reserveEvidenceFor(row, reserveByPoolId) {
|
||||
const live = reserveByPoolId.get(row.poolId);
|
||||
if (live) {
|
||||
return {
|
||||
source: "latest_reserve_report",
|
||||
liveReadStatus: live.liveReadStatus,
|
||||
baseBalanceRaw: live.baseBalanceRaw,
|
||||
quoteBalanceRaw: live.quoteBalanceRaw,
|
||||
poolHasCode: live.poolHasCode,
|
||||
errors: live.errors || [],
|
||||
};
|
||||
}
|
||||
if (row.reserveEvidence) {
|
||||
return {
|
||||
source: "matrix_reserve_evidence",
|
||||
liveReadStatus: row.reserveEvidence.liveReadStatus,
|
||||
baseBalanceRaw: row.reserveEvidence.baseBalanceRaw,
|
||||
quoteBalanceRaw: row.reserveEvidence.quoteBalanceRaw,
|
||||
poolHasCode: row.reserveEvidence.poolHasCode,
|
||||
errors: [],
|
||||
};
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function planForRow(row, evidence) {
|
||||
const policy = row.policy || {};
|
||||
const blockers = [];
|
||||
const actions = [];
|
||||
|
||||
if (!row.requiredForSpend) blockers.push("not_required_for_spend");
|
||||
if (!eligibleStatuses.has(row.status)) blockers.push(`status_not_rebalance_eligible:${row.status}`);
|
||||
if (!row.poolAddress) blockers.push("missing_pool_address");
|
||||
if (!row.baseToken?.address) blockers.push(`missing_base_address:${row.baseToken?.symbol || "unknown"}`);
|
||||
if (!row.quoteToken?.address) blockers.push(`missing_quote_address:${row.quoteToken?.symbol || "unknown"}`);
|
||||
if (!evidence) blockers.push("missing_reserve_evidence");
|
||||
|
||||
const base = asBigInt(evidence?.baseBalanceRaw);
|
||||
const quote = asBigInt(evidence?.quoteBalanceRaw);
|
||||
const imbalanceBps = ratioBps(base, quote);
|
||||
|
||||
if (evidence) {
|
||||
if (evidence.poolHasCode !== true) blockers.push("pool_code_not_confirmed");
|
||||
if (evidence.errors?.length) blockers.push("reserve_read_errors");
|
||||
if (evidence.liveReadStatus === "partial_balance") actions.push("refill_empty_or_low_side");
|
||||
if (evidence.liveReadStatus === "zero_balances") actions.push("fund_both_sides_before_rebalance");
|
||||
if (evidence.liveReadStatus === "missing_pool_address") blockers.push("reserve_report_missing_pool_address");
|
||||
if (evidence.liveReadStatus === "missing_token_address") blockers.push("reserve_report_missing_token_address");
|
||||
}
|
||||
|
||||
if (base === 0n && quote > 0n) actions.push("fund_base_side");
|
||||
if (quote === 0n && base > 0n) actions.push("fund_quote_side");
|
||||
if (base > 0n && quote > 0n && imbalanceBps !== null && imbalanceBps >= (policy.refillTriggerBps || 200)) {
|
||||
actions.push("quote_and_rebalance_to_target_inventory");
|
||||
}
|
||||
if (actions.length === 0 && blockers.length === 0) actions.push("monitor_no_rebalance_required");
|
||||
|
||||
return {
|
||||
poolId: row.poolId,
|
||||
chainId: row.chainId,
|
||||
network: row.network,
|
||||
protocol: row.protocol,
|
||||
status: row.status,
|
||||
productionRouteEligible: productionStatuses.has(row.status) && blockers.length === 0,
|
||||
baseToken: row.baseToken,
|
||||
quoteToken: row.quoteToken,
|
||||
poolAddress: row.poolAddress,
|
||||
policy: {
|
||||
maxPriceImpactBps: policy.maxPriceImpactBps ?? 100,
|
||||
minReserveUsd: policy.minReserveUsd ?? 1000,
|
||||
refillTriggerBps: policy.refillTriggerBps ?? 200,
|
||||
pauseOnReserveReadFailure: policy.pauseOnReserveReadFailure ?? true,
|
||||
},
|
||||
reserveEvidence: evidence,
|
||||
imbalanceBps,
|
||||
actions: [...new Set(actions)],
|
||||
blockers: [...new Set(blockers)],
|
||||
executionStatus: blockers.length ? "blocked" : actions.includes("monitor_no_rebalance_required") ? "no_action" : "operator_review_required",
|
||||
};
|
||||
}
|
||||
|
||||
const matrix = readJson(matrixPath);
|
||||
const reserveReport = existsSync(reserveReportPath) ? readJson(reserveReportPath) : null;
|
||||
const reserveByPoolId = new Map((reserveReport?.results || []).map((row) => [row.poolId, row]));
|
||||
const generatedAt = new Date().toISOString();
|
||||
|
||||
const rows = matrix.rows.filter((row) => row.requiredForSpend === true);
|
||||
const intents = rows.map((row) => planForRow(row, reserveEvidenceFor(row, reserveByPoolId)));
|
||||
const actionable = intents.filter((intent) => intent.executionStatus === "operator_review_required");
|
||||
const blocked = intents.filter((intent) => intent.executionStatus === "blocked");
|
||||
const noAction = intents.filter((intent) => intent.executionStatus === "no_action");
|
||||
|
||||
const payload = {
|
||||
generatedAt,
|
||||
sourceMatrix: "config/all-mainnet-pool-creation-matrix.json",
|
||||
sourceReserveReport: existsSync(reserveReportPath) ? "reports/status/all-mainnet-required-pool-balances-latest.json" : null,
|
||||
mode: "read_only_plan",
|
||||
executionGuardrails: [
|
||||
"This report never executes swaps or transfers.",
|
||||
"An execution wrapper must require an explicit --execute flag.",
|
||||
"Rows with reserve read errors or missing code must pause, not rebalance.",
|
||||
"Optional protocol rows are excluded until they become requiredForSpend or production-route eligible.",
|
||||
],
|
||||
summary: {
|
||||
requiredRows: rows.length,
|
||||
actionableRows: actionable.length,
|
||||
blockedRows: blocked.length,
|
||||
noActionRows: noAction.length,
|
||||
},
|
||||
intents,
|
||||
};
|
||||
|
||||
mkdirSync(resolve(repoRoot, "reports/status"), { recursive: true });
|
||||
writeFileSync(outPath, `${JSON.stringify(payload, null, 2)}\n`);
|
||||
console.log(`[OK] ALL Mainnet rebalance plan written: ${outPath}`);
|
||||
Reference in New Issue
Block a user