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
Original file line number Diff line number Diff line change
Expand Up @@ -72,10 +72,17 @@ export type {
TransferActivity,
};

/** Corridor copy differs by direction: money can only ARRIVE over the rails this
* wallet settles, but it can be PAID OUT to every corridor in the picker. */
const BANK_SUB = {
funding: 'ACH in the US, SEPA across the euro area',
payout: 'Local transfer in 55+ countries',
};

// Add-money source visuals — Aurora owns the icon + copy per source id; the brain
// supplies only the ordered ids + routing (the face is where icons live).
const SOURCE_COPY: Record<string, { title: string; sub: string; speed: string }> = {
bank: { title: 'Bank account', sub: 'ACH in the US, SEPA across the euro area', speed: 'Instant' },
bank: { title: 'Bank account', sub: BANK_SUB.payout, speed: 'Instant' },
crypto: { title: 'Crypto wallet', sub: 'Spark, Solana, Base address', speed: 'Instant' },
cashapp: { title: 'Cash App', sub: 'Use your Cash App balance', speed: 'Instant' },
applepay: { title: 'Apple Pay', sub: 'Use Apple Wallet', speed: 'Instant' },
Expand Down Expand Up @@ -757,7 +764,8 @@ export function AddMoneySheet({
<span className={clsx(styles.sourceContent, styles.sourceContentBordered)}>
<span className={styles.sourceLabels}>
<span className={styles.rowTitle}>Bank account</span>
<span className={styles.rowSub}>ACH in the US, SEPA across the euro area</span>
{/* Receive-only row: who can pay you is the full list. */}
<span className={styles.rowSub}>{BANK_SUB.payout}</span>
<span className={styles.rowSub}>Instant</span>
</span>
<SfSymbol name="chevron.right" size={14} className={styles.chevron} />
Expand Down Expand Up @@ -1052,6 +1060,9 @@ export function AddMoneySheet({
{sources.map((id, i) => {
const active = activeSources.find((a) => a.id === id);
const copy = SOURCE_COPY[id];
// Same row, different corridors by direction (see BANK_SUB).
const sub =
id === 'bank' && mode === 'add' ? BANK_SUB.funding : copy.sub;
// Crypto uses the glyph in withdraw/send; everything else (and
// add-mode crypto) is the polished SVG.
const Glyph = id === 'crypto' && mode !== 'add' ? IconWallet1 : null;
Expand Down Expand Up @@ -1091,7 +1102,7 @@ export function AddMoneySheet({
>
<span className={styles.sourceLabels}>
<span className={styles.rowTitle}>{copy.title}</span>
<span className={styles.rowSub}>{copy.sub}</span>
<span className={styles.rowSub}>{sub}</span>
<span className={styles.rowSub}>{copy.speed}</span>
</span>
<SfSymbol name="chevron.right" size={14} className={styles.chevron} />
Expand Down Expand Up @@ -1124,8 +1135,10 @@ export function AddMoneySheet({
emptyTitle={isSend ? 'No recipients yet' : 'No bank accounts yet'}
emptySub={
isSend
? 'Send to a US or euro-area bank account, or any crypto wallet'
: 'Add a US or euro-area bank account to get started'
? 'Send to a bank account in 55+ countries, or any crypto wallet'
: mode === 'add'
? 'Add a US or euro-area bank account to get started'
: 'Add a bank account in 55+ countries to cash out'
}
cta={{
label: isSend ? 'Add recipient' : 'Add bank',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,12 @@
import { useEffect, useRef, useState } from 'react';
import type { ExternalAccountInput, TransferDest } from '@/data/apiCalls';
import type { DepositSection, DepositWallet } from '@/lib/gridReads';
import { currencyFor, recipientNamesFor, type BankCountry } from '@/data/bankCountries';
import {
FUNDING_ACCOUNT_TYPES,
currencyFor,
recipientNamesFor,
type BankCountry,
} from '@/data/bankCountries';
import { useUsdRates } from '@/hooks/useUsdRates';
import { formatUsdCents, typedToCents } from './format';
import type { MoneySheetMode, ReceivedPayment, TransferActivity } from './types';
Expand Down Expand Up @@ -175,12 +180,23 @@ export function useMoneySheet({
const fxFractionDigits = stablecoinDest && isBtcDest ? 6 : 2;
const fxLabel = stablecoinDest ? cryptoCurrency : localCurrency;

// Country picker lists: Popular (by volume) on top, then All (alphabetical).
// Country picker lists: Popular on top, then All (alphabetical).
//
// PAYING OUT (withdraw, send) reaches every corridor in the list. FUNDING is
// narrower by necessity — money arrives over the rails this wallet settles, so
// Add money offers only FUNDING_ACCOUNT_TYPES. Each side has its own "popular"
// order too: payout ranks follow payment volume, funding ranks the corridors we
// can actually be paid over.
const funding = mode === 'add';
const countryPool = funding
? BANK_COUNTRIES.filter((c) => FUNDING_ACCOUNT_TYPES.includes(c.accountType))
: BANK_COUNTRIES;
Comment on lines +190 to +193

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.

P1 Funding filter conflates account eligibility

When Add Money is opened, filtering by accountType admits non-euro-area EUR_ACCOUNT countries such as Denmark, Norway, Sweden, and Switzerland, allowing users to proceed with countries outside the funding corridor advertised by this flow.

Prompt To Fix With AI
This is a comment left during a code review.
Path: components/grid-wallet-prod/src/apps/shared/wallet/useMoneySheet.ts
Line: 190-193

Comment:
**Funding filter conflates account eligibility**

When Add Money is opened, filtering by `accountType` admits non-euro-area `EUR_ACCOUNT` countries such as Denmark, Norway, Sweden, and Switzerland, allowing users to proceed with countries outside the funding corridor advertised by this flow.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

const rankOf = (c: BankCountry) => (funding ? c.fundingRank : c.popularRank) ?? 0;
const countryQ = countryQuery.trim().toLowerCase();
const allCountries = [...BANK_COUNTRIES].sort((a, b) => a.name.localeCompare(b.name));
const popularCountries = BANK_COUNTRIES.filter((c) => c.popularRank).sort(
(a, b) => (a.popularRank ?? 0) - (b.popularRank ?? 0),
);
const allCountries = [...countryPool].sort((a, b) => a.name.localeCompare(b.name));
const popularCountries = countryPool
.filter((c) => rankOf(c) > 0)
.sort((a, b) => rankOf(a) - rankOf(b));
const filteredCountries = allCountries.filter(
(c) =>
c.name.toLowerCase().includes(countryQ) ||
Expand Down
Loading
Loading