feat: add wasm-dot package for Polkadot transaction building and decoding#145
Merged
Conversation
481b7ac to
ede6160
Compare
58a71f1 to
751d3e2
Compare
3be05b1 to
fe73139
Compare
…ding WASM-based Polkadot/Substrate transaction builder, parser, and explainer for use by sdk-coin-dot (tdot). Supports transfers, staking operations, proxy management, and batched calls. Key capabilities: - Build unsigned extrinsics from high-level intents (transfer, stake, batch, proxy) - Parse signed/unsigned extrinsics with metadata-aware signed extension decoding - Explain transactions: derive type, extract outputs/inputs, attach DOT-specific metadata - Proxy type resolution from chain metadata (works across Polkadot, Kusama, Westend) - parseTransaction returns DotTransaction with .parse() method (PSBT pattern) BTC-0
fe73139 to
19a7ab6
Compare
OttoAllmendinger
requested changes
Feb 23, 2026
OttoAllmendinger
left a comment
Contributor
There was a problem hiding this comment.
let's try this: I will write a high level CONVENTIONS.md file that contains these re-occurring patterns an we'll see if the agents pick it up
lcovar
added a commit
that referenced
this pull request
Feb 23, 2026
remove hex methods, move parse() to standalone function, use get wasm() changes per otto's review: - remove Transaction.fromHex(), .toHex(), .toBroadcastFormat(), .callDataHex, .signablePayloadHex() - remove _context field and .parse() method from Transaction - rename parseTransactionData → parseTransaction (the actual parser) - rename getInner() → get wasm() (@internal) - remove top-level parseTransaction function (callers use DotTransaction.fromBytes directly) - move createParseContext to parser.ts (single source) - update tests: DotTransaction.fromBytes() for signing, parseTransaction() for decoded data - callers do their own base conversions (Uint8Array only on public API) separation of concerns: - Transaction.fromBytes(bytes) - deserialize for signing - parseTransaction(bytes, context?) - decode into structured data - explainTransaction(bytes, options) - high-level explanation BTC-0
lcovar
added a commit
that referenced
this pull request
Feb 23, 2026
remove hex methods, move parse() to standalone function, use get wasm() changes per otto's review: - remove Transaction.fromHex(), .toHex(), .toBroadcastFormat(), .callDataHex, .signablePayloadHex() - remove _context field and .parse() method from Transaction - rename parseTransactionData → parseTransaction (the actual parser) - rename getInner() → get wasm() (@internal) - remove top-level parseTransaction function (callers use DotTransaction.fromBytes directly) - move createParseContext to parser.ts (single source) - update tests: DotTransaction.fromBytes() for signing, parseTransaction() for decoded data - callers do their own base conversions (Uint8Array only on public API) separation of concerns: - Transaction.fromBytes(bytes) - deserialize for signing - parseTransaction(bytes, context?) - decode into structured data - explainTransaction(bytes, options) - high-level explanation BTC-0
7657d18 to
8ec4843
Compare
OttoAllmendinger
previously approved these changes
Feb 25, 2026
| specVersion: number; | ||
| /** Transaction format version */ | ||
| txVersion: number; | ||
| /** Runtime metadata bytes (hex encoded) - required for encoding calls */ |
Contributor
There was a problem hiding this comment.
seriously consider Uint8Array
Contributor
Author
There was a problem hiding this comment.
hesitating a bit since its a string anyway when we fetch from the node so ill just be doing a back and forth conversion but i understand your hate for strings
Contributor
Author
There was a problem hiding this comment.
Contributor
There was a problem hiding this comment.
well do we end up decoding it anyway or does it stay a string the whole time?
Contributor
Author
There was a problem hiding this comment.
ah it gets decoded to bytes so might as well start out with bytes.
remove hex methods, move parse() to standalone function, use get wasm() changes per otto's review: - remove Transaction.fromHex(), .toHex(), .toBroadcastFormat(), .callDataHex, .signablePayloadHex() - remove _context field and .parse() method from Transaction - rename parseTransactionData → parseTransaction (the actual parser) - rename getInner() → get wasm() (@internal) - remove top-level parseTransaction function (callers use DotTransaction.fromBytes directly) - move createParseContext to parser.ts (single source) - update tests: DotTransaction.fromBytes() for signing, parseTransaction() for decoded data - callers do their own base conversions (Uint8Array only on public API) separation of concerns: - Transaction.fromBytes(bytes) - deserialize for signing - parseTransaction(bytes, context?) - decode into structured data - explainTransaction(bytes, options) - high-level explanation BTC-0
replace magic number parameter with strongly-typed AddressFormat enum. improves type safety and makes the API self-documenting. BTC-3064
c915432 to
b82cd04
Compare
davidkaplanbitgo
approved these changes
Feb 26, 2026
lcovar
added a commit
that referenced
this pull request
Feb 26, 2026
document 7 architectural patterns enforced in code reviews: - prefer Uint8Array, avoid unnecessary base conversions - bigint for monetary amounts (conversions are caller's responsibility) - as const arrays for union types, not magic strings - builders return Transaction objects, not bytes - parsing separate from Transaction (standalone parseTransaction) - use wrapper classes over raw WASM bindings - consistent wrapper API (fromBytes, toBytes, getId, get wasm()) distilled from recurring review comments across wasm-utxo, wasm-solana, and wasm-dot. ref: PR #145 discussion.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
add wasm-dot package for Polkadot/Substrate transaction building, parsing, and signing. follows wasm-utxo conventions:
Uint8Arrayonly, signing separate from parsing,get wasm()for internal access.API
three entry points:
DotTransaction.fromBytes(bytes)— deserialize for signingparseTransaction(bytes, context)— decode into structured dataexplainTransaction(bytes, options)— high-level explanation with type derivationarchitecture
rust handles SCALE binary format (compact integers, MultiAddress, era encoding, recursive batch/proxy calls). typescript handles explain layer — deriving transaction types from pallet+method, extracting outputs/inputs. business logic changes don't require WASM rebuilds.
what's included
builder — build from declarative intents:
transfer,transferAll,stake,unstake,withdrawUnbonded,chilladdProxy,removeProxybatch/batchAllwith nested call encodingBigIntfor amounts (u64 — matches wasm-solana)parser — decode SCALE extrinsics:
utility.batchandproxy.proxy(depth-limited, max 10)explain — structured transaction explanation:
TransactionType: Send, StakingActivate, StakingUnlock, StakingWithdraw, StakingUnvote, StakingClaim, AddressInitialization, Batch, UnknownoutputAmount(sum of non-ALL outputs)conventions followed
Uint8Arrayeverywhere (no hex methods on Transaction)parseTransactionfunction)get wasm()accessor (notgetInner())DotTransaction.fromBytes()for signing (no top-levelparseTransactionthat returns Transaction)test coverage
test plan
cargo test— 28 passingcargo fmt+cargo clippy— cleannpm run build— WASM + TypeScript compilationnpm test— 30 passingnpx prettier --check— cleanTickets