Skip to content

Commit df46c8c

Browse files
feat: add prepareTelegramCampaign WIP
1 parent b2e371c commit df46c8c

File tree

2 files changed

+183
-0
lines changed

2 files changed

+183
-0
lines changed

src/web3telegram/IExecWeb3telegram.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,11 @@ import { getChainDefaultConfig } from '../config/config.js';
1919
import { isValidProvider } from '../utils/validators.js';
2020
import { getChainIdFromProvider } from '../utils/getChainId.js';
2121
import { resolveDappAddressFromCompass } from '../utils/resolveDappAddressFromCompass.js';
22+
import {
23+
prepareTelegramCampaign,
24+
PrepareTelegramCampaignParams,
25+
PrepareTelegramCampaignResponse,
26+
} from './prepareTelegramCampain.js';
2227

2328
type EthersCompatibleProvider =
2429
| AbstractProvider
@@ -129,6 +134,21 @@ export class IExecWeb3telegram {
129134
} as any) as Promise<SendTelegramResponse<Params>>;
130135
}
131136

137+
async prepareTelegramCampaign(
138+
args: PrepareTelegramCampaignParams
139+
): Promise<PrepareTelegramCampaignResponse> {
140+
await this.init();
141+
142+
return prepareTelegramCampaign({
143+
...args,
144+
iexec: this.iexec,
145+
dataProtector: this.dataProtector,
146+
ipfsNode: this.ipfsNode,
147+
ipfsGateway: this.ipfsGateway,
148+
dappAddressOrENS: this.dappAddressOrENS,
149+
});
150+
}
151+
132152
private async resolveConfig(): Promise<Web3telegramResolvedConfig> {
133153
const chainId = await getChainIdFromProvider(this.ethProvider);
134154
const chainDefaultConfig = getChainDefaultConfig(chainId, {
Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
import { Buffer } from 'buffer';
2+
import {
3+
MAX_DESIRED_APP_ORDER_PRICE,
4+
MAX_DESIRED_WORKERPOOL_ORDER_PRICE,
5+
} from '../config/config.js';
6+
import { handleIfProtocolError, WorkflowError } from '../utils/errors.js';
7+
import * as ipfs from '../utils/ipfs-service.js';
8+
import {
9+
addressOrEnsSchema,
10+
telegramContentSchema,
11+
positiveNumberSchema,
12+
labelSchema,
13+
throwIfMissing,
14+
senderNameSchema,
15+
} from '../utils/validators.js';
16+
import { GrantedAccess } from './types.js';
17+
import {
18+
DappAddressConsumer,
19+
DataProtectorConsumer,
20+
IExecConsumer,
21+
IpfsGatewayConfigConsumer,
22+
IpfsNodeConfigConsumer,
23+
} from './internalTypes.js';
24+
import { AddressOrENS, BulkRequest } from '@iexec/dataprotector';
25+
26+
export type PrepareTelegramCampaign = typeof prepareTelegramCampaign;
27+
28+
export type PrepareTelegramCampaignParams = {
29+
/**
30+
* Granted access to process in bulk.
31+
* use `fetchMyContacts({ bulkOnly: true })` to get granted accesses.
32+
* if not provided, the single message will be processed.
33+
*/
34+
grantedAccess: GrantedAccess[];
35+
maxProtectedDataPerTask?: number;
36+
senderName?: string;
37+
telegramContent: string;
38+
label?: string;
39+
workerpoolAddressOrEns?: AddressOrENS;
40+
dataMaxPrice?: number;
41+
appMaxPrice?: number;
42+
workerpoolMaxPrice?: number;
43+
};
44+
45+
export type PrepareTelegramCampaignResponse = {
46+
campaignRequest: BulkRequest;
47+
};
48+
49+
export const prepareTelegramCampaign = async ({
50+
iexec = throwIfMissing(),
51+
dataProtector = throwIfMissing(),
52+
workerpoolAddressOrEns = throwIfMissing(),
53+
dappAddressOrENS,
54+
ipfsNode,
55+
ipfsGateway,
56+
senderName,
57+
telegramContent,
58+
label,
59+
appMaxPrice = MAX_DESIRED_APP_ORDER_PRICE,
60+
workerpoolMaxPrice = MAX_DESIRED_WORKERPOOL_ORDER_PRICE,
61+
grantedAccess,
62+
maxProtectedDataPerTask,
63+
}: IExecConsumer &
64+
DappAddressConsumer &
65+
IpfsNodeConfigConsumer &
66+
IpfsGatewayConfigConsumer &
67+
DataProtectorConsumer &
68+
PrepareTelegramCampaignParams): Promise<PrepareTelegramCampaignResponse> => {
69+
try {
70+
const vWorkerpoolAddressOrEns = addressOrEnsSchema()
71+
.required()
72+
.label('WorkerpoolAddressOrEns')
73+
.validateSync(workerpoolAddressOrEns);
74+
const vSenderName = senderNameSchema()
75+
.label('senderName')
76+
.validateSync(senderName);
77+
const vTelegramContent = telegramContentSchema()
78+
.required()
79+
.label('telegramContent')
80+
.validateSync(telegramContent);
81+
const vLabel = labelSchema().label('label').validateSync(label);
82+
const vDappAddressOrENS = addressOrEnsSchema()
83+
.required()
84+
.label('dappAddressOrENS')
85+
.validateSync(dappAddressOrENS);
86+
const vAppMaxPrice = positiveNumberSchema()
87+
.label('appMaxPrice')
88+
.validateSync(appMaxPrice);
89+
const vWorkerpoolMaxPrice = positiveNumberSchema()
90+
.label('workerpoolMaxPrice')
91+
.validateSync(workerpoolMaxPrice);
92+
const vMaxProtectedDataPerTask = positiveNumberSchema()
93+
.label('maxProtectedDataPerTask')
94+
.validateSync(maxProtectedDataPerTask);
95+
96+
// TODO: factor this
97+
// Encrypt telegram content
98+
const telegramContentEncryptionKey = iexec.dataset.generateEncryptionKey();
99+
const encryptedFile = await iexec.dataset
100+
.encrypt(
101+
Buffer.from(vTelegramContent, 'utf8'),
102+
telegramContentEncryptionKey
103+
)
104+
.catch((e) => {
105+
throw new WorkflowError({
106+
message: 'Failed to encrypt message content',
107+
errorCause: e,
108+
});
109+
});
110+
// Push telegram message to IPFS
111+
const cid = await ipfs
112+
.add(encryptedFile, {
113+
ipfsNode,
114+
ipfsGateway,
115+
})
116+
.catch((e) => {
117+
throw new WorkflowError({
118+
message: 'Failed to upload encrypted telegram content',
119+
errorCause: e,
120+
});
121+
});
122+
const multiaddr = `/ipfs/${cid}`;
123+
// Prepare secrets for the requester
124+
// Use a positive integer as secret ID (required by iexec)
125+
// Using "1" as a fixed ID for the requester secret
126+
const requesterSecretId = 1;
127+
const secrets = {
128+
[requesterSecretId]: JSON.stringify({
129+
senderName: vSenderName,
130+
telegramContentMultiAddr: multiaddr,
131+
telegramContentEncryptionKey,
132+
}),
133+
};
134+
// TODO: end factor this
135+
136+
const { bulkRequest: campaignRequest } =
137+
await dataProtector.prepareBulkRequest({
138+
app: vDappAddressOrENS,
139+
appMaxPrice: vAppMaxPrice,
140+
workerpoolMaxPrice: vWorkerpoolMaxPrice,
141+
workerpool: vWorkerpoolAddressOrEns,
142+
args: vLabel,
143+
inputFiles: [],
144+
secrets,
145+
bulkAccesses: grantedAccess,
146+
maxProtectedDataPerTask: vMaxProtectedDataPerTask,
147+
});
148+
return { campaignRequest };
149+
} catch (error) {
150+
// Protocol error detected, re-throwing as-is
151+
if ((error as any)?.isProtocolError === true) {
152+
throw error;
153+
}
154+
// Handle protocol errors - this will throw if it's an ApiCallError
155+
// handleIfProtocolError transforms ApiCallError into a WorkflowError with isProtocolError=true
156+
handleIfProtocolError(error);
157+
// For all other errors
158+
throw new WorkflowError({
159+
message: 'Failed to prepareTelegramCampaign',
160+
errorCause: error,
161+
});
162+
}
163+
};

0 commit comments

Comments
 (0)