Skip to content

feat: add POST /v1/transaction/parse endpoint#321

Merged
TarikGul merged 9 commits into
mainfrom
tg-parse-tx
Apr 17, 2026
Merged

feat: add POST /v1/transaction/parse endpoint#321
TarikGul merged 9 commits into
mainfrom
tg-parse-tx

Conversation

@TarikGul
Copy link
Copy Markdown
Member

@TarikGul TarikGul commented Apr 15, 2026

Summary

Add a new endpoint to decode raw transactions (extrinsics) and return all their components without executing or submitting them.

Changes

  • Add POST /v1/transaction/parse endpoint
  • Add POST /v1/rc/transaction/parse relay chain variant (parachains only)

Request

{
  "tx": "0x..."
}

Response

Returns decoded extrinsic information:
- isSigned - whether the extrinsic is signed
- method - pallet and method names (lowerCamelCase)
- args - decoded call arguments
- signature - signer address and signature (signed only)
- nonce - account nonce (signed only)
- tip - tip amount (signed only)
- era - era/mortality information
- hash - Blake2-256 hash of the extrinsic

@TarikGul TarikGul requested review from Imod7 and eugypalu April 16, 2026 02:49
Copy link
Copy Markdown
Contributor

@Imod7 Imod7 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing Doc?

  • The docs/designs/TRANSACTION_PARSE.md document is mentioned in the description but I cannot find it.

Testing
I tested out the transaction/parse endpoint by:

  1. Copying the hex of extrinsic 2 of block 14619170 found here http://127.0.0.1:8080/v1/blocks/14619170/extrinsics-raw(while connected to Polkadot Asset Hub)

  2. Then requested

curl -X POST http://127.0.0.1:8080/v1/transaction/parse \
    -H "Content-Type: application/json" \
    -d '{"tx": "0x4d028400661afc2270012ae05911cdb04f57307da28817171d5f7744cc2d5f45d4c23cd60069be4add1ac9f44d94d703a3afc2a42561b31d1bd39a20880f37a26af334084e65b817e897556d37edd99c503d759d2b82463b06322b1cbeec0486562cac3d0c1502000000000a0300144bdc4d541922cbd8a9ec41676c945b9ac8a5403e3ac8a77c0c885457d11a450b5b7aa2ad2c04"}'

which returns

{"isSigned":true,"method":{"pallet":"balances","method":"transferKeepAlive"},"args":{"dest":{"id":"1TcVbQVQvr1axwg1tQk84oun2fuhRTY99zUXs8pAQWm3R9j"},"value":"4589938178651"},"signature":{"signer":{"id":"13JsuE3eET1Ynn17ErALm1KxCmuSU7nEF93nviVpdBQHtXWz"},"signature":"0x69be4add1ac9f44d94d703a3afc2a42561b31d1bd39a20880f37a26af334084e65b817e897556d37edd99c503d759d2b82463b06322b1cbeec0486562cac3d0c"},"nonce":"0","tip":"0","era":{"immortalEra":"0x00"},"hash":"0x25fb86a516a4af81ddb0b699dfcad1862b4b67ddae461bf57ec4fbe76fb0603f"}
  1. And then I compared with what http://127.0.0.1:8080/v1/blocks/14619170/extrinsics/2 returns

  2. All fields look aligned except the era

    • /parse returns "immortalEra":"0x00"
    • extrinsics/2 returns "era": { "mortalEra": ["64", "33"]

Copy link
Copy Markdown
Contributor

@Imod7 Imod7 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Era in transaction/parse

  • Just tested out the erain parse endpoint and it is fixed! Nice Job!

Testing rc/transaction/parse with recent blocks
Tested the rc endpoint in the same way:

  1. Copied extrinsic 2 from http://127.0.0.1:8080/v1/rc/blocks/30837376/extrinsics-raw (chain: PAH and relay: Polkadot)
  2. Gave the extrinsic as input in rc/transaction/parse
curl -X POST http://127.0.0.1:8080/v1/rc/transaction/parse \
    -H "Content-Type: application/json" \
    -d '{"tx": "0x45028400a447dfdd73278cf06c4833333ef0770670326f7d96c57bc53b40defb75b9fe02010a97925f83b0becbfca54682976919162dde4243bdd1aac60301aa9fbe11bc20ab5b08d9e227b3d0d9f06362341330ff03b9627e68146640320bb954d8b04b86a503040000050300b218e10305fd5cd7709ea3efcc61b16ab2b360622d2a212a2686cf4501a8a8750700c817a804"}'
  1. result:
{"isSigned":true,"method":{"pallet":"balances","method":"transferKeepAlive"},"args":{"dest":{"id":"152Wv1w2YUJ25PKma7zUtPidjQtAzc2f2wZFfKZw4PLxZR1M"},"value":"20000000000"},"signature":{"signer":{"id":"14iQCrAUvKCHBorbQ5wpVeKmw2DQ1pY5upFZLMid1aUF9kMf"},"signature":"0x0a97925f83b0becbfca54682976919162dde4243bdd1aac60301aa9fbe11bc20ab5b08d9e227b3d0d9f06362341330ff03b9627e68146640320bb954d8b04b86"},"nonce":"1","tip":"0","era":{"mortalEra":["64","58"]},"hash":"0x4961595f7e5574a7a196c8512c9df84b268abdb1a870e693fa064d99325fc351"}

Testing rc/transaction/parse with old blocks
Now I tested the rc endpoint with an old block:

  1. Copied extrinsic 2 from http://127.0.0.1:8080/v1/rc/blocks/14618110/extrinsics-raw (chain: PAH and relay: Polkadot)
  2. requested rc/transaction/parse for this tx
curl -X POST http://127.0.0.1:8080/v1/rc/transaction/parse \
    -H "Content-Type: application/json" \
    -d '{"tx": "0x51028400f4c0a91ac2ba294bf17294a5711f7835fe9c551c9f837919244921f2337f845b010463fe4df96e826dacdbdac0fa394fd4213b4d9057761156897f0c45a68cd959248845b0dd4500fed1eb27dc53f4aa522fe4932208bb7fdfef47784f58502f83750192d301000005000057cec7da459b32e53651a04d5c1fad02ba7dfbaa631075672ace0aa718fc44860b0054de678201"}'
  1. result:
{"code":400,"error":"Failed to parse transaction.","transaction":"0x51028400f4c0a91ac2ba294bf17294a5711f7835fe9c551c9f837919244921f2337f845b010463fe4df96e826dacdbdac0fa394fd4213b4d9057761156897f0c45a68cd959248845b0dd4500fed1eb27dc53f4aa522fe4932208bb7fdfef47784f58502f83750192d301000005000057cec7da459b32e53651a04d5c1fad02ba7dfbaa631075672ace0aa718fc44860b0054de678201","cause":"Failed to decode extrinsic: CannotDecodeSignature(DecodeErrorTrace { original_error: \"VariantNotFound(5)\", tracing_error: \"\" })","stack":"Error: Failed to decode extrinsic: CannotDecodeSignature(DecodeErrorTrace { original_error: \"VariantNotFound(5)\", tracing_error: \"\" })\n    at parse"}

Researched the error with Claude and here is the finding

  • v5 extrinsics (current blocks): work correctly
  • v4 extrinsics (old blocks): fails because parse_rc always uses current metadata

The parse endpoint works correctly when parsing current transactions. The v4 failure only happens with historical extrinsics from before Polkadot's v5 migration. Supporting historical parsing would require fetching metadata at the extrinsic's originating block (an at parameter), which is a separate feature.

@TarikGul
Copy link
Copy Markdown
Member Author

Yea i think this is expected, and was a decision I made conciously. The idea is that we don't know when the transaction is from and what metadata is needed without knowing the exact block. So its a bit of a design decision to just worry about transactions related to the tip of the chain, similar to how the rest of the transaction endpoints just worry about the tip of the chain.

@Imod7
Copy link
Copy Markdown
Contributor

Imod7 commented Apr 17, 2026

Yea i think this is expected, and was a decision I made conciously. The idea is that we don't know when the transaction is from and what metadata is needed without knowing the exact block. So its a bit of a design decision to just worry about transactions related to the tip of the chain, similar to how the rest of the transaction endpoints just worry about the tip of the chain.

Got it! Thank you so much for the clarification! So, from my tests both endpoints work as expected! ✅ Great work!

@TarikGul TarikGul merged commit 960dd4a into main Apr 17, 2026
15 checks passed
@TarikGul TarikGul deleted the tg-parse-tx branch April 17, 2026 14:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants