Skip to content

Commit 5aaa24d

Browse files
committed
chore: increases design parity for swap setup screens (and minor refactors)
1 parent e46e3fa commit 5aaa24d

File tree

6 files changed

+144
-61
lines changed

6 files changed

+144
-61
lines changed

ui/helpers/utils/remote-mode.test.ts

+37-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
1+
import { Hex } from 'viem';
12
import type { InternalAccount } from '@metamask/keyring-internal-api';
2-
import { isRemoteModeSupported } from './remote-mode';
3+
4+
import { CHAIN_IDS } from '../../../shared/constants/network';
5+
import {
6+
getChainNamesForDisplayByIds,
7+
isRemoteModeSupported,
8+
} from './remote-mode';
39

410
describe('Remote Mode Utils', () => {
511
describe('isRemoteModeSupported', () => {
@@ -61,3 +67,33 @@ describe('Remote Mode Utils', () => {
6167
});
6268
});
6369
});
70+
71+
describe('getChainNamesForDisplayByIds', () => {
72+
it('returns the correct chain name for a single known chain', () => {
73+
expect(getChainNamesForDisplayByIds([CHAIN_IDS.MAINNET])).toBe(
74+
'Ethereum Mainnet',
75+
);
76+
});
77+
78+
it('returns multiple chain names separated by commas', () => {
79+
expect(
80+
getChainNamesForDisplayByIds([CHAIN_IDS.MAINNET, CHAIN_IDS.SEPOLIA]),
81+
).toBe('Ethereum Mainnet, Sepolia');
82+
});
83+
84+
it('returns "Unknown" for unrecognized chain IDs', () => {
85+
expect(getChainNamesForDisplayByIds(['0x1234' as Hex])).toBe(
86+
'Unknown(0x1234)',
87+
);
88+
});
89+
90+
it('handles a mix of known and unknown chain IDs', () => {
91+
expect(
92+
getChainNamesForDisplayByIds([CHAIN_IDS.MAINNET, '0x1234' as Hex]),
93+
).toBe('Ethereum Mainnet, Unknown(0x1234)');
94+
});
95+
96+
it('returns an empty string for empty input', () => {
97+
expect(getChainNamesForDisplayByIds([])).toBe('');
98+
});
99+
});

ui/helpers/utils/remote-mode.ts

+13-2
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,21 @@
1+
import { Hex } from 'viem';
12
import type { InternalAccount } from '@metamask/keyring-internal-api';
2-
3-
const SUPPORTED_HARDWARE_WALLET_TYPES = ['Ledger Hardware', 'Lattice Hardware'];
3+
import { SUPPORTED_HARDWARE_WALLET_TYPES } from '../../pages/remote-mode/remote.constants';
4+
import { NETWORK_TO_NAME_MAP } from '../../../shared/constants/network';
45

56
export function isRemoteModeSupported(account: InternalAccount) {
67
// todo: add check that account also implements signEip7702Authorization()
78
return SUPPORTED_HARDWARE_WALLET_TYPES.includes(
89
account.metadata.keyring.type,
910
);
1011
}
12+
13+
export function getChainNamesForDisplayByIds(chainIds: Hex[]): string {
14+
return chainIds
15+
.map(
16+
(id) =>
17+
NETWORK_TO_NAME_MAP[id as keyof typeof NETWORK_TO_NAME_MAP] ||
18+
`Unknown(${id})`,
19+
)
20+
.join(', ');
21+
}

ui/pages/remote-mode/components/swap-allowance-card/remote-mode-swap-allowance-card.component.tsx

+14-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,10 @@ import {
1919
BorderRadius,
2020
AlignItems,
2121
} from '../../../../helpers/constants/design-system';
22+
2223
import { SwapAllowance, TokenInfo, TOKEN_DETAILS } from '../../remote.types';
24+
import { getChainNamesForDisplayByIds } from '../../../../helpers/utils/remote-mode';
25+
import { SUPPORTED_CHAINS_IDS } from '../../remote.constants';
2326

2427
/**
2528
* RemoteModeSwapAllowanceCard displays a card showing swap allowance details
@@ -94,7 +97,17 @@ export default function RemoteModeSwapAllowanceCard({
9497
>
9598
<Text variant={TextVariant.bodyMd}>Daily limit</Text>
9699
<Text variant={TextVariant.bodyMd} color={TextColor.textAlternative}>
97-
{swapAllowance.amount}
100+
{swapAllowance.amount} {selectedToken.symbol}
101+
</Text>
102+
</Box>
103+
<Box
104+
display={Display.Flex}
105+
justifyContent={JustifyContent.spaceBetween}
106+
gap={2}
107+
>
108+
<Text variant={TextVariant.bodyMd}>Networks</Text>
109+
<Text variant={TextVariant.bodyMd} color={TextColor.textAlternative}>
110+
{getChainNamesForDisplayByIds(SUPPORTED_CHAINS_IDS)}
98111
</Text>
99112
</Box>
100113
</Box>
+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import { CHAIN_IDS } from '../../../shared/constants/network';
2+
3+
export const SUPPORTED_CHAINS_IDS = [CHAIN_IDS.MAINNET];
4+
5+
export const SUPPORTED_HARDWARE_WALLET_TYPES = [
6+
'Ledger Hardware',
7+
'Lattice Hardware',
8+
];

ui/pages/remote-mode/remote.types.ts

+14-2
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
export enum TokenSymbol {
44
USDC = 'USDC',
55
WETH = 'WETH',
6+
WBTC = 'WBTC',
7+
BNB = 'BNB',
68
}
79
export type TokenInfo = {
810
symbol: TokenSymbol;
@@ -21,6 +23,16 @@ export const TOKEN_DETAILS: Record<TokenSymbol, TokenInfo> = {
2123
name: 'WETH',
2224
iconUrl: './images/eth_logo.png',
2325
},
26+
[TokenSymbol.WBTC]: {
27+
symbol: TokenSymbol.WBTC,
28+
name: 'WBTC',
29+
iconUrl: './images/eth_logo.png', // TODO: add WBTC icon
30+
},
31+
[TokenSymbol.BNB]: {
32+
symbol: TokenSymbol.BNB,
33+
name: 'BNB',
34+
iconUrl: './images/eth_logo.png', // TODO: add BNB icon
35+
},
2436
};
2537

2638
export type SwapAllowance = {
@@ -30,8 +42,8 @@ export type SwapAllowance = {
3042
};
3143

3244
export enum ToTokenOption {
33-
Any = 'Any available token',
34-
HighLiquidity = 'High liquidity tokens',
45+
AllowedOutcome = 'Select allowed outcome token',
46+
Any = 'Any token on Ethereum Mainnet',
3547
}
3648

3749
export enum DailyAllowanceTokenTypes {

ui/pages/remote-mode/setup/setup-swaps/remote-mode-setup-swaps.component.tsx

+58-55
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ import {
77
AvatarAccount,
88
AvatarAccountSize,
99
AvatarAccountVariant,
10+
AvatarIcon,
11+
AvatarIconSize,
1012
BannerAlert,
1113
BannerAlertSeverity,
1214
Box,
@@ -88,7 +90,7 @@ export default function RemoteModeSetupSwaps() {
8890
TokenSymbol.USDC,
8991
);
9092
const [selectedToToken, setSelectedToToken] = useState<ToTokenOption>(
91-
ToTokenOption.Any,
93+
ToTokenOption.AllowedOutcome,
9294
);
9395
const [dailyLimit, setDailyLimit] = useState<string>('');
9496
const [isAllowancesExpanded, setIsAllowancesExpanded] =
@@ -155,7 +157,7 @@ export default function RemoteModeSetupSwaps() {
155157
});
156158

157159
setSelectedFromToken(TokenSymbol.USDC);
158-
setSelectedToToken(ToTokenOption.Any);
160+
setSelectedToToken(ToTokenOption.AllowedOutcome);
159161
setDailyLimit('');
160162
};
161163

@@ -281,16 +283,10 @@ export default function RemoteModeSetupSwaps() {
281283
onChange={(value) =>
282284
setSelectedFromToken(value as TokenSymbol)
283285
}
284-
options={[
285-
{
286-
name: 'USDC',
287-
value: TokenSymbol.USDC,
288-
},
289-
{
290-
name: 'WETH',
291-
value: TokenSymbol.WETH,
292-
},
293-
]}
286+
options={Object.values(TokenSymbol).map((value) => ({
287+
name: value,
288+
value,
289+
}))}
294290
selectedOption={selectedFromToken}
295291
title="Select token"
296292
style={{ width: '100%' }}
@@ -319,35 +315,28 @@ export default function RemoteModeSetupSwaps() {
319315
flexDirection={FlexDirection.Column}
320316
gap={2}
321317
marginTop={2}
318+
marginBottom={4}
322319
>
323320
<Text>Swap to</Text>
324321
<Dropdown
325322
onChange={(value) =>
326323
setSelectedToToken(value as ToTokenOption)
327324
}
328-
options={[
329-
{
330-
name: ToTokenOption.Any,
331-
value: ToTokenOption.Any,
332-
},
333-
{
334-
name: ToTokenOption.HighLiquidity,
335-
value: ToTokenOption.HighLiquidity,
336-
},
337-
]}
325+
options={Object.values(ToTokenOption).map((value) => ({
326+
name: value,
327+
value,
328+
}))}
338329
selectedOption={selectedToToken}
339330
title="Select token"
340331
style={{ width: '100%' }}
341332
/>
342333
</Box>
343-
<Text
344-
variant={TextVariant.bodySm}
345-
marginTop={1}
346-
marginBottom={2}
347-
>
348-
Tip: This is a higher risk option if your authorized account
349-
is compromised.
350-
</Text>
334+
{selectedToToken === ToTokenOption.Any && (
335+
<Text variant={TextVariant.bodySm} marginBottom={4}>
336+
Tip: This is a higher risk option if your authorized account
337+
is compromised.
338+
</Text>
339+
)}
351340
<Button
352341
width={BlockSize.Full}
353342
size={ButtonSize.Lg}
@@ -369,15 +358,16 @@ export default function RemoteModeSetupSwaps() {
369358
</Box>
370359
</Card>
371360
<Box marginTop={4} marginBottom={2}>
372-
<Text>Only redeemable with MetaMask Swaps</Text>
361+
<Text>Only for MetaMask Swaps</Text>
373362
<Text color={TextColor.textMuted}>
374-
The allowances are only redeemable by the authorized account to
375-
use MetaMask Swaps, which comes with MEV protection.
363+
The authorized account can only use these allowances for
364+
MetaMask Swaps, which includes MEV protection to help prevent
365+
front-running and sandwich attacks.
376366
</Text>
377-
<Text>Slippage protection</Text>
367+
<Text marginTop={2}>Slippage protection</Text>
378368
<Text color={TextColor.textMuted}>
379369
Swap quotes are only received from DEX aggregators that have
380-
slippage/price protections.
370+
slippage and price protections.
381371
</Text>
382372
</Box>
383373
</Box>
@@ -431,26 +421,33 @@ export default function RemoteModeSetupSwaps() {
431421
<>
432422
<Card
433423
backgroundColor={BackgroundColor.backgroundMuted}
424+
marginTop={2}
434425
marginBottom={4}
435426
>
436427
<Box
437428
display={Display.Flex}
438429
gap={2}
439430
justifyContent={JustifyContent.spaceBetween}
440431
>
441-
<Box>
442-
<Text>Enable Remote Swaps</Text>
443-
<Text
444-
color={TextColor.textMuted}
445-
variant={TextVariant.bodySm}
446-
>
447-
Permission from {selectedHardwareAccount.metadata.name}
448-
</Text>
432+
<Box display={Display.Flex} gap={2}>
433+
<AvatarIcon
434+
iconName={IconName.Star}
435+
size={AvatarIconSize.Lg}
436+
/>
437+
<Box>
438+
<Text>Switch to to smart account</Text>
439+
<Text
440+
color={TextColor.textMuted}
441+
variant={TextVariant.bodySm}
442+
>
443+
Permission from {selectedHardwareAccount.metadata.name}
444+
</Text>
445+
</Box>
449446
</Box>
450447
<Text
451448
color={TextColor.infoDefault}
452449
onClick={() => {
453-
setCurrentStep(1);
450+
setCurrentStep(2);
454451
}}
455452
style={{ cursor: 'pointer' }}
456453
>
@@ -470,19 +467,25 @@ export default function RemoteModeSetupSwaps() {
470467
gap={2}
471468
justifyContent={JustifyContent.spaceBetween}
472469
>
473-
<Box>
474-
<Text>Update to smart account</Text>
475-
<Text
476-
color={TextColor.textMuted}
477-
variant={TextVariant.bodySm}
478-
>
479-
Permission from {selectedHardwareAccount.metadata.name}
480-
</Text>
470+
<Box display={Display.Flex} gap={2}>
471+
<AvatarIcon
472+
iconName={IconName.SwapHorizontal}
473+
size={AvatarIconSize.Lg}
474+
/>
475+
<Box>
476+
<Text>Set up Remote Swaps</Text>
477+
<Text
478+
color={TextColor.textMuted}
479+
variant={TextVariant.bodySm}
480+
>
481+
Permission from {selectedHardwareAccount.metadata.name}
482+
</Text>
483+
</Box>
481484
</Box>
482485
<Text
483486
color={TextColor.infoDefault}
484487
onClick={() => {
485-
setCurrentStep(2);
488+
setCurrentStep(1);
486489
}}
487490
style={{ cursor: 'pointer' }}
488491
>
@@ -503,9 +506,9 @@ export default function RemoteModeSetupSwaps() {
503506
</Text>
504507
<Text color={TextColor.infoDefault}>
505508
{isAllowancesExpanded ? (
506-
<Icon name={IconName.ArrowUp} size={IconSize.Sm} />
507-
) : (
508509
<Icon name={IconName.ArrowDown} size={IconSize.Sm} />
510+
) : (
511+
<Icon name={IconName.ArrowUp} size={IconSize.Sm} />
509512
)}
510513
</Text>
511514
</Box>

0 commit comments

Comments
 (0)