This guide shows you how to integrate wallets (like Phantom, Crossmint, or any custom wallet provider) with Faremeter to enable blockchain payments via HTTP. Whether you’re building for Solana or EVM chains, Faremeter’s modular architecture makes it straightforward to connect any wallet SDK.
The signature must follow EIP-712 exactly - the USDC contract will verify that the signature recovers to the from address. This is why smart wallets cannot use this scheme (they don’t have an EOA private key for signature recovery).
Note on Chain Types: If you’re using viem’s Chain type (from viem/chains), it already includes id and name fields along with many others. The payment handler only uses id and name, so you can pass a full Chain object directly - the extra fields will be ignored.
Copy
Ask AI
import { base } from "viem/chains";// base has: id, name, rpcUrls, blockExplorers, contracts, etc.// Payment handler only uses: id and nameconst wallet = { chain: base, ... };
All three methods are optional. Choose which to implement based on your wallet’s capabilities:updateTransaction only (most common)
Use when: Your wallet just needs to sign transactions
The payment handler builds the transaction automatically
Examples: Phantom, local keypair wallets, hardware wallets
buildTransaction only
Use when: Your wallet needs complete control over transaction construction AND signing happens inside buildTransaction
The payment handler lets you build everything, then sends the serialized transaction
Example: Squads multisig (builds with vault PDA as payer, coordinates proposals/approvals, signs within buildTransaction)
buildTransaction + updateTransaction
Use when: You need custom transaction construction but signing is separate
buildTransaction creates the tx structure, updateTransaction adds signatures
Example: Custom fee payer pattern (see Solana Example 3 below)
sendTransaction only
Use when: The wallet SDK doesn’t expose signed transactions or RPC access - it handles everything internally and only returns a hash
Why: Custodial/smart wallet SDKs (like Crossmint) manage their own RPC endpoints and transaction broadcasting
The payment handler just gets back a transaction hash
Only works with: Settlement scheme (exact scheme doesn’t support this)
Example: Crossmint smart wallets (see Solana Example 4 below)
Why sendTransaction? Some wallet SDKs (like Crossmint, custodial wallets) don’t give you direct RPC access or expose signed transaction objects. They handle the entire transaction lifecycle through their API and only return a transaction hash. Use sendTransaction for these wallets.
Important: Use raw cluster names (“mainnet-beta”, “devnet”, “testnet”) for the network field. The payment handler automatically converts these to x402 format (“solana-mainnet-beta”) internally.
No @faremeter/wallet-privy package: Privy is integrated directly via @privy-io/react-auth. The wallet object is created by adapting Privy’s wallet interface to match the shape expected by @faremeter/payment-evm or @faremeter/payment-solana.
No @faremeter/wallet-privy package: Privy is integrated directly via @privy-io/react-auth. The wallet object is created by adapting Privy’s wallet interface to match the shape expected by @faremeter/payment-solana.See the complete Privy tutorial for a full working example.
Example 3: Advanced Solana Wallet with Custom Transaction Building
If your wallet needs to customize transaction building with a custom fee payer:
Copy
Ask AI
import { PublicKey, VersionedTransaction, TransactionMessage, TransactionInstruction, Connection, Keypair,} from "@solana/web3.js";import { createPaymentHandler } from "@faremeter/payment-solana/exact";import { lookupKnownSPLToken } from "@faremeter/info/solana";async function createAdvancedSolanaWallet( network: string, connection: Connection, signingKeypair: Keypair, feePayerKeypair: Keypair) { const usdcInfo = lookupKnownSPLToken(network, "USDC"); if (!usdcInfo) { throw new Error(`Couldn't look up USDC on ${network}`); } const mint = new PublicKey(usdcInfo.address); const wallet = { network, publicKey: signingKeypair.publicKey, buildTransaction: async ( instructions: TransactionInstruction[], recentBlockHash: string ) => { // Build transaction with custom fee payer const message = new TransactionMessage({ instructions, payerKey: feePayerKeypair.publicKey, recentBlockhash: recentBlockHash, }).compileToV0Message(); const tx = new VersionedTransaction(message); // Sign with fee payer first tx.sign([feePayerKeypair]); return tx; }, updateTransaction: async (tx: VersionedTransaction) => { // Add wallet's signature after transaction is built tx.sign([signingKeypair]); return tx; }, }; return { wallet, handler: createPaymentHandler(wallet, mint, connection), };}
Why both methods? This example uses buildTransaction to construct the transaction with a custom fee payer (not the wallet’s publicKey), then updateTransaction to add the wallet’s signature. The payment handler calls buildTransaction first, then updateTransaction if it exists, allowing you to separate transaction construction from signing.Use case: This pattern enables gas sponsorship where a service pays transaction fees for users, improving UX by eliminating the need for users to hold SOL for fees.
Example 4: Smart Wallet with Settlement Scheme (Crossmint)
For Solana smart wallets (account abstraction), use the settlement scheme. The key difference is importing @faremeter/x-solana-settlement instead of @faremeter/payment-solana/exact:
When to use settlement vs exact scheme? Use the settlement scheme (@faremeter/x-solana-settlement) for smart wallets like Crossmint and Squads that use account abstraction. Use the exact scheme (@faremeter/payment-solana/exact) for standard EOA wallets like Phantom. The settlement scheme uses escrow PDAs - the client creates an escrow payment, and the server settles it after verification.
Implementation Notes: The Ledger wallet uses signEIP712HashedMessage (pre-hashing domain and message separately), while viem’s privateKeyToAccount uses standard EIP-712 signing. Both approaches produce compatible signatures when implemented correctly according to the EIP-712 specification.
Faremeter supports multiple payment schemes to accommodate different wallet types and use cases. This guide focuses on the “exact” scheme, which is the most widely compatible:
EVM: Under development - contact the team for smart wallet support
Why different schemes? EIP-3009 requires signing with an EOA private key for on-chain verification. Smart wallets use contract accounts without traditional private keys, so they need alternative payment schemes like settlement.
Test with a known-working reference like viem’s privateKeyToAccount
Different wallet SDKs may have different EIP-712 implementations - verify yours produces valid signatures
Verify Your Signature
Copy
Ask AI
import { verifyTypedData } from 'viem';// Test that your wallet's signature is validconst isValid = await verifyTypedData({ address: wallet.address, domain, types, primaryType, message, signature});
Common Issues
Signature doesn’t recover to the wallet address
SDK doesn’t support EIP-712 typed data signing
Wallet is a smart contract (use settlement scheme instead)