@abstraxn/relayer
v1.2.0
Published
Abstraxn Relayer package for handling gas-less transactions, facilitating smart contract interactions, and relaying user transactions efficiently.
Readme
Abstraxn Relayer SDK
Overview
The Abstraxn Relayer package is designed for handling gas-less transactions, facilitating smart contract interactions, and efficiently relaying user transactions on the Ethereum blockchain. Now with real-time WebSocket notifications for instant transaction status updates!
Installation
Using npm package manager:
npm install @abstraxn/relayerOr using yarn package manager:
yarn add @abstraxn/relayerUsage
import { Relayer } from "@abstraxn/relayer";
import { ChainId } from "@abstraxn/core-types";
const relayerConfig = {
relayerUrl: "https://your-relayer-url.com",
chainId: ChainId.MAINNET,
signer: yourSignerInstance,
provider: yourProviderInstance,
webSocket: {
enabled: true, // Enable WebSocket real-time updates
autoConnect: true, // Auto-connect on initialization
reconnection: true, // Auto-reconnect on disconnection
},
};
const relayer = new Relayer(relayerConfig);
// Example: Building a relayer transaction
const buildTxParams = {
contractAddress: "0xYourContractAddress",
abi: yourContractAbi,
method: "yourMethodName",
args: ["arg1", "arg2"],
};
// Build and send transaction with real-time updates
relayer.buildRelayerTx(buildTxParams).then(async (txData) => {
console.log("Build Relayer Transaction Response: ", txData);
// Send with real-time WebSocket notifications
const response = await relayer.sendRelayerTxWithRealTimeUpdates({
...txData,
enableRealTimeUpdates: true,
webSocketEvents: {
onTransactionUpdate: (update) => {
console.log(`Transaction ${update.txId} status: ${update.status}`);
if (update.status === 'confirmed') {
console.log('🎉 Transaction confirmed!', update.blockNumber);
}
},
onError: (error) => {
console.error('WebSocket error:', error);
},
},
});
console.log("Transaction ID:", response.transactionId);
});Server wallet signing (@abstraxn/server-signer)
For backend agents using an Abstraxn Server Wallet, use createRelayerSigner from
@abstraxn/server-signer instead of a local private-key/ethers wallet:
npm install @abstraxn/server-signerimport { Relayer } from "@abstraxn/relayer";
import { ServerSignerClient } from "@abstraxn/server-signer";
import { JsonRpcProvider, type Signer } from "ethers";
const client = new ServerSignerClient({ apiKey: process.env.ABSTRAXN_API_KEY! });
await client.authenticate({
userIdentity: "backend-agent",
accessKey: process.env.SERVER_WALLET_ACCESS_KEY!,
});
const rpcUrl = process.env.RPC_URL!;
const { signer } = client.createRelayerSigner({
rpcUrl,
chainId: 137,
organizationId: process.env.TURNKEY_ORG_ID!,
fromAddress: "0xYourServerWallet",
});
const relayer = new Relayer({
relayerUrl: process.env.RELAYER_URL!,
chainId: 137,
provider: new JsonRpcProvider(rpcUrl),
signer: signer as unknown as Signer,
});See @abstraxn/server-signer README for the full gasless flow.
API
Core Methods
buildRelayerTx(params: BuildRelayerTxParams)
- Builds a transaction to be sent to the relayer.
buildRelayerTxEIP712(params: BuildRelayerTxParams)
- Builds a transaction using EIP-712 signing standard.
sendRelayerTx(params: SendRelayerTxParams)
- Sends a transaction to the relayer for processing.
sendSafeRelayerTx(params: SendSafeRelayerTxParams)
- Sends a safe wallet transaction to the relayer for processing.
getRelayerTxStatus(transactionId: string)
- Retrieves the status of a relayer transaction.
Wallet Whitelist (v1.1.0+)
Restrict which wallet addresses can use your relayer. Enable the feature in the Abstraxn Dashboard (Relayer → Policies → Whitelist Wallets), then manage addresses in the dashboard or from your backend via the SDK methods below.
getWalletWhitelist()
- Returns the current whitelist state:
{ isWalletWhitelistEnabled, whitelistedWallets }.
- Returns the current whitelist state:
setWalletWhitelist(walletAddresses: string[])
- Adds wallet addresses to the whitelist. Existing entries are kept. Each address must be a valid EVM address (
0x+ 40 hex chars). Addresses are normalized (lowercased, deduplicated) server-side. - Updates are queued asynchronously; the method returns
{ message: 'Whitelist add queued' }when accepted. - Throws if all provided addresses are already whitelisted. If only some already exist, the new ones are added and the rest are skipped.
- Adds wallet addresses to the whitelist. Existing entries are kept. Each address must be a valid EVM address (
removeWalletWhitelist(walletAddresses: string[])
- Removes only the provided wallet addresses from the whitelist. Other whitelisted addresses are unchanged.
- Updates are queued asynchronously; the method returns
{ message: 'Whitelist remove queued' }when accepted. - Throws if none of the provided addresses exist in the whitelist. If only some exist, those are removed and the rest are ignored.
When isWalletWhitelistEnabled is true, sendRelayerTx / sendSafeRelayerTx only succeed if the wallet in the signed transaction is in whitelistedWallets. When disabled (default), behavior is unchanged.
// Read current whitelist (server-side only — requires API key on relayer URL)
const whitelist = await relayer.getWalletWhitelist();
console.log(whitelist.isWalletWhitelistEnabled, whitelist.whitelistedWallets);
// Add wallets to the whitelist (valid EVM addresses)
await relayer.setWalletWhitelist([
"0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb0",
]);
// → { message: "Whitelist add queued" }
// Remove specific wallets from the whitelist
await relayer.removeWalletWhitelist([
"0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb0",
]);
// → { message: "Whitelist remove queued" }
// Transactions still use the same send flow — enforcement is automatic
const buildTxParams = {
contractAddress: "0xYourContractAddress",
abi: yourContractAbi,
method: "yourMethodName",
args: ["arg1", "arg2"],
};
const txData = await relayer.buildRelayerTx(buildTxParams);
await relayer.sendRelayerTx(txData);
// If whitelist is ON and wallet not in list → 400:
// "Wallet 0x... is not whitelisted for this relayer"Security: Call
getWalletWhitelist,setWalletWhitelist, andremoveWalletWhitelistfrom your backend only. Your relayer URL must include the API key (e.g. query param). Do not expose these calls from public client code.
🚀 WebSocket Methods (New!)
sendRelayerTxWithRealTimeUpdates(params: SendRelayerTxWithWebSocketParams)
- Sends a transaction and automatically subscribes to real-time status updates.
sendSafeRelayerTxWithRealTimeUpdates(params: SendSafeRelayerTxWithWebSocketParams)
- Sends a safe wallet transaction and automatically subscribes to real-time status updates.
subscribeToTransaction(transactionId: string, events?: RelayerWebSocketEvents)
- Subscribe to real-time updates for a specific transaction.
unsubscribeFromTransaction(transactionId: string)
- Unsubscribe from transaction updates.
connectWebSocket() / disconnectWebSocket()
- Manual WebSocket connection control.
isWebSocketConnected(): boolean
- Check WebSocket connection status.
🔄 Real-time Features
WebSocket Events
interface RelayerWebSocketEvents {
onTransactionUpdate?: (update: TransactionStatusUpdate) => void;
onTransactionCreated?: (event: TransactionCreatedEvent) => void;
onConnect?: () => void;
onDisconnect?: () => void;
onError?: (error: Error) => void;
}Transaction Status Flow
- initiated → Transaction created and submitted to relayer
- pending → Transaction submitted to blockchain
- confirmed → Transaction successfully mined ✅
- failed → Transaction failed ❌
- rejected → Transaction rejected by network ❌
Examples
Basic Real-time Tracking
// Subscribe to existing transaction
await relayer.subscribeToTransaction(txId, {
onTransactionUpdate: (update) => {
console.log(`Status: ${update.status}`);
if (update.status === 'confirmed') {
console.log(`Confirmed in block ${update.blockNumber}`);
}
},
});Promise-based Tracking
const txData = await relayer.buildRelayerTx(params);
const response = await relayer.sendRelayerTx(txData);
const finalStatus = await new Promise((resolve, reject) => {
relayer.subscribeToTransaction(response.transactionId, {
onTransactionUpdate: (update) => {
if (update.status === 'confirmed') resolve(update);
if (update.status === 'failed') reject(new Error('Failed'));
},
});
});Multiple Transactions
const transactions = ['tx1', 'tx2', 'tx3'];
transactions.forEach(txId => {
relayer.subscribeToTransaction(txId, {
onTransactionUpdate: (update) => {
console.log(`[${txId}] Status: ${update.status}`);
},
});
});Wallet Whitelist Management
// 1. Enable whitelist in Dashboard: Relayer → Policies → Whitelist Wallets
// 2. From your backend, set allowed wallets
await relayer.setWalletWhitelist([
"0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb0",
]);
// 3. Verify state
const { isWalletWhitelistEnabled, whitelistedWallets } =
await relayer.getWalletWhitelist();
// 4. Only whitelisted wallets can relay transactions when enabled
if (isWalletWhitelistEnabled) {
const buildTxParams = {
contractAddress: "0xYourContractAddress",
abi: yourContractAbi,
method: "yourMethodName",
args: ["arg1", "arg2"],
};
const txData = await relayer.buildRelayerTx(buildTxParams);
await relayer.sendRelayerTx(txData); // blocked if signer not in list
}Migration Guide
Before (Polling)
const response = await relayer.sendRelayerTx(txData);
// Manual polling required
setInterval(async () => {
const status = await relayer.getRelayerTxStatus(response.transactionId);
console.log(status);
}, 2000);After (Real-time)
const response = await relayer.sendRelayerTxWithRealTimeUpdates({
...txData,
enableRealTimeUpdates: true,
webSocketEvents: {
onTransactionUpdate: (update) => console.log(update.status),
},
});
// Instant updates! 🚀Benefits
- ✅ Instant Updates: No more 2-5 second polling delays
- ✅ Better Performance: Reduced server load and bandwidth
- ✅ Improved UX: Real-time feedback for users
- ✅ Battery Efficient: No constant background requests
- ✅ Backward Compatible: Existing code still works
- ✅ Auto Fallback: Falls back to polling if WebSocket fails
For detailed examples, see WEBSOCKET_EXAMPLES.md.
