Files
cross-chain-pmm-lps/docs/11-safe-inventory-sizing.md
2026-03-02 12:14:07 -08:00

113 lines
5.5 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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.52 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.52 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.52) 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.51) · 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.150.2** on thin chains (e.g. Cronos) if sims show excessive capture; EUR tokens use `eurDefaults` (higher k, σ, feeBps).