@tuwaio/pulsar-solana
@tuwaio/pulsar-solana is the Solana Layer 4 (L4) package of Pulsar, the transaction tracking project of TUWA Stage 2 (“State & Connection”, next to Satellite Connect). Built on @solana/kit and @tuwaio/orbit-solana (Wallet Standard discovery and cached RPC clients), it provides the Solana adapter for @tuwaio/pulsar-core, a signature tracker and a helper to sign and send transactions. It does not use the legacy @solana/web3.js or gill.
🏛️ Core Capabilities
- Adapter:
pulsarSolanaAdapter({ rpcUrls })reads the connected wallet from the last connection saved by@tuwaio/orbit-core(Satellite Connect writes it) and finds it among the installed Wallet Standard wallets. Before signing it checks that the wallet is on the cluster of the transaction (devnet,solana:devnetand the genesis-hash chain IDsolana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1are the same cluster) and throwsSolanaChainMismatchErrorotherwise; it does not switch clusters. The transaction is saved with the genesis-hash chain ID of its cluster aschainId(CAIP-2, as CAIP-30 defines it for Solana). It also builds Solana Explorer links and retries failed transactions for UI kits such as Nova Transactions. - Signature tracker: polls
getSignatureStatusesevery second and writes the commitment toconfirmationStatusas it goes (processed, thenconfirmed, usually about a second after sending, so a UI can show the transaction as confirmed), until the transaction isfinalized(Success) or fails (Failed, as soon as the status carries an on-chain error). It fetches the fee, blockhash and instructions once withgetTransaction(commitmentconfirmed; legacy, version 0 and version 1 transactions) and searches the transaction history, so transactions that finished while the page was closed are found after a reload. The details are optional: agetTransactionerror never hides the status or fails the transaction, and a finalized transaction whose details are still missing after 10 checks is markedSuccesswithout them. - Expired transactions: a transaction whose signature is still unknown when the chain passes the last valid block height of its blockhash can no longer land; the tracker checks it once more and marks it
Failedwith an “expired” error, within seconds.signAndSendSolanaTxsaves that height aslastValidBlockHeight; for transactions sent otherwise, set it withupdateTxParams, or the tracker gives up one hour after sending. Errors ofgetSignatureStatusesandgetBlockHeightare retried. - Signing helper:
signAndSendSolanaTxbuilds a version 0 transaction from one or more instructions (for example generated by Codama ), sets the latest blockhash, and has aTransactionSendingSignersign and send it. Create the signer for a Wallet Standard account withcreateSolanaTransactionSendingSignerof@tuwaio/orbit-solana(0.5 and later), without React. - Standalone use:
solanaFetcherworks withinitializePollingTrackerfrom@tuwaio/pulsar-corewithout the store. See Solana Trackers Standalone .
The tracker writes its results to the store with updateTxParams, and the onSuccess and onError callbacks of executeTxAction receive the updated transaction; the store’s onTxFinished and subscribeTxFinished run for every finished transaction, also after a reload. An RPC outage says nothing about the transaction, so in the store errors of the RPC never end tracking: it asks every minute after 30 errors in a row. When it gives up, it marks the transaction Failed and keeps it in the pool.
💾 Installation
pnpm add @tuwaio/pulsar-solana @tuwaio/pulsar-core @tuwaio/orbit-core @tuwaio/orbit-solana @solana/kit @wallet-standard/app @wallet-standard/ui-core @wallet-standard/ui-registry zustand immer dayjs[!IMPORTANT]
@tuwaio/pulsar-core(>=0.12),@tuwaio/orbit-core(>=0.4),@tuwaio/orbit-solana(>=0.4),@solana/kit(>=8.2) anddayjs(1.x) are peer dependencies and must be installed alongside@tuwaio/pulsar-solana. The@wallet-standardpackages are the peer dependencies of@tuwaio/orbit-solana, andzustandandimmerthose of@tuwaio/pulsar-core.
🚀 Usage
import type { Instruction } from '@solana/kit';
import { OrbitAdapter } from '@tuwaio/orbit-core';
import { createSolanaClientWithCache, createSolanaTransactionSendingSigner } from '@tuwaio/orbit-solana';
import { createPulsarStore, type SolanaTransaction } from '@tuwaio/pulsar-core';
import { pulsarSolanaAdapter, signAndSendSolanaTx } from '@tuwaio/pulsar-solana';
import type { UiWalletAccount } from '@wallet-standard/ui-core';
const rpcUrls = { devnet: 'https://api.devnet.solana.com' };
export const pulsarStore = createPulsarStore<SolanaTransaction>({
name: 'pulsar-transactions',
adapter: pulsarSolanaAdapter({ rpcUrls }),
});
// `account`: the Wallet Standard account, for example `connectedAccount` of the Satellite Connect connection
export async function send(account: UiWalletAccount, instruction: Instruction) {
const client = createSolanaClientWithCache({ rpcUrlOrMoniker: 'devnet', rpcUrls });
const signer = createSolanaTransactionSendingSigner(account, 'devnet');
await pulsarStore.getState().executeTxAction({
actionFunction: () => signAndSendSolanaTx({ client, signer, instruction }),
params: {
adapter: OrbitAdapter.SOLANA,
desiredChainID: 'devnet', // the cluster of the connected wallet; saved as chainId 'solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1'
type: 'transfer',
title: 'Transfer',
},
});
}The step-by-step React setup, with Nova Connect and a Codama-generated program client, is in the React transaction tracking guide , and tracking without the store on Solana Trackers Standalone .
🌐 External Services
| Helper | Host | Purpose |
|---|---|---|
| Signature tracker | The URL of its cluster in rpcUrls, else the public endpoint of the cluster (api.<cluster>.solana.com) | getSignatureStatuses and getTransaction for the signature |
retryTxAction | The URL of its cluster in rpcUrls, else the public endpoint of the cluster | The RPC client passed to your actionFunction |
signAndSendSolanaTx | The client you pass | getLatestBlockhash; the signer sends the transaction |
The public api.*.solana.com endpoints are rate-limited; pass your own RPC URLs in production. Explorer links point to explorer.solana.com and are not requested by the package.
📚 API Reference
Every export, with signatures and types generated from the source, is documented at pulsar.docs.tuwa.io/packages/pulsar-solana .
📄 License
Licensed under the Apache-2.0 License. See the LICENSE file for details.