Skip to content

InternetOfPeers/hedera-proto-explorer

Repository files navigation

Hedera Proto Explorer

IMPORTANT ASSUMPTION: this procedure does not verify the signatures associated to the tx, nor that the downloaded record file and corresponding txs hashes! If you want to query a verified data source, use your own mirror node to download and verify the signatures associated to the record file.

To get all the information you need to configure AWS CLI with your credentials for this tool to work correctly; it downloads files from AWS S3.

Alternatively, you can download the (alpha and deprecated) state proofs from the mirror node, and get the record stream elements from there. Note that if a transaction generates child transactions, this method will only allow you to decode information for the parent transaction. Also keep in mind that state proofs will be removed soon, so don't rely on this script method too much ;)

How to get transactions details via AWS S3 or GCP Storage

Setup

You have two options:

  1. Set HPE_STORAGE_PROVIDER="aws" in the config file and initialize your AWS CLI with your credentials. Those credentials will be billed for the requests.

  2. Set HPE_STORAGE_PROVIDER="gcp" and a billing project ID (HPE_GCP_BILLING_PROJECT_ID) in the config file. Initialize the GCP CLI with your credentials.

Usage

The script support both human-friendly (i.e., 0.0.513587@1714079813.090631706) and mirror node (i.e., 0.0.513587-1714079813-090631706) transaction ID format.

Run the following script:

./examine.sh 0.0.513587-1714079813-090631706

The output will be:

❯ ./examine.sh 0.0.513587-1714079813-090631706
2025-03-05T13:08:08.3NZ-3870 ⚑ Started ./examine.sh (PID 3870) with the following configuration
2025-03-05T13:08:08.3NZ-3870 ⛶ Network ..............................: mainnet
2025-03-05T13:08:08.3NZ-3870 ⛶ Transaction ID .......................: 0.0.513587-1714079813-090631706
2025-03-05T13:08:08.3NZ-3870 ⛶ Records folder .......................: ./records
2025-03-05T13:08:09.3NZ-3870 ⚙ Transactions with the same ID: 1
2025-03-05T13:08:09.3NZ-3870 ☕ Downloading recordstreams/record0.0.3/2024-04-25T21_17_08.000248496Z.rcd.gz
bytes	800018	binary/octet-stream	"a88a4de02cfc283c9bb8f53473d5e875"	2024-04-25T21:17:15+00:00	COMPLETED	requester	AES256	z3SIH.ypHpLh1BLugG6JA3W7DdFcxbMH

=== Transaction #0 ATGcMV0XrYmiI1ZpGmZ5l5IW4wC5XDB1jO5m9qlAmmXyW3ulLW7w5ZPZtsY5XwF+ 01319c315d17ad89a22356691a6679979216e300b95c30758cee66f6a9409a65f25b7ba52d6ef0e593d9b6c6395f017e ===
{
  transaction: {
    signedTransactionBytes: 'ClgKGQoLCMWQq7EGEJrcmysSCAgAEAAYs6wfGAASBggAEAAYAxiAhK9fIgIIeDIAggMnEiUKCQgAEAAY0ciIAhIICAAQABizrB8aCQgAEAAYxaHpASID9vUBEswBCmQKIHcoN6wujR2qXjZWVOxzYBEP6a9i8khL0gIgT2JuXIKyGkDu761b22vDr/chkr5qaR/QqXPIdV2Y08/9S11nlChfAlMXZj0jIWgvFyN25CXzGB4rw+KhwOU8jPpnF3d+pBYACmQKIJUSLeJ3nu+RKNA7rsFMFMNOlg2U59HkwXbTZQS+/kh7GkDgkkcbbok6JZVz6dGgmaXQPTEz66X6EcvKx3BQID+b/BbwSaA6G9114w+olR3jqrIv2gMIAFkH6a+eexzVbCMK'
  },
  record: {
    receipt: {
      status: 'SUCCESS',
      exchangeRate: {
        currentRate: {
          hbarEquiv: 30000,
          centEquiv: 353419,
          expirationTime: { seconds: '1714082400' }
        },
        nextRate: {
          hbarEquiv: 30000,
          centEquiv: 357345,
          expirationTime: { seconds: '1714086000' }
        }
      }
    },
    transactionHash: 'ATGcMV0XrYmiI1ZpGmZ5l5IW4wC5XDB1jO5m9qlAmmXyW3ulLW7w5ZPZtsY5XwF+',
    consensusTimestamp: { seconds: '1714079829', nanos: 44599703 },
    transactionID: {
      transactionValidStart: { seconds: '1714079813', nanos: 90631706 },
      accountID: { accountNum: '513587' }
    },
    transactionFee: '68984744',
    transferList: {
      accountAmounts: [
        { accountID: { accountNum: '3' }, amount: '1765339' },
        { accountID: { accountNum: '98' }, amount: '60497465' },
        { accountID: { accountNum: '800' }, amount: '6721940' },
        { accountID: { accountNum: '513587' }, amount: '-68984744' }
      ]
    }
  }
}

=== Signatures #0 ATGcMV0XrYmiI1ZpGmZ5l5IW4wC5XDB1jO5m9qlAmmXyW3ulLW7w5ZPZtsY5XwF+ 01319c315d17ad89a22356691a6679979216e300b95c30758cee66f6a9409a65f25b7ba52d6ef0e593d9b6c6395f017e ===
{
  pubKeyPrefix: 'dyg3rC6NHapeNlZU7HNgEQ/pr2LySEvSAiBPYm5cgrI=',
  ed25519: '7u+tW9trw6/3IZK+amkf0KlzyHVdmNPP/UtdZ5QoXwJTF2Y9IyFoLxcjduQl8xgeK8PiocDlPIz6Zxd3fqQWAA==',
  pubKeyPrefixHex: '772837ac2e8d1daa5e365654ec7360110fe9af62f2484bd202204f626e5c82b2'
}
{
  pubKeyPrefix: 'lRIt4nee75Eo0DuuwUwUw06WDZTn0eTBdtNlBL7+SHs=',
  ed25519: '4JJHG26JOiWVc+nRoJml0D0xM+ul+hHLysdwUCA/m/wW8EmgOhvddeMPqJUd46qyL9oDCABZB+mvnnsc1WwjCg==',
  pubKeyPrefixHex: '95122de2779eef9128d03baec14c14c34e960d94e7d1e4c176d36504befe487b'
}

=== Body #0 ATGcMV0XrYmiI1ZpGmZ5l5IW4wC5XDB1jO5m9qlAmmXyW3ulLW7w5ZPZtsY5XwF+ 01319c315d17ad89a22356691a6679979216e300b95c30758cee66f6a9409a65f25b7ba52d6ef0e593d9b6c6395f017e ===
{
  transactionID: {
    transactionValidStart: { seconds: '1714079813', nanos: 90631706 },
    accountID: { shardNum: '0', realmNum: '0', accountNum: '513587' },
    scheduled: false
  },
  nodeAccountID: { shardNum: '0', realmNum: '0', accountNum: '3' },
  transactionFee: '200000000',
  transactionValidDuration: { seconds: '120' },
  memo: '',
  cryptoApproveAllowance: {
    nftAllowances: [
      {
        tokenId: { shardNum: '0', realmNum: '0', tokenNum: '4334673' },
        owner: { shardNum: '0', realmNum: '0', accountNum: '513587' },
        spender: { shardNum: '0', realmNum: '0', accountNum: '3821765' },
        serialNumbers: [ '31478' ]
      }
    ]
  }
}

2025-03-05T13:08:16.3NZ-3870 ✔ Transactions details in ./logs/0.0.513587-1714079813-090631706.txt
2025-03-05T13:08:16.3NZ-3870 🏁 Script ./examine.sh (PID 3870) ended

The output will be also saved in the default logs folder.

By default the script does not download the record file if it is already present. Override this behaviour with the overwrite-if-present parameter.

./examine.sh 0.0.513587-1714079813-090631706 overwrite-if-present

You can also use a testnet parameter to switch network, like this:

./examine.sh 0.0.513587-1714079813-090631706 testnet

If you want to change the default values, edit the config file.

How to get transactions details via Mirror Node's state proofs

The script support both human-friendly (i.e., 0.0.513587@1714079813.090631706) and mirror node (i.e., 0.0.513587-1714079813-090631706) transaction ID format.

Run the following script:

node proto-decode-transaction-via-mirror-node 0.0.513587@1714079813.090631706

The output will be:

Processing transaction: 0.0.513587-1714079813-090631706
Using mainnet mirror node
=== Record information ===
{
  receipt: {
    status: 'SUCCESS',
    exchangeRate: {
      currentRate: {
        hbarEquiv: 30000,
        centEquiv: 353419,
        expirationTime: { seconds: '1714082400' }
      },
      nextRate: {
        hbarEquiv: 30000,
        centEquiv: 357345,
        expirationTime: { seconds: '1714086000' }
      }
    }
  },
  transactionHash: 'ATGcMV0XrYmiI1ZpGmZ5l5IW4wC5XDB1jO5m9qlAmmXyW3ulLW7w5ZPZtsY5XwF+',
  consensusTimestamp: { seconds: '1714079829', nanos: 44599703 },
  transactionID: {
    transactionValidStart: { seconds: '1714079813', nanos: 90631706 },
    accountID: { accountNum: '513587' }
  },
  transactionFee: '68984744',
  transferList: {
    accountAmounts: [
      { accountID: { accountNum: '3' }, amount: '1765339' },
      { accountID: { accountNum: '98' }, amount: '60497465' },
      { accountID: { accountNum: '800' }, amount: '6721940' },
      { accountID: { accountNum: '513587' }, amount: '-68984744' }
    ]
  }
}
=== Transaction raw information ===
{
  signedTransactionBytes: 'ClgKGQoLCMWQq7EGEJrcmysSCAgAEAAYs6wfGAASBggAEAAYAxiAhK9fIgIIeDIAggMnEiUKCQgAEAAY0ciIAhIICAAQABizrB8aCQgAEAAYxaHpASID9vUBEswBCmQKIHcoN6wujR2qXjZWVOxzYBEP6a9i8khL0gIgT2JuXIKyGkDu761b22vDr/chkr5qaR/QqXPIdV2Y08/9S11nlChfAlMXZj0jIWgvFyN25CXzGB4rw+KhwOU8jPpnF3d+pBYACmQKIJUSLeJ3nu+RKNA7rsFMFMNOlg2U59HkwXbTZQS+/kh7GkDgkkcbbok6JZVz6dGgmaXQPTEz66X6EcvKx3BQID+b/BbwSaA6G9114w+olR3jqrIv2gMIAFkH6a+eexzVbCMK'
}

=== Signatures ===
{
  pubKeyPrefix: 'dyg3rC6NHapeNlZU7HNgEQ/pr2LySEvSAiBPYm5cgrI=',
  ed25519: '7u+tW9trw6/3IZK+amkf0KlzyHVdmNPP/UtdZ5QoXwJTF2Y9IyFoLxcjduQl8xgeK8PiocDlPIz6Zxd3fqQWAA==',
  pubKeyPrefixHex: '772837ac2e8d1daa5e365654ec7360110fe9af62f2484bd202204f626e5c82b2'
}
{
  pubKeyPrefix: 'lRIt4nee75Eo0DuuwUwUw06WDZTn0eTBdtNlBL7+SHs=',
  ed25519: '4JJHG26JOiWVc+nRoJml0D0xM+ul+hHLysdwUCA/m/wW8EmgOhvddeMPqJUd46qyL9oDCABZB+mvnnsc1WwjCg==',
  pubKeyPrefixHex: '95122de2779eef9128d03baec14c14c34e960d94e7d1e4c176d36504befe487b'
}

=== Body ===
{
  transactionID: {
    transactionValidStart: { seconds: '1714079813', nanos: 90631706 },
    accountID: { shardNum: '0', realmNum: '0', accountNum: '513587' },
    scheduled: false
  },
  nodeAccountID: { shardNum: '0', realmNum: '0', accountNum: '3' },
  transactionFee: '200000000',
  transactionValidDuration: { seconds: '120' },
  memo: '',
  cryptoApproveAllowance: {
    nftAllowances: [
      {
        tokenId: { shardNum: '0', realmNum: '0', tokenNum: '4334673' },
        owner: { shardNum: '0', realmNum: '0', accountNum: '513587' },
        spender: { shardNum: '0', realmNum: '0', accountNum: '3821765' },
        serialNumbers: [ '31478' ]
      }
    ]
  }
}

You can add the testnet parameter to execute the analysis on the testnet.

How to get scheduled transactions details via Mirror Node's APIs

Run the following script:

node proto-decode-schedule-via-mirror-node.js 0.0.226412

The output will be:

Processing scheduleID: 0.0.226412
Using mainnet mirror node
=== Transaction details ===
{
  transactionFee: '100000000',
  memo: 'Shocked, I tell you!',
  cryptoTransfer: {
    transfers: {
      accountAmounts: [
        { accountID: { accountNum: '98' }, amount: '1' },
        { accountID: { accountNum: '950' }, amount: '-1' }
      ]
    }
  }
}

You can add the testnet parameter to execute the analysis on the testnet.

Please consider scheduled transactions expire, so don't be surprised if the example above does not work with the mentioned scheduleID. You can retrieve a list of current active schedules via Mirror Node's APIs, like this:

❯ curl --silent https://mainnet.mirrornode.hedera.com/api/v1/schedules | jq
{
  "schedules": [
    {
      "admin_key": null,
      "deleted": false,
      "consensus_timestamp": "1620327749.254652999",
      "creator_account_id": "0.0.950",
      "executed_timestamp": "1620327749.254653000",
      "expiration_time": null,
      "memo": "",
      "payer_account_id": "0.0.950",
      "schedule_id": "0.0.226412",
      "signatures": [
        {
          "consensus_timestamp": "1620327749.254652999",
          "public_key_prefix": "Qg==",
          "signature": "SUZHg7uixmb5MjubWNSs4H1FRQdgHwgj9KEe0XWQD4yvD9W+AAQkZBy+FdOnYbz/bfTT3op++Opg\nfGKKRqYKAg==",
          "type": "ED25519"
        }
      ],
      "transaction_body": "CIDC1y8SFFNob2NrZWQsIEkgdGVsbCB5b3UhShMKEQoGCgIYYhACCgcKAxi2BxAB",
      "wait_for_expiry": false
    },
    ...
}

How to manually get transactions details

  1. First you want the tx hash

    curl -s https://mainnet-public.mirrornode.hedera.com/api/v1/transactions/0.0.513587-1714079813-090631706 | jq '.transactions[] | { consensus_timestamp, transaction_hash}'

    The output will be:

    {
      "consensus_timestamp": "1714079829.044599703",
      "transaction_hash": "ATGcMV0XrYmiI1ZpGmZ5l5IW4wC5XDB1jO5m9qlAmmXyW3ulLW7w5ZPZtsY5XwF+"
    }
  2. Then, you want the record file containing that tx

    curl -s "https://mainnet-public.mirrornode.hedera.com/api/v1/blocks?limit=1&order=asc&timestamp=gte:1714079829.044599703" | jq -r ".blocks[].name"

    The output will be:

    2024-04-25T21_17_08.000248496Z.rcd.gz
    
  3. Then you download the record file. Note: if 0.0.3 does not have that file, try 0.0.4, 0.0.5, and so on.

    mkdir records
    aws s3 cp --request-payer requester s3://hedera-mainnet-streams/recordstreams/record0.0.3/2024-04-25T21_17_08.000248496Z.rcd.gz ./records
  4. Ungzip the record file

    gzip -d ./records/2024-04-25T21_17_08.000248496Z.rcd.gz 
  5. Decode the record file and show tx's detail (--record parameter accepts also a path)

    node proto-decode-transaction.js --record=./records/2024-04-25T21_17_08.000248496Z.rcd --txhash=ATGcMV0XrYmiI1ZpGmZ5l5IW4wC5XDB1jO5m9qlAmmXyW3ulLW7w5ZPZtsY5XwF+

    The output will be:

    === Transaction #0 ATGcMV0XrYmiI1ZpGmZ5l5IW4wC5XDB1jO5m9qlAmmXyW3ulLW7w5ZPZtsY5XwF+ ===
    {
      transaction: {
        signedTransactionBytes: 'ClgKGQoLCMWQq7EGEJrcmysSCAgAEAAYs6wfGAASBggAEAAYAxiAhK9fIgIIeDIAggMnEiUKCQgAEAAY0ciIAhIICAAQABizrB8aCQgAEAAYxaHpASID9vUBEswBCmQKIHcoN6wujR2qXjZWVOxzYBEP6a9i8khL0gIgT2JuXIKyGkDu761b22vDr/chkr5qaR/QqXPIdV2Y08/9S11nlChfAlMXZj0jIWgvFyN25CXzGB4rw+KhwOU8jPpnF3d+pBYACmQKIJUSLeJ3nu+RKNA7rsFMFMNOlg2U59HkwXbTZQS+/kh7GkDgkkcbbok6JZVz6dGgmaXQPTEz66X6EcvKx3BQID+b/BbwSaA6G9114w+olR3jqrIv2gMIAFkH6a+eexzVbCMK'
      },
      record: {
        receipt: {
          status: 'SUCCESS',
          exchangeRate: {
            currentRate: {
              hbarEquiv: 30000,
              centEquiv: 353419,
              expirationTime: { seconds: '1714082400' }
            },
            nextRate: {
              hbarEquiv: 30000,
              centEquiv: 357345,
              expirationTime: { seconds: '1714086000' }
            }
          }
        },
        transactionHash: 'ATGcMV0XrYmiI1ZpGmZ5l5IW4wC5XDB1jO5m9qlAmmXyW3ulLW7w5ZPZtsY5XwF+',
        consensusTimestamp: { seconds: '1714079829', nanos: 44599703 },
        transactionID: {
          transactionValidStart: { seconds: '1714079813', nanos: 90631706 },
          accountID: { accountNum: '513587' }
        },
        transactionFee: '68984744',
        transferList: {
          accountAmounts: [
            { accountID: { accountNum: '3' }, amount: '1765339' },
            { accountID: { accountNum: '98' }, amount: '60497465' },
            { accountID: { accountNum: '800' }, amount: '6721940' },
            { accountID: { accountNum: '513587' }, amount: '-68984744' }
          ]
        }
      }
    }
    
    === Signatures #0 ATGcMV0XrYmiI1ZpGmZ5l5IW4wC5XDB1jO5m9qlAmmXyW3ulLW7w5ZPZtsY5XwF+ ===
    {
      pubKeyPrefix: 'dyg3rC6NHapeNlZU7HNgEQ/pr2LySEvSAiBPYm5cgrI=',
      ed25519: '7u+tW9trw6/3IZK+amkf0KlzyHVdmNPP/UtdZ5QoXwJTF2Y9IyFoLxcjduQl8xgeK8PiocDlPIz6Zxd3fqQWAA==',
      pubKeyPrefixHex: '772837ac2e8d1daa5e365654ec7360110fe9af62f2484bd202204f626e5c82b2'
    }
    {
      pubKeyPrefix: 'lRIt4nee75Eo0DuuwUwUw06WDZTn0eTBdtNlBL7+SHs=',
      ed25519: '4JJHG26JOiWVc+nRoJml0D0xM+ul+hHLysdwUCA/m/wW8EmgOhvddeMPqJUd46qyL9oDCABZB+mvnnsc1WwjCg==',
      pubKeyPrefixHex: '95122de2779eef9128d03baec14c14c34e960d94e7d1e4c176d36504befe487b'
    }
    
    === Body #0 ATGcMV0XrYmiI1ZpGmZ5l5IW4wC5XDB1jO5m9qlAmmXyW3ulLW7w5ZPZtsY5XwF+ ===
    {
      transactionID: {
        transactionValidStart: { seconds: '1714079813', nanos: 90631706 },
        accountID: { shardNum: '0', realmNum: '0', accountNum: '513587' },
        scheduled: false
      },
      nodeAccountID: { shardNum: '0', realmNum: '0', accountNum: '3' },
      transactionFee: '200000000',
      transactionValidDuration: { seconds: '120' },
      memo: '',
      cryptoApproveAllowance: {
        nftAllowances: [
          {
            tokenId: { shardNum: '0', realmNum: '0', tokenNum: '4334673' },
            owner: { shardNum: '0', realmNum: '0', accountNum: '513587' },
            spender: { shardNum: '0', realmNum: '0', accountNum: '3821765' },
            serialNumbers: [ '31478' ]
          }
        ]
      }
    }
    

Utils

Convert tx hash from base64 (MN API output) to hex (HashScan and MN API input)

echo "pPcK5zG1wfQqqd29LJOtp8HKof/OLSzdMA+rhBVLKmu4Tl0CfwDFLreHkXnAequi" | base64 -d | perl -pe 'BEGIN{$/=\1e6} $_=unpack "H*"'

a4f70ae731b5c1f42aa9ddbd2c93ada7c1caa1ffce2d2cdd300fab84154b2a6bb84e5d027f00c52eb7879179c07aaba2

Query a consensus node about account's balance

❯ grpcurl -import-path ./hedera-protobufs-static/services -proto=crypto_service.proto --plaintext -d '{"cryptogetAccountBalance":{"header":{"responseType":0},"accountID":{"accountNum":2}}}' 34.125.200.96:50211 proto.CryptoService/cryptoGetBalance
{
  "cryptogetAccountBalance": {
    "header": {},
    "accountID": {
      "accountNum": "2"
    },
    "balance": "1662808162851446"
  }
}

About

Explore the details of the Hedera transactions

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published