Skip to content

Commit 9a8001b

Browse files
authored
feat: CP-12194 modify derivation path (#462)
1 parent 3a61181 commit 9a8001b

File tree

6 files changed

+222
-102
lines changed

6 files changed

+222
-102
lines changed

apps/legacy/src/components/ledger/LedgerConnector.tsx

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,12 +52,18 @@ interface LedgerConnectorProps {
5252
onSuccess: (data: LedgerConnectorData) => void;
5353
onTroubleshoot: () => void;
5454
checkIfWalletExists?: boolean;
55+
addedDerivationPath?: DerivationPath;
56+
isEditScreen?: boolean;
57+
onReset?: () => void;
5558
}
5659

5760
export function LedgerConnector({
5861
onSuccess,
5962
onTroubleshoot,
6063
checkIfWalletExists,
64+
addedDerivationPath,
65+
isEditScreen,
66+
onReset,
6167
}: LedgerConnectorProps) {
6268
const theme = useTheme();
6369
const { capture } = useAnalyticsContext();
@@ -77,12 +83,15 @@ export function LedgerConnector({
7783
const [isLedgerExistsError, setIsLedgerExistsError] = useState(false);
7884

7985
const [pathSpec, setPathSpec] = useState<DerivationPath>(
80-
DerivationPath.BIP44,
86+
addedDerivationPath || DerivationPath.BIP44,
8187
);
8288
const [addresses, setAddresses] = useState<AddressType[]>([]);
8389
const [hasPublicKeys, setHasPublicKeys] = useState(false);
84-
const [dropdownDisabled, setDropdownDisabled] = useState(true);
90+
const [dropdownDisabled, setDropdownDisabled] = useState(
91+
isEditScreen ? false : true,
92+
);
8593
const lastAccountIndexWithBalance = useRef(0);
94+
const [isLoading, setIsLoading] = useState(false);
8695

8796
const { t } = useTranslation();
8897
const { importLedger } = useImportLedger();
@@ -92,6 +101,7 @@ export function LedgerConnector({
92101
setAddresses([]);
93102
setHasPublicKeys(false);
94103
setPathSpec(DerivationPath.BIP44);
104+
onReset?.();
95105
};
96106

97107
const getAddressFromXpubKey = useCallback(
@@ -156,6 +166,7 @@ export function LedgerConnector({
156166
);
157167

158168
const getXPublicKey = useCallback(async () => {
169+
setIsLoading(true);
159170
try {
160171
const xpubValue = await getExtendedPublicKey();
161172
const xpubXPValue = await getExtendedPublicKey(
@@ -184,6 +195,8 @@ export function LedgerConnector({
184195
capture('OnboardingLedgerConnectionFailed');
185196
setPublicKeyState(LedgerStatus.LEDGER_CONNECTION_FAILED);
186197
popDeviceSelection();
198+
} finally {
199+
setIsLoading(false);
187200
}
188201
}, [
189202
getExtendedPublicKey,
@@ -217,6 +230,7 @@ export function LedgerConnector({
217230
pubKeys: PubKeyType[] = [],
218231
emptyAccounts = 0,
219232
) => {
233+
setIsLoading(true);
220234
try {
221235
const pubKey = await getPublicKey(accountIndex, derivationPathSpec);
222236
const pubKeyXP = await getPublicKey(
@@ -283,6 +297,8 @@ export function LedgerConnector({
283297
capture('OnboardingLedgerConnectionFailed');
284298
setPublicKeyState(LedgerStatus.LEDGER_CONNECTION_FAILED);
285299
popDeviceSelection();
300+
} finally {
301+
setIsLoading(false);
286302
}
287303
},
288304
[
@@ -346,6 +362,10 @@ export function LedgerConnector({
346362
// Attempt to automatically connect using Ledger Live as soon as we
347363
// establish the transport.
348364
useEffect(() => {
365+
// When in edit mode, do not auto fetch keys
366+
if (isEditScreen) {
367+
return;
368+
}
349369
const retrieveKeys = async (selectedPathSpec: DerivationPath) => {
350370
setPublicKeyState(LedgerStatus.LEDGER_LOADING);
351371
setDropdownDisabled(true);
@@ -386,6 +406,7 @@ export function LedgerConnector({
386406
getDerivationPathValue,
387407
wasTransportAttempted,
388408
getXPublicKey,
409+
isEditScreen,
389410
]);
390411

391412
return (
@@ -412,7 +433,11 @@ export function LedgerConnector({
412433
}}
413434
>
414435
<Divider flexItem />
415-
<DerivedAddresses addresses={addresses} balanceSymbol="AVAX" />
436+
<DerivedAddresses
437+
addresses={addresses}
438+
balanceSymbol="AVAX"
439+
isLoading={isLoading}
440+
/>
416441
</Stack>
417442
)}
418443
</Stack>

apps/legacy/src/components/settings/pages/Ledger.tsx

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,19 @@ import {
88
Box,
99
Divider,
1010
Scrollbars,
11+
EditIcon,
1112
} from '@avalabs/core-k2-components';
1213
import { SettingsPageProps } from '../models';
1314
import { SettingsHeader } from '../SettingsHeader';
14-
import { REQUIRED_LEDGER_VERSION, useLedgerContext } from '@core/ui';
15+
import {
16+
REQUIRED_LEDGER_VERSION,
17+
useLedgerContext,
18+
useWalletContext,
19+
} from '@core/ui';
1520
import { Trans, useTranslation } from 'react-i18next';
1621
import { ConnectionIndicatorK2 } from '../../common/ConnectionIndicatorK2';
22+
import browser from 'webextension-polyfill';
23+
import { DerivationPath } from '@avalabs/core-wallets-sdk';
1724

1825
const StyledListNumber = styled(Box)`
1926
background-color: ${({ theme }) => theme.palette.grey[800]};
@@ -37,6 +44,7 @@ const InstructionLink = styled(Typography)`
3744
export function Ledger({ goBack, navigateTo, width }: SettingsPageProps) {
3845
const { t } = useTranslation();
3946
const { hasLedgerTransport, avaxAppVersion } = useLedgerContext();
47+
const { walletDetails } = useWalletContext();
4048

4149
return (
4250
<Stack
@@ -61,10 +69,29 @@ export function Ledger({ goBack, navigateTo, width }: SettingsPageProps) {
6169
</Stack>
6270
</ListItem>
6371
{hasLedgerTransport && (
64-
<ListItem sx={{ justifyContent: 'space-between' }}>
65-
<Typography variant="body2">{t('Ledger Version')}</Typography>
66-
<Typography variant="body2">{avaxAppVersion}</Typography>
67-
</ListItem>
72+
<>
73+
<ListItem sx={{ justifyContent: 'space-between' }}>
74+
<Typography variant="body2">{t('Ledger Version')}</Typography>
75+
<Typography variant="body2">{avaxAppVersion}</Typography>
76+
</ListItem>
77+
<ListItem sx={{ justifyContent: 'space-between' }}>
78+
<Typography variant="body2">{t('Derivation Path')}</Typography>
79+
<Typography
80+
variant="body2"
81+
sx={{ cursor: 'pointer' }}
82+
onClick={() =>
83+
browser.tabs.create({
84+
url: `/fullscreen.html#/accounts/add-wallet/ledger?walletId=${walletDetails?.id}&derivationPath=${walletDetails?.derivationPath}`,
85+
})
86+
}
87+
>
88+
{walletDetails?.derivationPath === DerivationPath.LedgerLive
89+
? t('Leger Live')
90+
: t('BIP44')}{' '}
91+
<EditIcon size={14} />
92+
</Typography>
93+
</ListItem>
94+
</>
6895
)}
6996
</List>
7097
{!hasLedgerTransport && (

apps/legacy/src/localization/locales/en/translation.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,8 @@
137137
"Avalanche C-Chain": "Avalanche C-Chain",
138138
"Avalanche X/P-Chain": "Avalanche X/P-Chain",
139139
"Avoid using a password that you use with other websites or that might be easy for someone to guess.": "Avoid using a password that you use with other websites or that might be easy for someone to guess.",
140+
"BIP44": "BIP44",
141+
"BIP44 (Current)": "BIP44 (Current)",
140142
"BIP44 (Default)": "BIP44 (Default)",
141143
"Back": "Back",
142144
"Balance": "Balance",
@@ -181,6 +183,7 @@
181183
"Change Authenticator App": "Change Authenticator App",
182184
"Change Authenticator?": "Change Authenticator?",
183185
"Change Password": "Change Password",
186+
"Change the Derivation Path": "Change the Derivation Path",
184187
"Chinese - Simplified": "Chinese - Simplified",
185188
"Chinese - Traditional": "Chinese - Traditional",
186189
"Choose Verification Method": "Choose Verification Method",
@@ -524,12 +527,14 @@
524527
"Ledger": "Ledger",
525528
"Ledger Disconnected": "Ledger Disconnected",
526529
"Ledger Live": "Ledger Live",
530+
"Ledger Live (Current)": "Ledger Live (Current)",
527531
"Ledger Live Support": "Ledger Live Support",
528532
"Ledger Status": "Ledger Status",
529533
"Ledger Version": "Ledger Version",
530534
"Ledger requires you to set up a wallet policy in the Bitcoin app.": "Ledger requires you to set up a wallet policy in the Bitcoin app.",
531535
"Ledger {{number}}": "Ledger {{number}}",
532536
"Legal": "Legal",
537+
"Leger Live": "Leger Live",
533538
"Lending": "Lending",
534539
"Limit exceeded": "Limit exceeded",
535540
"Liquidity Pool": "Liquidity Pool",

apps/legacy/src/pages/Accounts/AddWalletWithLedger.tsx

Lines changed: 43 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import { LedgerWrongVersionOverlay } from '../Ledger/LedgerWrongVersionOverlay';
1616
import { PubKeyType, SecretType } from '@core/types';
1717
import { NameYourWallet } from './components/NameYourWallet';
1818
import { DerivationPath } from '@avalabs/core-wallets-sdk';
19-
import { useImportLedger } from '@core/ui';
19+
import { useAccountsContext, useImportLedger, useQueryParams } from '@core/ui';
2020
import {
2121
LedgerConnector,
2222
LedgerConnectorData,
@@ -61,9 +61,23 @@ export function AddWalletWithLedger() {
6161
const { isImporting, importLedger } = useImportLedger();
6262
const [step, setStep] = useState(Step.Import);
6363
const [hasPublicKeys, setHasPublicKeys] = useState(false);
64+
const {
65+
accounts: { primary: primaryAccounts },
66+
deleteAccounts,
67+
} = useAccountsContext();
68+
69+
const params = useQueryParams();
70+
71+
const walletId = params.get('walletId') || undefined;
72+
73+
const derivationPath = params.get('derivationPath') as DerivationPath;
74+
75+
const isEditScreen = Boolean(walletId && derivationPath);
76+
6477
const [pathSpec, setPathSpec] = useState<DerivationPath>(
6578
DerivationPath.BIP44,
6679
);
80+
6781
const lastAccountIndexWithBalance = useRef(0);
6882
const [solanaKeys, setSolanaKeys] = useState<SolanaPublicKey[]>([]);
6983

@@ -88,6 +102,14 @@ export function AddWalletWithLedger() {
88102
lastAccountIndexWithBalance.current = data.lastAccountIndexWithBalance;
89103
}
90104

105+
const onReset = () => {
106+
setXpub('');
107+
setXpubXP('');
108+
setPublicKeys(undefined);
109+
setHasPublicKeys(false);
110+
lastAccountIndexWithBalance.current = 0;
111+
};
112+
91113
const handleImport = useCallback(
92114
async (name?: string) => {
93115
try {
@@ -115,6 +137,13 @@ export function AddWalletWithLedger() {
115137
numberOfAccountsToCreate: lastAccountIndexWithBalance.current + 1,
116138
});
117139

140+
if (walletId && primaryAccounts[walletId]) {
141+
const oldLegderAccountIds = primaryAccounts[walletId].map(
142+
(account) => account.id,
143+
);
144+
await deleteAccounts(oldLegderAccountIds);
145+
}
146+
118147
capture('LedgerImportSuccess');
119148
setStep(Step.Completed);
120149
} catch (err) {
@@ -129,14 +158,16 @@ export function AddWalletWithLedger() {
129158
},
130159
[
131160
capture,
132-
getErrorMessage,
133-
importLedger,
134-
lastAccountIndexWithBalance,
135-
pathSpec,
136161
publicKeys,
162+
solanaKeys,
163+
importLedger,
137164
xpub,
138165
xpubXP,
139-
solanaKeys,
166+
pathSpec,
167+
walletId,
168+
primaryAccounts,
169+
deleteAccounts,
170+
getErrorMessage,
140171
],
141172
);
142173

@@ -243,14 +274,19 @@ export function AddWalletWithLedger() {
243274
<Stack>
244275
<Stack direction="row" alignItems="flex-start" sx={{ mb: 1 }}>
245276
<PageTitle showBackButton={false}>
246-
{t('Add Wallet with Ledger')}
277+
{isEditScreen
278+
? t('Change the Derivation Path')
279+
: t('Add Wallet with Ledger')}
247280
</PageTitle>
248281
</Stack>
249282

250283
<LedgerConnector
251284
onSuccess={onSuccess}
252285
onTroubleshoot={() => setStep(Step.Troubleshoot)}
253286
checkIfWalletExists
287+
addedDerivationPath={derivationPath}
288+
isEditScreen={isEditScreen}
289+
onReset={onReset}
254290
/>
255291
</Stack>
256292
<Stack sx={{ p: 2, mb: 2, rowGap: 1 }}>

apps/legacy/src/pages/Onboarding/components/DerivationPathDropDown.tsx

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import {
77
useTheme,
88
} from '@avalabs/core-k2-components';
99
import { Dropdown, DropdownItem } from '@/components/common/Dropdown';
10+
import { useQueryParams } from '@core/ui';
1011

1112
interface DerivationPathDropdownProps {
1213
onPathSelected: (path: DerivationPath) => void;
@@ -19,9 +20,21 @@ export function DerivationPathDropdown({
1920
onPathSelected,
2021
isDisabled,
2122
}: DerivationPathDropdownProps) {
23+
const params = useQueryParams();
24+
const defaultDerivationPath = params.get('derivationPath') as DerivationPath;
25+
2226
const { t } = useTranslation();
2327
const theme = useTheme();
2428

29+
const bip44Label =
30+
defaultDerivationPath == DerivationPath.BIP44
31+
? t('BIP44 (Current)')
32+
: t('BIP44 (Default)');
33+
const ledgerLiveLabel =
34+
defaultDerivationPath == DerivationPath.LedgerLive
35+
? t('Ledger Live (Current)')
36+
: t('Ledger Live');
37+
2538
return (
2639
<Stack>
2740
<Dropdown
@@ -42,9 +55,9 @@ export function DerivationPathDropdown({
4255
renderValue: () => {
4356
switch (pathSpec) {
4457
case DerivationPath.LedgerLive:
45-
return <Typography>{t('Ledger Live')}</Typography>;
58+
return <Typography>{ledgerLiveLabel}</Typography>;
4659
case DerivationPath.BIP44:
47-
return <Typography>{t('BIP44 (Default)')}</Typography>;
60+
return <Typography>{bip44Label}</Typography>;
4861
}
4962
},
5063
onChange: (e) => {
@@ -69,7 +82,7 @@ export function DerivationPathDropdown({
6982
width: '100%',
7083
}}
7184
>
72-
<Typography variant="body2">{t('BIP44 (Default)')}</Typography>
85+
<Typography variant="body2">{bip44Label}</Typography>
7386
{pathSpec === DerivationPath.BIP44 && <CheckIcon />}
7487
</Stack>
7588
</DropdownItem>
@@ -86,7 +99,7 @@ export function DerivationPathDropdown({
8699
width: '100%',
87100
}}
88101
>
89-
<Typography variant="body2">{t('Ledger Live')}</Typography>
102+
<Typography variant="body2">{ledgerLiveLabel}</Typography>
90103
{pathSpec === DerivationPath.LedgerLive && <CheckIcon />}
91104
</Stack>
92105
</DropdownItem>

0 commit comments

Comments
 (0)