Language Rule
- Always respond in the same language the user is using. If the user asks in Chinese, respond in Chinese. If in English, respond in English.
Step 1: Get the transaction receipt — determine success/failure
Use the Foundry cast CLI to query the transaction receipt, passing in the tx hash and RPC endpoint.
Fields to focus on:
| Field | Meaning |
|---|---|
status |
0 = failure, 1 = success |
gasUsed |
Actual gas consumed |
logs |
Empty array [] = transaction reverted, no events emitted |
to |
Target contract address |
Step 2: Get the transaction details — obtain gas limit and input
Use the Foundry cast CLI to query the transaction details (tx), passing in the tx hash and RPC endpoint.
Fields to focus on:
| Field | Meaning |
|---|---|
gas |
Gas limit set by the sender |
input |
The calldata being called (function selector + encoded parameters) |
from / to |
Sender and target contract |
value |
Amount of native token sent |
Step 3: Determine the failure type — gasUsed vs gas limit
| Symptom | Diagnosis | Solution direction |
|---|---|---|
| gasUsed / gas ≈ 100% (e.g., 999,472 / 1,000,000) | Out of Gas (OOG) | Increase the gas limit or estimate gas |
| gasUsed far below gas limit (e.g., 50,000 / 1,000,000) | Revert | Need to obtain the revert reason, see Step 6 |
| gasUsed normal but status=0 | Internal call failed | Check balance, allowance, internal call return values |
| Transaction never made it on-chain | Nonce/Gas Price issue | Check the pending queue |
Step 4: Decode the function selector — determine what function was called
Use the 4byte feature of Foundry cast, passing in the first 4 bytes of the input, to look up the corresponding function signature.
Example: input 0xb51a038a → output unstake(uint256,address[],uint256[])
Step 5: Decode the full calldata — reconstruct the call parameters
Use the calldata-decode feature of Foundry cast, passing in the function signature obtained in Step 4 and the full input data.
The decoded parameters can be used to:
- Analyze whether the input parameters are incorrect
- Directly use them to retry the transaction
Step 6: Obtain the Revert Reason (non-OOG scenarios)
| Method | Description |
|---|---|
| Simulated call | Use Foundry cast call to simulate at the failure block number, specifying the from address and block number, to reconstruct the revert information |
| Replay transaction | Use Foundry cast run to replay the transaction (requires an archive node) |
| Online analysis platform | Use a third-party transaction analysis platform to view the detailed call stack (fallback option) |
Step 7: Query on-chain state — confirm data has been rolled back after the failed transaction
Use Foundry cast call to query the contract's public variables and mappings, passing in the contract address, function signature, and parameters.
For struct-type return values, the return types must be specified in ABI order.
State changes from a failed transaction are fully rolled back; you need to confirm the data is still in its original state.
Step 8: Compare successful vs failed transactions — find the differences
Compare the successful and failed transactions side by side:
| Comparison dimension | Description |
|---|---|
| Gas consumption | Determine whether it is OOG |
| Call parameters | Determine whether it is an input parameter issue |
| Target address | Determine whether the wrong contract was called |
| Block timestamp | Determine whether there are restrictions such as timelocks |
| Contract state | Determine whether preconditions are not met |
Step 9: Retry the transaction
| Scenario | Method |
|---|---|
| Normal retry | Use Foundry cast send without specifying a gas limit (let the node estimate automatically) |
| Known consumption range | Use Foundry cast send and specify a higher gas limit |
When retrying, use Foundry Keystore to manage the signing identity; do not pass the private key in plaintext in the command.
Security considerations
| Rule | Description |
|---|---|
| Private key management | Use Foundry Keystore to manage the signing identity; do not pass the private key in plaintext |
| Simulation first | Before actually sending, use a simulated call to confirm it will not revert |
| Send one by one | When retrying in batches, send one transaction first to verify, then send the rest after success |
| State confirmation | After sending, confirm status=1, then query the on-chain state to confirm the change took effect |
Complete debugging process summary
| Step | Operation | Purpose |
|---|---|---|
| 1 | Query the transaction receipt | Determine whether status is 0 (failed) |
| 2 | Query transaction details | Obtain the gas limit and input data |
| 3 | Compare gasUsed vs gas limit | Distinguish OOG from Revert |
| 4 | Decode the function selector | Determine which function was called |
| 5 | Decode the complete calldata | Restore the call parameters |
| 6 | Simulate the call to obtain the revert reason | Obtain the specific failure reason |
| 7 | Query the on-chain state | Confirm that the data has been rolled back |
| 8 | Compare with successful transactions | Identify the differences |
| 9 | Retry after fixing | Use Keystore signing to send, and confirm success |