@cardano-sdk/e2e 0.25.0 → 0.26.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 (77) hide show
  1. package/.env.example +1 -7
  2. package/CHANGELOG.md +13 -0
  3. package/README.md +0 -29
  4. package/dist/cjs/environment.d.ts.map +1 -1
  5. package/dist/cjs/environment.js.map +1 -1
  6. package/dist/cjs/factories.d.ts.map +1 -1
  7. package/dist/cjs/factories.js +7 -1
  8. package/dist/cjs/factories.js.map +1 -1
  9. package/dist/cjs/measurement-util.d.ts.map +1 -1
  10. package/dist/cjs/measurement-util.js.map +1 -1
  11. package/dist/cjs/scripts/is-local-network-ready.js.map +1 -1
  12. package/dist/cjs/scripts/mnemonic.js.map +1 -1
  13. package/dist/cjs/tools/multi-delegation-data-gen/utils/files.d.ts.map +1 -1
  14. package/dist/cjs/tools/multi-delegation-data-gen/utils/files.js.map +1 -1
  15. package/dist/cjs/tools/multi-delegation-data-gen/utils/terminal-progress-monitor.d.ts.map +1 -1
  16. package/dist/cjs/tools/multi-delegation-data-gen/utils/terminal-progress-monitor.js.map +1 -1
  17. package/dist/cjs/tools/multi-delegation-data-gen/utils/utils.d.ts.map +1 -1
  18. package/dist/cjs/tools/multi-delegation-data-gen/utils/utils.js.map +1 -1
  19. package/dist/cjs/tsconfig.tsbuildinfo +1 -1
  20. package/dist/esm/environment.d.ts.map +1 -1
  21. package/dist/esm/environment.js.map +1 -1
  22. package/dist/esm/factories.d.ts.map +1 -1
  23. package/dist/esm/factories.js +7 -1
  24. package/dist/esm/factories.js.map +1 -1
  25. package/dist/esm/measurement-util.d.ts.map +1 -1
  26. package/dist/esm/measurement-util.js.map +1 -1
  27. package/dist/esm/scripts/is-local-network-ready.js.map +1 -1
  28. package/dist/esm/scripts/mnemonic.js.map +1 -1
  29. package/dist/esm/tools/multi-delegation-data-gen/utils/files.d.ts.map +1 -1
  30. package/dist/esm/tools/multi-delegation-data-gen/utils/files.js.map +1 -1
  31. package/dist/esm/tools/multi-delegation-data-gen/utils/terminal-progress-monitor.d.ts.map +1 -1
  32. package/dist/esm/tools/multi-delegation-data-gen/utils/terminal-progress-monitor.js.map +1 -1
  33. package/dist/esm/tools/multi-delegation-data-gen/utils/utils.d.ts.map +1 -1
  34. package/dist/esm/tools/multi-delegation-data-gen/utils/utils.js.map +1 -1
  35. package/dist/esm/tsconfig.tsbuildinfo +1 -1
  36. package/docker-compose.yml +4 -0
  37. package/jest.config.js +0 -1
  38. package/local-network/scripts/common.sh +19 -0
  39. package/local-network/scripts/make-babbage.sh +2 -1
  40. package/local-network/scripts/mint-handles.sh +2 -18
  41. package/local-network/scripts/mint-tokens.sh +2 -18
  42. package/local-network/scripts/mnemonic_keys.sh +0 -0
  43. package/local-network/scripts/setup-wallets.sh +2 -17
  44. package/local-network/templates/babbage/submit-api-config.json +115 -0
  45. package/package.json +27 -29
  46. package/src/environment.ts +2 -6
  47. package/src/factories.ts +11 -5
  48. package/src/measurement-util.ts +1 -4
  49. package/src/scripts/is-local-network-ready.ts +1 -3
  50. package/src/scripts/mnemonic.ts +1 -3
  51. package/src/tools/multi-delegation-data-gen/utils/files.ts +1 -3
  52. package/src/tools/multi-delegation-data-gen/utils/terminal-progress-monitor.ts +2 -6
  53. package/src/tools/multi-delegation-data-gen/utils/utils.ts +1 -3
  54. package/test/artillery/StakePoolSearch.ts +5 -16
  55. package/test/artillery/artillery.ts +20 -61
  56. package/test/artillery/wallet-restoration/WalletRestoration.ts +1 -3
  57. package/test/artillery/wallet-restoration/queries.ts +1 -3
  58. package/test/artillery/wallet-restoration/types.ts +1 -3
  59. package/test/load-test-custom/stake-pool-search/stake-pool-search.test.ts +1 -3
  60. package/test/load-test-custom/wallet-init/wallet-init.test.ts +10 -1
  61. package/test/load-test-custom/wallet-restoration/wallet-restoration.test.ts +1 -4
  62. package/test/local-network/register-pool.test.ts +24 -14
  63. package/test/long-running/cache-invalidation.test.ts +7 -4
  64. package/test/long-running/multisig-wallet/MultiSigTx.ts +117 -0
  65. package/test/long-running/multisig-wallet/MultiSigWallet.ts +491 -0
  66. package/test/long-running/multisig-wallet/multisig-delegation-rewards.test.ts +318 -0
  67. package/test/projection/offline-fork.test.ts +6 -6
  68. package/test/projection/single-tenant-utxo.test.ts +1 -1
  69. package/test/providers/StakePoolProvider.test.ts +22 -17
  70. package/test/wallet/PersonalWallet/delegation.test.ts +6 -3
  71. package/test/wallet/PersonalWallet/handle.test.ts +2 -1
  72. package/test/wallet/PersonalWallet/mint.test.ts +2 -1
  73. package/test/wallet/PersonalWallet/multiAddress.test.ts +2 -1
  74. package/test/wallet/PersonalWallet/multisignature.test.ts +4 -2
  75. package/test/wallet/PersonalWallet/nft.test.ts +2 -1
  76. package/test/web-extension/extension/ui.ts +2 -8
  77. package/test/load-testing/tx-submit-load.test.ts +0 -341
@@ -1,18 +1,12 @@
1
1
  import { Agent, IncomingMessage } from 'http';
2
2
  import { Agent as HttpsAgent } from 'https';
3
3
 
4
- /**
5
- * Artillery context
6
- */
4
+ /** Artillery context */
7
5
  export interface ArtilleryContext<T> {
8
- /**
9
- * The unique Id of the virtual user
10
- */
6
+ /** The unique Id of the virtual user */
11
7
  _uid: string;
12
8
 
13
- /**
14
- * The variables of the virtual user session
15
- */
9
+ /** The variables of the virtual user session */
16
10
  vars: T;
17
11
  }
18
12
 
@@ -32,89 +26,54 @@ interface ArtilleryEventEmitter extends EventEmitter {
32
26
  removeListener<Event extends keyof ArtilleryEvents>(event: Event, listener: ArtilleryEvents[Event]): this;
33
27
  }
34
28
 
35
- /**
36
- * Parameters of an Artillery request
37
- */
29
+ /** Parameters of an Artillery request */
38
30
  export interface Params {
39
- /**
40
- * Name of the afterResponse hook
41
- */
31
+ /** Name of the afterResponse hook */
42
32
  afterResponse?: string;
43
33
 
44
- /**
45
- * The agent used to for the request
46
- */
34
+ /** The agent used to for the request */
47
35
  agent?: { http: Agent; https: HttpsAgent };
48
36
 
49
- /**
50
- * Name of the beforeRequest hook
51
- */
37
+ /** Name of the beforeRequest hook */
52
38
  beforeRequest?: string;
53
39
 
54
- /**
55
- * The variables to capture from the response
56
- */
40
+ /** The variables to capture from the response */
57
41
  capture: { as: string; json: string }[];
58
42
 
59
- /**
60
- * Unknown
61
- */
43
+ /** Unknown */
62
44
  decompress?: boolean;
63
45
 
64
- /**
65
- * Not yet tested in IOG
66
- */
46
+ /** Not yet tested in IOG */
67
47
  followRedirect?: boolean;
68
48
 
69
- /**
70
- * Not yet tested in IOG
71
- */
49
+ /** Not yet tested in IOG */
72
50
  followAllRedirects?: boolean;
73
51
 
74
- /**
75
- * The HTTP headers of the request
76
- */
52
+ /** The HTTP headers of the request */
77
53
  headers?: Record<string, string>;
78
54
 
79
- /**
80
- * Unknown
81
- */
55
+ /** Unknown */
82
56
  https?: unknown;
83
57
 
84
- /**
85
- * The json body for POST. Its value is the raw configured one in beforeRequest
86
- * and the evaluated one in afterResponse
87
- */
58
+ /** The json body for POST. Its value is the raw configured one in beforeRequest and the evaluated one in afterResponse */
88
59
  json?: unknown;
89
60
 
90
- /**
91
- * Unknown
92
- */
61
+ /** Unknown */
93
62
  match?: unknown[];
94
63
 
95
- /**
96
- * The HTTP method of the request
97
- */
64
+ /** The HTTP method of the request */
98
65
  method: 'DELETE' | 'GET' | 'POST' | 'PUT';
99
66
 
100
- /**
101
- * Unknown
102
- */
67
+ /** Unknown */
103
68
  retry: number;
104
69
 
105
- /**
106
- * Unknown
107
- */
70
+ /** Unknown */
108
71
  throwHttpErrors?: boolean;
109
72
 
110
- /**
111
- * The time out of the request in ms
112
- */
73
+ /** The time out of the request in ms */
113
74
  timeout: number;
114
75
 
115
- /**
116
- * URL of the request
117
- */
76
+ /** URL of the request */
118
77
  url: string;
119
78
  }
120
79
 
@@ -79,9 +79,7 @@ export const getAddresses: FunctionHook<WalletVars> = async ({ vars }, _, done)
79
79
  done();
80
80
  };
81
81
 
82
- /**
83
- * The current index of found addresses list
84
- */
82
+ /** The current index of found addresses list */
85
83
  let index = 0;
86
84
 
87
85
  export const walletRestoration: FunctionHook<WalletVars> = async ({ vars, _uid }, ee, done) => {
@@ -1,6 +1,4 @@
1
- /**
2
- * Query distinct addresses from db associated with users who are staking.
3
- */
1
+ /** Query distinct addresses from db associated with users who are staking. */
4
2
  export const findAddressesWithRegisteredStakeKey = `
5
3
  SELECT COUNT(*) AS tx_count, address, sa.view as stake_address
6
4
  FROM tx_out
@@ -1,9 +1,7 @@
1
1
  import { GroupedAddress } from '@cardano-sdk/key-management';
2
2
  import { PersonalWallet } from '@cardano-sdk/wallet';
3
3
 
4
- /**
5
- * The context variables shared between all the hooks.
6
- */
4
+ /** The context variables shared between all the hooks. */
7
5
  export interface WalletVars {
8
6
  walletLoads: number;
9
7
  addresses: GroupedAddress[];
@@ -39,9 +39,7 @@ enum MeasureTarget {
39
39
 
40
40
  const PAGE_SIZE = 20;
41
41
 
42
- /**
43
- * The set of pools id found while getting results
44
- */
42
+ /** The set of pools id found while getting results */
45
43
  const poolIds: Cardano.PoolId[] = [];
46
44
 
47
45
  const measurement = new MeasurementUtil<MeasureTarget | string>();
@@ -26,6 +26,7 @@ import {
26
26
  waitForWalletStateSettle,
27
27
  walletVariables
28
28
  } from '../../../src';
29
+ import { util } from '@cardano-sdk/key-management';
29
30
 
30
31
  // Example call that creates 5000 wallets in 10 minutes:
31
32
  // VIRTUAL_USERS_GENERATE_DURATION=600 VIRTUAL_USERS_COUNT=5000 yarn load-test-custom:wallet-init
@@ -84,7 +85,15 @@ const createWallet = async (accountIndex: number): Promise<PersonalWallet> => {
84
85
  measurementUtil.addMeasureMarker(MeasureTarget.keyAgent, accountIndex);
85
86
 
86
87
  measurementUtil.addStartMarker(MeasureTarget.wallet, accountIndex);
87
- const wallet = new PersonalWallet({ name: `Wallet ${accountIndex}` }, { ...providers, keyAgent, logger });
88
+ const wallet = new PersonalWallet(
89
+ { name: `Wallet ${accountIndex}` },
90
+ {
91
+ ...providers,
92
+ addressManager: util.createBip32Ed25519AddressManager(keyAgent),
93
+ logger,
94
+ witnesser: util.createBip32Ed25519Witnesser(keyAgent)
95
+ }
96
+ );
88
97
  walletUtil.initialize(wallet);
89
98
  return wallet;
90
99
  };
@@ -11,10 +11,7 @@ import { PersonalWallet } from '@cardano-sdk/wallet';
11
11
  import { logger } from '@cardano-sdk/util-dev';
12
12
  import { mapToGroupedAddress } from '../../artillery/wallet-restoration/WalletRestoration';
13
13
 
14
- /**
15
- * Env var MAX_USERS sets the maximum number of concurrent users to measure
16
- * default value 100
17
- */
14
+ /** Env var MAX_USERS sets the maximum number of concurrent users to measure default value 100 */
18
15
  const RESTORATION_TIMEOUT = process.env.RESTORATION_TIMEOUT
19
16
  ? Number.parseInt(process.env.RESTORATION_TIMEOUT)
20
17
  : 5 * MINUTE;
@@ -3,6 +3,7 @@ import { Cardano } from '@cardano-sdk/core';
3
3
  import {
4
4
  KeyAgentFactoryProps,
5
5
  TestWallet,
6
+ bip32Ed25519Factory,
6
7
  getEnv,
7
8
  getWallet,
8
9
  submitCertificate,
@@ -12,6 +13,7 @@ import {
12
13
  } from '../../src';
13
14
  import { logger } from '@cardano-sdk/util-dev';
14
15
 
16
+ import * as Crypto from '@cardano-sdk/crypto';
15
17
  import { AddressType, KeyRole } from '@cardano-sdk/key-management';
16
18
  import { firstValueFrom } from 'rxjs';
17
19
 
@@ -40,6 +42,7 @@ const wallet2Params: KeyAgentFactoryProps = {
40
42
  describe('local-network/register-pool', () => {
41
43
  let wallet1: TestWallet;
42
44
  let wallet2: TestWallet;
45
+ let bip32Ed25519: Crypto.Bip32Ed25519;
43
46
 
44
47
  beforeAll(async () => {
45
48
  jest.setTimeout(180_000);
@@ -63,6 +66,7 @@ describe('local-network/register-pool', () => {
63
66
 
64
67
  await waitForWalletStateSettle(wallet1.wallet);
65
68
  await waitForWalletStateSettle(wallet2.wallet);
69
+ bip32Ed25519 = await bip32Ed25519Factory.create(env.KEY_MANAGEMENT_PARAMS.bip32Ed25519, null, logger);
66
70
  });
67
71
 
68
72
  afterAll(() => {
@@ -75,18 +79,17 @@ describe('local-network/register-pool', () => {
75
79
 
76
80
  await walletReady(wallet);
77
81
 
78
- const poolKeyAgent = wallet.keyAgent;
82
+ const poolAddressManager = wallet.addressManager;
79
83
 
80
- const poolPubKey = await poolKeyAgent.derivePublicKey({
84
+ const poolPubKey = await poolAddressManager.derivePublicKey({
81
85
  index: 0,
82
86
  role: KeyRole.External
83
87
  });
84
88
 
85
- const bip32Ed25519 = await poolKeyAgent.getBip32Ed25519();
86
89
  const poolKeyHash = await bip32Ed25519.getPubKeyHash(poolPubKey);
87
90
  const poolId = Cardano.PoolId.fromKeyHash(poolKeyHash);
88
91
  const poolRewardAccount = (
89
- await poolKeyAgent.deriveAddress(
92
+ await poolAddressManager.deriveAddress(
90
93
  {
91
94
  index: 0,
92
95
  type: AddressType.External
@@ -117,13 +120,17 @@ describe('local-network/register-pool', () => {
117
120
 
118
121
  const rewardAccounts = await firstValueFrom(wallet.delegation.rewardAccounts$);
119
122
  const stakeKeyHash = Cardano.RewardAccount.toHash(rewardAccounts[0].address);
123
+ const stakeCredential = {
124
+ hash: stakeKeyHash as unknown as Crypto.Hash28ByteBase16,
125
+ type: Cardano.CredentialType.KeyHash
126
+ };
120
127
 
121
128
  await submitCertificate(registrationCert, wallet1);
122
129
 
123
130
  // Register stake key.
124
131
  const registerStakeKey: Cardano.StakeAddressCertificate = {
125
- __typename: Cardano.CertificateType.StakeKeyRegistration,
126
- stakeKeyHash
132
+ __typename: Cardano.CertificateType.StakeRegistration,
133
+ stakeCredential
127
134
  };
128
135
 
129
136
  await submitCertificate(registerStakeKey, wallet1);
@@ -132,7 +139,7 @@ describe('local-network/register-pool', () => {
132
139
  const delegationCert: Cardano.StakeDelegationCertificate = {
133
140
  __typename: Cardano.CertificateType.StakeDelegation,
134
141
  poolId,
135
- stakeKeyHash
142
+ stakeCredential
136
143
  };
137
144
 
138
145
  await submitCertificate(delegationCert, wallet1);
@@ -160,18 +167,17 @@ describe('local-network/register-pool', () => {
160
167
 
161
168
  await walletReady(wallet);
162
169
 
163
- const poolKeyAgent = wallet.keyAgent;
170
+ const poolAddressManager = wallet.addressManager;
164
171
 
165
- const poolPubKey = await poolKeyAgent.derivePublicKey({
172
+ const poolPubKey = await poolAddressManager.derivePublicKey({
166
173
  index: 0,
167
174
  role: KeyRole.External
168
175
  });
169
176
 
170
- const bip32Ed25519 = await poolKeyAgent.getBip32Ed25519();
171
177
  const poolKeyHash = await bip32Ed25519.getPubKeyHash(poolPubKey);
172
178
  const poolId = Cardano.PoolId.fromKeyHash(poolKeyHash);
173
179
  const poolRewardAccount = (
174
- await poolKeyAgent.deriveAddress(
180
+ await poolAddressManager.deriveAddress(
175
181
  {
176
182
  index: 0,
177
183
  type: AddressType.External
@@ -202,13 +208,17 @@ describe('local-network/register-pool', () => {
202
208
 
203
209
  const rewardAccounts = await firstValueFrom(wallet.delegation.rewardAccounts$);
204
210
  const stakeKeyHash = Cardano.RewardAccount.toHash(rewardAccounts[0].address);
211
+ const stakeCredential = {
212
+ hash: stakeKeyHash as unknown as Crypto.Hash28ByteBase16,
213
+ type: Cardano.CredentialType.KeyHash
214
+ };
205
215
 
206
216
  await submitCertificate(registrationCert, wallet2);
207
217
 
208
218
  // Register stake key.
209
219
  const registerStakeKey: Cardano.StakeAddressCertificate = {
210
- __typename: Cardano.CertificateType.StakeKeyRegistration,
211
- stakeKeyHash
220
+ __typename: Cardano.CertificateType.StakeRegistration,
221
+ stakeCredential
212
222
  };
213
223
 
214
224
  await submitCertificate(registerStakeKey, wallet2);
@@ -217,7 +227,7 @@ describe('local-network/register-pool', () => {
217
227
  const delegationCert: Cardano.StakeDelegationCertificate = {
218
228
  __typename: Cardano.CertificateType.StakeDelegation,
219
229
  poolId,
220
- stakeKeyHash
230
+ stakeCredential
221
231
  };
222
232
 
223
233
  await submitCertificate(delegationCert, wallet2);
@@ -1,8 +1,10 @@
1
+ import * as Crypto from '@cardano-sdk/crypto';
1
2
  import { AddressType, KeyRole } from '@cardano-sdk/key-management';
2
3
  import { Cardano } from '@cardano-sdk/core';
3
4
  import {
4
5
  KeyAgentFactoryProps,
5
6
  TestWallet,
7
+ bip32Ed25519Factory,
6
8
  getEnv,
7
9
  getTxConfirmationEpoch,
8
10
  getWallet,
@@ -23,6 +25,7 @@ const vrf = Cardano.VrfVkHex('2ee5a4c423224bb9c42107fc18a60556d6a83cec1d9dd37a71
23
25
  describe('cache invalidation', () => {
24
26
  let testProviderServer: Docker.Container;
25
27
  let wallet1: TestWallet;
28
+ let bip32Ed25519: Crypto.Bip32Ed25519;
26
29
 
27
30
  beforeAll(async () => {
28
31
  const port = await getRandomPort();
@@ -90,6 +93,7 @@ describe('cache invalidation', () => {
90
93
  });
91
94
 
92
95
  await waitForWalletStateSettle(wallet1.wallet);
96
+ bip32Ed25519 = await bip32Ed25519Factory.create(env.KEY_MANAGEMENT_PARAMS.bip32Ed25519, null, logger);
93
97
  });
94
98
 
95
99
  afterAll(async () => {
@@ -103,18 +107,17 @@ describe('cache invalidation', () => {
103
107
 
104
108
  await walletReady(wallet);
105
109
 
106
- const poolKeyAgent = wallet.keyAgent;
110
+ const poolAddressManager = wallet.addressManager;
107
111
 
108
- const poolPubKey = await poolKeyAgent.derivePublicKey({
112
+ const poolPubKey = await poolAddressManager.derivePublicKey({
109
113
  index: 0,
110
114
  role: KeyRole.External
111
115
  });
112
116
 
113
- const bip32Ed25519 = await poolKeyAgent.getBip32Ed25519();
114
117
  const poolKeyHash = await bip32Ed25519.getPubKeyHash(poolPubKey);
115
118
  const poolId = Cardano.PoolId.fromKeyHash(poolKeyHash);
116
119
  const poolRewardAccount = (
117
- await poolKeyAgent.deriveAddress(
120
+ await poolAddressManager.deriveAddress(
118
121
  {
119
122
  index: 0,
120
123
  type: AddressType.External
@@ -0,0 +1,117 @@
1
+ import * as Crypto from '@cardano-sdk/crypto';
2
+ import { Cardano, Serialization, deserializeTx } from '@cardano-sdk/core';
3
+ import { HexBlob } from '@cardano-sdk/util';
4
+
5
+ /**
6
+ * Represents a multi-signature transaction for the Cardano blockchain.
7
+ * This transaction can be serialized and transfer between participants of the multisig wallet.
8
+ * The transaction carries a bit of extra context, such as the expected signers and the signatures
9
+ * of the signers who have already signed. this way the participants will know if the transaction is ready to be sent,
10
+ * or they need to relay the transaction to additional participants (and to whom) for additional signing.
11
+ */
12
+ export class MultiSigTx {
13
+ #transaction: Cardano.Tx;
14
+ #expectedSigners: Array<Crypto.Ed25519PublicKeyHex> = [];
15
+
16
+ /**
17
+ * Initializes a new instance of the MultiSigTx class.
18
+ *
19
+ * @param {Cardano.Tx} transaction - The underlying Cardano transaction.
20
+ * @param {Array<Crypto.Ed25519PublicKeyHex>} expectedSigners - An array of expected signers' public keys.
21
+ */
22
+ constructor(transaction: Cardano.Tx, expectedSigners: Array<Crypto.Ed25519PublicKeyHex>) {
23
+ this.#transaction = transaction;
24
+ this.#expectedSigners = expectedSigners;
25
+ }
26
+
27
+ /**
28
+ * Serializes the multi-signature transaction to a CBOR hex blob.
29
+ *
30
+ * @returns {HexBlob} The serialized transaction as a hex-encoded string.
31
+ */
32
+ toCbor(): HexBlob {
33
+ const writer = new Serialization.CborWriter();
34
+
35
+ writer.writeStartArray(2);
36
+ writer.writeStartArray(this.#expectedSigners.length);
37
+
38
+ for (const signer of this.#expectedSigners) {
39
+ writer.writeByteString(Buffer.from(signer, 'hex'));
40
+ }
41
+
42
+ writer.writeEncodedValue(Buffer.from(Serialization.Transaction.fromCore(this.#transaction).toCbor(), 'hex'));
43
+ return writer.encodeAsHex();
44
+ }
45
+
46
+ /**
47
+ * Deserializes a CBOR hex blob into a MultiSigTx instance.
48
+ *
49
+ * @param {HexBlob} cbor - The CBOR hex blob representing the transaction.
50
+ * @returns {MultiSigTx} The deserialized MultiSigTx instance.
51
+ */
52
+ static fromCbor(cbor: HexBlob): MultiSigTx {
53
+ const reader = new Serialization.CborReader(cbor);
54
+
55
+ reader.readStartArray();
56
+ const length = reader.readStartArray();
57
+ const expectedSigners: Array<Crypto.Ed25519PublicKeyHex> = [];
58
+
59
+ if (length === null || length <= 0) throw new Error('Expected at least one signer');
60
+
61
+ for (let i = 0; i < length; i++)
62
+ expectedSigners.push(Crypto.Ed25519PublicKeyHex(Buffer.from(reader.readByteString()).toString('hex')));
63
+
64
+ reader.readEndArray();
65
+
66
+ const transaction = deserializeTx(reader.readEncodedValue());
67
+ reader.readEndArray();
68
+
69
+ return new MultiSigTx(transaction, expectedSigners);
70
+ }
71
+
72
+ /**
73
+ * Checks whether the transaction has been fully signed.
74
+ *
75
+ * @returns {boolean} True if the transaction is fully signed, otherwise false.
76
+ */
77
+ isFullySigned(): boolean {
78
+ return this.#expectedSigners.every((signer) => this.#transaction.witness.signatures.has(signer));
79
+ }
80
+
81
+ /**
82
+ * Retrieves the original Cardano transaction.
83
+ *
84
+ * @returns {Cardano.Tx} The Cardano transaction.
85
+ */
86
+ getTransaction(): Cardano.Tx {
87
+ return this.#transaction;
88
+ }
89
+
90
+ /**
91
+ * Identifies and returns the public keys of signers who have not yet signed the transaction.
92
+ *
93
+ * @returns {Array<Crypto.Ed25519PublicKeyHex>} An array of public keys of the missing signers.
94
+ */
95
+ getMissingSigners(): Array<Crypto.Ed25519PublicKeyHex> {
96
+ const missingSigners: Array<Crypto.Ed25519PublicKeyHex> = [];
97
+
98
+ for (const signer of this.#expectedSigners)
99
+ if (!this.#transaction.witness.signatures.has(signer)) missingSigners.push(signer);
100
+
101
+ return missingSigners;
102
+ }
103
+
104
+ /**
105
+ * Identifies and returns the public keys of signers who have signed the transaction.
106
+ *
107
+ * @returns {Array<Crypto.Ed25519PublicKeyHex>} An array of public keys of the signers who have already signed.
108
+ */
109
+ getAccountedForSigners(): Array<Crypto.Ed25519PublicKeyHex> {
110
+ const accountedSigners: Array<Crypto.Ed25519PublicKeyHex> = [];
111
+
112
+ for (const signer of this.#expectedSigners)
113
+ if (this.#transaction.witness.signatures.has(signer)) accountedSigners.push(signer);
114
+
115
+ return accountedSigners;
116
+ }
117
+ }