Server
server.ts
Copy
Ask AI
import express from "express"
import { createMiddleware } from "@faremeter/middleware/express"
import { x402Exact as solanaX402Exact } from "@faremeter/info/solana"
import { x402Exact } from "@faremeter/info/evm"
const app = express()
const multiChainPayment = await createMiddleware({
facilitatorURL: "https://facilitator.corbits.dev",
accepts: [
...solanaX402Exact({
network: "devnet",
payTo: process.env.SOLANA_ADDRESS,
asset: "USDC",
amount: "10000",
}),
x402Exact({
network: "base-sepolia",
payTo: process.env.EVM_ADDRESS,
asset: "USDC",
amount: "10000",
}),
],
})
app.get("/api/data", multiChainPayment, (req, res) => {
res.json({ data: "multi-chain protected content" })
})
app.listen(3000)
Client with rides
The simplest approach. Add wallets for both chains and rides selects the right one.client-rides.ts
Copy
Ask AI
import "dotenv/config"
import { payer } from "@faremeter/rides"
import { getLogger } from "@faremeter/logs"
const logger = await getLogger(["client"])
await payer.addLocalWallet(process.env.PAYER_KEYPAIR_PATH)
await payer.addLocalWallet(process.env.EVM_PRIVATE_KEY)
const response = await payer.fetch("http://localhost:3000/api/data")
logger.info(JSON.stringify(await response.json()))
Client with fetch wrapper
For more control over chain selection.client-fetch.ts
Copy
Ask AI
import "dotenv/config"
import { Keypair, PublicKey } from "@solana/web3.js"
import { wrap } from "@faremeter/fetch"
import type { PaymentExecer } from "@faremeter/types/client"
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"
import { lookupKnownSPLToken } from "@faremeter/info/solana"
import { getLogger } from "@faremeter/logs"
import { readFileSync } from "node:fs"
const logger = await getLogger(["client"])
const solanaKeypairBytes = JSON.parse(readFileSync(process.env.PAYER_KEYPAIR_PATH, "utf-8"))
const solanaKeypair = Keypair.fromSecretKey(new Uint8Array(solanaKeypairBytes))
const solanaWallet = await createSolanaWallet("devnet", solanaKeypair)
const evmWallet = await createEVMWallet({ id: 84532, name: "base-sepolia" }, process.env.EVM_PRIVATE_KEY)
const splTokenInfo = lookupKnownSPLToken("devnet", "USDC")
if (!splTokenInfo) throw new Error("Unknown SPL token")
const solanaMint = new PublicKey(splTokenInfo.address)
const preferEVM = (execers: PaymentExecer[]) => {
const evm = execers.find((e) => e.requirements.network.startsWith("base"))
return evm ?? execers[0]
}
const fetchWithPayment = wrap(fetch, {
handlers: [
createSolanaHandler(solanaWallet, solanaMint),
createEVMHandler(evmWallet),
],
payerChooser: preferEVM,
})
const response = await fetchWithPayment("http://localhost:3000/api/data")
logger.info(JSON.stringify(await response.json()))
Running the example
Copy
Ask AI
# Terminal 1
SOLANA_ADDRESS=7xKX... EVM_ADDRESS=0x1234... pnpm tsx server.ts
# Terminal 2 (rides)
PAYER_KEYPAIR_PATH=~/.config/solana/id.json EVM_PRIVATE_KEY=0x... pnpm tsx client-rides.ts
# Terminal 2 (fetch wrapper with EVM preference)
PAYER_KEYPAIR_PATH=~/.config/solana/id.json EVM_PRIVATE_KEY=0x... pnpm tsx client-fetch.ts
payerChooser.