113 lines
5.5 KiB
Markdown
113 lines
5.5 KiB
Markdown
# 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).
|