Skip to content
Merged
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
6 changes: 3 additions & 3 deletions app/components/UI/Money/selectors/featureFlags.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -912,8 +912,8 @@ describe('selectMoneyNoFeeDepositTokens', () => {
expect(result['0x38']).toEqual(
expect.arrayContaining(['USDC', 'aUSDC', 'aUSDT', 'USDT']),
);
expect(result['0xe708']).toEqual(['MUSD']);
expect(result['0x8f']).toEqual(['USDC', 'MUSD']);
expect(result['0xe708']).toEqual(['mUSD']);
expect(result['0x8f']).toEqual(['mUSD', 'USDC']);
});

it('lists Monad mUSD even though no route emits a Monad mUSD -> Monad mUSD deposit', () => {
Expand All @@ -923,7 +923,7 @@ describe('selectMoneyNoFeeDepositTokens', () => {

const result = selectMoneyNoFeeDepositTokens(state as never);

expect(result['0x8f']).toContain('MUSD');
expect(result['0x8f']).toContain('mUSD');
});

it('deduplicates symbols within a chain', () => {
Expand Down
12 changes: 10 additions & 2 deletions app/components/UI/Money/selectors/featureFlags.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@ import {
} from '../../../../util/remoteFeatureFlag';
import { isMoneyAccountEnabled } from '../../../../lib/Money/feature-flags';
import { WildcardTokenList } from '../../Earn/utils/wildcardTokenList';
import { MUSD_TOKEN_ADDRESS } from '../../Earn/constants/musd';
import {
MUSD_TOKEN_ADDRESS,
getTokenDisplaySymbol,
} from '../../Earn/constants/musd';
import {
MONEY_NO_FEE_TOKENS_FALLBACK,
ensureMonadMusdListed,
Expand Down Expand Up @@ -182,6 +185,9 @@ const AAVE_TOKEN_ALIASES = new Set(['ausdc', 'ausdt', 'adai', 'ausdcn']);
* - Strip the chain prefix ("eth_usdc" → "usdc")
* - Known aave tokens (see AAVE_TOKEN_ALIASES): "ausdc" → "aUSDC"
* - All others: full uppercase ("usdc" → "USDC")
*
* mUSD casing is handled by address via getTokenDisplaySymbol at the call
* site, not by alias here.
*/
const normalizeTokenSymbol = (tokenAlias: string): string => {
const underscoreIdx = tokenAlias.indexOf('_');
Expand Down Expand Up @@ -232,7 +238,9 @@ export const selectMoneyNoFeeDepositTokens = createSelector(
}

const srcChainHex = route.sourceChain.toLowerCase();
const symbol = normalizeTokenSymbol(route.sourceTokenAlias);
const normalized = normalizeTokenSymbol(route.sourceTokenAlias);
const symbol =
getTokenDisplaySymbol(route.sourceToken, normalized) ?? normalized;

if (!catalog[srcChainHex]) catalog[srcChainHex] = [];
if (!catalog[srcChainHex].includes(symbol)) {
Expand Down
24 changes: 16 additions & 8 deletions app/components/UI/Money/utils/depositFaqTokens.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,25 +7,33 @@ import {

describe('depositFaqTokens', () => {
describe('ensureMonadMusdListed', () => {
it('appends MUSD after existing Monad tokens', () => {
it('prepends mUSD before existing Monad tokens', () => {
expect(
ensureMonadMusdListed({ [CHAIN_IDS.MONAD]: ['USDC'] })[CHAIN_IDS.MONAD],
).toEqual(['USDC', 'MUSD']);
).toEqual(['mUSD', 'USDC']);
});

it('adds a Monad entry when the chain is absent', () => {
expect(ensureMonadMusdListed({ '0x1': ['USDC'] })).toEqual({
'0x1': ['USDC'],
[CHAIN_IDS.MONAD]: ['MUSD'],
[CHAIN_IDS.MONAD]: ['mUSD'],
});
});

it('does not duplicate MUSD when already present', () => {
it('moves mUSD to the front when present but not first', () => {
expect(
ensureMonadMusdListed({ [CHAIN_IDS.MONAD]: ['USDC', 'MUSD'] })[
ensureMonadMusdListed({ [CHAIN_IDS.MONAD]: ['USDC', 'mUSD'] })[
CHAIN_IDS.MONAD
],
).toEqual(['USDC', 'MUSD']);
).toEqual(['mUSD', 'USDC']);
});

it('does not duplicate mUSD when already first', () => {
expect(
ensureMonadMusdListed({ [CHAIN_IDS.MONAD]: ['mUSD', 'USDC'] })[
CHAIN_IDS.MONAD
],
).toEqual(['mUSD', 'USDC']);
});

it('does not mutate the input list', () => {
Expand All @@ -39,8 +47,8 @@ describe('depositFaqTokens', () => {
it('formats each chain as a bullet line with a friendly network name', () => {
expect(formatNoFeeTokenBullets(MONEY_NO_FEE_TOKENS_FALLBACK)).toBe(
[
'• Ethereum: USDC, aUSDC, USDT, aUSDT, DAI, aDAI, MUSD',
'• Linea: MUSD',
'• Ethereum: USDC, aUSDC, USDT, aUSDT, DAI, aDAI, mUSD',
'• Linea: mUSD',
'• Arbitrum: USDC, aUSDCN',
'• Base: USDC, aUSDC',
'• BNB Chain: USDC, aUSDC, aUSDT, USDT',
Expand Down
21 changes: 14 additions & 7 deletions app/components/UI/Money/utils/depositFaqTokens.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
import { CHAIN_IDS } from '@metamask/transaction-controller';
import { NETWORK_TO_NAME_MAP } from '../../../../core/Engine/constants';
import { WildcardTokenList } from '../../Earn/utils/wildcardTokenList';
import { MUSD_TOKEN } from '../../Earn/constants/musd';

const NETWORK_NAMES = NETWORK_TO_NAME_MAP as Record<string, string>;

/** Display symbol for mUSD in the FAQ no-fee list. */
const MUSD_SYMBOL = 'MUSD';
const MUSD_SYMBOL = MUSD_TOKEN.symbol;

/**
* Monad mUSD -> Monad mUSD needs no swap or bridge, so the relay fixed-spread
* flag omits it from its routes; depositing Monad mUSD still incurs no fee, so
* the FAQ lists it explicitly alongside the route-derived tokens. Mirrors the
* `isMonadMusd` no-fee edge case in useMoneyEarnableTokens.
* the FAQ lists it explicitly, first, ahead of the route-derived tokens.
* Mirrors the `isMonadMusd` no-fee edge case in useMoneyEarnableTokens.
*
* Returns a new list and never mutates the input (the input may be the shared
* MONEY_NO_FEE_TOKENS_FALLBACK constant).
Expand All @@ -20,10 +21,16 @@ export const ensureMonadMusdListed = (
list: WildcardTokenList,
): WildcardTokenList => {
const monadTokens = list[CHAIN_IDS.MONAD] ?? [];
if (monadTokens.includes(MUSD_SYMBOL)) {
if (monadTokens[0] === MUSD_SYMBOL) {
return list;
}
return { ...list, [CHAIN_IDS.MONAD]: [...monadTokens, MUSD_SYMBOL] };
return {
...list,
[CHAIN_IDS.MONAD]: [
MUSD_SYMBOL,
...monadTokens.filter((symbol) => symbol !== MUSD_SYMBOL),
],
};
};

export const MONEY_NO_FEE_TOKENS_FALLBACK: WildcardTokenList = {
Expand All @@ -34,9 +41,9 @@ export const MONEY_NO_FEE_TOKENS_FALLBACK: WildcardTokenList = {
'aUSDT',
'DAI',
'aDAI',
'MUSD',
'mUSD',
],
[CHAIN_IDS.LINEA_MAINNET]: ['MUSD'],
[CHAIN_IDS.LINEA_MAINNET]: ['mUSD'],
[CHAIN_IDS.ARBITRUM]: ['USDC', 'aUSDCN'],
[CHAIN_IDS.BASE]: ['USDC', 'aUSDC'],
[CHAIN_IDS.BSC]: ['USDC', 'aUSDC', 'aUSDT', 'USDT'],
Expand Down
Loading