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

5.5 KiB
Raw Blame History

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).