Skip to main content
Simulates a Solana transaction and returns a breakdown of expected asset changes, security validation results, and optionally an estimated SOL fee — all before the transaction is sent to the network. Supports both legacy Transaction and VersionedTransaction objects. Powered by Blockaid for security validation.

Installation

npm install @dynamic-labs-sdk/solana

Usage

import { simulateSolanaTransaction } from '@dynamic-labs-sdk/solana';
import { isSolanaWalletAccount } from '@dynamic-labs-sdk/solana';
import { getPrimaryWalletAccount } from '@dynamic-labs-sdk/client';
import {
  Transaction,
  SystemProgram,
  PublicKey,
} from '@solana/web3.js';

const walletAccount = getPrimaryWalletAccount();

if (walletAccount && isSolanaWalletAccount(walletAccount)) {
  const transaction = new Transaction().add(
    SystemProgram.transfer({
      fromPubkey: new PublicKey(walletAccount.address),
      toPubkey: new PublicKey(recipientAddress),
      lamports: 1_000_000_000, // 1 SOL
    })
  );

  const result = await simulateSolanaTransaction({
    walletAccount,
    transaction,
  });

  console.log('Assets going out:', result.outAssets);
  console.log('Security check:', result.validation?.result);
}

Parameters

ParameterTypeDescription
walletAccountSolanaWalletAccountThe wallet account initiating the transaction
transactionTransaction | VersionedTransactionThe Solana transaction to simulate
includeFeesboolean (optional)Whether to include a SOL fee estimate. Default: false
clientDynamicClient (optional)Only required when using multiple clients

Returns

Promise<SolanaSimulationResult> — an object with the following fields:
FieldTypeDescription
inAssetsAssetDiff[]Assets the wallet will receive
outAssetsAssetDiff[]Assets the wallet will send
validationBlockaidValidation (optional)Security assessment from Blockaid
validation.result'benign' | 'warning' | 'malicious'Overall security verdict
validation.descriptionstring (optional)Human-readable description
validation.reasonstring (optional)Reason for the verdict
feeDataSolanaTransactionFeeData (optional)Present only when includeFees: true
feeData.humanReadableAmountstringFee in SOL, formatted for display
feeData.nativeAmountbigintFee in lamports (0n for sponsored transactions)
feeData.usdAmountstring (optional)Fee in USD if price data is available
priceDataPriceDataPrice information for the assets involved
counterpartiesstring[] (optional)Other addresses involved in the transaction
When the transaction’s fee payer is different from the wallet address, feeData.nativeAmount is 0n — indicating the transaction fee is sponsored.

Examples

SOL transfer

const transaction = new Transaction().add(
  SystemProgram.transfer({
    fromPubkey: new PublicKey(walletAccount.address),
    toPubkey: new PublicKey(recipientAddress),
    lamports: 500_000_000, // 0.5 SOL
  })
);

const result = await simulateSolanaTransaction({
  walletAccount,
  transaction,
});

console.log('Assets out:', result.outAssets);

With fee estimation

const result = await simulateSolanaTransaction({
  walletAccount,
  transaction,
  includeFees: true,
});

if (result.feeData) {
  if (result.feeData.nativeAmount === 0n) {
    console.log('Transaction fee is sponsored');
  } else {
    console.log(`Estimated fee: ${result.feeData.humanReadableAmount} SOL`);
  }
}

Versioned transaction

import {
  VersionedTransaction,
  TransactionMessage,
  PublicKey,
} from '@solana/web3.js';

const messageV0 = new TransactionMessage({
  payerKey: new PublicKey(walletAccount.address),
  recentBlockhash: latestBlockhash,
  instructions: [instruction],
}).compileToV0Message();

const versionedTx = new VersionedTransaction(messageV0);

const result = await simulateSolanaTransaction({
  walletAccount,
  transaction: versionedTx,
});

Security validation

const result = await simulateSolanaTransaction({ walletAccount, transaction });

if (result.validation?.result === 'malicious') {
  console.warn('Transaction flagged as malicious. Blocking.');
  return;
}

if (result.validation?.result === 'warning') {
  console.warn('Warning:', result.validation.description);
}

Error handling

import { SimulationFailedError } from '@dynamic-labs-sdk/client';

try {
  const result = await simulateSolanaTransaction({ walletAccount, transaction });
} catch (error) {
  if (error instanceof SimulationFailedError) {
    console.error('Simulation failed:', error.message);
  }
}