Skip to content

Relay system architecture

The relay separates the public trust boundary from sponsor-key ownership. relay-api handles authentication, admission, typed intent validation, canonical calldata construction, and request planning. relay-signer owns sponsor lanes, transaction nonces, fee freezing, key-provider access, raw transaction construction, and broadcast.

client
  │ HTTPS or WSS + wallet-bound JWT
  ▼
relay-api
  ├─ one-time wallet challenge and JWT issuance
  ├─ strict envelope and method decoder
  ├─ wallet admission and delegation policy
  ├─ EIP-712 and optional EIP-7702 validation
  ├─ market, deadline, nonce, and binding policy
  └─ immutable signer plan
       │ private authenticated RPC
       ▼
relay-signer
  ├─ independent plan validation
  ├─ pinned sponsor lane and outer nonce
  ├─ cached proposed-head fee input
  ├─ transaction construction and key signing
  └─ eth_sendRawTransaction
       │
       ▼
Monad RPC

Wallet authentication

Authentication is outside the transaction hot path. The client requests a server-generated, five-minute challenge, signs the exact message with the secondary EOA using ERC-191 personal_sign, and exchanges it once. The relay recovers the wallet, rechecks the deployment's admission mode, and issues a one-hour wallet-bound JWT. Static deployments require an explicit allowlist record; allow-all testnet deployments admit every valid nonzero wallet without prior registration.

The message binds its domain, token URI, chain ID, wallet, nonce, issue time, expiry, and challenge ID. Login deliberately does not require AccountCore delegation because a new secondary wallet must authenticate before it submits onboarding. The current bounded challenge store is process-local, so multi-instance deployments must share the store or pin both authentication calls to one instance.

Closed execution surface

The public protocol has six typed methods:

  • wallet.execute_replace_by_slot_packed
  • wallet.execute_batch
  • wallet.create_replace_trigger
  • wallet.create_batch_trigger
  • wallet.cancel_trigger
  • account_core.authorize_account_signer_by_sig

The private automation method wallet.execute_trigger is not exposed by the public REST or WebSocket interfaces. Deployment configuration may disable any public method or restrict wallet methods to specific verified markets.

No hot-path transaction-building RPC

The API constructs transaction intent from configuration, validated request fields, and the latest coalesced monadNewHeads proposed-head snapshot. The signer obtains block height and base fee from that in-memory snapshot. The normal hot transaction path therefore performs no Ethereum JSON-RPC call before broadcast; eth_sendRawTransaction is the expected hot-path call. Authorization or AccountCore requests that explicitly require block-pinned preflight are the exception and perform the documented reads before planning.

Each signer lane owns one sponsor identity and its outer nonce sequence. HTTP requests are assigned through bounded signer selection. A WebSocket session receives one opaque affinity key at upgrade and stays pinned to one lane for the life of the connection. The service closes the connection if that lane becomes unavailable instead of silently remapping the session.

Availability model

Liveness measures process responsiveness. Readiness fails closed when configuration, contract identity, wallet admission, proposed-head freshness, key-provider, nonce, lane, or RPC requirements are not met. The load balancer must stop routing transaction traffic to an unready pod. A cached proposed head remains usable for five seconds after its last accepted update, regardless of the subscription's instantaneous connection state.