Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: CP-9472 add duplicated account dialog #90

Merged
merged 8 commits into from
Dec 5, 2024
Merged
Show file tree
Hide file tree
Changes from 6 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
16 changes: 16 additions & 0 deletions src/background/services/wallet/handlers/importLedger.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,22 @@ describe('src/background/services/wallet/handlers/importLedger', () => {

expect(error).toEqual('This wallet already exists');
});
it('should return with the id as `0` and the given `SecretType` after it checked the wallet is exist', async () => {
secretsService.isKnownSecret.mockResolvedValueOnce(false);

const { result } = await handle({
secretType: SecretType.Ledger,
xpub: 'xpubValue',
name: 'name',
dryRun: true,
});

expect(result).toEqual({
id: '0',
name: 'name',
type: SecretType.Ledger,
});
});

it('returns an ImportWalletResult if Ledger import is successful', async () => {
const walletId = crypto.randomUUID();
Expand Down
14 changes: 13 additions & 1 deletion src/background/services/wallet/handlers/importLedger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@ export class ImportLedgerHandler implements HandlerType {
}

handle: HandlerType['handle'] = async ({ request }) => {
const [{ xpub, xpubXP, pubKeys, secretType, name }] = request.params;
const [{ xpub, xpubXP, pubKeys, secretType, name, dryRun }] =
request.params;

if (
secretType !== SecretType.Ledger &&
Expand Down Expand Up @@ -68,6 +69,17 @@ export class ImportLedgerHandler implements HandlerType {
};
}

if (dryRun) {
return {
...request,
result: {
id: '0',
name,
type: secretType,
},
};
}

let id: string;
if (secretType === SecretType.Ledger) {
id = await this.walletService.addPrimaryWallet({
Expand Down
1 change: 1 addition & 0 deletions src/background/services/wallet/handlers/models.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export type ImportLedgerWalletParams = {
pubKeys?: PubKeyType[];
secretType: SecretType.Ledger | SecretType.LedgerLive;
name?: string;
dryRun?: boolean;
};

export type ImportWalletResult = {
Expand Down
91 changes: 75 additions & 16 deletions src/components/ledger/LedgerConnector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ import {
} from '@avalabs/core-k2-components';
import { DerivationPathDropdown } from '@src/pages/Onboarding/components/DerivationPathDropDown';
import { DerivedAddresses } from '@src/pages/Onboarding/components/DerivedAddresses';
import { SecretType } from '@src/background/services/secrets/models';
import { useImportLedger } from '@src/pages/Accounts/hooks/useImportLedger';

export interface AddressType {
address: string;
Expand Down Expand Up @@ -48,11 +50,13 @@ export interface LedgerConnectorData {
interface LedgerConnectorProps {
onSuccess: (data: LedgerConnectorData) => void;
onTroubleshoot: () => void;
isWalletExist?: boolean;
}

export function LedgerConnector({
onSuccess,
onTroubleshoot,
isWalletExist,
vvava marked this conversation as resolved.
Show resolved Hide resolved
}: LedgerConnectorProps) {
const theme = useTheme();
const { capture } = useAnalyticsContext();
Expand All @@ -69,6 +73,7 @@ export function LedgerConnector({
const [publicKeyState, setPublicKeyState] = useState<LedgerStatus>(
LedgerStatus.LEDGER_UNINITIATED
);
const [isLedgerExistsError, setIsLedgerExistsError] = useState(false);

const [pathSpec, setPathSpec] = useState<DerivationPath>(
DerivationPath.BIP44
Expand All @@ -77,6 +82,7 @@ export function LedgerConnector({
const [hasPublicKeys, setHasPublicKeys] = useState(false);
const [dropdownDisabled, setDropdownDisabled] = useState(true);
const { t } = useTranslation();
const { importLedger } = useImportLedger();

const resetStates = () => {
setPublicKeyState(LedgerStatus.LEDGER_LOADING);
Expand Down Expand Up @@ -110,12 +116,42 @@ export function LedgerConnector({
[capture, getAvaxBalance]
);

const isLedgerWalletExist = useCallback(
async ({ xpub, xpubXP, publicKeys, derivationPath }) => {
setIsLedgerExistsError(false);
try {
return await importLedger({
xpub,
xpubXP,
pubKeys: publicKeys,
secretType:
derivationPath === DerivationPath.BIP44
? SecretType.Ledger
: SecretType.LedgerLive,
dryRun: true,
});
} catch (e) {
setIsLedgerExistsError(true);
throw new Error('wallet already exists');
vvava marked this conversation as resolved.
Show resolved Hide resolved
}
},
[importLedger]
);

const getXPublicKey = useCallback(async () => {
try {
const xpubValue = await getExtendedPublicKey();
const xpubXPValue = await getExtendedPublicKey(
Avalanche.LedgerWallet.getAccountPath('X')
);
if (isWalletExist) {
await isLedgerWalletExist({
xpub: xpubValue,
xpubXP: xpubXPValue,
publicKeys: undefined,
derivationPath: DerivationPath.BIP44,
});
}
setPublicKeyState(LedgerStatus.LEDGER_CONNECTED);
capture('OnboardingLedgerConnected');
await getAddressFromXpubKey(xpubValue, 0);
Expand All @@ -133,6 +169,8 @@ export function LedgerConnector({
}
}, [
capture,
isLedgerWalletExist,
isWalletExist,
getAddressFromXpubKey,
getExtendedPublicKey,
onSuccess,
Expand Down Expand Up @@ -187,6 +225,14 @@ export function LedgerConnector({
...pubKeys,
{ evm: pubKey.toString('hex'), xp: pubKeyXP.toString('hex') },
];
if (isWalletExist) {
await isLedgerWalletExist({
xpub: '',
xpubXP: '',
publicKeys: publicKeyValue,
derivationPath: DerivationPath.LedgerLive,
});
}
setHasPublicKeys(true);
onSuccess({
xpub: '',
Expand All @@ -202,7 +248,15 @@ export function LedgerConnector({
popDeviceSelection();
}
},
[capture, getAvaxBalance, getPublicKey, onSuccess, popDeviceSelection]
[
capture,
isLedgerWalletExist,
isWalletExist,
getAvaxBalance,
getPublicKey,
onSuccess,
popDeviceSelection,
]
);

const tryPublicKey = useCallback(async () => {
Expand Down Expand Up @@ -336,21 +390,26 @@ export function LedgerConnector({
variant="caption"
sx={{ color: theme.palette.error.main }}
>
<Trans
i18nKey="Unable to connect. View the troubleshoot guide <linkText>here</linkText>"
components={{
linkText: (
<span
onClick={() => onTroubleshoot()}
style={{
cursor: 'pointer',
textDecoration: 'underline',
textDecorationColor: theme.palette.error.main,
}}
/>
),
}}
/>
{!isLedgerExistsError && (
<Trans
i18nKey={
'Unable to connect. View the troubleshoot guide <linkText>here</linkText>'
}
components={{
linkText: (
<span
onClick={() => onTroubleshoot()}
style={{
cursor: 'pointer',
textDecoration: 'underline',
textDecorationColor: theme.palette.error.main,
}}
/>
),
}}
/>
)}
{isLedgerExistsError && t('This wallet already exists')}
</Typography>
</Stack>
<Button onClick={() => tryPublicKey()} fullWidth>
Expand Down
3 changes: 3 additions & 0 deletions src/localization/locales/en/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -396,6 +396,7 @@
"Import": "Import",
"Import Account": "Import Account",
"Import Details": "Import Details",
"Import Duplicate Account?": "Import Duplicate Account?",
"Import Keystore File": "Import Keystore File",
"Import Private Key": "Import Private Key",
"Import with Fireblocks": "Import with Fireblocks",
Expand Down Expand Up @@ -832,6 +833,7 @@
"This Feature": "This Feature",
"This Ledger was not used to create this wallet. Please connect the original Ledger device to continue.": "This Ledger was not used to create this wallet. Please connect the original Ledger device to continue.",
"This URL is invalid": "This URL is invalid",
"This account has already been imported, do you want to continue?": "This account has already been imported, do you want to continue?",
"This action is only allowed for Seedless wallets.": "This action is only allowed for Seedless wallets.",
"This address already exists in the address book": "This address already exists in the address book",
"This application is malicious, do not proceed.": "This application is malicious, do not proceed.",
Expand All @@ -849,6 +851,7 @@
"This transaction is malicious do not proceed.": "This transaction is malicious do not proceed.",
"This transaction requires multiple approvals.": "This transaction requires multiple approvals.",
"This transaction requires two approvals": "This transaction requires two approvals",
"This wallet already exists": "This wallet already exists",
"This website": "This website",
"Threshold": "Threshold",
"Time Elapsed": "Time Elapsed",
Expand Down
1 change: 1 addition & 0 deletions src/pages/Accounts/AddWalletWithLedger.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,7 @@ export function AddWalletWithLedger() {
<LedgerConnector
onSuccess={onSuccess}
onTroubleshoot={() => setStep(Step.Troubleshoot)}
isWalletExist
/>
</Stack>
<Stack sx={{ p: 2, mb: 2, rowGap: 1 }}>
Expand Down
Loading
Loading