Skip to content
Mainnet Live. All executions, addresses and hashes are live.
WORMHOOK
conceptualv0.1 · skeleton docs

HookReceipt

What comes back, including when things go wrong.

Schema

hookreceipt.tsconceptual
type HookReceipt = {
  callId: string;
  status: "success" | "failed" | "partial";
  destinationTx?: string;   // EVM tx that executed (or rejected) the call
  outputHash?: string;      // H(hook output); absent when nothing was produced
  amountSpent?: string;     // decimal string, hook's spend currency
  timestamp: number;        // unix seconds, destination block time
};

Status semantics

StatusMeaningSpend
successThe action completed. outputHash commits to the result.Actual amount used, ≤ maxSpend
partialSome sub-operations succeeded (e.g. 2 of 3 swarm jobs accepted).Only for the accepted parts
failedThe hook reverted, or the gateway refused the call after delivery (e.g. expired).0

A failed receipt is still a receipt. It is how the gateway tells Solana that nothing happened, so the app can refund, retry with a new call, or surface the error.

When there is no receipt

Two cases produce no receipt for a given delivery:

  • Duplicate delivery (WH-302). The first delivery already produced the receipt for that call ID, and a second receipt could overwrite it.
  • Not delivered yet (WH-202). The call is still in transit. It will end in a receipt (success, failure, or expiry).

Verifying a receipt

On Solana, the router only records receipts carried by a VAA from the registered gateway emitter on the call's destination chain, for a call ID it has pending. Your program reads the receipt account; it does not need to verify signatures itself.

receipt.rsconceptual
// Reading a recorded receipt from your program (account layout is phase 2).
let receipt = HookReceiptAccount::load(&ctx.accounts.receipt)?;
require!(receipt.call_id == expected_call_id, MyError::WrongCall);
match receipt.status {
    Status::Success => settle(&receipt.output_hash, receipt.amount_spent)?,
    Status::Partial => settle_partial(&receipt)?,
    Status::Failed  => refund(ctx)?,
}

See Returning receipts for the return path.