Transaction Confirmation
How to reliably confirm Solana transactions using lastValidBlockHeight.
Confirming Transactions
Every transaction-building endpoint returns lastValidBlockHeight alongside the transaction. Use it to detect transaction expiry without indefinite polling.
import { Connection, VersionedTransaction } from '@solana/web3.js'
import bs58 from 'bs58'
const connection = new Connection('https://api.mainnet-beta.solana.com', 'confirmed')
const { transaction, lastValidBlockHeight } = await buildTx(...)
const tx = VersionedTransaction.deserialize(bs58.decode(transaction))
const signed = await wallet.signTransaction(tx)
const sig = await connection.sendRawTransaction(signed.serialize(), {
skipPreflight: false,
preflightCommitment: 'confirmed',
})
// Wait with expiry detection
const result = await connection.confirmTransaction(
{ signature: sig, lastValidBlockHeight, blockhash: tx.message.recentBlockhash },
'confirmed',
)
if (result.value.err) {
throw new Error(`Transaction failed: ${JSON.stringify(result.value.err)}`)
}
console.log('Confirmed:', sig)Handling Expiry
A Solana transaction expires after ~90 seconds if not included in a block. If confirmTransaction returns with TransactionExpiredBlockheightExceededError, the transaction was never executed and it is safe to retry.
import { TransactionExpiredBlockheightExceededError } from '@solana/web3.js'
try {
await connection.confirmTransaction({ signature, lastValidBlockHeight, blockhash }, 'confirmed')
} catch (err) {
if (err instanceof TransactionExpiredBlockheightExceededError) {
// Safe to retry — transaction was never executed
console.warn('Transaction expired, rebuilding...')
// Call the API again to get a fresh transaction
} else {
throw err
}
}Retry Strategy
- Build transaction via API → get
transaction+lastValidBlockHeight - Sign and submit
- Confirm with expiry detection
- If expired: rebuild from API (new blockhash), sign, submit
- If confirmed but on-chain error: inspect error, fix parameters, do not retry blindly
Do not resubmit the same signed transaction after expiry — always rebuild via the API to get a fresh blockhash.
Updated 4 days ago