Skip to content

Commit 888e248

Browse files
committed
fixup! feat: wallet manager can now handle multiple wallet accounts and types
1 parent 91a54a7 commit 888e248

File tree

2 files changed

+64
-37
lines changed

2 files changed

+64
-37
lines changed

packages/e2e/test/web-extension/extension/ui.ts

+63-35
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ import { Cardano } from '@cardano-sdk/core';
3232
import { CommunicationType, emip3encrypt, util } from '@cardano-sdk/key-management';
3333
import { HexBlob } from '@cardano-sdk/util';
3434
import { SodiumBip32Ed25519 } from '@cardano-sdk/crypto';
35-
import { combineLatest, firstValueFrom, of } from 'rxjs';
35+
import { combineLatest, firstValueFrom, merge, of } from 'rxjs';
3636
import { runtime } from 'webextension-polyfill';
3737

3838
const delegationConfig = {
@@ -222,6 +222,18 @@ const signerManager = new SignerManager(
222222
}
223223
);
224224

225+
const passphraseByteArray = Uint8Array.from(
226+
env.KEY_MANAGEMENT_PARAMS.passphrase.split('').map((letter) => letter.charCodeAt(0))
227+
);
228+
merge(signerManager.signDataRequest$, signerManager.transactionWitnessRequest$).subscribe((req) => {
229+
if (req.walletType === WalletType.InMemory) {
230+
req.sign(passphraseByteArray);
231+
} else {
232+
req.sign();
233+
}
234+
logger.info('Signed', req);
235+
});
236+
225237
// Expose signer manager.
226238
exposeSignerManagerApi(
227239
{
@@ -230,7 +242,9 @@ exposeSignerManagerApi(
230242
{ logger, runtime }
231243
);
232244

233-
const walletManager = new WalletManagerUi({ walletName }, { logger, runtime });
245+
type Metadata = { name: string };
246+
// TODO: toSerializableObj does not support serializing empty obj {}
247+
const walletManager = new WalletManagerUi<Metadata>({ walletName }, { logger, runtime });
234248

235249
// Wallet object does not change when wallets are activated/deactivated.
236250
// Instead, it's observable properties emit from the currently active wallet.
@@ -253,40 +267,50 @@ wallet.delegation.distribution$.subscribe((delegationDistrib) => {
253267
}
254268
});
255269

256-
const createWallet = async (accountIndex: number) => {
257-
logger.log('creating wallet');
258-
clearWalletValues();
259-
const bip32Ed25519 = new SodiumBip32Ed25519();
260-
const passphraseByteArray = Uint8Array.from(
261-
env.KEY_MANAGEMENT_PARAMS.passphrase.split('').map((letter) => letter.charCodeAt(0))
262-
);
263-
const entropy = Buffer.from(util.mnemonicWordsToEntropy(env.KEY_MANAGEMENT_PARAMS.mnemonic.split(' ')), 'hex');
264-
const rootPrivateKey = await bip32Ed25519.fromBip39Entropy(entropy, env.KEY_MANAGEMENT_PARAMS.passphrase);
265-
const encryptedRootPrivateKey = await emip3encrypt(Buffer.from(rootPrivateKey, 'hex'), passphraseByteArray);
266-
const encryptedEntropy = await emip3encrypt(entropy, passphraseByteArray);
267-
268-
const accountPrivateKey = await util.deriveAccountPrivateKey({
269-
accountIndex,
270-
bip32Ed25519,
271-
rootPrivateKey
272-
});
270+
const createWalletIfNotExistsAndActivate = async (accountIndex: number) => {
271+
const wallets = await firstValueFrom(walletManager.repository.wallets$);
272+
let walletId = wallets.find(
273+
(w) => w.type !== WalletType.Script && w.accounts.some((a) => a.accountIndex === accountIndex)
274+
)?.walletId;
275+
if (!walletId) {
276+
logger.log('creating wallet');
277+
clearWalletValues();
278+
const bip32Ed25519 = new SodiumBip32Ed25519();
279+
const entropy = Buffer.from(util.mnemonicWordsToEntropy(env.KEY_MANAGEMENT_PARAMS.mnemonic.split(' ')), 'hex');
280+
const rootPrivateKey = await bip32Ed25519.fromBip39Entropy(entropy, env.KEY_MANAGEMENT_PARAMS.passphrase);
281+
const encryptedRootPrivateKey = await emip3encrypt(Buffer.from(rootPrivateKey, 'hex'), passphraseByteArray);
282+
const encryptedEntropy = await emip3encrypt(entropy, passphraseByteArray);
283+
284+
const accountPrivateKey = await util.deriveAccountPrivateKey({
285+
accountIndex,
286+
bip32Ed25519,
287+
rootPrivateKey
288+
});
273289

274-
const extendedAccountPublicKey = await bip32Ed25519.getBip32PublicKey(accountPrivateKey);
275-
276-
logger.log('adding to repository wallet');
277-
// Add wallet to the repository.
278-
const walletId = await walletManager.repository.addWallet({
279-
encryptedSecrets: {
280-
entropy: HexBlob.fromBytes(encryptedEntropy),
281-
rootPrivateKeyBytes: HexBlob.fromBytes(encryptedRootPrivateKey)
282-
},
283-
extendedAccountPublicKey,
284-
type: WalletType.InMemory
285-
});
290+
const extendedAccountPublicKey = await bip32Ed25519.getBip32PublicKey(accountPrivateKey);
291+
292+
logger.log('adding to repository wallet');
293+
// Add wallet to the repository.
294+
walletId = await walletManager.repository.addWallet({
295+
encryptedSecrets: {
296+
entropy: HexBlob.fromBytes(encryptedEntropy),
297+
rootPrivateKeyBytes: HexBlob.fromBytes(encryptedRootPrivateKey)
298+
},
299+
extendedAccountPublicKey,
300+
type: WalletType.InMemory
301+
});
302+
await walletManager.repository.addAccount({
303+
accountIndex,
304+
metadata: { name: `Wallet #${accountIndex + 1}` },
305+
walletId
306+
});
286307

287-
logger.log(`Wallet added: ${walletId}`);
308+
logger.log(`Wallet added: ${walletId}`);
309+
} else {
310+
logger.info(`Wallet with accountIndex ${accountIndex} already exists`);
311+
}
288312

289-
await walletManager.destroy();
313+
// await walletManager.destroy();
290314
await walletManager.activate({
291315
accountIndex,
292316
chainId: env.KEY_MANAGEMENT_PARAMS.chainId,
@@ -299,8 +323,12 @@ const createWallet = async (accountIndex: number) => {
299323
setName(await wallet.getName());
300324
};
301325

302-
document.querySelector(selectors.btnActivateWallet1)!.addEventListener('click', async () => await createWallet(0));
303-
document.querySelector(selectors.btnActivateWallet2)!.addEventListener('click', async () => await createWallet(1));
326+
document
327+
.querySelector(selectors.btnActivateWallet1)!
328+
.addEventListener('click', async () => await createWalletIfNotExistsAndActivate(0));
329+
document
330+
.querySelector(selectors.btnActivateWallet2)!
331+
.addEventListener('click', async () => await createWalletIfNotExistsAndActivate(1));
304332
document.querySelector(selectors.deactivateWallet)!.addEventListener('click', async () => await deactivateWallet());
305333
document.querySelector(selectors.destroyWallet)!.addEventListener('click', async () => await destroyWallet());
306334
document.querySelector(selectors.btnDelegate)!.addEventListener('click', async () => {

packages/web-extension/src/walletManager/walletManagerUi.ts

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import { AnyWallet } from './types';
21
import { Cardano } from '@cardano-sdk/core';
32
import { MessengerDependencies, consumeRemoteApi } from '../messaging';
43
import { ObservableWallet } from '@cardano-sdk/wallet';
@@ -17,7 +16,7 @@ import { repositoryChannel, walletChannel, walletManagerChannel, walletManagerPr
1716
*/
1817
export class WalletManagerUi<Metadata extends {}> implements Shutdown {
1918
#remoteApi: WalletManagerApi & Shutdown;
20-
repository: WalletRepository<AnyWallet<Metadata>> & Shutdown;
19+
repository: WalletRepository<Metadata> & Shutdown;
2120

2221
/**
2322
* Observable wallet. Its properties can be subscribed to at any point, even before activating a wallet.

0 commit comments

Comments
 (0)