Skip to content

Comments

feat(pay): redesign payment options #263

Merged
jakubuid merged 2 commits intodevelopfrom
feat/pay-options-redesign
Feb 18, 2026
Merged

feat(pay): redesign payment options #263
jakubuid merged 2 commits intodevelopfrom
feat/pay-options-redesign

Conversation

@jakubuid
Copy link
Collaborator

Summary

  • Replace intro + confirmation screens with a flat card list options screen, "Why info required?" dialog, and post-IC summary screen (Kotlin PR #293 parity)
  • Rewrite PayFlowStep enum: remove intro/confirmation, add options/summary/whyInfoRequired
  • Non-IC payments skip summary and go directly from options to confirming
  • Extract reusable MerchantHeader and TokenIconWithNetwork components
graph LR
    A[Options] -->|IC with URL| B[WebView]
    A -->|IC without URL| C[Name Input]
    A -->|No IC| F[Confirming]
    B --> D[Summary]
    C --> E[Date of Birth]
    E --> D
    D --> F
    F --> G[Success]
    A -.->|side flow| H[Why Info Required?]
    H -.-> A
Loading

Files changed

Action File
CREATE PayOptionsView.swift — flat card list with network badges, IC badges
CREATE PayWhyInfoRequiredView.swift — explanation dialog
CREATE PaySummaryView.swift — post-IC confirmation
MODIFY PayPresenter.swift — new enum + routing logic
MODIFY PayContainerView.swift — switch cases for new steps
DELETE PayIntroView.swift — replaced by PayOptionsView
DELETE PayConfirmView.swift — replaced by PaySummaryView

Test plan

  • Select option without IC → "Pay $X" → confirming → success
  • Select option with WebView IC → "Continue" → WebView → summary → "Pay $X" → success
  • "Why info required?" → explanation → "Got it!" → back to options
  • Switching between options updates button text (Continue vs Pay $X)
  • Back navigation works at every step

Note: Yttrium stays at 0.10.32 — version 0.10.40 has a broken release (Swift bindings reference binary from 0.10.37). Per-option collectData will be adopted when a working Yttrium release is available.

🤖 Generated with Claude Code

…reen

Replace the intro + confirmation screens with a new options card list,
"Why info required?" explanation dialog, and post-IC summary screen.
This aligns the payment flow with the Kotlin SDK (PR #293).

- Replace PayIntroView with PayOptionsView (flat card list with
  per-option network badge overlays and IC badges)
- Replace PayConfirmView with PaySummaryView (shown after IC only)
- Add PayWhyInfoRequiredView explanation dialog
- Rewrite PayFlowStep enum: remove intro/confirmation, add
  options/summary/whyInfoRequired
- Update PayPresenter routing to skip summary for non-IC payments
- Extract reusable MerchantHeader and TokenIconWithNetwork components

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@claude
Copy link

claude bot commented Feb 16, 2026

Claude finished @jakubuid's task in 1m 26s —— View job


Code Review Complete

Reviewed PR #263: Payment flow redesign - Found 2 issues


Issue 1: Potential retain cycle in Task closures capturing self

ID: paypresenter-retain-cycle-task-a8f3
File: Example/WalletApp/PresentationLayer/Wallet/Pay/PayPresenter.swift:111
Severity: MEDIUM
Category: memory_management

Two Task closures at lines 111 and 305 capture self without [weak self] or @MainActor isolation guarantees. While @MainActor annotation on the Task provides main-actor isolation, it doesn't prevent retain cycles if the Task outlives the presenter or if the presenter holds a reference to something that captures the Task.

The PayPresenter is an ObservableObject that may be retained by SwiftUI views, and these Tasks perform async operations that could complete after the view is dismissed, potentially causing memory leaks.

Recommendation: Use [weak self] in Task closures that perform long-running operations:

Task { @MainActor [weak self] in
    guard let self = self else { return }
    // ... rest of implementation
}

Issue 2: Missing error handling for action.walletRpc force access

ID: paypresenter-walletrpc-access-319a
File: Example/WalletApp/PresentationLayer/Wallet/Pay/PayPresenter.swift:319
Severity: HIGH
Category: error_handling

Line 319 accesses action.walletRpc without checking if the action is actually a walletRpc action type. If the actions array contains non-walletRpc action types (e.g., collectData actions), this will crash or behave unexpectedly.

for action in actions {
    let rpcAction = action.walletRpc  // ⚠️ No type check
    let signature = try await ethSigner.signTypedData(AnyCodable(rpcAction.params))
    signatures.append(signature)
}

Exploit Scenario: If the backend returns mixed action types in the actions array, the app will crash when trying to access .walletRpc on a non-RPC action.

Recommendation: Add proper type checking before accessing action fields:

for action in actions {
    switch action {
    case .walletRpc(let rpcAction):
        let signature = try await ethSigner.signTypedData(AnyCodable(rpcAction.params))
        signatures.append(signature)
    default:
        // Handle or skip non-RPC actions
        continue
    }
}

Automated Checks

✅ No external domain URLs detected (only example.com in DEBUG preview code)
✅ No static resource cache-control issues found
✅ No GitHub Actions workflow security issues found


@jakubuid jakubuid changed the title feat(pay): redesign payment options as flat card list feat(pay): redesign payment options Feb 16, 2026
Prevent potential retain cycles in loadPaymentOptions() and
confirmPayment() Task closures that perform long-running async work.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@sonarqubecloud
Copy link

@jakubuid jakubuid merged commit cee0cee into develop Feb 18, 2026
11 of 13 checks passed
@jakubuid jakubuid deleted the feat/pay-options-redesign branch February 18, 2026 07:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant