Solana blockchain adapter powered by @solana/web3.js




Solana Adapter implementation powered by @solana/web3.js
_Seamlessly integrate your existing Solana setup with the Stablecoin Kits ecosystem_
- Solana Adapter
- Table of Contents
- Overview
- Why Solana Adapter?
- When and How Should I Use The Solana Adapter?
- I'm a developer using a kit
- Example
- I'm a developer making a Kit Provider
- Installation
- Quick Start
- 🚀 Easy Setup with Factory Methods (Recommended)
- 🏭 Production Considerations
- 🌐 Browser Support with Wallet Providers
- 🔧 Advanced Manual Setup
- Features
- Usage Examples
- Basic Usage with Factory Methods
- Multiple Private Key Format Support
- Cross-Chain Bridge (Solana → EVM)
- Browser Wallet Integration
- Manual Setup with Solana Clients
- Supported Networks
- API Reference
- Factory Methods
- createSolanaAdapterFromPrivateKey(params)
- createSolanaAdapterFromProvider(params)
- Constructor Options
- Methods
- Network Validation
- How It Works
- Common Scenarios
- Error Messages
- When Validation Runs
- Integration with Stablecoin Kits
- Development
- Contributing
- License
The Solana Adapter is a strongly-typed implementation of the Adapter interface for the Solana blockchain. Built on top of the popular @solana/web3.js library, it provides type-safe blockchain interactions through a unified interface that's designed to work seamlessly with the Bridge Kit for cross-chain USDC transfers between Solana and EVM networks, as well as any future kits for additional stablecoin operations. It can be used by any Kit built using the Stablecoin Kits architecture and/or any providers plugged into those kits.
- ⚡ Zero-config defaults - Built-in reliable RPC endpoints for Solana mainnet and devnet
- 🌐 Full Solana compatibility: Works with Solana mainnet and devnet
- 🔧 Bring your own setup: Use your existing Solana Connection and Keypair instances
- 🚀 Instant connectivity: Connect without researching RPC providers
- ⚡ High performance: Leverages Solana's fast and low-cost blockchain
- 🔒 Type-safe: Built with TypeScript strict mode for complete type safety
- 🎯 Simple API: Clean abstraction over complex blockchain operations
- 🔄 Transaction lifecycle: Complete prepare/estimate/execute workflow
- 🌉 Cross-chain ready: Seamlessly bridge USDC between Solana and EVM chains
#### I'm a developer using a kit
If you're using one of the kits to do some action, e.g. bridging from chain 'A' to chain 'B', then you only need to instantiate the adapter for your chain and pass it to the kit.
##### Example
``typescript`
const adapter = new SolanaAdapter({
connection,
signer: keypair,
})
#### I'm a developer making a Kit Provider
If you are making a provider for other Kit users to plug in to the kit, e.g. a BridgeProvider, and you'll need to interact with diff chains, then you'll need to use the abstracted Adapter methods to execute on chain.
`bash`
npm install @circle-fin/adapter-solana @solana/web3.js @solana/spl-tokenor
yarn add @circle-fin/adapter-solana @solana/web3.js @solana/spl-token
This adapter requires @solana/web3.js and @solana/spl-token as peer dependencies. Install them alongside the adapter.
Zero configuration required! 🎉
The adapter automatically handles browser compatibility by:
- Bundling the Buffer polyfill inline (~6KB gzipped)
- Setting up global Buffer before Solana libraries load
- Working seamlessly in all modern browsers
No additional packages or configuration needed!
Supported Versions:
- @solana/web3.js: ^1.98.2@solana/spl-token
- : ^0.4.13
If you encounter peer dependency warnings:
- Check your package versions: npm ls @solana/web3.js @solana/spl-tokennpm install @solana/web3.js@^1.98.2 @solana/spl-token@^0.4.13
- Ensure versions meet the minimum requirements
- Use to install compatible versions
The simplest way to get started is with our factory methods. With reliable default RPC endpoints - no need to configure Solana RPC providers!
`typescript
import { createSolanaAdapterFromPrivateKey } from '@circle-fin/adapter-solana'
// Create an adapter with built-in reliable RPC endpoints
const adapter = createSolanaAdapterFromPrivateKey({
privateKey: process.env.SOLANA_PRIVATE_KEY!, // Base58, Base64, or JSON array format
})
// Ready to use with Stablecoin Kits!
const address = await adapter.getAddress()
console.log('Connected address:', address)
`
✨ Key Feature: All Solana chains include reliable default RPC endpoints:
- Solana Mainnet: https://solana-mainnet.public.blastapi.iohttps://solana-devnet.public.blastapi.io
- Solana Devnet:
> ⚠️ Important for Production: The factory methods use Solana's default public RPC endpoints by default when no custom connection is provided, which may have rate limits and lower reliability. For production applications, we strongly recommend providing a custom connection with dedicated RPC providers like Helius, QuickNode, or Alchemy.
`typescript
import { createSolanaAdapterFromPrivateKey } from '@circle-fin/adapter-solana'
import { Connection } from '@solana/web3.js'
// Production-ready setup with custom RPC endpoints
const customConnection = new Connection(
https://solana-mainnet.g.alchemy.com/v2/${process.env.ALCHEMY_KEY},wss://solana-mainnet.g.alchemy.com/v2/${process.env.ALCHEMY_KEY}
{
commitment: 'confirmed',
wsEndpoint: ,
},
)
const adapter = createSolanaAdapterFromPrivateKey({
privateKey: process.env.SOLANA_PRIVATE_KEY!,
connection: customConnection,
})
`
For browser environments with wallet providers like Phantom, Solflare, or Backpack:
`typescript
import { createSolanaAdapterFromProvider } from '@circle-fin/adapter-solana'
// Create an adapter from a browser wallet
const adapter = await createSolanaAdapterFromProvider({
provider: window.solana, // Phantom, Solflare, etc.
})
`
For advanced use cases requiring full control over Connection and Keypair:
`typescript
import { SolanaAdapter } from '@circle-fin/adapter-solana'
import { Connection, Keypair } from '@solana/web3.js'
import bs58 from 'bs58'
// Use your existing Solana setup
const connection = new Connection('https://api.mainnet-beta.solana.com')
const keypair = Keypair.fromSecretKey(
bs58.decode(process.env.SOLANA_PRIVATE_KEY),
)
// Create the adapter
const adapter = new SolanaAdapter(
{
connection,
signer: keypair,
},
{
addressContext: 'developer-controlled',
supportedChains: [Solana],
},
)
`
For advanced scenarios like hardware wallets, multi-chain operations, or dynamic signer selection:
`typescript
import { SolanaAdapter } from '@circle-fin/adapter-solana'
import { Connection } from '@solana/web3.js'
import { Solana, SolanaDevnet } from '@core/chains'
// Create adapter with lazy signer initialization
const adapter = new SolanaAdapter(
{
connection: new Connection('https://api.mainnet-beta.solana.com'),
// Signer is initialized on-demand with context about the operation
signer: async (ctx) => {
// Access operation context: chain, address, etc.
console.log('Signing for chain:', ctx.chain.name)
// Example: Select different signers based on chain
if (ctx.chain.name === 'Solana') {
return await getMainnetSigner()
} else {
return await getDevnetSigner()
}
},
},
{
addressContext: 'user-controlled',
supportedChains: [Solana, SolanaDevnet],
},
)
// Signer is initialized only when needed
const prepared = await adapter.prepare(params, { chain: Solana })
`
Benefits of lazy initialization:
- ⚡ Performance - Signer initialized only when needed
- 🔐 Security - Shorter lifetime of sensitive keys in memory
- 🎯 Context-aware - Select signers based on chain, address, or other factors
- 🔄 Flexible - Support hardware wallets, KMS, or dynamic signer sources
Backward Compatibility:
`typescript`
// Traditional approach still works - no context parameter needed
const adapter = new SolanaAdapter(
{
connection,
signer: async () => {
// No ctx parameter - works for simple cases
return await initializeSigner()
},
},
capabilities,
)
- ✅ Full Solana compatibility - Works with Solana mainnet and devnet
- ✅ Solana/web3.js integration - Uses your existing Connection and Keypair
- ✅ Wallet provider support - Works with Phantom, Solflare, and other Solana wallets
- ✅ Factory methods - Easy setup with sensible defaults
- ✅ Network validation - Automatically validates wallet/connection matches configured network
- ✅ Transaction lifecycle - Complete prepare/estimate/execute workflow
- ✅ Type safety - Full TypeScript support with strict mode
- ✅ Cross-chain ready - Seamlessly bridge USDC between Solana and EVM chains
The createSolanaAdapterFromPrivateKey function automatically detects and handles different private key formats:
`typescript
// Base58 format (most common for Solana)
const adapterBase58 = createSolanaAdapterFromPrivateKey({
privateKey: '5Kk7z8gvn...', // Base58 string
})
// Base64 format
const adapterBase64 = createSolanaAdapterFromPrivateKey({
privateKey: 'MIGHAgEAMB...', // Base64 string
})
// JSON array format (array of bytes)
const adapterArray = createSolanaAdapterFromPrivateKey({
privateKey: '[1,2,3,4,5,...]', // JSON array string
})
`
`typescript
import { createSolanaAdapterFromProvider } from '@circle-fin/adapter-solana'
// Connect to user's Solana wallet
const adapter = await createSolanaAdapterFromProvider({
provider: window.solana, // Phantom, Solflare, etc.
})
`
`typescript
import { SolanaAdapter } from '@circle-fin/adapter-solana'
import { Connection, Keypair } from '@solana/web3.js'
import bs58 from 'bs58'
// Initialize with your Solana setup
const connection = new Connection('https://api.mainnet-beta.solana.com')
const keypair = Keypair.fromSecretKey(
bs58.decode(process.env.SOLANA_PRIVATE_KEY),
)
const adapter = new SolanaAdapter({
connection,
signer: keypair,
})
`
Works with all Solana networks supported by the Stablecoin Kits:
- Solana Mainnet - Production network
- Solana Devnet - Development and testing network
#### createSolanaAdapterFromPrivateKey(params)
Create an adapter from a private key (supports multiple formats).
`typescript`
interface CreateSolanaAdapterFromPrivateKeyParams {
privateKey: string // Supports Base58, Base64, or JSON array formats
connection?: Connection // Optional pre-configured Connection instance
capabilities?: AdapterCapabilities // Optional addressContext and supportedChains
}
#### createSolanaAdapterFromProvider(params)
Create an adapter from a Solana wallet provider.
`typescript`
interface CreateSolanaAdapterFromProviderParams {
provider: SolanaWalletProvider // Phantom, Solflare, etc.
connection?: Connection // Optional pre-configured Connection instance
capabilities?: AdapterCapabilities // Optional addressContext and supportedChains
}
`typescript`
interface SolanaAdapterOptions
connection?: Connection // Optional - can use getConnection instead
getConnection?: (params: { chain: ChainDefinition }) => Connection // Lazy connection init
signer:
| Signer // Direct signer (Keypair or ProviderSigner)
| ((ctx: OperationContext
}
Signer Options:
- Direct Signer: Pass a Keypair or browser wallet ProviderSigner directly
- Context-Aware Function: Pass an async function that receives operation context and returns a signer
- Enables chain-specific or address-specific signer selection
- Supports lazy initialization for hardware wallets or KMS
- Backward compatible - functions can ignore the context parameter if not needed
- getAddress() - Get the connected wallet addressprepare()
- - Prepare transactions for executionestimate()
- - Estimate transaction costsexecute()
- - Execute prepared transactionswaitForTransaction()
- - Wait for transaction confirmationcalculateTransactionFee()
- - Calculate transaction fees with optional buffer
You can see the implementation of each of these methods in the Solana Adapter's main implementation file.
The Solana adapter includes automatic network validation to prevent common errors where your wallet/connection is on a different network than your code configuration.
When you first use an adapter (via prepare()), the system automatically:
1. Check the genesis hash of your connection/wallet
2. Compare it against the expected network from your chain configuration
3. Throw a helpful error if there's a mismatch
4. Cache the validation result for subsequent operations
`typescript
// Adapter creation succeeds (no network validation yet)
const adapter = await createSolanaAdapterFromProvider({
provider: window.solana, // Connected to mainnet
chain: 'Solana_Devnet', // But code expects devnet!
})
// ❌ This will throw an error when you try to prepare a transaction
await adapter.prepare({
instructions: [...]
})
// Error: Network mismatch detected! Your wallet/connection is on Solana Mainnet,
// but the code is configured for Solana Devnet...
// ✅ Solutions:
// Option 1: Switch your wallet to devnet
// Option 2: Update your code to use 'Solana' instead of 'Solana_Devnet'
`
Network validation provides clear, actionable error messages:
- Network mismatch: Shows which network you're on vs. expected, with specific steps to fix
- Unsupported networks: Identifies unsupported networks by genesis hash
- Connection issues: Wraps connection errors with helpful context
Network validation occurs:
- ✅ During the first prepare() call - when you first attempt to prepare a transaction
- ✅ Cached after first validation - subsequent operations use the cached result
- ❌ Not during factory method calls
- ❌ Not during manual SolanaAdapter construction
This adapter is designed to work seamlessly across the Stablecoin Kits ecosystem. Here's an example with the Bridge Kit:
`typescript
import { BridgeKit } from '@circle-fin/bridge-kit'
import { createSolanaAdapterFromPrivateKey } from '@circle-fin/adapter-solana'
import { createViemAdapterFromPrivateKey } from '@circle-fin/adapter-viem-v2'
const kit = new BridgeKit()
// Solana adapter
const solanaAdapter = createSolanaAdapterFromPrivateKey({
privateKey: process.env.SOLANA_PRIVATE_KEY!,
})
// EVM adapter
const evmAdapter = createViemAdapterFromPrivateKey({
privateKey: process.env.EVM_PRIVATE_KEY as 0x${string},
chain: 'Ethereum',
})
// Ready for cross-chain bridging!
await kit.bridge({
from: solanaAdapter,
to: evmAdapter,
amount: '50.0',
})
`
This package is part of the Stablecoin Kits monorepo.
`bashBuild
nx build @circle-fin/adapter-solana
This project is licensed under the Apache 2.0 License. Contact support for details.
---