SkyhookThe Contracts

The Life of a Swap

Every Skyhook Bridge swap, in either pricing mode, passes through the same four stages in a fixed order: the requester opens a request and locks ETH, a counterparty proposes an intent to fill it, the contract accepts the intent after checking its note commitment, and the escrow is claimed against a proof that the Zcash payment is final. No stage can be skipped or reordered. Two exits cover the alternatives: a refund once the request’s refund time passes, and a cancellation before acceptance.

Throughout this page, Alice is the requester, who locks ETH and wants ZEC, and Bob is the liquidity provider, who pays ZEC and wants ETH.

The life of a swapInteractive
Who acts
What happens
On-chain
Escrowed ETH
Exits available
Every swap, in either mode, passes through these four stages in order. The two exits keep funds from ever being stuck: cancel before acceptance, and refund once the request's refund time passes.

Request and lock

Alice opens a swap by calling requestTransaction with a 104-byte blob that describes the Zcash payment she wants: the recipient, the amount and the expiry. The blob is the deal in miniature. Every later check is measured against it, and nobody (Alice, Bob or a third party) can change it once it is submitted.

Alice locks ETH in the same call, and the amount must equal howMuchEth exactly; a difference of a single wei reverts the call, so mispricing fails at the cheapest possible point. The request’s identifier is keccak(counter || blob). From this point the ETH stays in escrow until the swap ends through a claim or one of the exits.

Propose

Anyone can answer a request with an intent. In practice a liquidity provider usually responds first, since filling requests is its business, but the contract treats all proposers alike. The intent carries the complete Zcash action data together with its computed digests, all pinned by dataHash, so changing a single byte of the action data invalidates the proposal.

The contract checks that the intent’s recipient matches the blob and that the value offered clears the requester’s floor within her tolerance, and then assigns the intent an identifier. No funds move at this stage and neither side takes on any obligation.

Accept

Acceptance binds an intent to a request and is the central verification step of the lifecycle. The contract recomputes the note commitment from the openings supplied with the intent and compares it with the claimed commitment. This is the revealed-leaves check described in How It Works, now with funds at stake. For a lock-script request, acceptance also recomputes the compact digest over the ciphertext head.

Each acceptance can be used only once, and per-signer nonces protect against replay, so a recorded acceptance has no further value to anyone.

Claim

Once the Zcash payment has been mined and is final, anyone may submit the inclusion proof. The contract checks it against the anchor and pays the full escrow to the proposer. The payout is winner-take-all: the contract takes no fee, rake or surcharge. Fees are earned entirely off-chain, as the spread in the price a provider quotes, which keeps the settlement logic small and easy to audit.

At claim time the contract records the note’s spent nullifier. A given Zcash note can therefore settle at most one swap, however many intents or proposals referred to it.

Exits

  • Refund. If no claim has been made by the request’s refund time (refundTime), the funds return to the locker. Each request sets its own refund time, though a deployment may instead fix one for all requests. The clock runs from creation rather than from the last activity, so stalling can’t extend the exposure. As a result, no sequence of events can leave funds permanently immobilized.
  • Cancel. The requester can cancel only before any acceptance. Once an acceptance is recorded the commitment is mutual and can no longer be withdrawn. No fraud-proof exit is needed. Earlier, optimistic designs used long deadlines and planned one for proven fraud. Instead, for a non-interactive lock, the signed quote carries a deadline from which the contract extrapolates the Zcash payment’s expiryHeight, so the payment is mined promptly, within an hour at worst, or never becomes valid at all, and finality is proven directly rather than assumed and challenged.
graph LR R["request + lock"] --> P["propose"] P --> A["accept"] A --> C["claim"] A --> RF["refund (timeout)"] R --> CX["cancel (pre-accept)"]

See also