8

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)

6 Answers 6

4

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

1
  • This works for tx.Type=LegacyTxType, but for DynamicFeeTxType it throws ErrTxTypeNotSupported
    – Tharok
    Jun 13, 2022 at 17:13
3

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) )
2
  • 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()
    – Mariusz
    Feb 9, 2022 at 21:48
2

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!

3
  • It does help indeed. I had been looking into this myself but wasnt sure what to put as the eip signer field.
    – Kravitz
    Feb 22, 2019 at 9:17
  • okay, I updated the answer for the signer part. PTAL
    – Tony Dang
    Feb 26, 2019 at 8:52
  • This works for tx.Type=LegacyTxType, but for DynamicFeeTxType it throws ErrTxTypeNotSupported
    – Tharok
    Jun 13, 2022 at 17:14
1

You should use

types.LatestSignerForChainID()

instead of legacy EIP 155 signer. Curtesy to https://github.com/ethereum/go-ethereum/issues/23890#issuecomment-966794849

1

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:

  1. Get a block // You can save the baseFee here if you want.
  2. Get the Txs.
  3. Use above function to get "From" at scale.
1
  • None of the existing answers involve RPC calls other than for getting the transaction data.
    – Ismael
    Nov 3, 2022 at 6:30
0

This has changed recently,

New function looks like this:

func calcFrom(tx *types.Transaction) common.Address {
    msg, err := core.TransactionToMessage(tx, types.LatestSignerForChainID(tx.ChainId()), nil)
    if err != nil {
        panic(err)
    }

    return msg.From()
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.