Documentation Index
Fetch the complete documentation index at: https://docs.dynamic.xyz/docs/llms.txt
Use this file to discover all available pages before exploring further.
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);
}
Call simulateEvmTransaction inside a button handler to preview the transaction before the user confirms it:import { simulateEvmTransaction, isEvmWalletAccount } from '@dynamic-labs-sdk/evm';
import { useWalletAccounts } from '@dynamic-labs-sdk/react-hooks';
import { useState } from 'react';
import { parseEther } from 'viem';
function SimulateButton({ recipientAddress }) {
const walletAccounts = useWalletAccounts();
const walletAccount = walletAccounts[0];
const [result, setResult] = useState(null);
const handleSimulate = async () => {
if (!walletAccount || !isEvmWalletAccount(walletAccount)) return;
const simulation = await simulateEvmTransaction({
walletAccount,
transaction: {
from: walletAccount.address,
to: recipientAddress,
networkId: '1',
value: parseEther('0.1'),
},
});
setResult(simulation);
};
return (
<div>
<button onClick={handleSimulate}>Preview Transaction</button>
{result && (
<div>
<p>Security: {result.validation?.result}</p>
<p>Assets out: {result.outAssets.length}</p>
</div>
)}
</div>
);
}
Parameters
| Parameter | Type | Description |
|---|
walletAccount | EvmWalletAccount | The wallet account initiating the transaction |
transaction | object | The transaction to simulate (see below) |
transaction.from | string | The sender address |
transaction.to | string | The recipient or contract address |
transaction.networkId | string | The chain ID (e.g., '1' for Ethereum mainnet) |
transaction.value | bigint (optional) | Native token amount to send, in wei |
transaction.data | string (optional) | Encoded contract call data |
includeFees | boolean (optional) | Whether to include a gas fee estimate. Default: false |
client | DynamicClient (optional) | Only required when using multiple clients |
Returns
Promise<EvmSimulationResult> — an object with the following fields:
| Field | Type | Description |
|---|
inAssets | AssetDiff[] | Assets the wallet will receive |
outAssets | AssetDiff[] | Assets the wallet will send |
validation | BlockaidValidation (optional) | Security assessment from Blockaid |
validation.result | 'benign' | 'warning' | 'malicious' | Overall security verdict |
validation.description | string (optional) | Human-readable description |
validation.reason | string (optional) | Reason for the verdict |
feeData | EvmTransactionFeeData (optional) | Present only when includeFees: true |
feeData.humanReadableAmount | string | Fee in ETH, formatted for display |
feeData.nativeAmount | bigint | Fee in wei |
feeData.usdAmount | string (optional) | Fee in USD if price data is available |
feeData.gasEstimate | bigint | Estimated gas units |
priceData | PriceData | Price information for the assets involved |
counterparties | string[] (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);
}
}