@cardano-sdk/e2e 0.32.8 → 0.33.0

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.
Files changed (65) hide show
  1. package/CHANGELOG.md +29 -0
  2. package/dist/cjs/factories.d.ts +26 -2
  3. package/dist/cjs/factories.d.ts.map +1 -1
  4. package/dist/cjs/factories.js +30 -2
  5. package/dist/cjs/factories.js.map +1 -1
  6. package/dist/cjs/tools/multi-delegation-data-gen/index.js +3 -3
  7. package/dist/cjs/tools/multi-delegation-data-gen/index.js.map +1 -1
  8. package/dist/cjs/tools/multi-delegation-data-gen/utils/utils.d.ts +8 -8
  9. package/dist/cjs/tools/multi-delegation-data-gen/utils/utils.d.ts.map +1 -1
  10. package/dist/cjs/tools/multi-delegation-data-gen/utils/utils.js +1 -1
  11. package/dist/cjs/tools/multi-delegation-data-gen/utils/utils.js.map +1 -1
  12. package/dist/cjs/tsconfig.tsbuildinfo +1 -1
  13. package/dist/cjs/util/handle-util.d.ts.map +1 -1
  14. package/dist/cjs/util/handle-util.js +8 -2
  15. package/dist/cjs/util/handle-util.js.map +1 -1
  16. package/dist/cjs/util/util.d.ts +4 -4
  17. package/dist/cjs/util/util.d.ts.map +1 -1
  18. package/dist/cjs/util/util.js +13 -6
  19. package/dist/cjs/util/util.js.map +1 -1
  20. package/dist/esm/factories.d.ts +26 -2
  21. package/dist/esm/factories.d.ts.map +1 -1
  22. package/dist/esm/factories.js +29 -2
  23. package/dist/esm/factories.js.map +1 -1
  24. package/dist/esm/tools/multi-delegation-data-gen/index.js +3 -3
  25. package/dist/esm/tools/multi-delegation-data-gen/index.js.map +1 -1
  26. package/dist/esm/tools/multi-delegation-data-gen/utils/utils.d.ts +8 -8
  27. package/dist/esm/tools/multi-delegation-data-gen/utils/utils.d.ts.map +1 -1
  28. package/dist/esm/tools/multi-delegation-data-gen/utils/utils.js +1 -1
  29. package/dist/esm/tools/multi-delegation-data-gen/utils/utils.js.map +1 -1
  30. package/dist/esm/tsconfig.tsbuildinfo +1 -1
  31. package/dist/esm/util/handle-util.d.ts.map +1 -1
  32. package/dist/esm/util/handle-util.js +8 -2
  33. package/dist/esm/util/handle-util.js.map +1 -1
  34. package/dist/esm/util/util.d.ts +4 -4
  35. package/dist/esm/util/util.d.ts.map +1 -1
  36. package/dist/esm/util/util.js +14 -7
  37. package/dist/esm/util/util.js.map +1 -1
  38. package/package.json +18 -18
  39. package/src/factories.ts +71 -2
  40. package/src/tools/multi-delegation-data-gen/index.ts +4 -4
  41. package/src/tools/multi-delegation-data-gen/utils/utils.ts +12 -12
  42. package/src/util/handle-util.ts +8 -2
  43. package/src/util/util.ts +19 -10
  44. package/test/artillery/wallet-restoration/types.ts +2 -2
  45. package/test/load-test-custom/wallet-init/wallet-init.test.ts +4 -4
  46. package/test/load-test-custom/wallet-restoration/wallet-restoration.test.ts +2 -2
  47. package/test/long-running/delegation-rewards.test.ts +6 -6
  48. package/test/long-running/multisig-wallet/multisig-delegation-rewards.test.ts +6 -6
  49. package/test/long-running/shared-wallet-delegation-rewards.test.ts +199 -0
  50. package/test/wallet/PersonalWallet/byron.test.ts +2 -2
  51. package/test/wallet/PersonalWallet/delegation.test.ts +5 -5
  52. package/test/wallet/PersonalWallet/delegationDistribution.test.ts +15 -15
  53. package/test/wallet/PersonalWallet/handle.test.ts +4 -4
  54. package/test/wallet/PersonalWallet/metadata.test.ts +2 -2
  55. package/test/wallet/PersonalWallet/mint.test.ts +10 -4
  56. package/test/wallet/PersonalWallet/multiAddress.test.ts +2 -2
  57. package/test/wallet/PersonalWallet/multisignature.test.ts +10 -4
  58. package/test/wallet/PersonalWallet/nft.test.ts +27 -9
  59. package/test/wallet/PersonalWallet/phase2validation.test.ts +4 -4
  60. package/test/wallet/PersonalWallet/pouchDbWalletStores.test.ts +1 -1
  61. package/test/wallet/PersonalWallet/txChainHistory.test.ts +4 -3
  62. package/test/wallet/PersonalWallet/unspendableUtxos.test.ts +3 -3
  63. package/test/wallet/SharedWallet/delegation.test.ts +245 -0
  64. package/test/wallet/SharedWallet/simpleTx.test.ts +123 -0
  65. package/test/wallet/SharedWallet/ultils.ts +327 -0
@@ -0,0 +1,327 @@
1
+ import * as Crypto from '@cardano-sdk/crypto';
2
+ import {
3
+ AccountKeyDerivationPath,
4
+ KeyAgent,
5
+ KeyRole,
6
+ SignBlobResult,
7
+ SignDataContext,
8
+ SignTransactionContext,
9
+ TransactionSigner,
10
+ WitnessOptions,
11
+ WitnessedTx,
12
+ Witnesser,
13
+ util
14
+ } from '@cardano-sdk/key-management';
15
+ import { Cardano, Serialization, TxCBOR } from '@cardano-sdk/core';
16
+ import { HexBlob } from '@cardano-sdk/util';
17
+ import { Logger } from 'ts-log';
18
+ import { bip32Ed25519Factory, createStandaloneKeyAgent, getSharedWallet } from '../../../src';
19
+
20
+ const randomHexChar = () => Math.floor(Math.random() * 16).toString(16);
21
+ const randomPublicKey = () => Crypto.Ed25519PublicKeyHex(Array.from({ length: 64 }).map(randomHexChar).join(''));
22
+
23
+ const DERIVATION_PATH = {
24
+ index: 0,
25
+ role: KeyRole.External
26
+ };
27
+
28
+ const getKeyAgent = async (
29
+ mnemonics: string,
30
+ genesisParameters: Cardano.CompactGenesis,
31
+ bip32Ed25519: Crypto.Bip32Ed25519
32
+ ) => {
33
+ const keyAgent = await createStandaloneKeyAgent(mnemonics.split(' '), genesisParameters, bip32Ed25519);
34
+
35
+ const pubKey = await keyAgent.derivePublicKey(DERIVATION_PATH);
36
+
37
+ return { keyAgent, pubKey };
38
+ };
39
+
40
+ const buildScript = async (expectedSigners: Array<Crypto.Ed25519PublicKeyHex>, bip32Ed25519: Crypto.Bip32Ed25519) => {
41
+ const signers = [...expectedSigners];
42
+
43
+ // Sorting guarantees that we will always get the same script if the same keys are used.
44
+ signers.sort();
45
+
46
+ // We are going to use RequireAllOf for this POC to keep it simple, but RequireNOf makes more sense.
47
+ const script: Cardano.NativeScript = {
48
+ __type: Cardano.ScriptType.Native,
49
+ kind: Cardano.NativeScriptKind.RequireAllOf,
50
+ scripts: []
51
+ };
52
+
53
+ for (const signer of signers) {
54
+ script.scripts.push({
55
+ __type: Cardano.ScriptType.Native,
56
+ keyHash: await bip32Ed25519.getPubKeyHash(signer),
57
+ kind: Cardano.NativeScriptKind.RequireSignature
58
+ });
59
+ }
60
+
61
+ return script;
62
+ };
63
+
64
+ /**
65
+ * Merges two arrays of items into a single array, avoiding duplication of items.
66
+ *
67
+ * @param arr1 The first array of items.
68
+ * @param arr2 The second array of items.
69
+ * @param serializeFn The function to serialize the items.
70
+ * @returns The merged array of items.
71
+ * @private
72
+ */
73
+ const mergeArrays = <T>(arr1: T[], arr2: T[], serializeFn: (item: T) => HexBlob): T[] => {
74
+ const serializedItems = new Set(arr1.map(serializeFn));
75
+ const mergedArray = [...arr1];
76
+
77
+ for (const item of arr2) {
78
+ const serializedItem = serializeFn(item);
79
+ if (!serializedItems.has(serializedItem)) {
80
+ mergedArray.push(item);
81
+ serializedItems.add(serializedItem);
82
+ }
83
+ }
84
+ return mergedArray;
85
+ };
86
+
87
+ /**
88
+ * Merges two witnesses into a single one avoiding duplication of witness data.
89
+ *
90
+ * @param lhs The left-hand side witness.
91
+ * @param rhs The right-hand side witness.
92
+ * @returns The merged witness.
93
+ * @private
94
+ */
95
+ // eslint-disable-next-line complexity
96
+ const mergeWitnesses = (lhs?: Cardano.Witness, rhs?: Cardano.Witness): Cardano.Witness => {
97
+ if (!rhs) {
98
+ if (!lhs) return { signatures: new Map() } as unknown as Cardano.Witness;
99
+ return lhs as unknown as Cardano.Witness;
100
+ }
101
+ const mergedSignatures = new Map([...(lhs?.signatures ?? []), ...(rhs.signatures ?? [])]);
102
+
103
+ // Merge arrays of complex objects
104
+ const mergedRedeemers = mergeArrays(lhs?.redeemers || [], rhs.redeemers || [], (elem) =>
105
+ Serialization.Redeemer.fromCore(elem).toCbor()
106
+ );
107
+
108
+ const mergedScripts = mergeArrays(lhs?.scripts || [], rhs.scripts || [], (elem) =>
109
+ Serialization.Script.fromCore(elem).toCbor()
110
+ );
111
+
112
+ const mergedBootstrap = mergeArrays(lhs?.bootstrap || [], rhs.bootstrap || [], (elem) =>
113
+ Serialization.BootstrapWitness.fromCore(elem).toCbor()
114
+ );
115
+
116
+ const mergedDatums = mergeArrays(lhs?.datums || [], rhs.datums || [], (elem) =>
117
+ Serialization.PlutusData.fromCore(elem).toCbor()
118
+ );
119
+
120
+ return {
121
+ bootstrap: mergedBootstrap,
122
+ datums: mergedDatums,
123
+ redeemers: mergedRedeemers,
124
+ scripts: mergedScripts,
125
+ signatures: mergedSignatures
126
+ };
127
+ };
128
+
129
+ const getTxWithStubWitness = async (
130
+ body: Cardano.TxBody,
131
+ paymentScript: Cardano.RequireAllOfScript | Cardano.RequireAnyOfScript | Cardano.RequireAtLeastScript,
132
+ stakingScript: Cardano.RequireAllOfScript | Cardano.RequireAnyOfScript | Cardano.RequireAtLeastScript,
133
+ extraSigners?: TransactionSigner[],
134
+ witness?: Cardano.Witness
135
+ ): Promise<Cardano.Witness> => {
136
+ const mockSignature = Crypto.Ed25519SignatureHex(
137
+ // eslint-disable-next-line max-len
138
+ 'ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
139
+ );
140
+
141
+ // Depending on the script, we need to provide a different number of signatures, however we will always compute the
142
+ // transaction witness size with the maximum number of signatures possible since we don't know how many participants will want to sing
143
+ // the transaction.
144
+ const withdrawalSignatures = body.withdrawals && body.withdrawals.length > 0 ? stakingScript.scripts.length : 0;
145
+
146
+ const paymentSignatures = paymentScript.scripts.length;
147
+ const totalSignature = withdrawalSignatures + paymentSignatures + (extraSigners?.length || 0);
148
+ const signatureMap = new Map();
149
+
150
+ for (let i = 0; i < totalSignature; ++i) signatureMap.set(randomPublicKey(), mockSignature);
151
+
152
+ const stubWitness = mergeWitnesses({ scripts: [], signatures: new Map() }, witness as Cardano.Witness);
153
+
154
+ stubWitness.signatures = new Map([
155
+ ...(stubWitness.signatures ? stubWitness.signatures.entries() : []),
156
+ ...signatureMap.entries()
157
+ ]);
158
+ stubWitness.scripts = [...(stubWitness.scripts ?? []), paymentScript, stakingScript];
159
+
160
+ return stubWitness;
161
+ };
162
+
163
+ const createWitnessData = async (
164
+ keyAgent: KeyAgent,
165
+ paymentScript: Cardano.RequireAllOfScript | Cardano.RequireAnyOfScript | Cardano.RequireAtLeastScript,
166
+ stakingScript: Cardano.RequireAllOfScript | Cardano.RequireAnyOfScript | Cardano.RequireAtLeastScript,
167
+ tx: Serialization.Transaction,
168
+ context: SignTransactionContext,
169
+ options?: WitnessOptions
170
+ // eslint-disable-next-line max-params
171
+ ): Promise<Cardano.Witness> => ({
172
+ scripts: [paymentScript, stakingScript],
173
+ signatures: await keyAgent.signTransaction(
174
+ {
175
+ body: tx.body().toCore(),
176
+ hash: tx.getId()
177
+ },
178
+ context,
179
+ { ...options, additionalKeyPaths: [...(options?.additionalKeyPaths ?? []), DERIVATION_PATH] } // The key agent wont be able to find the right key if we don't provide the derivation path.
180
+ )
181
+ });
182
+
183
+ // Naive witnesser that always signs with the same key, this will work for this test since both
184
+ // stake and payment scripts use the same key.
185
+ export class SharedWalletWitnesser implements Witnesser {
186
+ #keyAgent: KeyAgent;
187
+ #paymentScript: Cardano.RequireAllOfScript | Cardano.RequireAnyOfScript | Cardano.RequireAtLeastScript;
188
+ #stakingScript: Cardano.RequireAllOfScript | Cardano.RequireAnyOfScript | Cardano.RequireAtLeastScript;
189
+
190
+ constructor(
191
+ keyAgent: KeyAgent,
192
+ paymentScript: Cardano.RequireAllOfScript | Cardano.RequireAnyOfScript | Cardano.RequireAtLeastScript,
193
+ stakingScript: Cardano.RequireAllOfScript | Cardano.RequireAnyOfScript | Cardano.RequireAtLeastScript
194
+ ) {
195
+ // At creation we should also check that our keyagent controls at least one key in each script, otherwise throw.
196
+ this.#keyAgent = keyAgent;
197
+ this.#paymentScript = paymentScript;
198
+ this.#stakingScript = stakingScript;
199
+ }
200
+
201
+ async signBlob(
202
+ _derivationPath: AccountKeyDerivationPath,
203
+ _blob: HexBlob,
204
+ _context: SignDataContext
205
+ ): Promise<SignBlobResult> {
206
+ throw new Error('Method not implemented.');
207
+ }
208
+
209
+ async witness(
210
+ tx: Serialization.Transaction,
211
+ context: SignTransactionContext,
212
+ options?: WitnessOptions
213
+ ): Promise<WitnessedTx> {
214
+ let witness;
215
+ const coreTx = tx.toCore();
216
+ const hash = tx.getId();
217
+
218
+ if (options?.stubSign !== undefined && options.stubSign) {
219
+ witness = await getTxWithStubWitness(
220
+ coreTx.body,
221
+ this.#paymentScript,
222
+ this.#stakingScript,
223
+ options.extraSigners,
224
+ coreTx.witness
225
+ );
226
+ } else {
227
+ witness = await createWitnessData(
228
+ this.#keyAgent,
229
+ this.#paymentScript,
230
+ this.#stakingScript,
231
+ new Serialization.Transaction(
232
+ Serialization.TransactionBody.fromCore(coreTx.body),
233
+ new Serialization.TransactionWitnessSet()
234
+ ),
235
+ context,
236
+ options
237
+ );
238
+
239
+ const extraSignatures: Cardano.Signatures = new Map();
240
+ if (options?.extraSigners) {
241
+ for (const extraSigner of options?.extraSigners) {
242
+ const extraSignature = await extraSigner.sign({
243
+ body: coreTx.body,
244
+ hash
245
+ });
246
+ extraSignatures.set(extraSignature.pubKey, extraSignature.signature);
247
+ }
248
+ }
249
+
250
+ witness.signatures = new Map([
251
+ ...(witness.signatures ? witness.signatures.entries() : []),
252
+ ...extraSignatures.entries()
253
+ ]);
254
+ }
255
+
256
+ const transaction = {
257
+ auxiliaryData: coreTx.auxiliaryData,
258
+ body: coreTx.body,
259
+ id: hash,
260
+ isValid: tx.isValid(),
261
+ witness: mergeWitnesses(coreTx.witness, witness)
262
+ };
263
+
264
+ return {
265
+ cbor: TxCBOR.serialize(transaction),
266
+ context: {
267
+ handleResolutions: context.handleResolutions ?? []
268
+ },
269
+ tx: transaction
270
+ };
271
+ }
272
+ }
273
+
274
+ /* eslint-disable @typescript-eslint/no-explicit-any */
275
+ export const buildSharedWallets = async (env: any, genesisParameters: Cardano.CompactGenesis, logger: Logger) => {
276
+ const bip32Ed25519 = await bip32Ed25519Factory.create(env.KEY_MANAGEMENT_PARAMS.bip32Ed25519, null, logger);
277
+ const aliceMnemonics = util.generateMnemonicWords().join(' ');
278
+ const bobMnemonics = util.generateMnemonicWords().join(' ');
279
+ const charlotteMnemonics = util.generateMnemonicWords().join(' ');
280
+
281
+ const alice = await getKeyAgent(aliceMnemonics, genesisParameters, bip32Ed25519);
282
+ const bob = await getKeyAgent(bobMnemonics, genesisParameters, bip32Ed25519);
283
+ const charlotte = await getKeyAgent(charlotteMnemonics, genesisParameters, bip32Ed25519);
284
+
285
+ const multiSigParticipants = [alice.pubKey, bob.pubKey, charlotte.pubKey];
286
+
287
+ const paymentScript = await buildScript(multiSigParticipants, bip32Ed25519);
288
+ const stakingScript = await buildScript(multiSigParticipants, bip32Ed25519);
289
+
290
+ const aliceMultiSigWallet = (
291
+ await getSharedWallet({
292
+ env,
293
+ logger,
294
+ name: 'Alice shared Wallet',
295
+ paymentScript,
296
+ polling: { interval: 50 },
297
+ stakingScript,
298
+ witnesser: new SharedWalletWitnesser(alice.keyAgent, paymentScript, stakingScript)
299
+ })
300
+ ).wallet;
301
+
302
+ const bobMultiSigWallet = (
303
+ await getSharedWallet({
304
+ env,
305
+ logger,
306
+ name: 'Bob shared Wallet',
307
+ paymentScript,
308
+ polling: { interval: 50 },
309
+ stakingScript,
310
+ witnesser: new SharedWalletWitnesser(bob.keyAgent, paymentScript, stakingScript)
311
+ })
312
+ ).wallet;
313
+
314
+ const charlotteMultiSigWallet = (
315
+ await getSharedWallet({
316
+ env,
317
+ logger,
318
+ name: 'Charlotte shared Wallet',
319
+ paymentScript,
320
+ polling: { interval: 50 },
321
+ stakingScript,
322
+ witnesser: new SharedWalletWitnesser(charlotte.keyAgent, paymentScript, stakingScript)
323
+ })
324
+ ).wallet;
325
+
326
+ return { aliceMultiSigWallet, bobMultiSigWallet, charlotteMultiSigWallet };
327
+ };