Skip to content

feat: cross-chain bridging research (attested + SPV + HTLC) - #56

Draft
tiero wants to merge 9 commits into
masterfrom
claude/advanced-asset-bridging
Draft

feat: cross-chain bridging research (attested + SPV + HTLC)#56
tiero wants to merge 9 commits into
masterfrom
claude/advanced-asset-bridging

Conversation

@tiero

@tiero tiero commented Jul 19, 2026

Copy link
Copy Markdown
Member

Summary

Research contracts exploring the cross-chain bridging design space for Arkade, from a trusted-quorum wrap bridge to a fully trustless on-chain SPV deposit to a fast-transfer HTLC swap. Each shape is documented with an honest trust model so a deployment can pick the right one per chain. Also adds the small compiler primitives the SPV path needs (hash256() / reverseBytes() as first-class expressions).

The LVGA-specific productization (payout pool, stable-value stability-vault variant) has been split into a separate PR — this one is bridge research only.

Contracts (examples/bridge/)

Contract Role Trust
bridge_mint.ark Attested deposit — mint wrapped asset on k-of-n custodian attestation quorum honesty
bridge_withdrawal.ark Attested withdrawal — burn on payout, consensus-enforced timeout refund quorum + timeout refund
bridge_spv.ark Trustless deposit — on-chain SPV proof (merkle inclusion + PoW + confirmations) replaces the quorum PoW + pinned difficulty + relayer
swap_htlc.ark Fast-transfer cross-chain swap leg — one Lightning payment secret chains LN → Arkade → EVM; introspection makes the claim permissionless HTLC preimage (no custody)

Highlights

  • Trustless SPV deposit. bridge_spv.ark verifies a Bitcoin/PoW deposit entirely on-chain: a hand-rolled merkle fold (hash256 + cat, per-level direction bit — OP_MERKLEBRANCHVERIFY is tagged-hash and unusable for Bitcoin trees), a single-header PoW check as an unsigned 256-bit BigNum compare, confirmation-depth headers, and a payment binding, then mints under control-asset accounting. Difficulty is governance-pinned (on-chain retarget is infeasible); documented honestly.
  • One secret, three legs. swap_htlc.ark chains LN, Arkade, and an EVM HTLC with a single SHA256 payment hash, so no chain verifies another's consensus. Introspection pins the payout, making completion permissionless (watchtower/operator) — removing beneficiary liveness while leaving the free option (inherent to cross-ledger swaps) intact and documented.
  • Honest trust model. A three-shape comparison (wrap / SPV / fast-transfer) covering who authorizes release, cross-chain verification, who can trigger, residual trust, and what each is best for.

Compiler primitives (supervised files)

To express the SPV merkle fold and PoW check, hash256() and reverseBytes() are exposed as first-class expressions (previously hash256 only parsed inside require(hash256(x) == y)). Wired through grammar, parser, models, typechecker, validator, and the +OP_CAT concat rewrite; OP_REVERSEBYTES constant added. Verified against arkade-os/emulator (pkg/arkade/opcode.go): OP_HASH256 is Bitcoin double-SHA256. These touch grammar.pest / models / compiler, which are supervised — flagging for review.

Testing

  • Behavioral tests for every contract (SPV opcode presence, HTLC pinning, quorum reconstruction, refund timelock) + roundtrip coverage; feature tests for the new primitives.
  • cargo fmt --check clean; full suite green (155 example + 169 feature tests); playground regenerated (26 contracts).

Open item

The SPV 256-bit PoW compare emits BigNum comparisons that require the opcode-emission sync in #51 (standard OP_LESSTHANOREQUAL on BigNums, not the removed Elements *64 family). This branch should rebase onto / land after #51 for correct 256-bit compares; nothing else depends on it.

🤖 Generated with Claude Code

https://claude.ai/code/session_01Ttf3oxgKCxBsYWJrQYfUfE

claude added 2 commits July 19, 2026 09:21
Replicate the Near Intents deposit/withdrawal model (PoA bridge:
omft.near factory mint on attested deposits, WITHDRAW_TO burn on
withdrawals) as Arkade covenant contracts:

- examples/bridge/bridge_mint.ark: deposit leg. k-of-n custodian
  quorum attests sha256(depositId || recipientSpk || amount || nonce)
  via checkSigFromStack; covenant mints exactly the attested amount of
  the wrapped asset under control-asset accounting, pins the recipient
  output to the attested script pubkey (enabling deposits directly
  into swap offers), and advances a monotonic nonce through state
  continuation for single-use attestations.

- examples/bridge/bridge_withdrawal.ark: withdrawal leg. Per-withdrawal
  escrow committing to destHash + unique withdrawalId; quorum-attested
  release() burns the wrapped tokens after destination-chain payout,
  and a consensus-enforced refund() after refundTime bounds custodial
  risk (an improvement over Near's operational-only refunds).

- examples/bridge/README.md: study of the Near Intents architecture
  (Verifier/intents.near, PoA bridge, Omni Bridge) with the mapping to
  Arkade, trust model comparison, and future work.

- tests: behavioral assertions (quorum unrolling, attestation
  reconstruction, supply checks, CLTV refund) plus roundtrip coverage.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ttf3oxgKCxBsYWJrQYfUfE
Rewrite the bridge contract comments and README in an affirmative,
protocol-agnostic voice (no third-party protocol references):

- Present deposit/withdrawal as an advanced bridge design leading with
  what the covenant enforces on-chain.
- Add an honest trust-model section: foreign-chain custody is trusted
  and unavoidable; enumerate exactly what a colluding quorum can and
  cannot do.
- Add an opsec section explaining why attest-only signing (custodians
  sign a small fixed message via checkSigFromStack, not the live tx)
  keeps keys air-gapped, makes signers non-interactive, enables
  permissionless relay, and caps the blast radius via the covenant.

Contract logic is unchanged; tests still pass.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ttf3oxgKCxBsYWJrQYfUfE
@coderabbitai

coderabbitai Bot commented Jul 19, 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 Plus

Run ID: 406e6331-e47b-4076-a591-0d16c56140a7

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/advanced-asset-bridging

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.

@github-actions

github-actions Bot commented Jul 19, 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-56/

Built from commit a91502333430769eab07c1e1c501c78282abd6e0 · Workflow run

claude added 3 commits July 19, 2026 14:49
Replace the custodian quorum on the deposit leg with an on-chain SPV proof:
a Bitcoin/PoW deposit is credited by verifying merkle inclusion +
proof-of-work + confirmation depth in the covenant itself, with no signer.

Compiler primitives (SUPERVISED files — grammar/models/compiler):
- Expose hash256() and reverseBytes() as first-class expressions (let,
  assignment, byte operands), not just inside require(hash256(x)==y).
  hash256 -> OP_HASH256 (Bitcoin double-SHA256, confirmed against
  arkade-os/emulator pkg/arkade/opcode.go); reverseBytes -> OP_REVERSEBYTES.
- Add OP_REVERSEBYTES constant; wire Hash256/ReverseBytes through parser,
  models, typechecker, validator, and the concat (+ -> OP_CAT) rewrite so
  hash256(node + sibling) lowers its inner + to a merkle-step concat.

examples/bridge/bridge_spv.ark (BridgeSpv):
- merkle inclusion via a hand-rolled hash256+cat fold with per-level
  direction bits (OP_MERKLEBRANCHVERIFY is tagged-hash/sorted-pair and
  cannot verify Bitcoin trees);
- single-header PoW as an unsigned 256-bit BigNum compare (0x00 sign-byte
  guard); confirmation headers chained by prevHash, each PoW-checked;
- payment binding: hash256(tx)==txid and the paid output matches the
  watched depositScript for >= mintAmount;
- mint under control-asset accounting with nonce state continuation.

Trust model documented honestly: difficulty is governance-pinned (no
on-chain retarget), header relaying is a liveness role, finality is
economic. SPV trades a k-of-n signer set for PoW + pinned-difficulty +
relayer liveness. README compares both deposit legs and lists v1 limits
(replay registry, 256-bit compare needs the PR #51 BigNum opcode sync).

Tests: 6 SPV bridge assertions (no-signature proof path, merkle/PoW
opcodes, control-asset mint, witness flattening) + roundtrip; 3 feature
tests for the new primitives. cargo fmt clean; full suite green.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ttf3oxgKCxBsYWJrQYfUfE
Add the solver fast-transfer route: a one-shot cross-chain swap with no
wrapped token and no bridge treasury, chained by a single Lightning payment
secret so no chain verifies another chain's consensus.

examples/bridge/swap_htlc.ark (SwapHtlc):
- claim(preimage) covenant: SHA256 hashlock (matches the LN payment hash so
  one secret unlocks the LN, Arkade, and EVM legs) + payout pinned by
  introspection to solverPk. No beneficiary signature, so any
  relayer/watchtower/operator can complete it once the secret is public and
  it can only pay the solver.
- refund() covenant: after refundTime the BTC returns, pinned to userPk;
  likewise permissionless and non-redirectable.
- L1 claim/refund tapscript leaves re-enforce the hashlock/timelock;
  unilateral CSV exit for the user (funder).

Introspection removes *beneficiary* liveness (delegatable completion), but
the free option is inherent to cross-ledger swaps and is documented as
priced-away (short T_evm + taker premium), not covenant-removable.

README: comprehensive fast-transfer section with the LN -> BTC on Arkade ->
LVGA on SwissLedger worked example, timelock-ordering table, liveness/free-
option analysis, and a three-shape trust comparison (wrap bridge vs SPV vs
fast-transfer swap).

Tests: 6 swap-HTLC assertions (structure, solver-pinned hashlocked claim,
no-beneficiary-signature claim, user-pinned timelocked refund, L1 hashlock
leaf, CSV unilateral) + roundtrip. cargo fmt clean; full suite green;
playground regenerated (26 contracts).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ttf3oxgKCxBsYWJrQYfUfE
Add a merchant-payment bridge-out where real LVGA lives in a SwissLedger
(EVM) liquidity pool and wrapped wLVGA is issued on Arkade against it.
Paying out is a BURN: the burn plus a merchant commitment is the whole
authorization -- no Arkade-side quorum signs the release.

examples/bridge/wlvga_burn.ark (WlvgaBurn):
- burnOut() verifies a merchant authorization with checkSigFromStack over
  sha256(protocolTag || merchantEvmAddr || amount || burnNonce), shrinks
  wLVGA supply by amount, and pins an OP_RETURN output committing
  protocolTag || merchantEvmAddr || num2bin(amount, 8).
- One secp256k1 key, two chains: the same merchant key/message is verified
  by checkSigFromStack on Arkade and by ecrecover on the SwissLedger pool,
  which matches the recovered address to the committed evmAddr and releases
  LVGA. Relay is permissionless (commitment + sig are self-authenticating);
  the monitoring node/webhook is liveness only.
- pubkey/signature stay strictly inside checkSigFromStack (never in a
  concatenation), so every hashed/committed field is bytes/int and the +
  operator lowers to OP_CAT -- the digest matches the merchant's off-chain
  signing and the EVM reconstruction byte-for-byte. Replay bounded by
  burnNonce.

README: burn-to-unlock section with the BTC -> wLVGA -> burn -> webhook ->
ecrecover -> LVGA flow, the one-key-two-chains explanation, the OP_RETURN
commitment format, and a trust model (release is on-chain/trustless;
residual trust is pool solvency + relayer liveness). Framed as the mirror
of the SPV deposit leg (inbound proof vs outbound burn). Trust-comparison
table extended to four shapes.

Tests: 6 burn-out assertions (structure, CSFS merchant auth, concat-not-add
message lowering, supply-shrink accounting, OP_RETURN commitment pinning) +
roundtrip. cargo fmt clean; full suite green; playground regenerated (27).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ttf3oxgKCxBsYWJrQYfUfE
@tiero
tiero force-pushed the claude/advanced-asset-bridging branch from 4b035fb to 7cb95d4 Compare July 24, 2026 22:58
claude added 3 commits July 24, 2026 23:24
Rework the bridge-out for the real deployment: the BTC side and the LVGA
liquidity provider (LP) are SEPARATE parties, and LVGA is a
transfer-restricted token that can never be redeemed for wLVGA.

Rename wlvga_burn.ark -> wlvga_payout.ark (WlvgaPayout) with two modes:
- payOut() (default, two parties): transfer the BTC-backed wLVGA claim to
  the LP (SingleSig(lpPk)) instead of burning it, so the LP is compensated
  in BTC for the LVGA it releases and the two roles may be distinct
  entities. Closes the solvency loop.
- burnOut() (option, same party): burn the wLVGA; only solvent when the LP
  is also the party that received the BTC at mint time (integrated MM).

Both modes authorize the payee with the merchant's secp256k1 key via
checkSigFromStack (mirrored by ecrecover on the SwissLedger pool) and pin
the OP_RETURN commitment protocolTag || merchantEvmAddr || num2bin(amount, 8).

Economics documented honestly: LVGA is one-way (whitelisted holders,
pool -> merchant only); wLVGA is a BTC-backed BEARER claim, never redeemed
for LVGA. The LP is a market maker taking CHF/BTC exposure for fees -- it
gives up LVGA (CHF), receives BTC (hedgeable to USDT), and prices fees into
its quote; the covenant guarantees it is paid in BTC for every payout it
services. The BTC and LVGA sides connect only through the LP's balance
sheet.

Tests updated to the two-mode contract (payOut transfers to LP with no
supply-shrink; burnOut shrinks supply; both carry CSFS + concatenated
message + pinned commitment) + roundtrip. cargo fmt clean; full suite
green; playground regenerated.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ttf3oxgKCxBsYWJrQYfUfE
Add examples/bridge/swissledger_pool.md: the destination-chain (EVM) pool
contract that auto-releases LVGA against an Arkade wLVGA payout, removing
per-payment operator discretion.

Flavor A (trusted reporter): a reporter attests the Arkade burn/transfer
happened; the contract independently re-binds destination, amount, and
uniqueness so the reporter is trusted for LIVENESS only, not correctness:
- ecrecover(payoutMsg, sig) == committed merchantEvmAddr  (no redirect)
- LVGA whitelist check                                    (transfer restriction)
- paid[burnNonce] mapping                                 (no replay/double-pay)
With reporter = pool operator the trust is incentive-aligned: a false report
drains the operator's own pool for no BTC, so the practical residual is
censorship/liveness, mitigated by permissionless/multiple reporters.

Spec pins the exact byte layout to match wlvga_payout.ark (protocolTag ||
merchantEvmAddr(20) || amount(8 LE) || burnNonce(8 LE), sha256) and flags the
two integration gotchas: little-endian 64-bit ints, and a recoverable
secp256k1 ECDSA signature over the raw sha256 digest (not EIP-191/keccak) so
one merchant key verifies via checkSigFromStack on Arkade and ecrecover on
EVM. Includes a reference Solidity sketch and contrasts Flavor B (on-EVM
Bitcoin SPV proof, no reporter trust). No Arkade change: wlvga_payout.ark
already emits the full commitment.

README: add an "Automated release on SwissLedger" subsection and update the
payout trust table (release automation row).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ttf3oxgKCxBsYWJrQYfUfE
…ments)

Add examples/stability/stability_lvga_payout.ark (StabilityPayout): a
BTC-collateralized, oracle-marked CHF claim that settles directly as a
merchant LVGA payment, fusing the stability vault settlement with the wLVGA
payout bridge-out.

seekerPayout():
- verifies the CHF/BTC oracle price (checkSigFromStack over
  sha256(ticker || price || time), 600s freshness);
- accrues funding and applies the exit fee -> payoutCHF;
- verifies a merchant invoice (checkSigFromStack, mirrored by ecrecover on
  the SwissLedger pool) and commits payoutCHF in the OP_RETURN;
- routes the seeker's BTC entitlement at the oracle price (seekerRaw) to the
  LP as compensation, with the collateral remainder returning to the
  provider (clamped when the provider is fully drawn down).

The merchant receives exactly the claim's CHF value regardless of BTC moves
during the holding period; the same oracle prices both sides. Price risk
lives with the vault PROVIDER (funded, over-collateralized, oracle-marked),
not the bridge LP or the user. Set lpPk = providerPk to run both as one
delta-neutral market maker; keep distinct for two independent parties. Focused
variant -- full vault lifecycle stays in stability_vault.ark (tests intact).

README: "Stable-value payouts" subsection tying BTC -> CHF vault claim ->
LVGA merchant payment into one rail, plus a Design bullet.

Tests: 5 assertions (structure, oracle+merchant CSFS + seeker checkSig,
seeker BTC pinned to LP / remainder to provider / not to seeker, OP_RETURN
commitment + 7 concats) + roundtrip. cargo fmt clean; full suite green;
playground regenerated (28 contracts).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ttf3oxgKCxBsYWJrQYfUfE
@tiero tiero changed the title feat: add Advanced Bridge contracts for cross-chain asset wrapping feat: cross-chain bridging suite (attested + SPV + HTLC + payout + stable-value) Jul 25, 2026
…rch PR

Keep this PR to the general cross-chain bridging research and move the
LVGA-specific productization to a separate PR.

Removed here (now on claude/lvga-bridge-stability):
- examples/bridge/wlvga_payout.ark
- examples/bridge/swissledger_pool.md
- examples/stability/stability_lvga_payout.ark
- their tests + roundtrip entries + module registration

Also genericized the swap_htlc worked example from LVGA/SwissLedger to a
generic EVM token/chain, so this PR carries no LVGA specifics. The
fast-transfer HTLC swap itself is a general primitive and stays here.

Remaining scope: bridge_mint, bridge_withdrawal, bridge_spv, swap_htlc, the
hash256/reverseBytes compiler primitives, and the three-shape trust model.
cargo fmt clean; full suite green (155 example + 169 feature); playground
regenerated (26 contracts).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ttf3oxgKCxBsYWJrQYfUfE
@tiero tiero changed the title feat: cross-chain bridging suite (attested + SPV + HTLC + payout + stable-value) feat: cross-chain bridging research (attested + SPV + HTLC) Jul 25, 2026
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