The JavaScript examples require
near-api-js 7.4 or later and borsh 2. The Rust examples use the near-api crate version 0.8.6, with Axum for the server, Reqwest for the client, and borsh 1 for serialization.Client
The client creates a signed delegate action: a message containing the sender, receiver, actions, nonce, and expiry block height. Signing it authorizes the call without broadcasting a transaction or paying transaction gas. This example shows how to sign aset_greeting call to hello.near-examples.testnet with zero attached deposit and an expiry of 120 blocks:
- JavaScript
- Rust
client.ts
/relay. The client’s private key stays on the client; the relayer receives only the signed delegate.
Relaying with wallets
Relaying with wallets
This example signs locally with a private key. To use a wallet, its signing interface must support delegate actions without immediately broadcasting them. Ordinary transaction signing and NEP-413 message signing produce different payloads and cannot replace delegate-action signing.
Relayer (server)
The relayer uses its own funded account to pay transaction gas. For parallel submissions, multiple access keys reduce nonce contention and failures caused by transactions executing out of order. The relayer’s signer rotates between the configured keys for each transaction. All keys must be registered as full-access keys on the relayer account. The/relay endpoint decodes the signed delegate from base64 and Borsh, wraps it in a transaction signed by the relayer, and sends it to NEAR:
- JavaScript
- Rust
server.ts
.env. Set CLIENT_ID and CLIENT_PRIVATE_KEY for the client, and RELAYER_ID and RELAYER_PRIVATE_KEYS for the server. RELAYER_PRIVATE_KEYS is a JSON array of private keys. Both processes must use the same network, and the client account must already exist and cover its storage requirements.
High volume parallel processing
When running a relayer that handles a large number of transactions, you can run into anonce collision problem. At the protocol level, each access key has its own nonce, which increases with each transaction to prevent replay attacks.
When multiple transactions are sent from the same access key simultaneously, their nonces might collide or they might execute out of order. For example, if Tx3 has a higher nonce than Tx1 and Tx2 and executes first, the earlier transactions can fail because their nonces are now too low.
The examples above use multiple full-access keys on the same relayer account. Both signing libraries rotate through the configured keys. This distributes transactions across independent nonces and reduces contention.
Key rotation reduces nonce contention, but a key can be reused while an earlier transaction is still pending. For sustained parallel traffic, coordinate submissions per key or wait for its pending transaction to complete before reusing it. Rotating relayer keys also does not change the nonce of a client’s signed delegate; clients should wait for one delegated call to finish before signing the next with the same key.
Gating the relayer
A relayer can choose which calls it will sponsor by checking the decoded delegate action before submitting it. For example, to sponsor only calls from a particular user to a particular contract, add this check after decoding the signed delegate in the endpoint:- JavaScript
- Rust
- JavaScript
- Rust