Skip to content

fix(maya): fix exchange rates using mayanode server#1484

Open
HashEngineering wants to merge 11 commits into
feature-mayafrom
fix/maya-exchange-rates
Open

fix(maya): fix exchange rates using mayanode server#1484
HashEngineering wants to merge 11 commits into
feature-mayafrom
fix/maya-exchange-rates

Conversation

@HashEngineering
Copy link
Copy Markdown
Collaborator

@HashEngineering HashEngineering commented May 4, 2026

Issue being fixed or feature implemented

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 swap quote functionality for more accurate trade estimates.
    • Introduced improved error messaging to better inform users about trade constraints.
  • Bug Fixes

    • Enhanced pool availability filtering for more reliable currency options.
    • Refined conversion pricing calculations to use real-time pool balance data.
  • Documentation

    • Updated Maya Protocol integration documentation reflecting API improvements.

@HashEngineering HashEngineering self-assigned this May 4, 2026
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 4, 2026

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 666353a6-2799-4e72-9a58-27fc1e8d4521

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

This PR migrates the Maya integration from the deprecated Midgard v2 pools API to the mayanode endpoint, replaces server-side pool pricing with client-side USD/fiat conversion, removes legacy API code, and updates error handling with new error types and UI strings.

Changes

Maya Midgard to Mayanode API Migration

Layer / File(s) Summary
Data Models & Schema
integrations/maya/src/main/java/org/dash/wallet/integrations/maya/model/PoolInfo.kt, SwapTradeResponse.kt, MayaErrorResponse.kt
PoolInfo fields refactored from legacy Midgard schema to mayanode snake_case JSON mappings (balance_cacao, balance_asset, etc.); price computation shifts from stored assetPriceUSD to derived assetPriceInCacao getter. SwapTradeUIModel adds expectedOutputAmount field. MayaErrorType adds AMOUNT_TOO_LOW enum and error string mapping expanded.
API Contract
integrations/maya/src/main/java/org/dash/wallet/integrations/maya/api/MayaApi.kt
New getDefaultSwapQuote(toAsset, value) suspend method added to interface and aggregator; updatePoolList() simplified to remove per-pool fiat-rate transformation.
API Implementation & Legacy Removal
integrations/maya/src/main/java/org/dash/wallet/integrations/maya/api/MayaWebApi.kt, MayaLegacyWebApi.kt, FiatExchangeRateApi.kt
MayaLegacyWebApi.kt deleted entirely; MayaWebApi constructor now injects current MayaEndpoint instead of legacyEndpoint; getPoolInfo() calls endpoint instead of legacy; getSwapInfo() computes expectedOutputAmount from quote with explicit BigDecimal scaling. FiatExchangeRateApi.observeFiatRate() now filters by currencyCode.
Dependency Injection
integrations/maya/src/main/java/org/dash/wallet/integrations/maya/di/MayaModule.kt
Legacy endpoint factory method provideMayaLegacyEndpoint() and its import removed.
Pricing & State Management
integrations/maya/src/main/java/org/dash/wallet/integrations/maya/ui/MayaViewModel.kt
New exchangeRates StateFlow observes all exchange rates. New applyPoolPrices(pools, usdToFiat) method filters available USDT/USDC pools, computes liquidity-weighted USD price via priceInUsd(), and updates pool.assetPriceFiat with BigDecimal arithmetic (RoundingMode.HALF_UP). updateInboundAddresses() now launches on Dispatchers.IO.
UI Integration
integrations/maya/src/main/java/org/dash/wallet/integrations/maya/ui/MayaConversionPreviewFragment.kt, MayaCryptoCurrencyPickerFragment.kt
MayaConversionPreviewFragment.updateConversionPreviewUI() derives output amount from expectedOutputAmount (scaled to 8 decimals) instead of amount.crypto. MayaCryptoCurrencyPickerFragment tightens pool filtering to require asset in defaultItemMap, case-insensitive status match for "available", and chain prefix validation via inboundAddresses.
Documentation & Configuration
integrations/maya/MAYA_PROTOCOL.md, .claude/agents/update-maya-currencies.md, .tx/config, integrations/maya/src/main/res/values/strings-maya.xml
Protocol documentation updated to mayanode pools endpoint and client-side pricing via CACAO/asset ratios and USDT/USDC liquidity. Legacy endpoint references removed; PoolInfo schema rewritten for snake_case fields; architecture diagram simplified; May 2026 verification timestamp. AI agent spec updated to fetch from mayanode and filter for "Available" status. Transifex config adds strings-maya.xml resource mapping. Error strings updated: "Contact Support" replaces "Report Issue"; new error messages for minimum-amount and quote-failure cases; %n replaces \n for line breaks.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰 From Midgard's legacy we hop away,
To mayanode's pools, bright as day!
Client-side prices with CACAO's might,
And Fiat conversions calculated right—
The Maya integration shines anew!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 5.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title 'fix(maya): fix exchange rates using mayanode server' directly describes the main change—migrating from the Midgard API to the mayanode server for exchange rate handling. This aligns with the primary objectives stated in commit messages (removing Midgard, switching to USD pools via mayanode).
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/maya-exchange-rates

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


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

Comment @coderabbitai help to get the list of available commands and usage tips.

@HashEngineering HashEngineering changed the base branch from master to feature-maya May 4, 2026 20:49
@HashEngineering
Copy link
Copy Markdown
Collaborator Author

@CodeRabbitReview

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 4, 2026

Tip

For best results, initiate chat on the files or code changes.

@HashEngineering: I'll review the changes in this PR now!

[review]

@HashEngineering
Copy link
Copy Markdown
Collaborator Author

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 8, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🧹 Nitpick comments (2)
integrations/maya/src/main/java/org/dash/wallet/integrations/maya/model/PoolInfo.kt (1)

57-61: 💤 Low value

Remove dead code: setAssetPrice method and assetPriceInCacao property

Neither setAssetPrice nor the assetPriceInCacao property it depends on have any call sites in the codebase. The applyPoolPrices() method in MayaViewModel sets pool.assetPriceFiat directly without invoking setAssetPrice().

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@integrations/maya/src/main/java/org/dash/wallet/integrations/maya/model/PoolInfo.kt`
around lines 57 - 61, Remove the dead API by deleting the setAssetPrice function
and the assetPriceInCacao property from PoolInfo; locate the symbols
setAssetPrice and assetPriceInCacao in PoolInfo.kt, verify there are no
remaining references (applyPoolPrices in MayaViewModel already assigns
pool.assetPriceFiat directly), and run a build to ensure no other code depends
on those members before committing.
integrations/maya/src/main/java/org/dash/wallet/integrations/maya/ui/MayaCryptoCurrencyPickerFragment.kt (1)

128-134: ⚡ Quick win

The new filter at line 129 makes the else branch in .map {} (lines 158–170) unreachable dead code.

Because defaultItemMap.containsKey(pool.asset) is already required to be true by the filter, every pool that reaches the .map {} block is guaranteed to satisfy the if at line 147. The else branch (lines 158–170) can never execute and should be removed.

♻️ Proposed cleanup
                 .map { pool ->
                     val chain = pool.asset.substringBefore('.')
                     val inbound = addresses.find { it.chain == chain }
                     val isEnabled = inbound != null && !inbound.halted
                     val price = if (isEnabled) {
                         GenericUtils.formatFiatWithoutComma(
                             viewModel.formatFiat(pool.assetPriceFiat)
                         )
                     } else {
                         null
                     }
                     val haltedLabel = if (inbound?.halted == true) getString(R.string.maya_halted_label) else null
-                    if (defaultItemMap.containsKey(pool.asset)) {
-                        defaultItemMap[pool.asset]!!.copy(
-                            iconUrl = GenericUtils.getCoinIcon(pool.currencyCode),
-                            iconSelectMode = IconSelectMode.None,
-                            additionalInfo = price,
-                            actionText = haltedLabel,
-                            actionBackgroundColor = if (inbound?.halted == true) R.color.gray_100 else null,
-                            actionTextColor = if (inbound?.halted == true) R.color.content_secondary else null,
-                            isEnabled = isEnabled,
-                            id = pool.asset
-                        )
-                    } else {
-                        IconifiedViewItem(
-                            pool.currencyCode,
-                            pool.asset,
-                            iconUrl = GenericUtils.getCoinIcon(pool.currencyCode),
-                            iconSelectMode = IconSelectMode.None,
-                            additionalInfo = price,
-                            actionText = haltedLabel,
-                            actionBackgroundColor = if (inbound?.halted == true) R.color.gray_100 else null,
-                            actionTextColor = if (inbound?.halted == true) R.color.content_secondary else null,
-                            isEnabled = isEnabled,
-                            id = pool.asset
-                        )
-                    }
+                    defaultItemMap[pool.asset]!!.copy(
+                        iconUrl = GenericUtils.getCoinIcon(pool.currencyCode),
+                        iconSelectMode = IconSelectMode.None,
+                        additionalInfo = price,
+                        actionText = haltedLabel,
+                        actionBackgroundColor = if (inbound?.halted == true) R.color.gray_100 else null,
+                        actionTextColor = if (inbound?.halted == true) R.color.content_secondary else null,
+                        isEnabled = isEnabled,
+                        id = pool.asset
+                    )
                 }.sortedBy { it.title }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@integrations/maya/src/main/java/org/dash/wallet/integrations/maya/ui/MayaCryptoCurrencyPickerFragment.kt`
around lines 128 - 134, The new upstream filter requires
defaultItemMap.containsKey(pool.asset) so the conditional inside the .map { pool
-> ... } (the if checking defaultItemMap.containsKey(pool.asset)) is now always
true; remove the unreachable else branch (the code creating the fallback/else
item) from the map block and simplify the map to only build the item for the
if-case, updating any variable references in that block (pool, defaultItemMap)
accordingly.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@integrations/maya/src/main/java/org/dash/wallet/integrations/maya/model/MayaErrorResponse.kt`:
- Around line 56-58: The current error-to-type mapping in MayaErrorResponse (the
branch that returns MayaErrorType.TRADING_IS_HALTED, AMOUNT_TOO_LOW or
QUOTE_ERROR) uses case-sensitive substring checks and can misclassify messages
with different casing; update the checks to be case-insensitive (e.g., normalize
the error string with lowercase()/uppercase() or use contains(..., ignoreCase =
true)) so the matches for "trading is halted" and "not enough asset to pay for
fees" reliably return MayaErrorType.TRADING_IS_HALTED and
MayaErrorType.AMOUNT_TOO_LOW respectively, otherwise fall back to
MayaErrorType.QUOTE_ERROR.

In
`@integrations/maya/src/main/java/org/dash/wallet/integrations/maya/model/PoolInfo.kt`:
- Around line 50-55: The assetPriceInCacao getter currently uses the throwing
BigDecimal(String) constructor for balanceCacao and also declares a local
variable named asset that shadows the class property; change the getter to
safely parse balanceCacao with toBigDecimalOrNull() (mirror balanceAsset usage),
return BigDecimal.ZERO if parsing fails or equals zero, and rename the local
parsed-asset variable (e.g., assetBd) to avoid shadowing the class property;
finally perform the divide with the same scale and RoundingMode.HALF_UP.

In
`@integrations/maya/src/main/java/org/dash/wallet/integrations/maya/ui/MayaViewModel.kt`:
- Around line 90-91: The backing MutableStateFlow _exchangeRates is currently
public and must be made private to prevent external emission; modify the
declaration of _exchangeRates (the MutableStateFlow<List<ExchangeRate>>) to be
private and keep the public immutable exchangeRates =
_exchangeRates.asStateFlow() so callers can only collect the state, not emit it
(this change should be applied inside the MayaViewModel where _exchangeRates and
exchangeRates are declared).
- Around line 115-126: Remove the dead diagnostic Flow block that observes
WalletUIConfig.SELECTED_CURRENCY and logs a computed rate (the chain starting
with walletUIConfig.observe(WalletUIConfig.SELECTED_CURRENCY) and including
flatMapLatest(exchangeRatesProvider::observeExchangeRate), onEach { ... } and
launchIn(viewModelScope)); this block never updates ViewModel state and uses
unsafe non-null assertions exchangeRate.rate!! and usdPrice.rate!! which can
throw NPEs and cancel the subscription. Delete the entire chain (or replace it
with a safe implementation that uses nullable checks on ExchangeRate.rate and
actually updates state via the ViewModel if needed) so no !! assertions remain
and the subscription is not silently killed.

---

Nitpick comments:
In
`@integrations/maya/src/main/java/org/dash/wallet/integrations/maya/model/PoolInfo.kt`:
- Around line 57-61: Remove the dead API by deleting the setAssetPrice function
and the assetPriceInCacao property from PoolInfo; locate the symbols
setAssetPrice and assetPriceInCacao in PoolInfo.kt, verify there are no
remaining references (applyPoolPrices in MayaViewModel already assigns
pool.assetPriceFiat directly), and run a build to ensure no other code depends
on those members before committing.

In
`@integrations/maya/src/main/java/org/dash/wallet/integrations/maya/ui/MayaCryptoCurrencyPickerFragment.kt`:
- Around line 128-134: The new upstream filter requires
defaultItemMap.containsKey(pool.asset) so the conditional inside the .map { pool
-> ... } (the if checking defaultItemMap.containsKey(pool.asset)) is now always
true; remove the unreachable else branch (the code creating the fallback/else
item) from the map block and simplify the map to only build the item for the
if-case, updating any variable references in that block (pool, defaultItemMap)
accordingly.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 31a93af7-5762-4f63-8022-d1bd4dd413e7

📥 Commits

Reviewing files that changed from the base of the PR and between 361752d and 9f459cf.

📒 Files selected for processing (15)
  • .claude/agents/update-maya-currencies.md
  • .tx/config
  • integrations/maya/MAYA_PROTOCOL.md
  • integrations/maya/src/main/java/org/dash/wallet/integrations/maya/api/FiatExchangeRateApi.kt
  • integrations/maya/src/main/java/org/dash/wallet/integrations/maya/api/MayaApi.kt
  • integrations/maya/src/main/java/org/dash/wallet/integrations/maya/api/MayaLegacyWebApi.kt
  • integrations/maya/src/main/java/org/dash/wallet/integrations/maya/api/MayaWebApi.kt
  • integrations/maya/src/main/java/org/dash/wallet/integrations/maya/di/MayaModule.kt
  • integrations/maya/src/main/java/org/dash/wallet/integrations/maya/model/MayaErrorResponse.kt
  • integrations/maya/src/main/java/org/dash/wallet/integrations/maya/model/PoolInfo.kt
  • integrations/maya/src/main/java/org/dash/wallet/integrations/maya/model/SwapTradeResponse.kt
  • integrations/maya/src/main/java/org/dash/wallet/integrations/maya/ui/MayaConversionPreviewFragment.kt
  • integrations/maya/src/main/java/org/dash/wallet/integrations/maya/ui/MayaCryptoCurrencyPickerFragment.kt
  • integrations/maya/src/main/java/org/dash/wallet/integrations/maya/ui/MayaViewModel.kt
  • integrations/maya/src/main/res/values/strings-maya.xml
💤 Files with no reviewable changes (2)
  • integrations/maya/src/main/java/org/dash/wallet/integrations/maya/api/MayaLegacyWebApi.kt
  • integrations/maya/src/main/java/org/dash/wallet/integrations/maya/di/MayaModule.kt

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