Skip to content

Commit 26715d1

Browse files
SeddikBellamineabbesBenayachePierreJeanjacquot
authored
feat: add multi-chain configuration and experimental networks support (#46)
* chore(deps): upgrade iexec dependency to v8.16.1 * feat: add allowExperimentalNetworks option to Web3TelegramConfigOptions * feat: refactor chain configuration to support multi-chain and experimental networks * feat: update getWeb3Provider to support experimental networks and custom hosts * feat: integrate experimental networks support in IExecWeb3telegram class * test: update test environment configuration * test: add comprehensive tests for experimental networks support * test: update e2e tests to use new chain configuration * test: update unit tests to use new chain configuration * fix: remove unused imports to resolve linting errors * fix: update dataProtectorSubgraph URL for arbitrum-sepolia-testnet * refactor(tests): rename variables * fix: improve .gitignore to ignore .env files in all directories --------- Co-authored-by: paypes <[email protected]> Co-authored-by: pjt <[email protected]>
1 parent 7eb21e3 commit 26715d1

File tree

14 files changed

+247
-108
lines changed

14 files changed

+247
-108
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
/.env
1414
/*.log
1515
/*.env
16+
**/.env
1617

1718
# TypeScript specific
1819
*.tsbuildinfo

package-lock.json

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@
5252
"buffer": "^6.0.3",
5353
"ethers": "^6.8.1",
5454
"graphql-request": "^6.1.0",
55-
"iexec": "^8.13.1",
55+
"iexec": "^8.16.1",
5656
"kubo-rpc-client": "^4.1.3",
5757
"yup": "^1.1.1"
5858
},

src/config/config.ts

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,7 @@ export const MAX_DESIRED_APP_ORDER_PRICE = 0;
33
export const MAX_DESIRED_WORKERPOOL_ORDER_PRICE = 0;
44
export const ANY_DATASET_ADDRESS = 'any';
55

6-
export const CHAIN_IDS = {
7-
BELLECOUR: 134,
8-
AVALANCHE_FUJI: 43113,
9-
ARBITRUM_SEPOLIA: 421614,
10-
} as const;
11-
12-
export const DEFAULT_CHAIN_ID = CHAIN_IDS.BELLECOUR;
6+
export const DEFAULT_CHAIN_ID = 134;
137

148
interface ChainConfig {
159
name: string;
@@ -19,10 +13,11 @@ interface ChainConfig {
1913
ipfsUploadUrl: string;
2014
ipfsGateway: string;
2115
whitelistSmartContract: string;
16+
isExperimental?: boolean;
2217
}
2318

2419
export const CHAIN_CONFIG: Record<number, ChainConfig> = {
25-
[CHAIN_IDS.BELLECOUR]: {
20+
134: {
2621
name: 'bellecour',
2722
dappAddress: 'web3telegram.apps.iexec.eth',
2823
prodWorkerpoolAddress: 'prod-v8-bellecour.main.pools.iexec.eth',
@@ -32,12 +27,29 @@ export const CHAIN_CONFIG: Record<number, ChainConfig> = {
3227
ipfsGateway: 'https://ipfs-gateway.v8-bellecour.iex.ec',
3328
whitelistSmartContract: '0x192C6f5AccE52c81Fcc2670f10611a3665AAA98F',
3429
},
30+
421614: {
31+
name: 'arbitrum-sepolia-testnet',
32+
dappAddress: 'web3telegram.apps.iexec.eth',
33+
prodWorkerpoolAddress: '0x39c3cdd91a7f1c4ed59108a9da4e79de9a1c1b59',
34+
dataProtectorSubgraph:
35+
'https://thegraph.arbitrum-sepolia-testnet.iex.ec/api/subgraphs/id/5YjRPLtjS6GH6bB4yY55Qg4HzwtRGQ8TaHtGf9UBWWd',
36+
ipfsGateway: 'https://ipfs-gateway.arbitrum-sepolia-testnet.iex.ec',
37+
ipfsUploadUrl: 'https://ipfs-upload.arbitrum-sepolia-testnet.iex.ec',
38+
whitelistSmartContract: '0x7291ff96100DA6CF97933C225B86124ef95aEc9b', // TODO: add the correct address
39+
isExperimental: true,
40+
},
3541
};
3642

37-
export function getChainConfig(chainId: number): ChainConfig {
43+
export const getChainDefaultConfig = (
44+
chainId: number,
45+
options?: { allowExperimentalNetworks?: boolean }
46+
): ChainConfig | null => {
3847
const config = CHAIN_CONFIG[chainId];
3948
if (!config) {
40-
throw new Error(`Unsupported chain ID: ${chainId}`);
49+
return null;
50+
}
51+
if (config.isExperimental && !options?.allowExperimentalNetworks) {
52+
return null;
4153
}
4254
return config;
43-
}
55+
};

src/utils/getWeb3Provider.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
11
import { getSignerFromPrivateKey } from 'iexec/utils';
22
import { Web3SignerProvider } from '../web3telegram/types.js';
33

4-
export const getWeb3Provider = (privateKey: string): Web3SignerProvider =>
5-
getSignerFromPrivateKey('bellecour', privateKey);
4+
export const getWeb3Provider = (
5+
privateKey: string,
6+
options: { allowExperimentalNetworks?: boolean; host?: number | string } = {}
7+
): Web3SignerProvider => {
8+
const chainHost = options?.host ? `${options.host}` : 'bellecour';
9+
return getSignerFromPrivateKey(chainHost, privateKey, {
10+
allowExperimentalNetworks: options?.allowExperimentalNetworks,
11+
providers: {},
12+
});
13+
};

src/web3telegram/IExecWeb3telegram.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import {
1414
Web3SignerProvider,
1515
FetchMyContactsParams,
1616
} from './types.js';
17-
import { CHAIN_CONFIG } from '../config/config.js';
17+
import { getChainDefaultConfig } from '../config/config.js';
1818
import { isValidProvider } from '../utils/validators.js';
1919
import { getChainIdFromProvider } from '../utils/getChainId.js';
2020

@@ -122,7 +122,9 @@ export class IExecWeb3telegram {
122122

123123
private async resolveConfig(): Promise<Web3telegramResolvedConfig> {
124124
const chainId = await getChainIdFromProvider(this.ethProvider);
125-
const chainDefaultConfig = CHAIN_CONFIG[chainId];
125+
const chainDefaultConfig = getChainDefaultConfig(chainId, {
126+
allowExperimentalNetworks: this.options.allowExperimentalNetworks,
127+
});
126128

127129
const subgraphUrl =
128130
this.options?.dataProtectorSubgraph ||
@@ -162,6 +164,7 @@ export class IExecWeb3telegram {
162164
{
163165
ipfsGatewayURL: ipfsGateway,
164166
...this.options?.iexecOptions,
167+
allowExperimentalNetworks: this.options.allowExperimentalNetworks,
165168
}
166169
);
167170
} catch (e: any) {

src/web3telegram/types.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,13 @@ export type Web3TelegramConfigOptions = {
107107
* If not provided, the default IPFS gateway URL for the detected chain will be used.
108108
*/
109109
ipfsGateway?: string;
110+
111+
/**
112+
* if true allows using a provider connected to an experimental networks (default false)
113+
*
114+
* ⚠️ experimental networks are networks on which the iExec's stack is partially deployed, experimental networks can be subject to instabilities or discontinuity. Access is provided without warranties.
115+
*/
116+
allowExperimentalNetworks?: boolean;
110117
};
111118

112119
export type DappAddressConsumer = {

tests/.env

Lines changed: 0 additions & 8 deletions
This file was deleted.

tests/e2e/constructor.test.ts

Lines changed: 103 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,15 @@
22
// needed to access and assert IExecDataProtector's private properties
33
import { describe, expect, it } from '@jest/globals';
44
import { Wallet } from 'ethers';
5-
import { IExecWeb3telegram } from '../../src/index.js';
5+
import { getWeb3Provider, IExecWeb3telegram } from '../../src/index.js';
66
import {
77
getTestWeb3SignerProvider,
88
MAX_EXPECTED_WEB2_SERVICES_TIME,
99
} from '../test-utils.js';
10-
import { CHAIN_CONFIG, CHAIN_IDS } from '../../src/config/config.js';
10+
import {
11+
DEFAULT_CHAIN_ID,
12+
getChainDefaultConfig,
13+
} from '../../src/config/config.js';
1114

1215
describe('IExecWeb3telegram()', () => {
1316
it('instantiates with a valid ethProvider', async () => {
@@ -25,7 +28,9 @@ describe('IExecWeb3telegram()', () => {
2528
);
2629
await web3telegram.init();
2730
const ipfsGateway = web3telegram['ipfsGateway'];
28-
expect(ipfsGateway).toStrictEqual(CHAIN_CONFIG[CHAIN_IDS.BELLECOUR].ipfsGateway);
31+
const defaultConfig = getChainDefaultConfig(DEFAULT_CHAIN_ID);
32+
expect(defaultConfig).not.toBeNull();
33+
expect(ipfsGateway).toStrictEqual(defaultConfig!.ipfsGateway);
2934
});
3035

3136
it('should use provided ipfs gateway url when ipfsGateway is provided', async () => {
@@ -48,8 +53,10 @@ describe('IExecWeb3telegram()', () => {
4853
getTestWeb3SignerProvider(wallet.privateKey)
4954
);
5055
await web3telegram.init();
51-
const graphQLClientUrl = web3telegram['graphQLClient'];
52-
expect(graphQLClientUrl['url']).toBe(CHAIN_CONFIG[CHAIN_IDS.BELLECOUR].dataProtectorSubgraph);
56+
const graphQLClient = web3telegram['graphQLClient'];
57+
const defaultConfig = getChainDefaultConfig(DEFAULT_CHAIN_ID);
58+
expect(defaultConfig).not.toBeNull();
59+
expect(graphQLClient['url']).toBe(defaultConfig!.dataProtectorSubgraph);
5360
});
5461

5562
it('should use provided data Protector Subgraph URL when subgraphUrl is provided', async () => {
@@ -102,11 +109,101 @@ describe('IExecWeb3telegram()', () => {
102109
expect(ipfsNode).toStrictEqual(customIpfsNode);
103110
expect(ipfsGateway).toStrictEqual(customIpfsGateway);
104111
expect(dappAddressOrENS).toStrictEqual(customDapp);
105-
expect(whitelistAddress).toStrictEqual(customDappWhitelistAddress.toLowerCase());
112+
expect(whitelistAddress).toStrictEqual(
113+
customDappWhitelistAddress.toLowerCase()
114+
);
106115
expect(await iexec.config.resolveSmsURL()).toBe(smsURL);
107116
expect(await iexec.config.resolveIexecGatewayURL()).toBe(iexecGatewayURL);
108117
});
109118

119+
describe('When instantiating SDK with an experimental network', () => {
120+
const experimentalNetworkSigner = getWeb3Provider(
121+
Wallet.createRandom().privateKey,
122+
{
123+
host: 421614,
124+
allowExperimentalNetworks: true,
125+
}
126+
);
127+
128+
describe('Without allowExperimentalNetworks', () => {
129+
it('should throw a configuration error', async () => {
130+
const web3telegram = new IExecWeb3telegram(experimentalNetworkSigner);
131+
await expect(web3telegram.init()).rejects.toThrow(
132+
'Missing required configuration for chainId 421614: dataProtectorSubgraph, dappAddress, whitelistSmartContract, ipfsGateway, prodWorkerpoolAddress, ipfsUploadUrl'
133+
);
134+
});
135+
});
136+
137+
describe('With allowExperimentalNetworks: true', () => {
138+
it('should resolve the configuration', async () => {
139+
const web3telegram = new IExecWeb3telegram(experimentalNetworkSigner, {
140+
allowExperimentalNetworks: true,
141+
});
142+
await expect(web3telegram.init()).resolves.toBeUndefined();
143+
expect(web3telegram).toBeInstanceOf(IExecWeb3telegram);
144+
});
145+
146+
it('should use Arbitrum Sepolia default configuration', async () => {
147+
const web3telegram = new IExecWeb3telegram(experimentalNetworkSigner, {
148+
allowExperimentalNetworks: true,
149+
});
150+
await web3telegram.init();
151+
152+
const arbitrumSepoliaConfig = getChainDefaultConfig(421614, {
153+
allowExperimentalNetworks: true,
154+
});
155+
expect(arbitrumSepoliaConfig).not.toBeNull();
156+
157+
expect(web3telegram['ipfsGateway']).toBe(
158+
arbitrumSepoliaConfig!.ipfsGateway
159+
);
160+
expect(web3telegram['ipfsNode']).toBe(arbitrumSepoliaConfig!.ipfsUploadUrl);
161+
expect(web3telegram['dappAddressOrENS']).toBe(
162+
arbitrumSepoliaConfig!.dappAddress
163+
);
164+
expect(web3telegram['dappWhitelistAddress']).toBe(
165+
arbitrumSepoliaConfig!.whitelistSmartContract.toLowerCase()
166+
);
167+
expect(web3telegram['defaultWorkerpool']).toBe(
168+
arbitrumSepoliaConfig!.prodWorkerpoolAddress
169+
);
170+
expect(web3telegram['graphQLClient']['url']).toBe(
171+
arbitrumSepoliaConfig!.dataProtectorSubgraph
172+
);
173+
});
174+
175+
it('should allow custom configuration override for Arbitrum Sepolia', async () => {
176+
const customIpfsGateway = 'https://custom-arbitrum-ipfs.com';
177+
const customDappAddress = 'custom.arbitrum.app.eth';
178+
179+
const web3telegram = new IExecWeb3telegram(experimentalNetworkSigner, {
180+
allowExperimentalNetworks: true,
181+
ipfsGateway: customIpfsGateway,
182+
dappAddressOrENS: customDappAddress,
183+
});
184+
await web3telegram.init();
185+
186+
expect(web3telegram['ipfsGateway']).toBe(customIpfsGateway);
187+
expect(web3telegram['dappAddressOrENS']).toBe(customDappAddress);
188+
189+
const arbitrumSepoliaConfig = getChainDefaultConfig(421614, {
190+
allowExperimentalNetworks: true,
191+
});
192+
expect(arbitrumSepoliaConfig).not.toBeNull();
193+
expect(web3telegram['ipfsNode']).toBe(arbitrumSepoliaConfig!.ipfsUploadUrl);
194+
expect(web3telegram['dappWhitelistAddress']).toBe(
195+
arbitrumSepoliaConfig!.whitelistSmartContract.toLowerCase()
196+
);
197+
expect(web3telegram['defaultWorkerpool']).toBe(
198+
arbitrumSepoliaConfig!.prodWorkerpoolAddress
199+
);
200+
expect(web3telegram['graphQLClient']['url']).toBe(
201+
arbitrumSepoliaConfig!.dataProtectorSubgraph
202+
);
203+
});
204+
});
205+
});
206+
110207
it(
111208
'When calling a read method should work as expected',
112209
async () => {

tests/e2e/fetchMyContacts.test.ts

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
import { describe, expect, it } from '@jest/globals';
22
import { IExecDataProtector } from '@iexec/dataprotector';
33
import { IExecWeb3telegram } from '../../src/index.js';
4-
import { CHAIN_CONFIG, CHAIN_IDS } from '../../src/config/config.js';
54
import {
6-
getTestConfig,
7-
waitSubgraphIndexing,
8-
} from '../test-utils.js';
5+
DEFAULT_CHAIN_ID,
6+
getChainDefaultConfig,
7+
} from '../../src/config/config.js';
8+
import { getTestConfig, waitSubgraphIndexing } from '../test-utils.js';
99
import { HDNodeWallet, Wallet } from 'ethers';
1010
import { NULL_ADDRESS } from 'iexec/utils';
1111
import {
@@ -22,6 +22,7 @@ describe('web3telegram.fetchMyContacts()', () => {
2222
let web3telegram: IExecWeb3telegram;
2323
let dataProtector: IExecDataProtector;
2424
let protectedData: any;
25+
const defaultConfig = getChainDefaultConfig(DEFAULT_CHAIN_ID);
2526

2627
beforeAll(async () => {
2728
wallet = Wallet.createRandom();
@@ -38,7 +39,7 @@ describe('web3telegram.fetchMyContacts()', () => {
3839
'pass with a granted access for a specific requester',
3940
async () => {
4041
await dataProtector.core.grantAccess({
41-
authorizedApp: CHAIN_CONFIG[CHAIN_IDS.BELLECOUR].dappAddress,
42+
authorizedApp: defaultConfig.dappAddress,
4243
protectedData: protectedData.address,
4344
authorizedUser: wallet.address,
4445
});
@@ -48,11 +49,11 @@ describe('web3telegram.fetchMyContacts()', () => {
4849
});
4950
expect(
5051
foundContactForASpecificRequester &&
51-
foundContactForASpecificRequester.address
52+
foundContactForASpecificRequester.address
5253
).toBeDefined();
5354
expect(
5455
foundContactForASpecificRequester &&
55-
foundContactForASpecificRequester.address
56+
foundContactForASpecificRequester.address
5657
).toBe(protectedData.address.toLocaleLowerCase());
5758
},
5859
MAX_EXPECTED_WEB2_SERVICES_TIME
@@ -63,7 +64,7 @@ describe('web3telegram.fetchMyContacts()', () => {
6364
async () => {
6465
const grantedAccessForAnyRequester = await dataProtector.core.grantAccess(
6566
{
66-
authorizedApp: CHAIN_CONFIG[CHAIN_IDS.BELLECOUR].dappAddress,
67+
authorizedApp: defaultConfig.dappAddress,
6768
protectedData: protectedData.address,
6869
authorizedUser: NULL_ADDRESS,
6970
}
@@ -103,7 +104,7 @@ describe('web3telegram.fetchMyContacts()', () => {
103104
const encryptionKey = await iexec.dataset.generateEncryptionKey();
104105
await iexec.dataset.pushDatasetSecret(dataset.address, encryptionKey);
105106
await dataProtector.core.grantAccess({
106-
authorizedApp: CHAIN_CONFIG[CHAIN_IDS.BELLECOUR].dappAddress,
107+
authorizedApp: defaultConfig.dappAddress,
107108
protectedData: dataset.address,
108109
authorizedUser: wallet.address,
109110
});
@@ -125,7 +126,7 @@ describe('web3telegram.fetchMyContacts()', () => {
125126
await waitSubgraphIndexing();
126127

127128
await dataProtector.core.grantAccess({
128-
authorizedApp: CHAIN_CONFIG[CHAIN_IDS.BELLECOUR].dappAddress,
129+
authorizedApp: defaultConfig.dappAddress,
129130
protectedData: notValidProtectedData.address,
130131
authorizedUser: wallet.address,
131132
});

0 commit comments

Comments
 (0)