> ## Documentation Index
> Fetch the complete documentation index at: https://seilabs-docs-evm-cookbook.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Debugging for EVM

> Advanced debugging techniques for EVM transactions on Sei. Learn transaction template generation and analysis using seid and Foundry cast tools.

export const RunSnippet = props => {
  const {method = 'eth_blockNumber', params = [], network = 'testnet', endpoint, label, title, description, decode = 'auto'} = props || ({});
  const ENDPOINTS = {
    testnet: 'https://evm-rpc-testnet.sei-apis.com',
    mainnet: 'https://evm-rpc.sei-apis.com'
  };
  const rpcUrl = endpoint || ENDPOINTS[network] || ENDPOINTS.testnet;
  const networkLabel = network === 'mainnet' ? 'Sei Mainnet' : network === 'testnet' ? 'Sei Testnet' : network;
  const requestBody = {
    jsonrpc: '2.0',
    id: 1,
    method,
    params
  };
  const requestJson = JSON.stringify(requestBody, null, 2);
  const [phase, setPhase] = useState('idle');
  const [result, setResult] = useState(null);
  const [errorMsg, setErrorMsg] = useState(null);
  const [elapsed, setElapsed] = useState(null);
  const [copied, setCopied] = useState(false);
  const [btnHover, setBtnHover] = useState(false);
  const groupThousands = s => s.replace(/\B(?=(\d{3})+(?!\d))/g, ',');
  const hexToDecimal = value => {
    if (typeof value !== 'string' || !(/^0x[0-9a-fA-F]+$/).test(value)) return null;
    if (value.length > 66) return null;
    try {
      return groupThousands(BigInt(value).toString(10));
    } catch (e) {
      return null;
    }
  };
  const run = async () => {
    setPhase('loading');
    setErrorMsg(null);
    setResult(null);
    setElapsed(null);
    const startedAt = typeof performance !== 'undefined' ? performance.now() : null;
    try {
      const response = await fetch(rpcUrl, {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json'
        },
        body: JSON.stringify(requestBody)
      });
      const data = await response.json();
      if (startedAt != null && typeof performance !== 'undefined') {
        setElapsed(Math.round(performance.now() - startedAt));
      }
      if (data && data.error) {
        setErrorMsg(data.error.message || 'RPC returned an error');
        setPhase('error');
        return;
      }
      setResult(data ? data.result : undefined);
      setPhase('success');
    } catch (err) {
      setErrorMsg(err && err.message ? err.message : 'Request failed');
      setPhase('error');
    }
  };
  const resultString = result === undefined ? 'undefined' : JSON.stringify(result, null, 2);
  const decoded = decode !== 'off' && typeof result === 'string' ? hexToDecimal(result) : null;
  const copyResult = () => {
    const flashCopied = () => {
      setCopied(true);
      setTimeout(() => setCopied(false), 2000);
    };
    if (typeof navigator !== 'undefined' && navigator.clipboard && navigator.clipboard.writeText) {
      navigator.clipboard.writeText(resultString).then(flashCopied, () => {});
      return;
    }
    if (typeof document !== 'undefined') {
      try {
        const ta = document.createElement('textarea');
        ta.value = resultString;
        ta.style.position = 'fixed';
        ta.style.opacity = '0';
        document.body.appendChild(ta);
        ta.select();
        document.execCommand('copy');
        document.body.removeChild(ta);
        flashCopied();
      } catch (e) {}
    }
  };
  const HAIRLINE = 'rgba(128, 128, 128, 0.25)';
  const surfaceStyle = {
    backgroundColor: 'rgba(128, 128, 128, 0.08)'
  };
  const monoStyle = {
    fontFamily: 'var(--sei-font-mono)'
  };
  const codeStyle = {
    backgroundColor: 'rgba(128, 128, 128, 0.05)',
    fontFamily: 'var(--sei-font-mono)'
  };
  const buttonStyle = {
    backgroundColor: btnHover ? 'var(--sei-maroon-200)' : 'var(--sei-maroon-100)',
    color: '#ffffff',
    fontFamily: 'var(--sei-font-mono)',
    textTransform: 'uppercase',
    letterSpacing: '0.04em',
    fontSize: '10px',
    opacity: phase === 'loading' ? 0.7 : 1,
    cursor: phase === 'loading' ? 'default' : 'pointer'
  };
  return <div className="not-prose w-full rounded-lg border overflow-hidden my-4" style={{
    borderColor: HAIRLINE
  }}>
			<div className="flex items-center justify-between gap-3 px-4 py-2.5 border-b" style={{
    ...surfaceStyle,
    borderBottomColor: HAIRLINE
  }}>
				<div className="flex flex-col min-w-0">
					<span className="text-sm font-medium text-neutral-900 dark:text-white truncate" style={monoStyle}>
						{title || method}
					</span>
					<span className="text-xs text-neutral-600 dark:text-neutral-400">{networkLabel}</span>
				</div>
				<button type="button" onClick={run} disabled={phase === 'loading'} onMouseEnter={() => setBtnHover(true)} onMouseLeave={() => setBtnHover(false)} className="inline-flex items-center gap-1.5 px-3 py-1.5 shrink-0 transition-colors" style={buttonStyle}>
					{phase === 'loading' ? <svg className="animate-spin h-4 w-4" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
								<circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4" />
								<path className="opacity-75" fill="currentColor" d="M4 12a8 8 0 0 1 8-8v4a4 4 0 0 0-4 4H4z" />
							</svg> : <svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="currentColor">
								<path d="M8 5v14l11-7z" />
							</svg>}
					{phase === 'loading' ? 'Running…' : label || 'Run'}
				</button>
			</div>

			{description ? <div className="px-4 pt-3 text-sm text-neutral-600 dark:text-neutral-400">{description}</div> : null}

			<div className="px-4 pt-3 pb-1">
				<span className="text-xs uppercase tracking-wide text-neutral-600 dark:text-neutral-400">Request</span>
			</div>
			<pre className="m-0 px-4 py-3 text-sm overflow-x-auto text-neutral-700 dark:text-neutral-300" style={codeStyle}>
				{requestJson}
			</pre>

			{phase === 'success' ? <div className="border-t" style={{
    borderTopColor: HAIRLINE
  }}>
					<div className="flex items-center justify-between px-4 pt-3 pb-1">
						<span className="text-xs uppercase tracking-wide text-neutral-600 dark:text-neutral-400">Response{elapsed != null ? ` · ${elapsed} ms` : ''}</span>
						<button type="button" onClick={copyResult} className="text-xs text-neutral-500 hover:text-neutral-800 dark:text-neutral-400 dark:hover:text-neutral-200 transition-colors">
							{copied ? 'Copied' : 'Copy'}
						</button>
					</div>
					<pre className="m-0 px-4 py-3 text-sm overflow-x-auto text-neutral-700 dark:text-neutral-300" style={codeStyle}>
						{resultString}
					</pre>
					{decoded ? <div className="px-4 pb-3 text-xs text-neutral-600 dark:text-neutral-400" style={monoStyle}>
							= {decoded} (decimal)
						</div> : null}
				</div> : null}

			{phase === 'error' ? <div className="border-t" style={{
    borderTopColor: HAIRLINE
  }}>
					<div className="px-4 pt-3 pb-1">
						<span className="text-xs uppercase tracking-wide text-neutral-600 dark:text-neutral-400">Error</span>
					</div>
					<pre className="m-0 px-4 py-3 text-sm overflow-x-auto text-red-600 dark:text-red-400" style={codeStyle}>
						{errorMsg}
					</pre>
				</div> : null}
		</div>;
};

## Overview

To debug EVM transactions on Sei, you need to understand both how transactions are created and how to analyze their behavior. This guide covers advanced debugging techniques: transaction template generation, analysis tools, and transaction inspection methods. Use them to find and fix issues in your EVM interactions.

## Transaction template generation

The `--generate-only` flag turns any `seid` transaction command into a template generator. The command creates a complete transaction structure but does not broadcast it. With the `--generate-only` flag and Foundry's `cast` tool, you can build, analyze, and debug transactions in the EVM environment.

### Basic command pattern

The general command pattern is:

```bash theme={null}
seid tx <module> <action> <parameters> --from <key> --evm-rpc http://url-to-sei-evm-rpc --generate-only
```

### Generating EVM transaction templates

To generate an EVM transaction template, use the `evm` module with `--generate-only`. This example sends SEI to another EVM address:

```bash theme={null}
seid tx evm send 0xRecipientAddress 1000000000000000000 \
--gas-fee-cap=100000000000 \
--gas-limit=21000 \
--evm-rpc=http://url-to-sei-evm-rpc \
--from=mykey \
--generate-only
```

<Info>This command returns a transaction template that you can analyze before you broadcast it. The template includes all transaction details, but the command does not execute the transaction.</Info>

***

## Analyzing EVM transactions with Cast

When you have a transaction hash, you can use Foundry's `cast` command to inspect the transaction details:

```bash theme={null}
cast tx 0x5010e6600e67f04a9bc3d3b670a7c2de380b180713d9a014a5dbd76b7e2190f1 \
--rpc-url=http://url-to-sei-evm-rpc
```

**Example output:**

```text theme={null}
blockHash               0x4696d63a9a9ae88b03bcc94ccbd87f407e994b309d1dff9c0626de51ac57b76e
blockNumber             130076639
from                    0xAa55a16dD4E73c48C968928983c2bcC98d913d96
transactionIndex        7
effectiveGasPrice       100000000000
accessList              []
chainId                 1329
gasLimit                2500000
hash                    0x5010e6600e67f04a9bc3d3b670a7c2de380b180713d9a014a5dbd76b7e2190f1
input                   0xc31d960f0000...
maxFeePerGas            100000000000
maxPriorityFeePerGas    100000000000
nonce                   3
to                      0x000000000000000000000000000000000000100b
type                    2
value                   0
```

### Additional analysis commands

**Get the transaction receipt:**

```bash theme={null}
cast receipt 0x5010e6600e67f04a9bc3d3b670a7c2de380b180713d9a014a5dbd76b7e2190f1 \
--rpc-url=http://url-to-sei-evm-rpc
```

**Decode the transaction input data:**

```bash theme={null}
cast 4byte-decode 0xc31d960f0000...
```

<Info>All template generation commands create JSON files. You can inspect, modify, and use these files for debugging before you execute the transactions.</Info>

***

## RPC consistency

<Warning>Always point `cast` commands to an EVM RPC endpoint (for example, `$EVM_RPC_URL`), not a Cosmos RPC URL.</Warning>

***

## Tracing and revert reasons

If your endpoint supports debug RPC methods, you can get full execution traces and revert reasons:

```bash theme={null}
# Full transaction trace
cast rpc debug_traceTransaction 0xTX_HASH '{"tracer":"callTracer","timeout":"120s"}' \
  --rpc-url=$EVM_RPC_URL

# Simulate and trace a call without broadcasting
cast rpc debug_traceCall '{"from":"0xFROM","to":"0xTO","data":"0xDATA"}' \
  'latest' '{"tracer":"callTracer","timeout":"120s"}' \
  --rpc-url=$EVM_RPC_URL
```

<Info>
  Many public RPC endpoints disable debug methods. If they are disabled, run a local fork and trace there. See the <a href="/evm/tracing">tracing documentation</a>.
</Info>

***

## Reproduce with a local fork

Fork the network locally to reproduce issues deterministically. You can then run traces even if the remote debug RPC is disabled:

```bash theme={null}
# Start a local fork
anvil --fork-url $EVM_RPC_URL

# Re-run calls against the fork
cast call 0xContract "method(uint256)" 1 --rpc-url=http://127.0.0.1:8545

# Trace the call on the fork via debug RPC
cast rpc debug_traceCall '{"to":"0xContract","data":"0xENCODED_DATA"}' \
  'latest' '{"tracer":"callTracer"}' --rpc-url=http://127.0.0.1:8545
```

***

## Event logs and decoding

Use the receipt to inspect the logs, and decode them with the contract ABI:

```bash theme={null}
# Fetch receipt JSON and view logs
cast receipt 0xTX_HASH --rpc-url=$EVM_RPC_URL --json | jq '.logs'

# Compute an event signature for topic[0]
cast keccak "Transfer(address,address,uint256)"
```

<Info>Decode event topics and data with the contract ABI (from your repository or a block explorer). Topic\[0] equals the keccak hash of the event signature.</Info>

***

## Nonce, balance, and gas diagnostics

Check common failure points quickly:

```bash theme={null}
cast nonce 0xYourAddress --rpc-url=$EVM_RPC_URL
cast balance 0xYourAddress --rpc-url=$EVM_RPC_URL
cast gas-price --rpc-url=$EVM_RPC_URL
cast block latest baseFeePerGas --rpc-url=$EVM_RPC_URL
cast chain-id --rpc-url=$EVM_RPC_URL
```

**Checklist:**

* Incorrect nonce (a pending transaction in the mempool)
* Insufficient native balance for gas
* Underpriced `maxFeePerGas` or `maxPriorityFeePerGas`
* Chain ID mismatch

## Try it live

Each `cast` diagnostic above is a plain read-only JSON-RPC call. Run four of them against Sei Mainnet here. The example address (`0xAa55…3d96`) is the sender from the `cast tx` output earlier on this page.

<RunSnippet method="eth_chainId" network="mainnet" title="cast chain-id" description="eth_chainId. The result decodes to 1329. A mismatch here is the most common cause of a rejected transaction." />

<RunSnippet method="eth_gasPrice" network="mainnet" title="cast gas-price" description="eth_gasPrice returns the current gas price in wei. If a transaction is stuck as underpriced, compare this value with your maxFeePerGas." />

<RunSnippet method="eth_getTransactionCount" params={['0xAa55a16dD4E73c48C968928983c2bcC98d913d96', 'latest']} network="mainnet" title="cast nonce 0xAa55…3d96" description="eth_getTransactionCount at the latest block returns the account's next nonce. Use your own address instead." />

<RunSnippet method="eth_getBalance" params={['0xAa55a16dD4E73c48C968928983c2bcC98d913d96', 'latest']} network="mainnet" title="cast balance 0xAa55…3d96" description="eth_getBalance returns the balance in wei. Before you investigate a failed send, confirm that the account can cover gas." />

***

## Offline workflow with --generate-only

Generate, inspect, sign, and broadcast a transaction safely:

```bash theme={null}
# 1) Generate a template (no broadcast)
seid tx evm send 0xTO 1000000000000000000 \
  --from=$WALLET_NAME --evm-rpc=$EVM_RPC_URL --generate-only > tx.json

# 2) Sign offline with your key
seid tx sign tx.json --from $WALLET_NAME --chain-id $CHAIN_ID > signed.json

# 3) Broadcast the signed tx
seid tx broadcast signed.json
```

<Warning>Never commit signed transactions or private keys. Use environment variables and `.gitignore` for sensitive data.</Warning>

***

## Precompile awareness

Calls to system precompiles (for example, addresses such as `0x...100b`) may have specific input and output formats and error behavior.

* See [EVM precompiles](/evm/precompiles/example-usage) and [CosmWasm precompiles](/evm/precompiles/cosmwasm-precompiles/example-usage)
* Cross-check expected selectors, parameter encoding, and revert messages

***

## Storage inspection

When you debug state changes, check the on-chain state directly:

```bash theme={null}
cast storage 0xContract 0xSLOT --rpc-url=$EVM_RPC_URL
```

***

## Transaction analysis

When you analyze transactions, follow these practices:

* Always verify EVM transactions thoroughly
* Use `cast` to decode the input data of EVM transactions
* Keep track of gas parameters
* Monitor the transaction status on the EVM layer

**Analysis tips:**

```bash theme={null}
# Use Foundry's cast tool for detailed transaction inspection
cast tx 0x5010e6600e67f04a9bc3d3b670a7c2de380b180713d9a014a5dbd76b7e2190f1 \
--rpc-url=$EVM_RPC_URL

# Get transaction receipt to verify success
cast receipt 0x5010e6600e67f04a9bc3d3b670a7c2de380b180713d9a014a5dbd76b7e2190f1 \
--rpc-url=$EVM_RPC_URL

# Decode transaction input data
cast 4byte-decode 0xa9059cbb000000...
```

<Info>
  <strong>Transaction analysis checklist:</strong> Always verify that a transaction succeeded before you continue. Check gas usage to optimize future transactions. Use Foundry's `cast` tool for detailed transaction inspection.
</Info>

***

## Error handling

Monitor EVM transactions so that you can handle potential issues:

```javascript theme={null}
try {
  // Check EVM transaction status
  const evmStatus = await checkEvmStatus(txHash);
  if (!evmStatus.success) {
    const evmError = await cast.call(['tx', txHash, '--rpc-url', evmRpcUrl]);
    console.error('EVM transaction failed:', evmError);
  }
} catch (error) {
  console.error('Transaction analysis failed:', error);
}
```

**Best practices for error handling:**

* Always check the transaction status on both the Cosmos and EVM layers
* Use detailed error logging to debug failed transactions
* Implement retry logic for network-related failures
* Monitor gas usage and adjust limits accordingly

***

## Security guidelines

<Warning>
  <strong>Critical security requirements:</strong> Keep private keys secure, and never include them in templates. When you work with wallet keys or mnemonics, use an `.env` file or other environment variables. Never commit sensitive information to version control. Always verify transaction details before you sign.
</Warning>

**Environment variable setup:**

```bash theme={null}
# Create .env file for sensitive data
WALLET_NAME=mykey
EVM_RPC_URL=http://url-to-sei-evm-rpc
PRIVATE_KEY=your_private_key_here

# Add .env to .gitignore
echo ".env" >> .gitignore
```

**Secure transaction execution:**

```bash theme={null}
# Use environment variables in commands
seid tx evm send 0x1234567890abcdef... 1000000000000000000 \
--from=$WALLET_NAME \
--evm-rpc=$EVM_RPC_URL

# Generate transaction template first to verify details
seid tx evm send 0x1234567890abcdef... 1000000000000000000 \
--from=$WALLET_NAME \
--evm-rpc=$EVM_RPC_URL \
--generate-only
```


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.