Is it possible to get the senders address using golang when all you have is the raw transaction string. I can decode it and get the nonce, hash, to etc as these are all exported functions from the types.Transactions package but I cant seem to find a way to get the actual senders address (using golang) Javascript has some functions for doing so - I should also state that I need to do this in a standalone script rather than being connected to a node (if possible)
5 Answers
Here's a full working example of how to decode a raw transaction and read the sender (from) address:
package main
import (
"encoding/hex"
"fmt"
"log"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/rlp"
)
func main() {
rawTx := "f86d8202b28477359400825208944592d8f8d7b001e72cb26a73e4fa1806a51ac79d880de0b6b3a7640000802ca05924bde7ef10aa88db9c66dd4f5fb16b46dff2319b9968be983118b57bb50562a001b24b31010004f13d9a26b320845257a6cfc2bf819a3d55e3fc86263c5f0772"
tx := new(types.Transaction)
rawTxBytes, err := hex.DecodeString(rawTx)
rlp.DecodeBytes(rawTxBytes, &tx)
msg, err := tx.AsMessage(types.NewEIP155Signer(tx.ChainId()))
if err != nil {
log.Fatal(err)
}
fmt.Println(msg.From().Hex())
// 0x96216849c49358B10257cb55b28eA603c874b05E
}
See this transaction in etherscan
-
This works for
tx.Type=LegacyTxType
, but for DynamicFeeTxType it throws ErrTxTypeNotSupported– HonzaJun 13, 2022 at 17:13
Just to update this answer, there is a requirement parameter on the AsMessage call. you need to pass a base fee, though the transaction is a free on, place a big int 0 into the call as shown below:
msgFrom, _ := tx.AsMessage(types.NewEIP2930Signer(tx.ChainId() ),big.NewInt(1) )
-
Hi, thanks for updating. What is base fee in this function? Can you explain it? Sep 17, 2021 at 8:25
-
Hmmm... this shows always 0x0000000000000000000000000000000000000000 as msgFrom.From().Hex()– MariuszFeb 9, 2022 at 21:48
we can use go to pick out the senders' address from raw tx as below sample code
if msg, err := tx.AsMessage(types.NewEIP155Signer(big.NewInt(1))); err == nil {
fmt.Println(msg.From().Hex())
} else {
fmt.Println(err.Error())
}
and depend on the chainId get out from the raw tx, then you can decide which signer need to use
// Depending on the presence of the chain ID, sign with EIP155 or homestead
if chainID != nil {
return types.SignTx(tx, types.NewEIP155Signer(chainID), key.PrivateKey)
}
return types.SignTx(tx, types.HomesteadSigner{}, key.PrivateKey)
-- or, we can simple get sender from tx as below code
signer := types.NewEIP155Signer(tx.ChainId())
sender, err := signer.Sender(tx)
if err != nil {
fmt.Printf("sender: %v", sender.Hex())
}
Hope this help!
You should use
types.LatestSignerForChainID()
instead of legacy EIP 155 signer. Curtesy to https://github.com/ethereum/go-ethereum/issues/23890#issuecomment-966794849
Above solutions are all incredibly expensive methods if you are doing them at scale given the amount of RPC-calls you have to make.
I found this method to be the cheapest when you already have the normal *types.Transaction:
func getFromCheap(tx *types.Transaction) string {
blockFeeFake := big.NewInt(10838863023) // For the from address it does not matter if you have the right number here
fromAddr, _ := tx.AsMessage(types.LatestSignerForChainID(tx.ChainId()), blockFeeFake)
return fromAddr.From().String()
}
This returns the "From" address as a string without any RPC calls. The fastest / most efficient way to get transactions is to:
- Get a block // You can save the baseFee here if you want.
- Get the Txs.
- Use above function to get "From" at scale.
-
None of the existing answers involve RPC calls other than for getting the transaction data.– Ismael ♦Nov 3, 2022 at 6:30