@cardano-sdk/e2e 0.14.2 → 0.16.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/.env.example +3 -0
- package/CHANGELOG.md +25 -0
- package/dist/cjs/factories.d.ts.map +1 -1
- package/dist/cjs/factories.js +5 -1
- package/dist/cjs/factories.js.map +1 -1
- package/dist/cjs/tsconfig.tsbuildinfo +1 -1
- package/dist/esm/factories.d.ts.map +1 -1
- package/dist/esm/factories.js +5 -1
- package/dist/esm/factories.js.map +1 -1
- package/dist/esm/tsconfig.tsbuildinfo +1 -1
- package/docker-compose.yml +20 -4
- package/local-network/scripts/cardano-node-ogmios.sh +13 -0
- package/local-network/scripts/mint-handles.sh +1 -0
- package/local-network/sdk-ipc/README.md +5 -0
- package/package.json +20 -19
- package/src/factories.ts +7 -1
- package/test/long-running/cache-invalidation.test.ts +1 -1
- package/test/long-running/delegation-rewards.test.ts +7 -9
- package/test/long-running/projector-ogmios-connection.test.ts +132 -0
- package/test/wallet/PersonalWallet/delegation.test.ts +2 -2
- package/test/wallet/PersonalWallet/delegationDistribution.test.ts +42 -78
- package/test/wallet/PersonalWallet/handle.test.ts +1 -1
- package/test/web-extension/extension/background/services.ts +17 -2
- package/test/web-extension/extension/ui.html +11 -0
- package/test/web-extension/extension/ui.ts +87 -0
- package/test/web-extension/extension/util.ts +4 -1
- package/test/web-extension/specs/wallet.spec.ts +51 -2
|
@@ -10,10 +10,16 @@ import {
|
|
|
10
10
|
import { adaPriceServiceChannel, getObservableWalletName, userPromptServiceChannel, walletName } from './const';
|
|
11
11
|
import { bip32Ed25519Factory, keyManagementFactory } from '../../../src';
|
|
12
12
|
|
|
13
|
+
import { Cardano } from '@cardano-sdk/core';
|
|
13
14
|
import { combineLatest, firstValueFrom, of } from 'rxjs';
|
|
14
15
|
import { runtime } from 'webextension-polyfill';
|
|
15
16
|
import { setupWallet } from '@cardano-sdk/wallet';
|
|
16
17
|
|
|
18
|
+
const delegationConfig = {
|
|
19
|
+
count: 3,
|
|
20
|
+
distribution: [10, 30, 60]
|
|
21
|
+
};
|
|
22
|
+
|
|
17
23
|
const api: UserPromptService = {
|
|
18
24
|
allowOrigin(origin) {
|
|
19
25
|
const container = document.querySelector<HTMLDivElement>('#requestAccess')!;
|
|
@@ -66,6 +72,30 @@ combineLatest([supplyDistribution.lovelaceSupply$, supplyDistribution.stake$]).s
|
|
|
66
72
|
(document.querySelector('#supplyDistribution')!.textContent = `${stake.live} out of ${lovelaceSupply.total}`)
|
|
67
73
|
);
|
|
68
74
|
|
|
75
|
+
/** Get pools from background service and assign weights */
|
|
76
|
+
const displayPoolIdsAndPreparePortfolio = async (): Promise<{ pool: Cardano.StakePool; weight: number }[]> => {
|
|
77
|
+
const pools = await backgroundServices.getPoolIds(delegationConfig.count);
|
|
78
|
+
const poolsSpan = document.querySelector('#multiDelegation .delegate .pools');
|
|
79
|
+
poolsSpan!.textContent = pools.map(({ id }) => id).join(' ');
|
|
80
|
+
return pools.map((pool, idx) => ({ pool, weight: delegationConfig.distribution[idx] }));
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
/** Build, sign and submit delegation transaction */
|
|
84
|
+
const sendDelegationTx = async (portfolio: { pool: Cardano.StakePool; weight: number }[]): Promise<void> => {
|
|
85
|
+
const pools = portfolio.map(({ pool: { hexId: id }, weight }) => ({ id, weight }));
|
|
86
|
+
const txBuilder = wallet.createTxBuilder();
|
|
87
|
+
|
|
88
|
+
let msg: string;
|
|
89
|
+
try {
|
|
90
|
+
const signedTx = await txBuilder.delegatePortfolio({ pools }).build().sign();
|
|
91
|
+
const txId = await wallet.submitTx(signedTx);
|
|
92
|
+
msg = `TxId: ${txId}`;
|
|
93
|
+
} catch (error) {
|
|
94
|
+
msg = `ERROR delegating: ${JSON.stringify(error)}`;
|
|
95
|
+
}
|
|
96
|
+
document.querySelector('#multiDelegation .delegateTxId')!.textContent = msg;
|
|
97
|
+
};
|
|
98
|
+
|
|
69
99
|
const setAddresses = ({ address, stakeAddress }: { address: string; stakeAddress: string }): void => {
|
|
70
100
|
document.querySelector('#address')!.textContent = address;
|
|
71
101
|
document.querySelector('#stakeAddress')!.textContent = stakeAddress;
|
|
@@ -100,6 +130,45 @@ const deactivateWallet = async (): Promise<void> => {
|
|
|
100
130
|
clearWalletValues();
|
|
101
131
|
};
|
|
102
132
|
|
|
133
|
+
/**
|
|
134
|
+
* Wallet does not have any active delegations.
|
|
135
|
+
* Show a `<p class="noDelegation">No delegation found</p>`
|
|
136
|
+
*/
|
|
137
|
+
const createEmptyDelegationEl = () => {
|
|
138
|
+
const emptyDistribution = document.createElement('p');
|
|
139
|
+
emptyDistribution.classList.add('noDelegation');
|
|
140
|
+
emptyDistribution.textContent = 'No delegation found';
|
|
141
|
+
return emptyDistribution;
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Create a list item for a delegation
|
|
146
|
+
* `<li> <span class="poolId">thePoolId</span> <span class="percent">50</span> </li>`
|
|
147
|
+
*/
|
|
148
|
+
const createDelegationLi = (poolId: string, percent: string) => {
|
|
149
|
+
const delegationLi = document.createElement('li');
|
|
150
|
+
const poolIdSpan = document.createElement('span');
|
|
151
|
+
poolIdSpan.classList.add('poolId');
|
|
152
|
+
poolIdSpan.textContent = poolId;
|
|
153
|
+
const delegationPercentageSpan = document.createElement('span');
|
|
154
|
+
delegationPercentageSpan.classList.add('percent');
|
|
155
|
+
delegationPercentageSpan.textContent = percent;
|
|
156
|
+
const separatorSpan = document.createElement('span');
|
|
157
|
+
separatorSpan.textContent = ' - ';
|
|
158
|
+
delegationLi.append(poolIdSpan);
|
|
159
|
+
delegationLi.append(separatorSpan);
|
|
160
|
+
delegationLi.append(delegationPercentageSpan);
|
|
161
|
+
return delegationLi;
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
/** Remove empty delegation message or multi-delegation list items to display new data */
|
|
165
|
+
const cleanupMultidelegationInfo = (multiDelegationDiv: Element) => {
|
|
166
|
+
multiDelegationDiv.querySelector('p.noDelegation')?.remove();
|
|
167
|
+
for (const delegationLi of multiDelegationDiv.querySelectorAll('ul > li')) {
|
|
168
|
+
delegationLi.remove();
|
|
169
|
+
}
|
|
170
|
+
};
|
|
171
|
+
|
|
103
172
|
const walletManager = new WalletManagerUi({ walletName }, { logger, runtime });
|
|
104
173
|
// Wallet object does not change when wallets are activated/deactivated.
|
|
105
174
|
// Instead, it's observable properties emit from the currently active wallet.
|
|
@@ -108,6 +177,19 @@ const wallet = walletManager.wallet;
|
|
|
108
177
|
// Wallet can be subscribed can be used even before it is actually created.
|
|
109
178
|
wallet.addresses$.subscribe(([{ address, rewardAccount }]) => setAddresses({ address, stakeAddress: rewardAccount }));
|
|
110
179
|
wallet.balance.utxo.available$.subscribe(({ coins }) => setBalance(coins.toString()));
|
|
180
|
+
wallet.delegation.distribution$.subscribe((delegationDistrib) => {
|
|
181
|
+
const multiDelegationDiv = document.querySelector('#multiDelegation .distribution');
|
|
182
|
+
cleanupMultidelegationInfo(multiDelegationDiv!);
|
|
183
|
+
|
|
184
|
+
if (delegationDistrib.size === 0) {
|
|
185
|
+
multiDelegationDiv?.appendChild(createEmptyDelegationEl());
|
|
186
|
+
} else {
|
|
187
|
+
const distributionUl = multiDelegationDiv?.querySelector('ul');
|
|
188
|
+
for (const [poolId, delegation] of delegationDistrib) {
|
|
189
|
+
distributionUl?.appendChild(createDelegationLi(poolId, (delegation.percentage * 100).toString()));
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
});
|
|
111
193
|
|
|
112
194
|
const createWallet = async (accountIndex: number) => {
|
|
113
195
|
clearWalletValues();
|
|
@@ -142,6 +224,11 @@ document.querySelector('#activateWallet1')!.addEventListener('click', async () =
|
|
|
142
224
|
document.querySelector('#activateWallet2')!.addEventListener('click', async () => await createWallet(1));
|
|
143
225
|
document.querySelector('#deactivateWallet')!.addEventListener('click', async () => await deactivateWallet());
|
|
144
226
|
document.querySelector('#destroyWallet')!.addEventListener('click', async () => await destroyWallet());
|
|
227
|
+
document.querySelector('#multiDelegation .delegate button')!.addEventListener('click', async () => {
|
|
228
|
+
const poolsAndWeights = await displayPoolIdsAndPreparePortfolio();
|
|
229
|
+
// multi-delegate with 10%, 30%, 60% distribution
|
|
230
|
+
await sendDelegationTx(poolsAndWeights);
|
|
231
|
+
});
|
|
145
232
|
|
|
146
233
|
document.querySelector('#buildAndSignTx')!.addEventListener('click', async () => {
|
|
147
234
|
const [{ address: ownAddress }] = await firstValueFrom(wallet.addresses$);
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { Cardano } from '@cardano-sdk/core';
|
|
1
2
|
import { Observable } from 'rxjs';
|
|
2
3
|
import { Origin } from '@cardano-sdk/dapp-connector';
|
|
3
4
|
import { RemoteApiProperties, RemoteApiPropertyType } from '@cardano-sdk/web-extension';
|
|
@@ -11,11 +12,13 @@ export interface UserPromptService {
|
|
|
11
12
|
export interface BackgroundServices {
|
|
12
13
|
adaUsd$: Observable<number>;
|
|
13
14
|
clearAllowList(): Promise<void>;
|
|
15
|
+
getPoolIds(count: number): Promise<Cardano.StakePool[]>;
|
|
14
16
|
}
|
|
15
17
|
|
|
16
18
|
export const adaPriceProperties: RemoteApiProperties<BackgroundServices> = {
|
|
17
19
|
adaUsd$: RemoteApiPropertyType.HotObservable,
|
|
18
|
-
clearAllowList: RemoteApiPropertyType.MethodReturningPromise
|
|
20
|
+
clearAllowList: RemoteApiPropertyType.MethodReturningPromise,
|
|
21
|
+
getPoolIds: RemoteApiPropertyType.MethodReturningPromise
|
|
19
22
|
};
|
|
20
23
|
|
|
21
24
|
export const logger = console;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/* eslint-disable max-statements */
|
|
1
2
|
import { getObservableWalletName } from '../extension/const';
|
|
2
3
|
|
|
3
4
|
const switchToWalletUi = async () => {
|
|
@@ -11,6 +12,8 @@ const switchToWalletUi = async () => {
|
|
|
11
12
|
});
|
|
12
13
|
};
|
|
13
14
|
|
|
15
|
+
const NUM_POOLS = 3;
|
|
16
|
+
|
|
14
17
|
describe('wallet', () => {
|
|
15
18
|
const pWalletFound = '#root > div > p:nth-child(4)';
|
|
16
19
|
const btnRefresh = '#root > div > button';
|
|
@@ -37,6 +40,11 @@ describe('wallet', () => {
|
|
|
37
40
|
const dappStakingAddress = '#root > div > p:nth-child(12)';
|
|
38
41
|
const dappUsedAddress = '#root > div > p:nth-child(13)';
|
|
39
42
|
|
|
43
|
+
const btnDelegate = '#multiDelegation .delegate button';
|
|
44
|
+
const spanPoolIds = '#multiDelegation .delegate .pools';
|
|
45
|
+
const liPools = '#multiDelegation .distribution li';
|
|
46
|
+
const liPercents = '#multiDelegation .distribution li .percent';
|
|
47
|
+
|
|
40
48
|
// The address is filled in by the tests, which are order dependent
|
|
41
49
|
let walletAddr1 = '';
|
|
42
50
|
let walletStakeAddr1 = '';
|
|
@@ -67,12 +75,12 @@ describe('wallet', () => {
|
|
|
67
75
|
await expect($(divAdaPrice)).toHaveText('2.99');
|
|
68
76
|
});
|
|
69
77
|
|
|
70
|
-
describe('
|
|
78
|
+
describe('web-extension grants access and creates key agent', () => {
|
|
71
79
|
before(async () => {
|
|
72
80
|
await $(btnGrantAccess).click();
|
|
73
81
|
await $(btnActivateWallet1).click();
|
|
74
82
|
});
|
|
75
|
-
it('
|
|
83
|
+
it('web-extension has access to remote ObservableWallet and SupplyDistribution', async () => {
|
|
76
84
|
await browser.waitUntil(async () => {
|
|
77
85
|
try {
|
|
78
86
|
BigInt(await $(spanBalance).getText());
|
|
@@ -88,6 +96,9 @@ describe('wallet', () => {
|
|
|
88
96
|
expect(walletStakeAddr1).toHaveTextContaining('stake');
|
|
89
97
|
await expect($(activeWalletName)).toHaveText(getObservableWalletName(0));
|
|
90
98
|
});
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
describe('dapp can use cip30 wallet api', () => {
|
|
91
102
|
it('dapp has access to cip30 WalletApi', async () => {
|
|
92
103
|
await browser.switchWindow('React App');
|
|
93
104
|
await expect($(pNetworkId)).toHaveText('Network Id (0 = testnet; 1 = mainnet): 0');
|
|
@@ -105,11 +116,49 @@ describe('wallet', () => {
|
|
|
105
116
|
await expect($(dappStakingAddress)).toHaveTextContaining(walletStakeAddr1);
|
|
106
117
|
await expect($(dappUsedAddress)).toHaveTextContaining(walletAddr1);
|
|
107
118
|
});
|
|
119
|
+
});
|
|
108
120
|
|
|
121
|
+
describe('web-extension can build transactions and use wallet manager', () => {
|
|
109
122
|
it('can build and sign a transaction', async () => {
|
|
110
123
|
await switchToWalletUi();
|
|
111
124
|
await buildAndSign();
|
|
112
125
|
});
|
|
126
|
+
|
|
127
|
+
it('can delegate to multiple pools', async () => {
|
|
128
|
+
(await $(btnDelegate)).click();
|
|
129
|
+
|
|
130
|
+
// There should be 3 pools available
|
|
131
|
+
await browser.waitUntil(async () => {
|
|
132
|
+
try {
|
|
133
|
+
const poolIds = await $(spanPoolIds).getText();
|
|
134
|
+
return poolIds.split(' ').length === NUM_POOLS;
|
|
135
|
+
} catch {
|
|
136
|
+
return false;
|
|
137
|
+
}
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
// Delegation transaction was submitted successfully
|
|
141
|
+
const txId = await $('#multiDelegation .delegateTxId').getText();
|
|
142
|
+
expect(txId).toHaveTextContaining('TxId');
|
|
143
|
+
|
|
144
|
+
// Wallet reports delegating to 3 pools
|
|
145
|
+
await browser.waitUntil(
|
|
146
|
+
async () => {
|
|
147
|
+
try {
|
|
148
|
+
const delegatedPools = await $$(liPools);
|
|
149
|
+
return delegatedPools.length === NUM_POOLS;
|
|
150
|
+
} catch {
|
|
151
|
+
return false;
|
|
152
|
+
}
|
|
153
|
+
},
|
|
154
|
+
{ timeout: 30_000, timeoutMsg: 'Expected wallet.delegation.distribution to report 3 delegations' }
|
|
155
|
+
);
|
|
156
|
+
|
|
157
|
+
// Check wallet delegation distribution is applied and displayed correctly
|
|
158
|
+
const delegationPercents = await $$(liPercents).map((el) => el.getText());
|
|
159
|
+
expect(delegationPercents.map((percent) => Math.round(Number.parseFloat(percent)))).toEqual([10, 30, 60]);
|
|
160
|
+
});
|
|
161
|
+
|
|
113
162
|
it('can switch to another wallet', async () => {
|
|
114
163
|
// Automatically deactivates first wallet, but keeps the store available for future activation
|
|
115
164
|
await $(btnActivateWallet2).click();
|