Gasless meta-transactions

Sign now, let a relayer pay the gas.

A NEP-366 meta-transaction lets one account sign a delegate action while a different account broadcasts it and pays the gas. With @fastnear/api you sign the delegate from a local key — no wallet — and hand the result to any relayer. The sender needs a key, but not a yoctoNEAR of balance.

How it flows
  • Sender signs a DelegateAction (their actions + nonce + maxBlockHeight) with near.signDelegate — offline-friendly, no gas.
  • Relayer wraps it in an ordinary transaction and broadcasts it with near.relayDelegate, paying the gas from a full-access key.
  • Everything out is a decimal string: nonce and maxBlockHeight are strings, and borshBase64 is the signed delegate a relayer transports.
Sign a delegate (sender)

near.signDelegate signs with a local key and never opens a wallet. The nonce comes from the sender's access key; maxBlockHeight defaults to the final block height plus blockHeightTtl.

import * as near from "@fastnear/api";
import { signerFromPrivateKey } from "@fastnear/utils";

// The sender holds a key but shouldn't pay gas.
const signed = await near.signDelegate({
  signerId: "alice.near",
  signer: signerFromPrivateKey(alicePrivateKey),
  receiverId: "guest-book.near",
  actions: [
    near.actions.functionCall({
      methodName: "add_message",
      args: { text: "gasless hello" },
      gas: "30 Tgas",
      deposit: "0",
    }),
  ],
  blockHeightTtl: 600,
});

// nonce + maxBlockHeight are decimal strings; borshBase64 is what a relayer sends.
near.print(signed.delegateAction);
Broadcast

A relayer pays and sends.

near.relayDelegate wraps the signed delegate in an ordinary transaction sent to the delegate's sender, signed and paid for by a full-access relayer key. Or POST signed.borshBase64 to a remote relayer service — the delegate is self-contained.

Relay it (relayer)

Pass a full-access relayerSigner/relayerId to pay the gas from a different account. The relayer never learns the sender's key.

// A relayer with a full-access key broadcasts it and pays the gas.
const result = await near.relayDelegate({
  delegateAction: signed.delegateAction,
  signature: signed.signatureBytes,
  relayerSigner: signerFromPrivateKey(relayerPrivateKey),
  relayerId: "relayer.near",
  waitUntil: "FINAL",
});

near.print(result);
Where the key lives
  • Server / agent: near.signDelegate signs with a local key — this page.
  • Browser wallet: nearWallet.signDelegateActions asks the connected wallet to sign instead. Same NEP-366 delegate, but it comes back as borshSerializedBase64 only — hand those bytes to a relayer that speaks raw NEP-366. near.relayDelegate takes the structured { delegateAction, signature } that near.signDelegate returns.
  • Either way the relayer pays; the sender authorizes the exact actions and a maxBlockHeight deadline.
Go deeper

AI agents: recipes.json carries the sign-delegate-local recipe (local key) and sign-delegate-actions (wallet). Preview the wrapped actions first with near.explain.tx. Rate-limited? Free trial credits are at dashboard.fastnear.com.