@ocap/indexdb 1.28.9 → 1.29.1

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/util.js DELETED
@@ -1,634 +0,0 @@
1
- const get = require('lodash/get');
2
- const uniq = require('lodash/uniq');
3
- const pick = require('lodash/pick');
4
- const uniqBy = require('lodash/uniqBy');
5
- const { createSortedList } = require('@ocap/util/lib/create-sorted-list');
6
- const { BN } = require('@ocap/util');
7
-
8
- const formatTokenMeta = (token, tokenStates, ...rest) => {
9
- if (!tokenStates) {
10
- return token;
11
- }
12
-
13
- const tokenState = tokenStates.filter(Boolean).find((x) => x.address === token.address);
14
- if (tokenState) {
15
- token.decimal = tokenState.decimal;
16
- token.unit = tokenState.unit;
17
- token.symbol = tokenState.symbol;
18
- token.icon = tokenState.icon;
19
- } else {
20
- console.warn('Invalid token state on formatting', token, tokenStates, ...rest);
21
- }
22
-
23
- return token;
24
- };
25
-
26
- const createIndexedAccount = async (x, getTokenFn) => {
27
- const tasks = Object.keys(x.tokens || {}).map((address) => getTokenFn(address));
28
- const tokenStates = await Promise.all(tasks);
29
-
30
- return {
31
- address: x.address,
32
- balance: x.balance || '0',
33
- moniker: x.moniker,
34
- nonce: x.nonce,
35
- numAssets: x.numAssets || 0,
36
- numTxs: x.numTxs || 0,
37
- recentNumTxs: [],
38
- renaissanceTime: x.context.renaissanceTime,
39
- tokens: Object.keys(x.tokens || {}).map((address) =>
40
- formatTokenMeta({ address, balance: x.tokens[address] }, tokenStates)
41
- ),
42
- genesisTime: x.context.genesisTime,
43
- migratedTo: x.migratedTo[0] || '',
44
- migratedFrom: x.migratedFrom[0] || '',
45
- };
46
- };
47
-
48
- const createIndexedAsset = (x) => ({
49
- address: x.address,
50
- issuer: x.issuer,
51
- moniker: x.moniker,
52
- owner: x.owner,
53
- parent: x.parent,
54
- readonly: x.readonly,
55
- transferrable: x.transferrable,
56
- ttl: x.ttl,
57
- consumedTime: x.consumedTime,
58
- genesisTime: x.context.genesisTime,
59
- renaissanceTime: x.context.renaissanceTime,
60
- data: x.data,
61
- display: x.display,
62
- endpoint: x.endpoint,
63
- tags: x.tags,
64
- });
65
-
66
- const createIndexedDelegation = (x, ctx) => {
67
- const result = {
68
- address: x.address,
69
- data: x.data,
70
- genesisTime: x.context.genesisTime,
71
- renaissanceTime: x.context.renaissanceTime,
72
- // https://discuss.elastic.co/t/updating-an-object-field/110735
73
- ops: [x.ops],
74
- };
75
- if (x.from) {
76
- result.from = x.from;
77
- } else if (ctx.senderState) {
78
- result.from = get(ctx, 'senderState.address', '');
79
- } else {
80
- result.from = get(ctx, 'tx.from', '');
81
- }
82
- if (x.to) {
83
- result.to = x.to;
84
- } else if (ctx.receiverState) {
85
- result.to = get(ctx, 'receiverState.address', '');
86
- } else {
87
- result.to = get(ctx, 'itx.to', '');
88
- }
89
- return result;
90
- };
91
-
92
- const createIndexedToken = (x) => ({
93
- address: x.address,
94
- issuer: x.issuer,
95
- name: x.name,
96
- description: x.description,
97
- symbol: x.symbol,
98
- unit: x.unit,
99
- decimal: x.decimal,
100
- icon: x.icon,
101
- website: x.website,
102
- totalSupply: x.totalSupply,
103
- initialSupply: x.initialSupply,
104
- maxTotalSupply: x.maxTotalSupply,
105
- foreignToken: x.foreignToken,
106
- tokenFactoryAddress: x.tokenFactoryAddress,
107
- metadata: x.metadata,
108
- spenders: x.spenders,
109
- minters: x.minters,
110
- type: x.type,
111
- data: x.data,
112
- genesisTime: x.context.genesisTime,
113
- renaissanceTime: x.context.renaissanceTime,
114
- });
115
-
116
- const createIndexedTokenFactory = (tokenFactory, context) => {
117
- return {
118
- ...pick(tokenFactory, [
119
- 'address',
120
- 'owner',
121
- 'tokenAddress',
122
- 'reserveAddress',
123
- 'curve',
124
- 'feeRate',
125
- 'currentSupply',
126
- 'reserveBalance',
127
- 'status',
128
- 'data',
129
- ]),
130
- token: formatTokenMeta({ address: tokenFactory.tokenAddress }, [context.itx.token]),
131
- reserveToken: formatTokenMeta({ address: tokenFactory.reserveAddress }, [context.config.token]),
132
- genesisTime: tokenFactory.context.genesisTime,
133
- renaissanceTime: tokenFactory.context.renaissanceTime,
134
- };
135
- };
136
-
137
- const createIndexedFactory = (factory, context) => {
138
- if (context.factoryTokens && context.factoryTokens.length > 0) {
139
- factory.input.tokens = factory.input.tokens.map((token) => formatTokenMeta(token, context.tokenStates));
140
- }
141
- return {
142
- ...pick(factory, [
143
- 'address',
144
- 'owner',
145
- 'name',
146
- 'description',
147
- 'settlement',
148
- 'limit',
149
- 'trustedIssuers',
150
- 'input',
151
- 'output',
152
- 'hooks',
153
- 'data',
154
- 'numMinted',
155
- 'lastSettlement',
156
- 'balance',
157
- 'display',
158
- ]),
159
- tokens: Object.keys(factory.tokens || {}).map((address) =>
160
- formatTokenMeta({ address, balance: factory.tokens[address] }, context.tokenStates)
161
- ),
162
- genesisTime: factory.context.genesisTime,
163
- renaissanceTime: factory.context.renaissanceTime,
164
- };
165
- };
166
-
167
- // These fields are used internally to filter transactions by some entity
168
- const createIndexedTransaction = async (tx, ctx, indexdb) => {
169
- tx.accounts = [tx.tx.from, tx.sender, tx.receiver];
170
- tx.assets = [];
171
- tx.tokens = [];
172
- tx.factories = [];
173
- tx.stakes = [];
174
- tx.rollups = [];
175
- tx.delegations = [];
176
- tx.tokenFactories = [];
177
-
178
- tx.valid = tx.code === 'OK';
179
-
180
- // accounts
181
- if (ctx.senderState) {
182
- tx.accounts.push(ctx.senderState.address);
183
- }
184
- if (ctx.receiverState) {
185
- tx.accounts.push(ctx.receiverState.address);
186
- }
187
- if (ctx.feeVaultState && ctx.feeVaultChange) {
188
- tx.accounts.push(ctx.feeVaultState.address);
189
- }
190
- if (ctx.gasVaultState && ctx.gasVaultChange) {
191
- tx.accounts.push(ctx.gasVaultState.address);
192
- }
193
- if (ctx.updatedAccounts && Array.isArray(ctx.updatedAccounts)) {
194
- tx.accounts.push(...ctx.updatedAccounts.map((x) => x.address));
195
- }
196
- if (ctx.delegatorState) {
197
- tx.accounts.push(ctx.delegatorState.address);
198
- }
199
- if (ctx.delegationState) {
200
- tx.delegations.push(ctx.delegationState.address);
201
- }
202
- if (ctx.delegationState && ctx.txType === 'fg:t:revoke_delegate') {
203
- const indexed = await indexdb.delegation.get(ctx.delegationState.address);
204
- if (indexed) {
205
- tx.accounts.push(indexed.to);
206
- }
207
- }
208
- if (Array.isArray(ctx.delegatorStates)) {
209
- tx.accounts.push(...ctx.delegatorStates.map((x) => x.address));
210
- }
211
- if (Array.isArray(ctx.signerStates)) {
212
- tx.accounts.push(...ctx.signerStates.map((x) => x.address));
213
- }
214
- if (Array.isArray(ctx.receiverStates)) {
215
- tx.accounts.push(...ctx.receiverStates.map((x) => x.address));
216
- }
217
-
218
- // assets
219
- if (ctx.assetState) {
220
- tx.assets.push(ctx.assetState.address);
221
- // index update asset for owners, so that wallet can sync this tx
222
- if (ctx.txType === 'fg:t:update_asset') {
223
- tx.accounts.push(ctx.assetState.owner);
224
- }
225
- if (ctx.txType === 'fg:t:mint_asset') {
226
- tx.accounts.push(ctx.ownerAddress);
227
- }
228
- }
229
- if (ctx.assetStates && Array.isArray(ctx.assetStates)) {
230
- tx.assets.push(...ctx.assetStates.map((x) => x.address));
231
- }
232
-
233
- // tokens
234
- if (ctx.tokenState) {
235
- tx.tokens.push(ctx.tokenState.address);
236
- }
237
- if (ctx.tokenStates && Array.isArray(ctx.tokenStates)) {
238
- tx.tokens.push(...ctx.tokenStates.map((x) => x.address));
239
- }
240
-
241
- // factories
242
- if (ctx.factoryState) {
243
- tx.factories.push(ctx.factoryState.address);
244
- }
245
-
246
- // stakes
247
- if (ctx.stakeState) {
248
- tx.stakes.push(ctx.stakeState.address);
249
- if (ctx.txType === 'fg:t:slash_stake') {
250
- tx.accounts.push(ctx.stakeState.sender);
251
- }
252
- if (ctx.txType === 'fg:t:return_stake') {
253
- tx.accounts.push(ctx.stakeState.sender);
254
- }
255
- }
256
- if (Array.isArray(ctx.stakeStates)) {
257
- tx.stakes.push(...ctx.stakeStates.map((x) => x.address));
258
- }
259
-
260
- // rollups
261
- if (ctx.rollupState) {
262
- tx.rollups.push(ctx.rollupState.address);
263
- }
264
-
265
- // token factories
266
- if (ctx.tokenFactoryState) {
267
- tx.tokenFactories.push(ctx.tokenFactoryState.address);
268
- }
269
-
270
- const pickedFields = ['address', 'symbol', 'decimal', 'unit'];
271
- if (Array.isArray(ctx.tokenStates)) {
272
- tx.tokenSymbols = ctx.tokenStates.map((t) => pick(t, pickedFields));
273
- } else if (ctx.tokenState) {
274
- tx.tokenSymbols = [pick(ctx.tokenState, pickedFields)];
275
- } else {
276
- tx.tokenSymbols = [];
277
- }
278
-
279
- tx.accounts = [...tx.accounts, ...tx.stakes];
280
-
281
- return tx;
282
- };
283
-
284
- const createIndexedStake = async (x, ctx, indexdb) => {
285
- const tokens = uniq(Object.keys(x.tokens || {}).concat(Object.keys(x.revokedTokens || {})));
286
- const existTokenStates = ctx.tokenStates || [];
287
- const missingTokenStates = await Promise.all(
288
- tokens.filter((a) => !existTokenStates.find((t) => t.address === a)).map((t) => indexdb.token.get(t))
289
- );
290
- const tokenStates = [...existTokenStates, ...missingTokenStates];
291
- return {
292
- ...pick(x, [
293
- 'address',
294
- 'sender',
295
- 'receiver',
296
- 'assets',
297
- 'slashers',
298
- 'revocable',
299
- 'data',
300
- 'nonce',
301
- 'message',
302
- 'revokeWaitingPeriod',
303
- 'revokedAssets',
304
- ]),
305
- tokens: Object.keys(x.tokens || {}).map((address) =>
306
- formatTokenMeta({ address, balance: x.tokens[address] }, tokenStates, x)
307
- ),
308
- revokedTokens: Object.keys(x.revokedTokens || {}).map((address) =>
309
- formatTokenMeta({ address, balance: x.revokedTokens[address] }, tokenStates)
310
- ),
311
- genesisTime: x.context.genesisTime,
312
- renaissanceTime: x.context.renaissanceTime,
313
- };
314
- };
315
-
316
- const createIndexedRollup = (x, ctx) => {
317
- const rollup = {
318
- ...pick(x, [
319
- 'address',
320
- 'paused',
321
- 'closed',
322
- 'tokenAddress',
323
- 'vaultAddress',
324
- 'contractAddress',
325
- 'seedValidators',
326
- 'validators',
327
- 'minStakeAmount',
328
- 'maxStakeAmount',
329
- 'minSignerCount',
330
- 'maxSignerCount',
331
- 'minBlockSize',
332
- 'maxBlockSize',
333
- 'minBlockInterval',
334
- 'minBlockConfirmation',
335
- 'minDepositAmount',
336
- 'maxDepositAmount',
337
- 'minWithdrawAmount',
338
- 'maxWithdrawAmount',
339
- 'depositFeeRate',
340
- 'withdrawFeeRate',
341
- 'proposerFeeShare',
342
- 'publisherFeeShare',
343
- 'minDepositFee',
344
- 'maxDepositFee',
345
- 'minWithdrawFee',
346
- 'maxWithdrawFee',
347
- 'issuer',
348
- 'blockHeight',
349
- 'blockHash',
350
- 'leaveWaitingPeriod',
351
- 'publishWaitingPeriod',
352
- 'publishSlashRate',
353
- 'migrateHistory',
354
- 'vaultHistory',
355
- 'data',
356
- ]),
357
- genesisTime: x.context.genesisTime,
358
- renaissanceTime: x.context.renaissanceTime,
359
- };
360
-
361
- if (ctx.tokenStates) {
362
- const tokenState = ctx.tokenStates.find((t) => t.address === x.tokenAddress);
363
- rollup.tokenInfo = formatTokenMeta({ address: x.tokenAddress, value: '0' }, ctx.tokenStates);
364
- rollup.foreignToken = tokenState.foreignToken;
365
- }
366
-
367
- return rollup;
368
- };
369
-
370
- const createIndexedRollupBlock = (x, ctx) => {
371
- return {
372
- ...pick(x, [
373
- 'hash',
374
- 'height',
375
- 'merkleRoot',
376
- 'previousHash',
377
- 'txsHash',
378
- 'txs',
379
- 'proposer',
380
- 'signatures',
381
- 'rollup',
382
- 'mintedAmount',
383
- 'burnedAmount',
384
- 'rewardAmount',
385
- 'minReward',
386
- 'governance',
387
- 'data',
388
- ]),
389
- genesisTime: x.context.genesisTime,
390
- renaissanceTime: x.context.renaissanceTime,
391
- tokenInfo: formatTokenMeta({ address: ctx.rollupState.tokenAddress, value: '0' }, ctx.tokenStates),
392
- validators: (x.signaturesList || x.signatures || []).map((v) => v.signer),
393
- };
394
- };
395
-
396
- const createIndexedTokenDistribution = (x) => {
397
- return {
398
- ...pick(x, 'tokenAddress', 'txTime'),
399
- account: x.account.toString(),
400
- gas: x.gas.toString(),
401
- fee: x.fee.toString(),
402
- slashedVault: x.slashedVault.toString(),
403
- stake: x.stake.toString(),
404
- revokedStake: x.revokedStake.toString(),
405
- gasStake: x.gasStake.toString(),
406
- };
407
- };
408
-
409
- const formatTxBeforeInsert = (row) => {
410
- const tx = { ...row };
411
- tx.sender = tx.sender || '';
412
- tx.receiver = tx.receiver || '';
413
-
414
- // index assets
415
- tx.assets = tx.assets || [];
416
- if (['transfer', 'transfer_v2'].includes(tx.type) && tx.tx.itxJson.assets) {
417
- tx.assets.push(...tx.tx.itxJson.assets);
418
- } else if (['transfer_v3', 'stake'].includes(tx.type)) {
419
- tx.assets.push(...createSortedList(tx.tx.itxJson.inputs.map((x) => x.assets)));
420
- } else if (['revoke_stake', 'slash_stake', 'return_stake'].includes(tx.type)) {
421
- tx.assets.push(...createSortedList(tx.tx.itxJson.outputs.map((x) => x.assets)));
422
- } else if (['exchange', 'exchange_v2'].includes(tx.type)) {
423
- tx.assets.push(...(tx.tx.itxJson.sender.assets || []), ...(tx.tx.itxJson.receiver.assets || []));
424
- } else if (['create_asset', 'update_asset', 'acquire_asset_v2', 'mint_asset'].includes(tx.type)) {
425
- tx.assets.push(tx.tx.itxJson.address);
426
- }
427
-
428
- // index factories
429
- tx.factories = tx.factories || [];
430
- if (['acquire_asset_v2', 'acquire_asset_v3', 'mint_asset', 'create_factory'].includes(tx.type)) {
431
- tx.factories.push(tx.tx.itxJson.factory);
432
- }
433
-
434
- // index tokens
435
- tx.tokens = tx.tokens || [];
436
- if (tx.type === 'transfer_v2' && tx.tx.itxJson.tokens) {
437
- tx.tokens.push(...tx.tx.itxJson.tokens.map((x) => x.address));
438
- } else if (['transfer_v3', 'stake'].includes(tx.type)) {
439
- tx.tokens.push(...createSortedList(tx.tx.itxJson.inputs.map((x) => x.tokens.map((t) => t.address))));
440
- } else if (['revoke_stake', 'slash_stake', 'return_stake'].includes(tx.type)) {
441
- tx.tokens.push(...createSortedList(tx.tx.itxJson.outputs.map((x) => x.tokens.map((t) => t.address))));
442
- } else if (tx.type === 'exchange_v2') {
443
- tx.tokens.push(
444
- ...(tx.tx.itxJson.sender.tokens || []).map((x) => x.address),
445
- ...(tx.tx.itxJson.receiver.tokens || []).map((x) => x.address)
446
- );
447
- }
448
-
449
- tx.accounts = tx.accounts || [];
450
- tx.stakes = tx.stakes || [];
451
-
452
- tx.assets = uniq(tx.assets).filter(Boolean);
453
- tx.factories = uniq(tx.factories).filter(Boolean);
454
- tx.tokens = uniq(tx.tokens).filter(Boolean);
455
- tx.accounts = uniq(tx.accounts).filter(Boolean);
456
- tx.stakes = uniq(tx.stakes).filter(Boolean);
457
- tx.rollups = uniq(tx.rollups).filter(Boolean);
458
- tx.tokenSymbols = uniqBy(tx.tokenSymbols, 'address');
459
-
460
- return tx;
461
- };
462
-
463
- const formatTxAfterRead = (tx) => {
464
- delete tx.assets;
465
- delete tx.factories;
466
- delete tx.tokens;
467
- delete tx.accounts;
468
- delete tx.stakes;
469
- delete tx.rollups;
470
- delete tx.delegations;
471
-
472
- return tx;
473
- };
474
-
475
- const formatDelegationAfterRead = (delegation) => {
476
- // https://discuss.elastic.co/t/updating-an-object-field/110735
477
- const ops = Array.isArray(delegation.ops) ? delegation.ops[0] : delegation.ops;
478
- delegation.ops = Object.keys(ops).map((x) => ({ key: x, value: ops[x] }));
479
- return delegation;
480
- };
481
-
482
- const parseDateTime = (str) => {
483
- if (!str) {
484
- return '';
485
- }
486
-
487
- const parsed = Date.parse(str);
488
- if (Number.isNaN(parsed)) {
489
- return '';
490
- }
491
-
492
- return new Date(parsed).toISOString();
493
- };
494
-
495
- const PAGE_SIZE_DEFAULT = 20;
496
- const PAGE_SIZE_MAX = 100;
497
-
498
- const formatPagination = ({ paging, defaultSortField, supportedSortFields = [] }) => {
499
- if (!defaultSortField) {
500
- throw new Error('argument defaultSortField is required');
501
- }
502
-
503
- const pagination = paging || { size: PAGE_SIZE_DEFAULT };
504
- if (Array.isArray(pagination.order)) {
505
- [pagination.order] = pagination.order;
506
- }
507
-
508
- if (!pagination.order) {
509
- pagination.order = { field: defaultSortField, type: 'desc' };
510
- }
511
-
512
- if (!pagination.order.field) {
513
- pagination.order.field = defaultSortField;
514
- }
515
-
516
- if (supportedSortFields.length > 0 && !supportedSortFields.includes(pagination.order.field)) {
517
- pagination.order.field = defaultSortField;
518
- }
519
-
520
- if (!pagination.order.type) {
521
- pagination.order.type = 'desc';
522
- }
523
-
524
- if (pagination.size === null || typeof pagination.size === 'undefined') {
525
- pagination.size = PAGE_SIZE_DEFAULT;
526
- }
527
-
528
- // Since Elasticsearch does not support cursor based pagination, we just use offset as cursor
529
- if (pagination.cursor) {
530
- pagination.cursor = Number(pagination.cursor);
531
- } else {
532
- pagination.cursor = 0;
533
- }
534
-
535
- pagination.size = Math.min(pagination.size, PAGE_SIZE_MAX);
536
-
537
- return pagination;
538
- };
539
-
540
- const formatNextPagination = (total, pagination) => {
541
- const nextCursor = pagination.cursor + pagination.size;
542
- if (total > nextCursor) {
543
- return { cursor: nextCursor, next: true, total };
544
- }
545
-
546
- return { cursor: '0', next: false, total };
547
- };
548
-
549
- const isDefaultTokenChanged = (tx, token) => {
550
- const itx = tx.tx.itxJson;
551
- if (
552
- [
553
- 'fg:t:transfer',
554
- 'fg:t:transfer_v2',
555
- 'fg:t:transfer_v3',
556
- 'fg:t:acquire_asset_v2',
557
- 'fg:t:acquire_asset_v3',
558
- 'fg:t:exchange',
559
- 'fg:t:exchange_v2',
560
- 'fg:t:deposit_token',
561
- 'fg:t:withdraw_token',
562
- 'fg:t:faucet',
563
- 'fg:t:poke',
564
- 'fg:t:setup_swap',
565
- 'fg:t:retrieve_swap',
566
- 'fg:t:stake',
567
- 'fg:t:revoke_stake',
568
- ].includes(itx.type_url) === false
569
- ) {
570
- return false;
571
- }
572
-
573
- const ZERO = new BN(0);
574
- const isDefaultToken = (id) => [token.address, ''].includes(id);
575
- const isPositive = (v) => new BN(v || 0).gt(ZERO);
576
- const isChangedByInput = (input) =>
577
- isPositive(input.value) || input.tokens.some((x) => isDefaultToken(x.address) && isPositive(x.value));
578
-
579
- switch (itx.type_url) {
580
- case 'fg:t:transfer':
581
- return isPositive(itx.value);
582
- case 'fg:t:transfer_v2':
583
- return isChangedByInput(itx);
584
- case 'fg:t:transfer_v3':
585
- case 'fg:t:acquire_asset_v3':
586
- return itx.inputs.some(isChangedByInput);
587
- case 'fg:t:acquire_asset_v2':
588
- return tx.receipts.some((r) => r.changes.some((c) => isDefaultToken(c.target) && isPositive(c.value)));
589
- case 'fg:t:exchange':
590
- return isPositive(itx.sender.value) || isPositive(itx.receiver.value);
591
- case 'fg:t:exchange_v2':
592
- return isChangedByInput(itx.sender) || isChangedByInput(itx.receiver);
593
- case 'fg:t:deposit_token':
594
- case 'fg:t:withdraw_token':
595
- return isPositive(itx.value);
596
- case 'fg:t:setup_swap':
597
- case 'fg:t:retrieve_swap':
598
- return isPositive(itx.value);
599
- case 'fg:t:poke':
600
- return true;
601
- case 'fg:t:faucet':
602
- return !itx.token;
603
- case 'fg:t:stake':
604
- return itx.inputs.some(isChangedByInput);
605
- case 'fg:t:revoke_stake':
606
- case 'fg:t:slash_stake':
607
- case 'fg:t:return_stake':
608
- return itx.outputs.some(isChangedByInput);
609
- default:
610
- return false;
611
- }
612
- };
613
-
614
- module.exports = {
615
- createIndexedAccount,
616
- createIndexedAsset,
617
- createIndexedFactory,
618
- createIndexedTokenFactory,
619
- createIndexedDelegation,
620
- createIndexedToken,
621
- createIndexedTransaction,
622
- createIndexedStake,
623
- createIndexedRollup,
624
- createIndexedRollupBlock,
625
- createIndexedTokenDistribution,
626
- formatPagination,
627
- formatNextPagination,
628
- formatTxAfterRead,
629
- formatTxBeforeInsert,
630
- parseDateTime,
631
- formatTokenMeta,
632
- isDefaultTokenChanged,
633
- formatDelegationAfterRead,
634
- };