Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@

## Unreleased (develop)

- fixed: NYM max swaps from EVM wallets now report the correct limit error instead of an unsupported-route error (edge-exchange-plugins 2.52.1).
- changed: Sign MoonPay buy/sell widget URLs and bind them to the customer's IP via the info server, for MoonPay's on-ramp IP-matching security upgrade.
- fixed: NYM max swaps from EVM wallets now report the correct limit error instead of an unsupported-route error (edge-exchange-plugins 2.52.1).
- fixed: Tapping Max on the Sell scene no longer briefly shows the entered fiat amount in the crypto field while the max is being calculated.

## 4.50.0 (2026-07-21)

Expand Down
27 changes: 25 additions & 2 deletions src/components/scenes/RampCreateScene.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,14 @@ export const RampCreateScene: React.FC<Props> = (props: Props) => {
null
)
const [pendingMaxNav, setPendingMaxNav] = useState(false)
// A monotonic id for the in-flight max flow, bumped synchronously (unlike the
// `pendingMaxNav` state). handleMaxPress captures the id for its request; any
// later Max, or a wallet/fiat switch that cancels the flow, increments it.
// The async sell max handler applies its result only if its captured id is
// still current, so a stale in-flight getMaxSpendExchangeAmount (e.g. for a
// since-switched asset, or a superseded earlier request) is discarded. A
// plain boolean cannot distinguish which request is current.
const maxRequestIdRef = React.useRef(0)
const hasAppliedInitialAmount = React.useRef(false)

// Selected currencies
Expand Down Expand Up @@ -568,6 +576,7 @@ export const RampCreateScene: React.FC<Props> = (props: Props) => {
}

// Clear amount and max state when switching crypto assets in sell mode
maxRequestIdRef.current += 1
setPendingMaxNav(false)
if (direction === 'sell') {
setAmountQuery({ empty: true })
Expand All @@ -585,6 +594,7 @@ export const RampCreateScene: React.FC<Props> = (props: Props) => {

const handleFiatDropdown = useHandler(async () => {
if (account == null) return
maxRequestIdRef.current += 1
setPendingMaxNav(false)
const result = await Airship.show<GuiFiatType>(bridge => (
<FiatListModal bridge={bridge} />
Expand Down Expand Up @@ -660,23 +670,36 @@ export const RampCreateScene: React.FC<Props> = (props: Props) => {
return
}

// Trigger a transient max flow: request quotes with {max:true} and auto-navigate when ready
// Trigger a transient max flow: request quotes and auto-navigate when ready.
// Do NOT flip `lastUsedInput` before the amount query is set to the max
// marker. For sell, computing the max is async; if `lastUsedInput` became
// 'crypto' while `amountQuery` still held the previously entered fiat
// amount, `displayCryptoAmount` would render that fiat value in the crypto
// field (e.g. "100 USD" shown as "100 BTC"). Set the max amount query first
// so the display memos take their max branch, then set the input type.
const maxRequestId = ++maxRequestIdRef.current
setPendingMaxNav(true)
setLastUsedInput(direction === 'buy' ? 'fiat' : 'crypto')

if (direction === 'sell') {
const maxSpendExchangeAmount = await getMaxSpendExchangeAmount(
selectedWallet,
selectedCrypto.tokenId,
denomination
)
// Discard the result if a newer Max, or a wallet/fiat switch that
// cancelled the flow, superseded this request while
// getMaxSpendExchangeAmount was in flight: this (now stale) max belongs
// to the previously selected asset.
if (maxRequestIdRef.current !== maxRequestId) return
setAmountQuery({
maxExchangeAmount: maxSpendExchangeAmount
})
setLastUsedInput('crypto')
Comment thread
cursor[bot] marked this conversation as resolved.
Comment thread
cursor[bot] marked this conversation as resolved.
} else {
setAmountQuery({
max: true
})
setLastUsedInput('fiat')
}
})

Expand Down
Loading