TypeScript Examples - Solana
Complete TypeScript examples for trading on Solana (Jupiter integration)
Prerequisites
npm install @solana/web3.js bs58Environment Variables
export NAOS_API_KEY="your-api-key"
export NAOS_API_DOMAIN="https://api.naos.trade"
export TRADING_SOL_PKEY="your-solana-private-key-base58"Setup
import { Keypair, VersionedTransaction } from '@solana/web3.js'
import bs58 from 'bs58'
const API_BASE_URL = process.env.NAOS_API_DOMAIN || 'http://localhost:3001'
const API_KEY = process.env.NAOS_API_KEY || 'your-api-key-here'
const TRADING_SOL_PKEY = process.env.TRADING_SOL_PKEY
interface SwapStep {
input: string
output: string
router: string
quoter: string
fee: number
tick: number
hook: string
poolType: string
address: string
}
interface QuoteResponse {
success: boolean
path?: Array<{ step: SwapStep }>
stats?: {
valueAmountInUsd: number
amountOut: string
amountOutMin: string
priceImpact?: number
txCostUsd?: number
}
transaction?: {
trade: string
quoteId: string
}
error?: string
}
async function makeRequest<T>(endpoint: string, options?: RequestInit): Promise<T> {
const response = await fetch(`${API_BASE_URL}${endpoint}`, {
method: options?.method || 'GET',
headers: {
'Authorization': `Bearer ${API_KEY}`,
'Content-Type': 'application/json',
...(options?.headers as Record<string, string> || {})
},
body: options?.body
})
if (!response.ok) throw new Error(`HTTP ${response.status}: ${await response.text()}`)
return await response.json() as T
}Get Quote
async function getQuote(params: {
token: string
amount: number
side: 'BUY' | 'SELL'
slippage: number
trader: string
chain: string
simulation?: boolean // Optional: run transaction simulation
}): Promise<QuoteResponse> {
const queryParams = new URLSearchParams({
token: params.token,
amount: params.amount.toString(),
side: params.side,
slippage: params.slippage.toString(),
trader: params.trader,
chain: params.chain
})
if (params.simulation) queryParams.append('simulation', 'true')
const response = await makeRequest<QuoteResponse>(`/api/v1/quote?${queryParams.toString()}`)
if (response.success && response.stats) {
console.log('Quote received:')
console.log(` Value: $${response.stats.valueAmountInUsd.toFixed(2)}`)
console.log(` Amount Out: ${response.stats.amountOut}`)
console.log(` Price Impact: ${response.stats.priceImpact?.toFixed(2) || 'N/A'}%`)
console.log(` TX Cost: $${response.stats.txCostUsd?.toFixed(4) || 'N/A'}`)
console.log(` Quote ID: ${response.transaction?.quoteId}`)
}
return response
}Execute Transaction
async function executeTransaction(params: {
txData: string
network: string
mev: boolean
skipSimulation: boolean
quoteId: string
}): Promise<any> {
const response = await makeRequest<any>('/api/v1/execute', {
method: 'POST',
body: JSON.stringify(params)
})
if (response.success) {
console.log('Transaction executed:')
console.log(` Status: ${response.status}`)
console.log(` TX Hash: ${response.txRes?.txHash}`)
console.log(` Spent: ${response.txRes?.spent}`)
console.log(` Received: ${response.txRes?.received}`)
}
return response
}Simple Buy Example
async function simpleBuySolana(): Promise<void> {
if (!TRADING_SOL_PKEY) {
throw new Error('TRADING_SOL_PKEY environment variable not set')
}
const keypair = Keypair.fromSecretKey(bs58.decode(TRADING_SOL_PKEY))
const traderAddress = keypair.publicKey.toBase58()
const params = {
token: '9fLGtf1rRkYd6Dy93hvYh2r8T8Wy2EPa6WHC5ibgpump',
trader: traderAddress,
amount: 1,
slippage: 1000
}
console.log('Getting quote...')
const quote = await getQuote({
token: params.token,
amount: params.amount,
side: 'BUY',
slippage: params.slippage,
trader: params.trader,
chain: 'SOL'
})
if (!quote.success || !quote.transaction?.trade) {
throw new Error(quote.error || 'Quote failed')
}
console.log('Signing transaction with Solana keypair...')
const txBuffer = Buffer.from(quote.transaction.trade, 'base64')
const transaction = VersionedTransaction.deserialize(txBuffer)
transaction.sign([keypair])
const signedTx = Buffer.from(transaction.serialize()).toString('base64')
console.log('Executing transaction...')
const result = await executeTransaction({
txData: signedTx,
network: 'SOL',
mev: false,
skipSimulation: false,
quoteId: quote.transaction.quoteId
})
console.log('Trade completed!')
console.log(`TX Hash: ${result.txRes?.txHash}`)
console.log(`Explorer: https://solscan.io/tx/${result.txRes?.txHash}`)
}Full Trading Flow (Buy → Sell)
Complete example showing buy and then sell 50% of holdings:
async function solanaFullTradingFlow(): Promise<void> {
if (!TRADING_SOL_PKEY) {
throw new Error('TRADING_SOL_PKEY environment variable not set')
}
const keypair = Keypair.fromSecretKey(bs58.decode(TRADING_SOL_PKEY))
const traderAddress = keypair.publicKey.toBase58()
const params = {
token: 'FDcjznQLP6KLCgrEPF35PNpFMebmGLDhPji8TCmVdkK8',
amount: 0.1,
slippage: 1000
}
console.log('='.repeat(80))
console.log('BUY STEP')
console.log('='.repeat(80))
console.log(`Token: ${params.token}`)
console.log(`Chain: SOL`)
console.log(`Trader: ${traderAddress}`)
console.log(`Amount: ${params.amount} SOL`)
console.log(`Slippage: ${params.slippage / 100}%`)
console.log('\nGetting token info...')
const tokenInfo = await makeRequest<any>(`/api/v1/token-info?tokenAddress=${params.token}&chain=SOL`)
const tokenDecimals = tokenInfo.tokenInfo?.token?.decimals || 6
console.log(`Token decimals: ${tokenDecimals}`)
const buyQuote = await getQuote({
token: params.token,
amount: params.amount,
side: 'BUY',
slippage: params.slippage,
trader: traderAddress,
chain: 'SOL'
})
if (!buyQuote.success || !buyQuote.transaction?.trade) {
throw new Error(buyQuote.error || 'Failed to get buy quote')
}
console.log('\nSigning buy transaction with Solana keypair...')
const buyTxBuffer = Buffer.from(buyQuote.transaction.trade, 'base64')
const buyTransaction = VersionedTransaction.deserialize(buyTxBuffer)
buyTransaction.sign([keypair])
const signedBuyTx = Buffer.from(buyTransaction.serialize()).toString('base64')
console.log('\nExecuting buy transaction...')
const buyResult = await executeTransaction({
txData: signedBuyTx,
network: 'SOL',
mev: false,
skipSimulation: false,
quoteId: buyQuote.transaction.quoteId
})
if (!buyResult.success) throw new Error(buyResult.error || 'Buy failed')
const tokensReceived = buyResult.txRes?.received || '0'
console.log('\nBUY COMPLETED!')
console.log(`TX Hash: ${buyResult.txRes?.txHash}`)
console.log(`Tokens Received: ${tokensReceived}`)
console.log(`SOL Spent: ${buyResult.txRes?.spent}`)
console.log(`Explorer: https://solscan.io/tx/${buyResult.txRes?.txHash}`)
console.log('\nWaiting 20 seconds before selling...')
await new Promise(resolve => setTimeout(resolve, 20000))
console.log('\n' + '='.repeat(80))
console.log('SELL STEP (50% of holdings)')
console.log('='.repeat(80))
const tokensReceivedBigInt = BigInt(tokensReceived)
if (tokensReceivedBigInt === 0n) {
throw new Error('No tokens received from buy transaction')
}
const balanceFormatted = Number(tokensReceivedBigInt) / Math.pow(10, tokenDecimals)
console.log(`Token Balance: ${balanceFormatted.toFixed(tokenDecimals)} tokens`)
const sellAmount50PercentRaw = balanceFormatted * 0.5
const sellAmount50Percent = Math.floor(sellAmount50PercentRaw * Math.pow(10, tokenDecimals)) / Math.pow(10, tokenDecimals)
console.log(`Selling 50%: ${sellAmount50Percent.toFixed(tokenDecimals)} tokens`)
const sellQuote = await getQuote({
token: params.token,
amount: sellAmount50Percent,
side: 'SELL',
slippage: params.slippage,
trader: traderAddress,
chain: 'SOL'
})
if (!sellQuote.success || !sellQuote.transaction?.trade) {
throw new Error(sellQuote.error || 'Failed to get sell quote')
}
console.log('\nSigning sell transaction with Solana keypair...')
const sellTxBuffer = Buffer.from(sellQuote.transaction.trade, 'base64')
const sellTransaction = VersionedTransaction.deserialize(sellTxBuffer)
sellTransaction.sign([keypair])
const signedSellTx = Buffer.from(sellTransaction.serialize()).toString('base64')
console.log('\nExecuting sell transaction...')
const sellResult = await executeTransaction({
txData: signedSellTx,
network: 'SOL',
mev: false,
skipSimulation: false,
quoteId: sellQuote.transaction.quoteId
})
if (!sellResult.success) throw new Error(sellResult.error || 'Sell failed')
console.log('\nSELL COMPLETED!')
console.log(`TX Hash: ${sellResult.txRes?.txHash}`)
console.log(`SOL Received: ${sellResult.txRes?.received}`)
console.log(`Tokens Spent: ${sellResult.txRes?.spent}`)
console.log(`Explorer: https://solscan.io/tx/${sellResult.txRes?.txHash}`)
console.log('\n' + '='.repeat(80))
console.log('SOLANA TRADING FLOW COMPLETED SUCCESSFULLY!')
console.log('='.repeat(80))
console.log(`Buy TX: https://solscan.io/tx/${buyResult.txRes?.txHash}`)
console.log(`Sell TX: https://solscan.io/tx/${sellResult.txRes?.txHash}`)
}Token Information
Get Solana token details:
async function getTokenInfo(tokenAddress: string): Promise<any> {
const response = await makeRequest<any>(
`/api/v1/token-info?tokenAddress=${tokenAddress}&chain=SOL`
)
if (response.success) {
console.log('Token Info:')
console.log(` Name: ${response.name || 'N/A'}`)
console.log(` Symbol: ${response.symbol || 'N/A'}`)
console.log(` Decimals: ${response.decimals}`)
console.log(` Price: $${response.priceUsd?.toFixed(6) || 'N/A'}`)
console.log(` Liquidity: $${response.liquidityUsd?.toLocaleString() || 'N/A'}`)
console.log(` Pool: ${response.poolAddress || 'N/A'}`)
}
return response
}Balance Checking
Check SOL and SPL token balances:
async function getBalance(walletAddress: string): Promise<any> {
const response = await makeRequest<any>(
`/api/v1/balance?walletAddress=${walletAddress}&network=SOL`
)
if (response.success) {
const formatted = Number(response.balance) / Math.pow(10, response.decimals || 9)
console.log(`SOL Balance: ${formatted.toFixed(6)} SOL`)
}
return response
}
async function getTokenBalance(
walletAddress: string,
tokenAddress: string
): Promise<any> {
const response = await makeRequest<any>(
`/api/v1/token-balance?walletAddress=${walletAddress}&tokenAddress=${tokenAddress}&network=SOL`
)
if (response.success) {
const formatted = Number(response.balance) / Math.pow(10, response.decimals || 6)
console.log(`Token Balance: ${formatted.toFixed(6)}`)
}
return response
}Keypair Management
Working with Solana keypairs:
import { Keypair } from '@solana/web3.js'
import bs58 from 'bs58'
function loadKeypair(privateKey: string): Keypair {
const decoded = bs58.decode(privateKey)
return Keypair.fromSecretKey(decoded)
}
function generateNewKeypair(): Keypair {
const keypair = Keypair.generate()
const privateKey = bs58.encode(keypair.secretKey)
console.log('Public Key:', keypair.publicKey.toBase58())
console.log('Private Key (base58):', privateKey)
return keypair
}
const keypair = loadKeypair(TRADING_SOL_PKEY!)
console.log('Loaded wallet:', keypair.publicKey.toBase58())Transaction Signing Details
Understanding Solana transaction signing:
async function signSolanaTransaction(
trade: string,
keypair: Keypair
): Promise<string> {
const txBuffer = Buffer.from(trade, 'base64')
const transaction = VersionedTransaction.deserialize(txBuffer)
transaction.sign([keypair])
const signedTxBuffer = Buffer.from(transaction.serialize())
const signedTx = signedTxBuffer.toString('base64')
return signedTx
}Error Handling
async function safeSolanaTrade() {
try {
await simpleBuySolana()
} catch (error: any) {
if (error.message.includes('Pool not found')) {
console.error('Token not found or has no liquidity on Jupiter')
} else if (error.message.includes('Insufficient balance')) {
console.error('Not enough SOL in wallet')
} else if (error.message.includes('Slippage')) {
console.error('Price moved too much, increase slippage tolerance')
} else if (error.message.includes('blockhash')) {
console.error('Transaction expired, retry with new quote')
} else if (error.message.includes('HTTP 401')) {
console.error('Invalid API key')
} else if (error.message.includes('HTTP 429')) {
console.error('Rate limit exceeded')
} else {
console.error('Unexpected error:', error.message)
}
}
}Running the Examples
Create a file solana-trading-test.ts:
import * as dotenv from 'dotenv'
dotenv.config()
async function main() {
console.log('Testing Solana Trading Flow...')
await solanaFullTradingFlow()
}
main().catch(console.error)Run it:
export NAOS_API_KEY="your-api-key"
export NAOS_API_DOMAIN="https://api.naos.trade"
export TRADING_SOL_PKEY="your-solana-private-key-base58"
npx ts-node solana-trading-test.tsBest Practices
Transaction Timing
Wait 20+ seconds between buy and sell for blockchain confirmation
Monitor transaction status on Solscan before next trade
Precision Handling
Use floor division for sell amounts to avoid rounding errors
Check token decimals: Most tokens use 6-9 decimals
Convert properly: Divide by
Math.pow(10, decimals)for display
Slippage Settings
5-10% (500-1000 bps) for most Solana tokens
10-20% (1000-2000 bps) for highly volatile or low liquidity tokens
Higher for pump.fun tokens: These can be extremely volatile
Security
Store private keys securely: Use environment variables
Base58 format: Solana private keys are base58 encoded
Test with small amounts: Start with 0.1 SOL or less
Never commit keys: Add
.envto.gitignore
Error Recovery
Retry on blockhash errors: Get a fresh quote
Check SOL balance: Ensure enough for transaction fees (~0.01 SOL)
Verify token existence: Use token-info endpoint first
Handle Jupiter errors: Some tokens may not be available
Important Differences from EVM
Serialization
Base64
Hex string
Private Key Format
Base58
0x-prefixed hex
Transaction Type
VersionedTransaction
Legacy/EIP-1559
Signing Library
@solana/web3.js
ethers.js
Approval Transactions
Not needed
Often required
Decimals
Usually 6-9
Usually 18
Explorer
solscan.io
etherscan.io, basescan.org
Solana-Specific Notes
Transaction Format
const txBuffer = Buffer.from(quote.transaction.trade, 'base64')
const transaction = VersionedTransaction.deserialize(txBuffer)
transaction.sign([keypair])
const signed = Buffer.from(transaction.serialize()).toString('base64')No Approval Needed
Unlike EVM:
Solana doesn't require separate approval transactions
Token accounts are created automatically if needed
All logic is in a single transaction
Jupiter Integration
Powered by Jupiter aggregator for best prices
Supports most SPL tokens and pump.fun tokens
Automatic route optimization
Advanced: Multiple Signers
If you need multiple signers:
const keypair1 = Keypair.fromSecretKey(bs58.decode(KEY1))
const keypair2 = Keypair.fromSecretKey(bs58.decode(KEY2))
transaction.sign([keypair1, keypair2])Common Token Addresses
Popular Solana tokens for testing:
const TOKENS = {
USDC: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v',
USDT: 'Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB',
SOL: 'So11111111111111111111111111111111111111112',
BONK: 'DezXAZ8z7PnrnRJjz3wXBoRgixCa6xjnB7YaB1pPB263',
WIF: 'EKpQGSJtjMFqKZ9KQanSqYXRcF8fBopzLHYxdM65zcjm'
}For complete playground with all scenarios, see: src/trading-suite/playground.ts
Last updated

