@cardano-sdk/e2e 0.28.1 → 0.29.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cardano-sdk/e2e",
3
- "version": "0.28.1",
3
+ "version": "0.29.1",
4
4
  "description": "End to end tests for the cardano-js-sdk packages.",
5
5
  "engines": {
6
6
  "node": ">=16.20.2"
@@ -80,20 +80,20 @@
80
80
  "dependencies": {
81
81
  "@cardano-foundation/ledgerjs-hw-app-cardano": "^6.0.0",
82
82
  "@cardano-ogmios/client": "5.6.0",
83
- "@cardano-sdk/cardano-services": "~0.24.2",
84
- "@cardano-sdk/cardano-services-client": "~0.16.2",
85
- "@cardano-sdk/core": "~0.23.0",
83
+ "@cardano-sdk/cardano-services": "~0.24.4",
84
+ "@cardano-sdk/cardano-services-client": "~0.16.4",
85
+ "@cardano-sdk/core": "~0.23.1",
86
86
  "@cardano-sdk/crypto": "~0.1.19",
87
- "@cardano-sdk/hardware-ledger": "~0.8.2",
88
- "@cardano-sdk/hardware-trezor": "~0.4.2",
89
- "@cardano-sdk/input-selection": "~0.12.9",
90
- "@cardano-sdk/key-management": "~0.17.1",
91
- "@cardano-sdk/ogmios": "~0.15.4",
92
- "@cardano-sdk/tx-construction": "~0.16.2",
87
+ "@cardano-sdk/hardware-ledger": "~0.8.4",
88
+ "@cardano-sdk/hardware-trezor": "~0.4.4",
89
+ "@cardano-sdk/input-selection": "~0.12.11",
90
+ "@cardano-sdk/key-management": "~0.18.0",
91
+ "@cardano-sdk/ogmios": "~0.15.6",
92
+ "@cardano-sdk/tx-construction": "~0.17.1",
93
93
  "@cardano-sdk/util": "~0.14.5",
94
- "@cardano-sdk/util-dev": "~0.19.2",
95
- "@cardano-sdk/util-rxjs": "~0.6.5",
96
- "@cardano-sdk/wallet": "~0.28.1",
94
+ "@cardano-sdk/util-dev": "~0.19.4",
95
+ "@cardano-sdk/util-rxjs": "~0.6.7",
96
+ "@cardano-sdk/wallet": "~0.29.0",
97
97
  "@dcspark/cardano-multiplatform-lib-nodejs": "^3.1.1",
98
98
  "@vespaiach/axios-fetch-adapter": "^0.3.0",
99
99
  "axios": "^0.27.2",
@@ -123,10 +123,10 @@
123
123
  "@babel/core": "^7.18.2",
124
124
  "@babel/preset-env": "^7.18.2",
125
125
  "@babel/preset-typescript": "^7.17.12",
126
- "@cardano-sdk/dapp-connector": "~0.12.1",
127
- "@cardano-sdk/projection": "~0.10.4",
128
- "@cardano-sdk/projection-typeorm": "~0.7.4",
129
- "@cardano-sdk/web-extension": "~0.19.0",
126
+ "@cardano-sdk/dapp-connector": "~0.12.2",
127
+ "@cardano-sdk/projection": "~0.10.6",
128
+ "@cardano-sdk/projection-typeorm": "~0.7.6",
129
+ "@cardano-sdk/web-extension": "~0.20.1",
130
130
  "@dcspark/cardano-multiplatform-lib-browser": "^3.1.1",
131
131
  "@emurgo/cardano-message-signing-asmjs": "^1.0.1",
132
132
  "@types/bunyan": "^1.8.8",
@@ -149,6 +149,7 @@
149
149
  "babel-loader": "^8.2.5",
150
150
  "blake2b-no-wasm": "2.1.4",
151
151
  "buffer": "^6.0.3",
152
+ "chromedriver": "^120.0.0",
152
153
  "copy-webpack-plugin": "^10.2.4",
153
154
  "crypto-browserify": "^3.12.0",
154
155
  "delay": "^5.0.0",
@@ -178,5 +179,5 @@
178
179
  "webpack-cli": "^4.9.2",
179
180
  "webpack-merge": "^5.8.0"
180
181
  },
181
- "gitHead": "586e56ff6b8b4666fa62b4e11b1d87461c36b9b8"
182
+ "gitHead": "6ffac02f90549b4dddda2abcc23b7640a314b8a9"
182
183
  }
package/src/factories.ts CHANGED
@@ -30,6 +30,7 @@ import {
30
30
  CommunicationType,
31
31
  InMemoryKeyAgent,
32
32
  KeyAgentDependencies,
33
+ Witnesser,
33
34
  util
34
35
  } from '@cardano-sdk/key-management';
35
36
  import {
@@ -282,6 +283,7 @@ export type GetWalletProps = {
282
283
  stores?: storage.WalletStores;
283
284
  customKeyParams?: KeyAgentFactoryProps;
284
285
  keyAgent?: AsyncKeyAgent;
286
+ witnesser?: Witnesser;
285
287
  };
286
288
 
287
289
  /** Delays initializing tx when nearing the epoch boundary. Relies on system clock being accurate. */
@@ -307,7 +309,7 @@ const patchInitializeTxToRespectEpochBoundary = <T extends ObservableWallet>(
307
309
  * @returns an object containing the wallet and providers passed to it
308
310
  */
309
311
  export const getWallet = async (props: GetWalletProps) => {
310
- const { env, idx, logger, name, polling, stores, customKeyParams, keyAgent } = props;
312
+ const { env, idx, logger, name, polling, stores, customKeyParams, keyAgent, witnesser } = props;
311
313
  const providers = {
312
314
  addressDiscovery: await addressDiscoveryFactory.create(
313
315
  env.ADDRESS_DISCOVERY,
@@ -365,7 +367,7 @@ export const getWallet = async (props: GetWalletProps) => {
365
367
  bip32Account,
366
368
  logger,
367
369
  stores,
368
- witnesser: util.createBip32Ed25519Witnesser(asyncKeyAgent)
370
+ witnesser: witnesser || util.createBip32Ed25519Witnesser(asyncKeyAgent)
369
371
  }
370
372
  );
371
373
 
@@ -1,57 +1,140 @@
1
1
  import {
2
+ AnyWallet,
2
3
  StoresFactory,
3
4
  WalletFactory,
5
+ WalletManager,
4
6
  WalletManagerActivateProps,
5
- WalletManagerWorker,
7
+ WalletRepository,
8
+ WalletType,
9
+ consumeSignerManagerApi,
6
10
  exposeApi,
11
+ observableWalletProperties,
12
+ repositoryChannel,
13
+ walletChannel,
7
14
  walletManagerChannel,
8
- walletManagerProperties
15
+ walletManagerProperties,
16
+ walletRepositoryProperties
9
17
  } from '@cardano-sdk/web-extension';
10
18
 
11
- import { AsyncKeyAgent } from '@cardano-sdk/key-management';
19
+ import { InvalidArgumentError, isNotNil } from '@cardano-sdk/util';
20
+ import { Metadata, env, logger } from '../util';
12
21
  import { storage as WebExtensionStorage, runtime } from 'webextension-polyfill';
13
- import { env, logger } from '../util';
14
- import { from, merge, of } from 'rxjs';
22
+ import { Witnesser } from '@cardano-sdk/key-management';
23
+ import { filter, from, merge, of } from 'rxjs';
15
24
  import { getWallet } from '../../../../src';
16
25
  import { storage } from '@cardano-sdk/wallet';
17
26
  import { toEmpty } from '@cardano-sdk/util-rxjs';
18
27
  import { walletName } from '../const';
19
28
 
20
29
  export interface WalletFactoryDependencies {
21
- keyAgent: AsyncKeyAgent;
30
+ witnesser: Witnesser;
22
31
  stores: storage.WalletStores;
23
32
  }
24
33
 
34
+ /**
35
+ * Gets the wallet name.
36
+ *
37
+ * @param wallet The wallet to get the name from.
38
+ * @param accountIndex The account index to get the name from.
39
+ * @private
40
+ */
41
+ const getWalletName = (wallet: AnyWallet<Metadata>, accountIndex?: number): string => {
42
+ let name = '';
43
+ switch (wallet.type) {
44
+ case WalletType.InMemory:
45
+ case WalletType.Ledger:
46
+ case WalletType.Trezor: {
47
+ if (accountIndex === undefined)
48
+ throw new InvalidArgumentError('accountIndex', `Account index is required for ${wallet.type} wallet`);
49
+
50
+ const account = wallet.accounts.find((acc) => acc.accountIndex === accountIndex);
51
+
52
+ if (!account)
53
+ throw new InvalidArgumentError('accountIndex', `Account ${accountIndex} not found in ${wallet.type} wallet`);
54
+
55
+ name = account.metadata.name;
56
+ break;
57
+ }
58
+ case WalletType.Script:
59
+ name = wallet.metadata.name;
60
+ break;
61
+ }
62
+
63
+ return name;
64
+ };
65
+
25
66
  /**
26
67
  * {@link WalletManagerActivateProps.provider} could be used to pass the necessary information
27
68
  * to construct providers for different networks.
28
69
  * Please check its documentation for examples.
29
70
  */
30
- const walletFactory: WalletFactory = {
31
- create: async (props: WalletManagerActivateProps, { keyAgent, stores }: WalletFactoryDependencies) =>
71
+ const walletFactory: WalletFactory<Metadata> = {
72
+ create: async (
73
+ props: WalletManagerActivateProps,
74
+ wallet: AnyWallet<Metadata>,
75
+ { witnesser, stores }: WalletFactoryDependencies
76
+ ) =>
32
77
  (
33
78
  await getWallet({
34
79
  env,
35
- keyAgent,
36
80
  logger,
37
- name: props.observableWalletName,
38
- stores
81
+ name: getWalletName(wallet, props.accountIndex),
82
+ stores,
83
+ witnesser
39
84
  })
40
85
  ).wallet
41
86
  };
42
87
 
43
88
  const storesFactory: StoresFactory = {
44
- create: ({ walletId }) => storage.createPouchDbWalletStores(walletId, { logger })
89
+ create: ({ name }) => storage.createPouchDbWalletStores(name, { logger })
45
90
  };
46
91
 
47
- export const wallet$ = (() => {
48
- const walletManager = new WalletManagerWorker(
49
- { walletName },
50
- { logger, managerStorage: WebExtensionStorage.local, runtime, storesFactory, walletFactory }
51
- );
52
- exposeApi(
53
- { api$: of(walletManager), baseChannel: walletManagerChannel(walletName), properties: walletManagerProperties },
54
- { logger, runtime }
55
- );
56
- return merge(walletManager.activeWallet$, from(walletManager.initialize()).pipe(toEmpty));
57
- })();
92
+ const walletRepository = new WalletRepository<Metadata>({
93
+ logger,
94
+ store: new storage.InMemoryCollectionStore()
95
+ });
96
+
97
+ const signerManagerApi = consumeSignerManagerApi({ logger, runtime });
98
+
99
+ const walletManager = new WalletManager<Metadata>(
100
+ { name: walletName },
101
+ {
102
+ logger,
103
+ managerStorage: WebExtensionStorage.local,
104
+ runtime,
105
+ signerManagerApi,
106
+ storesFactory,
107
+ walletFactory,
108
+ walletRepository
109
+ }
110
+ );
111
+
112
+ exposeApi(
113
+ {
114
+ api$: of(walletRepository),
115
+ baseChannel: repositoryChannel(walletName),
116
+ properties: walletRepositoryProperties
117
+ },
118
+ { logger, runtime }
119
+ );
120
+
121
+ exposeApi(
122
+ {
123
+ api$: of(walletManager),
124
+ baseChannel: walletManagerChannel(walletName),
125
+ properties: walletManagerProperties
126
+ },
127
+ { logger, runtime }
128
+ );
129
+
130
+ exposeApi(
131
+ {
132
+ api$: walletManager.activeWallet$.asObservable(),
133
+ baseChannel: walletChannel(walletName),
134
+ properties: observableWalletProperties
135
+ },
136
+ { logger, runtime }
137
+ );
138
+
139
+ export const wallet$ = (() =>
140
+ merge(walletManager.activeWallet$.pipe(filter(isNotNil)), from(walletManager.initialize()).pipe(toEmpty)))();
@@ -9,7 +9,7 @@
9
9
  "unlimitedStorage"
10
10
  ],
11
11
  "content_security_policy": {
12
- "extension_pages": "default-src 'self' http://localhost:3000; script-src 'self' 'wasm-unsafe-eval'; object-src 'self'; connect-src data: http://localhost:8080 https://backend.live-preprod.eks.lw.iog.io https://api.coingecko.com http://167.235.156.245:4000 http://localhost:3000 ws://localhost:3000 wss://localhost:3000 http://localhost:4000 ws://localhost:4000 wss://localhost:4000 http://testnet-dev-backend.dev.lw.iog.io:80 http://localhost:4567 https://testnet-dev-backend.dev.lw.iog.io:443 https://preprod-api.v2.prod.lw.iog.io; style-src * 'unsafe-inline'; img-src * data:; font-src https://fonts.gstatic.com;"
12
+ "extension_pages": "default-src 'self' http://localhost:3000; script-src 'self' 'wasm-unsafe-eval'; object-src 'self'; connect-src data: http://localhost:8080 https://backend.live-preprod.eks.lw.iog.io https://api.coingecko.com http://167.235.156.245:4000 http://localhost:3000 ws://localhost:3000 wss://localhost:3000 http://localhost:4011 ws://localhost:4011 wss://localhost:4011 http://localhost:4000 ws://localhost:4000 wss://localhost:4000 http://testnet-dev-backend.dev.lw.iog.io:80 http://localhost:4567 https://testnet-dev-backend.dev.lw.iog.io:443 https://preprod-api.v2.prod.lw.iog.io; style-src * 'unsafe-inline'; img-src * data:; font-src https://fonts.gstatic.com;"
13
13
  },
14
14
  "web_accessible_resources": [
15
15
  {
@@ -9,24 +9,35 @@ import {
9
9
  } from './util';
10
10
  import {
11
11
  RemoteApiPropertyType,
12
- WalletManagerUi,
12
+ SignerManager,
13
+ WalletType,
13
14
  consumeRemoteApi,
14
15
  consumeSupplyDistributionTracker,
15
- exposeApi
16
+ createKeyAgentFactory,
17
+ exposeApi,
18
+ exposeSignerManagerApi,
19
+ observableWalletProperties,
20
+ repositoryChannel,
21
+ walletChannel,
22
+ walletManagerChannel,
23
+ walletManagerProperties,
24
+ walletRepositoryProperties
16
25
  } from '@cardano-sdk/web-extension';
17
- import {
18
- adaPriceServiceChannel,
19
- getObservableWalletName,
20
- selectors,
21
- userPromptServiceChannel,
22
- walletName
23
- } from './const';
24
- import { keyManagementFactory } from '../../../src';
26
+ import { adaPriceServiceChannel, selectors, userPromptServiceChannel, walletName } from './const';
25
27
 
28
+ import * as Crypto from '@cardano-sdk/crypto';
29
+ import { Buffer } from 'buffer';
26
30
  import { Cardano } from '@cardano-sdk/core';
31
+ import {
32
+ CommunicationType,
33
+ InMemoryKeyAgent,
34
+ SerializableInMemoryKeyAgentData,
35
+ emip3encrypt,
36
+ util
37
+ } from '@cardano-sdk/key-management';
27
38
  import { HexBlob } from '@cardano-sdk/util';
28
39
  import { SodiumBip32Ed25519 } from '@cardano-sdk/crypto';
29
- import { combineLatest, firstValueFrom, of } from 'rxjs';
40
+ import { combineLatest, firstValueFrom, merge, of } from 'rxjs';
30
41
  import { runtime } from 'webextension-polyfill';
31
42
 
32
43
  const delegationConfig = {
@@ -156,7 +167,9 @@ const clearWalletValues = (): void => {
156
167
  };
157
168
 
158
169
  const destroyWallet = async (): Promise<void> => {
159
- await walletManager.destroy();
170
+ await walletManager.deactivate();
171
+ const activeWalletId = await firstValueFrom(walletManager.activeWalletId$);
172
+ await walletManager.destroyData(activeWalletId.walletId, env.KEY_MANAGEMENT_PARAMS.chainId);
160
173
  clearWalletValues();
161
174
  };
162
175
 
@@ -198,10 +211,64 @@ const cleanupMultidelegationInfo = (multiDelegationDiv: Element) => {
198
211
  }
199
212
  };
200
213
 
201
- const walletManager = new WalletManagerUi({ walletName }, { logger, runtime });
214
+ const signerManager = new SignerManager(
215
+ {
216
+ hwOptions: {
217
+ communicationType: CommunicationType.Web,
218
+ manifest: {
219
+ appUrl: 'https://web-extension.app',
220
+ email: 'e2e@web-extension.app'
221
+ }
222
+ }
223
+ },
224
+ {
225
+ keyAgentFactory: createKeyAgentFactory({
226
+ bip32Ed25519: new Crypto.SodiumBip32Ed25519(),
227
+ logger
228
+ })
229
+ }
230
+ );
231
+
232
+ const passphraseByteArray = Uint8Array.from(
233
+ env.KEY_MANAGEMENT_PARAMS.passphrase.split('').map((letter) => letter.charCodeAt(0))
234
+ );
235
+ merge(signerManager.signDataRequest$, signerManager.transactionWitnessRequest$).subscribe((req) => {
236
+ logger.info('Sign request', req);
237
+ if (req.walletType === WalletType.InMemory) {
238
+ void req.sign(new Uint8Array(passphraseByteArray));
239
+ } else {
240
+ void req.sign();
241
+ }
242
+ logger.info('Signed', req);
243
+ });
244
+
245
+ // Setup
246
+
247
+ // Expose local objects.
248
+ exposeSignerManagerApi(
249
+ {
250
+ signerManager
251
+ },
252
+ { logger, runtime }
253
+ );
254
+
255
+ // Consume remote objects.
256
+ const walletManager = consumeRemoteApi(
257
+ { baseChannel: walletManagerChannel(walletName), properties: walletManagerProperties },
258
+ { logger, runtime }
259
+ );
260
+
261
+ const repository = consumeRemoteApi(
262
+ { baseChannel: repositoryChannel(walletName), properties: walletRepositoryProperties },
263
+ { logger, runtime }
264
+ );
265
+
202
266
  // Wallet object does not change when wallets are activated/deactivated.
203
267
  // Instead, it's observable properties emit from the currently active wallet.
204
- const wallet = walletManager.wallet;
268
+ const wallet = consumeRemoteApi(
269
+ { baseChannel: walletChannel(walletName), properties: observableWalletProperties },
270
+ { logger, runtime }
271
+ );
205
272
 
206
273
  // Wallet can be subscribed can be used even before it is actually created.
207
274
  wallet.addresses$.subscribe(([{ address, rewardAccount }]) => setAddresses({ address, stakeAddress: rewardAccount }));
@@ -220,30 +287,71 @@ wallet.delegation.distribution$.subscribe((delegationDistrib) => {
220
287
  }
221
288
  });
222
289
 
223
- const createWallet = async (accountIndex: number) => {
224
- clearWalletValues();
225
-
226
- const keyAgent = await (
227
- await keyManagementFactory.create(
228
- env.KEY_MANAGEMENT_PROVIDER,
290
+ const createWalletIfNotExistsAndActivate = async (accountIndex: number) => {
291
+ const wallets = await firstValueFrom(repository.wallets$);
292
+ let walletId = wallets.find(
293
+ (w) => w.type !== WalletType.Script && w.accounts.some((a) => a.accountIndex === accountIndex)
294
+ )?.walletId;
295
+ if (!walletId) {
296
+ logger.log('creating wallet');
297
+ clearWalletValues();
298
+ const bip32Ed25519 = new SodiumBip32Ed25519();
299
+ const mnemonicWords = env.KEY_MANAGEMENT_PARAMS.mnemonic.split(' ');
300
+ const passphrase = new Uint8Array(passphraseByteArray);
301
+ const keyAgent = await InMemoryKeyAgent.fromBip39MnemonicWords(
229
302
  {
230
- ...env.KEY_MANAGEMENT_PARAMS,
231
- accountIndex
303
+ accountIndex,
304
+ chainId: env.KEY_MANAGEMENT_PARAMS.chainId,
305
+ getPassphrase: async () => passphrase,
306
+ mnemonicWords
232
307
  },
233
- logger
234
- )
235
- )({ bip32Ed25519: new SodiumBip32Ed25519(), logger });
308
+ { bip32Ed25519, logger }
309
+ );
310
+ const encryptedRootPrivateKey = (keyAgent.serializableData as SerializableInMemoryKeyAgentData)
311
+ .encryptedRootPrivateKeyBytes;
312
+
313
+ const entropy = Buffer.from(util.mnemonicWordsToEntropy(mnemonicWords), 'hex');
314
+ const encryptedEntropy = await emip3encrypt(entropy, passphraseByteArray);
315
+
316
+ logger.log('adding to repository wallet');
317
+ // Add wallet to the repository.
318
+ walletId = await repository.addWallet({
319
+ encryptedSecrets: {
320
+ entropy: HexBlob.fromBytes(encryptedEntropy),
321
+ rootPrivateKeyBytes: HexBlob.fromBytes(new Uint8Array(encryptedRootPrivateKey))
322
+ },
323
+ extendedAccountPublicKey: keyAgent.serializableData.extendedAccountPublicKey,
324
+ type: WalletType.InMemory
325
+ });
326
+ await repository.addAccount({
327
+ accountIndex,
328
+ metadata: { name: `wallet-${accountIndex}` },
329
+ walletId
330
+ });
331
+
332
+ logger.log(`Wallet added: ${walletId}`);
333
+ } else {
334
+ logger.info(`Wallet with accountIndex ${accountIndex} already exists`);
335
+ }
236
336
 
237
- await walletManager.destroy();
238
- await walletManager.activate({ keyAgent, observableWalletName: getObservableWalletName(accountIndex) });
337
+ // await walletManager.destroy();
338
+ await walletManager.activate({
339
+ accountIndex,
340
+ chainId: env.KEY_MANAGEMENT_PARAMS.chainId,
341
+ walletId
342
+ });
239
343
 
240
344
  // Same wallet object will return different names, based on which wallet is active
241
345
  // Calling this method before any wallet is active, will resolve only once a wallet becomes active
242
346
  setName(await wallet.getName());
243
347
  };
244
348
 
245
- document.querySelector(selectors.btnActivateWallet1)!.addEventListener('click', async () => await createWallet(0));
246
- document.querySelector(selectors.btnActivateWallet2)!.addEventListener('click', async () => await createWallet(1));
349
+ document
350
+ .querySelector(selectors.btnActivateWallet1)!
351
+ .addEventListener('click', async () => await createWalletIfNotExistsAndActivate(0));
352
+ document
353
+ .querySelector(selectors.btnActivateWallet2)!
354
+ .addEventListener('click', async () => await createWalletIfNotExistsAndActivate(1));
247
355
  document.querySelector(selectors.deactivateWallet)!.addEventListener('click', async () => await deactivateWallet());
248
356
  document.querySelector(selectors.destroyWallet)!.addEventListener('click', async () => await destroyWallet());
249
357
  document.querySelector(selectors.btnDelegate)!.addEventListener('click', async () => {
@@ -253,7 +361,10 @@ document.querySelector(selectors.btnDelegate)!.addEventListener('click', async (
253
361
  });
254
362
 
255
363
  document.querySelector(selectors.btnSignAndBuildTx)!.addEventListener('click', async () => {
364
+ logger.info('Building transaction');
256
365
  const [{ address: ownAddress }] = await firstValueFrom(wallet.addresses$);
366
+ logger.info(`Address: ${ownAddress}`);
367
+
257
368
  const builtTx = wallet
258
369
  .createTxBuilder()
259
370
  .addOutput({
@@ -35,3 +35,5 @@ export const disconnectPortTestObjProperties: RemoteApiProperties<DisconnectPort
35
35
  export const logger = console;
36
36
 
37
37
  export const env = getEnv(walletVariables);
38
+
39
+ export type Metadata = { name: string };