Skip to content
LogoLogo

Relay.create

Overview

Create a Tempo relay with a parsed RPC handler and a Fetch endpoint. Both methods share the same ordered plugins. Requests that plugins do not handle are forwarded to a Viem client.

Choose a chain-configured client for one chain or getClient for multiple chains. Exactly one is required. A relay with no plugins forwards requests without adding multisig coordination or fee sponsorship.

Recipes

Serve One Chain

import { createClient, http } from 'viem'
import { tempo } from 'viem/chains'
import { Relay } from 'viem/tempo'
 
const relay = Relay.create({
  client: createClient({ chain: tempo, transport: http() }), 
})
 
export default { fetch: relay.fetch }

Resolve Multiple Chains

import { createClientResolver, http } from 'viem'
import { tempo, tempoModerato } from 'viem/chains'
import { Relay } from 'viem/tempo'
 
const resolver = createClientResolver({
  chains: [tempo, tempoModerato],
  transport: () => http(),
})
const relay = Relay.create({ getClient: resolver.getClient }) 
 
const chainId = await relay.request(
  { method: 'eth_chainId' },
  { chainId: tempo.id }, 
)

A plugin may infer the chain from a signed payload or stored operation. Ordinary calls such as eth_blockNumber need an explicit chain when using getClient. The relay never selects the resolver's first chain as a default.

Relay.create

Creates handlers sharing one plugin pipeline.

Usage

import { createClient, Relay } from 'viem/tempo'
 
const client = createClient()
const relay = Relay.create({ client })

Parameters

options.client

  • Type: Chain-configured Viem Client

Supplies the default chain. Explicit and inferred chain IDs must match client.chain.id. Cannot be combined with getClient.

const relay = Relay.create({ client }) 

options.getClient

  • Type: ({ chainId }) => Client

Resolves a client only when forwarding requires one. Accepts createClientResolver().getClient directly and preserves its supported chain IDs. Cannot be combined with client.

const relay = Relay.create({ getClient: resolver.getClient }) 

options.plugins

  • Type: readonly Relay.Plugin[]
  • Default: []

Requests enter plugins in array order. Plugins are composed once per relay.

const relay = Relay.create({
  client,
  plugins: [Relay.multisig({ store })], 
})

options.resolveTokens

  • Type: (chainId: number) => readonly Address[] | Promise<readonly Address[]>
  • Default: Bundled Tempo token addresses for the selected chain.

Supplies fee-token candidates shared by fee selection and sponsorship. Results are memoized within each request and chain. Implement cross-request caching inside the resolver when fetching a remote token list.

const relay = Relay.create({
  client,
  resolveTokens: () => [Addresses.pathUsd], 
  plugins: [Relay.feeToken()],
})

Return Value

Relay.create.ReturnType

An object with request and fetch methods. Neither method requires this binding.

Errors

ErrorDescription
RpcResponse.InvalidParamsErrorBoth or neither client options were supplied, or the single client has no valid configured chain.

relay.request

Handles { method, params? } and returns Promise<unknown> containing the RPC result. The optional second argument preserves Viem request options, including cancellation, retries, and deduplication, and adds an optional numeric chainId.

await relay.request({ method: 'eth_blockNumber' }, { chainId: 4217 })

Invalid, conflicting, or missing required chain IDs reject with RpcResponse.InvalidParamsError. Resolver and downstream errors propagate. Locally handled requests need not resolve a client.

relay.fetch

Handles a standard Request and returns Promise<Response>. The optional second argument accepts the same request options as relay.request. The incoming request's abort signal is used unless an explicit signal is supplied.

export default {
  fetch(request: Request) {
    return relay.fetch(request, { chainId: 4217 })
  },
}

HTTP Behavior

RequestResponse
POST with Content-Type: application/jsonJSON-RPC response with HTTP 200.
Valid batchArray of responses, omitting notifications.
Notification or notification-only batchEmpty HTTP 204 response after execution.
Malformed JSONJSON-RPC parse error, code -32700.
Invalid request or empty batchJSON-RPC invalid-request error, code -32600.
Named parametersJSON-RPC invalid-params error; Tempo RPC uses positional parameters.
Method other than POSTHTTP 405 with Allow: POST.
Unsupported content typeHTTP 415.

RPC errors preserve their code, message, and data. Unexpected exceptions become JSON-RPC internal errors without exposing implementation details. A batch item that cannot be serialized fails individually.

Applications supply routing, authentication, CORS, and persistent storage. Read Run a Relay for deployment examples.

Migration

Replace Multisig.handleRequest with the multisig plugin. The low-level composer retains an existing downstream callback:

-import { Multisig } from 'viem/tempo'
+import { Relay } from 'viem/tempo'
 
-const request = Multisig.handleRequest(next, { store })
+const request = Relay.handleRequest(next, {
+  plugins: [Relay.multisig({ store })],
+})

For a service backed by a Viem client, use Relay.create({ client, plugins }) to obtain both parsed RPC and Fetch handlers.