Skip to main content
Simulates an EVM transaction and returns a breakdown of expected asset changes, security validation results, and optionally an estimated gas fee — all before the transaction is sent to the network. Powered by Blockaid for security validation.

Installation

npm install @dynamic-labs-sdk/evm

Usage

import { simulateEvmTransaction } from '@dynamic-labs-sdk/evm';
import { isEvmWalletAccount } from '@dynamic-labs-sdk/evm';
import { getPrimaryWalletAccount } from '@dynamic-labs-sdk/client';
import { parseEther } from 'viem';

const walletAccount = getPrimaryWalletAccount();

if (walletAccount && isEvmWalletAccount(walletAccount)) {
  const result = await simulateEvmTransaction({
    walletAccount,
    transaction: {
      from: walletAccount.address,
      to: '0xRecipientAddress',
      networkId: '1',
      value: parseEther('0.1'),
    },
  });

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

Parameters

ParameterTypeDescription
walletAccountEvmWalletAccountThe wallet account initiating the transaction
transactionobjectThe transaction to simulate (see below)
transaction.fromstringThe sender address
transaction.tostringThe recipient or contract address
transaction.networkIdstringThe chain ID (e.g., '1' for Ethereum mainnet)
transaction.valuebigint (optional)Native token amount to send, in wei
transaction.datastring (optional)Encoded contract call data
includeFeesboolean (optional)Whether to include a gas fee estimate. Default: false
clientDynamicClient (optional)Only required when using multiple clients

Returns

Promise<EvmSimulationResult> — 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
feeDataEvmTransactionFeeData (optional)Present only when includeFees: true
feeData.humanReadableAmountstringFee in ETH, formatted for display
feeData.nativeAmountbigintFee in wei
feeData.usdAmountstring (optional)Fee in USD if price data is available
feeData.gasEstimatebigintEstimated gas units
priceDataPriceDataPrice information for the assets involved
counterpartiesstring[] (optional)Other addresses involved in the transaction

Examples

Simple ETH transfer

const result = await simulateEvmTransaction({
  walletAccount,
  transaction: {
    from: walletAccount.address,
    to: recipientAddress,
    networkId: '1',
    value: parseEther('0.5'),
  },
});

console.log('Sending:', result.outAssets);

Contract call (ERC-20 transfer)

import { encodeFunctionData } from 'viem';

const result = await simulateEvmTransaction({
  walletAccount,
  transaction: {
    from: walletAccount.address,
    to: tokenContractAddress,
    networkId: '1',
    data: encodeFunctionData({
      abi: erc20Abi,
      functionName: 'transfer',
      args: [recipientAddress, parseUnits('100', 18)],
    }),
  },
});

console.log('Tokens going out:', result.outAssets);
console.log('Tokens coming in:', result.inAssets);

With gas fee estimation

const result = await simulateEvmTransaction({
  walletAccount,
  transaction: {
    from: walletAccount.address,
    to: recipientAddress,
    networkId: '137', // Polygon
    value: parseEther('1'),
  },
  includeFees: true,
});

if (result.feeData) {
  console.log(`Estimated fee: ${result.feeData.humanReadableAmount} MATIC`);
  if (result.feeData.usdAmount) {
    console.log(`≈ $${result.feeData.usdAmount}`);
  }
}

Security validation

const result = await simulateEvmTransaction({
  walletAccount,
  transaction: {
    from: walletAccount.address,
    to: contractAddress,
    networkId: '1',
    data: callData,
  },
});

if (result.validation?.result === 'malicious') {
  console.warn('This transaction has been flagged as malicious. Blocking.');
  return;
}

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

Error handling

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

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