@ocap/indexdb 1.28.8 → 1.29.0
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 +1 -1
- package/esm/db.d.mts +40 -0
- package/esm/db.mjs +62 -0
- package/esm/index.d.mts +58 -0
- package/esm/index.mjs +91 -0
- package/esm/main.d.mts +4 -0
- package/esm/main.mjs +5 -0
- package/esm/util.d.mts +374 -0
- package/esm/util.mjs +556 -0
- package/lib/_virtual/rolldown_runtime.cjs +29 -0
- package/lib/db.cjs +64 -0
- package/lib/db.d.cts +40 -0
- package/lib/index.cjs +96 -0
- package/lib/index.d.cts +58 -0
- package/lib/main.cjs +25 -0
- package/lib/main.d.cts +4 -0
- package/lib/util.cjs +579 -0
- package/lib/util.d.cts +374 -0
- package/package.json +37 -8
- package/lib/db.js +0 -61
- package/lib/index.js +0 -79
- package/lib/main.js +0 -4
- package/lib/util.js +0 -634
package/esm/util.mjs
ADDED
|
@@ -0,0 +1,556 @@
|
|
|
1
|
+
import { BN } from "@ocap/util";
|
|
2
|
+
import { createSortedList } from "@ocap/util/lib/create-sorted-list";
|
|
3
|
+
import get from "lodash/get.js";
|
|
4
|
+
import pick from "lodash/pick.js";
|
|
5
|
+
import uniq from "lodash/uniq.js";
|
|
6
|
+
import uniqBy from "lodash/uniqBy.js";
|
|
7
|
+
|
|
8
|
+
//#region src/util.ts
|
|
9
|
+
/**
|
|
10
|
+
* Format token with metadata from token states
|
|
11
|
+
* @param token - Token with address
|
|
12
|
+
* @param tokenStates - Array of token states for metadata lookup
|
|
13
|
+
* @param rest - Additional args for debug logging
|
|
14
|
+
*/
|
|
15
|
+
const formatTokenMeta = (token, tokenStates, ...rest) => {
|
|
16
|
+
if (!tokenStates) return token;
|
|
17
|
+
const tokenState = tokenStates.filter(Boolean).find((x) => x.address === token.address);
|
|
18
|
+
if (tokenState) {
|
|
19
|
+
token.decimal = tokenState.decimal;
|
|
20
|
+
token.unit = tokenState.unit;
|
|
21
|
+
token.symbol = tokenState.symbol;
|
|
22
|
+
token.icon = tokenState.icon;
|
|
23
|
+
} else console.warn("Invalid token state on formatting", token, tokenStates, ...rest);
|
|
24
|
+
return token;
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* Create indexed account from account state
|
|
28
|
+
*/
|
|
29
|
+
const createIndexedAccount = async (x, getTokenFn) => {
|
|
30
|
+
const tasks = Object.keys(x.tokens || {}).map((address) => getTokenFn(address));
|
|
31
|
+
const tokenStates = await Promise.all(tasks);
|
|
32
|
+
return {
|
|
33
|
+
address: x.address,
|
|
34
|
+
balance: x.balance || "0",
|
|
35
|
+
moniker: x.moniker || "",
|
|
36
|
+
nonce: x.nonce ?? 0,
|
|
37
|
+
numAssets: x.numAssets ?? 0,
|
|
38
|
+
numTxs: x.numTxs ?? 0,
|
|
39
|
+
recentNumTxs: [],
|
|
40
|
+
renaissanceTime: x.context.renaissanceTime,
|
|
41
|
+
tokens: Object.keys(x.tokens || {}).map((address) => formatTokenMeta({
|
|
42
|
+
address,
|
|
43
|
+
balance: x.tokens[address]
|
|
44
|
+
}, tokenStates)),
|
|
45
|
+
genesisTime: x.context.genesisTime,
|
|
46
|
+
migratedTo: x.migratedTo?.[0] || "",
|
|
47
|
+
migratedFrom: x.migratedFrom?.[0] || ""
|
|
48
|
+
};
|
|
49
|
+
};
|
|
50
|
+
/**
|
|
51
|
+
* Create indexed asset from asset state
|
|
52
|
+
* Note: display/endpoint/data types from IAssetState may differ from TIndexedAssetState,
|
|
53
|
+
* they are passed through without transformation
|
|
54
|
+
*/
|
|
55
|
+
const createIndexedAsset = (x) => ({
|
|
56
|
+
address: x.address,
|
|
57
|
+
issuer: x.issuer,
|
|
58
|
+
moniker: x.moniker,
|
|
59
|
+
owner: x.owner,
|
|
60
|
+
parent: x.parent,
|
|
61
|
+
readonly: x.readonly,
|
|
62
|
+
transferrable: x.transferrable,
|
|
63
|
+
ttl: String(x.ttl || 0),
|
|
64
|
+
consumedTime: x.consumedTime || "",
|
|
65
|
+
genesisTime: x.context.genesisTime,
|
|
66
|
+
renaissanceTime: x.context.renaissanceTime,
|
|
67
|
+
data: x.data,
|
|
68
|
+
display: x.display,
|
|
69
|
+
endpoint: x.endpoint,
|
|
70
|
+
tags: x.tags || []
|
|
71
|
+
});
|
|
72
|
+
/**
|
|
73
|
+
* Create indexed delegation from delegation state
|
|
74
|
+
*/
|
|
75
|
+
const createIndexedDelegation = (x, ctx) => {
|
|
76
|
+
const result = {
|
|
77
|
+
address: x.address,
|
|
78
|
+
data: x.data,
|
|
79
|
+
genesisTime: x.context.genesisTime,
|
|
80
|
+
renaissanceTime: x.context.renaissanceTime,
|
|
81
|
+
ops: [x.ops]
|
|
82
|
+
};
|
|
83
|
+
if (x.from) result.from = x.from;
|
|
84
|
+
else if (ctx.senderState) result.from = get(ctx, "senderState.address", "");
|
|
85
|
+
else result.from = get(ctx, "tx.from", "");
|
|
86
|
+
if (x.to) result.to = x.to;
|
|
87
|
+
else if (ctx.receiverState) result.to = get(ctx, "receiverState.address", "");
|
|
88
|
+
else result.to = get(ctx, "itx.to", "");
|
|
89
|
+
return result;
|
|
90
|
+
};
|
|
91
|
+
/**
|
|
92
|
+
* Create indexed token from token state
|
|
93
|
+
* Note: foreignToken/metadata/data types from ITokenState may differ from TIndexedTokenState,
|
|
94
|
+
* they are passed through without transformation
|
|
95
|
+
*/
|
|
96
|
+
const createIndexedToken = (x) => ({
|
|
97
|
+
address: x.address,
|
|
98
|
+
issuer: x.issuer || "",
|
|
99
|
+
name: x.name,
|
|
100
|
+
description: x.description,
|
|
101
|
+
symbol: x.symbol,
|
|
102
|
+
unit: x.unit,
|
|
103
|
+
decimal: x.decimal,
|
|
104
|
+
icon: x.icon || "",
|
|
105
|
+
website: x.website || "",
|
|
106
|
+
totalSupply: x.totalSupply,
|
|
107
|
+
initialSupply: x.initialSupply,
|
|
108
|
+
maxTotalSupply: x.maxTotalSupply || "",
|
|
109
|
+
foreignToken: x.foreignToken,
|
|
110
|
+
tokenFactoryAddress: x.tokenFactoryAddress || "",
|
|
111
|
+
metadata: x.metadata,
|
|
112
|
+
spenders: x.spenders || [],
|
|
113
|
+
minters: x.minters || [],
|
|
114
|
+
type: x.type || "",
|
|
115
|
+
data: x.data,
|
|
116
|
+
genesisTime: x.context.genesisTime,
|
|
117
|
+
renaissanceTime: x.context.renaissanceTime
|
|
118
|
+
});
|
|
119
|
+
/**
|
|
120
|
+
* Create indexed token factory from token factory state
|
|
121
|
+
* Note: token/reserveToken may not have all TIndexedTokenInput fields filled,
|
|
122
|
+
* they are populated with available metadata from context
|
|
123
|
+
*/
|
|
124
|
+
const createIndexedTokenFactory = (tokenFactory, context) => {
|
|
125
|
+
return {
|
|
126
|
+
...pick(tokenFactory, [
|
|
127
|
+
"address",
|
|
128
|
+
"owner",
|
|
129
|
+
"tokenAddress",
|
|
130
|
+
"reserveAddress",
|
|
131
|
+
"curve",
|
|
132
|
+
"feeRate",
|
|
133
|
+
"currentSupply",
|
|
134
|
+
"reserveBalance",
|
|
135
|
+
"status",
|
|
136
|
+
"data"
|
|
137
|
+
]),
|
|
138
|
+
token: formatTokenMeta({ address: tokenFactory.tokenAddress }, context.itx?.token ? [context.itx.token] : []),
|
|
139
|
+
reserveToken: formatTokenMeta({ address: tokenFactory.reserveAddress }, context.config?.token ? [context.config.token] : []),
|
|
140
|
+
genesisTime: tokenFactory.context.genesisTime,
|
|
141
|
+
renaissanceTime: tokenFactory.context.renaissanceTime
|
|
142
|
+
};
|
|
143
|
+
};
|
|
144
|
+
/**
|
|
145
|
+
* Create indexed factory from asset factory state
|
|
146
|
+
* Note: tokens array may not have all TTokenMeta fields filled,
|
|
147
|
+
* they are populated with available metadata from context
|
|
148
|
+
*/
|
|
149
|
+
const createIndexedFactory = (factory, context) => {
|
|
150
|
+
if (context.factoryTokens && context.factoryTokens.length > 0 && factory.input?.tokens) factory.input.tokens = factory.input.tokens.map((token) => formatTokenMeta(token, context.tokenStates));
|
|
151
|
+
return {
|
|
152
|
+
...pick(factory, [
|
|
153
|
+
"address",
|
|
154
|
+
"owner",
|
|
155
|
+
"name",
|
|
156
|
+
"description",
|
|
157
|
+
"settlement",
|
|
158
|
+
"limit",
|
|
159
|
+
"trustedIssuers",
|
|
160
|
+
"input",
|
|
161
|
+
"output",
|
|
162
|
+
"hooks",
|
|
163
|
+
"data",
|
|
164
|
+
"numMinted",
|
|
165
|
+
"lastSettlement",
|
|
166
|
+
"balance",
|
|
167
|
+
"display"
|
|
168
|
+
]),
|
|
169
|
+
tokens: Object.keys(factory.tokens || {}).map((address) => formatTokenMeta({
|
|
170
|
+
address,
|
|
171
|
+
balance: factory.tokens[address]
|
|
172
|
+
}, context.tokenStates)),
|
|
173
|
+
genesisTime: factory.context.genesisTime,
|
|
174
|
+
renaissanceTime: factory.context.renaissanceTime
|
|
175
|
+
};
|
|
176
|
+
};
|
|
177
|
+
/**
|
|
178
|
+
* Create indexed transaction from transaction context
|
|
179
|
+
* These fields are used internally to filter transactions by some entity
|
|
180
|
+
*/
|
|
181
|
+
const createIndexedTransaction = async (tx, ctx, indexdb) => {
|
|
182
|
+
tx.accounts = [
|
|
183
|
+
tx.tx.from,
|
|
184
|
+
tx.sender,
|
|
185
|
+
tx.receiver
|
|
186
|
+
].filter(Boolean);
|
|
187
|
+
tx.assets = [];
|
|
188
|
+
tx.tokens = [];
|
|
189
|
+
tx.factories = [];
|
|
190
|
+
tx.stakes = [];
|
|
191
|
+
tx.rollups = [];
|
|
192
|
+
tx.delegations = [];
|
|
193
|
+
tx.tokenFactories = [];
|
|
194
|
+
tx.valid = tx.code === "OK";
|
|
195
|
+
if (ctx.senderState) tx.accounts.push(ctx.senderState.address);
|
|
196
|
+
if (ctx.receiverState) tx.accounts.push(ctx.receiverState.address);
|
|
197
|
+
if (ctx.feeVaultState && ctx.feeVaultChange) tx.accounts.push(ctx.feeVaultState.address);
|
|
198
|
+
if (ctx.gasVaultState && ctx.gasVaultChange) tx.accounts.push(ctx.gasVaultState.address);
|
|
199
|
+
if (ctx.updatedAccounts && Array.isArray(ctx.updatedAccounts)) tx.accounts.push(...ctx.updatedAccounts.map((x) => x.address));
|
|
200
|
+
if (ctx.delegatorState) tx.accounts.push(ctx.delegatorState.address);
|
|
201
|
+
if (ctx.delegationState) tx.delegations.push(ctx.delegationState.address);
|
|
202
|
+
if (ctx.delegationState && ctx.txType === "fg:t:revoke_delegate") {
|
|
203
|
+
const indexed = await indexdb.delegation?.get(ctx.delegationState.address);
|
|
204
|
+
if (indexed) tx.accounts.push(indexed.to);
|
|
205
|
+
}
|
|
206
|
+
if (Array.isArray(ctx.delegatorStates)) tx.accounts.push(...ctx.delegatorStates.map((x) => x.address));
|
|
207
|
+
if (Array.isArray(ctx.signerStates)) tx.accounts.push(...ctx.signerStates.map((x) => x.address));
|
|
208
|
+
if (Array.isArray(ctx.receiverStates)) tx.accounts.push(...ctx.receiverStates.map((x) => x.address));
|
|
209
|
+
if (ctx.assetState) {
|
|
210
|
+
tx.assets.push(ctx.assetState.address);
|
|
211
|
+
if (ctx.txType === "fg:t:update_asset") tx.accounts.push(ctx.assetState.owner);
|
|
212
|
+
if (ctx.txType === "fg:t:mint_asset") tx.accounts.push(ctx.ownerAddress);
|
|
213
|
+
}
|
|
214
|
+
if (ctx.assetStates && Array.isArray(ctx.assetStates)) tx.assets.push(...ctx.assetStates.map((x) => x.address));
|
|
215
|
+
if (ctx.tokenState) tx.tokens.push(ctx.tokenState.address);
|
|
216
|
+
if (ctx.tokenStates && Array.isArray(ctx.tokenStates)) tx.tokens.push(...ctx.tokenStates.map((x) => x.address));
|
|
217
|
+
if (ctx.factoryState) tx.factories.push(ctx.factoryState.address);
|
|
218
|
+
if (ctx.stakeState) {
|
|
219
|
+
tx.stakes.push(ctx.stakeState.address);
|
|
220
|
+
if (ctx.txType === "fg:t:slash_stake") tx.accounts.push(ctx.stakeState.sender);
|
|
221
|
+
if (ctx.txType === "fg:t:return_stake") tx.accounts.push(ctx.stakeState.sender);
|
|
222
|
+
}
|
|
223
|
+
if (Array.isArray(ctx.stakeStates)) tx.stakes.push(...ctx.stakeStates.map((x) => x.address));
|
|
224
|
+
if (ctx.rollupState) tx.rollups.push(ctx.rollupState.address);
|
|
225
|
+
if (ctx.tokenFactoryState) tx.tokenFactories.push(ctx.tokenFactoryState.address);
|
|
226
|
+
const pickedFields = [
|
|
227
|
+
"address",
|
|
228
|
+
"symbol",
|
|
229
|
+
"decimal",
|
|
230
|
+
"unit"
|
|
231
|
+
];
|
|
232
|
+
if (Array.isArray(ctx.tokenStates)) tx.tokenSymbols = ctx.tokenStates.map((t) => pick(t, pickedFields));
|
|
233
|
+
else if (ctx.tokenState) tx.tokenSymbols = [pick(ctx.tokenState, pickedFields)];
|
|
234
|
+
else tx.tokenSymbols = [];
|
|
235
|
+
tx.accounts = [...tx.accounts, ...tx.stakes];
|
|
236
|
+
return tx;
|
|
237
|
+
};
|
|
238
|
+
/**
|
|
239
|
+
* Create indexed stake from stake state
|
|
240
|
+
* Note: tokens/revokedTokens arrays may not have all TTokenMeta fields filled,
|
|
241
|
+
* they are populated with available metadata from context
|
|
242
|
+
*/
|
|
243
|
+
const createIndexedStake = async (x, ctx, indexdb) => {
|
|
244
|
+
const tokens = uniq(Object.keys(x.tokens || {}).concat(Object.keys(x.revokedTokens || {})));
|
|
245
|
+
const existTokenStates = ctx.tokenStates || [];
|
|
246
|
+
const missingTokenStates = await Promise.all(tokens.filter((a) => !existTokenStates.find((t) => t.address === a)).map((t) => indexdb.token?.get(t)));
|
|
247
|
+
const tokenStates = [...existTokenStates, ...missingTokenStates.filter(Boolean)];
|
|
248
|
+
return {
|
|
249
|
+
...pick(x, [
|
|
250
|
+
"address",
|
|
251
|
+
"sender",
|
|
252
|
+
"receiver",
|
|
253
|
+
"assets",
|
|
254
|
+
"slashers",
|
|
255
|
+
"revocable",
|
|
256
|
+
"data",
|
|
257
|
+
"nonce",
|
|
258
|
+
"message",
|
|
259
|
+
"revokeWaitingPeriod",
|
|
260
|
+
"revokedAssets"
|
|
261
|
+
]),
|
|
262
|
+
tokens: Object.keys(x.tokens || {}).map((address) => formatTokenMeta({
|
|
263
|
+
address,
|
|
264
|
+
balance: x.tokens[address]
|
|
265
|
+
}, tokenStates, x)),
|
|
266
|
+
revokedTokens: Object.keys(x.revokedTokens || {}).map((address) => formatTokenMeta({
|
|
267
|
+
address,
|
|
268
|
+
balance: x.revokedTokens[address]
|
|
269
|
+
}, tokenStates)),
|
|
270
|
+
genesisTime: x.context.genesisTime,
|
|
271
|
+
renaissanceTime: x.context.renaissanceTime
|
|
272
|
+
};
|
|
273
|
+
};
|
|
274
|
+
/**
|
|
275
|
+
* Create indexed rollup from rollup state
|
|
276
|
+
* Note: foreignToken from TokenStateInfo is passed through without transformation
|
|
277
|
+
*/
|
|
278
|
+
const createIndexedRollup = (x, ctx) => {
|
|
279
|
+
const rollup = {
|
|
280
|
+
...pick(x, [
|
|
281
|
+
"address",
|
|
282
|
+
"paused",
|
|
283
|
+
"closed",
|
|
284
|
+
"tokenAddress",
|
|
285
|
+
"vaultAddress",
|
|
286
|
+
"contractAddress",
|
|
287
|
+
"seedValidators",
|
|
288
|
+
"validators",
|
|
289
|
+
"minStakeAmount",
|
|
290
|
+
"maxStakeAmount",
|
|
291
|
+
"minSignerCount",
|
|
292
|
+
"maxSignerCount",
|
|
293
|
+
"minBlockSize",
|
|
294
|
+
"maxBlockSize",
|
|
295
|
+
"minBlockInterval",
|
|
296
|
+
"minBlockConfirmation",
|
|
297
|
+
"minDepositAmount",
|
|
298
|
+
"maxDepositAmount",
|
|
299
|
+
"minWithdrawAmount",
|
|
300
|
+
"maxWithdrawAmount",
|
|
301
|
+
"depositFeeRate",
|
|
302
|
+
"withdrawFeeRate",
|
|
303
|
+
"proposerFeeShare",
|
|
304
|
+
"publisherFeeShare",
|
|
305
|
+
"minDepositFee",
|
|
306
|
+
"maxDepositFee",
|
|
307
|
+
"minWithdrawFee",
|
|
308
|
+
"maxWithdrawFee",
|
|
309
|
+
"issuer",
|
|
310
|
+
"blockHeight",
|
|
311
|
+
"blockHash",
|
|
312
|
+
"leaveWaitingPeriod",
|
|
313
|
+
"publishWaitingPeriod",
|
|
314
|
+
"publishSlashRate",
|
|
315
|
+
"migrateHistory",
|
|
316
|
+
"vaultHistory",
|
|
317
|
+
"data"
|
|
318
|
+
]),
|
|
319
|
+
genesisTime: x.context.genesisTime,
|
|
320
|
+
renaissanceTime: x.context.renaissanceTime
|
|
321
|
+
};
|
|
322
|
+
if (ctx.tokenStates) {
|
|
323
|
+
const tokenState = ctx.tokenStates.find((t) => t.address === x.tokenAddress);
|
|
324
|
+
rollup.tokenInfo = formatTokenMeta({
|
|
325
|
+
address: x.tokenAddress,
|
|
326
|
+
value: "0"
|
|
327
|
+
}, ctx.tokenStates);
|
|
328
|
+
if (tokenState) rollup.foreignToken = tokenState.foreignToken;
|
|
329
|
+
}
|
|
330
|
+
return rollup;
|
|
331
|
+
};
|
|
332
|
+
/**
|
|
333
|
+
* Create indexed rollup block from rollup block state
|
|
334
|
+
* Note: tokenInfo may not have all TIndexedTokenInput fields filled,
|
|
335
|
+
* they are populated with available metadata from context
|
|
336
|
+
*/
|
|
337
|
+
const createIndexedRollupBlock = (x, ctx) => {
|
|
338
|
+
const signatures = x.signaturesList || x.signatures || [];
|
|
339
|
+
return {
|
|
340
|
+
...pick(x, [
|
|
341
|
+
"hash",
|
|
342
|
+
"height",
|
|
343
|
+
"merkleRoot",
|
|
344
|
+
"previousHash",
|
|
345
|
+
"txsHash",
|
|
346
|
+
"txs",
|
|
347
|
+
"proposer",
|
|
348
|
+
"signatures",
|
|
349
|
+
"rollup",
|
|
350
|
+
"mintedAmount",
|
|
351
|
+
"burnedAmount",
|
|
352
|
+
"rewardAmount",
|
|
353
|
+
"minReward",
|
|
354
|
+
"governance",
|
|
355
|
+
"data"
|
|
356
|
+
]),
|
|
357
|
+
genesisTime: x.context.genesisTime,
|
|
358
|
+
renaissanceTime: x.context.renaissanceTime,
|
|
359
|
+
tokenInfo: ctx.rollupState ? formatTokenMeta({
|
|
360
|
+
address: ctx.rollupState.tokenAddress,
|
|
361
|
+
value: "0"
|
|
362
|
+
}, ctx.tokenStates) : void 0,
|
|
363
|
+
validators: signatures.map((v) => v.signer)
|
|
364
|
+
};
|
|
365
|
+
};
|
|
366
|
+
/**
|
|
367
|
+
* Create indexed token distribution
|
|
368
|
+
*/
|
|
369
|
+
const createIndexedTokenDistribution = (x) => {
|
|
370
|
+
return {
|
|
371
|
+
tokenAddress: x.tokenAddress,
|
|
372
|
+
txTime: x.txTime,
|
|
373
|
+
account: x.account.toString(),
|
|
374
|
+
gas: x.gas.toString(),
|
|
375
|
+
fee: x.fee.toString(),
|
|
376
|
+
slashedVault: x.slashedVault.toString(),
|
|
377
|
+
stake: x.stake.toString(),
|
|
378
|
+
revokedStake: x.revokedStake.toString(),
|
|
379
|
+
gasStake: x.gasStake.toString()
|
|
380
|
+
};
|
|
381
|
+
};
|
|
382
|
+
/**
|
|
383
|
+
* Format transaction before inserting to index
|
|
384
|
+
*/
|
|
385
|
+
const formatTxBeforeInsert = (row) => {
|
|
386
|
+
const tx = { ...row };
|
|
387
|
+
tx.sender = tx.sender || "";
|
|
388
|
+
tx.receiver = tx.receiver || "";
|
|
389
|
+
if (!tx.tx || !tx.tx.itxJson) return tx;
|
|
390
|
+
const itx = tx.tx.itxJson;
|
|
391
|
+
tx.assets = tx.assets || [];
|
|
392
|
+
if (["transfer", "transfer_v2"].includes(tx.type || "") && itx.assets) tx.assets.push(...itx.assets);
|
|
393
|
+
else if (["transfer_v3", "stake"].includes(tx.type || "") && itx.inputs) tx.assets.push(...createSortedList(itx.inputs.map((x) => x.assets || [])));
|
|
394
|
+
else if ([
|
|
395
|
+
"revoke_stake",
|
|
396
|
+
"slash_stake",
|
|
397
|
+
"return_stake"
|
|
398
|
+
].includes(tx.type || "") && itx.outputs) tx.assets.push(...createSortedList(itx.outputs.map((x) => x.assets || [])));
|
|
399
|
+
else if (["exchange", "exchange_v2"].includes(tx.type || "")) tx.assets.push(...itx.sender?.assets || [], ...itx.receiver?.assets || []);
|
|
400
|
+
else if ([
|
|
401
|
+
"create_asset",
|
|
402
|
+
"update_asset",
|
|
403
|
+
"acquire_asset_v2",
|
|
404
|
+
"mint_asset"
|
|
405
|
+
].includes(tx.type || "") && itx.address) tx.assets.push(itx.address);
|
|
406
|
+
tx.factories = tx.factories || [];
|
|
407
|
+
if ([
|
|
408
|
+
"acquire_asset_v2",
|
|
409
|
+
"acquire_asset_v3",
|
|
410
|
+
"mint_asset",
|
|
411
|
+
"create_factory"
|
|
412
|
+
].includes(tx.type || "") && itx.factory) tx.factories.push(itx.factory);
|
|
413
|
+
tx.tokens = tx.tokens || [];
|
|
414
|
+
if (tx.type === "transfer_v2" && itx.tokens) tx.tokens.push(...itx.tokens.map((x) => x.address));
|
|
415
|
+
else if (["transfer_v3", "stake"].includes(tx.type || "") && itx.inputs) tx.tokens.push(...createSortedList(itx.inputs.map((x) => (x.tokens || []).map((t) => t.address))));
|
|
416
|
+
else if ([
|
|
417
|
+
"revoke_stake",
|
|
418
|
+
"slash_stake",
|
|
419
|
+
"return_stake"
|
|
420
|
+
].includes(tx.type || "") && itx.outputs) tx.tokens.push(...createSortedList(itx.outputs.map((x) => (x.tokens || []).map((t) => t.address))));
|
|
421
|
+
else if (tx.type === "exchange_v2") tx.tokens.push(...(itx.sender?.tokens || []).map((x) => x.address), ...(itx.receiver?.tokens || []).map((x) => x.address));
|
|
422
|
+
tx.accounts = tx.accounts || [];
|
|
423
|
+
tx.stakes = tx.stakes || [];
|
|
424
|
+
tx.assets = uniq(tx.assets).filter(Boolean);
|
|
425
|
+
tx.factories = uniq(tx.factories).filter(Boolean);
|
|
426
|
+
tx.tokens = uniq(tx.tokens).filter(Boolean);
|
|
427
|
+
tx.accounts = uniq(tx.accounts).filter(Boolean);
|
|
428
|
+
tx.stakes = uniq(tx.stakes).filter(Boolean);
|
|
429
|
+
tx.rollups = uniq(tx.rollups || []).filter(Boolean);
|
|
430
|
+
tx.tokenSymbols = uniqBy(tx.tokenSymbols || [], "address");
|
|
431
|
+
return tx;
|
|
432
|
+
};
|
|
433
|
+
/**
|
|
434
|
+
* Format transaction after reading from index (remove internal indexing fields)
|
|
435
|
+
*/
|
|
436
|
+
const formatTxAfterRead = (tx) => {
|
|
437
|
+
delete tx.assets;
|
|
438
|
+
delete tx.factories;
|
|
439
|
+
delete tx.tokens;
|
|
440
|
+
delete tx.accounts;
|
|
441
|
+
delete tx.stakes;
|
|
442
|
+
delete tx.rollups;
|
|
443
|
+
delete tx.delegations;
|
|
444
|
+
return tx;
|
|
445
|
+
};
|
|
446
|
+
/**
|
|
447
|
+
* Format delegation after reading from index
|
|
448
|
+
*/
|
|
449
|
+
const formatDelegationAfterRead = (delegation) => {
|
|
450
|
+
const opsRecord = Array.isArray(delegation.ops) ? delegation.ops[0] : delegation.ops;
|
|
451
|
+
return {
|
|
452
|
+
...delegation,
|
|
453
|
+
ops: Object.keys(opsRecord).map((x) => ({
|
|
454
|
+
key: x,
|
|
455
|
+
value: opsRecord[x]
|
|
456
|
+
}))
|
|
457
|
+
};
|
|
458
|
+
};
|
|
459
|
+
/**
|
|
460
|
+
* Parse date time string to ISO format
|
|
461
|
+
*/
|
|
462
|
+
const parseDateTime = (str) => {
|
|
463
|
+
if (!str) return "";
|
|
464
|
+
const parsed = Date.parse(str);
|
|
465
|
+
if (Number.isNaN(parsed)) return "";
|
|
466
|
+
return new Date(parsed).toISOString();
|
|
467
|
+
};
|
|
468
|
+
const PAGE_SIZE_DEFAULT = 20;
|
|
469
|
+
const PAGE_SIZE_MAX = 100;
|
|
470
|
+
/**
|
|
471
|
+
* Format pagination parameters with defaults
|
|
472
|
+
*/
|
|
473
|
+
const formatPagination = ({ paging, defaultSortField, supportedSortFields = [] }) => {
|
|
474
|
+
if (!defaultSortField) throw new Error("argument defaultSortField is required");
|
|
475
|
+
const pagination = {
|
|
476
|
+
size: paging?.size ?? PAGE_SIZE_DEFAULT,
|
|
477
|
+
cursor: typeof paging?.cursor === "number" ? paging.cursor : Number(paging?.cursor) || 0,
|
|
478
|
+
order: {
|
|
479
|
+
field: defaultSortField,
|
|
480
|
+
type: "desc"
|
|
481
|
+
}
|
|
482
|
+
};
|
|
483
|
+
let inputOrder = paging?.order;
|
|
484
|
+
if (Array.isArray(inputOrder)) inputOrder = inputOrder[0];
|
|
485
|
+
if (inputOrder?.field) pagination.order.field = inputOrder.field;
|
|
486
|
+
if (supportedSortFields.length > 0 && !supportedSortFields.includes(pagination.order.field)) pagination.order.field = defaultSortField;
|
|
487
|
+
if (inputOrder?.type) pagination.order.type = inputOrder.type;
|
|
488
|
+
pagination.size = Math.min(pagination.size, PAGE_SIZE_MAX);
|
|
489
|
+
return pagination;
|
|
490
|
+
};
|
|
491
|
+
/**
|
|
492
|
+
* Format next pagination info for response
|
|
493
|
+
*/
|
|
494
|
+
const formatNextPagination = (total, pagination) => {
|
|
495
|
+
const nextCursor = pagination.cursor + pagination.size;
|
|
496
|
+
if (total > nextCursor) return {
|
|
497
|
+
cursor: String(nextCursor),
|
|
498
|
+
next: true,
|
|
499
|
+
total
|
|
500
|
+
};
|
|
501
|
+
return {
|
|
502
|
+
cursor: "0",
|
|
503
|
+
next: false,
|
|
504
|
+
total
|
|
505
|
+
};
|
|
506
|
+
};
|
|
507
|
+
/**
|
|
508
|
+
* Check if a transaction changes the default token balance
|
|
509
|
+
*/
|
|
510
|
+
const isDefaultTokenChanged = (tx, token) => {
|
|
511
|
+
const itx = tx.tx.itxJson;
|
|
512
|
+
if ([
|
|
513
|
+
"fg:t:transfer",
|
|
514
|
+
"fg:t:transfer_v2",
|
|
515
|
+
"fg:t:transfer_v3",
|
|
516
|
+
"fg:t:acquire_asset_v2",
|
|
517
|
+
"fg:t:acquire_asset_v3",
|
|
518
|
+
"fg:t:exchange",
|
|
519
|
+
"fg:t:exchange_v2",
|
|
520
|
+
"fg:t:deposit_token",
|
|
521
|
+
"fg:t:withdraw_token",
|
|
522
|
+
"fg:t:faucet",
|
|
523
|
+
"fg:t:poke",
|
|
524
|
+
"fg:t:setup_swap",
|
|
525
|
+
"fg:t:retrieve_swap",
|
|
526
|
+
"fg:t:stake",
|
|
527
|
+
"fg:t:revoke_stake"
|
|
528
|
+
].includes(itx.type_url || "") === false) return false;
|
|
529
|
+
const ZERO = new BN(0);
|
|
530
|
+
const isDefaultToken = (id) => [token.address, ""].includes(id);
|
|
531
|
+
const isPositive = (v) => new BN(v || 0).gt(ZERO);
|
|
532
|
+
const isChangedByInput = (input) => isPositive(input.value) || (input.tokens?.some((x) => isDefaultToken(x.address) && isPositive(x.value)) ?? false);
|
|
533
|
+
switch (itx.type_url) {
|
|
534
|
+
case "fg:t:transfer": return isPositive(itx.value);
|
|
535
|
+
case "fg:t:transfer_v2": return isChangedByInput(itx);
|
|
536
|
+
case "fg:t:transfer_v3":
|
|
537
|
+
case "fg:t:acquire_asset_v3": return (itx.inputs || []).some((input) => isChangedByInput(input));
|
|
538
|
+
case "fg:t:acquire_asset_v2": return (tx.receipts || []).some((r) => r.changes.some((c) => isDefaultToken(c.target) && isPositive(c.value)));
|
|
539
|
+
case "fg:t:exchange": return isPositive(itx.sender?.value) || isPositive(itx.receiver?.value);
|
|
540
|
+
case "fg:t:exchange_v2": return isChangedByInput(itx.sender || {}) || isChangedByInput(itx.receiver || {});
|
|
541
|
+
case "fg:t:deposit_token":
|
|
542
|
+
case "fg:t:withdraw_token": return isPositive(itx.value);
|
|
543
|
+
case "fg:t:setup_swap":
|
|
544
|
+
case "fg:t:retrieve_swap": return isPositive(itx.value);
|
|
545
|
+
case "fg:t:poke": return true;
|
|
546
|
+
case "fg:t:faucet": return !itx.token;
|
|
547
|
+
case "fg:t:stake": return (itx.inputs || []).some((input) => isChangedByInput(input));
|
|
548
|
+
case "fg:t:revoke_stake":
|
|
549
|
+
case "fg:t:slash_stake":
|
|
550
|
+
case "fg:t:return_stake": return (itx.outputs || []).some((output) => isChangedByInput(output));
|
|
551
|
+
default: return false;
|
|
552
|
+
}
|
|
553
|
+
};
|
|
554
|
+
|
|
555
|
+
//#endregion
|
|
556
|
+
export { createIndexedAccount, createIndexedAsset, createIndexedDelegation, createIndexedFactory, createIndexedRollup, createIndexedRollupBlock, createIndexedStake, createIndexedToken, createIndexedTokenDistribution, createIndexedTokenFactory, createIndexedTransaction, formatDelegationAfterRead, formatNextPagination, formatPagination, formatTokenMeta, formatTxAfterRead, formatTxBeforeInsert, isDefaultTokenChanged, parseDateTime };
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
//#region rolldown:runtime
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __copyProps = (to, from, except, desc) => {
|
|
9
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
10
|
+
for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
|
|
11
|
+
key = keys[i];
|
|
12
|
+
if (!__hasOwnProp.call(to, key) && key !== except) {
|
|
13
|
+
__defProp(to, key, {
|
|
14
|
+
get: ((k) => from[k]).bind(null, key),
|
|
15
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
return to;
|
|
21
|
+
};
|
|
22
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
|
|
23
|
+
value: mod,
|
|
24
|
+
enumerable: true
|
|
25
|
+
}) : target, mod));
|
|
26
|
+
|
|
27
|
+
//#endregion
|
|
28
|
+
|
|
29
|
+
exports.__toESM = __toESM;
|
package/lib/db.cjs
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
2
|
+
const require_rolldown_runtime = require('./_virtual/rolldown_runtime.cjs');
|
|
3
|
+
let _ocap_state = require("@ocap/state");
|
|
4
|
+
let _ocap_util_lib_ready = require("@ocap/util/lib/ready");
|
|
5
|
+
|
|
6
|
+
//#region src/db.ts
|
|
7
|
+
var BaseIndexDB = class extends _ocap_util_lib_ready.Ready {
|
|
8
|
+
constructor() {
|
|
9
|
+
super();
|
|
10
|
+
this.readyMarks = Object.fromEntries(_ocap_state.indexes.map((x) => [x, false]));
|
|
11
|
+
this.readyListenersAttached = false;
|
|
12
|
+
}
|
|
13
|
+
attachReadyListeners() {
|
|
14
|
+
if (this.readyListenersAttached) return;
|
|
15
|
+
for (const index of _ocap_state.indexes) {
|
|
16
|
+
if (typeof this[index] === "undefined") throw new Error(`Missing index ${index} in indexdb adapter: ${this.name}`);
|
|
17
|
+
this[index].onReady(() => this.markReady(index));
|
|
18
|
+
}
|
|
19
|
+
this.readyListenersAttached = true;
|
|
20
|
+
}
|
|
21
|
+
listTransactions(_params) {
|
|
22
|
+
throw new Error("listTransactions should be implemented in adapter");
|
|
23
|
+
}
|
|
24
|
+
listAssets(_params) {
|
|
25
|
+
throw new Error("listAssets should be implemented in adapter");
|
|
26
|
+
}
|
|
27
|
+
listTopAccounts(_params) {
|
|
28
|
+
throw new Error("listTopAccounts should be implemented in adapter");
|
|
29
|
+
}
|
|
30
|
+
listTokens(_params) {
|
|
31
|
+
throw new Error("listTokens should be implemented in adapter");
|
|
32
|
+
}
|
|
33
|
+
listFactories(_params) {
|
|
34
|
+
throw new Error("listFactories should be implemented in adapter");
|
|
35
|
+
}
|
|
36
|
+
listStakes(_params) {
|
|
37
|
+
throw new Error("listStakes should be implemented in adapter");
|
|
38
|
+
}
|
|
39
|
+
listDelegations(_params) {
|
|
40
|
+
throw new Error("listDelegations should be implemented in adapter");
|
|
41
|
+
}
|
|
42
|
+
listRollups(_params) {
|
|
43
|
+
throw new Error("listRollups should be implemented in adapter");
|
|
44
|
+
}
|
|
45
|
+
listRollupBlocks(_params) {
|
|
46
|
+
throw new Error("listRollupBlocks should be implemented in adapter");
|
|
47
|
+
}
|
|
48
|
+
listRollupValidators(_params) {
|
|
49
|
+
throw new Error("listRollupValidators should be implemented in adapter");
|
|
50
|
+
}
|
|
51
|
+
listTokenFactories(_params) {
|
|
52
|
+
throw new Error("listTokenFactories should be implemented in adapter");
|
|
53
|
+
}
|
|
54
|
+
getRelatedAddresses(_address) {
|
|
55
|
+
return [];
|
|
56
|
+
}
|
|
57
|
+
listBlocks() {
|
|
58
|
+
return [];
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
var db_default = BaseIndexDB;
|
|
62
|
+
|
|
63
|
+
//#endregion
|
|
64
|
+
exports.default = db_default;
|
package/lib/db.d.cts
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { IIndexDB, IIndexTable, IListAccountsResult, IListAssetsResult, IListDelegationsResult, IListFactoriesResult, IListRollupBlocksResult, IListRollupValidatorsResult, IListRollupsResult, IListStakesResult, IListTokenFactoriesResult, IListTokensResult, IListTransactionsResult, IndexTableTypeMap, Promisable, TRequestListAssets, TRequestListDelegations, TRequestListFactories, TRequestListRollupBlocks, TRequestListRollupValidators, TRequestListRollups, TRequestListStakes, TRequestListTokenFactories, TRequestListTokens, TRequestListTopAccounts, TRequestListTransactions } from "@ocap/types";
|
|
2
|
+
import { Ready } from "@ocap/util/lib/ready";
|
|
3
|
+
|
|
4
|
+
//#region src/db.d.ts
|
|
5
|
+
declare class BaseIndexDB extends Ready implements IIndexDB {
|
|
6
|
+
readyMarks: Record<string, boolean>;
|
|
7
|
+
readyListenersAttached: boolean;
|
|
8
|
+
name: string;
|
|
9
|
+
version: string;
|
|
10
|
+
tx: IIndexTable<IndexTableTypeMap['tx']>;
|
|
11
|
+
account: IIndexTable<IndexTableTypeMap['account']>;
|
|
12
|
+
asset: IIndexTable<IndexTableTypeMap['asset']>;
|
|
13
|
+
token: IIndexTable<IndexTableTypeMap['token']>;
|
|
14
|
+
factory: IIndexTable<IndexTableTypeMap['factory']>;
|
|
15
|
+
stake: IIndexTable<IndexTableTypeMap['stake']>;
|
|
16
|
+
delegation: IIndexTable<IndexTableTypeMap['delegation']>;
|
|
17
|
+
rollup: IIndexTable<IndexTableTypeMap['rollup']>;
|
|
18
|
+
rollupBlock: IIndexTable<IndexTableTypeMap['rollupBlock']>;
|
|
19
|
+
rollupValidator: IIndexTable<IndexTableTypeMap['rollupValidator']>;
|
|
20
|
+
tokenDistribution: IIndexTable<IndexTableTypeMap['tokenDistribution']>;
|
|
21
|
+
tokenFactory: IIndexTable<IndexTableTypeMap['tokenFactory']>;
|
|
22
|
+
[key: string]: unknown;
|
|
23
|
+
constructor();
|
|
24
|
+
attachReadyListeners(): void;
|
|
25
|
+
listTransactions(_params?: Partial<TRequestListTransactions>): Promisable<IListTransactionsResult>;
|
|
26
|
+
listAssets(_params?: Partial<TRequestListAssets>): Promisable<IListAssetsResult>;
|
|
27
|
+
listTopAccounts(_params?: Partial<TRequestListTopAccounts>): Promisable<IListAccountsResult>;
|
|
28
|
+
listTokens(_params?: Partial<TRequestListTokens>): Promisable<IListTokensResult>;
|
|
29
|
+
listFactories(_params?: Partial<TRequestListFactories>): Promisable<IListFactoriesResult>;
|
|
30
|
+
listStakes(_params?: Partial<TRequestListStakes>): Promisable<IListStakesResult>;
|
|
31
|
+
listDelegations(_params?: Partial<TRequestListDelegations>): Promisable<IListDelegationsResult>;
|
|
32
|
+
listRollups(_params?: Partial<TRequestListRollups>): Promisable<IListRollupsResult>;
|
|
33
|
+
listRollupBlocks(_params?: Partial<TRequestListRollupBlocks>): Promisable<IListRollupBlocksResult>;
|
|
34
|
+
listRollupValidators(_params?: Partial<TRequestListRollupValidators>): Promisable<IListRollupValidatorsResult>;
|
|
35
|
+
listTokenFactories(_params?: Partial<TRequestListTokenFactories>): Promisable<IListTokenFactoriesResult>;
|
|
36
|
+
getRelatedAddresses(_address: string): Promisable<string[]>;
|
|
37
|
+
listBlocks(): unknown[];
|
|
38
|
+
}
|
|
39
|
+
//#endregion
|
|
40
|
+
export { BaseIndexDB as default };
|