Skip to content

fix: terminal papi native signer#81

Merged
TarikGul merged 2 commits into
mainfrom
fix/terminal-papi-native-signer
May 13, 2026
Merged

fix: terminal papi native signer#81
TarikGul merged 2 commits into
mainfrom
fix/terminal-papi-native-signer

Conversation

@decrypto21

Copy link
Copy Markdown
Collaborator

Closes #80 (PJS does not support this signed-extension: AsPgas in dot init).

Swaps getPolkadotSignerFromPjs for PAPI-native getPolkadotSigner in packages/terminal/src/signer.ts. Transaction signing now routes through session.signRaw({ data: { tag: "Payload", value: hex(toSign) } }) - an opaque-bytes wire route that already exists in @novasamatech/host-papp 0.7.7. polkadot-api assembles callData ‖ extras ‖ additionalSigneds for every signed extension declared by the runtime, and the wallet just signs the resulting bytes. Any extension carried by the chain - including ones polkadot-api's PJS adapter doesn't have a built-in mapper for (AsPgas on Paseo Next v2, future runtime extensions) - survives end-to-end.

Root cause

Two stacked limitations on the previous path:

  1. @polkadot-api/pjs-signer hard-throws on any signed extension without a built-in mapper. The mapper table covers eight extensions only (CheckGenesis, CheckNonce, CheckTxVersion, CheckMortality, CheckSpecVersion, ChargeAssetTxPayment, ChargeTransactionPayment, CheckMetadataHash). AsPgas isn't in that list.
  2. host-papp's SigningPayloadRequest codec has fixed slots (era, nonce, tip, assetId, metadataHash, mode, …) and signedExtensions: Vector(str) - names only, no payload bytes. Even if PJS were patched to pass AsPgas through, the wire format itself can't carry the extension's extra and additionalSigned bytes.

The Payload-tag route on session.signRaw is a tagged-bytes channel the upstream @novasamatech/product-sdk already uses for non-bytes-typed raw requests, so the wallet code path is exercised in the field.

Changes

  • packages/terminal/src/signer.ts - replaces PJS-bridged construction with getPolkadotSigner(publicKey, "Sr25519", sign). signBytes is overridden post-construction to keep the Bytes-tag route (so the wallet's <Bytes>...</Bytes> anti-phishing wrap applies exactly once to arbitrary-data signing, not to tx signing).
  • packages/terminal/README.md - updates the Signing section to document the new wire path and the AsPgas fix.

Two tiny helpers (makeTxSignCallback, makeRawBytesSignCallback) replace the previous PJS field-translation glue and are unit-tested directly. Net diff: +150 / −288 lines (refactor reduces the file because the PJS field-translation glue is gone).

What this does not fix (explicit scope)

This PR fixes the terminal/QR-paired flow only (createSessionSigner / createSessionSignerForAccount). The in-host signer path - packages/signer/src/providers/host.ts calling accountsProvider.getProductAccountSigner() from @novasamatech/product-sdk - stays PJS-bridged and will still throw PJS does not support this signed-extension: <name> for arbitrary extensions until two things happen upstream:

  1. paritytech/triangle-js-sdks#168 merges - adds a signerType: 'createTransaction' option to getProductAccountSigner that builds a PAPI-native signer routing through the new host_create_transaction RPC.
  2. We bump @novasamatech/product-sdk to the release containing that change and flip the option in packages/signer/src/providers/host.ts.

The upstream PR is currently OPEN, mergeable, awaiting review. The follow-up here is effectively one line per call site once it ships.

Consumer impact in the meantime: apps using createSessionSigner (CLI/QR-paired) are unblocked by this PR. Apps reaching mobile signing via the in-host host provider still hit the original error on AsPgas-bearing extrinsics. playground-cli uses createSessionSignerForAccount, so dot init is covered.

Validation

  • pnpm check (biome lint + format, 205 files) - clean
  • pnpm build (all packages + examples) - pass
  • pnpm test - 725 tests across 14 packages, 0 failures
    • 13 in packages/terminal/src/signer.ts covering the new wire path and regression guards against the legacy signPayload call
  • pnpm exec tsc --noEmit (terminal package) - clean
  • Bundle size: no change (terminal stays at 4.6 KB gzip)

Test plan

  • pnpm check (biome) — clean
  • pnpm build (all packages + examples) - pass
  • pnpm test — 725/725 across 14 packages
  • Bundle size — no change (terminal: 4.6 KB gzip)
  • Local e2e roundtrip against Paseo Next v2 Asset Hub

@decrypto21 decrypto21 requested a review from TarikGul May 13, 2026 09:24
@github-actions

Copy link
Copy Markdown

📦 Bundle size impact

Comparing 2026-05-13T09:28:22.840Z2026-05-13T09:28:19.722Z

No size changes detected. 🟢

@UtkarshBhardwaj007 UtkarshBhardwaj007 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@TarikGul TarikGul merged commit 374b350 into main May 13, 2026
11 of 12 checks passed
@UtkarshBhardwaj007 UtkarshBhardwaj007 deleted the fix/terminal-papi-native-signer branch May 14, 2026 09:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

product-sdk-terminal cannot sign Paseo v2 Revive.map_account because AsPgas is not representable through the PJS signing bridge

3 participants