@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
@@ -1,6 +1,6 @@
1
1
  /* eslint-disable sonarjs/no-duplicate-string */
2
2
  import { Asset, Cardano, metadatum, nativeScriptPolicyId } from '@cardano-sdk/core';
3
- import { Assets, FinalizeTxProps, PersonalWallet } from '@cardano-sdk/wallet';
3
+ import { Assets, BaseWallet, FinalizeTxProps } from '@cardano-sdk/wallet';
4
4
  import { InitializeTxProps } from '@cardano-sdk/tx-construction';
5
5
  import { KeyRole, TransactionSigner, util } from '@cardano-sdk/key-management';
6
6
  import {
@@ -21,7 +21,7 @@ const env = getEnv(walletVariables);
21
21
  const logger = createLogger();
22
22
 
23
23
  // Returns [assets in wallet balance, assetInfos with nftMetadata for the assets in the balance]
24
- const walletBalanceAssetsAndNfts = (wallet: PersonalWallet) =>
24
+ const walletBalanceAssetsAndNfts = (wallet: BaseWallet) =>
25
25
  combineLatest([wallet.balance.utxo.total$, wallet.assetInfo$]).pipe(
26
26
  filter(([balance]) => !!balance.assets),
27
27
  map(([balance, assetInfos]): [Cardano.TokenMap, Assets] => [balance.assets!, assetInfos]),
@@ -41,7 +41,7 @@ describe('PersonalWallet.assets/nft', () => {
41
41
  const TOKEN_METADATA_2_INDEX = 1;
42
42
  const TOKEN_BURN_INDEX = 2;
43
43
 
44
- let wallet: PersonalWallet;
44
+ let wallet: BaseWallet;
45
45
  let policySigner: TransactionSigner;
46
46
  let policyId: Cardano.PolicyId;
47
47
  let policyScript: Cardano.NativeScript;
@@ -160,15 +160,21 @@ describe('PersonalWallet.assets/nft', () => {
160
160
  }
161
161
  }
162
162
  ]),
163
- witness: { extraSigners: [policySigner], scripts: [policyScript] }
163
+ signingOptions: {
164
+ extraSigners: [policySigner]
165
+ },
166
+ witness: { scripts: [policyScript] }
164
167
  };
165
168
 
166
169
  const unsignedTx = await wallet.initializeTx(txProps);
167
170
 
168
171
  const finalizeProps: FinalizeTxProps = {
169
172
  auxiliaryData,
173
+ signingOptions: {
174
+ extraSigners: [policySigner]
175
+ },
170
176
  tx: unsignedTx,
171
- witness: { extraSigners: [policySigner], scripts: [policyScript] }
177
+ witness: { scripts: [policyScript] }
172
178
  };
173
179
 
174
180
  const signedTx = await wallet.finalizeTx(finalizeProps);
@@ -270,14 +276,20 @@ describe('PersonalWallet.assets/nft', () => {
270
276
  }
271
277
  }
272
278
  ]),
273
- witness: { extraSigners: [policySigner], scripts: [policyScript] }
279
+ signingOptions: {
280
+ extraSigners: [policySigner]
281
+ },
282
+ witness: { scripts: [policyScript] }
274
283
  };
275
284
 
276
285
  const unsignedTx = await wallet.initializeTx(txProps);
277
286
 
278
287
  const finalizeProps: FinalizeTxProps = {
288
+ signingOptions: {
289
+ extraSigners: [policySigner]
290
+ },
279
291
  tx: unsignedTx,
280
- witness: { extraSigners: [policySigner], scripts: [policyScript] }
292
+ witness: { scripts: [policyScript] }
281
293
  };
282
294
 
283
295
  const signedTx = await wallet.finalizeTx(finalizeProps);
@@ -334,15 +346,21 @@ describe('PersonalWallet.assets/nft', () => {
334
346
  }
335
347
  }
336
348
  ]),
337
- witness: { extraSigners: [policySigner], scripts: [policyScript] }
349
+ signingOptions: {
350
+ extraSigners: [policySigner]
351
+ },
352
+ witness: { scripts: [policyScript] }
338
353
  };
339
354
 
340
355
  const unsignedTx = await wallet.initializeTx(txProps);
341
356
 
342
357
  const finalizeProps: FinalizeTxProps = {
343
358
  auxiliaryData,
359
+ signingOptions: {
360
+ extraSigners: [policySigner]
361
+ },
344
362
  tx: unsignedTx,
345
- witness: { extraSigners: [policySigner], scripts: [policyScript] }
363
+ witness: { scripts: [policyScript] }
346
364
  };
347
365
 
348
366
  const signedTx = await wallet.finalizeTx(finalizeProps);
@@ -1,5 +1,5 @@
1
+ import { BaseWallet, FinalizeTxProps, TransactionFailure } from '@cardano-sdk/wallet';
1
2
  import { Cardano, Serialization } from '@cardano-sdk/core';
2
- import { FinalizeTxProps, PersonalWallet, TransactionFailure } from '@cardano-sdk/wallet';
3
3
  import { Hash32ByteBase16 } from '@cardano-sdk/crypto';
4
4
  import { HexBlob, isNotNil } from '@cardano-sdk/util';
5
5
  import { InitializeTxProps } from '@cardano-sdk/tx-construction';
@@ -16,7 +16,7 @@ const logger = createLogger();
16
16
  * @param wallet The wallet which will set the collateral.
17
17
  */
18
18
  const createCollateral = async (
19
- wallet: PersonalWallet
19
+ wallet: BaseWallet
20
20
  ): Promise<{ collateralInput: Cardano.TxIn; collateralCoinValue: bigint }> => {
21
21
  const txBuilder = wallet.createTxBuilder();
22
22
 
@@ -53,7 +53,7 @@ const createCollateral = async (
53
53
  };
54
54
 
55
55
  describe('PersonalWallet/phase2validation', () => {
56
- let wallet: PersonalWallet;
56
+ let wallet: BaseWallet;
57
57
 
58
58
  afterAll(() => {
59
59
  wallet.shutdown();
@@ -150,6 +150,6 @@ describe('PersonalWallet/phase2validation', () => {
150
150
  expect([TransactionFailure.Phase2Validation, TransactionFailure.FailedToSubmit].includes(failedTx.reason)).toBe(
151
151
  true
152
152
  );
153
- expect(txFoundInHistory.body.fee).toEqual(collateralCoinValue);
153
+ expect(txFoundInHistory.body.totalCollateral).toEqual(collateralCoinValue);
154
154
  });
155
155
  });
@@ -14,7 +14,7 @@ describe('PersonalWallet/pouchDbWalletStores', () => {
14
14
  stores1 = storage.createPouchDbWalletStores(walletName, { logger });
15
15
  });
16
16
 
17
- it('stores and restores PersonalWallet, continues sync after initial load', async () => {
17
+ it('stores and restores BaseWallet, continues sync after initial load', async () => {
18
18
  const wallet1 = (await getWallet({ env, logger, name: 'Test Wallet', stores: stores1 })).wallet;
19
19
 
20
20
  // wallet1 fetched all responses from wallet provider
@@ -1,5 +1,5 @@
1
+ import { BaseWallet } from '@cardano-sdk/wallet';
1
2
  import { Cardano, CardanoNodeUtil, ProviderError } from '@cardano-sdk/core';
2
- import { PersonalWallet } from '@cardano-sdk/wallet';
3
3
  import { filter, firstValueFrom, map, take } from 'rxjs';
4
4
  import { getEnv, getWallet, normalizeTxBody, walletReady, walletVariables } from '../../../src';
5
5
  import { isNotNil } from '@cardano-sdk/util';
@@ -8,7 +8,7 @@ import { logger } from '@cardano-sdk/util-dev';
8
8
  const env = getEnv(walletVariables);
9
9
 
10
10
  describe('PersonalWallet/txChainHistory', () => {
11
- let wallet: PersonalWallet;
11
+ let wallet: BaseWallet;
12
12
  let signedTx: Cardano.Tx<Cardano.TxBody>;
13
13
 
14
14
  beforeEach(async () => {
@@ -61,7 +61,8 @@ describe('PersonalWallet/txChainHistory', () => {
61
61
  expect(normalizeTxBody(txFoundInHistory.body)).toEqual(normalizeTxBody(signedTx.body));
62
62
  });
63
63
 
64
- it('can detect a ValueNotConserved error', async () => {
64
+ // TODO LW-9972
65
+ it.skip('can detect a ValueNotConserved error', async () => {
65
66
  expect.assertions(1);
66
67
  // Search chain history to see if the transaction is there.
67
68
  await firstValueFrom(
@@ -1,5 +1,5 @@
1
1
  /* eslint-disable sonarjs/no-duplicate-string */
2
- import { PersonalWallet, utxoEquals } from '@cardano-sdk/wallet';
2
+ import { BaseWallet, utxoEquals } from '@cardano-sdk/wallet';
3
3
  import { createLogger } from '@cardano-sdk/util-dev';
4
4
  import { filter, firstValueFrom, map, take } from 'rxjs';
5
5
  import { firstValueFromTimed, getEnv, getWallet, walletReady, walletVariables } from '../../../src';
@@ -9,8 +9,8 @@ const env = getEnv(walletVariables);
9
9
  const logger = createLogger();
10
10
 
11
11
  describe('PersonalWallet/unspendableUtxos', () => {
12
- let wallet1: PersonalWallet;
13
- let wallet2: PersonalWallet;
12
+ let wallet1: BaseWallet;
13
+ let wallet2: BaseWallet;
14
14
 
15
15
  afterAll(() => {
16
16
  wallet1.shutdown();
@@ -0,0 +1,245 @@
1
+ /* eslint-disable max-statements */
2
+ import { BaseWallet, ObservableWallet } from '@cardano-sdk/wallet';
3
+ import { BigIntMath, isNotNil } from '@cardano-sdk/util';
4
+ import { Cardano, StakePoolProvider } from '@cardano-sdk/core';
5
+ import {
6
+ TX_TIMEOUT_DEFAULT,
7
+ firstValueFromTimed,
8
+ getEnv,
9
+ getWallet,
10
+ normalizeTxBody,
11
+ waitForWalletStateSettle,
12
+ walletReady,
13
+ walletVariables
14
+ } from '../../../src';
15
+ import { buildSharedWallets } from './ultils';
16
+ import { combineLatest, filter, firstValueFrom, map, take } from 'rxjs';
17
+ import { logger } from '@cardano-sdk/util-dev';
18
+
19
+ const env = getEnv(walletVariables);
20
+
21
+ const getWalletStateSnapshot = async (wallet: ObservableWallet) => {
22
+ const [rewardAccount] = await firstValueFrom(wallet.delegation.rewardAccounts$);
23
+ const [publicStakeKey] = await firstValueFrom(wallet.publicStakeKeys$);
24
+ const balanceAvailable = await firstValueFrom(wallet.balance.utxo.available$);
25
+ const balanceTotal = await firstValueFrom(wallet.balance.utxo.total$);
26
+ const deposit = await firstValueFrom(wallet.balance.rewardAccounts.deposit$);
27
+ const epoch = await firstValueFrom(wallet.currentEpoch$);
28
+ const utxoTotal = await firstValueFrom(wallet.utxo.total$);
29
+ const utxoAvailable = await firstValueFrom(wallet.utxo.available$);
30
+ const rewardsBalance = await firstValueFrom(wallet.balance.rewardAccounts.rewards$);
31
+
32
+ return {
33
+ balance: { available: balanceAvailable, deposit, total: balanceTotal },
34
+ epoch: epoch.epochNo,
35
+ isStakeCredentialRegistered: rewardAccount.credentialStatus === Cardano.StakeCredentialStatus.Registered,
36
+ publicStakeKey,
37
+ rewardAccount,
38
+ rewardsBalance,
39
+ utxo: { available: utxoTotal, total: utxoAvailable }
40
+ };
41
+ };
42
+
43
+ const waitForTx = async (wallet: ObservableWallet, hash: Cardano.TransactionId) => {
44
+ await firstValueFromTimed(
45
+ combineLatest([
46
+ wallet.transactions.history$.pipe(filter((txs) => txs.some(({ id }) => id === hash))),
47
+ // test that onChain$ works
48
+ wallet.transactions.outgoing.onChain$.pipe(filter(({ id }) => id === hash))
49
+ ]),
50
+ 'Tx not found on-chain for too long',
51
+ TX_TIMEOUT_DEFAULT
52
+ );
53
+ await waitForWalletStateSettle(wallet);
54
+ };
55
+
56
+ describe('SharedWallet/delegation', () => {
57
+ let fundingTx: Cardano.Tx<Cardano.TxBody>;
58
+ let faucetWallet: BaseWallet;
59
+ let faucetAddress: Cardano.PaymentAddress;
60
+ let aliceMultiSigWallet: BaseWallet;
61
+ let bobMultiSigWallet: BaseWallet;
62
+ let charlotteMultiSigWallet: BaseWallet;
63
+ let stakePoolProvider: StakePoolProvider;
64
+
65
+ const initialFunds = 10_000_000n;
66
+
67
+ beforeAll(async () => {
68
+ jest.setTimeout(180_000);
69
+
70
+ ({
71
+ wallet: faucetWallet,
72
+ providers: { stakePoolProvider }
73
+ } = await getWallet({ env, logger, name: 'Sending Wallet', polling: { interval: 50 } }));
74
+
75
+ // Make sure the wallet has sufficient funds to run this test
76
+ await walletReady(faucetWallet, initialFunds);
77
+
78
+ faucetAddress = (await firstValueFrom(faucetWallet.addresses$))[0].address;
79
+
80
+ ({ aliceMultiSigWallet, bobMultiSigWallet, charlotteMultiSigWallet } = await buildSharedWallets(
81
+ env,
82
+ await firstValueFrom(faucetWallet.genesisParameters$),
83
+ logger
84
+ ));
85
+
86
+ await Promise.all([
87
+ waitForWalletStateSettle(aliceMultiSigWallet),
88
+ waitForWalletStateSettle(bobMultiSigWallet),
89
+ waitForWalletStateSettle(charlotteMultiSigWallet)
90
+ ]);
91
+
92
+ const [{ address: receivingAddress }] = await firstValueFrom(aliceMultiSigWallet.addresses$);
93
+
94
+ logger.info(`Address ${faucetAddress} will send ${initialFunds} lovelace to address ${receivingAddress}.`);
95
+
96
+ // Send 10 tADA to the shared wallet.
97
+ const txBuilder = faucetWallet.createTxBuilder();
98
+ const txOutput = await txBuilder.buildOutput().address(receivingAddress).coin(initialFunds).build();
99
+ fundingTx = (await txBuilder.addOutput(txOutput).build().sign()).tx;
100
+ await faucetWallet.submitTx(fundingTx);
101
+
102
+ logger.info(
103
+ `Submitted transaction id: ${fundingTx.id}, inputs: ${JSON.stringify(
104
+ fundingTx.body.inputs.map((txIn) => [txIn.txId, txIn.index])
105
+ )} and outputs:${JSON.stringify(
106
+ fundingTx.body.outputs.map((txOut) => [txOut.address, Number.parseInt(txOut.value.coins.toString())])
107
+ )}.`
108
+ );
109
+ });
110
+
111
+ afterAll(() => {
112
+ faucetWallet.shutdown();
113
+ aliceMultiSigWallet.shutdown();
114
+ bobMultiSigWallet.shutdown();
115
+ charlotteMultiSigWallet.shutdown();
116
+ faucetWallet.shutdown();
117
+ });
118
+
119
+ const chooseDifferentPoolIdRandomly = async (delegateeBefore1stTx?: Cardano.PoolId): Promise<Cardano.PoolId> => {
120
+ const activePools = await stakePoolProvider.queryStakePools({
121
+ filters: { status: [Cardano.StakePoolStatus.Active] },
122
+ pagination: { limit: 2, startAt: 0 }
123
+ });
124
+ const filteredPools = activePools.pageResults.filter(({ id }) => id !== delegateeBefore1stTx);
125
+ return filteredPools[Math.round(Math.random() * (filteredPools.length - 1))]?.id;
126
+ };
127
+
128
+ test('delegation preconditions', async () => {
129
+ const addresses = await firstValueFrom(aliceMultiSigWallet.addresses$);
130
+ const currentEpoch = await firstValueFrom(aliceMultiSigWallet.currentEpoch$);
131
+ expect(addresses[0].rewardAccount).toBeTruthy();
132
+ expect(currentEpoch.epochNo).toBeGreaterThan(0);
133
+ });
134
+
135
+ test('balance & transaction', async () => {
136
+ const txFoundInHistory = await firstValueFrom(
137
+ aliceMultiSigWallet.transactions.history$.pipe(
138
+ map((txs) => txs.find((tx) => tx.id === fundingTx.id)),
139
+ filter(isNotNil),
140
+ take(1)
141
+ )
142
+ );
143
+
144
+ logger.info(`Found transaction id in chain history: ${txFoundInHistory.id}`);
145
+
146
+ expect(txFoundInHistory).toBeDefined();
147
+ expect(txFoundInHistory.id).toEqual(fundingTx.id);
148
+ expect(normalizeTxBody(txFoundInHistory.body)).toEqual(normalizeTxBody(fundingTx.body));
149
+
150
+ const tx1OutputCoins = 1_000_000n;
151
+ await walletReady(aliceMultiSigWallet, tx1OutputCoins);
152
+
153
+ const protocolParameters = await firstValueFrom(aliceMultiSigWallet.protocolParameters$);
154
+ const stakeKeyDeposit = BigInt(protocolParameters.stakeKeyDeposit);
155
+ const initialState = await getWalletStateSnapshot(aliceMultiSigWallet);
156
+ expect(initialState.balance.total.coins).toBe(initialState.balance.available.coins);
157
+ const poolId = await chooseDifferentPoolIdRandomly(initialState.rewardAccount.delegatee?.nextNextEpoch?.id);
158
+ expect(poolId).toBeDefined();
159
+ const initialDeposit = initialState.isStakeCredentialRegistered ? stakeKeyDeposit : 0n;
160
+ expect(initialState.balance.deposit).toBe(initialDeposit);
161
+
162
+ // Make a 1st tx with key registration (if not already registered) and stake delegation
163
+ // Also send some coin to another wallet
164
+ const destAddresses = (await firstValueFrom(faucetWallet.addresses$))[0].address;
165
+ const txBuilder = aliceMultiSigWallet.createTxBuilder();
166
+
167
+ let tx = (
168
+ await txBuilder
169
+ .addOutput(await txBuilder.buildOutput().address(destAddresses).coin(tx1OutputCoins).build())
170
+ .delegateFirstStakeCredential(poolId)
171
+ .build()
172
+ .sign()
173
+ ).tx;
174
+
175
+ tx = await bobMultiSigWallet.updateWitness({ sender: { id: 'e2e' }, tx });
176
+ tx = await charlotteMultiSigWallet.updateWitness({ sender: { id: 'e2e' }, tx });
177
+ await aliceMultiSigWallet.submitTx(tx);
178
+
179
+ // Test it locks available balance after tx is submitted
180
+ await firstValueFromTimed(
181
+ aliceMultiSigWallet.transactions.outgoing.inFlight$.pipe(filter((inFlight) => inFlight.length === 1)),
182
+ 'No tx in flight'
183
+ );
184
+
185
+ const tx1PendingState = await getWalletStateSnapshot(aliceMultiSigWallet);
186
+
187
+ // Updates total and available balance right after tx is submitted
188
+ const coinsSpentOnDeposit = initialState.isStakeCredentialRegistered ? 0n : stakeKeyDeposit;
189
+ const newRewardsWhileSigningAndSubmitting = tx1PendingState.rewardsBalance;
190
+ const expectedCoinsAfterTx1 =
191
+ initialState.balance.total.coins -
192
+ tx1OutputCoins -
193
+ tx.body.fee -
194
+ coinsSpentOnDeposit +
195
+ BigIntMath.sum(tx.body.withdrawals?.map((wd) => wd.quantity) || []) +
196
+ newRewardsWhileSigningAndSubmitting;
197
+ expect(tx1PendingState.balance.total.coins).toEqual(expectedCoinsAfterTx1);
198
+ expect(tx1PendingState.balance.available.coins).toEqual(expectedCoinsAfterTx1);
199
+ expect(tx1PendingState.balance.deposit).toEqual(stakeKeyDeposit);
200
+
201
+ await waitForTx(aliceMultiSigWallet, tx.id);
202
+ const tx1ConfirmedState = await getWalletStateSnapshot(aliceMultiSigWallet);
203
+
204
+ // Updates total and available balance after tx is on-chain
205
+ expect(tx1ConfirmedState.balance.total.coins).toBe(expectedCoinsAfterTx1);
206
+ expect(tx1ConfirmedState.balance.total).toEqual(tx1ConfirmedState.balance.available);
207
+ expect(tx1PendingState.balance.deposit).toEqual(stakeKeyDeposit);
208
+
209
+ // If less than two epochs have elapsed, delegatee will still delegate to former pool during current epoch
210
+ // if more than two epochs has elapsed, delegatee will delegate to new pool.
211
+ if (tx1ConfirmedState.epoch - initialState.epoch < 2) {
212
+ expect(tx1ConfirmedState.rewardAccount.delegatee?.currentEpoch?.id).toEqual(
213
+ initialState?.rewardAccount.delegatee?.currentEpoch?.id
214
+ );
215
+ expect(tx1ConfirmedState.rewardAccount.delegatee?.nextEpoch?.id).toEqual(
216
+ initialState?.rewardAccount.delegatee?.nextEpoch?.id
217
+ );
218
+ expect(tx1ConfirmedState.rewardAccount.delegatee?.nextNextEpoch?.id).toEqual(poolId);
219
+ } else {
220
+ expect(tx1ConfirmedState.rewardAccount.delegatee?.currentEpoch?.id).toEqual(poolId);
221
+ }
222
+
223
+ expect(tx1ConfirmedState.rewardAccount.credentialStatus).toBe(Cardano.StakeCredentialStatus.Registered);
224
+
225
+ // Make a 2nd tx with key de-registration
226
+ tx = (await aliceMultiSigWallet.createTxBuilder().delegateFirstStakeCredential(null).build().sign()).tx;
227
+ tx = await bobMultiSigWallet.updateWitness({ sender: { id: 'e2e' }, tx });
228
+ tx = await charlotteMultiSigWallet.updateWitness({ sender: { id: 'e2e' }, tx });
229
+
230
+ await aliceMultiSigWallet.submitTx(tx);
231
+
232
+ await waitForTx(aliceMultiSigWallet, tx.id);
233
+ const tx2ConfirmedState = await getWalletStateSnapshot(aliceMultiSigWallet);
234
+
235
+ // No longer delegating
236
+ expect(tx2ConfirmedState.rewardAccount.delegatee?.nextNextEpoch?.id).toBeUndefined();
237
+ expect(tx2ConfirmedState.rewardAccount.credentialStatus).toBe(Cardano.StakeCredentialStatus.Unregistered);
238
+
239
+ // Deposit is returned to wallet balance
240
+ const expectedCoinsAfterTx2 = expectedCoinsAfterTx1 + stakeKeyDeposit - tx.body.fee;
241
+ expect(tx2ConfirmedState.balance.total.coins).toBe(expectedCoinsAfterTx2);
242
+ expect(tx2ConfirmedState.balance.total).toEqual(tx2ConfirmedState.balance.available);
243
+ expect(tx2ConfirmedState.balance.deposit).toBe(0n);
244
+ });
245
+ });
@@ -0,0 +1,123 @@
1
+ import { BaseWallet } from '@cardano-sdk/wallet';
2
+ import { Cardano } from '@cardano-sdk/core';
3
+ import { buildSharedWallets } from './ultils';
4
+ import { filter, firstValueFrom, map, take } from 'rxjs';
5
+ import {
6
+ getEnv,
7
+ getWallet,
8
+ normalizeTxBody,
9
+ waitForWalletStateSettle,
10
+ walletReady,
11
+ walletVariables
12
+ } from '../../../src';
13
+ import { isNotNil } from '@cardano-sdk/util';
14
+ import { logger } from '@cardano-sdk/util-dev';
15
+
16
+ const env = getEnv(walletVariables);
17
+
18
+ describe('SharedWallet/simpleTx', () => {
19
+ let fundingTx: Cardano.Tx<Cardano.TxBody>;
20
+ let faucetWallet: BaseWallet;
21
+ let faucetAddress: Cardano.PaymentAddress;
22
+ let aliceMultiSigWallet: BaseWallet;
23
+ let bobMultiSigWallet: BaseWallet;
24
+ let charlotteMultiSigWallet: BaseWallet;
25
+ const initialFunds = 10_000_000n;
26
+
27
+ beforeAll(async () => {
28
+ ({ wallet: faucetWallet } = await getWallet({ env, logger, name: 'Sending Wallet', polling: { interval: 50 } }));
29
+
30
+ // Make sure the wallet has sufficient funds to run this test
31
+ await walletReady(faucetWallet, initialFunds);
32
+
33
+ faucetAddress = (await firstValueFrom(faucetWallet.addresses$))[0].address;
34
+
35
+ ({ aliceMultiSigWallet, bobMultiSigWallet, charlotteMultiSigWallet } = await buildSharedWallets(
36
+ env,
37
+ await firstValueFrom(faucetWallet.genesisParameters$),
38
+ logger
39
+ ));
40
+
41
+ await Promise.all([
42
+ waitForWalletStateSettle(aliceMultiSigWallet),
43
+ waitForWalletStateSettle(bobMultiSigWallet),
44
+ waitForWalletStateSettle(charlotteMultiSigWallet)
45
+ ]);
46
+
47
+ const [{ address: receivingAddress }] = await firstValueFrom(aliceMultiSigWallet.addresses$);
48
+
49
+ logger.info(`Address ${faucetAddress} will send ${initialFunds} lovelace to address ${receivingAddress}.`);
50
+
51
+ // Send 10 tADA to the shared wallet.
52
+ const txBuilder = faucetWallet.createTxBuilder();
53
+ const txOutput = await txBuilder.buildOutput().address(receivingAddress).coin(initialFunds).build();
54
+ fundingTx = (await txBuilder.addOutput(txOutput).build().sign()).tx;
55
+ await faucetWallet.submitTx(fundingTx);
56
+
57
+ logger.info(
58
+ `Submitted transaction id: ${fundingTx.id}, inputs: ${JSON.stringify(
59
+ fundingTx.body.inputs.map((txIn) => [txIn.txId, txIn.index])
60
+ )} and outputs:${JSON.stringify(
61
+ fundingTx.body.outputs.map((txOut) => [txOut.address, Number.parseInt(txOut.value.coins.toString())])
62
+ )}.`
63
+ );
64
+ });
65
+
66
+ afterAll(() => {
67
+ aliceMultiSigWallet.shutdown();
68
+ bobMultiSigWallet.shutdown();
69
+ charlotteMultiSigWallet.shutdown();
70
+ faucetWallet.shutdown();
71
+ });
72
+
73
+ it('submit a transaction and find it in chain history', async () => {
74
+ const txFoundInHistory = await firstValueFrom(
75
+ aliceMultiSigWallet.transactions.history$.pipe(
76
+ map((txs) => txs.find((tx) => tx.id === fundingTx.id)),
77
+ filter(isNotNil),
78
+ take(1)
79
+ )
80
+ );
81
+
82
+ logger.info(`Found transaction id in chain history: ${txFoundInHistory.id}`);
83
+
84
+ expect(txFoundInHistory).toBeDefined();
85
+ expect(txFoundInHistory.id).toEqual(fundingTx.id);
86
+ expect(normalizeTxBody(txFoundInHistory.body)).toEqual(normalizeTxBody(fundingTx.body));
87
+
88
+ const aliceAddress = (await firstValueFrom(aliceMultiSigWallet.addresses$))[0].address;
89
+ const bobAddress = (await firstValueFrom(bobMultiSigWallet.addresses$))[0].address;
90
+ const charlotteAddress = (await firstValueFrom(charlotteMultiSigWallet.addresses$))[0].address;
91
+
92
+ expect(aliceAddress).toEqual(bobAddress);
93
+ expect(aliceAddress).toEqual(charlotteAddress);
94
+
95
+ // Lets send ada from the shared wallet to the faucet wallet
96
+
97
+ // Alice will initiate the transaction.
98
+ const txBuilder = aliceMultiSigWallet.createTxBuilder();
99
+ const txOut = await txBuilder.buildOutput().address(faucetAddress).coin(1_000_000n).build();
100
+ let tx = (await txBuilder.addOutput(txOut).build().sign()).tx;
101
+
102
+ // Bob updates the transaction with his witness
103
+ tx = await bobMultiSigWallet.updateWitness({ sender: { id: 'e2e' }, tx });
104
+
105
+ // Charlotte updates the transaction with her witness
106
+ tx = await charlotteMultiSigWallet.updateWitness({ sender: { id: 'e2e' }, tx });
107
+ const txId = await charlotteMultiSigWallet.submitTx(tx);
108
+
109
+ const finalTxFound = await firstValueFrom(
110
+ aliceMultiSigWallet.transactions.history$.pipe(
111
+ map((txs) => txs.find((hydratedTx) => hydratedTx.id === txId)),
112
+ filter(isNotNil),
113
+ take(1)
114
+ )
115
+ );
116
+
117
+ logger.info(`Found transaction id in chain history: ${finalTxFound.id}`);
118
+
119
+ expect(finalTxFound).toBeDefined();
120
+ expect(finalTxFound.id).toEqual(tx.id);
121
+ expect(normalizeTxBody(finalTxFound.body)).toEqual(normalizeTxBody(tx.body));
122
+ });
123
+ });