From 02ff86ed67fbd3dabd17aeed67485a4cf4d09371 Mon Sep 17 00:00:00 2001 From: Tom Linton Date: Fri, 10 Mar 2023 09:28:39 +1300 Subject: [PATCH 1/7] fix deriving on bad paths --- .../app-extension/src/components/Onboarding/pages/Finish.tsx | 2 +- .../src/components/Onboarding/pages/MnemonicSearch.tsx | 2 +- packages/blockchains/solana/src/keyring/index.ts | 2 +- packages/common/src/crypto.ts | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/app-extension/src/components/Onboarding/pages/Finish.tsx b/packages/app-extension/src/components/Onboarding/pages/Finish.tsx index 08c85da5fa..34248c9311 100644 --- a/packages/app-extension/src/components/Onboarding/pages/Finish.tsx +++ b/packages/app-extension/src/components/Onboarding/pages/Finish.tsx @@ -43,7 +43,7 @@ export const Finish = ({ isAddingAccount }: { isAddingAccount?: boolean }) => { } setLoading(false); })(); - }, [onboardingData, isAddingAccount]); + }, [background, isAddingAccount, onboardingData, maybeCreateUser]); return !loading ? ( ; diff --git a/packages/blockchains/solana/src/keyring/index.ts b/packages/blockchains/solana/src/keyring/index.ts index 923fe9c664..309f908651 100644 --- a/packages/blockchains/solana/src/keyring/index.ts +++ b/packages/blockchains/solana/src/keyring/index.ts @@ -177,7 +177,7 @@ class SolanaHdKeyring extends SolanaKeyring implements HdKeyring { public nextDerivationPath(offset = 1) { this.ensureIndices(); const derivationPath = getIndexedPath( - Blockchain.ETHEREUM, + Blockchain.SOLANA, this.accountIndex, this.walletIndex! + offset ); diff --git a/packages/common/src/crypto.ts b/packages/common/src/crypto.ts index a4f149efe6..12d6ef1bdf 100644 --- a/packages/common/src/crypto.ts +++ b/packages/common/src/crypto.ts @@ -90,7 +90,7 @@ export const getIndexedPath = ( accountIndex + HARDENING, 0 + HARDENING, ]; - if (walletIndex >= 0) path.push(walletIndex + HARDENING); + if (walletIndex > 0) path.push(walletIndex - 1 + HARDENING); return new BIPPath.fromPathArray(path).toString(); }; From 8fed88a4e245c92a3638a2cf00dc9d8fca35a46c Mon Sep 17 00:00:00 2001 From: Tom Linton Date: Fri, 10 Mar 2023 10:40:22 +1300 Subject: [PATCH 2/7] add more tests --- packages/common/src/crypto.test.ts | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/packages/common/src/crypto.test.ts b/packages/common/src/crypto.test.ts index 7275b387f2..671567a9aa 100644 --- a/packages/common/src/crypto.test.ts +++ b/packages/common/src/crypto.test.ts @@ -1,4 +1,8 @@ -import { getIndexedPath, nextIndicesFromPaths } from "./crypto"; +import { + getAccountRecoveryPaths, + getIndexedPath, + nextIndicesFromPaths, +} from "./crypto"; import { Blockchain } from "./types"; test("gets correct account index for m/44'/501'", () => { @@ -80,3 +84,19 @@ test("gets correct next path after m/44'/501'/9'/0'/2'", () => { "m/44'/501'/9'/0'/3'" ); }); + +test("gets correct account recovery paths for Solana", () => { + const recoveryPaths = getAccountRecoveryPaths(Blockchain.SOLANA, 0); + expect(recoveryPaths[0]).toEqual("m/44'/501'/0'/0'"); + expect(recoveryPaths[1]).toEqual("m/44'/501'/0'/0'/0'"); + expect(recoveryPaths[2]).toEqual("m/44'/501'/0'/0'/1'"); + expect(recoveryPaths[3]).toEqual("m/44'/501'/0'/0'/2'"); +}); + +test("gets correct account recovery paths for Ethereum", () => { + const recoveryPaths = getAccountRecoveryPaths(Blockchain.ETHEREUM, 0); + expect(recoveryPaths[0]).toEqual("m/44'/60'/0'/0'"); + expect(recoveryPaths[1]).toEqual("m/44'/60'/0'/0'/0'"); + expect(recoveryPaths[2]).toEqual("m/44'/60'/0'/0'/1'"); + expect(recoveryPaths[3]).toEqual("m/44'/60'/0'/0'/2'"); +}); From 3e9bc156e40747ef6d7cd09db058f9700faf510b Mon Sep 17 00:00:00 2001 From: Tom Linton Date: Fri, 10 Mar 2023 12:10:24 +1300 Subject: [PATCH 3/7] allow recovery of bad paths --- .../Onboarding/pages/MnemonicSearch.tsx | 28 +++++--- .../Onboarding/pages/OnboardAccount.tsx | 14 ++-- .../Onboarding/pages/RecoverAccount.tsx | 72 ++++++++++++------- .../AddConnectWallet/ImportMnemonic.tsx | 9 ++- packages/common/src/crypto.ts | 16 +++-- .../src/hooks/useSignMessageForWallet.tsx | 13 ++-- 6 files changed, 96 insertions(+), 56 deletions(-) diff --git a/packages/app-extension/src/components/Onboarding/pages/MnemonicSearch.tsx b/packages/app-extension/src/components/Onboarding/pages/MnemonicSearch.tsx index b9c2bc391a..443352e072 100644 --- a/packages/app-extension/src/components/Onboarding/pages/MnemonicSearch.tsx +++ b/packages/app-extension/src/components/Onboarding/pages/MnemonicSearch.tsx @@ -2,7 +2,11 @@ // a loading indicator until it is found (or an error if it not found). import { useEffect, useState } from "react"; -import type { ServerPublicKey, WalletDescriptor } from "@coral-xyz/common"; +import type { + Blockchain, + ServerPublicKey, + WalletDescriptor, +} from "@coral-xyz/common"; import { getRecoveryPaths, UI_RPC_METHOD_PREVIEW_PUBKEYS, @@ -22,7 +26,9 @@ export const MnemonicSearch = ({ }: { serverPublicKeys: Array; mnemonic: string; - onNext: (walletDescriptors: Array) => void; + onNext: ( + wallets: Array<{ blockchain: Blockchain; descriptor: WalletDescriptor }> + ) => void; onRetry: () => void; }) => { const [error, setError] = useState(false); @@ -30,7 +36,10 @@ export const MnemonicSearch = ({ useEffect(() => { (async () => { - const walletDescriptors: Array = []; + const wallets: Array<{ + blockchain: Blockchain; + descriptor: WalletDescriptor; + }> = []; const blockchains = [ ...new Set(serverPublicKeys.map((x) => x.blockchain)), ]; @@ -46,15 +55,18 @@ export const MnemonicSearch = ({ for (const publicKey of searchPublicKeys) { const index = publicKeys.findIndex((p: string) => p === publicKey); if (index !== -1) { - walletDescriptors.push({ - derivationPath: recoveryPaths[index], - publicKey, + wallets.push({ + blockchain, + descriptor: { + derivationPath: recoveryPaths[index], + publicKey, + }, }); } } } - if (walletDescriptors.length > 0) { - onNext(walletDescriptors); + if (wallets.length > 0) { + onNext(wallets); } else { setError(true); } diff --git a/packages/app-extension/src/components/Onboarding/pages/OnboardAccount.tsx b/packages/app-extension/src/components/Onboarding/pages/OnboardAccount.tsx index c946d41b5b..070585748f 100644 --- a/packages/app-extension/src/components/Onboarding/pages/OnboardAccount.tsx +++ b/packages/app-extension/src/components/Onboarding/pages/OnboardAccount.tsx @@ -4,15 +4,8 @@ import type { SignedWalletDescriptor, WalletDescriptor, } from "@coral-xyz/common"; -import { - getCreateMessage, - UI_RPC_METHOD_KEYRING_STORE_KEEP_ALIVE, -} from "@coral-xyz/common"; -import { - useBackgroundClient, - useOnboarding, - useSignMessageForWallet, -} from "@coral-xyz/recoil"; +import { getCreateMessage } from "@coral-xyz/common"; +import { useOnboarding, useSignMessageForWallet } from "@coral-xyz/recoil"; import { useSteps } from "../../../hooks/useSteps"; import { CreatePassword } from "../../common/Account/CreatePassword"; @@ -59,7 +52,8 @@ export const OnboardAccount = ({ signedWalletDescriptors, selectedBlockchains, } = onboardingData; - const signMessageForWallet = useSignMessageForWallet(mnemonic); + + const signMessageForWallet = useSignMessageForWallet(blockchain!, mnemonic); useEffect(() => { // Reset blockchain keyrings on certain changes that invalidate the addresses diff --git a/packages/app-extension/src/components/Onboarding/pages/RecoverAccount.tsx b/packages/app-extension/src/components/Onboarding/pages/RecoverAccount.tsx index 7ca5d7b161..b7fd5051e8 100644 --- a/packages/app-extension/src/components/Onboarding/pages/RecoverAccount.tsx +++ b/packages/app-extension/src/components/Onboarding/pages/RecoverAccount.tsx @@ -4,8 +4,13 @@ import type { SignedWalletDescriptor, WalletDescriptor, } from "@coral-xyz/common"; -import { Blockchain, getAuthMessage } from "@coral-xyz/common"; -import { useOnboarding, useSignMessageForWallet } from "@coral-xyz/recoil"; +import { + Blockchain, + getAuthMessage, + UI_RPC_METHOD_SIGN_MESSAGE_FOR_PUBLIC_KEY, +} from "@coral-xyz/common"; +import { useBackgroundClient, useOnboarding } from "@coral-xyz/recoil"; +import { ethers } from "ethers"; import { useSteps } from "../../../hooks/useSteps"; import { CreatePassword } from "../../common/Account/CreatePassword"; @@ -31,6 +36,7 @@ export const RecoverAccount = ({ isOnboarded?: boolean; }) => { const { step, nextStep, prevStep } = useSteps(); + const background = useBackgroundClient(); const { onboardingData, setOnboardingData } = useOnboarding(); const { userId, @@ -41,7 +47,6 @@ export const RecoverAccount = ({ } = onboardingData; const authMessage = userId ? getAuthMessage(userId) : ""; - const signMessageForWallet = useSignMessageForWallet(mnemonic); const hardwareOnboardSteps = useHardwareOnboardSteps({ blockchain: serverPublicKeys.length > 0 @@ -87,42 +92,61 @@ export const RecoverAccount = ({ />, ...(keyringType === "mnemonic" ? [ - // Using a mnemonic + // Using a mnemonic { - setOnboardingData({ mnemonic }); - nextStep(); - }} - />, + setOnboardingData({ mnemonic }); + nextStep(); + }} + />, ) => { - const signedWalletDescriptors = await Promise.all( - walletDescriptors.map(async (w) => ({ - ...w, - signature: await signMessageForWallet(w, authMessage), - })) - ); - setOnboardingData({ signedWalletDescriptors }); - nextStep(); - }} + onNext={async ( + wallets: Array<{ + blockchain: Blockchain; + descriptor: WalletDescriptor; + }> + ) => { + const signedWalletDescriptors = await Promise.all( + wallets.map(async ({ blockchain, descriptor }) => { + const signature = await background.request({ + method: UI_RPC_METHOD_SIGN_MESSAGE_FOR_PUBLIC_KEY, + params: [ + blockchain, + descriptor.publicKey, + ethers.utils.base58.encode( + Buffer.from(authMessage, "utf-8") + ), + [mnemonic, [descriptor.derivationPath]], + ], + }); + return { + ...descriptor, + signature, + }; + }) + ); + setOnboardingData({ signedWalletDescriptors }); + nextStep(); + }} onRetry={prevStep} - />, - ] + />, + ] : hardwareOnboardSteps), ...(!isAddingAccount ? [ { - setOnboardingData({ password }); - nextStep(); - }} - />, + + setOnboardingData({ password }); + nextStep(); + }} + />, ] : []), ...(signedWalletDescriptors.length > 0 diff --git a/packages/app-extension/src/components/Unlocked/Settings/AddConnectWallet/ImportMnemonic.tsx b/packages/app-extension/src/components/Unlocked/Settings/AddConnectWallet/ImportMnemonic.tsx index 68502ef0ba..648b12257c 100644 --- a/packages/app-extension/src/components/Unlocked/Settings/AddConnectWallet/ImportMnemonic.tsx +++ b/packages/app-extension/src/components/Unlocked/Settings/AddConnectWallet/ImportMnemonic.tsx @@ -54,7 +54,7 @@ export function ImportMnemonic({ publicKey ?? null ); const [name, setName] = useState(null); - const signMessageForWallet = useSignMessageForWallet(mnemonic); + const signMessageForWallet = useSignMessageForWallet(blockchain, mnemonic); useEffect(() => { const prevTitle = nav.title; @@ -62,7 +62,7 @@ export function ImportMnemonic({ return () => { nav.setOptions({ headerTitle: prevTitle }); }; - }, [theme]); + }, [nav, theme]); // TODO replace the left nav button to go to the previous step if step > 0 @@ -106,6 +106,7 @@ export function ImportMnemonic({ ...(inputMnemonic ? [ { setMnemonic(mnemonic); @@ -115,6 +116,7 @@ export function ImportMnemonic({ // Must prompt for a name if using an input mnemonic, because we can't // easily generate one { setName(name); nextStep(); @@ -123,7 +125,8 @@ export function ImportMnemonic({ ] : []), 0) path.push(walletIndex - 1 + HARDENING); + if (walletIndex >= 0) path.push(walletIndex + HARDENING); return new BIPPath.fromPathArray(path).toString(); }; @@ -120,8 +120,8 @@ export const getAccountRecoveryPaths = ( blockchain: Blockchain, accountIndex: number ) => { - return [...Array(LOAD_PUBLIC_KEY_AMOUNT).keys()].map((j) => - getIndexedPath(blockchain, accountIndex, j) + return [...Array(LOAD_PUBLIC_KEY_AMOUNT + 1).keys()].map((j) => + getIndexedPath(blockchain, accountIndex, j - 1) ); }; @@ -207,7 +207,15 @@ export const getRecoveryPaths = (blockchain: Blockchain) => { // Legacy imported accounts (m/44/501'/0' and m/44/501'/0'/{0...n}) paths = paths.concat(legacyBip44ChangeRecoveryPaths(blockchain)); - if (blockchain === Blockchain.ETHEREUM) { + if (blockchain === Blockchain.SOLANA) { + // Handle legacy Solana wallets that were created in 0.5.0 that had + // Ethereum derivation paths + paths = paths.concat( + getAccountRecoveryPaths(Blockchain.SOLANA, 0).map((d) => + d.replace("501", "60") + ) + ); + } else if (blockchain === Blockchain.ETHEREUM) { paths = paths.concat( [...Array(LOAD_PUBLIC_KEY_AMOUNT).keys()].map(ethereumIndexed) ); diff --git a/packages/recoil/src/hooks/useSignMessageForWallet.tsx b/packages/recoil/src/hooks/useSignMessageForWallet.tsx index 20c61e0d46..f3570fddfd 100644 --- a/packages/recoil/src/hooks/useSignMessageForWallet.tsx +++ b/packages/recoil/src/hooks/useSignMessageForWallet.tsx @@ -1,20 +1,19 @@ -import type { WalletDescriptor } from "@coral-xyz/common"; -import { - getBlockchainFromPath, - UI_RPC_METHOD_SIGN_MESSAGE_FOR_PUBLIC_KEY, -} from "@coral-xyz/common"; +import type { Blockchain, WalletDescriptor } from "@coral-xyz/common"; +import { UI_RPC_METHOD_SIGN_MESSAGE_FOR_PUBLIC_KEY } from "@coral-xyz/common"; import { ethers } from "ethers"; import { useBackgroundClient } from "./"; -export const useSignMessageForWallet = (mnemonic?: string | true) => { +export const useSignMessageForWallet = ( + blockchain: Blockchain, + mnemonic?: string | true +) => { const background = useBackgroundClient(); const signMessageForWallet = async ( walletDescriptor: WalletDescriptor, message: string ) => { - const blockchain = getBlockchainFromPath(walletDescriptor.derivationPath); return await background.request({ method: UI_RPC_METHOD_SIGN_MESSAGE_FOR_PUBLIC_KEY, params: [ From e70747da5f7c75a4bca2dda1b7639c3e12537b4c Mon Sep 17 00:00:00 2001 From: Tom Linton Date: Fri, 10 Mar 2023 13:03:40 +1300 Subject: [PATCH 4/7] move blockchain into wallet descriptor type --- .../pages/HardwareDefaultWallet.tsx | 5 +- .../Onboarding/pages/HardwareDeriveWallet.tsx | 5 +- .../Onboarding/pages/HardwareSearchWallet.tsx | 4 +- .../Onboarding/pages/MnemonicSearch.tsx | 27 ++----- .../Onboarding/pages/RecoverAccount.tsx | 78 +++++++++---------- .../ConnectHardware/index.tsx | 2 +- .../Settings/AddConnectWallet/CreateMenu.tsx | 8 +- .../AddConnectWallet/ImportMnemonic.tsx | 4 +- .../common/Account/ImportWallets.tsx | 3 +- packages/background/src/backend/core.ts | 7 +- .../background/src/backend/keyring/index.ts | 24 ++---- packages/background/src/frontend/server-ui.ts | 6 +- packages/common/src/crypto.ts | 9 --- packages/common/src/types.ts | 1 + .../recoil/src/context/OnboardingProvider.tsx | 30 ++++--- 15 files changed, 88 insertions(+), 125 deletions(-) diff --git a/packages/app-extension/src/components/Onboarding/pages/HardwareDefaultWallet.tsx b/packages/app-extension/src/components/Onboarding/pages/HardwareDefaultWallet.tsx index 31a5290265..7619431e5f 100644 --- a/packages/app-extension/src/components/Onboarding/pages/HardwareDefaultWallet.tsx +++ b/packages/app-extension/src/components/Onboarding/pages/HardwareDefaultWallet.tsx @@ -44,7 +44,7 @@ export const HardwareDefaultWallet = ({ }[blockchain]; setLedgerWallet(ledgerWallet); })(); - }, [blockchain]); + }, [blockchain, transport]); // This is effectively the same as UI_RPC_METHOD_FIND_WALLET_DESCRIPTOR useEffect(() => { @@ -92,6 +92,7 @@ export const HardwareDefaultWallet = ({ const publicKey = publicKeys[0]; const derivationPath = recoveryPaths[0]; onNext({ + blockchain, derivationPath, publicKey, }); @@ -100,7 +101,7 @@ export const HardwareDefaultWallet = ({ setAccountIndex(accountIndex + 1); } })(); - }, [ledgerWallet, accountIndex]); + }, [accountIndex, background, blockchain, ledgerWallet, onError, onNext]); return ; }; diff --git a/packages/app-extension/src/components/Onboarding/pages/HardwareDeriveWallet.tsx b/packages/app-extension/src/components/Onboarding/pages/HardwareDeriveWallet.tsx index d66d23007b..554c6c2b01 100644 --- a/packages/app-extension/src/components/Onboarding/pages/HardwareDeriveWallet.tsx +++ b/packages/app-extension/src/components/Onboarding/pages/HardwareDeriveWallet.tsx @@ -37,7 +37,7 @@ export const HardwareDeriveWallet = ({ }[blockchain]; setLedgerWallet(ledgerWallet); })(); - }, [blockchain]); + }, [blockchain, transport]); useEffect(() => { (async () => { @@ -71,11 +71,12 @@ export const HardwareDeriveWallet = ({ // path if unusable onNext({ + blockchain, derivationPath, publicKey, }); })(); - }, [ledgerWallet]); + }, [background, blockchain, ledgerWallet, onError, onNext]); return ; }; diff --git a/packages/app-extension/src/components/Onboarding/pages/HardwareSearchWallet.tsx b/packages/app-extension/src/components/Onboarding/pages/HardwareSearchWallet.tsx index f81b103726..86bb568294 100644 --- a/packages/app-extension/src/components/Onboarding/pages/HardwareSearchWallet.tsx +++ b/packages/app-extension/src/components/Onboarding/pages/HardwareSearchWallet.tsx @@ -58,13 +58,13 @@ export const HardwareSearchWallet = ({ } } if (bs58.encode(ledgerAddress) === publicKey) { - onNext({ derivationPath, publicKey }); + onNext({ blockchain, derivationPath, publicKey }); return; } } setError(true); })(); - }, [publicKey]); + }, [blockchain, publicKey, onError, onNext, transport]); if (!error) { return ; diff --git a/packages/app-extension/src/components/Onboarding/pages/MnemonicSearch.tsx b/packages/app-extension/src/components/Onboarding/pages/MnemonicSearch.tsx index 443352e072..4186e7086c 100644 --- a/packages/app-extension/src/components/Onboarding/pages/MnemonicSearch.tsx +++ b/packages/app-extension/src/components/Onboarding/pages/MnemonicSearch.tsx @@ -2,11 +2,7 @@ // a loading indicator until it is found (or an error if it not found). import { useEffect, useState } from "react"; -import type { - Blockchain, - ServerPublicKey, - WalletDescriptor, -} from "@coral-xyz/common"; +import type { ServerPublicKey, WalletDescriptor } from "@coral-xyz/common"; import { getRecoveryPaths, UI_RPC_METHOD_PREVIEW_PUBKEYS, @@ -26,9 +22,7 @@ export const MnemonicSearch = ({ }: { serverPublicKeys: Array; mnemonic: string; - onNext: ( - wallets: Array<{ blockchain: Blockchain; descriptor: WalletDescriptor }> - ) => void; + onNext: (walletDescriptors: Array) => void; onRetry: () => void; }) => { const [error, setError] = useState(false); @@ -36,10 +30,7 @@ export const MnemonicSearch = ({ useEffect(() => { (async () => { - const wallets: Array<{ - blockchain: Blockchain; - descriptor: WalletDescriptor; - }> = []; + const walletDescriptors: Array = []; const blockchains = [ ...new Set(serverPublicKeys.map((x) => x.blockchain)), ]; @@ -55,18 +46,16 @@ export const MnemonicSearch = ({ for (const publicKey of searchPublicKeys) { const index = publicKeys.findIndex((p: string) => p === publicKey); if (index !== -1) { - wallets.push({ + walletDescriptors.push({ blockchain, - descriptor: { - derivationPath: recoveryPaths[index], - publicKey, - }, + derivationPath: recoveryPaths[index], + publicKey, }); } } } - if (wallets.length > 0) { - onNext(wallets); + if (walletDescriptors.length > 0) { + onNext(walletDescriptors); } else { setError(true); } diff --git a/packages/app-extension/src/components/Onboarding/pages/RecoverAccount.tsx b/packages/app-extension/src/components/Onboarding/pages/RecoverAccount.tsx index b7fd5051e8..860d793fa3 100644 --- a/packages/app-extension/src/components/Onboarding/pages/RecoverAccount.tsx +++ b/packages/app-extension/src/components/Onboarding/pages/RecoverAccount.tsx @@ -92,61 +92,59 @@ export const RecoverAccount = ({ />, ...(keyringType === "mnemonic" ? [ - // Using a mnemonic + // Using a mnemonic { - setOnboardingData({ mnemonic }); - nextStep(); - }} - />, + setOnboardingData({ mnemonic }); + nextStep(); + }} + />, - ) => { - const signedWalletDescriptors = await Promise.all( - wallets.map(async ({ blockchain, descriptor }) => { - const signature = await background.request({ - method: UI_RPC_METHOD_SIGN_MESSAGE_FOR_PUBLIC_KEY, - params: [ - blockchain, - descriptor.publicKey, - ethers.utils.base58.encode( - Buffer.from(authMessage, "utf-8") - ), - [mnemonic, [descriptor.derivationPath]], - ], - }); - return { - ...descriptor, - signature, - }; - }) - ); - setOnboardingData({ signedWalletDescriptors }); - nextStep(); - }} + onNext={async (walletDescriptors: Array) => { + const signedWalletDescriptors = await Promise.all( + walletDescriptors.map( + async ({ blockchain, derivationPath, publicKey }) => { + const signature = await background.request({ + method: UI_RPC_METHOD_SIGN_MESSAGE_FOR_PUBLIC_KEY, + params: [ + blockchain, + publicKey, + ethers.utils.base58.encode( + Buffer.from(authMessage, "utf-8") + ), + [mnemonic, [derivationPath]], + ], + }); + return { + blockchain, + derivationPath, + publicKey, + signature, + }; + } + ) + ); + setOnboardingData({ signedWalletDescriptors }); + nextStep(); + }} onRetry={prevStep} - />, - ] + />, + ] : hardwareOnboardSteps), ...(!isAddingAccount ? [ { - - setOnboardingData({ password }); - nextStep(); - }} - />, + setOnboardingData({ password }); + nextStep(); + }} + />, ] : []), ...(signedWalletDescriptors.length > 0 diff --git a/packages/app-extension/src/components/Unlocked/Settings/AddConnectWallet/ConnectHardware/index.tsx b/packages/app-extension/src/components/Unlocked/Settings/AddConnectWallet/ConnectHardware/index.tsx index 43c818e053..f95ea7e27b 100644 --- a/packages/app-extension/src/components/Unlocked/Settings/AddConnectWallet/ConnectHardware/index.tsx +++ b/packages/app-extension/src/components/Unlocked/Settings/AddConnectWallet/ConnectHardware/index.tsx @@ -41,7 +41,7 @@ export function ConnectHardware({ UI_RPC_METHOD_BLOCKCHAIN_KEYRINGS_ADD; await background.request({ method, - params: [blockchain, signedWalletDescriptor], + params: [signedWalletDescriptor], }); }; diff --git a/packages/app-extension/src/components/Unlocked/Settings/AddConnectWallet/CreateMenu.tsx b/packages/app-extension/src/components/Unlocked/Settings/AddConnectWallet/CreateMenu.tsx index 4edea6c29b..8dc5778254 100644 --- a/packages/app-extension/src/components/Unlocked/Settings/AddConnectWallet/CreateMenu.tsx +++ b/packages/app-extension/src/components/Unlocked/Settings/AddConnectWallet/CreateMenu.tsx @@ -66,7 +66,7 @@ export function CreateMenu({ blockchain }: { blockchain: Blockchain }) { ); } })(); - }, [blockchain]); + }, [background, blockchain]); useEffect(() => { const prevTitle = nav.title; @@ -74,7 +74,7 @@ export function CreateMenu({ blockchain }: { blockchain: Blockchain }) { return () => { nav.setOptions({ headerTitle: prevTitle }); }; - }, [nav.setOptions]); + }, [nav]); useEffect(() => { (async () => { @@ -84,7 +84,7 @@ export function CreateMenu({ blockchain }: { blockchain: Blockchain }) { }); setKeyringExists(blockchainKeyrings.includes(blockchain)); })(); - }, [blockchain]); + }, [background, blockchain]); const createNewWithPhrase = async () => { // Mnemonic based keyring. This is the simple case because we don't @@ -117,7 +117,7 @@ export function CreateMenu({ blockchain }: { blockchain: Blockchain }) { }); await background.request({ method: UI_RPC_METHOD_BLOCKCHAIN_KEYRINGS_ADD, - params: [blockchain, { ...walletDescriptor, signature }], + params: [{ ...walletDescriptor, signature }], }); newPublicKey = walletDescriptor.publicKey; // Keyring now exists, toggle to other options diff --git a/packages/app-extension/src/components/Unlocked/Settings/AddConnectWallet/ImportMnemonic.tsx b/packages/app-extension/src/components/Unlocked/Settings/AddConnectWallet/ImportMnemonic.tsx index 648b12257c..4f04989999 100644 --- a/packages/app-extension/src/components/Unlocked/Settings/AddConnectWallet/ImportMnemonic.tsx +++ b/packages/app-extension/src/components/Unlocked/Settings/AddConnectWallet/ImportMnemonic.tsx @@ -74,13 +74,13 @@ export function ImportMnemonic({ // import the path pk = await background.request({ method: UI_RPC_METHOD_KEYRING_IMPORT_WALLET, - params: [blockchain, signedWalletDescriptor], + params: [signedWalletDescriptor], }); } else { // Blockchain keyring doesn't exist, init pk = await background.request({ method: UI_RPC_METHOD_BLOCKCHAIN_KEYRINGS_ADD, - params: [blockchain, signedWalletDescriptor], + params: [signedWalletDescriptor], }); } } else { diff --git a/packages/app-extension/src/components/common/Account/ImportWallets.tsx b/packages/app-extension/src/components/common/Account/ImportWallets.tsx index ad8c6cb349..098b753c66 100644 --- a/packages/app-extension/src/components/common/Account/ImportWallets.tsx +++ b/packages/app-extension/src/components/common/Account/ImportWallets.tsx @@ -210,7 +210,7 @@ export function ImportWallets({ // If the query failed assume all are valid } })(); - }, [walletDescriptors]); + }, [background, blockchain, walletDescriptors]); // // Load a list of accounts and their associated balances @@ -239,6 +239,7 @@ export function ImportWallets({ .then(async (publicKeys: string[]) => { setWalletDescriptors( derivationPaths.map((derivationPath, i) => ({ + blockchain, publicKey: publicKeys[i], derivationPath, })) diff --git a/packages/background/src/backend/core.ts b/packages/background/src/backend/core.ts index c72fbb7d9b..7065b5800f 100644 --- a/packages/background/src/backend/core.ts +++ b/packages/background/src/backend/core.ts @@ -1259,7 +1259,7 @@ export class Backend { publicKey: publicKeys[index], derivationPath: recoveryPaths[index], }; - await this.blockchainKeyringsAdd(blockchain, { + await this.blockchainKeyringsAdd({ ...walletDescriptor, signature: "", }); @@ -1549,6 +1549,7 @@ export class Backend { const publicKey = publicKeys[0]; const derivationPath = recoveryPaths[0]; return { + blockchain, derivationPath, publicKey, }; @@ -1681,15 +1682,13 @@ export class Backend { * Add a new blockchain keyring to the keyring store (i.e. initialize it). */ async blockchainKeyringsAdd( - blockchain: Blockchain, signedWalletDescriptor: SignedWalletDescriptor ): Promise { await this.keyringStore.blockchainKeyringAdd( - blockchain, signedWalletDescriptor as WalletDescriptor ); - const { signature, publicKey } = signedWalletDescriptor; + const { blockchain, signature, publicKey } = signedWalletDescriptor; // Add the new public key to the API try { diff --git a/packages/background/src/backend/keyring/index.ts b/packages/background/src/backend/keyring/index.ts index 52e3ec5a85..7c49161a20 100644 --- a/packages/background/src/backend/keyring/index.ts +++ b/packages/background/src/backend/keyring/index.ts @@ -15,7 +15,6 @@ import { BACKEND_EVENT, DEFAULT_AUTO_LOCK_INTERVAL_SECS, defaultPreferences, - getBlockchainFromPath, NOTIFICATION_KEYRING_STORE_LOCKED, } from "@coral-xyz/common"; import type { KeyringStoreState } from "@coral-xyz/recoil"; @@ -408,14 +407,10 @@ export class KeyringStore { * Initialise a blockchain keyring. */ public async blockchainKeyringAdd( - blockchain: Blockchain, walletDescriptor: WalletDescriptor, persist = true ): Promise { - await this.activeUserKeyring.blockchainKeyringAdd( - blockchain, - walletDescriptor - ); + await this.activeUserKeyring.blockchainKeyringAdd(walletDescriptor); if (persist) { await this.persist(); } @@ -668,7 +663,7 @@ class UserKeyring { keyring.mnemonic = keyringInit.mnemonic; for (const signedWalletDescriptor of keyringInit.signedWalletDescriptors) { const blockchainKeyring = keyring.blockchains.get( - getBlockchainFromPath(signedWalletDescriptor.derivationPath) + signedWalletDescriptor.blockchain ); if (blockchainKeyring) { // Blockchain keyring already exists, just add the derivation path @@ -677,16 +672,12 @@ class UserKeyring { ); } else { // No blockchain keyring, create it - await keyring.blockchainKeyringAdd( - getBlockchainFromPath(signedWalletDescriptor.derivationPath), - signedWalletDescriptor - ); + await keyring.blockchainKeyringAdd(signedWalletDescriptor); } } // Set the active wallet to be the first keyring. - keyring.activeBlockchain = getBlockchainFromPath( - keyringInit.signedWalletDescriptors[0].derivationPath - ); + keyring.activeBlockchain = + keyringInit.signedWalletDescriptors[0].blockchain; return keyring; } @@ -768,10 +759,9 @@ class UserKeyring { /////////////////////////////////////////////////////////////////////////////// public async blockchainKeyringAdd( - blockchain: Blockchain, walletDescriptor: WalletDescriptor ): Promise { - const keyring = keyringForBlockchain(blockchain); + const keyring = keyringForBlockchain(walletDescriptor.blockchain); if (this.mnemonic) { // Initialising using a mnemonic await keyring.initFromMnemonic(this.mnemonic, [ @@ -781,7 +771,7 @@ class UserKeyring { // Initialising using a hardware wallet await keyring.initFromLedger([walletDescriptor]); } - this.blockchains.set(blockchain, keyring); + this.blockchains.set(walletDescriptor.blockchain, keyring); return walletDescriptor.publicKey; } diff --git a/packages/background/src/frontend/server-ui.ts b/packages/background/src/frontend/server-ui.ts index a549b627e2..ca1b8520b9 100644 --- a/packages/background/src/frontend/server-ui.ts +++ b/packages/background/src/frontend/server-ui.ts @@ -1110,13 +1110,9 @@ async function handleSetXnftPreferences( async function handleBlockchainKeyringsAdd( ctx: Context, - blockchain: Blockchain, signedWalletDescriptor: SignedWalletDescriptor ): Promise>> { - const resp = await ctx.backend.blockchainKeyringsAdd( - blockchain, - signedWalletDescriptor - ); + const resp = await ctx.backend.blockchainKeyringsAdd(signedWalletDescriptor); return [resp]; } diff --git a/packages/common/src/crypto.ts b/packages/common/src/crypto.ts index 03f61429cc..bda62cdbe5 100644 --- a/packages/common/src/crypto.ts +++ b/packages/common/src/crypto.ts @@ -19,15 +19,6 @@ export const getCoinType = (blockchain: Blockchain) => { return coinType + HARDENING; }; -export const getBlockchainFromPath = (derivationPath: string): Blockchain => { - const coinType = BIPPath.fromString(derivationPath).toPathArray()[1]; - return Object.keys(blockchainCoinType).find( - (key) => - blockchainCoinType[key] === coinType || - blockchainCoinType[key] === coinType - HARDENING - ) as Blockchain; -}; - export const legacyBip44Indexed = (blockchain: Blockchain, index: number) => { const coinType = getCoinType(blockchain); const path = [44 + HARDENING, coinType]; diff --git a/packages/common/src/types.ts b/packages/common/src/types.ts index ea16a83d31..f63116a5b3 100644 --- a/packages/common/src/types.ts +++ b/packages/common/src/types.ts @@ -105,6 +105,7 @@ export type KeyringInit = { // Location of a public key including the public key export type WalletDescriptor = { + blockchain: Blockchain; derivationPath: string; publicKey: string; }; diff --git a/packages/recoil/src/context/OnboardingProvider.tsx b/packages/recoil/src/context/OnboardingProvider.tsx index b3a82e8e68..9b54670817 100644 --- a/packages/recoil/src/context/OnboardingProvider.tsx +++ b/packages/recoil/src/context/OnboardingProvider.tsx @@ -14,7 +14,6 @@ import { BACKEND_API_URL, Blockchain, getAuthMessage, - getBlockchainFromPath, getCreateMessage, UI_RPC_METHOD_FIND_WALLET_DESCRIPTOR, UI_RPC_METHOD_KEYRING_STORE_CREATE, @@ -147,8 +146,8 @@ export function OnboardingProvider({ selectedBlockchains: data.signedWalletDescriptors ? [ ...new Set( - data.signedWalletDescriptors.map((s: SignedWalletDescriptor) => - getBlockchainFromPath(s.derivationPath) + data.signedWalletDescriptors.map( + (s: SignedWalletDescriptor) => s.blockchain ) ), ] @@ -171,7 +170,7 @@ export function OnboardingProvider({ setOnboardingData({ blockchain: null, signedWalletDescriptors: signedWalletDescriptors.filter( - (s) => getBlockchainFromPath(s.derivationPath) !== blockchain + (s) => s.blockchain !== blockchain ), }); } else { @@ -190,6 +189,8 @@ export function OnboardingProvider({ params: [blockchain, 0, mnemonic], }); + console.log(walletDescriptor); + const signature = await background.request({ method: UI_RPC_METHOD_SIGN_MESSAGE_FOR_PUBLIC_KEY, params: [ @@ -217,7 +218,7 @@ export function OnboardingProvider({ } } }, - [data] + [background, data, setOnboardingData] ); // @@ -225,7 +226,7 @@ export function OnboardingProvider({ // const createUser = useCallback( async (data: Partial) => { - const { inviteCode, userId, username, mnemonic } = data; + const { blockchain, inviteCode, userId, username, mnemonic } = data; const keyringInit = { signedWalletDescriptors: data.signedWalletDescriptors!, @@ -238,11 +239,10 @@ export function OnboardingProvider({ // Authenticate the user that the recovery has a JWT. // Take the first keyring init to fetch the JWT, it doesn't matter which // we use if there are multiple. - const { derivationPath, publicKey, signature } = - keyringInit.signedWalletDescriptors[0]; + const { publicKey, signature } = keyringInit.signedWalletDescriptors[0]; const authData = { - blockchain: getBlockchainFromPath(derivationPath), + blockchain: blockchain!, publicKey, signature, message: getAuthMessage(userId), @@ -264,11 +264,7 @@ export function OnboardingProvider({ username, inviteCode, waitlistId: getWaitlistId?.(), - blockchainPublicKeys: keyringInit.signedWalletDescriptors.map((b) => ({ - blockchain: getBlockchainFromPath(b.derivationPath), - publicKey: b.publicKey, - signature: b.signature, - })), + blockchainPublicKeys: keyringInit.signedWalletDescriptors, }); try { @@ -289,7 +285,7 @@ export function OnboardingProvider({ throw new Error(`error creating user`); } }, - [data] + [authenticate] ); // @@ -324,7 +320,7 @@ export function OnboardingProvider({ throw new Error(`error creating account`); } }, - [data] + [background] ); const maybeCreateUser = useCallback( @@ -338,7 +334,7 @@ export function OnboardingProvider({ return { ok: false }; } }, - [data] + [createStore, createUser] ); const contextValue = useMemo( From 09680033f17e908f463d4b935944568d4218b842 Mon Sep 17 00:00:00 2001 From: Tom Linton Date: Fri, 10 Mar 2023 13:17:36 +1300 Subject: [PATCH 5/7] revert changes to onboarding provider:w --- .../recoil/src/context/OnboardingProvider.tsx | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/packages/recoil/src/context/OnboardingProvider.tsx b/packages/recoil/src/context/OnboardingProvider.tsx index 9b54670817..e51bc93581 100644 --- a/packages/recoil/src/context/OnboardingProvider.tsx +++ b/packages/recoil/src/context/OnboardingProvider.tsx @@ -189,8 +189,6 @@ export function OnboardingProvider({ params: [blockchain, 0, mnemonic], }); - console.log(walletDescriptor); - const signature = await background.request({ method: UI_RPC_METHOD_SIGN_MESSAGE_FOR_PUBLIC_KEY, params: [ @@ -218,7 +216,7 @@ export function OnboardingProvider({ } } }, - [background, data, setOnboardingData] + [data] ); // @@ -226,7 +224,7 @@ export function OnboardingProvider({ // const createUser = useCallback( async (data: Partial) => { - const { blockchain, inviteCode, userId, username, mnemonic } = data; + const { inviteCode, userId, username, mnemonic } = data; const keyringInit = { signedWalletDescriptors: data.signedWalletDescriptors!, @@ -239,7 +237,8 @@ export function OnboardingProvider({ // Authenticate the user that the recovery has a JWT. // Take the first keyring init to fetch the JWT, it doesn't matter which // we use if there are multiple. - const { publicKey, signature } = keyringInit.signedWalletDescriptors[0]; + const { blockchain, publicKey, signature } = + keyringInit.signedWalletDescriptors[0]; const authData = { blockchain: blockchain!, @@ -285,7 +284,7 @@ export function OnboardingProvider({ throw new Error(`error creating user`); } }, - [authenticate] + [data] ); // @@ -320,7 +319,7 @@ export function OnboardingProvider({ throw new Error(`error creating account`); } }, - [background] + [data] ); const maybeCreateUser = useCallback( @@ -334,7 +333,7 @@ export function OnboardingProvider({ return { ok: false }; } }, - [createStore, createUser] + [data] ); const contextValue = useMemo( From a4348424b54dcb67e539ada944e57f4430f56b50 Mon Sep 17 00:00:00 2001 From: Tom Linton Date: Fri, 10 Mar 2023 13:26:30 +1300 Subject: [PATCH 6/7] remove blockchain param from use signed wallet --- .../Onboarding/pages/OnboardAccount.tsx | 4 +-- .../Onboarding/pages/RecoverAccount.tsx | 36 ++++--------------- .../AddConnectWallet/ImportMnemonic.tsx | 2 +- .../src/hooks/useSignMessageForWallet.tsx | 9 ++--- 4 files changed, 13 insertions(+), 38 deletions(-) diff --git a/packages/app-extension/src/components/Onboarding/pages/OnboardAccount.tsx b/packages/app-extension/src/components/Onboarding/pages/OnboardAccount.tsx index 070585748f..057205f30a 100644 --- a/packages/app-extension/src/components/Onboarding/pages/OnboardAccount.tsx +++ b/packages/app-extension/src/components/Onboarding/pages/OnboardAccount.tsx @@ -53,14 +53,14 @@ export const OnboardAccount = ({ selectedBlockchains, } = onboardingData; - const signMessageForWallet = useSignMessageForWallet(blockchain!, mnemonic); + const signMessageForWallet = useSignMessageForWallet(mnemonic); useEffect(() => { // Reset blockchain keyrings on certain changes that invalidate the addresses setOnboardingData({ signedWalletDescriptors: [], }); - }, [action, keyringType, mnemonic]); + }, [action, keyringType, mnemonic, setOnboardingData]); const steps = [ { const { step, nextStep, prevStep } = useSteps(); - const background = useBackgroundClient(); const { onboardingData, setOnboardingData } = useOnboarding(); const { userId, @@ -47,6 +41,7 @@ export const RecoverAccount = ({ } = onboardingData; const authMessage = userId ? getAuthMessage(userId) : ""; + const signMessageForWallet = useSignMessageForWallet(mnemonic); const hardwareOnboardSteps = useHardwareOnboardSteps({ blockchain: serverPublicKeys.length > 0 @@ -107,27 +102,10 @@ export const RecoverAccount = ({ mnemonic={mnemonic!} onNext={async (walletDescriptors: Array) => { const signedWalletDescriptors = await Promise.all( - walletDescriptors.map( - async ({ blockchain, derivationPath, publicKey }) => { - const signature = await background.request({ - method: UI_RPC_METHOD_SIGN_MESSAGE_FOR_PUBLIC_KEY, - params: [ - blockchain, - publicKey, - ethers.utils.base58.encode( - Buffer.from(authMessage, "utf-8") - ), - [mnemonic, [derivationPath]], - ], - }); - return { - blockchain, - derivationPath, - publicKey, - signature, - }; - } - ) + walletDescriptors.map(async (w) => ({ + ...w, + signature: await signMessageForWallet(w, authMessage), + })) ); setOnboardingData({ signedWalletDescriptors }); nextStep(); diff --git a/packages/app-extension/src/components/Unlocked/Settings/AddConnectWallet/ImportMnemonic.tsx b/packages/app-extension/src/components/Unlocked/Settings/AddConnectWallet/ImportMnemonic.tsx index 4f04989999..924c50734f 100644 --- a/packages/app-extension/src/components/Unlocked/Settings/AddConnectWallet/ImportMnemonic.tsx +++ b/packages/app-extension/src/components/Unlocked/Settings/AddConnectWallet/ImportMnemonic.tsx @@ -54,7 +54,7 @@ export function ImportMnemonic({ publicKey ?? null ); const [name, setName] = useState(null); - const signMessageForWallet = useSignMessageForWallet(blockchain, mnemonic); + const signMessageForWallet = useSignMessageForWallet(mnemonic); useEffect(() => { const prevTitle = nav.title; diff --git a/packages/recoil/src/hooks/useSignMessageForWallet.tsx b/packages/recoil/src/hooks/useSignMessageForWallet.tsx index f3570fddfd..bfc94e75ed 100644 --- a/packages/recoil/src/hooks/useSignMessageForWallet.tsx +++ b/packages/recoil/src/hooks/useSignMessageForWallet.tsx @@ -1,13 +1,10 @@ -import type { Blockchain, WalletDescriptor } from "@coral-xyz/common"; +import type { WalletDescriptor } from "@coral-xyz/common"; import { UI_RPC_METHOD_SIGN_MESSAGE_FOR_PUBLIC_KEY } from "@coral-xyz/common"; import { ethers } from "ethers"; import { useBackgroundClient } from "./"; -export const useSignMessageForWallet = ( - blockchain: Blockchain, - mnemonic?: string | true -) => { +export const useSignMessageForWallet = (mnemonic?: string | true) => { const background = useBackgroundClient(); const signMessageForWallet = async ( @@ -17,7 +14,7 @@ export const useSignMessageForWallet = ( return await background.request({ method: UI_RPC_METHOD_SIGN_MESSAGE_FOR_PUBLIC_KEY, params: [ - blockchain, + walletDescriptor.blockchain, walletDescriptor.publicKey, ethers.utils.base58.encode(Buffer.from(message, "utf-8")), [mnemonic, [walletDescriptor.derivationPath]], From 1e2621a6f97029c9c18a80fb69b6bf9ad919512f Mon Sep 17 00:00:00 2001 From: Tom Linton Date: Fri, 10 Mar 2023 14:59:44 +1300 Subject: [PATCH 7/7] stash --- .../Onboarding/pages/HardwareOnboard.tsx | 4 +++- .../components/common/Account/ImportWallets.tsx | 7 ++++--- packages/background/src/backend/core.ts | 9 +++------ .../background/src/backend/keyring/index.ts | 17 ++++------------- 4 files changed, 14 insertions(+), 23 deletions(-) diff --git a/packages/app-extension/src/components/Onboarding/pages/HardwareOnboard.tsx b/packages/app-extension/src/components/Onboarding/pages/HardwareOnboard.tsx index 0910b859b6..4f5b100998 100644 --- a/packages/app-extension/src/components/Onboarding/pages/HardwareOnboard.tsx +++ b/packages/app-extension/src/components/Onboarding/pages/HardwareOnboard.tsx @@ -52,8 +52,9 @@ export function useHardwareOnboardSteps({ // Flow for onboarding a hardware wallet. // const steps = [ - , + , { setTransport(transport); @@ -141,6 +142,7 @@ export function useHardwareOnboardSteps({ ? [ // Sign the found wallet descriptor for API submit - {derivationPathOptions.map((o, index) => ( - + {derivationPathOptions.map((o) => ( + {o.label} ))} diff --git a/packages/background/src/backend/core.ts b/packages/background/src/backend/core.ts index 7065b5800f..8bc6a149a1 100644 --- a/packages/background/src/backend/core.ts +++ b/packages/background/src/backend/core.ts @@ -1180,13 +1180,10 @@ export class Backend { return SUCCESS_RESPONSE; } - async ledgerImport( - blockchain: Blockchain, - signedWalletDescriptor: SignedWalletDescriptor - ) { + async ledgerImport(signedWalletDescriptor: SignedWalletDescriptor) { const { signature, ...walletDescriptor } = signedWalletDescriptor; - const { publicKey } = walletDescriptor; - await this.keyringStore.ledgerImport(blockchain, walletDescriptor); + const { blockchain, publicKey } = walletDescriptor; + await this.keyringStore.ledgerImport(walletDescriptor); try { await this.userAccountPublicKeyCreate(blockchain, publicKey, signature); } catch (error) { diff --git a/packages/background/src/backend/keyring/index.ts b/packages/background/src/backend/keyring/index.ts index 7c49161a20..c6d359ac92 100644 --- a/packages/background/src/backend/keyring/index.ts +++ b/packages/background/src/backend/keyring/index.ts @@ -486,15 +486,9 @@ export class KeyringStore { }); } - public async ledgerImport( - blockchain: Blockchain, - walletDescriptor: WalletDescriptor - ) { + public async ledgerImport(walletDescriptor: WalletDescriptor) { return await this.withUnlockAndPersist(async () => { - return await this.activeUserKeyring.ledgerImport( - blockchain, - walletDescriptor - ); + return await this.activeUserKeyring.ledgerImport(walletDescriptor); }); } @@ -850,11 +844,8 @@ class UserKeyring { return this.mnemonic; } - public async ledgerImport( - blockchain: Blockchain, - walletDescriptor: WalletDescriptor - ) { - const blockchainKeyring = this.blockchains.get(blockchain); + public async ledgerImport(walletDescriptor: WalletDescriptor) { + const blockchainKeyring = this.blockchains.get(walletDescriptor.blockchain); const ledgerKeyring = blockchainKeyring!.ledgerKeyring!; await ledgerKeyring.add(walletDescriptor); const name = DefaultKeyname.defaultLedger(