paritytech / paritytech/polkadot-cli
Expose tx signing payload / inherited_implication so external proofs & signatures can be composed (--build-only / --show-signing-payload)
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 10
- Forks
- 2
- Avg merge
- 12h 35m
- Merged PRs (30d)
- 4
Description
Summary
Give the CLI a way to obtain the signing payload of the transaction it is about to
build — specifically each custom extension's bound inherited_implication (and/or its
blake2_256) — so an external signer can sign it and the resulting proof/signature be
injected back via --ext.
This is the core capability gap from #251 (pain point #3). It is the one thing that
actually unblocks the value-releasing coinage flows (unload_recycler_into_coin, coin
transfer/split) and all protected-asset transfers; the documentation fixes from #251
only stop people from wrongly concluding --ext is the wall.
The chicken-and-egg problem
For these flows the ring-VRF proofs / ed25519 authorizations don't go in the call args —
they ride in a custom signed extension (AsCoinage::AsUnloadToken{People,LitePeople,Paid},
AuthorizeValueTransfer = Option<ed25519::Signature>). Per the runtime, each binds the
inherited_implication — blake2_256(call ++ trailing-extensions ++ their implicits) —
under a pallet-specific context.
So although:
--extcan already carry theAsUnloadTokenPeoplevalue / the signature, anddot verifiable prove --context … --message … --members …can produce the proof,
…they cannot be composed, because the message that must be signed is the inherited
implication of the very transaction the CLI is assembling — it depends on nonce, mortality/
era, genesis, spec/tx version, and the other extension values. There is no command to emit
that payload, hand it to an external signer, and inject the result back. Submitting without
it fails with System.CallFiltered.
Where it stands in the code
src/commands/tx.ts hands the assembled tx straight to polkadot-api's
signSubmitAndWatch (~:413); there is no intermediate hook that surfaces the per-extension
signing payload. There is a --dry-run path (src/core/dry-run.ts) but it estimates fees /
validates, it does not expose the implication.
This is deliberately Layer 3 of the verifiable-primitives plan, which was scoped out at
the time because polkadot-api lacks first-class support for it and it is sensitive to runtime
upgrades. Filing so the deferral is explicit and tracked, not forgotten.
Possible shapes (one or more)
--show-signing-payload— a dry-run-style mode that prints, per custom extension,
theinherited_implication(and/or itsblake2_256) for the fully-assembled tx, so an
external signer (dot verifiable prove, an ed25519 authorizer) can sign it.- Two-phase build —
dot tx … --build-onlyemits the payload(s) to sign →
dot tx … --attach-ext <signed>re-injects and submits without changing nonce/era
(the hard part: the second invocation must reproduce the exact same tx). - First-class integration — request the origin declaratively (e.g.
--as-coin,
--unload-token …) and have the CLI compute the bound proof internally. Most ergonomic,
most coupling to specific pallets; likely out of scope for the generic CLI.
Hard parts / risks
- polkadot-api must expose (or let us reconstruct) the V5-General inherited implication
before signing. Confirm whatpapisurfaces today; this may need an upstream change or a
careful local reconstruction that tracks runtime metadata. - The two-phase flow must guarantee byte-for-byte tx identity between build and submit
(nonce, era, tip, all extension values pinned) or the signature won't validate. - Keep it generic: the mechanism should work for any extension whose value binds the
implication, not hardcode coinage.
Related: fetching the ring to feed the proof (#251 pain point #4)
A turnkey unload also needs the target recycler's full member set / ring root to build the
proof. This must NOT go into dot verifiable — that command is deliberately raw-crypto-
only (no chain/pallet awareness). Options: document the manual dot <chain>.query … →
dot verifiable prove composition, or add a separate coinage/domain helper outside the
verifiable vertical. Tracking it here as the companion need; it can be split into its own
issue if/when this one is picked up.
Acceptance (for shape 1, the minimum unblock)
- A documented command/flag prints the exact
inherited_implication(and its blake2_256)
for a fully-assembled tx, per custom extension, given the same nonce/era/tip/--ext
values the real submission would use. - That payload, signed via
dot verifiable prove(or an ed25519 signer) and passed back via
--ext, produces a tx that the runtime accepts (noCallFiltered) for the coinage
unload_recycler_into_coinreference flow.
Refs #251.
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
Start in src/commands/tx.ts around the signSubmitAndWatch call and compare the existing path in src/core/dry-run.ts. Investigate what polkadot-api exposes for the V5-General inherited implication and how nonce, era, genesis, versions, tip, and extension values are assembled. Done means a documented payload-output flow can reproduce the exact transaction and the reference unload_recycler_into_coin submission is accepted with the externally supplied signature.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- cli, cryptography
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100