Skip to content

Instantly share code, notes, and snippets.

@msigwart
Forked from gluk64/reason.js
Last active July 11, 2022 07:29
Show Gist options
  • Star 8 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save msigwart/d3e374a64c8718f8ac5ec04b5093597f to your computer and use it in GitHub Desktop.
Save msigwart/d3e374a64c8718f8ac5ec04b5093597f 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
package main
import (
"context"
"fmt"
"github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethclient"
"log"
"math/big"
"os"
)
// Usage:
// go run revert-reason.go [transactionHash]
//
// Example:
// go run revert-reason.go 0xa6b112eedaa032be06cb73cb9dc70994ea7eb33d8cec9a4de7e28dcb26210969
func main() {
if len(os.Args) != 2 {
log.Fatal("Usage: go run revert-reason.go [txHash]")
}
txHash := common.HexToHash(os.Args[1])
// Connect to chain
client, err := ethclient.Dial("https://mainnet.infura.io") // --> change network here
if err != nil {
log.Fatal("Connection failed: " + err.Error())
}
// Get transaction object
tx, isPending, err := client.TransactionByHash(context.Background(), txHash)
if err != nil {
log.Fatal("Transaction not found")
}
if isPending {
log.Fatal("Transaction is still pending")
}
chainID, err := client.NetworkID(context.Background())
if err != nil {
log.Fatal(err)
}
msg, err := tx.AsMessage(types.NewEIP155Signer(chainID))
if err != nil {
log.Fatal(err)
}
// Get transaction receipt
receipt, err := client.TransactionReceipt(context.Background(), tx.Hash())
if err != nil {
log.Fatal("Failed to retrieve receipt: " + err.Error())
}
if receipt.Status == 1 {
fmt.Println("Transaction was successful")
return
}
// Get failure reason
reason := getFailureReason(client, msg.From(), tx, receipt.BlockNumber)
fmt.Println("Revert reason: " + reason)
}
func getFailureReason(client *ethclient.Client, from common.Address, tx *types.Transaction, blockNumber *big.Int) string {
code, err := client.CallContract(context.Background(), createCallMsgFromTransaction(from, tx), blockNumber)
if err != nil {
log.Fatal("Cannot not get revert reason: " + err.Error())
}
if len(code) == 0 {
return "no error message or out of gas"
}
return fmt.Sprintf(string(code[4:]))
}
func createCallMsgFromTransaction(from common.Address, tx *types.Transaction) ethereum.CallMsg {
return ethereum.CallMsg{
From: from,
To: tx.To(),
Gas: tx.Gas(),
GasPrice: tx.GasPrice(),
Value: tx.Value(),
Data: tx.Data(),
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment