Skip to content

fix(tips): confirm Product payments without EVM timeout - #237

Merged
knzeng-e merged 2 commits into
devfrom
feat/tip-payment-feedback
Oct 3, 2026
Merged

knzeng-e merged 2 commits into
devfrom
feat/tip-payment-feedback

Conversation

@knzeng-e

@knzeng-e knzeng-e commented Oct 3, 2026

Copy link
Copy Markdown
Owner

Outcome

Tips and gifts now give an explicit finalized success state in the contribution panel, on the originating action, and in a transient global notice. Product CDM contributions no longer spend 90 seconds waiting for an incompatible EVM receipt after the host has already finalized the native extrinsic.

Issue and context

Refs #229.

Local scope: docs/backlog/native-gifts-tips.md.

The contribution write path can return two different kinds of hash:

  • the viem adapter returns an EVM transaction hash;
  • Product CDM returns a native extrinsic hash after waitFor: finalized.

The UI previously sent both hashes to viem.waitForTransactionReceipt. In Product this created a systematic 90-second timeout even when the contribution had succeeded. The raw viem exception then dominated the mobile panel and made a finalized tip look failed.

Architecture and key concepts

RuntimeWritePort now declares a contribution confirmation mode:

  • evm-receipt: verify the EVM receipt, finality and matching contribution event;
  • finalized-event: trust Product only for native extrinsic finalization, then independently read the finalized ContributionReceived event by deterministic contribution ID.
sequenceDiagram
  participant UI as Contribution UI
  participant Host as Product CDM host
  participant Runtime as Artist runtime
  participant Read as Finalized EVM read model

  UI->>Host: musicGiftContribute(intentId, quote, value)
  Host->>Runtime: Revive call
  Runtime-->>Host: finalized native extrinsic hash
  Host-->>UI: finalized-event result
  loop bounded read-model catch-up
    UI->>Read: ContributionReceived(id = contributionId)
  end
  Read-->>UI: EVM receipt + exact shares
  UI-->>UI: Tip sent feedback and dated receipt
Loading

The durable contribution journal remains authoritative for retry behavior. A submitted hash is retained until a matching receipt is found; checking status never submits another contribution.

How it works

  1. The sender reviews the exact amount and recipient distribution as before.
  2. musicGiftContribute is submitted once and the intent reservation is persisted.
  3. Viem waits for and validates the EVM receipt. Product skips that incompatible lookup because its contract call already awaited native finality.
  4. Product polls the finalized indexed event for up to 18 seconds to allow RPC/read-model catch-up.
  5. A matching sender, amount and intent clears the journal and produces a dated success panel, green confirmed action and global notice.
  6. If confirmation remains unavailable, the UI presents a concise recovery message. Raw SDK detail is collapsed, the status action cannot resend, and a native Product hash is not mislabeled as a Blockscout EVM transaction.

Design decisions and tradeoffs

  • The adapter states the hash semantics explicitly instead of detecting Product from an error string or waiting for a known timeout.
  • Finalized-event lookup filters on the indexed contribution ID and reads shares from the same block instead of rescanning the complete contribution history on every attempt.
  • The 10 bounded reads use a two-second interval. This keeps normal Product confirmation responsive while preserving an uncertain journal if the public read endpoint lags longer.
  • The existing viem receipt path remains the primary EVM proof. Its finalized event is only a recovery path when the receipt provider is delayed.
  • Feedback is restrained and persistent enough to be understood: the modal contains the full receipt, the action changes to Tip sent, and the toast survives modal dismissal. No celebratory animation or fabricated social activity was added.

Security, failure, and operations

  • No contribution is considered confirmed without a finalized on-chain ContributionReceived event matching its deterministic ID.
  • Receipt sender and amount are still checked against the persisted reservation before it is cleared.
  • Uncertain submissions remain recoverable and cannot automatically trigger a second payment.
  • Product CDM still requires an explicit VITE_DOTIFY_RUNTIME_ADAPTER=product-cdm build; this PR does not silently enable a new payment rail.
  • No keys, secrets, demo signers or new payment policy are introduced.
  • A real funded Product-host tip is still required after deployment to validate host permission UX and public RPC indexing latency.

Review guide

Suggested order

  1. src/features/runtime/runtimePorts.ts, productCdmRuntimeAdapter.ts, viemRuntimeAdapter.ts: verify each adapter declares the correct hash/finality semantics.
  2. src/features/donations/contributions.ts: inspect the ID-filtered finalized event lookup and bounded confirmation strategy.
  3. src/features/donations/contributionFlow.ts: verify uncertain errors remain persisted and user copy does not expose SDK output by default.
  4. src/components/ArtistDonationButton.tsx and src/styles/contributions.css: review success, recovery, responsive layout and explorer-link behavior.
  5. Unit and Playwright tests: verify Product never enters the EVM receipt wait and uncertain status checks never resend.

Verify carefully

  • Can any Product confirmation path call waitForTransactionReceipt with a native extrinsic hash?
  • Can status recovery submit musicGiftContribute a second time?
  • Can an event with the wrong sender, amount or intent clear the journal?
  • Does the 320 px panel keep technical errors collapsed and all recovery actions reachable?
  • Does room notification still occur only after a verified finalized receipt?

Validation

Evidence What it proves
npm run test:unit -- src/features/donations/contributions.test.ts src/features/donations/contributionFlow.test.ts src/features/runtime/productCdmRuntimeAdapter.test.ts src/features/runtime/runtimeWriterProvider.test.ts 31 tests: adapter routing, native value conversion, no EVM receipt wait for Product, persistence and no-resend recovery.
npm run test:e2e -- e2e/artist-gift.spec.ts 17 Chromium scenarios across 320/390/430/1440 px: success feedback, rooms, pending close/reopen, recovery, rejection and mobile raw-timeout containment.
npm run build TypeScript and ordinary production bundle compile. Existing chunk-size and Browserslist warnings remain.
VITE_DOTIFY_RUNTIME_ADAPTER=product-cdm npm run build:product-devnet:frozen The Product CDM host bundle compiles with the finalized-event strategy. Existing chunk-size and Browserslist warnings remain.
Targeted ESLint, Prettier and git diff --check Changed source and tests satisfy repository static/style checks.
Playwright screenshots at 320, 390, 430 and 1440 px Confirmed feedback is readable; the 320 px recovery panel has no horizontal overflow.

Known limitations and follow-ups

  • No funded transaction was sent during automated validation.
  • Product-host validation should confirm the typical delay between host finalization and the public EVM RPC exposing ContributionReceived.
  • Issue Native gifts, work tips and artist earnings #229 remains open for its broader production activation and runtime validation scope.

Metadata checklist

  • Backlog issue linked with correct 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
  • Confirmed no applicable milestone on issue Native gifts, work tips and artist earnings #229
  • Reviewers requested when ownership is known (none beyond the assignee)
  • Draft/ready state is intentional

@knzeng-e knzeng-e self-assigned this Oct 3, 2026
@knzeng-e
knzeng-e marked this pull request as ready for review October 3, 2026 19:46
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 3, 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-10-03T19:50:37.508945Z 9130ff8 Draft marked ready
ℹ️ 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.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 9130ff8bed

ℹ️ 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".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread web/src/features/donations/contributions.ts Outdated
@knzeng-e
knzeng-e merged commit 2ba6ada into dev Oct 3, 2026
10 checks passed
@knzeng-e
knzeng-e deleted the feat/tip-payment-feedback branch October 3, 2026 21:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

1 participant