feat(evm): failed wasm precompile transaction don't propagate error message
I had an error when creating a transaction for the wasm pre-compile (which came to a contract error in wasm). When querying the evm transaction, i just get failed true with no logs attached.
❯ curl -X POST -H "Content-Type: application/json" --data '{"jsonrpc":"2.0","method":"debug_traceTransaction","params":["0xd7371d317b2b62591225ecbb852e6a9206a60078f946cdc4311ab04d54f99b10"],"id":1}' http://localhost:8545
{"jsonrpc":"2.0","id":1,"result":{"failed":true,"gas":30000000,"returnValue":"","structLogs":[]}}
The only way i was able to see the error was with this debug print:
data, err := p.Wasm.Execute(ctx, wasmContract, nibiruCaller, msgArgsBz, funds)
if err != nil {
fmt.Printf("Wasm execution failed: %v\n", err)
return
}
Here's the erorr message from the receipt (wasmcaller)
error: transaction execution reverted (action="sendTransaction", data=null, reason=null, invocation=null, revert=null, transaction={ "data": "", "from": "0xC0f4b45712670cf7865A14816bE9Af9091EDdA1d", "to": "0x0000000000000000000000000000000000000802" }, receipt={ "_type": "TransactionReceipt", "blobGasPrice": null, "blobGasUsed": null, "blockHash": "0x52a038f4bf72b1564cb2f314521a376f5c89423ffa20cd94befb4f32904371d7", "blockNumber": 78, "contractAddress": "0x0000000000000000000000000000000000000000", "cumulativeGasUsed": "609662", "from": "0xC0f4b45712670cf7865A14816bE9Af9091EDdA1d", "gasPrice": "1000000000000", "gasUsed": "609662", "hash": "0xb91c43da8fe370bcffeee969bf8376953a702fb09924959b9c4c54d64b4019b9", "index": 0, "logs": [ ], "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "root": null, "status": 0, "to": "0x0000000000000000000000000000000000000802" }, code=CALL_EXCEPTION, version=6.13.5)
action: "sendTransaction",
data: null,
reason: null,
invocation: null,
revert: null,
transaction: {
to: "0x0000000000000000000000000000000000000802",
from: "0xC0f4b45712670cf7865A14816bE9Af9091EDdA1d",
data: "",
},
receipt: TransactionReceipt {
provider: [Object ...],
to: "0x0000000000000000000000000000000000000802",
from: "0xC0f4b45712670cf7865A14816bE9Af9091EDdA1d",
contractAddress: "0x0000000000000000000000000000000000000000",
hash: "0xb91c43da8fe370bcffeee969bf8376953a702fb09924959b9c4c54d64b4019b9",
index: 0,
blockHash: "0x52a038f4bf72b1564cb2f314521a376f5c89423ffa20cd94befb4f32904371d7",
blockNumber: 78,
logsBloom: "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
gasUsed: 609662n,
blobGasUsed: null,
cumulativeGasUsed: 609662n,
gasPrice: 1000000000000n,
blobGasPrice: null,
type: 2,
status: 0,
root: undefined,
logs: [Getter],
toJSON: [Function: toJSON],
length: [Getter],
fee: [Getter],
getBlock: [AsyncFunction: getBlock],
getTransaction: [AsyncFunction: getTransaction],
getResult: [AsyncFunction: getResult],
confirmations: [AsyncFunction: confirmations],
removedEvent: [Function: removedEvent],
reorderedEvent: [Function: reorderedEvent],
[Symbol(Symbol.iterator)]: [Function],
},
shortMessage: "transaction execution reverted",
code: "CALL_EXCEPTION"
at makeError (/Users/mdarblade/code/sai/scripts/node_modules/ethers/lib.esm/utils/errors.js:124:21)
at assert (/Users/mdarblade/code/sai/scripts/node_modules/ethers/lib.esm/utils/errors.js:143:15)
at checkReceipt (/Users/mdarblade/code/sai/scripts/node_modules/ethers/lib.esm/providers/provider.js:1119:13)
at <anonymous> (/Users/mdarblade/code/sai/scripts/node_modules/ethers/lib.esm/providers/provider.js:1165:33)
Can be replicated on SAI by setting the value on this branch from 2_000_000 to 200_000 for the gas limit.
https://github.com/NibiruChain/sai-perps/blob/3e2aa3a1711ad06a5b8b2d3c93f2df28f09e11ac/scripts/localnet_test/test_simple_evm.ts#L18
TLDR; works as expected
Use debug_traceTransaction call to get error details.
Working example of debug_traceTransaction on testnet-2 (wasm precompile)
Sent wrong message to sai oracle contract via EVM:
curl -s -X POST --data '{
"jsonrpc": "2.0",
"method": "debug_traceTransaction",
"params": ["0x5644c4e9d47a896bc4660a615146cca3a5db39fc3d22b04c48c8df78665aa8f1", {"tracer": "callTracer"}],
"id": 1
}' -H "Content-Type: application/json" https://evm-rpc.testnet-2.nibiru.fi/ | jq
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"error": "precompile error: failed to run precompileWasm: execute method called: Error parsing into type oracle::state::OraclesExecuteMsg: unknown variant `increment1`, expected one of `set_price`, `update_expiration_time`, `create_token`, `delete_token`, `create_permission_group`, `update_permission_group`, `delete_permission_group`, `update_ownership`: execute wasm contract failed [CosmWasm/[email protected]/x/wasm/keeper/keeper.go:395]",
"from": "0xc0f4b45712670cf7865a14816be9af9091edda1d",
"gas": "0xee770",
"gasUsed": "0xee770",
"input": "0x61ffaee4000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000003f6e696269316b61716471796a38737364757534747672736570756b34677565726a396871666b7a38337870726a61737a7563396b706b637473347a776b35710000000000000000000000000000000000000000000000000000000000000000127b22696e6372656d656e7431223a207b7d7d00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"to": "0x0000000000000000000000000000000000000802",
"type": "CALL",
"value": "0x0"
}
}
Working example of debug_traceTransaction on testnet-2 (funtoken precompile)
Here the tx tries to send more ERC20 than user has.
curl -s -X POST --data '{
"jsonrpc": "2.0",
"method": "debug_traceTransaction",
"params": ["0xd67ca72bbea14d6a60f4e6895e6a2ed41db05a0d5fde5030255ca446d214d43f", {"tracer": "callTracer"}],
"id": 1
}' -H "Content-Type: application/json" https://evm-rpc.testnet-2.nibiru.fi | jq
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"error": "precompile error: failed to run precompileFunToken: error in ERC20.transfer from caller to EVM account: CallContractError: VMError: execution reverted with reason \"ERC20: transfer amount exceeds balance\"",
"from": "0xc0f4b45712670cf7865a14816be9af9091edda1d",
"gas": "0x2b8d8",
"gasUsed": "0x1e2bfc",
"input": "0xa9059cbb000000000000000000000000603871c2ddd41c26ee77495e2e31e6de7f9957e000000000000000000000000000000000000000000000000000000002540be400",
"output": "0x08c379a00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002645524332303a207472616e7366657220616d6f756e7420657863656564732062616c616e63650000000000000000000000000000000000000000000000000000",
"to": "0x7d4b7b8ca7e1a24928bb96d59249c7a5bd1dfbe6",
"type": "CALL",
"value": "0x0"
}
}
ethers.js script to debug tx
const trace = await provider.send(
'debug_traceTransaction', [
tx.hash,
{
// Use callTracer for better visibility into the call stack
tracer: 'callTracer',
// Include return data to see error messages
enableReturnData: true
}
]);
console.log(JSON.stringify(trace, null, 2));
Proper flow (for apps):
- Send tx (
eth_sendRawTransaction) -> returns tx hash - Wait for tx (
eth_getTransactionReceipt) - If tx failed, call
debug_traceTransactionto get error details.
debug_traceTransaction was empty for me when running out of gas during wasm precompile operation:
❯ curl -X POST -H "Content-Type: application/json" --data '{"jsonrpc":"2.0","method":"debug_traceTransaction","params":["0xd7371d317b2b62591225ecbb852e6a9206a60078f946cdc4311ab04d54f99b10"],"id":1}' http://localhost:8545
{"jsonrpc":"2.0","id":1,"result":{"failed":true,"gas":30000000,"returnValue":"","structLogs":[]}}
This is the log from 2 different txs from my local node:
- First, a tx with not enough gas
- Second, a tx with wrong msg