0

I've seen a variety of questions and answers in this forum about extracting the public key from a signed transaction hash. I am able to get the correct answer from newer transactions, but unable to with older transactions and am curious if anyone has any ideas.

https://etherscan.io/tx/0x8aa30f7d95cd5f22dd02e59434c0e66794c6e370ed2659ea532ed6fe49f9cce5

This is the signed transaction I am attempting to generate the public key for. Any help would be appreciated!

1 Answer 1

0

It essentially comes down to the three methods constructing transactions through the Ethereum history until now.

Below is a piece a tiny bit modified Python script originally published in this gist (full credit should go to the original author) covering the three types.

Explanation:

  • type_0_keys — legacy transactions before EIP-155.
  • type_1_keys — EIP-155 transactions.
  • type_2_keys — EIP-1559 transactions.

Replace NODE_ENDPOINT and TX_HASH with your values. Note also tx["chainId"] = 1 set for the Ethereum mainnet.

import web3
from eth_account._utils.signing import extract_chain_id, to_standard_v
from eth_account._utils.legacy_transactions import serializable_unsigned_transaction_from_dict

w3 = web3.Web3(web3.HTTPProvider("NODE_ENDPOINT"))
tx = w3.eth.get_transaction("TX_HASH")
tx = dict(tx)

type_0_keys = ['chainId', 'gas', 'gasPrice', 'nonce', 'to', 'value']
type_1_keys = ["to",
    "nonce",
    "value",
    "gas",
    'gasPrice',
    "chainId",
    "type"]
type_2_keys = ["to",
    "nonce",
    "value",
    "gas",
    "chainId",
    "maxFeePerGas",
    "maxPriorityFeePerGas",
    "type"]

s = w3.eth.account._keys.Signature(vrs=(
    to_standard_v(extract_chain_id(tx["v"])[1]),
    w3.to_int(tx["r"]),
    w3.to_int(tx["s"])
))

if tx["type"] == 0:
    keys_to_get = type_0_keys
elif tx["type"] == 1:
    keys_to_get = type_1_keys
elif tx["type"] == 2:
    keys_to_get = type_2_keys

if "chainId" not in tx:
    tx["chainId"] = 1

tt = {k:tx[k] for k in keys_to_get}
tt["data"] = tx["input"]

ut = serializable_unsigned_transaction_from_dict(tt)

public_key = s.recover_public_key_from_msg_hash(ut.hash())

if hasattr(public_key, 'to_hex'):
    public_key_hex = public_key.to_hex()
else:
    public_key_bytes = public_key.to_bytes()
    public_key_hex = public_key_bytes.hex()

print(public_key_hex)
1
  • Thank you SO much, I was struggling with this for around a week, and there isn't a great deal of info online (that I could find) about the differences between these types of transactions. This worked! Really appreciate the help. Commented Oct 2, 2023 at 14:05

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.