Solana Payment Setup
1. RPC
Use a private RPC in production. Scriptonia prefers Helius; other providers work if the URL is compatible. Env (server):If missing or invalid, it falls back to api.mainnet-beta.solana.com or api.devnet.solana.com based on NEXT_PUBLIC_SOLANA_NETWORK.
2. Treasury
Payments are sent to the Treasury (agent) wallet:GET /api/payment/config.
3. Network
Token Mode
Modes
| Mode | Env | Behavior |
|---|---|---|
| SOL placeholder | USE_SPL_TOKEN not true or mint unset | Treated as SOL. Conversion: 0.02 SOL. Used for dev/test. |
Balance and validation
Server- getSOLTokenBalance(wallet)
- validatePayment(wallet, requiredSOL) in lib/solana.ts
- With SPL: uses the mint and associated token account
- Without: SOL × 2,750,000
- PaymentForm uses
connection.getBalance(publicKey) - Fixed requiredSOL = 0.02 for the SOL placeholder UI
- For SPL, the client builds the tx via lib/solana-client.ts
- Balance checks for SPL are enforced on the server in
/api/paymentbefore the user is allowed to proceed
Phantom / Reown AppKit
Scriptonia uses Reown AppKit with the Solana adapter for connect and signing. Phantom and other Solana wallets work through the same adapter.Config
config/appkit.ts- projectId: NEXT_PUBLIC_REOWN_PROJECT_ID
- metadata: name, description, url, icons
- SolanaAdapter from
@reown/appkit-adapter-solana
Client
Hooks from:@reown/appkit@reown/appkit-adapter-solana/react
- useAppKitAccount
- useAppKitProvider
- useAppKitConnection
- Resolve agentAddress from
GET /api/payment/config - Call createPaymentTransaction from lib/solana-client
- Sign and send via:
- signAndSendTransaction
- or signTransaction + sendRawTransaction
connection.confirmTransaction(signature, 'confirmed')
Transaction Flow
1. Payment (client)
- User connects wallet (AppKit → Phantom or other)
- PaymentForm gets agentAddress from
/api/payment/config - Balance:
- SOL placeholder:
connection.getBalance(publicKey) - User needs ≥ 0.02 SOL
- SOL placeholder:
- createPaymentTransaction(from, to, amountSOL) in lib/solana-client:
- SOL: SystemProgram.transfer with 0.02 SOL
- User signs with wallet via AppKit
connection.confirmTransaction(signature, 'confirmed')- onPaymentConfirmed(signature, walletAddress)
2. Validation and Execute (server)
POST /api/payment (before the user sends the tx)- validatePayment(userWalletPubKey) in lib/solana.ts (SOL-based)
- On success, workflow moves to payment_processing
- Body can include transactionSignature
- verifyTransaction(signature) in lib/solana.ts:
- getSignatureStatus
- must be err === null
- must have a confirmation
- If valid:
- execution runs
- workflow updated with paymentDetails.transactionSignature
Troubleshooting
“Insufficient funds” (SOL)- Cause: SOL balance < 0.02
- Fix: Use devnet and airdrop, or fund the wallet on mainnet
“Balance fetch timed out” / RPC errors
- Cause: RPC slow or RPC URL wrong or placeholder
- Fix: Set a valid RPC URL
“Invalid agent address”
- Cause: TREASURY_WALLET missing or invalid
- Fix: Set TREASURY_WALLET to a valid Solana public key
/api/payment/configmust return it as agentAddress
“Wallet provider does not support transaction signing”
- Cause: Wallet did not expose signAndSendTransaction or signTransaction
- Fix: Update Reown/AppKit and adapter; ensure wallet is unlocked and on the correct network
“Invalid transaction signature” on Execute
- Cause: verifyTransaction failed
- Fix: Ensure the user waits for confirmation and that client and server use the same network and RPC