Docs Navigationexpand_more

Public Relayer

Public Relayer: Error Handling

Handle JSON-RPC and relayer-level execution errors safely.

Purpose

Map JSON-RPC errors and execution outcomes to retry, abort, or user-action flows. Relayer business errors return numeric codes in the JSON-RPC error object; execution status uses numeric status codes in relayer_getStatus results.

Relayer error codes

  • 4200 Insufficient Payment — increase feeAmount; never go below minFee from capabilities/fee data.
  • 4201 Invalid Signature — re-sign with fresh salt; ensure signer matches delegator.
  • 4202 Unsupported Payment Token — pick a token from relayer_getCapabilities.
  • 4204 Quote Expired — re-fetch relayer_getFeeData or re-estimate, re-sign, and resubmit within the ~45s validity window.
  • 4206 Unsupported Chain — confirm chain appears in capabilities for the correct endpoint (mainnet vs dev).
  • 4209 Unsupported Capability — adjust delegation scope/caveats.
  • 4210 Invalid Authorization List — at most one authorizationList entry; verify EIP-7702 nonce is current.
  • 4211 Simulation Failed — relayer pre-simulates; inspect revert data and fix call payload or scope.
  • 4216 Delegation Secret Mismatch — delegation was previously bound to a different delegationSecret; resubmit with the original secret or sign a fresh delegation.

Operational retry guidance

  • **Quote expiry loop:** if signing takes longer than ~45 seconds, fetch a fresh context from estimate or relayer_getFeeData, update the fee execution amount if needed, re-sign the delegation, and send immediately.
  • **Intermittent HTTP 404 on send:** the relayer may occasionally return 404 with no body under load. Retry the same payload with exponential backoff before assuming a client bug.
  • **In-flight transaction limit:** submitting multiple delegated actions in quick succession may hit an in-flight limit. Serialize submissions or add backoff between sends from the same delegator.
  • **Rate limits:** JSON-RPC may return Rate Limit Exceeded. Back off and retry; exact limits are not published — design for at-most-once send with idempotent task tracking.
  • **destinationUrl validation:** an invalid destinationUrl (for example trailing-slash mismatch) rejects the entire bundle. Validate URL format before send.

Webhook verification

The permissionless relayer signs webhook events with Ed25519. Fetch JWKS from https://relayer.1shotapi.com/.well-known/jwks.json (mainnet) or https://relayer.1shotapi.dev/.well-known/jwks.json (testnet).

To verify: remove the signature field from the event, serialize the remainder with stable sorted-key JSON, and verify Ed25519 over UTF-8 bytes using the public key matching keyId.

Node.js verification sketch

import { createPublicKey, verify } from "node:crypto";

function verifyRelayerWebhook(event, publicKeyJwk) {
  const { signature, ...payload } = event;
  const message = Buffer.from(JSON.stringify(payload), "utf8");
  const key = createPublicKey({ key: publicKeyJwk, format: "jwk" });
  return verify(null, message, key, Buffer.from(signature, "base64url"));
}
  • Live webhook payload shape: { type, data: { id, chainId, receipt, hash, ... }, signature, keyId }. type: 0 indicates confirmed; type: 4 indicates pending.
  • Do not use Dev Platform webhook samples for the permissionless relayer — payload shape and signing differ.
  • Treat Confirmed (relayer_getStatus status 200 or webhook confirmed type) as the public boundary for success/paid wording.

Status polling errors

  • Use result.receipt.transactionHash for confirmed transactions — top-level result.hash is often empty on Confirmed (200).
  • On Confirmed, receipt.blockHash and receipt.blockNumber may be unset; receipt.transactionHash is authoritative.
  • Status codes are numeric: 100 Pending, 110 Submitted, 200 Confirmed, 400 Rejected, 500 Reverted.