dequanto 0.2.27 → 0.2.29
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/lib/cjs/class/PackedRanges.js +422 -20
- package/lib/cjs/class/PackedRanges.js.map +1 -1
- package/lib/cjs/clients/Web3Client.js +2 -1
- package/lib/cjs/clients/Web3Client.js.map +1 -1
- package/lib/cjs/contracts/ContractReader.js +24 -1
- package/lib/cjs/contracts/ContractReader.js.map +1 -1
- package/lib/cjs/contracts/ContractWriter.js +1 -1
- package/lib/cjs/contracts/ContractWriter.js.map +1 -1
- package/lib/cjs/hardhat/HardhatProvider.js +7 -0
- package/lib/cjs/hardhat/HardhatProvider.js.map +1 -1
- package/lib/cjs/indexer/EventsIndexer.js +143 -98
- package/lib/cjs/indexer/EventsIndexer.js.map +1 -1
- package/lib/cjs/rpc/RpcContract.js +21 -13
- package/lib/cjs/rpc/RpcContract.js.map +1 -1
- package/lib/cjs/safe/GnosisSafeHandler.js +1 -1
- package/lib/cjs/safe/GnosisSafeHandler.js.map +1 -1
- package/lib/cjs/safe/transport/SafeServiceTransport.js +13 -3
- package/lib/cjs/safe/transport/SafeServiceTransport.js.map +1 -1
- package/lib/cjs/txs/TxWriter.js +5 -2
- package/lib/cjs/txs/TxWriter.js.map +1 -1
- package/lib/cjs/utils/$contract.js +7 -2
- package/lib/cjs/utils/$contract.js.map +1 -1
- package/lib/esm/class/PackedRanges.js.map +1 -1
- package/lib/esm/class/PackedRanges.mjs +422 -20
- package/lib/esm/clients/Web3Client.js.map +1 -1
- package/lib/esm/clients/Web3Client.mjs +2 -1
- package/lib/esm/contracts/ContractReader.js.map +1 -1
- package/lib/esm/contracts/ContractReader.mjs +24 -1
- package/lib/esm/contracts/ContractWriter.js.map +1 -1
- package/lib/esm/contracts/ContractWriter.mjs +1 -1
- package/lib/esm/hardhat/HardhatProvider.js.map +1 -1
- package/lib/esm/hardhat/HardhatProvider.mjs +7 -0
- package/lib/esm/indexer/EventsIndexer.js.map +1 -1
- package/lib/esm/indexer/EventsIndexer.mjs +143 -98
- package/lib/esm/rpc/RpcContract.js.map +1 -1
- package/lib/esm/rpc/RpcContract.mjs +21 -13
- package/lib/esm/safe/GnosisSafeHandler.js.map +1 -1
- package/lib/esm/safe/GnosisSafeHandler.mjs +1 -1
- package/lib/esm/safe/transport/SafeServiceTransport.js.map +1 -1
- package/lib/esm/safe/transport/SafeServiceTransport.mjs +13 -3
- package/lib/esm/txs/TxWriter.js.map +1 -1
- package/lib/esm/txs/TxWriter.mjs +5 -2
- package/lib/esm/utils/$contract.js.map +1 -1
- package/lib/esm/utils/$contract.mjs +7 -2
- package/lib/types/class/PackedRanges.d.ts +224 -0
- package/lib/types/clients/Web3Client.d.ts +4 -0
- package/lib/types/contracts/ContractReader.d.ts +1 -0
- package/lib/types/indexer/EventsIndexer.d.ts +5 -1
- package/lib/types/indexer/storage/interfaces.d.ts +1 -0
- package/lib/types/rpc/RpcContract.d.ts +16 -0
- package/lib/types/safe/GnosisSafeHandler.d.ts +1 -0
- package/lib/types/safe/transport/ISafeServiceTransport.d.ts +1 -0
- package/lib/types/utils/$contract.d.ts +1 -0
- package/package.json +1 -1
- package/src/class/PackedRanges.ts +447 -27
- package/src/clients/Web3Client.ts +6 -1
- package/src/contracts/ContractReader.ts +30 -3
- package/src/contracts/ContractWriter.ts +1 -1
- package/src/hardhat/HardhatProvider.ts +9 -0
- package/src/indexer/EventsIndexer.ts +173 -105
- package/src/indexer/storage/interfaces.ts +1 -0
- package/src/rpc/RpcContract.ts +34 -15
- package/src/safe/GnosisSafeHandler.ts +1 -1
- package/src/safe/transport/ISafeServiceTransport.ts +5 -1
- package/src/safe/transport/SafeServiceTransport.ts +15 -4
- package/src/txs/TxWriter.ts +6 -2
- package/src/utils/$contract.ts +7 -2
|
@@ -19,7 +19,7 @@ export class PackedRanges {
|
|
|
19
19
|
constructor(opts?: {
|
|
20
20
|
from?: number
|
|
21
21
|
to?: number
|
|
22
|
-
ranges?: [
|
|
22
|
+
ranges?: [number, number][]
|
|
23
23
|
}) {
|
|
24
24
|
|
|
25
25
|
if (opts != null) {
|
|
@@ -29,7 +29,8 @@ export class PackedRanges {
|
|
|
29
29
|
}
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
total ()
|
|
32
|
+
// Get the outer range [from..to] total capacity (regardless of tracked ranges)
|
|
33
|
+
total() {
|
|
33
34
|
let min = this.from;
|
|
34
35
|
let max = this.to ?? this.getMax();
|
|
35
36
|
if (min == null || max == null) {
|
|
@@ -37,7 +38,8 @@ export class PackedRanges {
|
|
|
37
38
|
}
|
|
38
39
|
return max - min;
|
|
39
40
|
}
|
|
40
|
-
|
|
41
|
+
// Get the sum of all tracked range lengths (total numbers visited/added)
|
|
42
|
+
totalAdded() {
|
|
41
43
|
let count = 0;
|
|
42
44
|
for (let i = 0; i < this.ranges.length; i++) {
|
|
43
45
|
let [min, max] = this.ranges[i];
|
|
@@ -45,11 +47,32 @@ export class PackedRanges {
|
|
|
45
47
|
}
|
|
46
48
|
return count;
|
|
47
49
|
}
|
|
48
|
-
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Calculates the number of elements remaining to be visited/added in the range.
|
|
53
|
+
* This is the difference between the total capacity and the number of elements already tracked.
|
|
54
|
+
*/
|
|
55
|
+
totalLeft() {
|
|
49
56
|
return this.total() - this.totalAdded();
|
|
50
57
|
}
|
|
51
58
|
|
|
52
59
|
|
|
60
|
+
/**
|
|
61
|
+
* Gets the next unvisited number in the range and marks it as visited.
|
|
62
|
+
*
|
|
63
|
+
* This method finds the next number that hasn't been added to the tracked ranges yet,
|
|
64
|
+
* automatically adds it to the ranges, and returns it. It respects the boundaries
|
|
65
|
+
* defined by `from` and `to` properties.
|
|
66
|
+
*
|
|
67
|
+
* The method works by:
|
|
68
|
+
* - Starting from `this.from` if no ranges exist
|
|
69
|
+
* - Filling gaps between existing ranges
|
|
70
|
+
* - Extending the last range if no gaps exist
|
|
71
|
+
* - Merging adjacent ranges when they become contiguous
|
|
72
|
+
*
|
|
73
|
+
* @returns The next unvisited number in the range, or `null` if all numbers up to `this.to` have been visited
|
|
74
|
+
* @throws {Error} If the internal ranges array is in an invalid state (unsorted or overlapping)
|
|
75
|
+
*/
|
|
53
76
|
next(): number {
|
|
54
77
|
let min = this.from;
|
|
55
78
|
if (this.ranges.length === 0) {
|
|
@@ -88,6 +111,14 @@ export class PackedRanges {
|
|
|
88
111
|
return r0Max;
|
|
89
112
|
}
|
|
90
113
|
|
|
114
|
+
/**
|
|
115
|
+
* Gets the maximum (upper bound) value from all tracked ranges.
|
|
116
|
+
*
|
|
117
|
+
* This method returns the highest number that has been visited/added to the ranges.
|
|
118
|
+
* It retrieves the upper bound of the last range in the sorted ranges array.
|
|
119
|
+
*
|
|
120
|
+
* @returns The maximum value in the tracked ranges, or `null` if no ranges have been added yet
|
|
121
|
+
*/
|
|
91
122
|
getMax() {
|
|
92
123
|
if (this.ranges.length === 0) {
|
|
93
124
|
return null;
|
|
@@ -96,6 +127,16 @@ export class PackedRanges {
|
|
|
96
127
|
return r[1];
|
|
97
128
|
}
|
|
98
129
|
|
|
130
|
+
/**
|
|
131
|
+
* Checks if a specific number has been visited/added to the tracked ranges.
|
|
132
|
+
*
|
|
133
|
+
* This method searches through all tracked ranges to determine if the given number
|
|
134
|
+
* falls within any of them. It performs a linear search through the ranges array,
|
|
135
|
+
* checking if the number is within the bounds (inclusive) of any range.
|
|
136
|
+
*
|
|
137
|
+
* @param nr - The number to check for inclusion in the tracked ranges
|
|
138
|
+
* @returns `true` if the number exists within any of the tracked ranges, `false` otherwise
|
|
139
|
+
*/
|
|
99
140
|
includes(nr: number) {
|
|
100
141
|
for (let i = 0; i < this.ranges.length; i++) {
|
|
101
142
|
let [a, b] = this.ranges[i];
|
|
@@ -106,6 +147,21 @@ export class PackedRanges {
|
|
|
106
147
|
return false;
|
|
107
148
|
}
|
|
108
149
|
|
|
150
|
+
/**
|
|
151
|
+
* Adds a number to the tracked ranges, marking it as visited.
|
|
152
|
+
*
|
|
153
|
+
* This method intelligently adds a number to the ranges by either:
|
|
154
|
+
* - Extending an existing range if the number is adjacent to it
|
|
155
|
+
* - Creating a new range if the number is isolated
|
|
156
|
+
* - Doing nothing if the number is already included in an existing range
|
|
157
|
+
*
|
|
158
|
+
* The method maintains the sorted order of ranges and automatically merges
|
|
159
|
+
* adjacent numbers into contiguous ranges for efficient storage.
|
|
160
|
+
*
|
|
161
|
+
* @param nr - The number to add to the tracked ranges
|
|
162
|
+
* @returns `true` if the number was successfully added (new or extended a range),
|
|
163
|
+
* `false` if the number was already present in the ranges
|
|
164
|
+
*/
|
|
109
165
|
add(nr: number) {
|
|
110
166
|
let modified = false;
|
|
111
167
|
for (let i = 0; i < this.ranges.length; i++) {
|
|
@@ -142,7 +198,43 @@ export class PackedRanges {
|
|
|
142
198
|
}
|
|
143
199
|
return true;
|
|
144
200
|
}
|
|
145
|
-
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* Adds a complete range to the tracked ranges and compacts the result.
|
|
204
|
+
*
|
|
205
|
+
* This method adds an entire range [min, max] to the tracked ranges array,
|
|
206
|
+
* then automatically compacts the ranges to merge any overlapping or adjacent
|
|
207
|
+
* ranges. This is useful for bulk operations where you want to mark multiple
|
|
208
|
+
* consecutive numbers as visited at once.
|
|
209
|
+
*
|
|
210
|
+
* Unlike the `add()` method which adds individual numbers, this method adds
|
|
211
|
+
* a complete range tuple and ensures the internal ranges array remains optimized
|
|
212
|
+
* by calling `compact()` after insertion.
|
|
213
|
+
*
|
|
214
|
+
* @param range - A tuple [min, max] representing the range to add, where both bounds are inclusive
|
|
215
|
+
*/
|
|
216
|
+
addRange(range: [number, number]) {
|
|
217
|
+
this.ranges.push(range);
|
|
218
|
+
this.compact();
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* Removes a specific number from the tracked ranges, marking it as unvisited.
|
|
223
|
+
*
|
|
224
|
+
* This method searches for the number within the tracked ranges and removes it by either:
|
|
225
|
+
* - Removing the entire range if it contains only the target number
|
|
226
|
+
* - Shrinking the range by adjusting its lower bound if the number is at the start
|
|
227
|
+
* - Shrinking the range by adjusting its upper bound if the number is at the end
|
|
228
|
+
* - Splitting the range into two separate ranges if the number is in the middle
|
|
229
|
+
*
|
|
230
|
+
* The method maintains the sorted order of ranges and ensures efficient storage
|
|
231
|
+
* by handling all edge cases appropriately.
|
|
232
|
+
*
|
|
233
|
+
* @param nr - The number to remove from the tracked ranges
|
|
234
|
+
* @returns `true` if the number was found and successfully removed from the ranges,
|
|
235
|
+
* `false` if the number was not present in any of the tracked ranges
|
|
236
|
+
*/
|
|
237
|
+
remove(nr: number) {
|
|
146
238
|
for (let i = 0; i < this.ranges.length; i++) {
|
|
147
239
|
let [min, max] = this.ranges[i];
|
|
148
240
|
if (min <= nr && nr <= max) {
|
|
@@ -160,8 +252,8 @@ export class PackedRanges {
|
|
|
160
252
|
return true;
|
|
161
253
|
}
|
|
162
254
|
|
|
163
|
-
let arr1 = [min, nr - 1] as [
|
|
164
|
-
let arr2 = [nr + 1, max] as [
|
|
255
|
+
let arr1 = [min, nr - 1] as [number, number];
|
|
256
|
+
let arr2 = [nr + 1, max] as [number, number];
|
|
165
257
|
this.ranges.splice(i, 1, arr1, arr2);
|
|
166
258
|
return true;
|
|
167
259
|
}
|
|
@@ -169,45 +261,373 @@ export class PackedRanges {
|
|
|
169
261
|
return false;
|
|
170
262
|
}
|
|
171
263
|
|
|
264
|
+
/**
|
|
265
|
+
* Removes a range of numbers from the tracked ranges, marking them as unvisited.
|
|
266
|
+
*
|
|
267
|
+
* This method subtracts the specified range from all tracked ranges, effectively
|
|
268
|
+
* removing all numbers within the given range from the visited/added set. It handles
|
|
269
|
+
* overlapping ranges by splitting or trimming existing ranges as needed.
|
|
270
|
+
*
|
|
271
|
+
* The method maintains the sorted order of ranges and ensures efficient storage
|
|
272
|
+
* by delegating to the `Ranges.subtract()` utility function.
|
|
273
|
+
*
|
|
274
|
+
* @param range - A tuple [min, max] representing the range to remove, where both bounds are inclusive
|
|
275
|
+
* @returns The current `PackedRanges` instance for method chaining
|
|
276
|
+
*/
|
|
277
|
+
subtractRange(range: [number, number]) {
|
|
278
|
+
this.ranges = Ranges.subtract(this.ranges, range);
|
|
279
|
+
return this;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
/**
|
|
283
|
+
* Removes multiple ranges of numbers from the tracked ranges, marking them as unvisited.
|
|
284
|
+
*
|
|
285
|
+
* This method subtracts all specified ranges from the tracked ranges, effectively
|
|
286
|
+
* removing all numbers within the given ranges from the visited/added set. It handles
|
|
287
|
+
* overlapping ranges by splitting or trimming existing ranges as needed for each
|
|
288
|
+
* range in the input array.
|
|
289
|
+
*
|
|
290
|
+
* The method maintains the sorted order of ranges and ensures efficient storage
|
|
291
|
+
* by delegating to the `Ranges.subtractMany()` utility function.
|
|
292
|
+
*
|
|
293
|
+
* @param ranges - An array of tuples [min, max] representing the ranges to remove, where both bounds are inclusive
|
|
294
|
+
* @returns The current `PackedRanges` instance for method chaining
|
|
295
|
+
*/
|
|
296
|
+
subtractRanges(ranges: [number, number][]) {
|
|
297
|
+
this.ranges = Ranges.subtractMany(this.ranges, ranges);
|
|
298
|
+
return this;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
/**
|
|
302
|
+
* Compacts the tracked ranges by merging overlapping and adjacent ranges.
|
|
303
|
+
*
|
|
304
|
+
* This method optimizes the internal ranges array by:
|
|
305
|
+
* - Merging overlapping ranges into single contiguous ranges
|
|
306
|
+
* - Joining adjacent ranges (e.g., [1,4] and [5,6] become [1,6])
|
|
307
|
+
* - Sorting ranges by their starting values
|
|
308
|
+
* - Removing redundant range entries
|
|
309
|
+
*
|
|
310
|
+
* This operation is useful after bulk modifications to ensure the ranges
|
|
311
|
+
* array remains in its most efficient form for storage and querying.
|
|
312
|
+
*/
|
|
172
313
|
compact() {
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
314
|
+
this.ranges = Ranges.compact(this.ranges);
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
/**
|
|
318
|
+
* Sets the tracked ranges to a new array of ranges and compacts them.
|
|
319
|
+
*
|
|
320
|
+
* This method replaces the entire internal ranges array with the provided ranges,
|
|
321
|
+
* then automatically compacts them to merge any overlapping or adjacent ranges.
|
|
322
|
+
* This is useful for bulk initialization or restoration of ranges from a saved state.
|
|
323
|
+
*
|
|
324
|
+
* After setting the ranges, the method ensures the internal ranges array is optimized
|
|
325
|
+
* by calling `compact()`, which merges overlapping ranges and joins adjacent ones.
|
|
326
|
+
*
|
|
327
|
+
* @param ranges - An array of tuples [min, max] representing the ranges to set, where both bounds are inclusive
|
|
328
|
+
*/
|
|
329
|
+
set(ranges: [number, number][]) {
|
|
330
|
+
this.ranges = ranges;
|
|
331
|
+
this.compact();
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
/**
|
|
335
|
+
* Serializes the tracked ranges to a JSON string representation.
|
|
336
|
+
*
|
|
337
|
+
* This method converts the internal ranges array into a JSON string format,
|
|
338
|
+
* which can be used for persistence, transmission, or storage purposes.
|
|
339
|
+
* The serialized string can later be parsed and used to restore the ranges
|
|
340
|
+
* via the constructor's `ranges` option.
|
|
341
|
+
*
|
|
342
|
+
* @returns A JSON string representation of the tracked ranges array
|
|
343
|
+
*/
|
|
344
|
+
serialize() {
|
|
345
|
+
return JSON.stringify(this.ranges);
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
/**
|
|
349
|
+
* Creates a new PackedRanges instance containing only the ranges starting from a specified number.
|
|
350
|
+
*
|
|
351
|
+
* This method filters the tracked ranges to include only those that contain or come after
|
|
352
|
+
* the specified `from` value. If a range overlaps with the `from` value, it is trimmed
|
|
353
|
+
* to start at `from`. All ranges before `from` are excluded from the result.
|
|
354
|
+
*
|
|
355
|
+
* The original PackedRanges instance remains unchanged; a new instance is returned with
|
|
356
|
+
* the filtered ranges.
|
|
357
|
+
*
|
|
358
|
+
* @param from - The starting number from which to pick ranges (inclusive)
|
|
359
|
+
* @returns A new PackedRanges instance containing only the ranges from the specified number onwards
|
|
360
|
+
*/
|
|
361
|
+
pickFrom(from: number): PackedRanges {
|
|
362
|
+
let arr = Ranges.pickFrom(this.ranges, from);
|
|
363
|
+
return new PackedRanges({ ranges: arr });
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
/**
|
|
367
|
+
* Creates a new PackedRanges instance containing only the ranges up to a specified number.
|
|
368
|
+
*
|
|
369
|
+
* This method filters the tracked ranges to include only those that contain or come before
|
|
370
|
+
* the specified `to` value. If a range overlaps with the `to` value, it is trimmed
|
|
371
|
+
* to end at `to`. All ranges after `to` are excluded from the result.
|
|
372
|
+
*
|
|
373
|
+
* The original PackedRanges instance remains unchanged; a new instance is returned with
|
|
374
|
+
* the filtered ranges.
|
|
375
|
+
*
|
|
376
|
+
* @param to - The ending number up to which to pick ranges (inclusive)
|
|
377
|
+
* @returns A new PackedRanges instance containing only the ranges up to the specified number
|
|
378
|
+
*/
|
|
379
|
+
pickTo(to: number): PackedRanges {
|
|
380
|
+
let arr = Ranges.pickTo(this.ranges, to);
|
|
381
|
+
return new PackedRanges({ ranges: arr });
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
|
|
385
|
+
/**
|
|
386
|
+
* Computes the intersection of multiple range arrays, returning only the ranges that are common to all inputs.
|
|
387
|
+
*
|
|
388
|
+
* This method performs a set intersection operation across multiple arrays of ranges,
|
|
389
|
+
* finding only those number ranges that appear in every input array. The result is
|
|
390
|
+
* compacted to merge any overlapping or adjacent ranges for efficient storage.
|
|
391
|
+
*
|
|
392
|
+
* For example:
|
|
393
|
+
* - Input: [[[1,5], [10,15]], [[3,7], [12,20]]]
|
|
394
|
+
* - Output: [[3,5], [12,15]] (ranges common to both arrays)
|
|
395
|
+
*
|
|
396
|
+
* @param rangesArr - An array of range arrays, where each range array contains tuples [min, max] representing inclusive number ranges
|
|
397
|
+
* @returns A compacted array of ranges representing the intersection of all input range arrays, or an empty array if no common ranges exist or if the input is empty
|
|
398
|
+
*/
|
|
399
|
+
static intersection(rangesArr: ([number, number][])[]): [number, number][] {
|
|
400
|
+
if (rangesArr.length === 0) {
|
|
401
|
+
return [];
|
|
402
|
+
}
|
|
403
|
+
let arr = Ranges.clone(rangesArr[0]);
|
|
404
|
+
for (let i = 1; i < rangesArr.length; i++) {
|
|
405
|
+
arr = Ranges.intersection(arr, rangesArr[i]);
|
|
406
|
+
}
|
|
407
|
+
return Ranges.compact(arr);
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
/**
|
|
411
|
+
* Computes the union of multiple range arrays, returning all ranges that appear in any of the inputs.
|
|
412
|
+
*
|
|
413
|
+
* This method performs a set union operation across multiple arrays of ranges,
|
|
414
|
+
* combining all number ranges from every input array. The result is compacted to
|
|
415
|
+
* merge any overlapping or adjacent ranges for efficient storage.
|
|
416
|
+
*
|
|
417
|
+
* For example:
|
|
418
|
+
* - Input: [[[1,5], [10,15]], [[3,7], [12,20]]]
|
|
419
|
+
* - Output: [[1,7], [10,20]] (all ranges merged and compacted)
|
|
420
|
+
*
|
|
421
|
+
* @param rangesArr - An array of range arrays, where each range array contains tuples [min, max] representing inclusive number ranges
|
|
422
|
+
* @returns A compacted array of ranges representing the union of all input range arrays, or an empty array if the input is empty
|
|
423
|
+
*/
|
|
424
|
+
static union(rangesArr: ([number, number][])[]): [number, number][] {
|
|
425
|
+
let arr = alot(rangesArr)
|
|
426
|
+
.mapMany(x => x)
|
|
427
|
+
.toArray();
|
|
428
|
+
return Ranges.compact(arr);
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
/**
|
|
432
|
+
* Computes the difference between two range arrays, removing all ranges in B from ranges in A.
|
|
433
|
+
*
|
|
434
|
+
* This method performs a set difference operation (A − B), subtracting all number ranges
|
|
435
|
+
* in `rangesB` from `rangesA`. The result contains only those portions of `rangesA` that
|
|
436
|
+
* do not overlap with any range in `rangesB`. The result is compacted to merge any
|
|
437
|
+
* overlapping or adjacent ranges for efficient storage.
|
|
438
|
+
*
|
|
439
|
+
* For example:
|
|
440
|
+
* - Input: rangesA = [[1,10], [20,30]], rangesB = [[5,15], [25,35]]
|
|
441
|
+
* - Output: [[1,4], [20,24]] (parts of A not covered by B)
|
|
442
|
+
*
|
|
443
|
+
* @param rangesA - The array of ranges to subtract from, where each range is a tuple [min, max] representing inclusive number ranges
|
|
444
|
+
* @param rangesB - The array of ranges to subtract, where each range is a tuple [min, max] representing inclusive number ranges
|
|
445
|
+
* @returns A compacted array of ranges representing the difference (A − B), or an empty array if all of A is covered by B
|
|
446
|
+
*/
|
|
447
|
+
static subtract(rangesA: [number, number][], rangesB: [number, number][]): [number, number][] {
|
|
448
|
+
let arr = Ranges.subtractMany(rangesA, rangesB);
|
|
449
|
+
return Ranges.compact(arr);
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
|
|
453
|
+
static pickFrom(ranges: [number, number][], from: number): [number, number][] {
|
|
454
|
+
let arr = Ranges.pickFrom(ranges, from);
|
|
455
|
+
return arr;
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
static pickTo(ranges: [number, number][], to: number): [number, number][] {
|
|
459
|
+
let arr = Ranges.pickTo(ranges, to);
|
|
460
|
+
return arr;
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
namespace Range {
|
|
465
|
+
|
|
466
|
+
// Check if two ranges overlap
|
|
467
|
+
export function overlaps(r1: [number, number], r2: [number, number]) {
|
|
468
|
+
let [x1, y1] = r1;
|
|
469
|
+
let [x2, y2] = r2;
|
|
470
|
+
let d = Math.min(y1, y2) - Math.max(x1, x2);
|
|
471
|
+
return d > -1;
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
// AND: A ∩ B
|
|
475
|
+
export function intersection(r1: [number, number], r2: [number, number]) {
|
|
476
|
+
let [x1, y1] = r1;
|
|
477
|
+
let [x2, y2] = r2;
|
|
478
|
+
let minY = Math.min(y1, y2);
|
|
479
|
+
let maxX = Math.max(x1, x2);
|
|
480
|
+
if (minY >= maxX) {
|
|
481
|
+
return [maxX, minY] as [number, number];
|
|
482
|
+
}
|
|
483
|
+
return null;
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
|
|
489
|
+
|
|
490
|
+
namespace Ranges {
|
|
491
|
+
export function clone(ranges: [number, number][]) {
|
|
492
|
+
let arr = [] as [number, number][];
|
|
493
|
+
for (let [x, y] of ranges) {
|
|
494
|
+
arr.push([x, y]);
|
|
495
|
+
}
|
|
496
|
+
return arr;
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
// AND: A ∩ B
|
|
500
|
+
export function intersection(rangesA: [number, number][], rangesB: [number, number][]) {
|
|
501
|
+
let arr = [] as [number, number][];
|
|
502
|
+
for (let i = 0; i < rangesA.length; i++) {
|
|
503
|
+
let rA = rangesA[i];
|
|
504
|
+
for (let j = 0; j < rangesB.length; j++) {
|
|
505
|
+
let union = Range.intersection(rA, rangesB[j]);
|
|
506
|
+
if (union) {
|
|
507
|
+
arr.push(union);
|
|
508
|
+
continue;
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
return arr;
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
export function compact (ranges: [number, number][]): [number, number][] {
|
|
516
|
+
for (let i = 0; i < ranges.length; i++) {
|
|
517
|
+
let rangeA = ranges[i];
|
|
518
|
+
for (let j = i + 1; j < ranges.length; j++) {
|
|
519
|
+
let rangeB = ranges[j];
|
|
520
|
+
if (Range.overlaps(rangeA, rangeB)) {
|
|
178
521
|
let [x1, y1] = rangeA;
|
|
179
522
|
let [x2, y2] = rangeB;
|
|
180
523
|
|
|
181
|
-
|
|
182
|
-
|
|
524
|
+
ranges[i] = [Math.min(x1, x2), Math.max(y1, y2)];
|
|
525
|
+
ranges.splice(j, 1);
|
|
183
526
|
j--;
|
|
184
527
|
continue;
|
|
185
528
|
}
|
|
186
529
|
}
|
|
187
530
|
}
|
|
188
531
|
|
|
189
|
-
|
|
532
|
+
ranges = alot(ranges)
|
|
190
533
|
.sortBy(([x]) => x)
|
|
191
534
|
.toArray();
|
|
535
|
+
|
|
536
|
+
// Join non overlapping ranges: [1,4],[5, 6] -> [1,6]
|
|
537
|
+
for (let i = 0; i < ranges.length - 1; i++) {
|
|
538
|
+
let A = ranges[i];
|
|
539
|
+
let B = ranges[i + 1];
|
|
540
|
+
let aLast = A[A.length - 1];
|
|
541
|
+
let bFirst = B[0];
|
|
542
|
+
if (aLast + 1 === bFirst) {
|
|
543
|
+
let bLast = B[B.length - 1];
|
|
544
|
+
A[A.length - 1] = bLast;
|
|
545
|
+
ranges.splice(i + 1, 1);
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
return ranges;
|
|
192
550
|
}
|
|
193
551
|
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
552
|
+
// Difference: A \ B
|
|
553
|
+
export function subtract(ranges:[number, number][], range: [number, number]) {
|
|
554
|
+
let arr = [] as [number, number][];
|
|
555
|
+
let [rmFrom, rmTo] = range;
|
|
556
|
+
for (let i = 0; i < ranges.length; i++) {
|
|
557
|
+
let A = ranges[i];
|
|
558
|
+
if (Range.overlaps(A, range) === false) {
|
|
559
|
+
arr.push(A);
|
|
560
|
+
continue;
|
|
561
|
+
}
|
|
562
|
+
let [Amin, Amax] = ranges[i];
|
|
563
|
+
if (Amin < rmFrom) {
|
|
564
|
+
arr.push([Amin, rmFrom - 1]);
|
|
565
|
+
}
|
|
566
|
+
if (Amax > rmTo) {
|
|
567
|
+
arr.push([rmTo + 1, Amax]);
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
return arr;
|
|
197
571
|
}
|
|
198
|
-
|
|
199
|
-
|
|
572
|
+
|
|
573
|
+
// Difference: A \ ∩B
|
|
574
|
+
export function subtractMany(ranges:[number, number][], rangeArr: [number, number][]) {
|
|
575
|
+
let arr = ranges;
|
|
576
|
+
for (let range of rangeArr) {
|
|
577
|
+
arr = subtract(arr, range);
|
|
578
|
+
}
|
|
579
|
+
return arr;
|
|
200
580
|
}
|
|
201
|
-
}
|
|
202
581
|
|
|
582
|
+
export function pickFrom(ranges: [number, number][], from: number): [number, number][] {
|
|
583
|
+
if (ranges == null || ranges.length === 0) {
|
|
584
|
+
return [];
|
|
585
|
+
}
|
|
586
|
+
let arr = [] as [number, number][];
|
|
587
|
+
for (let i = 0; i < ranges.length; i++) {
|
|
588
|
+
let A = ranges[i];
|
|
589
|
+
let aFirst = A[0];
|
|
590
|
+
let aLast = A[A.length - 1];
|
|
591
|
+
if (aLast < from) {
|
|
592
|
+
// This part is fully before from, ignore, search for the next part
|
|
593
|
+
continue;
|
|
594
|
+
}
|
|
595
|
+
if (from < aFirst) {
|
|
596
|
+
// No overlapping, pick all ranges
|
|
597
|
+
arr = ranges.slice(i).map(([x, y]) => [x, y]);
|
|
598
|
+
break;
|
|
599
|
+
}
|
|
600
|
+
let overlapped = [from, aLast] as [number, number];
|
|
601
|
+
arr = ranges.slice(i + 1).map(([x, y]) => [x, y]);
|
|
602
|
+
arr.unshift(overlapped)
|
|
603
|
+
break;
|
|
604
|
+
}
|
|
605
|
+
return arr
|
|
606
|
+
}
|
|
203
607
|
|
|
608
|
+
export function pickTo(ranges: [number, number][], to: number): [number, number][] {
|
|
609
|
+
if (ranges == null || ranges.length === 0) {
|
|
610
|
+
return [];
|
|
611
|
+
}
|
|
612
|
+
let arr = [] as [number, number][];
|
|
613
|
+
for (let i = 0; i < ranges.length; i++) {
|
|
614
|
+
let A = ranges[i];
|
|
615
|
+
let aFirst = A[0];
|
|
616
|
+
let aLast = A[A.length - 1];
|
|
204
617
|
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
let d = Math.min(y1, y2) - Math.max(x1, x2);
|
|
618
|
+
if (aFirst > to) {
|
|
619
|
+
// This part starts after 'to' => break (as sorted, next parts also start after 'to')
|
|
620
|
+
break;
|
|
621
|
+
}
|
|
210
622
|
|
|
211
|
-
|
|
623
|
+
if (aLast < to) {
|
|
624
|
+
// No overlapping, pick full range
|
|
625
|
+
arr.push([aFirst, aLast]);
|
|
626
|
+
} else {
|
|
627
|
+
// Overlapps
|
|
628
|
+
arr.push([aFirst, to]);
|
|
629
|
+
}
|
|
630
|
+
}
|
|
631
|
+
return arr;
|
|
212
632
|
}
|
|
213
633
|
}
|
|
@@ -586,6 +586,10 @@ export type TLogsRangeProgress<TLogParsed> = {
|
|
|
586
586
|
blocksPerSecond: number
|
|
587
587
|
timeLeftSeconds: number
|
|
588
588
|
completed: boolean
|
|
589
|
+
infos: {
|
|
590
|
+
fetched: number
|
|
591
|
+
cached: number
|
|
592
|
+
}
|
|
589
593
|
}
|
|
590
594
|
|
|
591
595
|
namespace RangeWorker {
|
|
@@ -658,7 +662,8 @@ namespace RangeWorker {
|
|
|
658
662
|
blocks: perf.blocks,
|
|
659
663
|
blocksPerSecond: Number(blocksPerSecFormatted),
|
|
660
664
|
timeLeftSeconds: leftSeconds,
|
|
661
|
-
completed: cursor >= toBlock
|
|
665
|
+
completed: cursor >= toBlock,
|
|
666
|
+
infos: { fetched: perf.blocks.loaded, cached: 0 }
|
|
662
667
|
});
|
|
663
668
|
|
|
664
669
|
let lastNodeStats = Date.now() - nodeStats;
|
|
@@ -19,8 +19,10 @@ import { $require } from '@dequanto/utils/$require';
|
|
|
19
19
|
import { $array } from '@dequanto/utils/$array';
|
|
20
20
|
import { RpcTypes } from '@dequanto/rpc/Rpc';
|
|
21
21
|
import { TEth } from '@dequanto/models/TEth';
|
|
22
|
-
import { TRpcContractCall } from '@dequanto/rpc/RpcContract';
|
|
22
|
+
import { RpcContract, TRpcContractCall } from '@dequanto/rpc/RpcContract';
|
|
23
23
|
import { WClient } from '@dequanto/clients/ClientPool';
|
|
24
|
+
import { $traces } from '@dequanto/utils/$traces';
|
|
25
|
+
import { $abiProvider } from '@dequanto/utils/$abiProvider';
|
|
24
26
|
|
|
25
27
|
|
|
26
28
|
|
|
@@ -35,7 +37,10 @@ export class ContractReader implements IContractReader {
|
|
|
35
37
|
private blockNumberTask: Promise<number>;
|
|
36
38
|
private options: TRpcContractCall = {};
|
|
37
39
|
|
|
38
|
-
constructor(public client: Web3Client = di.resolve(EthWeb3Client), private ctx?: {
|
|
40
|
+
constructor(public client: Web3Client = di.resolve(EthWeb3Client), private ctx?: {
|
|
41
|
+
name?: string
|
|
42
|
+
color?: boolean
|
|
43
|
+
}) {
|
|
39
44
|
|
|
40
45
|
}
|
|
41
46
|
forBlock (mix: number | Date | undefined) {
|
|
@@ -107,7 +112,29 @@ export class ContractReader implements IContractReader {
|
|
|
107
112
|
return result as TResult;
|
|
108
113
|
} catch (error) {
|
|
109
114
|
let args = params.map((x, i) => `[${i}] ${x}`).join('\n');
|
|
110
|
-
|
|
115
|
+
|
|
116
|
+
let { client } = this;
|
|
117
|
+
let { tx: txData } = await RpcContract.createCalldata({
|
|
118
|
+
address,
|
|
119
|
+
abi: abiArr,
|
|
120
|
+
method: method,
|
|
121
|
+
params: params,
|
|
122
|
+
blockNumber: blockNumber,
|
|
123
|
+
from: this.options.from,
|
|
124
|
+
});
|
|
125
|
+
let traces = await client.debug.traceCall(txData);
|
|
126
|
+
let output = await $traces.format({
|
|
127
|
+
tx: txData,
|
|
128
|
+
traces,
|
|
129
|
+
color: this.ctx?.color ?? false,
|
|
130
|
+
shortAddress: false,
|
|
131
|
+
async getABI(address) {
|
|
132
|
+
return $abiProvider.getAbi(address, client.network);
|
|
133
|
+
}
|
|
134
|
+
});
|
|
135
|
+
let tracesF = `\nTraces: \n` + output;
|
|
136
|
+
|
|
137
|
+
let err = new Error(`Read ${this.ctx?.name ?? ''} ${address}.${method}(${args}) failed with ${error.message}\n${tracesF}`);
|
|
111
138
|
err.stack = error.stack;
|
|
112
139
|
throw err;
|
|
113
140
|
}
|
|
@@ -131,7 +131,7 @@ export class ContractWriter implements IContractWriter {
|
|
|
131
131
|
let silentTxWriter = writerConfig?.silent ?? ContractWriter.SILENT;
|
|
132
132
|
if (silentTxWriter === false) {
|
|
133
133
|
writer.on('log', message => {
|
|
134
|
-
$logger.log(
|
|
134
|
+
$logger.log(`${abi.name}; ${message}`);
|
|
135
135
|
});
|
|
136
136
|
}
|
|
137
137
|
return writer;
|
|
@@ -419,6 +419,15 @@ export class HardhatProvider {
|
|
|
419
419
|
}
|
|
420
420
|
|
|
421
421
|
private async createTmpFile(solidityCode: string, options: Parameters<HardhatProvider['deploySol']>[1] = {}) {
|
|
422
|
+
|
|
423
|
+
// Ensure the code includes the necessary pragmas and license header.
|
|
424
|
+
if (solidityCode.includes('pragma solidity') === false) {
|
|
425
|
+
solidityCode = `pragma solidity ^0.8.0;\n${solidityCode}`;
|
|
426
|
+
}
|
|
427
|
+
if (solidityCode.includes('SPDX-License-Identifier') === false) {
|
|
428
|
+
solidityCode = `// SPDX-License-Identifier: MIT\n${solidityCode}`;
|
|
429
|
+
}
|
|
430
|
+
|
|
422
431
|
let contractName = options.contractName;
|
|
423
432
|
if (contractName == null) {
|
|
424
433
|
let matches = Array.from(solidityCode.matchAll(/contract\s+(?<name>[\w]+)/g));
|