Skip to content

Conversation

samholmes
Copy link
Contributor

@samholmes samholmes commented Sep 26, 2025

CHANGELOG

Does this branch warrant an entry to the CHANGELOG?

  • Yes
  • No

Dependencies

none

Requirements

If you have made any visual changes to the GUI. Make sure you have:

  • Tested on iOS device
  • Tested on Android device
  • Tested on small-screen device (iPod Touch)
  • Tested on large-screen device (tablet)


Note

Introduces a new Ramp Plugins architecture with multiple providers (Banxa, Bity, Moonpay, Paybis, Revolut, Simplex), new buy/sell flows and scenes, ramp deeplinks, persisted ramp settings, and supporting UI/utilities using React Query.

  • Ramps (Architecture):
    • Implement new Ramp Plugins system with store utils, rate/error helpers, and legacy store-id overrides.
    • Add providers: banxa, bity, moonpay, paybis, revolut, simplex.
  • Flows & Navigation:
    • New buy/sell scenes: RampCreateScene, RampSelectOptionScene; integrate into buyTab/sellTab with BuySellTabParamList.
    • Preserve legacy GUI plugin list under pluginListBuyOld/pluginListSellOld.
  • Deeplinks:
    • Add edge://ramp/... parsing and rampDeeplinkManager; keep fiatProvider handling for backward compatibility.
  • State & Settings:
    • Persist rampLastFiatCurrencyCode and rampLastCryptoSelection; new actions to update.
  • UI Components:
    • Add PillButton, DropdownInputButton, PaymentOptionCard, ErrorCard, BestRateBadge, ShimmerCard; enhance AlertCardUi4, Shimmer.
  • App/Infra:
    • Wrap app with QueryClientProvider (React Query); add @tanstack/react-query dependency.
    • Theme: add secondaryButtonDisabled.
  • DeepLinking & Parsing:
    • Update DeepLinkingActions and DeepLinkParser to support ramp links.
  • Tests:
    • Add tests for ramp store IDs, payment type icons/utils, deeplinks, and snapshot updates.
  • Misc:
    • Update router types, scenes, and minor fixes; package scripts tweak (verify).

Written by Cursor Bugbot for commit 7131a73. This will update automatically on new commits. Configure here.

cursor[bot]

This comment was marked as outdated.

cursor[bot]

This comment was marked as outdated.

@samholmes samholmes force-pushed the sam/ramps branch 7 times, most recently from 981e4c4 to ea62b8a Compare October 1, 2025 23:20
Copy link
Collaborator

@Jon-edge Jon-edge left a comment

Choose a reason for hiding this comment

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

Remove styled components, rebase and address lint warnings

cursor[bot]

This comment was marked as outdated.

props: MarginRemProps,
// TODO: Remove this prop once all designs using this prop have been updated.
/** @deprecated Your design should expect the component to have 0.5rem margins */
defaultRem: number = 0.5
Copy link
Collaborator

@Jon-edge Jon-edge Oct 6, 2025

Choose a reason for hiding this comment

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

defaultRem shouldn't be configurable, should just be a constant

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I know, it's only there to not break other places where useMarginRemStyle is used. See the comment.

Copy link
Collaborator

Choose a reason for hiding this comment

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

What about {aroundRem: 0}?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

That would override the defaultRem (should be called fallbackRem actually).

Copy link
Collaborator

@Jon-edge Jon-edge Oct 6, 2025

Choose a reason for hiding this comment

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

I mean pass {aroundRem: 0} at callsites like FilledTextInput if the marignRem props are not provided. FilledTextInput and others would perform the fallback logic. It will be uglier at the FilledTextInput, but then we don't need to even have this deprecation TODO to deal with in the common hook, and no one will mess up its usage in the future.

Comment on lines 8 to 9
// TODO: rename this hook to not be specific to margins because we want to
// our design system around these props
Copy link
Collaborator

Choose a reason for hiding this comment

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

Fix comment

const { isNative, address } = asset

if (!asset.rampProducts?.includes(direction)) continue
if (asset.rampProducts?.includes(direction) !== true) continue
Copy link

Choose a reason for hiding this comment

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

Bug: Asset Filtering Logic Error

The condition !asset.rampProducts?.includes(direction) was changed to asset.rampProducts?.includes(direction) !== true. This change is reported to alter the filtering logic for assets where rampProducts is undefined or null, as the two expressions are considered non-equivalent in this context.

Fix in Cursor Fix in Web

Copy link
Contributor Author

Choose a reason for hiding this comment

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

!asset.rampProducts?.includes(direction) means asset.rampProducts?.includes(direction) === false || asset.rampProducts?.includes(direction) == null, so the simplification of that is asset.rampProducts?.includes(direction) !== true.

nativeAmount: '',
fiatAmount: '',
fieldChanged: fieldNum ? 'fiat' : 'crypto'
fieldChanged: fieldNum !== 0 ? 'fiat' : 'crypto'
Copy link

Choose a reason for hiding this comment

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

Bug: Field Mapping Error Causes Incorrect Amount Tracking

The fieldChanged assignment was updated to use fieldNum !== 0 instead of fieldNum. This change inverts the field mapping when fieldNum is 0, causing fieldChanged to be 'fiat' instead of 'crypto' and potentially leading to incorrect amount change tracking.

Fix in Cursor Fix in Web

Copy link
Contributor Author

@samholmes samholmes Oct 7, 2025

Choose a reason for hiding this comment

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

What?... The whole point is to fix the lint error. fieldNum !== 0 is what fieldNum meant before anyway.

const dataMatch = /{{([^:]+):([^:]+)(?::([^}]+))?}}/.exec(data)

if (dataMatch) {
if (dataMatch != null) {
Copy link

Choose a reason for hiding this comment

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

Bug: Redundant Null Check in Regex Execution

The if (dataMatch != null) check for the regex exec result is redundant. exec returns either a truthy array or falsy null, so if (dataMatch) is sufficient and aligns better with common patterns.

Fix in Cursor Fix in Web

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It's just to fix the lint error.

nativeAmount: '',
fiatAmount: '',
fieldChanged: fieldNum ? 'fiat' : 'crypto'
fieldChanged: fieldNum !== 0 ? 'fiat' : 'crypto'
Copy link

Choose a reason for hiding this comment

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

Bug: Field Change Detection Fails For Negative Numbers

The fieldChanged assignment condition was updated from fieldNum ? to fieldNum !== 0 ?. This change from implicit truthiness to an explicit non-zero check raises concerns that it could lead to incorrect field change detection if fieldNum takes on values other than the expected 0 or 1, such as negative numbers.

Fix in Cursor Fix in Web

error != null ||
(zeroString(spendInfo.spendTargets[0].nativeAmount) &&
!SPECIAL_CURRENCY_INFO[pluginId].allowZeroTx)
getSpecialCurrencyInfo(pluginId).allowZeroTx !== true)
Copy link

Choose a reason for hiding this comment

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

Bug: Slider Incorrectly Disabled for Truthy Values

The disableSlider condition for zero-amount transactions now uses allowZeroTx !== true instead of !allowZeroTx. This change incorrectly disables the slider when allowZeroTx is a truthy non-boolean value (e.g., 1), preventing transactions that should be allowed.

Fix in Cursor Fix in Web

} else {
directionChange = 'to'
amount = isMaxAmount ? amount : round(amount, CRYPTO_DECIMALS)
}
Copy link

Choose a reason for hiding this comment

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

Bug: API Requests Use Incorrect Negative Precision

The round function uses negative precision values for both fiat and crypto amounts when preparing API requests. This causes amounts to round to the nearest hundred or hundred million, rather than to two or eight decimal places, leading to incorrect quote calculations.

Fix in Cursor Fix in Web

}

const flagUri =
countryData != null
Copy link

Choose a reason for hiding this comment

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

Bug: SwapInput Tracks Wrong Field On Change

The SwapInput component's onAmountChanged callback incorrectly tracks which input field was modified. The change from fieldNum ? 'fiat' : 'crypto' to fieldNum !== 0 ? 'fiat' : 'crypto' reverses the intended mapping of fieldNum to the fieldChanged type, causing misidentification of whether the fiat or crypto amount was adjusted.

Additional Locations (1)

Fix in Cursor Fix in Web

assetAction: params.assetAction,
savedAction: params.savedAction
})
}
Copy link

Choose a reason for hiding this comment

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

Bug: Transaction Metadata Guard Fails for Native Sells

The saveTxAction call in both Moonpay and Paybis ramp plugins is incorrectly guarded by if (tokenId != null). This prevents transaction metadata from being saved for native cryptocurrency sells, where tokenId is null.

Additional Locations (1)

Fix in Cursor Fix in Web

},
hiddenFeaturesMap: {
address: true
}
Copy link

Choose a reason for hiding this comment

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

Bug: Deep Link Handler Error Handling Flaw

The deeplinkHandler in fiatPlugin.tsx can return void or a Promise<void>. If the handler returns void and throws a synchronous error, the error won't be caught by the subsequent .catch() call, potentially leading to unhandled exceptions.

Additional Locations (1)

Fix in Cursor Fix in Web

@samholmes samholmes merged commit 0c32358 into develop Oct 7, 2025
3 checks passed
@samholmes samholmes deleted the sam/ramps branch October 7, 2025 17:54
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