@corpus-core/colibri-stateless 1.1.0 → 1.1.2
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 +26 -0
- package/c4w.js +1 -1
- package/c4w.wasm +0 -0
- package/cjs/chains.js +84 -0
- package/cjs/connectionState.js +156 -0
- package/cjs/eventEmitter.js +54 -0
- package/cjs/http.js +172 -0
- package/cjs/index.js +327 -0
- package/cjs/package.json +3 -0
- package/cjs/strategy.js +114 -0
- package/cjs/subscriptionManager.js +314 -0
- package/cjs/transactionVerifier.js +202 -0
- package/cjs/types.js +71 -0
- package/cjs/wasm.js +59 -0
- package/cjs/wasm_cjs.js +59 -0
- package/cjs/wasm_shared.js +187 -0
- package/index.d.ts +1 -0
- package/index.js +2 -0
- package/package.json +9 -5
- package/wasm.d.ts +8 -52
- package/wasm.js +27 -152
- package/wasm_cjs.d.ts +30 -0
- package/wasm_cjs.js +52 -0
- package/wasm_shared.d.ts +67 -0
- package/wasm_shared.js +177 -0
package/cjs/index.js
ADDED
|
@@ -0,0 +1,327 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Copyright (c) 2025 corpus.core
|
|
4
|
+
*
|
|
5
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
6
|
+
* this software and associated documentation files (the "Software"), to deal in
|
|
7
|
+
* the Software without restriction, including without limitation the rights to
|
|
8
|
+
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
|
9
|
+
* the Software, and to permit persons to whom the Software is furnished to do so,
|
|
10
|
+
* subject to the following conditions:
|
|
11
|
+
*
|
|
12
|
+
* The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
* copies or substantial portions of the Software.
|
|
14
|
+
*
|
|
15
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
|
17
|
+
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
|
18
|
+
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
|
19
|
+
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
20
|
+
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
21
|
+
*
|
|
22
|
+
* SPDX-License-Identifier: MIT
|
|
23
|
+
*/
|
|
24
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
25
|
+
exports.PrototypeProtection = exports.TransactionVerifier = exports.MethodType = exports.ProviderRpcError = exports.set_wasm_url = exports.Strategy = void 0;
|
|
26
|
+
// Import the Emscripten-generated module
|
|
27
|
+
const wasm_js_1 = require("./wasm.js");
|
|
28
|
+
const eventEmitter_js_1 = require("./eventEmitter.js");
|
|
29
|
+
const connectionState_js_1 = require("./connectionState.js");
|
|
30
|
+
const types_js_1 = require("./types.js");
|
|
31
|
+
Object.defineProperty(exports, "ProviderRpcError", { enumerable: true, get: function () { return types_js_1.ProviderRpcError; } });
|
|
32
|
+
Object.defineProperty(exports, "MethodType", { enumerable: true, get: function () { return types_js_1.MethodType; } });
|
|
33
|
+
const chains_js_1 = require("./chains.js");
|
|
34
|
+
const subscriptionManager_js_1 = require("./subscriptionManager.js");
|
|
35
|
+
const strategy_js_1 = require("./strategy.js");
|
|
36
|
+
exports.Strategy = strategy_js_1.default;
|
|
37
|
+
const transactionVerifier_js_1 = require("./transactionVerifier.js");
|
|
38
|
+
const http_js_1 = require("./http.js");
|
|
39
|
+
// Public helper for controlling WASM loading behavior in Node/bundlers.
|
|
40
|
+
var wasm_js_2 = require("./wasm.js");
|
|
41
|
+
Object.defineProperty(exports, "set_wasm_url", { enumerable: true, get: function () { return wasm_js_2.set_wasm_url; } });
|
|
42
|
+
// Re-export transaction verification utilities
|
|
43
|
+
var transactionVerifier_js_2 = require("./transactionVerifier.js");
|
|
44
|
+
Object.defineProperty(exports, "TransactionVerifier", { enumerable: true, get: function () { return transactionVerifier_js_2.TransactionVerifier; } });
|
|
45
|
+
Object.defineProperty(exports, "PrototypeProtection", { enumerable: true, get: function () { return transactionVerifier_js_2.PrototypeProtection; } });
|
|
46
|
+
// fetch_rpc und handle_request sind nach http.ts verschoben
|
|
47
|
+
// default_config, get_chain_id, chain_conf ausgelagert nach ./chains.ts
|
|
48
|
+
function cleanup_args(method, args) {
|
|
49
|
+
if (method == "eth_verifyLogs")
|
|
50
|
+
return args.map(arg => ({
|
|
51
|
+
transactionIndex: arg.transactionIndex,
|
|
52
|
+
blockNumber: arg.blockNumber
|
|
53
|
+
}));
|
|
54
|
+
return args;
|
|
55
|
+
}
|
|
56
|
+
class C4Client {
|
|
57
|
+
config;
|
|
58
|
+
eventEmitter;
|
|
59
|
+
connectionState;
|
|
60
|
+
subscriptionManager;
|
|
61
|
+
initMap = new Map();
|
|
62
|
+
flags = 0;
|
|
63
|
+
// Protect against prototype pollution by freezing critical methods
|
|
64
|
+
static CRITICAL_METHODS = ['rpc', 'request', 'verifyProof', 'createProof'];
|
|
65
|
+
static {
|
|
66
|
+
// Apply prototype pollution protection
|
|
67
|
+
transactionVerifier_js_1.PrototypeProtection.protectClass(C4Client, C4Client.CRITICAL_METHODS);
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Creates a new Colibri client instance.
|
|
71
|
+
*
|
|
72
|
+
* Example:
|
|
73
|
+
* ```ts
|
|
74
|
+
* import Colibri from '@corpus-core/colibri-stateless';
|
|
75
|
+
* const client = new Colibri({ chainId: 1 });
|
|
76
|
+
* const blockNumber = await client.request({ method: 'eth_blockNumber' });
|
|
77
|
+
* ```
|
|
78
|
+
*
|
|
79
|
+
* @param config Optional partial configuration; user config overrides defaults.
|
|
80
|
+
*/
|
|
81
|
+
constructor(config) {
|
|
82
|
+
const chainId = config?.chainId ? (0, chains_js_1.get_chain_id)(config?.chainId + '') : 1;
|
|
83
|
+
const chain_config = { ...chains_js_1.default_config[chainId + ''] };
|
|
84
|
+
// Protect against config manipulation (deep-freeze at sensitive boundaries)
|
|
85
|
+
const baseConfig = {
|
|
86
|
+
chains: {},
|
|
87
|
+
trusted_checkpoint: undefined,
|
|
88
|
+
rpcs: chain_config.rpcs || [],
|
|
89
|
+
beacon_apis: chain_config.beacon_apis || [],
|
|
90
|
+
prover: chain_config.prover || [],
|
|
91
|
+
checkpointz: chain_config.checkpointz || [],
|
|
92
|
+
...config, // User config overrides defaults
|
|
93
|
+
chainId,
|
|
94
|
+
};
|
|
95
|
+
// Apply config immutability/protection
|
|
96
|
+
transactionVerifier_js_1.PrototypeProtection.protectConfig(baseConfig, ['rpcs', 'beacon_apis', 'prover', 'checkpointz']);
|
|
97
|
+
this.config = baseConfig;
|
|
98
|
+
if (!this.config.warningHandler)
|
|
99
|
+
this.config.warningHandler = async (req, message) => console.warn(message);
|
|
100
|
+
if (!this.config.proofStrategy)
|
|
101
|
+
this.config.proofStrategy = strategy_js_1.default.VerifyIfPossible;
|
|
102
|
+
this.eventEmitter = new eventEmitter_js_1.EventEmitter();
|
|
103
|
+
this.connectionState = new connectionState_js_1.ConnectionState({ chainId: parseInt(this.config.chainId + ''), debug: this.config.debug }, async () => this.rpc('eth_chainId', [], types_js_1.MethodType.LOCAL), // specific callback to detect chainId
|
|
104
|
+
this.eventEmitter);
|
|
105
|
+
this.subscriptionManager = new subscriptionManager_js_1.SubscriptionManager(async (method, params) => this.rpc(method, params), this.eventEmitter, {
|
|
106
|
+
debug: this.config.debug,
|
|
107
|
+
pollingInterval: this.config.pollingInterval || (0, chains_js_1.chain_conf)(this.config, this.config.chainId)?.pollingInterval || 12000
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
// Prover config helpers are moved to wasm.ts (get_prover_config_hex)
|
|
111
|
+
async fetch_checkpointz() {
|
|
112
|
+
let checkpoint = undefined;
|
|
113
|
+
for (const url of [...(this.config.checkpointz || []), ...(this.config.beacon_apis || []), ...(this.config.prover || [])]) {
|
|
114
|
+
const response = await fetch(url + (url.endsWith('/') ? '' : '/') + 'eth/v1/beacon/states/head/finality_checkpoints', {
|
|
115
|
+
method: 'GET',
|
|
116
|
+
headers: {
|
|
117
|
+
"Content-Type": "application/json"
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
if (response.ok) {
|
|
121
|
+
const res = await response.json();
|
|
122
|
+
checkpoint = res?.data?.finalized?.root;
|
|
123
|
+
if (checkpoint)
|
|
124
|
+
break;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
if (!checkpoint)
|
|
128
|
+
throw new Error('No checkpoint found');
|
|
129
|
+
this.config.trusted_checkpoint = checkpoint;
|
|
130
|
+
// set trusted checkpoint in C state so we can use it in proof calls immediately
|
|
131
|
+
await (0, wasm_js_1.set_trusted_checkpoint)(this.config.chainId, checkpoint);
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Checks whether the RPC method is supported or proofable.
|
|
135
|
+
* @param method - The method to check
|
|
136
|
+
* @returns The method type
|
|
137
|
+
*/
|
|
138
|
+
async getMethodSupport(method) {
|
|
139
|
+
const c4w = await (0, wasm_js_1.getC4w)();
|
|
140
|
+
const free_buffers = [];
|
|
141
|
+
const method_type = c4w._c4w_get_method_type(BigInt(this.config.chainId), (0, wasm_js_1.as_char_ptr)(method, c4w, free_buffers));
|
|
142
|
+
free_buffers.forEach(ptr => c4w._free(ptr));
|
|
143
|
+
return method_type;
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Creates a proof for the given method and arguments.
|
|
147
|
+
* @param method - The method to create a proof for
|
|
148
|
+
* @param args - The arguments to create a proof for
|
|
149
|
+
* @returns The proof
|
|
150
|
+
*/
|
|
151
|
+
async createProof(method, args) {
|
|
152
|
+
const c4w = await (0, wasm_js_1.getC4w)();
|
|
153
|
+
const free_buffers = [];
|
|
154
|
+
let ctx = 0;
|
|
155
|
+
try {
|
|
156
|
+
// Call the C function
|
|
157
|
+
ctx = c4w._c4w_create_proof_ctx((0, wasm_js_1.as_char_ptr)(method, c4w, free_buffers), (0, wasm_js_1.as_char_ptr)(JSON.stringify(args), c4w, free_buffers), BigInt(this.config.chainId), this.flags);
|
|
158
|
+
while (true) {
|
|
159
|
+
const state = (0, wasm_js_1.as_json)(c4w._c4w_execute_proof_ctx(ctx), c4w, true);
|
|
160
|
+
switch (state.status) {
|
|
161
|
+
case "success":
|
|
162
|
+
return (0, wasm_js_1.as_bytes)(state.result, state.result_len, c4w);
|
|
163
|
+
case "error":
|
|
164
|
+
throw new Error(state.error);
|
|
165
|
+
case "waiting": {
|
|
166
|
+
await Promise.all(state.requests.map((req) => (0, http_js_1.handle_request)(req, this.config)));
|
|
167
|
+
break;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
finally {
|
|
173
|
+
free_buffers.forEach(ptr => c4w._free(ptr));
|
|
174
|
+
if (ctx)
|
|
175
|
+
c4w._c4w_free_proof_ctx(ctx);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Verifies a proof for the given method and arguments.
|
|
180
|
+
* @param method - The method to verify the proof for
|
|
181
|
+
* @param args - The arguments to verify the proof for
|
|
182
|
+
* @param proof - The proof to verify
|
|
183
|
+
* @returns The result
|
|
184
|
+
*/
|
|
185
|
+
async verifyProof(method, args, proof) {
|
|
186
|
+
const c4w = await (0, wasm_js_1.getC4w)();
|
|
187
|
+
const free_buffers = [];
|
|
188
|
+
let ctx = 0;
|
|
189
|
+
try {
|
|
190
|
+
// Call the C function
|
|
191
|
+
const checkpoint_ptr = this.config.trusted_checkpoint
|
|
192
|
+
? (0, wasm_js_1.as_char_ptr)(this.config.trusted_checkpoint, c4w, free_buffers)
|
|
193
|
+
: 0;
|
|
194
|
+
const witness_keys_ptr = this.config.checkpoint_witness_keys
|
|
195
|
+
? (0, wasm_js_1.as_char_ptr)(this.config.checkpoint_witness_keys, c4w, free_buffers)
|
|
196
|
+
: 0;
|
|
197
|
+
ctx = c4w._c4w_create_verify_ctx((0, wasm_js_1.copy_to_c)(proof, c4w, free_buffers), proof.length, (0, wasm_js_1.as_char_ptr)(method, c4w, free_buffers), (0, wasm_js_1.as_char_ptr)(JSON.stringify(args), c4w, free_buffers), BigInt(this.config.chainId), checkpoint_ptr, witness_keys_ptr);
|
|
198
|
+
while (true) {
|
|
199
|
+
const state = (0, wasm_js_1.as_json)(c4w._c4w_verify_proof(ctx), c4w, true);
|
|
200
|
+
switch (state.status) {
|
|
201
|
+
case "success":
|
|
202
|
+
return state.result;
|
|
203
|
+
case "error":
|
|
204
|
+
throw new Error(state.error);
|
|
205
|
+
case "waiting": {
|
|
206
|
+
await Promise.all(state.requests.map((req) => (0, http_js_1.handle_request)(req, this.config)));
|
|
207
|
+
break;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
finally {
|
|
213
|
+
free_buffers.forEach(ptr => c4w._free(ptr));
|
|
214
|
+
if (ctx)
|
|
215
|
+
c4w._c4w_free_verify_ctx(ctx);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Executes an RPC method. This includes:
|
|
220
|
+
* - Creating or fetching the proof
|
|
221
|
+
* - Verifying the proof
|
|
222
|
+
* - Returning the result
|
|
223
|
+
* @param method - The method to execute
|
|
224
|
+
* @param args - The arguments to execute the method with
|
|
225
|
+
* @returns The result
|
|
226
|
+
*/
|
|
227
|
+
async rpc(method, args, method_type) {
|
|
228
|
+
// eth_subscribe and eth_unsubscribe are handled by C4Client.request before this method is called.
|
|
229
|
+
// This rpc method is for the underlying data fetching/proving.
|
|
230
|
+
if (!this.initMap.get(this.config.chainId)) {
|
|
231
|
+
this.initMap.set(this.config.chainId, true);
|
|
232
|
+
if (!this.config.zk_proof && this.config.checkpointz && this.config.checkpointz.length > 0 && !this.config.trusted_checkpoint && (await (0, wasm_js_1.get_prover_config_hex)(this.config.chainId)).length == 2)
|
|
233
|
+
await this.fetch_checkpointz();
|
|
234
|
+
}
|
|
235
|
+
// Special handling for eth_sendTransaction with verification
|
|
236
|
+
if (method === 'eth_sendTransaction' && this.config.verifyTransactions) {
|
|
237
|
+
return await transactionVerifier_js_1.TransactionVerifier.verifyAndSendTransaction(args[0], this.config, (method, args, methodType) => this.rpc(method, args, methodType), http_js_1.fetch_rpc);
|
|
238
|
+
}
|
|
239
|
+
if (method_type === undefined)
|
|
240
|
+
method_type = await this.getMethodSupport(method);
|
|
241
|
+
switch (method_type) {
|
|
242
|
+
case types_js_1.MethodType.PROOFABLE: {
|
|
243
|
+
if (this.config.verify && !this.config.verify(method, args)) {
|
|
244
|
+
// skip verification and fetch directly
|
|
245
|
+
return await (0, http_js_1.fetch_rpc)(this.config.rpcs, { method, params: args }, false);
|
|
246
|
+
}
|
|
247
|
+
const proof = this.config.prover && this.config.prover.length
|
|
248
|
+
? await (0, http_js_1.fetch_rpc)(this.config.prover, {
|
|
249
|
+
method,
|
|
250
|
+
params: cleanup_args(method, args),
|
|
251
|
+
c4: await (0, wasm_js_1.get_prover_config_hex)(this.config.chainId),
|
|
252
|
+
zk_proof: !!this.config.zk_proof,
|
|
253
|
+
signers: this.config.checkpoint_witness_keys || '0x'
|
|
254
|
+
}, true)
|
|
255
|
+
: await this.createProof(method, args);
|
|
256
|
+
return this.verifyProof(method, args, proof);
|
|
257
|
+
}
|
|
258
|
+
case types_js_1.MethodType.UNPROOFABLE:
|
|
259
|
+
return await (0, http_js_1.fetch_rpc)(this.config.rpcs, { method, params: args }, false);
|
|
260
|
+
case types_js_1.MethodType.NOT_SUPPORTED:
|
|
261
|
+
throw new types_js_1.ProviderRpcError(4200, `Method ${method} is not supported by C4Client.rpc core`);
|
|
262
|
+
case types_js_1.MethodType.LOCAL:
|
|
263
|
+
return this.verifyProof(method, args, new Uint8Array());
|
|
264
|
+
}
|
|
265
|
+
// Should be unreachable if MethodType enum is comprehensive and handled
|
|
266
|
+
throw new types_js_1.ProviderRpcError(-32603, `Internal error: Unhandled method type for ${method} in C4Client.rpc core`);
|
|
267
|
+
}
|
|
268
|
+
static async register_storage(storage) {
|
|
269
|
+
const c4w = await (0, wasm_js_1.getC4w)();
|
|
270
|
+
c4w.storage = storage;
|
|
271
|
+
}
|
|
272
|
+
async request(args) {
|
|
273
|
+
if (!this.connectionState.initialConnectionAttempted) {
|
|
274
|
+
await this.connectionState.attemptInitialConnection();
|
|
275
|
+
}
|
|
276
|
+
const { method, params } = args;
|
|
277
|
+
const paramsArray = Array.isArray(params) ? params : (params ? [params] : []);
|
|
278
|
+
// Attempt to handle with SubscriptionManager first
|
|
279
|
+
const subscriptionResult = this.subscriptionManager.handleRequest(method, paramsArray);
|
|
280
|
+
if (subscriptionResult !== null) {
|
|
281
|
+
// If handleRequest returns a Promise, it means it's handling the request
|
|
282
|
+
return subscriptionResult;
|
|
283
|
+
}
|
|
284
|
+
let conf = (0, chains_js_1.chain_conf)(this.config, this.config.chainId);
|
|
285
|
+
let strategy = conf?.proofStrategy || this.config.proofStrategy;
|
|
286
|
+
// If not handled by SubscriptionManager, proceed with standard RPC call logic
|
|
287
|
+
try {
|
|
288
|
+
const result = strategy
|
|
289
|
+
? await strategy(this, args, this.config, http_js_1.fetch_rpc)
|
|
290
|
+
: await this.rpc(method, paramsArray);
|
|
291
|
+
this.connectionState.processSuccessfulRequest(method, result);
|
|
292
|
+
return result;
|
|
293
|
+
}
|
|
294
|
+
catch (error) {
|
|
295
|
+
const providerError = types_js_1.ProviderRpcError.createError(error, args);
|
|
296
|
+
this.connectionState.processFailedRequest(providerError);
|
|
297
|
+
throw providerError;
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
/**
|
|
301
|
+
* Registers an event listener on the Colibri client.
|
|
302
|
+
* @param event Event name (e.g. 'connect', 'disconnect', 'message')
|
|
303
|
+
* @param callback Callback invoked with event data
|
|
304
|
+
* @return This client for chaining
|
|
305
|
+
*/
|
|
306
|
+
on(event, callback) {
|
|
307
|
+
this.eventEmitter.on(event, callback);
|
|
308
|
+
if ((event === 'connect' || event === 'disconnect') && !this.connectionState.initialConnectionAttempted) {
|
|
309
|
+
this.connectionState.attemptInitialConnection().catch(err => {
|
|
310
|
+
if (this.config.debug)
|
|
311
|
+
console.error("[C4Client] Error during lazy initial connection attempt triggered by 'on':", err);
|
|
312
|
+
});
|
|
313
|
+
}
|
|
314
|
+
return this;
|
|
315
|
+
}
|
|
316
|
+
/**
|
|
317
|
+
* Removes a previously registered event listener from the Colibri client.
|
|
318
|
+
* @param event Event name
|
|
319
|
+
* @param callback Same function reference passed to on()
|
|
320
|
+
* @return This client for chaining
|
|
321
|
+
*/
|
|
322
|
+
removeListener(event, callback) {
|
|
323
|
+
this.eventEmitter.removeListener(event, callback);
|
|
324
|
+
return this;
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
exports.default = C4Client;
|
package/cjs/package.json
ADDED
package/cjs/strategy.js
ADDED
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Copyright (c) 2025 corpus.core
|
|
4
|
+
*
|
|
5
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
6
|
+
* this software and associated documentation files (the "Software"), to deal in
|
|
7
|
+
* the Software without restriction, including without limitation the rights to
|
|
8
|
+
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
|
9
|
+
* the Software, and to permit persons to whom the Software is furnished to do so,
|
|
10
|
+
* subject to the following conditions:
|
|
11
|
+
*
|
|
12
|
+
* The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
* copies or substantial portions of the Software.
|
|
14
|
+
*
|
|
15
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
|
17
|
+
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
|
18
|
+
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
|
19
|
+
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
20
|
+
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
21
|
+
*
|
|
22
|
+
* SPDX-License-Identifier: MIT
|
|
23
|
+
*/
|
|
24
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
25
|
+
const types_js_1 = require("./types.js");
|
|
26
|
+
function argsToArray(args) {
|
|
27
|
+
return Array.isArray(args) ? args : (args ? [args] : []);
|
|
28
|
+
}
|
|
29
|
+
function deepEqual(a, b) {
|
|
30
|
+
if (a === b)
|
|
31
|
+
return true;
|
|
32
|
+
if (a === null || b === null)
|
|
33
|
+
return false;
|
|
34
|
+
if (a.constructor !== b.constructor)
|
|
35
|
+
return false;
|
|
36
|
+
if (a instanceof Date)
|
|
37
|
+
return a.getTime() === b.getTime();
|
|
38
|
+
if (a instanceof RegExp)
|
|
39
|
+
return a.source === b.source && a.flags === b.flags;
|
|
40
|
+
if (a instanceof Uint8Array)
|
|
41
|
+
return a.length === b.length && a.every((value, index) => value === b[index]);
|
|
42
|
+
if (a instanceof Array)
|
|
43
|
+
return a.length === b.length && a.every((value, index) => deepEqual(value, b[index]));
|
|
44
|
+
if (a instanceof Object)
|
|
45
|
+
return Object.keys(a).every(key => b[key] === undefined || deepEqual(a[key], b[key]));
|
|
46
|
+
if (a instanceof String)
|
|
47
|
+
return a.toLowerCase() === b.toLowerCase();
|
|
48
|
+
if (a instanceof Number)
|
|
49
|
+
return a.toFixed(10) === b.toFixed(10);
|
|
50
|
+
if (a instanceof Boolean)
|
|
51
|
+
return a === b;
|
|
52
|
+
if (a instanceof BigInt)
|
|
53
|
+
return a.toString() === b.toString();
|
|
54
|
+
if (a instanceof Buffer)
|
|
55
|
+
return a.equals(b);
|
|
56
|
+
if (a instanceof Map)
|
|
57
|
+
return a.size === b.size && Array.from(a.entries()).every(([key, value]) => deepEqual(value, b.get(key)));
|
|
58
|
+
if (a instanceof Set)
|
|
59
|
+
return a.size === b.size && Array.from(a).every(value => b.has(value));
|
|
60
|
+
if (a instanceof Date)
|
|
61
|
+
return a.getTime() === b.getTime();
|
|
62
|
+
return a == b;
|
|
63
|
+
}
|
|
64
|
+
function fetch_unverified_rpc(config, req, fetch_rpc) {
|
|
65
|
+
const fallback_provider = config.fallback_provider;
|
|
66
|
+
if (fallback_provider)
|
|
67
|
+
return fallback_provider.request(req);
|
|
68
|
+
let conf = config.chains[config.chainId];
|
|
69
|
+
let rpcs = conf?.rpcs || config.rpcs;
|
|
70
|
+
if (!rpcs || !Array.isArray(rpcs) || rpcs.length === 0)
|
|
71
|
+
throw new Error("No RPC- Endpoint configured");
|
|
72
|
+
return fetch_rpc(rpcs, req, false);
|
|
73
|
+
}
|
|
74
|
+
function OnlyProofStrategy(client, req, config, fetch_rpc) {
|
|
75
|
+
return client.rpc(req.method, argsToArray(req.params));
|
|
76
|
+
}
|
|
77
|
+
async function ProofIfPossibleStrategy(client, req, config, fetch_rpc) {
|
|
78
|
+
const method_type = await client.getMethodSupport(req.method);
|
|
79
|
+
switch (method_type) {
|
|
80
|
+
case types_js_1.MethodType.PROOFABLE:
|
|
81
|
+
case types_js_1.MethodType.LOCAL:
|
|
82
|
+
return client.rpc(req.method, argsToArray(req.params), method_type);
|
|
83
|
+
default:
|
|
84
|
+
return fetch_unverified_rpc(config, req, fetch_rpc);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
async function WarningStrategy(client, req, config, fetch_rpc) {
|
|
88
|
+
const method_type = await client.getMethodSupport(req.method);
|
|
89
|
+
switch (method_type) {
|
|
90
|
+
case types_js_1.MethodType.LOCAL:
|
|
91
|
+
return client.rpc(req.method, argsToArray(req.params), method_type);
|
|
92
|
+
case types_js_1.MethodType.UNPROOFABLE:
|
|
93
|
+
case types_js_1.MethodType.NOT_SUPPORTED:
|
|
94
|
+
return fetch_unverified_rpc(config, req, fetch_rpc);
|
|
95
|
+
case types_js_1.MethodType.PROOFABLE: {
|
|
96
|
+
const [verified_result, unverified_result] = await Promise.all([
|
|
97
|
+
client.rpc(req.method, argsToArray(req.params), types_js_1.MethodType.PROOFABLE)
|
|
98
|
+
.catch(async (err) => {
|
|
99
|
+
await config.warningHandler(req, `[Warning] ${req.method} failed to be verfiy: ${err.message}, falling back to Default`);
|
|
100
|
+
return undefined;
|
|
101
|
+
}),
|
|
102
|
+
fetch_unverified_rpc(config, req, fetch_rpc)
|
|
103
|
+
]);
|
|
104
|
+
if (verified_result !== undefined && !deepEqual(verified_result, unverified_result))
|
|
105
|
+
await config.warningHandler(req, `[Warning] ${req.method} does not match the rpc-result`);
|
|
106
|
+
return unverified_result;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
exports.default = {
|
|
111
|
+
VerifiedOnly: OnlyProofStrategy,
|
|
112
|
+
VerifyIfPossible: ProofIfPossibleStrategy,
|
|
113
|
+
WarningWithFallback: WarningStrategy
|
|
114
|
+
};
|