paritytech / paritytech/polkadot-cli
Tracking: Extrinsic V5 support — metadata negotiation, extension versioning, capability-gated signing
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 10
- Forks
- 2
- Avg merge
- 12h 35m
- Merged PRs (30d)
- 4
Description
Umbrella issue for moving dot onto Extrinsic V5 where the network actually supports it, and for
fixing the metadata-version handling that blocks it.
Full research write-up: https://claude.ai/code/artifact/bd81821b-e454-4e12-9d75-168a3b9fabbe
The short version
We cannot "just move to v5", and v4 is not deprecated. But there is real, valuable work here, and
one live bug worth fixing on its own merits.
- Extrinsic v4 is not deprecated. RFC-124, the actual Extrinsic V5 specification, is still
open and unmerged. Every one of the 20 chains probed advertisesextrinsic.version = [4,5].
No removal timeline exists. - A v5 General transaction has no signature field. Authorization moves into a transaction
extension —pallet-verify-signature, metadata identifierVerifyMultiSignature. If a runtime
doesn't carry it, there is nowhere to put a signature. - Almost no chain carries it. Only people chains do. On Polkadot, Kusama, Westend, Paseo and
every asset hub / bridge hub / coretime / collectives / bulletin, v4 is not a legacy fallback —
it is the only way to sign anything. - So the policy is "v5 when the chain can authorize it, v4 otherwise" — gated on the extension
being present, not onversionscontaining 5. - We already emit v5 where we can.
dot tx --unsignedproduces a real v5 General extrinsic. VerifyMultiSignature: Disabledin the current code is correct, not a bug. Under v4 the
signature lives in the extrinsic's own signature field, so the extension must be inert.
Capability matrix (probed live, 2026-08-13)
| Chain | VerifyMultiSignature? |
Must use |
|---|---|---|
| paseo-people, preview-people, nextv2-people | yes | v5 General |
| polkadot, polkadot-asset-hub, polkadot-people, polkadot-bulletin | no | v4 Signed |
| polkadot bridge-hub / coretime / collectives | no | v4 Signed |
| kusama, kusama-asset-hub | no | v4 Signed |
| westend, westend-asset-hub | no | v4 Signed |
| paseo, paseo-asset-hub, paseo-asset-hub-next | no | v4 Signed |
| preview-relay, preview-asset-hub, preview-bulletin | no | v4 Signed |
Every chain: metadataVersions = [14,15,16], extrinsic.version = [4,5], extension versions {0}.
Proven on chain
Not argued from documentation — implemented and submitted:
| Test | Chain | Result |
|---|---|---|
| v4 signed on a chain that has the extension | preview-people | Finalized, block #171737, ExtrinsicSuccess |
| v5 General, signed | preview-people | Included — nonce 54 -> 55, tx 0xa76ab997aab6c0683a1debb59ee7e765b595656e12e2c5d380e402dba6f4b369 |
| v5 General, signed | nextv2-people | Payment, not BadProof — signature verified, account unfunded |
| v5 General, no signature extension | polkadot-asset-hub | UnknownOrigin (0x01000c) |
A working prototype is embedded in #294.
Work items
- #292 — Negotiate the highest supported metadata version instead of pinning v15
- #293 — Select the transaction-extension version from metadata instead of taking the first key
- #294 — Capability-gated Extrinsic V5 General signing
- #295 —
--extsilently ignores builtin extensions, makingCheckMetadataHashunreachable
Suggested order: #292 -> #293 -> #294. #295 is independent and can go any time.
#292 is worth doing regardless of v5: it fixes a live bug where which metadata version dot
operates on depends on your command history (read commands pin v15, dot tx lets polkadot-api
write v16 into the same cache file with no fingerprint).
Invariants we must not lose
These were expensive to establish. Each has bitten someone already.
CheckMetadataHashmust always be computed from metadata v15, even when we read v16 — the
merkleized hash diverges between the two. Direct ruling from bkchr after it broke signing on
Kusama Asset Hub. See #292.transaction_extensions_by_versionis keyed by extension version, not extrinsic version.
Theframe-metadatadoc comment says "extrinsic" and is wrong. v4 always uses key0. See #293.Metadata_metadata/state_getMetadatareturns v14 forever, by construction. It is a
fallback, never a negotiation target.- Metadata v15 reports the minimum supported extrinsic version, and has no extension-version
map. The day v4 is dropped, v14/v15 become structurally unusable. This is the real deadline. - V5 signer payloads are always blake2_256-hashed, unlike v4's >256-byte rule. The
extension-version byte is part of the payload. The cut is at the last authorization extension. VerifyMultiSignature::Signedis a struct{signature, account}, andDisabled= variant 0,
Signed= variant 1. Encode by name from metadata; subxt declares them in the opposite order.
Ecosystem constraints
- polkadot-api ships no v5 transaction builder — not in
2.2.2(ours), not in3.0.0-rc.5, not
in the newest canary. Every signer hardcodescreateV4Tx; the pjs signer throws "Only extrinsic
v4 is supported". Tracking issue polkadot-api/polkadot-api#760 is open and unstarted; the
maintainer is waiting on RFC-124 to merge. So we write our own signer against
PolkadotSigner.signTx, which returns complete extrinsic bytes that papi broadcasts untouched —
the approach papi's maintainer recommends in that thread. - papi 3.0 does not help. Its
TxCreatorhas atxExtVersionfield but every shipped creator
throws on anything but0. It broke in four of five RCs and has been stalled since 2026-07-29.
Revisit once it is stable and #760 is closed. - subxt defaults to v4 whenever v4 is advertised. Our policy is more aggressive than the
reference client, which is precisely why it must be gated. subxt also does not gate v5 signing,
so it will build signature-less General transactions that die asUnknownOrigin— don't copy it. - truapi is the reference implementation to follow (
rust/crates/truapi-server/src/host_logic/extrinsic.rs,
build_signed_extrinsic_v5). It delegates the implication hash toframe-decodeand signature
semantics to subxt rather than hand-rolling either.
Risk: this exact change already broke production
June 2025 — chains adopting metadata v16 caused polkadot-js to flip to Extrinsic V5. Signing broke
on Westend Asset Hub and Rococo. The default was reverted to v4 within a day
(polkadot-js/apps#11602, reverted by polkadot-js/api#6164: "we've decided to temporarily disable
ExtrinsicV5 and fall back to ExtrinsicV4 as the default until full support is in place").
Our differences must be the capability gate and an opt-in period. Do not flip defaults in the same
change that introduces the v5 code path.
Related existing issues
- #253 — exposing the tx signing payload /
inherited_implicationfor external proofs. This work
directly unblocks it; the v5 implication formula is exactly what it needs. Coordinate so the
payload seam is built once. - #252, #240 — transaction-extension discoverability and display; overlaps #293.
- #251 —
--extcomposability gaps; overlaps #295. - #284 — Ethereum/secp256k1 accounts; relevant to the
Ecdsa/EthMultiSignature variants.
Reproducing the research
Probes were run from a clean worktree off 031c4ba using only deps the repo already has
(polkadot-api/ws, @polkadot-api/substrate-client, @polkadot-api/substrate-bindings,
@polkadot-api/metadata-builders, @noble/hashes, @polkadot-labs/hdkd).
Always use an isolated DOT_HOME (export DOT_HOME=$(mktemp -d)) — never the real one.
Test baseline at time of writing: 1789 pass, 2 fail, both pre-existing network flakiness under
--concurrent (tx.test.ts "pallet-only with json" / "category-only with json"); they pass in
isolation.
References
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
This is an umbrella issue: start by reading work items #292–#295 and the prototype in #294, then inspect rust/crates/truapi-server/src/host_logic/extrinsic.rs and build_signed_extrinsic_v5. Treat metadata negotiation, extension-version selection, capability gating, and builtin extension handling as separate scopes; done requires the relevant subissues to pass without changing v4 defaults.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- api, backend-api-design, cli
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Quiet
- Clarity
- Needs clarification
- Newbie friendliness
- 25/100