Solana Integration Guide
This tutorial shows how to integrate T402 payments with Solana using SPL tokens.
Overview
Solana uses SPL tokens for USDT/USDC transfers. The T402 Solana implementation supports:
- SPL Token transfers (USDT, USDC)
- Ed25519 signatures
- Recent blockhash based replay protection
Prerequisites
- Node.js 18+ or Python 3.10+
- Solana wallet with devnet SOL and tokens
- Basic understanding of Solana concepts
Network Identifiers
| Network | CAIP-2 Identifier |
|---|---|
| Solana Mainnet | solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp |
| Solana Devnet | solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1 |
| Solana Testnet | solana:4uhcVJyU9pJkvQyS88uRDiswHXSCkY3z |
Token Addresses
| Token | Network | Mint Address |
|---|---|---|
| USDC | Mainnet | EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v |
| USDT | Mainnet | Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB |
| USDC | Devnet | 4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU |
Install Dependencies
npm install @t402/svm @t402/core @solana/web3.js @solana/spl-tokenClient Setup
Create a client that can sign Solana payment authorizations.
import { t402Client } from '@t402/core/client';
import { ExactSvmScheme, toClientSvmSigner } from '@t402/svm';
import { Keypair, Connection } from '@solana/web3.js';
import bs58 from 'bs58';
// Create connection
const connection = new Connection('https://api.mainnet-beta.solana.com');
// Create keypair from secret key
const secretKey = bs58.decode('your_base58_private_key');
const keypair = Keypair.fromSecretKey(secretKey);
// Create Solana signer
const svmSigner = toClientSvmSigner({
keypair,
connection,
});
// Create t402 client
const client = new t402Client()
.register('solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp', new ExactSvmScheme(svmSigner));Server Setup
Configure your server to accept Solana payments.
import express from 'express';
import { paymentMiddleware } from '@t402/express';
import { t402ResourceServer, createFacilitatorClient } from '@t402/core/server';
import { registerExactSvmServerScheme } from '@t402/svm/exact/server';
const app = express();
// Create facilitator client
const facilitator = createFacilitatorClient({
url: 'https://facilitator.t402.io',
});
// Create t402 server
const server = new t402ResourceServer(facilitator);
registerExactSvmServerScheme(server, {});
// Define routes with Solana payment
const routes = {
'/api/premium/*': {
accepts: {
scheme: 'exact',
network: 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp',
payTo: 'YourSolanaAddress',
price: '$0.01',
},
description: 'Premium API access',
},
};
// Apply middleware
app.use(paymentMiddleware(routes, server));
app.get('/api/premium/data', (req, res) => {
res.json({ data: 'Premium content' });
});
app.listen(3000);Make Payment Requests
import { wrapFetchWithPayment } from '@t402/fetch';
const fetchWithPay = wrapFetchWithPayment(fetch, client);
// Automatic payment handling
const response = await fetchWithPay('https://api.example.com/api/premium/data', {
method: 'GET',
});
const data = await response.json();
console.log(data);Solana-Specific Concepts
SPL Token Transfers
Solana uses SPL tokens for USDT/USDC. The payment flow:
- Client creates and signs SPL token transfer instruction
- Transaction includes recent blockhash for validity
- Facilitator submits transaction to network
- SPL program processes the transfer
Associated Token Accounts
Each wallet needs an Associated Token Account (ATA) for each token:
import { getAssociatedTokenAddress } from '@solana/spl-token';
// Get ATA for USDC
const ata = await getAssociatedTokenAddress(
new PublicKey('EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v'), // USDC mint
walletPublicKey,
);The facilitator automatically creates ATAs if they don’t exist, but this adds a small fee.
Transaction Priority
For faster confirmations, add priority fees:
import { ComputeBudgetProgram } from '@solana/web3.js';
// Add priority fee instruction
const priorityFeeIx = ComputeBudgetProgram.setComputeUnitPrice({
microLamports: 1000, // Priority fee in micro-lamports
});Blockhash Validity
Transactions are valid for ~60 seconds:
// Get recent blockhash
const { blockhash, lastValidBlockHeight } = await connection.getLatestBlockhash();
// Transaction is valid until lastValidBlockHeightTesting on Devnet
Get devnet SOL from the Solana Faucet.
- Configure for devnet:
const connection = new Connection('https://api.devnet.solana.com');
const routes = {
'/api/test/*': {
accepts: {
scheme: 'exact',
network: 'solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1',
payTo: 'YourDevnetAddress',
price: '$0.001',
},
},
};-
Use devnet wallet and tokens
-
Verify transactions on explorer.solana.com
Phantom Wallet Integration
For browser-based applications:
// Check if Phantom is available
if ('solana' in window) {
const phantom = window.solana;
if (phantom.isPhantom) {
// Connect to Phantom
const response = await phantom.connect();
const publicKey = response.publicKey;
// Create signer from Phantom
const signer = toClientSvmSigner({
publicKey,
signTransaction: (tx) => phantom.signTransaction(tx),
});
const client = new t402Client()
.register('solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp', new ExactSvmScheme(signer));
}
}Troubleshooting
Common Issues
| Issue | Solution |
|---|---|
| Blockhash expired | Retry with fresh blockhash |
| Insufficient SOL | Add SOL for transaction fees |
| Missing ATA | Create ATA before transfer |
| Signature verification failed | Ensure keypair matches public key |
RPC Errors
| Code | Description |
|---|---|
-32002 | Transaction simulation failed |
-32003 | Transaction already processed |
-32005 | Node unhealthy |
Related
- @t402/svm Reference - API documentation
- Solana Network Details - Chain configuration
- Multi-Chain App - Cross-chain integration