@rosen-bridge/abstract-extractor 2.1.0 → 2.1.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.
Files changed (127) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/package.json +14 -7
  3. package/.eslintignore +0 -1
  4. package/dist/lib/abstractExtractor.d.ts +0 -25
  5. package/dist/lib/abstractExtractor.d.ts.map +0 -1
  6. package/dist/lib/abstractExtractor.js +0 -3
  7. package/dist/lib/constants.d.ts +0 -4
  8. package/dist/lib/constants.d.ts.map +0 -1
  9. package/dist/lib/constants.js +0 -4
  10. package/dist/lib/ergo/AbstractErgoExtractor.d.ts +0 -80
  11. package/dist/lib/ergo/AbstractErgoExtractor.d.ts.map +0 -1
  12. package/dist/lib/ergo/AbstractErgoExtractor.js +0 -142
  13. package/dist/lib/ergo/AbstractErgoExtractorAction.d.ts +0 -92
  14. package/dist/lib/ergo/AbstractErgoExtractorAction.d.ts.map +0 -1
  15. package/dist/lib/ergo/AbstractErgoExtractorAction.js +0 -222
  16. package/dist/lib/ergo/AbstractErgoExtractorEntity.d.ts +0 -11
  17. package/dist/lib/ergo/AbstractErgoExtractorEntity.d.ts.map +0 -1
  18. package/dist/lib/ergo/AbstractErgoExtractorEntity.js +0 -57
  19. package/dist/lib/ergo/index.d.ts +0 -10
  20. package/dist/lib/ergo/index.d.ts.map +0 -1
  21. package/dist/lib/ergo/index.js +0 -10
  22. package/dist/lib/ergo/initializable/AbstractInitializable.d.ts +0 -48
  23. package/dist/lib/ergo/initializable/AbstractInitializable.d.ts.map +0 -1
  24. package/dist/lib/ergo/initializable/AbstractInitializable.js +0 -163
  25. package/dist/lib/ergo/initializable/AbstractInitializableAction.d.ts +0 -14
  26. package/dist/lib/ergo/initializable/AbstractInitializableAction.d.ts.map +0 -1
  27. package/dist/lib/ergo/initializable/AbstractInitializableAction.js +0 -16
  28. package/dist/lib/ergo/initializable/index.d.ts +0 -3
  29. package/dist/lib/ergo/initializable/index.d.ts.map +0 -1
  30. package/dist/lib/ergo/initializable/index.js +0 -3
  31. package/dist/lib/ergo/interfaces.d.ts +0 -47
  32. package/dist/lib/ergo/interfaces.d.ts.map +0 -1
  33. package/dist/lib/ergo/interfaces.js +0 -8
  34. package/dist/lib/ergo/network/AbstractNetwork.d.ts +0 -26
  35. package/dist/lib/ergo/network/AbstractNetwork.d.ts.map +0 -1
  36. package/dist/lib/ergo/network/AbstractNetwork.js +0 -3
  37. package/dist/lib/ergo/network/ExplorerNetwork.d.ts +0 -74
  38. package/dist/lib/ergo/network/ExplorerNetwork.d.ts.map +0 -1
  39. package/dist/lib/ergo/network/ExplorerNetwork.js +0 -185
  40. package/dist/lib/ergo/network/NodeNetwork.d.ts +0 -60
  41. package/dist/lib/ergo/network/NodeNetwork.d.ts.map +0 -1
  42. package/dist/lib/ergo/network/NodeNetwork.js +0 -131
  43. package/dist/lib/ergo/utils.d.ts +0 -8
  44. package/dist/lib/ergo/utils.d.ts.map +0 -1
  45. package/dist/lib/ergo/utils.js +0 -16
  46. package/dist/lib/index.d.ts +0 -4
  47. package/dist/lib/index.d.ts.map +0 -1
  48. package/dist/lib/index.js +0 -4
  49. package/dist/tests/AbstractErgoExtractor.mock.d.ts +0 -11
  50. package/dist/tests/AbstractErgoExtractor.mock.d.ts.map +0 -1
  51. package/dist/tests/AbstractErgoExtractor.mock.js +0 -11
  52. package/dist/tests/AbstractErgoExtractor.spec.d.ts +0 -2
  53. package/dist/tests/AbstractErgoExtractor.spec.d.ts.map +0 -1
  54. package/dist/tests/AbstractErgoExtractor.spec.js +0 -240
  55. package/dist/tests/AbstractErgoExtractorAction.mock.d.ts +0 -15
  56. package/dist/tests/AbstractErgoExtractorAction.mock.d.ts.map +0 -1
  57. package/dist/tests/AbstractErgoExtractorAction.mock.js +0 -27
  58. package/dist/tests/AbstractErgoExtractorAction.spec.d.ts +0 -2
  59. package/dist/tests/AbstractErgoExtractorAction.spec.d.ts.map +0 -1
  60. package/dist/tests/AbstractErgoExtractorAction.spec.js +0 -221
  61. package/dist/tests/initializable/AbstractInitializable.mock.d.ts +0 -61
  62. package/dist/tests/initializable/AbstractInitializable.mock.d.ts.map +0 -1
  63. package/dist/tests/initializable/AbstractInitializable.mock.js +0 -18
  64. package/dist/tests/initializable/AbstractInitializable.spec.d.ts +0 -2
  65. package/dist/tests/initializable/AbstractInitializable.spec.d.ts.map +0 -1
  66. package/dist/tests/initializable/AbstractInitializable.spec.js +0 -299
  67. package/dist/tests/initializable/AbstractInitializableAction.mock.d.ts +0 -15
  68. package/dist/tests/initializable/AbstractInitializableAction.mock.d.ts.map +0 -1
  69. package/dist/tests/initializable/AbstractInitializableAction.mock.js +0 -27
  70. package/dist/tests/initializable/AbstractInitializableAction.spec.d.ts +0 -2
  71. package/dist/tests/initializable/AbstractInitializableAction.spec.d.ts.map +0 -1
  72. package/dist/tests/initializable/AbstractInitializableAction.spec.js +0 -54
  73. package/dist/tests/initializable/testData.d.ts +0 -94
  74. package/dist/tests/initializable/testData.d.ts.map +0 -1
  75. package/dist/tests/initializable/testData.js +0 -235
  76. package/dist/tests/network/ExplorerNetwork.spec.d.ts +0 -2
  77. package/dist/tests/network/ExplorerNetwork.spec.d.ts.map +0 -1
  78. package/dist/tests/network/ExplorerNetwork.spec.js +0 -61
  79. package/dist/tests/network/NodeNetwork.spec.d.ts +0 -2
  80. package/dist/tests/network/NodeNetwork.spec.d.ts.map +0 -1
  81. package/dist/tests/network/NodeNetwork.spec.js +0 -48
  82. package/dist/tests/network/testData.d.ts +0 -752
  83. package/dist/tests/network/testData.d.ts.map +0 -1
  84. package/dist/tests/network/testData.js +0 -1401
  85. package/dist/tests/testData.d.ts +0 -32
  86. package/dist/tests/testData.d.ts.map +0 -1
  87. package/dist/tests/testData.js +0 -121
  88. package/dist/tests/testUtils.d.ts +0 -9
  89. package/dist/tests/testUtils.d.ts.map +0 -1
  90. package/dist/tests/testUtils.js +0 -31
  91. package/dist/tsconfig.tsbuildinfo +0 -1
  92. package/dist/vitest.config.d.ts +0 -3
  93. package/dist/vitest.config.d.ts.map +0 -1
  94. package/dist/vitest.config.js +0 -18
  95. package/lib/abstractExtractor.ts +0 -31
  96. package/lib/constants.ts +0 -3
  97. package/lib/ergo/AbstractErgoExtractor.ts +0 -227
  98. package/lib/ergo/AbstractErgoExtractorAction.ts +0 -319
  99. package/lib/ergo/AbstractErgoExtractorEntity.ts +0 -32
  100. package/lib/ergo/index.ts +0 -9
  101. package/lib/ergo/initializable/AbstractInitializable.ts +0 -228
  102. package/lib/ergo/initializable/AbstractInitializableAction.ts +0 -33
  103. package/lib/ergo/initializable/index.ts +0 -2
  104. package/lib/ergo/interfaces.ts +0 -51
  105. package/lib/ergo/network/AbstractNetwork.ts +0 -29
  106. package/lib/ergo/network/ExplorerNetwork.ts +0 -237
  107. package/lib/ergo/network/NodeNetwork.ts +0 -169
  108. package/lib/ergo/utils.ts +0 -15
  109. package/lib/index.ts +0 -3
  110. package/tests/AbstractErgoExtractor.mock.ts +0 -33
  111. package/tests/AbstractErgoExtractor.spec.ts +0 -284
  112. package/tests/AbstractErgoExtractorAction.mock.ts +0 -45
  113. package/tests/AbstractErgoExtractorAction.spec.ts +0 -268
  114. package/tests/initializable/AbstractInitializable.mock.ts +0 -44
  115. package/tests/initializable/AbstractInitializable.spec.ts +0 -386
  116. package/tests/initializable/AbstractInitializableAction.mock.ts +0 -45
  117. package/tests/initializable/AbstractInitializableAction.spec.ts +0 -64
  118. package/tests/initializable/testData.ts +0 -283
  119. package/tests/network/ExplorerNetwork.spec.ts +0 -73
  120. package/tests/network/NodeNetwork.spec.ts +0 -56
  121. package/tests/network/testData.ts +0 -1708
  122. package/tests/testData.ts +0 -140
  123. package/tests/testUtils.ts +0 -22
  124. package/tsconfig.build.json +0 -9
  125. package/tsconfig.build.tsbuildinfo +0 -1
  126. package/tsconfig.json +0 -9
  127. package/vitest.config.ts +0 -18
@@ -1,228 +0,0 @@
1
- import { AbstractLogger } from '@rosen-bridge/abstract-logger';
2
- import { groupBy, sortBy } from 'lodash-es';
3
- import { BlockInfo, ErgoNetworkType } from '@rosen-bridge/scanner-interfaces';
4
-
5
- import { AbstractBoxData, ExtendedTransaction } from '../interfaces';
6
- import { API_LIMIT, RETRIAL_COUNT } from '../../constants';
7
- import { AbstractErgoExtractor } from '../AbstractErgoExtractor';
8
- import { AbstractInitializableErgoExtractorAction } from './AbstractInitializableAction';
9
- import { ExplorerNetwork } from '../network/ExplorerNetwork';
10
- import { NodeNetwork } from '../network/NodeNetwork';
11
- import { AbstractErgoExtractorEntity } from '../AbstractErgoExtractorEntity';
12
-
13
- export abstract class AbstractInitializableErgoExtractor<
14
- ExtractedData extends AbstractBoxData,
15
- ExtractorEntity extends AbstractErgoExtractorEntity,
16
- > extends AbstractErgoExtractor<ExtractedData, ExtractorEntity> {
17
- protected initialize: boolean;
18
- private address: string;
19
- protected abstract actions: AbstractInitializableErgoExtractorAction<
20
- ExtractedData,
21
- ExtractorEntity
22
- >;
23
-
24
- private network: ExplorerNetwork | NodeNetwork;
25
-
26
- constructor(
27
- type: ErgoNetworkType,
28
- url: string,
29
- address: string,
30
- logger?: AbstractLogger,
31
- initialize = true,
32
- ) {
33
- super(logger);
34
- this.address = address;
35
- this.initialize = initialize;
36
- if (type == ErgoNetworkType.Explorer) {
37
- this.network = new ExplorerNetwork(url);
38
- this.initializeBoxes = (initialBlock: BlockInfo) => {
39
- return this.initializeWithExplorer(initialBlock);
40
- };
41
- } else if (type == ErgoNetworkType.Node) {
42
- this.network = new NodeNetwork(url);
43
- this.initializeBoxes = (initialBlock: BlockInfo) => {
44
- return this.initializeWithNode(initialBlock);
45
- };
46
- } else throw new Error(`Network type ${type} is not supported`);
47
- }
48
-
49
- /**
50
- * Initialize extractor using Explorer network
51
- * @param initialBlock
52
- */
53
- private initializeWithExplorer = async (initialBlock: BlockInfo) => {
54
- const explorerNetwork = this.network as ExplorerNetwork;
55
- let fromHeight = 0,
56
- toHeight = initialBlock.height;
57
- await this.initWithRetrial(async () => {
58
- while (fromHeight < toHeight) {
59
- let txs: Array<ExtendedTransaction>;
60
- // eslint-disable-next-line no-constant-condition
61
- while (true) {
62
- txs = await explorerNetwork.getAddressTransactionsWithHeight(
63
- this.address,
64
- fromHeight,
65
- toHeight,
66
- );
67
- this.logger.debug(
68
- `Found ${txs.length} transactions for the address from height ${fromHeight} to height ${toHeight}`,
69
- );
70
- if (txs.length < API_LIMIT || fromHeight === toHeight) {
71
- break; // Exit loop if we have fewer transactions than the limit or if the range is reduced to a single height
72
- }
73
- toHeight = Math.floor((toHeight - fromHeight) / 2) + fromHeight;
74
- this.logger.debug(
75
- `Limiting the query height range to [${fromHeight}, ${toHeight}]`,
76
- );
77
- }
78
- if (txs.length < API_LIMIT) {
79
- if (txs.length > 0) await this.processTransactionBatch(txs);
80
- } else {
81
- this.logger.debug(
82
- `Block at height ${fromHeight} has more than (or equal) ${API_LIMIT} relevant txs, processing all txs in the block`,
83
- );
84
- const blockId = await explorerNetwork.getBlockIdAtHeight(fromHeight);
85
- const blockTxs = await explorerNetwork.getBlockTxs(blockId);
86
- this.logger.debug(
87
- `Found ${blockTxs.length} transactions at height ${fromHeight}`,
88
- );
89
- await this.processTransactions(blockTxs, {
90
- hash: blockId,
91
- height: fromHeight,
92
- });
93
- }
94
- fromHeight = toHeight + 1;
95
- toHeight = initialBlock.height;
96
- }
97
- });
98
- };
99
-
100
- /**
101
- * Get the total tx count from Node network
102
- * @returns total tx count of the address
103
- */
104
- private getTotalTxCount = async () => {
105
- const response = await (
106
- this.network as NodeNetwork
107
- ).getAddressTransactionsWithOffsetLimit(this.address, 0, 0);
108
- return response.total;
109
- };
110
-
111
- /**
112
- * Initialize extractor using Node network
113
- * @param initialBlock
114
- */
115
- private initializeWithNode = async (initialBlock: BlockInfo) => {
116
- const txCountBeforeInit = await this.getTotalTxCount();
117
- let offset = 0,
118
- total = 1,
119
- round = 1;
120
- await this.initWithRetrial(async () => {
121
- // Repeat the whole process twice to cover all spent boxes
122
- // After round 1 all boxes have been saved and processed once
123
- // After round 2 spending information of all stored boxes are updated successfully
124
- while (round <= 2) {
125
- this.logger.debug(`Starting round ${round} of initialization`);
126
- while (offset < total) {
127
- const response = await (
128
- this.network as NodeNetwork
129
- ).getAddressTransactionsWithOffsetLimit(
130
- this.address,
131
- offset,
132
- API_LIMIT,
133
- );
134
- total = response.total;
135
- const txs = response.items.filter(
136
- (tx) => tx.inclusionHeight <= initialBlock.height,
137
- );
138
- this.logger.debug(
139
- `Found ${txs.length} transactions below the initial height with offset ${offset} and total number of transactions ${total}`,
140
- );
141
- if (txs.length > 0) await this.processTransactionBatch(txs);
142
- offset += API_LIMIT;
143
- }
144
- round++;
145
- offset = 0; // next round initial offset
146
- }
147
- });
148
- const txCountAfterInit = await this.getTotalTxCount();
149
- if (txCountAfterInit != txCountBeforeInit) {
150
- throw Error(
151
- 'Total transaction count changed during initialization phase, the stored data is not valid',
152
- );
153
- }
154
- };
155
-
156
- /**
157
- * Process a batch of transactions
158
- * group txs into blocks and process them using `processTransactions`
159
- * @param txs
160
- */
161
- private processTransactionBatch = async (txs: Array<ExtendedTransaction>) => {
162
- txs = sortBy(txs, (tx) => tx.inclusionHeight);
163
- const groupedTxs = groupBy(txs, (tx) => tx.blockId);
164
- this.logger.debug(
165
- `The transaction batch grouped to ${
166
- Object.keys(groupedTxs).length
167
- } blocks`,
168
- );
169
- for (const blockId in groupedTxs) {
170
- const blockTxs = groupedTxs[blockId];
171
- const block = { hash: blockId, height: blockTxs[0].inclusionHeight };
172
- this.logger.debug(
173
- `Processing transactions at height ${blockTxs[0].inclusionHeight}`,
174
- );
175
- const success = await this.processTransactions(blockTxs, block);
176
- if (!success)
177
- throw Error(
178
- `Processing transactions failed at height ${blockTxs[0].inclusionHeight}`,
179
- );
180
- }
181
- };
182
-
183
- /**
184
- * Initialize the extractor with retrial on any unexpected problem
185
- * its the common part of initialize with Node and Explorer network
186
- * @param job
187
- */
188
- private initWithRetrial = async (job: () => Promise<void>) => {
189
- let trial = 1;
190
- if (this.initialize) {
191
- this.logger.debug(
192
- `Initializing ${this.getId()} started, removing all existing data`,
193
- );
194
- await this.actions.removeAllData(this.getId());
195
- while (trial <= RETRIAL_COUNT) {
196
- try {
197
- await job();
198
- break;
199
- } catch (e) {
200
- this.logger.warn(
201
- `Initialization for ${this.getId()} failed with error :${e}`,
202
- );
203
- if (trial == RETRIAL_COUNT)
204
- throw Error(
205
- `Initialization for ${this.getId()} failed after ${RETRIAL_COUNT} retrial`,
206
- );
207
- trial += 1;
208
- this.logger.info(
209
- `Trying again to initialize ${this.getId()} with trial step ${trial}`,
210
- );
211
- }
212
- }
213
- this.logger.info(
214
- `Initialization completed successfully for ${this.getId()}`,
215
- );
216
- } else {
217
- this.logger.info(`Initialization for ${this.getId()} is turned off`);
218
- }
219
- };
220
-
221
- /**
222
- * initialize extractor database with data created below the initial height
223
- * ignore initialization if this feature is off
224
- * try to get data multiple times to pass accidental network problems
225
- * @param initialBlock
226
- */
227
- initializeBoxes: (initialBlock: BlockInfo) => Promise<void>;
228
- }
@@ -1,33 +0,0 @@
1
- import {
2
- DataSource,
3
- EntityTarget,
4
- FindOptionsWhere,
5
- } from '@rosen-bridge/extended-typeorm';
6
- import { AbstractLogger } from '@rosen-bridge/abstract-logger';
7
-
8
- import { AbstractErgoExtractorAction } from '../AbstractErgoExtractorAction';
9
- import { AbstractBoxData } from '../interfaces';
10
- import { AbstractErgoExtractorEntity } from '../AbstractErgoExtractorEntity';
11
-
12
- export abstract class AbstractInitializableErgoExtractorAction<
13
- ExtractedData extends AbstractBoxData,
14
- ExtractorEntity extends AbstractErgoExtractorEntity,
15
- > extends AbstractErgoExtractorAction<ExtractedData, ExtractorEntity> {
16
- constructor(
17
- dataSource: DataSource,
18
- repo: EntityTarget<ExtractorEntity>,
19
- logger?: AbstractLogger,
20
- ) {
21
- super(dataSource, repo, logger);
22
- }
23
-
24
- /**
25
- * remove all existing data for the extractor
26
- * @param extractorId
27
- */
28
- removeAllData = async (extractorId: string) => {
29
- await this.repository.delete({
30
- extractor: extractorId,
31
- } as FindOptionsWhere<ExtractorEntity>);
32
- };
33
- }
@@ -1,2 +0,0 @@
1
- export * from './AbstractInitializable';
2
- export * from './AbstractInitializableAction';
@@ -1,51 +0,0 @@
1
- import { OutputBox, Transaction } from '@rosen-bridge/scanner-interfaces';
2
-
3
- export interface ErgoBox extends OutputBox {
4
- blockId: string;
5
- inclusionHeight: number;
6
- spentBlockId?: string;
7
- spentHeight?: number;
8
- spentTransactionId?: string;
9
- spentIndex?: number;
10
- }
11
-
12
- export interface ExtendedTransaction extends Transaction {
13
- inclusionHeight: number;
14
- blockId: string;
15
- }
16
-
17
- export interface SpendInfo {
18
- boxId: string;
19
- txId: string;
20
- index: number;
21
- extras?: { [key: string]: string };
22
- }
23
-
24
- export interface AbstractBoxData {
25
- boxId: string;
26
- serialized: string;
27
- }
28
-
29
- export enum CallbackType {
30
- Insert = 'insert',
31
- Update = 'update',
32
- Spend = 'spend',
33
- Delete = 'delete',
34
- }
35
-
36
- export interface BoxInfo {
37
- boxId: string;
38
- }
39
-
40
- export type CallbackDataMap<ExtractedData extends AbstractBoxData> = {
41
- [CallbackType.Update]: BoxInfo[];
42
- [CallbackType.Insert]: ExtractedData[];
43
- [CallbackType.Delete]: ExtractedData[];
44
- [CallbackType.Spend]: BoxInfo[];
45
- };
46
-
47
- export type CallbackMap<ExtractedData extends AbstractBoxData> = {
48
- [K in CallbackType]: (data: CallbackDataMap<ExtractedData>[K]) => void;
49
- };
50
-
51
- export type TxExtra = { [key: string]: string };
@@ -1,29 +0,0 @@
1
- import { ErgoBox } from '../interfaces';
2
-
3
- export abstract class AbstractNetwork {
4
- /**
5
- * return related boxes by specified address with limit offset
6
- * @param address
7
- * @param offset
8
- * @param limit
9
- * @returns related boxes
10
- */
11
- abstract getBoxesByAddress: (
12
- address: string,
13
- offset: number,
14
- limit: number,
15
- ) => Promise<{ boxes: ErgoBox[]; hasNextBatch: boolean }>;
16
-
17
- /**
18
- * return related boxes by specified token with limit offset
19
- * @param tokenId
20
- * @param offset
21
- * @param limit
22
- * @returns related boxes
23
- */
24
- abstract getBoxesByTokenId: (
25
- tokenId: string,
26
- offset: number,
27
- limit: number,
28
- ) => Promise<{ boxes: ErgoBox[]; hasNextBatch: boolean }>;
29
- }
@@ -1,237 +0,0 @@
1
- import ergoExplorerClientFactory from '@rosen-clients/ergo-explorer';
2
- import { AbstractNetwork } from './AbstractNetwork';
3
- import { V1 } from '@rosen-clients/ergo-explorer';
4
- import { BlockInfo, Transaction } from '@rosen-bridge/scanner-interfaces';
5
-
6
- import { ErgoBox, ExtendedTransaction } from '../interfaces';
7
- import { mapValues, pick } from 'lodash-es';
8
- import { API_LIMIT } from '../../constants';
9
-
10
- export class ExplorerNetwork extends AbstractNetwork {
11
- private api;
12
-
13
- constructor(url: string) {
14
- super();
15
- this.api = ergoExplorerClientFactory(url);
16
- }
17
-
18
- /**
19
- * return spending information of a specified box by having spendTxId
20
- * @param boxId
21
- * @param spendTxId
22
- */
23
- getSpendingInfo = async (
24
- boxId: string,
25
- spendTxId: string,
26
- ): Promise<BlockInfo & { spendIndex: number }> => {
27
- const tx = await this.api.v1.getApiV1TransactionsP1(spendTxId);
28
- const spendIndex = tx.inputs?.findIndex((box) => box.boxId === boxId);
29
- if (spendIndex == undefined)
30
- throw Error(
31
- `Impossible behavior, the box [${boxId}] should have been spent in tx [${spendTxId}]`,
32
- );
33
- return {
34
- hash: tx.blockId,
35
- height: tx.inclusionHeight,
36
- spendIndex,
37
- };
38
- };
39
-
40
- /**
41
- * convert explorer api boxes to ErgoBox interface
42
- * @param box
43
- * @returns ErgoBox
44
- */
45
- private convertBox = async (box: V1.OutputInfo): Promise<ErgoBox> => {
46
- const spendInfo = box.spentTransactionId
47
- ? await this.getSpendingInfo(box.boxId, box.spentTransactionId)
48
- : undefined;
49
- return {
50
- blockId: box.blockId,
51
- boxId: box.boxId,
52
- creationHeight: box.creationHeight,
53
- inclusionHeight: box.settlementHeight,
54
- ergoTree: box.ergoTree,
55
- index: box.index,
56
- transactionId: box.transactionId,
57
- value: box.value,
58
- additionalRegisters: mapValues(
59
- box.additionalRegisters,
60
- 'serializedValue',
61
- ),
62
- assets:
63
- box.assets?.map((asset) => pick(asset, ['tokenId', 'amount'])) ?? [],
64
- spentHeight: spendInfo?.height,
65
- spentBlockId: spendInfo?.hash,
66
- spentTransactionId: box.spentTransactionId,
67
- spentIndex: spendInfo?.spendIndex,
68
- };
69
- };
70
-
71
- /**
72
- * convert explorer transaction to extractor transaction type
73
- * @param tx
74
- */
75
- private convertTransaction = (
76
- tx: V1.TransactionInfo,
77
- ): ExtendedTransaction => {
78
- return {
79
- id: tx.id,
80
- inclusionHeight: tx.inclusionHeight,
81
- blockId: tx.blockId,
82
- dataInputs:
83
- tx.dataInputs?.map((dataInput) => ({
84
- boxId: dataInput.boxId,
85
- })) ?? [],
86
- // TODO: Add input extension to explorer local/ergo/rosen-bridge/scanner/-/issues/156
87
- inputs: tx.inputs?.map((input) => ({ boxId: input.boxId })) ?? [],
88
- outputs:
89
- tx.outputs?.map((output) => ({
90
- boxId: output.boxId,
91
- transactionId: output.transactionId,
92
- additionalRegisters: mapValues(
93
- output.additionalRegisters,
94
- 'serializedValue',
95
- ),
96
- assets:
97
- output.assets?.map((asset) => pick(asset, ['tokenId', 'amount'])) ??
98
- [],
99
- ergoTree: output.ergoTree,
100
- creationHeight: output.creationHeight,
101
- index: output.index,
102
- value: output.value,
103
- })) ?? [],
104
- };
105
- };
106
-
107
- /**
108
- * convert explorer block transaction to transaction type
109
- * @param tx
110
- */
111
- private convertBlockTransaction = (tx: V1.TransactionInfo1): Transaction => {
112
- return {
113
- id: tx.id,
114
- dataInputs:
115
- tx.dataInputs?.map((dataInput) => ({
116
- boxId: dataInput.id,
117
- })) ?? [],
118
- // TODO: Add input extension local/ergo/rosen-bridge/scanner/-/issues/156
119
- inputs: tx.inputs?.map((input) => ({ boxId: input.id })) ?? [],
120
- outputs:
121
- tx.outputs?.map((output) => ({
122
- boxId: output.id,
123
- transactionId: output.txId,
124
- additionalRegisters: output.additionalRegisters,
125
- assets:
126
- output.assets?.map((asset) => pick(asset, ['tokenId', 'amount'])) ??
127
- [],
128
- ergoTree: output.ergoTree,
129
- creationHeight: output.creationHeight,
130
- index: output.index,
131
- value: output.value,
132
- })) ?? [],
133
- };
134
- };
135
-
136
- /**
137
- * use explorer api to return related transactions of the specified address in the height range
138
- * @param tokenId
139
- * @param offset
140
- * @param limit
141
- * @returns related transactions
142
- */
143
- getAddressTransactionsWithHeight = async (
144
- address: string,
145
- fromHeight: number,
146
- toHeight: number,
147
- ): Promise<Array<ExtendedTransaction>> => {
148
- const txs = await this.api.v1.getApiV1AddressesP1Transactions(address, {
149
- fromHeight,
150
- toHeight,
151
- limit: API_LIMIT,
152
- });
153
- if (!txs.items)
154
- throw new Error(
155
- 'Explorer AddressTransactions api expected to have items',
156
- );
157
- return txs.items.map((tx) => this.convertTransaction(tx));
158
- };
159
-
160
- /**
161
- * use explorer api to get the block id at the specified height
162
- * @param height
163
- * @returns block id
164
- */
165
- getBlockIdAtHeight = async (height: number): Promise<string> => {
166
- const id = await this.api.v0.getApiV0BlocksAtP1(height);
167
- return id[0];
168
- };
169
-
170
- /**
171
- * use explorer api to return all transactions in a block
172
- * @param blockId
173
- * @returns converted transactions
174
- */
175
- getBlockTxs = async (blockId: string): Promise<Array<Transaction>> => {
176
- const block = await this.api.v1.getApiV1BlocksP1(blockId);
177
- if (!block.block.blockTransactions) {
178
- throw new Error(
179
- `Expected explorer block api to include block transactions for block ${blockId}`,
180
- );
181
- }
182
- return block.block.blockTransactions.map((tx) =>
183
- this.convertBlockTransaction(tx),
184
- );
185
- };
186
-
187
- /**
188
- * use explorer api to return related boxes by specified address
189
- * @param address
190
- * @param offset
191
- * @param limit
192
- * @returns related boxes
193
- */
194
- getBoxesByAddress = async (
195
- address: string,
196
- offset: number,
197
- limit: number,
198
- ): Promise<{ boxes: ErgoBox[]; hasNextBatch: boolean }> => {
199
- const boxes = await this.api.v1.getApiV1BoxesUnspentByaddressP1(address, {
200
- offset: offset,
201
- limit: limit,
202
- sortDirection: 'desc',
203
- });
204
- if (!boxes.items)
205
- throw new Error('Explorer BoxesByAddress api expected to have items');
206
- const resultBoxes: Array<ErgoBox> = [];
207
- for (const box of boxes.items) {
208
- resultBoxes.push(await this.convertBox(box));
209
- }
210
- return { boxes: resultBoxes, hasNextBatch: boxes.total > offset + limit };
211
- };
212
-
213
- /**
214
- * use explorer api to return related boxes by specified token id
215
- * @param tokenId
216
- * @param offset
217
- * @param limit
218
- * @returns related boxes
219
- */
220
- getBoxesByTokenId = async (
221
- tokenId: string,
222
- offset: number,
223
- limit: number,
224
- ): Promise<{ boxes: ErgoBox[]; hasNextBatch: boolean }> => {
225
- const boxes = await this.api.v1.getApiV1BoxesBytokenidP1(tokenId, {
226
- offset: offset,
227
- limit: limit,
228
- });
229
- if (!boxes.items)
230
- throw new Error('Explorer BoxesByTokeId api expected to have items');
231
- const resultBoxes: Array<ErgoBox> = [];
232
- for (const box of boxes.items) {
233
- resultBoxes.push(await this.convertBox(box));
234
- }
235
- return { boxes: resultBoxes, hasNextBatch: boxes.total > offset + limit };
236
- };
237
- }