@iexec/web3mail 1.6.0 → 1.7.1

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 (35) hide show
  1. package/dist/utils/subgraphQuery.js +5 -2
  2. package/dist/utils/subgraphQuery.js.map +1 -1
  3. package/dist/utils/validators.d.ts +35 -0
  4. package/dist/utils/validators.js +45 -1
  5. package/dist/utils/validators.js.map +1 -1
  6. package/dist/web3mail/IExecWeb3mail.d.ts +4 -1
  7. package/dist/web3mail/IExecWeb3mail.js +38 -0
  8. package/dist/web3mail/IExecWeb3mail.js.map +1 -1
  9. package/dist/web3mail/fetchMyContacts.d.ts +1 -1
  10. package/dist/web3mail/fetchMyContacts.js +3 -1
  11. package/dist/web3mail/fetchMyContacts.js.map +1 -1
  12. package/dist/web3mail/fetchUserContacts.d.ts +1 -1
  13. package/dist/web3mail/fetchUserContacts.js +20 -3
  14. package/dist/web3mail/fetchUserContacts.js.map +1 -1
  15. package/dist/web3mail/internalTypes.d.ts +4 -0
  16. package/dist/web3mail/prepareEmailCampaign.d.ts +4 -0
  17. package/dist/web3mail/prepareEmailCampaign.js +106 -0
  18. package/dist/web3mail/prepareEmailCampaign.js.map +1 -0
  19. package/dist/web3mail/sendEmail.js +9 -5
  20. package/dist/web3mail/sendEmail.js.map +1 -1
  21. package/dist/web3mail/sendEmailCampaign.d.ts +4 -0
  22. package/dist/web3mail/sendEmailCampaign.js +43 -0
  23. package/dist/web3mail/sendEmailCampaign.js.map +1 -0
  24. package/dist/web3mail/types.d.ts +96 -1
  25. package/package.json +5 -6
  26. package/src/utils/subgraphQuery.ts +17 -14
  27. package/src/utils/validators.ts +68 -1
  28. package/src/web3mail/IExecWeb3mail.ts +53 -0
  29. package/src/web3mail/fetchMyContacts.ts +3 -0
  30. package/src/web3mail/fetchUserContacts.ts +28 -11
  31. package/src/web3mail/internalTypes.ts +5 -0
  32. package/src/web3mail/prepareEmailCampaign.ts +170 -0
  33. package/src/web3mail/sendEmail.ts +31 -5
  34. package/src/web3mail/sendEmailCampaign.ts +69 -0
  35. package/src/web3mail/types.ts +102 -1
@@ -0,0 +1,4 @@
1
+ import { SendEmailCampaignParams, SendEmailCampaignResponse } from './types.js';
2
+ import { DataProtectorConsumer } from './internalTypes.js';
3
+ export type SendEmailCampaign = typeof sendEmailCampaign;
4
+ export declare const sendEmailCampaign: ({ dataProtector, workerpoolAddressOrEns, campaignRequest, }: DataProtectorConsumer & SendEmailCampaignParams) => Promise<SendEmailCampaignResponse>;
@@ -0,0 +1,43 @@
1
+ import { NULL_ADDRESS } from 'iexec/utils';
2
+ import { ValidationError } from 'yup';
3
+ import { handleIfProtocolError, WorkflowError } from '../utils/errors.js';
4
+ import { addressOrEnsSchema, campaignRequestSchema, throwIfMissing, } from '../utils/validators.js';
5
+ export const sendEmailCampaign = async ({ dataProtector = throwIfMissing(), workerpoolAddressOrEns = throwIfMissing(), campaignRequest, }) => {
6
+ const vCampaignRequest = campaignRequestSchema()
7
+ .required()
8
+ .label('campaignRequest')
9
+ .validateSync(campaignRequest);
10
+ const vWorkerpoolAddressOrEns = addressOrEnsSchema()
11
+ .required()
12
+ .label('workerpoolAddressOrEns')
13
+ .validateSync(workerpoolAddressOrEns);
14
+ if (vCampaignRequest.workerpool !== NULL_ADDRESS &&
15
+ vCampaignRequest.workerpool.toLowerCase() !==
16
+ vWorkerpoolAddressOrEns.toLowerCase()) {
17
+ throw new ValidationError("workerpoolAddressOrEns doesn't match campaignRequest workerpool");
18
+ }
19
+ try {
20
+ // Process the prepared bulk request
21
+ const processBulkRequestResponse = await dataProtector.processBulkRequest({
22
+ bulkRequest: vCampaignRequest,
23
+ workerpool: vWorkerpoolAddressOrEns,
24
+ waitForResult: false,
25
+ });
26
+ return processBulkRequestResponse;
27
+ }
28
+ catch (error) {
29
+ // Protocol error detected, re-throwing as-is
30
+ if (error?.isProtocolError === true) {
31
+ throw error;
32
+ }
33
+ // Handle protocol errors - this will throw if it's an ApiCallError
34
+ // handleIfProtocolError transforms ApiCallError into a WorkflowError with isProtocolError=true
35
+ handleIfProtocolError(error);
36
+ // For all other errors
37
+ throw new WorkflowError({
38
+ message: 'Failed to sendEmailCampaign',
39
+ errorCause: error,
40
+ });
41
+ }
42
+ };
43
+ //# sourceMappingURL=sendEmailCampaign.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sendEmailCampaign.js","sourceRoot":"","sources":["../../src/web3mail/sendEmailCampaign.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,eAAe,EAAE,MAAM,KAAK,CAAC;AACtC,OAAO,EAAE,qBAAqB,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAC1E,OAAO,EACL,kBAAkB,EAClB,qBAAqB,EACrB,cAAc,GACf,MAAM,wBAAwB,CAAC;AAUhC,MAAM,CAAC,MAAM,iBAAiB,GAAG,KAAK,EAAE,EACtC,aAAa,GAAG,cAAc,EAAE,EAChC,sBAAsB,GAAG,cAAc,EAAE,EACzC,eAAe,GAEQ,EAAsC,EAAE;IAC/D,MAAM,gBAAgB,GAAG,qBAAqB,EAAE;SAC7C,QAAQ,EAAE;SACV,KAAK,CAAC,iBAAiB,CAAC;SACxB,YAAY,CAAC,eAAe,CAAoB,CAAC;IAEpD,MAAM,uBAAuB,GAAG,kBAAkB,EAAE;SACjD,QAAQ,EAAE;SACV,KAAK,CAAC,wBAAwB,CAAC;SAC/B,YAAY,CAAC,sBAAsB,CAAC,CAAC;IAExC,IACE,gBAAgB,CAAC,UAAU,KAAK,YAAY;QAC5C,gBAAgB,CAAC,UAAU,CAAC,WAAW,EAAE;YACvC,uBAAuB,CAAC,WAAW,EAAE,EACvC,CAAC;QACD,MAAM,IAAI,eAAe,CACvB,iEAAiE,CAClE,CAAC;IACJ,CAAC;IAED,IAAI,CAAC;QACH,oCAAoC;QACpC,MAAM,0BAA0B,GAAG,MAAM,aAAa,CAAC,kBAAkB,CAAC;YACxE,WAAW,EAAE,gBAAgB;YAC7B,UAAU,EAAE,uBAAuB;YACnC,aAAa,EAAE,KAAK;SACrB,CAAC,CAAC;QAEH,OAAO,0BAA0B,CAAC;IACpC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,6CAA6C;QAC7C,IAAK,KAAa,EAAE,eAAe,KAAK,IAAI,EAAE,CAAC;YAC7C,MAAM,KAAK,CAAC;QACd,CAAC;QAED,mEAAmE;QACnE,+FAA+F;QAC/F,qBAAqB,CAAC,KAAK,CAAC,CAAC;QAE7B,uBAAuB;QACvB,MAAM,IAAI,aAAa,CAAC;YACtB,OAAO,EAAE,6BAA6B;YACtC,UAAU,EAAE,KAAK;SAClB,CAAC,CAAC;IACL,CAAC;AACH,CAAC,CAAC"}
@@ -1,18 +1,47 @@
1
1
  import { EnhancedWallet } from 'iexec';
2
2
  import { IExecConfigOptions } from 'iexec/IExecConfig';
3
+ import type { BulkRequest } from '@iexec/dataprotector';
3
4
  export type Web3SignerProvider = EnhancedWallet;
4
5
  export type ENS = string;
5
6
  export type AddressOrENS = Address | ENS;
6
7
  export type Address = string;
7
8
  export type TimeStamp = string;
9
+ /**
10
+ * request to send email in bulk
11
+ *
12
+ * use `prepareEmailCampaign()` to create a `CampaignRequest`
13
+ *
14
+ * then use `sendEmailCampaign()` to send the campaign
15
+ */
16
+ export type CampaignRequest = BulkRequest;
17
+ /**
18
+ * authorization signed by the data owner granting access to this contact
19
+ *
20
+ * `GrantedAccess` are obtained by fetching contacts (e.g. `fetchMyContacts()` or `fetchUserContacts()`)
21
+ *
22
+ * `GrantedAccess` can be consumed for email campaigns (e.g. `prepareEmailCampaign()` then `sendEmailCampaign()`)
23
+ */
24
+ export type GrantedAccess = {
25
+ dataset: string;
26
+ datasetprice: string;
27
+ volume: string;
28
+ tag: string;
29
+ apprestrict: string;
30
+ workerpoolrestrict: string;
31
+ requesterrestrict: string;
32
+ salt: string;
33
+ sign: string;
34
+ remainingAccess: number;
35
+ };
8
36
  export type Contact = {
9
37
  address: Address;
10
38
  owner: Address;
11
39
  accessGrantTimestamp: TimeStamp;
12
40
  isUserStrict: boolean;
13
- name: string;
41
+ name?: string;
14
42
  remainingAccess: number;
15
43
  accessPrice: number;
44
+ grantedAccess: GrantedAccess;
16
45
  };
17
46
  export type SendEmailParams = {
18
47
  emailSubject: string;
@@ -32,6 +61,10 @@ export type FetchMyContactsParams = {
32
61
  * Get contacts for this specific user only
33
62
  */
34
63
  isUserStrict?: boolean;
64
+ /**
65
+ * If true, returns only contacts with bulk processing access grants
66
+ */
67
+ bulkOnly?: boolean;
35
68
  };
36
69
  export type FetchUserContactsParams = {
37
70
  /**
@@ -40,7 +73,14 @@ export type FetchUserContactsParams = {
40
73
  userAddress: Address;
41
74
  } & FetchMyContactsParams;
42
75
  export type SendEmailResponse = {
76
+ /**
77
+ * ID of the task
78
+ */
43
79
  taskId: string;
80
+ /**
81
+ * ID of the deal containing the task
82
+ */
83
+ dealId: string;
44
84
  };
45
85
  /**
46
86
  * Configuration options for Web3Mail.
@@ -83,3 +123,58 @@ export type Web3MailConfigOptions = {
83
123
  */
84
124
  allowExperimentalNetworks?: boolean;
85
125
  };
126
+ export type PrepareEmailCampaignParams = {
127
+ /**
128
+ * List of `GrantedAccess` to contacts to send emails to in bulk.
129
+ *
130
+ * use `fetchMyContacts({ bulkOnly: true })` to get granted accesses.
131
+ */
132
+ grantedAccesses: GrantedAccess[];
133
+ maxProtectedDataPerTask?: number;
134
+ senderName?: string;
135
+ emailSubject: string;
136
+ emailContent: string;
137
+ contentType?: string;
138
+ label?: string;
139
+ workerpoolAddressOrEns?: AddressOrENS;
140
+ dataMaxPrice?: number;
141
+ appMaxPrice?: number;
142
+ workerpoolMaxPrice?: number;
143
+ };
144
+ export type PrepareEmailCampaignResponse = {
145
+ /**
146
+ * The prepared campaign request
147
+ *
148
+ * Use this in `sendEmailCampaign()` to start or continue sending the campaign
149
+ */
150
+ campaignRequest: CampaignRequest;
151
+ };
152
+ export type SendEmailCampaignParams = {
153
+ /**
154
+ * The prepared campaign request from `prepareEmailCampaign()`
155
+ */
156
+ campaignRequest: CampaignRequest;
157
+ /**
158
+ * Workerpool address or ENS to use for processing
159
+ */
160
+ workerpoolAddressOrEns?: AddressOrENS;
161
+ };
162
+ export type SendEmailCampaignResponse = {
163
+ /**
164
+ * List of tasks created for the campaign
165
+ */
166
+ tasks: Array<{
167
+ /**
168
+ * ID of the task
169
+ */
170
+ taskId: string;
171
+ /**
172
+ * ID of the deal containing the task
173
+ */
174
+ dealId: string;
175
+ /**
176
+ * Index of the task in the bulk request
177
+ */
178
+ bulkIndex: number;
179
+ }>;
180
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@iexec/web3mail",
3
- "version": "1.6.0",
3
+ "version": "1.7.1",
4
4
  "description": "This product enables users to confidentially store data–such as mail address, documents, personal information ...",
5
5
  "main": "./dist/index.js",
6
6
  "type": "module",
@@ -20,8 +20,7 @@
20
20
  "scripts": {
21
21
  "build": "rm -rf dist && tsc --project tsconfig.build.json",
22
22
  "check-types": "tsc --noEmit",
23
- "test:prepare": "node tests/scripts/prepare-bellecour-fork-for-tests.js",
24
- "test": "NODE_OPTIONS=--experimental-vm-modules jest --testMatch \"**/tests/**/*.test.ts\" --forceExit -b",
23
+ "test:prepare": "node tests/scripts/prepare-bellecour-fork-for-tests.js && node tests/scripts/prepare-iexec.js",
25
24
  "test:coverage": "NODE_OPTIONS=--experimental-vm-modules jest --testMatch \"**/tests/**/*.test.ts\" --forceExit --coverage",
26
25
  "test:unit": "NODE_OPTIONS=--experimental-vm-modules jest --testMatch \"**/tests/unit/**/*.test.ts\" -b",
27
26
  "test:unit:coverage": "NODE_OPTIONS=--experimental-vm-modules jest --testMatch \"**/tests/unit/**/*.unit.ts\" --coverage",
@@ -31,7 +30,7 @@
31
30
  "format": "prettier --write \"(src|tests)/**/*.ts\"",
32
31
  "check-format": "prettier --check \"(src|tests)/**/*.ts\"",
33
32
  "stop-test-stack": "cd tests && docker compose down --volumes --remove-orphans",
34
- "start-test-stack": "cd tests && npm run stop-test-stack && node scripts/prepare-test-env.js && docker compose build && docker compose up -d && node scripts/prepare-bellecour-fork-for-tests.js"
33
+ "start-test-stack": "cd tests && npm run stop-test-stack && node scripts/prepare-test-env.js && docker compose build && docker compose up -d && npm run test:prepare"
35
34
  },
36
35
  "repository": {
37
36
  "type": "git",
@@ -49,15 +48,15 @@
49
48
  "dependencies": {
50
49
  "@ethersproject/bytes": "^5.7.0",
51
50
  "@ethersproject/random": "^5.7.0",
51
+ "@iexec/dataprotector": "^2.0.0-beta.21",
52
52
  "buffer": "^6.0.3",
53
53
  "ethers": "^6.13.2",
54
54
  "graphql-request": "^6.1.0",
55
- "iexec": "^8.20.0",
55
+ "iexec": "^8.22.2",
56
56
  "kubo-rpc-client": "^4.1.1",
57
57
  "yup": "^1.1.1"
58
58
  },
59
59
  "devDependencies": {
60
- "@iexec/dataprotector": "^2.0.0-beta.19",
61
60
  "@jest/globals": "^29.7.0",
62
61
  "@swc/core": "^1.3.96",
63
62
  "@swc/jest": "^0.2.29",
@@ -71,20 +71,23 @@ export const getValidContact = async (
71
71
  );
72
72
 
73
73
  // Convert protectedData[] into Contact[] using the map for constant time lookups
74
- return protectedDataList.map(({ id, name }) => {
75
- const contact = contactsMap.get(id);
76
- if (contact) {
77
- return {
78
- address: id,
79
- name: name,
80
- remainingAccess: contact.remainingAccess,
81
- accessPrice: contact.accessPrice,
82
- owner: contact.owner,
83
- accessGrantTimestamp: contact.accessGrantTimestamp,
84
- isUserStrict: contact.isUserStrict,
85
- };
86
- }
87
- });
74
+ return protectedDataList
75
+ .map(({ id, name }) => {
76
+ const contact = contactsMap.get(id);
77
+ if (contact) {
78
+ return {
79
+ address: id,
80
+ name: name,
81
+ remainingAccess: contact.remainingAccess,
82
+ accessPrice: contact.accessPrice,
83
+ owner: contact.owner,
84
+ accessGrantTimestamp: contact.accessGrantTimestamp,
85
+ isUserStrict: contact.isUserStrict,
86
+ grantedAccess: contact.grantedAccess,
87
+ };
88
+ }
89
+ })
90
+ .filter((contact) => !!contact);
88
91
  } catch (error) {
89
92
  throw new WorkflowError({
90
93
  message: 'Failed to fetch subgraph',
@@ -1,6 +1,7 @@
1
1
  import { isAddress } from 'ethers';
2
2
  import { IExec } from 'iexec';
3
- import { ValidationError, boolean, number, string } from 'yup';
3
+ import { NULL_ADDRESS } from 'iexec/utils';
4
+ import { ValidationError, boolean, number, object, string } from 'yup';
4
5
 
5
6
  export const isValidProvider = async (iexec: IExec) => {
6
7
  const client = await iexec.config.resolveContractsClient();
@@ -61,3 +62,69 @@ export const positiveNumberSchema = () =>
61
62
 
62
63
  export const booleanSchema = () =>
63
64
  boolean().strict().typeError('${path} should be a boolean');
65
+
66
+ const isPositiveIntegerStringTest = (value: string) => /^\d+$/.test(value);
67
+
68
+ const stringSchema = () =>
69
+ string().strict().typeError('${path} should be a string');
70
+
71
+ const positiveIntegerStringSchema = () =>
72
+ string().test(
73
+ 'is-positive-int',
74
+ '${path} should be a positive integer',
75
+ (value) => isUndefined(value) || isPositiveIntegerStringTest(value)
76
+ );
77
+
78
+ const positiveStrictIntegerStringSchema = () =>
79
+ string().test(
80
+ 'is-positive-strict-int',
81
+ '${path} should be a strictly positive integer',
82
+ (value) =>
83
+ isUndefined(value) ||
84
+ (value !== '0' && isPositiveIntegerStringTest(value))
85
+ );
86
+
87
+ export const campaignRequestSchema = () =>
88
+ object({
89
+ app: addressSchema().required(),
90
+ appmaxprice: positiveIntegerStringSchema().required(),
91
+ workerpool: addressSchema().required(),
92
+ workerpoolmaxprice: positiveIntegerStringSchema().required(),
93
+ dataset: addressSchema().oneOf([NULL_ADDRESS]).required(),
94
+ datasetmaxprice: positiveIntegerStringSchema().oneOf(['0']).required(),
95
+ params: stringSchema()
96
+ .test(
97
+ 'is-valid-bulk-params',
98
+ '${path} should be a valid JSON string with bulk_cid field',
99
+ (value) => {
100
+ try {
101
+ // eslint-disable-next-line @typescript-eslint/naming-convention
102
+ const { bulk_cid } = JSON.parse(value);
103
+ if (typeof bulk_cid === 'string') {
104
+ return true;
105
+ }
106
+ } catch {}
107
+ return false;
108
+ }
109
+ )
110
+ .required(),
111
+ requester: addressSchema().required(),
112
+ beneficiary: addressSchema().required(),
113
+ callback: addressSchema().required(),
114
+ category: positiveIntegerStringSchema().required(),
115
+ volume: positiveStrictIntegerStringSchema().required(),
116
+ tag: stringSchema().required(),
117
+ trust: positiveIntegerStringSchema().required(),
118
+ salt: stringSchema().required(),
119
+ sign: stringSchema().required(),
120
+ })
121
+ .strict()
122
+ .typeError('${path} should be a BulkRequest object')
123
+ .test('is-defined', '${path} is required', (value) => {
124
+ // Check if value is undefined, null, or an empty object (which would be coerced from undefined)
125
+ return (
126
+ value !== undefined &&
127
+ value !== null &&
128
+ !(typeof value === 'object' && Object.keys(value).length === 0)
129
+ );
130
+ });
@@ -1,9 +1,12 @@
1
1
  import { AbstractProvider, AbstractSigner, Eip1193Provider } from 'ethers';
2
2
  import { IExec } from 'iexec';
3
+ import { IExecDataProtectorCore } from '@iexec/dataprotector';
3
4
  import { GraphQLClient } from 'graphql-request';
4
5
  import { fetchUserContacts } from './fetchUserContacts.js';
5
6
  import { fetchMyContacts } from './fetchMyContacts.js';
6
7
  import { sendEmail } from './sendEmail.js';
8
+ import { prepareEmailCampaign } from './prepareEmailCampaign.js';
9
+ import { sendEmailCampaign } from './sendEmailCampaign.js';
7
10
  import {
8
11
  Contact,
9
12
  FetchUserContactsParams,
@@ -13,6 +16,10 @@ import {
13
16
  SendEmailResponse,
14
17
  Web3SignerProvider,
15
18
  FetchMyContactsParams,
19
+ PrepareEmailCampaignParams,
20
+ PrepareEmailCampaignResponse,
21
+ SendEmailCampaignParams,
22
+ SendEmailCampaignResponse,
16
23
  } from './types.js';
17
24
  import { isValidProvider } from '../utils/validators.js';
18
25
  import { getChainIdFromProvider } from '../utils/getChainId.js';
@@ -34,6 +41,7 @@ interface Web3mailResolvedConfig {
34
41
  ipfsGateway: string;
35
42
  defaultWorkerpool: string;
36
43
  iexec: IExec;
44
+ dataProtector: IExecDataProtectorCore;
37
45
  }
38
46
 
39
47
  export class IExecWeb3mail {
@@ -51,6 +59,8 @@ export class IExecWeb3mail {
51
59
 
52
60
  private iexec!: IExec;
53
61
 
62
+ private dataProtector!: IExecDataProtectorCore;
63
+
54
64
  private initPromise: Promise<void> | null = null;
55
65
 
56
66
  private ethProvider: EthersCompatibleProvider;
@@ -75,6 +85,7 @@ export class IExecWeb3mail {
75
85
  this.ipfsGateway = config.ipfsGateway;
76
86
  this.defaultWorkerpool = config.defaultWorkerpool;
77
87
  this.iexec = config.iexec;
88
+ this.dataProtector = config.dataProtector;
78
89
  });
79
90
  }
80
91
  return this.initPromise;
@@ -121,6 +132,36 @@ export class IExecWeb3mail {
121
132
  });
122
133
  }
123
134
 
135
+ async prepareEmailCampaign(
136
+ args: PrepareEmailCampaignParams
137
+ ): Promise<PrepareEmailCampaignResponse> {
138
+ await this.init();
139
+ await isValidProvider(this.iexec);
140
+ return prepareEmailCampaign({
141
+ ...args,
142
+ workerpoolAddressOrEns:
143
+ args.workerpoolAddressOrEns || this.defaultWorkerpool,
144
+ iexec: this.iexec,
145
+ dataProtector: this.dataProtector,
146
+ ipfsNode: this.ipfsNode,
147
+ ipfsGateway: this.ipfsGateway,
148
+ dappAddressOrENS: this.dappAddressOrENS,
149
+ });
150
+ }
151
+
152
+ async sendEmailCampaign(
153
+ args: SendEmailCampaignParams
154
+ ): Promise<SendEmailCampaignResponse> {
155
+ await this.init();
156
+ await isValidProvider(this.iexec);
157
+ return sendEmailCampaign({
158
+ ...args,
159
+ workerpoolAddressOrEns:
160
+ args.workerpoolAddressOrEns || this.defaultWorkerpool,
161
+ dataProtector: this.dataProtector,
162
+ });
163
+ }
164
+
124
165
  private async resolveConfig(): Promise<Web3mailResolvedConfig> {
125
166
  const chainId = await getChainIdFromProvider(this.ethProvider);
126
167
  const chainDefaultConfig = getChainDefaultConfig(chainId, {
@@ -184,6 +225,17 @@ export class IExecWeb3mail {
184
225
  throw new Error(`Failed to create GraphQLClient: ${error.message}`);
185
226
  }
186
227
 
228
+ const dataProtector = new IExecDataProtectorCore(this.ethProvider, {
229
+ iexecOptions: {
230
+ ipfsGatewayURL: ipfsGateway,
231
+ ...this.options?.iexecOptions,
232
+ allowExperimentalNetworks: this.options.allowExperimentalNetworks,
233
+ },
234
+ ipfsGateway,
235
+ ipfsNode,
236
+ subgraphUrl,
237
+ });
238
+
187
239
  return {
188
240
  dappAddressOrENS,
189
241
  dappWhitelistAddress: dappWhitelistAddress.toLowerCase(),
@@ -192,6 +244,7 @@ export class IExecWeb3mail {
192
244
  ipfsNode,
193
245
  ipfsGateway,
194
246
  iexec,
247
+ dataProtector,
195
248
  };
196
249
  }
197
250
  }
@@ -16,6 +16,7 @@ export const fetchMyContacts = async ({
16
16
  dappAddressOrENS = throwIfMissing(),
17
17
  dappWhitelistAddress = throwIfMissing(),
18
18
  isUserStrict = false,
19
+ bulkOnly = false,
19
20
  }: IExecConsumer &
20
21
  SubgraphConsumer &
21
22
  DappAddressConsumer &
@@ -24,6 +25,7 @@ export const fetchMyContacts = async ({
24
25
  const vIsUserStrict = booleanSchema()
25
26
  .label('isUserStrict')
26
27
  .validateSync(isUserStrict);
28
+ const vBulkOnly = booleanSchema().label('bulkOnly').validateSync(bulkOnly);
27
29
 
28
30
  const userAddress = await iexec.wallet.getAddress();
29
31
  return fetchUserContacts({
@@ -33,5 +35,6 @@ export const fetchMyContacts = async ({
33
35
  dappWhitelistAddress,
34
36
  userAddress,
35
37
  isUserStrict: vIsUserStrict,
38
+ bulkOnly: vBulkOnly,
36
39
  });
37
40
  };
@@ -27,6 +27,7 @@ export const fetchUserContacts = async ({
27
27
  dappWhitelistAddress = throwIfMissing(),
28
28
  userAddress,
29
29
  isUserStrict = false,
30
+ bulkOnly = false,
30
31
  }: IExecConsumer &
31
32
  SubgraphConsumer &
32
33
  DappAddressConsumer &
@@ -47,6 +48,7 @@ export const fetchUserContacts = async ({
47
48
  const vIsUserStrict = booleanSchema()
48
49
  .label('isUserStrict')
49
50
  .validateSync(isUserStrict);
51
+ const vBulkOnly = booleanSchema().label('bulkOnly').validateSync(bulkOnly);
50
52
 
51
53
  try {
52
54
  const [dappOrders, whitelistOrders] = await Promise.all([
@@ -55,12 +57,14 @@ export const fetchUserContacts = async ({
55
57
  userAddress: vUserAddress,
56
58
  appAddress: vDappAddressOrENS,
57
59
  isUserStrict: vIsUserStrict,
60
+ bulkOnly: vBulkOnly,
58
61
  }),
59
62
  fetchAllOrdersByApp({
60
63
  iexec,
61
64
  userAddress: vUserAddress,
62
65
  appAddress: vDappWhitelistAddress,
63
66
  isUserStrict: vIsUserStrict,
67
+ bulkOnly: vBulkOnly,
64
68
  }),
65
69
  ]);
66
70
 
@@ -84,6 +88,18 @@ export const fetchUserContacts = async ({
84
88
  accessPrice: order.order.datasetprice,
85
89
  accessGrantTimestamp: order.publicationTimestamp,
86
90
  isUserStrict: order.order.requesterrestrict !== ZeroAddress,
91
+ grantedAccess: {
92
+ dataset: order.order.dataset,
93
+ datasetprice: order.order.datasetprice.toString(),
94
+ volume: order.order.volume.toString(),
95
+ tag: order.order.tag.toString(),
96
+ apprestrict: order.order.apprestrict,
97
+ workerpoolrestrict: order.order.workerpoolrestrict,
98
+ requesterrestrict: order.order.requesterrestrict,
99
+ salt: order.order.salt,
100
+ sign: order.order.sign,
101
+ remainingAccess: order.remaining,
102
+ },
87
103
  };
88
104
  myContacts.push(contact);
89
105
  }
@@ -107,23 +123,24 @@ async function fetchAllOrdersByApp({
107
123
  userAddress,
108
124
  appAddress,
109
125
  isUserStrict,
126
+ bulkOnly,
110
127
  }: {
111
128
  iexec: IExec;
112
129
  userAddress: string;
113
130
  appAddress: string;
114
131
  isUserStrict: boolean;
132
+ bulkOnly: boolean;
115
133
  }): Promise<PublishedDatasetorder[]> {
116
- const ordersFirstPage = iexec.orderbook.fetchDatasetOrderbook(
117
- ANY_DATASET_ADDRESS,
118
- {
119
- app: appAddress,
120
- requester: userAddress,
121
- isAppStrict: true,
122
- isRequesterStrict: isUserStrict,
123
- // Use maxPageSize here to avoid too many round-trips (we want everything anyway)
124
- pageSize: 1000,
125
- }
126
- );
134
+ const ordersFirstPage = iexec.orderbook.fetchDatasetOrderbook({
135
+ dataset: ANY_DATASET_ADDRESS,
136
+ app: appAddress,
137
+ requester: userAddress,
138
+ isAppStrict: true,
139
+ isRequesterStrict: isUserStrict,
140
+ bulkOnly,
141
+ // Use maxPageSize here to avoid too many round-trips (we want everything anyway)
142
+ pageSize: 1000,
143
+ });
127
144
  const { orders: allOrders } = await autoPaginateRequest({
128
145
  request: ordersFirstPage,
129
146
  });
@@ -1,4 +1,5 @@
1
1
  import { IExec } from 'iexec';
2
+ import { IExecDataProtectorCore } from '@iexec/dataprotector';
2
3
  import { AddressOrENS } from './types.js';
3
4
  import { GraphQLClient } from 'graphql-request';
4
5
 
@@ -34,3 +35,7 @@ export type IExecConsumer = {
34
35
  export type SubgraphConsumer = {
35
36
  graphQLClient: GraphQLClient;
36
37
  };
38
+
39
+ export type DataProtectorConsumer = {
40
+ dataProtector: IExecDataProtectorCore;
41
+ };