Skip to main content
This example demonstrates how to make x402 payments on SKALE Base Sepolia testnet using the exact payment scheme. This uses EIP-3009 (Transfer with Authorization) for gasless USDC transfers. SKALE Base Sepolia is the first SKALE Expand deployment, sourcing liquidity from Base Sepolia. It supports multiple native EIP-3009 tokens including USDC, USDT, WBTC, and WETH.

What is EIP-3009?

EIP-3009 enables gasless payments by allowing you to:
  1. Sign an authorization message off-chain (EIP-712)
  2. A facilitator submits the transaction and pays gas
  3. The USDC contract verifies your signature and executes the transfer
This is perfect for micro-payments where gas costs would exceed the payment amount.

Full Example

import "dotenv/config";
import { createLocalWallet } from "@faremeter/wallet-evm";
import { createPaymentHandler } from "@faremeter/payment-evm/exact";
import { wrap as wrapFetch } from "@faremeter/fetch";

const { EVM_PRIVATE_KEY } = process.env;

if (!EVM_PRIVATE_KEY) {
  throw new Error("EVM_PRIVATE_KEY must be set in your environment");
}

// Define SKALE Base Sepolia chain
const skaleBaseSepolia = {
  id: 324705682,
  name: "SKALE Base Sepolia",
  rpcUrls: {
    default: {
      http: ["https://base-sepolia-testnet.skalenodes.com/v1/jubilant-horrible-ancha"],
    },
  },
};

// Parse command line arguments
const args = process.argv.slice(2);
const port = args[0] ?? "4021";
const endpoint = args[1] ?? "weather";
const url = `http://localhost:${port}/${endpoint}`;

console.log("Creating wallet for SKALE Base Sepolia USDC payments...");
const wallet = await createLocalWallet(skaleBaseSepolia, EVM_PRIVATE_KEY);
console.log(`Wallet address: ${wallet.address}`);

const fetchWithPayer = wrapFetch(fetch, {
  handlers: [createPaymentHandler(wallet)],
});

console.log(`Making payment request to ${url}...`);
const response = await fetchWithPayer(url);
console.log(`Response status: ${response.status}`);

if (response.ok) {
  const data = await response.json();
  console.log("Response data:", data);
} else {
  console.error(`Error: ${response.statusText}`);
}

Step-by-Step Breakdown

1. Load Private Key

const { EVM_PRIVATE_KEY } = process.env;

if (!EVM_PRIVATE_KEY) {
  throw new Error("EVM_PRIVATE_KEY must be set in your environment");
}
Your private key must be:
  • 64-character hex string
  • Prefixed with 0x
  • Example: 0x1234567890abcdef...

2. Define Custom Chain

const skaleBaseSepolia = {
  id: 324705682,
  name: "SKALE Base Sepolia",
  rpcUrls: {
    default: {
      http: ["https://base-sepolia-testnet.skalenodes.com/v1/jubilant-horrible-ancha"],
    },
  },
};
Since SKALE Base Sepolia is not yet included in viem’s chain definitions, we define it manually. Faremeter uses a simple ChainInfo type that only requires the chain ID, name, and RPC URL.

3. Create Wallet

const wallet = await createLocalWallet(skaleBaseSepolia, EVM_PRIVATE_KEY);
This creates a wallet interface that:
  • Uses your private key for signing
  • Connects to SKALE Base Sepolia RPC
  • Implements EIP-712 typed data signing (required for EIP-3009)

4. Create Payment Handler

const fetchWithPayer = wrapFetch(fetch, {
  handlers: [createPaymentHandler(wallet)],
});
The payment handler:
  • Defaults to USDC on the wallet’s chain
  • Signs EIP-3009 authorization messages
  • Uses EIP-712 typed data for secure signing

5. Make Payment

const response = await fetchWithPayer(url);
console.log(`Response status: ${response.status}`);

if (response.ok) {
  const data = await response.json();
  console.log("Response data:", data);
} else {
  console.error(`Error: ${response.statusText}`);
}
When a 402 response is received:
  1. The handler creates an EIP-3009 authorization
  2. Signs it using EIP-712 typed data
  3. Returns the authorization + signature
  4. The facilitator submits the transaction
  5. The original request is retried and returns successfully

Payment Flow

Custom Asset Selection

SKALE Base Sepolia supports multiple native EIP-3009 tokens:
  • USDC.e: 0x2e08028E3C4c2356572E096d8EF835cD5C6030bD
  • USDT: 0x3ca0a49f511c2c89c4dcbbf1731120d8919050bf
  • WBTC: 0x4512eacd4186b025186e1cf6cc0d89497c530e87
  • WETH: 0xf94056bd7f6965db3757e1b145f200b7346b4fc0
  • SKL: 0xaf2e0ff5b5f51553fdb34ce7f04a6c3201cee57b
  • ETHC: 0xD2Aaa00700000000000000000000000000000000
To specify a different asset:
const wallet = await createLocalWallet(skaleBaseSepolia, EVM_PRIVATE_KEY);

const fetchWithPayer = wrapFetch(fetch, {
  handlers: [
    createPaymentHandler(wallet, {
      asset: "USDC", // or custom contract info
    }),
  ],
});

Command Line Arguments

  • First argument: Server port (default: 4021)
  • Second argument: Endpoint path (default: weather)
Example:
tsx skale-base-sepolia-payment.ts 4021 weather

EIP-712 Signing Details

The authorization is signed using EIP-712 typed data: Domain:
{
  name: "USDC",
  version: "2",
  chainId: 324705682,  // SKALE Base Sepolia
  verifyingContract: "0x2e08028E3C4c2356572E096d8EF835cD5C6030bD" // USDC contract
}
Types:
{
  TransferWithAuthorization: [
    { name: "from", type: "address" },
    { name: "to", type: "address" },
    { name: "value", type: "uint256" },
    { name: "validAfter", type: "uint256" },
    { name: "validBefore", type: "uint256" },
    { name: "nonce", type: "bytes32" }
  ]
}
Message:
{
  from: "0x...",        // Your wallet address
  to: "0x...",          // Merchant address
  value: 1000000n,      // Amount (6 decimals, so 1 USDC = 1000000)
  validAfter: 1234567890n,
  validBefore: 1234568190n,
  nonce: "0x..."        // Random 32-byte nonce
}

Environment Variables

  • EVM_PRIVATE_KEY: Your EVM private key (0x-prefixed hex string)

Funding Your Wallet

Make sure your wallet has:
  • USDC: Sufficient USDC for payments (bridged from Base Sepolia)
  • Credits: SKALE Base Sepolia uses compute CREDITS to maintain EVM compatibility while offering gasless usage
You can get SKALE Base Sepolia tokens from:

SKALE Base Sepolia Features

SKALE Base Sepolia is the first SKALE Expand deployment with unique features:
  • Zero Gas Fees: All transactions are gas-free
  • Instant Finality: Single slot finality for immediate confirmation
  • Base Liquidity: Sources tokens from Base Sepolia via native bridge
  • Native EIP-3009: USDC, USDT, WBTC, WETH all support direct EIP-3009
  • High Performance: 268,435,455 block gas limit
  • Native Bridge: Permissionless bridging from Base Sepolia