@ocap/resolver 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.
Files changed (43) hide show
  1. package/esm/api.d.mts +24 -0
  2. package/esm/api.mjs +53 -0
  3. package/esm/hooks.d.mts +153 -0
  4. package/esm/hooks.mjs +267 -0
  5. package/esm/index.d.mts +201 -0
  6. package/esm/index.mjs +1327 -0
  7. package/esm/migration-chain.d.mts +52 -0
  8. package/esm/migration-chain.mjs +97 -0
  9. package/esm/package.mjs +5 -0
  10. package/esm/token-cache.d.mts +20 -0
  11. package/esm/token-cache.mjs +26 -0
  12. package/esm/token-distribution.d.mts +166 -0
  13. package/esm/token-distribution.mjs +241 -0
  14. package/esm/token-flow.d.mts +139 -0
  15. package/esm/token-flow.mjs +330 -0
  16. package/esm/types.d.mts +115 -0
  17. package/esm/types.mjs +1 -0
  18. package/lib/_virtual/rolldown_runtime.cjs +29 -0
  19. package/lib/api.cjs +54 -0
  20. package/lib/api.d.cts +24 -0
  21. package/lib/hooks.cjs +274 -0
  22. package/lib/hooks.d.cts +153 -0
  23. package/lib/index.cjs +1343 -0
  24. package/lib/index.d.cts +201 -0
  25. package/lib/migration-chain.cjs +99 -0
  26. package/lib/migration-chain.d.cts +52 -0
  27. package/lib/package.cjs +11 -0
  28. package/lib/token-cache.cjs +27 -0
  29. package/lib/token-cache.d.cts +20 -0
  30. package/lib/token-distribution.cjs +243 -0
  31. package/lib/token-distribution.d.cts +166 -0
  32. package/lib/token-flow.cjs +336 -0
  33. package/lib/token-flow.d.cts +139 -0
  34. package/lib/types.cjs +0 -0
  35. package/lib/types.d.cts +115 -0
  36. package/package.json +49 -21
  37. package/lib/api.js +0 -71
  38. package/lib/hooks.js +0 -339
  39. package/lib/index.js +0 -1486
  40. package/lib/migration-chain.js +0 -144
  41. package/lib/token-cache.js +0 -40
  42. package/lib/token-distribution.js +0 -358
  43. package/lib/token-flow.js +0 -445
@@ -0,0 +1,166 @@
1
+ import { IChainConfig, IChunkIterator, IIndexDB, IIndexTable, IPipelineLogger, IResolverTransaction, IStateDB, IStateTable, ITokenInfo, TTokenDistribution } from "./types.cjs";
2
+ import { BN } from "@ocap/util";
3
+
4
+ //#region src/token-distribution.d.ts
5
+
6
+ /**
7
+ * Token balance in array format (used in stake state for distribution)
8
+ */
9
+ interface ITokenBalance {
10
+ address: string;
11
+ balance: string;
12
+ value?: string;
13
+ }
14
+ /**
15
+ * Stake state with array-format tokens (for distribution calculation)
16
+ */
17
+ interface IDistributionStakeState {
18
+ address: string;
19
+ sender: string;
20
+ message: string;
21
+ tokens: ITokenBalance[];
22
+ revokedTokens: ITokenBalance[];
23
+ renaissanceTime?: string;
24
+ }
25
+ /**
26
+ * State snapshot for tracking token changes
27
+ */
28
+ interface IStateSnapshot {
29
+ [address: string]: {
30
+ tokens: Record<string, string>;
31
+ revokedTokens: Record<string, string>;
32
+ };
33
+ }
34
+ /**
35
+ * Transaction context for distribution calculation
36
+ */
37
+ interface IResolverTransactionContext {
38
+ txn?: unknown;
39
+ stateSnapshot?: IStateSnapshot;
40
+ stakeState?: {
41
+ tokens: Record<string, string>;
42
+ revokedTokens: Record<string, string>;
43
+ };
44
+ [key: string]: unknown;
45
+ }
46
+ /**
47
+ * Distribution with BN values (for calculation)
48
+ */
49
+ interface IDistribution {
50
+ tokenAddress: string;
51
+ account: InstanceType<typeof BN>;
52
+ gas: InstanceType<typeof BN>;
53
+ fee: InstanceType<typeof BN>;
54
+ slashedVault: InstanceType<typeof BN>;
55
+ stake: InstanceType<typeof BN>;
56
+ revokedStake: InstanceType<typeof BN>;
57
+ gasStake: InstanceType<typeof BN>;
58
+ other: InstanceType<typeof BN>;
59
+ txTime: string;
60
+ }
61
+ /**
62
+ * Raw distribution input (string/number values)
63
+ */
64
+ interface IRawDistribution {
65
+ tokenAddress: string;
66
+ account?: string | number;
67
+ gas?: string | number;
68
+ fee?: string | number;
69
+ slashedVault?: string | number;
70
+ stake?: string | number;
71
+ revokedStake?: string | number;
72
+ gasStake?: string | number;
73
+ other?: string | number;
74
+ txTime?: string;
75
+ }
76
+ /**
77
+ * Options for handleTx method
78
+ */
79
+ interface IHandleTxOptions {
80
+ context?: IResolverTransactionContext;
81
+ isHandleStake?: boolean;
82
+ }
83
+ /**
84
+ * Resolver interface for TokenDistributionManager
85
+ */
86
+ interface IDistributionResolver {
87
+ indexdb: IIndexDB;
88
+ statedb: IStateDB & {
89
+ stake: IStateTable<IDistributionStakeState>;
90
+ };
91
+ config: IChainConfig;
92
+ logger?: IPipelineLogger;
93
+ formatTx: (tx: IResolverTransaction) => Promise<IResolverTransaction & {
94
+ tokenSymbols: ITokenInfo[];
95
+ }>;
96
+ listTransactionsChunks: (params: {
97
+ timeFilter?: {
98
+ startDateTime: string;
99
+ };
100
+ tokenFilter?: {
101
+ tokenFilter?: {
102
+ tokens: string[];
103
+ };
104
+ };
105
+ }) => Promise<IChunkIterator<IResolverTransaction>>;
106
+ listStakeChunks: () => Promise<IChunkIterator<IDistributionStakeState>>;
107
+ }
108
+ /**
109
+ * TokenDistribution IndexDB table interface
110
+ */
111
+ type ITokenDistributionTable = IIndexTable<TTokenDistribution> & {
112
+ insert: (data: TTokenDistribution) => Promise<void>;
113
+ update: (tokenAddress: string, data: TTokenDistribution) => Promise<void>;
114
+ };
115
+ declare class TokenDistributionManager {
116
+ resolver: IDistributionResolver;
117
+ indexdb: IIndexDB & {
118
+ tokenDistribution: ITokenDistributionTable;
119
+ };
120
+ isProcessing: boolean;
121
+ constructor(resolver: IDistributionResolver);
122
+ formatDistribution(distribution: IRawDistribution): IDistribution;
123
+ getDistribution(tokenAddress: string): Promise<TTokenDistribution | null>;
124
+ saveDistribution(distribution: IDistribution, isEnsureLatest?: boolean): Promise<TTokenDistribution>;
125
+ /**
126
+ * Calculate token distribution based on all transaction data.
127
+ * This method is usually used to update historical token distribution data
128
+ *
129
+ * @param tokenAddress Token address
130
+ * @param force If force is false, only calculate distributions for new transactions after txTime in indexdb. default is false
131
+ * @returns The updated token distribution or null if failed
132
+ */
133
+ updateByToken(tokenAddress: string, force?: boolean): Promise<TTokenDistribution | null | undefined>;
134
+ /**
135
+ * Split out revokedStake / gasStake from stake
136
+ *
137
+ * @param distribution The distribution object to update
138
+ * @returns The updated distribution
139
+ */
140
+ splitStake(distribution: IDistribution): Promise<IDistribution>;
141
+ /**
142
+ * Update token distribution by a single transaction.
143
+ * This method is usually used when a tx is completed.
144
+ *
145
+ * @param tx The transaction object
146
+ * @param context The transaction context
147
+ * @returns The updated token distributions
148
+ */
149
+ updateByTx(tx: IResolverTransaction, context: IResolverTransactionContext): Promise<TTokenDistribution[] | undefined>;
150
+ /**
151
+ * Parse token distribution for a single transaction
152
+ * @param tx The transaction
153
+ * @param distribution The distribution to update
154
+ * @param options Handle options
155
+ * @returns The updated token distribution
156
+ */
157
+ handleTx(tx: IResolverTransaction, distribution: IDistribution, {
158
+ context,
159
+ isHandleStake
160
+ }?: IHandleTxOptions): Promise<IDistribution>;
161
+ handleModerator(distribution: IDistribution): IDistribution;
162
+ getStakeState(address: string, ctx: IResolverTransactionContext): Promise<IDistributionStakeState>;
163
+ isGasStake(stakeState: IDistributionStakeState): boolean;
164
+ }
165
+ //#endregion
166
+ export { TokenDistributionManager };
@@ -0,0 +1,336 @@
1
+ const require_rolldown_runtime = require('./_virtual/rolldown_runtime.cjs');
2
+ let _ocap_util = require("@ocap/util");
3
+ let _arcblock_validator = require("@arcblock/validator");
4
+ let _ocap_util_lib_error = require("@ocap/util/lib/error");
5
+ let lodash_uniq = require("lodash/uniq");
6
+ lodash_uniq = require_rolldown_runtime.__toESM(lodash_uniq);
7
+ let _ocap_state_lib_states_tx = require("@ocap/state/lib/states/tx");
8
+
9
+ //#region src/token-flow.ts
10
+ const ZERO = new _ocap_util.BN(0);
11
+ const paramsSchema = _arcblock_validator.Joi.object({
12
+ accountAddress: _arcblock_validator.schemas.tokenHolder.required(),
13
+ tokenAddress: _arcblock_validator.Joi.DID().prefix().role("ROLE_TOKEN").required(),
14
+ resolver: _arcblock_validator.Joi.object().required()
15
+ });
16
+ /**
17
+ * Parse transfer in/out list from transaction
18
+ * @param tx Transaction object
19
+ * @param tokenAddress Token address to filter by
20
+ * @returns Object containing transferInList and transferOutList
21
+ */
22
+ const getTransferList = (tx, tokenAddress) => {
23
+ const transferInList = [];
24
+ const transferOutList = [];
25
+ for (const receipt of tx.receipts || []) {
26
+ const changes = receipt.changes.filter((item) => item.target === tokenAddress && item.value !== "0");
27
+ for (const change of changes) {
28
+ const value = new _ocap_util.BN(change.value);
29
+ const item = {
30
+ address: receipt.address,
31
+ value: value.abs(),
32
+ action: change.action
33
+ };
34
+ if (value.lt(ZERO)) transferOutList.push(item);
35
+ else transferInList.push(item);
36
+ }
37
+ }
38
+ return {
39
+ transferInList,
40
+ transferOutList
41
+ };
42
+ };
43
+ /**
44
+ * Parse transfer flow from transaction
45
+ * @param tx Transaction object
46
+ * @param tokenAddress Token address to filter by
47
+ * @returns Array of transfer flows
48
+ */
49
+ const getTransferFlow = (tx, tokenAddress) => {
50
+ const { transferInList, transferOutList } = getTransferList(tx, tokenAddress);
51
+ const txTransfers = [];
52
+ for (const outItem of transferOutList) {
53
+ if (outItem.archived) continue;
54
+ const matchedInItem = transferInList.find((x) => x.value.eq(outItem.value));
55
+ if (matchedInItem) {
56
+ txTransfers.push({
57
+ from: outItem.address,
58
+ to: matchedInItem.address,
59
+ value: outItem.value,
60
+ hash: tx.hash
61
+ });
62
+ matchedInItem.archived = true;
63
+ outItem.archived = true;
64
+ continue;
65
+ }
66
+ for (const inItem of transferInList) {
67
+ if (inItem.archived) continue;
68
+ if (outItem.archived) continue;
69
+ if (outItem.value.gt(inItem.value)) {
70
+ txTransfers.push({
71
+ from: outItem.address,
72
+ to: inItem.address,
73
+ value: inItem.value,
74
+ hash: tx.hash
75
+ });
76
+ inItem.archived = true;
77
+ outItem.value = outItem.value.sub(inItem.value);
78
+ continue;
79
+ }
80
+ if (outItem.value.lt(inItem.value)) {
81
+ txTransfers.push({
82
+ from: outItem.address,
83
+ to: inItem.address,
84
+ value: outItem.value,
85
+ hash: tx.hash
86
+ });
87
+ outItem.archived = true;
88
+ inItem.value = inItem.value.sub(outItem.value);
89
+ continue;
90
+ }
91
+ if (outItem.value.eq(inItem.value)) {
92
+ txTransfers.push({
93
+ from: outItem.address,
94
+ to: inItem.address,
95
+ value: inItem.value,
96
+ hash: tx.hash
97
+ });
98
+ inItem.archived = true;
99
+ outItem.archived = true;
100
+ }
101
+ }
102
+ }
103
+ return txTransfers;
104
+ };
105
+ const getVaultAccounts = (config) => {
106
+ return Object.values(config.vaults).flat().concat(_ocap_state_lib_states_tx.FORGE_TOKEN_HOLDER);
107
+ };
108
+ const getInitialBalance = (address, config) => {
109
+ const account = config?.accounts?.find((x) => (0, _ocap_util.isSameDid)(x.address, address));
110
+ return account ? (0, _ocap_util.fromTokenToUnit)(account.balance ?? 0) : ZERO;
111
+ };
112
+ const getBalance = async (address, tokenAddress, { resolver, txn }) => {
113
+ const state = await resolver.statedb.account.get(address, {
114
+ txn,
115
+ traceMigration: false
116
+ });
117
+ if (!state) throw new _ocap_util_lib_error.CustomError("INVALID_REQUEST", `Invalid address ${address}`);
118
+ return state.tokens[tokenAddress] || 0;
119
+ };
120
+ const fixMigrateReceipts = async (tx, resolver) => {
121
+ const migrationChain = await resolver.getMigrationChain();
122
+ const txTime = new Date(tx.time);
123
+ tx.receipts?.forEach((receipt) => {
124
+ receipt.address = migrationChain.findAddressAtTime(receipt.address, txTime);
125
+ });
126
+ };
127
+ const verifyAccountRisk = async ({ accountAddress, tokenAddress, accountLimit = 400, txLimit = 1e4, tolerance = "0.0000000001" }, resolver, ctx = {}) => {
128
+ const validation = paramsSchema.validate({
129
+ accountAddress,
130
+ tokenAddress,
131
+ resolver
132
+ });
133
+ if (validation.error) throw new _ocap_util_lib_error.CustomError("INVALID_PARAMS", validation.error.message);
134
+ const { logger } = resolver;
135
+ const checkedAccounts = /* @__PURE__ */ new Map();
136
+ const checkedTx = /* @__PURE__ */ new Map();
137
+ const toleranceUnit = (0, _ocap_util.fromTokenToUnit)(tolerance, (await resolver.tokenCache.get(tokenAddress))?.decimal);
138
+ const vaultAccounts = getVaultAccounts(resolver.config);
139
+ const accountQueue = [[{
140
+ address: accountAddress,
141
+ chain: []
142
+ }]];
143
+ const execute = async (depth, txn) => {
144
+ const queue = accountQueue[depth];
145
+ for (let i = 0; i < queue.length; i++) {
146
+ if (checkedAccounts.size >= accountLimit) {
147
+ logger.warn("Account risk check reached max account size limit", {
148
+ address: accountAddress,
149
+ tokenAddress,
150
+ accountCount: checkedAccounts.size,
151
+ txCount: checkedTx.size,
152
+ depth,
153
+ accountLimit,
154
+ txLimit,
155
+ tolerance
156
+ });
157
+ return {
158
+ isRisky: false,
159
+ reason: "MAX_ACCOUNT_SIZE_LIMIT",
160
+ data: {
161
+ accountCount: checkedAccounts.size,
162
+ txCount: checkedTx.size
163
+ }
164
+ };
165
+ }
166
+ const { address, chain } = queue[i];
167
+ chain.push(address);
168
+ if (checkedAccounts.has(address)) continue;
169
+ const trustedConfig = await resolver.filter?.getTrustedAccountConfig?.(address);
170
+ if (trustedConfig && !trustedConfig.tolerance) {
171
+ checkedAccounts.set(address, true);
172
+ continue;
173
+ }
174
+ let balance = 0;
175
+ let transactions = [];
176
+ try {
177
+ [balance, transactions] = await Promise.all([getBalance(address, tokenAddress, {
178
+ resolver,
179
+ txn
180
+ }), resolver._getAllResults("transactions", (paging) => resolver.listTransactions({
181
+ paging,
182
+ accountFilter: { accounts: [address] }
183
+ }, ctx), txLimit)]);
184
+ } catch (e) {
185
+ if (e?.code === "EXCEED_LIMIT") {
186
+ logger.warn("Skip checking account cause tx count exceeding limit", {
187
+ address,
188
+ txLimit
189
+ });
190
+ checkedAccounts.set(address, true);
191
+ continue;
192
+ }
193
+ throw e;
194
+ }
195
+ let transferIn = getInitialBalance(address, resolver.config);
196
+ let transferOut = ZERO;
197
+ for (const tx of transactions) {
198
+ if (!checkedTx.has(tx.hash)) {
199
+ await fixMigrateReceipts(tx, resolver);
200
+ checkedTx.set(tx.hash, getTransferList(tx, tokenAddress));
201
+ }
202
+ const { transferInList, transferOutList } = checkedTx.get(tx.hash);
203
+ const transferInAmount = transferInList.filter((item) => (0, _ocap_util.isSameDid)(item.address, address)).map((item) => item.value).reduce((prev, cur) => prev.add(cur), ZERO);
204
+ const transferOutAmount = transferOutList.filter((item) => (0, _ocap_util.isSameDid)(item.address, address)).map((item) => item.value).reduce((prev, cur) => prev.add(cur), ZERO);
205
+ transferIn = transferIn.add(transferInAmount);
206
+ transferOut = transferOut.add(transferOutAmount);
207
+ if (transferInAmount.gt(ZERO)) {
208
+ if (!accountQueue[depth + 1]) accountQueue[depth + 1] = [];
209
+ const accountsToQueue = transferOutList.filter((item) => {
210
+ if (checkedAccounts.has(item.address)) return false;
211
+ if (_arcblock_validator.schemas.tokenHolder.validate(item.address).error) return false;
212
+ if (vaultAccounts.includes(item.address)) return false;
213
+ if (["gas", "fee"].includes(item.action || "")) return false;
214
+ return true;
215
+ }).map((item) => item.address);
216
+ accountQueue[depth + 1].push(...(0, lodash_uniq.default)(accountsToQueue).map((x) => ({
217
+ address: x,
218
+ chain: chain.concat()
219
+ })));
220
+ }
221
+ }
222
+ checkedAccounts.set(address, true);
223
+ const diff = transferIn.sub(transferOut).sub(new _ocap_util.BN(balance)).add((0, _ocap_util.fromTokenToUnit)(trustedConfig?.tolerance || 0));
224
+ if (diff.abs().gt(toleranceUnit)) {
225
+ const data = {
226
+ address: chain.join("->"),
227
+ balance,
228
+ transferIn: transferIn.toString(),
229
+ transferOut: transferOut.toString(),
230
+ accountCount: checkedAccounts.size,
231
+ txCount: checkedTx.size
232
+ };
233
+ logger.warn("Account balance does not match transfer records", {
234
+ ...data,
235
+ sourceAccount: accountAddress,
236
+ tokenAddress,
237
+ diff: diff.toString(),
238
+ depth,
239
+ accountLimit,
240
+ txLimit,
241
+ tolerance
242
+ });
243
+ return {
244
+ isRisky: true,
245
+ reason: "INVALID_BALANCE",
246
+ data
247
+ };
248
+ }
249
+ }
250
+ };
251
+ for (let depth = 0; depth < accountQueue.length; depth++) {
252
+ let isExecuted = false;
253
+ const result = await resolver.runAsLambda((txn) => {
254
+ if (isExecuted) throw new _ocap_util_lib_error.CustomError("INVALID_REQUEST", "verifyAccountRisk should not retry");
255
+ isExecuted = true;
256
+ return execute(depth, txn);
257
+ }, { retryLimit: 0 });
258
+ if (result) return result;
259
+ }
260
+ logger.info("Account risk check completed", {
261
+ address: accountAddress,
262
+ tokenAddress,
263
+ accountCount: checkedAccounts.size,
264
+ txCount: checkedTx.size,
265
+ depth: accountQueue.length,
266
+ accountLimit,
267
+ txLimit,
268
+ tolerance
269
+ });
270
+ return {
271
+ isRisky: false,
272
+ data: {
273
+ accountCount: checkedAccounts.size,
274
+ txCount: checkedTx.size
275
+ }
276
+ };
277
+ };
278
+ const listTokenFlows = async ({ accountAddress, tokenAddress, paging = {}, depth = 2, direction = "OUT" }, resolver, ctx = {}) => {
279
+ const { error } = paramsSchema.validate({
280
+ accountAddress,
281
+ tokenAddress,
282
+ resolver
283
+ });
284
+ if (error) throw new _ocap_util_lib_error.CustomError("INVALID_PARAMS", error.message);
285
+ const minAmount = (0, _ocap_util.fromTokenToUnit)(1, (await resolver.tokenCache.get(tokenAddress))?.decimal || 18);
286
+ const maxAccountSize = Math.min(200, paging.size || 200);
287
+ const maxDepth = Math.min(5, depth);
288
+ const vaultAccounts = getVaultAccounts(resolver.config);
289
+ const tokenFlows = [];
290
+ const checkedAccounts = /* @__PURE__ */ new Map();
291
+ const checkedTx = /* @__PURE__ */ new Map();
292
+ let curDepth = 1;
293
+ const depthQueue = { [curDepth]: [accountAddress] };
294
+ while (depthQueue[curDepth]?.length && curDepth <= maxDepth && checkedAccounts.size < maxAccountSize) {
295
+ for (const address of depthQueue[curDepth]) {
296
+ if (checkedAccounts.has(address)) continue;
297
+ if (_arcblock_validator.schemas.tokenHolder.validate(address).error) continue;
298
+ const transactions = await resolver._getAllResults("transactions", (page) => resolver.listTransactions({
299
+ paging: page,
300
+ accountFilter: { accounts: [address] },
301
+ tokenFilter: { tokens: [tokenAddress] }
302
+ }, ctx));
303
+ let accountsToQueue = [];
304
+ for (const tx of transactions) {
305
+ if (!checkedTx.has(tx.hash)) {
306
+ await fixMigrateReceipts(tx, resolver);
307
+ checkedTx.set(tx.hash, getTransferFlow(tx, tokenAddress));
308
+ }
309
+ const txTransfers = checkedTx.get(tx.hash).filter((item) => {
310
+ if (direction === "OUT" && item.from !== address) return false;
311
+ if (direction === "IN" && item.to !== address) return false;
312
+ if (item.value.lt(minAmount)) return false;
313
+ return true;
314
+ });
315
+ tokenFlows.push(...txTransfers.map((item) => ({
316
+ ...item,
317
+ value: item.value.toString()
318
+ })));
319
+ accountsToQueue = accountsToQueue.concat(txTransfers.map((item) => direction === "IN" ? item.from : item.to).filter((item) => !vaultAccounts.includes(item)));
320
+ }
321
+ checkedAccounts.set(address, true);
322
+ if (checkedAccounts.size >= maxAccountSize) break;
323
+ if (!depthQueue[curDepth + 1]) depthQueue[curDepth + 1] = [];
324
+ depthQueue[curDepth + 1].push(...(0, lodash_uniq.default)(accountsToQueue));
325
+ }
326
+ curDepth++;
327
+ }
328
+ return tokenFlows;
329
+ };
330
+
331
+ //#endregion
332
+ exports.fixMigrateReceipts = fixMigrateReceipts;
333
+ exports.getTransferFlow = getTransferFlow;
334
+ exports.getTransferList = getTransferList;
335
+ exports.listTokenFlows = listTokenFlows;
336
+ exports.verifyAccountRisk = verifyAccountRisk;
@@ -0,0 +1,139 @@
1
+ import { IChainConfig, IFilter, IMigrationChain, IPipelineLogger, IResolverPaging, IStateDB, ITokenCache, TTransactionReceipt } from "./types.cjs";
2
+ import { BN } from "@ocap/util";
3
+
4
+ //#region src/token-flow.d.ts
5
+
6
+ /**
7
+ * Transfer item with BN value for calculation
8
+ */
9
+ interface ITransferItem {
10
+ address: string;
11
+ value: InstanceType<typeof BN>;
12
+ action?: string;
13
+ archived?: boolean;
14
+ }
15
+ /**
16
+ * Transfer flow with BN value
17
+ */
18
+ interface ITransferFlow {
19
+ from: string;
20
+ to: string;
21
+ value: InstanceType<typeof BN>;
22
+ hash: string;
23
+ }
24
+ /**
25
+ * Transfer flow result with string value
26
+ */
27
+ interface ITransferFlowResult {
28
+ from: string;
29
+ to: string;
30
+ value: string;
31
+ hash: string;
32
+ }
33
+ /**
34
+ * Risk check result
35
+ */
36
+ interface IRiskCheckResult {
37
+ isRisky: boolean;
38
+ reason?: string;
39
+ data: {
40
+ address?: string;
41
+ balance?: string | number;
42
+ transferIn?: string;
43
+ transferOut?: string;
44
+ accountCount: number;
45
+ txCount: number;
46
+ };
47
+ }
48
+ /**
49
+ * Parameters for verifyAccountRisk
50
+ */
51
+ interface IVerifyAccountRiskParams {
52
+ accountAddress: string;
53
+ tokenAddress: string;
54
+ accountLimit?: number;
55
+ txLimit?: number;
56
+ tolerance?: string;
57
+ }
58
+ /**
59
+ * Parameters for listTokenFlows
60
+ */
61
+ interface IListTokenFlowsParams {
62
+ accountAddress: string;
63
+ tokenAddress: string;
64
+ paging?: IResolverPaging;
65
+ depth?: number;
66
+ direction?: 'IN' | 'OUT';
67
+ }
68
+ /**
69
+ * Simplified transaction for token flow
70
+ */
71
+ interface ITokenFlowTx {
72
+ hash: string;
73
+ time: string;
74
+ receipts?: TTransactionReceipt[];
75
+ [key: string]: unknown;
76
+ }
77
+ /**
78
+ * Resolver interface for token flow operations
79
+ */
80
+ interface ITokenFlowResolver {
81
+ config: IChainConfig;
82
+ tokenCache: ITokenCache;
83
+ filter?: IFilter;
84
+ logger: IPipelineLogger;
85
+ statedb: IStateDB;
86
+ getMigrationChain: () => Promise<IMigrationChain>;
87
+ _getAllResults: <T>(type: string, fetcher: (paging: IResolverPaging) => Promise<{
88
+ transactions?: T[];
89
+ data?: T[];
90
+ }>, limit?: number) => Promise<T[]>;
91
+ listTransactions: (params: {
92
+ paging?: IResolverPaging;
93
+ accountFilter?: {
94
+ accounts: string[];
95
+ };
96
+ tokenFilter?: {
97
+ tokens: string[];
98
+ };
99
+ }, ctx?: Record<string, unknown>) => Promise<{
100
+ transactions: ITokenFlowTx[];
101
+ }>;
102
+ runAsLambda: <T>(fn: (txn: unknown) => Promise<T>, options?: {
103
+ retryLimit?: number;
104
+ }) => Promise<T>;
105
+ }
106
+ /**
107
+ * Parse transfer in/out list from transaction
108
+ * @param tx Transaction object
109
+ * @param tokenAddress Token address to filter by
110
+ * @returns Object containing transferInList and transferOutList
111
+ */
112
+ declare const getTransferList: (tx: ITokenFlowTx, tokenAddress: string) => {
113
+ transferInList: ITransferItem[];
114
+ transferOutList: ITransferItem[];
115
+ };
116
+ /**
117
+ * Parse transfer flow from transaction
118
+ * @param tx Transaction object
119
+ * @param tokenAddress Token address to filter by
120
+ * @returns Array of transfer flows
121
+ */
122
+ declare const getTransferFlow: (tx: ITokenFlowTx, tokenAddress: string) => ITransferFlow[];
123
+ declare const fixMigrateReceipts: (tx: ITokenFlowTx, resolver: ITokenFlowResolver) => Promise<void>;
124
+ declare const verifyAccountRisk: ({
125
+ accountAddress,
126
+ tokenAddress,
127
+ accountLimit,
128
+ txLimit,
129
+ tolerance
130
+ }: IVerifyAccountRiskParams, resolver: ITokenFlowResolver, ctx?: Record<string, unknown>) => Promise<IRiskCheckResult>;
131
+ declare const listTokenFlows: ({
132
+ accountAddress,
133
+ tokenAddress,
134
+ paging,
135
+ depth,
136
+ direction
137
+ }: IListTokenFlowsParams, resolver: ITokenFlowResolver, ctx?: Record<string, unknown>) => Promise<ITransferFlowResult[]>;
138
+ //#endregion
139
+ export { fixMigrateReceipts, getTransferFlow, getTransferList, listTokenFlows, verifyAccountRisk };
package/lib/types.cjs ADDED
File without changes