@appliedblockchain/silentdatarollup-ethers-provider 1.0.9 → 1.0.10
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/dist/index.d.mts +11 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.js +163 -41
- package/dist/index.mjs +163 -41
- package/package.json +2 -2
package/dist/index.d.mts
CHANGED
|
@@ -5,6 +5,8 @@ declare const DEBUG_NAMESPACE = "silentdata:ethers-provider";
|
|
|
5
5
|
|
|
6
6
|
interface SilentDataRollupProviderConfig extends BaseConfig {
|
|
7
7
|
rpcUrl: string;
|
|
8
|
+
l1RpcUrl?: string;
|
|
9
|
+
registryContract?: string;
|
|
8
10
|
network?: NetworkName;
|
|
9
11
|
chainId?: number;
|
|
10
12
|
privateKey?: string;
|
|
@@ -42,6 +44,15 @@ declare class SilentDataRollupProvider extends JsonRpcProvider {
|
|
|
42
44
|
private baseProvider;
|
|
43
45
|
constructor(config: SilentDataRollupProviderConfig);
|
|
44
46
|
_send(payload: JsonRpcPayload | Array<JsonRpcPayload>): Promise<Array<JsonRpcResult>>;
|
|
47
|
+
private _isRegistryContractSet;
|
|
48
|
+
private _isNodeRuntime;
|
|
49
|
+
/**
|
|
50
|
+
* Get authentication headers if required for the given payload.
|
|
51
|
+
* Returns null if no auth headers are needed.
|
|
52
|
+
*/
|
|
53
|
+
private _getAuthHeaders;
|
|
54
|
+
private _sendWithoutAttestation;
|
|
55
|
+
private _sendWithPinnedTlsAndAttest;
|
|
45
56
|
static getRequest({ rpcUrl }: {
|
|
46
57
|
rpcUrl: string;
|
|
47
58
|
}): FetchRequest;
|
package/dist/index.d.ts
CHANGED
|
@@ -5,6 +5,8 @@ declare const DEBUG_NAMESPACE = "silentdata:ethers-provider";
|
|
|
5
5
|
|
|
6
6
|
interface SilentDataRollupProviderConfig extends BaseConfig {
|
|
7
7
|
rpcUrl: string;
|
|
8
|
+
l1RpcUrl?: string;
|
|
9
|
+
registryContract?: string;
|
|
8
10
|
network?: NetworkName;
|
|
9
11
|
chainId?: number;
|
|
10
12
|
privateKey?: string;
|
|
@@ -42,6 +44,15 @@ declare class SilentDataRollupProvider extends JsonRpcProvider {
|
|
|
42
44
|
private baseProvider;
|
|
43
45
|
constructor(config: SilentDataRollupProviderConfig);
|
|
44
46
|
_send(payload: JsonRpcPayload | Array<JsonRpcPayload>): Promise<Array<JsonRpcResult>>;
|
|
47
|
+
private _isRegistryContractSet;
|
|
48
|
+
private _isNodeRuntime;
|
|
49
|
+
/**
|
|
50
|
+
* Get authentication headers if required for the given payload.
|
|
51
|
+
* Returns null if no auth headers are needed.
|
|
52
|
+
*/
|
|
53
|
+
private _getAuthHeaders;
|
|
54
|
+
private _sendWithoutAttestation;
|
|
55
|
+
private _sendWithPinnedTlsAndAttest;
|
|
45
56
|
static getRequest({ rpcUrl }: {
|
|
46
57
|
rpcUrl: string;
|
|
47
58
|
}): FetchRequest;
|
package/dist/index.js
CHANGED
|
@@ -90,6 +90,7 @@ var SilentDataRollupSigner = class extends import_ethers.AbstractSigner {
|
|
|
90
90
|
};
|
|
91
91
|
|
|
92
92
|
// src/provider.ts
|
|
93
|
+
var import_silentdatarollup_core2 = require("@appliedblockchain/silentdatarollup-core");
|
|
93
94
|
var log = (0, import_debug.default)(import_silentdatarollup_core.DEBUG_NAMESPACE);
|
|
94
95
|
function isPromise(value) {
|
|
95
96
|
return value && typeof value.then === "function";
|
|
@@ -168,51 +169,78 @@ var SilentDataRollupProvider = class _SilentDataRollupProvider extends import_et
|
|
|
168
169
|
}
|
|
169
170
|
}
|
|
170
171
|
}
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
172
|
+
if (!this._isNodeRuntime() || !this._isRegistryContractSet()) {
|
|
173
|
+
return await this._sendWithoutAttestation(payload, isPrivateLogsRequest);
|
|
174
|
+
}
|
|
175
|
+
return await this._sendWithPinnedTlsAndAttest(payload, isPrivateLogsRequest);
|
|
176
|
+
}
|
|
177
|
+
_isRegistryContractSet() {
|
|
178
|
+
return Boolean(this.config.l1RpcUrl) && Boolean(this.config.registryContract);
|
|
179
|
+
}
|
|
180
|
+
_isNodeRuntime() {
|
|
181
|
+
return typeof process !== "undefined" && typeof process.versions === "object" && typeof process.versions.node === "string";
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* Get authentication headers if required for the given payload.
|
|
185
|
+
* Returns null if no auth headers are needed.
|
|
186
|
+
*/
|
|
187
|
+
async _getAuthHeaders(payload, isPrivateLogsRequest) {
|
|
174
188
|
const requiresAuthHeaders = isPrivateLogsRequest || import_silentdatarollup_core.SIGN_RPC_METHODS.includes(payload.method) || (0, import_silentdatarollup_core.isSignableContractCall)(payload, this.baseProvider.contracts) || this.config.alwaysSignEthCalls && payload.method === "eth_call";
|
|
175
|
-
if (requiresAuthHeaders) {
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
[import_silentdatarollup_core.HEADER_EIP712_DELEGATE_SIGNATURE]: xEip712DelegateSignature
|
|
181
|
-
} = await this.baseProvider.getDelegateHeaders(this);
|
|
182
|
-
request.setHeader(import_silentdatarollup_core.HEADER_DELEGATE, xDelegate);
|
|
183
|
-
if (xDelegateSignature) {
|
|
184
|
-
request.setHeader(import_silentdatarollup_core.HEADER_DELEGATE_SIGNATURE, xDelegateSignature);
|
|
185
|
-
}
|
|
186
|
-
if (xEip712DelegateSignature) {
|
|
187
|
-
request.setHeader(
|
|
188
|
-
import_silentdatarollup_core.HEADER_EIP712_DELEGATE_SIGNATURE,
|
|
189
|
-
xEip712DelegateSignature
|
|
190
|
-
);
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
if (this.config.smartWalletAddress) {
|
|
194
|
-
log("Setting smart wallet header:", this.config.smartWalletAddress);
|
|
195
|
-
request.setHeader(import_silentdatarollup_core.HEADER_SIGNER_SWC, this.config.smartWalletAddress);
|
|
196
|
-
}
|
|
189
|
+
if (!requiresAuthHeaders) {
|
|
190
|
+
return null;
|
|
191
|
+
}
|
|
192
|
+
const headers = {};
|
|
193
|
+
if (this.config.delegate) {
|
|
197
194
|
const {
|
|
198
|
-
[import_silentdatarollup_core.
|
|
199
|
-
[import_silentdatarollup_core.
|
|
200
|
-
[import_silentdatarollup_core.
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
request.setHeader(import_silentdatarollup_core.HEADER_SIGNATURE, xSignature);
|
|
206
|
-
}
|
|
207
|
-
if (xEip712Signature) {
|
|
208
|
-
request.setHeader(import_silentdatarollup_core.HEADER_EIP712_SIGNATURE, xEip712Signature);
|
|
195
|
+
[import_silentdatarollup_core.HEADER_DELEGATE]: xDelegate,
|
|
196
|
+
[import_silentdatarollup_core.HEADER_DELEGATE_SIGNATURE]: xDelegateSignature,
|
|
197
|
+
[import_silentdatarollup_core.HEADER_EIP712_DELEGATE_SIGNATURE]: xEip712DelegateSignature
|
|
198
|
+
} = await this.baseProvider.getDelegateHeaders(this);
|
|
199
|
+
headers[import_silentdatarollup_core.HEADER_DELEGATE] = xDelegate;
|
|
200
|
+
if (xDelegateSignature) {
|
|
201
|
+
headers[import_silentdatarollup_core.HEADER_DELEGATE_SIGNATURE] = xDelegateSignature;
|
|
209
202
|
}
|
|
210
|
-
if (
|
|
211
|
-
|
|
203
|
+
if (xEip712DelegateSignature) {
|
|
204
|
+
headers[import_silentdatarollup_core.HEADER_EIP712_DELEGATE_SIGNATURE] = xEip712DelegateSignature;
|
|
212
205
|
}
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
206
|
+
}
|
|
207
|
+
if (this.config.smartWalletAddress) {
|
|
208
|
+
log("Setting smart wallet header:", this.config.smartWalletAddress);
|
|
209
|
+
headers[import_silentdatarollup_core.HEADER_SIGNER_SWC] = this.config.smartWalletAddress;
|
|
210
|
+
}
|
|
211
|
+
const {
|
|
212
|
+
[import_silentdatarollup_core.HEADER_TIMESTAMP]: xTimestamp,
|
|
213
|
+
[import_silentdatarollup_core.HEADER_SIGNATURE]: xSignature,
|
|
214
|
+
[import_silentdatarollup_core.HEADER_EIP712_SIGNATURE]: xEip712Signature,
|
|
215
|
+
[import_silentdatarollup_core.HEADER_FROM_BLOCK]: xFromBlock
|
|
216
|
+
} = await this.baseProvider.getAuthHeaders(this, payload);
|
|
217
|
+
headers[import_silentdatarollup_core.HEADER_TIMESTAMP] = xTimestamp;
|
|
218
|
+
if (xSignature) {
|
|
219
|
+
headers[import_silentdatarollup_core.HEADER_SIGNATURE] = xSignature;
|
|
220
|
+
}
|
|
221
|
+
if (xEip712Signature) {
|
|
222
|
+
headers[import_silentdatarollup_core.HEADER_EIP712_SIGNATURE] = xEip712Signature;
|
|
223
|
+
}
|
|
224
|
+
if (xFromBlock) {
|
|
225
|
+
headers[import_silentdatarollup_core.HEADER_FROM_BLOCK] = xFromBlock;
|
|
226
|
+
}
|
|
227
|
+
const signatureType = this.config.authSignatureType ?? import_silentdatarollup_core.SignatureType.EIP191;
|
|
228
|
+
if (signatureType) {
|
|
229
|
+
headers[import_silentdatarollup_core.HEADER_SIGNATURE_TYPE] = signatureType;
|
|
230
|
+
}
|
|
231
|
+
return headers;
|
|
232
|
+
}
|
|
233
|
+
async _sendWithoutAttestation(payload, isPrivateLogsRequest) {
|
|
234
|
+
const request = this._getConnection();
|
|
235
|
+
request.body = JSON.stringify(payload);
|
|
236
|
+
request.setHeader("content-type", "application/json");
|
|
237
|
+
const authHeaders = await this._getAuthHeaders(
|
|
238
|
+
payload,
|
|
239
|
+
isPrivateLogsRequest
|
|
240
|
+
);
|
|
241
|
+
if (authHeaders) {
|
|
242
|
+
for (const [key, value] of Object.entries(authHeaders)) {
|
|
243
|
+
request.setHeader(key, value);
|
|
216
244
|
}
|
|
217
245
|
}
|
|
218
246
|
const response = await request.send();
|
|
@@ -223,6 +251,100 @@ var SilentDataRollupProvider = class _SilentDataRollupProvider extends import_et
|
|
|
223
251
|
}
|
|
224
252
|
return resp;
|
|
225
253
|
}
|
|
254
|
+
async _sendWithPinnedTlsAndAttest(payload, isPrivateLogsRequest) {
|
|
255
|
+
const https = await import(
|
|
256
|
+
/* webpackIgnore: true */
|
|
257
|
+
"https"
|
|
258
|
+
);
|
|
259
|
+
const { URL } = await import(
|
|
260
|
+
/* webpackIgnore: true */
|
|
261
|
+
"url"
|
|
262
|
+
);
|
|
263
|
+
const conn = this._getConnection();
|
|
264
|
+
const rpcUrlStr = conn.url;
|
|
265
|
+
if (!rpcUrlStr) {
|
|
266
|
+
throw new Error("Unable to determine rpcUrl for pinned TLS transport");
|
|
267
|
+
}
|
|
268
|
+
const rpcUrl = new URL(rpcUrlStr);
|
|
269
|
+
let exporterKey = null;
|
|
270
|
+
const doRequest = (method, path, body, headers2 = {}, forcedSocket) => new Promise((resolve, reject) => {
|
|
271
|
+
const req = https.request(
|
|
272
|
+
{
|
|
273
|
+
protocol: rpcUrl.protocol,
|
|
274
|
+
hostname: rpcUrl.hostname,
|
|
275
|
+
port: rpcUrl.port ? Number(rpcUrl.port) : 443,
|
|
276
|
+
path,
|
|
277
|
+
method,
|
|
278
|
+
headers: headers2,
|
|
279
|
+
agent: false,
|
|
280
|
+
createConnection: forcedSocket ? () => forcedSocket : void 0
|
|
281
|
+
},
|
|
282
|
+
(res) => {
|
|
283
|
+
const socket = res.socket;
|
|
284
|
+
const DomainSeparator = "CUSTOM-RPC ATTEST:";
|
|
285
|
+
const DOMAIN_SEPARATOR = Buffer.from(DomainSeparator, "utf8");
|
|
286
|
+
exporterKey = socket.exportKeyingMaterial(
|
|
287
|
+
32,
|
|
288
|
+
"tdx-attestation",
|
|
289
|
+
DOMAIN_SEPARATOR
|
|
290
|
+
);
|
|
291
|
+
const chunks = [];
|
|
292
|
+
res.on(
|
|
293
|
+
"data",
|
|
294
|
+
(d) => chunks.push(Buffer.isBuffer(d) ? d : Buffer.from(d))
|
|
295
|
+
);
|
|
296
|
+
res.on(
|
|
297
|
+
"end",
|
|
298
|
+
() => resolve({
|
|
299
|
+
statusCode: res.statusCode ?? 0,
|
|
300
|
+
body: Buffer.concat(chunks),
|
|
301
|
+
socket
|
|
302
|
+
})
|
|
303
|
+
);
|
|
304
|
+
}
|
|
305
|
+
);
|
|
306
|
+
req.on("error", reject);
|
|
307
|
+
if (body) {
|
|
308
|
+
req.write(body);
|
|
309
|
+
}
|
|
310
|
+
req.end();
|
|
311
|
+
});
|
|
312
|
+
const attest = await doRequest("GET", "/tdx/attest", void 0, {
|
|
313
|
+
connection: "keep-alive"
|
|
314
|
+
});
|
|
315
|
+
if (attest.statusCode < 200 || attest.statusCode >= 300) {
|
|
316
|
+
throw new Error(`/tdx/attest failed: HTTP ${attest.statusCode}`);
|
|
317
|
+
}
|
|
318
|
+
const isValid = await (0, import_silentdatarollup_core2.validateTdxAttestation)(
|
|
319
|
+
attest.body,
|
|
320
|
+
exporterKey,
|
|
321
|
+
this.config.l1RpcUrl,
|
|
322
|
+
this.config.registryContract
|
|
323
|
+
);
|
|
324
|
+
if (!isValid) {
|
|
325
|
+
throw new Error("TDX attestation validation failed");
|
|
326
|
+
}
|
|
327
|
+
const headers = {
|
|
328
|
+
"content-type": "application/json"
|
|
329
|
+
};
|
|
330
|
+
const authHeaders = await this._getAuthHeaders(
|
|
331
|
+
payload,
|
|
332
|
+
isPrivateLogsRequest
|
|
333
|
+
);
|
|
334
|
+
if (authHeaders) {
|
|
335
|
+
Object.assign(headers, authHeaders);
|
|
336
|
+
}
|
|
337
|
+
const rpcBody = Buffer.from(JSON.stringify(payload));
|
|
338
|
+
const rpc = await doRequest("POST", "/", rpcBody, headers, attest.socket);
|
|
339
|
+
if (rpc.statusCode < 200 || rpc.statusCode >= 300) {
|
|
340
|
+
throw new Error(`RPC POST / failed: HTTP ${rpc.statusCode}`);
|
|
341
|
+
}
|
|
342
|
+
let parsed = JSON.parse(rpc.body.toString("utf8"));
|
|
343
|
+
if (!Array.isArray(parsed)) {
|
|
344
|
+
parsed = [parsed];
|
|
345
|
+
}
|
|
346
|
+
return parsed;
|
|
347
|
+
}
|
|
226
348
|
static getRequest({ rpcUrl }) {
|
|
227
349
|
const request = new import_ethers2.FetchRequest(rpcUrl);
|
|
228
350
|
request.allowGzip = true;
|
package/dist/index.mjs
CHANGED
|
@@ -81,6 +81,7 @@ var SilentDataRollupSigner = class extends AbstractSigner {
|
|
|
81
81
|
};
|
|
82
82
|
|
|
83
83
|
// src/provider.ts
|
|
84
|
+
import { validateTdxAttestation } from "@appliedblockchain/silentdatarollup-core";
|
|
84
85
|
var log = debug(DEBUG_NAMESPACE2);
|
|
85
86
|
function isPromise(value) {
|
|
86
87
|
return value && typeof value.then === "function";
|
|
@@ -159,51 +160,78 @@ var SilentDataRollupProvider = class _SilentDataRollupProvider extends JsonRpcPr
|
|
|
159
160
|
}
|
|
160
161
|
}
|
|
161
162
|
}
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
163
|
+
if (!this._isNodeRuntime() || !this._isRegistryContractSet()) {
|
|
164
|
+
return await this._sendWithoutAttestation(payload, isPrivateLogsRequest);
|
|
165
|
+
}
|
|
166
|
+
return await this._sendWithPinnedTlsAndAttest(payload, isPrivateLogsRequest);
|
|
167
|
+
}
|
|
168
|
+
_isRegistryContractSet() {
|
|
169
|
+
return Boolean(this.config.l1RpcUrl) && Boolean(this.config.registryContract);
|
|
170
|
+
}
|
|
171
|
+
_isNodeRuntime() {
|
|
172
|
+
return typeof process !== "undefined" && typeof process.versions === "object" && typeof process.versions.node === "string";
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Get authentication headers if required for the given payload.
|
|
176
|
+
* Returns null if no auth headers are needed.
|
|
177
|
+
*/
|
|
178
|
+
async _getAuthHeaders(payload, isPrivateLogsRequest) {
|
|
165
179
|
const requiresAuthHeaders = isPrivateLogsRequest || SIGN_RPC_METHODS.includes(payload.method) || isSignableContractCall(payload, this.baseProvider.contracts) || this.config.alwaysSignEthCalls && payload.method === "eth_call";
|
|
166
|
-
if (requiresAuthHeaders) {
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
[HEADER_EIP712_DELEGATE_SIGNATURE]: xEip712DelegateSignature
|
|
172
|
-
} = await this.baseProvider.getDelegateHeaders(this);
|
|
173
|
-
request.setHeader(HEADER_DELEGATE, xDelegate);
|
|
174
|
-
if (xDelegateSignature) {
|
|
175
|
-
request.setHeader(HEADER_DELEGATE_SIGNATURE, xDelegateSignature);
|
|
176
|
-
}
|
|
177
|
-
if (xEip712DelegateSignature) {
|
|
178
|
-
request.setHeader(
|
|
179
|
-
HEADER_EIP712_DELEGATE_SIGNATURE,
|
|
180
|
-
xEip712DelegateSignature
|
|
181
|
-
);
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
if (this.config.smartWalletAddress) {
|
|
185
|
-
log("Setting smart wallet header:", this.config.smartWalletAddress);
|
|
186
|
-
request.setHeader(HEADER_SIGNER_SWC, this.config.smartWalletAddress);
|
|
187
|
-
}
|
|
180
|
+
if (!requiresAuthHeaders) {
|
|
181
|
+
return null;
|
|
182
|
+
}
|
|
183
|
+
const headers = {};
|
|
184
|
+
if (this.config.delegate) {
|
|
188
185
|
const {
|
|
189
|
-
[
|
|
190
|
-
[
|
|
191
|
-
[
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
request.setHeader(HEADER_SIGNATURE, xSignature);
|
|
197
|
-
}
|
|
198
|
-
if (xEip712Signature) {
|
|
199
|
-
request.setHeader(HEADER_EIP712_SIGNATURE, xEip712Signature);
|
|
186
|
+
[HEADER_DELEGATE]: xDelegate,
|
|
187
|
+
[HEADER_DELEGATE_SIGNATURE]: xDelegateSignature,
|
|
188
|
+
[HEADER_EIP712_DELEGATE_SIGNATURE]: xEip712DelegateSignature
|
|
189
|
+
} = await this.baseProvider.getDelegateHeaders(this);
|
|
190
|
+
headers[HEADER_DELEGATE] = xDelegate;
|
|
191
|
+
if (xDelegateSignature) {
|
|
192
|
+
headers[HEADER_DELEGATE_SIGNATURE] = xDelegateSignature;
|
|
200
193
|
}
|
|
201
|
-
if (
|
|
202
|
-
|
|
194
|
+
if (xEip712DelegateSignature) {
|
|
195
|
+
headers[HEADER_EIP712_DELEGATE_SIGNATURE] = xEip712DelegateSignature;
|
|
203
196
|
}
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
197
|
+
}
|
|
198
|
+
if (this.config.smartWalletAddress) {
|
|
199
|
+
log("Setting smart wallet header:", this.config.smartWalletAddress);
|
|
200
|
+
headers[HEADER_SIGNER_SWC] = this.config.smartWalletAddress;
|
|
201
|
+
}
|
|
202
|
+
const {
|
|
203
|
+
[HEADER_TIMESTAMP]: xTimestamp,
|
|
204
|
+
[HEADER_SIGNATURE]: xSignature,
|
|
205
|
+
[HEADER_EIP712_SIGNATURE]: xEip712Signature,
|
|
206
|
+
[HEADER_FROM_BLOCK]: xFromBlock
|
|
207
|
+
} = await this.baseProvider.getAuthHeaders(this, payload);
|
|
208
|
+
headers[HEADER_TIMESTAMP] = xTimestamp;
|
|
209
|
+
if (xSignature) {
|
|
210
|
+
headers[HEADER_SIGNATURE] = xSignature;
|
|
211
|
+
}
|
|
212
|
+
if (xEip712Signature) {
|
|
213
|
+
headers[HEADER_EIP712_SIGNATURE] = xEip712Signature;
|
|
214
|
+
}
|
|
215
|
+
if (xFromBlock) {
|
|
216
|
+
headers[HEADER_FROM_BLOCK] = xFromBlock;
|
|
217
|
+
}
|
|
218
|
+
const signatureType = this.config.authSignatureType ?? SignatureType.EIP191;
|
|
219
|
+
if (signatureType) {
|
|
220
|
+
headers[HEADER_SIGNATURE_TYPE] = signatureType;
|
|
221
|
+
}
|
|
222
|
+
return headers;
|
|
223
|
+
}
|
|
224
|
+
async _sendWithoutAttestation(payload, isPrivateLogsRequest) {
|
|
225
|
+
const request = this._getConnection();
|
|
226
|
+
request.body = JSON.stringify(payload);
|
|
227
|
+
request.setHeader("content-type", "application/json");
|
|
228
|
+
const authHeaders = await this._getAuthHeaders(
|
|
229
|
+
payload,
|
|
230
|
+
isPrivateLogsRequest
|
|
231
|
+
);
|
|
232
|
+
if (authHeaders) {
|
|
233
|
+
for (const [key, value] of Object.entries(authHeaders)) {
|
|
234
|
+
request.setHeader(key, value);
|
|
207
235
|
}
|
|
208
236
|
}
|
|
209
237
|
const response = await request.send();
|
|
@@ -214,6 +242,100 @@ var SilentDataRollupProvider = class _SilentDataRollupProvider extends JsonRpcPr
|
|
|
214
242
|
}
|
|
215
243
|
return resp;
|
|
216
244
|
}
|
|
245
|
+
async _sendWithPinnedTlsAndAttest(payload, isPrivateLogsRequest) {
|
|
246
|
+
const https = await import(
|
|
247
|
+
/* webpackIgnore: true */
|
|
248
|
+
"node:https"
|
|
249
|
+
);
|
|
250
|
+
const { URL } = await import(
|
|
251
|
+
/* webpackIgnore: true */
|
|
252
|
+
"node:url"
|
|
253
|
+
);
|
|
254
|
+
const conn = this._getConnection();
|
|
255
|
+
const rpcUrlStr = conn.url;
|
|
256
|
+
if (!rpcUrlStr) {
|
|
257
|
+
throw new Error("Unable to determine rpcUrl for pinned TLS transport");
|
|
258
|
+
}
|
|
259
|
+
const rpcUrl = new URL(rpcUrlStr);
|
|
260
|
+
let exporterKey = null;
|
|
261
|
+
const doRequest = (method, path, body, headers2 = {}, forcedSocket) => new Promise((resolve, reject) => {
|
|
262
|
+
const req = https.request(
|
|
263
|
+
{
|
|
264
|
+
protocol: rpcUrl.protocol,
|
|
265
|
+
hostname: rpcUrl.hostname,
|
|
266
|
+
port: rpcUrl.port ? Number(rpcUrl.port) : 443,
|
|
267
|
+
path,
|
|
268
|
+
method,
|
|
269
|
+
headers: headers2,
|
|
270
|
+
agent: false,
|
|
271
|
+
createConnection: forcedSocket ? () => forcedSocket : void 0
|
|
272
|
+
},
|
|
273
|
+
(res) => {
|
|
274
|
+
const socket = res.socket;
|
|
275
|
+
const DomainSeparator = "CUSTOM-RPC ATTEST:";
|
|
276
|
+
const DOMAIN_SEPARATOR = Buffer.from(DomainSeparator, "utf8");
|
|
277
|
+
exporterKey = socket.exportKeyingMaterial(
|
|
278
|
+
32,
|
|
279
|
+
"tdx-attestation",
|
|
280
|
+
DOMAIN_SEPARATOR
|
|
281
|
+
);
|
|
282
|
+
const chunks = [];
|
|
283
|
+
res.on(
|
|
284
|
+
"data",
|
|
285
|
+
(d) => chunks.push(Buffer.isBuffer(d) ? d : Buffer.from(d))
|
|
286
|
+
);
|
|
287
|
+
res.on(
|
|
288
|
+
"end",
|
|
289
|
+
() => resolve({
|
|
290
|
+
statusCode: res.statusCode ?? 0,
|
|
291
|
+
body: Buffer.concat(chunks),
|
|
292
|
+
socket
|
|
293
|
+
})
|
|
294
|
+
);
|
|
295
|
+
}
|
|
296
|
+
);
|
|
297
|
+
req.on("error", reject);
|
|
298
|
+
if (body) {
|
|
299
|
+
req.write(body);
|
|
300
|
+
}
|
|
301
|
+
req.end();
|
|
302
|
+
});
|
|
303
|
+
const attest = await doRequest("GET", "/tdx/attest", void 0, {
|
|
304
|
+
connection: "keep-alive"
|
|
305
|
+
});
|
|
306
|
+
if (attest.statusCode < 200 || attest.statusCode >= 300) {
|
|
307
|
+
throw new Error(`/tdx/attest failed: HTTP ${attest.statusCode}`);
|
|
308
|
+
}
|
|
309
|
+
const isValid = await validateTdxAttestation(
|
|
310
|
+
attest.body,
|
|
311
|
+
exporterKey,
|
|
312
|
+
this.config.l1RpcUrl,
|
|
313
|
+
this.config.registryContract
|
|
314
|
+
);
|
|
315
|
+
if (!isValid) {
|
|
316
|
+
throw new Error("TDX attestation validation failed");
|
|
317
|
+
}
|
|
318
|
+
const headers = {
|
|
319
|
+
"content-type": "application/json"
|
|
320
|
+
};
|
|
321
|
+
const authHeaders = await this._getAuthHeaders(
|
|
322
|
+
payload,
|
|
323
|
+
isPrivateLogsRequest
|
|
324
|
+
);
|
|
325
|
+
if (authHeaders) {
|
|
326
|
+
Object.assign(headers, authHeaders);
|
|
327
|
+
}
|
|
328
|
+
const rpcBody = Buffer.from(JSON.stringify(payload));
|
|
329
|
+
const rpc = await doRequest("POST", "/", rpcBody, headers, attest.socket);
|
|
330
|
+
if (rpc.statusCode < 200 || rpc.statusCode >= 300) {
|
|
331
|
+
throw new Error(`RPC POST / failed: HTTP ${rpc.statusCode}`);
|
|
332
|
+
}
|
|
333
|
+
let parsed = JSON.parse(rpc.body.toString("utf8"));
|
|
334
|
+
if (!Array.isArray(parsed)) {
|
|
335
|
+
parsed = [parsed];
|
|
336
|
+
}
|
|
337
|
+
return parsed;
|
|
338
|
+
}
|
|
217
339
|
static getRequest({ rpcUrl }) {
|
|
218
340
|
const request = new FetchRequest(rpcUrl);
|
|
219
341
|
request.allowGzip = true;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@appliedblockchain/silentdatarollup-ethers-provider",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.10",
|
|
4
4
|
"description": "Ethers.js provider for Silent Data",
|
|
5
5
|
"author": "Applied Blockchain",
|
|
6
6
|
"homepage": "https://github.com/appliedblockchain/silent-data-rollup-providers#readme",
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
"dependencies": {
|
|
29
29
|
"debug": "4.3.7",
|
|
30
30
|
"ethers": "6.13.2",
|
|
31
|
-
"@appliedblockchain/silentdatarollup-core": "1.0.
|
|
31
|
+
"@appliedblockchain/silentdatarollup-core": "1.0.10"
|
|
32
32
|
},
|
|
33
33
|
"devDependencies": {
|
|
34
34
|
"@types/debug": "4.1.12",
|