OS Trading Engine
Technical Documentation
Integrations
Solana Web3.js

Solana Web3.js

Nexgent uses @solana/web3.js for all Solana blockchain interactions including wallet management, balance queries, and transaction signing.

Overview

FeatureUsage
Wallet KeypairsLoad and manage wallet keys
Balance QueriesCheck on-chain SOL balances
Transaction SigningSign swap transactions
RPC ConnectionCommunicate with Solana network

Configuration

# Solana RPC URL (mainnet)
SOLANA_RPC_URL=https://api.mainnet-beta.solana.com

# Wallet private keys (base58 encoded)
WALLET_1=your-base58-private-key
WALLET_2=another-private-key
⚠️

Never commit private keys to version control. Use environment variables or a secrets manager.


Wallet Management

Wallet Loader

Loads wallets from environment variables at startup:

// infrastructure/wallets/wallet-loader.ts
 
import { Keypair } from '@solana/web3.js';
import bs58 from 'bs58';
 
export class WalletLoader {
  loadWallets(): { wallets: Map<string, Keypair>; errors: WalletError[] } {
    const wallets = new Map<string, Keypair>();
    const errors: WalletError[] = [];
    
    // Load WALLET_1, WALLET_2, etc.
    for (let i = 1; i <= 10; i++) {
      const envKey = `WALLET_${i}`;
      const privateKey = process.env[envKey];
      
      if (privateKey) {
        try {
          // Decode base58 private key
          const secretKey = bs58.decode(privateKey);
          const keypair = Keypair.fromSecretKey(secretKey);
          const publicKey = keypair.publicKey.toBase58();
          
          wallets.set(publicKey, keypair);
          console.log(`✅ Loaded wallet ${i}: ${publicKey.slice(0, 8)}...`);
        } catch (error) {
          errors.push({
            envKey,
            error: 'Invalid private key format',
          });
        }
      }
    }
    
    return { wallets, errors };
  }
}

Wallet Store

Stores keypairs in memory for transaction signing:

// infrastructure/wallets/wallet-store.ts
 
class WalletStore {
  private wallets: Map<string, Keypair> = new Map();
  
  initialize(wallets: Map<string, Keypair>): void {
    this.wallets = wallets;
    console.log(`💼 Wallet store initialized with ${wallets.size} wallets`);
  }
  
  getKeypair(walletAddress: string): Keypair | undefined {
    return this.wallets.get(walletAddress);
  }
  
  hasWallet(walletAddress: string): boolean {
    return this.wallets.has(walletAddress);
  }
  
  getAddresses(): string[] {
    return Array.from(this.wallets.keys());
  }
}
 
export const walletStore = new WalletStore();

Balance Service

Queries on-chain SOL balances via RPC:

// infrastructure/external/solana/solana-balance-service.ts
 
import { Connection, PublicKey, LAMPORTS_PER_SOL } from '@solana/web3.js';
 
class SolanaBalanceService {
  private connection: Connection | null = null;
  
  initialize(rpcUrl?: string): void {
    const url = rpcUrl || process.env.SOLANA_RPC_URL 
      || 'https://api.mainnet-beta.solana.com';
    this.connection = new Connection(url, 'confirmed');
    console.log(`✅ Solana RPC initialized: ${url}`);
  }
  
  async getOnChainBalance(walletAddress: string): Promise<OnChainBalanceResult> {
    // Validate address
    if (!this.isValidAddress(walletAddress)) {
      throw new SolanaBalanceServiceError(
        `Invalid address: ${walletAddress}`,
        'INVALID_ADDRESS'
      );
    }
    
    // Reject simulation wallets
    if (walletAddress.startsWith('sim_')) {
      throw new SolanaBalanceServiceError(
        'Cannot check balance for simulation wallets',
        'SIMULATION_WALLET'
      );
    }
    
    const publicKey = new PublicKey(walletAddress);
    const balanceLamports = await this.connection!.getBalance(publicKey);
    const balanceSol = balanceLamports / LAMPORTS_PER_SOL;
    
    return {
      walletAddress,
      balanceLamports,
      balanceSol,
    };
  }
  
  isValidAddress(address: string): boolean {
    try {
      new PublicKey(address);
      return true;
    } catch {
      return false;
    }
  }
}

Transaction Signing

Jupiter returns base64-encoded transactions that need to be signed:

// In JupiterSwapProvider
 
private signTransaction(base64Transaction: string, keypair: Keypair): string {
  // Decode base64 to buffer
  const transactionBuffer = Buffer.from(base64Transaction, 'base64');
  
  // Deserialize (Jupiter uses VersionedTransaction v0)
  const transaction = VersionedTransaction.deserialize(transactionBuffer);
  
  // Sign with wallet keypair
  transaction.sign([keypair]);
  
  // Serialize and encode back to base64
  const signedBuffer = transaction.serialize();
  return Buffer.from(signedBuffer).toString('base64');
}

Token Metadata Service

Fetches SPL token metadata from on-chain:

// infrastructure/external/solana/token-metadata-service.ts
 
import { Connection, PublicKey } from '@solana/web3.js';
 
class TokenMetadataService {
  private connection: Connection;
  
  async getTokenSymbol(tokenAddress: string): Promise<string | null> {
    try {
      const mintAddress = new PublicKey(tokenAddress);
      
      // Get token account info
      const accountInfo = await this.connection.getAccountInfo(mintAddress);
      
      if (!accountInfo) {
        return null;
      }
      
      // Parse metadata from account data
      // (Implementation depends on token metadata program)
      
      return symbol;
    } catch (error) {
      console.error(`Failed to fetch metadata for ${tokenAddress}`);
      return null;
    }
  }
}

RPC Connection

Connection Configuration

import { Connection, Commitment } from '@solana/web3.js';
 
// Create connection with commitment level
const connection = new Connection(
  process.env.SOLANA_RPC_URL || 'https://api.mainnet-beta.solana.com',
  'confirmed'  // Commitment level
);

Commitment Levels

LevelDescriptionUse Case
processedFastest, may be rolled backNot recommended
confirmedSupermajority confirmationBalance queries
finalizedFully finalizedCritical operations

Nexgent uses confirmed commitment for balance queries. Transaction confirmations from Jupiter use their own confirmation mechanism.


Key Types

Keypair

import { Keypair } from '@solana/web3.js';
 
// From secret key (byte array)
const keypair = Keypair.fromSecretKey(secretKey);
 
// Get public key (wallet address)
const address = keypair.publicKey.toBase58();
 
// Sign data
transaction.sign([keypair]);

PublicKey

import { PublicKey } from '@solana/web3.js';
 
// From string (base58)
const publicKey = new PublicKey('So11111111111111111111111111111111111111112');
 
// SOL mint address constant
const SOL_MINT = new PublicKey('So11111111111111111111111111111111111111112');

VersionedTransaction

import { VersionedTransaction } from '@solana/web3.js';
 
// Deserialize from bytes
const transaction = VersionedTransaction.deserialize(buffer);
 
// Sign
transaction.sign([keypair]);
 
// Serialize
const bytes = transaction.serialize();

Constants

import { LAMPORTS_PER_SOL } from '@solana/web3.js';
 
// Convert lamports to SOL
const sol = lamports / LAMPORTS_PER_SOL;  // 1 SOL = 1,000,000,000 lamports
 
// Convert SOL to lamports
const lamports = sol * LAMPORTS_PER_SOL;
 
// SOL mint address (Wrapped SOL)
const SOL_MINT_ADDRESS = 'So11111111111111111111111111111111111111112';

Error Handling

ErrorCauseResolution
INVALID_ADDRESSMalformed wallet addressCheck address format
SIMULATION_WALLETTried to query sim walletUse real addresses for live mode
RPC_ERRORRPC connection failedCheck RPC URL, try again
WALLET_NOT_FOUNDKeypair not in storeCheck env vars, restart

Security

Private Key Handling

  1. Never store in database - Keys are in env vars only
  2. Memory only - Loaded at startup, stored in Map
  3. No logging - Never log private keys
  4. Limited access - Only walletStore.getKeypair() returns keypairs
// Safe: Return keypair only for signing
const keypair = walletStore.getKeypair(walletAddress);
 
// Never: Don't expose or log
console.log(keypair.secretKey); // ❌ NEVER