nestjs-solana-kit
v0.3.0
Published
Production-ready NestJS module for Solana blockchain. Built on @solana/kit v5.x with 12 services: RPC, accounts, transactions, subscriptions, PDAs, ALTs, and more. Full TypeScript support with derived types.
Maintainers
Readme
NestJS Module for Solana Kit
Type-safe NestJS integration for Solana blockchain with @solana/kit v5.x. Provides ready-to-use services for accounts, transactions, blocks, programs, and real-time subscriptions with full TypeScript support and dependency injection.
Features
- Modern SDK Integration: Built on
@solana/kitv5.x (Solana's new modular web3.js architecture) with full TypeScript support - Type-Safe with Derived Types: All types are automatically derived from
@solana/kitusing TypeScript utility types (ReturnType, Awaited, Omit, etc.), ensuring perfect compatibility and automatic updates when the SDK changes - NestJS Native: Designed for NestJS with dependency injection and module configuration
- High-Level API: Simplified methods for common Solana operations
- 12 Production-Ready Services:
SolanaRpcService- RPC client management and health checksSolanaConfigService- Centralized configuration managementSolanaAccountService- Account queries, balances, token accounts, batch operationsSolanaBlockService- Block and epoch informationSolanaTransactionService- Transaction building, signing, sending, confirmationSolanaSubscriptionService- WebSocket subscriptions with auto-reconnectSolanaUtilsService- Type conversions, token formatting, legacy SDK compatSolanaProgramService- Program deployment and account queriesSolanaAddressService- PDA/ATA derivation utilitiesSolanaAltService- Address Lookup Table management with cachingSolanaAuthorityService- Keypair/signer management and cachingSolanaEventService- On-chain event extraction and discriminator utilities
- Flexible Configuration: Both static and async module registration
- Production Ready: Built-in error handling, logging, and retry mechanisms
Type Safety & Derivation
This library takes a unique approach to type safety by deriving all types directly from @solana/kit rather than manually redefining them. This ensures:
- ✅ Perfect compatibility - Types always match the actual SDK behavior
- ✅ Automatic updates - When
@solana/kitupdates, types update automatically - ✅ Zero drift - No manual type maintenance or version sync issues
- ✅ IDE support - Full autocomplete and type checking from the official SDK
Examples of Type Derivation
// AccountInfo: Derived by combining base types from @solana/kit
export type AccountInfo = AccountInfoBase & AccountInfoWithBase64EncodedData;
// BlockhashInfo: Extracted from API return type
export type BlockhashInfo = ReturnType<GetLatestBlockhashApi['getLatestBlockhash']>['value'];
// BlockInfo variants: Base type + specific transaction details
export type BlockInfo = Omit<NonNullable<ReturnType<GetBlockApi['getBlock']>>, 'transactions'>;
export type BlockInfoWithSignatures = BlockInfo & { signatures: readonly Base58EncodedBytes[] };
export type BlockInfoWithTransactions = BlockInfo & { transactions: readonly TransactionForFullBase58<void>[] };
// Subscription types: Direct from notification APIs
export type AccountNotification = SolanaRpcResponse<AccountInfo>;
export type SignatureNotification = ReturnType<SignatureNotificationsApi['signatureNotifications']>;Generic Type Support
The library uses TypeScript generics to provide context-aware return types:
// getBlock returns different types based on the includeTransactions parameter
const blockWithTxs = await solanaBlock.getBlock(slot, true); // BlockInfoWithTransactions
const blockWithSigs = await solanaBlock.getBlock(slot, false); // BlockInfoWithSignaturesInstallation
# npm
npm install nestjs-solana-kit @solana/kit
# yarn
yarn add nestjs-solana-kit @solana/kit
# pnpm
pnpm add nestjs-solana-kit @solana/kitPeer Dependencies:
@nestjs/common(^10.0.0 || ^11.0.0) - NestJS framework@nestjs/core(^10.0.0 || ^11.0.0) - NestJS corereflect-metadata(^0.1.13 || ^0.2.0) - Reflection metadatarxjs(^7.0.0) - Reactive extensions
Note: This library supports both NestJS v10 and v11. Development uses the latest v11 for best DX while maintaining backward compatibility with v10.
Quick Start
1. Static Module Registration
For simple applications with hardcoded configuration:
import { Module } from '@nestjs/common';
import { SolanaModule } from 'nestjs-solana-kit';
@Module({
imports: [
SolanaModule.register({
rpcUrl: 'https://api.devnet.solana.com',
// cluster is auto-detected via getGenesisHash() if not provided
commitment: 'confirmed',
}),
],
})
export class AppModule {}2. Async Module Registration
For applications using ConfigModule or dynamic configuration:
import { Module } from '@nestjs/common';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { SolanaModule } from 'nestjs-solana-kit';
@Module({
imports: [
ConfigModule.forRoot(),
SolanaModule.registerAsync({
imports: [ConfigModule],
useFactory: (configService: ConfigService) => ({
rpcUrl: configService.get('SOLANA_RPC_URL'),
// cluster is optional - auto-detected if not provided
commitment: 'confirmed',
wsUrl: configService.get('SOLANA_WS_URL'),
}),
inject: [ConfigService],
}),
],
})
export class AppModule {}3. Cluster Auto-Detection
The library automatically detects the cluster from your RPC endpoint using getGenesisHash():
// Works with any RPC provider (Helius, QuickNode, Alchemy, etc.)
SolanaModule.register({
rpcUrl: 'https://my-helius-endpoint.com/api-key',
// No cluster needed - auto-detected!
})
// Explicit cluster takes precedence (skips RPC call)
SolanaModule.register({
rpcUrl: 'https://my-helius-endpoint.com/api-key',
cluster: 'devnet', // Override auto-detection
})
// Localhost URLs are detected as 'localnet' without RPC call
SolanaModule.register({
rpcUrl: 'http://localhost:8899',
// Automatically detected as 'localnet'
})Detection priority:
- Explicit
clusteroption (if provided) localhost/127.0.0.1URLs →localnetgetGenesisHash()RPC call → maps to known clusters- Falls back to
mainnet-betaif detection fails
4. Cluster Type
Use the Cluster type and CLUSTERS constant for type-safe cluster references:
import { CLUSTERS, Cluster } from 'nestjs-solana-kit';
// Type-safe cluster values
const myCluster: Cluster = CLUSTERS.DEVNET; // 'devnet'
const mainnet: Cluster = CLUSTERS.MAINNET; // 'mainnet-beta'Usage Examples
Account Operations
import { Injectable } from '@nestjs/common';
import { SolanaAccountService } from 'nestjs-solana-kit';
@Injectable()
export class MyService {
constructor(private readonly accountService: SolanaAccountService) {}
async getWalletInfo(address: string) {
// Get SOL balance
const balance = await this.accountService.getBalanceInSol(address);
// Get token accounts
const tokens = await this.accountService.getTokenAccounts(address);
// Get token decimals
const decimals = await this.accountService.getTokenDecimals(mintAddress);
// Batch fetch accounts with rate limiting
const accounts = await this.accountService.batchGetAccounts(addresses, {
batchSize: 100,
delayMs: 50,
});
}
}Transaction Building
import { Injectable } from '@nestjs/common';
import { SolanaTransactionService, SolanaUtilsService } from 'nestjs-solana-kit';
@Injectable()
export class TransferService {
constructor(
private readonly txService: SolanaTransactionService,
private readonly utilsService: SolanaUtilsService,
) {}
async buildTransferForClient(userAddress: string, instructions: Instruction[]) {
// Create noop signer for client-side signing
const userSigner = this.utilsService.toNoopSigner(userAddress);
// Build unsigned transaction
const base64Tx = await this.txService.buildUnsignedBase64({
feePayer: userSigner.address,
instructions,
});
return { transaction: base64Tx };
}
}PDA Derivation
import { Injectable } from '@nestjs/common';
import { SolanaAddressService } from 'nestjs-solana-kit';
@Injectable()
export class ProgramService {
constructor(private readonly addressService: SolanaAddressService) {}
async getUserPda(programId: string, userAddress: string) {
const { address, bump } = await this.addressService.derivePda(
programId,
['user_state', userAddress]
);
return address;
}
async getUserAta(owner: string, mint: string) {
return this.addressService.deriveAta(owner, mint);
}
}Event Processing
import { Injectable } from '@nestjs/common';
import { SolanaEventService } from 'nestjs-solana-kit';
@Injectable()
export class EventProcessor {
constructor(private readonly eventService: SolanaEventService) {}
extractEvents(logs: string[]) {
// Get event discriminator
const discriminator = this.eventService.getEventDiscriminator('TransferEvent');
// Extract events from transaction logs
const events = this.eventService.extractEventsFromLogs(logs, [
this.eventService.createEventConfig('TransferEvent', decodeTransferEvent),
]);
return events;
}
}Documentation
- Services Reference - Complete API documentation for all 12 services
Contributing
npm install # Install dependencies
npm test # Run tests
npm run lint # Lint code
npm run build # Build packagePre-commit hooks run type-check and lint-staged automatically.
License
MIT
