npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@net-protocol/relay

v0.1.4

Published

Net Relay SDK for submitting transactions via x402 payment relay service

Readme

@net-protocol/relay

Status: In Development - Do not use yet. Will have breaking changes and may be incomplete.

Net Relay SDK for submitting transactions via x402 payment relay service.

This package provides client-side functionality for interacting with the Net relay service, which allows users to submit on-chain transactions without holding ETH by paying with USDC via x402.

Installation

npm install @net-protocol/relay
# or
yarn add @net-protocol/relay

Features

  • Session Management: Create session tokens for authenticated batch requests
  • Balance Checking: Check backend wallet balance before submitting transactions
  • Wallet Funding: Fund backend wallets via x402 payments (USDC)
  • Transaction Submission: Submit batches of transactions via relay service
  • Retry Logic: Automatic retry with exponential backoff for failed transactions
  • Transaction Batching: Automatically batch transactions to respect API limits
  • Confirmation Waiting: Wait for transaction confirmations on-chain

Quick Start

Basic Usage

import {
  createRelaySession,
  submitTransactionsViaRelay,
} from "@net-protocol/relay";
import { privateKeyToAccount } from "viem/accounts";

// Create a session token
const account = privateKeyToAccount("0x...");
const { sessionToken } = await createRelaySession({
  apiUrl: "https://api.example.com",
  chainId: 84532,
  operatorAddress: "0x...",
  secretKey: "your-secret-key",
  account,
});

// Submit transactions
const result = await submitTransactionsViaRelay({
  apiUrl: "https://api.example.com",
  chainId: 84532,
  operatorAddress: "0x...",
  secretKey: "your-secret-key",
  transactions: [
    {
      to: "0x...",
      data: "0x...",
    },
  ],
  sessionToken,
});

Using the RelayClient Class

For a more convenient API, use the RelayClient class:

import { RelayClient } from "@net-protocol/relay";
import { privateKeyToAccount } from "viem/accounts";

const client = new RelayClient({
  apiUrl: "https://api.example.com",
  chainId: 84532,
});

const account = privateKeyToAccount("0x...");

// Create session
const { sessionToken } = await client.createSession({
  operatorAddress: "0x...",
  secretKey: "your-secret-key",
  account,
});

// Check balance
const balance = await client.checkBalance({
  operatorAddress: "0x...",
  secretKey: "your-secret-key",
});

// Fund backend wallet (if needed)
if (!balance.sufficientBalance) {
  const x402Client = client.createX402Client(account);
  await client.fundBackendWallet({
    operatorAddress: "0x...",
    secretKey: "your-secret-key",
    ...x402Client,
  });
}

// Submit transactions
const result = await client.submitTransactions({
  operatorAddress: "0x...",
  secretKey: "your-secret-key",
  transactions: [...],
  sessionToken,
});

API Reference

Functions

createRelaySession

Create a relay session token for authenticated batch requests.

function createRelaySession(params: {
  apiUrl: string;
  chainId: number;
  operatorAddress: Address;
  secretKey: string;
  account: LocalAccount;
  expiresIn?: number; // Optional, default: 3600 seconds
}): Promise<{ sessionToken: string; expiresAt: number }>;

checkBackendWalletBalance

Check the balance of the backend wallet for a given operator.

function checkBackendWalletBalance(params: {
  apiUrl: string;
  chainId: number;
  operatorAddress: Address;
  secretKey: string;
}): Promise<CheckBalanceResult>;

fundBackendWallet

Fund a backend wallet via x402 payment (USDC).

function fundBackendWallet(params: {
  apiUrl: string;
  chainId: number;
  operatorAddress: Address;
  secretKey: string;
  fetchWithPayment: typeof fetch;
  httpClient: {
    getPaymentSettleResponse: (
      getHeader: (name: string) => string | null
    ) => { transaction?: string; txHash?: string } | null;
  };
}): Promise<RelayFundResult>;

submitTransactionsViaRelay

Submit a batch of transactions via the relay service.

function submitTransactionsViaRelay(params: {
  apiUrl: string;
  chainId: number;
  operatorAddress: Address;
  secretKey: string;
  transactions: WriteTransactionConfig[];
  sessionToken: string;
}): Promise<RelaySubmitResult>;

retryFailedTransactions

Retry failed transactions with exponential backoff.

function retryFailedTransactions(params: {
  apiUrl: string;
  chainId: number;
  operatorAddress: Address;
  secretKey: string;
  failedIndexes: number[];
  originalTransactions: WriteTransactionConfig[];
  backendWalletAddress: Address;
  sessionToken: string;
  config?: RetryConfig;
  recheckFunction?: (
    failedIndexes: number[],
    transactions: WriteTransactionConfig[],
    backendWalletAddress: Address
  ) => Promise<number[]>;
}): Promise<RelaySubmitResult>;

waitForConfirmations

Wait for transaction confirmations on-chain.

function waitForConfirmations(params: {
  publicClient: PublicClient;
  transactionHashes: Hash[];
  confirmations?: number; // Default: 1
  timeout?: number; // Default: 60000ms
  onProgress?: (confirmed: number, total: number) => void;
}): Promise<Array<{ hash: Hash; receipt: any }>>;

batchTransactions

Batch transactions to respect API limits.

function batchTransactions(
  transactions: WriteTransactionConfig[]
): WriteTransactionConfig[][];

createRelayX402Client

Create an x402 client for relay payments.

function createRelayX402Client(
  account: LocalAccount,
  chainId?: number
): {
  fetchWithPayment: typeof fetch;
  httpClient: {
    getPaymentSettleResponse: (
      getHeader: (name: string) => string | null
    ) => { transaction?: string; txHash?: string } | null;
  };
};

Classes

RelayClient

High-level class-based API for the relay service.

class RelayClient {
  constructor(options: { apiUrl: string; chainId: number });

  createSession(params: {...}): Promise<{ sessionToken: string; expiresAt: number }>;
  checkBalance(params: {...}): Promise<CheckBalanceResult>;
  fundBackendWallet(params: {...}): Promise<RelayFundResult>;
  submitTransactions(params: {...}): Promise<RelaySubmitResult>;
  retryFailedTransactions(params: {...}): Promise<RelaySubmitResult>;
  createX402Client(account: LocalAccount): {...};
}

Types

CheckBalanceResult

interface CheckBalanceResult {
  backendWalletAddress: Address;
  balanceWei: string;
  balanceEth: string;
  sufficientBalance: boolean;
  minRequiredWei: string;
  minRequiredEth: string;
}

RelayFundResult

interface RelayFundResult {
  paymentTxHash: Hash;
  backendWalletAddress: Address;
}

RelaySubmitResult

interface RelaySubmitResult {
  transactionHashes: Hash[];
  successfulIndexes: number[];
  failedIndexes: number[];
  errors: { index: number; error: string }[];
  backendWalletAddress: Address;
  appFeeTransactionHash: Hash; // Always included
}

RetryConfig

interface RetryConfig {
  maxRetries?: number; // Default: 3
  initialDelay?: number; // Default: 1000ms
  maxDelay?: number; // Default: 30000ms
  backoffMultiplier?: number; // Default: 2
}

Constants

  • MAX_TRANSACTIONS_PER_BATCH: Maximum transactions per batch (100)
  • MAX_BATCH_SIZE_BYTES: Maximum batch size in bytes (900KB)
  • MAX_TRANSACTION_SIZE_BYTES: Maximum transaction size in bytes (100KB)

Usage Examples

Complete Upload Flow

import {
  RelayClient,
  batchTransactions,
  waitForConfirmations,
} from "@net-protocol/relay";
import { privateKeyToAccount } from "viem/accounts";
import { createPublicClient, http } from "viem";
import { base } from "viem/chains";

const client = new RelayClient({
  apiUrl: "https://api.example.com",
  chainId: 84532,
});

const account = privateKeyToAccount("0x...");
const publicClient = createPublicClient({
  chain: base,
  transport: http(),
});

// 1. Create session
const { sessionToken } = await client.createSession({
  operatorAddress: account.address,
  secretKey: "your-secret-key",
  account,
});

// 2. Check balance
const balance = await client.checkBalance({
  operatorAddress: account.address,
  secretKey: "your-secret-key",
});

// 3. Fund if needed
if (!balance.sufficientBalance) {
  const x402Client = client.createX402Client(account);
  await client.fundBackendWallet({
    operatorAddress: account.address,
    secretKey: "your-secret-key",
    ...x402Client,
  });
}

// 4. Prepare transactions
const transactions = [
  // ... your transactions
];

// 5. Batch transactions
const batches = batchTransactions(transactions);

// 6. Submit each batch
const allHashes: Hash[] = [];
for (const batch of batches) {
  const result = await client.submitTransactions({
    operatorAddress: account.address,
    secretKey: "your-secret-key",
    transactions: batch,
    sessionToken,
  });

  allHashes.push(...result.transactionHashes);

  // Retry failed transactions if any
  if (result.failedIndexes.length > 0) {
    const retryResult = await client.retryFailedTransactions({
      operatorAddress: account.address,
      secretKey: "your-secret-key",
      failedIndexes: result.failedIndexes,
      originalTransactions: batch,
      backendWalletAddress: result.backendWalletAddress,
      sessionToken,
    });

    allHashes.push(...retryResult.transactionHashes);
  }
}

// 7. Wait for confirmations
const receipts = await waitForConfirmations({
  publicClient,
  transactionHashes: allHashes,
  confirmations: 1,
  onProgress: (confirmed, total) => {
    console.log(`Confirmed ${confirmed}/${total}`);
  },
});

Chain Support

The package supports multiple chains via the chainId parameter:

  • Base Sepolia (84532): Uses x402.org facilitator
  • Base Mainnet (8453): Uses Coinbase CDP facilitator (automatic)

Error Handling

All functions throw errors with descriptive messages. Common error scenarios:

  • Session expired: Session token has expired, create a new one
  • Insufficient balance: Backend wallet needs funding
  • Payment failed: x402 payment could not be processed
  • Transaction failed: Transaction was rejected by the network
  • Rate limit: Too many requests, retry after delay

License

MIT