Skip to content

Commit 3875875

Browse files
committed
feat: add secret keys for imported accounts in encrypted wallet file
1 parent 62ef27c commit 3875875

File tree

14 files changed

+99
-33
lines changed

14 files changed

+99
-33
lines changed

src/app/pages/Welcome.tsx

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ const Welcome: FC = () => {
4242
const [importedWithFile, setImportedWithFile] = useState(false);
4343
const [isLoading, setIsLoading] = useState(false);
4444
const [importedWalletAccounts, setImportedWalletAccounts] = useState<WalletAccount[]>([]);
45+
const [skForImportedAccounts, setSkForImportedAccounts] = useState<Record<string, string>>({});
4546
const { registerWallet, importWalletFromClient } = useMidenContext();
4647
const { trackEvent } = useAnalytics();
4748
const syncFromBackend = useWalletStore(s => s.syncFromBackend);
@@ -62,7 +63,7 @@ const Welcome: FC = () => {
6263
} else {
6364
try {
6465
console.log('importing wallet from client');
65-
await importWalletFromClient(password, seedPhraseFormatted, importedWalletAccounts);
66+
await importWalletFromClient(password, seedPhraseFormatted, importedWalletAccounts, skForImportedAccounts);
6667
} catch (e) {
6768
console.error(e);
6869
}
@@ -75,7 +76,8 @@ const Welcome: FC = () => {
7576
registerWallet,
7677
onboardingType,
7778
importWalletFromClient,
78-
importedWalletAccounts
79+
importedWalletAccounts,
80+
skForImportedAccounts
7981
]);
8082

8183
const onAction = async (action: OnboardingAction) => {
@@ -100,6 +102,7 @@ const Welcome: FC = () => {
100102
const seedPhrase = action.payload.split(' ');
101103
setSeedPhrase(seedPhrase);
102104
setImportedWalletAccounts(action.walletAccounts);
105+
setSkForImportedAccounts(action.skForImportedAccounts);
103106
setImportedWithFile(true);
104107
navigate('/#create-password');
105108
break;

src/lib/miden/back/actions.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,9 +76,14 @@ export function registerNewWallet(password: string, mnemonic?: string, ownMnemon
7676
});
7777
}
7878

79-
export function registerImportedWallet(password: string, mnemonic: string, walletAccounts: WalletAccount[]) {
79+
export function registerImportedWallet(
80+
password: string,
81+
mnemonic: string,
82+
walletAccounts: WalletAccount[],
83+
skForImportedAccounts: Record<string, string>
84+
) {
8085
return withInited(async () => {
81-
await Vault.spawnFromMidenClient(password, mnemonic, walletAccounts);
86+
await Vault.spawnFromMidenClient(password, mnemonic, walletAccounts, skForImportedAccounts);
8287
await unlock(password);
8388
});
8489
}

src/lib/miden/back/main.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ async function processRequest(req: WalletRequest, port: Runtime.Port): Promise<W
3939
await Actions.registerNewWallet(req.password, req.mnemonic, req.ownMnemonic);
4040
return { type: WalletMessageType.NewWalletResponse };
4141
case WalletMessageType.ImportFromClientRequest:
42-
await Actions.registerImportedWallet(req.password, req.mnemonic, req.walletAccounts);
42+
await Actions.registerImportedWallet(req.password, req.mnemonic, req.walletAccounts, req.skForImportedAccounts);
4343
return { type: WalletMessageType.ImportFromClientResponse };
4444
case WalletMessageType.UnlockRequest:
4545
await Actions.unlock(req.password);

src/lib/miden/back/vault.ts

Lines changed: 28 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,12 @@ export class Vault {
134134
});
135135
}
136136

137-
static async spawnFromMidenClient(password: string, mnemonic: string, walletAccounts: WalletAccount[]) {
137+
static async spawnFromMidenClient(
138+
password: string,
139+
mnemonic: string,
140+
walletAccounts: WalletAccount[],
141+
skForImportedAccounts: Record<string, string>
142+
) {
138143
return withError('Failed to spawn from miden client', async () => {
139144
await clearStorage(false);
140145

@@ -160,9 +165,18 @@ export class Vault {
160165
if (!walletAccount) {
161166
throw new PublicError('Account from Miden Client not found in provided wallet accounts');
162167
}
163-
const walletSeed = deriveClientSeed(walletAccount.type, mnemonic, walletAccount.hdIndex);
164-
const secretKey = SecretKey.rpoFalconWithRNG(walletSeed);
165-
await midenClient.webClient.addAccountSecretKeyToWebStore(secretKey);
168+
if (walletAccount.hdIndex === -1) {
169+
const skHex = skForImportedAccounts[walletAccount.publicKey];
170+
if (!skHex) {
171+
throw new PublicError('Secret key for imported account not found');
172+
}
173+
const sk = SecretKey.deserialize(new Uint8Array(Buffer.from(skHex, 'hex')));
174+
await midenClient.webClient.addAccountSecretKeyToWebStore(sk);
175+
} else {
176+
const walletSeed = deriveClientSeed(walletAccount.type, mnemonic, walletAccount.hdIndex);
177+
const secretKey = SecretKey.rpoFalconWithRNG(walletSeed);
178+
await midenClient.webClient.addAccountSecretKeyToWebStore(secretKey);
179+
}
166180
}
167181
});
168182

@@ -348,11 +362,16 @@ export class Vault {
348362
static async revealPrivateKey(accPublicKey: string, password: string) {
349363
const passKey = await Vault.toValidPassKey(password);
350364
return await withError('Failed to reveal private key', async () => {
351-
const secretKeyHex = await fetchAndDecryptOneWithLegacyFallBack<string>(
352-
accAuthSecretKeyStrgKey(accPublicKey),
353-
passKey
354-
);
355-
return secretKeyHex;
365+
try {
366+
const secretKeyHex = await fetchAndDecryptOneWithLegacyFallBack<string>(
367+
accAuthSecretKeyStrgKey(accPublicKey),
368+
passKey
369+
);
370+
return secretKeyHex;
371+
} catch (e) {
372+
console.error('Error fetching and decrypting private key:', e);
373+
throw e;
374+
}
356375
});
357376
}
358377

@@ -363,12 +382,10 @@ export class Vault {
363382
const pubKeyWord = secretKey.publicKey().toCommitment();
364383

365384
const pubKeyHex = pubKeyWord.toHex().slice(2); // remove '0x' prefix
366-
console.log({ pubKeyHex });
367385
const publicKey = await withWasmClientLock(async () => {
368386
const midenClient = await getMidenClient();
369387
return await midenClient.importPublicAccountFromPrivateKey(secretKey);
370388
});
371-
console.log({ publicKey });
372389
const newAccount: WalletAccount = {
373390
publicKey,
374391
name: getNewAccountName(allAccounts),

src/lib/miden/front/client.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,8 +103,13 @@ export const [MidenContextProvider, useMidenContext] = constate(() => {
103103
);
104104

105105
const importWalletFromClient = useCallback(
106-
async (password: string, mnemonic: string, walletAccounts: WalletAccount[]) => {
107-
await storeImportWalletFromClient(password, mnemonic, walletAccounts);
106+
async (
107+
password: string,
108+
mnemonic: string,
109+
walletAccounts: WalletAccount[],
110+
skForImportedAccounts: Record<string, string>
111+
) => {
112+
await storeImportWalletFromClient(password, mnemonic, walletAccounts, skForImportedAccounts);
108113
},
109114
[storeImportWalletFromClient]
110115
);

src/lib/miden/sdk/miden-client-interface.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -149,14 +149,12 @@ export class MidenClientInterface {
149149
}
150150

151151
async importPublicAccountFromPrivateKey(privateKey: SecretKey): Promise<string> {
152-
console.log('Importing public account from private key, secret key:', privateKey);
153152
const accountBuilder = new AccountBuilder(new Uint8Array(32).fill(0))
154153
.accountType(AccountType.RegularAccountImmutableCode)
155154
.storageMode(AccountStorageMode.public())
156155
.withAuthComponent(AccountComponent.createAuthComponent(privateKey))
157156
.withBasicWalletComponent();
158157
const wallet = accountBuilder.build().account;
159-
console.log('Importing public account from private key, account id:', wallet.id().toString());
160158
// add the secret key to the web client's keystore
161159
await this.webClient.addAccountSecretKeyToWebStore(privateKey);
162160
// register the new account in the web client
@@ -199,6 +197,15 @@ export class MidenClientInterface {
199197
return result;
200198
}
201199

200+
async getAccountPkcByPublicKey(publicKey: string): Promise<string> {
201+
const acc = await this.webClient.getAccount(accountIdStringToSdk(publicKey));
202+
if (!acc) {
203+
throw new Error('Account not found');
204+
}
205+
const result = acc.getPublicKeys()[0].toHex();
206+
return result.slice(2); // remove 0x prefix
207+
}
208+
202209
async importAccountById(accountId: string) {
203210
const result = await this.webClient.importAccountById(accountIdStringToSdk(accountId));
204211
return result;

src/lib/shared/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -503,6 +503,7 @@ export interface ImportFromClientRequest extends WalletMessageBase {
503503
password: string;
504504
mnemonic: string;
505505
walletAccounts: WalletAccount[];
506+
skForImportedAccounts: Record<string, string>;
506507
}
507508

508509
export interface ImportFromClientResponse extends WalletMessageBase {

src/lib/store/index.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -93,12 +93,13 @@ export const useWalletStore = create<WalletStore>()(
9393
// State will be synced via StateUpdated notification
9494
},
9595

96-
importWalletFromClient: async (password, mnemonic, walletAccounts) => {
96+
importWalletFromClient: async (password, mnemonic, walletAccounts, skForImportedAccounts) => {
9797
const res = await request({
9898
type: WalletMessageType.ImportFromClientRequest,
9999
password,
100100
mnemonic,
101-
walletAccounts
101+
walletAccounts,
102+
skForImportedAccounts
102103
});
103104
assertResponse(res.type === WalletMessageType.ImportFromClientResponse);
104105
},
@@ -187,12 +188,10 @@ export const useWalletStore = create<WalletStore>()(
187188
},
188189

189190
importPublicAccountByPrivateKey: async privateKey => {
190-
console.log(privateKey);
191191
const res = await request({
192192
type: WalletMessageType.ImportAccountRequest,
193193
privateKey
194194
});
195-
console.log(res);
196195
assertResponse(res.type === WalletMessageType.ImportAccountResponse);
197196
},
198197

src/lib/store/types.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,12 @@ export interface WalletActions {
7373

7474
// Auth actions
7575
registerWallet: (password: string, mnemonic?: string, ownMnemonic?: boolean) => Promise<void>;
76-
importWalletFromClient: (password: string, mnemonic: string, walletAccounts: WalletAccount[]) => Promise<void>;
76+
importWalletFromClient: (
77+
password: string,
78+
mnemonic: string,
79+
walletAccounts: WalletAccount[],
80+
skForImportedAccounts: Record<string, string>
81+
) => Promise<void>;
7782
unlock: (password: string) => Promise<void>;
7883

7984
// Account actions

src/screens/encrypted-file-flow/ExportFileComplete.tsx

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ const ExportFileComplete: React.FC<ExportFileCompleteProps> = ({
3232
}) => {
3333
const { t } = useTranslation();
3434
const { midenClient, midenClientLoading } = useMidenClient();
35-
const { revealMnemonic, accounts } = useMidenContext();
35+
const { revealMnemonic, accounts, revealPrivateKey } = useMidenContext();
3636
const { fullPage } = useAppEnv();
3737

3838
const getExportFile = useCallback(async () => {
@@ -42,14 +42,22 @@ const ExportFileComplete: React.FC<ExportFileCompleteProps> = ({
4242
const walletDbDump = await exportDb();
4343

4444
const seedPhrase = await revealMnemonic(walletPassword);
45-
45+
const secretKeysForImportedAccounts: Record<string, string> = {};
46+
47+
for (const account of accounts) {
48+
if (account.hdIndex === -1) {
49+
const pubKey = await midenClient.getAccountPkcByPublicKey(account.publicKey);
50+
const sk = await revealPrivateKey(pubKey, walletPassword);
51+
secretKeysForImportedAccounts[account.publicKey] = sk;
52+
}
53+
}
4654
const filePayload: DecryptedWalletFile = {
4755
seedPhrase,
4856
midenClientDbContent: midenClientDbDump,
4957
walletDbContent: walletDbDump,
50-
accounts
58+
accounts,
59+
secretKeysForImportedAccounts
5160
};
52-
5361
const salt = generateSalt();
5462
const passKey = await generateKey(filePassword);
5563
const derivedKey = await deriveKey(passKey, salt);

0 commit comments

Comments
 (0)