@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.
- package/CHANGELOG.md +29 -0
- package/dist/cjs/factories.d.ts +26 -2
- package/dist/cjs/factories.d.ts.map +1 -1
- package/dist/cjs/factories.js +30 -2
- package/dist/cjs/factories.js.map +1 -1
- package/dist/cjs/tools/multi-delegation-data-gen/index.js +3 -3
- package/dist/cjs/tools/multi-delegation-data-gen/index.js.map +1 -1
- package/dist/cjs/tools/multi-delegation-data-gen/utils/utils.d.ts +8 -8
- package/dist/cjs/tools/multi-delegation-data-gen/utils/utils.d.ts.map +1 -1
- package/dist/cjs/tools/multi-delegation-data-gen/utils/utils.js +1 -1
- package/dist/cjs/tools/multi-delegation-data-gen/utils/utils.js.map +1 -1
- package/dist/cjs/tsconfig.tsbuildinfo +1 -1
- package/dist/cjs/util/handle-util.d.ts.map +1 -1
- package/dist/cjs/util/handle-util.js +8 -2
- package/dist/cjs/util/handle-util.js.map +1 -1
- package/dist/cjs/util/util.d.ts +4 -4
- package/dist/cjs/util/util.d.ts.map +1 -1
- package/dist/cjs/util/util.js +13 -6
- package/dist/cjs/util/util.js.map +1 -1
- package/dist/esm/factories.d.ts +26 -2
- package/dist/esm/factories.d.ts.map +1 -1
- package/dist/esm/factories.js +29 -2
- package/dist/esm/factories.js.map +1 -1
- package/dist/esm/tools/multi-delegation-data-gen/index.js +3 -3
- package/dist/esm/tools/multi-delegation-data-gen/index.js.map +1 -1
- package/dist/esm/tools/multi-delegation-data-gen/utils/utils.d.ts +8 -8
- package/dist/esm/tools/multi-delegation-data-gen/utils/utils.d.ts.map +1 -1
- package/dist/esm/tools/multi-delegation-data-gen/utils/utils.js +1 -1
- package/dist/esm/tools/multi-delegation-data-gen/utils/utils.js.map +1 -1
- package/dist/esm/tsconfig.tsbuildinfo +1 -1
- package/dist/esm/util/handle-util.d.ts.map +1 -1
- package/dist/esm/util/handle-util.js +8 -2
- package/dist/esm/util/handle-util.js.map +1 -1
- package/dist/esm/util/util.d.ts +4 -4
- package/dist/esm/util/util.d.ts.map +1 -1
- package/dist/esm/util/util.js +14 -7
- package/dist/esm/util/util.js.map +1 -1
- package/package.json +18 -18
- package/src/factories.ts +71 -2
- package/src/tools/multi-delegation-data-gen/index.ts +4 -4
- package/src/tools/multi-delegation-data-gen/utils/utils.ts +12 -12
- package/src/util/handle-util.ts +8 -2
- package/src/util/util.ts +19 -10
- package/test/artillery/wallet-restoration/types.ts +2 -2
- package/test/load-test-custom/wallet-init/wallet-init.test.ts +4 -4
- package/test/load-test-custom/wallet-restoration/wallet-restoration.test.ts +2 -2
- package/test/long-running/delegation-rewards.test.ts +6 -6
- package/test/long-running/multisig-wallet/multisig-delegation-rewards.test.ts +6 -6
- package/test/long-running/shared-wallet-delegation-rewards.test.ts +199 -0
- package/test/wallet/PersonalWallet/byron.test.ts +2 -2
- package/test/wallet/PersonalWallet/delegation.test.ts +5 -5
- package/test/wallet/PersonalWallet/delegationDistribution.test.ts +15 -15
- package/test/wallet/PersonalWallet/handle.test.ts +4 -4
- package/test/wallet/PersonalWallet/metadata.test.ts +2 -2
- package/test/wallet/PersonalWallet/mint.test.ts +10 -4
- package/test/wallet/PersonalWallet/multiAddress.test.ts +2 -2
- package/test/wallet/PersonalWallet/multisignature.test.ts +10 -4
- package/test/wallet/PersonalWallet/nft.test.ts +27 -9
- package/test/wallet/PersonalWallet/phase2validation.test.ts +4 -4
- package/test/wallet/PersonalWallet/pouchDbWalletStores.test.ts +1 -1
- package/test/wallet/PersonalWallet/txChainHistory.test.ts +4 -3
- package/test/wallet/PersonalWallet/unspendableUtxos.test.ts +3 -3
- package/test/wallet/SharedWallet/delegation.test.ts +245 -0
- package/test/wallet/SharedWallet/simpleTx.test.ts +123 -0
- 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
|
+
};
|