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
4200Insufficient Payment — increasefeeAmount; never go belowminFeefrom capabilities/fee data.4201Invalid Signature — re-sign with freshsalt; ensure signer matchesdelegator.4202Unsupported Payment Token — pick a token fromrelayer_getCapabilities.4204Quote Expired — re-fetchrelayer_getFeeDataor re-estimate, re-sign, and resubmit within the ~45s validity window.4206Unsupported Chain — confirm chain appears in capabilities for the correct endpoint (mainnet vs dev).4209Unsupported Capability — adjust delegation scope/caveats.4210Invalid Authorization List — at most oneauthorizationListentry; verify EIP-7702nonceis current.4211Simulation Failed — relayer pre-simulates; inspect revertdataand fix call payload or scope.4216Delegation Secret Mismatch — delegation was previously bound to a differentdelegationSecret; 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
contextfrom estimate orrelayer_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: 0indicates confirmed;type: 4indicates pending. - Do not use Dev Platform webhook samples for the permissionless relayer — payload shape and signing differ.
- Treat Confirmed (
relayer_getStatusstatus200or webhook confirmed type) as the public boundary for success/paid wording.
Status polling errors
- Use
result.receipt.transactionHashfor confirmed transactions — top-levelresult.hashis often empty on Confirmed (200). - On Confirmed,
receipt.blockHashandreceipt.blockNumbermay be unset;receipt.transactionHashis authoritative. - Status codes are numeric: 100 Pending, 110 Submitted, 200 Confirmed, 400 Rejected, 500 Reverted.