Fork EthTx transaction decoder by Palmera
Project description
Palmera EthTx - Ethereum transactions decoder by Palmera
Introduction
Source Code: https://github.com/ethtx/ethtx
Installation
pip install palmera-ethtx
Requirements
The package needs a few external resources, defined in EthTxConfig
object:
- RPC node - required to have access to the raw Ethereum data; it must be a full archive node with
the
debug
option ON - Etherscan API key - required to get the source code and ABI for smart contracts used in transaction
- (Optional) MongoDB database - required to store smart contracts' ABI and semantics used in the decoding process.
If you don't want to setup permanent database, you can enter
mongomock://localhost/ethtx
, then in-memory mongo will be set up that discards all data with every run.
Getting started
from ethtx import EthTx, EthTxConfig
from ethtx.models.decoded_model import DecodedTransaction
ethtx_config = EthTxConfig(
mongo_connection_string="mongomock://localhost/ethtx", ##MongoDB connection string,
etherscan_api_key="", ##Etherscan API key,
web3nodes={
"mainnet": {
"hook": "_Geth_archive_node_URL_", # multiple nodes supported, separate them with comma
"poa": _POA_chain_indicator_ # represented by bool value
}
},
default_chain="mainnet",
etherscan_urls={"mainnet": "https://api.etherscan.io/api", },
)
ethtx = EthTx.initialize(ethtx_config)
decoded_transaction: DecodedTransaction = ethtx.decoders.decode_transaction(
'0x50051e0a6f216ab9484c2080001c7e12d5138250acee1f4b7c725b8fb6bb922d')
Features
EthTx most important functions:
- Raw node data access:
web3provider = ethtx.providers.web3provider
from ethtx.models.w3_model import W3Transaction, W3Block, W3Receipt, W3CallTree
# read raw transaction data directly from the node
w3transaction: W3Transaction = web3provider.get_transaction(
'0x50051e0a6f216ab9484c2080001c7e12d5138250acee1f4b7c725b8fb6bb922d')
w3block: W3Block = web3provider.get_block(w3transaction.blockNumber)
w3receipt: W3Receipt = web3provider.get_receipt(w3transaction.hash.hex())
w3calls: W3CallTree = web3provider.get_calls(w3transaction.hash.hex())
- ABI decoding:
from ethtx.models.decoded_model import (
DecodedTransfer,
DecodedBalance,
DecodedEvent, DecodedCall,
)
from ethtx.models.objects_model import Transaction, Event, Block, Call
# read the raw transaction from the node
transaction = Transaction.from_raw(
w3transaction=w3transaction, w3receipt=w3receipt, w3calltree=w3calls
)
# get proxies used in the transaction
proxies = ethtx.decoders.get_proxies(transaction.root_call, "mainnet")
block: Block = Block.from_raw(
w3block=web3provider.get_block(transaction.metadata.block_number),
chain_id="mainnet",
)
# decode transaction components
abi_decoded_events: List[Event] = ethtx.decoders.abi_decoder.decode_events(
transaction.events, block.metadata, transaction.metadata
)
abi_decoded_calls: DecodedCall = ethtx.decoders.abi_decoder.decode_calls(
transaction.root_call, block.metadata, transaction.metadata, proxies
)
abi_decoded_transfers: List[
DecodedTransfer
] = ethtx.decoders.abi_decoder.decode_transfers(abi_decoded_calls, abi_decoded_events)
abi_decoded_balances: List[DecodedBalance] = ethtx.decoders.abi_decoder.decode_balances(
abi_decoded_transfers
)
# decode a single event
raw_event: Event = transaction.events[3]
abi_decoded_event: DecodedEvent = ethtx.decoders.abi_decoder.decode_event(
raw_event, block.metadata, transaction.metadata
)
# decode a single call
raw_call: Call = transaction.root_call.subcalls[0]
abi_decoded_call: DecodedCall = ethtx.decoders.abi_decoder.decode_call(
raw_call, block.metadata, transaction.metadata, proxies
)
- Semantic decoding:
from ethtx.models.decoded_model import DecodedTransactionMetadata
# semantically decode transaction components
decoded_metadata: DecodedTransactionMetadata = (
ethtx.decoders.semantic_decoder.decode_metadata(
block.metadata, transaction.metadata, "mainnet"
)
)
decoded_events: List[DecodedEvent] = ethtx.decoders.semantic_decoder.decode_events(
abi_decoded_events, decoded_metadata, proxies
)
decoded_calls: Call = ethtx.decoders.semantic_decoder.decode_calls(
abi_decoded_calls, decoded_metadata, proxies
)
decoded_transfers: List[
DecodedTransfer
] = ethtx.decoders.semantic_decoder.decode_transfers(
abi_decoded_transfers, decoded_metadata
)
decoded_balances: List[
DecodedBalance
] = ethtx.decoders.semantic_decoder.decode_balances(
abi_decoded_balances, decoded_metadata
)
# semantically decode a single event
decoded_event: DecodedEvent = ethtx.decoders.semantic_decoder.decode_event(
abi_decoded_events[0], decoded_metadata, proxies
)
# semantically decode a single call
decoded_call: Call = ethtx.decoders.semantic_decoder.decode_call(
abi_decoded_calls.subcalls[0], decoded_metadata, proxies
)
- ABI decoding:
Test the Eth.tx:
make script
- Example
# Decoding transaction on Goerli
decoded_transaction_goerli: DecodedTransaction = ethtx.decoders.decode_transaction(
"0xd028241a7bbd2068439351994c286614190b26ecbc1cc27f6f2e76c7d2325f5b", "goerli"
)
Etherscan Link: Tx of Safe Address in Goerli
Ethtx.Info Link: Tx of Safe Address in Goerli
Response
{
"balances": [
{
"holder": {
"address": "0x7161be2924b4710d3754be067e01b0cd4544c695",
"badge": "receiver",
"name": "GnosisSafeProxy"
},
"tokens": [
{
"balance": "-100,000.0000",
"token_address": "0xaaaa826d36d58a9b0e1055a75dce79ae99751c18",
"token_standard": "ERC20",
"token_symbol": "OmniseaBaseToken"
}
]
},
{
"holder": {
"address": "0x00b97496700288c1bceb90ecc04a40c4aeac8bb4",
"badge": null,
"name": "0x00b97496700288c1bceb90ecc04a40c4aeac8bb4"
},
"tokens": [
{
"balance": "100,000.0000",
"token_address": "0xaaaa826d36d58a9b0e1055a75dce79ae99751c18",
"token_standard": "ERC20",
"token_symbol": "OmniseaBaseToken"
}
]
}
],
"block_metadata": {
"block_hash": "0xc52f44b85b399d3341181864f85ebbcbf92f6081f74ded078dbbfd8d8b388b03",
"block_number": "9647726",
"canonical": true,
"gas_limit": "30000000",
"gas_used": "16010508",
"miner": "0x8dc847af872947ac18d5d63fa646eb65d4d99560",
"parent_hash": "0x9103881de8ca4f9e7ac0b76114a66fe68be4d5d1991c1bde64ae5a996d8f6883",
"timestamp": "2023-09-06T16:04:36",
"tx_count": "90"
},
"calls": {
"arguments": [
{
"name": "to",
"type": "address",
"value": {
"address": "0xaaaa826d36d58a9b0e1055a75dce79ae99751c18",
"badge": null,
"name": "OmniseaBaseToken"
}
},
{
"name": "value",
"type": "uint256",
"value": "0"
},
{
"name": "data",
"type": "bytes",
"value": "0xa9059cbb00000000000000000000000000b97496700288c1bceb90ecc0...800000"
},
{
"name": "operation",
"type": "uint8",
"value": "0"
},
{
"name": "safeTxGas",
"type": "uint256",
"value": "0"
},
{
"name": "baseGas",
"type": "uint256",
"value": "0"
},
{
"name": "gasPrice",
"type": "uint256",
"value": "0"
},
{
"name": "gasToken",
"type": "address",
"value": {
"address": "0x0000000000000000000000000000000000000000",
"badge": null,
"name": "0x0000000000000000000000000000000000000000"
}
},
{
"name": "refundReceiver",
"type": "address",
"value": {
"address": "0x0000000000000000000000000000000000000000",
"badge": null,
"name": "0x0000000000000000000000000000000000000000"
}
},
{
"name": "signatures",
"type": "bytes",
"value": "0x3fe2737edc8e26ab9aa25ae3f03b783032f140d87d382ca4b1400d8994...000001"
}
],
"call_id": "",
"call_type": "call",
"chain_id": "goerli",
"error": null,
"from_address": {
"address": "0xf285e70ca2002b796a575e473285282bbf39d790",
"badge": "sender",
"name": "0xf285e70ca2002b796a575e473285282bbf39d790"
},
"function_guessed": false,
"function_name": "execTransaction",
"function_signature": "0x6a761202",
"gas_used": "90538",
"indent": "0",
"outputs": [
{
"name": "",
"type": "bool",
"value": "True"
}
],
"status": true,
"subcalls": [
{
"arguments": [
{
"name": "to",
"type": "address",
"value": {
"address": "0xaaaa826d36d58a9b0e1055a75dce79ae99751c18",
"badge": null,
"name": "OmniseaBaseToken"
}
},
{
"name": "value",
"type": "uint256",
"value": "0"
},
{
"name": "data",
"type": "bytes",
"value": "0xa9059cbb00000000000000000000000000b97496700288c1bceb90ecc0...800000"
},
{
"name": "operation",
"type": "uint8",
"value": "0"
},
{
"name": "safeTxGas",
"type": "uint256",
"value": "0"
},
{
"name": "baseGas",
"type": "uint256",
"value": "0"
},
{
"name": "gasPrice",
"type": "uint256",
"value": "0"
},
{
"name": "gasToken",
"type": "address",
"value": {
"address": "0x0000000000000000000000000000000000000000",
"badge": null,
"name": "0x0000000000000000000000000000000000000000"
}
},
{
"name": "refundReceiver",
"type": "address",
"value": {
"address": "0x0000000000000000000000000000000000000000",
"badge": null,
"name": "0x0000000000000000000000000000000000000000"
}
},
{
"name": "signatures",
"type": "bytes",
"value": "0x3fe2737edc8e26ab9aa25ae3f03b783032f140d87d382ca4b1400d8994...000001"
}
],
"call_id": "0",
"call_type": "delegatecall",
"chain_id": "goerli",
"error": null,
"from_address": {
"address": "0x7161be2924b4710d3754be067e01b0cd4544c695",
"badge": "receiver",
"name": "GnosisSafeProxy"
},
"function_guessed": false,
"function_name": "execTransaction",
"function_signature": "0x6a761202",
"gas_used": "65065",
"indent": "1",
"outputs": [
{
"name": "",
"type": "bool",
"value": "True"
}
],
"status": true,
"subcalls": [
{
"arguments": [
{
"name": "hash",
"type": "bytes32",
"value": "0x2f1aa87e0b2fc0d0f8b6b33ec3718da2b110d59197ceb66e3c74c338b169a6e2"
},
{
"name": "v",
"type": "bytes8",
"value": "0x000000000000000000000000000000000000000000000000000000000000001b"
},
{
"name": "r",
"type": "bytes32",
"value": "0x3fe2737edc8e26ab9aa25ae3f03b783032f140d87d382ca4b1400d899483f17a"
},
{
"name": "s",
"type": "bytes32",
"value": "0x71292f1b4be1e6b8caf9927caade2fdc5043aed142a34d2ef4af23ed809ef558"
}
],
"call_id": "0_0000",
"call_type": "staticcall",
"chain_id": "goerli",
"error": null,
"from_address": {
"address": "0x7161be2924b4710d3754be067e01b0cd4544c695",
"badge": "receiver",
"name": "GnosisSafeProxy"
},
"function_guessed": false,
"function_name": "ecrecover",
"function_signature": "0x2f1aa87e",
"gas_used": "3000",
"indent": "2",
"outputs": [
{
"name": "",
"type": "address",
"value": {
"address": "0x00b97496700288c1bceb90ecc04a40c4aeac8bb4",
"badge": null,
"name": "0x00b97496700288c1bceb90ecc04a40c4aeac8bb4"
}
}
],
"status": true,
"subcalls": [],
"timestamp": "2023-09-06T16:04:36",
"to_address": {
"address": "0x0000000000000000000000000000000000000001",
"badge": null,
"name": "Precompiled"
},
"tx_hash": "0xd028241a7bbd2068439351994c286614190b26ecbc1cc27f6f2e76c7d2325f5b",
"value": "0.0"
},
{
"arguments": [
{
"name": "recipient",
"type": "address",
"value": {
"address": "0x00b97496700288c1bceb90ecc04a40c4aeac8bb4",
"badge": null,
"name": "0x00b97496700288c1bceb90ecc04a40c4aeac8bb4"
}
},
{
"name": "amount",
"type": "uint256",
"value": "100000"
}
],
"call_id": "0_0001",
"call_type": "call",
"chain_id": "goerli",
"error": null,
"from_address": {
"address": "0x7161be2924b4710d3754be067e01b0cd4544c695",
"badge": "receiver",
"name": "GnosisSafeProxy"
},
"function_guessed": false,
"function_name": "transfer",
"function_signature": "0xa9059cbb",
"gas_used": "13260",
"indent": "2",
"outputs": [
{
"name": "",
"type": "bool",
"value": "True"
}
],
"status": true,
"subcalls": [],
"timestamp": "2023-09-06T16:04:36",
"to_address": {
"address": "0xaaaa826d36d58a9b0e1055a75dce79ae99751c18",
"badge": null,
"name": "OmniseaBaseToken"
},
"tx_hash": "0xd028241a7bbd2068439351994c286614190b26ecbc1cc27f6f2e76c7d2325f5b",
"value": "0.0"
}
],
"timestamp": "2023-09-06T16:04:36",
"to_address": {
"address": "0x3e5c63644e683549055b9be8653de26e0b4cd36e",
"badge": null,
"name": "GnosisSafeL2"
},
"tx_hash": "0xd028241a7bbd2068439351994c286614190b26ecbc1cc27f6f2e76c7d2325f5b",
"value": "0.0"
}
],
"timestamp": "2023-09-06T16:04:36",
"to_address": {
"address": "0x7161be2924b4710d3754be067e01b0cd4544c695",
"badge": "receiver",
"name": "GnosisSafeProxy"
},
"tx_hash": "0xd028241a7bbd2068439351994c286614190b26ecbc1cc27f6f2e76c7d2325f5b",
"value": "0.0"
},
"events": [
{
"call_id": null,
"chain_id": "goerli",
"contract": {
"address": "0x7161be2924b4710d3754be067e01b0cd4544c695",
"badge": "receiver",
"name": "GnosisSafeProxy"
},
"event_guessed": false,
"event_name": "SafeMultiSigTransaction",
"event_signature": "0x66753cd2356569ee081232e3be8909b950e0a76c1f8460c3a5e3c2be32b11bed",
"index": "81",
"parameters": [
{
"name": "to",
"type": "address",
"value": {
"address": "0xaaaa826d36d58a9b0e1055a75dce79ae99751c18",
"badge": null,
"name": "OmniseaBaseToken"
}
},
{
"name": "value",
"type": "uint256",
"value": "0"
},
{
"name": "data",
"type": "bytes",
"value": "0xa9059cbb00000000000000000000000000b97496700288c1bceb90ecc0...800000"
},
{
"name": "operation",
"type": "uint8",
"value": "0"
},
{
"name": "safeTxGas",
"type": "uint256",
"value": "0"
},
{
"name": "baseGas",
"type": "uint256",
"value": "0"
},
{
"name": "gasPrice",
"type": "uint256",
"value": "0"
},
{
"name": "gasToken",
"type": "address",
"value": {
"address": "0x0000000000000000000000000000000000000000",
"badge": null,
"name": "0x0000000000000000000000000000000000000000"
}
},
{
"name": "refundReceiver",
"type": "address",
"value": {
"address": "0x0000000000000000000000000000000000000000",
"badge": null,
"name": "0x0000000000000000000000000000000000000000"
}
},
{
"name": "signatures",
"type": "bytes",
"value": "0x3fe2737edc8e26ab9aa25ae3f03b783032f140d87d382ca4b1400d8994...000001"
},
{
"name": "additionalInfo",
"type": "bytes",
"value": "0x0000000000000000000000000000000000000000000000000000000000...000002"
}
],
"timestamp": "2023-09-06T16:04:36",
"tx_hash": "0xd028241a7bbd2068439351994c286614190b26ecbc1cc27f6f2e76c7d2325f5b"
},
{
"call_id": null,
"chain_id": "goerli",
"contract": {
"address": "0xaaaa826d36d58a9b0e1055a75dce79ae99751c18",
"badge": null,
"name": "OmniseaBaseToken"
},
"event_guessed": false,
"event_name": "Transfer",
"event_signature": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
"index": "82",
"parameters": [
{
"name": "from",
"type": "address",
"value": {
"address": "0x7161be2924b4710d3754be067e01b0cd4544c695",
"badge": "receiver",
"name": "GnosisSafeProxy"
}
},
{
"name": "to",
"type": "address",
"value": {
"address": "0x00b97496700288c1bceb90ecc04a40c4aeac8bb4",
"badge": null,
"name": "0x00b97496700288c1bceb90ecc04a40c4aeac8bb4"
}
},
{
"name": "value",
"type": "uint256",
"value": "100000"
}
],
"timestamp": "2023-09-06T16:04:36",
"tx_hash": "0xd028241a7bbd2068439351994c286614190b26ecbc1cc27f6f2e76c7d2325f5b"
},
{
"call_id": null,
"chain_id": "goerli",
"contract": {
"address": "0x7161be2924b4710d3754be067e01b0cd4544c695",
"badge": "receiver",
"name": "GnosisSafeProxy"
},
"event_guessed": false,
"event_name": "ExecutionSuccess",
"event_signature": "0x442e715f626346e8c54381002da614f62bee8d27386535b2521ec8540898556e",
"index": "83",
"parameters": [
{
"name": "txHash",
"type": "bytes32",
"value": "0x2f1aa87e0b2fc0d0f8b6b33ec3718da2b110d59197ceb66e3c74c338b169a6e2"
},
{
"name": "payment",
"type": "uint256",
"value": "0"
}
],
"timestamp": "2023-09-06T16:04:36",
"tx_hash": "0xd028241a7bbd2068439351994c286614190b26ecbc1cc27f6f2e76c7d2325f5b"
}
],
"metadata": {
"block_hash": "0xc52f44b85b399d3341181864f85ebbcbf92f6081f74ded078dbbfd8d8b388b03",
"block_number": "9647726",
"chain_id": "goerli",
"from_address": null,
"gas_limit": "96325",
"gas_price": "1",
"gas_used": "90538",
"receiver": {
"address": "0x7161be2924b4710d3754be067e01b0cd4544c695",
"badge": "receiver",
"name": "GnosisSafeProxy"
},
"sender": {
"address": "0xf285e70ca2002b796a575e473285282bbf39d790",
"badge": "sender",
"name": "0xf285e70ca2002b796a575e473285282bbf39d790"
},
"success": true,
"timestamp": "2023-09-06 16:04:36",
"to_address": null,
"tx_hash": "0xd028241a7bbd2068439351994c286614190b26ecbc1cc27f6f2e76c7d2325f5b",
"tx_index": "21",
"tx_value": "0"
},
"status": true,
"transfers": [
{
"from_address": {
"address": "0x7161be2924b4710d3754be067e01b0cd4544c695",
"badge": "receiver",
"name": "GnosisSafeProxy"
},
"to_address": {
"address": "0x00b97496700288c1bceb90ecc04a40c4aeac8bb4",
"badge": null,
"name": "0x00b97496700288c1bceb90ecc04a40c4aeac8bb4"
},
"token_address": "0xaaaa826d36d58a9b0e1055a75dce79ae99751c18",
"token_standard": "ERC20",
"token_symbol": "OmniseaBaseToken",
"value": "100000"
}
]
}
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
palmera-ethtx-1.0.8.tar.gz
(71.3 kB
view details)
Built Distribution
palmera_ethtx-1.0.8-py3-none-any.whl
(121.9 kB
view details)
File details
Details for the file palmera-ethtx-1.0.8.tar.gz
.
File metadata
- Download URL: palmera-ethtx-1.0.8.tar.gz
- Upload date:
- Size: 71.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/4.0.2 CPython/3.10.1
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 0b92cf23f8bef266d02e158b1f7202bd0dba0d76758be0904017fac262b18b81 |
|
MD5 | e07f187732c5159fa6e36ebc1d184819 |
|
BLAKE2b-256 | 88f56a49758cb719345e23b853f1565b80b6856086c40030188c8e89f6da5bb4 |
File details
Details for the file palmera_ethtx-1.0.8-py3-none-any.whl
.
File metadata
- Download URL: palmera_ethtx-1.0.8-py3-none-any.whl
- Upload date:
- Size: 121.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/4.0.2 CPython/3.10.1
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 756fd6dc7fede4a2d31649e897d7499fb96812e49716315e3d5b437c7463be29 |
|
MD5 | e5adae4d0226746fc4375407b371e630 |
|
BLAKE2b-256 | d34cedd8c3d757e2a460bce08d0f287ff3f434bf6f724b3929b85cd93fb2d1b8 |