chore: sync submodule state (parent ref update)
Made-with: Cursor
This commit is contained in:
156
docs/08-simulation-model.md
Normal file
156
docs/08-simulation-model.md
Normal file
@@ -0,0 +1,156 @@
|
||||
# Two-Layer Routing Simulation Model
|
||||
|
||||
Design graph vs deployed graph; multi-chain supergraph; edge types; PMM edge function; router optimization; scenario-based simulation; and the three key metrics.
|
||||
|
||||
---
|
||||
|
||||
## 1. Two-layer model
|
||||
|
||||
- **Design graph** — What *could* route: 11 EVM chains, hub per chain, cW* tokens and anchor stables as defined in `config/token-map.json`, `config/chains.json`, `config/pool-matrix.json`. No per-chain addresses; topology and assumed liquidity/fees only.
|
||||
- **Deployed graph** — What *actually* routes: filled from `config/deployment-status.json` (cw token addresses, anchor addresses, PMM pool addresses and params). Until that is populated, simulation is **structural** (topology + assumed params), not empirical (real addresses, depths, aggregator behavior).
|
||||
|
||||
Until deployment state is filled, run **scenario-based** simulation only.
|
||||
|
||||
---
|
||||
|
||||
## 2. Multi-chain routing supergraph
|
||||
|
||||
**Nodes:** `(chain c, token t)`. Examples: `(56, cWUSDC)`, `(137, USDT)`, `(42161, DAI)`.
|
||||
|
||||
### Edge types
|
||||
|
||||
**A) DEX swap edge (PMM or AMM)**
|
||||
|
||||
```
|
||||
(c, t_a) --[swap]--> (c, t_b)
|
||||
```
|
||||
|
||||
Stateful output: `y = f_e(x; s_e)` (output amount depends on input size and pool state).
|
||||
|
||||
**B) Bridge edge (cross-chain transfer)**
|
||||
|
||||
```
|
||||
(c_i, cWUSDC) --[bridge]--> (c_j, cWUSDC)
|
||||
```
|
||||
|
||||
Bridge cost model (with optional latency risk premium):
|
||||
|
||||
- **Base:** `y = x * (1 - β_ij) - γ_ij`
|
||||
- `β_ij`: fractional bridge fee/slippage
|
||||
- `γ_ij`: fixed cost (gas + messaging + relayer)
|
||||
- **With latency risk:** `y = x * (1 - β_ij) - γ_ij - ρ(Δt) * x`
|
||||
- `ρ(Δt)`: penalty increasing with bridge finality time (e.g. piecewise linear in Δt). Stops the sim from overestimating “free” cross-chain loop arb; include bridge latency and probabilistic settlement delay so cross-chain arbitrage loops are not under-penalized.
|
||||
|
||||
**C) Mint/Burn to Home (ChainID 138)**
|
||||
|
||||
If 138 is the canonical issuer and redemption is allowed:
|
||||
|
||||
```
|
||||
(138, cUSDC) <--> (c, cWUSDC)
|
||||
```
|
||||
|
||||
Model as bridge-like edges with their own fees, latency, and risk.
|
||||
|
||||
---
|
||||
|
||||
## 3. Single-sided PMM edge function (router drain risk)
|
||||
|
||||
For each public chain `c` and cW token `T`, edge pools are:
|
||||
|
||||
```
|
||||
(c, T) <--> (c, Q) where Q ∈ {USDT, USDC, DAI, BUSD, mUSD}
|
||||
```
|
||||
|
||||
(availability of Q differs by chain.)
|
||||
|
||||
Use an oracle-anchored, inventory-sensitive slippage function (PMM-like). Practical form:
|
||||
|
||||
- `y(x) = (1 - φ) * P * [ x - k * ( x - D * ln(1 + x/D) ) ]`
|
||||
- `P`: oracle price (≈ 1 for USD pegs; EURUSD-based for EUR pegs)
|
||||
- `k`: curvature (lower = tighter peg, more attractive to routers)
|
||||
- `φ`: fee (e.g. bps)
|
||||
- **Effective depth** (key for router drain):
|
||||
- `D = D_0 * min(1, I_T / I_T^*)`
|
||||
- `I_T`: remaining inventory of T in the pool; `I_T^*`: target/baseline inventory.
|
||||
|
||||
As inventory is drained, D drops and marginal rate worsens, reproducing “routers drain LP until marginal rate worsens.”
|
||||
|
||||
---
|
||||
|
||||
## 4. Router behavior = flow optimization with path splitting
|
||||
|
||||
Aggregators choose 1–N paths and split flow. For input `X` converting `(c, S) → (c, T)`:
|
||||
|
||||
- Choose paths `P_i` and allocations `x_i` with `max_{x_i ≥ 0} Σ_i F_{P_i}(x_i)` s.t. `Σ_i x_i = X`.
|
||||
- At optimum, **marginal output equalizes** across used paths: `d/dx F_{P_i}(x_i) = λ`.
|
||||
|
||||
So PMM pools are “mined” for inventory: as long as their marginal rate is best, routers keep allocating to them.
|
||||
|
||||
**Cross-chain:** For routes `(c_1, S) → … → (c_2, T)` including bridge edges, a bridge+swap route is chosen when:
|
||||
|
||||
- effective cost = (swap impact + fees on DEX edges) + (bridge fee + gas + latency risk on bridge edges)
|
||||
is lower than alternatives.
|
||||
|
||||
If PMM pools are too tight (low k, low fee), they become preferred entry/exit ramps on many chains → inventory oscillation and frequent bot intervention.
|
||||
|
||||
---
|
||||
|
||||
## 5. What you can simulate right now (design-only)
|
||||
|
||||
**A) Design routing stress test**
|
||||
|
||||
Assume: all 11 chains; hub quote per chain; one PMM pool per cW token vs hub; optional extra quote pools on some chains. Run:
|
||||
|
||||
- Stable-to-stable demand per chain
|
||||
- Random bridge inflow/outflow shocks
|
||||
- “Arb/MEV” agents that trade toward oracle when profitable
|
||||
|
||||
Outputs:
|
||||
|
||||
- Inventory drawdown distributions per cW token per chain
|
||||
- Frequency/size of bot interventions
|
||||
- How often routers pick your pools vs alternatives
|
||||
|
||||
**B) Topology sensitivity**
|
||||
|
||||
Compare:
|
||||
|
||||
- **Hub model:** only `cW* / USDC` (or hub) per chain
|
||||
- **Full quote model:** `cW* / {USDC, USDT, DAI, BUSD, mUSD}`
|
||||
|
||||
Typically: full quote increases route cycles, MEV, and inventory churn; hub model reduces reflexivity and control costs.
|
||||
|
||||
---
|
||||
|
||||
## 6. Moving to deployment-realistic simulation
|
||||
|
||||
Use **`config/deployment-status.json`** (see below) to define:
|
||||
|
||||
- Per chain: cW token addresses, anchor stable addresses, which PMM pools exist and their params (fee, k, initial liquidity), and whether each pool is “defense” vs “public routing.”
|
||||
|
||||
With that, you can simulate: reachable routes (graph correctness), pool parameters (k, fee), and bridge availability — even before feeding real pool balances.
|
||||
|
||||
---
|
||||
|
||||
## 7. Three metrics to watch
|
||||
|
||||
1. **Router capture ratio**
|
||||
- `capture(T, c) = (volume routed through your PMM pools) / (total relevant stable volume on chain c for token T)`
|
||||
|
||||
2. **Inventory churn**
|
||||
- `churn(T, c) = Σ_t |ΔI_{T,t}| / I_T^*`
|
||||
- High churn → expensive rebalancing and bot intervention.
|
||||
|
||||
3. **Intervention cost**
|
||||
- Bridge/mint/burn volume and cost needed to keep pegs inside band.
|
||||
|
||||
Interpretation: aim to be a **peg stabilizer** (good); avoid becoming the **global routing venue** (expensive).
|
||||
|
||||
---
|
||||
|
||||
## 8. Config and params
|
||||
|
||||
- **Design graph:** `config/token-map.json`, `config/chains.json`, `config/pool-matrix.json`
|
||||
- **Deployed graph:** `config/deployment-status.json`
|
||||
- **Simulation parameters:** `config/simulation-params.json` (hub per chain, default k, fee, inventory targets)
|
||||
- **Peg bands:** `config/peg-bands.json`
|
||||
50
docs/09-simulation-params-sheet.md
Normal file
50
docs/09-simulation-params-sheet.md
Normal file
@@ -0,0 +1,50 @@
|
||||
# First-pass simulation parameter sheet
|
||||
|
||||
Design-only consistent defaults for scenario-based simulation. Source: [../config/simulation-params.json](../config/simulation-params.json).
|
||||
|
||||
---
|
||||
|
||||
## Default PMM (global)
|
||||
|
||||
| Param | Value | Notes |
|
||||
|-------|--------|-------|
|
||||
| k | 0.1 | Curvature; lower = tighter peg |
|
||||
| feeBps | 25 | Fee in basis points |
|
||||
| inventoryTargetUnits | 1_000_000 | I_T^* baseline |
|
||||
| depthD0Units | 500_000 | D_0 for depth formula |
|
||||
|
||||
---
|
||||
|
||||
## Per-chain parameters (11 design chains)
|
||||
|
||||
| Chain | Name | Hub | k | feeBps | Inventory target | bridgeBeta | bridgeGamma |
|
||||
|-------|------|-----|---|--------|------------------|-----------|-------------|
|
||||
| 1 | Ethereum Mainnet | USDC | 0.1 | 25 | 1_000_000 | 0.001 | 50 |
|
||||
| 10 | Optimism | USDC | 0.1 | 25 | 500_000 | 0.001 | 20 |
|
||||
| 25 | Cronos | USDT | 0.12 | 30 | 300_000 | 0.002 | 15 |
|
||||
| 56 | BSC (BNB Chain) | USDT | 0.1 | 25 | 800_000 | 0.001 | 10 |
|
||||
| 100 | Gnosis Chain | USDC | 0.12 | 30 | 400_000 | 0.0015 | 15 |
|
||||
| 137 | Polygon | USDC | 0.1 | 25 | 600_000 | 0.001 | 5 |
|
||||
| 42161 | Arbitrum One | USDC | 0.1 | 25 | 500_000 | 0.001 | 15 |
|
||||
| 8453 | Base | USDC | 0.1 | 25 | 400_000 | 0.001 | 10 |
|
||||
| 43114 | Avalanche C-Chain | USDC | 0.11 | 28 | 350_000 | 0.0015 | 20 |
|
||||
| 42220 | Celo | USDC | 0.12 | 30 | 300_000 | 0.002 | 15 |
|
||||
| 1111 | Wemix | USDT | 0.12 | 30 | 250_000 | 0.002 | 20 |
|
||||
|
||||
- **bridgeBeta:** fractional bridge fee/slippage (β_ij).
|
||||
- **bridgeGammaUnits:** fixed cost units (γ_ij) for gas + messaging + relayer (nominal).
|
||||
|
||||
---
|
||||
|
||||
## Scenario defaults
|
||||
|
||||
- **Design routing stress test:** Assume all 11 chains; one PMM per cW token vs hub; optional extra quote pools on chains 1, 56, 137.
|
||||
- **Topology sensitivity:** Hub model = all chains; full-quote model = chains 1, 56, 137 only (compare capture, churn, intervention cost).
|
||||
|
||||
---
|
||||
|
||||
## Usage
|
||||
|
||||
1. Run **design-only** scenario sims using `simulation-params.json` (no addresses required).
|
||||
2. When deployment data exists, fill `deployment-status.json` per chain (cwTokens, anchorAddresses, pmmPools, bridgeAvailable).
|
||||
3. Iterate k/fee and inventory targets from sim outputs (router capture ratio, inventory churn, intervention cost). See [08-simulation-model.md](08-simulation-model.md) §7.
|
||||
134
docs/10-behavioral-stability-analysis.md
Normal file
134
docs/10-behavioral-stability-analysis.md
Normal file
@@ -0,0 +1,134 @@
|
||||
# Behavioral Stability Analysis
|
||||
|
||||
From architecture to **behavioral stability**: what the two-layer + PMM stack enables, how the three metrics interact, what to simulate first, and where the system can break.
|
||||
|
||||
---
|
||||
|
||||
## 1. What you have systemically
|
||||
|
||||
### Layer A — Design graph
|
||||
|
||||
- “What could route”: all 11 chains, all potential cW* pools.
|
||||
- Lets you simulate **future expansion** before deploying.
|
||||
- Prevents accidental routing exposure when adding pools.
|
||||
|
||||
### Layer B — Deployment graph
|
||||
|
||||
- “What actually routes”: defined by `config/deployment-status.json`.
|
||||
- **Kill switch**: remove a pool from deployment-status to disable routing.
|
||||
- Acts as exposure registry, routing firewall, expansion throttle.
|
||||
|
||||
That separation is central-bank-grade control: programmable monetary corridor, not just liquidity.
|
||||
|
||||
---
|
||||
|
||||
## 2. PMM depth as state variable
|
||||
|
||||
Depth:
|
||||
|
||||
```
|
||||
D = D_0 · min(1, I_T / I_T^*)
|
||||
```
|
||||
|
||||
This gives:
|
||||
|
||||
- **Self-limiting router exposure**: drain → D drops → marginal rate worsens.
|
||||
- **Endogenous slippage widening**: no ad-hoc circuit breaker needed for normal stress.
|
||||
- **Routers drain you → marginal rate worsens → routers leave.**
|
||||
|
||||
So the mechanism is **mathematically stabilizing**.
|
||||
|
||||
---
|
||||
|
||||
## 3. Three metrics — economic interpretation
|
||||
|
||||
| Metric | Economic meaning | Target / risk |
|
||||
|--------|------------------|----------------|
|
||||
| **Router capture ratio** | Are you the primary stable swap venue? | High capture = revenue + inventory risk. Low = safer peg, less fee income. |
|
||||
| **Inventory churn** | Stress metric: Σ\|ΔI_T\| / I_T^* per epoch | Healthy: 0.3–0.8 normal, <1.5 stress. If churn >1.5–2.0, bot intervenes constantly. |
|
||||
| **Intervention cost** | “Monetary defense budget”: bridge/mint/burn to keep peg | Linear in volume → OK. Exponential during topology switch → danger. |
|
||||
|
||||
---
|
||||
|
||||
## 4. What to simulate first
|
||||
|
||||
### A) Hub-only across all 11 chains
|
||||
|
||||
One PMM per cW per chain vs hub.
|
||||
|
||||
**Questions:**
|
||||
|
||||
- Does router capture stabilize around **10–30%**?
|
||||
- Does churn remain **<1** under normal volume?
|
||||
- Is intervention frequency **periodic** rather than constant?
|
||||
|
||||
**This is the baseline.**
|
||||
|
||||
### B) Full-quote on chains 1, 56, 137
|
||||
|
||||
Enable extra quotes (USDT, DAI, etc.) only on Ethereum, BSC, Polygon.
|
||||
|
||||
**Watch for:**
|
||||
|
||||
- Multi-hop reflexivity
|
||||
- Increased churn
|
||||
- Increased router capture
|
||||
- **Nonlinear** intervention cost
|
||||
|
||||
**Rule of thumb:** If churn increases >50% vs hub model → do not deploy full-quote.
|
||||
|
||||
### C) Bridge shock scenario
|
||||
|
||||
Inject e.g.:
|
||||
|
||||
- 5% supply migration 137 → 56 over 24 blocks, or
|
||||
- 10% whale exit on one chain
|
||||
|
||||
**Measure:**
|
||||
|
||||
- Time to re-center peg
|
||||
- Total bot injection required
|
||||
- Peak deviation
|
||||
|
||||
**Interpretation:**
|
||||
|
||||
- **Damped oscillator** → good.
|
||||
- **Resonant feedback loop** → bad.
|
||||
|
||||
---
|
||||
|
||||
## 5. Where it can break (advanced)
|
||||
|
||||
### Cross-chain arbitrage loops
|
||||
|
||||
If **bridge cost < slippage difference**, routers do: Chain A → bridge → Chain B → swap → bridge back.
|
||||
|
||||
**Model must include:** bridge latency + probabilistic settlement delay. Otherwise risk is underestimated.
|
||||
|
||||
### k too tight globally
|
||||
|
||||
Default k = 0.1, fee = 25 bps. If inventory target is high and k is tight, you can become the cheapest stable venue on thin chains.
|
||||
|
||||
**Simulate:** k ∈ {0.05, 0.1, 0.2}. Often **k = 0.15–0.2** is safer cross-chain.
|
||||
|
||||
### EUR tokens (cWEURC, cWEURT)
|
||||
|
||||
- FX volatility; USD-quoted hubs; dual-source peg risk.
|
||||
- Need: **slightly higher k**, **slightly wider band**, possibly **higher fee**.
|
||||
- Do **not** treat EUR and USD tokens symmetrically.
|
||||
|
||||
---
|
||||
|
||||
## 6. System-level framing
|
||||
|
||||
The architecture is a **multi-chain programmable monetary corridor**. Each PMM pool is a **localized peg defense membrane**. `deployment-status.json` is the exposure registry, routing firewall, and expansion throttle.
|
||||
|
||||
---
|
||||
|
||||
## 7. Next steps (options)
|
||||
|
||||
1. Run a synthetic 30-day stress sim and extract equilibrium metrics.
|
||||
2. Derive analytical stability conditions for k, fee, D_0.
|
||||
3. Design adaptive k control law (automatic routing dampener).
|
||||
4. Model MEV + oracle-lag attack surface.
|
||||
5. **Derive safe inventory target sizing formula per chain** → see [11-safe-inventory-sizing.md](11-safe-inventory-sizing.md).
|
||||
112
docs/11-safe-inventory-sizing.md
Normal file
112
docs/11-safe-inventory-sizing.md
Normal file
@@ -0,0 +1,112 @@
|
||||
# Safe Inventory Target Sizing (Closed-Form Approximation)
|
||||
|
||||
A closed-form approximation for **I_T^*** (inventory target) per chain so capital allocation can be justified mathematically instead of heuristically. Inputs: expected routed volume, bridge β/γ, refill latency, and target band.
|
||||
|
||||
---
|
||||
|
||||
## 1. Objective
|
||||
|
||||
Choose **I_T^*** per chain and per cW token so that:
|
||||
|
||||
1. With high probability we do **not** deplete inventory before bridge/mint can refill.
|
||||
2. Peg stays inside the target band during normal and stressed flow.
|
||||
3. Intervention cost (bridge/mint/burn) remains bounded and preferably linear in volume.
|
||||
|
||||
---
|
||||
|
||||
## 2. Assumptions
|
||||
|
||||
- **Epoch**: time window over which we measure flow (e.g. 1 hour or “refill cycle”).
|
||||
- **V_epoch**: expected **net outflow** of cW token from the pool during one epoch (routed volume, one-sided; we conservatively use net outflow).
|
||||
- **σ**: volatility multiplier for V (e.g. 1.5–2 for “stress”); so worst-case net outflow in one epoch is on the order of **V_epoch · σ**.
|
||||
- **T_refill**: refill latency (time or blocks) for bridge/mint to restore inventory on this chain.
|
||||
- **β**: bridge fee (fraction) for refill path; **γ**: fixed cost per refill (gas + relayer).
|
||||
- **Band**: we require that after a shock we do not breach the circuit-break band (e.g. 2% for USD). That effectively caps how far inventory can fall before we must intervene.
|
||||
|
||||
---
|
||||
|
||||
## 3. First-order formula
|
||||
|
||||
**Safe inventory target (units of cW token):**
|
||||
|
||||
```
|
||||
I_T^* ≥ V_epoch · σ · (1 + T_refill / T_epoch) / (1 - β) + γ_buffer
|
||||
```
|
||||
|
||||
**Interpretation:**
|
||||
|
||||
- **V_epoch · σ**: worst-case net outflow in one epoch.
|
||||
- **T_refill / T_epoch**: number of “epochs” in one refill cycle; we need to cover outflow over that period without going to zero.
|
||||
- **(1 − β)**: bridge fee reduces effective refill; we size so that after fee we still refill enough.
|
||||
- **γ_buffer**: small buffer for fixed costs (e.g. one or a few refill batches); can be set to a multiple of γ or a constant.
|
||||
|
||||
**Simpler variant (single refill cycle):**
|
||||
|
||||
If refill is exactly one epoch and we want to absorb one full shock without depleting:
|
||||
|
||||
```
|
||||
I_T^* ≥ V_epoch · σ / (1 - β) + buffer
|
||||
```
|
||||
|
||||
**buffer** = small constant or γ · (typical refill count per epoch).
|
||||
|
||||
---
|
||||
|
||||
## 4. Per-chain inputs (from your config)
|
||||
|
||||
From `config/simulation-params.json` and `config/token-map.json`:
|
||||
|
||||
- **β** = `bridgeBeta` for the chain (refill path).
|
||||
- **γ** = `bridgeGammaUnits` (nominal; use for γ_buffer if desired).
|
||||
- **V_epoch**: not in config; must be estimated or taken from simulation (e.g. expected routed volume per epoch for that chain/token).
|
||||
- **σ**: e.g. 1.5–2 for stress.
|
||||
- **T_refill, T_epoch**: in blocks or seconds; chain-dependent (e.g. 1 epoch = 1 hour, T_refill = 20 min → T_refill/T_epoch ≈ 1/3).
|
||||
|
||||
---
|
||||
|
||||
## 5. Depth consistency (D_0 vs I_T^*)
|
||||
|
||||
Your PMM uses **D = D_0 · min(1, I_T / I_T^*)**. For the pool to stay “deep” enough under stress:
|
||||
|
||||
- **D_0** should be sized so that at **I_T = I_T^***, the pool can absorb a typical trade size without slipping past the band. A simple rule: **D_0** on the order of **I_T^* / 2** to **I_T^*** (so that at target inventory, effective depth is meaningful). So:
|
||||
|
||||
```
|
||||
D_0 ≈ (0.5 to 1.0) · I_T^*
|
||||
```
|
||||
|
||||
Then the formula above gives **I_T^***; set **D_0** accordingly.
|
||||
|
||||
---
|
||||
|
||||
## 6. EUR tokens (cWEURC, cWEURT)
|
||||
|
||||
- Same formula applies, but use **EUR-specific** expected volume and, if refill is via a different path, **EUR bridge β/γ**.
|
||||
- Use **wider band** (and possibly higher σ) to reflect FX and dual-source peg risk; that may imply a **larger buffer** or **higher σ** in the sizing formula.
|
||||
|
||||
---
|
||||
|
||||
## 7. Usage
|
||||
|
||||
1. **Estimate V_epoch** per chain (and per token if needed) from historical or simulated routed volume.
|
||||
2. Set **σ** (e.g. 1.5–2) and **T_refill / T_epoch** from chain/contract data.
|
||||
3. Read **β** (and optionally **γ**) from `simulation-params.json`.
|
||||
4. Compute **I_T^*** from the formula; optionally add **γ_buffer**.
|
||||
5. Set **D_0 ≈ (0.5–1) · I_T^*** for that pool.
|
||||
6. Put **inventoryTargetUnits** (and depth) into `simulation-params.json` or `deployment-status.json` and run simulations to validate churn and intervention cost.
|
||||
|
||||
This gives a **justified starting point** for capital allocation per chain; tune from there using the three metrics (capture, churn, intervention cost) and stress tests (hub-only, full-quote, bridge shock).
|
||||
|
||||
---
|
||||
|
||||
## 8. Example first pass (chains 1, 56, 137, 25)
|
||||
|
||||
Assumptions: σ = 1.5 (USD), σ = 2 (EUR); T_refill/T_epoch = 0.33; γ_buffer = 2·γ. Formula: I_T^* ≥ V_epoch·σ·(1 + 0.33)/(1 − β) + γ_buffer; D_0 = 0.75·I_T^*.
|
||||
|
||||
| Chain | Name | Hub | β | γ | V_epoch (example) | I_T^* (USD) | I_T^* (EUR) | D_0 (USD) |
|
||||
|-------|---------|------|-------|----|-------------------|-------------|-------------|-----------|
|
||||
| 1 | Ethereum| USDC | 0.001 | 50 | 100_000 | ~200k | ~266k | ~150k |
|
||||
| 56 | BSC | USDT | 0.001 | 10 | 80_000 | ~160k | ~213k | ~120k |
|
||||
| 137 | Polygon | USDC | 0.001 | 5 | 60_000 | ~120k | ~160k | ~90k |
|
||||
| 25 | Cronos | USDT | 0.002 | 15 | 30_000 | ~60k | ~80k | ~45k |
|
||||
|
||||
Run `node scripts/size-inventory.cjs` or `node scripts/size-inventory.cjs --v-epoch '{"1":100000,"56":80000,"137":60000,"25":30000}'` to regenerate from your `simulation-params.json`. Use **k = 0.15–0.2** on thin chains (e.g. Cronos) if sims show excessive capture; EUR tokens use `eurDefaults` (higher k, σ, feeBps).
|
||||
135
docs/12-sim-scorecard.md
Normal file
135
docs/12-sim-scorecard.md
Normal file
@@ -0,0 +1,135 @@
|
||||
# Simulation Scorecard Contract
|
||||
|
||||
Simulator runs must emit a **scorecard JSON** so results are comparable and deployability can be gated. This document defines the output schema and pass/fail gates.
|
||||
|
||||
---
|
||||
|
||||
## 1. Scorecard JSON schema
|
||||
|
||||
Every run (hub-only, full-quote, bridge shock) should produce a scorecard with at least:
|
||||
|
||||
| Field | Type | Description |
|
||||
|-------|------|--------------|
|
||||
| `capture_mean` | number | Mean router capture ratio (fraction 0–1) across chains/tokens |
|
||||
| `capture_p95` | number | 95th percentile capture |
|
||||
| `churn_mean` | number | Mean inventory churn per epoch |
|
||||
| `churn_p95` | number | 95th percentile churn |
|
||||
| `churn_max` | number | Max churn observed |
|
||||
| `intervention_cost_total` | number | Total intervention cost (bridge/mint/burn) in run |
|
||||
| `intervention_cost_per_1M_volume` | number | Intervention cost per 1M routed volume |
|
||||
| `peak_deviation_bps` | number | Peak peg deviation in basis points |
|
||||
| `reflexive_route_count` | number | Count of multi-hop routes through multiple PMM pools (reflexivity) |
|
||||
| `drain_half_life_epochs` | object | Per (token, chain): epochs until PMM inventory halves under routing pressure; **too short = routing magnet** |
|
||||
| `path_concentration_index` | number | HHI on path shares (0–1); **high = you dominate execution**; lower = flow diversified (safer) |
|
||||
| `arb_volume_total` | number | Total volume traded by arb step (PR#2) |
|
||||
| `arb_profit_total` | number | Arb profit from **execution** (actual PMM output vs oracle), not mid (PR#2 refinement) |
|
||||
| `peak_deviation_bps_pre_arb` | number | Max pool \|δ\| before arb step (diagnostic: is arb doing the work?) |
|
||||
| `peak_deviation_bps_post_arb` | number | Max pool \|δ\| after arb (current primary gate) |
|
||||
| `peak_deviation_bps_post_bot` | number | Max pool \|δ\| after bot (inventory rebalancing effect) |
|
||||
| `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 |
|
||||
| `scenario` | string | e.g. `hub_only_11`, `full_quote_1_56_137`, `bridge_shock_137_56` |
|
||||
| `runId` | string | Optional run identifier |
|
||||
|
||||
**Example (minimal):**
|
||||
|
||||
```json
|
||||
{
|
||||
"scenario": "hub_only",
|
||||
"capture_mean": 0.18,
|
||||
"capture_p95": 0.28,
|
||||
"churn_mean": 0.45,
|
||||
"churn_p95": 0.82,
|
||||
"churn_max": 1.1,
|
||||
"intervention_cost_total": 1200,
|
||||
"intervention_cost_per_1M_volume": 8.5,
|
||||
"peak_deviation_bps": 18,
|
||||
"reflexive_route_count": 0
|
||||
}
|
||||
```
|
||||
|
||||
A machine-readable schema lives in `config/scorecard-schema.json` for validation.
|
||||
|
||||
---
|
||||
|
||||
## 2. Pass/fail gates (“deployable” scenarios)
|
||||
|
||||
From [10-behavioral-stability-analysis.md](10-behavioral-stability-analysis.md):
|
||||
|
||||
| Gate | Condition | Rationale |
|
||||
|------|-----------|-----------|
|
||||
| **Churn (normal)** | `churn_mean` in [0.3, 0.8] | Healthy baseline |
|
||||
| **Churn (stress)** | `churn_max` < 1.5 | Avoid constant bot intervention |
|
||||
| **Capture (baseline)** | `capture_mean` in [0.10, 0.30] | Peg stabilizer, not global venue |
|
||||
| **Intervention** | `intervention_cost_per_1M_volume` stable (no explosive jump vs baseline) | Linear in volume |
|
||||
| **Full-quote vs hub** | If full-quote: `churn_mean` increase vs hub < 50% | Don’t deploy full-quote if churn jumps >50% |
|
||||
| **Peak deviation** | `peak_deviation_bps` below circuit-break (e.g. 200 bps USD) | Stay inside band |
|
||||
| **Drain half-life** | `drain_half_life_epochs` not collapsing under full-quote vs hub | Routing magnet check |
|
||||
| **Path concentration** | `path_concentration_index` not spiking during bridge shock | Diversified routing |
|
||||
| **Reflexivity** | `reflexive_route_count` low relative to total routes | Avoid feedback loops |
|
||||
|
||||
**Sanity checks (PR#2):** Arb volume should rise when k is tight; bot interventions should rise when inventory targets are low.
|
||||
|
||||
**Pass:** All gates satisfied for the scenario.
|
||||
**Fail:** Any gate violated; do not treat scenario as deployable without parameter change or topology reduction.
|
||||
|
||||
---
|
||||
|
||||
## 3. Phase 0 comparison (three scenarios)
|
||||
|
||||
Run and compare:
|
||||
|
||||
1. **Hub-only** across all 11 chains
|
||||
2. **Full-quote** only on 1, 56, 137
|
||||
3. **Bridge shock** (e.g. 137 → 56)
|
||||
|
||||
Compare deltas:
|
||||
|
||||
- **churn +%** (full-quote vs hub)
|
||||
- **intervention cost +%** (full-quote vs hub)
|
||||
- **peak deviation** under shock
|
||||
|
||||
If churn jumps >50% with full-quote → clear “don’t deploy full-quote” rule.
|
||||
|
||||
---
|
||||
|
||||
## 4. Phase 0: Runnable scenarios and knob guidance
|
||||
|
||||
**Exact scenario JSONs to run** (in `config/scenarios/`):
|
||||
|
||||
| Scenario file | Description | Expected pass |
|
||||
|---------------|-------------|----------------|
|
||||
| `hub_only_11.json` | Hub topology, all 11 chains, 720 epochs | churn_mean in [0.3, 0.8], capture_mean in [0.10, 0.30], churn_max < 1.5 |
|
||||
| `full_quote_1_56_137.json` | Full-quote on Ethereum, BSC, Polygon; 720 epochs | Same gates; churn_mean increase vs hub_only_11 < 50% |
|
||||
| `bridge_shock_137_56.json` | Hub on 1/56/137; 5% migration 137 to 56 over 24 epochs | peak_deviation_bps < 200; damped re-center (not resonant). **Note:** Shock is a **stress injection** (paired local sell/buy), not cross-chain router equilibrium; see §6. |
|
||||
|
||||
**One command = one scorecard = pass/fail:** Run sim with scenario JSON; validate output against `config/scorecard-schema.json`; apply gates from section 2.
|
||||
|
||||
**If fail, what knob to turn first:**
|
||||
|
||||
| Symptom | First knob | Then |
|
||||
|---------|------------|------|
|
||||
| Capture too high | Increase feeBps | Then increase k |
|
||||
| Churn too high | Reduce pool count (hub model only) | Then increase k |
|
||||
| Intervention cost explodes | Increase latency penalty rho or widen bands | Add caps (maxTradeSizeUnits, maxDailyNotional) |
|
||||
| Drain half-life too short | Increase k or lower depth | Consider publicRoutingEnabled false on defense pools |
|
||||
| Path concentration too high | Widen topology or increase fee on dominant pools | Reduce single-pool magnetism |
|
||||
|
||||
---
|
||||
|
||||
## 5. Bridge shock modeling (Phase 0)
|
||||
|
||||
The **bridge shock** scenario (`bridge_shock_137_56.json`) is implemented as a **stress injection**, not as cross-chain path enumeration:
|
||||
|
||||
- Each epoch during the shock window, the sim adds **paired local trades**: sell cW→hub on the “from” chain (137), buy cW with hub on the “to” chain (56), at a magnitude that sums to the configured migration over the window.
|
||||
- This tests **corridor defense under forced migration** (can arb + bot keep deviation and intervention in check?), which is what matters operationally for Phase 0.
|
||||
- It does **not** model a router endogenously choosing to bridge because it’s cheaper; that requires cross-chain path selection (PR#3). When you add cross-chain routing, you can validate whether the same stress emerges from router equilibrium.
|
||||
|
||||
Be explicit when interpreting results: shock metrics answer “given forced migration, does the system damp?” not “does routing naturally push flow across chains?”
|
||||
|
||||
---
|
||||
|
||||
## 6. Confirming EUR defaults
|
||||
|
||||
Run **hub-only baseline** with (a) USD-only tokens, (b) USD + EUR tokens. Compare: churn_mean, churn_max, peak_deviation_bps, intervention_cost_per_1M_volume. If EUR tokens meaningfully worsen these: increase eurDefaults.k (e.g. 0.25), widen bands for EUR in peg-bands.json, and/or add routing caps (maxTradeSizeUnits) for EUR pools.
|
||||
110
docs/14-phase0-knob-tuning.md
Normal file
110
docs/14-phase0-knob-tuning.md
Normal file
@@ -0,0 +1,110 @@
|
||||
# Phase 0 Knob Tuning Reference
|
||||
|
||||
Based on scorecard interpretation: which levers to pull first and what patterns confirm the right move. See [12-sim-scorecard.md](12-sim-scorecard.md) for gates.
|
||||
|
||||
---
|
||||
|
||||
## 1. Hub-only: capture too high (PMM-heavy)
|
||||
|
||||
**Signals:** `capture_mean` near 1; churn < 1; intervention mostly inject.
|
||||
|
||||
**First lever:** Raise **feeBps** (not k). USD default: **25 → 35–50 bps** on public-routing pools.
|
||||
|
||||
**Then if still high:** k 0.10 → 0.15.
|
||||
|
||||
**Success:** capture_mean toward 10–30%; churn similar or better; arb_volume_total and intervention_cost_total fall.
|
||||
|
||||
---
|
||||
|
||||
## 2. Full-quote: path concentration high + inject/withdraw by chain
|
||||
|
||||
**Signals:** Higher `path_concentration_index`; 56/137 show withdraw (mesh reflexivity).
|
||||
|
||||
**First lever:** **Topology / controls:** keep hub-only default; full-quote only where tolerable with `maxTradeSizeUnits` lower and/or `publicRoutingEnabled=false` on optional pools.
|
||||
|
||||
**Second:** Two-tier design: defense pool (tighter k, maybe no public routing) vs public_routing pool (looser k, higher fee). Deployment-status schema supports roles.
|
||||
|
||||
**Success:** path_concentration_index drops; drain_half_life improves; intervention more one-directional.
|
||||
|
||||
---
|
||||
|
||||
## 3. Bridge shock: peak deviation at circuit-break level
|
||||
|
||||
**Signals:** `peak_deviation_bps_*` ~1000+ bps (e.g. 1015).
|
||||
|
||||
**First lever:** **Inventory / depth:** increase `inventoryTargetUnits` on impacted chains by 1.5–2×; keep D₀ = 0.75–1.0 × I*.
|
||||
|
||||
**Second:** Bot speed: `BOT_MAX_FRACTION_OF_TARGET` 0.25 → 0.4 (e.g. shock-scenario override).
|
||||
|
||||
**Third:** Corridor: low-water 0.5 → **0.75**, high-water 1.5 → **1.25**.
|
||||
|
||||
**Success:** peak_deviation_bps_post_arb and _post_bot drop; intervention_cost rises but deviation stays under circuit-break.
|
||||
|
||||
---
|
||||
|
||||
## 4. “Capture high” vs background AMM
|
||||
|
||||
Background AMM is 5 bps + infinite depth. If PMM still dominates:
|
||||
|
||||
- **Option A:** Raise PMM feeBps (recommended first).
|
||||
- **Option B:** Raise AMM fee to 20–30 bps if modeling Uni-style; keep 5 bps only if modeling Curve-style stable rails (then PMM should be defense, not venue → higher PMM fee/k).
|
||||
|
||||
---
|
||||
|
||||
## Quick checklist
|
||||
|
||||
| Issue | First move | Then |
|
||||
|-------|------------|------|
|
||||
| Hub capture too high | **Done:** default feeBps 35; chains 56/137 at 50 bps (sink chains); chain 1 at 35 | k 0.10 → 0.15 if needed |
|
||||
| Full-quote concentration high | Disable/cap optional pools; hub-only default | Role split: defense vs public_routing |
|
||||
| Shock peak deviation too high | Increase I* and D₀ on 1/56/137 | **Done:** corridor 0.75/1.25, speed 0.40 in script |
|
||||
|
||||
---
|
||||
|
||||
---
|
||||
|
||||
## 5. Deviation probe fix (marginal vs average)
|
||||
|
||||
**Problem:** With a finite probe (e.g. 500), implied price was an *average* over that size; the PMM curve always shows a discount at finite size, so `peak_deviation_bps_*` stayed high and arb churned volume.
|
||||
|
||||
**Fix:** Use **analytical marginal** for implied price: at x=0 the derivative is (1−fee)·P, so `pHat = (1 − s.fee) * s.P`. This avoids the (1−k) bias from a finite sell probe (which gave ~−1014 bps for EUR with k=0.2). At equilibrium, deviation = −fee (e.g. −35 bps). `DELTA_ARB_BPS` is set to 40 so equilibrium doesn’t trigger arb.
|
||||
|
||||
**After fix:** peak_deviation_* ≈ fee (e.g. 35 bps); arb_volume_total and intervention drop; worst_pool_diagnostic is no longer dominated by EUR.
|
||||
|
||||
---
|
||||
|
||||
---
|
||||
|
||||
## 6. Worst-pool diagnostic (scorecard)
|
||||
|
||||
When `peak_deviation_bps_pre_arb ≈ post_arb ≈ post_bot`, the **worst** pool may be rotating or not moving. The scorecard now includes (last epoch):
|
||||
|
||||
- `worst_pool_diagnostic`: `{ pre_arb, post_arb, post_bot }`, each `{ key, deviation_bps, I_T_ratio, D_effective }`.
|
||||
|
||||
**Interpretation:**
|
||||
|
||||
- Same pool worst all three phases + **low I_T_ratio** → depth problem (raise I*/D₀ or tighten corridor).
|
||||
- Same pool + **I_T_ratio ≈ 1** → curve/fee or routing pressure (raise feeBps / k).
|
||||
- Rotating worst pool → routing re-creating deviation; fee/k/controls to reduce demand.
|
||||
|
||||
**Diagnostic now includes `oracle_P` and `p_hat`:** If you see `p_hat ≈ 1.10` and `oracle_P = 1.00` for EUR pools, the bug is EUR reference price (see §7).
|
||||
|
||||
---
|
||||
|
||||
## 7. EUR oracle reference (P for cWEUR* vs USDC)
|
||||
|
||||
**Problem:** EUR pools (cWEURC, cWEURT) were using P = 1 (USD) so deviation looked ~8–12% (800–1200 bps) even at target inventory.
|
||||
|
||||
**Fix:** Oracle P in “quote per base” (USDC per cWEUR*):
|
||||
|
||||
- **USD-pegged:** P = 1.0.
|
||||
- **EUR-pegged vs USDC:** P = **EURUSD** (e.g. 1.10).
|
||||
|
||||
**Config:** `simulation-params.json` → `eurUsd`: 1.10 (USDC per 1 EUR). If missing, `eurPegMultiplier` is used; if that is 1.0, fallback 1.1 so EUR isn’t treated as USD. Optional later: `scenario.oracleModel.eurUsd` to override per run.
|
||||
|
||||
**After fix:** EUR pools drop out of worst_pool_diagnostic; peak_deviation_bps falls; arb volume and intervention reflect true routing pressure.
|
||||
|
||||
---
|
||||
|
||||
*Last updated from Phase 0 scorecard interpretation.*
|
||||
|
||||
Reference in New Issue
Block a user