dequanto 0.2.27 → 0.2.30
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 +30 -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 +30 -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 +35 -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
|
@@ -7,7 +7,7 @@ import { ITxLogItem } from '@dequanto/txs/receipt/ITxLogItem';
|
|
|
7
7
|
import { $date } from '@dequanto/utils/$date';
|
|
8
8
|
import { $require } from '@dequanto/utils/$require';
|
|
9
9
|
import { TAddress } from '@dequanto/models/TAddress';
|
|
10
|
-
import { IEventsIndexerMetaStore, IEventsIndexerStore, TEventsIndexerItem } from './storage/interfaces';
|
|
10
|
+
import { IEventsIndexerMetaStore, IEventsIndexerStore, TEventsIndexerItem, TEventsIndexerMeta } from './storage/interfaces';
|
|
11
11
|
import { FsEventsIndexerStore } from './storage/FsEventsIndexerStore';
|
|
12
12
|
import { FsEventsMetaStore } from './storage/FsEventsMetaStore';
|
|
13
13
|
import { class_Dfr } from 'atma-utils';
|
|
@@ -15,6 +15,7 @@ import { TLogsRangeProgress } from '@dequanto/clients/Web3Client';
|
|
|
15
15
|
import { WClient } from '@dequanto/clients/ClientPool';
|
|
16
16
|
import { TEth } from '@dequanto/models/TEth';
|
|
17
17
|
import { l } from '@dequanto/utils/$logger';
|
|
18
|
+
import { PackedRanges } from '@dequanto/class/PackedRanges';
|
|
18
19
|
|
|
19
20
|
|
|
20
21
|
export class EventsIndexer <TContract extends ContractBase> {
|
|
@@ -86,18 +87,27 @@ export class EventsIndexer <TContract extends ContractBase> {
|
|
|
86
87
|
}
|
|
87
88
|
): Promise<{
|
|
88
89
|
logs: ITxLogItem<GetTypes<TContract>['Events'][TLogName]['outputParams']>[],
|
|
90
|
+
infos: {
|
|
91
|
+
fetched: number,
|
|
92
|
+
cached: number,
|
|
93
|
+
}
|
|
89
94
|
}> {
|
|
90
95
|
let contract = this.contract;
|
|
91
96
|
let client = contract.client;
|
|
97
|
+
let fromBlock = filter?.fromBlock;
|
|
92
98
|
let toBlock = filter?.toBlock ?? await client.getBlockNumber();
|
|
93
99
|
let events = Array.isArray(event) ? event as string[] : [ event as string ];
|
|
94
100
|
let filterKey = this.getFilterKey(filter?.params);
|
|
95
|
-
let ranges = await this.getRanges(events, this.options.initialBlockNumber, toBlock, {
|
|
96
|
-
|
|
101
|
+
let ranges = await this.getRanges(events, this.options.initialBlockNumber, toBlock, {
|
|
102
|
+
fromBlock,
|
|
103
|
+
filterKey
|
|
104
|
+
});
|
|
105
|
+
let { logs, infos } = await this.getPastLogsRanges(ranges, events, toBlock, fromBlock, {
|
|
97
106
|
params: filter?.params as any
|
|
98
107
|
});
|
|
99
108
|
return {
|
|
100
|
-
logs: logs as any
|
|
109
|
+
logs: logs as any,
|
|
110
|
+
infos,
|
|
101
111
|
};
|
|
102
112
|
}
|
|
103
113
|
|
|
@@ -122,17 +132,19 @@ export class EventsIndexer <TContract extends ContractBase> {
|
|
|
122
132
|
> {
|
|
123
133
|
let contract = this.contract;
|
|
124
134
|
let client = contract.client;
|
|
135
|
+
let fromBlock = options?.fromBlock;
|
|
125
136
|
let toBlock = options?.toBlock ?? await client.getBlockNumber();
|
|
126
137
|
let events = Array.isArray(event) ? event as string[] : [ event as string ];
|
|
127
138
|
let filterKey = this.getFilterKey(options?.params);
|
|
128
|
-
let ranges = await this.getRanges(events,
|
|
139
|
+
let ranges = await this.getRanges(events, this.options.initialBlockNumber, toBlock, {
|
|
140
|
+
fromBlock,
|
|
129
141
|
filterKey
|
|
130
142
|
});
|
|
131
143
|
|
|
132
144
|
let dfrInner = new class_Dfr<any>();
|
|
133
145
|
let dfrOuter = new class_Dfr<any>();
|
|
134
146
|
|
|
135
|
-
this.getPastLogsRanges(ranges, events, toBlock,
|
|
147
|
+
this.getPastLogsRanges(ranges, events, toBlock, fromBlock, {
|
|
136
148
|
params: options?.params,
|
|
137
149
|
blockRangeLimits: options?.blockRangeLimits,
|
|
138
150
|
streamed: true,
|
|
@@ -162,7 +174,7 @@ export class EventsIndexer <TContract extends ContractBase> {
|
|
|
162
174
|
}
|
|
163
175
|
}
|
|
164
176
|
|
|
165
|
-
async removeCached (params
|
|
177
|
+
async removeCached (params?: {
|
|
166
178
|
fromBlock: number
|
|
167
179
|
}) {
|
|
168
180
|
let events = await this.store.fetch({ fromBlock: params.fromBlock });
|
|
@@ -170,12 +182,15 @@ export class EventsIndexer <TContract extends ContractBase> {
|
|
|
170
182
|
await this.store.removeMany(events);
|
|
171
183
|
|
|
172
184
|
let metas = await this.storeMeta.fetch();
|
|
173
|
-
let lastBlock = params
|
|
185
|
+
let lastBlock = (params?.fromBlock ?? 0) - 1;
|
|
174
186
|
if (lastBlock < 0) {
|
|
187
|
+
// remove all metas
|
|
175
188
|
await this.storeMeta.removeMany(metas)
|
|
176
189
|
} else {
|
|
190
|
+
// adjust the lastBlock and the ranges
|
|
177
191
|
metas.forEach(x => {
|
|
178
192
|
x.lastBlock = Math.min(x.lastBlock, lastBlock);
|
|
193
|
+
x.ranges = PackedRanges.pickTo(x.ranges, x.lastBlock);
|
|
179
194
|
});
|
|
180
195
|
await this.storeMeta.upsertMany(metas);
|
|
181
196
|
}
|
|
@@ -184,107 +199,88 @@ export class EventsIndexer <TContract extends ContractBase> {
|
|
|
184
199
|
private async getRanges (events: string[], initialBlockNumber: number, toBlock: number, opts: {
|
|
185
200
|
fromBlock?: number
|
|
186
201
|
filterKey?: string
|
|
187
|
-
}): Promise<
|
|
188
|
-
let fromBlock = opts?.fromBlock ?? initialBlockNumber;
|
|
202
|
+
}): Promise<TRangeLoader> {
|
|
203
|
+
let fromBlock = opts?.fromBlock ?? initialBlockNumber ?? await this.getInitialBlockNumber();
|
|
189
204
|
if (fromBlock != null) {
|
|
190
205
|
$require.lte(fromBlock, toBlock, `Invalid block range order`);
|
|
191
206
|
}
|
|
192
207
|
let logsMetaArr = await this.storeMeta.fetch();
|
|
193
208
|
let eventsBlock = alot(logsMetaArr)
|
|
194
209
|
.filter(x => x.filterKey == opts?.filterKey)
|
|
195
|
-
.toDictionary(x => x.event, x => x
|
|
196
|
-
|
|
197
|
-
|
|
210
|
+
.toDictionary(x => x.event, x => x);
|
|
211
|
+
|
|
212
|
+
let logsMeta = await alot(events).mapAsync(async event => {
|
|
213
|
+
let lastBlock = eventsBlock[event]?.lastBlock ?? initialBlockNumber ?? await this.getInitialBlockNumber();
|
|
214
|
+
let ranges = eventsBlock[event]?.ranges ?? [];
|
|
198
215
|
return {
|
|
199
216
|
event: event,
|
|
200
|
-
lastBlock:
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
let blockNr = opts?.fromBlock ?? await this.getInitialBlockNumber();
|
|
206
|
-
logsMeta.filter(x => x.lastBlock == null).forEach(x => x.lastBlock = blockNr);
|
|
207
|
-
}
|
|
217
|
+
lastBlock: lastBlock,
|
|
218
|
+
ranges: ranges,
|
|
219
|
+
filterKey: opts?.filterKey
|
|
220
|
+
};
|
|
221
|
+
}).toArrayAsync();
|
|
208
222
|
|
|
209
|
-
let
|
|
210
|
-
let
|
|
223
|
+
let intersactionRange = PackedRanges.intersection(logsMeta.map(x => x.ranges));
|
|
224
|
+
let rangesToLoad = PackedRanges.subtract([[fromBlock, toBlock]], intersactionRange);
|
|
211
225
|
|
|
212
|
-
let
|
|
213
|
-
|
|
214
|
-
let [ block ] = blockNumberSteps;
|
|
215
|
-
ranges.push({
|
|
216
|
-
fromBlock: block,
|
|
217
|
-
toBlock: block,
|
|
218
|
-
events: events
|
|
219
|
-
});
|
|
220
|
-
}
|
|
221
|
-
for (let i = 0; i < blockNumberSteps.length - 1; i++) {
|
|
222
|
-
let from = blockNumberSteps[i];
|
|
223
|
-
if (i > 0) {
|
|
224
|
-
// The range includes both blocks: [x, y], but we want (x, y], so we make [x + 1, y]
|
|
225
|
-
from += 1;
|
|
226
|
-
}
|
|
227
|
-
let to = blockNumberSteps[i + 1];
|
|
228
|
-
let events = logsMeta.filter(x => x.lastBlock < to).map(x =>x.event);
|
|
229
|
-
ranges.push({
|
|
226
|
+
let ranges = rangesToLoad.map(([from, to]) => {
|
|
227
|
+
return {
|
|
230
228
|
fromBlock: from,
|
|
231
229
|
toBlock: to,
|
|
232
|
-
events: events
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
230
|
+
events: events,
|
|
231
|
+
filterKey: opts?.filterKey
|
|
232
|
+
} as TRange
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
return {
|
|
236
|
+
fromBlock,
|
|
237
|
+
load: ranges,
|
|
238
|
+
current: logsMeta,
|
|
239
|
+
};
|
|
236
240
|
}
|
|
237
|
-
|
|
238
|
-
|
|
241
|
+
// Save indexed logs every 2 minutes
|
|
242
|
+
private async getPastLogsRanges (ranges: TRangeLoader, events: string[], toBlock: number, fromBlock?: number, options?: TEventLogOptions<any>) {
|
|
239
243
|
const PERSIST_INTERVAL = $date.parseTimespan('2min');
|
|
240
244
|
// Save indexed logs every 10k logs
|
|
241
245
|
const PERSIST_COUNT = 10_000;
|
|
242
246
|
|
|
247
|
+
fromBlock ??= ranges.fromBlock ?? 0;
|
|
248
|
+
|
|
243
249
|
let time = Date.now();
|
|
244
250
|
let contract = this.contract;
|
|
245
251
|
let buffer = [] as ITxLogItem<any>[];
|
|
246
|
-
let isStreamed = options?.streamed ?? false
|
|
252
|
+
let isStreamed = options?.streamed ?? false;
|
|
253
|
+
let infos = {
|
|
254
|
+
cached: 0,
|
|
255
|
+
fetched: 0,
|
|
256
|
+
};
|
|
247
257
|
|
|
258
|
+
let cachedStreamedBuffer = [];
|
|
248
259
|
if (isStreamed && typeof options?.onProgress === 'function') {
|
|
249
|
-
|
|
260
|
+
cachedStreamedBuffer = await this.getItemsFromStore({
|
|
250
261
|
fromBlock: fromBlock,
|
|
251
|
-
toBlock: toBlock,
|
|
262
|
+
toBlock: toBlock + 1,
|
|
252
263
|
events,
|
|
253
264
|
params: options?.params,
|
|
254
265
|
});
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
// }
|
|
274
|
-
|
|
275
|
-
// Adjust ranges to skip blocks already in storage
|
|
276
|
-
for (let i = 0; i < ranges.length; i++) {
|
|
277
|
-
let range = ranges[i];
|
|
278
|
-
if (range.toBlock <= lastBlock) {
|
|
279
|
-
ranges.splice(i, 1);
|
|
280
|
-
i--;
|
|
281
|
-
continue;
|
|
282
|
-
}
|
|
283
|
-
if (range.fromBlock < lastBlock) {
|
|
284
|
-
range.fromBlock = lastBlock + 1;
|
|
285
|
-
}
|
|
286
|
-
}
|
|
287
|
-
}
|
|
266
|
+
infos.cached = cachedStreamedBuffer.length;
|
|
267
|
+
// Note: we don't emit progress right away to keep the order in progress callback
|
|
268
|
+
// Consider: we have blocks [100-150] in cache
|
|
269
|
+
// Requesting range: [50-200]
|
|
270
|
+
// Later we fetch [50-100) and (150-200]
|
|
271
|
+
// The cached response will be inserted after block.100 to keep consistent order
|
|
272
|
+
// if (arr?.length > 0) {
|
|
273
|
+
// let lastBlock = arr[arr.length - 1].blockNumber;
|
|
274
|
+
// await options.onProgress({
|
|
275
|
+
// logs: arr,
|
|
276
|
+
// paged: arr,
|
|
277
|
+
// completed: false,
|
|
278
|
+
// blocksPerSecond: 0,
|
|
279
|
+
// blocks: { total: 0, loaded: 0 },
|
|
280
|
+
// timeLeftSeconds: 0,
|
|
281
|
+
// latestBlock: lastBlock
|
|
282
|
+
// });
|
|
283
|
+
// }
|
|
288
284
|
}
|
|
289
285
|
|
|
290
286
|
let bufferCount = 0;
|
|
@@ -294,8 +290,8 @@ export class EventsIndexer <TContract extends ContractBase> {
|
|
|
294
290
|
let uniqueCount = 0;
|
|
295
291
|
let unique = {};
|
|
296
292
|
|
|
297
|
-
for (let i = 0; i < ranges.length; i++) {
|
|
298
|
-
let range = ranges[i];
|
|
293
|
+
for (let i = 0; i < ranges.load.length; i++) {
|
|
294
|
+
let range = ranges.load[i];
|
|
299
295
|
let { fromBlock, toBlock, events: rangeEvents } = range;
|
|
300
296
|
|
|
301
297
|
let fetched = await contract.getPastLogs(rangeEvents?.length > 0 ? rangeEvents : events, {
|
|
@@ -305,13 +301,14 @@ export class EventsIndexer <TContract extends ContractBase> {
|
|
|
305
301
|
toBlock: toBlock,
|
|
306
302
|
blockRangeLimits: options?.blockRangeLimits,
|
|
307
303
|
params: options?.params,
|
|
308
|
-
onProgress: async
|
|
304
|
+
onProgress: async chunk => {
|
|
309
305
|
onProgressCount++;
|
|
310
306
|
|
|
311
|
-
buffer.push(...
|
|
312
|
-
bufferCount +=
|
|
307
|
+
buffer.push(...chunk.logs);
|
|
308
|
+
bufferCount += chunk.logs.length;
|
|
309
|
+
infos.fetched += chunk.logs.length;
|
|
313
310
|
|
|
314
|
-
for (let log of
|
|
311
|
+
for (let log of chunk.logs) {
|
|
315
312
|
let key = log.id + '';
|
|
316
313
|
if (key in unique) {
|
|
317
314
|
uniqueCount += 1;
|
|
@@ -326,9 +323,9 @@ export class EventsIndexer <TContract extends ContractBase> {
|
|
|
326
323
|
l`OnProgressCalled cyan<${ onProgressCount}> BufferCount cyan<${bufferCount}> SavedCount cyan<${savedCount}> Unique `
|
|
327
324
|
}
|
|
328
325
|
|
|
329
|
-
let isCompleted = i < ranges.length - 1
|
|
326
|
+
let isCompleted = i < ranges.load.length - 1
|
|
330
327
|
? false
|
|
331
|
-
:
|
|
328
|
+
: chunk.completed;
|
|
332
329
|
|
|
333
330
|
let now = Date.now();
|
|
334
331
|
|
|
@@ -341,24 +338,64 @@ export class EventsIndexer <TContract extends ContractBase> {
|
|
|
341
338
|
buffer = [];
|
|
342
339
|
time = now;
|
|
343
340
|
savedCount += arr.length;
|
|
344
|
-
await this.upsert(arr, events,
|
|
341
|
+
await this.upsert(arr, events, ranges, fromBlock, chunk.latestBlock, options);
|
|
345
342
|
}
|
|
346
343
|
|
|
347
344
|
if (options?.onProgress) {
|
|
348
345
|
// completed must be set to true only when the last Range completes
|
|
349
|
-
|
|
350
|
-
|
|
346
|
+
chunk.completed = isCompleted;
|
|
347
|
+
if (cachedStreamedBuffer.length > 0) {
|
|
348
|
+
if (chunk.logs.length > 0) {
|
|
349
|
+
// Preserve the order of logs in progress callback:
|
|
350
|
+
// insert cached.blockNumber < fetched.blockNumber first
|
|
351
|
+
let [ first ] = chunk.logs;
|
|
352
|
+
let i = 0;
|
|
353
|
+
for (; i < cachedStreamedBuffer.length; i++) {
|
|
354
|
+
let x = cachedStreamedBuffer[i];
|
|
355
|
+
if (x.blockNumber > first.blockNumber) {
|
|
356
|
+
break;
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
if (i > 0) {
|
|
360
|
+
let before = cachedStreamedBuffer.splice(0, i);
|
|
361
|
+
chunk.logs = before.concat(chunk.logs);
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
if (isCompleted) {
|
|
365
|
+
// insert everything left from cache
|
|
366
|
+
chunk.logs = chunk.logs.concat(cachedStreamedBuffer);
|
|
367
|
+
cachedStreamedBuffer = [];
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
await options.onProgress({
|
|
371
|
+
...chunk,
|
|
372
|
+
infos,
|
|
373
|
+
});
|
|
351
374
|
}
|
|
352
375
|
}
|
|
353
376
|
});
|
|
354
377
|
|
|
355
378
|
if (buffer.length > 0) {
|
|
356
|
-
await this.upsert(buffer, events, toBlock, options);
|
|
379
|
+
await this.upsert(buffer, events, ranges, fromBlock, toBlock, options);
|
|
357
380
|
}
|
|
358
381
|
}
|
|
359
382
|
|
|
360
|
-
// Upsert final, if buffer is empty, we still persist the "toBlock" value
|
|
361
|
-
await this.upsert(buffer, events, toBlock, options);
|
|
383
|
+
// Upsert final, if buffer is empty, we still persist the "toBlock" value and the ranges
|
|
384
|
+
await this.upsert(buffer, events, ranges, fromBlock, toBlock, options);
|
|
385
|
+
|
|
386
|
+
if (isStreamed && typeof options?.onProgress === 'function' && cachedStreamedBuffer.length > 0) {
|
|
387
|
+
let lastBlock = cachedStreamedBuffer[cachedStreamedBuffer.length - 1].blockNumber;
|
|
388
|
+
await options.onProgress({
|
|
389
|
+
logs: cachedStreamedBuffer,
|
|
390
|
+
paged: cachedStreamedBuffer,
|
|
391
|
+
completed: true,
|
|
392
|
+
blocksPerSecond: 0,
|
|
393
|
+
blocks: { total: 0, loaded: 0 },
|
|
394
|
+
timeLeftSeconds: 0,
|
|
395
|
+
latestBlock: lastBlock,
|
|
396
|
+
infos,
|
|
397
|
+
});
|
|
398
|
+
}
|
|
362
399
|
|
|
363
400
|
if (isStreamed === true) {
|
|
364
401
|
return;
|
|
@@ -371,7 +408,13 @@ export class EventsIndexer <TContract extends ContractBase> {
|
|
|
371
408
|
params: options?.params
|
|
372
409
|
});
|
|
373
410
|
|
|
374
|
-
|
|
411
|
+
infos.fetched = bufferCount;
|
|
412
|
+
infos.cached = logs.length - infos.fetched;
|
|
413
|
+
|
|
414
|
+
return {
|
|
415
|
+
logs,
|
|
416
|
+
infos,
|
|
417
|
+
};
|
|
375
418
|
}
|
|
376
419
|
|
|
377
420
|
|
|
@@ -389,7 +432,7 @@ export class EventsIndexer <TContract extends ContractBase> {
|
|
|
389
432
|
}
|
|
390
433
|
let filterKey = this.getFilterKey(filter.params);
|
|
391
434
|
arr = arr.filter(x => x.filterKey == filterKey);
|
|
392
|
-
return arr;
|
|
435
|
+
return alot(arr).sortBy(x => x.id).toArray();
|
|
393
436
|
}
|
|
394
437
|
private getFilterKey (params) {
|
|
395
438
|
if (params == null) {
|
|
@@ -413,7 +456,14 @@ export class EventsIndexer <TContract extends ContractBase> {
|
|
|
413
456
|
}
|
|
414
457
|
|
|
415
458
|
@memd.deco.queued()
|
|
416
|
-
private async upsert (
|
|
459
|
+
private async upsert (
|
|
460
|
+
logs: TEventsIndexerItem[],
|
|
461
|
+
events: string[],
|
|
462
|
+
ranges: TRangeLoader,
|
|
463
|
+
fromBlock: number,
|
|
464
|
+
latestBlock: number,
|
|
465
|
+
options: { params? }
|
|
466
|
+
) {
|
|
417
467
|
let filterKey = this.getFilterKey(options?.params);
|
|
418
468
|
if (logs?.length > 0) {
|
|
419
469
|
for (let log of logs) {
|
|
@@ -421,11 +471,22 @@ export class EventsIndexer <TContract extends ContractBase> {
|
|
|
421
471
|
}
|
|
422
472
|
await this.store.upsertMany(logs);
|
|
423
473
|
}
|
|
424
|
-
const logsMeta = events.map(event =>
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
474
|
+
const logsMeta = events.map(event => {
|
|
475
|
+
let currentMeta = ranges
|
|
476
|
+
.current
|
|
477
|
+
.find(x => x.event === event);
|
|
478
|
+
|
|
479
|
+
let arr = PackedRanges.union([
|
|
480
|
+
currentMeta?.ranges ?? [],
|
|
481
|
+
[[fromBlock, latestBlock]]
|
|
482
|
+
]);
|
|
483
|
+
return {
|
|
484
|
+
event,
|
|
485
|
+
lastBlock: latestBlock,
|
|
486
|
+
filterKey: filterKey,
|
|
487
|
+
ranges: arr,
|
|
488
|
+
};
|
|
489
|
+
});
|
|
429
490
|
await this.storeMeta.upsertMany(logsMeta);
|
|
430
491
|
}
|
|
431
492
|
}
|
|
@@ -434,8 +495,15 @@ type TRange = {
|
|
|
434
495
|
events: string[]
|
|
435
496
|
fromBlock: number
|
|
436
497
|
toBlock: number
|
|
498
|
+
filterKey?: string
|
|
437
499
|
}
|
|
438
500
|
|
|
439
501
|
|
|
502
|
+
type TRangeLoader = {
|
|
503
|
+
fromBlock: number
|
|
504
|
+
current: TEventsIndexerMeta[]
|
|
505
|
+
load: TRange[]
|
|
506
|
+
}
|
|
507
|
+
|
|
440
508
|
type GetEventLogNames<T extends ContractBase> = keyof T['Types']['Events'];
|
|
441
509
|
type GetTypes<T extends ContractBase> = T['Types'];
|
package/src/rpc/RpcContract.ts
CHANGED
|
@@ -92,40 +92,59 @@ export class RpcContract {
|
|
|
92
92
|
return alot(requests).mapAsync(req => this.getCallRequestRaw(req)).toArrayAsync();
|
|
93
93
|
}
|
|
94
94
|
private async getCallRequestRaw (request: TRpcContractCall) {
|
|
95
|
-
let
|
|
95
|
+
let {
|
|
96
|
+
tx,
|
|
97
|
+
abiItem,
|
|
98
|
+
blockNumber
|
|
99
|
+
} = await RpcContract.createCalldata(request, this.defaults);
|
|
100
|
+
|
|
101
|
+
let rpc = new Rpc();
|
|
102
|
+
return {
|
|
103
|
+
methodRequest: rpc.req.eth_call(tx, blockNumber ?? 'latest'),
|
|
104
|
+
methodAbi: abiItem
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
static async createCalldata (request: TRpcContractCall, options?: {
|
|
110
|
+
client?: Web3Client
|
|
111
|
+
address?: TEth.Address
|
|
112
|
+
abi?: TAbiItem[]
|
|
113
|
+
}) {
|
|
114
|
+
let address = request.address ?? options?.address;
|
|
96
115
|
$require.Address(address);
|
|
97
116
|
|
|
98
117
|
let data = request.data;
|
|
99
118
|
let { abi, method, params, blockNumber } = request;
|
|
100
|
-
let abiArr = $web3Abi.ensureAbis(abi ??
|
|
119
|
+
let abiArr = $web3Abi.ensureAbis(abi ?? options?.abi);
|
|
101
120
|
let abiItem = abiArr?.find(x => x.name === method);
|
|
102
121
|
if (abiItem == null) {
|
|
103
|
-
abiItem =
|
|
122
|
+
abiItem = options?.abi?.find(x => x.name === method);
|
|
104
123
|
}
|
|
105
124
|
|
|
106
125
|
if (data == null) {
|
|
107
126
|
$require.notNull(abiItem, `Method ${method} not found. Available methods: ${abiArr?.map(x => x.name) }`);
|
|
108
127
|
data = $abiUtils.serializeMethodCallData(abiItem, params ?? []);
|
|
109
128
|
}
|
|
129
|
+
|
|
110
130
|
if (blockNumber instanceof Date) {
|
|
111
|
-
let
|
|
131
|
+
let client = $require.notNull(options?.client, `Blocknumber is Date: ${blockNumber}, Client is required.`);
|
|
132
|
+
let resolver = di.resolve(BlockDateResolver, client);
|
|
112
133
|
blockNumber = await resolver.getBlockNumberFor(blockNumber);
|
|
113
134
|
}
|
|
114
|
-
|
|
115
|
-
from: request.from ?? void 0,
|
|
116
|
-
to: address,
|
|
117
|
-
value: $hex.ensure(request.value ?? 0n),
|
|
118
|
-
data: data,
|
|
119
|
-
};
|
|
120
|
-
let rpc = new Rpc();
|
|
135
|
+
|
|
121
136
|
return {
|
|
122
|
-
|
|
123
|
-
|
|
137
|
+
tx: {
|
|
138
|
+
from: request.from ?? void 0,
|
|
139
|
+
to: address,
|
|
140
|
+
value: $hex.ensure(request.value ?? 0n),
|
|
141
|
+
data: data,
|
|
142
|
+
},
|
|
143
|
+
abiItem,
|
|
144
|
+
blockNumber
|
|
124
145
|
};
|
|
125
146
|
}
|
|
126
147
|
|
|
127
|
-
|
|
128
|
-
|
|
129
148
|
// async submit (contract: TRpcContract, req: TRpcContractCallReq) {
|
|
130
149
|
// let abis = contract.abi;
|
|
131
150
|
// let abi = abis.find(x => x.name === req.method);
|
|
@@ -12,7 +12,11 @@ export interface ISafeServiceTransport {
|
|
|
12
12
|
|
|
13
13
|
confirmTx(safeTxHash: string, sig: { signature: string, owner: TAddress }): Promise<SafeServiceTypes.SignatureResponse>
|
|
14
14
|
|
|
15
|
-
getSafeInfo(safeAddress: TAddress): Promise<{
|
|
15
|
+
getSafeInfo(safeAddress: TAddress): Promise<{
|
|
16
|
+
pending?: number
|
|
17
|
+
nonce: number
|
|
18
|
+
threshold: number
|
|
19
|
+
}>
|
|
16
20
|
|
|
17
21
|
estimateSafeTransaction(safeAddress: TAddress, safeTxEstimation): Promise<SafeServiceTypes.SafeMultisigTransactionEstimateResponse>
|
|
18
22
|
|
|
@@ -101,10 +101,21 @@ class SafeServiceClientInner {
|
|
|
101
101
|
return data;
|
|
102
102
|
}
|
|
103
103
|
|
|
104
|
-
async getSafeInfo(safeAddress: string): Promise<SafeServiceTypes.SafeInfoResponse> {
|
|
105
|
-
let
|
|
106
|
-
let { data } = await $http.get<SafeServiceTypes.SafeInfoResponse>(
|
|
107
|
-
|
|
104
|
+
async getSafeInfo(safeAddress: string): Promise<SafeServiceTypes.SafeInfoResponse & { pending?: number}> {
|
|
105
|
+
let safeUrl = `${this.params.txServiceUrl}/api/v1/safes/${safeAddress}`;
|
|
106
|
+
let { data: safeInfo } = await $http.get<SafeServiceTypes.SafeInfoResponse>(safeUrl);
|
|
107
|
+
|
|
108
|
+
let pendingUrl = `${this.params.txServiceUrl}/api/v1/safes/${safeAddress}/multisig-transactions/?executed=false&ordering=-nonce&limit=1`
|
|
109
|
+
let { data: pendingTxs } = await $http.get<SafeServiceTypes.SafeMultisigTransactionListResponse>(pendingUrl);
|
|
110
|
+
let nonce = Number(safeInfo.nonce);
|
|
111
|
+
let pending = 0;
|
|
112
|
+
if (pendingTxs.results?.length > 0) {
|
|
113
|
+
pending = $require.Number(Number(pendingTxs.results[0].nonce) + 1 - nonce);
|
|
114
|
+
}
|
|
115
|
+
return {
|
|
116
|
+
...safeInfo,
|
|
117
|
+
pending
|
|
118
|
+
};
|
|
108
119
|
}
|
|
109
120
|
|
|
110
121
|
async estimateSafeTransaction(safeAddress: string, safeTransaction: SafeServiceTypes.SafeMultisigTransactionEstimate): Promise<SafeServiceTypes.SafeMultisigTransactionEstimateResponse> {
|
package/src/txs/TxWriter.ts
CHANGED
|
@@ -296,7 +296,9 @@ export class TxWriter extends class_EventEmitter<ITxWriterEvents> implements ITx
|
|
|
296
296
|
tx.hash = hash;
|
|
297
297
|
this.onSent.resolve(hash);
|
|
298
298
|
this.emit('transactionHash', hash);
|
|
299
|
-
this.
|
|
299
|
+
if (this.client.platform !== 'hardhat') {
|
|
300
|
+
this.emit('log', `Tx hash: ${hash}`);
|
|
301
|
+
}
|
|
300
302
|
})
|
|
301
303
|
// .on('confirmation', (confNumber, receipt) => {
|
|
302
304
|
// tx.hash = receipt.transactionHash ?? tx.hash;
|
|
@@ -344,7 +346,9 @@ export class TxWriter extends class_EventEmitter<ITxWriterEvents> implements ITx
|
|
|
344
346
|
let hash = tx.hash;
|
|
345
347
|
let status = receipt.status;
|
|
346
348
|
let gasFormatted = $gas.formatUsed(this.builder.data, <any>receipt);
|
|
347
|
-
|
|
349
|
+
|
|
350
|
+
let message = `${status ? '✓' : '✕'} ${gasFormatted} ${hash}`;
|
|
351
|
+
this.emit('log', message);
|
|
348
352
|
|
|
349
353
|
this.onCompleted.resolve(receipt);
|
|
350
354
|
} catch (error) {
|
package/src/utils/$contract.ts
CHANGED
|
@@ -299,8 +299,8 @@ export namespace $contract {
|
|
|
299
299
|
address?: TEth.Address
|
|
300
300
|
abi: TAbiItem[]
|
|
301
301
|
}
|
|
302
|
-
|
|
303
|
-
|
|
302
|
+
let knownContracts = [] as IContractMeta[];
|
|
303
|
+
let knownContractsAddresses = {} as Record<string, IContractMeta>
|
|
304
304
|
|
|
305
305
|
export function getFlattened() {
|
|
306
306
|
return alot(knownContracts).mapMany(x => x.abi).toArray();
|
|
@@ -332,6 +332,11 @@ export namespace $contract {
|
|
|
332
332
|
return $abiUtils.getMethodSignature(item) === selector;
|
|
333
333
|
});
|
|
334
334
|
}
|
|
335
|
+
|
|
336
|
+
export function clear () {
|
|
337
|
+
knownContracts = [];
|
|
338
|
+
knownContractsAddresses = {};
|
|
339
|
+
}
|
|
335
340
|
}
|
|
336
341
|
|
|
337
342
|
function formatJson(json) {
|