Skip to main content

Solana Payment Setup

1. RPC

Use a private RPC in production. Scriptonia prefers Helius; other providers work if the URL is compatible. Env (server):
HELIUS_RPC_URL=
# or
SOLANA_RPC_URL=
Public (client-safe):
NEXT_PUBLIC_SOLANA_RPC_URL=
NEXT_PUBLIC_SOLANA_NETWORK=mainnet
Priority: HELIUS_RPC_URL → SOLANA_RPC_URL → NEXT_PUBLIC_SOLANA_RPC_URL.
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:
TREASURY_WALLET=
Exposed to the client only as agentAddress via GET /api/payment/config.

3. Network

NEXT_PUBLIC_SOLANA_NETWORK=mainnet
# or
NEXT_PUBLIC_SOLANA_NETWORK=devnet
lib/solana.ts and the wallet use this for mainnet vs devnet.

Token Mode

Modes

ModeEnvBehavior
SOL placeholderUSE_SPL_TOKEN not true or mint unsetTreated 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
Client
  • 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/payment before 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
Used:
  • useAppKitAccount
  • useAppKitProvider
  • useAppKitConnection
PaymentForm uses address, walletProvider, connection to:
  • 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')
Connect button and modal come from the AppKit/Reown UI. Phantom is selected when the user picks it in the wallet list.

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
  • 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
POST /api/execute (after the user pays)
  • 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/config must 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