@appliedblockchain/silentdatarollup-core 1.0.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/README.md ADDED
@@ -0,0 +1,17 @@
1
+ # Silent Data [Rollup] Providers - Core Package
2
+
3
+ This package contains the core functionality for the other packages.
4
+
5
+ ## Overview
6
+
7
+ The Core Package serves as the foundation for all other packages within the `packages` folder. It provides essential utilities, shared components, and common functionality that can be utilized across the entire project.
8
+
9
+ ## Features
10
+
11
+ - Shared utilities and helper functions
12
+ - Common interfaces and types
13
+ - Configuration management
14
+
15
+ ## License
16
+
17
+ This project is licensed under the [MIT License](LICENSE).
@@ -0,0 +1,561 @@
1
+ // src/Base.ts
2
+ import debug2 from "debug";
3
+
4
+ // src/constants.ts
5
+ var SIGN_RPC_METHODS = [
6
+ "eth_getTransactionByHash",
7
+ "eth_getTransactionCount",
8
+ "eth_getProof",
9
+ "eth_getTransactionReceipt"
10
+ ];
11
+ var eip721Domain = {
12
+ name: "Silent Data [Rollup]",
13
+ version: "1"
14
+ };
15
+ var delegateEIP721Types = {
16
+ Ticket: [
17
+ { name: "expires", type: "string" },
18
+ { name: "ephemeralAddress", type: "string" }
19
+ ]
20
+ };
21
+ var DEBUG_NAMESPACE = "silentdata:core";
22
+ var DEBUG_NAMESPACE_SILENTDATA_INTERCEPTOR = "silentdata:interceptor";
23
+ var HEADER_SIGNATURE = "x-signature";
24
+ var HEADER_TIMESTAMP = "x-timestamp";
25
+ var HEADER_EIP712_SIGNATURE = "x-eip712-signature";
26
+ var HEADER_DELEGATE = "x-delegate";
27
+ var HEADER_DELEGATE_SIGNATURE = "x-delegate-signature";
28
+ var HEADER_EIP712_DELEGATE_SIGNATURE = "x-eip712-delegate-signature";
29
+ var DEFAULT_DELEGATE_EXPIRES = 24 * 60 * 60;
30
+ var DELEGATE_EXPIRATION_THRESHOLD_BUFFER = 5;
31
+ var WHITELISTED_METHODS = [
32
+ "eth_blockNumber",
33
+ "eth_call",
34
+ "eth_chainId",
35
+ "eth_estimateGas",
36
+ "eth_feeHistory",
37
+ "eth_gasPrice",
38
+ "eth_getBalance",
39
+ "eth_getBlockByHash",
40
+ "eth_getBlockByNumber",
41
+ "eth_getCode",
42
+ "eth_getFilterChanges",
43
+ "eth_getFilterLogs",
44
+ "eth_getHashrate",
45
+ "eth_getHeaderByHash",
46
+ "eth_getLogs",
47
+ "eth_getProof",
48
+ "eth_getTransactionByHash",
49
+ "eth_getTransactionCount",
50
+ "eth_getTransactionReceipt",
51
+ "eth_hashrate",
52
+ "eth_maxPriorityFeePerGas",
53
+ "eth_mining",
54
+ "eth_newBlockFilter",
55
+ "eth_sendRawTransaction",
56
+ "eth_submitTransaction",
57
+ "eth_syncing",
58
+ "eth_newFilter",
59
+ "eth_newPendingTransactionFilter",
60
+ "net_listening",
61
+ "net_version",
62
+ "net_peerCount",
63
+ "web3_clientVersion",
64
+ "web3_sha3",
65
+ "zkevm_batchNumber",
66
+ "zkevm_batchNumberByBlockNumber",
67
+ "zkevm_consolidatedBlockNumber",
68
+ "zkevm_estimateGasPrice",
69
+ "zkevm_getBatchByNumber",
70
+ "zkevm_getFullBlockByHash",
71
+ "zkevm_getFullBlockByNumber",
72
+ "zkevm_getLatestGlobalExitRoot",
73
+ "zkevm_isBlockConsolidated",
74
+ "zkevm_isBlockVirtualized",
75
+ "zkevm_verifiedBatchNumber",
76
+ "zkevm_virtualBatchNumber"
77
+ ];
78
+
79
+ // src/types.ts
80
+ var ChainId = /* @__PURE__ */ ((ChainId2) => {
81
+ ChainId2[ChainId2["MAINNET"] = 51966] = "MAINNET";
82
+ ChainId2[ChainId2["TESTNET"] = 1001] = "TESTNET";
83
+ return ChainId2;
84
+ })(ChainId || {});
85
+ var NetworkName = /* @__PURE__ */ ((NetworkName2) => {
86
+ NetworkName2["MAINNET"] = "sdr";
87
+ NetworkName2["TESTNET"] = "sdr-testnet";
88
+ return NetworkName2;
89
+ })(NetworkName || {});
90
+ var SignatureType = /* @__PURE__ */ ((SignatureType2) => {
91
+ SignatureType2["Raw"] = "RAW";
92
+ SignatureType2["EIP191"] = "EIP191";
93
+ SignatureType2["EIP712"] = "EIP712";
94
+ return SignatureType2;
95
+ })(SignatureType || {});
96
+
97
+ // src/utils.ts
98
+ import debug from "debug";
99
+ import { Wallet } from "ethers";
100
+ var log = debug(DEBUG_NAMESPACE);
101
+ function getAuthEIP721Types(payload) {
102
+ return {
103
+ Call: [
104
+ {
105
+ name: "request",
106
+ type: Array.isArray(payload) ? "JsonRPCRequest[]" : "JsonRPCRequest"
107
+ },
108
+ { name: "timestamp", type: "string" }
109
+ ],
110
+ JsonRPCRequest: [
111
+ { name: "jsonrpc", type: "string" },
112
+ { name: "method", type: "string" },
113
+ { name: "params", type: "string" },
114
+ { name: "id", type: "uint256" }
115
+ ]
116
+ };
117
+ }
118
+ async function signAuthHeaderTypedData(signer, payload, timestamp) {
119
+ log("Preparing payload for signTypedData");
120
+ const preparePayload = (p) => ({
121
+ ...p,
122
+ params: JSON.stringify(p.params)
123
+ });
124
+ const preparedPayload = Array.isArray(payload) ? payload.map(preparePayload) : preparePayload(payload);
125
+ const message = {
126
+ request: preparedPayload,
127
+ timestamp
128
+ };
129
+ const types = getAuthEIP721Types(payload);
130
+ log(
131
+ "Signing typed data",
132
+ JSON.stringify({ eip721Domain, types, message }, null, 2)
133
+ );
134
+ const signature = await signer.signTypedData(eip721Domain, types, message);
135
+ log("Signature generated:", signature);
136
+ return signature;
137
+ }
138
+ async function signAuthHeaderRawMessage(signer, payload, timestamp) {
139
+ log("Preparing raw message for signing");
140
+ const serialRequest = JSON.stringify(payload);
141
+ const xMessage = serialRequest + timestamp;
142
+ log("Raw message:", xMessage);
143
+ const signature = await signer.signMessage(xMessage);
144
+ log("Raw signature generated:", signature);
145
+ return signature;
146
+ }
147
+ async function signTypedDelegateHeader(signer, message) {
148
+ log("Signing typed delegate header");
149
+ const signature = await signer.signTypedData(
150
+ eip721Domain,
151
+ delegateEIP721Types,
152
+ message
153
+ );
154
+ log("Signature generated:", signature);
155
+ return signature;
156
+ }
157
+ async function signRawDelegateHeader(signer, message) {
158
+ log("Signing raw delegate header");
159
+ log("Raw message:", message);
160
+ const signature = await signer.signMessage(JSON.stringify(message));
161
+ log("Raw signature generated:", signature);
162
+ return signature;
163
+ }
164
+ async function getAuthHeaders(signer, payload, signatureType) {
165
+ const xTimestamp = (/* @__PURE__ */ new Date()).toISOString();
166
+ const headers = {
167
+ [HEADER_TIMESTAMP]: xTimestamp
168
+ };
169
+ switch (signatureType) {
170
+ case "RAW" /* Raw */:
171
+ log("Generating raw signature");
172
+ headers[HEADER_SIGNATURE] = await signAuthHeaderRawMessage(
173
+ signer,
174
+ payload,
175
+ xTimestamp
176
+ );
177
+ break;
178
+ case "EIP712" /* EIP712 */:
179
+ log("Generating EIP712 signature");
180
+ headers[HEADER_EIP712_SIGNATURE] = await signAuthHeaderTypedData(
181
+ signer,
182
+ payload,
183
+ xTimestamp
184
+ );
185
+ break;
186
+ default:
187
+ throw new Error(`Unsupported signature type: ${signatureType}`);
188
+ }
189
+ return headers;
190
+ }
191
+ function isSignableContractCall(payload, contractMethodsToSign, contract) {
192
+ if (!contractMethodsToSign || !contract) {
193
+ return false;
194
+ }
195
+ log("Checking if contract call is signable");
196
+ log("Contract methods to sign:", contractMethodsToSign);
197
+ if (payload.method !== "eth_call") {
198
+ log("Payload method is not eth_call, returning false");
199
+ return false;
200
+ }
201
+ const params = payload.params;
202
+ if (!params || params.length === 0 || typeof params[0] !== "object") {
203
+ log("Invalid params, returning false");
204
+ return false;
205
+ }
206
+ const methodSignature = params[0].data.slice(2, 10);
207
+ log("Method signature:", methodSignature);
208
+ const isSignable = contractMethodsToSign.some((methodName) => {
209
+ const fragment = contract.interface.getFunction(methodName);
210
+ return !!fragment && methodSignature.startsWith(fragment.selector.slice(2));
211
+ });
212
+ log("Is signable contract call:", isSignable);
213
+ return isSignable;
214
+ }
215
+ var defaultGetDelegate = async (provider) => {
216
+ return Wallet.createRandom();
217
+ };
218
+ var prepareTypedDataPayload = (p) => ({
219
+ ...p,
220
+ params: JSON.stringify(p.params)
221
+ });
222
+
223
+ // src/Base.ts
224
+ var log2 = debug2(DEBUG_NAMESPACE);
225
+ var SilentDataRollupBase = class {
226
+ constructor(config) {
227
+ this.currentDelegateSigner = null;
228
+ this.delegateSignerExpires = 0;
229
+ this.cachedDelegateHeaders = null;
230
+ this.cachedHeadersExpiry = 0;
231
+ this.contract = null;
232
+ this.contractMethodsToSign = [];
233
+ this.config = {
234
+ ...config,
235
+ authSignatureType: config.authSignatureType ?? "RAW" /* Raw */
236
+ };
237
+ this.delegateConfig = this.resolveDelegateConfig(config);
238
+ log2(
239
+ "SilentDataRollupBase initialized with config:",
240
+ JSON.stringify(config, null, 2)
241
+ );
242
+ }
243
+ resolveDelegateConfig(config) {
244
+ if (config.delegate === true) {
245
+ return {
246
+ getDelegate: defaultGetDelegate,
247
+ expires: DEFAULT_DELEGATE_EXPIRES
248
+ };
249
+ } else if (typeof config.delegate === "object") {
250
+ return {
251
+ getDelegate: config.delegate.getDelegate ?? defaultGetDelegate,
252
+ expires: config.delegate.expires ?? DEFAULT_DELEGATE_EXPIRES
253
+ };
254
+ }
255
+ return null;
256
+ }
257
+ async getDelegateSigner(provider) {
258
+ if (!this.delegateConfig) {
259
+ log2("getDelegateSigner: No delegate config, returning null");
260
+ return null;
261
+ }
262
+ const now = Math.floor(Date.now() / 1e3);
263
+ log2("getDelegateSigner: Current time:", now);
264
+ const isDelegateSignerValid = this.currentDelegateSigner && this.delegateSignerExpires - DELEGATE_EXPIRATION_THRESHOLD_BUFFER > now;
265
+ if (isDelegateSignerValid) {
266
+ log2(
267
+ "getDelegateSigner: Returning existing delegate signer, expires in:",
268
+ this.delegateSignerExpires - now,
269
+ "seconds"
270
+ );
271
+ return this.currentDelegateSigner;
272
+ } else {
273
+ log2("getDelegateSigner: Getting new delegate signer");
274
+ try {
275
+ const newSigner = await this.delegateConfig.getDelegate(provider);
276
+ this.currentDelegateSigner = newSigner;
277
+ this.delegateSignerExpires = now + this.delegateConfig.expires;
278
+ log2(
279
+ "getDelegateSigner: New delegate signer set, expires in:",
280
+ this.delegateConfig.expires,
281
+ "seconds"
282
+ );
283
+ return newSigner;
284
+ } catch (error) {
285
+ log2("getDelegateSigner: Error getting delegate signer:", error);
286
+ throw new Error("Failed to get delegate signer");
287
+ }
288
+ }
289
+ }
290
+ async getDelegateSignerMessage(provider) {
291
+ if (!this.delegateConfig) {
292
+ log2("No delegate config, returning null");
293
+ return null;
294
+ }
295
+ const delegateSigner = await this.getDelegateSigner(provider);
296
+ if (!delegateSigner) {
297
+ log2("Failed to get delegate signer, returning null");
298
+ return null;
299
+ }
300
+ return {
301
+ expires: new Date(this.delegateSignerExpires * 1e3).toISOString(),
302
+ ephemeralAddress: await delegateSigner.getAddress()
303
+ };
304
+ }
305
+ /**
306
+ * Signs a raw delegate header message.
307
+ * This method can be overridden by extending classes to customize the signing process.
308
+ * @param provider - The provider used for signing
309
+ * @param message - The delegate signer message to be signed
310
+ * @returns A promise that resolves to the signature string
311
+ */
312
+ async signRawDelegateHeader(provider, message) {
313
+ log2("signRawDelegateHeader: Signing raw delegate header");
314
+ log2("signRawDelegateHeader: Raw message:", JSON.stringify(message, null, 2));
315
+ const signature = await provider.signer.signMessage(JSON.stringify(message));
316
+ log2("signRawDelegateHeader: Raw signature generated:", signature);
317
+ return signature;
318
+ }
319
+ /**
320
+ * Signs a typed delegate header message.
321
+ * This method can be overridden by extending classes to customize the signing process.
322
+ * @param provider - The provider used for signing
323
+ * @param message - The delegate signer message to be signed
324
+ * @returns A promise that resolves to the signature string
325
+ */
326
+ async signTypedDelegateHeader(provider, message) {
327
+ log2("signTypedDelegateHeader: Signing typed delegate header");
328
+ log2(
329
+ "signTypedDelegateHeader: Typed message:",
330
+ JSON.stringify(message, null, 2)
331
+ );
332
+ const signature = await provider.signer.signTypedData(
333
+ eip721Domain,
334
+ delegateEIP721Types,
335
+ message
336
+ );
337
+ log2("signTypedDelegateHeader: Signature generated:", signature);
338
+ return signature;
339
+ }
340
+ async getDelegateHeaders(provider) {
341
+ log2("Getting delegate headers");
342
+ const now = Math.floor(Date.now() / 1e3);
343
+ const signatureType = this.config.authSignatureType;
344
+ const isCachedHeadersValid = this.cachedDelegateHeaders && this.cachedHeadersExpiry - DELEGATE_EXPIRATION_THRESHOLD_BUFFER > now;
345
+ if (isCachedHeadersValid) {
346
+ log2("Returning cached delegate headers");
347
+ return this.cachedDelegateHeaders;
348
+ }
349
+ try {
350
+ const delegateSignerMessage = await this.getDelegateSignerMessage(provider);
351
+ if (!delegateSignerMessage) {
352
+ throw new Error("Failed to get delegate signer message");
353
+ }
354
+ const delegateSigner = await this.getDelegateSigner(provider);
355
+ if (!delegateSigner) {
356
+ throw new Error("Failed to get delegate signer");
357
+ }
358
+ const headers = {
359
+ [HEADER_DELEGATE]: JSON.stringify(delegateSignerMessage)
360
+ };
361
+ switch (signatureType) {
362
+ case "RAW" /* Raw */:
363
+ log2("Generating delegate raw signature");
364
+ headers[HEADER_DELEGATE_SIGNATURE] = await this.signRawDelegateHeader(
365
+ provider,
366
+ delegateSignerMessage
367
+ );
368
+ break;
369
+ case "EIP712" /* EIP712 */:
370
+ log2("Generating delegate EIP712 signature");
371
+ headers[HEADER_EIP712_DELEGATE_SIGNATURE] = await this.signTypedDelegateHeader(provider, delegateSignerMessage);
372
+ break;
373
+ default:
374
+ throw new Error(`Unsupported signature type: ${signatureType}`);
375
+ }
376
+ this.cachedDelegateHeaders = headers;
377
+ this.cachedHeadersExpiry = new Date(delegateSignerMessage.expires).getTime() / 1e3;
378
+ return this.cachedDelegateHeaders;
379
+ } catch (error) {
380
+ log2("Error getting delegate headers:", error);
381
+ throw new Error("Failed to get delegate headers");
382
+ }
383
+ }
384
+ async getAuthHeaders(provider, payload) {
385
+ log2("Getting auth headers", JSON.stringify(payload, null, 2));
386
+ const xTimestamp = (/* @__PURE__ */ new Date()).toISOString();
387
+ const headers = {
388
+ [HEADER_TIMESTAMP]: xTimestamp
389
+ };
390
+ const signatureType = this.config.authSignatureType;
391
+ switch (signatureType) {
392
+ case "RAW" /* Raw */:
393
+ log2("Generating auth header raw signature");
394
+ headers[HEADER_SIGNATURE] = await this.signAuthHeaderRawMessage(
395
+ provider,
396
+ payload,
397
+ xTimestamp
398
+ );
399
+ break;
400
+ case "EIP712" /* EIP712 */:
401
+ log2("Generating auth headerEIP712 signature");
402
+ headers[HEADER_EIP712_SIGNATURE] = await this.signAuthHeaderTypedData(
403
+ provider,
404
+ payload,
405
+ xTimestamp
406
+ );
407
+ break;
408
+ default:
409
+ throw new Error(`Unsupported signature type: ${signatureType}`);
410
+ }
411
+ log2("Auth headers:", JSON.stringify(headers, null, 2));
412
+ return headers;
413
+ }
414
+ async signAuthHeaderRawMessage(provider, payload, timestamp) {
415
+ const xMessage = this.prepareSignatureMessage(payload, timestamp);
416
+ const delegateSigner = await this.getDelegateSigner(this);
417
+ const signer = delegateSigner ?? provider.signer;
418
+ const signature = await this.signMessage(signer, xMessage);
419
+ log2("Message signed. Signature:", signature);
420
+ return signature;
421
+ }
422
+ async signAuthHeaderTypedData(provider, payload, timestamp) {
423
+ const message = this.prepareSignatureTypedData(payload, timestamp);
424
+ const types = getAuthEIP721Types(payload);
425
+ const delegateSigner = await this.getDelegateSigner(this);
426
+ const signer = delegateSigner ?? provider.signer;
427
+ log2(
428
+ "Signing typed data",
429
+ JSON.stringify({ message, types, eip721Domain }, null, 2)
430
+ );
431
+ const signature = await this.signTypedData(
432
+ signer,
433
+ eip721Domain,
434
+ types,
435
+ message
436
+ );
437
+ log2("Message signed. Signature:", signature);
438
+ return signature;
439
+ }
440
+ /**
441
+ * Signs a message using the provided signer.
442
+ * This method can be overridden to customize the signing process.
443
+ * @param signer - The signer to use
444
+ * @param message - The message to sign
445
+ * @returns A promise that resolves to the signature string
446
+ */
447
+ async signMessage(signer, message) {
448
+ return signer.signMessage(message);
449
+ }
450
+ /**
451
+ * Signs typed data using the provided signer.
452
+ * This method can be overridden to customize the signing process.
453
+ * @param signer - The signer to use
454
+ * @param domain - The EIP-712 domain
455
+ * @param types - The EIP-712 types
456
+ * @param message - The message to sign
457
+ * @returns A promise that resolves to the signature string
458
+ */
459
+ async signTypedData(signer, domain, types, message) {
460
+ return signer.signTypedData(domain, types, message);
461
+ }
462
+ setContract(contract, contractMethodsToSign) {
463
+ log2("Setting contract and methods to sign: ", contractMethodsToSign);
464
+ this.contract = contract;
465
+ this.contractMethodsToSign = contractMethodsToSign;
466
+ }
467
+ /**
468
+ * Prepares the message to be signed for the x-signature header.
469
+ */
470
+ prepareSignatureMessage(payload, timestamp) {
471
+ log2("Preparing raw message for signing", {
472
+ payload: JSON.stringify(payload, null, 2),
473
+ timestamp
474
+ });
475
+ const serialRequest = JSON.stringify(payload);
476
+ const xMessage = serialRequest + timestamp;
477
+ log2("Raw message to be signed:", xMessage);
478
+ return xMessage;
479
+ }
480
+ /**
481
+ * Prepares the message to be signed for the x-eip712-signature header.
482
+ */
483
+ prepareSignatureTypedData(payload, timestamp) {
484
+ log2("Preparing payload for signTypedData");
485
+ const preparedPayload = Array.isArray(payload) ? payload.map(prepareTypedDataPayload) : prepareTypedDataPayload(payload);
486
+ const message = {
487
+ request: preparedPayload,
488
+ timestamp
489
+ };
490
+ log2("Prepared payload for signTypedData", JSON.stringify(message, null, 2));
491
+ return message;
492
+ }
493
+ };
494
+
495
+ // src/contract.ts
496
+ import {
497
+ Contract as Contract2,
498
+ Interface
499
+ } from "ethers";
500
+ var CustomContractRunner = class {
501
+ constructor(signer) {
502
+ this.provider = signer.provider;
503
+ this.signer = signer;
504
+ }
505
+ async sendTransaction(tx) {
506
+ tx.nonce = await this.signer.getNonce();
507
+ return this.signer.sendTransaction(tx);
508
+ }
509
+ };
510
+ var SilentDataRollupContract = class extends Contract2 {
511
+ constructor(address, abi, runner, contractMethodsToSign) {
512
+ const contractInterface = new Interface(abi);
513
+ contractMethodsToSign.forEach((method) => {
514
+ if (!contractInterface.hasFunction(method)) {
515
+ throw new Error(
516
+ `Method to sign '${method}' not found in the contract ABI`
517
+ );
518
+ }
519
+ });
520
+ const baseProvider = runner.baseProvider || runner.provider?.baseProvider;
521
+ const runnerIsSigner = typeof runner.sendTransaction === "function";
522
+ if (runnerIsSigner) {
523
+ runner = new CustomContractRunner(runner);
524
+ }
525
+ super(address, abi, runner);
526
+ if (typeof baseProvider?.setContract === "function") {
527
+ baseProvider.setContract(this, contractMethodsToSign);
528
+ }
529
+ }
530
+ };
531
+
532
+ export {
533
+ SIGN_RPC_METHODS,
534
+ eip721Domain,
535
+ delegateEIP721Types,
536
+ DEBUG_NAMESPACE,
537
+ DEBUG_NAMESPACE_SILENTDATA_INTERCEPTOR,
538
+ HEADER_SIGNATURE,
539
+ HEADER_TIMESTAMP,
540
+ HEADER_EIP712_SIGNATURE,
541
+ HEADER_DELEGATE,
542
+ HEADER_DELEGATE_SIGNATURE,
543
+ HEADER_EIP712_DELEGATE_SIGNATURE,
544
+ DEFAULT_DELEGATE_EXPIRES,
545
+ DELEGATE_EXPIRATION_THRESHOLD_BUFFER,
546
+ WHITELISTED_METHODS,
547
+ ChainId,
548
+ NetworkName,
549
+ SignatureType,
550
+ getAuthEIP721Types,
551
+ signAuthHeaderTypedData,
552
+ signAuthHeaderRawMessage,
553
+ signTypedDelegateHeader,
554
+ signRawDelegateHeader,
555
+ getAuthHeaders,
556
+ isSignableContractCall,
557
+ defaultGetDelegate,
558
+ prepareTypedDataPayload,
559
+ SilentDataRollupBase,
560
+ SilentDataRollupContract
561
+ };