Skip to main content
Payment handlers connect wallets to payment schemes. Each handler knows how to sign payments for a specific blockchain. This page covers configuring the built-in handlers for Solana and EVM.

Solana handler

pnpm add @faremeter/payment-solana @faremeter/wallet-solana @solana/web3.js
import { Keypair } from "@solana/web3.js"
import { createPaymentHandler } from "@faremeter/payment-solana/exact"
import { createLocalWallet } from "@faremeter/wallet-solana"

const keypair = Keypair.fromSecretKey(new Uint8Array(keypairBytes))
const wallet = await createLocalWallet("devnet", keypair)
const handler = createPaymentHandler(wallet, wallet.mint)
The Solana handler supports:
  • SPL token transfers (USDC)
  • Native SOL transfers
  • Devnet, testnet, and mainnet-beta

SPL token payments

SPL token payments use the splToken scheme. The handler constructs a token transfer transaction and signs it with the wallet.

Native SOL payments

SOL payments use the exact scheme with native SOL as the asset. The handler constructs a system transfer and signs it.

EVM handler

pnpm add @faremeter/payment-evm @faremeter/wallet-evm
import { createPaymentHandler } from "@faremeter/payment-evm/exact"
import { createLocalWallet } from "@faremeter/wallet-evm"

const wallet = await createLocalWallet({ id: 84532, name: "Base Sepolia" }, privateKey)
const handler = createPaymentHandler(wallet)
The EVM handler supports:
  • EIP-3009 gasless USDC transfers
  • ERC-20 token transfers
  • Base Sepolia, Base, Polygon, Skale, Monad

Gasless payments

EIP-3009 payments are gasless. The client signs an EIP-712 typed message authorizing a transfer. The facilitator submits the transaction on-chain and pays the gas. The client never needs native tokens.

Using both handlers

Register multiple handlers with the fetch wrapper to support both chains simultaneously:
import { Keypair } from "@solana/web3.js"
import { wrap } from "@faremeter/fetch"
import { createPaymentHandler as createSolanaHandler } from "@faremeter/payment-solana/exact"
import { createPaymentHandler as createEVMHandler } from "@faremeter/payment-evm/exact"
import { createLocalWallet as createSolanaWallet } from "@faremeter/wallet-solana"
import { createLocalWallet as createEVMWallet } from "@faremeter/wallet-evm"

const keypair = Keypair.fromSecretKey(new Uint8Array(keypairBytes))
const solanaWallet = await createSolanaWallet("devnet", keypair)
const evmWallet = await createEVMWallet({ id: 84532, name: "Base Sepolia" }, privateKey)

const fetchWithPayment = wrap(fetch, {
  handlers: [
    createSolanaHandler(solanaWallet, solanaWallet.mint),
    createEVMHandler(evmWallet),
  ],
})
The fetch wrapper passes 402 requirements to each handler. The first handler that can fulfill a requirement is used. To customize selection, provide a payerChooser — see Fetch Wrapper.

Further reading