-
-
Save gluk64/fdea559472d957f1138ed93bcbc6f78a to your computer and use it in GitHub Desktop.
// This is universal, works with Infura -- set provider accordingly | |
const ethers = require('ethers') | |
//const provider = ethers.getDefaultProvider('rinkeby') | |
const provider = new ethers.providers.JsonRpcProvider(process.env.WEB3_URL) | |
function hex_to_ascii(str1) { | |
var hex = str1.toString(); | |
var str = ''; | |
for (var n = 0; n < hex.length; n += 2) { | |
str += String.fromCharCode(parseInt(hex.substr(n, 2), 16)); | |
} | |
return str; | |
} | |
async function reason() { | |
var args = process.argv.slice(2) | |
let hash = args[0] | |
console.log('tx hash:', hash) | |
console.log('provider:', process.env.WEB3_URL) | |
let tx = await provider.getTransaction(hash) | |
if (!tx) { | |
console.log('tx not found') | |
} else { | |
let code = await provider.call(tx, tx.blockNumber) | |
let reason = hex_to_ascii(code.substr(138)) | |
console.log('revert reason:', reason) | |
} | |
} | |
reason() |
#!/bin/bash | |
# This is for geth | |
# Fetching revert reason -- https://ethereum.stackexchange.com/questions/48383/how-to-receive-revert-reason-for-past-transactions | |
if [ -z "$1" ] | |
then | |
echo "Usage: revert-reason <TX_HASH>" | |
exit | |
fi | |
TX=$1 | |
SCRIPT=" tx = eth.getTransaction( \"$TX\" ); tx.data = tx.input; eth.call(tx, tx.blockNumber)" | |
geth --exec "$SCRIPT" attach http://localhost:8545 | cut -d '"' -f 2 | cut -c139- | xxd -r -p | |
echo |
Though you can use ethers.utils.toUtf8String('0x' + code.substr(138));
on L27 and not need hex_to_ascii
at all
Thanks for putting this together. I forked and made a few mods including the above recommendation.
Nice. I bundled this up with some other features into https://github.com/justinjmoses/eth-reveal/
Thanks, this is quite useful! I also forked and added a Go version of the script: https://gist.github.com/msigwart/d3e374a64c8718f8ac5ec04b5093597f
I added an NPM package, eth-revert-reason
that will return the reason in any case (any network, Geth or Parity).
Please excuse the ignorance, but this does not work with ganache, correct?
provider.call()
is not working for me after successfully retrieving the transaction, so maybe I'm doing something wrong?
Apologies for the multiple questions.
I tested this on Rinkeby (https://rinkeby.etherscan.io/tx/0x512b05c7fadf8c30fc62fb9400bbeb47169174d908648ac531f5db9dd1aeaa96) and, as you can see, it failed (on purpose by me setting the gas too low).
When this transaction was first called, and failed, my try/catch
block output as part of the return in my console logs:
reason: 'transaction failed',
code: 'CALL_EXCEPTION',
However, when reason
runs, no code
is returned for the provider.call()
, which I believe is somehow equivalent to provider.getTransaction()
. Likewise, if I run provider.getTransactionReceipt(hash)
, the output contains no mention of a failure (unless one looks at status: 0
):
{
to: '0xaa4041ca5d6d14e566DCE4A70d3b9ad585F0Da64',
from: '0xA0b5B95617a5c6Bf0116d47C2a4c93164aaE3328',
contractAddress: null,
transactionIndex: 3,
gasUsed: BigNumber { _hex: '0x01823e', _isBigNumber: true },
logsBloom: '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000',
blockHash: '0x07c16e6922a64606c31bb742621eb1a93a57724c7cda771522315ef1d3bcc580',
transactionHash: '0x512b05c7fadf8c30fc62fb9400bbeb47169174d908648ac531f5db9dd1aeaa96',
logs: [],
blockNumber: 6825108,
confirmations: 64,
cumulativeGasUsed: BigNumber { _hex: '0x034d77', _isBigNumber: true },
status: 0,
byzantium: true
}
Am I misunderstanding something here about how this is supposed to work?
const a = await provider.getTransaction('0xdc6506137b443a6ad6734b0047a6d00d31748110589b379d72461bc57e510e94');
try {
let code = await provider.call(a, a.blockNumber)
} catch (err) {
const code = err.data.replace('Reverted ','');
console.log({err});
let reason = ethers.utils.toUtf8String('0x' + code.substr(138));
console.log('revert reason:', reason);
}
I had to catch one more level for it to work "ethers": "5.0.3",
The bash script gives an error
-bash: ./revert-reason.sh: line 9: syntax error near unexpected token `fi'
-bash: ./revert-reason.sh: line 9: `fi'
Should this snippet work also with latest 5.4 ethers.js please?
I'm trying it together with typescript and there is type issue between getTransaction()
returning TransactionResponse
and call()
method requesting TransactionRequest
.
When I tried to re-type it then I'm still receiving only:
code:'CALL_EXCEPTION'
data:'0x'
reason:'missing revert data in call exception'
Though you can use
ethers.utils.toUtf8String('0x' + code.substr(138));
on L27 and not needhex_to_ascii
at all
Wow it works!! But is this really all I need?
Should this snippet work also with latest 5.4 ethers.js please?
I'm trying it together with typescript and there is type issue between
getTransaction()
returningTransactionResponse
andcall()
method requestingTransactionRequest
.When I tried to re-type it then I'm still receiving only:
code:'CALL_EXCEPTION' data:'0x' reason:'missing revert data in call exception'
same with me
This works for me:
const tx = await provider.getTransaction(txHash)
const response = await provider.call(
{
to: tx.to,
from: tx.from,
nonce: tx.nonce,
gasLimit: tx.gasLimit,
gasPrice: tx.gasPrice,
data: tx.data,
value: tx.value,
chainId: tx.chainId,
type: tx.type ?? undefined,
accessList: tx.accessList,
},
tx.blockNumber,
)
// This should be your error code
const firstFourBytes = response.slice(0, 10)
const tx = await provider.getTransaction(txHash)
const response = await provider.call(
{
to: tx.to,
from: tx.from,
nonce: tx.nonce,
gasLimit: tx.gasLimit,
gasPrice: tx.gasPrice,
data: tx.data,
value: tx.value,
chainId: tx.chainId,
type: tx.type ?? undefined,
accessList: tx.accessList,
},
tx.blockNumber,
)
const reason = ethers.utils.toUtf8String('0x' + response.substring(138))
Awesome - just what I was looking for!