CLI tool for decoding Phantasma transactions (Carbon + VM) and hex-encoded event data.
- Decode Carbon transactions (Call, Call_Multi, mint/burn/transfer).
- Decode VM transactions (script disassembly + method calls).
- Decode hex-encoded event data for classic events.
- Decode NFT ROM bytes with dedicated parsers:
- legacy/common VM dictionary ROM format,
- CROWN-specific ROM layout (address + timestamp).
- Convert Carbon
bytes32addresses to Phantasma addresses and back. - JSON or pretty output.
- Optional ABI resolution from files or RPC.
- Node.js with ESM support (Node 18+ recommended).
# install globally (recommended for CLI usage)
npm i -g pha-decode
# or run once via npx
npx pha-decode --help
# local dev install
npm install
npm run buildpha-decode <txHex>
pha-decode tx --hex <txHex> [--carbon-addresses <mode>]
pha-decode tx --hash <txHash> --rpc <url> [--carbon-addresses <mode>]
pha-decode event --hex <eventHex> [--kind <eventKind>]
pha-decode rom --hex <romHex> [--symbol <symbol>] [--token-id <tokenId>] [--rom-format <mode>]
pha-decode address --bytes32 <hex>
pha-decode address --pha <address>pha-decode tx --hex accepts either:
- a full Carbon SignedTxMsg hex (serialized transaction bytes), or
- a raw VM script hex.
It does not accept the carbonTxData field returned by RPC. carbonTxData is
payload-only (no SignedTxMsg header), so the CLI cannot decode it by itself.
If you only have a tx hash or RPC response, use --hash instead:
pha-decode tx --hash <txHash> --rpc <url>Notes:
- For Carbon
Phantasma_Rawtransactions,pha-decodeextracts and decodes the inner VM transaction automatically. Use--vm-detail(and--resolveif you have ABI data) to inspect method calls. - If RPC lacks full VM bytes, the tool falls back to script/payload fields and emits a warning.
--format <json|pretty>Output format (default:pretty).--rpc <url>RPC endpoint for--hash(use JSON-RPC, e.g.https://pharpc1.phantasma.info/rpc).--resolveFetch contracts from RPC and merge ABI for VM call decoding.--abi <path>ABI JSON file or directory (merged with built-ins).--vm-detail <all|calls|ops|none>Control VM output detail (default:all).--carbon-detail <all|call|msg|none>Control Carbon output detail (default:call).--carbon-addresses <bytes32|pha>Carbon address display mode in tx output (default:bytes32).--protocol <number>Protocol version for interop ABI selection (default: latest known).--verboseEnable SDK logging.--kind <eventKind>Event kind hint for hex-encoded (classic) events (event mode only).--symbol <symbol>ROM symbol hint (rom mode only, e.g.CROWN).--token-id <tokenId>ROM token id hint (rom mode only; used for CROWN display name).--rom-format <auto|legacy|crown>Select ROM parser mode (default:auto).--bytes32 <hex>Carbon bytes32 address input (address mode only).--pha <address>Phantasma address input (address mode only).--helpShow help.
Decode a tx hash from RPC:
pha-decode tx --hash 155422A6882C3342933521DDC1A335292BF6448DBD489ED0BE21CFC74AFBA52A \
--rpc https://pharpc1.phantasma.info/rpc \
--format json \
--carbon-addresses pha \
--vm-detail calls \
--carbon-detail callDecode a local tx hex (shorthand):
pha-decode 0xDEADBEEF...Decode hex-encoded event data (classic event):
pha-decode event --hex 0xAABBCC... --kind TokenMintDecode ROM in auto mode (uses CROWN hint to pick the dedicated parser):
pha-decode rom \
--hex 220100F100396A4B73E3ABCD6B9039712944D7DF9E8ABE7211E519A91176E83A28D01B10027965 \
--symbol CROWN \
--token-id 80367770225206466995541877216191568684251978941303868068127874072614271067693 \
--format prettyForce legacy/common ROM parser:
pha-decode rom --hex 0x... --rom-format legacyDecode Carbon bytes32 into a Phantasma address:
pha-decode address --bytes32 f100396a4b73e3abcd6b9039712944d7df9e8abe7211e519a91176e83a28d01bConvert Phantasma address back to Carbon bytes32:
pha-decode address --pha P2KKzrLNZK75f4Vtp4wwWocfgoqywBo3zKBWxBXjLgbxXmLJSON output is stable and machine-friendly:
{
"source": "tx-hash",
"input": "155422A6...",
"rpc": { "url": "https://...", "method": "getTransaction" },
"carbon": { "...": "..." },
"vm": { "...": "..." },
"event": { "...": "..." },
"warnings": [],
"errors": []
}Notes:
- Field
carbon.callis the human-readable call decode (module/method + args). - Field
carbon.msgis the raw payload decode (moduleId/methodId + args hex). - Use
--carbon-detailto show one or both. - Use
--carbon-addresses phato render known Carbon bytes32 address fields as Phantasma addresses. - Event hex decoding applies to classic events; newer structured events do not need hex decoding.
- If
--kindis omitted in event mode, the tool returns raw hex with a warning. - ROM decoding has separate parser paths:
legacyfor common historical VM dictionary ROMs,crownfor CROWN ROMs (Address+UInt32timestamp), which is intentionally not a generic NFT ROM schema.
- Address conversion mode:
--bytes32->--phainfers Carbon kind via chain rule (first 15 bytes == 0=> system, otherwise user),--pha->--bytes32supports user/system addresses; interop addresses are rejected.
When enabled, conversion is applied only to known Carbon address fields:
carbon.gasFromcarbon.witnesses[].addresscarbon.msg.tocarbon.msg.fromcarbon.msg.transferF[].tocarbon.msg.transferF[].fromcarbon.msg.transferN[].tocarbon.msg.transferN[].fromcarbon.msg.mintF[].tocarbon.msg.burnF[].fromcarbon.msg.mintN[].tocarbon.msg.burnN[].fromcarbon.call.args[].valuewhentype=bytes32carbon.call.args[].value[]whentype=bytes32[]carbon.call.args[].value.ownerwhentype=token_info|series_info|nft_importcarbon.call.args[].value.towhentype=stake_import|txmsg_mint_fungiblecarbon.call.args[].value.addresswhentype=name_import|member_importcarbon.call.args[].value.info.ownerwhentype=organization_import|series_importcarbon.call.args[].value.memberImports[].addresswhentype=organization_importcarbon.call.args[].value.imports[].originatorwhentype=series_importcarbon.call.args[].value.imports[].ownerwhentype=series_import- all the same typed mappings for:
carbon.call.sections[].args[]carbon.calls[].args[]carbon.calls[].sections[].args[]
This repo ships a justfile:
justlist commandsjust bbuildjust trun testsjust r <args>rundist/cli/index.jsjust d <args>run in dev mode (tsx)
--resolvedepends ongetContractsRPC output. If the RPC returns an empty set, VM calls remain unresolved.- Unknown methods or argument types fall back to raw hex (no guessing).
- ROM auto mode chooses parser from context (
CROWN=> crown parser), then falls back to the other parser with a warning if the first parser fails.