Skip to main content

Decoding Transactions

TransactionDecoder turns a Transaction's data field into a typed DecodedTransaction so you can pattern-match on the result instead of re-parsing hex-delimited strings.

It is a pure, stateless, zero-I/O decoder — no network round-trip, no ABI lookup. For full typed return decoding of contract calls, combine it with SmartContractController.

Example

import 'package:abidock_mvx/abidock_mvx.dart';

final decoded = const TransactionDecoder().decode(tx);

switch (decoded) {
case NativeEgldTransfer(:final memo):
print('EGLD memo: ${memo ?? '(none)'}');

case EsdtTransfer(:final tokenIdentifier, :final amount, :final functionCall):
print('$amount of $tokenIdentifier'
'${functionCall == null ? '' : ' → ${functionCall.function}'}');

case NftTransfer(:final collection, :final nonce, :final destination):
print('$collection #$nonce${destination.bech32}');

case MultiTransfer(:final transfers):
print('${transfers.length} tokens bundled');

case ContractCall(:final call):
print('call ${call.function}(${call.arguments.length} args)');

case ContractDeploy(:final bytecode, :final arguments):
print('deploy ${bytecode.length} bytes of code, ${arguments.length} ctor args');

case ContractUpgrade(:final bytecode):
print('upgrade with ${bytecode.length} bytes');

case ContractChangeOwner(:final newOwner):
print('change owner → ${newOwner.bech32}');

case ClaimDeveloperRewards():
print('claim developer rewards');

case UnknownTransaction(:final reason):
print('could not decode: $reason');
}

Shapes recognised

OutcomeInput shape
NativeEgldTransferempty data, or free-form UTF-8 with no @ separators
EsdtTransferESDTTransfer@<tokenHex>@<amountHex>[@<function>@<arg>...]
NftTransferESDTNFTTransfer@<collectionHex>@<nonceHex>@<amountHex>@<destinationHex>[@<function>@<arg>...]
MultiTransferMultiESDTNFTTransfer@<destHex>@<countHex>@(<tokenHex>@<nonceHex>@<amountHex>)+[@<function>@<arg>...]
ContractCallany other <function>@<argHex>... payload
ContractDeploy<codeHex>@<vmTypeHex>@<metadataHex>[@<argHex>...] with receiver == Address.zero()
ContractUpgradeupgradeContract@<codeHex>@<metadataHex>[@<argHex>...]
ContractChangeOwnerChangeOwnerAddress@<newOwnerHex>
ClaimDeveloperRewardsClaimDeveloperRewards (no args)
UnknownTransactioninvalid UTF-8, truncated transfer list, or malformed argument

The decoder never throws — anything it doesn't understand becomes UnknownTransaction with a reason string explaining what failed.

Inner contract calls

Token transfers frequently nest a contract call inside the data field (e.g. "send X WEGLD to router and call swap"). The ESDT/NFT/Multi outcomes all carry an optional functionCall that decodes the inner call when present:

if (decoded case EsdtTransfer(:final functionCall?) ) {
print('Inner call: ${functionCall.function}');
for (final arg in functionCall.arguments) {
print(' arg: 0x${arg.map((b) => b.toRadixString(16).padLeft(2, '0')).join()}');
}
}