Skip to content

[CRITICAL][Tier-A] Cross-chain Merkle-Patricia proof verification for EVM HTLC reveals #386

Description

@jotel-dev

Tier
Tier A · CRITICAL — Cryptographic cross-chain verification (not a full light client).

Context
contracts/atomic-swap/src/lib.rs implements verify_merkle_proof as a SHA-256 hash stub (env.crypto().sha256(&log_data)). The relayer (apps/relayer/src/evm-htlc.ts) passes secrets from Soroban released events to the EVM leg without proving the EVM log actually exists. A malicious relayer can fabricate secrets that pass this stub and drain the counterpart HTLC.

Goal
Replace the stub with deterministic Merkle-Patricia Trie (MPT) inclusion verification inside the Soroban contract. The relayer must submit an EVM log proof alongside the secret, and the Soroban contract must verify it against a trusted EVM block header root before accepting record_evm_reveal.

Non-goals
No full EVM execution client inside Soroban.
No BLS/SNARK wrapping of the MPT verification (gas-costly).
No RPC calls from inside the contract — proofs are submitted by the relayer.

Data model
Add to DataKey in AtomicSwapContract:

  • VerifiedEVMBlock(u32) -> (block_hash, header_root, verified_at_ledger) per EVM chain ID.

Implementation plan

  1. Add an MPT verification module under contracts/atomic-swap/src/mpt.rs that traverses a Merkle-Patricia path for an EVM log topic/value against a provided root using only Soroban host crypto.
  2. Modify record_evm_reveal to accept (evm_tx_hash, secret, evm_block_height, chain_id, mpt_root, mpt_proof_bytes).
  3. Before storing CrossChainTxInfo, reconstruct the MPT node path from mpt_proof_bytes and assert it reaches mpt_root.
  4. Gate on a previously verified block header: the relayer must first call a new verify_evm_header(chain_id, block_number, header_rlp, header_proof) that stores the header root. record_evm_reveal then uses the most recent verified root for that chain.
  5. Update apps/relayer/src/evm-htlc.ts to fetch eth_getProof for the HTLC log and submit the MPT proof to Soroban.
  6. Add contracts/atomic-swap/src/mpt_test.rs with property tests for known MPT fixtures.

Thresholds

  • InsufficientFinality (12) must also fire when record_evm_reveal is called with a block whose header is unverified.
  • Reorg buffer remains MAX_REORG_WINDOW_LEDGERS = 50.

Acceptance criteria

  • verify_merkle_proof no longer exists as a SHA-256 stub; the compiler rejects any caller passing raw log_data without an MPT proof.
  • A red-team fixture (forged MPT proof) is rejected by record_evm_reveal.
  • The relayer successfully processes a real LogHTLCWithdraw from Goerli/Sepolia using an ethers-generated MPT proof.
  • get_events on the Soroban RPC still decodes released correctly; no breaking change to decodeReleasedEvent.

Related files

  • contracts/atomic-swap/src/lib.rs
  • contracts/atomic-swap/src/relayer_integration.rs
  • apps/relayer/src/evm-htlc.ts
  • apps/relayer/src/soroban-watcher.ts
  • apps/api/src/lib/stellar.js
  • contracts-evm/HTLC.sol

Contributor notes
Keep the MPT verifier pure and exhaustively tested against hard-coded test vectors — this is the only path to staying Tier A. Soroban host crypto is limited; if MPT is too expensive, use a precompile-style batching of node hashes rather than one big proof.

telegram link : t.me/nullifiersystem

Metadata

Metadata

Assignees

Labels

GrantFox OSSIssue tracked in GrantFox OSSMaybe RewardedIssue may be eligible for a GrantFox rewardThird CampaignCampaign: Third Campaigncritical

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions