@cardano-sdk/e2e 0.12.1 → 0.13.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 +20 -0
- package/dist/cjs/tsconfig.tsbuildinfo +1 -1
- package/dist/esm/tsconfig.tsbuildinfo +1 -1
- package/docker-compose.yml +2 -2
- package/package.json +20 -33
- package/test/blockfrost/StakePoolCompare.test.ts +6 -12
- package/test/local-network/register-pool.test.ts +2 -2
- package/test/providers/StakePoolProvider.test.ts +2 -2
- package/test/wallet/PersonalWallet/delegationDistribution.test.ts +242 -0
- package/test/wallet/PersonalWallet/multiAddress.test.ts +12 -16
- package/test/web-extension/extension/manifest.json +1 -1
- package/test/web-extension/webpack.config.base.js +7 -1
package/docker-compose.yml
CHANGED
|
@@ -30,7 +30,7 @@ services:
|
|
|
30
30
|
ports:
|
|
31
31
|
- ${FILE_SERVER_PORT:-7890}:80
|
|
32
32
|
environment:
|
|
33
|
-
|
|
33
|
+
NGINX_PORT: 80
|
|
34
34
|
healthcheck:
|
|
35
35
|
test: ['CMD-SHELL', 'wget -O /dev/null http://localhost || exit 1']
|
|
36
36
|
timeout: 10s
|
|
@@ -71,7 +71,7 @@ services:
|
|
|
71
71
|
|
|
72
72
|
provider-server:
|
|
73
73
|
environment:
|
|
74
|
-
|
|
74
|
+
TOKEN_METADATA_SERVER_URL: stub://
|
|
75
75
|
volumes:
|
|
76
76
|
- ./local-network/config/network:/config
|
|
77
77
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cardano-sdk/e2e",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.13.0",
|
|
4
4
|
"description": "End to end tests for the cardano-js-sdk packages.",
|
|
5
5
|
"engines": {
|
|
6
6
|
"node": ">=16.0"
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
"test:web-extension:watch:run": "yarn test:web-extension:run --watch",
|
|
46
46
|
"test:web-extension:watch": "run-s test:web-extension:build test:web-extension:watch:bg",
|
|
47
47
|
"test:web-extension:watch:bg": "run-p test:web-extension:watch:build test:web-extension:watch:run",
|
|
48
|
-
"local-network:common": "docker compose -p local-network-e2e -f docker-compose.yml -f ../../compose/common.yml $FILES up",
|
|
48
|
+
"local-network:common": "USE_BLOCKFROST=false docker compose -p local-network-e2e -f docker-compose.yml -f ../../compose/common.yml $FILES up",
|
|
49
49
|
"local-network:up": "FILES='' yarn local-network:common",
|
|
50
50
|
"local-network:dev": "FILES='-f ../../compose/dev.yml' yarn local-network:common",
|
|
51
51
|
"local-network:profile:up": "FILES='-f ../../compose/pg-agent.yml' yarn local-network:common",
|
|
@@ -73,20 +73,6 @@
|
|
|
73
73
|
"wait-for-network": "ts-node src/scripts/is-local-network-ready.ts"
|
|
74
74
|
},
|
|
75
75
|
"repository": "https://github.com/input-output-hk/cardano-js-sdk",
|
|
76
|
-
"contributors": [
|
|
77
|
-
"Rhys Bartels-Waller <rhys.bartelswaller@iohk.io> (https://iohk.io)",
|
|
78
|
-
"Martynas Kazlauskas <martynas.kazlauskas@iohk.io> (https://iohk.io)",
|
|
79
|
-
"Daniele Ricci <daniele.ricci@iohk.io> (https://iohk.io)",
|
|
80
|
-
"Ivaylo Andonov <ivaylo.andonov@iohk.io> (https://iohk.io)",
|
|
81
|
-
"Mircea Hasegan <mircea.hasegan@iohk.io> (https://iohk.io)",
|
|
82
|
-
"Angel Castillo Bacigalupi <angel.castillo@iohk.io> (https://iohk.io)",
|
|
83
|
-
"Seung Eun Song <seungeun.song@iohk.io> (https://iohk.io)",
|
|
84
|
-
"Dmytro Iakymenko <dmytro.iakymenko@iohk.io> (https://iohk.io)",
|
|
85
|
-
"Tomislav Horaček <tomislav.horacek@iohk.io> (https://iohk.io)",
|
|
86
|
-
"Michael Chappell <michael.chappell@iohk.io> (https://iohk.io)",
|
|
87
|
-
"Leonel Gobbi <leonel.gobbi@globant.com> (https://www.globant.com)",
|
|
88
|
-
"Juan Cruz Vieiro <juan.vieiro@globant.com> (https://www.globant.com)"
|
|
89
|
-
],
|
|
90
76
|
"license": "Apache-2.0",
|
|
91
77
|
"publishConfig": {
|
|
92
78
|
"access": "public"
|
|
@@ -94,18 +80,18 @@
|
|
|
94
80
|
"dependencies": {
|
|
95
81
|
"@cardano-foundation/ledgerjs-hw-app-cardano": "^6.0.0",
|
|
96
82
|
"@cardano-ogmios/client": "5.6.0",
|
|
97
|
-
"@cardano-sdk/cardano-services": "~0.
|
|
98
|
-
"@cardano-sdk/cardano-services-client": "~0.9.
|
|
99
|
-
"@cardano-sdk/core": "~0.
|
|
100
|
-
"@cardano-sdk/crypto": "~0.1.
|
|
101
|
-
"@cardano-sdk/hardware-ledger": "~0.2.
|
|
102
|
-
"@cardano-sdk/key-management": "~0.7.
|
|
103
|
-
"@cardano-sdk/ogmios": "~0.
|
|
104
|
-
"@cardano-sdk/tx-construction": "~0.5.
|
|
105
|
-
"@cardano-sdk/util": "~0.
|
|
106
|
-
"@cardano-sdk/util-dev": "~0.
|
|
107
|
-
"@cardano-sdk/util-rxjs": "~0.4.
|
|
108
|
-
"@cardano-sdk/wallet": "~0.
|
|
83
|
+
"@cardano-sdk/cardano-services": "~0.12.0",
|
|
84
|
+
"@cardano-sdk/cardano-services-client": "~0.9.4",
|
|
85
|
+
"@cardano-sdk/core": "~0.13.0",
|
|
86
|
+
"@cardano-sdk/crypto": "~0.1.6",
|
|
87
|
+
"@cardano-sdk/hardware-ledger": "~0.2.3",
|
|
88
|
+
"@cardano-sdk/key-management": "~0.7.2",
|
|
89
|
+
"@cardano-sdk/ogmios": "~0.12.0",
|
|
90
|
+
"@cardano-sdk/tx-construction": "~0.5.3",
|
|
91
|
+
"@cardano-sdk/util": "~0.11.0",
|
|
92
|
+
"@cardano-sdk/util-dev": "~0.12.0",
|
|
93
|
+
"@cardano-sdk/util-rxjs": "~0.4.11",
|
|
94
|
+
"@cardano-sdk/wallet": "~0.14.0",
|
|
109
95
|
"@vespaiach/axios-fetch-adapter": "^0.3.0",
|
|
110
96
|
"axios": "^0.27.2",
|
|
111
97
|
"bunyan": "^1.8.15",
|
|
@@ -130,10 +116,10 @@
|
|
|
130
116
|
"@babel/core": "^7.18.2",
|
|
131
117
|
"@babel/preset-env": "^7.18.2",
|
|
132
118
|
"@babel/preset-typescript": "^7.17.12",
|
|
133
|
-
"@cardano-sdk/dapp-connector": "~0.9.
|
|
134
|
-
"@cardano-sdk/projection": "~0.6.
|
|
135
|
-
"@cardano-sdk/projection-typeorm": "~0.
|
|
136
|
-
"@cardano-sdk/web-extension": "~0.
|
|
119
|
+
"@cardano-sdk/dapp-connector": "~0.9.4",
|
|
120
|
+
"@cardano-sdk/projection": "~0.6.4",
|
|
121
|
+
"@cardano-sdk/projection-typeorm": "~0.3.0",
|
|
122
|
+
"@cardano-sdk/web-extension": "~0.12.0",
|
|
137
123
|
"@dcspark/cardano-multiplatform-lib-browser": "^3.1.1",
|
|
138
124
|
"@emurgo/cardano-message-signing-asmjs": "^1.0.1",
|
|
139
125
|
"@types/bunyan": "^1.8.8",
|
|
@@ -165,6 +151,7 @@
|
|
|
165
151
|
"null-loader": "^4.0.1",
|
|
166
152
|
"readable-stream": "^3.6.0",
|
|
167
153
|
"shx": "^0.3.3",
|
|
154
|
+
"source-map-loader": "^4.0.1",
|
|
168
155
|
"ts-jest": "^28.0.7",
|
|
169
156
|
"typeorm": "^0.3.15",
|
|
170
157
|
"typeorm-extension": "^2.7.0",
|
|
@@ -177,5 +164,5 @@
|
|
|
177
164
|
"webpack-cli": "^4.9.2",
|
|
178
165
|
"webpack-merge": "^5.8.0"
|
|
179
166
|
},
|
|
180
|
-
"gitHead": "
|
|
167
|
+
"gitHead": "c7c3523ee84b5ec53d781b0e05511c2312fd6397"
|
|
181
168
|
}
|
|
@@ -100,7 +100,7 @@ describe('StakePoolCompare', () => {
|
|
|
100
100
|
|
|
101
101
|
// Fetch all stake pools with all reward history and organize in a StakePoolRecord
|
|
102
102
|
const fetchAll = async (provider: StakePoolProvider) =>
|
|
103
|
-
Object.fromEntries((await fetchAllPools(provider, {
|
|
103
|
+
Object.fromEntries((await fetchAllPools(provider, { apyEpochsBackLimit: 1_000_000 })).map((_) => [_.id, _]));
|
|
104
104
|
|
|
105
105
|
const startServer = async (args: string[]) => {
|
|
106
106
|
const port = await getRandomPort();
|
|
@@ -170,8 +170,8 @@ describe('StakePoolCompare', () => {
|
|
|
170
170
|
let metricTwo: Cardano.StakePoolMetrics;
|
|
171
171
|
|
|
172
172
|
beforeAll(() => {
|
|
173
|
-
metricOne = poolOne.metrics
|
|
174
|
-
metricTwo = poolTwo.metrics
|
|
173
|
+
metricOne = poolOne.metrics!;
|
|
174
|
+
metricTwo = poolTwo.metrics!;
|
|
175
175
|
});
|
|
176
176
|
|
|
177
177
|
// check apy
|
|
@@ -212,12 +212,6 @@ describe('StakePoolCompare', () => {
|
|
|
212
212
|
|
|
213
213
|
it('rewardAccount', () => expect(poolOne.rewardAccount).toBe(poolTwo.rewardAccount));
|
|
214
214
|
|
|
215
|
-
describe('transactions', () => {
|
|
216
|
-
it('registration', () => expect(poolOne.transactions.registration).toEqual(poolTwo.transactions.registration));
|
|
217
|
-
|
|
218
|
-
it('retirement', () => expect(poolOne.transactions.retirement).toEqual(poolTwo.transactions.retirement));
|
|
219
|
-
});
|
|
220
|
-
|
|
221
215
|
// a known problem on db-sync implementation makes this test to fail on the given preprod pools
|
|
222
216
|
if (!poolsExcludeStatus.has(id)) it('status', () => expect(poolOne.status).toBe(poolTwo.status));
|
|
223
217
|
else it('status', () => expect(poolOne.status).not.toBe(poolTwo.status));
|
|
@@ -230,14 +224,14 @@ describe('StakePoolCompare', () => {
|
|
|
230
224
|
const result = await fetchAllPools(providerOne, { sort: { field: 'saturation', order: 'asc' } });
|
|
231
225
|
|
|
232
226
|
for (let i = 1; i < result.length; ++i)
|
|
233
|
-
expect(result[i - 1].metrics
|
|
227
|
+
expect(result[i - 1].metrics?.saturation).toBeLessThanOrEqual(result[i].metrics!.saturation);
|
|
234
228
|
});
|
|
235
229
|
|
|
236
230
|
it('by saturation desc', async () => {
|
|
237
231
|
const result = await fetchAllPools(providerOne, { sort: { field: 'saturation', order: 'desc' } });
|
|
238
232
|
|
|
239
233
|
for (let i = 1; i < result.length; ++i)
|
|
240
|
-
expect(result[i - 1].metrics
|
|
234
|
+
expect(result[i - 1].metrics?.saturation).toBeGreaterThanOrEqual(result[i].metrics!.saturation);
|
|
241
235
|
});
|
|
242
236
|
});
|
|
243
237
|
|
|
@@ -261,7 +255,7 @@ describe('StakePoolCompare', () => {
|
|
|
261
255
|
|
|
262
256
|
statusCount[pool.status]++;
|
|
263
257
|
|
|
264
|
-
if (pool.metrics
|
|
258
|
+
if (pool.metrics!.livePledge >= pool.pledge) poolsMeetingPledge++;
|
|
265
259
|
else {
|
|
266
260
|
poolsNotMeetingPledge++;
|
|
267
261
|
|
|
@@ -144,7 +144,7 @@ describe('local-network/register-pool', () => {
|
|
|
144
144
|
expect(result.pageResults[0].hexId).toBe(Cardano.PoolIdHex(poolKeyHash));
|
|
145
145
|
expect(result.pageResults[0].id).toBe(poolId);
|
|
146
146
|
expect(result.pageResults[0].status).toBe(Cardano.StakePoolStatus.Activating);
|
|
147
|
-
expect(result.pageResults[0].metrics
|
|
147
|
+
expect(result.pageResults[0].metrics?.livePledge).toBeLessThan(result.pageResults[0].pledge);
|
|
148
148
|
});
|
|
149
149
|
|
|
150
150
|
test('meets pledge', async () => {
|
|
@@ -229,6 +229,6 @@ describe('local-network/register-pool', () => {
|
|
|
229
229
|
expect(result.pageResults[0].hexId).toBe(Cardano.PoolIdHex(poolKeyHash));
|
|
230
230
|
expect(result.pageResults[0].id).toBe(poolId);
|
|
231
231
|
expect(result.pageResults[0].status).toBe(Cardano.StakePoolStatus.Activating);
|
|
232
|
-
expect(result.pageResults[0].metrics
|
|
232
|
+
expect(result.pageResults[0].metrics?.livePledge).toBeGreaterThan(result.pageResults[0].pledge);
|
|
233
233
|
});
|
|
234
234
|
});
|
|
@@ -260,13 +260,13 @@ describe('StakePoolProvider', () => {
|
|
|
260
260
|
it('with pledgeMet false', async () => {
|
|
261
261
|
const { pageResults } = await query({ pledgeMet: false });
|
|
262
262
|
|
|
263
|
-
for (const pool of pageResults) expect(pool.pledge > pool.metrics
|
|
263
|
+
for (const pool of pageResults) expect(pool.pledge > pool.metrics!.livePledge).toBeTruthy();
|
|
264
264
|
});
|
|
265
265
|
|
|
266
266
|
it('with pledgeMet true', async () => {
|
|
267
267
|
const { pageResults } = await query({ pledgeMet: true });
|
|
268
268
|
|
|
269
|
-
for (const pool of pageResults) expect(pool.pledge <= pool.metrics
|
|
269
|
+
for (const pool of pageResults) expect(pool.pledge <= pool.metrics!.livePledge).toBeTruthy();
|
|
270
270
|
});
|
|
271
271
|
|
|
272
272
|
it('pools number = meeting pools number + not meeting pools number', async () => {
|
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
import { Cardano } from '@cardano-sdk/core';
|
|
2
|
+
import { DelegatedStake, PersonalWallet, createUtxoBalanceByAddressTracker } from '@cardano-sdk/wallet';
|
|
3
|
+
import { MINUTE, getWallet } from '../../../src';
|
|
4
|
+
import { Observable, filter, firstValueFrom, map, tap } from 'rxjs';
|
|
5
|
+
import { Percent } from '@cardano-sdk/util';
|
|
6
|
+
import { createLogger } from '@cardano-sdk/util-dev';
|
|
7
|
+
import { firstValueFromTimed, submitAndConfirm, walletReady } from '../../util';
|
|
8
|
+
import { getEnv, walletVariables } from '../../../src/environment';
|
|
9
|
+
|
|
10
|
+
const env = getEnv(walletVariables);
|
|
11
|
+
const logger = createLogger();
|
|
12
|
+
const TEST_FUNDS = 1_000_000_000n;
|
|
13
|
+
|
|
14
|
+
/** Distribute the wallet funds evenly across all its addresses */
|
|
15
|
+
const distributeFunds = async (wallet: PersonalWallet) => {
|
|
16
|
+
await walletReady(wallet, 0n);
|
|
17
|
+
const addresses = await firstValueFrom(wallet.addresses$);
|
|
18
|
+
expect(addresses.length).toBeGreaterThan(1);
|
|
19
|
+
|
|
20
|
+
// Check that we have enough funds. Otherwise, fund it from wallet account at index 0
|
|
21
|
+
let { coins: totalCoins } = await firstValueFrom(wallet.balance.utxo.available$);
|
|
22
|
+
|
|
23
|
+
const coinDeficit = TEST_FUNDS - totalCoins;
|
|
24
|
+
if (coinDeficit > 10_000_000n) {
|
|
25
|
+
logger.debug(
|
|
26
|
+
`Insufficient funds in wallet account index 1. Missing ${coinDeficit}. Transferring from wallet account index 0`
|
|
27
|
+
);
|
|
28
|
+
const fundingWallet = (await getWallet({ env, idx: 0, logger, name: 'WalletAcct0', polling: { interval: 50 } }))
|
|
29
|
+
.wallet;
|
|
30
|
+
await walletReady(fundingWallet);
|
|
31
|
+
const fundingTxBuilder = fundingWallet.createTxBuilder();
|
|
32
|
+
const { tx } = await fundingTxBuilder
|
|
33
|
+
.addOutput(fundingTxBuilder.buildOutput().address(addresses[0].address).coin(coinDeficit).toTxOut())
|
|
34
|
+
.build()
|
|
35
|
+
.sign();
|
|
36
|
+
await submitAndConfirm(fundingWallet, tx);
|
|
37
|
+
await walletReady(wallet);
|
|
38
|
+
totalCoins = (await firstValueFrom(wallet.balance.utxo.available$)).coins;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const coinsPerAddress = totalCoins / BigInt(addresses.length);
|
|
42
|
+
|
|
43
|
+
const txBuilder = wallet.createTxBuilder();
|
|
44
|
+
|
|
45
|
+
logger.debug(`Sending ${coinsPerAddress} to the ${addresses.length - 1} derived addresses`);
|
|
46
|
+
// The first one was generated when the wallet was created.
|
|
47
|
+
for (let i = 1; i < addresses.length; ++i) {
|
|
48
|
+
const derivedAddress = addresses[i];
|
|
49
|
+
txBuilder.addOutput(txBuilder.buildOutput().address(derivedAddress.address).coin(coinsPerAddress).toTxOut());
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const { tx: signedTx } = await txBuilder.build().sign();
|
|
53
|
+
await submitAndConfirm(wallet, signedTx);
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
/** await for rewardAccounts$ to be registered, unregistered, as defined in states */
|
|
57
|
+
const rewardAccountStatuses = async (
|
|
58
|
+
rewardAccounts$: Observable<Cardano.RewardAccountInfo[]>,
|
|
59
|
+
statuses: Cardano.StakeKeyStatus[]
|
|
60
|
+
) =>
|
|
61
|
+
firstValueFromTimed(
|
|
62
|
+
rewardAccounts$.pipe(
|
|
63
|
+
tap((accts) => accts.map(({ address, keyStatus }) => logger.debug(address, keyStatus))),
|
|
64
|
+
map((accts) => accts.map(({ keyStatus }) => keyStatus)),
|
|
65
|
+
filter((statusArr) => statusArr.every((s) => statuses.includes(s)))
|
|
66
|
+
),
|
|
67
|
+
`Timeout waiting for all reward accounts stake keys to be one of ${statuses.join('|')}`,
|
|
68
|
+
MINUTE
|
|
69
|
+
);
|
|
70
|
+
|
|
71
|
+
/** Create stakeKey deregistration transaction for all reward accounts */
|
|
72
|
+
const deregisterAllStakeKeys = async (wallet: PersonalWallet): Promise<void> => {
|
|
73
|
+
const txBuilder = wallet.createTxBuilder();
|
|
74
|
+
txBuilder.delegate();
|
|
75
|
+
const { tx: deregTx } = await txBuilder.build().sign();
|
|
76
|
+
await submitAndConfirm(wallet, deregTx);
|
|
77
|
+
|
|
78
|
+
await rewardAccountStatuses(wallet.delegation.rewardAccounts$, [
|
|
79
|
+
Cardano.StakeKeyStatus.Unregistered,
|
|
80
|
+
Cardano.StakeKeyStatus.Unregistering
|
|
81
|
+
]);
|
|
82
|
+
logger.debug('Deregistered all stake keys');
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
const createStakeKeyRegistrationCert = (rewardAccount: Cardano.RewardAccount): Cardano.Certificate => ({
|
|
86
|
+
__typename: Cardano.CertificateType.StakeKeyRegistration,
|
|
87
|
+
stakeKeyHash: Cardano.RewardAccount.toHash(rewardAccount)
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
const createDelegationCert = (rewardAccount: Cardano.RewardAccount, poolId: Cardano.PoolId): Cardano.Certificate => ({
|
|
91
|
+
__typename: Cardano.CertificateType.StakeDelegation,
|
|
92
|
+
poolId,
|
|
93
|
+
stakeKeyHash: Cardano.RewardAccount.toHash(rewardAccount)
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
const getPoolIds = async (wallet: PersonalWallet, count: number): Promise<Cardano.StakePool[]> => {
|
|
97
|
+
const activePools = await wallet.stakePoolProvider.queryStakePools({
|
|
98
|
+
filters: { status: [Cardano.StakePoolStatus.Active] },
|
|
99
|
+
pagination: { limit: count, startAt: 0 }
|
|
100
|
+
});
|
|
101
|
+
expect(activePools.pageResults.length).toBeGreaterThanOrEqual(count);
|
|
102
|
+
return Array.from({ length: count }).map((_, index) => activePools.pageResults[index]);
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
const delegateToMultiplePools = async (wallet: PersonalWallet) => {
|
|
106
|
+
// Delegating to multiple pools should be added in TxBuilder. Doing it manually for now.
|
|
107
|
+
// Prepare stakeKey registration certificates
|
|
108
|
+
const rewardAccounts = await firstValueFrom(wallet.delegation.rewardAccounts$);
|
|
109
|
+
const stakeKeyRegCertificates = rewardAccounts.map(({ address }) => createStakeKeyRegistrationCert(address));
|
|
110
|
+
|
|
111
|
+
const poolIds = await getPoolIds(wallet, rewardAccounts.length);
|
|
112
|
+
const delegationCertificates = rewardAccounts.map(({ address }, index) =>
|
|
113
|
+
createDelegationCert(address, poolIds[index].id)
|
|
114
|
+
);
|
|
115
|
+
|
|
116
|
+
logger.debug(
|
|
117
|
+
`Delegating to pools ${poolIds.map(({ id }) => id)} and registering ${stakeKeyRegCertificates.length} stake keys`
|
|
118
|
+
);
|
|
119
|
+
|
|
120
|
+
const txBuilder = wallet.createTxBuilder();
|
|
121
|
+
// Artificially add the certificates in TxBuilder. An api improvement will make the UX better
|
|
122
|
+
txBuilder.partialTxBody.certificates = [...stakeKeyRegCertificates, ...delegationCertificates];
|
|
123
|
+
const { tx } = await txBuilder.build().sign();
|
|
124
|
+
await submitAndConfirm(wallet, tx);
|
|
125
|
+
return poolIds;
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
describe('PersonalWallet/delegationDistribution', () => {
|
|
129
|
+
let wallet: PersonalWallet;
|
|
130
|
+
|
|
131
|
+
beforeAll(async () => {
|
|
132
|
+
wallet = (await getWallet({ env, idx: 1, logger, name: 'Wallet', polling: { interval: 50 } })).wallet;
|
|
133
|
+
await distributeFunds(wallet);
|
|
134
|
+
await deregisterAllStakeKeys(wallet);
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
afterAll(() => {
|
|
138
|
+
wallet.shutdown();
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
it('reports observable wallet multi delegation as delegationDistribution by pool', async () => {
|
|
142
|
+
await walletReady(wallet);
|
|
143
|
+
const walletAddresses = await firstValueFromTimed(wallet.addresses$);
|
|
144
|
+
const rewardAccounts = await firstValueFrom(wallet.delegation.rewardAccounts$);
|
|
145
|
+
|
|
146
|
+
// No stake distribution initially
|
|
147
|
+
const delegationDistribution = await firstValueFrom(wallet.delegation.distribution$);
|
|
148
|
+
expect(delegationDistribution).toEqual(new Map());
|
|
149
|
+
|
|
150
|
+
const poolIds = await delegateToMultiplePools(wallet);
|
|
151
|
+
|
|
152
|
+
// Check that reward addresses were delegated
|
|
153
|
+
await walletReady(wallet);
|
|
154
|
+
await rewardAccountStatuses(wallet.delegation.rewardAccounts$, [
|
|
155
|
+
Cardano.StakeKeyStatus.Registering,
|
|
156
|
+
Cardano.StakeKeyStatus.Registered
|
|
157
|
+
]);
|
|
158
|
+
logger.debug('Delegations successfully done');
|
|
159
|
+
|
|
160
|
+
const totalBalance = await firstValueFrom(wallet.balance.utxo.total$);
|
|
161
|
+
const perAddrBalance = await Promise.all(
|
|
162
|
+
rewardAccounts.map((_, index) => {
|
|
163
|
+
const address = walletAddresses[index].address;
|
|
164
|
+
return firstValueFrom(
|
|
165
|
+
createUtxoBalanceByAddressTracker(wallet.utxo, [address]).utxo.total$.pipe(map(({ coins }) => coins))
|
|
166
|
+
);
|
|
167
|
+
})
|
|
168
|
+
);
|
|
169
|
+
|
|
170
|
+
// Check delegation.delegationDistribution$ has the delegation information
|
|
171
|
+
const expectedDelegationDistribution: DelegatedStake[] = rewardAccounts.map(({ address }, index) => ({
|
|
172
|
+
percentage: Percent(Number(perAddrBalance[index]) / Number(totalBalance.coins)),
|
|
173
|
+
pool: expect.objectContaining({ id: poolIds[index].id }),
|
|
174
|
+
rewardAccounts: [address],
|
|
175
|
+
stake: perAddrBalance[index]
|
|
176
|
+
}));
|
|
177
|
+
const actualDelegationDistribution = await firstValueFrom(wallet.delegation.distribution$);
|
|
178
|
+
|
|
179
|
+
expect([...actualDelegationDistribution.values()]).toEqual(expectedDelegationDistribution);
|
|
180
|
+
|
|
181
|
+
// Send all coins to the last address. Check that stake distribution is 100 for that address and 0 for the rest
|
|
182
|
+
const { coins: totalCoins } = await firstValueFrom(wallet.balance.utxo.total$);
|
|
183
|
+
let txBuilder = wallet.createTxBuilder();
|
|
184
|
+
const { tx: txMoveFunds } = await txBuilder
|
|
185
|
+
.addOutput(
|
|
186
|
+
txBuilder
|
|
187
|
+
.buildOutput()
|
|
188
|
+
.address(walletAddresses[walletAddresses.length - 1].address)
|
|
189
|
+
.coin(totalCoins - 2_000_000n) // leave some behind for fees
|
|
190
|
+
.toTxOut()
|
|
191
|
+
)
|
|
192
|
+
.build()
|
|
193
|
+
.sign();
|
|
194
|
+
await submitAndConfirm(wallet, txMoveFunds);
|
|
195
|
+
|
|
196
|
+
let simplifiedDelegationDistribution: Partial<DelegatedStake>[] = await firstValueFrom(
|
|
197
|
+
wallet.delegation.distribution$.pipe(
|
|
198
|
+
map((delegatedStake) =>
|
|
199
|
+
[...delegatedStake.values()].map(({ pool, percentage }) => ({
|
|
200
|
+
id: pool.id,
|
|
201
|
+
name: pool.metadata?.name,
|
|
202
|
+
percentage
|
|
203
|
+
}))
|
|
204
|
+
)
|
|
205
|
+
)
|
|
206
|
+
);
|
|
207
|
+
expect(simplifiedDelegationDistribution).toEqual(
|
|
208
|
+
rewardAccounts.map((_, index) => ({
|
|
209
|
+
id: poolIds[index].id,
|
|
210
|
+
name: poolIds[index].metadata?.name,
|
|
211
|
+
// Expect approx 100% allocation to the last address
|
|
212
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
213
|
+
percentage: (expect as any).closeTo(index === walletAddresses.length - 1 ? 1 : 0)
|
|
214
|
+
}))
|
|
215
|
+
);
|
|
216
|
+
|
|
217
|
+
// Delegate all reward accounts to the same pool. delegationDistribution$ should have 1 entry with 100% distribution
|
|
218
|
+
txBuilder = wallet.createTxBuilder();
|
|
219
|
+
const { tx: txDelegateTo1Pool } = await txBuilder.delegate(poolIds[0].id).build().sign();
|
|
220
|
+
await submitAndConfirm(wallet, txDelegateTo1Pool);
|
|
221
|
+
simplifiedDelegationDistribution = await firstValueFrom(
|
|
222
|
+
wallet.delegation.distribution$.pipe(
|
|
223
|
+
map((distribution) =>
|
|
224
|
+
[...distribution.values()].map((delegatedStake) => ({
|
|
225
|
+
id: delegatedStake.pool.id,
|
|
226
|
+
name: delegatedStake.pool.metadata?.name,
|
|
227
|
+
percentage: delegatedStake.percentage,
|
|
228
|
+
rewardAccounts: delegatedStake.rewardAccounts
|
|
229
|
+
}))
|
|
230
|
+
)
|
|
231
|
+
)
|
|
232
|
+
);
|
|
233
|
+
expect(simplifiedDelegationDistribution).toEqual([
|
|
234
|
+
{
|
|
235
|
+
id: poolIds[0].id,
|
|
236
|
+
name: poolIds[0].metadata?.name,
|
|
237
|
+
percentage: Percent(1),
|
|
238
|
+
rewardAccounts: rewardAccounts.map(({ address }) => address)
|
|
239
|
+
}
|
|
240
|
+
]);
|
|
241
|
+
});
|
|
242
|
+
});
|
|
@@ -65,17 +65,13 @@ describe('PersonalWallet/multiAddress', () => {
|
|
|
65
65
|
);
|
|
66
66
|
|
|
67
67
|
addressesToBeDiscovered.push(address);
|
|
68
|
-
|
|
69
|
-
const txOutput = await txBuilder.buildOutput().address(address.address).coin(3_000_000n).build();
|
|
70
|
-
txBuilder.addOutput(txOutput);
|
|
68
|
+
txBuilder.addOutput(txBuilder.buildOutput().address(address.address).coin(3_000_000n).toTxOut());
|
|
71
69
|
}
|
|
72
70
|
|
|
73
71
|
// Remove duplicates
|
|
74
72
|
addressesToBeDiscovered = [...new Set(addressesToBeDiscovered)];
|
|
75
73
|
|
|
76
|
-
const
|
|
77
|
-
|
|
78
|
-
const { tx: signedTx } = await unsignedTx.sign();
|
|
74
|
+
const { tx: signedTx } = await txBuilder.build().sign();
|
|
79
75
|
|
|
80
76
|
await wallet.submitTx(signedTx);
|
|
81
77
|
|
|
@@ -125,17 +121,17 @@ describe('PersonalWallet/multiAddress', () => {
|
|
|
125
121
|
txBuilder = newWallet.wallet.createTxBuilder();
|
|
126
122
|
|
|
127
123
|
const fundingWalletAddresses = await firstValueFromTimed(wallet.addresses$);
|
|
128
|
-
const returnAdaOutput = await txBuilder
|
|
129
|
-
.buildOutput()
|
|
130
|
-
.address(fundingWalletAddresses[0].address)
|
|
131
|
-
.coin(totalBalance.coins - 1_500_000n) // Let's leave some behind for fees.
|
|
132
|
-
.build();
|
|
133
|
-
|
|
134
|
-
txBuilder.addOutput(returnAdaOutput);
|
|
135
124
|
|
|
136
|
-
const
|
|
137
|
-
|
|
138
|
-
|
|
125
|
+
const { tx: returnAdaSignedTx } = await txBuilder
|
|
126
|
+
.addOutput(
|
|
127
|
+
txBuilder
|
|
128
|
+
.buildOutput()
|
|
129
|
+
.address(fundingWalletAddresses[0].address)
|
|
130
|
+
.coin(totalBalance.coins - 1_500_000n) // Let's leave some behind for fees.
|
|
131
|
+
.toTxOut()
|
|
132
|
+
)
|
|
133
|
+
.build()
|
|
134
|
+
.sign();
|
|
139
135
|
await newWallet.wallet.submitTx(returnAdaSignedTx);
|
|
140
136
|
|
|
141
137
|
// Search chain history to see if the transaction is there.
|
|
@@ -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://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: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,7 +9,8 @@ require('dotenv').config({ path: path.join(__dirname, '../../', '.env') });
|
|
|
9
9
|
|
|
10
10
|
module.exports = {
|
|
11
11
|
baseConfig: {
|
|
12
|
-
devtool: '
|
|
12
|
+
devtool: 'source-map',
|
|
13
|
+
ignoreWarnings: [/Failed to parse source map/],
|
|
13
14
|
mode: 'development',
|
|
14
15
|
module: {
|
|
15
16
|
// configuration regarding modules
|
|
@@ -18,6 +19,11 @@ module.exports = {
|
|
|
18
19
|
test: /docker\.js$/,
|
|
19
20
|
use: 'null-loader'
|
|
20
21
|
},
|
|
22
|
+
{
|
|
23
|
+
enforce: 'pre',
|
|
24
|
+
test: /\.js$/,
|
|
25
|
+
use: ['source-map-loader']
|
|
26
|
+
},
|
|
21
27
|
{
|
|
22
28
|
exclude: /node_modules/,
|
|
23
29
|
resolve: {
|