Overview
Transactions are the primary way to interact with the Solana blockchain. Hermis provides comprehensive tools for creating, signing, and sending transactions with proper error handling and confirmation tracking.
Transaction Lifecycle
Create → Sign → Send → Confirm → Finalize
Create
Build a transaction with instructions
Sign
Sign with wallet’s private key
Send
Broadcast to Solana network
Confirm
Wait for block confirmation
Finalize
Transaction is finalized on chain
Creating Transactions
Basic Transfer
React + web3.js
React + Kit
Vanilla TS + web3.js
Vanilla TS + Kit
import { Transaction , SystemProgram , LAMPORTS_PER_SOL , PublicKey } from '@solana/web3.js' ;
import { useWallet , useConnection } from '@hermis/solana-headless-react' ;
function SendSOL () {
const { publicKey , signAndSendTransaction } = useWallet ();
const { connection } = useConnection ();
const send = async ( recipient : string , amount : number ) => {
const transaction = new Transaction ();
transaction . add (
SystemProgram . transfer ({
fromPubkey: publicKey ! ,
toPubkey: new PublicKey ( recipient ),
lamports: amount * LAMPORTS_PER_SOL
})
);
// Set recent blockhash
const { blockhash } = await connection . getLatestBlockhash ();
transaction . recentBlockhash = blockhash ;
transaction . feePayer = publicKey ! ;
// Sign and send
const signature = await signAndSendTransaction ( transaction , connection );
return signature ;
};
return < button onClick ={() => send ( 'recipient...' , 0.1 )}> Send 0.1 SOL </ button > ;
}
Signing Transactions
Sign Only
React + web3.js
React + Kit
Vanilla TS + web3.js
Vanilla TS + Kit
import { useWallet , useConnection } from '@hermis/solana-headless-react' ;
const { signTransaction } = useWallet ();
const { connection } = useConnection ();
// Sign without sending
const signedTx = await signTransaction ( transaction );
// Can be sent later or by another service
const signature = await connection . sendRawTransaction ( signedTx . serialize ());
Sign Multiple
React + web3.js
React + Kit
Vanilla TS + web3.js
Vanilla TS + Kit
import { useWallet , useConnection } from '@hermis/solana-headless-react' ;
const { signAllTransactions } = useWallet ();
const { connection } = useConnection ();
const transactions = [ tx1 , tx2 , tx3 ];
const signedTxs = await signAllTransactions ( transactions );
// Send all transactions
for ( const tx of signedTxs ) {
await connection . sendRawTransaction ( tx . serialize ());
}
Sending Transactions
With Confirmation
React + web3.js
React + Kit
Vanilla TS + web3.js
Vanilla TS + Kit
import { useWallet , useConnection } from '@hermis/solana-headless-react' ;
const { signAndSendTransaction } = useWallet ();
const { connection } = useConnection ();
const signature = await signAndSendTransaction ( transaction , connection );
// Wait for confirmation
await connection . confirmTransaction ( signature , 'confirmed' );
console . log ( 'Transaction confirmed:' , signature );
With Options
React + web3.js
React + Kit
Vanilla TS + web3.js
Vanilla TS + Kit
import { useWallet , useConnection } from '@hermis/solana-headless-react' ;
const { signAndSendTransaction } = useWallet ();
const { connection } = useConnection ();
const signature = await signAndSendTransaction (
transaction ,
connection ,
{
skipPreflight: false ,
preflightCommitment: 'confirmed' ,
maxRetries: 3 ,
}
);
Transaction Confirmation
Commitment Levels
Processed Fastest - Transaction processed but not confirmed
Confirmed Recommended - Confirmed by supermajority
Finalized Safest - Finalized by the network
Tracking Status
This hook works universally with transaction signatures from both web3.js and Kit architectures.
import { useSolanaTransaction } from '@hermis/solana-headless-react' ;
function TransactionStatus ({ signature } : { signature : string }) {
const { status , loading } = useSolanaTransaction ( signature );
if ( loading ) return < div > Checking status ...</ div > ;
return (
< div >
< p > Status : { status ?. status }</ p >
< p > Confirmations : { status ?. confirmations }</ p >
{ status ?. error && < p > Error : { status . error }</ p >}
</ div >
);
}
SPL Token Transactions
Transfer Tokens
React + web3.js
React + Kit
Vanilla TS + web3.js
Vanilla TS + Kit
import { useWallet , useConnection } from '@hermis/solana-headless-react' ;
import {
getAssociatedTokenAddress ,
createTransferInstruction ,
createAssociatedTokenAccountInstruction
} from '@solana/spl-token' ;
import { PublicKey , Transaction } from '@solana/web3.js' ;
const { publicKey , signAndSendTransaction } = useWallet ();
const { connection } = useConnection ();
const transferTokens = async (
mintAddress : PublicKey ,
recipient : PublicKey ,
amount : number
) => {
// Get token accounts (ATAs)
const fromTokenAccount = await getAssociatedTokenAddress (
mintAddress ,
publicKey !
);
const toTokenAccount = await getAssociatedTokenAddress (
mintAddress ,
recipient
);
// Check if recipient's ATA exists
const toAccountInfo = await connection . getAccountInfo ( toTokenAccount );
// Create transaction
const transaction = new Transaction ();
// Create recipient's ATA if it doesn't exist
if ( ! toAccountInfo ) {
transaction . add (
createAssociatedTokenAccountInstruction (
publicKey ! , // payer
toTokenAccount , // ata
recipient , // owner
mintAddress // mint
)
);
}
// Add transfer instruction
transaction . add (
createTransferInstruction (
fromTokenAccount ,
toTokenAccount ,
publicKey ! ,
amount
)
);
const { blockhash } = await connection . getLatestBlockhash ();
transaction . recentBlockhash = blockhash ;
transaction . feePayer = publicKey ! ;
return await signAndSendTransaction ( transaction , connection );
};
Error Handling
Hermis uses HermisError for type-safe transaction error handling:
import {
isHermisError ,
HERMIS_ERROR__TRANSACTION__SEND_FAILED ,
HERMIS_ERROR__NETWORK__INSUFFICIENT_BALANCE
} from '@hermis/errors' ;
try {
await signAndSendTransaction ( transaction , connection );
} catch ( error ) {
if ( isHermisError ( error , HERMIS_ERROR__NETWORK__INSUFFICIENT_BALANCE )) {
console . error ( `Insufficient balance: required ${ error . context . required } , available ${ error . context . available } ` );
} else if ( isHermisError ( error , HERMIS_ERROR__TRANSACTION__SEND_FAILED )) {
console . error ( `Transaction failed: ${ error . message } ` );
} else if ( isHermisError ( error )) {
console . error ( `Error [ ${ error . code } ]: ${ error . message } ` );
}
}
Common Error Patterns
Handle insufficient funds with typed context: import { isHermisError , HERMIS_ERROR__NETWORK__INSUFFICIENT_BALANCE } from '@hermis/errors' ;
if ( isHermisError ( error , HERMIS_ERROR__NETWORK__INSUFFICIENT_BALANCE )) {
// Access typed context: address, required, available
const needed = error . context . required - error . context . available ;
showToast ( `Need ${ needed } more lamports` );
}
Handle transaction send failures: import { isHermisError , HERMIS_ERROR__TRANSACTION__SEND_FAILED } from '@hermis/errors' ;
if ( isHermisError ( error , HERMIS_ERROR__TRANSACTION__SEND_FAILED )) {
// HermisError provides formatted message
showToast ( error . message );
// Optionally retry or get fresh blockhash
const { blockhash } = await connection . getLatestBlockhash ( 'finalized' );
transaction . recentBlockhash = blockhash ;
}
Handle transaction signing failures: import { isHermisError , HERMIS_ERROR__TRANSACTION__SIGNATURE_FAILED } from '@hermis/errors' ;
if ( isHermisError ( error , HERMIS_ERROR__TRANSACTION__SIGNATURE_FAILED )) {
showToast ( 'Failed to sign transaction' );
}
Handle any HermisError with automatic formatting: import { isHermisError } from '@hermis/errors' ;
if ( isHermisError ( error )) {
// All HermisErrors provide formatted messages
console . error ( `[ ${ error . code } ] ${ error . message } ` );
showToast ( error . message );
}
Retry Logic
React + web3.js
React + Kit
Vanilla TS + web3.js
Vanilla TS + Kit
import { useWallet , useConnection } from '@hermis/solana-headless-react' ;
import { Transaction } from '@solana/web3.js' ;
const { signAndSendTransaction } = useWallet ();
const { connection } = useConnection ();
const sendWithRetry = async (
transaction : Transaction ,
maxRetries = 3
) => {
for ( let i = 0 ; i < maxRetries ; i ++ ) {
try {
// Refresh blockhash on retry
if ( i > 0 ) {
const { blockhash } = await connection . getLatestBlockhash ();
transaction . recentBlockhash = blockhash ;
}
const signature = await signAndSendTransaction ( transaction , connection );
await connection . confirmTransaction ( signature );
return signature ;
} catch ( error ) {
if ( i === maxRetries - 1 ) throw error ;
await new Promise ( resolve => setTimeout ( resolve , 1000 * ( i + 1 )));
}
}
};
Transaction Fees
Estimating Fees
React + web3.js
React + Kit
Vanilla TS + web3.js
Vanilla TS + Kit
import { useWallet , useConnection } from '@hermis/solana-headless-react' ;
import { Transaction , LAMPORTS_PER_SOL } from '@solana/web3.js' ;
const { publicKey } = useWallet ();
const { connection } = useConnection ();
const estimateFee = async ( transaction : Transaction ) => {
const { blockhash } = await connection . getLatestBlockhash ();
transaction . recentBlockhash = blockhash ;
transaction . feePayer = publicKey ! ;
const fee = await connection . getFeeForMessage (
transaction . compileMessage ()
);
return fee . value / LAMPORTS_PER_SOL ; // Convert to SOL
};
Priority Fees
React + web3.js
React + Kit
Vanilla TS + web3.js
Vanilla TS + Kit
import { useWallet , useConnection } from '@hermis/solana-headless-react' ;
import { Transaction , ComputeBudgetProgram } from '@solana/web3.js' ;
const { publicKey , signAndSendTransaction } = useWallet ();
const { connection } = useConnection ();
// Add priority fee to transaction
transaction . add (
ComputeBudgetProgram . setComputeUnitPrice ({
microLamports: 1000 , // Priority fee
})
);
const signature = await signAndSendTransaction ( transaction , connection );
Best Practices
Always set recent blockhash
Check account balances first
Use appropriate commitment levels
What’s Next?