Debug Playbook
1. Revert Decoding
Debugging smart contracts on the Somnia Network requires an understanding of how and why transactions fail. Every reverted transaction carries encoded data that can reveal the root cause of failure, whether it’s due to logic errors, insufficient gas, failed access checks, or internal Solidity panics.
1.1 Anatomy of a Revert
When a transaction fails on Somnia, the EVM halts execution and returns revert data, an ABI-encoded payload that follows one of these three formats:
Error(string)
0x08c379a0
Standard revert reason with message
require(balance > 0, "Zero balance");
Panic(uint256)
0x4e487b71
Internal error (e.g., overflow, div/0, invalid enum)
assert(x > 0);
Custom Errors
Function selector of custom error
error Unauthorized(address caller);
On Somnia, these behave identically to Ethereum but may differ in gas costs and stack trace length depending on the validator node configuration.
1.2 Catching and Displaying Reverts in Hardhat
When running tests or scripts on Somnia, wrap calls in try/catch to capture the revert reason.
try {
await treasury.withdraw(1000);
} catch (error: any) {
console.log('Revert reason:', error.reason || error.message);
console.log('Full error data:', error.data || error.error?.data);
}In Chai matchers:
If your contract uses custom errors, Hardhat will not automatically print the name. Decode it manually:
1.3 Decoding Panic Codes
Internal Solidity panics correspond to low-level EVM exceptions. Somnia propagates these codes like any other EVM chain.
0x01
Assertion failed
Logic invariant broken
0x11
Arithmetic overflow/underflow
Unchecked math operation
0x12
Division by zero
Incorrect math division
0x21
Invalid enum conversion
Out-of-bounds value
0x31
Storage array index out of bounds
Bad loop or mapping access
0x32
Memory array index out of bounds
Corrupt array operation
To detect Panic errors dynamically:
1.4 Advanced Revert Inspection with Hardhat Traces
Hardhat’s tracing layer can reveal the full execution path of a revert.
You’ll see nested calls, gas usage per function, and exactly where the failure occurred. This is invaluable for multi-contract interactions like on-chain governance or liquidity management.
Example output:
1.5 Custom Error Decoding for Verified Contracts
If a Somnia contract is verified on the explorer, you can fetch its ABI dynamically to decode errors programmatically:
Then use iface.parseError(error.data) to decode reverts directly from on-chain logs or transactions.
2. Common Error Patterns on Somnia
Even experienced developers encounter recurring issues. Below are the most common EVM-level errors observed when deploying or testing on Somnia Testnet (Shannon) and Mainnet.
execution reverted
Fallback revert with no message
Add explicit revert messages or decode ABI data
out of gas
Gas exhausted mid-call
Use estimateGas() or increase gas limit
invalid opcode
Calling a non-existent function
Validate ABI and deployed bytecode
nonce too low
Pending transaction not mined yet
Wait for confirmation or reset nonce
replacement underpriced
Gas bump too small
Raise gas price by 10–20%
static call violation
State-changing call via eth_call
Use .sendTransaction() instead
2.1 Example: Catching a Custom Error in Somnia Treasury Contract
Decoding in JS:
2.2 Handling Complex Contract Interactions
When interacting with multi-layered DeFi protocols or bridging modules on Somnia, reverts can originate several calls deep. Use Hardhat’s trace or Foundry’s -vvvv verbosity to see the full stack.
Foundry example:
This reveals each opcode execution, event emission, and revert reason.
2.3 Invalid ABI or Proxy Conflicts
Many Somnia projects use upgradeable proxies. Reverts from a proxy may originate in the implementation contract. If you get a generic execution reverted, verify you’re using the correct implementation ABI:
3. Transaction Simulation
Simulating transactions allows developers to predict revert causes, estimate gas usage, and test behaviors without risking real SOMI or STT.
3.1 Fork Somnia Networks Locally
Create a local fork of Somnia Mainnet or Shannon Testnet:
Or in configuration:
This mirrors on-chain state locally, so you can safely replay any transaction.
3.2 Using callStatic for Dry-Run Simulation
callStatic runs a transaction without broadcasting or altering state.
3.3 Using eth_call Manually
For raw RPC simulation:
If the call reverts, inspect error.data to decode it with the ABI.
3.4 Impersonating Accounts for Privileged Actions
Simulate admin or contract-controlled operations:
Stop impersonation when finished:
3.5 Snapshot and Rollback Control
Snapshots let you test different outcomes quickly:
This resets the blockchain to its previous state instantly.
3.6 Simulating On-Chain Transactions
If you have a failed transaction hash from Somnia Mainnet:
This reproduces the failure locally and lets you inspect the revert reason directly in Hardhat.
3.7 Advanced Fork Testing with Foundry
You can use cheatcodes like:
3.8 Gas Profiling and Cost Analysis
Somnia gas costs can differ from Ethereum due to consensus differences. Always estimate gas usage per function:
Compare against Shannon and Mainnet to identify anomalies.
3.9 Full Transaction Lifecycle Test
Last updated