Skip to content

feat(hedge): sketch CappedSynth — margined, capped, RFQ-settled synthetic#43

Draft
tiero wants to merge 10 commits into
masterfrom
claude/capped-synth-sketch
Draft

feat(hedge): sketch CappedSynth — margined, capped, RFQ-settled synthetic#43
tiero wants to merge 10 commits into
masterfrom
claude/capped-synth-sketch

Conversation

@tiero

@tiero tiero commented Jun 10, 2026

Copy link
Copy Markdown
Member

What this is

A design sketch (not a finished feature) exploring a capital-efficient alternative to InventoryHedge (#41): a perpetual, BTC-settled margined synthetic — a bounded contract-for-difference — rather than a fully-funded forward.

It is InventoryHedge with three deliberate changes:

  1. PnL is struck against an entryPrice, with per-leg margin, so the posted pot is margin (< notional) — the capital efficiency a market-making desk actually wants when hedging residual delta. Payout clamps into [0, totalCollateral], so each leg's loss is bounded by its own margin.
  2. No liquidation engine — the clamp makes "underwater" impossible by construction, so there is nothing to liquidate and no keeper to run. This is the rung that fits Arkade's settlement-container model: on Bitcoin you can have self-custody or fast liquidations, not both, so build the instrument that needs no liquidations. The price of that is a payout cap (the tail beyond the pot is unhedged) — acceptable for a delta-flat hedger whose underlying loss is itself bounded.
  3. Oracle demoted to a fee'd fallback. The headline path settle() is cooperative — both legs co-sign the settlement price, so there is no oracle and therefore zero adverse selection (see feat: InventoryHedge — market-maker inventory-hedging vault #41 design doc §9.b). settleOracleClaim() survives only for an unresponsive counterparty and charges the adverse-selection premium (exitFeeBps) to the initiator instead of waving it away.

Margin / PnL model (claim leg = short BTC / long fiat)

newNotionalFiat = notionalFiat × (1 + fundingRatePerSec × elapsed / 1e12)
entrySats       = newNotionalFiat × 1e8 / entryPrice
settleSats      = newNotionalFiat × 1e8 / settlePrice
gross           = claimMargin + (settleSats − entrySats)
claimPayout     = clamp(gross, 0, totalCollateral)
longPayout      = totalCollateral − claimPayout
⇒ claim net ∈ [−claimMargin, longMargin]   (symmetric, fully bounded)

Leaves

Leaf Role Oracle Fee
transfer reassign the desk's leg
addMargin top up the pot (only raises the cap)
updateFunding roll funding into notional, rate ≥ 0
settle cooperative close, both legs co-sign the price
settleOracleClaim fallback when counterparty is dark exitFeeBps

Deliberately deferred (it's a sketch)

  • Funding resizes notional (inherited, audited path) rather than transferring margin between legs — a truer perp does the latter.
  • Only the claim-initiated oracle fallback is written; the long-initiated mirror is omitted.
  • No removeMargin (needs an oracle MTM check like removeCapital).
  • No price collar / cooperative-settle timeout (tx.time) gating the fallback.
  • No dedicated test or playground registry entry yet — currently covered only by the example-enumerating compilation_roundtrip / asm_structural suites.

Validation

  • cargo fmt --check clean
  • Full cargo test green (the example-enumerating tests pick up capped_synth.ark)
  • Compiles to 5 functions × 2 variants; checkSigFromStack confined to settleOracleClaim only — the cooperative settle carries no oracle in either variant, matching InventoryHedge's redeem/withdraw variant split.

Relationship to #41

Independent instrument; #41 is unchanged. If the direction is wanted, the follow-up is: dedicated tests, playground registration, a docs/mm-residual-hedge.md §11 (forward / capped-synthetic / perp comparison), and the deferred pieces above.

https://claude.ai/code/session_01E3fpVJfLdM3ye3ZWy5VxGg


Generated by Claude Code

claude added 9 commits June 10, 2026 00:01
Perpetual, BTC-settled, fully-collateralized market-maker inventory hedge
generalizing stability_vault.ark: a desk converts residual BTC inventory into a
delta-flat fiat claim (claim leg) while a treasury holds the BTC long leg and
earns funding. Oracle-marked, no liquidation, one instance per BTC/<fiat> pair.

- examples/hedging/inventory_hedge.ark (+ compiled .json): transfer,
  updateFunding, addCapital, removeCapital, claimExit, longExit (12 tapleaves).
- tests/inventory_hedge_test.rs: roundtrip (both variants, non-empty witness
  schemas), oracle-path checks, claimExit clamp branches, <SERVER_KEY> injection,
  updatedAt-stripped determinism.
- docs/mm-residual-hedge.md (design note) + docs/hedging/inventory_hedge_tx_flows.md
  (per-function tx layouts).
- playground: Hedging project folder wired in main.js.

https://claude.ai/code/session_01E3fpVJfLdM3ye3ZWy5VxGg
Merge docs/hedging/inventory_hedge_tx_flows.md into docs/mm-residual-hedge.md as
'Part II — Transaction flows', cross-referencing the design sections (§2/§4/§6/
§9). Remove the standalone file and point the playground Hedging folder at the
single doc.

https://claude.ai/code/session_01E3fpVJfLdM3ye3ZWy5VxGg
Drop the Exit suffix: claimExit -> redeem (desk redeems its fiat claim for BTC),
longExit -> withdraw (treasury-driven settlement). Update the contract, tests,
and the Part II transaction-flow doc.

https://claude.ai/code/session_01E3fpVJfLdM3ye3ZWy5VxGg
Add require(newTargetFiat > 0) in removeCapital so a claim driven non-positive by
a negative *initial* funding rate (not prevented at construction) can't make
minCollateral <= 0 and trivially pass the ratio check — which would let the long
leg drain the vault. Matches the existing updateFunding guard.

Deliberately NOT added to redeem/withdraw: their claimRaw <= 0 clamp branch is
the correct terminal settlement for a wiped claim (all collateral to the long
leg); a hard require there would abort a legitimate withdraw. Documented inline.

Also: clarify fundingRatePerSec doc (runtime >= 0; negative only possible at
construction, unsupported), and note split/merge are deferred (design doc Part II).

https://claude.ai/code/session_01E3fpVJfLdM3ye3ZWy5VxGg
- tests: assert the oracle message is RECONSTRUCTED on-chain (>=2 OP_CAT +
  OP_SHA256), matching stability_vault_test, so a compiler regression that drops
  cat/hash can't slip the replay guard; add addCapital-must-not-call-oracle
  negative test (code-review finding 5).
- tests: reword redeem clamp-branch comment — the dust guard IS the third OP_IF,
  not a fourth branch (CodeRabbit nitpick).
- docs: add 'text' language tags to fenced code blocks (markdown-lint nitpick).

https://claude.ai/code/session_01E3fpVJfLdM3ye3ZWy5VxGg
Per design decision (leave logic as-is, document only):
- updateFunding: note the known limitation that a negative *initial* rate bricks
  repricing (require(delta > 0) can't pass); funds aren't locked since
  redeem/withdraw still settle; a validating factory would seal it off.
- Settlement math: note the fail-closed int64 ceiling (~9.2e10 minor units /
  ~$922M) on claimRaw, inherited verbatim from stability_vault.ark — overflow
  aborts via OP_MUL64+OP_VERIFY, never a wrong payout. Split-division deferred
  (no modulo operator; avoid diverging from the audited reference).

https://claude.ai/code/session_01E3fpVJfLdM3ye3ZWy5VxGg
…dback)

A passive provider settling at a lagging oracle mark is adversely selected:
the settlement initiator holds a free option on the oracle delay, which is why
oracle-priced AMMs died on Ethereum (picked off when oracle error > fee, ignored
when below). Stability-style lending tolerates the 0.2-0.3% enter/exit premium
because settlement is rare; a hedging book may not.

- design doc: new §9.b spelling out the problem, why §6 internalization is
  load-bearing (not an optimization), that the dropped exit fee is only sound
  desk<->own-treasury, that 'no perp-spot basis' needs qualification, and that
  the §8 order-book/RFQ layer is closer to required than optional for any
  public version.
- contract header: trust-scope note on fee-free redeem/withdraw — reinstate
  seekerExitFee for any external counterparty.

https://claude.ai/code/session_01E3fpVJfLdM3ye3ZWy5VxGg
CodeRabbit finding: the constructor cannot validate collateralRatioPct, and a
negative ratio (<= -100) makes minCollateral non-positive so the ratio check
trivially passes — the long leg could drain a live claim. Add
require(collateralRatioPct >= 0), the same in-function defense-in-depth pattern
as the existing newTargetFiat guard. StabilityOffer seals this at take() time;
with no factory here the in-function guard is the equivalent.

https://claude.ai/code/session_01E3fpVJfLdM3ye3ZWy5VxGg
…etic

A design alternative to InventoryHedge explored in discussion: a perpetual
BTC-settled *margined* synthetic (bounded CFD) rather than a fully-funded
forward. Three deliberate changes over InventoryHedge:

  1. PnL struck against an entryPrice with per-leg margin, so the posted pot is
     margin (< notional) — the capital efficiency a desk wants. Payout clamps
     into [0, totalCollateral], so each leg's loss is bounded by its own margin
     and there is no liquidation engine to run (the rung that fits Arkade's
     settlement-container model).
  2. Headline path settle() is COOPERATIVE: both legs co-sign the price, no
     oracle, hence zero adverse selection (doc 9.b).
  3. The oracle path survives only as a fee'd fallback (settleOracleClaim),
     charging the adverse-selection premium to the initiator.

Marked SKETCH: funding resizes notional (inherited) rather than transferring
margin; only the claim-initiated fallback is written; no removeMargin, no price
collar / cooperative-settle timeout. Compiles; covered by the example-
enumerating roundtrip/asm tests. Not wired into a dedicated test or the
playground registry yet.

https://claude.ai/code/session_01E3fpVJfLdM3ye3ZWy5VxGg
@coderabbitai

coderabbitai Bot commented Jun 10, 2026

Copy link
Copy Markdown

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 3eacbe3b-39c2-46df-9c31-9290bd250ca6

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/capped-synth-sketch

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions

github-actions Bot commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

Playground Preview

A live preview of this PR's playground is available at:
https://arkade-os.github.io/compiler/pr-previews/pr-43/

Built from commit 4cb3bad4a0dab8b226b9094056feb8a1515d38b9 · Workflow run

Standalone doc for the capped-synthetic sketch, cross-linking
mm-residual-hedge.md §9.b (adverse selection). Covers: why a margined
instrument, the forward/capped/perp design-rung table, the margin/PnL bound
that removes the need for a liquidation engine, cooperative settle vs. fee'd
oracle fallback, the RFQ price-discovery boundary, the leaf table, and the
deliberately-deferred list.

https://claude.ai/code/session_01E3fpVJfLdM3ye3ZWy5VxGg
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants