Combine @abstraxn/server-signer and @abstraxn/relayer so your backend agent can sign meta-transactions with an Abstraxn Server Wallet and submit them gaslessly through the relayer.

How it works

authenticate()           → Abstraxn server wallet session
createRelayerSigner()    → Abstraxn signs meta-tx (not a local private key)
buildRelayerTxEIP712()   → encode + sign authorization
sendRelayerTx()          → relayer pays gas and calls executeMetaTransaction
StepWho signs / pays
Meta-tx authorizationAbstraxn Server Wallet
On-chain executionRelayer (gas tank)

Install

npm install @abstraxn/server-signer @abstraxn/relayer ethers

1. Authenticate the server wallet

Use the same userIdentity string every time — it must match the value you used when the wallet was first created.
import { ServerSignerClient } from '@abstraxn/server-signer';

const client = new ServerSignerClient({
  apiKey: process.env.ABSTRAXN_API_KEY!,
});

// First run: omit accessKey — SDK creates wallet and returns session.accessKey
// Later runs: pass the saved accessKey
const session = await client.authenticate({
  userIdentity: 'my-backend-agent-001',
  accessKey: process.env.SERVER_WALLET_ACCESS_KEY,
});

if (session.didCreate) {
  // Save session.accessKey — required to recover this wallet later
  await saveToSecretsManager(session.accessKey);
}
userIdentity is permanent. Changing it creates a new wallet. accessKey must match the key from the first authenticate() for that identity.

2. Create a relayer signer

createRelayerSigner() returns a signer the relayer SDK can use. Signing is handled remotely by Abstraxn — your backend never holds the wallet private key.
import { JsonRpcProvider, type Signer } from 'ethers';

const rpcUrl = process.env.RPC_URL!;
const me = await client.whoami<{ result: { address: string; organizationId: string } }>();

const { signer } = client.createRelayerSigner({
  rpcUrl,
  chainId: 137,
  organizationId: me.result.organizationId,
  fromAddress: me.result.address,
});

3. Build and send a gasless transaction

Pick the build method that matches your contract (see Relayer guide):
MethodWhen to use
buildRelayerTxEIP712Default — most Abstraxn meta-tx contracts
buildRelayerTxContracts that verify EIP-191 signMessage hashes
import { Relayer } from '@abstraxn/relayer';
import { ChainId } from '@abstraxn/core-types';

const relayer = new Relayer({
  relayerUrl: process.env.RELAYER_URL!,
  chainId: ChainId.POLYGON_MAINNET,
  provider: new JsonRpcProvider(rpcUrl),
  signer: signer as unknown as Signer,
});

const buildTxParams = {
  contractAddress: '0xYourContract',
  abi: yourContractAbi,
  method: 'yourMethod',
  args: ['arg1'],
};

// EIP-712 (recommended)
const txData = await relayer.buildRelayerTxEIP712(buildTxParams);

// — or EIP-191 personal sign for legacy contracts:
// const txData = await relayer.buildRelayerTx(buildTxParams);

const { transactionId } = await relayer.sendRelayerTx(txData);
const status = await relayer.getRelayerTxStatus(transactionId);
Use buildRelayerTx only if your contract does not verify EIP-712 MetaTransaction typed data.

Prerequisites

  • Same userIdentity on every authenticate() call for that wallet
  • Contract exposes getNonce(address) and your target method in the ABI
  • Contract is whitelisted on your relayer app
  • Relayer gas tank has balance on the target chain
  • fromAddress / server wallet address owns the on-chain meta-tx nonce

Environment variables

VariableDescription
ABSTRAXN_API_KEYApp API key from dashboard
SERVER_WALLET_ACCESS_KEY64-char hex from first authenticate() (omit on first run)
RPC_URLChain JSON-RPC URL
RELAYER_URLRelayer URL from dashboard

Next Steps