> ## Documentation Index
> Fetch the complete documentation index at: https://docs.sei.io/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' ? 'pacific-1 · mainnet' : network === 'testnet' ? 'atlantic-2 · 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 cardClass = 'not-prose w-full rounded-lg border overflow-hidden my-4';
  const headerClass = 'flex items-center justify-between gap-3 px-4 py-2.5 border-b';
  const labelClass = 'text-xs uppercase tracking-wide text-neutral-500 dark:text-neutral-500';
  const preClass = 'm-0 px-4 py-3 text-sm overflow-x-auto text-neutral-700 dark:text-neutral-300';
  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={cardClass} style={{
    borderColor: HAIRLINE
  }}>
			<div className={headerClass} 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-500 dark:text-neutral-500">{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={labelClass}>Request</span>
			</div>
			<pre className={preClass} 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={labelClass}>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={preClass} style={codeStyle}>
						{resultString}
					</pre>
					{decoded ? <div className="px-4 pb-3 text-xs text-neutral-500 dark:text-neutral-500" 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={labelClass}>Error</span>
					</div>
					<pre className={`${preClass} text-red-600 dark:text-red-400`} style={codeStyle}>
						{errorMsg}
					</pre>
				</div> : null}
		</div>;
};

## Overview

Debugging EVM transactions on Sei requires understanding both the transaction creation process and how to analyze transaction behavior. This guide covers advanced debugging techniques using transaction template generation, analysis tools, and comprehensive transaction inspection methods to help developers identify and resolve issues in their EVM interactions.

## Transaction Template Generation

The `--generate-only` flag transforms any Sei CLI transaction command into a template generator, creating complete transaction structures without broadcasting them. Through the `--generate-only` flag and Foundry's `cast` tool, developers can craft, analyze, and debug transactions across the EVM environment.

### Basic Command Pattern

The general pattern follows this structure:

```bash theme={"dark"}
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`. Here's an example sending SEI to another EVM address:

```bash theme={"dark"}
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 broadcasting. The template includes all transaction details without executing the actual transaction.</Info>

***

## Analyzing EVM Transactions with Cast

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

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

**Example Output:**

```text theme={"dark"}
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 transaction receipt:**

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

**Decode transaction input data:**

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

<Info>All template generation commands create JSON files that you can inspect, modify, and use for debugging before executing the actual 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 retrieve full execution traces and revert reasons:

```bash theme={"dark"}
# 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 disabled, run a local fork and trace there. See Tracing docs at <a href="/evm/tracing">/evm/tracing</a>.
</Info>

***

## Reproduce with a Local Fork

Fork the network locally to reproduce issues deterministically and run traces even if remote debug RPC is disabled:

```bash theme={"dark"}
# 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 logs and decode with the contract ABI:

```bash theme={"dark"}
# 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/data using the contract ABI (from your repo or block explorer). Topic\[0] equals the keccak of the event signature.</Info>

***

## Nonce, Balance, and Gas Diagnostics

Check common failure points quickly:

```bash theme={"dark"}
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 (pending tx in mempool)
* Insufficient native balance for gas
* Underpriced `maxFeePerGas`/`maxPriorityFeePerGas`
* Chain ID mismatch

## Try it live

Each `cast` diagnostic above is a plain read-only JSON-RPC call. Run the same four against Sei mainnet right 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 — 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 — the current gas price in wei. Compare it against your maxFeePerGas when a transaction is stuck as underpriced." />

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

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

***

## Offline Workflow with --generate-only

Generate, inspect, sign, and broadcast safely:

```bash theme={"dark"}
# 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 like `0x...100b`) may have specific input/output formats and error behavior.

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

***

## Storage Inspection

Verify on-chain state directly when debugging state changes:

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

***

## Transaction Analysis

When analyzing transactions, follow these essential practices:

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

**Analysis Tips:**

```bash theme={"dark"}
# 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 transaction success before proceeding. Check gas usage to optimize future transactions. Use Foundry's cast tool for detailed transaction inspection.
</Info>

***

## Error Handling

Handle potential EVM transaction issues with proper monitoring:

```javascript theme={"dark"}
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 transaction status on both Cosmos and EVM layers
* Use detailed error logging for debugging 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. Use an `.env` file or other environment variables when working with wallet keys or mnemonics. Never commit sensitive information to version control. Always verify transaction details before signing.
</Warning>

**Environment Variable Setup:**

```bash theme={"dark"}
# 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={"dark"}
# 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
```
