Route Classic payments through the runtime writer port - #120
Draft
knzeng-e wants to merge 1 commit into
Draft
Conversation
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.
Outcome
Classic unlock payments now go through Dotify's
RuntimeWritePortinstead of constructing a viem writer directly inside the catalog hook. This gives the Product/CDM path one controlled write seam while keeping the tracked deployment on the proven viem/passkey/EVM route.Refs #85.
Issue and context
Local scope:
docs/backlog/polkadot-product-readiness-and-killer-dapp-roadmap.md.The current Product payment planning needs Dotify to execute track payments, rights-sensitive runtime writes, and future DOT/CASH settlement through explicit adapters. Before this PR, Classic unlock was the exception:
useCatalogdirectly importedcreateViemRuntimeWriter, fetched an EVM wallet client, and submittedmusicRoyPayAccessitself.That made the Product CDM writer technically present but unreachable from the main listener payment flow. It also kept payment logic tied to one signer implementation, which would make the future CASH settlement work harder to isolate.
Architecture and key concepts
The runtime boundary is now symmetric:
Classic unlock CTA -> useCatalog.payForTrackAccess -> RuntimeWritePort.payForAccess -> viem writer by default OR Product CDM writer when VITE_DOTIFY_RUNTIME_ADAPTER=product-cdmRuntimeWritePortremains the authority boundary for contract writes. The viem adapter still writes through the active passkey/EVM wallet. The Product CDM adapter is lazy and fail-closed: it is only bundled when the build opts in, and it does not contact the Product host during React render.How it works
runtimeWriterProvider.tsselects the write adapter from the same runtime adapter config used by reads. In viem mode, it resolves the current EVM wallet client per write so account/network changes are respected. In Product CDM mode, it initializes the Product contract resolver on first write, verifies the deployment, and routes the transaction through Product contract handles.useCatalogmemoizes both runtime reader and writer, thenpayForTrackAccesssubmits payment throughruntimeWriter.payForAccess. Wallet gating now names the real signer requirement:Design decisions and tradeoffs
The PR deliberately does not add a new env var.
VITE_DOTIFY_RUNTIME_ADAPTERalready selects the runtime contract graph; using it for writes keeps reads and writes on one explicit deployment decision.The PR does not implement CASH payment, DOT/CASH conversion, or Coinage settlement. Current Classic unlock still pays native runtime value into
musicRoyPayAccess. CASH settlement remains a separate design because CASH lives on the Product money rail while the artist runtime lives on Asset Hub.The PR also does not invent a Product signer manager. If Product CDM transaction submission lacks host evidence or signer support, it fails explicitly rather than falling back to viem or a hidden signer.
Security, failure, and operations
The production default remains
viem. Product CDM writes require an explicitVITE_DOTIFY_RUNTIME_ADAPTER=product-cdmbuild and a Product host account. There is no demo signer, no silent fallback, and no wallet bypass.Operational docs were updated because the meaning of
VITE_DOTIFY_RUNTIME_ADAPTERchanged from read-only selection to read/write runtime adapter selection. The tracked Product profile still leaves the flag unset, so this PR does not change the deployed Product payment behavior until an operator intentionally enables CDM mode.Review guide
Suggested order
web/src/features/runtime/runtimeWriterProvider.ts- verify lazy Product setup, viem-per-write wallet resolution, and fail-closed adapter selection.web/src/hooks/useCatalog.ts- verify Classic unlock now callsruntimeWriter.payForAccessand no longer constructs viem directly.web/src/features/runtime/runtimeWriterProvider.test.ts- verify the default viem path, Product non-bundled error, and Product no-fallback routing.web/e2e/classic-unlock.spec.ts- verify the e2e assertion matches the current UI wording.Verify carefully
Validation
npm run test:unit -- runtimeWriterProvider runtimeReaderProvider productCdmRuntimeAdapter viemRuntimeAdapternpm run buildnpm run lintApp.tsxandArtistShell.tsx.npm run test:e2e -- classic-unlock.spec.tsnpm run test:unitnpx prettier --check ...Note: the global
npm run fmt:checkstill fails on pre-existing files outside this PR (productHost,useSession,turn, signaling tests, README). I did not format those to avoid unrelated churn.Known limitations and follow-ups
This is not Product-native CASH settlement. Next work should capture real Product host transaction evidence, then design the CASH receipt/indexer/precompile path before changing value flow.
The markdown docs picked up table alignment from Prettier in touched files. The semantic updates are the Product runtime-write boundary and CASH limitation notes.
Metadata checklist
docs/backlog/polkadot-product-readiness-and-killer-dapp-roadmap.mdDotify sprints)