Skip to content

fix: improve ctx error handling - #1419

Merged
HashEngineering merged 10 commits into
masterfrom
fix/ctx-error-handling
Aug 11, 2025
Merged

fix: improve ctx error handling#1419
HashEngineering merged 10 commits into
masterfrom
fix/ctx-error-handling

Conversation

@HashEngineering

@HashEngineering HashEngineering commented Aug 7, 2025

Copy link
Copy Markdown
Collaborator

Issue being fixed or feature implemented

improve error handing when purchasing CTX gift cards.
Handle timeouts, error 500 and others.
Give the user the option to send a report to CTX or DCG depending on the type of error.

Related PR's and Dependencies

Screenshots / Videos

How Has This Been Tested?

  • QA (Mobile Team)

Checklist:

  • I have performed a self-review of my own code and added comments where necessary
  • I have added or updated relevant unit/integration/functional/e2e tests

Summary by CodeRabbit

  • New Features

    • Added a "Contact Support" option in the gift card details dialog, allowing users to report issues via pre-filled email.
    • Enhanced error dialogs for gift card purchases with an option to send detailed error reports by email.
  • Improvements

    • Gift card error messages now provide more detail, including merchant and fiat amount information.
    • Support for tracking the service name associated with Dash payments for improved transaction context.
    • Enhanced error handling for gift card purchases, including better detection and reporting of network propagation issues.
    • Increased network timeout durations for improved connectivity reliability.
  • Bug Fixes

    • Improved handling of fiat currency conversions when purchasing gift cards in non-USD currencies.
    • Authorization headers are now redacted from network logs to improve security.
  • Documentation

    • Added new error message strings for server errors related to gift card purchases.
  • Tests

    • Added tests covering server error handling and exception construction for gift card transactions.

@HashEngineering HashEngineering self-assigned this Aug 7, 2025
@coderabbitai

coderabbitai Bot commented Aug 7, 2025

Copy link
Copy Markdown
Contributor

Walkthrough

This update introduces enhancements to transaction metadata handling, error reporting, and user support in the gift card purchase flow. Key changes include propagating an optional service name through payment APIs, improved exception handling and reporting, UI support for contacting support, and expanded test coverage. Several method signatures and data classes were updated to support these features.

Changes

Cohort / File(s) Change Summary
Transaction Service API & Metadata
common/src/main/java/org/dash/wallet/common/services/SendPaymentService.kt, wallet/src/de/schildbach/wallet/payments/SendCoinsTaskRunner.kt, features/exploredash/src/main/java/org/dash/wallet/features/exploredash/network/service/stubs/FakeDashSpendService.kt, wallet/src/de/schildbach/wallet/di/AppModule.kt
The payWithDashUrl method now accepts an optional serviceName parameter. This context is propagated through the payment flow, with transaction metadata set if provided. The payment runner includes improved error handling to detect network-broadcast transactions after HTTP failures. Dependency injection is updated accordingly.
Gift Card Exception & Data Handling
features/exploredash/src/main/java/org/dash/wallet/features/exploredash/repository/CTXSpendRepository.kt, features/exploredash/src/main/java/org/dash/wallet/features/exploredash/data/ctxspend/model/GiftCardResponse.kt, features/exploredash/src/main/java/org/dash/wallet/features/exploredash/ui/ctxspend/CTXSpendViewModel.kt, features/exploredash/src/main/java/org/dash/wallet/features/exploredash/ui/ctxspend/dialogs/GiftCardDetailsViewModel.kt
GiftCardResponse gains new fields. CTXSpendException now supports a cause of type Throwable and can carry a GiftCardResponse. Exception creation and reporting logic is updated in view models and repositories, with improved error message construction and propagation.
Gift Card Purchase & Support UI
features/exploredash/src/main/java/org/dash/wallet/features/exploredash/ui/ctxspend/dialogs/GiftCardDetailsDialog.kt, features/exploredash/src/main/java/org/dash/wallet/features/exploredash/ui/ctxspend/dialogs/PurchaseGiftCardConfirmDialog.kt, features/exploredash/src/main/java/org/dash/wallet/features/exploredash/ui/ctxspend/PurchaseGiftCardFragment.kt, features/exploredash/src/main/res/layout/dialog_gift_card_details.xml, features/exploredash/src/main/res/values/strings-explore-dash.xml
Adds a "Contact Support" UI in the gift card details dialog, with logic to compose and launch support emails containing error and transaction details. Error dialogs now offer email reporting. The purchase fragment's balance check logic is refactored for clarity. Layout and string resources are updated to support these changes.
HTTP Client & Logging
common/src/main/java/org/dash/wallet/common/util/Constants.kt, features/exploredash/src/main/java/org/dash/wallet/features/exploredash/network/RemoteDataSource.kt
Increases HTTP client timeout values from 15s to 20s and configures logging to redact the "Authorization" header.
Testing
features/exploredash/src/test/java/org/dash/wallet/features/exploredash/CTXSpendExceptionTest.kt
Adds tests for server error handling and exception construction with resource strings and gift card responses.

Sequence Diagram(s)

sequenceDiagram
    participant UI as GiftCardDetailsDialog
    participant VM as CTXSpendViewModel
    participant Email as Email App

    UI->>VM: createEmailIntent(subject, sentToCTX, ex)
    VM->>VM: Compose email with error & transaction details
    VM-->>UI: Return email intent
    UI->>Email: Launch chooser with intent
Loading
sequenceDiagram
    participant Repo as CTXSpendRepository
    participant VM as CTXSpendViewModel
    participant Pay as SendPaymentService/SendCoinsTaskRunner

    VM->>Pay: payWithDashUrl(dashUri, serviceName)
    Pay->>Pay: Process payment, set metadata if serviceName
    Pay-->>VM: Return Transaction or throw Exception
    VM->>Repo: saveGiftCardDummy(txId, giftCardResponse)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~40 minutes

Possibly related PRs

  • fix(dashspend): metadata & barcode #1368: Modifies payWithDashUrl signatures to include serviceName parameter and propagates it through payment processing methods, closely related to the current changes.

Suggested labels

codex

Poem

A bunny hopped through code so bright,
Adding service names to payments' flight.
Now errors send an email plea,
With details for support to see.
Gift cards, logs, and tests all new—
This patch brings help for me and you!
🐇💌

Note

🔌 MCP (Model Context Protocol) integration is now available in Early Access!

Pro users can now connect to remote MCP servers under the Integrations page to get reviews and chat conversations that understand additional development context.


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e9eee97 and 3859827.

📒 Files selected for processing (1)
  • wallet/src/de/schildbach/wallet/payments/SendCoinsTaskRunner.kt (7 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • wallet/src/de/schildbach/wallet/payments/SendCoinsTaskRunner.kt
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build
✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/ctx-error-handling

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai generate unit tests to generate unit tests for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (2)
features/exploredash/src/main/java/org/dash/wallet/features/exploredash/data/ctxspend/model/GiftCardResponse.kt (1)

27-29: Consider consistency in nullable field handling.

The new fields default to empty strings while other nullable fields in the class don't have explicit defaults. Also, these fields lack @SerializedName annotations unlike most other fields.

If these are API response fields, consider adding @SerializedName annotations:

+@SerializedName("cardFiatAmount")
 val cardFiatAmount: String? = "",
+@SerializedName("cardFiatCurrency") 
 val cardFiatCurrency: String? = "",
+@SerializedName("merchantName")
 val merchantName: String? = "",

If they're computed fields, consider defaulting to null for consistency:

-val cardFiatAmount: String? = "",
-val cardFiatCurrency: String? = "",
-val merchantName: String? = "",
+val cardFiatAmount: String? = null,
+val cardFiatCurrency: String? = null,
+val merchantName: String? = null,
wallet/src/de/schildbach/wallet/payments/SendCoinsTaskRunner.kt (1)

272-310: Consider extracting retry delays as a constant and remove empty line.

The error handling logic is well-implemented for recovering from HTTP timeouts. Consider these improvements:

  1. Extract the delays array as a companion object constant for better maintainability
  2. Remove the empty line at line 308
+    companion object {
+        private const val WALLET_EXCEPTION_MESSAGE = "this method can't be used before creating the wallet"
+        private val log = LoggerFactory.getLogger(SendCoinsTaskRunner::class.java)
+        private val NETWORK_CHECK_DELAYS_MS = listOf(0L, 1000L, 3000L, 5000L)
+    }

         } catch (e: Exception) {
             if (e !is DirectPayException) {
                 log.warn("Payment submission failed, but transaction may have been sent: ${sendRequest.tx.txId}", e)
                 val tx = sendRequest.tx
-                val delays = listOf(0L, 1000L, 3000L, 5000L)
-
-                for (delayMs in delays) {
+                for (delayMs in NETWORK_CHECK_DELAYS_MS) {
                     delay(delayMs)
                     if (isTransactionOnNetwork(tx)) {
                         log.info("Transaction found on network despite HTTP timeout: ${tx.txId}")
                         wallet.commitTx(tx)
                         return tx
                     }
                 }

                 log.warn("Transaction not found on network after timeout, treating as failed: ${tx.txId}")
                 // throw exception below
             }
             throw e
         }

-
         return sendCoins(sendRequest, txCompleted = true, checkBalanceConditions = true)
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between cdaa34e and c10f594.

📒 Files selected for processing (16)
  • common/src/main/java/org/dash/wallet/common/services/SendPaymentService.kt (1 hunks)
  • common/src/main/java/org/dash/wallet/common/util/Constants.kt (1 hunks)
  • features/exploredash/src/main/java/org/dash/wallet/features/exploredash/data/ctxspend/model/GiftCardResponse.kt (1 hunks)
  • features/exploredash/src/main/java/org/dash/wallet/features/exploredash/network/RemoteDataSource.kt (1 hunks)
  • features/exploredash/src/main/java/org/dash/wallet/features/exploredash/network/service/stubs/FakeDashSpendService.kt (2 hunks)
  • features/exploredash/src/main/java/org/dash/wallet/features/exploredash/repository/CTXSpendRepository.kt (1 hunks)
  • features/exploredash/src/main/java/org/dash/wallet/features/exploredash/ui/ctxspend/CTXSpendViewModel.kt (7 hunks)
  • features/exploredash/src/main/java/org/dash/wallet/features/exploredash/ui/ctxspend/PurchaseGiftCardFragment.kt (1 hunks)
  • features/exploredash/src/main/java/org/dash/wallet/features/exploredash/ui/ctxspend/dialogs/GiftCardDetailsDialog.kt (6 hunks)
  • features/exploredash/src/main/java/org/dash/wallet/features/exploredash/ui/ctxspend/dialogs/GiftCardDetailsViewModel.kt (2 hunks)
  • features/exploredash/src/main/java/org/dash/wallet/features/exploredash/ui/ctxspend/dialogs/PurchaseGiftCardConfirmDialog.kt (4 hunks)
  • features/exploredash/src/main/res/layout/dialog_gift_card_details.xml (2 hunks)
  • features/exploredash/src/main/res/values/strings-explore-dash.xml (1 hunks)
  • features/exploredash/src/test/java/org/dash/wallet/features/exploredash/CTXSpendExceptionTest.kt (3 hunks)
  • wallet/src/de/schildbach/wallet/di/AppModule.kt (1 hunks)
  • wallet/src/de/schildbach/wallet/payments/SendCoinsTaskRunner.kt (7 hunks)
🧰 Additional context used
🧠 Learnings (9)
📓 Common learnings
Learnt from: HashEngineering
PR: dashpay/dash-wallet#1390
File: features/exploredash/src/main/java/org/dash/wallet/features/exploredash/ui/ctxspend/CTXSpendViewModel.kt:129-145
Timestamp: 2025-05-08T18:11:40.249Z
Learning: The hardcoded test data in the purchaseGiftCard() function of CTXSpendViewModel is intentionally left in place for testing the error handling for limit mismatch, and will be fixed later before release.
Learnt from: HashEngineering
PR: dashpay/dash-wallet#1410
File: wallet/src/de/schildbach/wallet/data/InvitationLinkData.kt:79-84
Timestamp: 2025-07-12T07:12:04.769Z
Learning: HashEngineering prefers to handle defensive validation improvements for URI parsing in follow-up PRs rather than including them in the current PR when the main focus is on replacing Firebase with AppsFlyer.
📚 Learning: 2025-05-08T18:11:40.249Z
Learnt from: HashEngineering
PR: dashpay/dash-wallet#1390
File: features/exploredash/src/main/java/org/dash/wallet/features/exploredash/ui/ctxspend/CTXSpendViewModel.kt:129-145
Timestamp: 2025-05-08T18:11:40.249Z
Learning: The hardcoded test data in the purchaseGiftCard() function of CTXSpendViewModel is intentionally left in place for testing the error handling for limit mismatch, and will be fixed later before release.

Applied to files:

  • features/exploredash/src/main/java/org/dash/wallet/features/exploredash/ui/ctxspend/dialogs/GiftCardDetailsViewModel.kt
  • features/exploredash/src/main/res/values/strings-explore-dash.xml
  • features/exploredash/src/main/java/org/dash/wallet/features/exploredash/repository/CTXSpendRepository.kt
  • features/exploredash/src/main/java/org/dash/wallet/features/exploredash/ui/ctxspend/dialogs/PurchaseGiftCardConfirmDialog.kt
  • features/exploredash/src/main/res/layout/dialog_gift_card_details.xml
  • features/exploredash/src/main/java/org/dash/wallet/features/exploredash/data/ctxspend/model/GiftCardResponse.kt
  • features/exploredash/src/main/java/org/dash/wallet/features/exploredash/ui/ctxspend/dialogs/GiftCardDetailsDialog.kt
  • features/exploredash/src/test/java/org/dash/wallet/features/exploredash/CTXSpendExceptionTest.kt
  • features/exploredash/src/main/java/org/dash/wallet/features/exploredash/ui/ctxspend/PurchaseGiftCardFragment.kt
  • features/exploredash/src/main/java/org/dash/wallet/features/exploredash/ui/ctxspend/CTXSpendViewModel.kt
📚 Learning: 2025-04-19T07:01:17.535Z
Learnt from: HashEngineering
PR: dashpay/dash-wallet#1362
File: wallet/src/de/schildbach/wallet/ui/more/SettingsViewModel.kt:107-115
Timestamp: 2025-04-19T07:01:17.535Z
Learning: In the Dash Wallet app, DashPayConfig methods like isTransactionMetadataInfoShown() already use withContext(Dispatchers.IO) internally, so wrapping these calls with another withContext(Dispatchers.IO) in ViewModels is redundant.

Applied to files:

  • features/exploredash/src/main/java/org/dash/wallet/features/exploredash/ui/ctxspend/dialogs/GiftCardDetailsViewModel.kt
  • features/exploredash/src/main/java/org/dash/wallet/features/exploredash/ui/ctxspend/dialogs/PurchaseGiftCardConfirmDialog.kt
  • common/src/main/java/org/dash/wallet/common/services/SendPaymentService.kt
  • wallet/src/de/schildbach/wallet/di/AppModule.kt
  • features/exploredash/src/main/java/org/dash/wallet/features/exploredash/ui/ctxspend/dialogs/GiftCardDetailsDialog.kt
  • features/exploredash/src/main/java/org/dash/wallet/features/exploredash/network/service/stubs/FakeDashSpendService.kt
  • features/exploredash/src/test/java/org/dash/wallet/features/exploredash/CTXSpendExceptionTest.kt
  • features/exploredash/src/main/java/org/dash/wallet/features/exploredash/ui/ctxspend/PurchaseGiftCardFragment.kt
  • wallet/src/de/schildbach/wallet/payments/SendCoinsTaskRunner.kt
  • features/exploredash/src/main/java/org/dash/wallet/features/exploredash/ui/ctxspend/CTXSpendViewModel.kt
📚 Learning: 2025-05-12T09:15:56.594Z
Learnt from: Syn-McJ
PR: dashpay/dash-wallet#1391
File: integrations/coinbase/src/main/java/org/dash/wallet/integrations/coinbase/ui/convert_currency/ConvertViewFragment.kt:134-155
Timestamp: 2025-05-12T09:15:56.594Z
Learning: The SegmentedPicker composable in Dash Wallet has a safety check for empty options, returning early if options.isEmpty() is true.

Applied to files:

  • features/exploredash/src/main/java/org/dash/wallet/features/exploredash/ui/ctxspend/dialogs/PurchaseGiftCardConfirmDialog.kt
  • features/exploredash/src/main/java/org/dash/wallet/features/exploredash/ui/ctxspend/dialogs/GiftCardDetailsDialog.kt
📚 Learning: 2025-04-19T07:01:17.535Z
Learnt from: HashEngineering
PR: dashpay/dash-wallet#1362
File: wallet/src/de/schildbach/wallet/ui/more/SettingsViewModel.kt:107-115
Timestamp: 2025-04-19T07:01:17.535Z
Learning: In Dash Wallet, DataStore operations (like those in DashPayConfig through BaseConfig) already handle background threading internally. Adding another layer of withContext(Dispatchers.IO) around these calls in ViewModels is redundant because the Jetpack DataStore API automatically dispatches its operations to a background thread.

Applied to files:

  • features/exploredash/src/main/java/org/dash/wallet/features/exploredash/ui/ctxspend/dialogs/PurchaseGiftCardConfirmDialog.kt
  • features/exploredash/src/main/java/org/dash/wallet/features/exploredash/ui/ctxspend/dialogs/GiftCardDetailsDialog.kt
  • features/exploredash/src/main/java/org/dash/wallet/features/exploredash/ui/ctxspend/CTXSpendViewModel.kt
📚 Learning: 2025-05-12T09:14:36.656Z
Learnt from: Syn-McJ
PR: dashpay/dash-wallet#1391
File: wallet/src/de/schildbach/wallet/ui/payments/PaymentsFragment.kt:111-119
Timestamp: 2025-05-12T09:14:36.656Z
Learning: In the dashpay/dash-wallet project, explicitly unregistering ViewPager2 callbacks is not considered critical since memory leaks haven't been observed in practice with the memory profiler.

Applied to files:

  • features/exploredash/src/main/java/org/dash/wallet/features/exploredash/ui/ctxspend/dialogs/PurchaseGiftCardConfirmDialog.kt
📚 Learning: 2025-04-16T17:07:27.359Z
Learnt from: HashEngineering
PR: dashpay/dash-wallet#1377
File: wallet/src/de/schildbach/wallet/service/platform/PlatformService.kt:0-0
Timestamp: 2025-04-16T17:07:27.359Z
Learning: For PlatformService in the Dash Wallet, the implementation should avoid throwing exceptions when Constants.SUPPORTS_PLATFORM is false. The platform should only be initialized when SUPPORTS_PLATFORM is true, and initialization should be done lazily to defer Platform creation until needed.

Applied to files:

  • wallet/src/de/schildbach/wallet/di/AppModule.kt
  • features/exploredash/src/test/java/org/dash/wallet/features/exploredash/CTXSpendExceptionTest.kt
  • wallet/src/de/schildbach/wallet/payments/SendCoinsTaskRunner.kt
  • features/exploredash/src/main/java/org/dash/wallet/features/exploredash/ui/ctxspend/CTXSpendViewModel.kt
📚 Learning: 2025-05-07T14:18:11.161Z
Learnt from: Syn-McJ
PR: dashpay/dash-wallet#1389
File: features/exploredash/src/main/java/org/dash/wallet/features/exploredash/ui/explore/SearchFragment.kt:45-46
Timestamp: 2025-05-07T14:18:11.161Z
Learning: In the ExploreViewModel of the dash-wallet application, `appliedFilters` is a StateFlow (not LiveData), so Flow operators like `distinctUntilChangedBy` can be used with it.

Applied to files:

  • features/exploredash/src/main/java/org/dash/wallet/features/exploredash/ui/ctxspend/PurchaseGiftCardFragment.kt
📚 Learning: 2025-05-06T15:46:59.440Z
Learnt from: Syn-McJ
PR: dashpay/dash-wallet#1386
File: wallet/src/de/schildbach/wallet/ui/send/SendCoinsViewModel.kt:108-0
Timestamp: 2025-05-06T15:46:59.440Z
Learning: In UI code where frequent updates to a value might trigger expensive operations (like the SendCoinsViewModel's `executeDryrun` method), it's preferable to use a Flow with debounce rather than launching a new coroutine for each update. This prevents race conditions, reduces resource usage, and provides a more reactive architecture.

Applied to files:

  • features/exploredash/src/main/java/org/dash/wallet/features/exploredash/ui/ctxspend/PurchaseGiftCardFragment.kt
  • features/exploredash/src/main/java/org/dash/wallet/features/exploredash/ui/ctxspend/CTXSpendViewModel.kt
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build
🔇 Additional comments (42)
common/src/main/java/org/dash/wallet/common/util/Constants.kt (1)

64-66: LGTM! Timeout increase supports better error handling.

Increasing timeouts from 15 to 20 seconds provides more resilience for network operations, which aligns with the PR's goal of improving CTX error handling for timeouts and HTTP 500 errors.

features/exploredash/src/main/java/org/dash/wallet/features/exploredash/network/RemoteDataSource.kt (1)

67-67: Excellent security improvement!

Redacting the Authorization header prevents sensitive tokens from being exposed in logs, which is a security best practice.

features/exploredash/src/main/res/values/strings-explore-dash.xml (1)

232-232: LGTM! String resource supports improved error handling.

The new server error message provides clear guidance to users and aligns with the PR's objective of enhancing error reporting with appropriate support contact options.

features/exploredash/src/main/java/org/dash/wallet/features/exploredash/ui/ctxspend/dialogs/GiftCardDetailsViewModel.kt (2)

167-175: LGTM! Enhanced exception with gift card context.

Including the giftCard response in the exception provides valuable context for error reporting and user support, which aligns with the PR's objective of improving error handling.


183-191: LGTM! Enriched exception data for better error reporting.

Adding the gift card response to the exception enables more detailed error reports when purchases are rejected, supporting the PR's enhanced error handling goals.

common/src/main/java/org/dash/wallet/common/services/SendPaymentService.kt (1)

56-56: LGTM! Interface extension supports transaction metadata.

The addition of the nullable serviceName parameter is well-designed to support associating service metadata with payment transactions while maintaining backward compatibility.

features/exploredash/src/main/res/layout/dialog_gift_card_details.xml (2)

324-326: LGTM! Enhanced error TextView for better UX.

The addition of string resource reference and tools visibility improves the design-time preview while maintaining runtime behavior.


365-396: LGTM! Well-implemented contact support UI.

The new contact support section follows consistent styling patterns with proper constraints and matches the existing UI design. This supports the PR objective of providing users with error reporting options.

features/exploredash/src/main/java/org/dash/wallet/features/exploredash/network/service/stubs/FakeDashSpendService.kt (2)

68-68: LGTM! Proper interface implementation.

The method signature correctly matches the updated SendPaymentService interface with the added serviceName parameter.


77-77: LGTM! Correct parameter forwarding.

The serviceName parameter is properly forwarded to the underlying realService.payWithDashUrl call, maintaining the delegation pattern.

features/exploredash/src/main/java/org/dash/wallet/features/exploredash/ui/ctxspend/PurchaseGiftCardFragment.kt (1)

356-371: LGTM! Improved balance checking with better currency handling.

The refactored method uses early returns for better readability and handles non-USD payment currencies correctly by converting them to USD Fiat instances while preserving the numeric value for accurate balance comparisons.

features/exploredash/src/main/java/org/dash/wallet/features/exploredash/ui/ctxspend/dialogs/PurchaseGiftCardConfirmDialog.kt (5)

132-146: LGTM! Enhanced network error handling with user reporting.

The dialog now provides users with the option to report network errors via email, improving error visibility and support interaction as intended by the PR objectives.


159-170: LGTM! Comprehensive limit error handling with reporting.

The spending limit error dialog correctly sets sentToCTX = true and provides appropriate email subject, enabling users to report CTX-specific issues directly.


171-193: LGTM! Proper HTTP 500 error handling with CTX reporting.

The new server error handling correctly identifies CTX internal server errors and provides appropriate reporting mechanism with sentToCTX = true.


200-215: LGTM! Generic error handling with DCG reporting.

The fallback error handling correctly sets sentToCTX = false for non-CTX specific errors, routing reports to DCG as intended.


232-232: LGTM! Updated method call aligns with signature change.

The call to saveGiftCardDummy now passes the full GiftCardResponse object instead of just the ID, which aligns with the method signature updates mentioned in the AI summary.

features/exploredash/src/test/java/org/dash/wallet/features/exploredash/CTXSpendExceptionTest.kt (3)

19-21: LGTM - New imports support enhanced testing

The new imports correctly support the additional test cases for CTXSpendException constructor overloads.


46-53: LGTM - Server error test validates correct behavior

The serverErrorTest() correctly validates that server errors (HTTP 500) are properly handled:

  • Error code is correctly set to 500
  • isLimitError correctly returns false (500 errors are not limit errors)
  • isNetworkError correctly returns false (500 errors are server errors, not network errors)

71-85: LGTM - ResourceString constructor test validates new functionality

The resourceStringTest() correctly validates the new constructor that accepts a ResourceString and optional GiftCardResponse:

  • Uses proper test data with realistic parameters
  • Correctly verifies that errorCode is null when using ResourceString constructor
  • Properly tests that isLimitError returns false for ResourceString-based exceptions
features/exploredash/src/main/java/org/dash/wallet/features/exploredash/repository/CTXSpendRepository.kt (4)

43-44: LGTM - More general exception handling

Changing the parameter type from Exception to Throwable is appropriate as it allows handling of all throwable types including errors, not just exceptions.


46-46: LGTM - Enhanced exception context

The new giftCardResponse property allows CTXSpendException to carry additional context about the gift card transaction, which supports better error reporting and debugging.


49-52: LGTM - Constructor supports new functionality

The updated secondary constructor properly accepts and assigns the optional GiftCardResponse, enabling richer exception context for error reporting flows.


57-58: Verify unchecked Map parsing in CTXSpendRepository

We confirmed this is the only location using Gson().fromJson(errorBody, Map::class.java) with an unchecked cast:

  • features/exploredash/src/main/java/org/dash/wallet/features/exploredash/repository/CTXSpendRepository.kt (lines 57–58)

Ensure that every error response from the CTX Spend API is always a JSON object matching Map<String, Any>. To improve robustness, consider:

  • Adding unit tests that parse representative error JSON (including nested objects/arrays).
  • Switching back to a TypeToken<Map<String, Any>>() {}-based parse for compile-time safety if structure can vary.
  • Keeping the existing try/fallback (emptyMap()) logic for null or malformed inputs.
wallet/src/de/schildbach/wallet/di/AppModule.kt (1)

115-118: LGTM - Dependency injection properly updated

The addition of TransactionMetadataProvider parameter and its injection into SendCoinsTaskRunner correctly supports the enhanced payment service functionality that can track service names with transactions.

features/exploredash/src/main/java/org/dash/wallet/features/exploredash/ui/ctxspend/dialogs/GiftCardDetailsDialog.kt (5)

25-25: LGTM - Import supports activity result handling

The ActivityResultContracts import is correctly added to support the new email intent launcher functionality.


84-84: LGTM - Additional ViewModel injection

The ctxSpendViewModel is properly injected using viewModels() delegate to support the email intent creation functionality.


98-100: LGTM - Activity result launcher properly configured

The ActivityResultLauncher is correctly registered to handle external email intent launching without requiring specific result handling.


172-176: LGTM - Contact support visibility properly controlled

The visibility logic correctly shows the contact support option only when there's an error, providing users with a way to report issues when they encounter problems.


186-198: LGTM - Contact support implementation is well-structured

The contact support click handler properly:

  • Creates an email intent with descriptive subject including transaction ID
  • Passes the error as CTXSpendException for detailed reporting
  • Uses Intent.createChooser for better user experience
  • Launches through the registered ActivityResultLauncher
features/exploredash/src/main/java/org/dash/wallet/features/exploredash/ui/ctxspend/CTXSpendViewModel.kt (8)

44-44: LGTM - Import supports service name tracking

The ServiceName import correctly supports the enhanced payment service functionality that tracks the source service for transactions.


152-157: LGTM - Code optimization with local variable

Introducing the fiatAmount local variable eliminates redundant formatting calls and improves code readability by calculating the formatted amount once.


177-181: LGTM - Enhanced exception with better context

The updated CTXSpendException creation properly:

  • Includes formatted fiat amount and merchant ID in the message for better debugging
  • Passes the original throwable as the cause for complete error context

186-186: LGTM - Clearer error message

The updated exception message "purchaseGiftCard error: no merchant" is more descriptive than the previous version.


190-190: LGTM - Service name tracking implementation

The payWithDashUrl call correctly includes the service name parameter, using the merchant's source or defaulting to ServiceName.CTXSpend. This enables proper transaction metadata tracking.


278-285: LGTM - Method signature updated for richer data

The saveGiftCardDummy method signature change from String to GiftCardResponse is beneficial:

  • Uses cardFiatAmount from the response for more accurate pricing
  • Uses the response's id field for the note, providing better data consistency

332-342: LGTM - Email intent method enhanced for flexible reporting

The updated createEmailIntent method properly:

  • Accepts a sentToCTX boolean to determine the recipient email address
  • Makes the exception parameter nullable to handle cases where no exception exists
  • Maintains the same email creation flow with enhanced flexibility

348-402: LGTM - Comprehensive error reporting implementation

The enhanced createReportEmail method provides excellent detailed reporting:

  • Handles nullable exceptions gracefully
  • Includes comprehensive gift card response information when available
  • Adds stack trace information for debugging
  • Uses descriptive field labels like "amount entered" for clarity
  • Properly formats all the information in a readable structure
wallet/src/de/schildbach/wallet/payments/SendCoinsTaskRunner.kt (5)

59-59: LGTM!

The dependency injection of TransactionMetadataProvider is properly implemented.

Also applies to: 80-81


176-180: LGTM!

The optional serviceName parameter is correctly added and propagated through the payment flow.


183-209: LGTM!

The serviceName parameter is correctly propagated through the payment request creation flow, and the visibility change to private for createRequestFromPaymentIntent is appropriate.


233-247: LGTM!

The serviceName parameter is correctly propagated to the directPay method.


249-258: LGTM!

The transaction metadata is correctly set after completing the transaction and before submitting the payment.

Comment thread wallet/src/de/schildbach/wallet/payments/SendCoinsTaskRunner.kt

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (1)
wallet/src/de/schildbach/wallet/payments/SendCoinsTaskRunner.kt (1)

312-331: Simplify and harden isTransactionOnNetwork

a) return try { … } combined with multiple inner return statements makes the control-flow hard to read.
b) The fallback branch (tx == null) still checks only isTransactionLocked, missing chain-locks or peer broadcasts (same concern raised in earlier reviews).

private fun isTransactionOnNetwork(transaction: Transaction): Boolean = try {
    val wallet = walletData.wallet ?: return false
    val candidate = wallet.getTransaction(transaction.txId) ?: transaction
    val c = candidate.confidence ?: return false

    c.source == TransactionConfidence.Source.NETWORK ||
    c.confidenceType == TransactionConfidence.ConfidenceType.BUILDING ||
    c.numBroadcastPeers() > 0 ||
    c.isTransactionLocked ||
    c.isChainLocked
} catch (e: Exception) {
    log.debug("Error checking transaction network status: ${e.message}")
    false
}

This keeps the code linear, covers all known confidence indicators and avoids nested returns.
(Feel free to drop the chain-lock/broadcast checks in the fallback if you prefer the previous ultra-conservative stance.)

🧹 Nitpick comments (1)
wallet/src/de/schildbach/wallet/payments/SendCoinsTaskRunner.kt (1)

272-306: Tighten the HTTP-failure recovery loop

  1. The first delay in delays is 0L; this causes an immediate isTransactionOnNetwork() check right after the catch, duplicating the call you already need at the end of the loop.
    Dropping the zero-delay entry removes redundant work.

  2. wallet.commitTx(tx) inside the loop may throw IllegalStateException if the tx has already been committed by another thread/peer. Wrapping it in a try/catch (and ignoring IllegalStateException) keeps the recovery path bomb-proof.

-val delays = listOf(0L, 1000L, 3000L, 5000L)
+val delays = listOf(1000L, 3000L, 5000L)
 ...
-    if (isTransactionOnNetwork(tx)) {
+    if (isTransactionOnNetwork(tx)) {
         log.info("Transaction found on network despite HTTP timeout: ${tx.txId}")
-        wallet.commitTx(tx)
+        try {
+            wallet.commitTx(tx)
+        } catch (e: IllegalStateException) {
+            // already in wallet – safe to ignore
+        }
         return tx
     }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c10f594 and e9eee97.

📒 Files selected for processing (4)
  • features/exploredash/src/main/java/org/dash/wallet/features/exploredash/repository/CTXSpendRepository.kt (1 hunks)
  • features/exploredash/src/main/java/org/dash/wallet/features/exploredash/ui/ctxspend/CTXSpendViewModel.kt (7 hunks)
  • features/exploredash/src/test/java/org/dash/wallet/features/exploredash/CTXSpendExceptionTest.kt (3 hunks)
  • wallet/src/de/schildbach/wallet/payments/SendCoinsTaskRunner.kt (7 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • features/exploredash/src/main/java/org/dash/wallet/features/exploredash/repository/CTXSpendRepository.kt
  • features/exploredash/src/test/java/org/dash/wallet/features/exploredash/CTXSpendExceptionTest.kt
  • features/exploredash/src/main/java/org/dash/wallet/features/exploredash/ui/ctxspend/CTXSpendViewModel.kt
🧰 Additional context used
🧠 Learnings (10)
📓 Common learnings
Learnt from: HashEngineering
PR: dashpay/dash-wallet#1390
File: features/exploredash/src/main/java/org/dash/wallet/features/exploredash/ui/ctxspend/CTXSpendViewModel.kt:129-145
Timestamp: 2025-05-08T18:11:40.249Z
Learning: The hardcoded test data in the purchaseGiftCard() function of CTXSpendViewModel is intentionally left in place for testing the error handling for limit mismatch, and will be fixed later before release.
Learnt from: HashEngineering
PR: dashpay/dash-wallet#1410
File: wallet/src/de/schildbach/wallet/data/InvitationLinkData.kt:79-84
Timestamp: 2025-07-12T07:12:04.769Z
Learning: HashEngineering prefers to handle defensive validation improvements for URI parsing in follow-up PRs rather than including them in the current PR when the main focus is on replacing Firebase with AppsFlyer.
📚 Learning: 2025-04-19T07:01:17.535Z
Learnt from: HashEngineering
PR: dashpay/dash-wallet#1362
File: wallet/src/de/schildbach/wallet/ui/more/SettingsViewModel.kt:107-115
Timestamp: 2025-04-19T07:01:17.535Z
Learning: In the Dash Wallet app, DashPayConfig methods like isTransactionMetadataInfoShown() already use withContext(Dispatchers.IO) internally, so wrapping these calls with another withContext(Dispatchers.IO) in ViewModels is redundant.

Applied to files:

  • wallet/src/de/schildbach/wallet/payments/SendCoinsTaskRunner.kt
📚 Learning: 2025-08-08T13:29:37.702Z
Learnt from: HashEngineering
PR: dashpay/dash-wallet#1419
File: wallet/src/de/schildbach/wallet/payments/SendCoinsTaskRunner.kt:312-331
Timestamp: 2025-08-08T13:29:37.702Z
Learning: Dash Wallet: For network presence checks, if a transaction is not in the wallet, we generally won’t have broadcast peer data (likely 0) and chain-locks only arrive after the block containing the transaction; thus fallback confidence checks on the local transaction often remain false. It’s safe but usually non-effective to include them; primary detection should rely on the wallet-known transaction.

Applied to files:

  • wallet/src/de/schildbach/wallet/payments/SendCoinsTaskRunner.kt
📚 Learning: 2025-04-19T07:01:17.535Z
Learnt from: HashEngineering
PR: dashpay/dash-wallet#1362
File: wallet/src/de/schildbach/wallet/ui/more/SettingsViewModel.kt:107-115
Timestamp: 2025-04-19T07:01:17.535Z
Learning: In Dash Wallet, DataStore operations (like those in DashPayConfig through BaseConfig) already handle background threading internally. Adding another layer of withContext(Dispatchers.IO) around these calls in ViewModels is redundant because the Jetpack DataStore API automatically dispatches its operations to a background thread.

Applied to files:

  • wallet/src/de/schildbach/wallet/payments/SendCoinsTaskRunner.kt
📚 Learning: 2025-05-08T18:11:40.249Z
Learnt from: HashEngineering
PR: dashpay/dash-wallet#1390
File: features/exploredash/src/main/java/org/dash/wallet/features/exploredash/ui/ctxspend/CTXSpendViewModel.kt:129-145
Timestamp: 2025-05-08T18:11:40.249Z
Learning: The hardcoded test data in the purchaseGiftCard() function of CTXSpendViewModel is intentionally left in place for testing the error handling for limit mismatch, and will be fixed later before release.

Applied to files:

  • wallet/src/de/schildbach/wallet/payments/SendCoinsTaskRunner.kt
📚 Learning: 2025-05-06T15:46:59.440Z
Learnt from: Syn-McJ
PR: dashpay/dash-wallet#1386
File: wallet/src/de/schildbach/wallet/ui/send/SendCoinsViewModel.kt:108-0
Timestamp: 2025-05-06T15:46:59.440Z
Learning: In UI code where frequent updates to a value might trigger expensive operations (like the SendCoinsViewModel's `executeDryrun` method), it's preferable to use a Flow with debounce rather than launching a new coroutine for each update. This prevents race conditions, reduces resource usage, and provides a more reactive architecture.

Applied to files:

  • wallet/src/de/schildbach/wallet/payments/SendCoinsTaskRunner.kt
📚 Learning: 2025-05-12T09:14:36.656Z
Learnt from: Syn-McJ
PR: dashpay/dash-wallet#1391
File: wallet/src/de/schildbach/wallet/ui/payments/PaymentsFragment.kt:111-119
Timestamp: 2025-05-12T09:14:36.656Z
Learning: In the dashpay/dash-wallet project, explicitly unregistering ViewPager2 callbacks is not considered critical since memory leaks haven't been observed in practice with the memory profiler.

Applied to files:

  • wallet/src/de/schildbach/wallet/payments/SendCoinsTaskRunner.kt
📚 Learning: 2025-05-07T14:18:11.161Z
Learnt from: Syn-McJ
PR: dashpay/dash-wallet#1389
File: features/exploredash/src/main/java/org/dash/wallet/features/exploredash/ui/explore/SearchFragment.kt:45-46
Timestamp: 2025-05-07T14:18:11.161Z
Learning: In the ExploreViewModel of the dash-wallet application, `appliedFilters` is a StateFlow (not LiveData), so Flow operators like `distinctUntilChangedBy` can be used with it.

Applied to files:

  • wallet/src/de/schildbach/wallet/payments/SendCoinsTaskRunner.kt
📚 Learning: 2025-07-12T07:12:04.769Z
Learnt from: HashEngineering
PR: dashpay/dash-wallet#1410
File: wallet/src/de/schildbach/wallet/data/InvitationLinkData.kt:79-84
Timestamp: 2025-07-12T07:12:04.769Z
Learning: HashEngineering prefers to handle defensive validation improvements for URI parsing in follow-up PRs rather than including them in the current PR when the main focus is on replacing Firebase with AppsFlyer.

Applied to files:

  • wallet/src/de/schildbach/wallet/payments/SendCoinsTaskRunner.kt
📚 Learning: 2025-04-16T17:07:27.359Z
Learnt from: HashEngineering
PR: dashpay/dash-wallet#1377
File: wallet/src/de/schildbach/wallet/service/platform/PlatformService.kt:0-0
Timestamp: 2025-04-16T17:07:27.359Z
Learning: For PlatformService in the Dash Wallet, the implementation should avoid throwing exceptions when Constants.SUPPORTS_PLATFORM is false. The platform should only be initialized when SUPPORTS_PLATFORM is true, and initialization should be done lazily to defer Platform creation until needed.

Applied to files:

  • wallet/src/de/schildbach/wallet/payments/SendCoinsTaskRunner.kt
🪛 detekt (1.23.8)
wallet/src/de/schildbach/wallet/payments/SendCoinsTaskRunner.kt

[warning] 329-329: The caught exception is swallowed. The original exception could be lost.

(detekt.exceptions.SwallowedException)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build

Comment on lines +256 to +258
serviceName?.let {
metadataProvider.setTransactionService(sendRequest.tx.txId, serviceName)
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Delay setting metadata until the transaction is committed

metadataProvider.setTransactionService() is called immediately after wallet.completeTx(), i.e. before the transaction is definitely persisted (commitTx()) later in the method.
If the subsequent HTTP submission fails and the retry loop ultimately decides that the transaction never reached the network, the metadata row will still have been written and will point at a tx that never becomes part of the wallet.

Consider moving the metadata write to the “success” paths (wallet.commitTx(tx) inside the retry loop and the sendCoins() call at the end).
This guarantees the metadata is stored only when the transaction is actually accepted by the wallet.

🤖 Prompt for AI Agents
In wallet/src/de/schildbach/wallet/payments/SendCoinsTaskRunner.kt around lines
256 to 258, the call to metadataProvider.setTransactionService() occurs
immediately after wallet.completeTx(), before the transaction is committed with
commitTx(). To fix this, move the metadataProvider.setTransactionService() call
into the success paths where the transaction is definitely persisted, such as
inside the retry loop after wallet.commitTx(tx) and after the final sendCoins()
call. This ensures metadata is only set when the transaction is successfully
accepted by the wallet.

@abaranouski abaranouski 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.

looks good

@HashEngineering
HashEngineering merged commit 9361f00 into master Aug 11, 2025
3 checks passed
@HashEngineering
HashEngineering deleted the fix/ctx-error-handling branch March 17, 2026 15:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants