Skip to content

feat: guard Product CDM signer mapping - #126

Merged
knzeng-e merged 1 commit into
devfrom
agent/product-cdm-write-smoke
Aug 30, 2026
Merged

feat: guard Product CDM signer mapping#126
knzeng-e merged 1 commit into
devfrom
agent/product-cdm-write-smoke

Conversation

@knzeng-e

@knzeng-e knzeng-e commented Aug 29, 2026

Copy link
Copy Markdown
Owner

Outcome

This PR hardens the opt-in Product CDM write path before Dotify attempts real Product-host runtime transactions. A Product CDM write now refuses to submit unless the host-selected signer public key and its derived pallet-revive H160 account match the Product identity that Dotify connected for key/session requests.

Issue and context

Refs #85.

Issue #85 tracks proving Product host compatibility before making Product SDK integrations part of the trusted path. Previous PRs introduced typed runtime read/write ports, an experimental Product CDM/PAPI adapter, Product sr25519 key/session proofs, and typed Classic unlock payment intents. The remaining write risk was identity divergence: a Product host could theoretically expose a signer that is not the same runtime account the UI/backend authenticated for access.

That matters because Classic unlock is a money and entitlement flow. If Product CDM writes eventually submit musicRoyPayAccess, the paid access must be recorded for the same H160 account Dotify uses for protected-key requests. This PR closes that preflight gap without enabling Product writes in the shipped profile.

Local scope document: docs/backlog/polkadot-product-readiness-and-killer-dapp-roadmap.md.

Architecture and key concepts

The write path remains behind RuntimeWritePort:

useCatalog
  -> createRuntimeWriter
  -> viem writer by default
  -> Product CDM writer only when VITE_DOTIFY_RUNTIME_ADAPTER=product-cdm
       -> Product host SignerManager
       -> selected Product public key
       -> derive pallet-revive H160
       -> compare with connected Dotify Product identity
       -> create Product CDM contract resolver
       -> submit runtime tx

pallet-revive maps a 32-byte Product/Substrate-style public key into the H160 account used by the EVM-compatible runtime surface. Dotify already derives that H160 when the user connects with Use Polkadot app. This PR passes that expected H160 into the Product writer setup and checks it before any CDM transaction handle is created.

How it works

useCatalog now passes both productPublicKey and evmAddress for Product-host wallets into createRuntimeWriter.

runtimeWriterProvider now imports Product signer APIs through the public @parity/product-sdk/wallet export, derives H160 through @parity/product-sdk/address, and verifies:

  • the host signer-reported H160, when present, matches the H160 derived from the signer public key;
  • the derived H160 matches the connected Dotify Product identity H160;
  • the selected public key matches the connected Dotify Product identity public key when that public key is available.

Any mismatch destroys the signer manager and fails before createProductCdmContracts can build a transaction-capable resolver.

Design decisions and tradeoffs

The default runtime adapter remains viem. Product CDM writes are still opt-in because Dotify has not yet captured live Product-host evidence for native value forwarding, approval UX, and post-payment access reads.

This PR does not bump Product SDK packages even though npm was rechecked on 2026-08-30 and newer Product SDK packages exist. That is deliberate: dependency migration and signer/account safety are different review surfaces. The SDK 0.25.x line should be tested in a dedicated compatibility PR.

This PR also does not model CASH settlement. CASH remains an unsupported future rail until PCF/Product confirms how People-chain CASH can settle Asset-Hub runtime entitlements with verifiable evidence.

Security, failure, and operations

Product CDM writes now fail closed on identity/account ambiguity. The host cannot silently submit a runtime transaction for an H160 that differs from the Product identity Dotify connected.

No production environment variable changes are required. VITE_DOTIFY_RUNTIME_ADAPTER=product-cdm remains a non-default, explicit smoke/test build setting. The published Product profile should stay on viem until a real Product host transaction smoke proves:

  • host transaction approval is explicit;
  • native pricePlanck value reaches musicRoyPayAccess;
  • musicAccHasPaid and musicAccCanAccess read true after inclusion;
  • the backend releases the protected key only through the same Product identity.

Review guide

Suggested order

  1. web/src/features/runtime/runtimeWriterProvider.ts - review the signer setup, public SDK import path, H160 derivation, mismatch handling, and fail-closed ordering.
  2. web/src/hooks/useCatalog.ts - confirm the Product identity H160 is passed into the writer only for Product-host wallets.
  3. web/src/features/runtime/runtimeWriterProvider.test.ts - verify the happy path, public-key mismatch, H160 mismatch, and signer-reported/derived H160 disagreement.
  4. docs/operations/product-devnet-deployment.md - review the manual Product CDM write smoke checklist and confirm it does not imply the default Product deployment is write-ready.
  5. docs/operations/dependency-security-status.md and Product roadmap docs - confirm the 2026-08-30 SDK drift is represented without mixing dependency upgrades into this PR.

Verify carefully

  • A Product CDM write cannot proceed when the signer H160 differs from the connected Product identity H160.
  • A malformed or internally inconsistent signer account fails before contract resolution.
  • No viem fallback occurs after Product CDM writer setup starts.
  • Product writes remain opt-in and the tracked Product profile still defaults to viem.
  • The docs distinguish implemented mapping guards from the still-missing real host-signed transaction evidence.

Validation

Evidence What it proves
npm run test:unit -- src/features/runtime/runtimeWriterProvider.test.ts src/features/runtime/productCdmRuntimeAdapter.test.ts src/features/payments/paymentModel.test.ts Product writer mapping checks, CDM tx routing, and Classic payment intent behavior pass in focused tests.
npm run test:unit Full web unit suite passes: 41 files / 326 tests.
npm run test:e2e -- classic-unlock.spec.ts The deterministic Classic unlock flow still locks before payment and opens only after payment success.
npm run build Standalone production build compiles with the public Product SDK export paths.
npm run build:product-devnet Product build compiles with the Product-only writer imports. Catalog refresh was skipped in the sandbox because fetch was unavailable; the existing bootstrap snapshot was kept.
npm run lint ESLint passes with the existing 3 React hook dependency warnings in App.tsx / ArtistShell.tsx.
git diff --check No whitespace errors.

Known limitations and follow-ups

This PR does not close #85. Remaining issue scope:

  • run the real Product-host signed transaction smoke from inside the Product container;
  • prove native value forwarding for Classic unlock;
  • prove post-payment musicAccHasPaid / musicAccCanAccess from the same Product H160;
  • test Product SDK 0.25.x in a dedicated compatibility PR;
  • confirm the Product-supported CASH settlement model before exposing CASH conversion, bridge, or receipt UI.

Metadata checklist

  • Backlog issue linked with correct close/reference semantics
  • Local backlog document linked
  • Added to Project 5 (Dotify sprints)
  • Project Priority, Track, Phase, Type, and Backlog doc mirror the issue
  • Workflow status matches draft/review state
  • Assignee set
  • Applicable labels set
  • Applicable milestone set, or confirmed none exists
  • Reviewers requested when ownership is known
  • Draft/ready state is intentional

@knzeng-e knzeng-e added dotify-backlog Tracked by docs/backlog/backlog.json and Project 5 product-sdk Polkadot Product SDK / Host / Playground integration labels Aug 29, 2026
@knzeng-e knzeng-e self-assigned this Aug 29, 2026
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Aug 29, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-08-29T23:04:10.996197Z 652a974 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@knzeng-e knzeng-e moved this from Todo to In Review in Dotify sprints Aug 29, 2026

@knzeng-e knzeng-e left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

reviewed

@knzeng-e
knzeng-e merged commit 6c84de9 into dev Aug 30, 2026
4 checks passed
@github-project-automation github-project-automation Bot moved this from In Review to Done in Dotify sprints Aug 30, 2026
@knzeng-e
knzeng-e deleted the agent/product-cdm-write-smoke branch August 30, 2026 00:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dotify-backlog Tracked by docs/backlog/backlog.json and Project 5 product-sdk Polkadot Product SDK / Host / Playground integration

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

1 participant