Skip to content

Tracking Status

The server derives the recipe status from on-chain evidence at the SRA: deposits seen, bridges sent, executions settled. The server does not assert a status. The status stays correct when funds arrive late or when a retry occurs.

Lifecycle

PENDING → BRIDGING → EXECUTING → COMPLETED
                                → FAILED
PENDING (no funds within 1h)    → ABANDONED
type RecipeState =
  | "PENDING"    // quote issued, SRA not yet funded
  | "BRIDGING"   // funds received, bridge in flight (cross-chain only)
  | "EXECUTING"  // destination action in progress
  | "COMPLETED"
  | "FAILED"     // carries failureReason
  | "ABANDONED"; // the SRA received no funds within 1 hour after the quote

An ABANDONED recipe is not locked. Funds that arrive late still execute. A new watchStatus call picks the recipe up again from live evidence.

watchStatus

The SDK polls the server, with backoff. Polling stops on a terminal state (COMPLETED / FAILED / ABANDONED).

const watcher = sr.watchStatus(quote.sra, {
  interval: 4000,          // ms; default 4000
  timeout: 600_000,        // total watch bound, default 10 min; 0 = poll indefinitely
  maxRetries: 5,           // consecutive poll failures tolerated; default 5
  onStatusChange: (s) => console.log(s.state),
  onError: (e) => console.error(e),   // persistent poll failure or timeout
});
 
await watcher.done;   // resolves on terminal state / unsubscribe, rejects on persistent failure
watcher.stop();       // or call watcher() - unsubscribe

getStatus

Use getStatus for one read of the same data:

const status = await sr.getStatus(sra);
// status.state          - RecipeState
// status.deposits       - per-deposit evidence: deposit tx, bridge tx, execution tx
// status.failureReason  - the first deposit error when state === 'FAILED'

Recovering funds

There is no on-chain refund fallback. When the destination action reverts, the funds stay in the SRA. The SRA is non-custodial. Only the owner can recover the funds. getWithdrawCalls returns the recovery calls for the owner to sign:

const { data, receiver } = await sr.getWithdrawCalls({
  sra,
  tokens: [{ chainId: 42161, token: "0xTOKEN" }],
});
 
for (const { chainId, calls } of data) {
  for (const call of calls) {
    await wallet.sendTransaction({ ...call, chainId, value: BigInt(call.value) });
  }
}

Other SRA reads

sr.getSraInfo({ sra })              // the stored routing config: owner, actions, src tokens, slippage
sr.getSraFeeEstimates({ sra })      // per-chain bridge fee estimates (incl. sponsored entries)
sr.getDepositStatus({ sra, owner, destChainId, vaultId })
                                    // deposit phase (pending/bridging/deposited/failed) + vault balance