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
debugoption 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
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
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
|