Skip to content

Extract runtime contract ports - #109

Merged
knzeng-e merged 3 commits into
devfrom
feat/product-runtime-ports
Aug 3, 2026
Merged

Extract runtime contract ports#109
knzeng-e merged 3 commits into
devfrom
feat/product-runtime-ports

Conversation

@knzeng-e

@knzeng-e knzeng-e commented Jul 26, 2026

Copy link
Copy Markdown
Owner

Outcome

Extracts Dotify's runtime contract reads and writes behind typed frontend ports. The current viem/EVM behavior is preserved, but the listener and artist hooks no longer need to import contract ABIs directly for catalog reads, access checks, Classic payments, artist runtime bootstrap, track publication, access updates, release activation, or royalty payment history.

This is the next stacked step after the Product DevNet baseline in #108. It prepares the codebase for a Product-native CDM/PAPI adapter without making Product account signing authoritative yet.

Issue and context

Refs #85.

Local scope docs:

  • docs/backlog/polkadot-product-readiness-and-killer-dapp-roadmap.md
  • docs/explanation/product-devnet-architecture.md
  • docs/explanation/architecture-overview.md

The Product DevNet baseline proves that Dotify can run inside a compatible Product host, publish through Bulletin/DotNS, and use an app-scoped Product account as presence identity. The next blocker is contract portability. Today Dotify's authoritative runtime path is viem against Paseo Asset Hub EVM, while Product contract helpers are expected to move through CDM/PAPI and host-mediated signing.

Without a port boundary, adding that adapter would force Product-specific conditionals into useCatalog and useArtistConsole, two hooks that already sit on critical listening and artist-publish paths. This PR keeps the product behavior unchanged and moves the contract boundary into a small typed feature module first.

Architecture and key concepts

The new boundary is intentionally narrow:

flowchart LR
  Catalog[useCatalog] --> ReadPort[RuntimeReadPort]
  Artist[useArtistConsole] --> ReadPort
  Artist --> WritePort[RuntimeWritePort]
  ReadPort --> Viem[ViemRuntimeAdapter]
  WritePort --> Viem
  Viem --> Contracts[Paseo Asset Hub EVM SmartRuntimes]
  Future[Future ProductRuntimeAdapter] -. same ports .-> ReadPort
  Future -. same ports .-> WritePort
Loading

RuntimeReadPort owns contract reads needed by the current UI:

  • directory and runtime discovery;
  • runtime track snapshots and royalty splits;
  • Free/paid access checks;
  • pending artist-runtime bootstrap state;
  • royalty payment event history.

RuntimeWritePort owns the existing write surface:

  • create artist runtime;
  • install runtime bootstrap steps;
  • register track;
  • pay for Classic access;
  • update access policy;
  • deactivate or reactivate a release;
  • wait for a transaction receipt.

createViemRuntimeReader and createViemRuntimeWriter are the only implementations in this PR. Product-native writes remain a follow-up adapter behind the same interfaces.

How it works

In standalone and Netlify/Fly mode, the hooks instantiate the viem adapter with the configured RPC URL and existing wallet client. Catalog loading still enumerates the artist directory and SmartRuntime records when the backend catalog API is not configured. Free access checks still use the zero address for walletless visitors. Classic unlocks still submit musicRoyPayAccess with value through the connected EVM wallet.

In the artist console, runtime bootstrap, track registration, access updates, release activation, and royalty payment history now call the runtime port instead of issuing raw readContract, writeContract, and getLogs calls inline.

Design decisions and tradeoffs

The PR extracts ports before adding the Product adapter. That keeps the risk small: the active runtime behavior is the same, but the next PR can focus on CDM/PAPI mapping instead of untangling UI hooks at the same time.

Alternatives considered:

  • Add Product conditionals directly in the hooks: rejected because it would mix host concerns into high-risk product workflows.
  • Replace viem immediately: rejected because current Dotify contracts, tests, and production deployment still use the EVM runtime path.
  • Move all catalog reads to the backend API only: deferred because direct runtime reads still support local/demo and transaction preflight behavior.

Security, failure, and operations

Security invariants preserved:

  • Product identity is still not treated as an EVM signer.
  • No hidden signer or fallback account is introduced.
  • Protected key delivery remains backend-authoritative.
  • Runtime reads and writes still fail through the existing user-facing error paths.
  • Room guests remain wallet-free and never receive source keys.

Operationally, there are no new environment variables or hosted settings. This PR updates architecture docs because it changes the contract integration boundary, but it does not require Netlify, Fly, or Product DevNet dashboard changes.

Review guide

Suggested order

  1. web/src/features/runtime/runtimePorts.ts - verify the port shape is small enough for both viem and future CDM/PAPI adapters.
  2. web/src/features/runtime/viemRuntimeAdapter.ts - verify each method preserves the previous ABI call, pagination, zero-address handling, royalty split fallback, event log normalization, and receipt waiting behavior.
  3. web/src/hooks/useCatalog.ts - verify catalog discovery, walletless Free access, paid access, and registry refresh behavior did not change.
  4. web/src/hooks/useArtistConsole.ts - verify artist runtime bootstrap, release registration, access edits, activation edits, and royalty history still use the same user-facing states.
  5. Docs under docs/explanation, docs/backlog, and docs/index.html - verify the Product roadmap now says ports are delivered but CDM/PAPI and Product-signed key requests remain future work.

Verify carefully

  • Does the viem adapter preserve the exact SmartRuntime function names and argument order?
  • Can a Product account accidentally reach an EVM write path through these ports?
  • Do zero-address runtime and pending-runtime results still become null before reaching hooks?
  • Does a failed royalty split read skip only that split instead of failing the whole runtime catalog?
  • Does this PR avoid new Netlify/Fly/Product env requirements?

Validation

Evidence What it proves
git diff --cached --check No whitespace errors in the staged runtime-port diff.
cd web && npm run lint ESLint has 0 errors; 3 existing React hook dependency warnings remain in App.tsx and ArtistShell.tsx.
cd web && npm run test:unit -- --run src/features/runtime/viemRuntimeAdapter.test.ts Focused adapter tests cover directory pagination, track snapshots with splits, royalty payment log normalization, write routing, and receipt waiting.
cd web && npm run test:unit 28 frontend test files / 186 tests pass across catalog, access, rooms, Product host, deployment safety, and artist publication guard behavior.
cd web && npm run build The standard standalone production build compiles after the hook refactor.
cd web && npm run build:product-devnet The Product DevNet build compiles against the same ported hooks.
node scripts/backlog-sync.mjs --check --offline Backlog sync passes; existing warnings remain for active item 24 without GitHub mapping and duplicate backlog doc 08.

Known limitations and follow-ups

This PR should remain Refs #85, not Closes #85.

Remaining before #85 can close:

  • add a generated CDM/PAPI Product runtime adapter behind these ports;
  • add backend Product signature-scheme verification and address binding before protected key delivery;
  • prototype Product resource allocation;
  • prototype bounded Statement Store presence;
  • attach real Product host/Desktop/Web smoke evidence after operator deployment.

Metadata checklist

  • Backlog issue linked with correct close/reference semantics: Refs [Product SDK][P1] Prove Product host compatibility before integration #85
  • 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: knzeng-e
  • Applicable labels set: dotify-backlog, product-sdk
  • 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 Jul 26, 2026
@knzeng-e knzeng-e self-assigned this Jul 26, 2026
@knzeng-e knzeng-e moved this from Todo to In Progress in Dotify sprints Jul 26, 2026
@knzeng-e knzeng-e mentioned this pull request Jul 26, 2026
15 tasks
@knzeng-e
knzeng-e changed the base branch from feat/product-devnet-adaptation to dev August 3, 2026 13:33
@knzeng-e
knzeng-e marked this pull request as ready for review August 3, 2026 13:33
@knzeng-e
knzeng-e merged commit dfc6655 into dev Aug 3, 2026
4 checks passed
@github-project-automation github-project-automation Bot moved this from In Progress to Done in Dotify sprints Aug 3, 2026
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